侧边栏壁纸
  • 累计撰写 17 篇文章
  • 累计创建 9 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

FishBot ROS2 项目五大模块解析

王富贵
2026-04-21 / 0 评论 / 0 点赞 / 2 阅读 / 0 字

FishBot ROS2 项目五大模块解析

写在前面

本文用通俗易懂的方式,帮你快速理解 FishBot 机器人项目的代码结构。不需要深厚的 ROS2 基础,看完就能明白每个模块是干嘛的。


模块总览

┌─────────────────────────────────────────────────────────────┐
│                     src 目录结构                             │
├─────────────────────────────────────────────────────────────┤
│  fishbot_description    →  机器人长什么样                     │
│  fishbot_interfaces     →  机器人用什么语言交流               │
│  fishbot_bringup        →  机器人开机启动器                   │
│  fishbot_cartographer   →  机器人绘图师(建图)               │
│  fishbot_navigation2    →  机器人导航系统                     │
└─────────────────────────────────────────────────────────────┘

模块一:fishbot_description —— 机器人的"身份证"

一句话解释

告诉系统:FishBot 长什么样、有多高、雷达装在哪里。

核心文件

urdf/fishbot.urdf —— 机器人的"三维简历"

里面定义了什么

部件形状尺寸安装位置
底盘(base_link)圆柱体高12cm,半径10cm离地7.6cm
激光雷达(laser_link)圆柱体高2cm,半径2cm底盘上方7.5cm
雷达坐标系(laser_frame)圆柱体同上同上

为什么要这个模块

想象你要给朋友介绍你的车:

  • 车长4米、宽1.8米
  • 雷达装在车顶正中央
  • 轮胎在四个角落

没有这些信息,导航软件连你的车能不能通过某个窄路都不知道。

实际作用

  1. 可视化:在 RViz 里能看到机器人的 3D 模型
  2. 碰撞检测:导航时知道机器人边界在哪里
  3. 坐标转换:激光雷达的数据要转换到机器人中心坐标系才能用

模块二:fishbot_interfaces —— 机器人的"方言词典"(消息实体类)

一句话解释

定义 FishBot 专用的通信格式,就像微信里的表情包,只有懂的人才能理解。

核心文件

1. 消息文件 msg/MyCustomMessage.msg

bool bool_test      →  布尔值(是/否)
float32 float32_test →  小数(如温度 25.5)
int32 int32_test    →  整数(如电量 80)
...(还有 byte、char、double 等各种类型)

这是干嘛的?

ROS2 自带很多标准消息(比如表示位置、速度的消息),但有时候不够用。比如你想发一个"机器人状态"消息,包含电量、温度、错误码,就可以自定义一个。

2. 服务文件 srv/FishBotConfig.srv

string key      →  配置项名称(如"max_speed")
string value    →  配置值(如"0.5")
---
string key      →  返回的配置项
string value    →  返回的配置值

这是干嘛的?

消息是"广播"(我说大家听),服务是"一对一问答"(你问我答)。

比如你想修改机器人的最大速度:

  • 你问:把 max_speed 改成 0.5
  • 机器人答:好的,max_speed 现在是 0.5

为什么要这个模块

ROS2 是一个分布式系统,不同节点之间要"说话"。这个模块就是定义"词汇表",确保大家说的是同一种语言。


模块三:fishbot_bringup —— 机器人的"开机键"

一句话解释

一键启动所有硬件驱动,就像电脑开机时自动加载显卡、声卡驱动一样。

核心文件

launch/bringup.launch.py —— 启动脚本

启动时干了什么(按顺序)

第1步:urdf2tf
    → 把机器人模型发布到 TF 坐标系
    → 让系统知道各个部件的相对位置

第2步:odom2tf
    → 订阅里程计话题 /odom
    → 把里程计数据转换成 TF 坐标变换
    → 告诉系统:机器人现在在哪里

第3步:micro_ros_agent
    → 通过 UDP 端口 8888 连接底层单片机
    → 接收底层传感器数据,发送控制指令

第4步:ros_serail2wifi
    → 串口转 WiFi 桥接
    → 让激光雷达的数据能通过网络传输

第5步:ydlidar(延迟5秒启动)
    → 启动激光雷达驱动
    → 开始扫描周围环境,发布 /scan 话题

核心代码解析

src/odom2tf.cpp 干了什么:

// 订阅 /odom 话题(里程计数据)
odom_subscribe_ = this->create_subscription<nav_msgs::msg::Odometry>(
    "odom", ...);

