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 本章知识体系

下面这张图帮你理清本章的核心逻辑:

第四章:底盘控制与里程计知识体系 差速驱动模型 驱动插件配置 里程计与odom 线速度 + 角速度 → 轮速 左轮/右轮独立控制 URDF + gazebo插件标签 cmd_vel话题订阅 轮距/轮径/扭矩参数 odom → base_footprint TF树发布 位置(x,y) + 朝向(yaw) 键盘控制 → 差速驱动 → 里程计输出 → odom坐标系

4.6 避坑指南

最后,分享几个我踩过的坑:

我曾经犯过的错:

  1. 轮距和模型不匹配:URDF里轮子间距是0.4米,插件里写成0.35米。结果机器人转弯半径完全不对。
  2. 忘记设置publish_odom_tf为true:里程计数据发布了,但TF树里没有odom坐标系,导航节点直接报错。
  3. 键盘控制时机器人不动:检查后发现是teleop_twist_keyboard默认发布到/cmd_vel,但插件监听的是/robot/cmd_vel。命名空间没对上。

嗯,这一章的内容就到这。你配置好差速驱动插件后,记得先用键盘控制让机器人走几圈,同时用rostopic echo /odom看看里程计数据对不对。如果一切正常,恭喜你,你的机器人已经具备了最基本的移动能力。

课后练习:修改wheel_separation参数,观察机器人转弯半径的变化。试试把轮距从0.4改成0.6,看看同样的角速度指令下,转弯半径是变大还是变小?

可可精品资料库