← Design notebook

BUILT BY AUTONOMOUS SYSTEMS · WORK IN PROGRESS

Leg v2 on the single-leg rig: the plan to a first physical leg (M3)

Written 2026-10-27 by the planner (Fable 5.1) for the Opus implementer. Not committed. Read first: cad/fivebar.py, cad/build_leg.py, cad/leg_studies.py, sim/leg_rig.py, exports/leg/{bom.json,print-plan.json,leg.json,rig-results.json}, exports/leg/fea/summary.json, research/leg-suspension.md (sections 1-8), docs/decisions.yaml D36-D41, docs/milestones.yaml M2-M3, catalog/{hardware,alternates,sourcing,images}.json.

Every price and stock line below says where and when it was read. "Checked today" = 2026-10-27 by this session or by catalog/alternates.json (also 2026-10-27). Sections marked TODO (next session) were cut short by the usage limit.


0. In one paragraph

Build the leg exactly as drawn (no spring, TPU stops kept, wheel fitted but unpowered), print it in PA6-CF after a day of PA6-CF fit coupons (not a PETG leg: PETG shrinkage does not transfer to PA6-CF seats), and hang it on one 8080 extrusion post with two HGR15 profile rails and four HGH15CA blocks behind the hip frame, a 6.35 mm aluminium carriage plate bolted to the frame's six M5 flange inserts, weight plates on two rods for the ballast, printed TPU bumpers under the carriage, and a braced extrusion base with a plywood deck the wheel lands on. Power the RS-04s from the user's FLEXVOLT 60 V pack (48-55 V window, it is the only regen sink that needs no custom electronics), through a 30 A DC fuse and a 12 V-coil DC contactor held in by the pendant loop with a 1 s off-delay; CAN at 1 Mbit/s from a candleLight USB adapter to the laptop, a Feather M4 CAN as the rig's sensor and safety node. The controller is sim/leg_rig.py's own virtual-model controller run at 500 Hz from Python over SocketCAN, first against a MuJoCo backend, then against the motors, with every run logged and overlaid on rig-results.json. Bench tests come before the leg stands: the RS-04's unpowered back-drive torque against speed (decides D39's knee case), the rotor inertia, the TPU sleeve's stiffness, the heat-set insert's torque-tension and pull-out in printed PA6-CF, and the tyre's radial rate. Then stand, squat, jump, drop, and the power cut last, with the bumper set high until the damping is known.


1. Review: what is ready to build, what to simplify, what to defer

1.1 Ready (as of commit 8717f28 plus the uncommitted 07:49 edits to cad/fivebar.py, cad/leg_studies.py)

1.2 Known gaps (flag to the main session)

1.3 Simplify for the first physical leg (decisions made here)

  1. No PETG leg. PETG and PA6-CF shrink differently and PETG prints on a brass nozzle at different flow, so a PETG fit check does not prove a PA6-CF bearing seat, insert hole or dowel fit, and a second 180 h print buys nothing. Instead: PA6-CF fit coupons first (one evening of printing, section 6.2): a 20 mm slice of the hip frame around one motor (10 x M4 lug pattern, two dowel holes, the 61812 seat with its lip), an upper-link hub face (AO face, 8 x M5 inserts, 2 dowels, the spigot recess), a knee eye (two 12 x 18 x 20 sleeves pressed), a knee boss (two 6201 seats and the 27 mm web), an apex eye (61812 seat) and a hub stub (the 60 mm journal with the circlip groove). Every seat diameter gets dialled in on the coupons (LeRobot's builder cracked both bearing seats pressing 15 x 21 bearings into a print; Primo's rule: light fit plus retaining compound, never a heavy interference in PA-CF). Then the structural parts, hip frame last (section 6.2).
  2. The wheel is fitted but not driven on the rig. Every rig scenario commands zero wheel torque (d.ctrl[wheel] = 0); the tyre test is static. No BotWheel driver is bought for M3. When the wheel must turn under power (after the drop test passes), the driver is the robot's Flipsky 75100 (14-84 V, $65, in stock at Flipsky CN, catalog 2026-10-25); backup ODrive Pro ($229, 58 V max; S1 sold out). The BotWheel's phase and hall leads are taped along the links for M3; the through-hub cable route is tried later.
  3. The stops stay as drawn (TPU 95A sleeves on Ø16 steel pins, the links' radial stop faces: D53). The rig's bottom bumper is set so the carriage lands on the rig at a leg length of 115 mm, above the leg's own stops (101.5 mm), for every test until the power-off damping is measured; only the deliberate collapse test (last) lowers the bumper.
  4. No spring (D39, research section 8.7). The knee-to-knee add-on stays on the shelf.
  5. Cheaper bearings: 6812-2RS and 6201-2RS from Bearings Direct / VXB (section 6.1), $120 + $69 less per leg.
  6. Ballast is standard 1 in weight plates on two rods, not a welded block: the carriage's own plate, blocks and rods are already about 3.3 kg of the 4.56 kg dummy mass, and plates make the half-mass adjustable for the sim's --half-mass sweeps.
  7. First motor tests in a printed bench fixture, not in the hip frame, so the bench tests start the day the motors arrive (the hip frame is the last and riskiest print).

1.4 Defer


2. The rig

Module frame as in cad/fivebar.py: x forward, y outwards (+y is the linkage and wheel side), z up, y = 0 the motors' output face. Numbers from fivebar.Y and hip_frame(): the frame's flange ends and its six M5 insert bosses are flush on the plane y = -82.3 mm (the robot's centre plane), inserts at (x, z) = (-83, +-70), (0, +-70), (+83, +-70) (fivebar.frame_mounts(), the source of truth), flanges 13 mm thick (z 62-75; 7 mm until the 2026-10-27 review: too weak across the print's layers) spanning x +-95; the motors' rear faces are at y = -80.3 (2 mm inboard of that plane), their 310 mm harnesses exit radially from the O94 rear covers; the stop posts are at (+-104.1, +52.5) and (+-20.6, -25.4) (D53; their TPU sleeves are Ø32, from the frame's face to y 19). Knees reach x +-225 (z +8) at the 101.5 mm crouch and x +-60 (z -149) at 392 mm; the wheel axle is at (0, -L), and (+-103, -282) at +-20 deg of lean at 300 mm; the tyre's mid-plane is y = 104.6 (tyre y 82-127).

