Skip to content
Merged
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
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [0.4.3] - 2026-10-10

_The `v0.4.3` tag was moved on 2026-10-18 to include the EL05 motor OTA
fix and docs below; the version number is unchanged._

### Fixed

- **`motor_ota_update.py` mis-read EL05 images.** EL05 versions have five
parts (`1.0.5.0.4`); the example kept four and compared the motor's raw
bytes (`10.5.0.4`), so a good flash was reported as a mismatch. It now
parses five-part versions and compares the vendor spelling.
- **Force-position could not close a left-hand RS00 follower to 0.0.** Root
cause (0089s, diagnostic firmware, 2026-10-10): a RobStride motor takes an MIT
motion frame whose byte 0 equals its own CAN ID for another command and
Expand All @@ -26,6 +33,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **`motor_ota_update.py` runs as two passes of the same command**: the first
switches the motor to its private protocol, the second (after a 24 V power
cycle) flashes, verifies, records the version in the follower (0x5C) and
switches back to MIT. The version is recorded only after the motor confirmed
it, or blind when the motor returned to MIT by itself (RS00). `--to-mit`
switches back without flashing.
- **The motor OTA sets the motion envelope to the motor's rating** when it
differs (`ensure_envelope()`); travel calibration and open direction are
kept. `--keep-envelope` skips it.
- **`docs/MOTOR_OTA.md`** (and `MOTOR_OTA-zh.md`): customer guide to updating
the motor firmware over USB-C.
- **RS00 followers use motor CAN ID 17 (left) / 18 (right).**
`detail::expected_motor_can_id(model_id, side)` (Python
`expected_motor_can_id`) is the rule; `FollowerGripper` warns on open when the
Expand All @@ -49,6 +67,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **Chinese documents are named `<NAME>-zh.md`.** `README_CN.md` is now
`README-zh.md` and `docs/USAGE_CN.md` is `docs/USAGE-zh.md`; links inside the
repository are updated. English files stay authoritative.
- Shipped follower image is now **1.2.16** (was 1.2.14 in 0.4.2; leader
unchanged at 1.2.6). It carries 1.2.15: an RS00's open direction follows the
side in its firmware SN, auto-calibration corrects a stored direction that
Expand Down
2 changes: 1 addition & 1 deletion README_CN.md → README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ python python/examples/follower_status.py left

## 文档

- [docs/USAGE_CN.md](docs/USAGE_CN.md)([English](docs/USAGE.md))—— 夹爪、腕部相机、视触觉传感器的完整上手流程
- [docs/USAGE-zh.md](docs/USAGE-zh.md)([English](docs/USAGE.md))—— 夹爪、腕部相机、视触觉传感器的完整上手流程
- [docs/INSTALL.md](docs/INSTALL.md) —— 构建选项、纯 C++ 构建、环境陷阱
- [docs/CALIBRATION.md](docs/CALIBRATION.md) —— 编码器零点、行程、鱼眼内参
- [docs/EXAMPLES.md](docs/EXAMPLES.md) —— 每个示例脚本与控制器参数
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# taccap-gripper

[中文](README_CN.md)
[中文](README-zh.md)

C++17 / Python SDK for the **TacCap-Gripper**, XenseRobotics' multimodal tactile
data-collection gripper. One namespace: `xense::taccap::` in C++,
Expand Down Expand Up @@ -345,7 +345,8 @@ looking healthy while it drops status frames.
`FollowerGripper` refuses followers below firmware 1.2.5. Leader and follower
firmware are versioned independently. Required motor firmware: EL05 ≥ 1.0.5.0.4,
RS00 ≥ 0.0.3.32. Image table, motor model, RS00 setup and motor OTA:
[firmware/README.md](firmware/README.md).
[firmware/README.md](firmware/README.md). Step-by-step motor firmware update:
[docs/MOTOR_OTA.md](docs/MOTOR_OTA.md) ([中文](docs/MOTOR_OTA-zh.md)).

### Checking versions

Expand Down Expand Up @@ -378,8 +379,9 @@ Logs: every process writes a DEBUG log to `~/.taccaplogs/session_*.log`

