Metadata-Version: 2.5
Name: microcmm
Version: 0.1.0
Summary: Python library + CLI for MicroScribe-3D digitizer arms (RS-232, no Windows DLL)
Project-URL: Repository, https://github.com/Revise-Robotics/microcmm
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: pyserial>=3.5
Description-Content-Type: text/markdown

# microcmm

Python library + CLI for reading positions from a MicroScribe-3D digitizer arm
over its RS-232 serial port. Speaks the Immersion HCI protocol directly (no
Windows DLL) and does the forward kinematics on the host using the arm's own
EEPROM calibration. Millimeters everywhere.

## Install

```
pip install microcmm
# or
uv add microcmm
```

## Usage

```python
from microcmm import MicroScribe

with MicroScribe("/dev/cu.usbserial-XXXX") as ms:
    # You should be homing right now: arm in its home pose (stylus seated
    # in the holder and vertical, counterweight against the stylus holder).
    ms.home()
    # (Advanced: ms.assume_homed() if the arm is already homed this power cycle.)
    print(ms.info.serial_number)
    p = ms.pose()
    print(p.x, p.y, p.z)
```

## CLI

```
microcmm <command>
```

- `info` - identify the arm, dump its calibration constants
- `point` - read one stylus position
- `stream` - continuously print positions
- `capture -o points.csv` - capture points on keypress, write CSV
- `dist` - measure distances between captured point pairs
- `home` - set the home position (arm must be in its home pose)
- `ports` - list serial ports

## Notes

- **Homing is mandatory.** The arm only reads correctly if it was in its home
  pose (stylus seated in the holder and vertical, counterweight pressed
  against the bottom of the stylus holder) at power-on or when `home` was
  sent. This is lost at every power cycle. The library refuses to return
  positions until you call `home()` or explicitly `assume_homed()` - an
  unhomed arm produces garbage that looks plausible.
- **Only tested on a MicroScribe-3D model D (5-DOF).** The library refuses
  other models by precaution, not because they can't work - if you have one,
  run with `allow_untested_models=True` and report back, we'll add it.
- **Pedals are not implemented** because we don't have one. The raw button
  byte is exposed on every packet if you want to try.
- 5-DOF arms have no roll about the stylus axis; the reported orientation
  (XYZ-fixed roll/pitch/yaw) reflects that.
- Accuracy validated with a 45-point single-divot pivot test: 0.66 mm RMS.
  Avoid poses with the stylus aligned with the forearm (singularity).
- Not implemented, on purpose: analog channels, baud switching, EEPROM
  writes (SET_PARAMS / SET_HOME / RESTORE_FACTORY), motion-report streaming,
  custom tip offsets (MSTIP.DAT). Ask if you need one.

## Dev

Install dependencies with `uv sync`, then:

```
uv run pytest
uv run ruff check src tests
uv run mypy src tests
```

Tests run without hardware: the kinematics is checked against golden
joint-angles-to-XYZ values captured from a real arm.
