P5c-5 触觉链路打通:接触传感器此前是"完全静默失效",已定位并修复
两条独立的静默坑,都不报错、不告警,只会"永远收不到数据":
1) world 里没声明 contact-system 系统插件。
gz-sim 的 <sensor type="contact"> 不由 ignition-sensors 库实现,而是由
ignition-gazebo6-contact-system 插件实现 —— 所以环境里根本没有
libignition-sensors6-contact.so(相机/IMU/lidar 的后端都在,唯独缺它),
那不是包缺失。不声明插件的症状:话题不出现、日志空白。
实测:加上插件后 /tactile/left/raw、/tactile/right/raw 立刻出现。
2) 接触传感器的三个必备写法,错一个就静默失效:
- <contact><collision> 必须写 URDF→SDF 自动生成的 collision 名;
留空 <contact/> 会被补成 SDF 规范的默认值 __default__(不存在的
collision)。实测生成名:
sim_left_finger_mount_fixed_joint_lump__sim_left_finger_tip_collision
- 话题必须写在 <contact><topic> 里,写在外层 <sensor><topic> 无效,
gz 会静默改用默认 scoped 话题名。
- 传感器必须挂在有碰撞体的 link 上(指尖),不是另建的空 link。
两处均已按实测结果修正,并把"为什么这么写"写进文件注释。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -131,55 +131,70 @@
|
|||||||
=======================================================================
|
=======================================================================
|
||||||
真机上是视触觉:一块弹性体 + 内置相机,读出三向力、深度图、力矢量图。
|
真机上是视触觉:一块弹性体 + 内置相机,读出三向力、深度图、力矢量图。
|
||||||
仿真里没法真的模拟弹性体形变成像,采取的务实方案是:
|
仿真里没法真的模拟弹性体形变成像,采取的务实方案是:
|
||||||
用 Gazebo 内置的 contact sensor 取接触点的三向力,
|
用 Gazebo 内置的 contact sensor 取接触处的真实接触力,
|
||||||
再由自定义插件(devices/sim/gazebo/sensor_plugins/)把它
|
再由 sim_tactile_adapter 把力投影到指尖坐标系,
|
||||||
按 Orisys 的 TactileStatus 消息格式发布出去,
|
按 Orisys 的 TactileStatus 消息格式发布出去。
|
||||||
含切向/法向分解,使 P6 的力判据在仿真里可跑。
|
|
||||||
|
|
||||||
这里只挂 contact sensor 与自定义插件的位置占位;
|
⚠️ 这里**不再**新建空的 tactile link。
|
||||||
插件的实现与消息映射在 P5c-5 完成。
|
曾经的做法是建两个空的 sim_tactile_*_link(既无 visual 也无
|
||||||
|
collision),挂在 **法兰** 的 tcp 上(不是指尖),而 <contact> 里
|
||||||
|
又引用了一个 <collision>sim_tactile_left_link_collision</collision>
|
||||||
|
—— 那个 collision 元素根本不存在。三重错叠在一起,
|
||||||
|
结果是传感器**永远收不到任何数据**,而 Gazebo 不会为此报任何错:
|
||||||
|
话题在、没有输出、看起来像"还没接触"。极难查。
|
||||||
|
这也正是把传感器挂到真实碰撞体所在的 link(指尖)上的理由 ——
|
||||||
|
"接触到的就是读到的",中间不再有需要对齐的第二套几何。
|
||||||
|
|
||||||
为什么要挂两个(left/right):
|
为什么要挂两个(left/right):
|
||||||
真机是双指各贴一片,tangential_1/2 + normal 三路力分别来自两片,
|
真机是双指各贴一片,tangential_1/2 + normal 三路力分别来自两片,
|
||||||
单指的数据无法复现"旋拧时切向力从哪一侧来"这个判据。
|
单指的数据无法复现"旋拧时切向力从哪一侧来"这个判据。
|
||||||
|
|
||||||
|
⚠️ 单位不是牛顿!真机读数是**形变任意单位**、基线会漂移,
|
||||||
|
所有阈值都按"相对静止均值的增量"使用(见
|
||||||
|
devices/sensors/orisys/manifest.yaml)。仿真给的是牛顿,
|
||||||
|
所以两者的数值**不能直接共用阈值** —— 标度换算由
|
||||||
|
config/tactile.yaml 的 force_scale 负责,详见该文件与 README。
|
||||||
======================================================================= -->
|
======================================================================= -->
|
||||||
<xacro:if value="${tactile_enable}">
|
<xacro:if value="${tactile_enable}">
|
||||||
<link name="${prefix}tactile_left_link"/>
|
<gazebo reference="${prefix}left_finger_tip">
|
||||||
<link name="${prefix}tactile_right_link"/>
|
|
||||||
|
|
||||||
<joint name="${prefix}tactile_left_joint" type="fixed">
|
|
||||||
<parent link="${prefix}tcp"/>
|
|
||||||
<child link="${prefix}tactile_left_link"/>
|
|
||||||
<origin xyz="0 0.035 0.005" rpy="0 0 0"/>
|
|
||||||
</joint>
|
|
||||||
<joint name="${prefix}tactile_right_joint" type="fixed">
|
|
||||||
<parent link="${prefix}tcp"/>
|
|
||||||
<child link="${prefix}tactile_right_link"/>
|
|
||||||
<origin xyz="0 -0.035 0.005" rpy="0 0 0"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<gazebo reference="${prefix}tactile_left_link">
|
|
||||||
<sensor name="tactile_left" type="contact">
|
<sensor name="tactile_left" type="contact">
|
||||||
<always_on>true</always_on>
|
<always_on>true</always_on>
|
||||||
<update_rate>100</update_rate>
|
<update_rate>100</update_rate>
|
||||||
<!-- 话题名与真机 tactile_node 发布的完全一致:
|
|
||||||
/tactile/left/status (arm_msgs/TactileStatus)
|
|
||||||
这样 P6 的状态机在仿真/真机之间不用改一行判断。 -->
|
|
||||||
<contact>
|
<contact>
|
||||||
<collision>${prefix}tactile_left_link_collision</collision>
|
<!-- ⚠️ 这个名字不是我们起的,是 sdformat 从 URDF 转 SDF 时**自动生成**的:
|
||||||
|
规则 =「fixed 关节链的父 link」+ "_fixed_joint_lump__" +「本 link」
|
||||||
|
+ "_" + collision 名。本机实测生成名(2026-09-23,Fortress 6.16):
|
||||||
|
sim_left_finger_mount_fixed_joint_lump__sim_left_finger_tip_collision
|
||||||
|
|
||||||
|
为什么不得不写死一个"自动生成的名字"(很脆,但有理由):
|
||||||
|
a) URDF 的 <collision> 不能命名,所以没法给它一个稳定名字;
|
||||||
|
b) 留空 <contact/> 不会"监测全部",而是被补成 SDF 规范的默认值
|
||||||
|
`collision=__default__` —— 一个不存在的 collision。
|
||||||
|
症状是传感器**永远没有输出**,gz 不报错、话题也不出现。
|
||||||
|
已实测确认(这是本节最大的一条坑)。
|
||||||
|
所以只能写死,并用启动检查兜住改名:
|
||||||
|
robot_description.check_tactile_collisions() 会把展开后的
|
||||||
|
URDF 转成 SDF,核对这两个名字是否存在 —— 一旦 sdformat 改了命名
|
||||||
|
规则,启动时就会明确报错,而不是静默失效。 -->
|
||||||
|
<collision>${prefix}left_finger_mount_fixed_joint_lump__${prefix}left_finger_tip_collision</collision>
|
||||||
|
<!-- ⚠️ 话题必须写在**这里**(contact/topic),不能写在外层的
|
||||||
|
<sensor><topic> 里 —— 接触传感器只认 contact/topic。
|
||||||
|
写错位置不会报错:gz 会静默改用默认的 scoped 话题名
|
||||||
|
/world/<world>/model/<model>/link/<link>/sensor/<sensor>/contact
|
||||||
|
于是"按 /tactile/left/raw 去订阅"永远收不到东西。实测确认。 -->
|
||||||
|
<topic>/tactile/left/raw</topic>
|
||||||
</contact>
|
</contact>
|
||||||
<topic>/tactile/left/raw</topic>
|
|
||||||
</sensor>
|
</sensor>
|
||||||
</gazebo>
|
</gazebo>
|
||||||
|
|
||||||
<gazebo reference="${prefix}tactile_right_link">
|
<gazebo reference="${prefix}right_finger_tip">
|
||||||
<sensor name="tactile_right" type="contact">
|
<sensor name="tactile_right" type="contact">
|
||||||
<always_on>true</always_on>
|
<always_on>true</always_on>
|
||||||
<update_rate>100</update_rate>
|
<update_rate>100</update_rate>
|
||||||
<contact>
|
<contact>
|
||||||
<collision>${prefix}tactile_right_link_collision</collision>
|
<collision>${prefix}right_finger_mount_fixed_joint_lump__${prefix}right_finger_tip_collision</collision>
|
||||||
|
<topic>/tactile/right/raw</topic>
|
||||||
</contact>
|
</contact>
|
||||||
<topic>/tactile/right/raw</topic>
|
|
||||||
</sensor>
|
</sensor>
|
||||||
</gazebo>
|
</gazebo>
|
||||||
</xacro:if>
|
</xacro:if>
|
||||||
|
|||||||
@@ -221,6 +221,40 @@
|
|||||||
<render_engine>ogre2</render_engine>
|
<render_engine>ogre2</render_engine>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
<!-- =========================================================================
|
||||||
|
接触系统插件(触觉传感器必需)
|
||||||
|
=========================================================================
|
||||||
|
⚠️ 这是本项目踩得最深的一个坑,务必看懂:
|
||||||
|
|
||||||
|
**gz-sim 里的 `<sensor type="contact">` 不是由 ignition-sensors 库
|
||||||
|
实现的,而是由这个 contact-system 系统插件实现的。**
|
||||||
|
所以 conda 环境里根本不存在 libignition-sensors6-contact.so
|
||||||
|
(相机/IMU/lidar 的后端都在,唯独没有 contact)—— 那不是包缺失,
|
||||||
|
而是接触本来就不归 sensors 库管。
|
||||||
|
|
||||||
|
不声明它的后果是**彻底静默**:
|
||||||
|
- 传感器永远不会被创建
|
||||||
|
- /tactile/left/raw 话题不出现(连空消息都没有)
|
||||||
|
- Gazebo 日志里**什么都不打**:没有 error、没有 warn
|
||||||
|
- 看起来就像"还没接触到东西",而实际上永远不会接触到
|
||||||
|
|
||||||
|
实测确认方式(2026-09-23):
|
||||||
|
ign topic -l | grep tactile # 不声明时:无任何输出
|
||||||
|
# 加上下面这行插件后立刻出现 /tactile/left/raw 与 /tactile/right/raw
|
||||||
|
|
||||||
|
⚠️ 另外两个必须同时满足的条件(否则一样是静默失效):
|
||||||
|
1. `<contact><collision>` 里写的是 **URDF 转 SDF 后自动生成的 collision 名**
|
||||||
|
(URDF 无法给 collision 命名),例如
|
||||||
|
sim_left_finger_mount_fixed_joint_lump__sim_left_finger_tip_collision
|
||||||
|
留空 `<contact/>` 不会"监测全部",而是被补成 SDF 规范的默认值
|
||||||
|
`__default__`(一个不存在的 collision)。启动检查
|
||||||
|
robot_description.check_tactile_collisions() 会核对这两个名字,
|
||||||
|
一旦 sdformat 换了命名规则就明确报错。
|
||||||
|
2. 传感器必须挂在**有碰撞体的那个 link** 上(指尖),不是另建空 link。
|
||||||
|
========================================================================= -->
|
||||||
|
<plugin filename="libignition-gazebo6-contact-system.so"
|
||||||
|
name="ignition::gazebo::systems::Contact"/>
|
||||||
|
|
||||||
<!-- =========================================================================
|
<!-- =========================================================================
|
||||||
RealSense D435 —— 眼在手外(俯视工作台)
|
RealSense D435 —— 眼在手外(俯视工作台)
|
||||||
=========================================================================
|
=========================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user