Build plan
From ordering parts to a trained robot rolling on your desk: every step in order, how long it takes and what to watch for.
Plan on about 15 hours of hands-on work plus 9 to 10 hours of unattended printing. At an hour a day that is two to three weeks from ordering parts to a trained robot rolling on your desk: days 1 to 4 waiting for parts while you train in sim, days 5 to 12 building, the rest on the real robot. With parts and prints already on the desk, a long weekend is enough.
The detailed procedures live on the Mechanical page (printing, one joint step by step, O-rings, magnets, where each board mounts) and the Electronics page (soldering the power board, bring-up, troubleshooting). This table is the order of work.
| # | Step | Hands-on | Waiting | Watch out for |
|---|---|---|---|---|
| 0 | Order parts (see Parts) | 30 min | 2 to 5 days | Battery: 2S, 450 to 500 mAh, no thicker than 12.5 mm, with a charger. Mini560: the fixed 5 V version. ESP32: classic WROOM-32. Servos: 180°, not 360°. |
| 1 | While you wait: install Python and MuJoCo, run ouro_model.py, test_gaits.py, train roll and bite |
1 h | 12 min + 5 min of training on 10 cores; 1 to 2 h on a 4-core laptop | macOS: run the MuJoCo viewer with mjpython. |
| 2 | Measure one MG90S with calipers, edit the numbers at the top of cad/components.py and cad/make_parts.py, run make_parts.py and check_fit.py, print coupon.stl, test the fit |
1 h | 25 min print | Expect one reprint. Clone servos vary by ±0.5 mm in spline height and horn shape. The coupon checks the pocket, the horn recess and the pivot screw before you spend 9 hours printing. |
| 3 | Print 4 × link, link_s3_battery, link_s4_esp32, link_s5_power, tail, head in PETG, belly down, no supports |
30 min | 8 to 10 h | First-layer squish stiffens the 1 mm leaf spring (stiffness goes with thickness cubed). Check each spring flexes by hand and looks 1 mm thick. |
| 4 | Flash firmware/servo_center to one ESP32. Plug each servo into it in turn, let it centre at 1500 µs, fit the horn pointing along the link, number the servo |
40 min | Arduino-ESP32 core 3.x is required. CH340 boards may need upload speed 460800. | |
| 5 | Build one joint completely (Mechanical page, one joint step by step) and fold it by hand: it must swing to −69° and stop on plastic at +90° with the electronics untouched | 30 min | Horn fitted one spline tooth off (about 15°). Refit so the link is straight at 1500 µs. | |
| 6 | Build the other seven joints, fit the O-rings | 2 h | Zip-tie tail left proud of the belly. Cut flush. | |
| 7 | Latch: superglue two magnets into the tail (same pole out), drive the two M3 steel screws into the head with a ring lug under each, lay the bare sense wire in its groove across the tail notches | 40 min | 10 min glue | Stainless screws: a magnet will not hold them. |
| 8 | Measure latch pull-off with a kitchen scale: hook the head pins, pull the tail, read the peak. Target 130 to 200 g | 20 min | Too strong and the startle cannot open it; too weak and the wheel bursts. Shim the magnets deeper with paper to weaken. | |
| 9 | Flash ouro_robot to the robot's ESP32 and ouro_dongle to the other, before cutting any pins. Confirm telemetry arrives with nothing connected (play_gait.py PORT wave 2) |
40 min | No telemetry: ROBOT_ID or channel differs between the two sketches. |
|
| 10 | Solder the power board (66 × 20.5 mm layout on the Electronics page). Fit XT30 and the 3 A polyfuse to the battery lead. Follow the bring-up steps: both rails must read 5.0 V on a meter before anything is connected | 2.5 h | A "5 V" Mini560 that is really the adjustable version. A pack with a PH2.0 plug: it must be changed to XT30, one lead at a time. | |
| 11 | Cut the ESP32's header pins flush, solder the signal and sensor wires to the stubs, mount battery, ESP32, IMUs and power board (Mechanical page, where each board mounts), route servo leads through the wire channels with a 15 mm slack loop at every joint, fit the three extensions | 2.5 h | Wires taped across a leaf spring stop it flexing. Fix them to the solid blocks only. Run firmware/i2c_scan: it must list 0x40, 0x68, 0x69. |
|
| 12 | calibrate.py, then wave, cobra, bite on the desk |
1 h | A joint that curls the wrong way: answer "n" in calibration, do not rewire. | |
| 13 | sysid.py; put your delay and slew numbers into _set_params(); python train.py roll --init policies/roll.zip --steps 500000 |
45 min | 3 min | Round trip over 30 ms: USB-serial driver buffering (FTDI latency timer). |
| 14 | run_policy.py PORT roll --gain 0.4, raise the gain |
1 to 2 h | The wheel rocks but does not roll: friction. Clean the O-rings and the desk. |
You are done when the robot, starting flat, bites its tail, rolls at least 50 cm and opens on command, three times out of five, on video.