Command line¶
Five commands. scan is the one you will actually use.
cubemars doctor # environment, interfaces, bring-up lines
cubemars scan # what is on the bus, and what mode it is in
cubemars monitor --id 1 # live state
cubemars jog --id 1 --position 0.1 # a gentle move
cubemars dump-spec AK40-10 # fields, derived values, provenance
Every command takes --url, defaulting to socketcan:can0 on Linux and
slcan:/dev/ttyUSB0@1M elsewhere. --motor selects the spec, defaulting to AK40-10.
Recipes¶
Bringing up a bus for the first time¶
cubemars doctor
Shows your Python, python-can, which optional backends are installed, every CAN interface
with its link state, bitrate and CAN controller state, and the exact ip link lines to
run. It never runs them — this library does not shell out to sudo.
A healthy interface looks like:
can0 link up 1000000 bit/s
can state ERROR-ACTIVE
ERROR-PASSIVE or BUS-OFF means nothing is acknowledging frames — no other powered
node, or missing termination:
can0 link up 1000000 bit/s
can state ERROR-PASSIVE <- nothing is ACKing; check motor power and termination
link ? is a third state, and it means the tool could not tell — neither
/sys/class/net/<iface>/flags nor ip could be read. It is deliberately not reported as
down: on a slim container or a BusyBox rootfs with no iproute2, calling a healthy
interface down is how you get sent to fix something that was never broken.
can0 link ? 1000000 bit/s
A bitrate read from sysfs beside a ? link, as above, is exactly that case.
Clear it once the cause is fixed:
sudo ip link set can0 down && sudo ip link set can0 up type can bitrate 1000000
Finding a motor whose id you don’t know¶
cubemars scan --poke 8
A servo-mode driver uploads unprompted, so a plain scan finds it. A MIT-mode driver
only replies when commanded, so it looks like a dead bus until you prod it. --poke N
sends enter-MIT frames to ids 1..N, which produce no motion.
2 motor(s), 85 frame(s):
id 1 mode MIT
MIT replies : 43 on arbitration id 0x001 (43)
-> the manual is ambiguous here; record this id and pass reply_mode= to pin it.
last : -1.6939 rad +0.011 rad/s +0.001 Nm 32 C fault 0
id 3 mode servo
servo status : 42
--poke leaves those drivers in MIT mode, which is why it is opt-in.
Nothing at all on the bus¶
cubemars scan --timeout 5
No motors found. 0 frame(s) seen in total.
Nothing at all arrived. In order of likelihood:
1. A servo-mode driver with its CAN status rate set to 0 in CubeMarsTool
never uploads anything.
2. A MIT-mode driver only replies when commanded - try --poke 4.
3. Power, wiring, termination, or a bitrate other than 1 Mbit/s.
Cause 1 is the one that wastes an afternoon: the wiring is fine and the driver is simply configured never to speak. Check it before touching a cable.
If frames are arriving but none look like an AK reply, scan prints them so you can see
what else is on the bus.
Checking a motor before a run¶
cubemars monitor --id 1
Prints state continuously. In MIT mode it sends zero-gain, zero-torque frames to elicit replies — the motor is not driven. In servo mode it is fully passive:
cubemars monitor --id 1 --mode servo
Watch for a plausible temperature, no fault, and a position that holds still.
A first, cautious move¶
cubemars jog --id 1 --position 0.1 --kp 5 --kd 0.3 --zero
Prints what it is about to do and asks before moving. Defaults are deliberately timid:
±0.5 rad maximum, kp=5. Ctrl-C still sends a safe stop and exits MIT mode.
About to command AK40-10-KV170 id 1:
position +0.1 rad (field limit +/-12.5)
kp 5, kd 0.3
for 3 s at 100 Hz
Clamp the motor before continuing.
Proceed? [y/N]
Add --yes for scripts. Raise --max-position deliberately if you mean to go further.
Checking what the library believes about a motor¶
cubemars dump-spec AK40-10
Every wire field with its resolution, the derived values, and where each constant came from:
ERPM -> rad/s (output) 7.479983e-04
velocity field saturates above 25.55 V
effective torque limit 4.1 Nm
permanent zero (origin mode 1) REFUSED (single encoder)
gear_ratio 10.0 [datasheet: cubemars.com AK40-10 KV170 spec table]
pole_pairs 14 [datasheet: ...]
mit.position_side Side.OUTPUT [measured: bench 2026-09-16, ...]
servo.position_side unknown (...)
-> 1 unknown: servo.position_side
Anything still unknown will make the conversions that need it refuse rather than
guess. With no argument, lists every known model and variant:
cubemars dump-spec
A different adapter or motor¶
cubemars scan --url "slcan:/dev/tty.usbmodem1101@1M" # USB-CAN on macOS
cubemars scan --url "gs_usb:0@1M" # CANable / candleLight
cubemars scan --url "socketcan:vcan0" # virtual, no hardware
cubemars monitor --url socketcan:can1 --id 2 --motor AK80-9
Testing with no hardware at all¶
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan && sudo ip link set up vcan0
cubemars scan --url socketcan:vcan0
A vcan interface behaves like a real one, which is how this project’s CI exercises the
socketcan path. For a motor that actually answers, use the simulator through the
examples instead: every one takes --sim.
Exit codes¶
Code |
Meaning |
|---|---|
0 |
success; for |
1 |
|
2 |
|
Library errors print as error: <message> on stderr.