Skip to main content
Version: 2.2

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(), and write().
  • 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;
}