Unter Linux erfolgt die Anbindung von CAN-Bus Hardware meistens per SocketCAN über den Kernel. Dabei wird im System dann ein CAN-Interface bereitgestellt, zum Beispiel can0
.
Mit der Software Cannelloni von Maximilian Güntner ist es möglich dieses CAN-Interface über eine Ethernetverbindung an einen anderen Linux-Rechner weiterzuleiten. Hierbei wird auf dem zweiten Rechner ein virtuelles CAN-Interface, zum Beispiel vcan0
, erzeugt. Die CAN-Nachrichten werden dann mittels UDP zwischen beiden Systemen übertragen.
Dies ist beispielsweise dann sinnvoll, wenn man Software auf einem System testen möchte, das keine echte CAN-Hardware angeschlossen hat. So kann man sich dann beispielsweise das CAN-Interface von einem Raspberry Pi auf seinen Development-PC holen und dort direkt mit dem virtuellen Interface arbeiten.
Wichtig
Cannelloni ist nicht für den Produktiveinsatz vorgesehen und sollte nur dort verwendet werden, wo ein Paketverlust toleriert werden kann. Es gibt keine Garantie, dass die CAN-Nachrichten ihr Ziel (das jeweils andere System) erreichen, oder dass sie in der richtigen Reihenfolge ankommen.
Inhalt
- Installation von Cannelloni
- Beispiel zur Nutzung
- Permanenter Betrieb über SystemD-Services
- Weitere Informationen
Installation von Cannelloni
Für die Installation muss Cannelloni auf dem jeweiligen System kompiliert werden. Hierzu installieren wir zunächst die benötigten Tools:
1 | sudo apt install build-essential cmake git |
Anschließend laden wir uns den aktuellen Quellcode von GitHub und kompilieren Cannelloni:
1 | git clone https://github.com/mguentner/cannelloni.git |
Nun können wir schon Cannelloni im aktuellen Verzeichnis mittels ./cannelloni [...]
ausführen, oder wir installieren es global im System:
1 | sudo make install |
Beispiel zur Nutzung
In diesem Beispiel werden wir das physikalische CAN-Interface can0
von einem Raspberry Pi mit der IP-Adresse 192.168.1.50 auf das virtuelle CAN-Interface vcan0
eines Desktop-PCs mit der IP-Adresse 192.168.1.201 weiterleiten.
Zur Vorbereitung laden wir zunächst auf dem Desktop-PC das Kernelmodul vcan
und legen das Interface vcan0
an:
1 | sudo modprobe vcan |
Da das virtuelle CAN-Interface vcan0
im Normalfall immer schneller ist als das echte CAN-Interface, müssen wir die Bandbreite von vcan0
auf dem Desktop-PC begrenzen. Hierzu nutzen wir die Traffic Control vom Linux Kernel.
Idealerweise sollte die Bandbreite des virtuellen vcan0
Interfaces der des echten can0
Interfaces entsprechen. In diesem Beispiel sind es 500 kBit/s.
1 | sudo tc qdisc add dev vcan0 root tbf rate 500kbit latency 100ms burst 1000 |
Anschließend starten wir Cannelloni auf dem Desktop-PC mit dem virtuellen CAN-Interface, der IP-Adresse des Raspberry Pi und der Ausgabe der CAN-Nachrichten.
Optional könnten mit -r
und -l
noch der entfernte und der lokale Port mit angegeben werden. Ohne Angabe wird für beides der Standardport 20000 verwendet.
1 | user@desktop-pc:~/cannelloni$ ./cannelloni -I vcan0 -R 192.168.1.50 -d c |
Nun folgt noch der Start von Cannelloni auf dem Raspberry Pi nach dem gleichen Muster, nur dieses mal dem physikalischen CAN-Interface und der IP-Adresse des Desktop-PCs.
1 | pi@raspberrypi:~/cannelloni$ ./cannelloni -I can0 -R 192.168.1.201 -d c |
Solange nun Cannelloni auf beiden Systemen läuft, werden die CAN-Nachrichten bidirektional über das Ethernet zwischen beiden CAN-Interfaces ausgetauscht. Das heißt Nachrichten, die am Raspberry Pi auf can0
ankommen, kommen auch auf dem Desktop-PC auf vcan0
an und Nachrichten, die am Desktop-PC an vcan0
gesendet werden, werden auch am Raspberry Pi über can0
gesendet.
Durch den Parameter -d c
beim Start von Cannelloni werden zudem im jeweiligen Terminal die eingehenden und ausgehenden CAN-Nachrichten angezeigt:
1 | LC|EFF Frame ID[83902468] Length:8 0 0 f4 40 0 0 12 41 |
Das virtuelle CAN-Interface vcan0
am Desktop-PC kann nun (nahezu) identisch dem physikalischen CAN-Interface can0
das Raspberry Pi verwendet werden. Alle Daten werden zwischen beiden Interfaces quasi gespiegelt.
Permanenter Betrieb über SystemD-Services
Das oben gezeigte Beispiel eignet sich hervorragend zum Testen oder für die zeitweise Nutzung. Möchten wir nun aber permanent das CAN-Interface an ein anderes System übertragen, so brauchen wir ein paar SystemD-Services. Zudem sollte Cannelloni dafür systemweit installiert sein, wie oben beschrieben.
Auf dem System mit vcan0
Auf dem System mit der virtuellen Schnittstelle vcan0
erstellen wir uns dafür zwei SystemD-Services.
Der erste Service sorgt als “Oneshot” dafür, dass das Interface beim Systemstart (oder manuellem Aufruf) angelegt und konfiguriert wird. Dazu benötigen wir noch ein einfaches Skript, welches von diesem Service gestartet wird.
Das Skript muss nur für den root-Nutzer verfügbar sein, weshalb wir es unter /usr/local/sbin/
anlegen. Interfacename und Geschwindigkeit müssen gegebenenfalls angepasst werden.
1 | sudo nano /usr/local/sbin/vcan0-setup.sh |
1 |
|
Damit das Skript gestartet werden kann, machen wir es noch für den root-Nutzer ausführbar.
1 | sudo chmod u+x /usr/local/sbin/vcan0-setup.sh |
Dazu legen wir den zugehörigen SystemD-Service an.
1 | sudo nano /etc/systemd/system/vcan0-setup.service |
1 | [Unit] |
Dann fehlt noch der zweite Service für Cannelloni selbst.
1 | sudo nano /etc/systemd/system/cannelloni-vcan0.service |
1 | [Unit] |
Optional könnte bei ExecStart
am Ende auch wieder -d c
mit angegeben werden, um alle Datenpakete in das Log zu schreiben. Dies würde ich für den produktiven Betrieb aber nicht empfehlen.
Zu guter Letzt aktivieren wir die beiden Services noch, damit sie beim Systemstart automatisch gestartet werden und starten sie anschließend einmal per Hand.
Hinweis: vcan0-setup.service
würde auch automatisch vor dem Start von cannelloni-vcan0.service
vom SystemD gestartet werden, da dieser als Abhängigkeit definiert ist. Zum Testen ist es aber sinnvoll beides einzeln zu starten.
1 | sudo systemctl daemon-reload |
Ebenso können natürlich beide Services auch per Hand gestoppt werden. Beim Stopp von vcan0-setup.service
würde außerdem das vcan0
Interface auch wieder entfernt werden.
Auf dem System mit can0
Auf dem System mit der echten Schnittstelle can0
benötigen wir nur einen SystemD-Service für Cannelloni. Dieser ist nahezu identisch mit dem Service auf dem anderen System.
1 | sudo nano /etc/systemd/system/cannelloni-can0.service |
1 | [Unit] |
Auch diesen Service aktivieren und starten wir nun wieder.
1 | sudo systemctl daemon-reload |
Wenn nun alle drei Services auf beiden Systemen laufen (bzw. gestartet wurden), sollten die CAN-Nachrichten zwischen den Beiden Interfaces can0
und vcan0
übertragen werden. Der SystemD kümmert sich darum, dass die Services laufen und gegebenenfalls bei Fehlern oder Systemneustarts automatisch neu gestartet werden.
Weitere Informationen
Weitere Informationen zur genauen Funktionsweise von Cannelloni, möglichen Verzögerungen bei der Übertragung, Timeouts, oder der Nutzung von SCTP anstelle von UDP sind auf der GitHub-Seite von Cannelloni zu finden.