// 收到数据后,转换成 TF 并广播出去
tf_broadcaster_->sendTransform(transform);

里程计是什么?

就像汽车的里程表,记录走了多远。机器人通过编码器计算:

  • 我向前走了 1 米
  • 我向左转了 30 度

把这些信息转换成坐标,系统就能追踪机器人位置。

为什么要这个模块

没有它,你需要手动启动五六个程序,还要确保顺序正确。这个模块就是"一键启动"的解决方案。


模块四:fishbot_cartographer —— 机器人的"绘图师"

一句话解释

让机器人边走路边画地图,就像你第一次进陌生大楼时边走边记路。

核心文件

  • launch/cartographer.launch.py —— 启动脚本
  • config/fishbot_2d.lua —— 算法配置文件

建图原理(简化版)

         激光雷达扫描
              │
              ▼
    ┌─────────────────────┐
    │  看到障碍物在3米处   │
    │  看到障碍物在5米处   │
    │  看到墙在2米处      │
    └─────────────────────┘
              │
              ▼
    结合里程计(我走了1米)
              │
              ▼
    ┌─────────────────────┐
    │  原来那个障碍物      │
    │  现在离我2米了      │
    │  → 更新地图         │
    └─────────────────────┘

关键配置解读

fishbot_2d.lua 中的重要参数:

-- 使用2D SLAM(不是3D)
MAP_BUILDER.use_trajectory_builder_2d = true

-- 激光雷达有效范围:10厘米 ~ 3.5米
trajectory_builder_2d.min_range = 0.10
trajectory_builder_2d.max_range = 3.5

-- 使用里程计数据辅助建图
use_odometry = true

-- 开启回环检测(识别"这里我来过")
trajectory_builder_2d.use_online_correlative_scan_matching = true

建图时启动了哪些节点

节点作用
cartographer_node核心算法,处理激光数据,构建地图
cartographer_occupancy_grid_node把地图转换成栅格格式(黑白图)
rviz_node可视化工具,实时显示建图过程

为什么要这个模块

机器人需要知道环境长什么样才能导航。这个模块就是"探索新环境"时用的。

使用场景

  • 新办公室第一次部署机器人
  • 家里买了机器人,先让它"逛一圈"建图
  • 环境布局变了,重新建图

模块五:fishbot_navigation2 —— 机器人的"导航系统"

一句话解释

给定目标点,自动规划路线、避开障碍、到达目的地。就像手机地图导航,但机器人真的在走。

核心文件

  • launch/navigation2.launch.py —— 启动脚本
  • config/nav2_params.yaml —— 导航参数配置
  • maps/room.yaml + room.pgm —— 预存地图

导航系统架构

┌─────────────────────────────────────────────────────────────┐
│                      Navigation2 架构                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │   AMCL      │    │  Map Server │    │   Planner   │     │
│  │  (定位)    │    │  (地图服务)│    │ (全局规划) │     │
│  │             │    │             │    │             │     │
│  │ "我在哪?"  │    │ "环境长啥样?"│   │ "整体路线?" │     │
│  └──────┬──────┘    └──────┬──────┘    └──────┬──────┘     │
│         │                  │                  │            │
│         └──────────────────┼──────────────────┘            │
│                            ▼                               │
│                   ┌─────────────────┐                      │
│                   │  BT Navigator   │                      │
│                   │  (行为树导航)  │                      │
│                   └────────┬────────┘                      │
│                            │                               │
│         ┌──────────────────┼──────────────────┐            │
│         ▼                  ▼                  ▼            │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │  Controller │    │ Local Costmap│    │   Behavior  │     │
│  │ (局部控制) │    │ (局部地图) │    │ (异常恢复) │     │
│  │             │    │             │    │             │     │
│  │ "下一步怎走?"│   │ "附近有障碍?"│   │ "卡住怎么办?"│    │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

各组件详解

1. AMCL(自适应蒙特卡洛定位)

作用:确定机器人在地图中的位置

原理

  • 发射一堆"虚拟粒子"在地图上
  • 每个粒子猜测:"我可能在这里"
  • 根据激光雷达数据,排除不可能的猜测
  • 最终收敛到真实位置

配置参数

min_particles: 500      # 最少粒子数
max_particles: 2000     # 最多粒子数
laser_model_type: "likelihood_field"  # 激光模型

2. Planner(全局规划器)

作用:计算从起点到终点的最优路径

算法:NavFn(基于 Dijkstra/A*)

类比:就像地图 App 给你规划的蓝色路线

3. Controller(局部控制器)

作用:沿着全局路径走,同时避开突然出现的障碍

