P5c-6 场景物料落地 + Gazebo 中文手册:工件/通止规模型、场景校验、两处静默失效修复
一、场景物料(新增)
devices/sim/gazebo/models/workpiece/ 带三个孔的铝板。碰撞体是"带方孔的平板",
视觉额外加两个 φ14/φ7 亮环 —— 因为真机的 HoughCircles 就是靠这两个亮环找孔,
只按碰撞体建视觉会让"孔检测"在仿真里永远失败,而那看起来像算法问题。
devices/sim/gazebo/models/gauge/ 通止规:通端/套环/握柄/止端四段,各段异色
便于肉眼判断方向。接触刚度刻意比台面软 —— 位置控制器会"刚性压进去",
用默认刚度会被弹飞(注释里写了原因,不是随手抄的参数)。
devices/sim/gazebo/models/gauge_stand/ 规座(static)。规直接站在台面上会立刻倒,
加个方孔底座把它立住。
三个模型都是 model.sdf + model.config,原点在**底面中心**,单位米。
二、场景配置与校验(新增)
config/scene.yaml 物体不再写死在 world 里,改为 scene.yaml + 启动时动态 spawn。
理由:world 是"环境"(地面/台面/相机/系统插件),场景是"这一批活做什么"。
动 world 的风险面太大 —— 它只要丢一个系统声明,所有模型都 spawn 不进去(见旧坑 2)。
含 operating(相机到工件的距离等作业条件)与 gates_px(像素门槛)。
sim_scene.py 摆放校验:从 SDF **逐碰撞体**解析 AABB(不抄尺寸,避免漂移),
检查原点在底面 / 不穿台面 / 不出界 / 物体之间不嵌入。
重叠判定必须逐碰撞体三维判,不能拿总包围盒相交 ——
正常装配里本来就有嵌套(规立在规座方孔里),粗判会误报,
而误报的后果是人把检查整个关掉,之后真重叠也抓不到。
另有成像几何:把亮环/孔间距按相机距离换算成像素,与门槛比对。
scripts/check_sim_scene.py 验收工具(退出码可用):摆放 + 门槛漂移 + 成像几何 +
悬停高度 vs 工作空间 + 手外相机是否**完整**看得见工件 + Gazebo 实际位姿。
三、修掉两处静默失效(都是"看起来一切正常")
1) parse_spawned_poses 一直是**死代码**:它按 "x: N / y: N / z: N" 解析,
而 Fortress 实际输出是方括号两行(XYZ / RPY)。对不上 → 永远返回空 →
调用方按设计"降级成跳过位姿核对" → 位姿检查**从来没跑过**,
而日志只说"跳过",看起来像正常降级。
现在两种格式都支持,并用真实抓下来的输出样本做回归测试。
教训:宽容降级会把"没检查"伪装成"检查通过"。
2) stop_sim_gz.sh 的模式表里漏了 robot_state_publisher(而注释里写着它有覆盖):
脚本报"已停止",它却还在发上一份 /robot_description 与 TF,
下一次启动就会"改了描述却不生效"。
顺带修掉同源的两个问题:awk 用 -v 传模式导致它匹配到自己、每次复查都多报
一个空命令行的幽灵 PID;以及"杀的时候"和"复查的时候"两份扫描实现会各自漂移。
现在共用同一个 scan_pids(),模式改用环境变量传递,并在杀完之后**再扫一遍**:
有残留就报出来并非零退出 —— 下次再有漏项,不再静默。
实测:--list 列出全套 9 个进程;停止后 rc=0 且 pgrep 干净。
四、相机:D405 分辨率对齐真机
仿真的 D405 此前渲染 640x480,而真机跑 848x480(fx 337 而非 447)。后果是
58mm 的两孔间距成像只剩 85px,低于 hole_distance_min=90 ——
孔检测在仿真里根本不可能通过,而现象看起来像"算法不行"。
已把 xacro 与 cameras.yaml 一起改成 848x480,并把启动时的比对从"只比视场"
扩成"视场 + 图幅"(sim_cameras.check_camera_consistency),
不一致时说明它对像素门槛的影响。
五、文档
devices/sim/gazebo/README.md 重写为中文手册:使用方法 / 建模要求 / 导入格式 /
配置方式(含"改哪里才真的生效"的接线表)/ 11 条实测坑(每条都有"怎么发现")。
manifest.yaml 的进度、assets、description、坑清单与本轮状态对齐。
scripts/README.md 补两个验收工具与停止脚本;根 README 补仿真入口与手册链接。
cameras.yaml 里一处过期的函数名(check_fov_consistency)修正。
六、测试
新增 test_sim_scene.py(79 条,此前 sim_scene.py 完全没有单测 —— 这正是
位姿解析死掉却无人发现的原因)与 test_check_sim_scene.py(21 条),
含三条回归:world_boxes 的偏移碰撞体不能被对称化放大(假重叠)、
center_bore 不能被 _bore 后缀吃掉、Fortress 位姿输出格式。
全量:src/arm_sim_gazebo + arm_interfaces + arm_application 共 515 通过。
同时附上 config/site.example.yaml 的重新生成(此前 site.yaml 的注释改动没同步,
它的 parity 测试是红的)。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Gazebo 模型清单文件。命名规则见同目录 workpiece 的 model.config。
|
||||
|
||||
这个模型的 <name> 是 gauge,与目录名一致。
|
||||
注意它**不**对应 YOLO 的类别名 —— 通止规是被夹爪夹着的,不靠视觉去找它
|
||||
(真机上是人工放到夹爪里的,仿真里由 config/scene.yaml 摆好)。
|
||||
所以"名字必须等于类别名"这条约束对工件成立,对规不成立。
|
||||
-->
|
||||
<model>
|
||||
<name>gauge</name>
|
||||
<version>1.0</version>
|
||||
<sdf version="1.9">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>ros2 通止规装配项目</name>
|
||||
<email></email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
螺纹通止规:通端 φ6.0×30mm(朝下,要能穿过 φ7 孔)、
|
||||
夹持段 φ30×45mm(夹爪夹这里)、止端 φ8.0×8mm(朝上,应通不过 φ7 孔)。
|
||||
总长 86mm,钢件,约 0.265kg。
|
||||
|
||||
螺纹不建模(旋入靠状态机的 screw_pitch_mm 做运动学同步,不是螺纹几何),
|
||||
接触刚度故意给软(kp=5e4)以匹配位置控制夹爪 —— 两处原因都写在 model.sdf 文件头。
|
||||
</description>
|
||||
</model>
|
||||
@@ -0,0 +1,193 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
=============================================================================
|
||||
devices/sim/gazebo/models/gauge/model.sdf
|
||||
通止规(螺纹通止规)。被夹爪夹住、往工件孔里旋入的那个"规"。
|
||||
|
||||
位姿由 config/scene.yaml 决定,不在本文件里写死(见 workpiece 的同类说明)。
|
||||
|
||||
============================================================================
|
||||
结构(局部坐标:原点在最下端的规尖,+Z 朝上,与真机"竖直朝下装配"一致)
|
||||
============================================================================
|
||||
|
||||
┌──────┐ ← 止端 NO-GO φ8.0 × 8mm z 0.078~0.086
|
||||
│ │ 通不过 φ7 的孔(过盈 0.5mm 半径)→ 判断"孔大了"
|
||||
├──────┤
|
||||
│ │
|
||||
│ │ ← 夹持段 GROUND φ30 × 45mm z 0.033~0.078
|
||||
│ │ 夹爪夹这里。φ30 是**按夹爪的实际开合范围选的**:
|
||||
│ │ 实测两指指尖间距 fw=0 时约 27~29mm、fw=0.10 时约 128mm
|
||||
│ │ (见 README 的实测表)。取 30mm 让夹爪在接近闭合处
|
||||
│ │ 夹住 —— 既能夹稳,又不会一上来就顶到行程末端。
|
||||
├──────┤ ← 台肩 COLLAR φ16 × 3mm z 0.030~0.033
|
||||
│ │ 进入孔前会先碰到工件表面,是"到底了"的硬限位
|
||||
└──────┘
|
||||
││││ ← 通端 GO φ6.0 × 30mm z 0~0.030
|
||||
││││ 要通过 φ7 的光孔(单边间隙 0.5mm)→ 判断"孔小了"
|
||||
▼▼▼▼
|
||||
|
||||
通端/止端的方向是有讲究的:**朝下的是通端**。因为装配时规是竖直朝下插入的,
|
||||
真正进入孔里的必须是通端;止端朝上、只在人工复核(把规拔出来调头再试)时用。
|
||||
若两者装反,仿真里会表现成"规怎么都插不进孔",而看模型外观完全正常。
|
||||
|
||||
============================================================================
|
||||
⚠️ 螺纹没有建模 —— 这是有意的,不是说简化
|
||||
============================================================================
|
||||
SDF 里没有螺纹几何,本框架也**不需要**它:
|
||||
S08 的旋入是状态机按 site.yaml 的 screw_pitch_mm 同步下发"绕世界 Z 旋转
|
||||
+ 按螺距下降"(见 stage3_search_node 的 insert 段)。物理上就是一根光轴
|
||||
在光孔里转,螺距是**运动学参数**,不是几何参数。
|
||||
所以仿真能验证的是"旋入动作/时序/力判据的联动对不对",
|
||||
**不能**验证螺纹啮合本身(会不会卡牙、螺纹精度够不够)。
|
||||
|
||||
============================================================================
|
||||
⚠️ 单位:米。坐标原点在规尖,所以场景里 z = 台面高度 就是"规立在台面上"。
|
||||
=============================================================================
|
||||
-->
|
||||
<sdf version="1.9">
|
||||
<model name="gauge">
|
||||
|
||||
<static>false</static>
|
||||
<self_collide>false</self_collide>
|
||||
|
||||
<link name="body">
|
||||
|
||||
<!-- =====================================================================
|
||||
惯量
|
||||
=====================================================================
|
||||
钢件(ρ≈7850)。按各段体积算:
|
||||
通端 π·0.003²·0.030 = 8.5e-7
|
||||
台肩 π·0.008²·0.003 = 6.0e-7
|
||||
夹持段 π·0.015²·0.045 = 3.18e-5
|
||||
止端 π·0.004²·0.008 = 4.0e-7
|
||||
合计 ≈ 3.38e-5 m³ → 质量 ≈ 0.265kg
|
||||
惯量按"等效圆柱"(r=15mm, h=86mm)算,够用 —— 接触仿真里
|
||||
规的姿态由接触约束主导,惯量的精确值不影响结论。
|
||||
===================================================================== -->
|
||||
<inertial>
|
||||
<mass>0.265</mass>
|
||||
<inertia>
|
||||
<ixx>1.784e-04</ixx>
|
||||
<ixy>0</ixy>
|
||||
<ixz>0</ixz>
|
||||
<iyy>1.784e-04</iyy>
|
||||
<iyz>0</iyz>
|
||||
<izz>2.980e-05</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
|
||||
<!-- =====================================================================
|
||||
通端 GO —— φ6.0 × 30mm(朝下)
|
||||
=====================================================================
|
||||
⚠️ 接触刚度(kp/kd)故意给得**软**,这是本模型最关键的一处调参:
|
||||
夹爪是**位置控制**的(config/controllers.yaml 只有 position 接口),
|
||||
夹持力不是"设"出来的,而是由位置误差乘接触刚度决定的。
|
||||
用默认硬接触(world 里台面是 kp=1e7)时,夹爪指令闭合的几毫米
|
||||
会变成几百牛的挤压力 —— 实测夹一块薄板时指尖力传感器读到过
|
||||
700N 量级。那种力量下规会被弹飞,整条装配流程没法看。
|
||||
把规这一侧的 kp 降到 5e4(比台面低 200 倍):夹持 0.5mm 的
|
||||
指令过盈 ≈ 25N,既夹得住(不掉),又不会弹飞。
|
||||
想让夹持更紧/更松,首选的旋钮是**指令过盈量**,而不是继续改 kp。
|
||||
===================================================================== -->
|
||||
<collision name="go_stud">
|
||||
<pose>0 0 0.015 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.003</radius><length>0.030</length></cylinder></geometry>
|
||||
<surface>
|
||||
<friction><ode><mu>0.25</mu><mu2>0.25</mu2></ode></friction>
|
||||
<contact>
|
||||
<ode>
|
||||
<kp>5e4</kp>
|
||||
<kd>5e2</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.0005</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<!-- 台肩 -->
|
||||
<collision name="collar">
|
||||
<pose>0 0 0.0315 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.008</radius><length>0.003</length></cylinder></geometry>
|
||||
<surface>
|
||||
<friction><ode><mu>0.25</mu><mu2>0.25</mu2></ode></friction>
|
||||
<contact>
|
||||
<ode><kp>5e4</kp><kd>5e2</kd><max_vel>0.01</max_vel><min_depth>0.0005</min_depth></ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<!-- 夹持段:夹爪夹这里,同样用软接触。
|
||||
摩擦给 0.4:真机夹爪指垫是橡胶/聚氨酯,比金属-金属的 0.25 高。
|
||||
给太低(<0.2)规会在指间打滑自转,而现象看起来像"夹爪没夹紧"。 -->
|
||||
<collision name="grip">
|
||||
<pose>0 0 0.0555 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.015</radius><length>0.045</length></cylinder></geometry>
|
||||
<surface>
|
||||
<friction><ode><mu>0.4</mu><mu2>0.4</mu2></ode></friction>
|
||||
<contact>
|
||||
<ode><kp>5e4</kp><kd>5e2</kd><max_vel>0.01</max_vel><min_depth>0.0005</min_depth></ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<!-- 止端 NO-GO -->
|
||||
<collision name="nogo_stud">
|
||||
<pose>0 0 0.082 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.004</radius><length>0.008</length></cylinder></geometry>
|
||||
<surface>
|
||||
<friction><ode><mu>0.25</mu><mu2>0.25</mu2></ode></friction>
|
||||
<contact>
|
||||
<ode><kp>5e4</kp><kd>5e2</kd><max_vel>0.01</max_vel><min_depth>0.0005</min_depth></ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<!-- =====================================================================
|
||||
视觉
|
||||
===================================================================== -->
|
||||
<!-- 通端:深色(发黑处理的量规就是黑的),与工件的灰形成对比,
|
||||
便于在 D405 画面里看清"规尖是不是对准了孔"。 -->
|
||||
<visual name="go_stud_vis">
|
||||
<pose>0 0 0.015 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.003</radius><length>0.030</length></cylinder></geometry>
|
||||
<material>
|
||||
<ambient>0.08 0.08 0.09 1</ambient>
|
||||
<diffuse>0.12 0.12 0.13 1</diffuse>
|
||||
<specular>0.1 0.1 0.1 1</specular>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="collar_vis">
|
||||
<pose>0 0 0.0315 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.008</radius><length>0.003</length></cylinder></geometry>
|
||||
<material>
|
||||
<ambient>0.7 0.7 0.68 1</ambient>
|
||||
<diffuse>0.8 0.8 0.78 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<!-- 夹持段:亮色 + 滚花的感觉只用颜色区分(不建真实滚花网格,
|
||||
它对物理与视觉判据都没有影响,只会让模型变重)。 -->
|
||||
<visual name="grip_vis">
|
||||
<pose>0 0 0.0555 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.015</radius><length>0.045</length></cylinder></geometry>
|
||||
<material>
|
||||
<ambient>0.75 0.75 0.72 1</ambient>
|
||||
<diffuse>0.85 0.85 0.82 1</diffuse>
|
||||
<specular>0.3 0.3 0.3 1</specular>
|
||||
</material>
|
||||
</visual>
|
||||
<!-- 止端:做成红色,一眼能区分通端/止端。
|
||||
这不是装饰 —— 现场最容易犯的错就是把规装反(通端朝上),
|
||||
红色让"哪头朝下"在预览里瞬间可判。 -->
|
||||
<visual name="nogo_stud_vis">
|
||||
<pose>0 0 0.082 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.004</radius><length>0.008</length></cylinder></geometry>
|
||||
<material>
|
||||
<ambient>0.6 0.05 0.05 1</ambient>
|
||||
<diffuse>0.8 0.08 0.08 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
</link>
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Gazebo 模型清单文件。命名规则见同目录 workpiece 的 model.config。
|
||||
-->
|
||||
<model>
|
||||
<name>gauge_stand</name>
|
||||
<version>1.0</version>
|
||||
<sdf version="1.9">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>ros2 通止规装配项目</name>
|
||||
<email></email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
通止规座:60×60×32mm 方块、中心 7×7 贯通方孔,静态(工装,不该被推走)。
|
||||
|
||||
存在的唯一理由:让通止规能立住。规的支撑面只有 φ6,高 86mm,
|
||||
直接立在台面上会在 0.2 秒内倒掉(实测 RPY 变成躺平)—— 详见 model.sdf 文件头。
|
||||
规座与规的关系是"插在孔里",属于正常嵌套,不是碰撞重叠。
|
||||
</description>
|
||||
</model>
|
||||
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
=============================================================================
|
||||
devices/sim/gazebo/models/gauge_stand/model.sdf
|
||||
通止规座(规架)。作用只有一个:让通止规能**立住**。
|
||||
|
||||
============================================================================
|
||||
为什么必须有这个东西(这是实测出来的,不是设计出来的)
|
||||
============================================================================
|
||||
第一版没有规座,直接把规"立"在台面上,结果它 0.2 秒内就倒了:
|
||||
ign model -m gauge -p → RPY = (-1.09, -0.37, 0.64) ← 已经躺平
|
||||
|
||||
原因很直接:规的支撑面是 φ6 的规尖,而它本身高 86mm、
|
||||
重心在夹持段(约 55mm 高处)。这种细高比(高/底面直径 ≈ 14)
|
||||
在真实世界里也立不住 —— 真机现场是把规插在规座里、或者直接放进夹爪。
|
||||
|
||||
于是有两种"让规待着"的办法,这里选了第一种:
|
||||
方案 A(本模型):加一个规座,规插在方孔里立着
|
||||
✔ 与现场一致(规座是真实存在的工装)
|
||||
✔ 夹爪能真的从上方去夹 —— P6 的"夹取"这一步才有东西可夹
|
||||
方案 B:让规一开始就"浮"在空中(<static>true</static>)
|
||||
✘ 视觉假、也不可夹取(static 物体夹不动,力会直接顶到夹爪上)
|
||||
|
||||
============================================================================
|
||||
几何
|
||||
============================================================================
|
||||
▣ 60×60×32 的方块,中心一个 7×7 的**贯通方孔**
|
||||
规的通端(φ6)插进方孔,台肩(φ16)坐在方块顶面上 → 立住
|
||||
方孔贯通是为了让 30mm 长的通端有地方去:座高 32mm、
|
||||
规尖落在座底面之上 2mm(离台面 2mm,避免与台面接触)
|
||||
|
||||
孔为什么是方的:
|
||||
SDF 没有布尔运算,挖不出圆孔。这里用 4 个 box 围出方孔,
|
||||
与工件用同一套办法(见 workpiece/model.sdf 的说明)。
|
||||
φ6 的规过 7×7 的方孔:对边间隙 0.5mm,足够。
|
||||
|
||||
坐标原点:座底面中心。所以场景里 z = 台面高度 就把它放在台面上。
|
||||
<static>true</static>:规座是工装,不该被机械臂推走。
|
||||
static 物体不需要 <inertial>(SDF 允许省略)。
|
||||
=============================================================================
|
||||
-->
|
||||
<sdf version="1.9">
|
||||
<model name="gauge_stand">
|
||||
|
||||
<static>true</static>
|
||||
<self_collide>false</self_collide>
|
||||
|
||||
<link name="base">
|
||||
|
||||
<!-- 四块围出中间的 7×7 贯通方孔(局部坐标,底面中心为原点) -->
|
||||
<collision name="stand_south">
|
||||
<pose>0 -0.01675 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.060 0.0265 0.032</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<collision name="stand_north">
|
||||
<pose>0 0.01675 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.060 0.0265 0.032</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<collision name="stand_west">
|
||||
<pose>-0.01675 0 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.0265 0.007 0.032</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<collision name="stand_east">
|
||||
<pose>0.01675 0 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.0265 0.007 0.032</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
|
||||
<visual name="stand_south_vis">
|
||||
<pose>0 -0.01675 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.060 0.0265 0.032</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.25 0.28 0.32 1</ambient>
|
||||
<diffuse>0.33 0.36 0.40 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="stand_north_vis">
|
||||
<pose>0 0.01675 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.060 0.0265 0.032</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.25 0.28 0.32 1</ambient>
|
||||
<diffuse>0.33 0.36 0.40 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="stand_west_vis">
|
||||
<pose>-0.01675 0 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.0265 0.007 0.032</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.25 0.28 0.32 1</ambient>
|
||||
<diffuse>0.33 0.36 0.40 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="stand_east_vis">
|
||||
<pose>0.01675 0 0.016 0 0 0</pose>
|
||||
<geometry><box><size>0.0265 0.007 0.032</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.25 0.28 0.32 1</ambient>
|
||||
<diffuse>0.33 0.36 0.40 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
</link>
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Gazebo 模型清单文件。作用是让这个目录能被当成 model:// 资源引用,
|
||||
并给 GUI / `ign model --list` 提供可读信息。
|
||||
|
||||
⚠️ 命名规则(两条都是框架约定,改之前先看 README 的"建模要求"):
|
||||
1. <name> 必须与**目录名一致**(此处 workpiece),否则 model:// 引用会
|
||||
找不到 —— 而 Gazebo 只会静默跳过,不报错。
|
||||
2. <name> 必须与推理用的**类别名一致**(YOLO 的 labels 里那个名字)。
|
||||
否则仿真里算出的工件坐标和检测结果对不上:明明检测到工件,
|
||||
坐标却是另一个东西的。这条最容易在"新建一个模型试试"时被破坏。
|
||||
-->
|
||||
<model>
|
||||
<name>workpiece</name>
|
||||
<version>1.0</version>
|
||||
<sdf version="1.9">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>ros2 通止规装配项目</name>
|
||||
<email></email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
通止规装配的工件:140×100×12mm 板,中心 φ40 光孔(会被检测的 max_radius 滤掉),
|
||||
两侧各一个 φ7 光孔、孔心间距 58mm、孔口带 φ14 亮环(二阶段 HoughCircles 检测的目标)。
|
||||
|
||||
详细说明(尺寸怎么反推出来的、哪些是近似)见 model.sdf 文件头与
|
||||
devices/sim/gazebo/README.md 的"仿真 ≠ 真机"一节。
|
||||
</description>
|
||||
</model>
|
||||
@@ -0,0 +1,325 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
=============================================================================
|
||||
devices/sim/gazebo/models/workpiece/model.sdf
|
||||
工件(被装配的对象)。
|
||||
|
||||
由 config/scene.yaml 决定摆在台面上的哪个位置,启动时由 gazebo_sim.launch.py
|
||||
用 ros_gz_sim create -file 生成。**不要**把位姿写死在这里 ——
|
||||
位姿属于"场景",不属于"模型",分开才能同一个模型摆多处。
|
||||
|
||||
============================================================================
|
||||
这个模型在还原真机的什么
|
||||
============================================================================
|
||||
尺寸与孔位不是随便定的,是按真机检测参数(src/arm_application/config/
|
||||
hole_detect.yaml)反推出来的,每条都对得上:
|
||||
|
||||
两个螺纹孔间距 58mm
|
||||
依据 insert_bolt_radius_mm: 29.0(注释写明"两目标孔物理间距~58mm")。
|
||||
这两个孔就是二阶段要对准的 k1 / k2。
|
||||
|
||||
孔口是"环"而不是"洞"(视觉上)
|
||||
检测用的是 HoughCircles 找**亮环**,且 hough_min_radius=10 /
|
||||
hough_max_radius=30。换算成物理尺寸(真机 D405:848 宽、87° 视场,
|
||||
fx≈447,相机到工件约 0.23m):
|
||||
radius_px = r_m × 447 / 0.23 ≈ r_m × 1943
|
||||
10px ≈ 5.1mm 30px ≈ 15.4mm
|
||||
也就是说**能被检测到的圆,半径必须在 5.1~15.4mm 之间**。
|
||||
本模型把每个螺纹孔的亮环外径做成 φ14(半径 7mm → 约 13.6px,落在
|
||||
区间中段),孔本身 φ7(半径 3.5mm → 约 6.8px,**低于下限会被滤掉**)。
|
||||
这正是真机上的情形:检测到的是嵌件的环,不是螺纹孔本身。
|
||||
|
||||
中间有个大孔,且必须被滤掉
|
||||
hole_detect 的 max_radius=30("滤掉中间大孔")与 site.yaml 的
|
||||
"过小会配到中心孔" 都说明真件中心有一个大孔。这里做成 φ40
|
||||
(半径 20mm → 约 38.9px > 30)→ 会被 max_radius 正确滤除。
|
||||
它的存在是有意义的:中心的**光孔**正是通止规的"通端要通过"的区域,
|
||||
也是二阶段粗居中时 bbox 的中心特征。
|
||||
|
||||
============================================================================
|
||||
⚠️ 两个必须知道的近似(都写在 README 的"仿真≠真机"一节)
|
||||
============================================================================
|
||||
1) SDF **没有布尔运算**,无法在板上"挖"一个圆孔。所以:
|
||||
碰撞体 = 用 10 个 box 拼出板子,留下**方孔**
|
||||
中心 40×40mm、两侧 7×7mm
|
||||
视觉 = 同一批 box(保证视觉与碰撞完全一致,不会骗人)
|
||||
+ 每个孔上方贴一个亮圆盘 / 暗圆柱,做出"环 + 暗孔"的样子
|
||||
相机从上往下看到的仍然是**圆环**(贴片是圆的),所以二阶段的圆检测
|
||||
在仿真里能看到该看到的东西;而通止规要穿过的是那个方孔 ——
|
||||
φ6 的规过 7×7 的方孔:对边间隙 0.5mm,足够。
|
||||
方孔在 GUI 里看得出来,这是有意的取舍,不是 bug。
|
||||
|
||||
2) 真机是 **M6 螺纹孔**,仿真里按**光孔**建模(SDF 没有螺纹)。
|
||||
孔的直径(φ7)比 M6 的小径(≈4.9mm)大,是为了让接触求解器稳定:
|
||||
world 的 contact_surface_layer 是 1mm,间隙小于 1mm 时求解器会认为
|
||||
一直贴着。**因此仿真里的插入力/接触力只能定性参考,不能用来标定真机的
|
||||
力阈值** —— 真机阈值必须在真机上标。
|
||||
|
||||
============================================================================
|
||||
单位:米。SDF 一律用米,用毫米建模的必须先缩放(见 README 的建模要求)。
|
||||
坐标原点:板子**底面中心**。所以场景里把 z 设成台面高度,板子就正好落在台面上。
|
||||
=============================================================================
|
||||
-->
|
||||
<sdf version="1.9">
|
||||
<model name="workpiece">
|
||||
|
||||
<!-- 静态试跑时可把下面这行改成 true 钉住工件(调试检测/对孔时很有用:
|
||||
否则一次误碰就把它推走了,而你会以为是检测出问题)。
|
||||
正常装配流程必须 false —— 工件被推动本身就是要观察的物理现象。 -->
|
||||
<static>false</static>
|
||||
<self_collide>false</self_collide>
|
||||
|
||||
<link name="body">
|
||||
|
||||
<!-- =====================================================================
|
||||
惯量
|
||||
=====================================================================
|
||||
铝合金(ρ≈2700)实心等效:无孔板体积 0.14×0.10×0.012 = 1.68e-4 m³
|
||||
→ 质量 0.454kg。三个孔挖掉约 1.7e-5 m³(≈10%),但这里**不扣**,
|
||||
偏保守(略重 = 略稳,不会因为惯量偏小而在接触里抖)。
|
||||
惯量按整块长方体的公式算:I = m/12 × (另两边平方和)
|
||||
========================================================================= -->
|
||||
<inertial>
|
||||
<mass>0.454</mass>
|
||||
<inertia>
|
||||
<ixx>3.804e-04</ixx>
|
||||
<ixy>0</ixy>
|
||||
<ixz>0</ixz>
|
||||
<iyy>7.404e-04</iyy>
|
||||
<iyz>0</iyz>
|
||||
<izz>1.110e-03</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
|
||||
<!-- =====================================================================
|
||||
碰撞体:10 个 box 拼出的"带方孔的板"
|
||||
=====================================================================
|
||||
切分方式(局部坐标,原点在底面中心,x 沿 140mm 方向):
|
||||
y 方向切 5 条带,等宽处由孔决定:
|
||||
A [-0.050,-0.020] 只避开中心孔
|
||||
B [-0.020,-0.0035] 避开中心孔
|
||||
C [-0.0035,0.0035] 同时避开中心孔与两侧小孔
|
||||
D [ 0.0035,0.020] 同 B
|
||||
E [ 0.020, 0.050] 整条实心
|
||||
x 方向按各带里有哪些孔再切。
|
||||
留下的孔(都是方孔):
|
||||
中心 x∈[-0.020,0.020] y∈[-0.020,0.020] 40×40mm
|
||||
左 x∈[-0.0325,-0.0255] y∈[-0.0035,0.0035] 7×7mm @ x=-29mm
|
||||
右 x∈[ 0.0255, 0.0325] 同上 7×7mm @ x=+29mm
|
||||
两侧小孔中心距恰好 58mm(0.058),与 insert_bolt_radius_mm=29 对齐。
|
||||
===================================================================== -->
|
||||
|
||||
<!-- A:最下一条带,整条实心 -->
|
||||
<collision name="plate_a">
|
||||
<pose>0 -0.035 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.140 0.030 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
|
||||
<!-- B:中心孔左侧 -->
|
||||
<collision name="plate_b_left">
|
||||
<pose>-0.045 -0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<!-- B:中心孔右侧 -->
|
||||
<collision name="plate_b_right">
|
||||
<pose>0.045 -0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
|
||||
<!-- C:穿过三个孔的那条带,被切成 4 段(见上面 x 切分) -->
|
||||
<collision name="plate_c_far_left">
|
||||
<pose>-0.05125 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0375 0.007 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<!-- 中心孔与小孔之间那道 5.5mm 的窄壁 —— 真件上就是这里最薄,
|
||||
也是通止规对孔时最容易别到的地方,保留它是有意义的。 -->
|
||||
<collision name="plate_c_web_left">
|
||||
<pose>-0.02275 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0055 0.007 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<collision name="plate_c_web_right">
|
||||
<pose>0.02275 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0055 0.007 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<collision name="plate_c_far_right">
|
||||
<pose>0.05125 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0375 0.007 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
|
||||
<!-- D:中心孔左/右 -->
|
||||
<collision name="plate_d_left">
|
||||
<pose>-0.045 0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
<collision name="plate_d_right">
|
||||
<pose>0.045 0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
|
||||
<!-- E:最上一条带,整条实心 -->
|
||||
<collision name="plate_e">
|
||||
<pose>0 0.035 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.140 0.030 0.012</size></box></geometry>
|
||||
<surface><friction><ode><mu>0.6</mu><mu2>0.6</mu2></ode></friction></surface>
|
||||
</collision>
|
||||
|
||||
<!-- =====================================================================
|
||||
视觉:与碰撞体**同一批 box**(不另画一个"漂亮但不一样"的板子)
|
||||
=====================================================================
|
||||
材质:深灰哑光。选哑光是因为真机的金属件在 D405 的环形光下不会
|
||||
镜面反光到过曝 —— 过曝会把亮环淹掉,检测直接失效。
|
||||
===================================================================== -->
|
||||
<visual name="plate_a_vis">
|
||||
<pose>0 -0.035 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.140 0.030 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_b_left_vis">
|
||||
<pose>-0.045 -0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_b_right_vis">
|
||||
<pose>0.045 -0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_c_far_left_vis">
|
||||
<pose>-0.05125 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0375 0.007 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_c_web_left_vis">
|
||||
<pose>-0.02275 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0055 0.007 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_c_web_right_vis">
|
||||
<pose>0.02275 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0055 0.007 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_c_far_right_vis">
|
||||
<pose>0.05125 0 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.0375 0.007 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_d_left_vis">
|
||||
<pose>-0.045 0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_d_right_vis">
|
||||
<pose>0.045 0.01175 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.050 0.0165 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="plate_e_vis">
|
||||
<pose>0 0.035 0.006 0 0 0</pose>
|
||||
<geometry><box><size>0.140 0.030 0.012</size></box></geometry>
|
||||
<material>
|
||||
<ambient>0.35 0.36 0.38 1</ambient>
|
||||
<diffuse>0.42 0.43 0.45 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<!-- =====================================================================
|
||||
两个螺纹孔的"嵌件环"(视觉)—— 二阶段要检测的就是这个环
|
||||
=====================================================================
|
||||
做法:一个**亮**圆盘(φ14,环的外径)贴在孔里 2mm 深处,
|
||||
再叠一个**暗**圆柱(φ7,孔本身)比它高 1mm。
|
||||
上往下看:暗圆柱把亮盘中心挡掉 → 剩下的就是一圈亮环(φ7→φ14)。
|
||||
这不是"画个圆假装有孔",而是用两个实体拼出环的**可见几何**,
|
||||
所以遮挡关系是对的、深度也是对的(孔比面低 1mm)。
|
||||
|
||||
为什么亮盘用 φ14:见文件头 —— 要让环外径落在
|
||||
hough 的 10~30px 有效区间,而 13.6px 正好在区间中段。
|
||||
===================================================================== -->
|
||||
<visual name="insert_left_ring">
|
||||
<pose>-0.029 0 0.010 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.007</radius><length>0.001</length></cylinder></geometry>
|
||||
<material>
|
||||
<!-- 亮:嵌件是机加工面,比哑光的板面亮得多 —— 检测靠的就是这个对比 -->
|
||||
<ambient>0.85 0.85 0.82 1</ambient>
|
||||
<diffuse>0.95 0.95 0.90 1</diffuse>
|
||||
<specular>0.2 0.2 0.2 1</specular>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="insert_left_bore">
|
||||
<pose>-0.029 0 0.0075 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.0035</radius><length>0.007</length></cylinder></geometry>
|
||||
<material>
|
||||
<!-- 暗:孔内是阴影 + 无光,与亮环形成对比,HoughCircles 才能锁定 -->
|
||||
<ambient>0.02 0.02 0.02 1</ambient>
|
||||
<diffuse>0.03 0.03 0.03 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<visual name="insert_right_ring">
|
||||
<pose>0.029 0 0.010 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.007</radius><length>0.001</length></cylinder></geometry>
|
||||
<material>
|
||||
<ambient>0.85 0.85 0.82 1</ambient>
|
||||
<diffuse>0.95 0.95 0.90 1</diffuse>
|
||||
<specular>0.2 0.2 0.2 1</specular>
|
||||
</material>
|
||||
</visual>
|
||||
<visual name="insert_right_bore">
|
||||
<pose>0.029 0 0.0075 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.0035</radius><length>0.007</length></cylinder></geometry>
|
||||
<material>
|
||||
<ambient>0.02 0.02 0.02 1</ambient>
|
||||
<diffuse>0.03 0.03 0.03 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<!-- 中心大孔:只做一个暗的深孔。半径 20mm → 约 38.9px,
|
||||
超过 hough_max_radius=30,会被检测正确滤掉(真件也是这个行为)。 -->
|
||||
<visual name="center_bore">
|
||||
<pose>0 0 0.007 0 0 0</pose>
|
||||
<geometry><cylinder><radius>0.020</radius><length>0.010</length></cylinder></geometry>
|
||||
<material>
|
||||
<ambient>0.02 0.02 0.02 1</ambient>
|
||||
<diffuse>0.03 0.03 0.03 1</diffuse>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
</link>
|
||||
</model>
|
||||
</sdf>
|
||||
Reference in New Issue
Block a user