# claude_feetech_controller

Clean refactor of `our_feetech_controller` for **zero + direction calibration** and
**live sim mirroring** of Feetech STS3215 servos. Shared bus code lives in
`feetech_bus.py`; robots are described in `configs.py`; calibration state lands in
`calib/<config>.json`.

## 1. Calibrate a servo (by hand)

```
python calibrate_servo.py <servo_id> --config gripper
```

- Torque is disabled so you can move the servo freely.
- **Step 1** — move to the URDF zero pose, press Enter. That physical position becomes
  tick 2048 (`INST_OFSCAL`), stored in the servo's EEPROM (survives power cycles).
- **Step 2** — move in the URDF-**negative** direction for that joint, press Enter. The
  tool records the **sign** so ticks map to URDF radians.

Writes `calib/gripper.json` (merged, keyed by servo id — run once per servo to build a
whole robot). For the gripper the joint defaults to `jaw`; override with `--joint`.

## 2. Live-mirror the servo into MuJoCo

```
python live_mirror.py --config gripper
```

Opens the MuJoCo viewer, disables torque, and drives the model's joint from the live
encoder reading (tick → sign·radians). Move the servo by hand and the sim follows.
Read-only — it never commands the servos.

## Servo IDs
Connect **one servo at a time**, then:
```
python set_id.py <old_id> <new_id>
```
See what's on the bus with `python scan_ids.py`.

## Arm (6 servos) — config `arm`
Convention: servo id `i` drives joint `output_i` (ids 0..5 == output_0..output_5).
1. Assign ids with `set_id.py` (one servo on the bus at a time).
2. Calibrate each: `python calibrate_servo.py <id> --config arm` — the joint is auto-resolved
   from the id, so you don't pass `--joint`. Move to zero, Enter; move negative, Enter.
3. Live-mirror all six: `python live_mirror.py --config arm` (uses the lit two_servo_pretty model).

## Layout
- `feetech_bus.py` — connection, read pos/temp, torque, `set_zero_here` (INST_OFSCAL), `set_id`
- `configs.py` — config name → model + joint(s)
- `calibrate_servo.py`, `live_mirror.py`, `set_id.py`, `scan_ids.py` — the tools
- uses Cameron's existing `stl_transfers/mj_umi_v2/umi_gripper_v2.xml` (properly lit); override with `--model`
- `scservo_patch.py` — SDK compatibility shim (unchanged from our_feetech_controller)
- `calib/` — calibration output

Requires (already on the Mac): `feetech-servo-sdk`, `mujoco`. Default port
`/dev/tty.usbserial-0001` @ 115200 (override with `--port`).
