3. URDF与机器人建模:使用URDF描述机械臂与AGV底盘、xacro宏定义、在Rviz2中可视化模型
好,咱们进入第三章。这一章我打算聊聊机器人建模,也就是怎么用URDF把机械臂和AGV底盘“画”出来。你可能会觉得,建模不就是写点XML嘛,有啥好讲的?嗯,我刚开始也这么想,直到我在一个项目里,因为一个坐标轴写反了,整个机械臂在Rviz里拧成了麻花……那场面,真是哭笑不得。
说白了,URDF就是机器人的“骨架描述文件”。它告诉ROS2你的机器人长什么样,关节在哪,能怎么动。咱们这一章,就把它彻底搞明白。
3.1 URDF基础:link和joint
URDF的核心就两个东西:link和joint。link是刚体部件,比如底盘、连杆、末端执行器。joint是连接两个link的关节,定义了它们之间的相对运动关系。
我习惯把link想象成骨头,joint想象成关节。骨头本身不会动,是关节让骨头动起来的。这个类比很直观,你想想看。
一个最简单的link定义长这样:
<link name="base_link">
<visual>
<geometry>
<box size="0.5 0.3 0.1"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
</link>
这里我定义了一个叫base_link的底盘,形状是个长方体,涂成蓝色。注意,visual标签只负责显示,不影响碰撞检测。如果你要做物理仿真,还得加一个collision标签,内容通常和visual一样。
joint的定义稍微复杂一点:
<joint name="arm_joint" type="fixed">
<parent link="base_link"/>
<child link="arm_link"/>
<origin xyz="0.2 0 0.1" rpy="0 0 0"/>
</joint>
这个joint把arm_link固定在base_link上,偏移了(0.2, 0, 0.1)米。注意rpy是欧拉角,顺序是绕X、Y、Z轴旋转。我在项目中吃过亏,rpy的顺序千万别搞错,否则模型会歪得你怀疑人生。
3.2 用xacro简化模型描述
写URDF最痛苦的是什么?重复劳动。一个六轴机械臂,六个link、六个joint,每个都得写一遍。而且如果你要改尺寸,得挨个改。这时候,xacro就派上用场了。
xacro是URDF的宏扩展工具。你可以定义变量、写宏、做数学运算。说白了,就是给URDF加上了编程能力。
举个例子,定义一个通用的连杆宏:
<xacro:macro name="link_box" params="name length width height color">
<link name="${name}">
<visual>
<geometry>
<box size="${length} ${width} ${height}"/>
</geometry>
<material name="${color}">
<color rgba="0 0 1 1"/>
</material>
</visual>
</link>
</xacro:macro>
然后你只需要一行就能生成一个link:
<xacro:link_box name="arm_link_1" length="0.1" width="0.05" height="0.3" color="red"/>
是不是清爽多了?我个人习惯把机械臂的每个连杆长度、关节限位都定义成xacro变量,放在一个单独的config.xacro文件里。这样改参数时,只需要改一个地方,所有地方自动更新。
3.3 机械臂与AGV底盘的联合建模
咱们这个课程的主题是“协同”,所以机械臂和AGV底盘得放在一个URDF里。怎么做?很简单,把AGV底盘作为根link,机械臂作为子link挂上去。
我一般这样组织文件结构:
robot.urdf.xacro:主文件,包含所有部件chassis.urdf.xacro:AGV底盘定义arm.urdf.xacro:机械臂定义sensors.urdf.xacro:激光雷达、相机等传感器config.xacro:全局参数
主文件里用<xacro:include>把其他文件包含进来:
<?xml version="1.0"?>
<robot name="mobile_manipulator" xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:include file="$(find my_robot_description)/urdf/config.xacro"/>
<xacro:include file="$(find my_robot_description)/urdf/chassis.urdf.xacro"/>
<xacro:include file="$(find my_robot_description)/urdf/arm.urdf.xacro"/>
<xacro:include file="$(find my_robot_description)/urdf/sensors.urdf.xacro"/>
</robot>
这里要注意,包含顺序很重要。先定义底盘,再定义机械臂,因为机械臂的joint要引用底盘的link。如果顺序反了,xacro会报错说找不到父link。
机械臂和底盘的连接,用一个固定joint:
<joint name="base_to_arm" type="fixed">
<parent link="chassis_link"/>
<child link="arm_base_link"/>
<origin xyz="${arm_mount_x} ${arm_mount_y} ${arm_mount_z}" rpy="0 0 0"/>
</joint>
这样,机械臂就稳稳地站在AGV底盘上了。嗯,这里要注意,arm_mount_x这些变量要在config.xacro里定义好,方便后期调整安装位置。
3.4 在Rviz2中可视化模型
模型写好了,怎么验证?当然是放到Rviz2里看看。Rviz2是ROS2的3D可视化工具,能实时显示机器人模型、传感器数据、路径规划结果等。
首先,你得有一个launch文件来启动显示。我常用的launch文件长这样:
import launch
from launch_ros.actions import Node
def generate_launch_description():
return launch.LaunchDescription([
Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
output='screen',
parameters=[{'robot_description': open('robot.urdf.xacro').read()}]
),
Node(
package='joint_state_publisher_gui',
executable='joint_state_publisher_gui',
name='joint_state_publisher_gui',
output='screen'
),
Node(
package='rviz2',
executable='rviz2',
name='rviz2',
output='screen'
)
])
这个launch文件启动了三个节点:
- robot_state_publisher:读取URDF,发布TF变换和机器人模型
- joint_state_publisher_gui:提供一个滑块界面,让你手动调节关节角度
- rviz2:可视化界面
启动后,在Rviz2中添加RobotModel显示,选择/robot_description话题,你的机器人就出现了。如果一切正常,你应该能看到AGV底盘上站着一个机械臂。
robot_state_publisher没有正确加载URDF。检查一下launch文件里robot_description参数的路径是否正确。另外,确保你的URDF文件没有语法错误,可以用check_urdf命令检查。
在Rviz2中,你还可以添加TF显示,看看各个坐标系之间的关系是否正确。如果某个link的坐标系飘到了奇怪的地方,那多半是joint的origin写错了。
3.5 本章知识体系
为了让你更直观地理解本章内容,我画了一张流程图,展示URDF建模到Rviz可视化的完整链路:
这张图展示了从定义link和joint,到用xacro封装,再到生成URDF,最后通过robot_state_publisher在Rviz2中可视化的完整链路。每一步都环环相扣,缺一不可。
好了,这一章的内容就到这里。URDF建模是机器人开发的基础,看似简单,但细节很多。我建议你动手写一个自己的URDF,哪怕只是一个底盘加一个连杆,然后在Rviz里看看效果。只有亲手踩过坑,才能真正记住。
可可精品资料库