Diliverycart(四)

EPRobot 学习进展记录|最近阶段

一、当前整体目标发生了什么变化

这一阶段一开始,我们主要是在解决:

Ubuntu 能不能通过 ROS 控制小车 → RViz 能不能显示雷达和地图 → 能不能自己 SLAM 扫图。

现在已经进一步推进到了:

直接使用队友扫好的地图 → 加载静态地图 → AMCL 定位 → move_base + TEB 自主导航。

也就是说,已经从"把车跑起来"进入了真正的导航阶段。


二、ROS 多机通信重新跑通

目前小车 EPRobot 的 IP:

复制代码
172.20.10.3

Ubuntu 与小车已经能互相通信。

Ubuntu 中 ROS 配置确认过:

复制代码
echo $ROS_MASTER_URI

返回:

复制代码
http://EPRobot2:11311

Ubuntu:

复制代码
echo $ROS_HOSTNAME

返回:

复制代码
ubuntu

EPRobot:

复制代码
echo $ROS_MASTER_URI

也是:

复制代码
http://EPRobot:11311

并且 EPRobot 自己的 ROS 主机名配置正常。

本阶段再次确认的重要知识

ROS 多机通信不仅要求:

复制代码
Ubuntu → 能找到 EPRobot

还必须:

复制代码
EPRobot → 能找到 ubuntu

之前出现过:

复制代码
ping ubuntu

竟然解析成:

复制代码
10.189.140.66

导致 EPRobot 无法访问 Ubuntu。

原因是 /etc/hosts 里 ubuntu 对应的 IP 已经过期。

所以再次明确:

每次换手机热点 / IP 改变,都要检查 /etc/hosts。


三、/cmd_vel 控制问题

之前我们一直测试:

复制代码
rostopic pub -r 5 /cmd_vel geometry_msgs/Twist ...

一开始出现过一个很奇怪的问题:

Ubuntu 发 /cmd_vel,小车有时不动;

在 EPRobot 终端发,同样指令却能动。

后来逐步确认:

复制代码
rostopic info /cmd_vel

能看到:

复制代码
Subscribers:
* /base_control

说明底盘控制节点确实订阅 /cmd_vel。

然后检查:

复制代码
rosnode info /base_control

确认:

复制代码
Subscriptions:
/cmd_vel

程序源码中也确认了:

复制代码
self.cmd_vel_topic = rospy.get_param('~cmd_vel_topic','/cmd_vel')
self.sub = rospy.Subscriber(self.cmd_vel_topic,Twist,self.cmdCB,...)

也就是说:

/cmd_vel 就是正确的控制话题。


四、为什么 Ctrl+C 后小车还不立即停

使用:

复制代码
rostopic pub -r 5 /cmd_vel ...

代表:

以 5Hz 持续不断发送速度指令。

所以终端会一直占着,这不是"卡住"。

停止发布:

复制代码
Ctrl+C

但为了确保小车马上收到"速度=0"的指令,我们后来固定采用:

复制代码
rostopic pub -1 /cmd_vel geometry_msgs/Twist \
'{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}'

最终确认:

前进命令 → Ctrl+C → 再发一次 0 速度

可以全部在 Ubuntu 同一个终端完成。


五、安装了键盘遥控节点 teleop_twist_keyboard

因为手工敲 /cmd_vel 太麻烦,而且不好控制扫图,所以我们开始安装:

teleop_twist_keyboard

其中teleoperation就是远程操控的意思


六、解决 Ubuntu apt 被占用的问题

安装时执行:

复制代码
sudo apt install ros-melodic-teleop-twist-keyboard

出现:

复制代码
无法获得锁 /var/lib/dpkg/lock-frontend

检查:

复制代码
sudo lsof /var/lib/dpkg/lock-frontend

发现是:

复制代码
unattended-upgrade
PID 2281

一直占着锁,而且跑了几个小时。

普通:

复制代码
sudo kill 2281

都没停掉。

最后使用:

复制代码
sudo kill -9 2281

才结束。

之后成功安装:

复制代码
sudo apt install ros-melodic-teleop-twist-keyboard

再验证:

复制代码
rospack find teleop_twist_keyboard

成功返回:

复制代码
/opt/ros/melodic/share/teleop_twist_keyboard

结论

键盘遥控包安装成功。


七、键盘控制小车已经实现

补充一个ros的语法:rosrun 包名 节点可执行文件

比如

启动:

复制代码
rosrun teleop_twist_keyboard teleop_twist_keyboard.py

成功出现:

复制代码
Reading from the keyboard and Publishing to Twist!

按键:

复制代码
   u    i    o
   j    k    l
   m    ,    .

主要记:

复制代码
i  前进
,  后退
k  停止
u  前进+左转
o  前进+右转
m  后退+左转
.  后退+右转

调速度:

