Lauszus / socketsocketcan

SocketCAN over TCP to a Python server

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SocketCAN over TCP

Original author Thomas Bruen

Modified by Kristian Lauszus, 2019-2023


For when you want to use the Python CAN package but are running on a resource-constrained device, such as a Raspberry Pi.

I've found that for a busy bus (> 1000 messages/ second), my Raspberry Pi was dropping messages: we'd reached the limit of what Python could achieve. However, it's still a really powerful library for processing messages and integrating other services.

This package lets you run python-can on a more powerful machine, by setting up a TCP connection to the Linux device. A small C client runs on the Linux device to send/ receive CAN messages (with timestamp). This is perfect for listening to a bus and sending occasional messages. I haven't tested this* with anything that demands high-frequency periodic sending of messages, but using the CAN broadcast manager will probably be better than using this directly.

* I haven't tested this much at all. Sorry. I did have 3 terminals running cangen at a 1ms interval for 10 minutes, and didn't have any issues (it was identical to candump except where candump locked up and dropped a few hundred messages).

CAN Set-up

Enable vcan or can0 (or whichever) on the Linux device:

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set vcan0 up

or

sudo ip link set can0 up type can bitrate 1000000

Installation

Client

Copy the client folder to your Linux device and run make

Server

Using a virtual environment is really recommended here.

pip install -e path/to/socketsocketcan-repo

Usage

On creating a TCPBus object, it will block until a connection with the client is made (i.e. start the client now). Then, you can use the bus to send() and recv() messages as usual. By default, the bus accepts connections from any host, you can limit this using the hostname="A_PARTICULAR_HOSTNAME"keyword arguent.

The TCPBus runs a couple of threads in the background: one to write 'sent' messages to the socket, so that the client can read them in and actually put them on the CAN bus, and another to receive and messages from the client and put them in a queue so the recv method can retrieve them.

As the quotes above impied, calling send() doesn't actually send the message. It puts the message on a queue, which a thread will write to the socket as soon as possible. (I haven't looked at how long it actually takes from putting it on the queue and it actually being sent: it will vary depending on resources and you'd have to make sure the clocks on the two computers are synchronised to the sub millisecond level.)

The client has a similar structure: there is one thread to poll the CAN bus for new messages and put them in a buffer, a second thread to copy from that buffer to the TCP socket, and a third to read from the TCP socket and send the messages via the CAN Bus.

Client

./client CANCHANNEL HOSTNAME PORT e.g. ./client vcan0 my-can-server 5000

Server

from socketsocketcan import TCPBus
from can import Message
bus = TCPBus(5000) #start the client now.
bus.send(Message(arbitration_id=0x100,data=list(range(5))))
print(bus.recv()) #this will be the message you just send (unless)

Forwarder

You can also use this to forward a socketcan socket to another machine via TCP. Fx to forward can0 to vcan0 from a server with IP address 192.168.4.1 to a client:

Server

sudo cp socketsocketcan-server@.service /etc/systemd/system/
sudo chmod 644 /etc/systemd/system/socketsocketcan-server@.service
sudo systemctl daemon-reload

sudo systemctl enable "$(systemd-escape --template socketsocketcan-server@.service "can0 0.0.0.0 8000")"
sudo systemctl start "$(systemd-escape --template socketsocketcan-server@.service "can0 0.0.0.0 8000")"

Client

sudo cp socketsocketcan-client@.service /etc/systemd/system/
sudo chmod 644 /etc/systemd/system/socketsocketcan-client@.service
sudo systemctl daemon-reload

sudo systemctl enable "$(systemd-escape --template socketsocketcan-client@.service "vcan0 192.168.4.1 8000")"
sudo systemctl start "$(systemd-escape --template socketsocketcan-client@.service "vcan0 192.168.4.1 8000")"

Note you might need to change the User and PATH_SOCKETSOCKETCAN_CLIENT_DIR in socketsocketcan-server@.service and socketsocketcan-client@.service files.

About

SocketCAN over TCP to a Python server

License:MIT License


Languages

Language:C++ 65.0%Language:Python 32.9%Language:Makefile 2.1%