Metadata-Version: 2.4
Name: pyrh56
Version: 0.3.0
Summary: Python driver for the Inspire Robots RH56 dexterous hand
Project-URL: Homepage, https://github.com/WiseZenn/pyrh56
Project-URL: Documentation, https://github.com/WiseZenn/pyrh56#readme
Project-URL: Repository, https://github.com/WiseZenn/pyrh56
Project-URL: Issues, https://github.com/WiseZenn/pyrh56/issues
Author: WiseZenn
License: MIT
License-File: LICENSE
Keywords: dexterous-hand,inspire-robots,rh56,robotics,serial
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Hardware
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Requires-Python: >=3.10
Requires-Dist: pyserial>=3.5
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# pyrh56

[![CI](https://github.com/WiseZenn/pyrh56/actions/workflows/ci.yml/badge.svg)](https://github.com/WiseZenn/pyrh56/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/pyrh56)](https://pypi.org/project/pyrh56/)
[![Python](https://img.shields.io/pypi/pyversions/pyrh56)](https://pypi.org/project/pyrh56/)
[![License](https://img.shields.io/pypi/l/pyrh56)](https://github.com/WiseZenn/pyrh56/blob/main/LICENSE)
[![Ruff](https://img.shields.io/badge/lint-ruff-261230)](https://github.com/astral-sh/ruff)
[![Mypy](https://img.shields.io/badge/type-mypy-blue)](https://github.com/python/mypy)

[中文](README_CN.md)

A low-level Python driver for the Inspire Robots RH56 6-DOF dexterous hand —
serial transport, protocol codec, validated writes, feedback, fault handling,
calibration, and diagnostics.

> This is an independent project. It is **not** affiliated with or endorsed by
> Inspire Robots. "RH56" is used solely to identify the compatible hardware.

---

## Install

```
pip install pyrh56
```

Python ≥ 3.10. Runtime dependency: [pyserial](https://github.com/pyserial/pyserial).

The PyPI package is `pyrh56`; the import package is `rh56_sdk`:

```python
from rh56_sdk import RH56Config, RH56Driver
```

Dev install:

```
pip install -e ".[dev]"
```

---

## Quick Start

```python
from rh56_sdk import RH56Config, RH56Driver

with RH56Driver("COM3") as hand:
    hand.move_to([1000, 1000, 1000, 1000, 700, 900])  # open
    angle  = hand.read_angle()
    force  = hand.read_force()
    status = hand.read_status()
```

Mock mode — no hardware needed:

```python
hand = RH56Driver.mock()
hand.connect()
hand.read_angle()  # → [0, 0, 0, 0, 0, 0]
```

---

## Protocol

The RH56 uses a private RS-232/RS-485 binary protocol (per user manual V1.08).

| Direction | Frame |
|-----------|-------|
| Host → RH56 | `EB 90` ID Len CMD Payload… Checksum |
| RH56 → Host | `90 EB` ID Len CMD Payload… Checksum |

- All 16-bit data is little-endian.
- Checksum = low 8 bits of the byte sum over everything after the header.
- Implementation: [src/rh56_sdk/protocol.py](src/rh56_sdk/protocol.py).

---

## API

### Connection

`connect()`, `disconnect()`, `is_connected` — built on `pyserial`, transaction-locked.

### Motion

| Method | Description |
|--------|-------------|
| `move_to(frame)` | Write 6-channel frame with validation and limits |
| `move_finger(i, value)` | Single-finger incremental, based on last command frame |
| `set_speed(values)` | 6-channel speed (0–1000) |
| `set_force_threshold(values)` | 6-channel force threshold (0–1000) |
| `stop_motion()` | Emergency stop: zero all speeds, wait for ACK |
| `recover_open_unchecked(confirm=True)` | Emergency open, bypass ACK validation |

### Feedback

`read_angle()`, `read_actuator_position()`, `read_force()`, `read_current()`,
`read_voltage()`, `read_status()`, `read_error()`, `read_temperature()`,
`read_feedback()`.

Each read retries up to 3 times (100 ms timeout, 10 ms interval). Consecutive
failures trigger communication fault detection.

### Fault Handling

| Method / Attribute | Description |
|--------------------|-------------|
| `clear_error()` | Write CLEAR_ERROR=1, re-read STATUS/ERROR to verify |
| `safe_stop` | Auto-set on hardware fault; blocks motion commands |
| `communication_fault` | Set when consecutive read failures reach threshold |
| `miss_count`, `is_stale`, `feedback_age` | Read health status |
| `reset_miss_count()` | Reset the communication fault counter |

### Calibration & Diagnostics

Separated from the driver core — accessed via standalone objects:

```python
from rh56_sdk.calibration import ForceCalibration
from rh56_sdk.diagnostics import RH56Diagnostics

cal = ForceCalibration(hand)
cal.run_official(wait=True, require_confirm=False)   # hardware force calibration
cal.measure_baseline(samples=50)                      # software zero baseline
cal.validate_baseline(tolerance=30)                   # zero validation
cal.get_net_force()                                   # net force (zero offset removed)
cal.save_profile("baseline.json")                     # save calibration profile

diag = RH56Diagnostics(hand)
snapshot = diag.read_feedback_snapshot()              # typed feedback snapshot
diag.characterize_angle_tracking(require_confirm=False)  # angle tracking characterization
```

---

## Exceptions

```
RH56Error
├── RH56ConnectionError
│   └── RH56NotConnectedError
├── RH56ProtocolError
│   ├── RH56ChecksumError
│   └── RH56FrameError
├── RH56SafetyError
│   ├── RH56BusyError
│   ├── RH56ValidationError
│   │   └── RH56ServoLimitError
│   └── RH56HardwareError
│       └── RH56CalibrationError
└── RH56TimeoutError
```

---

## Architecture

```
examples/          ← 15 standalone example scripts
rh56_grasp/        ← high-level grasp control (pre-shape, force-aware close, state machine)
src/rh56_sdk/
├── transport.py   ← serial abstraction (pyserial + mock)
├── protocol.py    ← binary protocol codec
├── safety.py      ← frame validation & clamping
├── driver.py      ← unified public API
├── calibration.py ← force sensor calibration
├── diagnostics.py ← feedback snapshots & characterization
├── configuration.py, constants.py, enums.py, exceptions.py, models.py, registers.py
tests/             ← 43 unit tests, no hardware required
```

Dependency direction: `examples / grasp → driver → protocol / safety → transport`

---

## Safety

- Defaults to conservative limits (thumb flex 200–700). `FACTORY_LIMITS` for full range.
- All writes validated before serial encoding: length (must be 6), type (rejects
  bool/NaN/Inf), range per-finger.
- `safe_stop` auto-engages on hardware fault; blocks subsequent motion until
  `clear_error()` succeeds.
- `recover_open_unchecked` requires `confirm=True` to execute.

---

## Development

```
pytest                     # 43 tests, no hardware required
ruff check .               # lint, line-length=100
mypy src/rh56_sdk          # strict type check
```

CI covers Windows / macOS / Linux, Python 3.10–3.13, with CodeQL and 70%
coverage threshold. Pre-commit hooks are configured (`.pre-commit-config.yaml`).

---

## Examples

| File | Description |
|------|-------------|
| [01_list_ports.py](examples/01_list_ports.py) | Enumerate serial ports |
| [02_connect.py](examples/02_connect.py) | Connect & disconnect |
| [03_open_close.py](examples/03_open_close.py) | Open & close hand |
| [04_single_finger.py](examples/04_single_finger.py) | Single-finger control |
| [05_set_speed.py](examples/05_set_speed.py) | Speed configuration |
| [06_set_force_threshold.py](examples/06_set_force_threshold.py) | Force threshold |
| [07_read_state.py](examples/07_read_state.py) | Read angle/force/status |
| [08_read_feedback.py](examples/08_read_feedback.py) | Composite feedback read |
| [09_move_and_readback.py](examples/09_move_and_readback.py) | Move & readback |
| [10_safety_test.py](examples/10_safety_test.py) | Safety validation |
| [11_diagnostics.py](examples/11_diagnostics.py) | Diagnostic snapshots |
| [13_force_calibration.py](examples/13_force_calibration.py) | Force calibration |
| [14_force_zero_validation.py](examples/14_force_zero_validation.py) | Zero validation |
| [15_angle_tracking_characterization.py](examples/15_angle_tracking_characterization.py) | Angle tracking |
| [16_grasp_controller_demo.py](examples/16_grasp_controller_demo.py) | High-level grasp |

---

## License

MIT — see [LICENSE](LICENSE).

## Disclaimer

This project is an independent Python driver. It is **not** developed by,
affiliated with, endorsed by, or sponsored by **Inspire Robots**
(因时机器人). "RH56" is used solely as a descriptive reference to the
compatible hardware product.

The communication protocols were derived from publicly available documentation
for interoperability purposes. No proprietary software or firmware is distributed.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. Users are
responsible for validating all commands before sending them to physical hardware
and for ensuring compliance with applicable laws.
