4、机器人底盘控制与里程计:配置差速驱动插件,实现键盘控制移动,理解odom坐标系
好,咱们进入第四章。这一章,说白了就是让机器人真正动起来。
前面几章我们把机器人模型搭好了,环境也建好了。但模型只是个壳子,你得给它装上“腿”和“眼睛”。这里的“腿”就是差速驱动插件,“眼睛”就是里程计。我当年刚接触Gazebo时,卡在最久的就是这章——模型加载进去了,怎么推它都不走,急得我直挠头。
4.1 差速驱动模型:机器人怎么转弯的?
先聊点基础的。差速驱动,你想想看,就是两个轮子各自独立转动。左轮转得快、右轮转得慢,车就往右拐。反过来就往左拐。两个轮子转速一样,那就直行。
听起来简单吧?但实际项目中,我遇到过轮子打滑、PID参数没调好导致机器人原地画圈的情况。嗯,这些坑后面会讲到。
差速驱动的核心公式其实就两个:
- 线速度:v = (v_left + v_right) / 2
- 角速度:ω = (v_right - v_left) / L (L是轮距)
你发给机器人的/cmd_vel话题,里面就是线速度和角速度。Gazebo里的差速驱动插件会帮你把这两个值换算成左右轮的目标转速。
4.2 配置差速驱动插件
好,上干货。我们要在机器人的URDF或SDF文件中加入差速驱动插件。我个人习惯用URDF加标签的方式,这样结构更清晰。
下面是一个典型的差速驱动插件配置:
<gazebo>
<plugin name="diff_drive" filename="libgazebo_ros_diff_drive.so">
<ros>
<namespace>/</namespace>
<argument>cmd_vel:=cmd_vel</argument>
<argument>odom:=odom</argument>
</ros>
<left_joint>left_wheel_joint</left_joint>
<right_joint>right_wheel_joint</right_joint>
<wheel_separation>0.4</wheel_separation>
<wheel_diameter>0.2</wheel_diameter>
<max_wheel_torque>20</max_wheel_torque>
<max_wheel_acceleration>1.0</max_wheel_acceleration>
<command_timeout>0.5</command_timeout>
<publish_odom>true</publish_odom>
<publish_odom_tf>true</publish_odom_tf>
<odometry_frame>odom</odometry_frame>
<robot_base_frame>base_footprint</robot_base_frame>
</plugin>
</gazebo>
关键参数说明:
wheel_separation:左右轮之间的距离。这个值必须和你的模型一致,差1厘米都不行。我曾经因为量错轮距,机器人走直线都走歪。wheel_diameter:轮子直径。直接影响里程计精度。max_wheel_torque:最大扭矩。设太小了爬坡上不去,设太大了电机容易过热。command_timeout:指令超时时间。如果超过这个时间没收到/cmd_vel,机器人会自动停止。这是安全机制。
4.3 键盘控制:让机器人听你指挥
插件配好了,怎么测试?最简单的方法就是用键盘控制。
ROS里有个现成的工具叫teleop_twist_keyboard。安装方式:
sudo apt install ros-noetic-teleop-twist-keyboard
然后启动你的机器人Gazebo仿真,再开一个新终端运行:
rosrun teleop_twist_keyboard teleop_twist_keyboard.py
按i键前进,逗号键后退,j和l键左右转。嗯,就这么简单。
但这里有个坑——键盘控制默认发布的话题是/cmd_vel,而你的差速驱动插件监听的是/cmd_vel。如果命名空间不对,机器人不会有任何反应。我刚开始学的时候,折腾了半小时才发现是话题名没对上。
小技巧:用rostopic list查看当前所有话题,确认/cmd_vel存在。再用rostopic echo /cmd_vel查看数据是否在发布。这是排查问题的第一步。
4.4 理解odom坐标系
机器人动起来了,但你怎么知道它走了多远、转了多少度?这就靠里程计了。
odom坐标系,说白了就是机器人相对于起点的位置和姿态。它通过轮子编码器数据积分得到。注意,是积分——这意味着误差会累积。
在Gazebo仿真中,里程计数据是“完美”的,因为仿真器直接知道机器人的真实位置。但在真实机器人上,轮子打滑、地面不平都会导致里程计漂移。我记得有一次做项目,机器人走了10米,里程计显示走了9.2米,差了8%。后来发现是轮子气压不足。
odom坐标系在TF树中的位置是这样的:
map → odom → base_footprint → base_link → ...
- map:全局坐标系,固定不变
- odom:里程计坐标系,相对于map会漂移
- base_footprint:机器人在地面的投影
你可以用tf_echo工具查看odom到base_footprint的变换:
rosrun tf tf_echo odom base_footprint
这会实时显示机器人的位置(x, y)和朝向(yaw)。
4.5 本章知识体系
下面这张图帮你理清本章的核心逻辑:
4.6 避坑指南
最后,分享几个我踩过的坑:
我曾经犯过的错:
- 轮距和模型不匹配:URDF里轮子间距是0.4米,插件里写成0.35米。结果机器人转弯半径完全不对。
- 忘记设置
publish_odom_tf为true:里程计数据发布了,但TF树里没有odom坐标系,导航节点直接报错。 - 键盘控制时机器人不动:检查后发现是
teleop_twist_keyboard默认发布到/cmd_vel,但插件监听的是/robot/cmd_vel。命名空间没对上。
嗯,这一章的内容就到这。你配置好差速驱动插件后,记得先用键盘控制让机器人走几圈,同时用rostopic echo /odom看看里程计数据对不对。如果一切正常,恭喜你,你的机器人已经具备了最基本的移动能力。
课后练习:修改wheel_separation参数,观察机器人转弯半径的变化。试试把轮距从0.4改成0.6,看看同样的角速度指令下,转弯半径是变大还是变小?
可可精品资料库