博客地址:https://www.cnblogs.com/zylyehuo/
适用环境:Ubuntu 22.04、ROS 2 Humble、Ranger Mini V3。
录制话题固定为:/cmd_vel、/odom、/lio/odom、/tf、/tf_static。
全部八部分累计应有 157 个 bag
1. 测试目标
本测试仅负责采集 Ranger Mini V3 的底盘运动数据。所有 rosbag 录制完成后,再统一进行数据处理、轨迹对齐和误差统计。
测试分为以下五部分:
- 静止误差测试;
- 正向与反向直线运动测试;
- 正向与反向圆周运动测试;
- 正向与反向启停响应测试;
- 正向与反向转向切换及回正测试。
2. 重要操作原则
- 每一次测试对应一个独立 bag,不把多个工况录入同一个 bag。
- 每一个测试小节中,终端 1 的录包指令只对应紧随其后的终端 2 速度指令。
- 每次录包开始后先静止 5 秒,再发布运动指令。
- 运动结束后必须持续发布零速度,保留完整停车过程。
- 零速度发布结束、车辆确认停止后,再在录包终端按
Ctrl+C。 - 每次动态测试都尽量从相同起点和相同初始朝向开始。
- 测试过程中不得同时运行导航、LQR、MPPI、键盘遥控或其他
/cmd_vel发布节点。
3. 终端分工
| 终端 | 作用 |
|---|---|
| 终端 1 | 执行当前测试对应的 ros2 bag record 指令 |
| 终端 2 | 执行当前测试对应的 /cmd_vel 指令 |
| 终端 3 | 保留紧急停车指令 |
4. 一次性建立测试目录
bash
mkdir -p ~/ranger_motion_test/01_static_error
mkdir -p ~/ranger_motion_test/02_straight/forward
mkdir -p ~/ranger_motion_test/02_straight/reverse
mkdir -p ~/ranger_motion_test/03_circle/forward
mkdir -p ~/ranger_motion_test/03_circle/reverse
mkdir -p ~/ranger_motion_test/04_start_stop/forward
mkdir -p ~/ranger_motion_test/04_start_stop/reverse
mkdir -p ~/ranger_motion_test/05_steering_switch/forward
mkdir -p ~/ranger_motion_test/05_steering_switch/reverse
检查目录:
bash
find ~/ranger_motion_test -type d | sort
目录结构:
text
~/ranger_motion_test/
├── 01_static_error/
├── 02_straight/
│ ├── forward/
│ └── reverse/
├── 03_circle/
│ ├── forward/
│ └── reverse/
├── 04_start_stop/
│ ├── forward/
│ └── reverse/
└── 05_steering_switch/
├── forward/
└── reverse/
5. 测试前检查
5.1 检查 /cmd_vel 消息类型
bash
ros2 topic type /cmd_vel
预期输出:
text
geometry_msgs/msg/Twist
5.2 检查 /cmd_vel 发布者
bash
ros2 topic info /cmd_vel -v
正式测试前,应关闭导航、LQR、MPPI、遥控器和其他所有 /cmd_vel 发布节点。
5.3 检查轮式里程计
bash
ros2 topic hz /odom
bash
ros2 topic echo /odom --once
5.4 检查雷达定位里程计
bash
ros2 topic hz /lio/odom
bash
ros2 topic echo /lio/odom --once
5.5 紧急停车指令
终端 3 中提前保留以下命令。车辆运动异常时立即执行:
bash
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
6. 测试总表
| 部分 | 测试内容 | 工况数 | 单工况次数 | Bag 数量 |
|---|---|---|---|---|
| 第一部分 | 静止误差 | 1 | 3 | 3 |
| 第二部分 | 正反向直线 | 6 | 3 | 18 |
| 第三部分 | 正反向圆周 | 4 | 3 | 12 |
| 第四部分 | 正反向启停 | 2 | 5 | 10 |
| 第五部分 | 正反向转向切换 | 2 | 3 | 6 |
| 总计 | --- | 15 | --- | 49 |
第一部分:静止误差测试
1.1 作用
用于记录车辆完全静止时,轮式里程计和雷达定位里程计的位置漂移、航向漂移、随机波动和定位跳变。该结果决定后续厘米级运动误差统计的可信下限。
1.2 测试要求
- 车辆保持上电且完全静止;
- 不触碰车辆;
- 人员不要在雷达近距离范围内频繁移动;
- 每次持续 60 秒;
- 共录制 3 次。
静止测试第 1 次:STATIC_T60_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/01_static_error/STATIC_T60_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
持续发布零速度 60 秒:
bash
timeout --signal=INT 60s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
静止测试第 2 次:STATIC_T60_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/01_static_error/STATIC_T60_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
持续发布零速度 60 秒:
bash
timeout --signal=INT 60s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
静止测试第 3 次:STATIC_T60_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/01_static_error/STATIC_T60_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
持续发布零速度 60 秒:
bash
timeout --signal=INT 60s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第二部分:正向与反向直线运动测试
2.1 作用
用于评价实际速度、实际行驶距离、直线横向漂移、航向漂移、正反向对称性,以及轮式里程计相对于雷达定位里程计的累计偏差。
2.2 场地要求
- 建议在地面标记一条至少 7 m 的直线;
- 标记车辆初始参考点和车身初始中心线;
- 前方和后方均预留足够安全距离;
- 每次测试重新回到相同起点和相同朝向。
2.3 工况表
| 工况 | linear.x |
angular.z |
运动时间 | 理论距离 | 次数 |
|---|---|---|---|---|---|
| 正向直线 | 0.2 m/s | 0 rad/s | 10 s | 2.0 m | 3 |
| 反向直线 | -0.2 m/s | 0 rad/s | 10 s | -2.0 m | 3 |
| 正向直线 | 0.4 m/s | 0 rad/s | 10 s | 4.0 m | 3 |
| 反向直线 | -0.4 m/s | 0 rad/s | 10 s | -4.0 m | 3 |
| 正向直线 | 0.6 m/s | 0 rad/s | 10 s | 6.0 m | 3 |
| 反向直线 | -0.6 m/s | 0 rad/s | 10 s | -6.0 m | 3 |
建议按"正向 0.2 → 反向 0.2 → 正向 0.4 → 反向 0.4 → 正向 0.6 → 反向 0.6"的顺序测试。
2.4 正向直线 0.2 m/s
- 运动时间:10 秒
- 角速度:0 rad/s
- 理论距离:2.0 m
- 重复次数:3 次
第 1 次:FWD_STRAIGHT_V020_T10_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V020_T10_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:FWD_STRAIGHT_V020_T10_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V020_T10_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:FWD_STRAIGHT_V020_T10_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V020_T10_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
2.5 反向直线 -0.2 m/s
- 运动时间:10 秒
- 角速度:0 rad/s
- 理论距离:-2.0 m
- 重复次数:3 次
第 1 次:REV_STRAIGHT_V020_T10_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V020_T10_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:REV_STRAIGHT_V020_T10_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V020_T10_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:REV_STRAIGHT_V020_T10_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V020_T10_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
2.6 正向直线 0.4 m/s
- 运动时间:10 秒
- 角速度:0 rad/s
- 理论距离:4.0 m
- 重复次数:3 次
第 1 次:FWD_STRAIGHT_V040_T10_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V040_T10_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:FWD_STRAIGHT_V040_T10_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V040_T10_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:FWD_STRAIGHT_V040_T10_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V040_T10_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
2.7 反向直线 -0.4 m/s
- 运动时间:10 秒
- 角速度:0 rad/s
- 理论距离:-4.0 m
- 重复次数:3 次
第 1 次:REV_STRAIGHT_V040_T10_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V040_T10_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:REV_STRAIGHT_V040_T10_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V040_T10_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:REV_STRAIGHT_V040_T10_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V040_T10_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
2.8 正向直线 0.6 m/s
- 运动时间:10 秒
- 角速度:0 rad/s
- 理论距离:6.0 m
- 重复次数:3 次
只有在 0.2 m/s 和 0.4 m/s 工况运行安全且场地允许时,才执行本工况。
第 1 次:FWD_STRAIGHT_V060_T10_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V060_T10_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.6, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:FWD_STRAIGHT_V060_T10_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V060_T10_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.6, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:FWD_STRAIGHT_V060_T10_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/forward/FWD_STRAIGHT_V060_T10_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.6, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
2.9 反向直线 -0.6 m/s
- 运动时间:10 秒
- 角速度:0 rad/s
- 理论距离:-6.0 m
- 重复次数:3 次
只有在 0.2 m/s 和 0.4 m/s 工况运行安全且场地允许时,才执行本工况。
第 1 次:REV_STRAIGHT_V060_T10_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V060_T10_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.6, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:REV_STRAIGHT_V060_T10_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V060_T10_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.6, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:REV_STRAIGHT_V060_T10_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/02_straight/reverse/REV_STRAIGHT_V060_T10_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布直线运动速度 10 秒:
bash
timeout --signal=INT 10s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.6, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第三部分:正向与反向圆周运动测试
3.1 作用
用于评价实际转弯半径、角速度响应、左右转向对称性、正反向转向对称性、圆周闭合误差和转弯过程中的轮胎侧滑。
3.2 参数
理论半径:
R=\\frac{\|v\|}{\|\\omega\|}=\\frac{0.3}{0.2}=1.5\\ \\mathrm{m}
理论一周时间:
T=\\frac{2\\pi}{\|\\omega\|}=\\frac{2\\pi}{0.2}\\approx31.42\\ \\mathrm{s}
- 建议测试场地至少为 4 m × 4 m 的无障碍区域;
- 每个工况重复 3 次;
- 每次运动时间为 31.42 秒。
3.3 工况对应关系
| 正向工况 | 对应反向工况 | 理论半径 |
|---|---|---|
(0.3, 0.2) |
(-0.3, -0.2) |
1.5 m |
(0.3, -0.2) |
(-0.3, 0.2) |
1.5 m |
3.4 正向圆周:0.3 m/s,0.2 rad/s
- 运动时间:31.42 秒
- 理论半径:1.5 m
- 重复次数:3 次
第 1 次:FWD_CIRCLE_V030_WP020_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/forward/FWD_CIRCLE_V030_WP020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 2 次:FWD_CIRCLE_V030_WP020_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/forward/FWD_CIRCLE_V030_WP020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 3 次:FWD_CIRCLE_V030_WP020_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/forward/FWD_CIRCLE_V030_WP020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
3.5 反向圆周:-0.3 m/s,-0.2 rad/s
- 运动时间:31.42 秒
- 理论半径:1.5 m
- 重复次数:3 次
第 1 次:REV_CIRCLE_VN030_WN020_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/reverse/REV_CIRCLE_VN030_WN020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 2 次:REV_CIRCLE_VN030_WN020_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/reverse/REV_CIRCLE_VN030_WN020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 3 次:REV_CIRCLE_VN030_WN020_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/reverse/REV_CIRCLE_VN030_WN020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
3.6 正向圆周:0.3 m/s,-0.2 rad/s
- 运动时间:31.42 秒
- 理论半径:1.5 m
- 重复次数:3 次
第 1 次:FWD_CIRCLE_V030_WN020_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/forward/FWD_CIRCLE_V030_WN020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 2 次:FWD_CIRCLE_V030_WN020_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/forward/FWD_CIRCLE_V030_WN020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 3 次:FWD_CIRCLE_V030_WN020_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/forward/FWD_CIRCLE_V030_WN020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
3.7 反向圆周:-0.3 m/s,0.2 rad/s
- 运动时间:31.42 秒
- 理论半径:1.5 m
- 重复次数:3 次
第 1 次:REV_CIRCLE_VN030_WP020_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/reverse/REV_CIRCLE_VN030_WP020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 2 次:REV_CIRCLE_VN030_WP020_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/reverse/REV_CIRCLE_VN030_WP020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第 3 次:REV_CIRCLE_VN030_WP020_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/03_circle/reverse/REV_CIRCLE_VN030_WP020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布圆周运动速度 31.42 秒:
bash
timeout --signal=INT 31.42s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第一次执行该方向时,可先将运动时间临时改为 2 秒,以低速确认实际运动方向和转向方向。
第四部分:正向与反向启停响应测试
4.1 作用
用于记录速度指令开始后的启动延迟、加速过程、稳态速度、零速度指令后的制动过程、停车时间和停车附加距离。
4.2 工况
| 工况 | 运动速度 | 运动时间 | 零速度记录时间 | 次数 |
|---|---|---|---|---|
| 正向启停 | 0.4 m/s | 5 s | 8 s | 5 |
| 反向启停 | -0.4 m/s | 5 s | 8 s | 5 |
4.3 正向启停
- 运动时间:5 秒
- 停车后零速度持续时间:8 秒
- 重复次数:5 次
第 1 次:FWD_START_STOP_V040_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/forward/FWD_START_STOP_V040_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:FWD_START_STOP_V040_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/forward/FWD_START_STOP_V040_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:FWD_START_STOP_V040_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/forward/FWD_START_STOP_V040_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 4 次:FWD_START_STOP_V040_run04
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/forward/FWD_START_STOP_V040_run04 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 5 次:FWD_START_STOP_V040_run05
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/forward/FWD_START_STOP_V040_run05 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
4.4 反向启停
- 运动时间:5 秒
- 停车后零速度持续时间:8 秒
- 重复次数:5 次
第 1 次:REV_START_STOP_V040_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/reverse/REV_START_STOP_V040_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 2 次:REV_START_STOP_V040_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/reverse/REV_START_STOP_V040_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 3 次:REV_START_STOP_V040_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/reverse/REV_START_STOP_V040_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 4 次:REV_START_STOP_V040_run04
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/reverse/REV_START_STOP_V040_run04 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第 5 次:REV_START_STOP_V040_run05
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/04_start_stop/reverse/REV_START_STOP_V040_run05 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
发布运动速度 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.4, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
停车并继续记录 8 秒:
bash
timeout --signal=INT 8s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第五部分:正向与反向转向切换及回正测试
5.1 作用
用于评价左右转向切换、转向回正延迟、转向机构滞后、正反向回正差异,以及转向切换过程中是否出现车轮或车身摆动。
该测试始终保持非零线速度,不发布纯角速度,不要求双阿克曼底盘原地旋转。
5.2 正向转向切换过程
- 静止记录 5 秒;
linear.x=0.3、angular.z=0.2,持续 5 秒;linear.x=0.3、angular.z=0,持续 3 秒;linear.x=0.3、angular.z=-0.2,持续 5 秒;- 发布零速度 5 秒;
- 重复 3 次。
正向第 1 次:FWD_STEER_SWITCH_V030_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/05_steering_switch/forward/FWD_STEER_SWITCH_V030_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
第一段转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
直线回正段 3 秒:
bash
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
反方向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
正向第 2 次:FWD_STEER_SWITCH_V030_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/05_steering_switch/forward/FWD_STEER_SWITCH_V030_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
第一段转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
直线回正段 3 秒:
bash
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
反方向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
正向第 3 次:FWD_STEER_SWITCH_V030_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/05_steering_switch/forward/FWD_STEER_SWITCH_V030_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
第一段转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
直线回正段 3 秒:
bash
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
反方向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
5.3 反向转向切换过程
- 静止记录 5 秒;
linear.x=-0.3、angular.z=-0.2,持续 5 秒;linear.x=-0.3、angular.z=0,持续 3 秒;linear.x=-0.3、angular.z=0.2,持续 5 秒;- 发布零速度 5 秒;
- 重复 3 次。
反向第 1 次:REV_STEER_SWITCH_V030_run01
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/05_steering_switch/reverse/REV_STEER_SWITCH_V030_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
第一段反向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
反向直线回正段 3 秒:
bash
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
反方向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
反向第 2 次:REV_STEER_SWITCH_V030_run02
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/05_steering_switch/reverse/REV_STEER_SWITCH_V030_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
第一段反向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
反向直线回正段 3 秒:
bash
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
反方向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
反向第 3 次:REV_STEER_SWITCH_V030_run03
终端 1:开始录包
bash
ros2 bag record \
-o ~/ranger_motion_test/05_steering_switch/reverse/REV_STEER_SWITCH_V030_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:按顺序执行本次测试对应的速度指令
bash
sleep 5
第一段反向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.2}}"
反向直线回正段 3 秒:
bash
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
反方向转向 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.3, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.2}}"
停车并继续记录 5 秒:
bash
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:确认车辆已经停止后,按 Ctrl+C 结束本次录包。
第六部分:角速度增量自动阶梯响应测试
6.1 测试目的
该部分不再要求人工逐级执行每一个角度指令。终端 2 中的循环命令会自动连续发布完整阶梯序列,用于测试 Ranger Mini V3 对不同角速度增量的响应能力。
测试范围统一为:
\|\\omega_{\\mathrm{cmd}}\| \\leq 0.2\\ \\mathrm{rad/s}
每次测试自动完成:
- 从
0.00 rad/s按固定增量升到+0.20 rad/s; - 从
+0.20 rad/s按相同增量降回0.00 rad/s; - 保持直线指令 3 秒;
- 从
0.00 rad/s按固定增量降到-0.20 rad/s; - 从
-0.20 rad/s按相同增量升回0.00 rad/s; - 发布零速度 5 秒并结束测试。
/cmd_vel.angular.z的单位是rad/s,因此这里测试的是角速度指令增量 ,不是直接向底盘发布机械车轮转角。后续分析时,应以 bag 中实际记录到的新一级/cmd_vel首帧时间作为阶跃开始时刻。
6.2 测试变量
| 参数 | 设置 |
|---|---|
| 正向线速度 | 0.2 m/s |
| 反向线速度 | -0.2 m/s |
| 最大角速度绝对值 | 0.2 rad/s |
| 每一级保持时间 | 2 s |
| 正负阶梯之间的回正时间 | 3 s |
| 停车后记录时间 | 5 s |
| 每个工况重复次数 | 3 次 |
6.3 需要测试的角速度增量
| 组别 | 单次增量 Δω |
正向上升序列示例 | 主要作用 |
|---|---|---|---|
| G01 | 0.01 rad/s |
0.00, 0.01, ..., 0.20 |
检查小增量死区、微小指令能否立即执行 |
| G02 | 0.02 rad/s |
0.00, 0.02, ..., 0.20 |
检查小到中等增量的响应连续性 |
| G05 | 0.05 rad/s |
0.00, 0.05, 0.10, 0.15, 0.20 |
检查中等阶跃的延迟与超调 |
| G10 | 0.10 rad/s |
0.00, 0.10, 0.20 |
检查较大阶跃的快速响应能力 |
| G20 | 0.20 rad/s |
0.00, 0.20 |
检查允许范围内最大单次跳变 |
这五组可以判断:增量过小时是否落入死区,增量增大后延迟是否缩短,以及较大增量是否引起超调、摆动或转弯半径突变。
6.4 建立测试目录
bash
mkdir -p ~/ranger_motion_test/06_angular_step/G01_DW001/forward
mkdir -p ~/ranger_motion_test/06_angular_step/G01_DW001/reverse
mkdir -p ~/ranger_motion_test/06_angular_step/G02_DW002/forward
mkdir -p ~/ranger_motion_test/06_angular_step/G02_DW002/reverse
mkdir -p ~/ranger_motion_test/06_angular_step/G05_DW005/forward
mkdir -p ~/ranger_motion_test/06_angular_step/G05_DW005/reverse
mkdir -p ~/ranger_motion_test/06_angular_step/G10_DW010/forward
mkdir -p ~/ranger_motion_test/06_angular_step/G10_DW010/reverse
mkdir -p ~/ranger_motion_test/06_angular_step/G20_DW020/forward
mkdir -p ~/ranger_motion_test/06_angular_step/G20_DW020/reverse
检查目录:
bash
find ~/ranger_motion_test/06_angular_step -type d | sort
6.5 测试数量
| 增量组 | 正向次数 | 反向次数 | Bag 数量 |
|---|---|---|---|
Δω=0.01 rad/s |
3 | 3 | 6 |
Δω=0.02 rad/s |
3 | 3 | 6 |
Δω=0.05 rad/s |
3 | 3 | 6 |
Δω=0.10 rad/s |
3 | 3 | 6 |
Δω=0.20 rad/s |
3 | 3 | 6 |
| 合计 | 15 | 15 | 30 |
6.6 增量 Δω=0.01 rad/s
该组分别执行正向和反向测试,每个方向重复 3 次。终端命令会自动完成完整的正负角速度升降阶梯。
正向第 1 次:FWD_ANGULAR_STEP_G01_DW001_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G01_DW001/forward/FWD_ANGULAR_STEP_G01_DW001_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.01 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.19 -0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.01 -0.01 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.19 0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.01 rad/s的正向自动阶梯测试。
正向第 2 次:FWD_ANGULAR_STEP_G01_DW001_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G01_DW001/forward/FWD_ANGULAR_STEP_G01_DW001_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.01 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.19 -0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.01 -0.01 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.19 0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.01 rad/s的正向自动阶梯测试。
正向第 3 次:FWD_ANGULAR_STEP_G01_DW001_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G01_DW001/forward/FWD_ANGULAR_STEP_G01_DW001_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.01 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.19 -0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.01 -0.01 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.19 0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.01 rad/s的正向自动阶梯测试。
反向第 1 次:REV_ANGULAR_STEP_G01_DW001_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G01_DW001/reverse/REV_ANGULAR_STEP_G01_DW001_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.01 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.19 0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.01 0.01 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.19 -0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 2 次:REV_ANGULAR_STEP_G01_DW001_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G01_DW001/reverse/REV_ANGULAR_STEP_G01_DW001_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.01 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.19 0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.01 0.01 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.19 -0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 3 次:REV_ANGULAR_STEP_G01_DW001_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G01_DW001/reverse/REV_ANGULAR_STEP_G01_DW001_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.01 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.19 0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.01 0.01 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.19 -0.01 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
6.7 增量 Δω=0.02 rad/s
该组分别执行正向和反向测试,每个方向重复 3 次。终端命令会自动完成完整的正负角速度升降阶梯。
正向第 1 次:FWD_ANGULAR_STEP_G02_DW002_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G02_DW002/forward/FWD_ANGULAR_STEP_G02_DW002_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.02 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.18 -0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.02 -0.02 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.18 0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.02 rad/s的正向自动阶梯测试。
正向第 2 次:FWD_ANGULAR_STEP_G02_DW002_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G02_DW002/forward/FWD_ANGULAR_STEP_G02_DW002_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.02 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.18 -0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.02 -0.02 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.18 0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.02 rad/s的正向自动阶梯测试。
正向第 3 次:FWD_ANGULAR_STEP_G02_DW002_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G02_DW002/forward/FWD_ANGULAR_STEP_G02_DW002_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.02 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.18 -0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.02 -0.02 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.18 0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.02 rad/s的正向自动阶梯测试。
反向第 1 次:REV_ANGULAR_STEP_G02_DW002_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G02_DW002/reverse/REV_ANGULAR_STEP_G02_DW002_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.02 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.18 0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.02 0.02 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.18 -0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 2 次:REV_ANGULAR_STEP_G02_DW002_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G02_DW002/reverse/REV_ANGULAR_STEP_G02_DW002_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.02 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.18 0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.02 0.02 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.18 -0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 3 次:REV_ANGULAR_STEP_G02_DW002_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G02_DW002/reverse/REV_ANGULAR_STEP_G02_DW002_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.02 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.18 0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.02 0.02 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.18 -0.02 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
6.8 增量 Δω=0.05 rad/s
该组分别执行正向和反向测试,每个方向重复 3 次。终端命令会自动完成完整的正负角速度升降阶梯。
正向第 1 次:FWD_ANGULAR_STEP_G05_DW005_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G05_DW005/forward/FWD_ANGULAR_STEP_G05_DW005_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.05 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.15 -0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.05 -0.05 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.15 0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.05 rad/s的正向自动阶梯测试。
正向第 2 次:FWD_ANGULAR_STEP_G05_DW005_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G05_DW005/forward/FWD_ANGULAR_STEP_G05_DW005_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.05 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.15 -0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.05 -0.05 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.15 0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.05 rad/s的正向自动阶梯测试。
正向第 3 次:FWD_ANGULAR_STEP_G05_DW005_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G05_DW005/forward/FWD_ANGULAR_STEP_G05_DW005_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.05 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.15 -0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.05 -0.05 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.15 0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.05 rad/s的正向自动阶梯测试。
反向第 1 次:REV_ANGULAR_STEP_G05_DW005_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G05_DW005/reverse/REV_ANGULAR_STEP_G05_DW005_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.05 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.15 0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.05 0.05 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.15 -0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 2 次:REV_ANGULAR_STEP_G05_DW005_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G05_DW005/reverse/REV_ANGULAR_STEP_G05_DW005_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.05 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.15 0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.05 0.05 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.15 -0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 3 次:REV_ANGULAR_STEP_G05_DW005_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G05_DW005/reverse/REV_ANGULAR_STEP_G05_DW005_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.05 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.15 0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.05 0.05 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.15 -0.05 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
6.9 增量 Δω=0.10 rad/s
该组分别执行正向和反向测试,每个方向重复 3 次。终端命令会自动完成完整的正负角速度升降阶梯。
正向第 1 次:FWD_ANGULAR_STEP_G10_DW010_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G10_DW010/forward/FWD_ANGULAR_STEP_G10_DW010_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.10 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 -0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 -0.10 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.10 rad/s的正向自动阶梯测试。
正向第 2 次:FWD_ANGULAR_STEP_G10_DW010_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G10_DW010/forward/FWD_ANGULAR_STEP_G10_DW010_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.10 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 -0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 -0.10 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.10 rad/s的正向自动阶梯测试。
正向第 3 次:FWD_ANGULAR_STEP_G10_DW010_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G10_DW010/forward/FWD_ANGULAR_STEP_G10_DW010_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.10 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 -0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 -0.10 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.10 rad/s的正向自动阶梯测试。
反向第 1 次:REV_ANGULAR_STEP_G10_DW010_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G10_DW010/reverse/REV_ANGULAR_STEP_G10_DW010_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.10 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 0.10 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 -0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 2 次:REV_ANGULAR_STEP_G10_DW010_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G10_DW010/reverse/REV_ANGULAR_STEP_G10_DW010_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.10 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 0.10 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 -0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 3 次:REV_ANGULAR_STEP_G10_DW010_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G10_DW010/reverse/REV_ANGULAR_STEP_G10_DW010_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.10 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.10 0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 0.10 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.10 -0.10 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
6.10 增量 Δω=0.20 rad/s
该组分别执行正向和反向测试,每个方向重复 3 次。终端命令会自动完成完整的正负角速度升降阶梯。
正向第 1 次:FWD_ANGULAR_STEP_G20_DW020_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G20_DW020/forward/FWD_ANGULAR_STEP_G20_DW020_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.20 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.20 -0.20 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.20 rad/s的正向自动阶梯测试。
正向第 2 次:FWD_ANGULAR_STEP_G20_DW020_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G20_DW020/forward/FWD_ANGULAR_STEP_G20_DW020_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.20 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.20 -0.20 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.20 rad/s的正向自动阶梯测试。
正向第 3 次:FWD_ANGULAR_STEP_G20_DW020_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G20_DW020/forward/FWD_ANGULAR_STEP_G20_DW020_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.20 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.20 -0.20 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.20 rad/s的正向自动阶梯测试。
反向第 1 次:REV_ANGULAR_STEP_G20_DW020_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G20_DW020/reverse/REV_ANGULAR_STEP_G20_DW020_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.00 0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.20 0.20 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 2 次:REV_ANGULAR_STEP_G20_DW020_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G20_DW020/reverse/REV_ANGULAR_STEP_G20_DW020_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.00 0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.20 0.20 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
反向第 3 次:REV_ANGULAR_STEP_G20_DW020_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/06_angular_step/G20_DW020/reverse/REV_ANGULAR_STEP_G20_DW020_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
sleep 5
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 -0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" -0.00 0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 3s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.20 0.20 0.20); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
for w in $(LC_NUMERIC=C seq -f "%.2f" 0.00 -0.20 0.00); do
timeout --signal=INT 2s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: -0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: ${w}}}"
done
timeout --signal=INT 5s ros2 topic pub -r 20 \
/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
终端 1:终端 2 的零速度指令结束、车辆完全停止后,按 Ctrl+C 停止录包。
反向时角速度符号与正向匹配工况相反,以保持相同的等效转向方向。测试前确认车辆后方安全。
6.11 本部分录包后重点检查的数据
后续统一处理 bag 时,应针对每一次角速度等级变化计算:
- 新一级
/cmd_vel.angular.z首帧时间; /odom.twist.twist.angular.z开始变化的时间;/lio/odom航向变化率开始变化的时间;- 指令到实际响应的延迟;
- 实际角速度达到目标值 90% 所需时间;
- 稳态角速度误差;
- 角速度超调量;
- 升阶和降阶响应是否一致;
- 正角速度和负角速度响应是否一致;
- 正向与反向响应是否一致;
angular.z=0后的回正时间和残余横摆角速度。
终端循环在不同角速度等级之间会重新启动一次
ros2 topic pub进程。后续延迟统计必须使用 bag 中实际记录到的/cmd_vel时间戳,不能只按名义上的每 2 秒切换时间计算。
第七部分:单节点连续变速与不规则曲线响应测试
7.1 修改目的
前六部分保持原样。本部分针对前六部分分析中发现的阶段切换空档,重新设计尚未录制的第七部分。
每次测试均在终端中启动一个持续存在的 ROS 2 发布节点。整个速度序列由同一个 publisher 以 20 Hz 连续发送,阶段切换时只修改 Twist 数值,不重新启动 ros2 topic pub 进程。
因此,第七部分可以用于评价真实的连续变速和连续曲率切换响应。
命令块直接粘贴到终端运行,不会在工作区中创建 Python 脚本文件。
7.2 测试作用
- 线速度连续加速、减速时的响应延迟和超调;
- 线速度变化过程中实际转弯半径是否合理;
- 线速度和角速度同时变化时的耦合迟滞;
- 正负角速度连续切换时的横摆超调和回正时间;
- 低速大曲率、高速小曲率和高速大曲率的响应差异;
- 正向与反向执行相同等效序列时的性能差异;
- 为后续建立
cmd_vel → 实际速度/角速度动态模型提供多工况数据。
7.3 安全限制
| 项目 | 限制 |
|---|---|
| 最大线速度绝对值 | 0.5 m/s |
| 最大角速度绝对值 | 0.2 rad/s |
| 发布频率 | 20 Hz |
| 是否允许纯角速度 | 不允许 |
| 每个方向重复次数 | 3 次 |
| 建议场地 | 不小于 10 m × 10 m |
- 第一次执行每个 Profile 时,终端 3 必须保留紧急停车指令;
- 反向测试前确认车辆后方和侧后方空间充足;
- 每个 bag 只执行该小节对应的一个完整命令块;
- 命令运行期间不要再启动其他
/cmd_vel发布节点。
7.4 建立测试目录
bash
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/forward
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/reverse
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/forward
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/reverse
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/forward
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/reverse
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/forward
mkdir -p ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/reverse
检查目录:
bash
find ~/ranger_motion_test/07_continuous_variable -type d | sort
7.5 测试数量
| Profile | 正向次数 | 反向次数 | Bag 数量 |
|---|---|---|---|
| A:连续直线加减速 | 3 | 3 | 6 |
| B:近似恒定半径连续变速 | 3 | 3 | 6 |
| C:连续不规则 S 形复合曲线 | 3 | 3 | 6 |
| D:快速速度与曲率连续切换 | 3 | 3 | 6 |
| 合计 | 12 | 12 | 24 |
前六部分已经录制 79 个 bag。完成本部分后,累计为:
79+24=103\\ \\text{个 bag}
7.6 Profile A:连续直线加减速
在 angular.z=0 条件下,由同一个发布节点连续逐级加速和减速,用于得到不受发布节点重启影响的纵向动态基线。
速度序列表
| 段号 | 作用 | 正向 linear.x |
正向 angular.z |
持续时间 | 反向对应 linear.x |
反向对应 angular.z |
|---|---|---|---|---|---|---|
| 1 | 静止预记录 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
| 2 | 低速起步 | 0.10 m/s | 0.00 rad/s | 3 s | -0.10 m/s | 0.00 rad/s |
| 3 | 加速至 0.20 m/s | 0.20 m/s | 0.00 rad/s | 3 s | -0.20 m/s | 0.00 rad/s |
| 4 | 加速至 0.30 m/s | 0.30 m/s | 0.00 rad/s | 3 s | -0.30 m/s | 0.00 rad/s |
| 5 | 加速至 0.40 m/s | 0.40 m/s | 0.00 rad/s | 3 s | -0.40 m/s | 0.00 rad/s |
| 6 | 加速至 0.50 m/s | 0.50 m/s | 0.00 rad/s | 3 s | -0.50 m/s | 0.00 rad/s |
| 7 | 减速至 0.40 m/s | 0.40 m/s | 0.00 rad/s | 3 s | -0.40 m/s | 0.00 rad/s |
| 8 | 减速至 0.30 m/s | 0.30 m/s | 0.00 rad/s | 3 s | -0.30 m/s | 0.00 rad/s |
| 9 | 减速至 0.20 m/s | 0.20 m/s | 0.00 rad/s | 3 s | -0.20 m/s | 0.00 rad/s |
| 10 | 减速至 0.10 m/s | 0.10 m/s | 0.00 rad/s | 3 s | -0.10 m/s | 0.00 rad/s |
| 11 | 主动零速度停车 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
Profile A 正向第 1 次:FWD_CONT_PROFILE_A_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/forward/FWD_CONT_PROFILE_A_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_a_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("低速起步", 0.10000, 0.00000, 3.00),
("加速至 0.20 m/s", 0.20000, 0.00000, 3.00),
("加速至 0.30 m/s", 0.30000, 0.00000, 3.00),
("加速至 0.40 m/s", 0.40000, 0.00000, 3.00),
("加速至 0.50 m/s", 0.50000, 0.00000, 3.00),
("减速至 0.40 m/s", 0.40000, 0.00000, 3.00),
("减速至 0.30 m/s", 0.30000, 0.00000, 3.00),
("减速至 0.20 m/s", 0.20000, 0.00000, 3.00),
("减速至 0.10 m/s", 0.10000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile A 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile A 正向第 2 次:FWD_CONT_PROFILE_A_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/forward/FWD_CONT_PROFILE_A_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_a_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("低速起步", 0.10000, 0.00000, 3.00),
("加速至 0.20 m/s", 0.20000, 0.00000, 3.00),
("加速至 0.30 m/s", 0.30000, 0.00000, 3.00),
("加速至 0.40 m/s", 0.40000, 0.00000, 3.00),
("加速至 0.50 m/s", 0.50000, 0.00000, 3.00),
("减速至 0.40 m/s", 0.40000, 0.00000, 3.00),
("减速至 0.30 m/s", 0.30000, 0.00000, 3.00),
("减速至 0.20 m/s", 0.20000, 0.00000, 3.00),
("减速至 0.10 m/s", 0.10000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile A 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile A 正向第 3 次:FWD_CONT_PROFILE_A_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/forward/FWD_CONT_PROFILE_A_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_a_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("低速起步", 0.10000, 0.00000, 3.00),
("加速至 0.20 m/s", 0.20000, 0.00000, 3.00),
("加速至 0.30 m/s", 0.30000, 0.00000, 3.00),
("加速至 0.40 m/s", 0.40000, 0.00000, 3.00),
("加速至 0.50 m/s", 0.50000, 0.00000, 3.00),
("减速至 0.40 m/s", 0.40000, 0.00000, 3.00),
("减速至 0.30 m/s", 0.30000, 0.00000, 3.00),
("减速至 0.20 m/s", 0.20000, 0.00000, 3.00),
("减速至 0.10 m/s", 0.10000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile A 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile A 反向第 1 次:REV_CONT_PROFILE_A_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/reverse/REV_CONT_PROFILE_A_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_a_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:低速起步", -0.10000, -0.00000, 3.00),
("反向对应:加速至 0.20 m/s", -0.20000, -0.00000, 3.00),
("反向对应:加速至 0.30 m/s", -0.30000, -0.00000, 3.00),
("反向对应:加速至 0.40 m/s", -0.40000, -0.00000, 3.00),
("反向对应:加速至 0.50 m/s", -0.50000, -0.00000, 3.00),
("反向对应:减速至 0.40 m/s", -0.40000, -0.00000, 3.00),
("反向对应:减速至 0.30 m/s", -0.30000, -0.00000, 3.00),
("反向对应:减速至 0.20 m/s", -0.20000, -0.00000, 3.00),
("反向对应:减速至 0.10 m/s", -0.10000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile A 反向第 2 次:REV_CONT_PROFILE_A_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/reverse/REV_CONT_PROFILE_A_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_a_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:低速起步", -0.10000, -0.00000, 3.00),
("反向对应:加速至 0.20 m/s", -0.20000, -0.00000, 3.00),
("反向对应:加速至 0.30 m/s", -0.30000, -0.00000, 3.00),
("反向对应:加速至 0.40 m/s", -0.40000, -0.00000, 3.00),
("反向对应:加速至 0.50 m/s", -0.50000, -0.00000, 3.00),
("反向对应:减速至 0.40 m/s", -0.40000, -0.00000, 3.00),
("反向对应:减速至 0.30 m/s", -0.30000, -0.00000, 3.00),
("反向对应:减速至 0.20 m/s", -0.20000, -0.00000, 3.00),
("反向对应:减速至 0.10 m/s", -0.10000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile A 反向第 3 次:REV_CONT_PROFILE_A_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_A_straight_ramp/reverse/REV_CONT_PROFILE_A_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_a_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:低速起步", -0.10000, -0.00000, 3.00),
("反向对应:加速至 0.20 m/s", -0.20000, -0.00000, 3.00),
("反向对应:加速至 0.30 m/s", -0.30000, -0.00000, 3.00),
("反向对应:加速至 0.40 m/s", -0.40000, -0.00000, 3.00),
("反向对应:加速至 0.50 m/s", -0.50000, -0.00000, 3.00),
("反向对应:减速至 0.40 m/s", -0.40000, -0.00000, 3.00),
("反向对应:减速至 0.30 m/s", -0.30000, -0.00000, 3.00),
("反向对应:减速至 0.20 m/s", -0.20000, -0.00000, 3.00),
("反向对应:减速至 0.10 m/s", -0.10000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
7.7 Profile B:近似恒定半径连续变速
保持 v/ω≈2.0 m,连续改变线速度和角速度。若底盘模型理想,理论曲率在变速过程中应近似不变。
速度序列表
| 段号 | 作用 | 正向 linear.x |
正向 angular.z |
持续时间 | 反向对应 linear.x |
反向对应 angular.z |
|---|---|---|---|---|---|---|
| 1 | 静止预记录 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
| 2 | 正曲率低速 | 0.10 m/s | 0.05 rad/s | 3 s | -0.10 m/s | -0.05 rad/s |
| 3 | 正曲率加速 1 | 0.20 m/s | 0.10 rad/s | 3 s | -0.20 m/s | -0.10 rad/s |
| 4 | 正曲率加速 2 | 0.30 m/s | 0.15 rad/s | 3 s | -0.30 m/s | -0.15 rad/s |
| 5 | 正曲率最高速度 | 0.40 m/s | 0.20 rad/s | 3 s | -0.40 m/s | -0.20 rad/s |
| 6 | 正曲率减速 1 | 0.30 m/s | 0.15 rad/s | 3 s | -0.30 m/s | -0.15 rad/s |
| 7 | 正曲率减速 2 | 0.20 m/s | 0.10 rad/s | 3 s | -0.20 m/s | -0.10 rad/s |
| 8 | 连续直线回正 | 0.20 m/s | 0.00 rad/s | 3 s | -0.20 m/s | 0.00 rad/s |
| 9 | 负曲率低速 | 0.10 m/s | -0.05 rad/s | 3 s | -0.10 m/s | 0.05 rad/s |
| 10 | 负曲率加速 1 | 0.20 m/s | -0.10 rad/s | 3 s | -0.20 m/s | 0.10 rad/s |
| 11 | 负曲率加速 2 | 0.30 m/s | -0.15 rad/s | 3 s | -0.30 m/s | 0.15 rad/s |
| 12 | 负曲率最高速度 | 0.40 m/s | -0.20 rad/s | 3 s | -0.40 m/s | 0.20 rad/s |
| 13 | 负曲率减速 1 | 0.30 m/s | -0.15 rad/s | 3 s | -0.30 m/s | 0.15 rad/s |
| 14 | 负曲率减速 2 | 0.20 m/s | -0.10 rad/s | 3 s | -0.20 m/s | 0.10 rad/s |
| 15 | 主动零速度停车 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
Profile B 正向第 1 次:FWD_CONT_PROFILE_B_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/forward/FWD_CONT_PROFILE_B_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_b_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正曲率低速", 0.10000, 0.05000, 3.00),
("正曲率加速 1", 0.20000, 0.10000, 3.00),
("正曲率加速 2", 0.30000, 0.15000, 3.00),
("正曲率最高速度", 0.40000, 0.20000, 3.00),
("正曲率减速 1", 0.30000, 0.15000, 3.00),
("正曲率减速 2", 0.20000, 0.10000, 3.00),
("连续直线回正", 0.20000, 0.00000, 3.00),
("负曲率低速", 0.10000, -0.05000, 3.00),
("负曲率加速 1", 0.20000, -0.10000, 3.00),
("负曲率加速 2", 0.30000, -0.15000, 3.00),
("负曲率最高速度", 0.40000, -0.20000, 3.00),
("负曲率减速 1", 0.30000, -0.15000, 3.00),
("负曲率减速 2", 0.20000, -0.10000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile B 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile B 正向第 2 次:FWD_CONT_PROFILE_B_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/forward/FWD_CONT_PROFILE_B_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_b_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正曲率低速", 0.10000, 0.05000, 3.00),
("正曲率加速 1", 0.20000, 0.10000, 3.00),
("正曲率加速 2", 0.30000, 0.15000, 3.00),
("正曲率最高速度", 0.40000, 0.20000, 3.00),
("正曲率减速 1", 0.30000, 0.15000, 3.00),
("正曲率减速 2", 0.20000, 0.10000, 3.00),
("连续直线回正", 0.20000, 0.00000, 3.00),
("负曲率低速", 0.10000, -0.05000, 3.00),
("负曲率加速 1", 0.20000, -0.10000, 3.00),
("负曲率加速 2", 0.30000, -0.15000, 3.00),
("负曲率最高速度", 0.40000, -0.20000, 3.00),
("负曲率减速 1", 0.30000, -0.15000, 3.00),
("负曲率减速 2", 0.20000, -0.10000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile B 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile B 正向第 3 次:FWD_CONT_PROFILE_B_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/forward/FWD_CONT_PROFILE_B_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_b_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正曲率低速", 0.10000, 0.05000, 3.00),
("正曲率加速 1", 0.20000, 0.10000, 3.00),
("正曲率加速 2", 0.30000, 0.15000, 3.00),
("正曲率最高速度", 0.40000, 0.20000, 3.00),
("正曲率减速 1", 0.30000, 0.15000, 3.00),
("正曲率减速 2", 0.20000, 0.10000, 3.00),
("连续直线回正", 0.20000, 0.00000, 3.00),
("负曲率低速", 0.10000, -0.05000, 3.00),
("负曲率加速 1", 0.20000, -0.10000, 3.00),
("负曲率加速 2", 0.30000, -0.15000, 3.00),
("负曲率最高速度", 0.40000, -0.20000, 3.00),
("负曲率减速 1", 0.30000, -0.15000, 3.00),
("负曲率减速 2", 0.20000, -0.10000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile B 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile B 反向第 1 次:REV_CONT_PROFILE_B_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/reverse/REV_CONT_PROFILE_B_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_b_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:正曲率低速", -0.10000, -0.05000, 3.00),
("反向对应:正曲率加速 1", -0.20000, -0.10000, 3.00),
("反向对应:正曲率加速 2", -0.30000, -0.15000, 3.00),
("反向对应:正曲率最高速度", -0.40000, -0.20000, 3.00),
("反向对应:正曲率减速 1", -0.30000, -0.15000, 3.00),
("反向对应:正曲率减速 2", -0.20000, -0.10000, 3.00),
("反向对应:连续直线回正", -0.20000, -0.00000, 3.00),
("反向对应:负曲率低速", -0.10000, 0.05000, 3.00),
("反向对应:负曲率加速 1", -0.20000, 0.10000, 3.00),
("反向对应:负曲率加速 2", -0.30000, 0.15000, 3.00),
("反向对应:负曲率最高速度", -0.40000, 0.20000, 3.00),
("反向对应:负曲率减速 1", -0.30000, 0.15000, 3.00),
("反向对应:负曲率减速 2", -0.20000, 0.10000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile B 反向第 2 次:REV_CONT_PROFILE_B_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/reverse/REV_CONT_PROFILE_B_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_b_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:正曲率低速", -0.10000, -0.05000, 3.00),
("反向对应:正曲率加速 1", -0.20000, -0.10000, 3.00),
("反向对应:正曲率加速 2", -0.30000, -0.15000, 3.00),
("反向对应:正曲率最高速度", -0.40000, -0.20000, 3.00),
("反向对应:正曲率减速 1", -0.30000, -0.15000, 3.00),
("反向对应:正曲率减速 2", -0.20000, -0.10000, 3.00),
("反向对应:连续直线回正", -0.20000, -0.00000, 3.00),
("反向对应:负曲率低速", -0.10000, 0.05000, 3.00),
("反向对应:负曲率加速 1", -0.20000, 0.10000, 3.00),
("反向对应:负曲率加速 2", -0.30000, 0.15000, 3.00),
("反向对应:负曲率最高速度", -0.40000, 0.20000, 3.00),
("反向对应:负曲率减速 1", -0.30000, 0.15000, 3.00),
("反向对应:负曲率减速 2", -0.20000, 0.10000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile B 反向第 3 次:REV_CONT_PROFILE_B_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_B_constant_radius/reverse/REV_CONT_PROFILE_B_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_b_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:正曲率低速", -0.10000, -0.05000, 3.00),
("反向对应:正曲率加速 1", -0.20000, -0.10000, 3.00),
("反向对应:正曲率加速 2", -0.30000, -0.15000, 3.00),
("反向对应:正曲率最高速度", -0.40000, -0.20000, 3.00),
("反向对应:正曲率减速 1", -0.30000, -0.15000, 3.00),
("反向对应:正曲率减速 2", -0.20000, -0.10000, 3.00),
("反向对应:连续直线回正", -0.20000, -0.00000, 3.00),
("反向对应:负曲率低速", -0.10000, 0.05000, 3.00),
("反向对应:负曲率加速 1", -0.20000, 0.10000, 3.00),
("反向对应:负曲率加速 2", -0.30000, 0.15000, 3.00),
("反向对应:负曲率最高速度", -0.40000, 0.20000, 3.00),
("反向对应:负曲率减速 1", -0.30000, 0.15000, 3.00),
("反向对应:负曲率减速 2", -0.20000, 0.10000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
7.8 Profile C:连续不规则 S 形复合曲线
连续改变速度、曲率大小和曲率符号,用于模拟导航控制器输出的非规则复合运动指令。
速度序列表
| 段号 | 作用 | 正向 linear.x |
正向 angular.z |
持续时间 | 反向对应 linear.x |
反向对应 angular.z |
|---|---|---|---|---|---|---|
| 1 | 静止预记录 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
| 2 | 低速小正曲率 | 0.15 m/s | 0.04 rad/s | 3 s | -0.15 m/s | -0.04 rad/s |
| 3 | 加速并增大正曲率 | 0.30 m/s | 0.12 rad/s | 3 s | -0.30 m/s | -0.12 rad/s |
| 4 | 高速小正曲率 | 0.50 m/s | 0.08 rad/s | 3 s | -0.50 m/s | -0.08 rad/s |
| 5 | 减速并切换大负曲率 | 0.25 m/s | -0.18 rad/s | 3 s | -0.25 m/s | 0.18 rad/s |
| 6 | 加速并减小负曲率 | 0.40 m/s | -0.05 rad/s | 3 s | -0.40 m/s | 0.05 rad/s |
| 7 | 低速最大正角速度 | 0.20 m/s | 0.20 rad/s | 3 s | -0.20 m/s | -0.20 rad/s |
| 8 | 高速负曲率 | 0.45 m/s | -0.12 rad/s | 3 s | -0.45 m/s | 0.12 rad/s |
| 9 | 连续直线回正 | 0.30 m/s | 0.00 rad/s | 3 s | -0.30 m/s | 0.00 rad/s |
| 10 | 主动零速度停车 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
Profile C 正向第 1 次:FWD_CONT_PROFILE_C_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/forward/FWD_CONT_PROFILE_C_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_c_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("低速小正曲率", 0.15000, 0.04000, 3.00),
("加速并增大正曲率", 0.30000, 0.12000, 3.00),
("高速小正曲率", 0.50000, 0.08000, 3.00),
("减速并切换大负曲率", 0.25000, -0.18000, 3.00),
("加速并减小负曲率", 0.40000, -0.05000, 3.00),
("低速最大正角速度", 0.20000, 0.20000, 3.00),
("高速负曲率", 0.45000, -0.12000, 3.00),
("连续直线回正", 0.30000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile C 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile C 正向第 2 次:FWD_CONT_PROFILE_C_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/forward/FWD_CONT_PROFILE_C_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_c_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("低速小正曲率", 0.15000, 0.04000, 3.00),
("加速并增大正曲率", 0.30000, 0.12000, 3.00),
("高速小正曲率", 0.50000, 0.08000, 3.00),
("减速并切换大负曲率", 0.25000, -0.18000, 3.00),
("加速并减小负曲率", 0.40000, -0.05000, 3.00),
("低速最大正角速度", 0.20000, 0.20000, 3.00),
("高速负曲率", 0.45000, -0.12000, 3.00),
("连续直线回正", 0.30000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile C 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile C 正向第 3 次:FWD_CONT_PROFILE_C_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/forward/FWD_CONT_PROFILE_C_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_c_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("低速小正曲率", 0.15000, 0.04000, 3.00),
("加速并增大正曲率", 0.30000, 0.12000, 3.00),
("高速小正曲率", 0.50000, 0.08000, 3.00),
("减速并切换大负曲率", 0.25000, -0.18000, 3.00),
("加速并减小负曲率", 0.40000, -0.05000, 3.00),
("低速最大正角速度", 0.20000, 0.20000, 3.00),
("高速负曲率", 0.45000, -0.12000, 3.00),
("连续直线回正", 0.30000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile C 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile C 反向第 1 次:REV_CONT_PROFILE_C_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/reverse/REV_CONT_PROFILE_C_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_c_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:低速小正曲率", -0.15000, -0.04000, 3.00),
("反向对应:加速并增大正曲率", -0.30000, -0.12000, 3.00),
("反向对应:高速小正曲率", -0.50000, -0.08000, 3.00),
("反向对应:减速并切换大负曲率", -0.25000, 0.18000, 3.00),
("反向对应:加速并减小负曲率", -0.40000, 0.05000, 3.00),
("反向对应:低速最大正角速度", -0.20000, -0.20000, 3.00),
("反向对应:高速负曲率", -0.45000, 0.12000, 3.00),
("反向对应:连续直线回正", -0.30000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile C 反向第 2 次:REV_CONT_PROFILE_C_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/reverse/REV_CONT_PROFILE_C_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_c_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:低速小正曲率", -0.15000, -0.04000, 3.00),
("反向对应:加速并增大正曲率", -0.30000, -0.12000, 3.00),
("反向对应:高速小正曲率", -0.50000, -0.08000, 3.00),
("反向对应:减速并切换大负曲率", -0.25000, 0.18000, 3.00),
("反向对应:加速并减小负曲率", -0.40000, 0.05000, 3.00),
("反向对应:低速最大正角速度", -0.20000, -0.20000, 3.00),
("反向对应:高速负曲率", -0.45000, 0.12000, 3.00),
("反向对应:连续直线回正", -0.30000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile C 反向第 3 次:REV_CONT_PROFILE_C_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_C_irregular_curve/reverse/REV_CONT_PROFILE_C_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_c_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:低速小正曲率", -0.15000, -0.04000, 3.00),
("反向对应:加速并增大正曲率", -0.30000, -0.12000, 3.00),
("反向对应:高速小正曲率", -0.50000, -0.08000, 3.00),
("反向对应:减速并切换大负曲率", -0.25000, 0.18000, 3.00),
("反向对应:加速并减小负曲率", -0.40000, 0.05000, 3.00),
("反向对应:低速最大正角速度", -0.20000, -0.20000, 3.00),
("反向对应:高速负曲率", -0.45000, 0.12000, 3.00),
("反向对应:连续直线回正", -0.30000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
7.9 Profile D:快速速度与曲率连续切换
每段保持 2 秒,在相邻阶段之间进行较大幅度的速度和角速度变化,用于测试短时动态、转向超调和连续切换稳定性。
速度序列表
| 段号 | 作用 | 正向 linear.x |
正向 angular.z |
持续时间 | 反向对应 linear.x |
反向对应 angular.z |
|---|---|---|---|---|---|---|
| 1 | 静止预记录 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
| 2 | 中低速直线 | 0.20 m/s | 0.00 rad/s | 2 s | -0.20 m/s | 0.00 rad/s |
| 3 | 高速最大正角速度 | 0.50 m/s | 0.20 rad/s | 2 s | -0.50 m/s | -0.20 rad/s |
| 4 | 低速最大负角速度 | 0.15 m/s | -0.20 rad/s | 2 s | -0.15 m/s | 0.20 rad/s |
| 5 | 中高速小正角速度 | 0.40 m/s | 0.05 rad/s | 2 s | -0.40 m/s | -0.05 rad/s |
| 6 | 中低速负角速度 | 0.25 m/s | -0.10 rad/s | 2 s | -0.25 m/s | 0.10 rad/s |
| 7 | 高速最大负角速度 | 0.50 m/s | -0.20 rad/s | 2 s | -0.50 m/s | 0.20 rad/s |
| 8 | 低速较大正角速度 | 0.20 m/s | 0.15 rad/s | 2 s | -0.20 m/s | -0.15 rad/s |
| 9 | 中速连续回正 | 0.35 m/s | 0.00 rad/s | 2 s | -0.35 m/s | 0.00 rad/s |
| 10 | 主动零速度停车 | 0.00 m/s | 0.00 rad/s | 5 s | 0.00 m/s | 0.00 rad/s |
Profile D 正向第 1 次:FWD_CONT_PROFILE_D_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/forward/FWD_CONT_PROFILE_D_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_d_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("中低速直线", 0.20000, 0.00000, 2.00),
("高速最大正角速度", 0.50000, 0.20000, 2.00),
("低速最大负角速度", 0.15000, -0.20000, 2.00),
("中高速小正角速度", 0.40000, 0.05000, 2.00),
("中低速负角速度", 0.25000, -0.10000, 2.00),
("高速最大负角速度", 0.50000, -0.20000, 2.00),
("低速较大正角速度", 0.20000, 0.15000, 2.00),
("中速连续回正", 0.35000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile D 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile D 正向第 2 次:FWD_CONT_PROFILE_D_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/forward/FWD_CONT_PROFILE_D_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_d_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("中低速直线", 0.20000, 0.00000, 2.00),
("高速最大正角速度", 0.50000, 0.20000, 2.00),
("低速最大负角速度", 0.15000, -0.20000, 2.00),
("中高速小正角速度", 0.40000, 0.05000, 2.00),
("中低速负角速度", 0.25000, -0.10000, 2.00),
("高速最大负角速度", 0.50000, -0.20000, 2.00),
("低速较大正角速度", 0.20000, 0.15000, 2.00),
("中速连续回正", 0.35000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile D 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile D 正向第 3 次:FWD_CONT_PROFILE_D_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/forward/FWD_CONT_PROFILE_D_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_d_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("中低速直线", 0.20000, 0.00000, 2.00),
("高速最大正角速度", 0.50000, 0.20000, 2.00),
("低速最大负角速度", 0.15000, -0.20000, 2.00),
("中高速小正角速度", 0.40000, 0.05000, 2.00),
("中低速负角速度", 0.25000, -0.10000, 2.00),
("高速最大负角速度", 0.50000, -0.20000, 2.00),
("低速较大正角速度", 0.20000, 0.15000, 2.00),
("中速连续回正", 0.35000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只执行 Profile D 的正向连续序列。整个过程中只有一个
/cmd_vel发布节点。
Profile D 反向第 1 次:REV_CONT_PROFILE_D_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/reverse/REV_CONT_PROFILE_D_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_d_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:中低速直线", -0.20000, -0.00000, 2.00),
("反向对应:高速最大正角速度", -0.50000, -0.20000, 2.00),
("反向对应:低速最大负角速度", -0.15000, 0.20000, 2.00),
("反向对应:中高速小正角速度", -0.40000, -0.05000, 2.00),
("反向对应:中低速负角速度", -0.25000, 0.10000, 2.00),
("反向对应:高速最大负角速度", -0.50000, 0.20000, 2.00),
("反向对应:低速较大正角速度", -0.20000, -0.15000, 2.00),
("反向对应:中速连续回正", -0.35000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile D 反向第 2 次:REV_CONT_PROFILE_D_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/reverse/REV_CONT_PROFILE_D_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_d_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:中低速直线", -0.20000, -0.00000, 2.00),
("反向对应:高速最大正角速度", -0.50000, -0.20000, 2.00),
("反向对应:低速最大负角速度", -0.15000, 0.20000, 2.00),
("反向对应:中高速小正角速度", -0.40000, -0.05000, 2.00),
("反向对应:中低速负角速度", -0.25000, 0.10000, 2.00),
("反向对应:高速最大负角速度", -0.50000, 0.20000, 2.00),
("反向对应:低速较大正角速度", -0.20000, -0.15000, 2.00),
("反向对应:中速连续回正", -0.35000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
Profile D 反向第 3 次:REV_CONT_PROFILE_D_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/07_continuous_variable/profile_D_fast_switch/reverse/REV_CONT_PROFILE_D_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_profile_d_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:中低速直线", -0.20000, -0.00000, 2.00),
("反向对应:高速最大正角速度", -0.50000, -0.20000, 2.00),
("反向对应:低速最大负角速度", -0.15000, 0.20000, 2.00),
("反向对应:中高速小正角速度", -0.40000, -0.05000, 2.00),
("反向对应:中低速负角速度", -0.25000, 0.10000, 2.00),
("反向对应:高速最大负角速度", -0.50000, 0.20000, 2.00),
("反向对应:低速较大正角速度", -0.20000, -0.15000, 2.00),
("反向对应:中速连续回正", -0.35000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向序列同时反转线速度和角速度,以保持对应的等效转向关系。
7.10 第七部分录制后的完整性判据
第七部分每个 bag 应满足:
/cmd_vel在整个运动阶段持续约 20 Hz;- 相邻阶段的
/cmd_vel时间间隔不应出现约 1 s 的发布节点重启空档; - 正常情况下,相邻消息最大间隔应接近
0.05 s,允许少量系统调度波动; - 每个阶段的真实持续时间应接近速度序列表中的设置值;
- 最终主动零速度阶段应直接紧接在最后一个非零指令之后。
录包后可先检查消息频率:
bash
ros2 bag play <对应的bag目录>
# 另一个终端检查
ros2 topic hz /cmd_vel
第八部分:前六部分缺失物理工况的连续发布补充测试
8.1 增加本部分的原因
根据前六部分 bag 分析,仍缺少三类能够直接支撑底盘动态结论的数据:
- 非零速度之后立即、主动发布零速度时的真实制动响应;
- 车辆保持运动时,左转---回正---右转的连续切换响应;
- 车辆保持恒定线速度时,
angular.z在0~0.2 rad/s范围内按不同增量连续变化的响应。
本部分不替换、删除或覆盖前六部分已有 bag。所有补充数据使用新的目录和包名。
8.2 建立补充测试目录
bash
mkdir -p ~/ranger_motion_test/08_completion/active_zero_brake/forward
mkdir -p ~/ranger_motion_test/08_completion/active_zero_brake/reverse
mkdir -p ~/ranger_motion_test/08_completion/continuous_steer_switch/forward
mkdir -p ~/ranger_motion_test/08_completion/continuous_steer_switch/reverse
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/forward
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/reverse
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/forward
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/reverse
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/forward
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/reverse
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/forward
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/reverse
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/forward
mkdir -p ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/reverse
检查目录:
bash
find ~/ranger_motion_test/08_completion -type d | sort
8.3 补充测试数量
| 补充工况 | 工况数量 | 单工况次数 | Bag 数量 |
|---|---|---|---|
| 主动零速度制动:正向/反向 0.2、0.4、0.5 m/s | 6 | 3 | 18 |
| 连续左转---回正---右转:正向/反向 | 2 | 3 | 6 |
| 连续角速度阶梯:5 种增量,正向/反向 | 10 | 3 | 30 |
| 合计 | 18 | --- | 54 |
完成第七、八部分后,全部数据量为:
79+24+54=157\\ \\text{个 bag}
8.4 主动零速度制动测试
8.4.1 测试目的
车辆由同一个 publisher 持续接收非零速度,随后在下一个 20 Hz 周期内直接切换为零速度。该测试用于与第四部分的命令断流/看门狗停车结果区分。
8.4.2 工况
| 方向 | 速度 | 非零速度时间 | 主动零速度时间 | 次数 |
|---|---|---|---|---|
| 正向 | 0.2 m/s | 5 s | 5 s | 3 |
| 反向 | -0.2 m/s | 5 s | 5 s | 3 |
| 正向 | 0.4 m/s | 5 s | 5 s | 3 |
| 反向 | -0.4 m/s | 5 s | 5 s | 3 |
| 正向 | 0.5 m/s | 5 s | 5 s | 3 |
| 反向 | -0.5 m/s | 5 s | 5 s | 3 |
8.4.3 正向 0.2 m/s 主动停车
第 1 次:FWD_ACTIVE_ZERO_BRAKE_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v020_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.2 m/s", 0.20000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
第 2 次:FWD_ACTIVE_ZERO_BRAKE_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v020_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.2 m/s", 0.20000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
第 3 次:FWD_ACTIVE_ZERO_BRAKE_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v020_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.2 m/s", 0.20000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
8.4.4 反向 -0.2 m/s 主动停车
第 1 次:REV_ACTIVE_ZERO_BRAKE_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v020_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.2 m/s", -0.20000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
第 2 次:REV_ACTIVE_ZERO_BRAKE_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v020_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.2 m/s", -0.20000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
第 3 次:REV_ACTIVE_ZERO_BRAKE_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v020_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.2 m/s", -0.20000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
8.4.5 正向 0.4 m/s 主动停车
第 1 次:FWD_ACTIVE_ZERO_BRAKE_V040_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V040_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v040_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.4 m/s", 0.40000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
第 2 次:FWD_ACTIVE_ZERO_BRAKE_V040_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V040_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v040_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.4 m/s", 0.40000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
第 3 次:FWD_ACTIVE_ZERO_BRAKE_V040_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V040_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v040_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.4 m/s", 0.40000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
8.4.6 反向 -0.4 m/s 主动停车
第 1 次:REV_ACTIVE_ZERO_BRAKE_V040_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V040_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v040_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.4 m/s", -0.40000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
第 2 次:REV_ACTIVE_ZERO_BRAKE_V040_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V040_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v040_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.4 m/s", -0.40000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
第 3 次:REV_ACTIVE_ZERO_BRAKE_V040_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V040_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v040_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.4 m/s", -0.40000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
8.4.7 正向 0.5 m/s 主动停车
第 1 次:FWD_ACTIVE_ZERO_BRAKE_V050_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V050_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v050_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.5 m/s", 0.50000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
第 2 次:FWD_ACTIVE_ZERO_BRAKE_V050_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V050_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v050_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.5 m/s", 0.50000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
第 3 次:FWD_ACTIVE_ZERO_BRAKE_V050_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/forward/FWD_ACTIVE_ZERO_BRAKE_V050_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_fwd_v050_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正向 0.5 m/s", 0.50000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
非零速度与零速度由同一 publisher 连续发送,可直接统计主动零速度后的制动延迟和制动距离。
8.4.8 反向 -0.5 m/s 主动停车
第 1 次:REV_ACTIVE_ZERO_BRAKE_V050_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V050_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v050_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.5 m/s", -0.50000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
第 2 次:REV_ACTIVE_ZERO_BRAKE_V050_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V050_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v050_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.5 m/s", -0.50000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
第 3 次:REV_ACTIVE_ZERO_BRAKE_V050_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/active_zero_brake/reverse/REV_ACTIVE_ZERO_BRAKE_V050_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_active_brake_rev_v050_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向 -0.5 m/s", -0.50000, 0.00000, 5.00),
("立即主动发布零速度", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方安全。
8.5 保持运动状态下的连续转向切换与回正
8.5.1 测试目的
该测试补齐第五部分缺少的连续转向切换数据。车辆在整个转向序列中保持|linear.x|=0.3 m/s,不会在左转、回正和右转之间停车。
正向序列:
- 零速度预记录 5 s;
v=0.3、ω=0.2,持续 5 s;v=0.3、ω=0,持续 3 s;v=0.3、ω=-0.2,持续 5 s;v=0.3、ω=0,持续 3 s;- 主动零速度 5 s。
反向序列同时反转 linear.x 和 angular.z。
8.5.2 正向连续转向切换
正向第 1 次:FWD_CONT_STEER_SWITCH_V030_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_steer_switch/forward/FWD_CONT_STEER_SWITCH_V030_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_steer_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("连续正向第一转向", 0.30000, 0.20000, 5.00),
("保持运动并回正", 0.30000, 0.00000, 3.00),
("连续切换至反方向转向", 0.30000, -0.20000, 5.00),
("保持运动并再次回正", 0.30000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本次测试用于统计连续回正和角速度换向,不允许中途启动其他发布节点。
正向第 2 次:FWD_CONT_STEER_SWITCH_V030_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_steer_switch/forward/FWD_CONT_STEER_SWITCH_V030_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_steer_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("连续正向第一转向", 0.30000, 0.20000, 5.00),
("保持运动并回正", 0.30000, 0.00000, 3.00),
("连续切换至反方向转向", 0.30000, -0.20000, 5.00),
("保持运动并再次回正", 0.30000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本次测试用于统计连续回正和角速度换向,不允许中途启动其他发布节点。
正向第 3 次:FWD_CONT_STEER_SWITCH_V030_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_steer_switch/forward/FWD_CONT_STEER_SWITCH_V030_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_steer_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("连续正向第一转向", 0.30000, 0.20000, 5.00),
("保持运动并回正", 0.30000, 0.00000, 3.00),
("连续切换至反方向转向", 0.30000, -0.20000, 5.00),
("保持运动并再次回正", 0.30000, 0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本次测试用于统计连续回正和角速度换向,不允许中途启动其他发布节点。
8.5.3 反向连续转向切换
反向第 1 次:REV_CONT_STEER_SWITCH_V030_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_steer_switch/reverse/REV_CONT_STEER_SWITCH_V030_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_steer_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:连续正向第一转向", -0.30000, -0.20000, 5.00),
("反向对应:保持运动并回正", -0.30000, -0.00000, 3.00),
("反向对应:连续切换至反方向转向", -0.30000, 0.20000, 5.00),
("反向对应:保持运动并再次回正", -0.30000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方和侧后方空间充足。
反向第 2 次:REV_CONT_STEER_SWITCH_V030_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_steer_switch/reverse/REV_CONT_STEER_SWITCH_V030_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_steer_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:连续正向第一转向", -0.30000, -0.20000, 5.00),
("反向对应:保持运动并回正", -0.30000, -0.00000, 3.00),
("反向对应:连续切换至反方向转向", -0.30000, 0.20000, 5.00),
("反向对应:保持运动并再次回正", -0.30000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方和侧后方空间充足。
反向第 3 次:REV_CONT_STEER_SWITCH_V030_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_steer_switch/reverse/REV_CONT_STEER_SWITCH_V030_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_steer_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("反向对应:连续正向第一转向", -0.30000, -0.20000, 5.00),
("反向对应:保持运动并回正", -0.30000, -0.00000, 3.00),
("反向对应:连续切换至反方向转向", -0.30000, 0.20000, 5.00),
("反向对应:保持运动并再次回正", -0.30000, -0.00000, 3.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
测试前确认车辆后方和侧后方空间充足。
8.6 保持运动状态下的连续角速度增量复核
8.6.1 测试目的
该测试保留第六部分原始 bag,同时补录真正连续的角速度阶梯。车辆在线速度恒定的情况下,angular.z 在 -0.2~0.2 rad/s 范围内连续升降,阶段之间不重新创建 publisher。
测试增量为:
| 组别 | 单次角速度增量 | 主要判断 |
|---|---|---|
| G01 | 0.01 rad/s |
微小增量死区和最低可靠响应阈值 |
| G02 | 0.02 rad/s |
小增量连续跟随能力 |
| G05 | 0.05 rad/s |
中等增量的延迟、误差和超调 |
| G10 | 0.10 rad/s |
较大增量的快速响应能力 |
| G20 | 0.20 rad/s |
允许范围内最大单次阶跃 |
统一设置:
- 正向线速度:
0.2 m/s; - 反向线速度:
-0.2 m/s; - 每个角速度等级保持:
2 s; - 正、负阶梯之间保持直线:
3 s; - 最终主动零速度:
5 s; - 每组正向、反向各重复 3 次。
8.6.2 连续增量 Δω=0.01 rad/s
正向上升等级:0.00, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20 rad/s。
随后按相同等级降回 0,保持运动直线 3 秒,再对负角速度执行同样的连续升降序列。
正向第 1 次:FWD_CONT_ANGULAR_STEP_G01_DW001_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/forward/FWD_CONT_ANGULAR_STEP_G01_DW001_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g01_dw001_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.01 rad/s", 0.20000, 0.01000, 2.00),
("正等效方向上升至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向上升至 0.03 rad/s", 0.20000, 0.03000, 2.00),
("正等效方向上升至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向上升至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向上升至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向上升至 0.07 rad/s", 0.20000, 0.07000, 2.00),
("正等效方向上升至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向上升至 0.09 rad/s", 0.20000, 0.09000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.11 rad/s", 0.20000, 0.11000, 2.00),
("正等效方向上升至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向上升至 0.13 rad/s", 0.20000, 0.13000, 2.00),
("正等效方向上升至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向上升至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向上升至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向上升至 0.17 rad/s", 0.20000, 0.17000, 2.00),
("正等效方向上升至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向上升至 0.19 rad/s", 0.20000, 0.19000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.19 rad/s", 0.20000, 0.19000, 2.00),
("正等效方向下降至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向下降至 0.17 rad/s", 0.20000, 0.17000, 2.00),
("正等效方向下降至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向下降至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向下降至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向下降至 0.13 rad/s", 0.20000, 0.13000, 2.00),
("正等效方向下降至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向下降至 0.11 rad/s", 0.20000, 0.11000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.09 rad/s", 0.20000, 0.09000, 2.00),
("正等效方向下降至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向下降至 0.07 rad/s", 0.20000, 0.07000, 2.00),
("正等效方向下降至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向下降至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向下降至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向下降至 0.03 rad/s", 0.20000, 0.03000, 2.00),
("正等效方向下降至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向下降至 0.01 rad/s", 0.20000, 0.01000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.01 rad/s", 0.20000, -0.01000, 2.00),
("负等效方向上升至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向上升至 -0.03 rad/s", 0.20000, -0.03000, 2.00),
("负等效方向上升至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向上升至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向上升至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向上升至 -0.07 rad/s", 0.20000, -0.07000, 2.00),
("负等效方向上升至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向上升至 -0.09 rad/s", 0.20000, -0.09000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.11 rad/s", 0.20000, -0.11000, 2.00),
("负等效方向上升至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向上升至 -0.13 rad/s", 0.20000, -0.13000, 2.00),
("负等效方向上升至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向上升至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向上升至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向上升至 -0.17 rad/s", 0.20000, -0.17000, 2.00),
("负等效方向上升至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向上升至 -0.19 rad/s", 0.20000, -0.19000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.19 rad/s", 0.20000, -0.19000, 2.00),
("负等效方向下降至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向下降至 -0.17 rad/s", 0.20000, -0.17000, 2.00),
("负等效方向下降至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向下降至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向下降至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向下降至 -0.13 rad/s", 0.20000, -0.13000, 2.00),
("负等效方向下降至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向下降至 -0.11 rad/s", 0.20000, -0.11000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.09 rad/s", 0.20000, -0.09000, 2.00),
("负等效方向下降至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向下降至 -0.07 rad/s", 0.20000, -0.07000, 2.00),
("负等效方向下降至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向下降至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向下降至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向下降至 -0.03 rad/s", 0.20000, -0.03000, 2.00),
("负等效方向下降至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向下降至 -0.01 rad/s", 0.20000, -0.01000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.01 rad/s的正向连续阶梯。
正向第 2 次:FWD_CONT_ANGULAR_STEP_G01_DW001_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/forward/FWD_CONT_ANGULAR_STEP_G01_DW001_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g01_dw001_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.01 rad/s", 0.20000, 0.01000, 2.00),
("正等效方向上升至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向上升至 0.03 rad/s", 0.20000, 0.03000, 2.00),
("正等效方向上升至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向上升至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向上升至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向上升至 0.07 rad/s", 0.20000, 0.07000, 2.00),
("正等效方向上升至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向上升至 0.09 rad/s", 0.20000, 0.09000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.11 rad/s", 0.20000, 0.11000, 2.00),
("正等效方向上升至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向上升至 0.13 rad/s", 0.20000, 0.13000, 2.00),
("正等效方向上升至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向上升至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向上升至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向上升至 0.17 rad/s", 0.20000, 0.17000, 2.00),
("正等效方向上升至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向上升至 0.19 rad/s", 0.20000, 0.19000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.19 rad/s", 0.20000, 0.19000, 2.00),
("正等效方向下降至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向下降至 0.17 rad/s", 0.20000, 0.17000, 2.00),
("正等效方向下降至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向下降至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向下降至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向下降至 0.13 rad/s", 0.20000, 0.13000, 2.00),
("正等效方向下降至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向下降至 0.11 rad/s", 0.20000, 0.11000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.09 rad/s", 0.20000, 0.09000, 2.00),
("正等效方向下降至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向下降至 0.07 rad/s", 0.20000, 0.07000, 2.00),
("正等效方向下降至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向下降至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向下降至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向下降至 0.03 rad/s", 0.20000, 0.03000, 2.00),
("正等效方向下降至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向下降至 0.01 rad/s", 0.20000, 0.01000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.01 rad/s", 0.20000, -0.01000, 2.00),
("负等效方向上升至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向上升至 -0.03 rad/s", 0.20000, -0.03000, 2.00),
("负等效方向上升至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向上升至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向上升至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向上升至 -0.07 rad/s", 0.20000, -0.07000, 2.00),
("负等效方向上升至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向上升至 -0.09 rad/s", 0.20000, -0.09000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.11 rad/s", 0.20000, -0.11000, 2.00),
("负等效方向上升至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向上升至 -0.13 rad/s", 0.20000, -0.13000, 2.00),
("负等效方向上升至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向上升至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向上升至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向上升至 -0.17 rad/s", 0.20000, -0.17000, 2.00),
("负等效方向上升至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向上升至 -0.19 rad/s", 0.20000, -0.19000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.19 rad/s", 0.20000, -0.19000, 2.00),
("负等效方向下降至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向下降至 -0.17 rad/s", 0.20000, -0.17000, 2.00),
("负等效方向下降至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向下降至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向下降至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向下降至 -0.13 rad/s", 0.20000, -0.13000, 2.00),
("负等效方向下降至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向下降至 -0.11 rad/s", 0.20000, -0.11000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.09 rad/s", 0.20000, -0.09000, 2.00),
("负等效方向下降至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向下降至 -0.07 rad/s", 0.20000, -0.07000, 2.00),
("负等效方向下降至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向下降至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向下降至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向下降至 -0.03 rad/s", 0.20000, -0.03000, 2.00),
("负等效方向下降至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向下降至 -0.01 rad/s", 0.20000, -0.01000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.01 rad/s的正向连续阶梯。
正向第 3 次:FWD_CONT_ANGULAR_STEP_G01_DW001_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/forward/FWD_CONT_ANGULAR_STEP_G01_DW001_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g01_dw001_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.01 rad/s", 0.20000, 0.01000, 2.00),
("正等效方向上升至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向上升至 0.03 rad/s", 0.20000, 0.03000, 2.00),
("正等效方向上升至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向上升至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向上升至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向上升至 0.07 rad/s", 0.20000, 0.07000, 2.00),
("正等效方向上升至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向上升至 0.09 rad/s", 0.20000, 0.09000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.11 rad/s", 0.20000, 0.11000, 2.00),
("正等效方向上升至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向上升至 0.13 rad/s", 0.20000, 0.13000, 2.00),
("正等效方向上升至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向上升至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向上升至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向上升至 0.17 rad/s", 0.20000, 0.17000, 2.00),
("正等效方向上升至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向上升至 0.19 rad/s", 0.20000, 0.19000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.19 rad/s", 0.20000, 0.19000, 2.00),
("正等效方向下降至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向下降至 0.17 rad/s", 0.20000, 0.17000, 2.00),
("正等效方向下降至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向下降至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向下降至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向下降至 0.13 rad/s", 0.20000, 0.13000, 2.00),
("正等效方向下降至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向下降至 0.11 rad/s", 0.20000, 0.11000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.09 rad/s", 0.20000, 0.09000, 2.00),
("正等效方向下降至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向下降至 0.07 rad/s", 0.20000, 0.07000, 2.00),
("正等效方向下降至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向下降至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向下降至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向下降至 0.03 rad/s", 0.20000, 0.03000, 2.00),
("正等效方向下降至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向下降至 0.01 rad/s", 0.20000, 0.01000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.01 rad/s", 0.20000, -0.01000, 2.00),
("负等效方向上升至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向上升至 -0.03 rad/s", 0.20000, -0.03000, 2.00),
("负等效方向上升至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向上升至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向上升至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向上升至 -0.07 rad/s", 0.20000, -0.07000, 2.00),
("负等效方向上升至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向上升至 -0.09 rad/s", 0.20000, -0.09000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.11 rad/s", 0.20000, -0.11000, 2.00),
("负等效方向上升至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向上升至 -0.13 rad/s", 0.20000, -0.13000, 2.00),
("负等效方向上升至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向上升至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向上升至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向上升至 -0.17 rad/s", 0.20000, -0.17000, 2.00),
("负等效方向上升至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向上升至 -0.19 rad/s", 0.20000, -0.19000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.19 rad/s", 0.20000, -0.19000, 2.00),
("负等效方向下降至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向下降至 -0.17 rad/s", 0.20000, -0.17000, 2.00),
("负等效方向下降至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向下降至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向下降至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向下降至 -0.13 rad/s", 0.20000, -0.13000, 2.00),
("负等效方向下降至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向下降至 -0.11 rad/s", 0.20000, -0.11000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.09 rad/s", 0.20000, -0.09000, 2.00),
("负等效方向下降至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向下降至 -0.07 rad/s", 0.20000, -0.07000, 2.00),
("负等效方向下降至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向下降至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向下降至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向下降至 -0.03 rad/s", 0.20000, -0.03000, 2.00),
("负等效方向下降至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向下降至 -0.01 rad/s", 0.20000, -0.01000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.01 rad/s的正向连续阶梯。
反向第 1 次:REV_CONT_ANGULAR_STEP_G01_DW001_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/reverse/REV_CONT_ANGULAR_STEP_G01_DW001_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g01_dw001_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.01 rad/s", -0.20000, -0.01000, 2.00),
("正等效方向上升至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向上升至 0.03 rad/s", -0.20000, -0.03000, 2.00),
("正等效方向上升至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向上升至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向上升至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向上升至 0.07 rad/s", -0.20000, -0.07000, 2.00),
("正等效方向上升至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向上升至 0.09 rad/s", -0.20000, -0.09000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.11 rad/s", -0.20000, -0.11000, 2.00),
("正等效方向上升至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向上升至 0.13 rad/s", -0.20000, -0.13000, 2.00),
("正等效方向上升至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向上升至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向上升至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向上升至 0.17 rad/s", -0.20000, -0.17000, 2.00),
("正等效方向上升至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向上升至 0.19 rad/s", -0.20000, -0.19000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.19 rad/s", -0.20000, -0.19000, 2.00),
("正等效方向下降至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向下降至 0.17 rad/s", -0.20000, -0.17000, 2.00),
("正等效方向下降至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向下降至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向下降至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向下降至 0.13 rad/s", -0.20000, -0.13000, 2.00),
("正等效方向下降至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向下降至 0.11 rad/s", -0.20000, -0.11000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.09 rad/s", -0.20000, -0.09000, 2.00),
("正等效方向下降至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向下降至 0.07 rad/s", -0.20000, -0.07000, 2.00),
("正等效方向下降至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向下降至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向下降至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向下降至 0.03 rad/s", -0.20000, -0.03000, 2.00),
("正等效方向下降至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向下降至 0.01 rad/s", -0.20000, -0.01000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.01 rad/s", -0.20000, 0.01000, 2.00),
("负等效方向上升至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向上升至 -0.03 rad/s", -0.20000, 0.03000, 2.00),
("负等效方向上升至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向上升至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向上升至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向上升至 -0.07 rad/s", -0.20000, 0.07000, 2.00),
("负等效方向上升至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向上升至 -0.09 rad/s", -0.20000, 0.09000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.11 rad/s", -0.20000, 0.11000, 2.00),
("负等效方向上升至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向上升至 -0.13 rad/s", -0.20000, 0.13000, 2.00),
("负等效方向上升至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向上升至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向上升至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向上升至 -0.17 rad/s", -0.20000, 0.17000, 2.00),
("负等效方向上升至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向上升至 -0.19 rad/s", -0.20000, 0.19000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.19 rad/s", -0.20000, 0.19000, 2.00),
("负等效方向下降至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向下降至 -0.17 rad/s", -0.20000, 0.17000, 2.00),
("负等效方向下降至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向下降至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向下降至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向下降至 -0.13 rad/s", -0.20000, 0.13000, 2.00),
("负等效方向下降至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向下降至 -0.11 rad/s", -0.20000, 0.11000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.09 rad/s", -0.20000, 0.09000, 2.00),
("负等效方向下降至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向下降至 -0.07 rad/s", -0.20000, 0.07000, 2.00),
("负等效方向下降至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向下降至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向下降至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向下降至 -0.03 rad/s", -0.20000, 0.03000, 2.00),
("负等效方向下降至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向下降至 -0.01 rad/s", -0.20000, 0.01000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 2 次:REV_CONT_ANGULAR_STEP_G01_DW001_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/reverse/REV_CONT_ANGULAR_STEP_G01_DW001_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g01_dw001_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.01 rad/s", -0.20000, -0.01000, 2.00),
("正等效方向上升至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向上升至 0.03 rad/s", -0.20000, -0.03000, 2.00),
("正等效方向上升至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向上升至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向上升至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向上升至 0.07 rad/s", -0.20000, -0.07000, 2.00),
("正等效方向上升至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向上升至 0.09 rad/s", -0.20000, -0.09000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.11 rad/s", -0.20000, -0.11000, 2.00),
("正等效方向上升至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向上升至 0.13 rad/s", -0.20000, -0.13000, 2.00),
("正等效方向上升至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向上升至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向上升至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向上升至 0.17 rad/s", -0.20000, -0.17000, 2.00),
("正等效方向上升至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向上升至 0.19 rad/s", -0.20000, -0.19000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.19 rad/s", -0.20000, -0.19000, 2.00),
("正等效方向下降至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向下降至 0.17 rad/s", -0.20000, -0.17000, 2.00),
("正等效方向下降至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向下降至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向下降至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向下降至 0.13 rad/s", -0.20000, -0.13000, 2.00),
("正等效方向下降至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向下降至 0.11 rad/s", -0.20000, -0.11000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.09 rad/s", -0.20000, -0.09000, 2.00),
("正等效方向下降至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向下降至 0.07 rad/s", -0.20000, -0.07000, 2.00),
("正等效方向下降至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向下降至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向下降至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向下降至 0.03 rad/s", -0.20000, -0.03000, 2.00),
("正等效方向下降至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向下降至 0.01 rad/s", -0.20000, -0.01000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.01 rad/s", -0.20000, 0.01000, 2.00),
("负等效方向上升至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向上升至 -0.03 rad/s", -0.20000, 0.03000, 2.00),
("负等效方向上升至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向上升至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向上升至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向上升至 -0.07 rad/s", -0.20000, 0.07000, 2.00),
("负等效方向上升至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向上升至 -0.09 rad/s", -0.20000, 0.09000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.11 rad/s", -0.20000, 0.11000, 2.00),
("负等效方向上升至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向上升至 -0.13 rad/s", -0.20000, 0.13000, 2.00),
("负等效方向上升至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向上升至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向上升至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向上升至 -0.17 rad/s", -0.20000, 0.17000, 2.00),
("负等效方向上升至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向上升至 -0.19 rad/s", -0.20000, 0.19000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.19 rad/s", -0.20000, 0.19000, 2.00),
("负等效方向下降至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向下降至 -0.17 rad/s", -0.20000, 0.17000, 2.00),
("负等效方向下降至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向下降至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向下降至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向下降至 -0.13 rad/s", -0.20000, 0.13000, 2.00),
("负等效方向下降至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向下降至 -0.11 rad/s", -0.20000, 0.11000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.09 rad/s", -0.20000, 0.09000, 2.00),
("负等效方向下降至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向下降至 -0.07 rad/s", -0.20000, 0.07000, 2.00),
("负等效方向下降至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向下降至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向下降至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向下降至 -0.03 rad/s", -0.20000, 0.03000, 2.00),
("负等效方向下降至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向下降至 -0.01 rad/s", -0.20000, 0.01000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 3 次:REV_CONT_ANGULAR_STEP_G01_DW001_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G01_DW001/reverse/REV_CONT_ANGULAR_STEP_G01_DW001_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g01_dw001_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.01 rad/s", -0.20000, -0.01000, 2.00),
("正等效方向上升至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向上升至 0.03 rad/s", -0.20000, -0.03000, 2.00),
("正等效方向上升至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向上升至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向上升至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向上升至 0.07 rad/s", -0.20000, -0.07000, 2.00),
("正等效方向上升至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向上升至 0.09 rad/s", -0.20000, -0.09000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.11 rad/s", -0.20000, -0.11000, 2.00),
("正等效方向上升至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向上升至 0.13 rad/s", -0.20000, -0.13000, 2.00),
("正等效方向上升至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向上升至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向上升至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向上升至 0.17 rad/s", -0.20000, -0.17000, 2.00),
("正等效方向上升至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向上升至 0.19 rad/s", -0.20000, -0.19000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.19 rad/s", -0.20000, -0.19000, 2.00),
("正等效方向下降至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向下降至 0.17 rad/s", -0.20000, -0.17000, 2.00),
("正等效方向下降至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向下降至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向下降至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向下降至 0.13 rad/s", -0.20000, -0.13000, 2.00),
("正等效方向下降至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向下降至 0.11 rad/s", -0.20000, -0.11000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.09 rad/s", -0.20000, -0.09000, 2.00),
("正等效方向下降至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向下降至 0.07 rad/s", -0.20000, -0.07000, 2.00),
("正等效方向下降至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向下降至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向下降至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向下降至 0.03 rad/s", -0.20000, -0.03000, 2.00),
("正等效方向下降至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向下降至 0.01 rad/s", -0.20000, -0.01000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.01 rad/s", -0.20000, 0.01000, 2.00),
("负等效方向上升至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向上升至 -0.03 rad/s", -0.20000, 0.03000, 2.00),
("负等效方向上升至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向上升至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向上升至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向上升至 -0.07 rad/s", -0.20000, 0.07000, 2.00),
("负等效方向上升至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向上升至 -0.09 rad/s", -0.20000, 0.09000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.11 rad/s", -0.20000, 0.11000, 2.00),
("负等效方向上升至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向上升至 -0.13 rad/s", -0.20000, 0.13000, 2.00),
("负等效方向上升至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向上升至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向上升至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向上升至 -0.17 rad/s", -0.20000, 0.17000, 2.00),
("负等效方向上升至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向上升至 -0.19 rad/s", -0.20000, 0.19000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.19 rad/s", -0.20000, 0.19000, 2.00),
("负等效方向下降至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向下降至 -0.17 rad/s", -0.20000, 0.17000, 2.00),
("负等效方向下降至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向下降至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向下降至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向下降至 -0.13 rad/s", -0.20000, 0.13000, 2.00),
("负等效方向下降至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向下降至 -0.11 rad/s", -0.20000, 0.11000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.09 rad/s", -0.20000, 0.09000, 2.00),
("负等效方向下降至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向下降至 -0.07 rad/s", -0.20000, 0.07000, 2.00),
("负等效方向下降至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向下降至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向下降至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向下降至 -0.03 rad/s", -0.20000, 0.03000, 2.00),
("负等效方向下降至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向下降至 -0.01 rad/s", -0.20000, 0.01000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
8.6.3 连续增量 Δω=0.02 rad/s
正向上升等级:0.00, 0.02, 0.04, 0.06, 0.08, 0.10, 0.12, 0.14, 0.16, 0.18, 0.20 rad/s。
随后按相同等级降回 0,保持运动直线 3 秒,再对负角速度执行同样的连续升降序列。
正向第 1 次:FWD_CONT_ANGULAR_STEP_G02_DW002_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/forward/FWD_CONT_ANGULAR_STEP_G02_DW002_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g02_dw002_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向上升至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向上升至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向上升至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向上升至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向上升至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向上升至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向下降至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向下降至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向下降至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向下降至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向下降至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向下降至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向上升至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向上升至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向上升至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向上升至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向上升至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向上升至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向下降至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向下降至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向下降至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向下降至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向下降至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向下降至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.02 rad/s的正向连续阶梯。
正向第 2 次:FWD_CONT_ANGULAR_STEP_G02_DW002_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/forward/FWD_CONT_ANGULAR_STEP_G02_DW002_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g02_dw002_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向上升至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向上升至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向上升至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向上升至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向上升至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向上升至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向下降至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向下降至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向下降至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向下降至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向下降至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向下降至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向上升至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向上升至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向上升至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向上升至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向上升至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向上升至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向下降至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向下降至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向下降至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向下降至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向下降至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向下降至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.02 rad/s的正向连续阶梯。
正向第 3 次:FWD_CONT_ANGULAR_STEP_G02_DW002_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/forward/FWD_CONT_ANGULAR_STEP_G02_DW002_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g02_dw002_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向上升至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向上升至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向上升至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向上升至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向上升至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向上升至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.18 rad/s", 0.20000, 0.18000, 2.00),
("正等效方向下降至 0.16 rad/s", 0.20000, 0.16000, 2.00),
("正等效方向下降至 0.14 rad/s", 0.20000, 0.14000, 2.00),
("正等效方向下降至 0.12 rad/s", 0.20000, 0.12000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.08 rad/s", 0.20000, 0.08000, 2.00),
("正等效方向下降至 0.06 rad/s", 0.20000, 0.06000, 2.00),
("正等效方向下降至 0.04 rad/s", 0.20000, 0.04000, 2.00),
("正等效方向下降至 0.02 rad/s", 0.20000, 0.02000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向上升至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向上升至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向上升至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向上升至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向上升至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向上升至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.18 rad/s", 0.20000, -0.18000, 2.00),
("负等效方向下降至 -0.16 rad/s", 0.20000, -0.16000, 2.00),
("负等效方向下降至 -0.14 rad/s", 0.20000, -0.14000, 2.00),
("负等效方向下降至 -0.12 rad/s", 0.20000, -0.12000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.08 rad/s", 0.20000, -0.08000, 2.00),
("负等效方向下降至 -0.06 rad/s", 0.20000, -0.06000, 2.00),
("负等效方向下降至 -0.04 rad/s", 0.20000, -0.04000, 2.00),
("负等效方向下降至 -0.02 rad/s", 0.20000, -0.02000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.02 rad/s的正向连续阶梯。
反向第 1 次:REV_CONT_ANGULAR_STEP_G02_DW002_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/reverse/REV_CONT_ANGULAR_STEP_G02_DW002_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g02_dw002_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向上升至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向上升至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向上升至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向上升至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向上升至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向上升至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向下降至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向下降至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向下降至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向下降至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向下降至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向下降至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向上升至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向上升至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向上升至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向上升至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向上升至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向上升至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向下降至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向下降至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向下降至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向下降至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向下降至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向下降至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 2 次:REV_CONT_ANGULAR_STEP_G02_DW002_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/reverse/REV_CONT_ANGULAR_STEP_G02_DW002_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g02_dw002_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向上升至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向上升至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向上升至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向上升至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向上升至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向上升至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向下降至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向下降至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向下降至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向下降至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向下降至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向下降至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向上升至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向上升至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向上升至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向上升至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向上升至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向上升至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向下降至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向下降至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向下降至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向下降至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向下降至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向下降至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 3 次:REV_CONT_ANGULAR_STEP_G02_DW002_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G02_DW002/reverse/REV_CONT_ANGULAR_STEP_G02_DW002_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g02_dw002_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向上升至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向上升至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向上升至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向上升至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向上升至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向上升至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.18 rad/s", -0.20000, -0.18000, 2.00),
("正等效方向下降至 0.16 rad/s", -0.20000, -0.16000, 2.00),
("正等效方向下降至 0.14 rad/s", -0.20000, -0.14000, 2.00),
("正等效方向下降至 0.12 rad/s", -0.20000, -0.12000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.08 rad/s", -0.20000, -0.08000, 2.00),
("正等效方向下降至 0.06 rad/s", -0.20000, -0.06000, 2.00),
("正等效方向下降至 0.04 rad/s", -0.20000, -0.04000, 2.00),
("正等效方向下降至 0.02 rad/s", -0.20000, -0.02000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向上升至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向上升至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向上升至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向上升至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向上升至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向上升至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.18 rad/s", -0.20000, 0.18000, 2.00),
("负等效方向下降至 -0.16 rad/s", -0.20000, 0.16000, 2.00),
("负等效方向下降至 -0.14 rad/s", -0.20000, 0.14000, 2.00),
("负等效方向下降至 -0.12 rad/s", -0.20000, 0.12000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.08 rad/s", -0.20000, 0.08000, 2.00),
("负等效方向下降至 -0.06 rad/s", -0.20000, 0.06000, 2.00),
("负等效方向下降至 -0.04 rad/s", -0.20000, 0.04000, 2.00),
("负等效方向下降至 -0.02 rad/s", -0.20000, 0.02000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
8.6.4 连续增量 Δω=0.05 rad/s
正向上升等级:0.00, 0.05, 0.10, 0.15, 0.20 rad/s。
随后按相同等级降回 0,保持运动直线 3 秒,再对负角速度执行同样的连续升降序列。
正向第 1 次:FWD_CONT_ANGULAR_STEP_G05_DW005_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/forward/FWD_CONT_ANGULAR_STEP_G05_DW005_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g05_dw005_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.05 rad/s的正向连续阶梯。
正向第 2 次:FWD_CONT_ANGULAR_STEP_G05_DW005_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/forward/FWD_CONT_ANGULAR_STEP_G05_DW005_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g05_dw005_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.05 rad/s的正向连续阶梯。
正向第 3 次:FWD_CONT_ANGULAR_STEP_G05_DW005_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/forward/FWD_CONT_ANGULAR_STEP_G05_DW005_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g05_dw005_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.15 rad/s", 0.20000, 0.15000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.05 rad/s", 0.20000, 0.05000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.15 rad/s", 0.20000, -0.15000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.05 rad/s", 0.20000, -0.05000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.05 rad/s的正向连续阶梯。
反向第 1 次:REV_CONT_ANGULAR_STEP_G05_DW005_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/reverse/REV_CONT_ANGULAR_STEP_G05_DW005_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g05_dw005_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 2 次:REV_CONT_ANGULAR_STEP_G05_DW005_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/reverse/REV_CONT_ANGULAR_STEP_G05_DW005_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g05_dw005_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 3 次:REV_CONT_ANGULAR_STEP_G05_DW005_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G05_DW005/reverse/REV_CONT_ANGULAR_STEP_G05_DW005_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g05_dw005_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.15 rad/s", -0.20000, -0.15000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.05 rad/s", -0.20000, -0.05000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.15 rad/s", -0.20000, 0.15000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.05 rad/s", -0.20000, 0.05000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
8.6.5 连续增量 Δω=0.10 rad/s
正向上升等级:0.00, 0.10, 0.20 rad/s。
随后按相同等级降回 0,保持运动直线 3 秒,再对负角速度执行同样的连续升降序列。
正向第 1 次:FWD_CONT_ANGULAR_STEP_G10_DW010_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/forward/FWD_CONT_ANGULAR_STEP_G10_DW010_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g10_dw010_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.10 rad/s的正向连续阶梯。
正向第 2 次:FWD_CONT_ANGULAR_STEP_G10_DW010_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/forward/FWD_CONT_ANGULAR_STEP_G10_DW010_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g10_dw010_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.10 rad/s的正向连续阶梯。
正向第 3 次:FWD_CONT_ANGULAR_STEP_G10_DW010_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/forward/FWD_CONT_ANGULAR_STEP_G10_DW010_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g10_dw010_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.10 rad/s", 0.20000, 0.10000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.10 rad/s", 0.20000, -0.10000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.10 rad/s的正向连续阶梯。
反向第 1 次:REV_CONT_ANGULAR_STEP_G10_DW010_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/reverse/REV_CONT_ANGULAR_STEP_G10_DW010_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g10_dw010_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 2 次:REV_CONT_ANGULAR_STEP_G10_DW010_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/reverse/REV_CONT_ANGULAR_STEP_G10_DW010_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g10_dw010_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 3 次:REV_CONT_ANGULAR_STEP_G10_DW010_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G10_DW010/reverse/REV_CONT_ANGULAR_STEP_G10_DW010_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g10_dw010_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.10 rad/s", -0.20000, -0.10000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.10 rad/s", -0.20000, 0.10000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
8.6.6 连续增量 Δω=0.20 rad/s
正向上升等级:0.00, 0.20 rad/s。
随后按相同等级降回 0,保持运动直线 3 秒,再对负角速度执行同样的连续升降序列。
正向第 1 次:FWD_CONT_ANGULAR_STEP_G20_DW020_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/forward/FWD_CONT_ANGULAR_STEP_G20_DW020_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g20_dw020_fwd_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.20 rad/s的正向连续阶梯。
正向第 2 次:FWD_CONT_ANGULAR_STEP_G20_DW020_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/forward/FWD_CONT_ANGULAR_STEP_G20_DW020_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g20_dw020_fwd_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.20 rad/s的正向连续阶梯。
正向第 3 次:FWD_CONT_ANGULAR_STEP_G20_DW020_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/forward/FWD_CONT_ANGULAR_STEP_G20_DW020_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g20_dw020_fwd_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("正等效方向上升至 0.20 rad/s", 0.20000, 0.20000, 2.00),
("正等效方向下降至 0.00 rad/s", 0.20000, 0.00000, 2.00),
("保持运动直线回正", 0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.20 rad/s", 0.20000, -0.20000, 2.00),
("负等效方向下降至 -0.00 rad/s", 0.20000, -0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
本 bag 只对应
Δω=0.20 rad/s的正向连续阶梯。
反向第 1 次:REV_CONT_ANGULAR_STEP_G20_DW020_V020_run01
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/reverse/REV_CONT_ANGULAR_STEP_G20_DW020_V020_run01 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g20_dw020_rev_run01")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 2 次:REV_CONT_ANGULAR_STEP_G20_DW020_V020_run02
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/reverse/REV_CONT_ANGULAR_STEP_G20_DW020_V020_run02 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g20_dw020_rev_run02")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
反向第 3 次:REV_CONT_ANGULAR_STEP_G20_DW020_V020_run03
终端 1:开始录制本次测试对应的 bag
bash
ros2 bag record \
-o ~/ranger_motion_test/08_completion/continuous_angular_step/G20_DW020/reverse/REV_CONT_ANGULAR_STEP_G20_DW020_V020_run03 \
/cmd_vel /odom /lio/odom /tf /tf_static
终端 2:一次性复制并执行下面的完整命令块
bash
python3 - <<'PY'
import time
import rclpy
from geometry_msgs.msg import Twist
rclpy.init()
node = rclpy.create_node("ranger_cont_angular_g20_dw020_rev_run03")
publisher = node.create_publisher(Twist, "/cmd_vel", 10)
schedule = [
("静止预记录", 0.00000, 0.00000, 5.00),
("正等效方向上升至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("正等效方向上升至 0.20 rad/s", -0.20000, -0.20000, 2.00),
("正等效方向下降至 0.00 rad/s", -0.20000, -0.00000, 2.00),
("保持运动直线回正", -0.20000, 0.00000, 3.00),
("负等效方向上升至 -0.20 rad/s", -0.20000, 0.20000, 2.00),
("负等效方向下降至 -0.00 rad/s", -0.20000, 0.00000, 2.00),
("主动零速度停车", 0.00000, 0.00000, 5.00),
]
rate_hz = 20.0
period = 1.0 / rate_hz
message = Twist()
# 等待 DDS 完成发现;之后始终由同一个发布节点连续发送。
time.sleep(1.0)
try:
for index, (label, linear_x, angular_z, hold_time) in enumerate(
schedule, start=1
):
print(
f"[{index:02d}/{len(schedule):02d}] "
f"{label}: linear.x={linear_x:.3f}, "
f"angular.z={angular_z:.3f}, hold={hold_time:.2f} s",
flush=True,
)
message.linear.x = float(linear_x)
message.linear.y = 0.0
message.linear.z = 0.0
message.angular.x = 0.0
message.angular.y = 0.0
message.angular.z = float(angular_z)
end_time = time.monotonic() + float(hold_time)
next_publish = time.monotonic()
while rclpy.ok() and time.monotonic() < end_time:
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
next_publish += period
sleep_time = next_publish - time.monotonic()
if sleep_time > 0.0:
time.sleep(sleep_time)
else:
next_publish = time.monotonic()
except KeyboardInterrupt:
print("收到中断,立即连续发布零速度。", flush=True)
finally:
message.linear.x = 0.0
message.angular.z = 0.0
# 即使人工中断,也连续发布约 1 s 零速度后再退出。
for _ in range(20):
publisher.publish(message)
rclpy.spin_once(node, timeout_sec=0.0)
time.sleep(period)
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
PY
终端 1:终端 2 完成最终零速度阶段、车辆完全停止后,按 Ctrl+C 停止录包。
反向时线速度和角速度符号已按相同等效转向关系进行处理。
8.7 第八部分完成后可补齐的分析指标
8.7.1 主动停车
- 零速度指令首帧到实际速度下降至 10% 的时间;
- 零速度指令首帧到车辆完全停止的时间;
- 主动零速度后的制动距离;
- 主动停车与第四部分命令断流停车的时间和距离差;
- 正向、反向以及不同速度下的制动对称性。
8.7.2 连续转向切换
ω=±0.2 → 0的真实回正延迟;ω=+0.2 → -0.2或反向切换的过零时间;- 横摆角速度超调;
- 回正阶段残余角速度;
- 正向、反向和左右转向对称性。
8.7.3 连续角速度增量
- 不同
Δω下的响应延迟、上升时间和稳态误差; - 小增量是否存在死区;
- 增量大小与超调量之间的关系;
- 升阶与降阶是否存在滞回;
- 正角速度与负角速度是否对称;
- 正向与反向是否对称;
- 能够兼顾快速响应、低误差和低超调的推荐角速度增量。
8.8 测试结束后的数量检查
第七部分应生成 24 个 bag:
bash
find ~/ranger_motion_test/07_continuous_variable -name metadata.yaml | wc -l
预期输出:
text
24
第八部分应生成 54 个 bag:
bash
find ~/ranger_motion_test/08_completion -name metadata.yaml | wc -l
预期输出:
text
54
全部八部分累计应有 157 个 bag:
bash
find ~/ranger_motion_test -name metadata.yaml | wc -l
预期输出:
text
157
所有新增测试均使用新的目录和 bag 名称,不会覆盖前六部分已经录制的 79 个 bag。