Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 104 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,109 +8,149 @@
<a href="https://github.com/orcahand/orca_core/actions/workflows/test.yml" target="_blank"><img alt="Tests" src="https://github.com/orcahand/orca_core/actions/workflows/test.yml/badge.svg"/></a>
</div>

Orca Core is the core control package of the ORCA Hand. It's used to abstract hardware, provide scripts for calibration and tensioningm and to control the hand with simple high-level control methods in joint space.
# Orca Core

## Get Started
`orca_core` is the Python control package for the ORCA Hand. The refactored codebase is organized around a small set of explicit objects:

To get started with Orca Core, follow these steps:
- `OrcaHandConfig` loads the static hand description from `config.yaml`.
- `CalibrationResult` loads the mutable runtime state from `calibration.yaml`.
- `BaseHand` provides backend-agnostic joint-space helpers.
- `OrcaHand` adds hardware connection, torque, calibration, telemetry, and maintenance tasks.
- `OrcaJointPositions` is the typed container used for joint-space commands.

1. **Create a virtual environment** (recommended):
The practical workflow is:

```sh
python -m venv venv
source venv/bin/activate
```
1. Choose a model config.
2. Connect to the hardware.
3. Call `init_joints()` to enable torque, apply motor settings, calibrate when needed, and move to neutral.
4. Command joint-space poses through `set_joint_positions(...)`.

You can also use **Poetry**, **pyenv**, **conda**, or any other environment manager if you prefer.
## Install

2. **Install dependencies**:

```sh
pip install -e .
```
```sh
python -m venv .venv
source .venv/bin/activate
pip install -e .
```

3. **Check the configuration file**:
## Quick Start

- Review the config file (e.g., `orca_core/orca_core/models/orcahand_v1_right/config.yaml`) and make sure it matches your hardware setup.
Start by checking the model config you want to use. The bundled models live under:

4. **Run the tension and calibration scripts**:
- `orca_core/models/v2/orcahand_right/config.yaml`
- `orca_core/models/v1/orcahand_right/config.yaml`
- `orca_core/models/v1/orcahand_left/config.yaml`

```sh
python scripts/tension.py orca_core/models/orcahand_v1_right
python scripts/calibrate.py orca_core/models/orcahand_v1_right
```
The refactored code expects `config_path` to point to the `config.yaml` file itself, not just the model directory.
Use the `v2` config as the canonical reference for the current schema. Older `v1` configs may still need the legacy `calib_*` keys renamed to `calibration_*`.

Replace the path with your specific hand model folder if needed.
For a first-time hardware bring-up, the recommended operator flow is:

5. **Move the hand to the neutral position**:
```sh
python scripts/setup.py orca_core/models/v2/orcahand_right/config.yaml
```

```sh
python scripts/neutral.py orca_core/models/orcahand_v1_right
```
If the hand is already assembled and tensioned, the shorter path is:

6. **Example usage: test.py**
```sh
python scripts/calibrate.py orca_core/models/v2/orcahand_right/config.yaml
python scripts/neutral.py orca_core/models/v2/orcahand_right/config.yaml
```

Here is a minimal example script you can use to test your setup:
## Python Usage

```python
from orca_core import OrcaHand
import time
```python
from orca_core import OrcaHand

hand = OrcaHand('orca_core/models/orcahand_v1_right')
status = hand.connect()
print(status)
if not status[0]:
print("Failed to connect to the hand.")
exit(1)
hand = OrcaHand(config_path="orca_core/models/v2/orcahand_right/config.yaml")

hand.enable_torque()
success, message = hand.connect()
if not success:
raise RuntimeError(message)

joint_dict = {
"index_mcp": 90,
"middle_pip": 30,
}
try:
hand.init_joints()

hand.set_joint_pos(joint_dict, num_steps=25, step_size=0.001)
neutral = hand.config.neutral_position
hand.set_joint_positions(
{
"thumb_mcp": neutral["thumb_mcp"] + 10,
"index_mcp": neutral["index_mcp"] + 10,
"middle_mcp": neutral["middle_mcp"] + 10,
},
num_steps=25,
step_size=0.01,
)

time.sleep(2)
hand.disable_torque()
print(hand.get_joint_position().as_dict())
finally:
hand.stop_task()
hand.disconnect()
```
```

### Notes on units

---
- Joint-space values use the same units as `joint_roms` and `neutral_position` in your model config. The bundled hand configs use degrees.
- Low-level motor position telemetry returned by `get_motor_pos()` is in radians.
- Motor current is reported in mA and motor temperature in C.

## Key Scripts

