CAN setup¶
AK drivers run at 1 Mbit/s. The manual says changing it is not recommended.
Linux (production)¶
socketcan is the production path. The kernel owns the bitrate — python-can cannot set it — so bring the interface up first:
sudo ip link set can0 up type can bitrate 1000000
sudo ip link set can0 txqueuelen 1000
Then, with no privileges:
from cubemarspycan import CanTransport, MotorBus
with CanTransport.open("socketcan:can0") as tp, MotorBus(tp) as bus:
...
CanTransport reads the configured bitrate back from
/sys/class/net/can0/can_bittiming/bitrate and warns if it is not 1 Mbit/s, because a
mismatch looks exactly like a wiring fault.
cubemars doctor lists your interfaces, their state and their bitrates, and prints the
bring-up lines. It never runs them. This library does not shell out to sudo, ever.
Persisting it¶
With systemd-networkd, /etc/systemd/network/80-can.network:
[Match]
Name=can0
[CAN]
BitRate=1M
No hardware? Use vcan¶
A virtual CAN interface behaves like a real one. It is how this project covers the
socketcan-only code — interface opening, bitrate and controller-state read-back, kernel
receive filters — that python-can’s in-process virtual backend never touches:
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0
cubemars scan --url socketcan:vcan0
pytest -m socketcan # the interface-backed tests
Note that a vcan interface has no bit timing and no error state, so
read_socketcan_bitrate() and read_socketcan_state() return None for it. That is the
useful case to test: it is the same shape as a gs_usb adapter whose kernel exposes no
can_bittiming directory, which once made doctor report “no bitrate set” for a
perfectly healthy 1 Mbit/s link.
macOS and Windows (development)¶
socketcan is a Linux kernel facility and does not exist elsewhere. Asking for it raises
UnsupportedPlatform with that explanation rather than a confusing OSError.
Use a USB-CAN adapter:
pip install "cubemarspycan[slcan]"
cubemars scan --url "slcan:/dev/tty.usbmodem1101@1M"
pip install "cubemarspycan[gs-usb]" # CANable / candleLight native
cubemars scan --url "gs_usb:0@1M"
Loop rates on slcan¶
An slcan send is an ASCII line over a USB CDC endpoint: typically 0.5–2 ms, with macOS scheduling spikes into the tens of milliseconds. Plan for 200–500 Hz; 1 kHz needs gs_usb or Linux socketcan.
MotorBus.transport.stats.tx_percentiles() reports p50/p95/max send time in milliseconds,
so this is measurable rather than mysterious.
Bringing your own bus¶
The URL forms are sugar. Any can.BusABC works:
import can
from cubemarspycan import CanTransport, MotorBus
bus = can.interface.Bus(channel="can0", interface="socketcan", fd=False)
with MotorBus(CanTransport(bus)) as motor_bus:
...
CanTransport only shuts down buses it opened itself.