Files
ros_contorl/docs/GRIPPER.md
T
arm_dev 04137fb6e5 修复平行夹爪串口通讯问题
今天三次实测都在"首轮咬合结束→张开到 400"之后停住,微抬 Z 3mm 那条
厂家 MoveL 从未下发。日志只写"夹爪 pos 后 8s 未到位(没有 /gripper/states)",
照着去查夹爪开合,方向是错的。

真实原因是串口会话坏了:旧节点从昨天 18:25 一直跑,写命令(FC06)有回显
——ctrl pos=400 有记录、手指也确实张开——读 0x0201 却连续 264 次无应答
(0x0200 和写都有应答)。_on_timer 读失败就 return,一帧状态都不发,
流水线拿不到状态,就在 _shift_flange_z 之前退出了。

改法(都按"读不到要如实说读不到"):

- dh_pgea:串口 EIO/termios 错误从 DhPgeaError 里分出来,单独抛
  DhPgeaBusError。以前 termios.error(5) 从 timer 回调冒出去,整个节点带
  traceback 退出。
- dh_pgea_node:读失败也发 /gripper/states,data 增到 6 个元素,最后一位
  online(1=刚读回,0=离线、前 5 个是旧值);5 元素老消费者不受影响。
  离线时不发 /gripper/joint_states(关节状态没有离线位,不能拿旧开口冒充
  现在的)。EIO 立刻重开串口,连续 30 拍读不到也重开一次,1 秒最多一次。
- pipeline_node:超时不再一律说"未到位",三种情况分开——真没到位 /
  只有离线帧(总线无应答,不是没张开)/ 一帧都没收到(节点没在发)。
- gauge_gripper、operator_gripper_state:离线帧不当有效状态,夹爪页显示
  "总线无应答"。
- gauge_config:登记 unwind_lift_mm 和 unwind_open_permille。这两个键
  上一次只写进了 site.yaml,加载器按"不认识的键"直接拒绝启动
  gauge_assembly 段(test_shipped_site_yaml_s07_step_cannot_deadlock 当时
  是红的)。
- site_io:恢复 7af9e3d 误删的 listed_arms / absolutize_site_paths 等
  (operator_gripper_state 还在导入 listed_arms,操作台夹爪页一导入就
  ImportError)。按 76c9b9c 恢复,只增不减。

实测验收:重启节点后 --cli probe 读回
data=[1.0, 2.0, 9.0, 0.0, 20.0, 1.0],online=1、grip=2(咬住)、pos=9,
0x0201 不再无应答。

单测 931 passed。新增负向用例:离线帧不能被当成有效状态、EIO 必须抛
DhPgeaBusError、夹爪超时不能报成"未到位"。剩余 6 个失败与本次无关
(伺服限速、回调遮蔽、operator_camera_view 直接继承 Node、
site.yaml 缺 screw_stage_depth_mm、臂控制器未激活,以及 parallel_cli
用例因当前有真实夹爪节点占着串口而走了另一条分支)。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 10:10:37 +08:00