复制代码
q/z  整体速度 +10% / -10%
w/x  只调线速度 +10% / -10%
e/c  只调转向速度 +10% / -10%

第一次实际扫图时,把速度从:

复制代码
speed 0.5
turn 1.0

一直降到了大约(按键盘里的z)

复制代码
speed ≈ 0.15
turn ≈ 0.31

八、进一步理解了阿克曼底盘

EPRobot 是:

后轮驱动 + 前轮转向的阿克曼底盘。

不是那种可以左右轮反向、原地旋转的小车。

所以更像汽车:

复制代码
后轮 → 推动车前后运动
前轮 → 改变转向角

因此实际控制最适合:

复制代码
i    直走
u/o  边走边转
k    停

而不是频繁用 j/l 原地转。

手册也明确说明 EPRobot 是后轮驱动、前轮转向的阿克曼结构。EPRobotV2智能小车使用手册-202505(1)


九、RViz 显示配置搞明白了

RViz 里学习了:

复制代码
Fixed Frame = map

添加:

复制代码
Map       → /map
LaserScan → /scan

并且知道:

复制代码
Add → By topic

对于已经存在的话题最方便。

RViz 配置也保存过。

地图显示含义

复制代码
白色     已判断为可通行区域
黑色     障碍物/墙
灰绿色   未知、尚未扫描区域

十、第一次真正跑 GMapping 建图

正式启动:

复制代码
roslaunch robot_navigation robot_slam_laser.launch slam_methods:=gmapping

确认:

复制代码
rosnode list | grep gmapping

出现:

复制代码
/gmapping

再检查:

复制代码
rostopic info /map

看到:

复制代码
Publishers:
/gmapping

所以确认:

/scan + /odom → gmapping → /map

这一整条建图链路已经跑起来。


十一、解决了一个非常关键的 TF 问题

当时虽然:

复制代码
/gmapping
/map
/odom
/scan

都有了,但 RViz 仍然:

复制代码
No tf data

执行:

复制代码
rosrun tf tf_echo map base_link

报:

复制代码
Could not find a connection between 'map' and 'base_link'
TF has two or more unconnected trees

检查发现 TF 是断开的:

复制代码
map
 ↓
odom
以及
base_footprint
↓
base_link
↓
base_laser_link

缺:

复制代码
odom → base_footprint

十二、最终定位到参数 is_pub_odom_tf

执行:

复制代码
rosparam get /base_control/is_pub_odom_tf

返回:

复制代码
false

但是:

复制代码
rostopic echo -n 1 /odom

已经有:

复制代码
frame_id: "odom"
child_frame_id: "base_footprint"

这说明:

里程计消息 /odom 有,

但没有发布对应 TF。

搜索:

复制代码
grep -R -n "is_pub_odom_tf" \
~/robot_ws/src/eprobot_start \
~/robot_ws/src/robot_navigation

发现:

复制代码
EPRobot_start.launch       → true
robot_lidar.launch.bak_nav → true
robot_lidar.launch         → false

所以修改:

复制代码
~/robot_ws/src/robot_navigation/launch/robot_lidar.launch

把:

复制代码
<param name="is_pub_odom_tf" type="string" value="false"/>

改成true:

复制代码
<param name="is_pub_odom_tf" type="string" value="true"/>

重新启动 SLAM 后:

复制代码
rosrun tf tf_echo map base_link

终于开始连续输出:

复制代码
Translation: ...
Rotation: ...

这一步非常重要

正确 TF 树变成:

复制代码
map
 ↓
odom
 ↓
base_footprint
 ↓
base_link
 ↓
base_laser_link

这也是这一阶段非常关键的一个故障排查成果。


十三、自己实际体验了一次完整扫图

使用:

复制代码
GMapping + teleop_twist_keyboard + RViz

真的把场地扫出来过。

但第一版地图出现:

复制代码
射线状发散
墙体重影
边界撕裂
地图发生扭曲

后来分析主要与:

复制代码
转弯太快
频繁左右修正
阿克曼底盘运动特点
里程计累计误差
激光匹配不稳定

有关。

后来重新清空:

复制代码
rosnode kill /gmapping

确认:

复制代码
rostopic info /map

一度变成:

复制代码
Publishers: None

再重新启动 gmapping。

RViz 里的旧 Map 也:

复制代码
Remove

再重新:

复制代码
Add → /map → Map

从而真正开始了一张新地图。


十四、最终决定:不继续自己扫,使用队友地图

虽然已经完整体验过 GMapping 建图,但因为队友的地图质量更好,所以决定:

比赛导航直接使用队友已经扫好的地图。

队友地图位置:

复制代码
~/robot_ws/src/robot_navigation/maps

文件:

复制代码
map.pgm
map.yaml

执行:

复制代码
cd ~/robot_ws/src/robot_navigation/maps
ls -lh map.pgm map.yaml

