调试与测试
相关源文件
以下文件用于生成此 Wiki 页面的上下文:
本文档介绍 IB-Robot 开发的调试和测试基础设施。内容包括 VS Code 调试配置、使用 pytest 进行单元测试、用于调试的构建系统配置,以及配置验证工具。
有关通用 VS Code 设置和环境配置,请参阅 VS Code 配置。有关构建系统详情,请参阅 构建系统与 Mixin。
VS Code 调试基础设施
工作区提供了预配置的启动配置,用于调试带有正确环境设置的 Python ROS2 节点。
Python 环境配置
Python 调试器需要显式配置 PYTHONPATH 以定位 ROS2 包、LeRobot 库和工作区包。
Key Path Configurations:
- venv/bin/python3 # 项目虚拟环境
- libs/lerobot/src # LeRobot 库
- src # 工作区 ROS2 包
- /opt/ros/humble/lib/python3.10/site-packages
启动配置
工作区在 .vscode/launch.json:1-28 中定义了两个主要调试配置:
通用 Python 节点调试器
"name": "ROS2: Debug Python Node (Current File)"
将当前打开的 Python 文件作为独立脚本进行调试。使用工作区范围的 PYTHONPATH 配置。
使用场景: 在开发过程中调试单个节点,逐步执行初始化代码。
动作分发器节点调试器
"name": "ROS2: Action Dispatcher Node"
为 action_dispatcher_node.py 预配置的调试器,带有特定的 ROS 参数:- 设置 robot_name 参数为 test_single_arm_single_cam - 包含所有必需的路径配置
使用场景: 调试动作分发管道、时间平滑和队列管理。
调试环境图
graph TB
subgraph "VS Code Debugger"
LAUNCH["launch.json<br/>Debug Configurations"]
SETTINGS["settings.json<br/>Python paths"]
LAUNCH --> DEBUG_CURRENT["Debug Current File"]
LAUNCH --> DEBUG_DISPATCHER["Debug Action Dispatcher"]
end
subgraph "Python Path Resolution"
VENV["${workspaceFolder}/venv"]
LEROBOT["${workspaceFolder}/libs/lerobot/src"]
SRC["${workspaceFolder}/src"]
ROS2["/opt/ros/humble/lib/python3.10/site-packages"]
SETTINGS --> VENV
SETTINGS --> LEROBOT
SETTINGS --> SRC
SETTINGS --> ROS2
end
subgraph "Target Nodes"
NODE_CURRENT["Current File<br/>(any .py)"]
NODE_DISPATCHER["action_dispatcher_node.py"]
DEBUG_CURRENT --> NODE_CURRENT
DEBUG_DISPATCHER --> NODE_DISPATCHER
end
VENV -.->|import path| NODE_CURRENT
LEROBOT -.->|import path| NODE_CURRENT
SRC -.->|import path| NODE_CURRENT
ROS2 -.->|import path| NODE_CURRENT
VENV -.->|import path| NODE_DISPATCHER
LEROBOT -.->|import path| NODE_DISPATCHER
SRC -.->|import path| NODE_DISPATCHER
ROS2 -.->|import path| NODE_DISPATCHER
使用 pytest 进行单元测试
代码库使用 pytest 进行 Python 模块的单元测试。测试文件遵循 test_*.py 命名约定。
示例:TemporalSmoother 测试套件
test_temporal_smoother.py 模块展示了全面的测试模式:
src/action_dispatch/test/test_temporal_smoother.py:1-247
测试结构
test_temporal_smoother.py
├── TestTemporalSmootherConfig # 配置验证测试
│ ├── test_default_config()
│ ├── test_custom_config()
│ └── test_invalid_chunk_size()
├── TestTemporalSmoother # 核心算法测试
│ ├── test_basic_update_and_get()
│ ├── test_disabled_smoothing()
│ ├── test_cross_frame_smoothing()
│ ├── test_tensor_input()
│ ├── test_reset()
│ └── test_empty_input()
├── TestTemporalSmootherManager # 管理 API 测试
│ ├── test_manager_basic()
│ ├── test_manager_toggle()
│ └── test_manager_peek()
└── TestSmoothingFormula # 数学正确性测试
├── test_weight_calculation()
├── test_positive_coeff_weights()
└── test_cumulative_weights()
关键测试模式
配置验证
src/action_dispatch/test/test_temporal_smoother.py:23-48
def test_invalid_chunk_size(self):
with pytest.raises(ValueError):
TemporalSmootherConfig(chunk_size=0)
数值正确性
src/action_dispatch/test/test_temporal_smoother.py:91-118
测试验证跨帧平滑产生的值介于旧动作块和新动作块之间,不完全等于任何一个:
assert not np.allclose(first_action.numpy(), np.ones(7) * 1.0)
assert not np.allclose(first_action.numpy(), np.ones(7) * 2.0)
边界情况处理
src/action_dispatch/test/test_temporal_smoother.py:146-161
测试空输入、1D 数组重塑和空计划错误。
来源: src/action_dispatch/test/test_temporal_smoother.py:1-247
运行测试
# 运行包中的所有测试
pytest src/action_dispatch/test/
# 运行特定测试文件
pytest src/action_dispatch/test/test_temporal_smoother.py
# 运行并显示详细输出
pytest src/action_dispatch/test/test_temporal_smoother.py -v
# 运行特定测试类
pytest src/action_dispatch/test/test_temporal_smoother.py::TestTemporalSmoother
# 运行特定测试方法
pytest src/action_dispatch/test/test_temporal_smoother.py::TestTemporalSmoother::test_cross_frame_smoothing
来源: src/action_dispatch/test/test_temporal_smoother.py:245-247
构建系统调试配置
colcon 构建系统通过 mixin 支持多种构建配置。
可用的 Mixin
.colcon/mixin/build.mixin.yaml:1-19
Mixin |
用途 |
CMake 参数 |
|---|---|---|
|
带调试符号的调试构建 |
` -DCMAKE_BUILD_TYPE=Debug` |
|
优化的生产构建 |
|
|
带调试符号的优化构建 |
|
|
启用测试构建 |
|
|
禁用测试构建 |
|
|
启用代码检查 |
|
|
开发模式 |
Debug + symlink-install + no tests |
|
生产模式 |
Release + no tests + no tracing |
构建配置流程
graph TB
subgraph "Mixin Loading"
INDEX[".colcon/mixin/index.yaml"]
BUILD_MIXIN[".colcon/mixin/build.mixin.yaml"]
INDEX -->|references| BUILD_MIXIN
end
subgraph "Mixin Definitions"
DEBUG["debug:<br/>CMAKE_BUILD_TYPE=Debug<br/>EXPORT_COMPILE_COMMANDS=ON"]
RELEASE["release:<br/>CMAKE_BUILD_TYPE=Release<br/>EXPORT_COMPILE_COMMANDS=ON"]
DEV["dev:<br/>symlink-install: true<br/>Debug + no tests"]
PROD["prod:<br/>Release + no tests<br/>TRACETOOLS_DISABLED=ON"]
BUILD_MIXIN --> DEBUG
BUILD_MIXIN --> RELEASE
BUILD_MIXIN --> DEV
BUILD_MIXIN --> PROD
end
subgraph "Build Commands"
CMD_DEBUG["colcon build --mixin debug"]
CMD_DEV["colcon build --mixin dev"]
CMD_PROD["colcon build --mixin prod"]
DEBUG -.->|applied by| CMD_DEBUG
DEV -.->|applied by| CMD_DEV
PROD -.->|applied by| CMD_PROD
end
subgraph "Build Output"
BUILD_DIR["build/<br/>CMake artifacts"]
INSTALL_DIR["install/<br/>Runtime files"]
COMPILE_DB["compile_commands.json<br/>for IntelliSense"]
CMD_DEBUG --> BUILD_DIR
CMD_DEBUG --> INSTALL_DIR
CMD_DEBUG --> COMPILE_DB
end
来源: .colcon/mixin/build.mixin.yaml:1-19, .colcon/mixin/index.yaml:1-4
使用示例
# 调试构建并生成 compile_commands.json
colcon build --mixin debug
# 开发构建带 symlink-install
colcon build --mixin dev
# 生产构建(优化,无调试符号)
colcon build --mixin prod
# 调试构建并启用测试
colcon build --mixin debug test
# 组合多个 mixin
colcon build --mixin dev lint
配置验证
validate_config.py 脚本强制执行 YAML 文件间的配置一致性。
验证架构
graph TB
subgraph "Input Files"
ROBOT_CONFIG["robot_config YAML<br/>so101_single_arm.yaml"]
CTRL_CONFIG["controllers YAML<br/>auto-resolved from robot_config"]
MOVEIT_CONFIG["MoveIt controllers YAML<br/>(optional)"]
end
subgraph "ConfigValidator Class"
LOAD["load_yaml()<br/>Parse YAML files"]
RESOLVE["resolve_ros_path()<br/>Handle $(find) and $(env)"]
VALIDATE_JOINTS["validate_joints_config()<br/>Extract joint definitions"]
VALIDATE_CTRL["validate_controller_config()<br/>Check controller joints"]
VALIDATE_MOVEIT["validate_moveit_config()<br/>Check MoveIt joints"]
LOAD --> RESOLVE
RESOLVE --> VALIDATE_JOINTS
VALIDATE_JOINTS --> VALIDATE_CTRL
VALIDATE_CTRL --> VALIDATE_MOVEIT
end
subgraph "Validation Checks"
CHECK1["arm + gripper = all joints"]
CHECK2["Controller joints match robot_config"]
CHECK3["MoveIt joints match robot_config"]
VALIDATE_JOINTS --> CHECK1
VALIDATE_CTRL --> CHECK2
VALIDATE_MOVEIT --> CHECK3
end
subgraph "Output"
ERRORS["errors: List[str]<br/>Configuration mismatches"]
WARNINGS["warnings: List[str]<br/>Non-critical issues"]
SUMMARY["Validation Summary<br/>Exit code 0/1/2"]
CHECK1 --> ERRORS
CHECK2 --> ERRORS
CHECK3 --> WARNINGS
ERRORS --> SUMMARY
WARNINGS --> SUMMARY
end
ROBOT_CONFIG --> LOAD
CTRL_CONFIG --> LOAD
MOVEIT_CONFIG --> LOAD
验证逻辑
验证器实现 DRY(Don’t Repeat Yourself)原则,确保关节列表一致:
scripts/validate_config.py:103-131
关键验证:
关节集合一致性: 验证
joints.all == joints.arm ∪ joints.gripper控制器关节匹配: 验证控制器配置使用正确的关节子集
MoveIt 关节匹配: 确保 MoveIt 控制器引用正确的关节
路径解析
scripts/validate_config.py:53-101
支持 ROS 风格的路径替换:- $(find package_name) - 搜索工作区 install、src 和 /opt/ros/ - $(env VAR_NAME) - 读取环境变量
使用方法
# 验证默认机器人配置
python scripts/validate_config.py
# 验证特定配置并显示详细输出
python scripts/validate_config.py \
--robot-config src/robot_config/config/robots/so101_single_arm.yaml \
--verbose
# 显式指定所有配置
python scripts/validate_config.py \
--robot-config src/robot_config/config/robots/so101_single_arm.yaml \
--controllers-config src/so101_moveit/config/lerobot/so101/ros2_controllers.yaml \
--moveit-config src/robot_moveit/config/lerobot/so101/moveit_controllers.yaml
退出码
代码 |
含义 |
|---|---|
0 |
所有验证通过 |
1 |
发现配置错误 |
2 |
文件未找到或解析错误 |
来源: scripts/validate_config.py:10-16, scripts/validate_config.py:297-350
调试工作流
调试 Python 节点
工作流 1:调试当前文件
在 VS Code 中打开 Python 节点文件
在代码中设置断点
按
F5或选择 “ROS2: Debug Python Node (Current File)”调试器使用正确的
PYTHONPATH配置启动
使用场景: 在开发过程中快速调试单个节点。
工作流 2:带 ROS 参数调试
对于需要特定 ROS 参数的节点,创建自定义启动配置:
{
"name": "Debug My Node",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/src/my_package/my_package/my_node.py",
"args": [
"--ros-args",
"-p", "robot_name:=my_robot",
"-p", "use_sim:=false"
],
"env": {
"PYTHONPATH": "${workspaceFolder}/libs/lerobot/src:..."
}
}
调试构建问题
启用编译命令
所有 debug/release mixin 都启用 CMAKE_EXPORT_COMPILE_COMMANDS=ON:
.colcon/mixin/build.mixin.yaml:3-7
这会为 C++ IntelliSense 生成 build/*/compile_commands.json。
构建输出分析
# 带详细输出构建
colcon build --event-handlers console_direct+
# 在调试模式下构建特定包
colcon build --packages-select my_package --mixin debug
# 显示 CMake 配置
colcon build --cmake-args --trace
调试动作分发管道
预配置的动作分发器调试器支持逐步调试:
动作队列管理: 在
ActionDispatcherNode._control_loop_callback()中设置断点时间平滑: 在
TemporalSmoother.update()或_apply_smoothing()中设置断点推理触发: 在
_trigger_inference_if_needed()中设置断点
推荐断点: -
src/action_dispatch/action_dispatch/temporal_smoother.py:145-206
- update() 方法 -
src/action_dispatch/action_dispatch/temporal_smoother.py:208-246
- _apply_smoothing() 方法
来源: .vscode/launch.json:14-27, src/action_dispatch/action_dispatch/temporal_smoother.py:1-322
测试模式
单元测试组织
测试应放置在 <package>/test/test_<module>.py:
src/my_package/
├── my_package/
│ ├── __init__.py
│ ├── my_module.py
│ └── my_node.py
└── test/
├── test_my_module.py
└── test_my_node.py
测试类结构
将相关测试组织成与代码结构匹配的类:
class TestMyConfig:
"""Tests for configuration dataclass."""
def test_default_config(self):
...
def test_invalid_config(self):
...
class TestMyClass:
"""Tests for main class functionality."""
def test_basic_operation(self):
...
def test_edge_case(self):
...
来源: src/action_dispatch/test/test_temporal_smoother.py:23-243
使用 NumPy/Torch 进行数值测试
对于数值算法,使用 np.testing.assert_array_almost_equal()
或 torch.allclose():
# From test_temporal_smoother.py
np.testing.assert_array_almost_equal(
action,
expected_action,
decimal=6
)
# 验证值在有效范围内(非精确相等)
assert not np.allclose(smoothed, old_value)
assert not np.allclose(smoothed, new_value)
来源: src/action_dispatch/test/test_temporal_smoother.py:89-118, src/action_dispatch/test/test_temporal_smoother.py:224-243
异常测试
测试无效输入是否引发适当的异常:
def test_invalid_chunk_size(self):
with pytest.raises(ValueError):
TemporalSmootherConfig(chunk_size=0)
with pytest.raises(ValueError):
TemporalSmootherConfig(chunk_size=-1)
def test_get_next_action_raises_on_empty(self):
with pytest.raises(IndexError):
smoother.get_next_action()
来源: src/action_dispatch/test/test_temporal_smoother.py:43-48, src/action_dispatch/test/test_temporal_smoother.py:156-161
集成测试设置
对于 ROS2 集成测试,初始化 ROS 上下文:
import rclpy
import pytest
@pytest.fixture
def ros_context():
rclpy.init()
yield
rclpy.shutdown()
def test_node_lifecycle(ros_context):
node = MyNode()
# Test node...
node.destroy_node()
推荐扩展
工作区推荐特定的 VS Code 扩展以获得最佳调试体验:
扩展 |
用途 |
|---|---|
|
Python 调试和 IntelliSense |
|
C++ 调试和 IntelliSense |
|
原生代码的 LLDB 调试器 |
|
CMake 集成 |
|
YAML 语法和验证 |
|
ROS 开发环境包 |
总结
IB-Robot 调试和测试基础设施提供:
VS Code 集成: 预配置的启动配置,带有正确的 Python 路径解析
单元测试: 基于 pytest 的测试套件,具有全面的覆盖模式
构建配置: 用于 debug/release/development 构建的 Colcon mixin
配置验证: YAML 一致性的自动验证
调试工作流: 常见调试场景的文档化模式
有关工作区设置,请参阅 VS Code 配置。有关构建系统详情,请参阅 构建系统与 Mixin。
来源: .vscode/ 中的所有文件, .colcon/, scripts/validate_config.py:1-351, src/action_dispatch/test/test_temporal_smoother.py:1-247