2.1 Layout (one post, two rails, behind the hip frame, where the sim already puts the rail)

          side view (looking along +x)                 plan (looking down)
   post 8080 |B|                                        ┌───── base 700 (x) x 900 (y) ─────┐
     rails   |B|  carriage plate 6.35 mm                │         post ▓▓ at y -132..-212   │
   blocks  ▓▓|B|▓ y -89..-117                           │   brace ─╲   ▓▓                    │
             |B|▓──┐ hip frame flange face y -82.3      │           ╲  ▓▓ rails (x = +-20)   │
             |B|▓  │ motors y -80..-25                  │   deck      ▓▓ plate x +-150       │
             |B|▓  │ links y 0..80, tyre y 82..127      │        frame x +-95                │
   bumper ▄▄ |B|   └── wheel E = (0, -L)                │        wheel lands here, x +-110   │
   ───────────────── deck (18 mm plywood on 4040)       └──────────────────────────────────┘

2.2 What the rig CAD must check (task T2)

A clearance sweep of the posed leg (fivebar.assembly() at 14 lengths 101.5-392 mm and leans -20/0/+20 deg) against post, rails, blocks, brace, bumpers, bracket, deck and plate (minimum 10 mm); the carriage's travel against the rail length for the 120 N m jump; the block loads at the jump's 3,700 N; the post's bending with and without the brace; the motor harness grommets (vendor STEP, references/vendor/robstride-rs-04/RS04.stp) against the plate and its slot at the frame's lug clocking (7 deg); the masses; the TPU bumper's crush energy.


3. Electronics and power

3.1 The RS-04 as a load

