# SO-100 parametric arm (in our locked parts)

A modular, parametric reproduction of the open-source **SO-ARM100**, built entirely from our locked
parts — `st3215` servo + `wrap_holder` + `yoke_exact` — connected by parametric printable bridges.
Started from the SO-100's 5-DOF chain; a parametric **wrist_yaw was added -> now 6-DOF + gripper**
(demonstrating the chain is genuinely parametric). ~1.5× bulkier than the SO-100 (our servos + 103mm yokes).

## Regenerate everything
```
bash so100_build_all.sh        # bridges -> URDFs -> hero render -> collision check (run ON LAB)
```

## Source of truth
- **`so100_para.py`** — the generator. SO-100 joint chain (exact origins/rpy/axes/limits), our servo+holder
  placed so each servo's real output (+Y) = the joint it drives. Knobs: `ROLLS` (free roll per output axis,
  optimized to aim each yoke at the next servo), `SPACERS` (per-joint bridge extension so our bigger servos
  don't intersect). `connect` arg -> phase-2 connected URDF with yokes + bridges. Exposes `servo_pose`,
  `_T`, `_mat` used by the other tools.
- **`so100_bridge.py`** — builds the printable structural bridge solids (tapered beam + cup at the yoke
  far-end + boss mating the holder), one per link -> `so100_bridge_<link>.stl`.
- **`so100_optimize_rolls.py`** — coordinate descent that sets `ROLLS` to minimize each yoke->next-holder gap.

## Outputs
- `so100_para.urdf` (phase 1, servos floating at SO-100 poses) ·
  `so100_para_connected.urdf` (phase 2, connected/printable).
- Viewer: `cad.omidlab.net/?dir=/data/cameron/repos/smith300_para_stuff&file=so100_para_connected.urdf`

## Verify (real FK + FCL mesh collision — the URDF is visual-only so MuJoCo contacts are vacuous)
- `so100_check.py <urdf> "j=a,j2=a2"|<scalar>` — servo-servo + bridge-through-other-servo at a pose.
- `so100_sweep.py` — steps each joint across its limits (others 0).
- `so100_random.py <N>` — fraction of random whole-arm poses that are collision-free (currently 79%).
- `so100_at.py <joint> <ang>` — list cross-link colliding pairs. `so100_envelope.py` — size vs real SO-100.
- `so100_render.py <urdf> <out> "j=a,..." [focus_link] [dist]` — render at a specific per-joint pose.

## Status (2026-06-24)
Phase 1 + Phase 2 done; 6-DOF + gripper. Connected: servo -> yoke (grips output) -> printable bridge ->
next holder. All printed parts watertight/sliceable. Rest + normal poses collision-free. Reproducible
from source (`so100_build_all.sh`). Heroes: `so100_ready_hero.png` (5-DOF), `so100_6dof_hero.png`.
TODO: bolt holes (boss<->holder, real STS3215 mount pattern), flush bridge mating, tuned/real gripper
(currently representative 2-jaw).