## Documentation

- [docs/USAGE.md](docs/USAGE.md) ([中文](docs/USAGE_CN.md)) — end-to-end bring-up of gripper, wrist camera and tactile sensor
- [docs/USAGE.md](docs/USAGE.md) ([中文](docs/USAGE-zh.md)) — end-to-end bring-up of gripper, wrist camera and tactile sensor
- [docs/INSTALL.md](docs/INSTALL.md) — build options, C++-only builds, environment traps
- [docs/MOTOR_OTA.md](docs/MOTOR_OTA.md) ([中文](docs/MOTOR_OTA-zh.md)) — updating the follower's motor firmware over USB-C
- [docs/CALIBRATION.md](docs/CALIBRATION.md) — encoder zero, travel span, fisheye intrinsics
- [docs/EXAMPLES.md](docs/EXAMPLES.md) — every example script and controller parameter
- [firmware/README.md](firmware/README.md) — firmware images, flashing, motor setup
Expand Down
152 changes: 152 additions & 0 deletions docs/MOTOR_OTA-zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# 升级从夹爪的电机固件

> 本文是 [MOTOR_OTA.md](MOTOR_OTA.md) 的中文版,以英文版为准。

从夹爪里的 RobStride 电机运行着自己的固件,和夹爪主控(MCU)的固件是两套。本文介绍如何用
`python/examples/motor_ota_update.py`,通过夹爪的 USB-C 线升级电机固件。电机不需要拆下来。

| 电机 | 电机固件要求 |
| --- | --- |
| EL05 | ≥ 1.0.5.0.4 |

## 开始之前

- **夹爪固件 1.2.16**(升级电机至少需要 1.2.8)。用 `follower_status.py` 查看,看 `[fw]`
那一行。如果版本较旧,先用 `ota_update.py` 升级夹爪固件并断电重启。升级夹爪固件会把电机切回
常规协议,所以必须先升级夹爪、再升级电机,顺序不能反。
- **SDK 0.4.3 或更新版本**,并且 `import xense.taccap` 能正常导入。
- **我们提供的电机固件镜像**,例如 `EL05_1.0.5.0.4.bin`。请保持原文件名:脚本会从文件名读出
电机型号和版本,并与镜像内容和夹爪记录核对。
- **没有别的程序在使用夹爪。** 先停掉你自己的程序。
- **两指之间清空。** 每次断电重启后,夹爪会自动开合一次做标定。

下文的"断电重启"一律指:拔下夹爪的 **24V 电源线**,等约 2 秒再插回。USB 线可以不拔,夹爪主控和
电机都由 24V 供电。

## 为什么同一条命令要运行两遍

我们的 SDK 让电机工作在 **MIT 协议**下。电机只在**私有协议**下接受固件升级,而切换协议要到下次
上电才生效。所以一次升级的过程是:

1. 运行脚本:脚本把电机切到私有协议;
2. 断电重启;
3. 再运行一遍同样的命令:脚本刷写固件、核对版本、把新版本记进夹爪,如果运动安全包络和电机额定值
不一致就顺带改正,最后把电机切回 MIT;
4. 断电重启。

私有协议只在升级时使用。全部完成后夹爪回到 MIT,可以正常使用。

## 操作步骤

下面以左侧从夹爪为例;右侧用 `right`,或者用完整序列号(例如 `TCGU01A25Z0017s`)指定。

### 1. 查看当前状态

```bash
python python/examples/follower_status.py left
```

看 `[fw]`(夹爪固件)和 `[motor fw]`(电机固件)两行。此时电机固件可能显示读不到:电机在 MIT 下、
且夹爪里还没有记录时就是这样,属于正常现象。

### 2. 第一遍:切到私有协议

```bash
python python/examples/motor_ota_update.py EL05_1.0.5.0.4.bin left
```

