Skip to main content
One-time setup for the Almond Axol CAN buses. Installs the gs_usb kernel driver if the kernel lacks it (see can.driver — needed on NVIDIA Jetson / ZED Box), writes persistent udev rules, assigns fixed interface names, registers a startup script in the root crontab, installs a hotplug bring-up service, and brings up the interfaces immediately. Driver selection is host-safe: NVIDIA L4T/Jetson kernels that omit gs_usb build the vendored backport; an older or unverifiable native Linux driver is conservatively replaced; a Linux 6.13+ in-tree driver (including a resolved weak-updates symlink) is kept when it advertises every ID needed by the adapters currently attached. Maintained 6.2+ distro kernels with a backport are also kept when kmod metadata proves endpoint discovery, including signed Secure Boot builds. On a Secure Boot/signature-enforcing host that genuinely needs an unsigned backport, setup stops before changing the active module and tells you to sign/enroll it or use a newer native kernel. A trusted, signed legacy Almond backport is recognized only when its selected/loaded source identity, canonical path, and USB-ID fingerprint match. Installation verifies the selected and loaded module identities and restores the previous module/config on failure. Up to four buses, each optional and independent:
  • Left arm → can_alm_axol_l (Axol Hub channel 0)
  • Right arm → can_alm_axol_r (Axol Hub channel 1)
  • Powered cart’s wheel bus (if present) → can_alm_axol_b
  • Chest bus / lift controller (if present) → can_alm_axol_c
The Axol Hub and Mantis Hub are dual-channel USB CAN adapters; the wheel and chest buses use single-channel adapters. can.setup identifies all of them by probing the devices on their CAN lines: an Axol arm has a shoulder motor at ID 0x001, a Mantis publishes trigger frames on ID 0x009 (both the 6-byte and current 7-byte firmware frame are accepted), the wheel bus has Damiao motors at IDs 0x010x04, and the jelly_legs lift controller answers a status request on the chest bus. The attached devices must be powered for automatic identification. Already configured adapters are probed again when attached, so a live response corrects stale Axol/Mantis or wheel/chest assignments from an earlier setup. If an apparently-up gs_usb adapter is not receiving, setup resets the relevant bus and retries before deciding it is silent. A silent or unplugged configured single-channel adapter keeps its previous assignment as an explicitly unverified fallback; a new silent adapter is offered to the operator and can replace that fallback. An unresolved adapter pinned to two roles is rejected before rules are written. For a silent dual-channel hub, the normal axol can.setup prompt lets the operator keep the previous role or choose Axol/Mantis; no separate reassignment command is needed. Each identified adapter is pinned by USB serial, and the startup scripts bring every configured interface up while skipping anything unplugged. A Jetson host’s built-in system CAN controller is ignored entirely. Running axol can.setup is deliberately a disruptive link reset for every attached adapter in its supported scope: the Axol arm pair, powered-cart wheel bus, chest/lift bus, and Mantis pair are taken down, restored to 1 Mbit/s with the expected queue length, and brought back up before they are trusted. Both channels of a dual hub go down before either comes back up; wheel and lift adapters reset independently. This does not reboot/zero/calibrate an actuator, clear a healthy saved assignment, reload a healthy USB driver, or touch the Jetson’s built-in mttcan interfaces. As a one-time migration on older Jetson installs, setup automatically rebuilds an Almond-managed gs_usb override that predates reliable build identity; overrides outside Almond’s managed path and signature-enforcing hosts still fail closed. Do not run setup during an active robot operation. The Mantis handheld data-collection rig uses the same dual-channel CAN board as the arm hub, with one gripper bus per channel — each bus carries that side’s Damiao gripper motor (ID 0x008) and trigger node (ID 0x009):
  • Channel 0 → can_mantis_l (left gripper)
  • Channel 1 → can_mantis_r (right gripper)
The Mantis profile gets its own udev rule file, startup script, and hotplug bring-up unit, so the robot and rig can be discovered and configured together by one axol can.setup run. Its managed names are isolated from the Axol profile, so configuring or correcting one profile does not evict the other. A replug of the handheld brings its interfaces back up without operator action. If a trigger and arm motor are both silent, setup asks whether that adapter is Axol, Mantis, or should be skipped; no hardware-profile flag is needed.
sudo will be invoked automatically where required.
After setup, the interfaces come up automatically on every reboot (via a @reboot cron hook) and whenever the adapter re-enumerates mid-session: a udev rule pulls in the axol-can-up.service bring-up whenever the hub (re-)appears, so a replug — or a USB drop caused by motor EMI — heals itself within a second or two without operator action. You don’t need can.setup just to use the cart — axol teleop brings the cart’s own interface up on its own — but pinning it gives the adapter a stable name across reboots.
The same bring-up script also recovers the bus after an emergency stop. Cutting motor power mid-motion leaves the in-flight CAN commands unacknowledged, so without intervention they would all replay the instant the arm is powered back on — snapping it to its pre-e-stop position. The CAN layer detects the stalled bus, flaps the interfaces to drop the stale frames, and holds every send until a probe frame is acknowledged on the wire again, so the arm stays put until the bus is genuinely back online.A momentary TX-queue overflow is handled more gently. Both arm channels share one dual-channel USB adapter, so a brief stall of its USB pipe — e.g. camera traffic during data collection — can back the queue up while the bus itself is healthy and draining. Told apart from a dead bus by how long it persists, a brief overflow just drops the frame (a rate-limited warning) and the next command proceeds, so heavy USB traffic no longer crashes teleop or data collection mid-session; only an overflow that keeps persisting (nothing draining) escalates to the interface flap and probe-gated hold above.
On Raspberry Pi 5 hosts, can.setup additionally applies an RP1 USB quirk (axol-rp1-usb-quirk.service): the Pi 5’s USB controllers ship with a hair-trigger babble/loss-of-activity detector that EMI from the arms can trip, kicking the hub off the bus (disabled by hub (EMI?) in dmesg). The quirk enables the controller’s noise filter — the workaround recommended by Raspberry Pi engineers. If disconnects persist, add a ferrite choke to (or shield) the hub’s USB cable, or put a small powered USB hub between the Pi and the Axol Hub.