今天三次实测都在"首轮咬合结束→张开到 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>
4.4 KiB
大寰夹爪(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 ~/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 ~/ros2/scripts/run_gripper.sh --arm 89 # /gripper/open /gripper/close
bash ~/ros2/scripts/run_gripper.sh --arm 91 # dual_gripper 仅 right
双爪同时:
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。
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。