```text
=== motor OTA, step 1 of 2 ===
the motor is on the MIT protocol and does not answer OTA frames there,
so it has to be switched to its private protocol first.
Switch the motor to the private protocol? type 'yes': yes

done. Now unplug the gripper's 24 V power cable for ~2 s and plug it back (USB may stay in),
wait ~10 s, then run the same command again to flash.
```

**断电重启**,等约 10 秒。私有协议下电机保持不使能,夹爪不会做标定,这是正常的。

### 3. 第二遍:刷写

```bash
python python/examples/motor_ota_update.py EL05_1.0.5.0.4.bin left
```

```text
=== motor OTA, step 2 of 2 ===
gripper : TCGU01A25Z0017s firmware FirmwareVersion(1.2.16.0)
motor : EL05 can_id 1 uid ...
motor fw now : 1.0.5.0.2
image : EL05_1.0.5.0.4.bin
92,584 B, 11,573 packs, version 1.0.5.0.4
envelope : at the motor's rating, unchanged
Flash the MOTOR with this image? type 'yes': yes
[########################################] 100.0% 11,573/11,573
=== done in 28s; waiting for the motor ===
motor fw : 1.0.5.0.2 -> 1.0.5.0.4
recorded : motor fw 1.0.5.0.4 in follower flash
switched the motor back to the MIT protocol.

Done. Now unplug the gripper's 24 V power cable for ~2 s and plug it back (USB may stay in);
the gripper auto-calibrates (~10 s, keep the jaws clear) and is ready to use.
```

刷写大约需要半分钟。开始时出现 `motor OTA start: no reply (attempt 1/6)` 这类警告是正常的:
电机要先重启进 bootloader,之后的某次重试才会应答。

**运动安全包络。** 如果夹爪里存的运动安全包络(力矩和过热保护)和电机额定值不一致,脚本会在刷写
之后把它改成额定值(EL05:cont 1.1 / peak 1.8 N·m),并在你确认刷写前提示:

```text
envelope : stored cont 1.000 / peak 2.000 N*m, will be set to cont 1.100 / peak 1.800 after flashing
```

行程标定和开合方向保持不变。加 `--keep-envelope` 可以不改包络。

### 4. 断电重启并确认

**断电重启**,等夹爪标定完(约 10 秒),然后运行:

```bash
python python/examples/follower_status.py left
```

`[motor fw]` 应显示新版本,例如 `MotorVersion(1.0.5.0.4, flash: host-written)`。版本已经记在
夹爪里,之后在 MIT 下也能直接读到。

## 出现问题时

| 现象 | 处理方法 |
| --- | --- |
| `cannot tell the motor model from ...` | 镜像文件被改了名。恢复原文件名,或加 `--model EL05`。 |
| `this gripper records a ... motor, the image is for ...` | 镜像对应的是另一种电机型号。不要强行刷写,请联系我们。 |
| `follower firmware ... lacks the 0x5B relay` | 先升级夹爪固件(见"开始之前")。 |
| `motor OTA ...: no reply after N attempts` | 断电重启后再运行一遍同样的命令。中断的升级会从头开始,电机不会损坏。 |
| 刷写后提示 `!! expected ...` | 断电重启后再运行一遍同样的命令。 |
| 脚本中途停止,之后夹爪不再标定 | 电机还停在私有协议。运行 `python python/examples/motor_ota_update.py --to-mit left`,再断电重启。 |

不刷写、只把电机切回 MIT:

```bash
python python/examples/motor_ota_update.py --to-mit left
```

然后断电重启。

## 在自己的代码里调用

这个脚本只是对 `xense.taccap.MotorOtaSession` 的简单封装:

```python
import xense.taccap as t

g = t.FollowerGripper(t.find_left().mcu_device)
m = g.motor
# the motor must already be on the private protocol (see step 2)
session = t.MotorOtaSession(m, m.get_can_id())
session.preflight("EL05") # private protocol + recorded model
session.update_from_file("EL05_1.0.5.0.4.bin", lambda done, total: None)
m.set_motor_fw_version("1.0.5.0.4") # record it for MIT reads
m.switch_protocol(t.MotorProtocol.Mit) # then power-cycle
```
Loading
Loading