算法:DWB(Dynamic Window Approach)

原理

  • 考虑当前速度和加速度限制
  • 在可行的速度范围内采样
  • 选择"最像沿着路径走、又不会撞墙"的速度指令

速度限制

max_vel_x: 0.26         # 最大前进速度 0.26 m/s
max_vel_theta: 1.0      # 最大旋转速度 1.0 rad/s
acc_lim_x: 2.5          # 最大加速度

4. Costmap(代价地图)

作用:标记哪里可以走、哪里不行

两种地图

  • 全局代价地图:基于预存地图,包含静态障碍(墙、家具)
  • 局部代价地图:基于实时激光数据,包含动态障碍(人、移动的箱子)

膨胀层(Inflation)

  • 在障碍物外围加"缓冲圈"
  • 机器人不会贴着墙走,留安全距离

5. Behavior Server(行为服务器)

作用:处理异常情况

支持的行为

  • Spin:原地旋转(用于脱困或调整方向)
  • BackUp:后退(前面有障碍时)
  • Wait:等待
  • AssistedTeleop:人工辅助遥控

6. BT Navigator(行为树导航)

作用:协调所有组件,决定"现在该干什么"

行为树逻辑示例

如果 目标点更新了?
    → 重新规划路径
否则如果 路径被阻挡?
    → 尝试恢复行为(旋转/后退)
否则如果 到达目标?
    → 停止,报告成功
否则
    → 继续沿着路径走

导航流程示例

用户:去会议室!
  │
  ▼
AMCL:我在大厅,坐标 (10, 20)
  │
  ▼
Planner:规划路径 → 大厅 → 走廊 → 会议室
  │
  ▼
Controller:第一步,向前0.5米,速度0.2m/s
  │
  ▼
突然!有人走过
  │
  ▼
Local Costmap:检测到动态障碍
  │
  ▼
Controller:减速,绕行
  │
  ▼
到达会议室!

为什么要这个模块

这是机器人的"大脑"。前面的模块让机器人"能看、能走",这个模块让机器人"知道要去哪、怎么去"。


五个模块协作流程

┌─────────────────────────────────────────────────────────────────────┐
│                         完整工作流程                                 │
└─────────────────────────────────────────────────────────────────────┘

阶段一:准备(只需一次)
══════════════════════════════════════════════════════════════════════

    fishbot_description
           │
           ▼
    定义机器人模型(长什么样)
           │
           ▼
    fishbot_interfaces
           │
           ▼
    定义通信格式(说什么语言)


阶段二:开机(每次启动)
══════════════════════════════════════════════════════════════════════

    fishbot_bringup
           │
           ├── 加载机器人模型
           ├── 连接底层硬件(单片机)
           ├── 启动激光雷达
           └── 启动里程计转换
           │
           ▼
    机器人现在:能感知(激光)、能定位(里程计)


阶段三:建图(新环境)
══════════════════════════════════════════════════════════════════════

    fishbot_cartographer
           │
           ├── 接收激光数据
           ├── 融合里程计
           ├── 实时构建地图
           └── 保存地图文件
           │
           ▼
    得到:room.pgm(地图图片)+ room.yaml(地图信息)


阶段四:导航(日常使用)
══════════════════════════════════════════════════════════════════════

    fishbot_navigation2
           │
           ├── 加载预存地图
           ├── AMCL 定位当前位置
           ├── 接收目标点
           ├── 规划路径
           ├── 实时避障
           └── 到达目标

常用命令速查

# 1. 编译项目
colcon build

# 2. 启动基础功能(bringup)
ros2 launch fishbot_bringup bringup.launch.py

# 3. 启动建图
ros2 launch fishbot_cartographer cartographer.launch.py

# 4. 保存地图
ros2 run nav2_map_server map_saver_cli -f ~/map

# 5. 启动导航
ros2 launch fishbot_navigation2 navigation2.launch.py

# 6. 查看 TF 坐标系
ros2 run tf2_tools view_frames

# 7. 可视化
ros2 run rviz2 rviz2

总结

模块核心职责类比
description定义机器人外形身份证照片
interfaces定义通信语言方言词典
bringup启动硬件驱动电脑开机
cartographer构建环境地图探险家绘图
navigation2自主导航避障手机导航

这五个模块层层递进:

  1. 先定义"我是谁"
  2. 再定义"我说什么语言"
  3. 然后"启动我的身体"
  4. 接着"学会画地图"
  5. 最终"自主行走"

希望这份文档能帮你快速理解项目结构!有问题随时问。

0

评论区