- `scripts/setup.py`: guided tension -> calibrate -> verify workflow.
- `scripts/calibrate.py`: run calibration and persist `calibration.yaml`.
- `scripts/tension.py`: hold the spools in place for tendon tensioning.
- `scripts/neutral.py`: move to the configured neutral pose.
- `scripts/zero.py`: move all configured joints to zero.
- `scripts/record_angles.py` / `scripts/replay_angles.py`: capture and replay waypoint-based motions.
- `scripts/record_continuous.py` / `scripts/replay_continuous.py`: capture and replay continuous trajectories.
- `scripts/slider_joint.py` / `scripts/slider_motor.py`: manual debugging UIs.

## Configuration and calibration files

Each hand model directory contains:

- `config.yaml`: static model and hardware metadata.
- `calibration.yaml`: calibration output written after calibration runs.

The refactored config loader expects canonical calibration keys such as:

- `calibration_current`
- `calibration_step_size`
- `calibration_step_period`
- `calibration_threshold`
- `calibration_num_stable`
- `calibration_sequence`

If you are migrating an older config that still uses `calib_*` keys, rename those fields before using it with the refactored API.

## Troubleshooting

### Serial Port Permissions (Linux)
### Serial port permissions on Linux

On Linux, the serial port (e.g., `/dev/ttyUSB0`) is owned by the `dialout` group. If your user is not in this group, you will get a **permission denied** error and motors won't be detected.
On Linux, the serial port is usually owned by the `dialout` group. If your user is not in that group, the hand may fail to connect.

**Permanent fix** (requires re-login):
Permanent fix:

```sh
sudo usermod -aG dialout $USER
```

**Temporary fix** (resets on reboot/replug):
Temporary fix:

```sh
sudo chmod 666 /dev/ttyUSB0
```

### Serial Port Path

Make sure the `port` field in your `config.yaml` matches your operating system:
### Port mismatch

| OS | Example port |
|-------|---------------------------------|
| Linux | `/dev/ttyUSB0` |
| macOS | `/dev/tty.usbserial-XXXXXXXX` |
`OrcaHand.connect()` first tries the configured port, then attempts USB auto-detection, then falls back to an interactive chooser. If connection succeeds on a different port, the package updates `config.yaml` automatically.

---
## Documentation

**Note:**
- Always ensure your `config.yaml` matches your hardware and wiring.
- All scripts in the `scripts/` folder take the model path as their first argument.
- For more advanced usage, see the other scripts and the API documentation.
The MkDocs site in `docs/` expands on:

---
- hardware setup
- the `config.yaml` schema
- calibration and tensioning workflow
- the package architecture
- the current Python API
36 changes: 30 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
# About Orca
# ORCA Core

## Welcome to the Orca Hand Core Documentation
`orca_core` is the software layer that turns an ORCA Hand model description and calibration state into a controllable hardware interface.

This site provides all the necessary information to get started with Orca Hand Software. Here you'll find instructions covering software of the core API for controlling the hand as well initial instructions for setting everything up.
The codebase is now organized around a few explicit concepts:

Whether you're configuring your first system or extending its capabilities, this documentation is intended to support development and experimentation with the control software.
- `OrcaHandConfig` is the static description of a hand model, loaded from `config.yaml`.
- `CalibrationResult` is the mutable calibration state, loaded from `calibration.yaml`.
- `BaseHand` defines the shared joint-space interface.
- `OrcaHand` is the hardware-backed implementation used for real hands.
- `MotorClient` implementations handle the concrete motor bus protocol.

