3、创建第一个机器人模型:用URDF描述底盘、加激光雷达、在Gazebo里跑起来
好,咱们正式开始动手了。
这一章的目标很明确:用URDF文件描述一个最简单的机器人——一个圆形底盘,顶上装一个激光雷达。然后把它扔进Gazebo里,看看能不能动起来。
你可能会问:URDF是什么?说白了,它就是机器人的“身份证”。告诉仿真器你的机器人长什么样、有多重、关节在哪、传感器装在哪。
3.1 URDF的基本结构
URDF文件用XML格式写。核心就两个东西:link 和 joint。
- link:机器人的一个刚体部件。比如底盘、轮子、雷达支架。
- joint:连接两个link的关节。可以是固定的,也可以旋转的。
我个人习惯,先画个草图再写代码。你想想看,一个机器人底盘,你总得知道它半径多少、高度多少吧?
核心原则:每个link必须有visual(外观)、collision(碰撞体)、inertial(惯性参数)。Gazebo对碰撞体和惯性要求很严格,缺了它模型会乱飘。
3.2 编写第一个URDF:底盘
我们先写底盘。一个圆柱体,半径0.2米,高度0.15米。
<?xml version="1.0"?>
<robot name="my_robot">
<link name="base_link">
<visual>
<geometry>
<cylinder radius="0.2" length="0.15"/>
</geometry>
<material name="blue">
<color rgba="0 0 0.8 1"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.2" length="0.15"/>
</geometry>
</collision>
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0"
iyy="0.1" iyz="0"
izz="0.1"/>
</inertial>
</link>
</robot>
嗯,这里要注意:inertia的值不能随便填。我见过有人全填0,结果Gazebo直接崩溃。对于圆柱体,你可以用公式算,或者参考ROS官方给的默认值。
小技巧:如果你不确定惯性参数,可以用inertia_calculator这个Python脚本算一下。网上搜一下就有。
3.3 添加激光雷达传感器
激光雷达不能直接贴在底盘上,那样视野会被挡住。我们需要加一个固定关节,把雷达支架抬高。
<link name="laser_link">
<visual>
<geometry>
<box size="0.05 0.05 0.05"/>
</geometry>
<material name="red">
<color rgba="0.8 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.05 0.05 0.05"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.001" ixy="0" ixz="0"
iyy="0.001" iyz="0"
izz="0.001"/>
</inertial>
</link>
<joint name="laser_joint" type="fixed">
<parent link="base_link"/>
<child link="laser_link"/>
<origin xyz="0 0 0.2" rpy="0 0 0"/>
</joint>
这里origin xyz="0 0 0.2"表示雷达支架在底盘上方0.2米处。为什么是0.2?因为底盘高度0.15米,雷达装在顶上,再留点空间。
我在项目中遇到过一个问题:雷达的坐标系和底盘坐标系没对齐,导致建图时地图是歪的。所以rpy(翻滚、俯仰、偏航)一定要确认清楚。
3.4 在Gazebo中加载模型
URDF写好了,怎么让Gazebo认识它?你需要一个launch文件。
<launch>
<!-- 启动Gazebo世界 -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
</include>
<!-- 把机器人模型加载到参数服务器 -->
<param name="robot_description"
textfile="$(find my_robot_description)/urdf/my_robot.urdf"/>
<!-- 在Gazebo中生成机器人 -->
<node name="spawn_urdf"
pkg="gazebo_ros"
type="spawn_model"
args="-param robot_description -urdf -model my_robot" />
</launch>
运行这个launch文件,你应该能看到Gazebo里出现一个蓝色圆柱体,顶上有个红色小方块。
避坑指南:我曾经因为spawn_model的参数写错,机器人死活不出来。检查一下-param后面的名字,必须和<param name="...">一致。
3.5 让激光雷达真正工作
光有模型还不够,激光雷达要能发数据。你需要给laser_link添加Gazebo插件。
<gazebo reference="laser_link">
<sensor type="ray" name="laser_sensor">
<pose>0 0 0 0 0 0</pose>
<visualize>true</visualize>
<update_rate>10</update_rate>
<ray>
<scan>
<horizontal>
<samples>360</samples>
<resolution>1</resolution>
<min_angle>-3.14159</min_angle>
<max_angle>3.14159</max_angle>
</horizontal>
</scan>
<range>
<min>0.1</min>
<max>10.0</max>
<resolution>0.01</resolution>
</range>
</ray>
<plugin name="laser_controller" filename="libgazebo_ros_ray_sensor.so">
<topicName>/scan</topicName>
<frameName>laser_link</frameName>
</plugin>
</sensor>
</gazebo>
这段代码告诉Gazebo:在laser_link上装一个360度激光雷达,扫描范围0.1到10米,数据发布到/scan话题。
你可以在终端用rostopic echo /scan看看数据有没有出来。如果没数据,八成是插件路径不对,或者libgazebo_ros_ray_sensor.so没装。
3.6 本章知识体系
为了让你更直观地理解,我画了一张图:
3.7 常见问题与避坑
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 模型在Gazebo里乱飘 | 缺少碰撞体或惯性参数 | 检查每个link是否有<collision>和<inertial> |
| 激光雷达没数据 | 插件路径不对或没装 | 运行sudo apt install ros-noetic-gazebo-ros-pkgs |
| 模型颜色不对 | material定义错误 | 检查<material>标签内的rgba值 |
| 关节位置不对 | origin坐标算错 |
用rviz可视化查看TF树 |
我的经验:第一次做URDF,别追求完美。先让模型在Gazebo里“站起来”,再慢慢调参数。我曾经花了一整天调颜色,结果发现雷达没装好,白忙活。
好了,这一章的内容就这些。你跟着做一遍,应该能看到一个蓝色底盘加红色雷达的模型在Gazebo里稳稳当当。下一章我们会给它装上轮子,让它跑起来。
可可精品资料库