RaspberryPi control
How to Use SocketCAN(Download the code from RaspberryPi_dome)
SocketCAN is a CAN bus communication framework under Linux. It treats CAN devices as network interfaces, allowing you to send and receive CAN frames just like operating ordinary sockets (TCP/UDP).
(1) Key Features
- Based on Socket API
CAN data can be sent and received using standard BSD socket calls such as
socket()
,bind()
,read()
, andwrite()
. - Unified Interface
Different brands of CAN hardware (USB-CAN adapters, PCIe CAN cards, etc.) are registered as network interfaces such as
can0
,can1
, etc. via kernel drivers, so there is no need to write different code for different hardware. - Protocol Extensions Supports standard CAN (11-bit ID), extended CAN (29-bit ID), CAN FD, and higher-layer protocols such as ISO-TP.
- Kernel-Level Filtering CAN frames can be filtered directly in the kernel to reduce user-space processing overhead.
(2)How to use(spi to can)
Hardware Connection:

[RaspberryPi SPI] --- SPI ---> [MCP2515 CAN controller] --- CAN_H/CAN_L ---> [actuator]
Environment Configuration
- Enabling SPI on the Raspberry Pi
sudo raspi-config
# enter Interface Options → SPI → Enable
Verify that the SPI device exists:
ls /dev/spidev0.*
- Install the MCP2515 driver
The Raspberry Pi kernel supports SPI-CAN (most Raspbian kernels have it built-in). Edit /boot/firmware/config.txt
and add:
# MCP2515 SPI CAN
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25,spimaxfrequency=1000000
dtoverlay=spi-bcm2835
oscillator
: Crystal oscillator frequency
interrupt
: GPIO connection to MCP2515 INT pin
Reboot the Raspberry Pi:
sudo reboot
- Configuring the CAN interface
# Set the CAN bus baud rate
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
# Test sending and receiving
cansend can0 05060000#0000000000000000 # Send frame to executor
candump can0 # Another terminal monitors the message
can0 is the SPI-CAN mapped interface.
The baud rate must match that of the actuator.
- Code example:
import can
# open can0
bus = can.interface.Bus(channel='can0', bustype='socketcan')
# Construct a CAN frame (assuming ID = 0x05060000)
msg = can.Message(arbitration_id=0x05060000,
data=[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
is_extended_id=True)
# send
bus.send(msg)
print("Command sent.")
# Receive feedback
response = bus.recv(timeout=1)
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
int main() {
// Creating a socket
int s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s < 0) {
perror("Socket creation failed");
return -1;
}
// Get the interface index of can0
struct ifreq ifr;
strcpy(ifr.ifr_name, "can0");
if (ioctl(s, FIONREAD, &ifr) < 0) {
perror("IOCTL failed");
close(s);
return -1;
}
// Set the socket address structure
struct sockaddr_can addr = {};
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
// Bind the socket to the can0 interface
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Bind failed");
close(s);
return -1;
}
struct can_frame frame = {};
frame.can_id = 0x05060000;
frame.can_dlc = 8;
frame.data = {00, 00, 00, 00, 00, 00, 00, 00};
write(s, &frame, sizeof(frame));
// Define the structure for receiving CAN frames
struct can_frame frame;
// Read a frame of data
int nbytes = read(s, &frame, sizeof(struct can_frame));
if (nbytes < 0) {
perror("Read failed");
}
else{
// Output received CAN frame information
std::cout << "Received CAN frame:" << std::endl;
std::cout << "ID: " << std::hex << frame.can_id << std::endl;
std::cout << "Data: ";
for (int i = 0; i < frame.can_dlc; i++) {
std::cout << std::hex << (int)frame.data[i] << " ";
}
std::cout << std::endl;
}
// close socket
close(s);
return 0;
}