RS-04 (catalog/leg_actuators.json, research/robstride-open-source-2026-10-26.md section 4): rated 48 V, operating 24-60 V with an over-voltage fault at 60 V (the manual; rcdrone's listing says 15-60 V), 40 N m rated on a 345 x 345 mm heat sink, 120 N m peak at 90 A phase current, Kt 2.1 N m/A at the output, 9:1, 200 rpm no load. On the rig the two motors hold about 12 N m each standing (10 W each); the 60 N m jump is about 1 kW mechanical per motor for 0.3 s, so 45-50 A of bus current at 48 V for 0.3 s; landings and squats push energy back into the bus (16 J per 150 mm drop, up to 19 J per squat half-cycle). A bench supply cannot sink that: 16 J into a 2 mF output stage is a 135 V spike, and the RS-04 faults at 60 V. So:

3.2 Power: the FLEXVOLT pack for every test that moves, a bench supply for the bench

3.3 The safety line (the turret bench's pendant pattern, docs/turret-plan.md section 2)

3.4 CAN, sensing, the rig node


4. Software path: from sim/leg_rig.py to the motors

4.1 What is reused unchanged

fivebar.fk / ik / stance / jacobian / stop_angles and sim.leg_rig.vmc / Gains / clip_motor / pin_forces are the controller: a spring-damper on the virtual leg (kp_L 3,000 N/m, kd_L 250, kp_th 150 N m/rad, kd_th 6) with the gravity feed-forward ff = half_mass * g - (rotor + half the wheel link) * g, mapped by J^T to the two motors, each torque clipped to the RS-04's torque-speed line and the 60 N m cap. The scenario commands (command(): stand-up ramp, 0.5 Hz squat, the jump's crouch / push / tuck, the drop's hold) are reused too.

4.2 What is sim-only and must NOT be ported (the "firmware cancel" list)

4.3 The RS-04 private protocol (29-bit extended IDs, 1 Mbit/s)

From the RobStride Python SDK README, the Seeed wiki, robstride_ros2 and the firmware release notes (all read today):

4.4 Code layout (new files, the implementer's worktree)

4.5 Bring-up order

  1. rig/run.py --backend sim reproduces rig-results.json (stand-up and squat peaks within 5 %, jump height within 10 mm) with the controller running through the bus abstraction at 500 Hz: proves the port.
  2. One motor on the bench supply in the dyno fixture: scan, read parameters, enable, zero, MIT torque steps of 1-5 N m with Kp = Kd = 0, feedback at 500 Hz, loop jitter measured (target: 99 % of ticks within +-0.3 ms; if Python cannot, drop to 250 Hz for the first stand and move the loop to the Feather later).
  3. Two motors in the hip frame on the rig, carriage on the bottom bumper, leg hanging: the controller holds a commanded length in the air (no ground), then the stand.

5. Bench test sequence (M3 list first), each with the sim's number and the pass/fail

Fixtures (task T4): the dyno pair, two printed PETG lug plates (10 x M4 on O106 with the two O5 dowel holes) on a plywood board holding the two RS-04s output-to-output through a printed coupler disc (9 x M5 + 3 pin sockets each side); an insert coupon (a PA6-CF block printed in the output adapter's orientation pa6_cf_z with M5 heat-set inserts); a post coupon (a PA6-CF block printed web-down like the hip frame, with the stop pin's Ø16 x 23 blind hole: the Ø16 x 40 pin set in it with Loctite 638, the TPU sleeve on it, pressed square by a flat anvil as the link's stop face presses it); a tyre cradle (the BotWheel on its 4 x M6 flange, pressed radially against a flat plate).

# Test Method Sim assumes Pass / decision
B1 RS-04 power-off damping (decides D39) Motor A unpowered (bus lead unplugged), motor B drives it through the coupler in velocity mode at 0.5, 1, 2, 4, 7, 10, 13, 15 rad/s both directions, B's torque feedback at 500 Hz = A's drag; repeat with A powered but disabled (stop state), and with damper 0x2023 = 1; also by hand: a 0.3 m lever and 2-10 kg masses, speed from video 5.9 N m s/rad linear (20 % of shorted phases); the undamped case is 0 Deliver the curve tau(omega). The main session reruns sim/leg_rig.py power_off with it (flag F1). If the knee force stays at or below the fault case's SF 1.0 figure, no spring and D39 stands; if not: the knee-to-knee spring, softer longer-travel bumpers, and a firmware sit-down before any planned power-off
B2 Rotor inertia Motor alone, no load, MIT torque step 2 N m for 0.2 s from rest, log omega(t); J = tau / alpha corrected by the friction measured from the steady speed; also a spin-down from 10 rad/s 3e-4 kg m^2 rotor, 0.0243 reflected A value with +-20 %; the main session sets ARMATURE (flag F1) and the landing predictions move with it
B3 TPU stop sleeve and its pin (D53) Sleeve on the post coupon's pin, a flat anvil 30 mm tall square on its side (as the link's stop face), load 0-2,000 N in 200 N steps by a bathroom scale under a lever (or the S-type cell), deflection by dial gauge; 10 cycles to 7 mm. Then the bare pin, loaded sideways 10.5 mm above the coupon's face to 2,100 N (twice the 1,038 N of E3), the pin's tilt by dial gauge on its tip 256 N/mm (E 9.8 MPa over 19 x 11 mm, 8 mm wall), 7.5 mm travel before the pin, 856 N m/rad at the 57.8 mm arm; the pin bears 19 MPa on the print at E3 (leg_studies.py stop_checks) Measured k within 0.5-2x of 256 N/mm, no tearing after 10 cycles; STOP_K / STOP_TRAVEL updated (flag F1). The pin: no permanent tilt (< 0.05 mm at its tip after unloading), no crack at the hole's mouth
B4 Heat-set insert torque-tension and pull-out (M5, PA6-CF) M5 x 30 through a washer stack and the S-type cell into the coupon; tighten in 0.5 N m steps to 4 N m, record tension; then pull-out to failure 1,200 N preload per M5 (HUB_PRELOAD_N), mu 0.15 A torque that gives >= 1,200 N with pull-out >= 2,400 N and no thread strip; that torque becomes the assembly spec; leg_studies.py reruns with the measured preload (flag F2)
B5 Tyre radial stiffness Wheel in the cradle, 0-1,000 N in 100 N steps, deflection by dial gauge; three spots round the tyre 7.7 ms / 0.7 contact (about 100-250 N/mm) A rate and a hysteresis figure; TYRE_SOLREF refitted (flag F1); if under 100 N/mm the landing loads fall and the drop test's predicted numbers are regenerated first
S1 Stand-up (stand_up) From 140 mm to 300 mm in 1 s, hold 10 s; load plate under the wheel peak motor 12.1 N m, wheel 140 N, axle 127 N, knee 120 N, L 140-303 Holds 300 +-10 mm, peak torque <= 18 N m, no oscillation > 5 mm p-p, load plate 100-150 N steady, motor temperature rise < 10 C in 10 min
S2 Squat (squat) Three squats 300 -> 150 mm at 0.5 Hz, then 30 cycles peak 12.2 N m, 1.0 rad/s, wheel 139 N, L 157-302 Tracks within +-15 mm, peak <= 18 N m, VBUS stays under 58 V (regen), nothing loosens (re-check every screw after)
S3 Jump (jump, 60 N m cap) Crouch to 150, push at the cap, tuck, land; load plate removed; tether on height 278.9 mm, peak 60 N m at up to 16.7 rad/s, wheel 3,700 N, gearbox 97.6 N m, knee 753 N, L 156-345 First jump >= 200 mm (losses the sim does not have) and <= 320 mm; landing motor torque feedback <= 70 N m; leg settles to 250 +-15 mm within 0.5 s; inspect the knees, adapters and stop sleeves; then compare with the sim rerun at the measured J and tyre rate
S4 Drop 150 (drop_150) Carriage pinned 150 mm up, leg holding 300, pin pulled axle 1,719 N, motor 35.5 N m, gearbox 66.5, knee 551 N, L 284-330 Motor torque feedback <= 55 N m, leg back to 300 +-10 mm within 0.5 s, no damage on inspection, measured L(t) within 20 % of the sim's dip (16 mm)
S5 Power cut, bumper high Standing at 300, open the contactor by the pendant with 5.9 N m s/rad: 1.74 rad/s, knee 192 N; undamped 12.2 rad/s The carriage lands on the bumper at 115 mm; fall time within 30 % of the sim rerun with B1's curve
S6 Power cut onto the leg's stops (only if B1 and the rerun say the knee stays under the fault limit) Bumper shimmed down to 101.5 mm, same cut undamped: 1,745 N knee, 109 N m stop; damped 264 N, 10.9 N m (rig-results.json, D53's stops) D39: nothing breaks; knees, eye sleeves, pins and 6201s inspected after; the sleeves show no permanent set

Order: B1-B5 as the motors arrive (B3, B4 need only coupons; B5 needs the wheel), then S1-S6. Every run writes exports/rig/runs/<date>-<test>.json with raw series and the criteria verdict.


6. Build package

6.1 BOM: leg (per leg), rig, electronics — primary and backup

Prices as read on the date given; the leg's McMaster lines are from catalog/hardware.json (2026-10-26) and exports/leg/bom.json; alternates from catalog/alternates.json (2026-10-27).

Leg, bought (per leg):

Part Qty Primary Backup
RobStride RS-04 (CAN 2.0, not CAN-FD) 2 Seeed Studio $255, CN warehouse (11 on hand + 80 due 2026-11-14 on 10-25; page returned 403 today) OpenELAB $297.99, orderable, 8-15 business days, duties included (today); rcdrone.top $319 orderable; aifitlab $255 and roboticscenter.ai $295 both backordered 4-6 weeks
ODrive BotWheel BW0124 1 (sold as 2) ODrive US shop $269 per 2-pack, orderable (today) ODrive EU EUR 269 per pair, 40 in stock (today)
6812-2RS / 61812 (60 x 78 x 10) 4 Bearings Direct 6812-2RS $38.58, 5 in stock (today) VXB Kit7454 $49.99; McMaster 6656K236 (2Z) $69.11
6201-2RS (12 x 32 x 10) 4 Bearings Direct $2.13, 4,428 in stock VXB 4-pack $19.99; McMaster 5972K42 $19.37
Knee pin ISO 7379 12 x 90, M10 2 McMaster 92981A411 $8.02 Aspen ME343-1015X90X12 (box of 10, $168.80, plain)
M10 nyloc 2 McMaster 94645A220 $0.46 any class 10 M10 nyloc
M12 thin washer DIN 433 4 McMaster 98689A118 $0.14 any 13 x 20 x 2
Knee spacer tube 5/8 x 0.065 wall, cut 28 mm 2 McMaster 9056K68 $6.26 per 6 in any 6061 tube 15.9 x 12.6
Eye sleeve DIN 179 12 x 18 x 20 4 McMaster 96990A403 $16.11 JW Winco DIN 179-B12-20 (stainless, price not shown); Reid DM-12025 $7.88 is 25 long (eye change)
Stop pin Ø16 x 40, 52100, vented, M8-tapped pull-out (D53) 4 McMaster 98432A386 $5.88 McMaster 91595A845 $5.01 (plain: print a Ø2 vent through the hole's floor, and it cannot be pulled); Aspen Fasteners ME397-16X40 $192.49 per 8
M5 heat-set insert 7.9 long 6 (+ coupons) McMaster 94459A775 $0.27 CNC Kitchen M5 x 9.5 (3DJake, deeper hole)
M4 x 20 SHCS 20 McMaster 91290A168 $0.14 any 12.9
O5 x 16 dowel 8 McMaster 91595A352 $0.38 any DIN 6325 m6 (4 into the motors, 2 in each adapter's face)
M5 x 25 SHCS 18 McMaster 91290A252 $0.22 any 12.9 (heads sit 0.6 mm below the adapter's face: not longer)
M5 x 40 SHCS partial thread 16 McMaster 91290A662 $0.16 any 12.9
M6 x 30 SHCS 4 McMaster 91290A332 $0.23 measure the BotWheel's thread depth first (bom.json note)
DIN 471-60 circlip 1 McMaster 98541A174 $3.05 McMaster 90154A811 $4.41 (zinc)
Filament PA6-CF 3 kg + 1 spare Bambu Lab US $79.99/kg (catalog 10-25); Gigaparts $79.99 in stock (today) Bambu PAHT-CF $94.99/kg (same nozzle, slightly weaker)
Filament TPU 95A HF, PETG 1 + 1 kg Bambu US $41.99, $13.99 any

Leg, machined to order (per leg; D40, D46):

Part Qty Primary Backup
Output adapter, 6061-T6, exports/leg/cnc/output_adapter.step + the callouts in exports/leg/cnc/README.md 2 JLCCNC instant price on upload (estimate $40 each, 5-10 days shipping from China) Xometry instant quote from the STEP

Leg bought total about $930 with the alternate bearings ($1,121 all-McMaster), plus the adapters (about $80 per leg) and filament about $300.

Rig (quantities for one rig):

Part Qty Primary Backup / note
HGR15 rail 1,000 mm + 2 HGH15CA 2 sets VXB "Beefy Square" HGH15 1,000 mm kit, $159.95 (page labels reversed; 5-10 business days) eBay HIWIN HGR15 + 2 blocks $49.99 + $38 shipping (DE); generic Amazon sets exist (not read today); HGR20/HGH20CA sets as the stronger backup
Post HFS8-8080 x 1,200 1 MISUMI US configurator (EU catalog about EUR 43.6/m; TODO US price) 80 x 80 from 8020.net / TNUTZ
Base 4040 8-series: 2 x 900, 3 x 700; brace 1 x 800 6 MISUMI HFS8-4040 (TODO price) any 40 x 40 10 mm-slot
8-series brackets (4040 corner x 12, 8080 foot x 4, brace ends x 2), M8 T-nuts and screws lot MISUMI HBLFSN8 family (TODO) 8020 / TNUTZ equivalents
M4 T-nuts for the rails (8-series slot) 34 MISUMI HNTT8-4 (TODO) drill and tap a 6061 bar strip instead
Plywood deck 18 mm, 700 x 900; load-plate pad 400 x 300 x 12 1 + 1 hardware store (Home Depot lists prices) MDF
Carriage plate 6061-T6 6.35 mm 300 x 320 1 SendCutSend instant quote (est. $60-90) Xometry instant quote
Ballast rods 25 mm Al, 150 mm; 1 in spring collars; weight plates 2 x 2.5 lb + 2 x 5 lb lot McMaster round bar / collars (TODO numbers); plates from any sports store threaded 1 in-8 rod with nuts
TPU bumpers, PETG bumper and pin brackets, pod printed P1S
Webbing 25 mm + 2 carabiners; drop pin 10 mm lot hardware store
4 x 50 kg half-bridge cells + HX711 1 kit Amazon kit about $10 (today, snippets) SparkFun HX711 $4.95 + 200 kg S-type $96.95 (in stock today)

Electronics:

Part Qty Primary Backup
FLEXVOLT 60 V dock adapter, 12 AWG 1 Terrafirma (eBay) about $16.50 Newegg $23.35; Etsy $16
Mean Well LRS-600-48 bench supply 1 Jameco $59.90 (68 in stock) LRS-600N2-48 $66.10; RSP-1000-48 $267.95
Fuse KLDR030 + Class CC holder 1 Standard Electric $31.70 (536) + holder TODO Blue Sea 5191 $29.93 + MRBF 60 A (58 V)
DC contactor LEV100A4ANG (12 V coil) 1 RS UK GBP 98.80 (65 ready) Cytech $172.99; EV200AAANA GBP 174 RS; TODO a US-stock cheaper part
Off-delay timer relay 12 V, 1 s 1 TODO part a 555 + MOSFET on the Feather's proto area
Mean Well DDR-30L-12 (coil and pod 12 V) 1 Bravo Electro $27.60 Jameco $27.60
USB-CAN: BTT U2C V2.1 1 BIQU $23.99 orderable FYSETC UCAN $8; InnoMaker USB2CAN (isolated) RS GBP 56.99; PCAN-USB $256
Adafruit Feather M4 CAN Express 1 Adafruit 4759 $24.95 in stock a second one as spare
Adafruit VL53L1X 1 Adafruit 3967 $14.95 in stock draw-wire CALT CWP-S (about $125-140)
Pendant AbleNet Specs IC 1 AbleNet $75 in stock Coyote Direct $60
Pod panel parts: XT60E-F, 3.5 mm jack, rocker, 5 x 20 holder 1 each per catalog/sourcing.json parts (Jameco XT60E-F $0.95, Switchcraft 35PM2A, E-Switch RCA1913, Littelfuse 03455LS1H $7.16)
12 AWG silicone wire 2 m red/black, XT30 plugs x 4, XT60 pair, 22 AWG twisted pair 3 m, 120 ohm x 2, ferrules, heat-shrink lot Amazon / Digi-Key

Electronics about $330-470 depending on the contactor; rig about $400-500; whole first build about $2,400-2,700 plus the motors' shipping and duties.

6.2 Print plan on the P1S (hardened nozzle and extruder, textured PEI, glue; PA6-CF dried 8-12 h at 80 C before

every print, fed from a dry box, not the AMS)

Hours from exports/leg/print-plan.json (grams / density / 14 cm^3 per h for PA6-CF: rough, expect +20 %).

Day Prints Material Hours Purpose
1 dyno lug plates x 2, coupler disc, bumper/pin brackets, pod PETG 10 bench fixtures and rig parts (order of parts does not wait on them)
1-2 fit coupons: frame motor-ring slice, hub face (the link's side: spigot recess, clearance and dowel holes), knee eye, knee boss, apex eye, hub stub; insert coupon; post coupon PA6-CF 8 every seat and insert dialled in before any big part; B3 and B4 run on these
2 stop sleeves x 4 (+2 spare), TPU bumpers x 2 TPU 10 B3, the rig's bottom stop
3-5 upper links x 2 PA6-CF 48
5-6 front link PA6-CF 29 turned on the bed
6-8 wheel link PA6-CF 40 turned
8-10 hip frame PA6-CF 66 last: the biggest print (274 x 154 x 81, turned 45 deg with 0.8 mm to spare, 1,006 g with the 13 mm flanges and the stop posts' backed ears, D53); print it only after the coupons prove the seats and the P1S holds PA6-CF flat at that size (a 150 x 150 test slab first if there is any doubt)
10 apex spacer, spares PA6-CF 2

About 198 h of printing (the adapters are machined now): 9 days if nothing fails; plan three weeks with drying and one reprint. The motors' lead time from China (1-3 weeks) runs in parallel; the bench fixtures and coupons are done before the motors arrive.

6.3 SendCutSend

The rig's one part: the carriage plate (6061-T6, 0.25 in, 300 x 320 mm, hole table in section 2.1, deburred). The leg's machined parts (the two output adapters, CNC, D46) are ordered the same day from exports/leg/cnc/: JLCCNC or Xometry, the STEP plus the README's callouts. cad/build_rig.py exports exports/rig/sendcutsend/carriage_plate.dxf (flat, mm, holes as circles, no text) and the order sheet with the instant price read at upload. Everything else on the rig is extrusion, bought hardware or printed.

6.4 Assembly order (torques from B4; threadlocker on every screw into steel; never a hard press into PA6-CF)

  1. On receipt (review M7): each O5 dowel must slip into the RS-04's locating holes by hand (drawn Ø5 0/-0.01; an m6 pin is +0.004/+0.012). If one does not, polish its motor end or buy -0.01 pins: the pins are pressed into the frame only, never into both. Depth-gauge one motor's lug threads too: the M4 x 20s take 4.9 mm (the drawing promises 5).
  2. Hip frame: M5 inserts (6) set with the soldering iron at the coupon-proven temperature (the stop pins go in last, step 7); the two 61812s pressed in from the motor side onto the lip (light fit + retaining compound if the coupon says so); O5 dowels pressed into the frame's locating holes (the motor then slides onto them).
  3. Output adapters (machined) onto the motors: the motor's 3 pins into the adapter's sockets, 9 x M5 x 25 (no washers: the heads sit in the pockets), threadlocker, the motor maker's torque; two O5 x 16 dowels pressed into each adapter's face (H7 holes, 8 mm in). Then each motor into the frame on its 2 dowels and 10 x M4 x 20 (heads 11 mm down in the counterbores), the adapter's j6 journal into the frame's 61812 with retaining compound (Loctite 641: it comes apart). The frame's dowel holes set each motor's turn so its harness leaves level and outwards (the front one forwards, 25 deg up; the rear one backwards, 11 deg down): check both clear the flanges.
  4. Upper links: two eye sleeves pressed end to end from the outer face until the outer one is flush with that face (the press stops there: there is no floor under them; review S2); the link onto the adapter's face (over its 2 dowels and spigot, 8 x M5 x 40 into the tapped holes, heads in the hub's counterbores, B4 torque: the printed link under the heads sets the limit).
  5. Knees: two 6201s and the spacer tube into each lower link's boss (cut each spacer to that boss's measured seat-to-seat distance + 0.03 mm, not to the nominal 28: review S4), a DIN 433 washer each side, the 12 x 90 shoulder screw from the outer side through the eye, the M10 nyloc in the pocket torqued onto the steel sleeve.
  6. Apex (review M5: the hub's Ø64 shoulder is outboard of the outer bearing, so the bearings go in before the hub): the inner 61812 pressed into the front link from the inside, the apex spacer, the outer 61812 pressed from the outside against the web, then the wheel link's hub through both from the outside, the DIN 471-60 circlip.
  7. Wheel: 4 x M6 x 30 from inside the hub (measure the flange's thread depth first; bom.json note), cable taped along the wheel link and rear upper link.
  8. Stop pins, last (D53): each Ø16 x 40 pin, its vent flat turned to face its motor's axis (square to the stop's load) and its tapped end up, a thin coat of Loctite 638 in the 23 mm blind hole, pushed in by hand or a light press until it sits on the hole's floor (never a hard press into PA6-CF; the flat lets the air and compound out); wipe off what comes out, 24 h before a load. Then each TPU sleeve pushed on over its pin, its cap outwards (a stretch fit: no glue). Each post sits midway between two lug screws (front motor 43/79 and 187/223 deg, rear 101/137 and -43/-7 deg), 19 mm from its axis: a hex key reaches them past the sleeve's edge, and a sleeve pulls off by hand for a socket (review S8). A pin comes out with an M8 screw in its tapped end and a puller. Swing the leg by hand to both stops: each link's radial stop face meets its sleeve square on, no clash, free knees.
  9. Carriage plate: blocks on (16 x M4), rods on, plate onto the frame's six inserts (M5 x 16); carriage onto the rails from the top, end caps on, tethers on; bumpers set at the 115 mm position, ballast plates to the rig.json figure.
  10. Electrics: pod, fuse, contactor, pendant, CAN chain with both terminators, VBUS read on the laptop before any enable.
  11. First power: bench supply at 48 V, current limit 5 A, carriage on the bumper, leg in the air: scan, parameters, limit_torque 60, zero both motors at a jig-defined pose (upper links horizontal on the knee-out stops is the simplest reference: phi = +3 deg / -183 deg), enable, hold a length in the air, then the stand.

7. Ordered task list for the Opus implementer

Work in your own worktree on new files; cad/fivebar.py, cad/leg_studies.py and sim/leg_rig.py are the main session's (requests to them are the F items at the end). Estimates are working days.

# Task Files Acceptance Est.
T1 Order list so purchasing starts today: every bought part of section 6.1 with price, link, date checked, primary and backup, quantity, and the TODO prices filled (MISUMI configurator, holder, timer, contactor backup) docs/leg-rig-orders.md, catalog/rig.json (items in the catalog schema) every line has a price and a buy link read on the day, or a printed/SendCutSend note; totals per vendor 0.5
T2 Rig CAD and checks: post, rails and blocks (envelopes), carriage plate, rods, bumpers and brackets, base frame, deck, brace, pod; the checks of section 2.2 cad/rig_parts.py, cad/build_rig.py -> exports/rig/{*.step,*.stl,rig.json,print-plan.json,bom.json,renders} clearance sweep >= 10 mm at 14 lengths x 3 leans; carriage mass and the plate figure in rig.json; block loads and post stress printed; renders of the rig with the leg at 130/300/392 mm and the jump apex; read the frame's insert positions and mount plane from fivebar.frame_mounts() (z +-70 since the 13 mm flanges) without editing fivebar 2
T3 Carriage plate DXF and SendCutSend sheet exports/rig/sendcutsend/carriage_plate.dxf, exports/rig/sendcutsend/README.md DXF re-imports with the hole table of section 2.1; the instant price recorded 0.5
T4 Bench fixtures CAD: dyno lug plates and coupler, insert coupon, post coupon (the stop pin's hole, fivebar.STOP_PIN), tyre cradle, the six fit coupons cad/rig_bench.py -> exports/rig/bench/ each a valid solid, fits the bed, STL + STEP; coupon seat diameters parameterised +-0.1 mm in three steps 1
T5 Print schedule from the two print plans (leg + rig) in the order of section 6.2 with drying windows tools/print_schedule.py -> exports/rig/print-schedule.md the table of section 6.2 regenerated from the JSON, total hours, the hip frame last 0.5
T6 RS-04 driver (section 4.3), with the frame layout verified against the RS04 manual section 4 rig/rs04.py, rig/tests/test_rs04.py pack/unpack round-trips for every type; MIT encoding at the RS04 ranges exact at the end points; a recorded-frame test; CLI scan/enable/stop/param works on one motor 1.5
T7 Bus abstraction + MuJoCo backend rig/bus.py, rig/sim_bus.py, rig/can_bus.py run.py --backend sim reproduces rig-results.json stand-up and squat peaks within 5 % and the jump height within 10 mm 1
T8 Controller port + runner + safety state machine (section 4.2, 4.5) rig/leg_control.py, rig/run.py, rig/criteria.json the sim-backend runs of all five scenarios; the RUN-frame, VBUS, temperature, length-window and rate-limit aborts each demonstrated in sim by fault injection 1.5
T9 Logging and comparison rig/log.py, rig/compare.py -> exports/rig/runs/ 500 Hz npz + JSON summary with rig-results keys; overlay plots; pass/fail from criteria.json; a sample run checked in 1
T10 Wiring page (section 3): one diagram a person builds from, connector pinouts, wire gauges, fuse, contactor, timer, pendant loop, CAN chain and terminators, grounds docs/leg-rig-wiring.md, exports/rig/wiring.svg every wire has a gauge and both ends named; the pendant chain traced from button to contactor coil and to the Feather 1
T11 Feather firmware rig/firmware/feather_rig/code.py RUN frame at 100 Hz only while the loop is closed; ToF and HX711 frames at 50 Hz; USB log; tested on the bench with the U2C 1
T12 Bench test procedures and analysis (section 5 B1-B5) docs/leg-bench-tests.md, rig/bench/{backdrive,spin_down,fit_params}.py each test has a step list, a data sheet template, and a script that turns the data into the sim parameter it feeds (b(omega) table, J, k_stop, preload-torque curve, k_tyre) 1
T13 Assembly and safety docs (section 6.4 plus a pre-test checklist: tethers, bumper height, pack voltage, pendant test, clear zone) docs/leg-rig-assembly.md, docs/leg-rig-safety.md checklists usable at the bench; torques filled from B4 0.5
T14 Site page: the rig on the progress site with the shared top bar (renders, print schedule, BOM, run results) designer/ (per the site conventions) linked from the progress page; no URL needed to reach it 0.5

Flagged for the main session (owner of fivebar.py, leg_studies.py, sim/leg_rig.py):

First five for the implementer, in order: T1, T2, T4 (so the fixtures print while parts ship), T6, T7 — then T8/T9 as a pair, T10/T11 as a pair.


8. Top risks

  1. RS-04 supply: five sellers, all China; two backordered 4-6 weeks. Order on day 1 from Seeed (or OpenELAB with duties included) and nothing else on the plan waits on the motors except the bench tests.
  2. PA6-CF on a P1S at the hip frame's size (274 x 148, 782 g, turned 45 deg): warping and layer adhesion without a heated chamber. Mitigation: coupons and a test slab first, textured PEI with glue, the chamber pre-warmed, the frame printed last; the fallback is splitting the frame (a fivebar change, main session).
  3. Bearing seats in printed PA6-CF crack on a hard press (LeRobot) or walk when loose: the coupons set a light fit; retaining compound as the backup.
  4. The power-off collapse is the knees' governing case and depends on one unmeasured motor behaviour: B1 is first, the bumper stays high until it is known, and the spring add-on is on the shelf.
  5. Regen over-voltage on a 60 V-limited motor: no bench-supply dynamics, the pack at 48-55 V, VBUS watched every tick, a 58 V abort.
  6. A 500 Hz Python loop over USB-CAN may jitter: measured in bring-up step 2; 250 Hz is acceptable for the first stand (the sim can confirm the margin at 250 Hz: F1), and the Feather is the landing place for a 1 kHz loop.
  7. The hold-to-run contactor: the proper parts are GBP 99-174 and not all in US stock; the backup is a listed-price Amazon EV relay, to be verified, or the AC-side cut when on the bench supply.
  8. The rail blocks' roll moment (880 N m at the jump) and rail alignment: two rails on one post face, blocks 250 mm apart, checked in T2; loosen-and-retighten alignment on assembly, and the first jumps at 30 N m.
  9. Insert preload in PA6-CF is an assumption (1,200 N) behind the hub joint checks: B4 before the adapters are torqued.
  10. The motor harness clocking against the carriage plate (2 mm behind the motors' rear faces): T2 checks the vendor STEP; the plate's top slot is the escape.

9. TODO (next session)