第3章 几何与可视化
标签 · 导入外部模型 · 颜色与纹理
好,咱们直接进入正题。URDF 里怎么让机器人「看起来像那么回事」?说白了就靠三个东西:<geometry> 定义形状,<mesh> 把外部模型拽进来,<material> 给皮肤上色。我刚开始做机器人仿真时,觉得随便画个方块就能跑,后来发现——嗯,视觉上太丑,连调试心情都受影响。这一章我把压箱底的经验翻出来,咱们一次聊透。
3.1 <geometry> 标签:搭积木的基础
你想想看,URDF 里的每个 link 都得有个形状,不然仿真器里就是一团空气。<geometry> 支持三种原生体:box、cylinder、sphere。我个人习惯在原型阶段全用基本体,快,而且不容易出 bug。
<link name="base_link">
<visual>
<geometry>
<box size="0.4 0.3 0.1" />
</geometry>
</visual>
</link>
box 的 size 是 xyz 半边长(注意是全长,不是半长)。cylinder 要指定 radius 和 length,sphere 只一个 radius。我在项目里遇到过一个问题:圆柱的 length 写成了直径,结果 Gazebo 里轮子直接陷进地面一半…… 所以记得,length 是高度,不是直径。
<cylinder> 代替 <box> 做轮子,因为圆柱的碰撞计算更稳定,不容易卡地形。
3.2 <mesh> 导入外部模型:让机器人有灵魂
基本体太单调?那就上 <mesh>。你可以把 SolidWorks、Blender 导出的 STL 或 Collada(.dae)文件塞进来。我一般用 STL 做碰撞,用 DAE 做可视化(因为 DAE 自带颜色)。
<link name="arm_link">
<visual>
<geometry>
<mesh filename="package://my_robot/meshes/arm.dae" scale="1.0 1.0 1.0" />
</geometry>
</visual>
</link>
注意 filename 的路径写法。我推荐用 package:// 形式,这样不管你的包放在哪,ROS 都能找到。曾经有个同事直接把路径写进去,结果换台电脑模型全红…… 嗯,后来他老老实实改成了 package 路径。
| 格式 | 优点 | 缺点 |
|---|---|---|
| STL (.stl) | 通用、轻量、碰撞稳定 | 无颜色信息,二进制/ASCII混用 |
| Collada (.dae) | 支持颜色、纹理、材质 | 文件较大,有时导入会丢材质 |
| OBJ (.obj) | 带纹理坐标,可读性好 | URDF 官方不直接支持,需转DAE |
3.3 <material> 颜色与纹理:给机器人穿衣服
光有形状还不够,颜色对了才能一眼认出零件。<material> 可以定义在 link 内部,也可以单独拎出来作为全局资源。我通常把常用颜色放在 URDF 顶部,像调色板一样。
<material name="blue_metal">
<color rgba="0.2 0.4 0.9 1.0" />
</material>
<link name="chassis">
<visual>
<geometry>
<box size="0.5 0.4 0.2" />
</geometry>
<material name="blue_metal" />
</visual>
</link>
rgba 四个值范围 0~1,不是 0~255。我见过有人写 rgba="255 0 0 1",结果 Gazebo 里一片惨白…… 记住,0~1 归一化。
<material> 支持 <texture>,但 Gazebo 和 Rviz 的支持程度不一样。我个人的经验是:用 DAE 模型自带的纹理最稳,或者直接在模型文件里引用图片。如果你非要在 URDF 里写纹理,记得用 filename 属性指向 png/jpg。
再说一个细节:<material> 可以被子 link 继承吗?不行。每个 link 的 visual 都得显式指定 material。我一开始也以为会像 CSS 一样层叠,结果…… 机器人一半身子是透明的。所以,每个 visual 块都老老实实加上 <material> 吧。
3.4 可视化与碰撞的几何分离
这是很多新手忽略的点。URDF 里 <visual> 和 <collision> 可以完全不同。比如你有一个精细的 DAE 模型做视觉,但碰撞用一个简单的圆柱体,性能会好很多。
<link name="head">
<visual>
<geometry>
<mesh filename="package://bot/meshes/head.dae" />
</geometry>
</visual>
<collision>
<geometry>
<sphere radius="0.15" />
</geometry>
</collision>
</link>
我做过一个机械臂项目,视觉模型有 2 万面,碰撞用 6 个球体包络,仿真速度直接翻倍。你想想看,何必让物理引擎去算那些螺丝孔的碰撞呢?