84 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 大寰夹爪(PGEA + RGI)
两只爪都走工控机 **USB–RS485 + 官方 Modbus RTU**,不走 Flexiv `Gripper` / Studio `GripperDahuanModbus`。示教器里关掉对应设备,避免抢总线。`run_real.sh` 保持 `load_gripper:=false`。
| 臂 | 型号 | 串口 | 脚本 |
|----|------|------|------|
| 左 89 | PGEA-100-20-W 平行 | `/dev/ttyUSB0` | `run_gripper.sh --arm 89` |
| 右 91 | RGI-100-30-O-S-M1 旋转 | `/dev/ttyUSB1` | `run_gripper.sh --arm 91` |
端口、行程、力/速写在 `site.yaml`:`robots[].gripper`(每臂)+ 全局 `gripper` / `gripper.parallel` / `gripper.rotary`。双爪 ROS 节点读 `robots[]` 两侧。不要改包内 Python 默认值。
源码:`src/arm_application/arm_application/dh_official.py`、`dual_gripper.py`、`dh_pgea.py`。消息:`arm_msgs`(**不要**往官方 `flexiv_msgs` 塞自定义夹爪类型)。
## 命令行
```bash
# 左臂平行爪
bash ~/ros2/scripts/run_gripper.sh --arm 89 --cli probe
bash ~/ros2/scripts/run_gripper.sh --arm 89 --cli init # 写 0xA5 回零;已经 initialized 也会再做一次
bash ~/ros2/scripts/run_gripper.sh --arm 89 --cli open
bash ~/ros2/scripts/run_gripper.sh --arm 89 --cli close
bash ~/ros2/scripts/run_gripper.sh --arm 89 --cli pos 500 # 0=合 1000=开(‰)
# 右臂旋转爪
bash ~/ros2/scripts/run_gripper.sh --arm 91 --cli open
bash ~/ros2/scripts/run_gripper.sh --arm 91 --cli close
bash ~/ros2/scripts/run_gripper.sh --arm 91 --cli rotate 90
bash ~/ros2/scripts/run_gripper.sh --arm 91 --cli revolutions 2
```
PGEA 力/速:`gripper.force_pct`(最低 20)`speed_pct` `open_position` `close_position`。RGI 不要 `auto_init: true`(`robots[]` 里已关)。
平行爪的 `--cli` 在驱动没跑时会先把节点拉起来,再把命令发到 `/gripper/ctrl`。`auto_init` 仍用这一臂在 `site.yaml` 里的值(现场 `false`,不写 `0xA5`,不回零)。串口被别的进程占着时,报的是占用。
## ROS 节点
单爪:
```bash
bash ~/ros2/scripts/run_gripper.sh --arm 89 # /gripper/open /gripper/close
bash ~/ros2/scripts/run_gripper.sh --arm 91 # dual_gripper 仅 right
```
双爪同时:
```bash
bash ~/ros2/scripts/run_dual_gripper.sh
```
| 名称 | 类型 |
|------|------|
| `/dual_gripper_driver/left/command` | `arm_msgs/msg/GripperCommand` |
| `/dual_gripper_driver/right/command` | 同上 |
| `/dual_gripper_driver/left/status` | `arm_msgs/msg/GripperStatus` |
| `/dual_gripper_driver/right/status` | 同上 |
| `/dual_gripper_driver/left/execute` | `arm_msgs/srv/GripperExecute` |
| `/dual_gripper_driver/right/execute` | 同上 |
`command` 字段:`init` `open` `close` `move`;右爪另有 `rotate` `rotate_by` `rotate_revolutions` `home_rotation`。
```bash
ros2 service call /dual_gripper_driver/left/execute arm_msgs/srv/GripperExecute \
"{command: {command: 'open', wait_complete: true, timeout: 10.0}}"
ros2 service call /dual_gripper_driver/right/execute arm_msgs/srv/GripperExecute \
"{command: {command: 'rotate', position: 90.0, wait_complete: true, timeout: 10.0}}"
```
USB 未插齐时节点仍可起来(`allow_offline:=true`),对应侧 `status.error_msg` 会写连接失败。
## `/gripper/states` 的离线帧
`data` 是 6 个元素:
`[initialized, grip_state, position, target_pos, target_force, online]`。
`online=0` 表示这一帧**没读到总线**,前 5 个是上一次读到的值,不是现在的状态。老节点只发 5 个元素(那时它只在读成功时才发),5 元素帧按有效帧处理。
读 `0x0201` 无应答时节点照样发离线帧,`/gripper/joint_states` **不发**:关节状态没有离线位,宁可不发,也不要把上一次的开口当成现在的。
流水线 `_wait_gripper` 只认有效帧;超时没等到有效帧时报「读不到状态(只有离线帧,Modbus 无应答),不是夹爪没张开」,不能再报成「夹爪没到位」——2026-10-20 读 `0x0201` 一连 264 次无应答,实测在张开后停住、微抬没有下发,日志却只写「未到位」。
串口 `EIO`(USB 掉线)抛 `DhPgeaBusError`,节点先关串口再重开(1 秒最多一次),不再整进程带 traceback 退出。没有应答(`DhPgeaError`)先继续重试;连续 `BUS_REOPEN_AFTER_FAILURES=30` 拍都读不到也重开一次——2026-10-20 那次就是写有回显、读一直无应答,重启节点立刻恢复,说明坏的是串口会话。
用户需在 `dialout`:`sudo usermod -aG dialout $USER`。