# Odin-Nav-Stack **Repository Path**: taochangbo123/Odin-Nav-Stack ## Basic Information - **Project Name**: Odin-Nav-Stack - **Description**: Odin1 NeuPAN quadruped navigation stack (FireDog adapted) - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-28 - **Last Updated**: 2026-09-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

Odin-Nav-Stack

多底盘移动机器人自主导航栈 · Odin1 空间感知 + NeuPAN 神经规划

license noetic humble
--- 本仓库是一套**底盘无关**的移动机器人自主导航系统:NeuPAN 规划内核支持差速(`diff`)与阿克曼(`acker`)两类运动学,最终只输出一条与底盘无关的速度指令 `/cmd_vel`(`linear.x` 前进 + `angular.z` 转向)。换底盘 = 换一个“`/cmd_vel` 桥接层”而已,规划器一行不改。目前仓库内置两种桥接: - **YHS 轮式底盘**(差速 DT / 阿克曼 FW / 四轮 FR / 麦克纳姆 MK)——通过 SocketCAN(PCAN-USB)直连,`yhs_can_control` 驱动。**当前默认底盘。** - **四足机器人**(FireDog / Unitree Go2)——通过 TCP(tiji SDK)或串口桥接,同样吃 `/cmd_vel`。 系统以 **Odin1** 空间感知模块(3D SLAM 建图 + 重定位,输出点云 / 里程计 / IMU / 图像,可选接入)为传感器,以 **NeuPAN** 端到端神经局部规划器为核心: - 🚀 **自主导航与动态避障** —— 全局 A\* + NeuPAN 局部规划,支持绕障、卡死脱困、动态障碍记忆 - 🗺️ **建图与重定位导航** —— 一条命令建图,重启后基于 `.bin` 地图自动重定位 - 🔧 **多底盘适配** —— 差速 / 阿克曼 / 四足通吃:重训 DUNE 足迹模型 + 标定安装偏移 + 换桥接层即可 - 🖥️ **纯软件仿真** —— 无硬件也能在 ROS2 仿真里测试规划器、调参、验证新模型 - 🧠 **语义扩展(可选)** —— YOLO 物体检测 + VLM 场景理解 + VLN 视觉语言导航 > **新手指引**:没有机器人 → 从 [路径 A:仿真](#路径-a仿真ros2无硬件先跑通) 开始;有机器人 → 从 [路径 B:Docker 部署](#路径-bdocker-实机部署推荐) 开始;要改源码 → [路径 C:源码编译](#路径-c源码编译开发调试)。 --- ## 目录 - [系统架构](#系统架构) - [支持的底盘与传感器](#支持的底盘与传感器) - [硬件与软件要求](#硬件与软件要求) - [仓库目录结构](#仓库目录结构) - [新手上路:三条路径](#新手上路三条路径) - [路径 A:仿真(ROS2)](#路径-a仿真ros2无硬件先跑通) - [路径 B:Docker 部署(推荐)](#路径-bdocker-实机部署推荐) - [路径 C:源码编译](#路径-c源码编译开发调试) - [实机工作流:建图 → 导航](#实机工作流建图--导航) - [接口参考(扩展用)](#接口参考扩展用) - [速度下发与底盘接入](#速度下发与底盘接入) - [调参指引](#调参指引) - [适配新底盘 / 新机器人](#适配新底盘--新机器人) - [语义扩展:YOLO / VLM / VLN](#语义扩展yolo--vlm--vln) - [FAQ](#faq) - [故障排查](#故障排查) - [开源组件与许可](#开源组件与许可) --- ## 系统架构 ``` ┌─────────────────────────────────────────────┐ │ Odin1 传感器(可选) │ │ SLAM / 重定位 · 稠密点云 · 里程计 · IMU │ └──────────────┬──────────────────────────────┘ │ USB 3.0 ┌──────────────────▼──────────────────┐ │ odin_ros_driver (ROS1) │ │ 发布 /odin1/cloud_slam /odin1/odometry │ │ 发布 TF: odom → odin1_base_link │ │ (重定位模式额外发布 odom → map) │ └───────┬──────────────────┬───────────┘ │ 点云 │ 里程计/TF ┌─────────────▼────────┐ │ │ 点云 → 扫描 │ │ │ pc_to_scan 高度滤波 │ │ │ → /scan(±45° 扇形) │ │ └──────────┬───────────┘ │ ▼ │ ┌──────────────────────┐ │ │ fake360 障碍记忆 │ │ │ → /scan_360(360°) │ │ │ (或 YHS /scan3) │ │ └──────────┬───────────┘ │ ▼ │ ┌──────────────────────┐ │ │ 全局规划 map_planner │ │ │ 栅格地图→膨胀→A* │ │ │ → /initial_path │ (重定位/建图模式) │ goal_state_machine │ │ └──────────┬───────────┘ │ ▼ │ ┌────────────────────────────────▼────────┐ │ NeuPAN 局部规划器 │ │ DUNE 距离场 + NRMP MPC │ │ → /cmd_vel (Twist) │ └──────────────────────┬───────────────────┘ │ /cmd_vel (linear.x + angular.z) ┌────────────────▼────────────────┐ │ 速度桥接层(按底盘选) │ │ yhs_can_control (YHS 轮式, CAN) │ │ tiji_bridge (FireDog, TCP) │ │ serial_cmd_vel (嵌入式, 串口) │ └────────────────┬─────────────────┘ │ CAN / TCP / UART ┌────────────────▼─────────────────┐ │ 机器人底盘(差速/阿克曼/四足) │ └──────────────────────────────────┘ ``` **数据流一句话**:Odin1 点云 → 高度滤波 → 360° 障碍记忆 →(栅格地图下 A\* 出全局路径)→ NeuPAN 局部规划 → `/cmd_vel` → 桥接层 → 底盘。 | 模块 | 路径 | 作用 | |---|---|---| | Odin1 驱动 | `ros_ws/src/odin_ros_driver/` | 采集点云/里程计,SLAM 建图与重定位 | | 点云→扫描 | `whole.launch` 内 `pc_to_scan` | 高度滤波,只留“会撞到且跨不过”的障碍带 | | 障碍记忆 | `ros_ws/src/fake360/` | 把有限 FOV 扫描累积成 360° 记忆(占用格持续到再次扫到才更新) | | 草坪检测 | `ros_ws/src/grass_detector/` | 识别绿色草坪并入障碍(可选,户外用) | | 全局规划 | `ros_ws/src/map_planner/` | 栅格地图 A\*、目标状态机、路径平滑 | | 局部规划 | `NeuPAN/` | NeuPAN 端到端神经规划(本栈核心) | | YHS 底盘驱动 | `ros_ws/src/yhs_can_control/` | `/cmd_vel` → YHS 轮式底盘(SocketCAN),发布轮式里程计 `/odom` | | 四足桥接 | `ros_ws/src/tiji_bridge/` | `/cmd_vel` → FireDog(tiji SDK,TCP) | | 串口桥接 | `scripts/serial_cmd_vel_bridge.py` | `/cmd_vel` → 嵌入式底盘(UART ASCII) | | 语义检测 | `ros_ws/src/yolo_ros/` | YOLO 物体检测 + 语音指令(可选) | | VLM | `ros_ws/src/odin_vlm_terminal/` | 视觉语言模型场景描述(可选) | | 仿真 | `ros_ws/src/neupan_ros2/` + `ros_ws/src/ddr_minimal_sim/` | ROS2 纯软件仿真 | > **依赖已内联**:`NeuPAN`、`odin_ros_driver`、`yolov5` 等依赖已作为普通目录合入仓库,直接 `git clone` 即可,无需 `--recursive`。 --- ## 支持的底盘与传感器 | 组件 | 说明 | 桥接层 | 关键参数 | |---|---|---|---| | **YHS 轮式底盘**(默认) | DT 差速 / FW 前转向 / FR 四轮 / MK 麦克纳姆 | `yhs_can_control`(SocketCAN) | `CHASSIS_TYPE`、`yhs_can_control.yaml` 的 `if_name`/`wheel_base` | | FireDog 四足 | 1.174 × 0.7177 m,TCP 高层控制 | `tiji_bridge`(tiji SDK) | `TIJI_IP`、`tiji_bridge.launch` | | Unitree Go2 | 0.70 × 0.35 m | `unitree_control`(参考实现) | 官方 SDK | | 任意嵌入式底盘 | STM32 等 | `serial_cmd_vel_bridge.py`(UART) | `SERIAL_PORT`/`SERIAL_BAUD`/`SERIAL_RATE` | | **Odin1 传感器**(可选) | 3D 建图 + 重定位 + 点云/里程计/IMU | `odin_ros_driver`(USB 3.0) | `control_command.yaml` | > 底盘与传感器解耦:Odin1 负责“我在哪”,底盘负责“我怎么动”。YHS 底盘只有轮式里程计(`/odom`),可配合 Odin1 做定位(混合模式 `use_yhs=true + use_odin1=true`);也可纯 YHS 跑(`ODIN1=0`,仅超声波感知)。 --- ## 硬件与软件要求 | 项目 | 要求 | |---|---| | 传感器 | Odin1 空间感知模块(USB 3.0,可选) | | 机器人 | 底盘无关:差速 / 阿克曼 / 四足。YHS 轮式(默认)或 FireDog 四足已实测 | | 机载电脑 | NVIDIA Jetson Orin(JetPack 5.x),或 x86 主机 | | 操作系统 | Ubuntu 20.04(实机 ROS1)/ Ubuntu 22.04(仿真 ROS2) | | ROS | ROS1 Noetic(实机)/ ROS2 Humble(仿真) | | Docker(可选) | 24.0+,Compose v2 | --- ## 仓库目录结构 ``` Odin-Nav-Stack/ ├── deploy.sh # 一键部署/启动入口(install/start/mapping/reloc/doctor/…) ├── start_slam.sh # 启动 SLAM 导航(免建图) ├── start_mapping.sh # 启动建图 ├── start_relocalization.sh # 启动重定位导航(基于已建地图) ├── stop_nav.sh # 停止 ├── setup_can.sh # 上电 SocketCAN(YHS 底盘,免密授权) ├── sim_test.sh # ROS2 仿真一键测试 ├── train_dune.sh # DUNE 足迹模型训练 ├── map_edit.sh # 栅格地图手工修补 ├── build_image.sh # 构建 Docker 镜像 ├── docker/ │ ├── Dockerfile.{global,cn,x86_64} # 三种镜像源/架构 │ ├── docker-compose.yml │ ├── entrypoint.sh # 容器入口(launch/mapping/shell/save) │ ├── configs/ # ★ 实机可调配置(bind-mount,改完重启脚本生效) │ └── maps/ # ★ 地图持久化(grid / relocalization / pcd) ├── ros_ws/src/ # ROS1 工作空间(实机 + 仿真共用) │ ├── odin_ros_driver/ # Odin1 驱动 │ ├── yhs_can_control/ # YHS 底盘 CAN 驱动 │ ├── robot_common/ # 共享 topic 名 │ ├── robot_msgs/ # 底盘消息定义 │ ├── map_planner/ # A* + 目标状态机 │ ├── fake360/ # 障碍记忆 │ ├── neupan_ros2/ # ROS2 仿真规划器 │ ├── ddr_minimal_sim/ # ROS2 仿真环境 │ └── …(grass_detector / pcd2pgm / tiji_bridge / yolo_ros 等) ├── NeuPAN/ # 神经规划内核 ├── scripts/ # 辅助脚本(串口桥/录图/同步参数等) ├── docs/ │ ├── DOCKER_SETUP.md # Docker 部署详细说明 │ └── TUNING_GUIDE.md # ★ 完整调参手册 └── yolov5/ # 语义检测(子模块,可选) ``` --- ## 新手上路:三条路径 | 你的情况 | 选择 | |---|---| | 没有机器人,想先了解 / 调参 / 验证算法 | **路径 A:仿真** | | 有机器人,想最快跑起来 | **路径 B:Docker 部署** | | 要改源码、深度开发 | **路径 C:源码编译** | --- ## 路径 A:仿真(ROS2,无硬件先跑通) > 需要:Ubuntu 22.04 + ROS2 Humble + Python 依赖(torch / cvxpy 等)。 > 仿真用 ROS2 版规划器 `neupan_ros2`,与实机 NeuPAN **同核**,调参经验直接互通。 ### A1. 编译仿真工作空间 ```bash cd ros_ws source /opt/ros/humble/setup.bash colcon build --symlink-install --packages-select neupan_ros2 ddr_minimal_sim source install/setup.bash ``` 依赖(若无): ```bash pip3 install "numpy<2.0" torch torchvision scipy matplotlib pyyaml sudo apt install ros-humble-desktop-full # 已装 ROS2 可跳过 ``` > `--symlink-install` 让配置目录以软链接方式安装——**之后改 yaml 场景/机器人配置都不用重新编译**,只有改 C++ 才需要 `colcon build`。 ### A2. 一键启动仿真 在**仓库根目录**: ```bash ./sim_test.sh # 交互式菜单,无脑回车即可 ./sim_test.sh -l # 列出全部场景 ./sim_test.sh -s empty -r simulation -g 3 3 # empty 场景 + 仿真小车 + 自动发目标 (3,3) ./sim_test.sh -s maze --no-rviz # 无界面模式 ``` 内置场景(`ros_ws/src/ddr_minimal_sim/config/scenario_*.yaml`):`empty` 空旷、`maze` 迷宫、`corridor` 走廊、`narrow_passage` 窄通道、`park_pedestrians` / `campus_pedestrians` 含行人、`polygon_random` 随机多边形、`u_trap` U 形陷阱。 内置机器人(`ros_ws/src/neupan_ros2/config/robots/<名>/`):`simulation` 仿真小车(0.322×0.220 m,自带模型,开箱即用)、`odin_dog` 狗(1.174×0.7177 m)、`car` 实车(1.08×0.76 m)、`limo` / `ranger` / `scout` 等参考配置。 启动后在 RViz 工具栏 **「2D Goal Pose」** 点地图发目标,机器人自主避障导航过去。 ### A3. 仿真里调参(免重启) - **规划器 `adjust` 段**(`q_s` / `eta` / `d_max` / `p_u` …)改 `ros_ws/src/neupan_ros2/config/robots/<机器人>/planner.yaml`,节点 **每 1 秒热加载**,不用重启仿真。 - **场景**(障碍物/初始位姿)改 `ros_ws/src/ddr_minimal_sim/config/scenario_*.yaml`,Ctrl+C 重启脚本。 - **机器人尺寸**(`length`/`width`)改 planner.yaml 后重启,但**必须与 DUNE 模型训练几何一致**(改了尺寸要重训,见[适配新底盘](#适配新底盘--新机器人))。 ### A4. 在仿真里测你自己训练的模型 ```bash ./train_dune.sh -l <长> -w <宽> -n <模型名> --bg # 后台训练,见"适配新底盘" ./train_dune.sh --status # 看进度 ./sim_test.sh -s empty -r <模型名> # 训完直接测 ``` --- ## 路径 B:Docker 实机部署(推荐) > 不用在主机装 ROS / PyTorch,容器内自带全部依赖。详细说明见 [docs/DOCKER_SETUP.md](docs/DOCKER_SETUP.md)。 ### B1. 准备 ```bash # 1. 克隆仓库(依赖已内联,无需 --recursive) git clone https://gitee.com/taochangbo123/Odin-Nav-Stack.git cd Odin-Nav-Stack # 2. Odin1 USB 规则(只需一次,无 Odin1 可跳过) echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="2207", ATTR{idProduct}=="0019", MODE="0666", GROUP="plugdev"' \ | sudo tee /etc/udev/rules.d/99-odin-usb.rules sudo udevadm control --reload && sudo udevadm trigger # 3. 构建镜像(三选一) docker build -f docker/Dockerfile.x86_64 -t odin-nav:latest . # x86 主机 docker build -f docker/Dockerfile.global -t odin-nav:latest . # Jetson(JetPack 5.x) docker build -f docker/Dockerfile.cn -t odin-nav:latest . # 国内镜像源加速 ``` > **Jetson JetPack 6.x**:`docker build -f docker/Dockerfile.global --build-arg BASE_IMAGE=dustynv/ros:noetic-pytorch-l4t-r36.2.0 -t odin-nav:latest .` 也可以用一键脚本完成以上全部:`./deploy.sh install`(自动装 docker、写 udev、构建镜像)。 ### B2. 一键使用 仓库根目录封装好了脚本,**不需要记 roslaunch 命令**: ```bash ./start_mapping.sh mymap # ① 建图 ./start_relocalization.sh mymap # ② 基于地图重定位导航(常用) ./start_slam.sh # ② 或:免建图 SLAM 直接导航 ./stop_nav.sh # ③ 停止 ``` 启动后 RViz 自动打开,**点工具栏「2D Nav Goal」发目标**即可。RViz 没弹出来?宿主机先执行 `xhost +local:` 允许容器访问 X server。 ### B3. 选择底盘 / 传感器(环境变量) 容器入口按环境变量选择底盘与传感器(改 `docker/docker-compose.yml` 或启动时覆盖): | 环境变量 | 默认 | 说明 | |---|---|---| | `CHASSIS` | `yhs` | `yhs` = YHS 轮式底盘(SocketCAN);`odin` = 四足(tiji/串口桥) | | `CHASSIS_TYPE` | `DT` | YHS 型号:`DT` 差速 / `FW` 前转向 / `FR` 四轮 / `MK` 麦克纳姆 | | `ODIN1` | `1` | `1` = 运行 Odin1 传感器驱动做定位;`0` = 纯底盘(仅轮式/超声波感知) | | `TIJI_IP` | `192.168.29.112` | FireDog IP(`CHASSIS=odin`);设 `none` 改用串口桥 | | `SERIAL_PORT/BAUD/RATE` | `/dev/ttyUSB0` / `115200` / `20` | 串口桥参数 | | `ENTRYPOINT_MODE` | `launch` | `launch` 导航 / `mapping` 建图(由 start 脚本覆盖) | 示例: ```bash CHASSIS=yhs CHASSIS_TYPE=DT ./start_slam.sh # YHS 差速底盘(默认) CHASSIS=yhs CHASSIS_TYPE=FW ./start_slam.sh # YHS 阿克曼底盘 CHASSIS=odin TIJI_IP=192.168.1.20 ./start_slam.sh # FireDog 换 IP CHASSIS=odin TIJI_IP=none ./start_slam.sh # 嵌入式底盘走串口 ODIN1=0 ./start_slam.sh # 纯 YHS 底盘,不开 Odin1 ``` > **YHS 底盘还需要先把 SocketCAN 拉起来**。`start_*.sh` 已自动调用 `setup_can.sh`(先 down → 设 bitrate 500000 → up)。首次使用前配置一次免密授权(一次性): ```bash # 用你的密码执行,之后 setup_can.sh 里的 sudo ip 命令不再弹密码 echo 'test ALL=(ALL) NOPASSWD: /usr/sbin/ip link set down can0, /usr/sbin/ip link set up can0, /usr/sbin/ip link set can0 type can bitrate 500000' \ | sudo tee /etc/sudoers.d/99-can0 && sudo chmod 0440 /etc/sudoers.d/99-can0 ``` 也可以手动:`sudo ip link set down can0 && sudo ip link set can0 type can bitrate 500000 && sudo ip link set up can0`。 ### B4. 不改镜像改配置 所有可调配置都 bind-mount 在 `docker/configs/`(主机直接改,**重启脚本生效**;NeuPAN 的 `adjust` 参数热加载)。首次部署先把默认配置拷出来: ```bash mkdir -p docker/configs docker/maps cp ros_ws/src/odin_ros_driver/config/control_command.yaml docker/configs/ cp NeuPAN/neupan/ros/configs/config.yaml docker/configs/ cp NeuPAN/neupan/ros/configs/planner.yaml docker/configs/ cp ros_ws/src/map_planner/launch/whole.launch docker/configs/ cp ros_ws/src/yhs_can_control/config/yhs_can_control.yaml docker/configs/ cp ros_ws/src/yhs_can_control/launch/yhs_can_control.launch docker/configs/ ``` | 文件 | 控制 | |---|---| | `control_command.yaml` | Odin1 驱动:模式(`custom_map_mode`)、地图路径、时钟、数据流开关 | | `config.yaml` | NeuPAN:话题、坐标系、DUNE 模型路径、卡死脱困 | | `planner.yaml` | NeuPAN:MPC 权重、机器人尺寸、`adjust` 调参段 | | `whole.launch` | A\*、fake360、高度滤波、TF、底盘选择 | | `yhs_can_control.yaml` | YHS 底盘:CAN 接口名、里程计 frame、轮距、超声波布局 | | `yhs_can_control.launch` | YHS 底盘节点启动 | | `maps/` | 地图持久化:`.bin` 重定位图 / `.pgm` 栅格图 / `.pcd` 点云 | --- ## 路径 C:源码编译(开发调试) ### C1. 克隆仓库 ```bash git clone https://gitee.com/taochangbo123/Odin-Nav-Stack.git cd Odin-Nav-Stack ``` ### C2. 安装系统依赖(ROS1 Noetic) ```bash export ROS_DISTRO=noetic sudo apt update sudo apt install -y \ ros-${ROS_DISTRO}-tf2-ros ros-${ROS_DISTRO}-tf2-geometry-msgs \ ros-${ROS_DISTRO}-cv-bridge ros-${ROS_DISTRO}-tf2-eigen \ ros-${ROS_DISTRO}-pcl-ros ros-${ROS_DISTRO}-move-base \ ros-${ROS_DISTRO}-dwa-local-planner ros-${ROS_DISTRO}-can-msgs ``` ### C3. 修改 Odin1 驱动(用 Odin1 时必需) **配置**:打开 `ros_ws/src/odin_ros_driver/config/control_command.yaml`,确认 `use_host_ros_time: 1`。 > ⚠️ 必须为 1!Odin1 内部时钟是开机时长(uptime),与主机墙上时间差很远;不开启会导致 TF 时间戳错乱、导航异常。 **代码**:编辑 `ros_ws/src/odin_ros_driver/include/host_sdk_sample.h`(注意改 **ROS1** 段,不是 ROS2 段): 1. `publishOdometry` 里**注释掉低频 TF 发布**(`OdometryType::STANDARD` 分支的 `tf_broadcaster->sendTransform(...)` 整段); 2. `OdometryType::HIGHFREQ` 分支**添加高频 TF 发布**(发布 `odom → odin1_base_link`)。完整代码块见 `docs/DOCKER_SETUP.md`。 ### C4. 创建 NeuPAN Python 环境 ```bash # 安装 miniconda 后: conda install -n base -c conda-forge mamba export ROS_DISTRO=noetic mamba create -n neupan -y mamba activate neupan conda config --env --add channels conda-forge conda config --env --remove channels defaults conda config --env --add channels robostack-${ROS_DISTRO} mamba install -n neupan ros-${ROS_DISTRO}-desktop colcon-common-extensions catkin_tools rosdep ros-dev-tools -y mamba run -n neupan pip install torch==2.8.0 --index-url https://download.pytorch.org/whl/cpu pip install -e NeuPAN ``` > **Jetson 用户**:把 PyTorch 换成 [NVIDIA 官方 Jetson wheel](https://forums.developer.nvidia.com/t/pytorch-for-jetson/72048)。 ### C5. 编译 ROS 工作空间 **系统 ROS 编译**(推荐,先 `mamba deactivate` 退出 conda): ```bash cd ros_ws source /opt/ros/${ROS_DISTRO}/setup.bash catkin_make -DCMAKE_BUILD_TYPE=Release source devel/setup.bash ``` **Conda ROS 编译**(无系统 ROS 时): ```bash mamba activate neupan mamba install -c conda-forge -c robostack-noetic \ ros-noetic-pcl-ros ros-noetic-compressed-image-transport \ ros-noetic-compressed-depth-image-transport ros-noetic-image-transport cd ros_ws catkin_make -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DPCL_VISUALIZATION=OFF -DQT_HOST_PATH=$CONDA_PREFIX ``` ### C6. 启动(源码方式) ```bash # 终端 1:建图/导航 launch(等价于容器入口) roslaunch map_planner whole.launch use_yhs:=true use_odin1:=true chassis_type:=DT # 终端 2:NeuPAN 局部规划器 mamba activate neupan python NeuPAN/neupan/ros/neupan_ros.py ``` --- ## 实机工作流:建图 → 导航 > Docker 用户直接用根目录脚本;源码安装用户用括号里的等价命令。 ### 第 1 步:建图 ```bash ./start_mapping.sh mymap # Docker 一键 ``` 然后**推着 / 遛着机器人走遍要建图的区域**,按脚本提示依次执行:开始记录 → 走完 → 停止记录 → 保存转换。产物: - `docker/maps/relocalization/mymap.bin` —— 重定位用的 SLAM 地图 - `docker/maps/grid/mymap.pgm` —— A\* 用的栅格地图(可用 GIMP / `./map_edit.sh` 手工修补) - `docker/maps/pcd/mymap.pcd` —— 原始点云 ### 第 2 步:导航(二选一) **方式一:重定位导航(推荐,大场景)** ```bash ./start_relocalization.sh mymap ``` - 需在**原始建图轨迹 1m / ±10° 范围内**启动(自动重定位); - 重定位成功后 RViz Fixed Frame 设为 `map`,能看到 `map → odom → base_link` TF 树; - 可选:`GRASS=1 ./start_relocalization.sh mymap` 开启草坪检测(户外避草坪); - 用空白栅格图测 A\*:`./start_relocalization.sh mymap empty`。 **方式二:SLAM 免建图导航(小场景 / 快速验证)** ```bash ./start_slam.sh ``` 无需地图,驱动以里程计模式运行,NeuPAN 直接用实时 SLAM 点云避障。 ### 第 3 步:发目标 RViz 工具栏 **「2D Nav Goal」** 点击地图 → A\* 全局规划 → NeuPAN 局部跟踪避障 → 到达后报告 `/neupan/arrive`。 --- ## 接口参考(扩展用) 本节是本栈的**对外契约**——接入新底盘、新传感器、新规划器、新可视化都从这里入手。 ### 1. ROS Topic 接口 | Topic | 类型 | 方向 | 生产者 → 消费者 | 说明 | |---|---|---|---|---| | `/odin1/cloud_slam` | `sensor_msgs/PointCloud2` | 输入 | odin_ros_driver → pc_to_scan / grass / fake360 | Odin1 SLAM 稠密点云 | | `/odin1/odometry` | `nav_msgs/Odometry` | 输入 | odin_ros_driver → NeuPAN | Odin1 里程计 | | `/scan` | `sensor_msgs/LaserScan` | 内部 | pc_to_scan → fake360 | 高度滤波后的 ±45° 扫描 | | `/scan3` | `sensor_msgs/LaserScan` | 输入 | yhs_can_control → fake360 | YHS 超声波伪扫描(纯底盘模式用) | | `/scan_360` | `sensor_msgs/LaserScan` | 内部 | fake360 → NeuPAN | 360° 障碍记忆扫描 | | `/scan_360_grass` | `sensor_msgs/LaserScan` | 内部 | grass_detector → NeuPAN | 并入草坪障碍后的扫描(`GRASS=1`) | | `/map` | `nav_msgs/OccupancyGrid` | 输入 | map_server → map_planner | 栅格地图(重定位模式) | | `/inflated_map` | `nav_msgs/OccupancyGrid` | 输出 | map_planner → RViz | 膨胀后的地图 | | `/move_base_simple/goal` | `geometry_msgs/PoseStamped` | 输入 | RViz → goal_state_machine | 导航目标(重定位模式) | | `/neupan/goal` | `geometry_msgs/PoseStamped` | 输入 | 外部 → NeuPAN | 导航目标(SLAM 模式,NeuPAN 直连) | | `/initial_path` | `nav_msgs/Path` | 内部 | map_planner → NeuPAN | A\* 全局参考路径 | | `/waypoints` | `nav_msgs/Path` | 输入 | 外部 → NeuPAN | 路点输入(NeuPAN 自行插值) | | **`/cmd_vel`** | `geometry_msgs/Twist` | **输出** | NeuPAN → 桥接层 | **核心输出**:`linear.x` 前进、`angular.z` 转向 | | `/neupan/arrive` | 自定义 | 输出 | NeuPAN → goal_state_machine | 到达事件 | | `/odom` | `nav_msgs/Odometry` | 输出 | yhs_can_control → 外部 | YHS 轮式里程计 | | `/chassis_info_fb` | `robot_msgs/DgtChassisInfoFb` | 输出 | yhs_can_control → 外部 | YHS 底盘反馈(控制/IO/BMS) | | `/yhs/control_mode` | `std_msgs/Bool` | 输出 | yhs_can_control → 外部 | 底盘控制模式(joypad/自动) | | `/ultrasonic` | `robot_msgs/Ultrasonic` | 输出 | yhs_can_control → 外部 | YHS 超声波原始数据 | > **跨 ROS1/ROS2**:容器内 `whole.launch` 自带 `foxglove_bridge`,把上述所有 ROS1 topic 以 WebSocket(`ws://:8765`)暴露,宿主机 ROS2 / Foxglove Studio 无需装 ROS1 即可订阅。也可用 `docs/DOCKER_SETUP.md` 里的 UDP 桥接 `/cmd_vel`。 ### 2. TF 坐标接口 | 变换 | 来源 | 说明 | |---|---|---| | `odom → odin1_base_link` | odin_ros_driver(动态) | Odin1 里程计位姿 | | `odom → map` | odin_ros_driver(重定位模式) | 重定位成功后发布 | | `odin1_base_link → base_link` | `whole.launch` 静态 TF | **安装偏移**(换底盘要改) | | `base_link → ul_link` | `yhs_can_control.launch` 静态 TF | 超声波传感器相对底盘 | | `odom → base_link` | yhs_can_control(`tfUsed`) | YHS 轮式里程计(与 Odin1 二选一,避免 TF 冲突) | ### 3. 配置文件接口 | 文件 | 命名空间 / 段 | 关键项 | |---|---|---| | `config.yaml` | `topic.*` / `frame.*` / `odom_feedback` / `stuck_escape` / `prealign` / `adaptive_d_max` / `scan_range` | 话题名、坐标系、DUNE 路径、卡死脱困 | | `planner.yaml` | `receding` / `robot.*` / `ipath.*` / `pan.*` / `adjust.*` | MPC、运动学、尺寸、路径、权重 | | `whole.launch` | `` | A\*、fake360、高度滤波、TF、底盘选择 | | `control_command.yaml` | `register_keys` | Odin1 数据流、模式、地图路径 | | `yhs_can_control.yaml` | `yhs_can_control.*` / `ultrasonic.*` | CAN 接口、里程计、轮距、超声波 | ### 4. Launch 参数接口(`whole.launch`) | 参数 | 默认 | 说明 | |---|---|---| | `use_yhs` | `true` | 是否启动 YHS 底盘 CAN 驱动 | | `use_odin1` | `false` | 是否启动 Odin1 传感器 + pc_to_scan + 相关 TF | | `chassis_type` | `DT` | YHS 型号(DT/FW/FR/MK) | | `use_grid_map` | `true` | 是否启用栅格地图 + A\* + map_server(重定位模式) | | `use_fake360` | `true` | 是否启用 360° 障碍记忆 | | `use_grass_detector` | `false` | 是否启用草坪检测 | | `inflation_radius` | `0.25` | 静态地图膨胀半径 | | `goal_tolerance` | `0.6` | 目标到达容差 | | `fake360_cell_decay_sec` | `4.0` | 占用格衰减时间(秒) | | `fake360_confirm_free_frames` | `3` | 清除占用格需的“实际命中更远”帧数 | | `obstacle_cost_weight` / `obstacle_cost_safe_distance` | `3.0` / `0.5` | A\* 居中偏好 | | `smoothing_iterations` / `smoothing_max_deviation_m` | `20` / `0.20` | 路径平滑 | ### 5. 扩展新模块的三个入口 - **新规划器**:实现“订阅障碍扫描 + 发布 `/cmd_vel`”即可替换 NeuPAN,上层 A\* / fake360 不变。 - **新传感器**:替换 `topic.scan`(NeuPAN)与 pc_to_scan 的 `cloud_in`,输出 `LaserScan` 即可。 - **新底盘**:订阅 `/cmd_vel` 转成底盘协议,回发里程计 `/odom` + TF `odom→base_link`。参考 `yhs_can_control`(CAN)或 `scripts/serial_cmd_vel_bridge.py`(串口)即可。 --- ## 速度下发与底盘接入 NeuPAN 的最终输出是 `/cmd_vel`(`linear.x` + `angular.z`)——**这层接口与底盘类型无关**,接哪种底盘取决于桥接层。 ### YHS 轮式底盘(默认) `yhs_can_control` 直接订阅 `/cmd_vel`,转成 YHS 协议 CAN 帧(控制帧 `0x98C4D1D0` + IO 解锁帧 `0x98C4D7D0`),经 SocketCAN 下发;同时回读底盘反馈帧发布 `/odom` / `/chassis_info_fb` / `/scan3`。 - CAN 接口:`yhs_can_control.yaml` 的 `if_name`(默认 `can0`) - 解锁:驱动启动后以 5 Hz 发送解锁 IO 帧(下降沿解锁,见 `yhs_dt_can_control.cpp` 的 `UnlockTimerCb`) - 里程计 frame:`odom_frame` / `base_link_frame`,`tfUsed` 控制是否自己广播 `odom→base_link`(配 Odin1 定位时设为 `false` 避免 TF 冲突) ### FireDog 四足(tiji SDK,TCP) `tiji_bridge` 把 `/cmd_vel` 转成 `HighCmd.bodyVel = {vx, vy, vyaw}`,按 100 Hz 持续发送。内置安全机制(参数在 `tiji_bridge.launch` 改): | 机制 | 参数 | 默认 | 说明 | |---|---|---|---| | 速度限幅 | `max_vx` / `max_vy` / `max_vyaw` | 0.8 / 0.4 / 1.4 | 与 SDK 示例一致 | | 指令看门狗 | `cmd_timeout` | 0.5 s | `/cmd_vel` 超时自动发零速 | | 起立闸门 | `stand_settle` / `stand_timeout` | 1.0 / 3.0 s | 起立稳定前闸住速度 | ### 串口(STM32 等嵌入式底盘) `scripts/serial_cmd_vel_bridge.py` 把 `/cmd_vel` 以 ASCII 行 `vx vy omega\r\n` 写到串口(默认 `/dev/ttyUSB0` @ 115200,20 Hz),协议在脚本 `serialize()` 里改。设 `TIJI_IP=none` 时容器入口自动启动。 ### 自定底盘(扩展模板) 最小桥接层只需两件事:① 订阅 `/cmd_vel`;② 发布 `/odom` + TF `odom→base_link`。参考实现:`yhs_can_control`(CAN)、`scripts/serial_cmd_vel_bridge.py`(串口)。 --- ## 调参指引 完整参数手册见 **[docs/TUNING_GUIDE.md](docs/TUNING_GUIDE.md)**(每个参数的含义、推荐区间、按症状查表)。速查: | 症状 | 调哪里 | |---|---| | **遇障停在原地不绕行** | `planner.yaml` → **调高 `adjust.p_u`**(前进驱动权重)。停车点间距恰好等于 `d_max` 就是这个病 | | 提速后开始剐蹭障碍 | `ref_speed` 涨了就要按比例**调低 `adjust.p_u`** | | 绕障太贴 / 太远 | `adjust.d_max`(斥力作用半径,超出即完全无视)、`adjust.eta` | | 路径抖动 | `adjust.p_w` / `p_dw` / `p_w_cross`(角速度阻尼三件套)、`cmd_w_lpf_alpha` | | 目标点停不准 | `whole.launch` → `goal_tolerance`(默认 0.6 m) | | 起点/终点被判占用 | `whole.launch` → `inflation_radius`(必须 ≥ 机器人半宽) | | 机器人尺寸变了 | `planner.yaml` → `robot.length/width`(**必须重训 DUNE!**) | | 误避能跨过的障碍 | `whole.launch` → `pc_to_scan` 的 `min_height`/`max_height` | **修改生效方式**:仿真里 `adjust` 段热加载(1 秒);实机改 yaml 后重启对应节点;改 `.launch` 重启 launch;改 C++ 需 `catkin_make --pkg <包名>`。 **仿真调参同步到实车**:在仿真调好后,用 `scripts/sync_planner_params.py` 把 `adjust`/MPC 参数同步到 `docker/configs/planner.yaml`(`--dry-run` 预览、`--check` 校验),它会拦截“机器人尺寸不一致”和“速度超过 FireDog SDK 限幅”等危险配置。 > 核心调参思想(详见 TUNING_GUIDE 的 `p_u` vs `eta` 尺度不对称一节):绕障奖励是线性项(`eta·T·d_max`),前进驱动是二次项(`p_u²·T·ref_speed²`)。低速平台照抄上游权重会让绕障项压倒前进项上百倍,“贴着 `d_max` 停住”就成了真正的全局最优。所以 `ref_speed` 降到 0.5 后必须把 `p_u` 抬到 ~8,并把 `p_w`/`p_dw`/`p_w_cross` 一起按 ~6 倍抬。 --- ## 适配新底盘 / 新机器人 本栈“底盘无关”,换新机器人 = 以下**五步配套修改**。默认配置面向 YHS 实车(1.08 × 0.76 m,`car` 模型);换成其他底盘同理。 ### 1. 训练 DUNE 足迹模型(必需) DUNE 是按机器人几何形状训练的距离场网络——它学会“任意一点到机器人矩形足迹的距离”。**换了尺寸必须重训**。 ```bash ./train_dune.sh # 交互式:问尺寸/名字/规模 ./train_dune.sh -l 1.08 -w 0.76 -n my_car # 直接指定(单位:米) ./train_dune.sh --quick # 先快速试跑验证流程 ./train_dune.sh --status # 查看进度 ``` - 训练产物:`NeuPAN/example/dune_train/model/<名字>/model_.pth` - 产物自动生成仿真机器人配置,训完即可 `./sim_test.sh -s empty -r <名字>` 测试 - 实机使用:把 `config.yaml` 的 `dune_checkpoint` 指向新模型,并同步 `planner.yaml` 的 `robot.length/width` > 运动学选择:`kinematics: diff`(差速 / 履带 / 四足)或 `acker`(阿克曼舵轮,需在训练 yaml 和 `planner.yaml` 都改为 `acker`)。 ### 2. 标定安装偏移 TF(传感器不在机器人中心时) `whole.launch` 里用静态 TF 描述传感器与底盘中心的关系: ```xml ``` - `base_link` = **机器人几何中心**(DUNE 足迹中心);`odin1_base_link` = Odin1 中心; - `x/y/z` 是**传感器坐标系下底盘中心的位置**,方向别搞反。NeuPAN 通过 TF 自动补偿偏心(含原地旋转圆弧)。 ### 3. 点云高度滤波(只切传感器所在高度) `whole.launch` 里 `pc_to_scan` 的滤波带(相对 `odin1_base_link`): ```xml ``` 只保留传感器高度附近 ±几厘米的点,地面斜坡和头顶悬空物进不了 `/scan`。离线建图 `pcd2pgm` 的同名参数保持一致。 ### 4. 运动学与速度限幅 `planner.yaml` 的 `robot:` 段: ```yaml robot: kinematics: 'diff' # diff 差速 / acker 阿克曼 max_speed: [0.8, 0.8] # [线速度 m/s, 角速度 rad/s],对齐底盘实际限幅 max_acce: [1.0, 0.8] length: 1.08 # 必须与 DUNE 训练几何一致 width: 0.76 ``` ### 5. 接底盘桥接层 - **YHS 轮式底盘**:设 `CHASSIS=yhs`、`CHASSIS_TYPE=DT|FW|FR|MK`,改 `yhs_can_control.yaml` 的 `if_name`(CAN 口)、`wheel_base`(阿克曼轮距)、`odom_frame`/`base_link_frame`(里程计 frame)。 - **四足 / 嵌入式**:设 `CHASSIS=odin` + `TIJI_IP`(TCP)或 `TIJI_IP=none`(串口),改对应桥接参数。 - **全新底盘**:照[自定底盘模板](#自定底盘扩展模板)写一个 `/cmd_vel` 订阅器。 > **换机器人最小改动清单**:① 重训 DUNE(尺寸)→ ② 改安装偏移 TF → ③ 改高度滤波 → ④ 改 `kinematics`/`max_speed`/`length`/`width` → ⑤ 换桥接层。改完先 `./sim_test.sh -r <新模型>` 仿真验证,再上实车。 --- ## 语义扩展:YOLO / VLM / VLN > **算力提示**:以下功能计算量大,机载算力不足时部署到伴生电脑(ROS 主从)。Docker 镜像不含这些。 ### YOLO 物体检测 + 语音导航 导航到检测到的具体物体,需要 Odin1 深度图与去畸变图像。安装依赖后两个终端启动: ```bash roslaunch odin_ros_driver odin1_ros1.launch ./run_yolo_detector.sh ``` 交互命令(支持中文):`list` 列出物体 · `物体名` 显示 3D 位置 · `去第N个物体的方向` 发目标 · `mode` 切换文字/语音。 ### VLM 场景理解 / VLN 视觉语言导航 分别见 `ros_ws/src/odin_vlm_terminal/` 与 `scripts/VLN.py`,需额外模型与多终端协作,详见旧版流程或 `docs/`。 --- ## FAQ **如何确认重定位成功?** RViz `Global Options → Fixed Frame` 设为 `map`,`Add → TF`;出现 map 与 odom 两套坐标轴且相连即成功。 **发布目标后提示起点/终点被占用?** 看 `/inflated_map`,起终点必须在膨胀区外;或调小 `whole.launch` 的 `inflation_radius`。 **总在目标点附近停不下来?** 调大 `whole.launch` 的 `goal_tolerance`。 **仿真里机器人停在障碍前不动?** 先量停车点车身到障碍的间距。**若恰好等于 `adjust.d_max`,是代价函数配平问题**(调高 `p_u`),不是感知或尺寸问题。详见 [TUNING_GUIDE](docs/TUNING_GUIDE.md)。 **YHS 底盘不动?** 常见三件事:① CAN 口 `if_name` 对不对(`setup_can.sh` 后 `ip -details link show can0` 应 `ERROR-ACTIVE`);② 底盘是否退出**手操(joypad)模式**(`/yhs/control_mode`);③ 是否给了导航目标(`/cmd_vel` 是否有消息,`rostopic hz /cmd_vel`)。 --- ## 故障排查 | 现象 | 原因 | 处理 | |---|---|---| | YHS `Send message failed : Network is down` | CAN 口 down 或 USB 掉线 | `sudo ip link set up can0`;重启容器重新绑 socket | | YHS 一直 `Timeout waiting for CAN frame` 但手操能动 | 底盘在 joypad/手操模式,不往外发反馈 | 关手操遥控器 / 切自动档,`cat /sys/class/net/can0/statistics/rx_packets` 看是否涨 | | `use_host_ros_time` 报错 / TF 时间戳乱 | Odin1 时钟未对齐 | `control_command.yaml` 设 `use_host_ros_time: 1` | | torch 与 torchvision 冲突 | torchvision 覆盖 CUDA 版 PyTorch | 重装 CUDA 版 wheel(见旧版/历史记录) | | 仿真 `import neupan` 失败 | NeuPAN 未装到当前 Python | `pip3 install --no-deps -e ./NeuPAN` 或设 `PYTHONPATH` | | 容器退出 `cannot find /dev/bus/usb` | Odin1 未插或 udev 规则缺失 | `lsusb` 检查,重载 udev 规则 | | `/cmd_vel` 静默 | NeuPAN 进程挂了 | `docker logs odin-nav`,查配置/topic 名 | --- ## 开源组件与许可 本仓库整体以 Apache-2.0 发布(见 [LICENSE](LICENSE));以下第三方组件以子模块或运行时依赖引入,保留原始许可: | 组件 | 引入方式 | 许可 | 用途 | |---|---|---|---| | [NeuPAN](https://github.com/hanruihua/NeuPAN) | 子模块 `NeuPAN/` | GPL-3.0 | 端到端神经规划(DUNE + NRMP MPC) | | odin_ros_driver | 子模块 `ros_ws/src/odin_ros_driver/` | Apache-2.0 | Odin1 官方 ROS 驱动 | | [YOLOv5](https://github.com/ultralytics/yolov5) | 子模块 `yolov5/` | AGPL-3.0 | 物体检测(语义导航) | | Fire SDK | `ros_ws/src/tiji_sdk_2.0.0/` | 厂商 SDK | FireDog 高层控制 | | vosk / llama.cpp / SmolVLM | 运行时下载 | 各自许可 | 语音识别 / VLM | 公开部署或二次分发时,请一并保留各组件的许可声明。