一、基础环境准备
1. 检查当前环境(ctrl+alt+T打开新终端)
#检查检查 Ubuntu 系统版本 lsb_release -a #检查当前ros2环境变量 echo $ROS_DISTRO # 检查是否存在 ROS 1 的包(应无输出或未安装) dpkg -l | grep ros-noetic-turtlebot3 # 检查当前已安装的 ROS 2 Humble 相关包 apt list --installed | grep ros-humble-turtlebot3 apt list --installed | grep ros-humble-nav2预期输出如下:输出中的Description:应当显示Ubuntu 22.04.x LTS
预期输出如下:终端应直接输出humble
根据最后三条指令的内容,发给ai,进行我们的环境安装包的安装,完整安装了 ROS 2 Humble 版本的turtlebot3全系列包(包括仿真环境turtlebot3-gazebo、键盘控制turtlebot3-teleop、甚至是用于后续导航的turtlebot3-navigation2),需要补齐Nav2导航组件、TEB规划器以及建图算法工具箱的参考以下安装内容
2. 核心安装包更新与一键配置
一键安装缺失的 Nav2 导航核心及相关插件
# 1. 更新本地系统软件源索引 sudo apt update # 2. 一键安装大作业所需的全部官方 ROS 2 核心导航、建图算法与稳定中间件(剔除TEB) # 在ROS 2 Humble中,TEB算法虽然已被开源移植,但它并没有被打包进官方的Ubuntu apt二进制源中 # 我们在步骤3中通过开源下载 sudo apt install -y \ ros-humble-navigation2 \ ros-humble-nav2-bringup \ ros-humble-slam-toolbox \ ros-humble-rmw-cyclonedds-cpp检查并配置.bashrc环境变量
# 1. 确保刷新了 Humble 核心环境 echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc # 2. 设置小车模型为 burger 汉堡包(如果是 waffle_pi 请自行修改) echo "export TURTLEBOT3_MODEL=burger" >> ~/.bashrc # 3. 指定通信中间件为 CycloneDDS 确保数据吞吐稳定 echo "export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp" >> ~/.bashrc # 4. 激活当前终端的环境变量 source ~/.bashrc3. 构建工作空间并安装TEB
新建工作空间并进入
mkdir -p ~/turtlebot3_ws/src cd ~/turtlebot3_ws/src下载以下三个源码的.zip文件,并将其放到我们的~/turtlebot3_ws/src目录下
GitHub - ROBOTIS-GIT/turtlebot3_simulations at humble · GitHubSimulations for TurtleBot3. Contribute to ROBOTIS-GIT/turtlebot3_simulations development by creating an account on GitHub.https://github.com/ROBOTIS-GIT/turtlebot3_simulations/tree/humbleGitHub - ROBOTIS-GIT/turtlebot3 at humble · GitHubROS packages for Turtlebot3. Contribute to ROBOTIS-GIT/turtlebot3 development by creating an account on GitHub.
https://github.com/ROBOTIS-GIT/turtlebot3/tree/humbleGitHub - ros-navigation/navigation2_tutorials at humble · GitHubTutorial code referenced in https://docs.nav2.org/ - GitHub - ros-navigation/navigation2_tutorials at humble
https://github.com/ros-navigation/navigation2_tutorials/tree/humble
# 1. 解压官方 TEB 教程包并规范重命名 unzip navigation2_tutorials-humble.zip -d . mv navigation2_tutorials-humble navigation2_tutorials # 2. 解压 TurtleBot3 核心包并规范重命名 unzip turtlebot3-humble.zip -d . mv turtlebot3-humble turtlebot3 # 3. 解压 TurtleBot3 仿真包并规范重命名 unzip turtlebot3_simulations-humble.zip -d . mv turtlebot3_simulations-humble turtlebot3_simulations # 4. 清理掉已经解压完的 zip 包,保持工作空间干净 rm *.zip # 5. ls检查检查目录结构 ls一键安装底层依赖并编译
# 1. 回到工作空间的根目录 cd ~/turtlebot3_ws # 2. 更新本地 rosdep 数据库 rosdep update # 3. 一键自动安装 src 目录下所有源码包缺少的底层系统依赖 rosdep install --from-paths src --ignore-src -r -y # 4. 一键编译,确保在 ~/turtlebot3_ws 目录下,执行编译命令 colcon build刷新并永久化工作空间环境
# 将工作空间的刷新脚本写入环境 echo "source ~/turtlebot3_ws/install/setup.bash" >> ~/.bashrc # 让其在当前终端立即生效 source ~/.bashrc二、Gazebo 仿真、扫图与建图 (SLAM)
1. 启动 Gazebo 物理仿真迷宫世界
打开一个新的终端,执行以下指令,打开我们的世界:
export TURTLEBOT3_MODEL=burger ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py2. 启动 SLAM 异步建图工具箱
打开一个新的终端,执行以下指令,启动建图算法节点执行打开rviz2
export TURTLEBOT3_MODEL=burger ros2 launch slam_toolbox online_async_launch.py use_sim_time:=True3. 启动 Rviz2
打开一个新的终端,执行以下指令,启动建图算法节点执行打开rviz2,点击右下方的add按钮
export TURTLEBOT3_MODEL=burger ros2 launch turtlebot3_bringup rviz2.launch.py rviz_config:=/home/a/turtlebot3_ws/src/turtlebot3/turtlebot3_bringup/rviz/turtlebot3_slam.rviz选择我们的map并点击OK,将其添加到我们的左侧栏里
展开我们的map,并在对应的topic栏选择map
此时我们的地图显示成功,进入下一步
4. 启动键盘遥控节点(开始扫图)
打开一个新的终端,执行以下指令,开始构建我们的地图
export TURTLEBOT3_MODEL=burger ros2 run turtlebot3_teleop teleop_keyboard扫图操作:将鼠标指针保持点击在终端4窗口内部,使用键盘上的w(前进)、a(左转)、s(后退)、d(右转)、x(刹车/停止) 来控制小车,眼睛看着 Rviz2(终端 2 的界面),控制小车缓缓地在迷宫里兜圈子,把原本灰色的“未知区域”全部“刮”成白色,直到障碍物的黑色轮廓完整连成一片
5. 保存地图
打开一个新的终端,执行以下指令,保存我们构建的地图
mkdir -p ~/turtlebot3_ws/src/my_map ros2 run nav2_map_server map_saver_cli -f ~/turtlebot3_ws/src/my_map/map --fmt png执行以上命令后,我们在src目录下创建my_map文件夹会显示我们刚刚保存的地图
关闭我们刚刚建图打开的所有终端
三、开启自主导航实战
1. 启动 Gazebo 物理仿真世界
打开一个新的终端,导航需要物理世界提供真实的激光雷达和里程计数据,所以执行以下指令,打开我们的世界:
export TURTLEBOT3_MODEL=burger ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py2. 修改我们的配置文件burger.yaml
修改并保存参数,在编辑器中改完你想要的参数(比如把use_astar改成true,或者调整了sim_time),按下Ctrl + S保存文件
# 用 VS Code 打开 code /home/a/turtlebot3_ws/src/turtlebot3/turtlebot3_navigation2/param/burger.yaml按照以下表格内容,分别对我们的数据进行修改,每次只修改一个实验组对应的参数,其他参数全部恢复成默认值。测试完并记录数据后,再把这个参数改回去,接着测下一个(执行完步骤n后回到该步骤修改参数,继续顺序执行)
实验组别 | 核心参数名称 | 默认值 / 基准值 | 实验修改值 | 参数物理意义与实验观察点 |
Dijkstra 组 |
|
| 保持 | 此时使用 Dijkstra 算法,全图盲目搜索,计算时间较长,路径几何最优。 |
A* 组 |
|
| 修改为 | 开启 A* 启发式搜索。对比观察终端日志中的计算时间(Time)是否暴跌。 |
敏感度调节组 A |
|
| 调大至 或者调小至 | 网格底色代价。数值越大,算法越倾向于走直线;数值越小,路径越容易产生细微折线。 |
敏感度调节组 B |
|
| 调大至 | 代价因子。调大后,小车规划的路径会刻意远离圆柱体等障碍物,走空旷地带。 |
所属节点名称(Ctrl + F 搜索):planner_server
实验内容大纲 | 对应参数名称 | 默认值 / 基准值 | 实验修改建议值 | 参数物理机理与实验报告分析点 |
3.2 局部规划:激进速度流 |
|
| 调大至 调大至 | 小车最高线速度变快,且更渴望直奔终点。观察其在圆柱体阵列中是否容易刹车不及、速度产生剧烈震荡。 |
3.2 局部规划:保守贴线流 |
|
| 调大至 调大至 | 强化贴合全局路径的惩罚。小车会死死咬住中线,在障碍物前极度小心、频繁扭捏微调。 |
3.3 轨迹控制:直道响应速度 |
|
| 调大至 或者调小至 | 最大角速度。数值越大,偏离直道后修正车头的响应速度越快,误差曲线收敛越陡峭。 |
3.3 轨迹控制:稳态误差控制 |
|
| 暴增至 | 路径跟踪权重。数值极高时,稳态误差极小,但由于惯性,容易在直道两侧来回“画龙”蛇形震荡。 |
3.3 轨迹控制:U型弯前视时间 |
|
| 极限缩短至 | 近视眼效应:走一步看一步。过弯动作生硬,频繁打方向和减速,但在窄道内贴边紧。 |
3.3 轨迹控制:U型弯前视时间 |
|
| 大幅延长至 | 远视眼效应:类比大前视距离。过弯圆弧极顺滑,但无法感知眼前的急弯,入弯过早切内圈导致直接撞墙。 |
所属节点名称(Ctrl + F 搜索):controller_server
算法模式 | 需要修改的参数项名 | 默认值(DWA) | 切换修改值(TEB) | 综合对比观察点(走廊/死胡同/密集障碍物) |
切换为 TEB 算法 |
|
|
| 1. 死胡同场景:DWA 无法倒车卡死,TEB 能够弹性倒车脱困。 2. 速度平滑度:TEB 过弯呈平滑圆弧,DWA 呈生硬折线且速度频繁震荡。 |
当你做完 DWA 所有的调参,进入 “DWA 与 TEB 综合对比” 环节时,你需要修改控制器的核心插件声明:所属节点名称(Ctrl + F 搜索):controller_server中的FollowPath
3. 启动 Nav2 导航堆栈
打开一个新的终端,所以执行以下指令,启动定位算法(AMCL)、地图服务器(Map Server)和路径规划器:
export TURTLEBOT3_MODEL=burger ros2 launch turtlebot3_navigation2 navigation2.launch.py use_sim_time:=True map:=/home/a/turtlebot3_ws/src/my_map/map.yaml此时我们rviz打开后我们的小车没有找到自己的位置,左侧的导航状态目前是unknown(未知)
4. 在地图上对小车进行定位
先对小车进行定位:在 Rviz2 顶部的工具栏中,点击2D Pose Estimate按钮,观察 Gazebo 中小车的位置(默认在中心),在 Rviz2 地图的中心对应的位置,按住鼠标左键不放,顺着小车车头的朝向拉出一个绿色的箭头,然后松开,此时小车周围散落的绿色粒子群会瞬间聚拢,红色雷达点会和地图的黑色墙壁完美重合
此时我们还可以打开一个新的终端,并执行以下指令来确定我们的雷达和地图对齐(即定位是否精准)
ros2 topic echo /amcl_pose --field pose.covariance方向方差(第1个值):代表小车在横向位置上的不确定度,
方向方差(第7个值):代表小车在纵向位置上的不确定度。
朝向角方差(第36个值,即最后一个值):代表车头角度的不确定度。对齐良好的标准:这些数值应该非常接近 0(通常在
0.001到0.01数量级)。如果数值很大(比如超过0.5),说明小车自己都“不知道自己在哪”,雷达必然没有对齐
5. 算法的导航验证
下发导航目标:点击 Rviz2 顶部工具栏的Nav2 Goal按钮(图标通常是一个带有绿色箭头的靶心),在地图上选择一个距离小车较远、且中间隔着几个圆柱体障碍物的空白区域(最好是对角线),点击鼠标左键并拖拽出一个箭头(箭头方向代表小车到达终点后的车头朝向)后松开。
注意:我们每一次实验的起点和终点要相同!
你会看到地图上瞬间生成了一条从当前位置到终点的粉色平滑长线条。
观察算法的表现(记录实验数据):在机器人接收到导航目标(Nav2 Goal)并开始自主移动后,保持 Rviz2 可视化界面与控制终端(终端 2)前台运行。不进行任何人工干预,通过拦截系统的底层日志时间戳,提取关键量化指标:
拦截全局规划耗时():读取日志中
bt_navigator启动时间戳与controller_server首次计算控制量的时间戳,两者的绝对差值即为全局规划算法(Dijkstra/A*)的纯计算响应时间。
统计局部重规划频次():统计全程日志输出
Passing new path to controller的总次数,用以量化评估局部规划器对全局轨迹的跟踪敏感度与刷新频率。
计算绝对导航总耗时():在终端打印出
Reached the goal!时,拦截该行时间戳并与启动时间戳相减,计算出机器人从起点到终点的实际运行总时间。
定性观察速度动态波动:在机器人通过密集障碍物等瓶颈路段时,实时监听/cmd_vel话题,记录角速度(angular.z)在正负号之间的跳变频率,作为评估算法控制平滑度与速度震荡的依据。()
在工作空间中创建并编写文件:打开终端,直接利用绝对路径在 TurtleBot3 源码路径下新建并打开文件
gedit /home/a/turtlebot3_ws/src/turtlebot3/turtlebot3_navigation2/vel_oscillation_node.py复制以下代码
#!/usr/bin/env python3 import rclpy from rclpy.node import Node from geometry_msgs.msg import Twist import time class VelOscillationPlanner(Node): def __init__(self): super().__init__('vel_oscillation_planner') # 订阅 /cmd_vel 话题 self.subscription = self.create_subscription( Twist, '/cmd_vel', self.cmd_vel_callback, 10 ) # 核心统计变量 self.last_sign = 0 # 记录上一次角速度的正负号 (1代表正, -1代表负, 0代表静止) self.jump_count = 0 # 跳变次数计数器 self.start_time = None # 导航开始时间 self.get_logger().info('🚀 速度震荡与控制抖动实时监听节点已启动...') self.get_logger().info('正在等待小车运行并发布 /cmd_vel 数据...\n') def cmd_vel_callback(self, msg): current_w = msg.angular.z current_time = time.time() # 只有当小车真正开始运动时,才初始化启动时间 if self.start_time is None and (abs(msg.linear.x) > 0.001 or abs(current_w) > 0.001): self.start_time = current_time self.get_logger().info('⏱️ 检测到小车启动,开始统计跳变频率...') # 确定当前速度符号 if current_w > 0.005: current_sign = 1 # 左转 elif current_w < -0.005: current_sign = -1 # 右转 else: current_sign = 0 # 保持直行 # 核心逻辑:判断符号是否发生穿零跳变(从左打方向突变为右打方向,或反之) if self.last_sign != 0 and current_sign != 0 and current_sign != self.last_sign: self.jump_count += 1 # 计算从启动到现在的平均跳变频率 (次/秒) duration = current_time - self.start_time frequency = self.jump_count / duration if duration > 0 else 0.0 # 终端高亮实时打印 print(f"⚠️ [检测到震荡] 当前角速度: {current_w:6.3f} | 总跳变次数: {self.jump_count:3d} | 平均频率: {frequency:5.2f} Hz") # 更新状态,留待下一帧对比 if current_sign != 0: self.last_sign = current_sign def main(args=None): rclpy.init(args=args) node = VelOscillationPlanner() try: rclpy.spin(node) except KeyboardInterrupt: print("\n🛑 监听结束。") finally: node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()赋予脚本执行权限:由于是在
src源码目录内新建的脚本,Linux 系统默认不给予其执行权限。你必须在终端中运行以下命令,将其变成可执行文件:
chmod +x /home/a/turtlebot3_ws/src/turtlebot3/turtlebot3_navigation2/vel_oscillation_node.py在实验中快捷运行:在 Rviz2 中点击
Nav2 Goal下发了导航目标,小车开始在仿真环境里自主移动时,立刻新建一个终端 3,直接通过路径运行这个脚本:
python3 /home/a/turtlebot3_ws/src/turtlebot3/turtlebot3_navigation2/vel_oscillation_node.py保存可视化状态凭证:系统提示Goal succeeded后,对 Rviz2 界面进行全屏截图,记录全局路径几何形态、局部代价地图膨胀层与静态地图的贴合情况,作为轨迹跟踪特性的直观物证。