A custom anthropomorphic 6-DOF leader-follower robotic arm system roughly based on the open-source SO-100 design. Built for hands-on experience in mechanical design, embedded systems, and robot teleoperation, with imitation learning via the LeRobot framework.
Status: ✅ Core pipeline complete. Both arms were built, calibrated, and made to teleoperate end-to-end. An ACT policy trained on a 50-episode pick-and-place dataset was run autonomously on the physical follower arm via a dead-man's-switch-gated control loop. Full session-by-session history lives in docs/context.md.
Autonomous policy. An ACT policy trained on 50 teleoperated demonstrations, running on the follower arm with no human input: approach, grasp, transport, release. Clip is 1.25× real time.
Teleoperation. The leader arm (bottom) is backdriven by hand; the follower (top) mirrors it at 50 Hz over a single half-duplex servo bus. This is how the training demonstrations were recorded.
| Property | Value |
|---|---|
| Configuration | Leader-follower (2 arms) |
| Degrees of Freedom | 6 per arm (5 + gripper) |
| Actuators | FEETECH STS3215 (6× per arm, 12 total) |
| Servo Driver | Waveshare Bus Servo Adapter (A) — half-duplex TTL, USB host |
| Compute | NVIDIA Jetson Orin Nano Super (JetPack 7.2, Ubuntu 24.04) |
| Bus interface | USB CDC-ACM on /dev/ttyACM0 at 1 Mbps |
| Bus topology | Single bus — both arms (follower IDs 1–6, leader IDs 7–12) |
| Framework | LeRobot (feetech extra, editable install) |
| CAD Tool | Onshape (public) |
| Reach | 433 mm |
| Payload | 1.2 kg @ worst case scenario (maximum reach) |
| Leader | Follower |
|---|---|
![]() |
![]() |
CAD renders (Onshape, 2026-08-09) of the finished leader and follower arm assemblies.
Real hardware photos (2026-08-21) of the finished leader and follower arms.
hexarm/
├── cad/ # Mechanical design files and exports (Onshape)
├── media/ # Hardware photos of robots & workspace (media/pictures/)
├── software/ # Control, calibration, and low-level setup scripts
└── docs/ # Technical documentation and debugging logs
Key entry points inside software/:
software/
├── control/teleop.py # leader-follower teleoperation loop (working)
├── control/record_dataset.py # records teleoperated demos into a LeRobotDataset
├── control/run_policy.py # runs a trained checkpoint on the physical follower arm
├── calibration/ # LeRobot-based calibration + arm control
├── vision/camera_preview.py # headless MJPEG live-view tool for camera positioning
└── low-lvl-setup/ # raw SDK diagnostics and one-time setup tools
- Hardware Assembly Guide — fastener reference, build order, workspace setup
- Teleop Control Loop — 50 Hz
sync_read→sync_writedesign reference - Servo Protocol Reference — STS3215 packet protocol + hardware-verified gotchas
- Project Context — full hardware/software handoff
- Postmortems — consolidated incident log (symptom → root cause → fix → lesson)
- Servo Comms Bring-Up — full UART/SDK debugging chronology
- CAD Assembly (Onshape, public) — full parametric model, leader and follower arms modeled separately
- ADR — 0001: compute platform selection (Pi Zero 2W → Jetson Orin Nano Super), 0002: single-bus servo topology (vs. LeRobot's two-bus default)
- NVIDIA Jetson Orin Nano Super (JetPack 7.2, Ubuntu 24.04 / aarch64)
- 1× Waveshare Bus Servo Adapter (A) — set to USB-Servo mode
- 12× FEETECH STS3215 servos (both arms daisy-chained on one bus)
- 12 V DC supply for the servo bus (via the board's barrel jack) - minimum 5A
- 19 V DC supply for Jetson Orin Nano Super (comes with the Dev Kit)
| Adapter | Output | Powers | Connector |
|---|---|---|---|
| Jetson power supply | 19V, 2.37A max | Jetson Orin Nano Super | Jetson's barrel jack |
| Servo bus power supply | 12V, 5A max | Servo bus (both arms) | Waveshare board's barrel jack |
Full connection sequence:
- Daisy-chain both arms' servo JST connectors into the one Waveshare Bus Servo Adapter (A) that's in use - 2 JST ports on the adapter; one per arm.
- Confirm the board's physical mode switch is set to USB-Servo.
- Plug the 12V/5A adapter into the Waveshare board's barrel jack (servo bus power).
- Plug the 19V/2.37A adapter into the Jetson's barrel jack (compute power).
- Connect the Waveshare board to the Jetson via USB.
- Power on the Jetson and SSH in (ssh username@hostname.local).
# Clone the repo
git clone https://github.com/evanapplebaum/hexarm.git
cd hexarm
# Raw SDK diagnostics only need pyserial — use the hexarm .venv
# Note that these 'low-level' scripts were created to modify servo registers or isolate issues while debugging hardware.
# Also note that ALL STS3215 SERVOES SHIP WITH ID = 1. Attempts to ping 2 servoes with the same ID at the same time will fail (both servoes will attempt to respond simultaneously --> jumbled data)
source .venv/bin/activate
python software/low-lvl-setup/ping_one.py --id 1 # via the scservo_sdk path
python software/low-lvl-setup/raw_ping.py --id 1 # raw pyserial diagnostic
deactivate
# Anything importing LeRobot (teleop, calibration, recording) uses the
# separate lerobot-env venv (Python 3.12+, CUDA-linked torch build)
# — see requirements.txt for exact pinned versions and the Jetson-specific
# install steps (custom torch wheel + a small local LeRobot patch)
source /data/lerobot-env/bin/activate
# Run leader-follower teleoperation:
python software/control/teleop.pyNote: LeRobot is not installable on Intel Mac (no x86_64 torch build). For Mac-side diagnostics, a lightweight
pyserial-only venv drives the samelow-lvl-setupscripts over the board's USB port (/dev/cu.usbmodem*). See docs/context.md for the full per-platform setup and the servo bus bring-up procedure.
| Task | Status |
|---|---|
| Jetson Orin Nano Super flashed (JetPack 7.2) + SSH | ✅ Done |
Servo bus over USB (/dev/ttyACM0, CDC-ACM) |
✅ Done |
| Servo communication verified (raw pyserial + scservo_sdk) | ✅ Done |
LeRobot installed on Jetson (pip install -e ".[feetech]") |
✅ Done |
| Servo IDs assigned — follower 1–6, leader 7–12, single bus | ✅ Done |
| All 12 servos responding on one bus | ✅ Done |
| Per-joint calibration (both arms) | ✅ Done — clean re-calibration complete (2026-07-27); follower re-calibrated again (2026-08-03) after a broken joint was reprinted and reassembled |
Leader-follower teleoperation (teleop.py) |
✅ Done (2026-06-03) |
| Encoder wrap-around fix — code rewrite | ✅ Done (2026-06-02) |
| Angle limits flashed to servo EPROM | ✅ Done (2026-07-27) |
| Cameras (wrist + overhead, 2× Arducam OV9782 global shutter) | ✅ Done — overhead mounted & locked (2026-07-31), wrist mount reprinted, installed, and placement confirmed (2026-08-05) |
| Dataset recording | ✅ Done — hexarm/pick_and_place_v2 (2026-08-10, 50 episodes, verified + visually reviewed); superseded by hexarm/pick_and_place_v3 (2026-08-20, 50 episodes re-recorded with wider claw opening + higher drop-off arc, see postmortem #10) |
| Policy training | ✅ Done — v2: 25,000-step ACT run (2026-08-14), best of 5 via direct eval, L1 loss 0.1742→0.0942, monotonic, no overfitting. v3: 30,000-step ACT run on the re-recorded dataset (completed 2026-08-21, ~12h07m), best checkpoint confirmed via the same direct-eval method — see docs/context.md session 15 log. |
| Run trained policy on hardware | ✅ Done (2026-08-21) — v3's checkpoint run on the physical follower arm via software/control/run_policy.py (dead-man's-switch gated, mirrors go_neutral.py --diagnostic); postmortem #10's margin issues confirmed fixed. |
- CAD — individual part design
- CAD — full assembly
- Docs — hardware assembly guide
- ADR — compute platform selection
- ADR — single-bus servo topology
- Servo communication over UART/USB (register read/write)
- Per-servo configuration tool (ID, baud, return delay)
- Joint-limit calibration tool
- Docs — servo protocol reference
- Compute — Jetson Orin Nano Super provisioned and networked
- Software — LeRobot installed and verified
- Build — print and source all parts
- Build — assemble both arms
- Integration — servo IDs assigned, both arms on one bus
- Software — leader-follower control loop (LeRobot)
- Data — record demonstration dataset (2026-08-10, 50 episodes)
- Training — train ACT or diffusion policy
- Deploy — run policy on hardware (v3, 2026-08-21 — postmortem #10 margins confirmed fixed)
- Demo — hardware photos in README (2026-08-21; video skipped by choice — recordings ran too long)
MIT License — see LICENSE

















