Calibration and self-check¶
This page covers two one-off jobs: calibrating the leader gripper's zero and travel, and confirming the Pico4U tracker chain is live. Check the whole chain with the preview before recording.
Gripper calibration (zero + travel)¶
When you need it¶
gripper.pos is a normalized opening: 0.0 is fully closed, from the encoder zero latched in calibration step 1; 1.0 is fully open, from the travel maximum written in step 2 (command set ≥ V2.1). Both values live in MCU flash and survive power cycles and collection PC changes. Two situations call for calibration:
| Situation | How it shows | Who catches it |
|---|---|---|
| Never calibrated | The collection program refuses to connect to the leader gripper, with the calibration command in the error | The program; you cannot miss it |
| Calibrated, but the stored value no longer matches the real travel (the encoder was refitted, a mechanical limit moved, or the firmware was erased) | It connects, but gripper.pos does not reach 1.0 at the mechanical limit |
Only you, in the preview; see Confirm it took effect |
The first case's error:
This leader gripper has no encoder-max calibration, so its jaw travel is unknown
and gripper.pos cannot be computed (...).
Calibrate it once, then re-run:
python third_party/taccap-gripper/python/examples/calibrate.py <left|right>
Calibrating one side of a bimanual setup is worse than calibrating neither
Calibrating one side leaves left_gripper.pos and right_gripper.pos on different scales: the same grip reads differently on each side, and the data does not show it. If you calibrate, calibrate both sides.
How to calibrate¶
Run once per unit (the path is relative to the xense-taccap-lerobot workspace; in the SDK repository it is python/examples/calibrate.py):
python third_party/taccap-gripper/python/examples/calibrate.py left
python third_party/taccap-gripper/python/examples/calibrate.py right
- Side: read from the firmware SN (via
Cmd::GetSn, not the CH343 chip serial), the same rule collection uses, socalibrate.py leftalways calibrates theleftunit. - Check: the script prints the resolved firmware SN and every gripper the scan saw; two units on the same side raise an error listing both SNs.
- Pin a unit: pass its firmware SN directly (
calibrate.py TCGU01A28Z0024m; that SN is an example).
On firmware that is too old, the script exits and changes nothing:
✗ encoder-max calibration needs command set >= V2.1 (leader >= 1.2.0); this gripper reports 1.1.0.
Nothing was changed. Flash it first: ...
Flash first per Firmware OTA upgrade: the image is chosen by role, and update the SDK before the firmware.
Once the version passes, the script prints the current reading (raw and clamped); follow the two prompts:
- Fully closed → Enter. It sends
SetEncoderZeroto latch the zero, then re-reads to verify the residual (tolerance ±0.01rad). - Fully open to the mechanical limit → Enter. The angle goes straight into
EncoderMaxCalin MCU flash, with no second confirmation; a 10Hz live readout follows for checking.
Get the fingers in position first, then press Enter
The firmware latches the raw count the instant it receives the command; moving the fingers afterwards invalidates the calibration.
Output looks like:
================================================================
TacCap leader-gripper encoder calibration
================================================================
requested : left (resolved by side)
firmware SN : TCGU01A28Z0031m
side : Left
mcu serial : 5C96089694
mcu device : /dev/serial/by-id/usb-1a86_USB_Dual_Serial_5C96089694-if02
visible : TCGU01A28Z0032m (Right), TCGU01A28Z0031m (Left)
Step 1/2: hold the gripper FULLY CLOSED.
→ press [Enter] when held closed:
post-latch reading: raw=+0.0058 rad (+0.33°) cooked=+0.0058
✓ zero latched OK (|raw post-zero| ≤ 0.010 rad)
Step 2/2: open the gripper to its MECHANICAL LIMIT.
→ press [Enter] when fully open:
fully-open reading: +1.1486 rad (+65.81°)
✓ stored: max_rad = 1.1486 rad (65.81°)
A previously calibrated unit gets an extra existing span: … — will be overwritten header line.
- Closed is always 0: there is no
gripper_closed_radconfig; negative drift is clamped to 0 (the raw value stays inraw_position_rad), and beyond -0.1rad it triggers a rate-limited warning. - Fields:
position_radis still raw radians; normalization only adds apositionfield.
Confirm it took effect¶
First, the startup log prints this as each side connects:
If that line is missing, there is no need to check further: an uncalibrated leader does not connect, and the program exits with the calibration command in the error.
Second, the curve in Rerun. Run with --display_data=true and find gripper.pos in the scalar panel:
| Action | Expected |
|---|---|
| Fully open | reaches 1.0 |
| Fully closed | drops to 0.0 |
Well below 1.0 when fully open → recalibrate that unit
If fully open fingers only reach around 0.8, the travel maximum in flash no longer matches the real travel, and the program does not report an error. Recalibrate with the same command.
Scope¶
- Leader only: the leader has no auto-calibration, so this cannot be skipped. The follower rejects the command; since V1.9 it auto-calibrates at power-on (close to stall for the zero, open to stall for the travel maximum), and its
gripper.posis normalized bygripper_open_rad. - Firmware: command set ≥ V2.1 (that is leader ≥ 1.2.0 / follower ≥ 1.1.0, the difference); on older firmware the leader errors out at collection time and asks for the OTA, see Firmware OTA upgrade.
Pico4U tracker self-check¶
The tracker needs no calibration, and its side is matched from the SN; binding is in Binding the tracker to the headset. The command below only reads: it prints the pose to confirm the chain and the assembly.
python -m lerobot.robots.taccap_gripper.check_tracker
# Pin a specific tracker SN (like PC2310MLL3200496G):
python -m lerobot.robots.taccap_gripper.check_tracker <tracker SN>
# Convert to that side's gripper tip:
python -m lerobot.robots.taccap_gripper.check_tracker --side right
Prints raw (the tracker's own pose) and ee (the gripper tip pose) at 10Hz. Wave the gripper: raw xyz should change smoothly and the SN should match (Reading a tracker SN).
- Mount transform: the tracker-to-gripper-tip transform is built in, one per side, with nothing to set;
--sidepicks which side to apply, and without iteeequalsraw. - Pivot check: rest the midpoint of the two fingers on a fixed point and turn the handle;
ee xyzshould barely move whileraw xyzchanges widely. - Rerun: add
--display_data=truewhen you preview before recording to see gripper data and tracker poses together.
Next → Data collection.