# Fast DDS `.164` 专用链路设计与回滚规格 - 日期:2026-07-23 - 适用环境:RDKx5(ROS 2 Humble)与 WSL(ROS 2 Humble) - ROS Domain:`22` - 状态:设计已确认,DDS 配置尚未部署 ## 1. 目标 将 WSL 与 RDKx5 之间的 ROS 2/DDS 数据固定在以下链路: ```text WSL 192.168.10.151 <-> RDKx5 192.168.10.164 (wlx200db0c3fca5) ``` RDKx5 的 `192.168.10.210`(`wlan0`)继续用于 SSH 和 VS Code,不承担 WSL 与 RDKx5 之间的 DDS 数据。 本次不开发 `obstacle_nav_web`,只优化 DDS 网络选择。 ## 2. 已确认的现状 ### RDKx5 - 主机:`sunrise@192.168.10.210` - ROS 2:Humble - 默认 RMW:`rmw_fastrtps_cpp` - `~/.bashrc` 已设置 `ROS_DOMAIN_ID=22` - DDS 专用网卡:`wlx200db0c3fca5`,地址 `192.168.10.164/24` - 管理网卡:`wlan0`,地址 `192.168.10.210/24` - 两张网卡处于同一子网,普通路由优先级为 `.210` 的 metric 600、`.164` 的 metric 601。因此不能依赖普通路由保证 DDS 使用 `.164`。 ### WSL - 用户:`hikos` - 默认 RMW:`rmw_fastrtps_cpp` - ROS 2 接口:`eth4`,地址 `192.168.10.151/24` - 到 `.164` 和 `.210` 均经 `eth4` 直连 - WSL 端配置必须放在 `/home/hikos/Yiliao2026/` 中 ## 3. 采用方案 继续使用 Fast DDS,不修改系统路由、网卡 metric 或防火墙。双方通过 Fast DDS 默认 participant profile 显式选择接口,并设置对端 discovery peer。 ### 跨主机 UDP - RDKx5 的自定义 UDPv4 transport 只允许本地地址 `192.168.10.164`。 - WSL 的自定义 UDPv4 transport 只允许本地地址 `192.168.10.151`。 - RDKx5 discovery peer 指向 `192.168.10.151`。 - WSL discovery peer 指向 `192.168.10.164`。 - 不对单个 DDS 端口做端口转发;DDS 发现和数据端口由 Fast DDS 按 Domain 和 participant 管理。 ### 同主机通信 配置保留 SHM transport。RDKx5 内部 ROS 节点之间及 WSL 内部 ROS 节点之间优先使用共享内存,避免将同主机的大流量消息无意义地送入无线链路。 ### 生效范围 只有从指定环境脚本启动的 ROS 2 participant 才受该配置约束。为保证实际 Nav2 数据都走 `.164`,RDKx5 的底盘、雷达、`obstacle_scanner` 和 Nav2 必须从同一个已加载 RDK 环境脚本的终端或其子进程启动;WSL 现有软件必须从已加载 WSL 环境脚本的终端或其子进程启动。 ## 4. 计划新增文件 ### RDKx5 ```text /home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh ``` ### WSL ```text /home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh ``` ### 变更与回滚记录 ```text /home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md ``` 当前设计规格即保存在上述变更文档中。实施时必须在同一文档中追加实际文件内容、执行命令、验证结果、文件校验值和回滚结果,不另建无法互相对应的零散说明。 ## 5. 环境脚本行为 两个脚本均设计为由 Bash `source` 加载,不作为独立子进程执行。 脚本必须: 1. 检查当前主机是否存在预期的本地 IP;不存在时输出明确错误并返回非零。 2. 检查 XML 文件存在且可读。 3. 设置 `ROS_DOMAIN_ID=22`。 4. 设置 `RMW_IMPLEMENTATION=rmw_fastrtps_cpp`。 5. 将 Humble 使用的 `FASTRTPS_DEFAULT_PROFILES_FILE` 指向对应 XML;如当前 Fast DDS 同时支持新变量,则将 `FASTDDS_DEFAULT_PROFILES_FILE` 指向同一文件。 6. 输出本次选择的 Domain、RMW、配置文件和本地 DDS 地址,便于启动前人工核对。 7. 不修改 `~/.bashrc`、`~/.profile` 或系统服务环境。 ## 6. 使用流程 ### RDKx5 ```bash source /opt/ros/humble/setup.bash source /home/sunrise/yiliao_ws/install/setup.bash source /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh ros2 launch obstacle_nav2 obstacle_nav2.launch.py ``` ### WSL ```bash source /opt/ros/humble/setup.bash source /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh # 在同一终端启动现有软件 ``` ## 7. 精简验证 实施后只执行以下必要验证: 1. 双端加载环境脚本,确认本地 IP、XML、`ROS_DOMAIN_ID=22` 和 `rmw_fastrtps_cpp` 正确。 2. 使用唯一命名的临时 ROS 2 话题验证 WSL 与 RDKx5 能互相发现并收发消息。 3. 从该环境启动实际 `ros2 launch`,确认 WSL 能看到关键话题;观察 DDS 数据经过 `.164`,`.210` 上的 SSH 保持正常,并且没有 WSL 相关 DDS 数据使用 `.210`。 验证记录应包含执行命令、成功或失败、关键输出摘要。无需进行长时间带宽统计、完整 Nav2 功能回归或 costmap 性能调优。 ## 8. 失败保护和回滚 ### 快速回滚 1. 停止从专用 DDS 环境启动的 ROS 2 节点。 2. 关闭已加载环境脚本的终端,或在当前终端取消 DDS 配置变量。 3. 新开终端,仅加载原有 ROS 2 和工作空间环境,然后按原命令重新启动。 4. 验证默认 ROS graph 恢复。 ### 文件级回滚 配置验证失败且不再保留时,只删除本规格第 4 节列出的四个新增配置文件;如果目录为空,再删除新增的 `config/dds` 目录。不得删除工作空间、现有 package、路由表或其他用户文件。 实施文档必须记录精确的删除命令。在执行删除前,应再次解析并核对绝对路径分别位于: - `/home/sunrise/yiliao_ws/config/dds/` - `/home/hikos/Yiliao2026/config/dds/` ### 不需要回滚的项目 因为本方案不修改以下项目,所以回滚不得操作它们: - RDKx5 与 WSL 的路由表 - 防火墙规则 - 网卡 metric - `~/.bashrc` 与 `~/.profile` - `obstacle_nav2`、`obstacle_scanner` 和其他 ROS package - SSH 与 VS Code 配置 ## 9. 变更记录要求 实施时,本文件必须追加: - 每个新增文件的绝对路径与完整内容 - 修改前的网络和 ROS 环境摘要 - 实际执行命令及执行顺序 - 每项精简验证的结果 - 新增文件的 SHA-256 - 完整回滚命令 - 若发生失败,失败现象、停止位置以及是否已回滚 如果实施内容与本设计不一致,必须先在本文件记录差异及原因,再执行该项变更。 ## 10. 验收标准 - WSL 与 RDKx5 在 Domain 22 中能发现并收发 ROS 2 消息。 - 由专用环境启动的跨主机 DDS 通信只使用 WSL `.151` 与 RDKx5 `.164`。 - `.210` 上的 SSH 和 VS Code 管理链路保持可用。 - 未修改路由表、系统启动文件、现有 ROS package 或 Nav2 参数。 - 所有实际修改、验证和回滚方式均记录在本文件中。 # Fast DDS `.164` 专用链路实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 让从专用环境启动的 WSL 与 RDKx5 ROS 2 participant 只通过 `.151 <-> .164` 交换跨主机 DDS 数据,同时保持 `.210` 的管理链路不变。 **Architecture:** 双端保持 `rmw_fastrtps_cpp` 和 Domain 22,分别加载一个 Fast DDS 默认 participant profile。profile 保留 SHM 供同主机通信,并用带接口白名单的自定义 UDPv4 transport 约束跨主机通信;sourceable Bash 脚本负责前置检查和环境变量设置。 **Tech Stack:** ROS 2 Humble、Fast DDS 2.6.x、Bash、Fast DDS XML profiles、`tcpdump`、Git。 --- ## 文件职责 - `/home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml`:RDKx5 participant transport,只允许 UDPv4 使用 `.164`,peer 为 WSL `.151`。 - `/home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh`:验证 RDKx5 网卡和 XML 后,导出 Domain、RMW 和 profile 环境变量。 - `/home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml`:WSL participant transport,只允许 UDPv4 使用 `.151`,peer 为 RDKx5 `.164`。 - `/home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh`:验证 WSL 网卡和 XML 后,导出 Domain、RMW 和 profile 环境变量。 - `/home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md`:设计、计划、实际变更、证据、提交号和回滚命令的唯一记录。 ### Task 1:实施前保护与基线 **Files:** - Modify: `/home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md` - [ ] **Step 1:确认目标文件不会被覆盖** 在 RDKx5 执行: ```bash for path in \ /home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml \ /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh; do if [ -e "$path" ]; then echo "STOP: existing file: $path" >&2 exit 1 fi done ``` 在 WSL 执行: ```bash for path in \ /home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml \ /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh; do if [ -e "$path" ]; then echo "STOP: existing file: $path" >&2 exit 1 fi done ``` Expected:两段命令均无输出且返回 `0`。任何文件已存在都停止实施,先将其路径、SHA-256 和内容写入本文件,不能覆盖。 - [ ] **Step 2:采集最小基线** RDKx5: ```bash ip -br -4 addr ip -4 route source /opt/ros/humble/setup.bash python3 -c 'from rclpy.utilities import get_rmw_implementation_identifier; print(get_rmw_implementation_identifier())' grep -n 'ROS_DOMAIN_ID' /home/sunrise/.bashrc git -C /home/sunrise/yiliao_ws status --short ``` WSL: ```bash ip -br -4 addr ip -4 route get 192.168.10.164 source /opt/ros/humble/setup.bash python3 -c 'from rclpy.utilities import get_rmw_implementation_identifier; print(get_rmw_implementation_identifier())' git -C /home/hikos/Yiliao2026 status --short ``` Expected:RDKx5 存在 `.164` 和 `.210`,WSL 存在 `.151`,双方 RMW 均为 `rmw_fastrtps_cpp`。记录现有 dirty files,后续提交不得包含它们。 - [ ] **Step 3:把基线摘要追加到唯一变更文档** 用 `apply_patch` 在本文件末尾增加 `## 实施记录` 和 `### 实施前基线`,写入上述命令的关键输出、实施开始时间以及“目标文件原先不存在”。不要粘贴无关的大段 package 列表。 - [ ] **Step 4:提交基线记录** ```bash cd /home/sunrise/yiliao_ws git add -- docs/crucial_change/2026-07-23-fastdds-164-network-change.md git diff --cached --check git diff --cached --name-only git commit -m "docs: record Fast DDS network baseline" -- \ docs/crucial_change/2026-07-23-fastdds-164-network-change.md ``` Expected:待提交文件列表只有该 Markdown 文档。 ### Task 2:RDKx5 Fast DDS 配置 **Files:** - Create: `/home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml` - Create: `/home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh` - Modify: `/home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md` - [ ] **Step 1:运行存在性测试并确认失败** ```bash test -f /home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml && \ test -f /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh ``` Expected:返回非零,因为两个文件尚未创建。 - [ ] **Step 2:创建 RDKx5 XML** 创建目录 `/home/sunrise/yiliao_ws/config/dds`: ```bash mkdir -p /home/sunrise/yiliao_ws/config/dds ``` 然后用 `apply_patch` 创建 `fastdds_rdk_164.xml`,完整内容为: ```xml rdk_udp_164 UDPv4
192.168.10.164
rdk_shm SHM
192.168.10.151
rdk_udp_164 rdk_shm false
``` - [ ] **Step 3:创建 RDKx5 环境脚本** 用 `apply_patch` 创建 `use_rdk_dds_164.sh`,完整内容为: ```bash #!/usr/bin/env bash if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then echo "ERROR: source this file instead of executing it" >&2 exit 64 fi _rdk_dds_profile="/home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml" if ! ip -4 addr show dev wlx200db0c3fca5 2>/dev/null | grep -q 'inet 192\.168\.10\.164/'; then echo "ERROR: wlx200db0c3fca5 does not own 192.168.10.164" >&2 unset _rdk_dds_profile return 1 fi if [[ ! -r "${_rdk_dds_profile}" ]]; then echo "ERROR: unreadable Fast DDS profile: ${_rdk_dds_profile}" >&2 unset _rdk_dds_profile return 1 fi export ROS_DOMAIN_ID=22 export RMW_IMPLEMENTATION=rmw_fastrtps_cpp export ROS_LOCALHOST_ONLY=0 export FASTRTPS_DEFAULT_PROFILES_FILE="${_rdk_dds_profile}" export FASTDDS_DEFAULT_PROFILES_FILE="${_rdk_dds_profile}" printf 'DDS link enabled: domain=%s rmw=%s local=192.168.10.164 profile=%s\n' \ "${ROS_DOMAIN_ID}" "${RMW_IMPLEMENTATION}" "${_rdk_dds_profile}" unset _rdk_dds_profile ``` 设置权限: ```bash chmod 0644 /home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml chmod 0755 /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh ``` - [ ] **Step 4:验证语法和 Fast DDS 实际加载** ```bash bash -n /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh python3 -c "import xml.etree.ElementTree as ET; ET.parse('/home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml'); print('XML well-formed')" source /opt/ros/humble/setup.bash source /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh python3 -c "import rclpy; rclpy.init(); n=rclpy.create_node('rdk_dds_profile_check'); print('RMW participant created'); n.destroy_node(); rclpy.shutdown()" ``` Expected:依次输出 `XML well-formed`、环境摘要和 `RMW participant created`,stderr 中没有 XML profile 或 transport 错误。 - [ ] **Step 5:记录 RDKx5 文件内容与校验值** ```bash sha256sum \ /home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml \ /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh ``` 用 `apply_patch` 在本文件的实施记录中加入两个文件的完整内容、权限、SHA-256 和 Step 4 的结果。 - [ ] **Step 6:只提交 RDKx5 配置和文档** ```bash cd /home/sunrise/yiliao_ws git add -- \ config/dds/fastdds_rdk_164.xml \ config/dds/use_rdk_dds_164.sh \ docs/crucial_change/2026-07-23-fastdds-164-network-change.md git diff --cached --check git diff --cached --name-only git commit -m "feat: add dedicated Fast DDS 164 profile" -- \ config/dds/fastdds_rdk_164.xml \ config/dds/use_rdk_dds_164.sh \ docs/crucial_change/2026-07-23-fastdds-164-network-change.md ``` Expected:提交只包含上述三个路径。 ### Task 3:WSL Fast DDS 配置 **Files:** - Create: `/home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml` - Create: `/home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh` - Modify: `/home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md` - [ ] **Step 1:运行存在性测试并确认失败** ```bash test -f /home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml && \ test -f /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh ``` Expected:返回非零,因为两个文件尚未创建。 - [ ] **Step 2:创建 WSL XML** 创建目录 `/home/hikos/Yiliao2026/config/dds`: ```bash mkdir -p /home/hikos/Yiliao2026/config/dds ``` 然后用 `apply_patch` 创建 `fastdds_wsl_151.xml`,完整内容为: ```xml wsl_udp_151 UDPv4
192.168.10.151
wsl_shm SHM
192.168.10.164
wsl_udp_151 wsl_shm false
``` - [ ] **Step 3:创建 WSL 环境脚本** 用 `apply_patch` 创建 `use_wsl_dds_164_link.sh`,完整内容为: ```bash #!/usr/bin/env bash if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then echo "ERROR: source this file instead of executing it" >&2 exit 64 fi _wsl_dds_profile="/home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml" if ! ip -4 addr show dev eth4 2>/dev/null | grep -q 'inet 192\.168\.10\.151/'; then echo "ERROR: eth4 does not own 192.168.10.151" >&2 unset _wsl_dds_profile return 1 fi if [[ ! -r "${_wsl_dds_profile}" ]]; then echo "ERROR: unreadable Fast DDS profile: ${_wsl_dds_profile}" >&2 unset _wsl_dds_profile return 1 fi export ROS_DOMAIN_ID=22 export RMW_IMPLEMENTATION=rmw_fastrtps_cpp export ROS_LOCALHOST_ONLY=0 export FASTRTPS_DEFAULT_PROFILES_FILE="${_wsl_dds_profile}" export FASTDDS_DEFAULT_PROFILES_FILE="${_wsl_dds_profile}" printf 'DDS link enabled: domain=%s rmw=%s local=192.168.10.151 peer=192.168.10.164 profile=%s\n' \ "${ROS_DOMAIN_ID}" "${RMW_IMPLEMENTATION}" "${_wsl_dds_profile}" unset _wsl_dds_profile ``` 设置权限: ```bash chmod 0644 /home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml chmod 0755 /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh ``` - [ ] **Step 4:验证语法和 Fast DDS 实际加载** ```bash bash -n /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh python3 -c "import xml.etree.ElementTree as ET; ET.parse('/home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml'); print('XML well-formed')" source /opt/ros/humble/setup.bash source /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh python3 -c "import rclpy; rclpy.init(); n=rclpy.create_node('wsl_dds_profile_check'); print('RMW participant created'); n.destroy_node(); rclpy.shutdown()" ``` Expected:依次输出 `XML well-formed`、环境摘要和 `RMW participant created`,stderr 中没有 XML profile 或 transport 错误。 - [ ] **Step 5:记录 WSL 文件并提交** ```bash sha256sum \ /home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml \ /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh cd /home/hikos/Yiliao2026 git add -- \ config/dds/fastdds_wsl_151.xml \ config/dds/use_wsl_dds_164_link.sh git diff --cached --check git diff --cached --name-only git commit -m "feat: bind WSL Fast DDS to 192.168.10.151" -- \ config/dds/fastdds_wsl_151.xml \ config/dds/use_wsl_dds_164_link.sh git rev-parse HEAD ``` Expected:提交只包含两个 WSL 配置文件。用 `apply_patch` 把文件完整内容、权限、SHA-256、加载验证结果和 WSL commit 写入 RDKx5 的唯一变更文档,然后单独提交该文档: ```bash cd /home/sunrise/yiliao_ws git add -- docs/crucial_change/2026-07-23-fastdds-164-network-change.md git diff --cached --check git diff --cached --name-only git commit -m "docs: record WSL Fast DDS deployment" -- \ docs/crucial_change/2026-07-23-fastdds-164-network-change.md ``` Expected:RDKx5 本次提交只包含该 Markdown 文档。 ### Task 4:双向通信与网卡检查 **Files:** - Modify: `/home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md` - [ ] **Step 1:清理 ROS 2 daemon 并加载双方环境** RDKx5: ```bash source /opt/ros/humble/setup.bash source /home/sunrise/yiliao_ws/install/setup.bash source /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh ros2 daemon stop || true ``` WSL: ```bash source /opt/ros/humble/setup.bash source /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh ros2 daemon stop || true ``` Expected:两个终端显示 Domain 22、Fast DDS 和各自本地专用地址。 - [ ] **Step 2:验证 WSL 到 RDKx5** 先在 RDKx5 运行: ```bash timeout 20 ros2 topic echo /dds_164_smoke_20260723 std_msgs/msg/String --once ``` 随后在 WSL 运行: ```bash ros2 topic pub --once /dds_164_smoke_20260723 std_msgs/msg/String "{data: wsl_to_rdk}" ``` Expected:RDKx5 输出 `data: wsl_to_rdk`。 - [ ] **Step 3:验证 RDKx5 到 WSL** 先在 WSL 运行: ```bash timeout 20 ros2 topic echo /dds_164_smoke_return_20260723 std_msgs/msg/String --once ``` 随后在 RDKx5 运行: ```bash ros2 topic pub --once /dds_164_smoke_return_20260723 std_msgs/msg/String "{data: rdk_to_wsl}" ``` Expected:WSL 输出 `data: rdk_to_wsl`。 - [ ] **Step 4:确认 DDS 使用 `.164` 而非 `.210`** 在 RDKx5 两个终端同时开始短抓包: ```bash sudo timeout 15 tcpdump -ni wlx200db0c3fca5 -c 5 'udp and host 192.168.10.151' ``` ```bash sudo timeout 15 tcpdump -ni wlan0 -c 1 'udp and host 192.168.10.151' ``` 抓包期间重复 Step 2 的一次发布。Expected:`wlx200db0c3fca5` 捕获到 UDP;`wlan0` 超时且捕获 `0 packets`。当前 SSH 命令仍能返回: ```bash ssh sunrise@192.168.10.210 'echo management-link-ok' ``` - [ ] **Step 5:记录并提交精简验证结果** 用 `apply_patch` 写入双向消息结果、两张网卡的抓包摘要和 `management-link-ok`。如果任一步失败,停止到 Task 6 的快速回滚,不启动 Nav2。 ```bash cd /home/sunrise/yiliao_ws git add -- docs/crucial_change/2026-07-23-fastdds-164-network-change.md git diff --cached --check git commit -m "docs: record dedicated DDS link verification" -- \ docs/crucial_change/2026-07-23-fastdds-164-network-change.md ``` ### Task 5:实际 `obstacle_nav2` 最小验证 **Files:** - Modify: `/home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md` - [ ] **Step 1:安全启动 Nav2** 在已加载 RDKx5 专用 DDS 环境的终端运行: ```bash ros2 launch obstacle_nav2 obstacle_nav2.launch.py enable_motion:=false ``` Expected:launch 启动,真实底盘速度输出仍映射到 `/cmd_vel_disabled`。 - [ ] **Step 2:WSL 检查关键话题** 在已加载 WSL 专用 DDS 环境的终端运行: ```bash ros2 topic list | grep -E '^/obstacles$|^/local_costmap/costmap$|^/global_costmap/costmap$' ``` Expected:至少出现 `/obstacles`,并出现 local/global costmap 话题;如果当前 Nav2 使用 `costmap_raw` 命名,则记录实际名称,不修改 Nav2 参数。 - [ ] **Step 3:结束测试并记录结果** 使用 `Ctrl+C` 正常停止本次 launch。用 `apply_patch` 记录启动命令、关键话题、停止方式和最终结论;不执行运动目标、不修改 costmap 参数。 - [ ] **Step 4:提交最终记录** ```bash cd /home/sunrise/yiliao_ws git add -- docs/crucial_change/2026-07-23-fastdds-164-network-change.md git diff --cached --check git commit -m "docs: finalize Fast DDS 164 deployment record" -- \ docs/crucial_change/2026-07-23-fastdds-164-network-change.md ``` ### Task 6:回滚演练说明与最终核对 **Files:** - Modify: `/home/sunrise/yiliao_ws/docs/crucial_change/2026-07-23-fastdds-164-network-change.md` - [ ] **Step 1:写明快速回滚命令** 停止由专用环境启动的 ROS 节点后,在当前终端执行: ```bash unset FASTRTPS_DEFAULT_PROFILES_FILE unset FASTDDS_DEFAULT_PROFILES_FILE unset RMW_IMPLEMENTATION unset ROS_LOCALHOST_ONLY export ROS_DOMAIN_ID=22 ``` 推荐的实际快速回滚方式是关闭该终端并新开终端,避免残留环境变量。将上述命令原样保存在实施记录中。 - [ ] **Step 2:写明文件级回滚命令,但成功时不执行** 只有用户要求撤销或部署失败时才执行。执行前分别确认四个绝对路径仍位于批准目录,然后删除具体文件,不递归删除工作空间: ```bash rm -- \ /home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml \ /home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh rmdir --ignore-fail-on-non-empty /home/sunrise/yiliao_ws/config/dds ``` ```bash rm -- \ /home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml \ /home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh rmdir --ignore-fail-on-non-empty /home/hikos/Yiliao2026/config/dds ``` - [ ] **Step 3:最终范围核对** ```bash git -C /home/sunrise/yiliao_ws status --short git -C /home/sunrise/yiliao_ws log -5 --oneline git -C /home/hikos/Yiliao2026 status --short git -C /home/hikos/Yiliao2026 log -3 --oneline ``` Expected:新提交只涉及四个 DDS 配置文件和本 Markdown;原有 dirty files 仍保持原状态,未被暂存、修改或清理。 ## 实施记录 ### 实施前基线 - 实施日期:2026-07-23(Asia/Shanghai) - 用户已明确允许直接在 RDKx5 `master` 和 WSL `zbw` 当前分支实施,并要求仅按明确路径提交。 - 四个目标配置文件在实施前均不存在,未覆盖任何已有文件。 - RDKx5: - `wlx200db0c3fca5` 为 `UP`,地址 `192.168.10.164/24`。 - `wlan0` 为 `UP`,地址 `192.168.10.210/24`。 - 默认路由优先使用 `wlan0`(metric 600),`.164` 网卡 metric 为 601。 - `~/.bashrc:141` 为 `export ROS_DOMAIN_ID=22`。 - 当前 RMW 为 `rmw_fastrtps_cpp`。 - 实施开始时仓库已有用户内容:`?? src/origincar_birdseye/`。 - WSL: - `eth4` 为 `UP`,地址 `192.168.10.151/24`。 - `ip route get 192.168.10.164` 的结果为 `dev eth4 src 192.168.10.151`。 - 当前 RMW 为 `rmw_fastrtps_cpp`。 - 实施开始时仓库已有用户内容:`.vscode/browse.vc.db*` 修改,以及 `.codex`、`resource/`、`src/navigation/`、`src/obstacle_scanner/`、`src/origincar_birdseye/`、`src/third_party/`、`tf_bag/` 等未跟踪路径。 - 本任务不会暂存、修改或清理上述已有用户内容。 ### RDKx5 配置实施结果 - 新增目录:`/home/sunrise/yiliao_ws/config/dds/` - `/home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml` - 权限:`0644` - SHA-256:`f6714ed471930500bc42d5100113782fb585ce50d48326118a0d0a3c8903d1be` - `/home/sunrise/yiliao_ws/config/dds/use_rdk_dds_164.sh` - 权限:`0755` - SHA-256:`5b40b2d3c61bd9d7eedfdb11ef1bb43dd60b3cdbb67ddcb1e2da01ab79996059` XML 完整内容: ```xml rdk_udp_164 UDPv4
192.168.10.164
rdk_shm SHM
192.168.10.151
rdk_udp_164 rdk_shm false
``` 环境脚本完整内容: ```bash #!/usr/bin/env bash if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then echo "ERROR: source this file instead of executing it" >&2 exit 64 fi _rdk_dds_profile="/home/sunrise/yiliao_ws/config/dds/fastdds_rdk_164.xml" if ! ip -4 addr show dev wlx200db0c3fca5 2>/dev/null | grep -q 'inet 192\.168\.10\.164/'; then echo "ERROR: wlx200db0c3fca5 does not own 192.168.10.164" >&2 unset _rdk_dds_profile return 1 fi if [[ ! -r "${_rdk_dds_profile}" ]]; then echo "ERROR: unreadable Fast DDS profile: ${_rdk_dds_profile}" >&2 unset _rdk_dds_profile return 1 fi export ROS_DOMAIN_ID=22 export RMW_IMPLEMENTATION=rmw_fastrtps_cpp export ROS_LOCALHOST_ONLY=0 export FASTRTPS_DEFAULT_PROFILES_FILE="${_rdk_dds_profile}" export FASTDDS_DEFAULT_PROFILES_FILE="${_rdk_dds_profile}" printf 'DDS link enabled: domain=%s rmw=%s local=192.168.10.164 profile=%s\n' \ "${ROS_DOMAIN_ID}" "${RMW_IMPLEMENTATION}" "${_rdk_dds_profile}" unset _rdk_dds_profile ``` 验证结果: - `bash -n`:通过。 - XML well-formed:通过。 - Fast DDS/RMW participant 实际创建:通过,输出 `RMW participant created`。 - 环境摘要:Domain `22`、RMW `rmw_fastrtps_cpp`、本地 DDS 地址 `.164`。 - 首次从 PowerShell 直接拼接远端 `python3 -c` 时,引号在 SSH 边界被破坏,Python 在读取 XML 前即报 `SyntaxError`。该失败与 XML 内容无关,未修改配置;改为通过 WSL Bash 和 stdin 传入验证程序后,相同验证完整通过。 ### WSL 配置实施结果 - 新增目录:`/home/hikos/Yiliao2026/config/dds/` - `/home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml` - 权限:`0644` - SHA-256:`bcf9c6e8e8b724cda1c6d83f02491ae0ad9ad7faec5be5dc01b8d60ea826d7ba` - `/home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh` - 权限:`0755` - SHA-256:`7fe539eab3ddaa5b79a32145cd1d10834468ae47a73de239944b34c61be61f52` - WSL Git commit:`b8840ec94bca8668f7d56d80b75c9db0298d18a3`,该提交只包含上述两个文件。 XML 完整内容: ```xml wsl_udp_151 UDPv4
192.168.10.151
wsl_shm SHM
192.168.10.164
wsl_udp_151 wsl_shm false
``` 环境脚本完整内容: ```bash #!/usr/bin/env bash if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then echo "ERROR: source this file instead of executing it" >&2 exit 64 fi _wsl_dds_profile="/home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml" if ! ip -4 addr show dev eth4 2>/dev/null | grep -q 'inet 192\.168\.10\.151/'; then echo "ERROR: eth4 does not own 192.168.10.151" >&2 unset _wsl_dds_profile return 1 fi if [[ ! -r "${_wsl_dds_profile}" ]]; then echo "ERROR: unreadable Fast DDS profile: ${_wsl_dds_profile}" >&2 unset _wsl_dds_profile return 1 fi export ROS_DOMAIN_ID=22 export RMW_IMPLEMENTATION=rmw_fastrtps_cpp export ROS_LOCALHOST_ONLY=0 export FASTRTPS_DEFAULT_PROFILES_FILE="${_wsl_dds_profile}" export FASTDDS_DEFAULT_PROFILES_FILE="${_wsl_dds_profile}" printf 'DDS link enabled: domain=%s rmw=%s local=192.168.10.151 peer=192.168.10.164 profile=%s\n' \ "${ROS_DOMAIN_ID}" "${RMW_IMPLEMENTATION}" "${_wsl_dds_profile}" unset _wsl_dds_profile ``` 验证结果: - `bash -n`:通过。 - XML well-formed:通过。 - Fast DDS/RMW participant 实际创建:通过,输出 `RMW participant created`。 - 环境摘要:Domain `22`、RMW `rmw_fastrtps_cpp`、本地 DDS 地址 `.151`、peer `.164`。 - WSL 提交命令在工具等待窗口内没有返回,但后台提交随后正常完成;复核 commit `b8840ec9` 只包含两个批准的配置文件,原有 `.vscode` 暂存内容未进入该提交。 ### 实施偏差:WSL 接口名不稳定 - 发现时间:2026-07-23 双向通信复核期间。 - 复现:WSL 重启前 `.151` 位于 `eth4`;重启后仍为 `192.168.10.151/24`,但接口名变为 `eth3`。原脚本执行时返回 `ERROR: eth4 does not own 192.168.10.151`。 - 根因:WSL 镜像网络接口编号会在实例重启后变化,接口名不是稳定标识。 - 修正:WSL 环境脚本不再要求接口名为 `eth4`,改为在所有本地 IPv4 接口中查找 `192.168.10.151/`。Fast DDS XML 仍按稳定 IP `.151` 建立 interface whitelist,网络约束不变。 - 范围:只修改 `/home/hikos/Yiliao2026/config/dds/use_wsl_dds_164_link.sh` 的前置检查和错误文本;不修改 XML、路由表、RDKx5 配置或 ROS package。 - 失败保护:如果 `.151` 在任何接口上都不存在,脚本仍返回非零并拒绝启用 DDS 环境。 ### 实施偏差:关闭 Domain 22 内建发现多播 - 发现时间:2026-07-23 受控双向通信与双网卡抓包期间。 - 受控条件:测试前 RDKx5 无其他 Domain 22 socket;RDK 测试 participant 的 UDP socket 只绑定 `.164`,WSL 测试 participant 只绑定 `.151`。 - 消息结果:WSL 到 RDKx5 发布/订阅成功。 - 抓包结果:`.164` 捕获 189 个 Domain 22 包;`.210` 捕获 3 个包,三者均为 WSL `.151` 发往 `239.255.0.1:12900` 的 SPDP 多播,没有发往 `.210` 的 Domain 22 单播。 - 根因:配置 initial peer 不会自动关闭 Fast DDS 内建发现多播;同一局域网中的两张 RDKx5 网卡都会收到该多播帧。 - 修正:在 RDKx5 和 WSL profile 的 `` 中加入 `true`,保留双端 initial peer 进行单播发现。 - 范围:只修改两个已批准的 Fast DDS XML;不修改系统网卡的多播设置、路由、防火墙或 ROS package。 - 修正后的必要验收:双向消息仍成功,`.164` Domain 22 抓包大于零,`.210` Domain 22 抓包为零。 ### WSL 接口名修正结果 - 修正提交:`9349f53cbc78851d9d053799af26f8055f58f9d3` - 修正后脚本 SHA-256:`4dd272d34bbc480e7f5d112348fad7bb59532f155cdabbdc7e7b98dda7ff6155` - 当前 WSL 接口为 `eth3`、地址仍为 `.151` 时,脚本加载通过。 - 实际 participant socket 为 `.151:12900`、`.151:12910`、`.151:12911` 及 `.151` 上的自定义 UDP socket,没有绑定 WSL 的其他地址。 修正后脚本完整内容: ```bash #!/usr/bin/env bash if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then echo "ERROR: source this file instead of executing it" >&2 exit 64 fi _wsl_dds_profile="/home/hikos/Yiliao2026/config/dds/fastdds_wsl_151.xml" if ! ip -o -4 addr show 2>/dev/null | grep -q 'inet 192\.168\.10\.151/'; then echo "ERROR: no local IPv4 interface owns 192.168.10.151" >&2 unset _wsl_dds_profile return 1 fi if [[ ! -r "${_wsl_dds_profile}" ]]; then echo "ERROR: unreadable Fast DDS profile: ${_wsl_dds_profile}" >&2 unset _wsl_dds_profile return 1 fi export ROS_DOMAIN_ID=22 export RMW_IMPLEMENTATION=rmw_fastrtps_cpp export ROS_LOCALHOST_ONLY=0 export FASTRTPS_DEFAULT_PROFILES_FILE="${_wsl_dds_profile}" export FASTDDS_DEFAULT_PROFILES_FILE="${_wsl_dds_profile}" printf 'DDS link enabled: domain=%s rmw=%s local=192.168.10.151 peer=192.168.10.164 profile=%s\n' \ "${ROS_DOMAIN_ID}" "${RMW_IMPLEMENTATION}" "${_wsl_dds_profile}" unset _wsl_dds_profile ``` ### 关闭发现多播的文件结果 - RDKx5 XML: - 新 SHA-256:`9c7acb168af9eacd93b41e03e02f8554570c94853ab5cd485782ba9483b72be8` - commit:`e7c3fe9` - WSL XML: - 新 SHA-256:`990904e92ff54c76e04b70a7aa27fc9331484b2292635f1c22dddaeb0b16d52d` - commit:`4b11f35` - 两个 XML 均只在 `` 下新增: ```xml true ``` - 两端 XML well-formed 检查通过,Fast DDS/RMW participant 实际创建通过,没有 profile 或 transport 解析错误。 ### 双向与网卡验证过程 1. 首次使用 `ros2 topic` CLI 测试时,既有 Domain 0 daemon 干扰等待逻辑,改用不依赖 CLI daemon 的临时 `rclpy` 发布/订阅节点。 2. 关闭发现多播前的受控测试:双向消息成功,`.164` 捕获 189 个 Domain 22 包,`.210` 只捕获 3 个 SPDP 多播包,没有 `.210` 单播。 3. 关闭发现多播后的首次重测开始前,RDKx5 上出现一套由其他终端启动的未配置 `obstacle_nav2`,其 Domain 22 socket 绑定 `0.0.0.0`,破坏了“无其他 participant”的受控前提。该次消息超时不作为 XML 结论。 4. 当前运行命令确认为 `ros2 launch obstacle_nav2 obstacle_nav2.launch.py enable_motion:=true`,来源终端 `pts/3`;进程环境只有 `ROS_DOMAIN_ID=22`、`ROS_LOCALHOST_ONLY=0`,没有 Fast DDS profile 变量。 5. 因该 launch 已启用真实运动,实施者未擅自终止。最终双向和双网卡验证等待该 launch 停止,或获得明确授权后用专用 DDS 环境重新启动。 ### 双向与网卡最终验证结果 - 用户在收到“需要停止或明确授权”的说明后指示继续;实施者对 PID `12541` 的 `enable_motion:=true` launch 发送一次 `SIGINT`。 - launch 在正常清理后退出,复核子进程数为 `0`;未终止其父 shell,未修改启动文件。 - 在 RDKx5 无其他 Domain 22 participant 的受控条件下: - RDK 测试 participant socket 只绑定 `.164`。 - WSL 测试 participant socket 只绑定 `.151`。 - WSL -> RDKx5:收到 `wsl_to_rdk`。 - RDKx5 -> WSL:收到 `rdk_to_wsl`。 - 抓包探针消息 `capture_probe` 收到。 - `wlx200db0c3fca5` 的 Domain 22 抓包:`163 packets captured`。 - `wlan0` 的 Domain 22 抓包:`0 packets captured`。 - `.210` SSH 返回 `management-link-ok`。 - 结论:对从专用环境启动的 Domain 22 participant,跨主机 DDS 数据只使用 WSL `.151` 与 RDKx5 `.164`,`.210` 保持为管理链路。