Bring-up
Hang the robot, legs straight, for this whole chapter. Power the 48 V bus from a current-limited bench supply until the acceptance tests say otherwise. Each test adds energy; on a failure, fix the cause and re-run from that test.
Robot computer setup
- Install Ubuntu 24.04 (or 22.04) on the mini PC. Disable sleep and automatic updates; set it to power on when 12 V arrives (BIOS: Restore on AC power loss).
- Flash each CANable with the candleLight firmware so it appears as a SocketCAN interface (
gs_usb), and pin the interface names to the adapters' serial numbers:
# /etc/udev/rules.d/80-foh-can.rules (one line per adapter; read serials with `udevadm info`)
SUBSYSTEM=="net", ACTION=="add", ATTRS{serial}=="00XXXXXX", NAME="can0" # left leg
SUBSYSTEM=="net", ACTION=="add", ATTRS{serial}=="00YYYYYY", NAME="can1" # right leg
SUBSYSTEM=="net", ACTION=="add", ATTRS{serial}=="00ZZZZZZ", NAME="can2" # waist + left arm
SUBSYSTEM=="net", ACTION=="add", ATTRS{serial}=="00WWWWWW", NAME="can3" # right arm
# bring the buses up (put this in a systemd unit once it works by hand)
for c in can0 can1 can2 can3; do sudo ip link set $c type can bitrate 1000000; sudo ip link set $c up; done
ip -details link show can0 | grep -o "can state [A-Z-]*" # expect ERROR-ACTIVE
- Install Python 3.11+,
python-can,onnxruntime,numpy, and the FOH control package once it exists (Software). Until then,candumpandcansendfromcan-utilsdo every check on this page. - Confirm the IMU enumerates on USB and streams at 200 Hz or more with its vendor tool.
First power-on
Prove that every device answers, with no motor enabled.
Power up on the bench supply
Bench supply at 48 V, current limit 1.5 A, on the distribution block's pack terminals. Breaker on, E-stop released: the contactor closes and the actuators' LEDs come on. A supply current that climbs to the limit is a short: cut power, back to Pre-power checks.
Inventory
lsusb # four gs_usb devices, the IMU, the hub
ip link show type can # can0..can3
for c in can0 can1 can2 can3; do timeout 2 candump $c; done # silence: no actuator talks unprompted
Read every actuator
Poll each ID on each bus with the RobStride tool or the control package's read-only status command; nothing moves.
Power down
Buses down, computer shut down, then the supply.
Motor ID and config
| Property | Set with | Notes |
|---|---|---|
| CAN ID | RobStride vendor tool over its USB-CAN module, or the control package's set-id, one actuator at a time on the bench, before it goes into a limb | Actuators ship at ID 127. The ID is editable in standby only. Label the actuator the moment the ID is written. |
| Current limit | Written per model: 60 % of the default, capped at 40 A (Duke V2's rule) | RS03 26 A, RS06 34 A, RS02 14 A, RS05 7 A. Saved to the drive. |
| Torque limit | A ratio on every run, 0.05 to 0.8 | 0.05 for smoke tests, 0.3 for joint sweeps, 0.6 for standing. |
| Zero | Joint zeroing |
| Bus | Joint | ID | Model | Joint | ID | Model |
|---|
Positive direction: the URDF's joint axis is the truth. Set every actuator's direction flag so that a positive command produces the URDF's positive rotation, checked joint by joint at 5 % torque. Do not rely on mounting orientation alone.
Joint zeroing
The zero pose is the URDF at all joint angles zero: standing straight, arms hanging, palms inward. The control stack assumes encoder zero is that pose.
Set the zeros
Motors unpowered for movement but on the bus. Hold each joint at zero with a square or a spirit level against the printed reference faces (every adapter has a flat), then write the current position as zero on every actuator and save it to the drive. Do not use the vendor tool's temporary mechanical zero: it is lost at power-off.
Verify
Ramp every joint to zero at 10 % torque, robot hanging; stay clear.
Acceptance tests
| Test | Procedure | Pass |
|---|---|---|
| A1 Bus integrity | Cold power-up three times; read every actuator each time | Four buses ERROR-ACTIVE and 23 answers every time; zero error frames in ip -s link |
| A2 CAN latency | Command-response round trip on each bus at 1 % torque, 1000 samples | 99th percentile under 1 ms per actuator; a 6-actuator bus completes a cycle inside the 2 ms loop |
| A3 Harness wiggle | Log all actuators while flexing every connector, loom and limb entry | Zero dropouts |
| A4 Per-joint motion | 0.1 rad sine on each joint alone, 5 % torque | Only the commanded joint moves, in the URDF's positive direction; no grinding or knocking |
| A5 Zero and model | Hold each arm joint at 30 % torque with gravity compensation from the URDF masses | Residual torque within ±0.5 N·m of zero at every arm joint; adjust the URDF masses to the weighed parts if not |
| A6 Packs | Swap the bench supply for the packs; repeat A1 and A4 | Same results; pack voltage sag under 2 V during the sine |
| A7 Posture | Hanging, PD hold of the zero pose then a crouch, 60 % torque | Poses reached smoothly; no joint exceeds 60 °C in five minutes |
| A8 Standing | Feet on the floor, hoist slack, the standing policy from simulation, E-stop in hand | Balances for two minutes; recovers from a 20 N push at the shoulders (stiff joints alone survive 8 N·s in simulation; the policy must do better) |
| A9 First step | Walking policy, one velocity step of 0.2 m/s and stop, hoist attached and slack | Robot steps and stops; the stop command zeroes the gait within one stride |
Before A8, confirm the software stop layers: the control process zeroes commands on Ctrl-C; the watchdog zeroes them 200 ms after a lost command stream; the gamepad's stop button pre-empts everything. The E-stop is the last stop, and the hoist catches what the E-stop drops.