!!! Info
To ensure the hand functions as intended, we strongly recommend following the official guide on the [ORCA Hand Official site](https://orcahand.com) closely.
If you are new to the project, the shortest useful path through the docs is:

1. Set up the motor chain and choose the right model config.
2. Review the `config.yaml` schema and confirm it matches your hardware.
3. Run the setup or calibration workflow.
4. Use `OrcaHand` for joint-space control.

## What changed in the refactor

The older docs described a more script-centric package and used several outdated names. The current codebase is centered on:

- explicit config and calibration data objects
- a backend-agnostic `BaseHand`
- a hardware-specific `OrcaHand`
- typed joint payloads via `OrcaJointPositions`
- canonical config keys such as `calibration_sequence` instead of `calib_sequence`

## Recommended first steps

- Read the getting-started pages if you are bringing up hardware.
- Read the API page if you are integrating `orca_core` into another Python project.
- Read the repository structure page if you want the high-level architecture before diving into the source.
119 changes: 96 additions & 23 deletions docs/pages/getting-started-docs/initial-tensioning-and-calibration.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,111 @@
# Calibration and Tensioning
# Tensioning And Calibration

## Calibration
This page documents the current maintenance workflow used by the refactored package.

Calibration ensures the hand operates with high accuracy and precision. It should be performed regularly, especially:
## Two files, two roles

- After extended use
- After slack has built up in the tendons
- After tensioning, to restore precision
The bring-up flow depends on two YAML files:

The calibration sequence is defined step-by-step in the `config.py` file, as explained in the [**Setting-up Config**](setting-up-config.md) guide.
- `config.yaml` stores the static hand description and calibration procedure.
- `calibration.yaml` stores the results of running that procedure on a specific physical hand.

**Be careful when modifying calibration steps**, some are intended to run independently and may not function correctly if grouped or reordered.
`OrcaHand` loads both:

## Tensioning
- `OrcaHandConfig` from `config.yaml`
- `CalibrationResult` from `calibration.yaml`

Tendons should be firm (not slack), but **not overtightened**. A small amount of give is acceptable.
## What calibration does

To tension the hand:
`hand.calibrate()` walks through the configured `calibration_sequence`, drives joints toward their mechanical limits, and writes the resulting values back to `calibration.yaml`.

1. Move all servos **fully counter-clockwise (CCW)**. Instead of moving all servos by hand you can also run `tension.py --move_motors` that turns all servos CCW using the calibration current specified in `config.py`.
2. Run the `tension.py` script located in the `scripts` folder. This locks the servos in place and secures the bottom spools.
3. Using the included 3D-printed **ratchet** (found in the spools print file or included in the kit), rotate the **top spool of each servo clockwise** to tighten the tendons.
4. As you turn, you should **hear or feel a "clicking" sound**, this confirms the ratchet is engaged and the tendon is being tensioned.
The stored result includes:

> **Careful:** It’s easy to overtension the tendons when using the ratchet. Overtensioning can interfere with performance. Tighten **only until the tendon feels firm**.
- per-motor lower and upper limits
- per-motor joint-to-motor ratios
- a `calibrated` flag
- a `wrist_calibrated` flag

## Initial Calibration and Tensioning (After Assembly)
Partial progress is written during calibration, so an interrupted run is not fully lost.

When the hand is first assembled, because tendons are spooled by hand, significant slack is introduced. This must be corrected before using the hand for other tasks.
## What `init_joints()` does

Recommended steps:
For most application code, you should prefer:

1. Run calibration (for all joints). Significant slack will accumulate during this step, this is expected, and calibration may seem ineffective at first.
2. Perform the tensioning procedure as described above.
3. Repeat steps 1 and 2 **1-2 more times**, or until **no additional slack** appears after calibration completes.
```python
hand.init_joints()
```

This ensures the tendons are properly tensioned and the hand is correctly calibrated.
instead of manually calling each bring-up step.

`init_joints()`:

1. enables torque
2. applies the configured control mode
3. applies the configured current limit
4. calibrates if the hand is not yet calibrated
5. computes wrap offsets
6. moves to neutral

## Recommended workflow after assembly

The easiest operator path is the guided script:

```sh
python scripts/setup.py orca_core/models/v2/orcahand_right/config.yaml
```

That workflow repeats tensioning and calibration with motion checks in between.

## Manual workflow

If you want to run the steps yourself:

1. Tension the hand:

```sh
python scripts/tension.py orca_core/models/v2/orcahand_right/config.yaml --move_motors
```

2. Run calibration:

```sh
python scripts/calibrate.py orca_core/models/v2/orcahand_right/config.yaml
```

3. Move to neutral:

```sh
python scripts/neutral.py orca_core/models/v2/orcahand_right/config.yaml
```

## Tensioning guidance

The goal is to remove slack without overtightening.

Typical procedure:

1. Use `tension.py --move_motors` to drive the spools into a useful starting state.
2. Let `tension.py` hold the motors in place.
3. Tighten the top spools gradually with the mechanical tool.
4. Stop as soon as the tendons feel firm and consistent.

Too much tension can hurt motion quality and calibration quality.

## When to recalibrate

Run calibration again when:

- the hand has been re-strung
- tendon slack has changed noticeably
- the wrist has been serviced
- joint tracking no longer matches expectation

## Wrist calibration behavior

The wrist is handled slightly differently:

- wrist calibration status is tracked separately
- `--force-wrist` can force wrist recalibration
- if wrist steps are missing from the sequence, the code can append them when needed

This lets you skip unnecessary wrist passes during routine finger recalibration while still supporting a full bring-up when required.
Loading