D1 ROS 2 开机服务与跨主机发现配置
D1 机器人 ROS 2 开机自启动、Cyclone DDS 网络发现,以及开发主机连接机器人的配置方法。
配置目标
机器人开机后自动启动 ROS 2 服务。
机器人统一使用 ROS Domain ID
69(例子) 和 Cyclone DDS。开发主机通过有线网络发现机器人 ROS 2 节点。
避免 ROS 2 daemon 使用错误的 RMW 实现。
避免开机时
eth0尚未就绪导致节点启动失败。
网络参数
设备 |
网卡 |
IPv4 地址 |
ROS Domain ID |
RMW 实现 |
|---|---|---|---|---|
D1 机器人 |
|
|
|
|
开发主机 |
|
|
|
|
开始配置前确认主机可以访问机器人:
ping -c 3 192.168.19.90
机器人 ROS 2 环境
机器人登录 shell 使用 /opt/d1_ros2/env.sh 统一加载 ROS 2 环境。在 /home/robot/.bashrc 末尾添加:
# D1 ROS 2 environment
source /opt/d1_ros2/env.sh
不要再单独配置 /opt/ros/humble/setup.bash 和 ROS_DOMAIN_ID,避免登录 shell 与 systemd 服务使用不同的 RMW 配置。
/opt/d1_ros2/ros2.env 的关键配置如下:
ROS_DOMAIN_ID=69
ROS_LOCALHOST_ONLY=0
ROS_LOG_LEVEL=DEBUG
RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
CYCLONEDDS_URI=file:///opt/d1_ros2/cyclonedds.xml
Cyclone DDS 网络配置
编辑机器人 /opt/d1_ros2/cyclonedds.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd">
<Domain>
<General>
<Interfaces>
<NetworkInterface name="eth0" priority="default" multicast="true" />
</Interfaces>
<AllowMulticast>true</AllowMulticast>
</General>
<Discovery>
<ParticipantIndex>auto</ParticipantIndex>
<MaxAutoParticipantIndex>99</MaxAutoParticipantIndex>
</Discovery>
</Domain>
</CycloneDDS>
如果配置为 lo,ROS 2 节点只能在机器人本机发现,外部开发主机无法发现机器人 topic。
systemd 开机服务
机器人使用以下三个服务:
服务 |
启动内容 |
|---|---|
|
系统状态与基础设备节点 |
|
主控制器与机器人状态发布节点 |
|
指令网关与遥控相关节点 |
服务启动顺序为:
d1_system.service
↓
d1_bringup.service
↓
d1_command.service
等待 eth0 就绪
Cyclone DDS 指定 eth0 后,服务必须等待网卡获得 IPv4 地址。分别创建:
/etc/systemd/system/d1_system.service.d/wait-for-eth0.conf
/etc/systemd/system/d1_bringup.service.d/wait-for-eth0.conf
/etc/systemd/system/d1_command.service.d/wait-for-eth0.conf
三个文件内容相同:
[Unit]
Wants=network-online.target
After=network-online.target NetworkManager-wait-online.service
[Service]
ExecStartPre=/usr/bin/timeout 60 /bin/bash -c 'until /usr/sbin/ip -4 -o address show dev eth0 scope global | /usr/bin/grep -q "inet "; do /usr/bin/sleep 1; done'
应用配置:
sudo systemctl daemon-reload
sudo systemctl enable d1_system.service
sudo systemctl enable d1_bringup.service
sudo systemctl enable d1_command.service
按依赖顺序重启:
sudo systemctl stop d1_command.service d1_bringup.service d1_system.service
sudo systemctl start d1_system.service
sudo systemctl start d1_bringup.service
sudo systemctl start d1_command.service
开发主机配置
在开发主机 /home/example/.bashrc 末尾添加:
source /opt/ros/humble/setup.bash
export ROS_DOMAIN_ID=69
export ROS_LOCALHOST_ONLY=0
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
应用并确认配置:
source ~/.bashrc
echo "$ROS_DOMAIN_ID"
echo "$ROS_LOCALHOST_ONLY"
echo "$RMW_IMPLEMENTATION"
预期输出:
69
0
rmw_fastrtps_cpp
ROS 2 daemon 刷新
如果修改环境后仍看不到机器人 topic,停止旧 daemon 并重新启动:
ros2 daemon stop
ros2 daemon start
ros2 topic list
也可以绕过 daemon 直接检查 DDS 发现结果:
ros2 topic list --no-daemon
正常情况下可以看到带机器人命名空间的 topic,例如:
/d15039751/joint_states
/d15039751/robot_description
/d15039751/command/cmd_twist
/d15039751/system_status_broadcaster/diagnostic
/tf
/tf_static
状态检查
在机器人上检查服务:
systemctl is-enabled d1_system.service d1_bringup.service d1_command.service
systemctl is-active d1_system.service d1_bringup.service d1_command.service
查看本次开机日志:
journalctl -b -u d1_system.service \
-u d1_bringup.service \
-u d1_command.service --no-pager
检查网卡和控制器:
ip -4 -br address show dev eth0
source /opt/d1_ros2/env.sh
ros2 control list_controllers -c /d15039751/controller_manager
ros2 control list_controllers -c /d15039751/command_manager
常见问题
只能看到 /parameter_events 和 /rosout
通常是 ROS 2 daemon 使用了错误的 RMW 实现。检查 daemon:
pgrep -af ros2-daemon
机器人应显示:
--ros-domain-id 69 --rmw-implementation rmw_cyclonedds_cpp
重新加载环境并刷新 daemon:
source /opt/d1_ros2/env.sh
ros2 daemon stop
ros2 daemon start
当前主机看不到机器人 topic
首先检查当前终端,而不是只检查 .bashrc 文件:
echo "$ROS_DOMAIN_ID"
如果输出为 42,说明当前终端仍然保留旧环境。执行:
source ~/.bashrc
ros2 daemon stop
ros2 daemon start
eth0: does not match an available interface
该错误表示服务启动时 eth0 尚未创建或尚未获得 IPv4 地址。确认三个 systemd drop-in 文件已经安装,然后执行:
sudo systemctl daemon-reload
sudo systemctl restart d1_system.service
sudo systemctl restart d1_bringup.service
sudo systemctl restart d1_command.service