注意#
本节操作较为复杂,如有不理解的地方可以跳转到文末的配套讲解视频进行辅助学习。
简介#
在前面的仿真系列和 MAVROS2 真机文章中,我们分别介绍了仿真环境搭建和基于 MAVROS2 的 真机Offboard 控制。PX4 从 v1.14 版本开始,官方推荐使用 uXRCE-DDS 中间件替代 MAVROS,作为 ROS2 与 PX4 之间的通信桥梁。
本文以 Pixhawk 6C(官方飞控板)和 Nvidia Jetson Orin NX(机载电脑)为例,完整演示如何在真机上部署 uXRCE-DDS 中间件。内容包括:
- uXRCE-DDS 架构原理(Client/Agent 模型、DDS 全局数据空间)
- PX4 固件烧录(命令行
make upload+ 地面站两种方式) - 飞控端串口参数配置与 uXRCE-DDS Client 启用
- 机载电脑 WiFi 热点自动启动配置
- Agent 启动与连通性测试
- 常见问题排查
前提条件:本文假设读者已按照 ROS2+PX4 仿真环境开发教程 完成仿真环境搭建,并按 ROS2 真机实践:为机载电脑刷机 完成机载电脑的 Ubuntu 22.04 刷机。如果你是第一次接触 PX4 真机,建议先阅读 使用机载电脑控制 PX4 无人机(MAVROS2) 了解真机操作的基本流程。
uXRCE-DDS 架构原理#
为什么用 DDS 替代 MAVROS?#
在 ROS1 时代和 ROS2 早期,MAVROS 是连接 ROS 与 PX4 飞控的标准方案。但 MAVROS 本质上是一个协议桥接器——它将飞控端的 MAVLink 协议”翻译”成 ROS 话题,这意味着:
- 你需要发布/订阅
mavros命名空间下的专用话题(如/mavros/setpoint_position/local) - 系统中需要一个中心化的 MAVROS 节点来维护所有通信映射(在ROS1时代的ROS_Master)
- 在多机场景中扩展性受限
uXRCE-DDS 采用完全不同的思路。它基于 DDS(Data Distribution Service)——一种去中心化的实时数据分发协议,让 PX4 内部的 uORB 话题直接映射为 ROS2 话题。这带来的好处:
- 原生 ROS2 话题:飞控的传感器数据直接以 ROS2 标准话题发布,无需 MAVROS 转译层。之前在仿真中写的 Offboard 控制代码可以直接搬到真机上用,话题名都不需要改。
- 分布式架构:所有 ROS2 节点在同一个 DDS 数据空间中自动发现彼此,不存在单点瓶颈(没有 ROS1 时代的 Master 节点)。
- 低延迟:DDS 使用 UDP 多播和共享内存进行数据传输,延迟远低于 MAVLink 串行化开销。
Client/Agent 通信模型#
uXRCE-DDS 采用 Client-Agent 架构:
飞控端(Client):运行在 PX4 内部,负责将 uORB 话题的消息序列化为 DDS 格式。它只做一件事——把飞控内部的 uORB 消息桥接到 Agent。Client 本身不参与 DDS 发现、不维护拓扑。
机载电脑端(Agent):运行 Micro-XRCE-DDS-Agent(之前我们仿真中用 MicroXRCEAgent udp4 -p 8888 启动的那个),负责:
- 接收来自 Client 的串行化 uORB 消息
- 将它们发布到 ROS2 的 DDS 全局数据空间
- 从 DDS 空间接收 ROS2 控制指令并转发给 Client
DDS 全局数据空间(Global Data Space):只要 ROS2 节点运行在同一个 ROS_DOMAIN_ID 下,它们就能自动发现彼此的话题、服务和 action。你不需要手动配置任何连接关系——发布者和订阅者自动匹配。
ROS_DOMAIN_ID 的作用#
DDS 将同一个局域网内使用相同 ROS_DOMAIN_ID 的所有节点视为”在同一数据空间内”。可以用以下命令查看当前 domain ID:
echo $ROS_DOMAIN_IDbash如果输出为空,默认值为 0。在多机编队场景中,你可以为每组无人机-机载电脑分配不同的 domain ID 来隔离通信。只要 domain ID 一致且在同一局域网下,ROS2 节点之间就能互相发现——这正是分布式架构的核心优势。
硬件准备#
需要的硬件设备:
- Pixhawk 6C(或其他 PX4 原生飞控板,固件版本 ≥ v1.14)
- Nvidia Jetson Orin NX(或其他机载电脑,已刷 Ubuntu 22.04)
- USB-TypeC 线(连接飞控到本地电脑,用于烧录和参数配置)
- 杜邦线 ×3(连接飞控 TELEM2 到机载电脑 UART)
- 机载电脑供电线(12V)
- 飞控供电电池
- 数传模块(用于地面站,可选但强烈建议保留)
飞控固件版本要求:uXRCE-DDS 中间件在 PX4 v1.14 及以上版本的源码中才包含。目前最新稳定版已到 v1.16(26年7月已出现v1.17),建议使用最新版本。
PX4 固件烧录#
确保飞控固件版本 ≥ v1.14。如果已有的固件版本满足要求可以跳过本节,否则选择以下两种方式之一重新烧录。
方式一:命令行编译上传(推荐)#
克隆 PX4 源码并编译上传。这种方式适合已经搭建好 PX4 开发环境的读者。
cd ~/PX4-Autopilotbash在烧录之前,先确认飞控板对应的编译目标(board target)。Pixhawk 6C 的目标为 px4_fmu-v6c:
# 查看所有可用的编译目标
make list_config_targets | grep -i "v6c"bash确认飞控通过 USB-TypeC 连接到电脑后,查看串口:
ls -l /dev/ttyACM*
# 应输出类似 /dev/ttyACM0bash
使用 make upload 一键编译并烧录:
make px4_fmu-v6c uploadbash
# 查看串口参数,确认波特率为 115200
stty -F /dev/ttyACM0 115200 raw -echo
cat /dev/ttyACM0
# 按回车后出现 nsh> 提示符表示飞控正常运行bash常见问题:如果
make upload报权限错误,执行sudo usermod -a -G dialout $USER后重新登录。
方式二:QGroundControl 地面站烧录#
如果不想通过命令行编译,也可以用 QGC 直接烧录预编译固件。
- 打开 QGroundControl,通过 USB 连接飞控
- 进入 “Vehicle Setup” → “Firmware” 页面
- 拔掉 USB 再重新插入,QGC 会自动识别飞控型号
- 确认显示的版本号 ≥ v1.14,点击 “OK” 开始烧录
- 等待进度条完成
注意:地面站烧录会重置所有参数,如果之前配置过参数请先导出备份。
飞控端串口参数配置#
这一节是部署中最容易出错的环节——我们需要准确理解飞控内部串口的命名映射关系。
串口映射关系#
Pixhawk 6C 有三个 TELEM 端口,每个端口在飞控 NSH 内部对应不同的 TTY 设备:
| 物理端口 | 飞控内部 TTY | 默认用途 | 默认波特率 |
|---|---|---|---|
| TELEM1 | /dev/ttyS5 | 数传(MAVLink) | 57600 |
| TELEM2 | /dev/ttyS3 | 机载电脑 | 921600 |
| TELEM3 | /dev/ttyS0 | 备用 | — |
本文使用 TELEM2 连接机载电脑。TELEM2 的六针引脚排列为:VCC(5V)、TX、RX、PWM、GPIO、GND。我们只需要接三根线:
| TELEM2 引脚 | 连接到 | Jetson Orin NX UART2 引脚 |
|---|---|---|
| TX | → | Pin 10 (RX) |
| RX | → | Pin 8 (TX) |
| GND | → | Pin 6 (GND) |
不要连接 VCC!飞控和机载电脑各自独立供电。
不同机载电脑的 UART 引脚和 TTY 设备名不同。以 Jetson Orin NX 为例:
| UART | TX 引脚 | RX 引脚 | GND 引脚 | TTY 设备 |
|---|---|---|---|---|
| UART1(默认调试口) | Pin 8 | Pin 10 | Pin 6 | /dev/ttyTHS0 |
| UART2 | Pin 12 | Pin 14 | Pin 6 | /dev/ttyTHS1 |
本文使用 UART2(/dev/ttyTHS1),以保留 UART1 作为调试口。读者请根据自己的机载电脑型号查阅对应引脚图。
飞控通过 USB 连到本地电脑后,使用 mavlink_shell 工具进入飞控的 NSH 终端:
cd ~/PX4-Autopilot
./Tools/mavlink_shell.py /dev/ttyACM0:9600bash注意:进入 NSH 的波特率是 9600(不是 115200 也不是 921600)。如果之前 QGC 占用了串口,需要先关闭地面站。
进入后出现 nsh> 提示符。先用 mavlink status 查看当前 MAVLink 实例分配情况:
nsh> mavlink status
instance #0:
TX queue: ...
...
UART: /dev/ttyS5, 57600 baud ← TELEM1 (数传)
instance #1:
...
UART: /dev/ttyS3, 921600 baud ← TELEM2 (机载电脑)
instance #2:
...
UART: /dev/ttyACM0, 9600 baud ← USB (当前连接)plaintext可以看到飞控已自动为 TELEM2 分配了 MAVLink 实例 #1,波特率 921600。但我们需要让 TELEM2 走 uXRCE-DDS 而不是 MAVLink,否则两者会冲突。
查看当前 MAVLink 参数配置:
nsh> param show MAV_1_CONFIG
MAV_1_CONFIG = 102 ← 102 对应 TELEM2
nsh> param show MAV_1_MODE
MAV_1_MODE = 0 ← 0 = Normal (MAVLink)plaintext参数 102 是 TELEM2 的硬件端口编号。我们需要:
- 将
MAV_1_CONFIG设为 0(禁用该 MAVLink 实例) - 停止当前已在 TELEM2 (ttyS3) 上运行的 MAVLink 实例
# 1. 禁用 TELEM2 上的 MAVLink
param set MAV_1_CONFIG 0
# 2. 停止正在运行的 ttyS3 上的 MAVLink 实例
mavlink stop -d /dev/ttyS3bash再次检查 mavlink status,应只剩两个实例(TELEM1 + USB),TELEM2 的 MAVLink 已停下。
启用 uXRCE-DDS Client#
现在在 TELEM2 上启动 uXRCE-DDS Client:
nsh> uxrce_dds_client start -d /dev/ttyS3 -b 921600plaintext参数说明:
-d /dev/ttyS3:指定 TELEM2 对应的串口设备-b 921600:波特率,需与 MAV_1_RATE 保持一致
可选的命名空间参数:加
-n <namespace>可在所有发布的话题前添加命名空间前缀(如/px4_1/fmu/...),这在多机场景中区分不同飞控实例时非常有用。单机可以不指定。
设置 DDS 配置参数,确保 DDS Client 绑定正确的端口:
nsh> param set UXRCE_DDS_CFG 102plaintext为什么设为 102? 这个参数指定 uXRCE-DDS Client 应该绑定到哪个硬件端口。102 = TELEM2(与 MAV_1_CONFIG=102 对应同一个端口)。默认值为 0(未配置),需要显式设置。
验证 Client 已启动:
nsh> uxrce_dds_client status
# 输出应显示 running 状态,但此时尚未连接到 Agent("not connected" 是正常的)plaintext
# 飞控 NSH 中执行的完整命令序列
param set MAV_1_CONFIG 0 # 禁用 MAVLink on TELEM2
mavlink stop -d /dev/ttyS3 # 停止现有 MAVLink 实例
uxrce_dds_client start -d /dev/ttyS3 -b 921600 # 启动 uXRCE-DDS Client
param set UXRCE_DDS_CFG 102 # 绑定 DDS 到 TELEM2
uxrce_dds_client status # 验证状态bash硬件接线#
将飞控 TELEM2 的 TX、RX、GND 三根杜邦线连接到机载电脑 UART2 对应引脚:
| TELEM2 引脚 | 连接到 | Jetson Orin NX UART2 引脚 |
|---|---|---|
| TX | → | Pin 10 (RX) |
| RX | → | Pin 8 (TX) |
| GND | → | Pin 6 (GND) |
如果你使用 USB-TTL 转接线(方式类似 MAVROS 文章中的方法一),则机载电脑端走 /dev/ttyUSB0。下面以 UART 直连(/dev/ttyTHS1)为例。
机载电脑 WiFi 热点配置#
在实际飞行中,我们无法给机载电脑接显示器和键鼠,必须通过远程 SSH 操作。这就要求机载电脑和本地电脑在同一个局域网内。最可靠的方式是让机载电脑自己创建一个 WiFi 热点,本地电脑连接这个热点后通过固定 IP SSH 过去。
创建热点#
在机载电脑(Jetson Orin NX)上打开终端:
nm-connection-editorbash在弹出的图形界面中:
- 点击 ”+” → 选择 “Wi-Fi” → 点击 “Create”
- Connection name:任取,如
北航中法工程师学院是XX - SSID:与 Connection name 相同即可
- Mode:选择 Hotspot(热点模式)
- Wi-Fi Security:选择 “WPA & WPA2 Personal”,设置一个 8 位以上密码
- 切换到 IPv4 Settings 选项卡,Method 选择 “Manual”:
- Address:
192.168.10.1 - Netmask:
24 - Gateway:
192.168.10.1
- Address:
- IPv6 Settings:Method 选择 “Ignore”
- 点击 “Save”
设置开机自动启动热点#
首先删除之前保存的 WiFi 连接记录(防止上电后自动连到其他 WiFi):
# 列出所有已保存的连接
nmcli connection show
# 删除不需要的连接(保留刚创建的热点)
sudo nmcli connection delete "<旧 WiFi 名称>"bash将热点设为自动连接:
nmcli connection modify "北航中法工程师学院是XX" connection.autoconnect yes
nmcli connection modify "北航中法工程师学院是XX" connection.autoconnect-priority 10bash激活热点:
nmcli connection up "北航中法工程师学院是XX"bash此时在本地电脑上搜索 WiFi,应能看到 北航中法工程师学院是XX 信号。连接后验证:
ping 192.168.10.1bash之后每次飞控上电 → 机载电脑供电 → 自动启动热点 → 本地电脑连接 → SSH:
ssh jetson@192.168.10.1bash启动 Agent 与连通测试#
连接前检查#
在 SSH 进入机载电脑后,先不要给飞控上电。执行以下准备步骤:
# 1. 将用户加入 dialout 组(防止串口权限问题)
sudo usermod -a -G dialout $USER
# 重新登录使生效
# 2. 查看可用的串口设备
ls -l /dev/ttyTHS*
# 应输出 /dev/ttyTHS1(UART2)bash确认机载电脑上已安装 Micro-XRCE-DDS-Agent(仿真环境中应该已装好,若未安装参考 ROS2+PX4 仿真环境开发教程 中 MicroXRCE-DDS Agent 安装部分)。
验证硬件连通性#
先测试飞控 → 机载电脑的串口通信是否正常。给飞控上电后,用 cat 检测是否有数据流:
stty -F /dev/ttyTHS1 921600 raw -echo
cat /dev/ttyTHS1bash如果出现乱码(MAVLink 或 uXRCE-DDS 二进制数据),说明物理连接和串口配置正确:
如果没有任何输出,请检查:
- 飞控 TELEM2 TX ↔ 机载电脑 UART RX 是否正确交叉连接
- 波特率是否匹配(飞控端和机载电脑端都应为 921600)
- 飞控端
uxrce_dds_client start是否已执行 - 是否被其他进程(如地面站)占用了串口
启动 Micro-XRCE-DDS-Agent#
# 激活 ROS2 环境
source /opt/ros/humble/setup.bash
# 启动 Agent,通过串口连接飞控
MicroXRCEAgent serial --dev /dev/ttyTHS1 -b 921600bash成功连接时,终端会输出类似以下信息:
[info] Serial agent starting...
[info] Connect to serial device: /dev/ttyTHS1, baudrate: 921600
[info] Connection established
[info] Client connected: 0x00000001
[info] Topic created: /fmu/out/vehicle_odometry
[info] Topic created: /fmu/out/imu
[info] Topic created: /fmu/out/...
...plaintext
至此,uXRCE-DDS 中间件部署完成。 Agent 会自动将飞控的 uORB 话题发布为 ROS2 话题。在另一个终端中验证:
source /opt/ros/humble/setup.bash
ros2 topic list | grep fmubash应看到大量 /fmu/out/... 开头的飞控数据话题。现在你的 ROS2 Offboard 控制代码可以直接在机载电脑上运行,话题名和仿真环境完全一致!
完整启动流程#
每次真机飞行前,按以下顺序操作:
- 本地电脑连接机载电脑热点
北航中法工程师学院是XX - 确认本地电脑能 ping 通
192.168.10.1 - 给飞控上电(通过电池),等待飞控启动完成
- 确认地面站(QGC)通过数传连接到飞控
- SSH 进入机载电脑:
ssh jetson@192.168.10.1 - 在 SSH 终端中启动 Agent:
source /opt/ros/humble/setup.bash
MicroXRCEAgent serial --dev /dev/ttyTHS1 -b 921600bash- 开另一个 SSH 终端,运行 ROS2 控制节点:
source /opt/ros/humble/setup.bash
source ~/ros2_ws/install/setup.bash
ros2 run offboard_control simple_offboard # 以之前的 Offboard 节点为例bash重要提示:根据经验,Agent 第一次连接成功后尽量保持飞控通电不断开。如果在飞行中反复断开重连串口,有时会导致后续连接失败。建议准备好后一次连通,中间不要改动。
参数速查表#
| 参数 | 值 | 说明 |
|---|---|---|
MAV_1_CONFIG | 0(禁用) | 将 TELEM2 上的 MAVLink 卸任 |
MAV_2_CONFIG | 101(TELEM1) | 数传保留在 TELEM1 |
UXRCE_DDS_CFG | 102(TELEM2) | DDS Client 绑定 TELEM2 |
SER_TEL2_BAUD | 921600 | TELEM2 波特率 |
uXRCE-DDS vs MAVROS 对比#
| uXRCE-DDS | MAVROS | |
|---|---|---|
| PX4 官方推荐 | v1.14+ 推荐 | 旧方案,仍在维护 |
| 话题命名 | 原生 ROS2 话题 | /mavros/ 命名空间 |
| 架构 | 去中心化 DDS | 中心化桥接 |
| 多机扩展 | DDS 自动发现 | 需手动配置 |
| 仿真/真机代码复用 | 话题完全一致,代码无需修改 | 需替换话题前缀 |
| 稳定性 | 仍在活跃开发 | 成熟稳定(ROS1 时代积累) |
| 真机延迟 | 低(UDP 多播) | 较低(MAVLink 串行化) |
建议:新项目优先选择 uXRCE-DDS。如果飞控固件版本 < v1.14 无法升级,或有大量遗留 MAVROS 代码需要兼容,可以继续使用 MAVROS。参考 使用机载电脑控制 PX4 无人机(MAVROS2)。
常见问题排查#
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| NSH 终端连接不上,串口被占用 | QGC 或其他进程占用了 ACM0 | 关闭 QGC 地面站后重试 |
uxrce_dds_client start 报错 | 波特率不匹配或 TELEM2 仍被 MAVLink 占用 | 确认 MAV_1_CONFIG=0,确认 mavlink stop -d /dev/ttyS3 已执行 |
| Agent 启动后一直是 “not connected” | UXRCE_DDS_CFG 未正确设置 | param set UXRCE_DDS_CFG 102 |
| cat /dev/ttyTHS1 无输出 | 接线错误或波特率不对 | 检查 TX/RX 是否交叉连接,波特率是否 921600 |
Agent 连上但 ros2 topic list 无 /fmu/ 话题 | ROS2 环境未 source 或 domain ID 不匹配 | source /opt/ros/humble/setup.bash,检查 echo $ROS_DOMAIN_ID |
| 串口设备名不是 ttyTHS1 | 使用了 UART 编号不同 | ls /dev/ttyTHS* 查看可用设备 |
总结#
本文完整演示了 Pixhawk 6C + Jetson Orin NX 上部署 uXRCE-DDS 中间件的全流程——从固件烧录、飞控 NSH 终端操作、MAVLink 卸任与 DDS Client 启用、硬件接线,到机载电脑热点配置和 Agent 启动。uXRCE-DDS 作为 PX4 官方推荐的 ROS2 通信方案,在代码复用性(仿真代码直接上真机)、扩展性(DDS 自动发现)和延迟方面都有显著优势。
当然,MAVROS 作为久经考验的老方案,在稳定性和社区文档积累上仍有其价值。读者可以根据自己的飞控固件版本和项目需求灵活选择。如果你同时使用两种方案进行对比测试,欢迎在评论区分享经验。
最后,感谢大家的耐心阅读,如有错漏请批评指正!
完整讲解视频#
如果下方视频加载较慢,可前往知乎观看:https://www.zhihu.com/zvideo/1981084557504701099 ↗