Initialize odin1 workspace
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# catkin_ws
|
||||
|
||||
## 简介说明
|
||||
16dof采用留形科技的odin1空间记忆模组作为视觉方案
|
||||
采用的odin1固件版本为0.12.0
|
||||
本目录按 ROS 2 工作空间组织,工作空间根目录为当前目录,源码目录为 `src/`。
|
||||
固件下载链接:https://vvcazjv268.feishu.cn/file/AAsOba7nSoGj22xclcKcoadE
|
||||
Odin1驱动0.11.0获取链接:https://github.com/manifoldsdk/odin_ros_driver.git
|
||||
本目录仅仅附带
|
||||
```text
|
||||
catkin_ws/
|
||||
├── src/ 空
|
||||
├── runros.sh
|
||||
├── readme.md 本文档
|
||||
└── odin1的使用手册.md
|
||||
```
|
||||
所附带链接为留形科技官方下载链接
|
||||
并默认已配置 官方 ROS 2 功能包:
|
||||
|
||||
- `src/odin_ros_driver`
|
||||
以及参照官方教程完成系统规则写入
|
||||
附带官方github链接:https://github.com/manifoldsdk/odin_ros_driver
|
||||
|
||||
- 注意 odin1需配套对应 **odin1固件版本**, **驱动版本** 以及 **mindcloud软件版本**,详情请查阅官方说明
|
||||
|
||||
## 目录结构
|
||||
|
||||
```text
|
||||
catkin_ws/
|
||||
├── src/
|
||||
│ └── odin_ros_driver/
|
||||
├── build/
|
||||
├── install/
|
||||
├── runros.sh
|
||||
├── readme.md
|
||||
└── log/
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `src/` 用于存放 ROS 2 功能包源码。
|
||||
- `build/`、`install/`、`log/` 为 `colcon build` 后生成的工作空间产物。
|
||||
|
||||
## 扫图相关(需先完成control_command.yaml配置)
|
||||
|
||||
fire:~/catkin_ws/src/odin_ros_driver/config/control_command.yaml
|
||||
```yaml
|
||||
#存颜色
|
||||
recorddata: 1 # 0: off; 1: on
|
||||
#存地图
|
||||
custom_map_mode: 1 # 0: Odometry mode 1: SLAM mode 2: Relocalization mode
|
||||
```
|
||||
|
||||
### 运行odin
|
||||
```bash
|
||||
# 启动官方历程
|
||||
./runros.sh
|
||||
#新建终端 保存地图
|
||||
cd ~/catkin_ws/src/odin_ros_driver/
|
||||
./set_param.sh save_map 1
|
||||
```
|
||||
将生成的文件导入留形官方后处理软件mindcloud
|
||||
下载地址:https://version.manifoldtech.cn/download/mcs
|
||||
|
||||
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. 进入工作空间根目录:
|
||||
|
||||
```bash
|
||||
cd ~/catkin_ws
|
||||
```
|
||||
## 提供一个一键构建脚本runros.sh
|
||||
```bash
|
||||
#请先赋予可执行权限,此脚本可代替ros2空间构建命令
|
||||
./runros.sh
|
||||
```
|
||||
2. 先加载 ROS 2 环境:
|
||||
|
||||
```bash
|
||||
source /opt/ros/<你的发行版>/setup.bash
|
||||
```
|
||||
|
||||
3. 构建工作空间:
|
||||
|
||||
```bash
|
||||
colcon build
|
||||
```
|
||||
|
||||
4. 加载工作空间环境:
|
||||
|
||||
```bash
|
||||
source /home/lcf/catkin_ws/install/setup.bash
|
||||
```
|
||||
|
||||
5. 查看工作空间中的包:
|
||||
|
||||
```bash
|
||||
colcon list
|
||||
```
|
||||
|
||||
6. 在当前终端加载环境:
|
||||
|
||||
```bash
|
||||
source ~/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
7. 一键启动默认 ROS 2 驱动:
|
||||
|
||||
```bash
|
||||
~/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
默认等价于:
|
||||
|
||||
```bash
|
||||
source ~/catkin_ws/install/setup.bash
|
||||
ros2 launch odin_ros_driver odin1_ros2.launch.py
|
||||
```
|
||||
|
||||
8. 如需只打开一个已加载环境的干净交互 bash:
|
||||
|
||||
```bash
|
||||
~/catkin_ws/runros.sh --shell
|
||||
```
|
||||
|
||||
9. 直接通过脚本执行 `ros2` 或 `rviz2` 命令:
|
||||
|
||||
```bash
|
||||
~/catkin_ws/runros.sh ros2 topic list
|
||||
~/catkin_ws/runros.sh rviz2 -d /home/lcf/catkin_ws/src/odin_ros_driver/config/odin_ros2.rviz
|
||||
```
|
||||
|
||||
## 说明
|
||||
|
||||
- 当前根目录已经是 ROS 2 工作空间根目录,无需额外执行 `ros2 workspace create` 之类命令。
|
||||
- 若构建失败,请先确认系统已安装 ROS 2、`colcon` 以及包依赖。
|
||||
- `runros.sh` 会自动查找 `/opt/ros` 下可用的 ROS 2 发行版,并在存在 `install/setup.bash` 时自动叠加当前工作空间环境。
|
||||
- `runros.sh` 会将 ROS 2 运行日志写入工作空间下的 `log/ros2/`,避免依赖用户主目录中的默认 `~/.ros/log`。
|
||||
- 直接执行 `runros.sh` 且不带参数时,会默认执行 `ros2 launch odin_ros_driver odin1_ros2.launch.py`,用于一键启动驱动。
|
||||
- 如需只进入 shell,请显式使用 `runros.sh --shell`;该模式会进入一个不读取用户 `~/.bashrc`/`~/.profile` 的干净交互 bash,避免用户 shell 初始化脚本覆盖或污染当前 ROS 环境。
|
||||
- 直接执行 `runros.sh` 且带参数时,会在完成环境加载后直接执行该命令,适合一键启动 `ros2` 或 `rviz2`。
|
||||
@@ -0,0 +1,609 @@
|
||||
# Odin1 的使用手册
|
||||
|
||||
## 1. 文档来源与适用范围
|
||||
|
||||
本文根据 Odin1 官方仓库内容整理,官方仓库克隆位置为:
|
||||
|
||||
- `/home/lcf/catkin_ws/ziliao/odin_ros_driver`
|
||||
|
||||
本手册重点面向你当前这台机器上的 **ROS2 使用方式**,并结合你当前工作空间实际路径整理为可直接操作的版本:
|
||||
|
||||
- 工作空间根目录:`/home/lcf/catkin_ws`
|
||||
- 实际运行包目录:`/home/lcf/catkin_ws/src/odin_ros_driver`
|
||||
- 官方参考仓库目录:`/home/lcf/catkin_ws/ziliao/odin_ros_driver`
|
||||
|
||||
## 2. Odin1 是什么
|
||||
|
||||
Odin1 官方 ROS 驱动 `odin_ros_driver` 是一个同时支持 ROS1 和 ROS2 的驱动包,核心用途包括:
|
||||
|
||||
- 连接 Odin1 设备并发布点云、IMU、RGB、里程计、TF 等数据
|
||||
- 提供里程计模式、SLAM 建图模式、重定位模式
|
||||
- 支持 RViz 可视化
|
||||
- 支持在线调节 AE/AWB
|
||||
- 支持地图保存与重定位
|
||||
|
||||
官方说明里明确推荐:
|
||||
|
||||
- ROS2 推荐使用 `Humble`
|
||||
- Ubuntu 推荐使用 `22.04`
|
||||
- 设备固件版本要求 `v0.11.11`
|
||||
|
||||
## 3. 官方仓库里与 ROS2 最相关的文件
|
||||
|
||||
- `README.md`
|
||||
- 官方主说明,包含安装、运行、建图、常见问题
|
||||
- `RELOCALIZATION_GUIDE.md`
|
||||
- 重定位专门说明
|
||||
- `config/control_command.yaml`
|
||||
- 运行参数总配置,建图和重定位主要看这个文件
|
||||
- `launch_ROS2/odin1_ros2.launch.py`
|
||||
- ROS2 启动入口
|
||||
- `script/build_ros2.sh`
|
||||
- 官方 ROS2 构建脚本
|
||||
- `set_param.sh`
|
||||
- 用于在运行时发送参数命令,保存地图时会用到
|
||||
|
||||
## 4. ROS2 启动流程总结
|
||||
|
||||
官方 README 的 ROS2 逻辑本质上是两步:
|
||||
|
||||
```bash
|
||||
source /home/lcf/catkin_ws/install/setup.bash
|
||||
ros2 launch odin_ros_driver odin1_ros2.launch.py
|
||||
```
|
||||
|
||||
你当前环境里已经额外有一个一键脚本:
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
这条命令现在默认就等价于上面两条命令,所以日常使用时建议优先用它。
|
||||
|
||||
## 5. ROS2 启动时实际会拉起什么
|
||||
|
||||
根据官方 `launch_ROS2/odin1_ros2.launch.py`,启动时会拉起以下节点:
|
||||
|
||||
- `host_sdk_sample`
|
||||
- 主驱动节点,负责设备连接、数据流和核心逻辑
|
||||
- `pcd2depth_ros2_node`
|
||||
- 深度图相关节点
|
||||
- `cloud_reprojection_ros2_node`
|
||||
- 点云投影相关节点
|
||||
- `image_overlay_node`
|
||||
- 图像叠加相关节点
|
||||
- `rviz2`
|
||||
- 默认会同时启动 RViz2,并加载 `config/odin_ros2.rviz`
|
||||
|
||||
所以官方 ROS2 launch 不是只起一个驱动进程,而是“驱动 + 辅助处理节点 + RViz2”的完整演示链路。
|
||||
|
||||
## 6. 先决条件
|
||||
|
||||
### 6.1 系统与依赖
|
||||
|
||||
官方建议:
|
||||
|
||||
- Ubuntu 22.04
|
||||
- ROS2 Humble
|
||||
- OpenCV 只保留一个版本
|
||||
- 已安装 `yaml-cpp`、`libusb`、`Eigen3`、OpenSSL 等依赖
|
||||
|
||||
### 6.2 Udev 规则
|
||||
|
||||
官方要求添加 udev 规则,否则可能遇到 USB 访问权限问题:
|
||||
|
||||
```bash
|
||||
sudo vim /etc/udev/rules.d/99-odin-usb.rules
|
||||
```
|
||||
|
||||
写入:
|
||||
|
||||
```bash
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2207", ATTR{idProduct}=="0019", MODE="0666", GROUP="plugdev"
|
||||
```
|
||||
|
||||
然后执行:
|
||||
|
||||
```bash
|
||||
sudo udevadm control --reload
|
||||
sudo udevadm trigger
|
||||
```
|
||||
|
||||
### 6.3 可能遇到的 USB 权限问题
|
||||
|
||||
如果启动时报:
|
||||
|
||||
- `LIBUSB_ERROR_ACCESS`
|
||||
- `LIBUSB_ERROR_BUSY`
|
||||
|
||||
优先检查:
|
||||
|
||||
1. 是否已经添加 udev 规则
|
||||
2. 当前用户是否在 `plugdev` 组
|
||||
3. 是否有旧的 `host_sdk_sample` 进程还在占用设备
|
||||
|
||||
可用命令:
|
||||
|
||||
```bash
|
||||
ps aux | grep host_sdk_sample
|
||||
killall host_sdk_sample
|
||||
```
|
||||
|
||||
## 7. 你当前环境下的推荐使用方式
|
||||
|
||||
### 7.1 一键启动
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
该命令会自动:
|
||||
|
||||
1. 加载 `/opt/ros/humble/setup.bash`
|
||||
2. 加载 `/home/lcf/catkin_ws/install/setup.bash`
|
||||
3. 执行:
|
||||
|
||||
```bash
|
||||
ros2 launch odin_ros_driver odin1_ros2.launch.py
|
||||
```
|
||||
|
||||
### 7.2 只加载环境
|
||||
|
||||
```bash
|
||||
source /home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
### 7.3 只开一个干净 shell
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh --shell
|
||||
```
|
||||
|
||||
## 8. Odin1 的三种工作模式
|
||||
|
||||
官方通过 `config/control_command.yaml` 中的 `custom_map_mode` 控制工作模式:
|
||||
|
||||
- `0`:里程计模式
|
||||
- `1`:SLAM 建图模式
|
||||
- `2`:重定位模式
|
||||
|
||||
### 8.1 里程计模式
|
||||
|
||||
```yaml
|
||||
custom_map_mode: 0
|
||||
```
|
||||
|
||||
特点:
|
||||
|
||||
- `map` 和 `odom` 视为同一位姿
|
||||
- 不进行回环建图
|
||||
- 适合只看实时位姿和点云
|
||||
|
||||
如果里程计漂移,官方建议在运行过程中执行:
|
||||
|
||||
```bash
|
||||
cd /home/lcf/catkin_ws/src/odin_ros_driver
|
||||
./set_param.sh algo_reset 1
|
||||
```
|
||||
|
||||
### 8.2 SLAM 建图模式
|
||||
|
||||
```yaml
|
||||
custom_map_mode: 1
|
||||
```
|
||||
|
||||
特点:
|
||||
|
||||
- 在里程计模式基础上增加回环检测和地图保存能力
|
||||
- 启动后自动开始建图并缓存地图数据
|
||||
- 地图不会自动保存,必须手动触发保存
|
||||
|
||||
### 8.3 重定位模式
|
||||
|
||||
```yaml
|
||||
custom_map_mode: 2
|
||||
```
|
||||
|
||||
特点:
|
||||
|
||||
- 基于已有地图重新定位
|
||||
- 必须指定地图文件路径
|
||||
- 成功后会发布 `map -> odom` 的 TF
|
||||
|
||||
## 9. ROS2 下怎么建图
|
||||
|
||||
这是你最关心的部分,按下面流程做。
|
||||
|
||||
### 9.1 第一步:修改配置为建图模式
|
||||
|
||||
编辑实际运行中的配置文件:
|
||||
|
||||
- `/home/lcf/catkin_ws/src/odin_ros_driver/config/control_command.yaml`
|
||||
|
||||
至少确认这些字段:
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 1
|
||||
relocalization_map_abs_path: ""
|
||||
```
|
||||
|
||||
建议同时关注:
|
||||
|
||||
- `strict_usb3.0_check`
|
||||
- 默认 `0`,允许非严格 USB3.0;但官方强调建图最好使用 USB3.0
|
||||
- `senddtof`
|
||||
- 点云开关
|
||||
- `sendodom`
|
||||
- 里程计开关
|
||||
- `sendcloudslam`
|
||||
- SLAM 点云开关
|
||||
- `sendcloudrender`
|
||||
- 渲染点云开关
|
||||
- `showpath`
|
||||
- 是否显示路径
|
||||
|
||||
如果你想更明显地看路径,可考虑:
|
||||
|
||||
```yaml
|
||||
showpath: 1
|
||||
```
|
||||
|
||||
### 9.2 第二步:启动驱动
|
||||
|
||||
推荐直接执行:
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
或者手动执行:
|
||||
|
||||
```bash
|
||||
source /home/lcf/catkin_ws/install/setup.bash
|
||||
ros2 launch odin_ros_driver odin1_ros2.launch.py
|
||||
```
|
||||
|
||||
### 9.3 第三步:移动设备开始建图
|
||||
|
||||
驱动启动后,Odin1 会自动开始建图并缓存地图数据。
|
||||
|
||||
建议操作方式:
|
||||
|
||||
- 使用 USB3.0 连接
|
||||
- 启动后缓慢移动设备
|
||||
- 尽量覆盖你希望建图的区域
|
||||
- 尽量回到已走过区域,帮助回环闭合
|
||||
- 场景中应有足够几何/纹理特征
|
||||
|
||||
### 9.4 第四步:保存地图
|
||||
|
||||
建图完成后,进入包目录:
|
||||
|
||||
```bash
|
||||
cd /home/lcf/catkin_ws/src/odin_ros_driver
|
||||
```
|
||||
|
||||
执行官方命令:
|
||||
|
||||
```bash
|
||||
./set_param.sh save_map 1
|
||||
```
|
||||
|
||||
`set_param.sh` 的本质是向 `/tmp/odin_command.txt` 写入:
|
||||
|
||||
```bash
|
||||
set save_map 1
|
||||
```
|
||||
|
||||
主驱动会读取这个命令并调用 SDK 保存地图。
|
||||
|
||||
### 9.5 第五步:找到保存出来的地图文件
|
||||
|
||||
配置文件里写明:
|
||||
|
||||
```yaml
|
||||
mapping_result_dest_dir: ""
|
||||
mapping_result_file_name: ""
|
||||
```
|
||||
|
||||
如果这两个都为空,则官方默认保存到:
|
||||
|
||||
- `{ws}/src/odin_ros_driver/map/{driver_start_time}/`
|
||||
|
||||
结合你当前工作空间,默认可按下面路径去找:
|
||||
|
||||
- `/home/lcf/catkin_ws/src/odin_ros_driver/map/`
|
||||
|
||||
实际生成的地图文件通常是 `.bin` 文件。
|
||||
|
||||
### 9.6 第六步:重复保存
|
||||
|
||||
官方说明允许重复执行:
|
||||
|
||||
```bash
|
||||
./set_param.sh save_map 1
|
||||
```
|
||||
|
||||
但两次保存之间建议至少间隔 **5 秒**。
|
||||
|
||||
## 10. 重定位怎么用
|
||||
|
||||
官方重定位文档单独给了更详细说明,这里按实用方式整理。
|
||||
|
||||
### 10.1 自动重定位
|
||||
|
||||
修改配置:
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/home/lcf/catkin_ws/src/odin_ros_driver/map/你的地图目录/xxx.bin"
|
||||
custom_init_pos: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
|
||||
```
|
||||
|
||||
推荐条件:
|
||||
|
||||
- 起始位置距离原始建图轨迹 1 米以内
|
||||
- 起始朝向与建图时偏差不超过 ±10°
|
||||
- 场景特征明显
|
||||
|
||||
启动后行为:
|
||||
|
||||
1. 尝试将当前观测和已有地图匹配
|
||||
2. 成功后发布 `map -> odom` TF
|
||||
3. 失败时进入后备模式并继续尝试
|
||||
|
||||
### 10.2 指定初始位姿重定位
|
||||
|
||||
如果你知道大概起点位置,可设置:
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/绝对路径/xxx.bin"
|
||||
custom_init_pos: [x, y, z, qx, qy, qz, qw]
|
||||
```
|
||||
|
||||
含义是:
|
||||
|
||||
- `x y z`:地图坐标系中的位置
|
||||
- `qx qy qz qw`:四元数姿态
|
||||
|
||||
例如绕 Z 轴 90°:
|
||||
|
||||
```yaml
|
||||
custom_init_pos: [5.2, -3.1, 0.0, 0.0, 0.0, 0.707, 0.707]
|
||||
```
|
||||
|
||||
### 10.3 与官方文档的一个小冲突
|
||||
|
||||
官方主 README 的参数表里写过:
|
||||
|
||||
- `custom_init_pos`:currently unused
|
||||
|
||||
但官方单独的 `RELOCALIZATION_GUIDE.md` 已经把它作为重定位功能来详细说明,并给了示例,因此更应以重定位指南为准。
|
||||
|
||||
如果你实际测试发现 `custom_init_pos` 不生效,优先检查:
|
||||
|
||||
1. `custom_map_mode` 是否为 `2`
|
||||
2. `custom_init_pos` 是否正好 7 个值
|
||||
3. 四元数是否归一化
|
||||
4. 地图文件路径是否为绝对路径
|
||||
|
||||
## 11. 建图与重定位的推荐操作套路
|
||||
|
||||
### 11.1 首次建图
|
||||
|
||||
1. 把 `custom_map_mode` 设为 `1`
|
||||
2. 启动:
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
3. 缓慢移动 Odin1,采完整个区域
|
||||
4. 返回包目录保存地图:
|
||||
|
||||
```bash
|
||||
cd /home/lcf/catkin_ws/src/odin_ros_driver
|
||||
./set_param.sh save_map 1
|
||||
```
|
||||
|
||||
5. 到 `map/` 目录下找到 `.bin` 地图文件
|
||||
|
||||
### 11.2 下次基于已有地图定位
|
||||
|
||||
1. 把 `custom_map_mode` 改为 `2`
|
||||
2. 把 `relocalization_map_abs_path` 指到上一步生成的 `.bin`
|
||||
3. 若知道起点,补 `custom_init_pos`
|
||||
4. 再执行:
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
## 12. 常用参数解释
|
||||
|
||||
以下参数来自官方 `control_command.yaml`,是 ROS2 下最常用的一批。
|
||||
|
||||
### 12.1 时间与同步
|
||||
|
||||
- `use_host_ros_time`
|
||||
- `0`:使用设备时间,官方推荐
|
||||
- `1`:收到数据时用主机 ROS 时间
|
||||
- `2`:对齐到主机时间轴
|
||||
|
||||
建议:
|
||||
|
||||
- 一般先保持 `0`
|
||||
|
||||
### 12.2 传感器输出
|
||||
|
||||
- `sendimu`
|
||||
- 是否发布 IMU
|
||||
- `sendodom`
|
||||
- 是否发布里程计
|
||||
- `senddtof`
|
||||
- 是否发布原始点云
|
||||
- `sendcloudslam`
|
||||
- 是否发布 SLAM 点云
|
||||
- `sendcloudrender`
|
||||
- 是否发布渲染后的点云
|
||||
- `sendrgb`
|
||||
- 是否发布 RGB 图像
|
||||
- `sendrgbcompressed`
|
||||
- 是否发布压缩 RGB 图像
|
||||
|
||||
### 12.3 点云质量相关
|
||||
|
||||
- `cloud_raw_confidence_threshold`
|
||||
- 原始点云置信度阈值,官方示例是 `35`
|
||||
- `dtof_fps`
|
||||
- 官方注释给出 `100`、`145`、`290` 等档位
|
||||
|
||||
### 12.4 其他
|
||||
|
||||
- `recorddata`
|
||||
- 是否录制官方私有格式数据,空间占用很大
|
||||
- `devstatuslog`
|
||||
- 是否记录设备状态日志
|
||||
- `showpath`
|
||||
- 是否显示路径
|
||||
- `showcamerapose`
|
||||
- 是否显示相机位姿
|
||||
|
||||
## 13. ROS2 下常用话题
|
||||
|
||||
官方 README 给出的常用话题包括:
|
||||
|
||||
- `/odin1/imu`
|
||||
- `/odin1/image`
|
||||
- `/odin1/image_undistort`
|
||||
- `/odin1/image/compressed`
|
||||
- `/odin1/cloud_raw`
|
||||
- `/odin1/cloud_render`
|
||||
- `/odin1/cloud_slam`
|
||||
- `/odin1/odometry`
|
||||
- `/odin1/odometry_high`
|
||||
- `/odin1/path`
|
||||
- `/tf`
|
||||
- `/odin1/reprojected_image`
|
||||
|
||||
重定位成功后,`/tf` 中会出现 `map -> odom` 关系。
|
||||
|
||||
## 14. 在线调参能力
|
||||
|
||||
官方驱动提供四个 ROS2 服务,可在驱动运行时调整自动曝光和自动白平衡:
|
||||
|
||||
- `/odin1/get_ae`
|
||||
- `/odin1/get_awb`
|
||||
- `/odin1/set_ae`
|
||||
- `/odin1/set_awb`
|
||||
|
||||
示例:
|
||||
|
||||
```bash
|
||||
source /home/lcf/catkin_ws/install/setup.bash
|
||||
ros2 service call /odin1/get_ae odin_ros_driver/srv/GetAe
|
||||
ros2 service call /odin1/get_awb odin_ros_driver/srv/GetAwb
|
||||
ros2 service call /odin1/set_ae odin_ros_driver/srv/SetAe "{mode: 0}"
|
||||
ros2 service call /odin1/set_awb odin_ros_driver/srv/SetAwb "{mode: 0}"
|
||||
```
|
||||
|
||||
## 15. 常见问题总结
|
||||
|
||||
### 15.1 启动后设备很快断开
|
||||
|
||||
官方认为 ROS2 在复杂网络环境下容易因为广播导致阻塞,从而出现设备断开。
|
||||
|
||||
如果不需要跨设备通信,可先尝试:
|
||||
|
||||
```bash
|
||||
export ROS_LOCALHOST_ONLY=1
|
||||
```
|
||||
|
||||
### 15.2 RViz 卡死或长时间无响应
|
||||
|
||||
官方建议先给 Odin1 重新上电。
|
||||
|
||||
### 15.3 重启设备后 RViz 出现 `TF_OLD_DATA`
|
||||
|
||||
官方说明这是时间戳冲突导致的,点击 RViz 底部 reset 按钮可清掉旧状态。
|
||||
|
||||
### 15.4 图像相关节点一启动就崩
|
||||
|
||||
官方提示这通常与系统里安装了多个 OpenCV 版本有关。
|
||||
|
||||
### 15.5 `Missing camera node 'cam_0'`
|
||||
|
||||
官方建议重新插拔 USB。
|
||||
|
||||
### 15.6 录 bag 时 IMU 或高频里程计丢帧
|
||||
|
||||
官方仓库提供了:
|
||||
|
||||
- `script/rosbag2_qos.yaml`
|
||||
|
||||
录制时建议:
|
||||
|
||||
```bash
|
||||
ros2 bag record -a \
|
||||
--qos-profile-overrides-path src/odin_ros_driver/script/rosbag2_qos.yaml \
|
||||
-o my_bag
|
||||
```
|
||||
|
||||
## 16. 你当前环境下的最简建图命令
|
||||
|
||||
### 16.1 建图前
|
||||
|
||||
编辑:
|
||||
|
||||
- `/home/lcf/catkin_ws/src/odin_ros_driver/config/control_command.yaml`
|
||||
|
||||
设置:
|
||||
|
||||
```yaml
|
||||
custom_map_mode: 1
|
||||
```
|
||||
|
||||
### 16.2 启动建图
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
### 16.3 保存地图
|
||||
|
||||
```bash
|
||||
cd /home/lcf/catkin_ws/src/odin_ros_driver
|
||||
./set_param.sh save_map 1
|
||||
```
|
||||
|
||||
### 16.4 做重定位
|
||||
|
||||
编辑:
|
||||
|
||||
- `/home/lcf/catkin_ws/src/odin_ros_driver/config/control_command.yaml`
|
||||
|
||||
设置:
|
||||
|
||||
```yaml
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/home/lcf/catkin_ws/src/odin_ros_driver/map/你的目录/你的地图.bin"
|
||||
```
|
||||
|
||||
然后再次启动:
|
||||
|
||||
```bash
|
||||
/home/lcf/catkin_ws/runros.sh
|
||||
```
|
||||
|
||||
## 17. 我对官方文档的实用化结论
|
||||
|
||||
如果只用一句话总结官方仓库的 ROS2 使用方式:
|
||||
|
||||
- **建图**:把 `custom_map_mode` 设为 `1`,启动驱动,移动设备采图,最后执行 `./set_param.sh save_map 1`
|
||||
- **重定位**:把 `custom_map_mode` 设为 `2`,设置 `relocalization_map_abs_path` 指向 `.bin` 地图,再重新启动驱动
|
||||
- **启动**:在你当前环境里,最省事的方式就是直接运行 `/home/lcf/catkin_ws/runros.sh`
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
2026-06-19 15:19:22 CST
|
||||
- 初始化 `/home/lcf/catkin_ws2` 为 ROS 2 工作空间根目录。
|
||||
- 确认根目录已存在 `src/`,其中包含 ROS 2 包 `src/odin_ros_driver`。
|
||||
- 新增工作空间根目录 `README.md`,补充目录结构、构建命令与环境加载说明。
|
||||
- 新增工作空间根目录 `.gitignore`,忽略 `build/`、`install/`、`log/` 目录。
|
||||
- 检查本机环境,确认已安装 `colcon`,且存在 ROS 2 发行版 `/opt/ros/humble`。
|
||||
- 使用 `source /opt/ros/humble/setup.bash && colcon list` 校验工作空间,已成功识别 `odin_ros_driver`。
|
||||
2026-06-19 15:19:22 CST
|
||||
- 新增工作空间根目录脚本 `runros.sh`,支持一键加载 ROS 2 基础环境与当前工作空间环境。
|
||||
- `runros.sh` 同时支持 `source ./runros.sh` 和直接执行 `./runros.sh` 两种使用方式。
|
||||
- 更新根目录 `README.md`,补充 `runros.sh` 的使用说明与行为说明。
|
||||
2026-06-19 15:35:12 CST
|
||||
- 为 `runros.sh` 增加调试日志落盘,记录脚本调用方式、ROS 环境加载结果、工作空间覆盖层加载结果与 shell 交接链路。
|
||||
- 修复 `runros.sh` 直接执行时拉起交互 shell 会读取用户 `~/.bashrc` 的问题,改为启动不读取用户 rc 文件的干净交互 bash。
|
||||
- 扩展 `runros.sh`,支持直接执行传入命令,例如 `ros2`、`rviz2`,以便一键在已加载环境中启动目标程序。
|
||||
- 修正用户 `~/.bashrc` 中会自我追加 `source` 语句的错误配置,并将重复加载工作空间环境的逻辑收敛为一次且带存在性判断。
|
||||
- 更新根目录 `README.md`,修正工作空间路径为 `/home/lcf/catkin_ws`,并补充直接执行 `ros2`/`rviz2` 的示例。
|
||||
2026-06-19 15:52:00 CST
|
||||
- 调整 `runros.sh` 默认行为:直接执行脚本时不再进入交互 shell,而是默认执行 `ros2 launch odin_ros_driver odin1_ros2.launch.py`,满足一键启动需求。
|
||||
- 为 `runros.sh` 新增 `--shell` 和 `--help` 入口,分别用于显式打开干净交互 shell 与查看脚本使用说明。
|
||||
- 更新根目录 `README.md`,补充 `runros.sh` 默认一键启动、`--shell` 模式及其与 `source install/setup.bash + ros2 launch` 的对应关系。
|
||||
- 为 `runros.sh` 新增工作空间内 `ROS_LOG_DIR` 设置,将 ROS 2 运行日志固定写入 `/home/lcf/catkin_ws/log/ros2`,避免依赖用户主目录默认日志目录导致的一键启动失败。
|
||||
2026-06-19 16:15:56 CST
|
||||
- 阅读 `/home/lcf/catkin_ws/ziliao/odin_ros_driver` 中的 Odin1 官方仓库资料,重点整理 ROS2 相关的 README、重定位指南、启动文件、配置文件和运行时命令接口。
|
||||
- 新增根目录说明文档 `/home/lcf/catkin_ws/odin1的使用手册.md`,总结 Odin1 在当前工作空间下的 ROS2 启动、建图、保存地图、重定位、常用参数、话题与常见问题。
|
||||
@@ -0,0 +1,359 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
WORKSPACE_ROOT="${SCRIPT_DIR}"
|
||||
DEBUG_LOG_FILE="${WORKSPACE_ROOT}/trae-debug-log-runros-shell-loop.ndjson"
|
||||
ROS_LOG_ROOT="${WORKSPACE_ROOT}/log/ros2"
|
||||
DEFAULT_LAUNCH_PACKAGE="odin_ros_driver"
|
||||
DEFAULT_LAUNCH_FILE="odin1_ros2.launch.py"
|
||||
|
||||
# Function: print_info
|
||||
# Input:
|
||||
# - $1: message text.
|
||||
# Output:
|
||||
# - Prints an informational message to stdout.
|
||||
# Description:
|
||||
# - Standardizes normal runtime messages for this script.
|
||||
# References:
|
||||
# - None.
|
||||
print_info() {
|
||||
echo "[INFO] $1"
|
||||
}
|
||||
|
||||
# Function: print_warn
|
||||
# Input:
|
||||
# - $1: warning text.
|
||||
# Output:
|
||||
# - Prints a warning message to stdout.
|
||||
# Description:
|
||||
# - Standardizes warning messages for this script.
|
||||
# References:
|
||||
# - None.
|
||||
print_warn() {
|
||||
echo "[WARN] $1"
|
||||
}
|
||||
|
||||
# Function: print_error
|
||||
# Input:
|
||||
# - $1: error text.
|
||||
# Output:
|
||||
# - Prints an error message to stderr.
|
||||
# Description:
|
||||
# - Standardizes error messages for this script.
|
||||
# References:
|
||||
# - None.
|
||||
print_error() {
|
||||
echo "[ERROR] $1" >&2
|
||||
}
|
||||
|
||||
# Function: write_debug_log
|
||||
# Input:
|
||||
# - $1: event name.
|
||||
# - $2: event detail text.
|
||||
# Output:
|
||||
# - Appends one NDJSON debug record to the local debug log file.
|
||||
# Description:
|
||||
# - Records runtime evidence for script invocation mode, environment loading,
|
||||
# and interactive shell handoff without changing business behavior.
|
||||
# References:
|
||||
# - Uses variables `DEBUG_LOG_FILE`, `WORKSPACE_ROOT`, and `ROS_DISTRO`
|
||||
# defined in this file.
|
||||
# - Called by `load_ros2_environment()`, `load_workspace_environment()`,
|
||||
# `start_interactive_shell()`, and `main()` in this file.
|
||||
write_debug_log() {
|
||||
local event_name="$1"
|
||||
local event_detail="$2"
|
||||
local invoke_mode="executed"
|
||||
|
||||
if is_script_sourced; then
|
||||
invoke_mode="sourced"
|
||||
fi
|
||||
|
||||
printf '{"ts":"%s","event":"%s","detail":"%s","pid":"%s","ppid":"%s","mode":"%s","shell":"%s","workspace":"%s","ros_distro":"%s"}\n' \
|
||||
"$(date '+%Y-%m-%dT%H:%M:%S%z')" \
|
||||
"${event_name}" \
|
||||
"${event_detail}" \
|
||||
"$$" \
|
||||
"$PPID" \
|
||||
"${invoke_mode}" \
|
||||
"${SHELL:-/bin/bash}" \
|
||||
"${WORKSPACE_ROOT}" \
|
||||
"${ROS_DISTRO:-unset}" >> "${DEBUG_LOG_FILE}"
|
||||
}
|
||||
|
||||
# Function: is_script_sourced
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Returns 0 when the script is sourced.
|
||||
# - Returns 1 when the script is executed directly.
|
||||
# Description:
|
||||
# - Detects whether the current script is loaded into the caller shell or
|
||||
# started as a standalone process.
|
||||
# References:
|
||||
# - Uses bash built-in variables `${BASH_SOURCE[0]}` and `${0}`.
|
||||
is_script_sourced() {
|
||||
[[ "${BASH_SOURCE[0]}" != "${0}" ]]
|
||||
}
|
||||
|
||||
# Function: find_ros2_setup
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Prints the absolute path of the detected ROS 2 `setup.bash`.
|
||||
# - Returns 1 if no ROS 2 installation is found.
|
||||
# Description:
|
||||
# - Prefers the current `ROS_DISTRO` when available, otherwise probes common
|
||||
# ROS 2 distributions from newer to older.
|
||||
# References:
|
||||
# - Uses environment variable `ROS_DISTRO`.
|
||||
# - Searches under `/opt/ros/<distro>/setup.bash`.
|
||||
find_ros2_setup() {
|
||||
local ros2_setup=""
|
||||
local distros=("jazzy" "iron" "humble" "galactic" "foxy" "rolling")
|
||||
local distro=""
|
||||
|
||||
if [ -n "${ROS_DISTRO}" ] && [ -f "/opt/ros/${ROS_DISTRO}/setup.bash" ]; then
|
||||
echo "/opt/ros/${ROS_DISTRO}/setup.bash"
|
||||
return 0
|
||||
fi
|
||||
|
||||
for distro in "${distros[@]}"; do
|
||||
if [ -f "/opt/ros/${distro}/setup.bash" ]; then
|
||||
ros2_setup="/opt/ros/${distro}/setup.bash"
|
||||
echo "${ros2_setup}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function: load_ros2_environment
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Returns 0 when the ROS 2 environment is sourced successfully.
|
||||
# - Returns 1 when no valid ROS 2 environment is found.
|
||||
# Description:
|
||||
# - Locates and loads the base ROS 2 environment required by the workspace.
|
||||
# References:
|
||||
# - Calls `find_ros2_setup()` in this file.
|
||||
# - Sources `/opt/ros/<distro>/setup.bash`.
|
||||
load_ros2_environment() {
|
||||
local ros2_setup=""
|
||||
|
||||
ros2_setup="$(find_ros2_setup)" || {
|
||||
write_debug_log "load_ros2_environment_failed" "no_ros2_setup_found"
|
||||
print_error "No ROS 2 installation was found under /opt/ros."
|
||||
return 1
|
||||
}
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${ros2_setup}"
|
||||
write_debug_log "load_ros2_environment" "${ros2_setup}"
|
||||
print_info "Loaded ROS 2 environment: ${ros2_setup}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function: load_workspace_environment
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Returns 0 after attempting to load the workspace environment.
|
||||
# Description:
|
||||
# - Loads the current workspace overlay when `install/setup.bash` exists.
|
||||
# When the workspace has not been built yet, it keeps only the base ROS 2
|
||||
# environment and prints the recommended next step.
|
||||
# References:
|
||||
# - Uses variable `WORKSPACE_ROOT` defined in this file.
|
||||
# - Sources `${WORKSPACE_ROOT}/install/setup.bash`.
|
||||
load_workspace_environment() {
|
||||
local workspace_setup="${WORKSPACE_ROOT}/install/setup.bash"
|
||||
|
||||
cd "${WORKSPACE_ROOT}" || return 1
|
||||
|
||||
if [ -f "${workspace_setup}" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${workspace_setup}"
|
||||
write_debug_log "load_workspace_environment" "${workspace_setup}"
|
||||
print_info "Loaded workspace environment: ${workspace_setup}"
|
||||
else
|
||||
write_debug_log "load_workspace_environment_missing" "${workspace_setup}"
|
||||
print_warn "Workspace overlay not found: ${workspace_setup}"
|
||||
print_warn "Run 'colcon build' first if you need package overlays."
|
||||
fi
|
||||
|
||||
export ROS_WORKSPACE="${WORKSPACE_ROOT}"
|
||||
print_info "Workspace root: ${WORKSPACE_ROOT}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function: ensure_ros_log_directory
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Returns 0 when the ROS 2 log directory is ready for use.
|
||||
# - Returns 1 when the log directory cannot be created.
|
||||
# Description:
|
||||
# - Ensures ROS 2 launch logs are written into the workspace-local log
|
||||
# directory instead of relying on the user's home directory.
|
||||
# References:
|
||||
# - Uses variables `ROS_LOG_ROOT` and `WORKSPACE_ROOT` defined in this file.
|
||||
# - Called by `main()` in this file.
|
||||
ensure_ros_log_directory() {
|
||||
mkdir -p "${ROS_LOG_ROOT}" || {
|
||||
write_debug_log "ensure_ros_log_directory_failed" "${ROS_LOG_ROOT}"
|
||||
print_error "Failed to create ROS log directory: ${ROS_LOG_ROOT}"
|
||||
return 1
|
||||
}
|
||||
|
||||
export ROS_LOG_DIR="${ROS_LOG_ROOT}"
|
||||
write_debug_log "ensure_ros_log_directory" "${ROS_LOG_DIR}"
|
||||
print_info "ROS log directory: ${ROS_LOG_DIR}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function: run_command_with_environment
|
||||
# Input:
|
||||
# - $@: command and arguments to execute.
|
||||
# Output:
|
||||
# - Replaces the current process with the provided command.
|
||||
# Description:
|
||||
# - Executes a user-specified command after the ROS 2 and workspace
|
||||
# environment have been loaded successfully.
|
||||
# References:
|
||||
# - Called by `main()` in this file.
|
||||
run_command_with_environment() {
|
||||
write_debug_log "run_command_with_environment" "$*"
|
||||
print_info "Running command with ROS 2 environment loaded: $*"
|
||||
exec "$@"
|
||||
}
|
||||
|
||||
# Function: launch_default_ros2_stack
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Replaces the current process with the default ROS 2 launch command.
|
||||
# Description:
|
||||
# - Starts the default `odin_ros_driver` ROS 2 launch file after the
|
||||
# workspace environment has been loaded successfully.
|
||||
# References:
|
||||
# - Uses variables `DEFAULT_LAUNCH_PACKAGE` and `DEFAULT_LAUNCH_FILE`
|
||||
# defined in this file.
|
||||
# - Calls `run_command_with_environment()` in this file.
|
||||
launch_default_ros2_stack() {
|
||||
write_debug_log "launch_default_ros2_stack" "${DEFAULT_LAUNCH_PACKAGE} ${DEFAULT_LAUNCH_FILE}"
|
||||
print_info "Starting default ROS 2 launch: ${DEFAULT_LAUNCH_PACKAGE} ${DEFAULT_LAUNCH_FILE}"
|
||||
run_command_with_environment ros2 launch "${DEFAULT_LAUNCH_PACKAGE}" "${DEFAULT_LAUNCH_FILE}"
|
||||
}
|
||||
|
||||
# Function: start_interactive_shell
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Replaces the current process with a clean interactive bash shell.
|
||||
# Description:
|
||||
# - Keeps the loaded ROS 2 and workspace environment in a new interactive
|
||||
# shell when the script is executed directly, while avoiding user shell
|
||||
# rc files that may recursively modify configuration.
|
||||
# References:
|
||||
# - Uses `/bin/bash --noprofile --norc -i`.
|
||||
start_interactive_shell() {
|
||||
write_debug_log "start_interactive_shell" "exec_clean_interactive_bash"
|
||||
print_info "Starting a clean interactive bash shell with ROS 2 environment loaded."
|
||||
exec /bin/bash --noprofile --norc -i
|
||||
}
|
||||
|
||||
# Function: print_usage
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Prints the script usage text to stdout.
|
||||
# Description:
|
||||
# - Documents the default one-click launch behavior, the custom command mode,
|
||||
# and the explicit shell mode for this script.
|
||||
# References:
|
||||
# - Uses variables `DEFAULT_LAUNCH_PACKAGE` and `DEFAULT_LAUNCH_FILE`
|
||||
# defined in this file.
|
||||
print_usage() {
|
||||
cat <<EOF
|
||||
Usage:
|
||||
source ${WORKSPACE_ROOT}/runros.sh
|
||||
${WORKSPACE_ROOT}/runros.sh
|
||||
${WORKSPACE_ROOT}/runros.sh --shell
|
||||
${WORKSPACE_ROOT}/runros.sh <command> [args...]
|
||||
|
||||
Behavior:
|
||||
- source runros.sh
|
||||
Load ROS 2 and workspace environment into the current shell.
|
||||
- runros.sh
|
||||
Launch: ros2 launch ${DEFAULT_LAUNCH_PACKAGE} ${DEFAULT_LAUNCH_FILE}
|
||||
- runros.sh --shell
|
||||
Open a clean interactive bash shell with the environment loaded.
|
||||
- runros.sh <command> [args...]
|
||||
Run the provided command with the environment loaded.
|
||||
EOF
|
||||
}
|
||||
|
||||
# Function: main
|
||||
# Input:
|
||||
# - None.
|
||||
# Output:
|
||||
# - Returns 0 on success.
|
||||
# - Returns 1 when required environment loading fails.
|
||||
# Description:
|
||||
# - Coordinates ROS 2 base environment loading, workspace overlay loading,
|
||||
# and chooses behavior for sourced vs executed usage.
|
||||
# References:
|
||||
# - Calls `is_script_sourced()` in this file.
|
||||
# - Calls `load_ros2_environment()` in this file.
|
||||
# - Calls `load_workspace_environment()` in this file.
|
||||
# - Calls `ensure_ros_log_directory()` in this file.
|
||||
# - Calls `launch_default_ros2_stack()` in this file.
|
||||
# - Calls `run_command_with_environment()` in this file.
|
||||
# - Calls `start_interactive_shell()` in this file.
|
||||
# - Calls `print_usage()` in this file.
|
||||
main() {
|
||||
write_debug_log "main_enter" "argv:$*"
|
||||
|
||||
if ! is_script_sourced; then
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
print_usage
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
load_ros2_environment || return 1
|
||||
load_workspace_environment || return 1
|
||||
ensure_ros_log_directory || return 1
|
||||
|
||||
if is_script_sourced; then
|
||||
if [ "$#" -gt 0 ]; then
|
||||
write_debug_log "main_warn" "arguments_ignored_when_sourced"
|
||||
print_warn "Arguments are ignored when the script is sourced."
|
||||
fi
|
||||
write_debug_log "main_exit" "current_shell_ready"
|
||||
print_info "Environment is ready in the current shell."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
write_debug_log "main_handoff" "default_launch_requested"
|
||||
launch_default_ros2_stack
|
||||
fi
|
||||
|
||||
if [ "$1" = "--shell" ]; then
|
||||
write_debug_log "main_handoff" "interactive_shell_requested"
|
||||
start_interactive_shell
|
||||
fi
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
write_debug_log "main_handoff" "command_execution_requested"
|
||||
run_command_with_environment "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,4 @@
|
||||
recorddata/
|
||||
/config/calib.yaml
|
||||
/log
|
||||
/map
|
||||
@@ -0,0 +1,642 @@
|
||||
# Relocalization Guide / 重定位使用指南
|
||||
|
||||
This guide explains how to use the relocalization feature in Odin ROS Driver, including automatic relocalization and init position relocalization modes.
|
||||
|
||||
本指南介绍如何使用 Odin ROS Driver 的重定位功能,包括自动重定位和指定初始位置重定位两种模式。
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents / 目录
|
||||
|
||||
1. [Overview / 概述](#overview--概述)
|
||||
2. [Prerequisites / 前提条件](#prerequisites--前提条件)
|
||||
3. [Mode 1: Auto Relocalization / 自动重定位](#mode-1-auto-relocalization--自动重定位)
|
||||
4. [Mode 2: Init Position Relocalization / 指定初始位置重定位](#mode-2-init-position-relocalization--指定初始位置重定位)
|
||||
5. [init_pos Format / init_pos 格式说明](#init_pos-format--init_pos-格式说明)
|
||||
6. [Configuration Examples / 配置示例](#configuration-examples--配置示例)
|
||||
7. [Programmatic API / 编程接口](#programmatic-api--编程接口)
|
||||
8. [Troubleshooting / 故障排除](#troubleshooting--故障排除)
|
||||
|
||||
---
|
||||
|
||||
## Overview / 概述
|
||||
|
||||
### English
|
||||
|
||||
Relocalization mode (`custom_map_mode: 2`) allows Odin to localize itself within a pre-built map. There are two approaches:
|
||||
|
||||
| Mode | Description | Use Case |
|
||||
|------|-------------|----------|
|
||||
| **Auto Relocalization** | Algorithm automatically searches for position in the map | Starting position is unknown or within recommended range |
|
||||
| **Init Position Relocalization** | User provides an initial pose estimate via `init_pos` | Starting position is known, faster convergence needed |
|
||||
|
||||
### 中文
|
||||
|
||||
重定位模式(`custom_map_mode: 2`)允许 Odin 在预先构建的地图中进行自我定位。有两种方式:
|
||||
|
||||
| 模式 | 描述 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| **自动重定位** | 算法自动在地图中搜索位置 | 起始位置未知,或在推荐范围内 |
|
||||
| **指定初始位置重定位** | 用户通过 `init_pos` 提供初始位姿估计 | 起始位置已知,需要更快收敛 |
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites / 前提条件
|
||||
|
||||
### English
|
||||
|
||||
1. **Pre-built map file**: A `.bin` map file created in SLAM mode (`custom_map_mode: 1`)
|
||||
2. **Map file path**: Know the absolute path to your map file
|
||||
3. **Starting position**: For init position mode, know the approximate starting pose in map coordinates
|
||||
|
||||
### 中文
|
||||
|
||||
1. **预构建的地图文件**:在 SLAM 模式(`custom_map_mode: 1`)下创建的 `.bin` 地图文件
|
||||
2. **地图文件路径**:知道地图文件的绝对路径
|
||||
3. **起始位置**:对于指定初始位置模式,需要知道在地图坐标系中的大致起始位姿
|
||||
|
||||
---
|
||||
|
||||
## Mode 1: Auto Relocalization / 自动重定位
|
||||
|
||||
### English
|
||||
|
||||
In auto relocalization mode, the algorithm automatically searches for the device's position within the map based on current sensor observations.
|
||||
|
||||
**Configuration** (`config/control_command.yaml`):
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/path/to/your/map.bin"
|
||||
# custom_init_pos is NOT set or uses default [0,0,0,0,0,0,1]
|
||||
```
|
||||
|
||||
**Recommended Starting Conditions**:
|
||||
- Within **1 meter** of a position on the original SLAM trajectory
|
||||
- Within **±10 degrees** of the original orientation
|
||||
- In a visually distinctive area of the map
|
||||
|
||||
**Behavior**:
|
||||
1. On startup, Odin attempts to match current observations with the map
|
||||
2. If successful, TF between `map` and `odom` frames is published
|
||||
3. If unsuccessful, system operates in fallback SLAM mode (map saving disabled)
|
||||
4. Relocalization attempts continue in background until successful
|
||||
|
||||
**Tips**:
|
||||
- Gently shaking or moving the device after startup can improve relocalization accuracy
|
||||
- Highly distinctive scenes may allow successful matching beyond the 1m/10° range
|
||||
|
||||
### 中文
|
||||
|
||||
在自动重定位模式下,算法根据当前传感器观测自动在地图中搜索设备位置。
|
||||
|
||||
**配置** (`config/control_command.yaml`):
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/path/to/your/map.bin"
|
||||
# custom_init_pos 不设置或使用默认值 [0,0,0,0,0,0,1]
|
||||
```
|
||||
|
||||
**推荐起始条件**:
|
||||
- 距离原始 SLAM 轨迹上某点 **1 米**以内
|
||||
- 朝向与原始方向偏差在 **±10 度**以内
|
||||
- 位于地图中视觉特征明显的区域
|
||||
|
||||
**行为**:
|
||||
1. 启动时,Odin 尝试将当前观测与地图匹配
|
||||
2. 如果成功,发布 `map` 和 `odom` 坐标系之间的 TF
|
||||
3. 如果失败,系统进入后备 SLAM 模式(地图保存功能禁用)
|
||||
4. 后台持续尝试重定位直到成功
|
||||
|
||||
**提示**:
|
||||
- 启动后轻轻晃动或移动设备可以提高重定位精度
|
||||
- 在特征明显的场景中,可能在超出 1m/10° 范围时也能成功匹配
|
||||
|
||||
---
|
||||
|
||||
## Mode 2: Init Position Relocalization / 指定初始位置重定位
|
||||
|
||||
### English
|
||||
|
||||
In init position relocalization mode, you provide an initial pose estimate to help the algorithm converge faster.
|
||||
|
||||
**Configuration** (`config/control_command.yaml`):
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/path/to/your/map.bin"
|
||||
custom_init_pos: [x, y, z, qx, qy, qz, qw]
|
||||
```
|
||||
|
||||
**When to Use**:
|
||||
- You know the approximate starting position (e.g., from external localization system)
|
||||
- Starting position is far from the recommended 1m/10° range
|
||||
- You need faster relocalization convergence
|
||||
- Deploying in a fixed docking station with known pose
|
||||
|
||||
**Behavior**:
|
||||
1. Algorithm uses provided `init_pos` as initial pose estimate
|
||||
2. Searches for matches in the vicinity of the provided position
|
||||
3. Faster convergence compared to auto mode when estimate is accurate
|
||||
|
||||
### 中文
|
||||
|
||||
在指定初始位置重定位模式下,您提供初始位姿估计以帮助算法更快收敛。
|
||||
|
||||
**配置** (`config/control_command.yaml`):
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/path/to/your/map.bin"
|
||||
custom_init_pos: [x, y, z, qx, qy, qz, qw]
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
- 您知道大致的起始位置(例如,来自外部定位系统)
|
||||
- 起始位置远离推荐的 1m/10° 范围
|
||||
- 需要更快的重定位收敛速度
|
||||
- 部署在已知位姿的固定充电桩
|
||||
|
||||
**行为**:
|
||||
1. 算法使用提供的 `init_pos` 作为初始位姿估计
|
||||
2. 在提供位置的附近搜索匹配
|
||||
3. 当估计准确时,比自动模式收敛更快
|
||||
|
||||
---
|
||||
|
||||
## init_pos Format / init_pos 格式说明
|
||||
|
||||
### English
|
||||
|
||||
`init_pos` is an array of **7 float values** representing position and orientation:
|
||||
|
||||
```yaml
|
||||
custom_init_pos: [x, y, z, qx, qy, qz, qw]
|
||||
```
|
||||
|
||||
| Index | Parameter | Description | Unit |
|
||||
|-------|-----------|-------------|------|
|
||||
| 0 | x | X position in map frame | meters |
|
||||
| 1 | y | Y position in map frame | meters |
|
||||
| 2 | z | Z position in map frame | meters |
|
||||
| 3 | qx | Quaternion X component | - |
|
||||
| 4 | qy | Quaternion Y component | - |
|
||||
| 5 | qz | Quaternion Z component | - |
|
||||
| 6 | qw | Quaternion W component | - |
|
||||
|
||||
**Important Notes**:
|
||||
- The quaternion must be normalized: `sqrt(qx² + qy² + qz² + qw²) ≈ 1.0`
|
||||
- Coordinates are relative to the **map frame** (world frame at SLAM start)
|
||||
- Default value `[0, 0, 0, 0, 0, 0, 1]` represents origin with no rotation
|
||||
|
||||
**Common Quaternion Values**:
|
||||
|
||||
| Orientation | qx | qy | qz | qw |
|
||||
|-------------|----|----|----|----|
|
||||
| No rotation (identity) | 0 | 0 | 0 | 1 |
|
||||
| 90° around Z-axis | 0 | 0 | 0.707 | 0.707 |
|
||||
| 180° around Z-axis | 0 | 0 | 1 | 0 |
|
||||
| -90° around Z-axis | 0 | 0 | -0.707 | 0.707 |
|
||||
|
||||
### 中文
|
||||
|
||||
`init_pos` 是一个包含 **7 个 float 值**的数组,表示位置和朝向:
|
||||
|
||||
```yaml
|
||||
custom_init_pos: [x, y, z, qx, qy, qz, qw]
|
||||
```
|
||||
|
||||
| 索引 | 参数 | 描述 | 单位 |
|
||||
|------|------|------|------|
|
||||
| 0 | x | 地图坐标系中的 X 位置 | 米 |
|
||||
| 1 | y | 地图坐标系中的 Y 位置 | 米 |
|
||||
| 2 | z | 地图坐标系中的 Z 位置 | 米 |
|
||||
| 3 | qx | 四元数 X 分量 | - |
|
||||
| 4 | qy | 四元数 Y 分量 | - |
|
||||
| 5 | qz | 四元数 Z 分量 | - |
|
||||
| 6 | qw | 四元数 W 分量 | - |
|
||||
|
||||
**重要说明**:
|
||||
- 四元数必须归一化:`sqrt(qx² + qy² + qz² + qw²) ≈ 1.0`
|
||||
- 坐标相对于**地图坐标系**(SLAM 启动时的世界坐标系)
|
||||
- 默认值 `[0, 0, 0, 0, 0, 0, 1]` 表示原点且无旋转
|
||||
|
||||
**常用四元数值**:
|
||||
|
||||
| 朝向 | qx | qy | qz | qw |
|
||||
|------|----|----|----|----|
|
||||
| 无旋转(单位四元数) | 0 | 0 | 0 | 1 |
|
||||
| 绕 Z 轴旋转 90° | 0 | 0 | 0.707 | 0.707 |
|
||||
| 绕 Z 轴旋转 180° | 0 | 0 | 1 | 0 |
|
||||
| 绕 Z 轴旋转 -90° | 0 | 0 | -0.707 | 0.707 |
|
||||
|
||||
---
|
||||
|
||||
## Configuration Examples / 配置示例
|
||||
|
||||
### Example 1: Auto Relocalization / 自动重定位示例
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/home/user/maps/office_map.bin"
|
||||
```
|
||||
|
||||
### Example 2: Init Position at Origin / 在原点指定初始位置
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/home/user/maps/office_map.bin"
|
||||
custom_init_pos: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
|
||||
```
|
||||
|
||||
### Example 3: Init Position with Offset / 带偏移的初始位置
|
||||
|
||||
Position at (5.2, -3.1, 0) with 90° rotation around Z-axis:
|
||||
|
||||
位置在 (5.2, -3.1, 0),绕 Z 轴旋转 90°:
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/home/user/maps/warehouse_map.bin"
|
||||
custom_init_pos: [5.2, -3.1, 0.0, 0.0, 0.0, 0.707, 0.707]
|
||||
```
|
||||
|
||||
### Example 4: Docking Station Pose / 充电桩位置
|
||||
|
||||
Known docking station at (10.5, 2.3, 0) facing -X direction (180° rotation):
|
||||
|
||||
已知充电桩位置在 (10.5, 2.3, 0),朝向 -X 方向(旋转 180°):
|
||||
|
||||
```yaml
|
||||
register_keys:
|
||||
custom_map_mode: 2
|
||||
relocalization_map_abs_path: "/home/user/maps/factory_map.bin"
|
||||
custom_init_pos: [10.5, 2.3, 0.0, 0.0, 0.0, 1.0, 0.0]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Programmatic API / 编程接口
|
||||
|
||||
### English
|
||||
|
||||
You can also set `init_pos` programmatically using the `lidar_set_custom_parameter` API. This is useful for:
|
||||
- Dynamic relocalization during runtime
|
||||
- Integration with external localization systems
|
||||
- Setting initial pose from robot's last known position
|
||||
|
||||
#### API Function
|
||||
|
||||
```cpp
|
||||
#include "lidar_api.h"
|
||||
|
||||
/**
|
||||
* @brief Set a custom parameter on the device
|
||||
* @param device Device handle obtained from lidar_open_device()
|
||||
* @param param_name Parameter name (e.g., "init_pos")
|
||||
* @param value_data Pointer to the parameter data
|
||||
* @param value_length Size of the data in bytes
|
||||
* @return 0 on success, -1 on error, -2 if file transfer in progress
|
||||
*/
|
||||
int lidar_set_custom_parameter(device_handle device,
|
||||
const char* param_name,
|
||||
const void* value_data,
|
||||
size_t value_length);
|
||||
```
|
||||
|
||||
#### Complete Example
|
||||
|
||||
```cpp
|
||||
#include "lidar_api.h"
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
|
||||
// Helper function to create quaternion from yaw angle (rotation around Z-axis)
|
||||
void yaw_to_quaternion(float yaw_rad, float* qx, float* qy, float* qz, float* qw) {
|
||||
*qx = 0.0f;
|
||||
*qy = 0.0f;
|
||||
*qz = sinf(yaw_rad / 2.0f);
|
||||
*qw = cosf(yaw_rad / 2.0f);
|
||||
}
|
||||
|
||||
int set_init_position(device_handle device,
|
||||
float x, float y, float z,
|
||||
float qx, float qy, float qz, float qw) {
|
||||
// init_pos format: [x, y, z, qx, qy, qz, qw] - 7 floats
|
||||
float init_pos[7] = {x, y, z, qx, qy, qz, qw};
|
||||
|
||||
int result = lidar_set_custom_parameter(
|
||||
device,
|
||||
"init_pos", // Parameter name
|
||||
init_pos, // Data pointer
|
||||
sizeof(init_pos) // 7 * sizeof(float) = 28 bytes
|
||||
);
|
||||
|
||||
if (result == 0) {
|
||||
printf("Successfully set init_pos: [%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f]\n",
|
||||
x, y, z, qx, qy, qz, qw);
|
||||
} else {
|
||||
printf("Failed to set init_pos, error code: %d\n", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Usage examples:
|
||||
|
||||
// Example 1: Set position at origin with no rotation
|
||||
void example_origin(device_handle device) {
|
||||
set_init_position(device,
|
||||
0.0f, 0.0f, 0.0f, // x, y, z
|
||||
0.0f, 0.0f, 0.0f, 1.0f // qx, qy, qz, qw (identity)
|
||||
);
|
||||
}
|
||||
|
||||
// Example 2: Set position with 90° yaw rotation
|
||||
void example_with_rotation(device_handle device) {
|
||||
float qx, qy, qz, qw;
|
||||
float yaw_degrees = 90.0f;
|
||||
float yaw_rad = yaw_degrees * M_PI / 180.0f;
|
||||
|
||||
yaw_to_quaternion(yaw_rad, &qx, &qy, &qz, &qw);
|
||||
|
||||
set_init_position(device,
|
||||
5.2f, -3.1f, 0.0f, // x, y, z
|
||||
qx, qy, qz, qw // quaternion from yaw
|
||||
);
|
||||
}
|
||||
|
||||
// Example 3: Set position from external localization system
|
||||
void example_from_external_localization(device_handle device,
|
||||
double ext_x, double ext_y, double ext_yaw) {
|
||||
float qx, qy, qz, qw;
|
||||
yaw_to_quaternion((float)ext_yaw, &qx, &qy, &qz, &qw);
|
||||
|
||||
set_init_position(device,
|
||||
(float)ext_x, (float)ext_y, 0.0f,
|
||||
qx, qy, qz, qw
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### ROS Integration Example
|
||||
|
||||
```cpp
|
||||
#include "lidar_api.h"
|
||||
#include <geometry_msgs/PoseWithCovarianceStamped.h> // ROS1
|
||||
// or
|
||||
#include <geometry_msgs/msg/pose_with_covariance_stamped.hpp> // ROS2
|
||||
|
||||
// Callback for /initialpose topic (from RViz "2D Pose Estimate" tool)
|
||||
void initialPoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg,
|
||||
device_handle device) {
|
||||
float init_pos[7] = {
|
||||
(float)msg->pose.pose.position.x,
|
||||
(float)msg->pose.pose.position.y,
|
||||
(float)msg->pose.pose.position.z,
|
||||
(float)msg->pose.pose.orientation.x,
|
||||
(float)msg->pose.pose.orientation.y,
|
||||
(float)msg->pose.pose.orientation.z,
|
||||
(float)msg->pose.pose.orientation.w
|
||||
};
|
||||
|
||||
int result = lidar_set_custom_parameter(device, "init_pos", init_pos, sizeof(init_pos));
|
||||
|
||||
if (result == 0) {
|
||||
ROS_INFO("Set init_pos from RViz: [%.2f, %.2f, %.2f]",
|
||||
init_pos[0], init_pos[1], init_pos[2]);
|
||||
} else {
|
||||
ROS_ERROR("Failed to set init_pos: %d", result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Important Notes
|
||||
|
||||
1. **Call timing**: Set `init_pos` **before** starting the stream with `lidar_start_stream()`
|
||||
2. **Map mode**: Ensure `custom_map_mode` is set to `2` (relocalization mode)
|
||||
3. **Map file**: The relocalization map must be set via `lidar_set_relocalization_map()` or YAML config
|
||||
4. **Thread safety**: `lidar_set_custom_parameter` is thread-safe but blocks until response received
|
||||
|
||||
### 中文
|
||||
|
||||
您也可以使用 `lidar_set_custom_parameter` API 以编程方式设置 `init_pos`。适用于:
|
||||
- 运行时动态重定位
|
||||
- 与外部定位系统集成
|
||||
- 从机器人上次已知位置设置初始位姿
|
||||
|
||||
#### API 函数
|
||||
|
||||
```cpp
|
||||
#include "lidar_api.h"
|
||||
|
||||
/**
|
||||
* @brief 在设备上设置自定义参数
|
||||
* @param device 从 lidar_open_device() 获取的设备句柄
|
||||
* @param param_name 参数名称(如 "init_pos")
|
||||
* @param value_data 指向参数数据的指针
|
||||
* @param value_length 数据大小(字节)
|
||||
* @return 成功返回 0,错误返回 -1,文件传输中返回 -2
|
||||
*/
|
||||
int lidar_set_custom_parameter(device_handle device,
|
||||
const char* param_name,
|
||||
const void* value_data,
|
||||
size_t value_length);
|
||||
```
|
||||
|
||||
#### 完整示例
|
||||
|
||||
```cpp
|
||||
#include "lidar_api.h"
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
|
||||
// 辅助函数:从偏航角(绕 Z 轴旋转)创建四元数
|
||||
void yaw_to_quaternion(float yaw_rad, float* qx, float* qy, float* qz, float* qw) {
|
||||
*qx = 0.0f;
|
||||
*qy = 0.0f;
|
||||
*qz = sinf(yaw_rad / 2.0f);
|
||||
*qw = cosf(yaw_rad / 2.0f);
|
||||
}
|
||||
|
||||
int set_init_position(device_handle device,
|
||||
float x, float y, float z,
|
||||
float qx, float qy, float qz, float qw) {
|
||||
// init_pos 格式: [x, y, z, qx, qy, qz, qw] - 7 个 float
|
||||
float init_pos[7] = {x, y, z, qx, qy, qz, qw};
|
||||
|
||||
int result = lidar_set_custom_parameter(
|
||||
device,
|
||||
"init_pos", // 参数名
|
||||
init_pos, // 数据指针
|
||||
sizeof(init_pos) // 7 * sizeof(float) = 28 字节
|
||||
);
|
||||
|
||||
if (result == 0) {
|
||||
printf("成功设置 init_pos: [%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f]\n",
|
||||
x, y, z, qx, qy, qz, qw);
|
||||
} else {
|
||||
printf("设置 init_pos 失败,错误码: %d\n", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 使用示例:
|
||||
|
||||
// 示例 1:在原点设置位置,无旋转
|
||||
void example_origin(device_handle device) {
|
||||
set_init_position(device,
|
||||
0.0f, 0.0f, 0.0f, // x, y, z
|
||||
0.0f, 0.0f, 0.0f, 1.0f // qx, qy, qz, qw(单位四元数)
|
||||
);
|
||||
}
|
||||
|
||||
// 示例 2:设置带 90° 偏航旋转的位置
|
||||
void example_with_rotation(device_handle device) {
|
||||
float qx, qy, qz, qw;
|
||||
float yaw_degrees = 90.0f;
|
||||
float yaw_rad = yaw_degrees * M_PI / 180.0f;
|
||||
|
||||
yaw_to_quaternion(yaw_rad, &qx, &qy, &qz, &qw);
|
||||
|
||||
set_init_position(device,
|
||||
5.2f, -3.1f, 0.0f, // x, y, z
|
||||
qx, qy, qz, qw // 从偏航角计算的四元数
|
||||
);
|
||||
}
|
||||
|
||||
// 示例 3:从外部定位系统设置位置
|
||||
void example_from_external_localization(device_handle device,
|
||||
double ext_x, double ext_y, double ext_yaw) {
|
||||
float qx, qy, qz, qw;
|
||||
yaw_to_quaternion((float)ext_yaw, &qx, &qy, &qz, &qw);
|
||||
|
||||
set_init_position(device,
|
||||
(float)ext_x, (float)ext_y, 0.0f,
|
||||
qx, qy, qz, qw
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### ROS 集成示例
|
||||
|
||||
```cpp
|
||||
#include "lidar_api.h"
|
||||
#include <geometry_msgs/PoseWithCovarianceStamped.h> // ROS1
|
||||
// 或
|
||||
#include <geometry_msgs/msg/pose_with_covariance_stamped.hpp> // ROS2
|
||||
|
||||
// /initialpose 话题的回调函数(来自 RViz 的 "2D Pose Estimate" 工具)
|
||||
void initialPoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg,
|
||||
device_handle device) {
|
||||
float init_pos[7] = {
|
||||
(float)msg->pose.pose.position.x,
|
||||
(float)msg->pose.pose.position.y,
|
||||
(float)msg->pose.pose.position.z,
|
||||
(float)msg->pose.pose.orientation.x,
|
||||
(float)msg->pose.pose.orientation.y,
|
||||
(float)msg->pose.pose.orientation.z,
|
||||
(float)msg->pose.pose.orientation.w
|
||||
};
|
||||
|
||||
int result = lidar_set_custom_parameter(device, "init_pos", init_pos, sizeof(init_pos));
|
||||
|
||||
if (result == 0) {
|
||||
ROS_INFO("从 RViz 设置 init_pos: [%.2f, %.2f, %.2f]",
|
||||
init_pos[0], init_pos[1], init_pos[2]);
|
||||
} else {
|
||||
ROS_ERROR("设置 init_pos 失败: %d", result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 重要说明
|
||||
|
||||
1. **调用时机**:在调用 `lidar_start_stream()` 启动数据流**之前**设置 `init_pos`
|
||||
2. **地图模式**:确保 `custom_map_mode` 设置为 `2`(重定位模式)
|
||||
3. **地图文件**:必须通过 `lidar_set_relocalization_map()` 或 YAML 配置设置重定位地图
|
||||
4. **线程安全**:`lidar_set_custom_parameter` 是线程安全的,但会阻塞直到收到响应
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting / 故障排除
|
||||
|
||||
### Relocalization Fails / 重定位失败
|
||||
|
||||
**English**:
|
||||
- Ensure starting position is within recommended range (1m/10°)
|
||||
- Check that the map file path is correct and file exists
|
||||
- Verify the environment hasn't changed significantly since mapping
|
||||
- Try gently moving the device to provide more observations
|
||||
|
||||
**中文**:
|
||||
- 确保起始位置在推荐范围内(1m/10°)
|
||||
- 检查地图文件路径是否正确且文件存在
|
||||
- 验证环境自建图以来没有显著变化
|
||||
- 尝试轻轻移动设备以提供更多观测
|
||||
|
||||
### init_pos Not Taking Effect / init_pos 未生效
|
||||
|
||||
**English**:
|
||||
- Verify `custom_map_mode` is set to `2`
|
||||
- Check that `custom_init_pos` has exactly 7 values
|
||||
- Ensure quaternion is normalized (sum of squares ≈ 1)
|
||||
- Restart the driver after modifying configuration
|
||||
|
||||
**中文**:
|
||||
- 验证 `custom_map_mode` 设置为 `2`
|
||||
- 检查 `custom_init_pos` 是否恰好有 7 个值
|
||||
- 确保四元数已归一化(平方和 ≈ 1)
|
||||
- 修改配置后重启驱动程序
|
||||
|
||||
### TF Not Published / TF 未发布
|
||||
|
||||
**English**:
|
||||
- Relocalization may still be in progress
|
||||
- Check ROS logs for relocalization status messages
|
||||
- System operates in fallback mode until relocalization succeeds
|
||||
|
||||
**中文**:
|
||||
- 重定位可能仍在进行中
|
||||
- 检查 ROS 日志中的重定位状态消息
|
||||
- 系统在重定位成功前以后备模式运行
|
||||
|
||||
### Map File Not Found / 地图文件未找到
|
||||
|
||||
**English**:
|
||||
- Use absolute path (starting with `/`)
|
||||
- Check file permissions
|
||||
- Verify file extension is `.bin`
|
||||
|
||||
**中文**:
|
||||
- 使用绝对路径(以 `/` 开头)
|
||||
- 检查文件权限
|
||||
- 验证文件扩展名为 `.bin`
|
||||
|
||||
---
|
||||
|
||||
## Related Topics / 相关话题
|
||||
|
||||
| Topic | Description |
|
||||
|-------|-------------|
|
||||
| `/odin1/odometry` | Odometry in odom frame |
|
||||
| `/odin1/odometry_highfreq` | High-frequency odometry |
|
||||
| `/odin1/cloud_slam` | SLAM point cloud in odom frame |
|
||||
| `/tf` | Transform tree (includes map→odom after successful relocalization) |
|
||||
|
||||
---
|
||||
|
||||
## See Also / 参见
|
||||
|
||||
- [README.md](README.md) - Main documentation
|
||||
- [config/control_command.yaml](config/control_command.yaml) - Configuration file
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# RC_WheelLeg / Odin1 ROS 工作区说明
|
||||
|
||||
本目录是一个 ROS 工作区归档,当前根目录为 `D:\桌面\catkin_ws`,主要内容位于子目录 `catkin_ws`。
|
||||
|
||||
## 目录内容
|
||||
|
||||
```text
|
||||
D:\桌面\catkin_ws
|
||||
└── catkin_ws
|
||||
├── README.md
|
||||
├── odin1的使用手册.md
|
||||
├── project.log
|
||||
├── runros.sh
|
||||
└── src
|
||||
└── odin_ros_driver
|
||||
├── .gitignore
|
||||
└── RELOCALIZATION_GUIDE.md
|
||||
```
|
||||
|
||||
## 文件说明
|
||||
|
||||
- `catkin_ws/README.md`:原工作区说明文档,描述 Odin1 与 ROS 工作区的基本使用方式。
|
||||
- `catkin_ws/odin1的使用手册.md`:Odin1 使用手册。
|
||||
- `catkin_ws/project.log`:项目日志文件。
|
||||
- `catkin_ws/runros.sh`:ROS 环境构建/运行相关脚本。
|
||||
- `catkin_ws/src/odin_ros_driver/`:Odin ROS 驱动目录。该目录内部当前保留了独立 Git 仓库元数据,外层仓库仅记录其中当前可见的普通文件。
|
||||
- `catkin_ws/src/odin_ros_driver/RELOCALIZATION_GUIDE.md`:重定位相关说明文档。
|
||||
|
||||
## 注意事项
|
||||
|
||||
- `catkin_ws/src/odin_ros_driver` 本身是一个独立 Git 仓库;在外层仓库提交时,应避免把其内部 `.git` 目录作为外层仓库内容提交。
|
||||
- 当前归档按磁盘现有内容整理,未包含 ROS 构建产物目录,例如 `build/`、`install/`、`log/`。
|
||||
- 如需完整恢复 `odin_ros_driver` 的驱动源码,应以其内部 Git 仓库或官方远程仓库状态为准。
|
||||
Reference in New Issue
Block a user