机械臂模型基础:URDF文件结构、link与joint的定义、在Rviz中可视化模型
做机器人仿真,第一步就是搞定模型描述。说白了,你得告诉计算机:这个机械臂长什么样?关节在哪?能怎么动?
URDF(Unified Robot Description Format)就是干这个的。它用XML格式,把机器人拆成一个个零件(link)和连接件(joint)。我刚开始接触时也觉得这东西有点繁琐,但后来发现——模型建得越清楚,后面调试越省心。
URDF文件长什么样?
一个完整的URDF文件,核心就两样东西:link 和 joint。你可以把link想象成骨骼,joint就是关节。骨骼决定形状,关节决定运动方式。
来看个最简单的例子——两连杆机械臂:
<robot name="simple_arm">
<link name="base_link">
<visual>
<geometry>
<box size="0.2 0.2 0.1"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
</visual>
</link>
<joint name="joint1" type="revolute">
<parent link="base_link"/>
<child link="arm_link"/>
<origin xyz="0 0 0.05" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="10" velocity="1"/>
</joint>
<link name="arm_link">
<visual>
<geometry>
<cylinder length="0.4" radius="0.02"/>
</geometry>
<origin xyz="0 0 0.2" rpy="0 0 0"/>
</visual>
</link>
</robot>
嗯,结构很清晰。根节点是 <robot>,里面包着link和joint。每个link有名字,有几何形状。每个joint连接两个link,定义运动类型和范围。
link的定义——机械臂的每一块骨头
link描述的是刚体部分。每个link可以包含三块内容:
- visual:可视化用的几何形状,Rviz里看到的就是它
- collision:碰撞检测用的形状,可以比visual简单些,省计算量
- inertial:惯性参数,质量、质心、惯量矩阵——做动力学仿真时必须填
我见过不少新手只写visual,不写collision和inertial。结果呢?仿真时要么碰撞检测不准,要么动力学计算报错。尤其是惯性参数,很多人嫌麻烦就随便填个1。我曾经在一个项目里吃过这个亏——机械臂仿真跑起来看着正常,一换真实硬件就抖得不行。后来查了半天,发现是惯量矩阵写错了。
关键点:做运动学仿真可以只写visual,但要做动力学仿真,inertial必须准确。质量、质心位置、惯量矩阵,一个都不能少。
几何形状支持三种基本类型:
| 形状 | 标签 | 参数 | 适用场景 |
|---|---|---|---|
| 长方体 | <box> | size="长 宽 高" | 基座、连接件 |
| 圆柱体 | <cylinder> | length radius | 连杆、臂体 |
| 球体 | <sphere> | radius | 关节球、末端 |
你想想看,实际机械臂的形状千奇百怪,光靠这三种基本几何肯定不够。所以URDF还支持用 <mesh> 导入STL或DAE文件。我一般先用CAD软件导出STL,再在URDF里引用,这样模型更真实。
joint的定义——关节怎么动
joint是URDF里最讲究的部分。它决定了两个link之间的相对运动关系。joint的类型有六种:
| 类型 | 说明 | 自由度 | 常见用途 |
|---|---|---|---|
| revolute | 旋转关节,有角度限制 | 1 | 肩关节、肘关节 |
| continuous | 连续旋转,无限制 | 1 | 车轮、转台 |
| prismatic | 平移关节,有行程限制 | 1 | 伸缩臂、滑轨 |
| fixed | 固定连接,不能动 | 0 | 法兰连接、传感器安装 |
| floating | 6自由度浮动 | 6 | 移动基座、无人机 |
| planar | 平面运动(2平移+1旋转) | 3 | AGV底盘 |
joint里最重要的几个属性:
- parent/child:父子关系,从父link指向子link。注意,URDF里joint的方向是从父到子,别搞反了
- origin:joint在父link坐标系下的位置和姿态。这个坐标决定了子link相对于父link的初始位置
- axis:旋转轴或平移方向。revolute和prismatic必须指定
- limit:运动范围、最大力矩、最大速度。revolute和prismatic必须写
注意:origin和axis的坐标系都是相对于父link的。我曾经见过有人把axis写成了相对于世界坐标系,结果关节转起来方向全错了。调试了半天才发现是坐标系理解有误。
坐标系与变换树
URDF本质上定义了一棵变换树。每个joint就是一个变换节点,从父link坐标系变换到子link坐标系。Rviz里看到的机器人模型,就是沿着这棵树逐级计算出来的。
我习惯用 tf2 的工具来验证变换树是否正确。启动机器人后,在终端输入:
rosrun tf2_tools view_frames.py
会生成一个PDF,里面画出了所有坐标系之间的变换关系。如果树结构不对,一眼就能看出来。
下面这张图展示了URDF中link和joint的组织方式:
在Rviz中可视化模型
模型写好了,怎么验证对不对?Rviz是最直观的工具。你不需要写任何代码,只要一个launch文件就能把模型加载进去。
基本步骤:
- 创建一个功能包,把URDF文件放进去
- 写一个launch文件,加载URDF并启动Rviz
- 在Rviz中添加RobotModel显示组件
- 添加TF显示组件,看坐标系对不对
一个最简的launch文件长这样:
<launch>
<param name="robot_description"
textfile="$(find my_robot_description)/urdf/my_arm.urdf"/>
<node name="robot_state_publisher"
pkg="robot_state_publisher" type="robot_state_publisher"/>
<node name="rviz" pkg="rviz" type="rviz"
args="-d $(find my_robot_description)/config/display.rviz"/>
</launch>
这里有个关键点——robot_state_publisher。它负责读取URDF里的joint信息,发布tf变换。没有它,Rviz里只能看到一堆link飘在那,动不起来。
小技巧:第一次在Rviz里看模型时,记得把"Fixed Frame"设成你的根link名字(比如base_link)。默认是"map",如果没设置就会报错。我刚开始用Rviz时,卡在这步卡了半小时。
模型加载成功后,你可以用 joint_state_publisher 的GUI界面拖动关节,实时看机械臂动起来。这个工具会读取URDF里joint的limit范围,生成滑块。拖动滑块,模型就跟着动——非常直观。
常见坑与避坑指南
做URDF模型时,有几个坑我几乎每次都会遇到:
- 坐标系搞反:origin的xyz和rpy,一定要搞清楚是相对于父link还是世界坐标系。答案是父link
- joint方向反了:axis写反了方向,关节转起来和预期相反。解决办法:在Rviz里拖动joint,看实际旋转方向
- link之间穿透:几何尺寸和origin没算好,两个link重叠在一起。我一般先在CAD里量好尺寸,再填到URDF里
- 惯性参数乱填:动力学仿真时模型乱飞,十有八九是惯量矩阵写错了。建议用SolidWorks或Fusion360导出准确的惯性参数
我曾经在一个六轴机械臂项目里,因为一个joint的axis写成了 0 1 0 而不是 0 0 1,导致整个臂的运动学解算全错。查了两天才找到问题。嗯,从那以后我每次写完URDF,第一件事就是在Rviz里手动拖一遍所有关节。
URDF是机器人仿真的基石。模型建得扎实,后面的运动学、动力学、轨迹规划才能顺利推进。别急着跳过这一步——花时间把模型调好,后面能省十倍的时间。