十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Gazebo 11中添加圆环模型:SDF文件手写与碰撞体配置指南

Gazebo 11中添加圆环模型:SDF文件手写与碰撞体配置指南 最近在整理自己的Gazebo仿真环境配置记录有个很有意思的需求是往场景里加一个圆环。可能有人觉得这不就是个模型吗直接拖进去不就行了实际操作下来完全不是这么回事。Gazebo 11自带的模型库里确实没有圆环就算是手动用圆柱体去拼也要想清楚定位和角度的问题。这篇笔记就把我在Gazebo 11里添加圆环模型的完整过程记录下来包括SDF文件怎么写、哪些参数容易踩坑、怎么确认圆环在仿真里真的“碰得到”。如果你是刚开始玩Gazebo、或者做穿越机/机械臂抓取这类需要环形目标的项目这篇应该能帮你省不少时间。1. 场景前的选择很重要圆环模型为什么不走GUI路线先别急着打开Gazebo就找Insert面板。圆环这个东西跟box、sphere、cylinder不一样它属于典型的“模型库没有、GUI菜单也找不到”的形状。想在仿真里放一个圆环本质上是在问一个问题我怎么把这个几何体告诉Gazebo1.1 哪些场景会用到圆环结构机器人仿真里圆环其实很常见只是很多人一开始没意识到。比如无人机穿越机竞赛需要在场地里布置几个竖直的门洞这种门洞就是圆环机械臂抓取项目经常要识别和抓取环形零件仿真里放一个圆环当目标物体还有管道巡检、避障测试、传感器标定比如激光雷达在圆环附近的点云特征这些场景都需要一个真实、稳定的环形几何体。我自己做的是无人机避障的仿真训练要模拟无人机穿过一个悬浮圆环的场景。如果圆环建模不准确或者碰撞体缺失训练出来的策略到了真机上根本没法用。所以别看只是“加一个圆环”它直接决定了后续任务的成败。1.2 为什么GUI里没有圆环、用圆柱挖洞为什么行不通打开Gazebo 11的左侧Insert面板你会看到不少基础形状但翻来覆去无非是box、sphere、cylinder这种。圆环也就是数学上说的torus不在这个列表里。这是有原因的Gazebo内置的GUI插入工具只提供最基础的凸几何体而圆环这种带孔的曲面体在物理引擎里处理起来要复杂得多。我看过不少人的第一反应是找一个半径比较大的圆柱稍微压扁一点然后在中间挖个洞。这个思路听起来很合理但问题在于SDF格式不支持布尔运算也就是没法在实体几何里做“相减”。你在Gazebo里放一个圆柱它永远是一个实心的圆柱中间不会平白无故多出一个通孔。所以在Gazebo 11里加圆环可行的路子有两条一条是手写SDF文件用torus这个几何类型直接定义圆环另一条是用一堆小圆柱体去近似拼接成一个圆环。两条路我后来都试过各有优劣。实现方案实现难度物理碰撞精度适用场景手写SDF torus低高几何体精确首选稳定可靠多圆柱组合近似中低有明显拼接感特殊场景应急下面我把这两条路的具体细节都拆开来讲。2. 圆环SDF文件拆解从几何参数到材质位姿要让Gazebo认识一个圆环核心就是写SDF。SDF是Gazebo原生支持的场景描述格式它不像URDF那样主要面向机器人本体建模而是能描述整个仿真环境包括光照、地面、模型、传感器这些。加圆环这件事基本就是写一个模型并把它放进world文件里。2.1 圆环的几何定义方式两套参数别搞混SDF里定义torus需要两个关键尺寸一个决定环的大小一个决定环的粗细。在Gazebo 11自带的sdformat 9版本里对应的标签是radius和inner_radius。geometry torus radius0.5/radius inner_radius0.05/inner_radius /torus /geometry这两个参数不搞明白的话后面一定会乱。radius指的是从圆环整体中心到管道中心线的距离可以理解成“环的主半径”。inner_radius指的是管道截面的半径也就是圆环这条“管子”本身的粗细。举个例子如果radius是0.5米inner_radius是0.05米那你看到的圆环整体外径大约是0.55米内孔直径大约是0.9米管子的粗细是0.1米。这个比例大概就是一个比较纤细的圆环适合当穿越门洞用。如果你想要一个粗壮的手环效果可以把inner_radius调到0.1米甚至更大。这里要特别提醒一点如果你用的是新版本的sdformat比如Gazebo 12以上或者一些ROS 2发行版自带的环境torus的标签可能会变成major_radius和minor_radius。这两套标签意思一样分别对应主半径和管道半径只是命名不同。我一开始在Gazebo 11里写的是major_radius结果加载报错一查才知道版本的差异。所以复制代码的时候一定先确认你手上是哪一版Gazebo。2.2 为什么碰撞体和视觉体要同时写SDF里模型要正常出现在仿真中Link下面通常需要两个部分一个visual负责显示一个collision负责物理碰撞。很多人为了省事只写visual结果模型看得到但机器人直接穿过去或者传感器检测不到就是这个原因。放在圆环这个例子上你希望Gazebo渲染出一个红色圆环同时在物理层面把圆环当作一个实体的“门洞”来处理——无人机能穿过去但碰到环壁会被挡住那visual和collision两个都要配齐。visual namevisual geometry torus radius0.5/radius inner_radius0.05/inner_radius /torus /geometry material ambient0.9 0.1 0.1 1/ambient diffuse0.9 0.1 0.1 1/diffuse specular0.1 0.1 0.1 1/specular /material /visual collision namecollision geometry torus radius0.5/radius inner_radius0.05/inner_radius /torus /geometry /collision材质部分就是RGBA颜色值前三个是RGB分量最后一个是透明度。默认的白色会跟背景混在一起不好辨认我换成红色之后一眼就能看到。如果你想要半透明的视觉效果比如测试视觉传感器透过圆环识别后方目标可以把最后一个值调成0.5左右。还有一点模型初始位置也是通过SDF控制的。pose标签里依次是x、y、z、roll、pitch、yaw前三个单位是米后三个单位是弧度。比如我想让圆环悬浮在地面上方1.2米处就写pose0 0 1.2 0 0 0/pose。如果想让圆环竖直立起来像一扇门一样就把pitch设成1.5708也就是90度的弧度值。3. 实操记录从零到一让圆环出现在Gazebo 11里到了动手环节。我的习惯是先建一个完整的world文件把天空、地面、圆环模型都放进去这样Gazebo一启动就是我要的场景。3.1 完整world文件参考新建一个ring.world文件内容如下?xml version1.0 ? sdf version1.7 world namering_world include urimodel://sun/uri /include include urimodel://ground_plane/uri /include model nametorus_ring statictrue/static pose0 0 1.2 0 0 0/pose link namelink visual namevisual geometry torus radius0.5/radius inner_radius0.05/inner_radius /torus /geometry material ambient0.9 0.1 0.1 1/ambient diffuse0.9 0.1 0.1 1/diffuse specular0.1 0.1 0.1 1/specular /material /visual collision namecollision geometry torus radius0.5/radius inner_radius0.05/inner_radius /torus /geometry /collision /link /model /world /sdf这个文件里有两个include一个是sun阳光一个是ground_plane地面。新手容易漏掉这两个结果启动后场景黑漆漆的一片或者圆环悬在空中看不到参照物。地面就相当于仿真世界的“地板”阳光是默认的光照来源建议保留。圆环模型本身放在model nametorus_ring里面。注意我加了statictrue/static这个标签的意思是让模型不受重力影响、不移动。如果不加圆环从1.2米高空掉下来就会直接砸到地面很多做悬浮目标的场景就不对了。如果你本来就想让圆环自由落体或者受到外力推挤那就删掉这一行。3.2 启动与验证步骤启动Gazebo加载这个world文件命令行这样做gazebo --verbose ring.world加上--verbose是为了让终端打印详细的加载日志一旦模型加载失败错误信息会直接显示出来。看到“Loading model: torus_ring”这样的输出基本就说明模型被识别到了。进入Gazebo界面后可以在左侧模型树里找到torus_ring这一项。点开它能看到link下面有visual和collision。如果模型树里这两个都存在说明文件解析成功圆环既可见也具备碰撞属性。还有一个很实用的确认方法直接在Gazebo窗口里选中圆环用工具栏上的移动旋转工具拖一下。如果模型能跟着动并且松手后不会穿模说明碰撞体生效了。我第一次验证的时候偷懒没加--verbose结果圆环一直没显示调试了半天才发现是SDF文件里标签名写错了但终端一直被日志刷屏看不到报错。所以启动时一定带上--verbose省得后面瞎猜。3.3 进阶用法让圆环反馈接触信息圆环如果只是摆在场景里当个静态障碍物很多项目其实用不到这步。但如果你的任务是“无人机穿过圆环并给一个触发信号”那就需要给圆环加一个接触传感器。接触传感器可以在圆环模型里面加上去直接在link内部加一个sensor节点sensor nametouch typecontact contact collisionlink::collision/collision /contact always_on1/always_on update_rate10/update_rate topic/torus_ring/contact/topic /sensor这里collision里写的格式是“链路名::碰撞体名”对应SDF中link的name是linkcollision的name是collision。update_rate是发布频率10意味着每秒发布10次接触数据如果你的无人机飞得快可以调高到50或100。启动后通过Gazebo的话题系统查看gz topic -e -t /torus_ring/contact当无人机撞到圆环的那一瞬间终端就会刷出contact消息。配合这个信号就能做穿越计数、碰撞报警这些功能了。我后来做无人机穿门训练就是靠这个接触传感器来确定“是否真的碰到过门框”比单纯看位置判断靠谱得多。4. 踩坑实录圆环不显示、掉落、碰不到怎么办这部分是纯经验贴。我在搞圆环模型的过程中踩过不少坑有些问题说出来很基础但坑住人的往往就是这些基础细节。常见问题现象排查方向模型加载失败圆环不出现终端有报错检查sdf标签名、sdf版本圆环直接掉到地上1.2米高度变0米检查static标签是否有/写在哪圆环看得到但穿模机器人直接穿过圆环检查collision是否漏写接触传感器无反馈撞到圆环没消息检查sensor的collision名称是否匹配圆环闪烁或变透明材质异常/纹理冲突检查material的RGBA透明度值4.1 模型加载失败、一闪而过如果你启动world之后什么都没看到终端里又有一堆红色或黄色警告十有八九是SDF文件解析出了问题。我遇到过一次特别典型的情况在网上找了一个现成的圆环SDF结果那篇教程写的是新版本标签major_radius而我用的Gazebo 11不认这个写法直接把整个模型丢弃了。排查方法是看终端里有没有“Unknown element”之类的提示如果有就把标签改回radius和inner_radius再试。这个方法也能用来排查sensor、material等各部分是不是写错。还有一个容易忽略的地方就是world文件顶部的版本号。Gazebo 11对应SDF 1.7写作sdf version1.7。如果你把版本号写成了适配新版Gazebo的1.9或者更高旧版解析器可能也会出问题。4.2 static位置不对导致圆环疯狂掉落static这个标签看着简单位置却很讲究。它必须放在model下面作为model的子元素不能放在link里面。我有一次把statictrue/static放到了link里面结果Gazebo解析的时候把它当成一个未知元素忽略掉圆环加载后直接失去固定约束在两秒钟内就从半空掉到了地上。最后检查才发现是这个低级错误。另外如果你做的是移动平台搭载圆环比如在AGV顶部放一个圆环作为识别靶标那就不能让模型static。此时圆环需要作为movement的一个link存在而不是一个独立的静态模型。4.3 圆环看得到但机器人直接穿过去这个是我觉得最坑的一个问题。视觉上圆环好好的材质鲜红但机器人一碰到圆环就穿过去了和碰空气一样。后来检查SDF才发现我只写了visual把collision整个漏掉了。Gazebo里视觉和碰撞是分开的两个属性visual只负责渲染画面collision才决定物理交互。你可以在可视情况下完全没有碰撞体画面看起来毫无异常。但机器人、传感器、物理引擎都不会感知到这个模型。所以写完SDF后养成一个好习惯展开模型树确认每个link下面既有visual又有collision。对于圆环这种门洞类目标用户希望机器人能穿过内孔但不能穿过环壁collision的精确性尤为重要。好在这块在SDF中没有额外处理geometry写法和visual完全一致Gazebo会自动把圆环的碰撞边界计算出来。4.4 接触传感器为什么不触发接触传感器加上去之后最烦人的情况是眼看着无人机撞上圆环了gz topic却一条消息都没有。这种问题先看两个地方。第一sensor里collision的名称是不是严格按照“link名::collision名”来写的。我在3.3小节里写过示例如果你的link不是叫link碰撞体也不是叫collision这里就要跟着改。第二always_on要设成1否则传感器只在特定状态下才工作。还有update_rate不要设成0那是禁用发布的意思。我之前有一次就是这个值没注意结果半天等不到消息一看是更新频率为0等于传感器整个休眠了。如果实在排查不出来可以把sensor的visualize属性打开设为true之后Gazebo会把传感器的检测范围可视化出来。虽然contact sensor可视化效果有限但至少能确认传感器本身有没有被加载。4.5 用多个圆柱拼接圆环的应急替代方案最后说一个不算bug但值得记录的备用方案。如果你的环境确实不支持torus或者你手头是一套特别老的Gazebo版本那就只能用多个小圆柱拼一个近似圆环。思路是这样的把圆环看成24根小圆柱沿着一个圆周排列每根圆柱的中心点落在那个圆周上朝向指向圆周的切线方向。用脚本生成这些位置和角度直接写到SDF文件里。import math segments 24 radius 0.5 tube 0.05 for i in range(segments): angle 2 * math.pi * i / segments x radius * math.cos(angle) y radius * math.sin(angle) yaw math.pi / 2 angle print(flink names{i}) print(f pose{x:.4f} {y:.4f} 0 0 0 {yaw:.4f}/pose) print( visual namev) print( geometrycylinderradius f{tube}/radiuslength0.15/length/cylinder/geometry) print( /visual) print( collision namec) print( geometrycylinderradius f{tube}/radiuslength0.15/length/cylinder/geometry) print( /collision) print(/link)这个脚本的关键在于yaw的计算。圆柱沿着圆周排布时它的轴向必须指向圆的切线方向也就是在朝向角上转90度。如果不做这一步所有圆柱都是朝同一个方向并排的根本围不成一个环。用这个方案拼出来的圆环物理碰撞会有明显的“棱角感”无人机撞上去时接触点不连续。所以能用torus还是优先用torus组合法是我在非常老的版本上才会选择的备用方案。我在实际跑这一系列实验的时候最深的体会是Gazebo里凡是GUI办不到的模型基本都要回到SDF文件本身去解决。圆环只是其中的一个典型代表它的难点不在于SDF有多复杂而在于搞清楚torus的尺寸关系、碰撞体与视觉体的分工以及static标签的正确位置。如果你把上面这个案例完整跑通了以后再在Gazebo里加自定义模型比如多面体、带孔零件思路其实是完全一样的。这篇笔记就写到这祝你的圆环早日出现在仿真世界里。
返回列表