确认地图存在。

单独测试过:

复制代码
source ~/robot_ws/devel/setup.bash
rosrun map_server map_server 

~/robot_ws/src/robot_navigation/maps/map.yaml

成功输出:

复制代码
Loading map from image ".../map.pgm"
Read a 384 X 384 map @ 0.050 m/cell

说明:

map.yaml + map.pgm 完整有效。


十六、开始进入正式"二维自主导航"

官方流程:

复制代码
roslaunch robot_navigation robot_navigation.launch

用于启动导航。

EPRobot 手册明确说明,地图构建完成后就可以进入二维地图自主导航;这套小车使用 TEB 作为适配阿克曼底盘的导航/局部规划算法。EPRobotV2智能小车使用手册-202505(1)(2)

这次启动成功后,终端出现:

复制代码
Received a 384 X 384 map @ 0.050 m/pix

还有:

复制代码
base control start...
is_pub_odom_tf : true
Serial Open Succeed

说明:

复制代码
地图 ✅
底盘 ✅
odom TF ✅
串口 ✅

十七、导航代价地图也已经起来

启动过程中看到:

复制代码
global_costmap: Using plugin "static_layer"
global_costmap: Using plugin "obstacle_layer"
global_costmap: Using plugin "inflation_layer"

以及:

复制代码
local_costmap ...

目前可以简单理解:

复制代码
static_layer
= 队友地图里的固定墙和障碍物
obstacle_layer
= 激光雷达实时看到的新障碍
inflation_layer
= 在障碍物周围留安全距离

所以导航时不是只看 map.pgm,而是:

复制代码
已有地图
+
实时雷达障碍
+
安全膨胀区域

一起决定哪里能走。


十八、确认 AMCL 和 move_base 已经工作

Ubuntu 执行:

复制代码
rostopic info /map

现在看到:

复制代码
Publishers:
* /map_server

说明当前已经不是 GMapping 在实时建图,而是:

map_server 正在发布队友的静态地图。

并且:

复制代码
Subscribers:
* /amcl
* /move_base

这两个非常重要。

可以理解为:

复制代码
map_server
   ↓
队友静态地图
   ↓
AMCL      → 我现在在哪里?
move_base → 我要怎么走到目标?

十九、RViz 现在用于"导航",不是"建图"

Ubuntu 本地没有:

复制代码
navigation_rviz.launch

所以执行:

复制代码
roslaunch robot_navigation navigation_rviz.launch

会报:

复制代码
is neither a launch file ...

原因是 Ubuntu 本地没有这个 robot_navigation 包/launch 文件。

但不影响使用。

直接:

复制代码
rviz

即可。

然后:

复制代码
Fixed Frame = map
Add
→ By topic
→ /map
→ Map

就能看到队友的地图。


二十、刚学到的两个导航按钮

现在已经进行到:

2D Pose Estimate

意思:

告诉 AMCL:"现实中的小车现在在地图哪里、车头朝哪边。"

操作:

复制代码
点击 2D Pose Estimate
→ 在地图中真实小车对应位置按下鼠标
→ 拖出箭头

其中:

复制代码
箭头起点 = 小车位置
箭头方向 = 车头方向

可以记:

2D Pose Estimate = 我现在在哪?


之后才用。

意思:

告诉导航系统:我要去哪。

同样:

复制代码
目标点位置 + 目标车头方向

然后:

复制代码
move_base + TEB

会自己规划路线并控制小车过去。

记:

2D Nav Goal = 我要去哪?


二十一、到目前为止整套系统可以这样理解

现在最重要的一张逻辑图:

复制代码
                ROS Master
                    │
                    │
      ┌─────────────┴─────────────┐
      │                           │
   EPRobot                     Ubuntu
      │                           │
      │                          RViz
      │                           │
      │                     显示地图/定位/路径
      │
      ├── map_server
      │      │
      │      └── 队友 map.yaml + map.pgm
      │
      ├── 激光雷达 /scan
      │
      ├── 底盘 /odom
      │
      ├── TF
      │
      ├── AMCL
      │      └── 判断"小车在哪"
      │
      └── move_base + TEB
             └── 判断"怎么走到目标"

二十二、目前进度停在哪里

现在已经完成:

复制代码
✅ Ubuntu ↔ EPRobot ROS 多机通信
✅ Bitvise SSH
✅ roscore
✅ 底盘 /cmd_vel
✅ 键盘遥控 teleop_twist_keyboard
✅ RViz
✅ LaserScan
✅ GMapping
✅ /map
✅ /odom
✅ TF 树修复
✅ 自己体验 SLAM 扫图
✅ 队友 map.pgm + map.yaml 加载
✅ map_server
✅ AMCL
✅ move_base
✅ global/local costmap
✅ TEB 导航框架启动
✅ RViz 显示队友地图