207 lines
12 KiB
Markdown
207 lines
12 KiB
Markdown
# ROS2 子项目 Agent 铁律
|
||
|
||
## 铁律 (Hard Rules)
|
||
|
||
**违反任何一条,所有变更立刻回滚。**
|
||
|
||
1. **只允许在本目录 `D:\xs\ros2` 下创建/修改/删除文件。**
|
||
- 任何系统临时目录(`%TEMP%`、`/tmp` 等) 一律禁止落盘。
|
||
- 在 Windows 下临时目录会残留垃圾文件且不清理,绝对禁止。
|
||
- 创建临时数据用 PowerShell 内存对象或 stdout,不写盘。
|
||
2. **禁止用 shell(PowerShell / cmd)编辑文件。**
|
||
- 改 / 写 / 读文件一律用内置工具:Read / Edit / Write / Glob / Grep。
|
||
- shell(本会话的 `bash` 工具)只允许运行可执行命令,例如 `docker ...`、`colcon ...`,**不允许用 `Set-Content`、`Out-File`、`>`、`>>` 写文件**。
|
||
- 禁止 `cd` / `Set-Location` 切换工作目录;需要别的目录时,在 `bash` 工具里用绝对路径,或者在 GUI / 编辑器里用内置工具定位。
|
||
3. **禁止到处创建文件/目录。**
|
||
- 不擅自创建 `.cache/`、`.tmp/`、`.bak/` 等隐藏目录。
|
||
- 不擅自创建 `test/xxx` 临时目录、"out/`、`日志/。
|
||
- 所有产出(镜像 `ros2-humble-dev:latest`、容器 `ros2_dev`、构建目录 `install/`、`build/`、`log/`)放在本项目内或其默认位置,不放别处。
|
||
4. **禁止问与思考循环。**
|
||
- 用户拒绝连续"要不要 / 要不要这样"。给出明确方案,直接开干。
|
||
- 必须问时,一次问清,不要反问。
|
||
5. **测试必须 100% 通过才能停手。**
|
||
- `docker compose build` + `colcon build` + `colcon test` + 节点启动 + `ros2 topic echo` 全绿才能汇报"完成"。
|
||
- 任何环节失败 → 自动修 → 再跑,直到全过。
|
||
|
||
## 子项目结构
|
||
|
||
```
|
||
D:\xs\ros2\
|
||
├── AGENTS.md # 本文件
|
||
├── README.md # 项目入口 + 架构 + 启动命令
|
||
├── pyproject.toml # PEP 621 workspace metadata(IDE 入口)
|
||
├── requirements.txt # venv runtime 依赖
|
||
├── requirements-dev.txt # venv 开发工具(ruff/black/mypy/pytest)
|
||
├── .flake8 / pyrightconfig.json # lint / 类型检查配置
|
||
├── .gitignore # 包含 .venv/ build/ install/ log/
|
||
│
|
||
├── docker/
|
||
│ ├── Dockerfile # ROS2 Humble 镜像
|
||
│ ├── docker-compose.yml # 容器编排
|
||
│ ├── bringup_e2e.log # 4 节点跨语言端到端验证日志(31KB)
|
||
│ ├── srv_e2e.log # Service 端到端(12+30=42,664B)
|
||
│ ├── robot_e2e.log # URDF + TF 端到端(11KB)
|
||
│ ├── vision_e2e.log # sensor_msgs/Image 端到端(49KB)
|
||
│ └── full_demo_e2e.log # 11 节点全开端到端(46KB)
|
||
│
|
||
├── tools/
|
||
│ ├── setup_venv.sh # Linux/WSL/Docker 一键 venv
|
||
│ └── setup_venv.ps1 # Windows 一键 venv(不污染系统 Python)
|
||
│
|
||
├── build.sh # 容器内 colcon build 一键脚本
|
||
├── start.sh / start.ps1 # 一键启动 + 构建 + 进开发终端
|
||
│
|
||
├── src/
|
||
│ ├── py_pubsub/ # ament_python — Topic pub/sub (Python)
|
||
│ │ ├── package.xml
|
||
│ │ ├── setup.py / setup.cfg
|
||
│ │ ├── py_pubsub/publisher_member_function.py
|
||
│ │ ├── py_pubsub/subscriber_member_function.py
|
||
│ │ ├── launch/pubsub_launch.py
|
||
│ │ ├── resource/py_pubsub
|
||
│ │ └── test/test_pubsub_launch.py # 4 pytest 用例
|
||
│ ├── cpp_pubsub/ # ament_cmake — Topic pub/sub (C++) + gtest
|
||
│ │ ├── package.xml
|
||
│ │ ├── CMakeLists.txt
|
||
│ │ ├── src/publisher_member_function.cpp
|
||
│ │ ├── src/subscriber_member_function.cpp
|
||
│ │ ├── launch/pubsub_launch.py
|
||
│ │ └── test/test_pub_sub.cpp # 2 gtest 用例
|
||
│ ├── py_srv/ # ament_python — Service demo
|
||
│ │ ├── package.xml
|
||
│ │ ├── setup.py / setup.cfg
|
||
│ │ ├── py_srv/add_two_ints_server.py
|
||
│ │ ├── py_srv/add_two_ints_client.py
|
||
│ │ ├── launch/srv_launch.py
|
||
│ │ └── test/test_srv.py # 1 pytest 用例
|
||
│ ├── py_action_demo/ # ament_python — Action 三件套 demo
|
||
│ │ ├── package.xml
|
||
│ │ ├── setup.py / setup.cfg
|
||
│ │ ├── py_action_demo/fibonacci_server.py
|
||
│ │ ├── py_action_demo/fibonacci_client.py
|
||
│ │ ├── launch/action_launch.py
|
||
│ │ └── test/test_action.py # 1 pytest 用例
|
||
│ ├── cpp_robot_tf2/ # ament_cmake — URDF + TF2 + JointState (C++)
|
||
│ │ ├── package.xml
|
||
│ │ ├── CMakeLists.txt
|
||
│ │ ├── urdf/simple_arm.urdf # 3 关节机械臂
|
||
│ │ ├── src/joint_state_publisher.cpp
|
||
│ │ ├── src/tf2_listener.cpp
|
||
│ │ ├── launch/robot_tf2_launch.py
|
||
│ │ └── test/test_tf2_lookup.cpp # 2 gtest 用例
|
||
│ ├── py_vision_demo/ # ament_python — sensor_msgs/Image (Python)
|
||
│ │ ├── package.xml
|
||
│ │ ├── setup.py / setup.cfg
|
||
│ │ ├── py_vision_demo/fake_camera.py
|
||
│ │ ├── py_vision_demo/image_processor.py
|
||
│ │ ├── launch/vision_launch.py
|
||
│ │ └── test/test_vision.py # 2 pytest 用例
|
||
│ └── bringup/ # ament_python — 顶层 launch 聚合
|
||
│ ├── package.xml
|
||
│ ├── setup.py / setup.cfg
|
||
│ ├── launch/
|
||
│ │ ├── pubsub_launch.py # 4 节点 Topic(pubsub)
|
||
│ │ ├── service_launch.py # AddTwoInts server
|
||
│ │ ├── action_launch.py # Fibonacci server
|
||
│ │ ├── robot_launch.py # URDF TF2(嵌套 cpp_robot_tf2)
|
||
│ │ ├── vision_launch.py # 嵌套 py_vision_demo
|
||
│ │ └── full_demo_launch.py # 11 节点一起
|
||
│ └── resource/bringup
|
||
│
|
||
└── doc/ # 14 篇深度文档
|
||
├── 00-overview.md # 架构 + 设计取舍
|
||
├── 01-quickstart.md # 5 分钟上手
|
||
├── 02-virtualenv.md # venv 工作流(本机不污染)
|
||
├── 10-concepts.md # Node/Topic/Service/Action/Parameter/TF
|
||
├── 20-topics.md # Topic pub/sub 深度
|
||
├── 30-services.md # Service 深度
|
||
├── 40-actions.md # Action 三件套深度
|
||
├── 50-tf2.md # TF2 坐标变换
|
||
├── 60-urdf.md # URDF 机器人模型
|
||
├── 70-launch.md # launch 文件系统
|
||
├── 80-package-build.md # colcon / ament 包构建
|
||
├── 85-docker.md # Docker 容器化开发
|
||
├── 90-testing.md # 测试金字塔策略
|
||
├── 99-embodied-ai.md # VLA / 机器人 / 具身智能路径
|
||
└── 100-embedded-deployment.md # 三机嵌入式部署(PC + RDK X5 + RK3506)
|
||
```
|
||
|
||
## 子项目工作流
|
||
|
||
| 步骤 | 命令 |
|
||
|---|---|
|
||
| 构建镜像(首次 5-10min) | `docker compose -f docker/docker-compose.yml build` |
|
||
| 启动容器 | `docker compose -f docker/docker-compose.yml up -d` |
|
||
| 容器内构建所有 7 个包 | `docker exec ros2_dev bash -lc "source /opt/ros/humble/setup.bash && cd /root/ros2_ws && colcon build --symlink-install --packages-select py_pubsub cpp_pubsub py_srv py_action_demo cpp_robot_tf2 py_vision_demo bringup"` |
|
||
| 跑所有单元/集成测试 | `docker exec ros2_dev bash -lc "source /opt/ros/humble/setup.bash && cd /root/ros2_ws && colcon test --packages-select py_pubsub cpp_pubsub py_srv py_action_demo cpp_robot_tf2 py_vision_demo bringup"` |
|
||
| 启动 4 节点 Topic | `docker exec ros2_dev bash -lc "source /root/ros2_ws/install/setup.bash && ros2 launch bringup pubsub_launch.py"` |
|
||
| 启动 Service 端到端 | `docker exec ros2_dev bash -lc "source install/setup.bash && ros2 launch bringup service_launch.py"` + `ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts '{a: 12, b: 30}'` |
|
||
| 启动 Action 端到端 | `ros2 launch bringup action_launch.py` + `ros2 action send_goal /fibonacci example_interfaces/action/Fibonacci '{order: 6}' --feedback` |
|
||
| 启动 TF2 演示 | `ros2 launch bringup robot_launch.py` |
|
||
| 启动 Vision 演示 | `ros2 launch bringup vision_launch.py` |
|
||
| 启动 11 节点 Full demo | `ros2 launch bringup full_demo_launch.py` |
|
||
| 进入开发终端 | `docker exec -it ros2_dev bash -lc "source /root/ros2_ws/install/setup.bash && exec bash"` |
|
||
| 本机 venv 初始化(不污染系统 Python) | `powershell .\tools\setup_venv.ps1` |
|
||
| 本机 venv 激活 | `.\.venv\Scripts\Activate.ps1` |
|
||
|
||
## 测试覆盖 (100% 通过)
|
||
|
||
| 包 | 测试类型 | 用例数 | 结果 |
|
||
|---|---|---|---|
|
||
| py_pubsub | pytest + in-process spin | 4/4 | PASSED |
|
||
| cpp_pubsub | gtest | 2/2 | PASSED |
|
||
| py_srv | pytest + Service in-process | 1/1 | PASSED |
|
||
| py_action_demo | pytest + Action in-process | 1/1 | PASSED |
|
||
| cpp_robot_tf2 | gtest | 2/2 | PASSED |
|
||
| py_vision_demo | pytest + Image in-process | 2/2 | PASSED |
|
||
| bringup | launch 6 文件就绪 | OK | PASSED |
|
||
|
||
**总计: 10/10 单元/集成测试 + 5 个端到端 demo 全部通过 100%。**
|
||
|
||
### 端到端日志(固化在 `docker/`)
|
||
- `bringup_e2e.log`:4 节点 Topic 跨语言互通(listener_cpp 同时收到 PY + CPP 消息)
|
||
- `srv_e2e.log`:Service 12+30=42
|
||
- `robot_e2e.log`:3 关节机械臂 + TF 实时打印(gripper 在 base_link 下位置)
|
||
- `vision_e2e.log`:fake_camera → image_processor 图像流(cv_bridge 解码 + 平均亮度)
|
||
- `full_demo_e2e.log`:11 节点同时运行(Topic + Service + Action + Robot + Vision)
|
||
|
||
## 子项目约定
|
||
|
||
### Python 包用 `ament_python`(`py_pubsub` / `py_srv` / `py_action_demo` / `py_vision_demo` / `bringup`)。
|
||
### C++ 包用 `ament_cmake`(`cpp_pubsub` / `cpp_robot_tf2`)。
|
||
### 跨包 launch 收纳到 `bringup` 包,包名**不能**叫 `launch`(与 ROS2 自带包同名,ament 索引冲突)。
|
||
### 所有 ROS2 节点默认参数 `period_ms=500`、`topic=chatter`,可在 launch 文件里覆盖。
|
||
### 源码注释一律中文,顶部 docstring 先写"用途 / 关键概念 / 运行方式",关键 API 旁写 inline。
|
||
### 跨语言互通演示:talker_py / talker_cpp 都用 `std_msgs/String`,见 `ros2 topic info chatter -v`。
|
||
|
||
## 嵌入式部署硬件清单(典型)
|
||
|
||
| 设备 | 角色 | ROS2 适配 |
|
||
|---|---|---|
|
||
| PC (x86) | 主控 | ✅ 完整 ROS2 + MoveIt2 + Nav2 + RViz |
|
||
| RDK X5 (ARM + 5 TOPS NPU) | 边缘 AI | ✅ 完整 ROS2 (视觉 / 语音 / SLAM) |
|
||
| RK3506 × 2 (ARM 3核 + 512MB RAM + 8GB eMMC) | 实时控制 | ✅ **精简 ROS2** (`ros-humble-ros-base`,不要 desktop) |
|
||
|
||
**关键提示**:
|
||
- RK3506 是 Linux 应用处理器(不是 MCU),**直接 apt 装 `ros-humble-ros-base`**,不用 micro-ROS
|
||
- 三机同 LAN 同 `ROS_DOMAIN_ID`,通过 FastDDS multicast 自动发现(或 `ROS_STATIC_PEERS` 单播)
|
||
- RK3506 用精简包 + 关 daemon + 关 GUI,可省 ~300MB RAM
|
||
- 详细步骤 + 故障排查见 `doc/100-embedded-deployment.md`
|
||
|
||
## RMW / 网络注意事项
|
||
|
||
- Docker Desktop on Windows + host network 模式下,默认 `rmw_fastrtps_cpp` 工作良好。
|
||
- **不要在 docker-compose.yml 里设 `RMW_IMPLEMENTATION=rmw_cyclonedds_cpp`**:镜像没装 cyclone dds,
|
||
CMake 配置阶段会失败。切换 RMW 时务必 `rm -rf build/ install/ log/` 再 build。
|
||
- `ros2 launch` 调 `IncludeLaunchDescription` 时,被包含的子 launch 文件必须在被包含包的 `share/<pkg>/launch/` 下被 colcon 实际安装 — 检查 `data_files` 里 `glob('launch/*.py')` 是否覆盖到。
|
||
|
||
## 调试速查
|
||
|
||
| 症状 | 排查 |
|
||
|---|---|
|
||
| `rcl_xxx not found` | `source /opt/ros/humble/setup.bash` |
|
||
| `Command ['cat', path]` 空格丢了 | launch 里别用 cat,改用 `open().read()` |
|
||
| `rcl_shutdown already called` | 测试 fixture 别在 callback 里 shutdown |
|
||
| `frame not exist` | robot_state_publisher 还没算完,等 1-2s |
|
||
| `Cannot connect to Docker daemon` | 启动 Docker Desktop |
|
||
| Windows venv import rclpy 飘红 | 正常,rclpy 没 Windows wheels,在容器里跑 | |