1. 为什么这套环境值得单独写一篇避坑指南
Jetson Orin 系列(Nano、NX、AGX Orin)配上 Intel RealSense D435i,再跑 ROS2,这套组合在机器人感知、机械臂抓取、SLAM 建图这些场景里出现频率极高。但真正动手搭过的人都知道,这不是"装个驱动就能跑"的事。Jetson 是 ARM64 架构,RealSense 官方对 x86 的支持远好于 ARM,ROS2 的版本又和 Ubuntu 版本强绑定,三个变量叠在一起,任何一个环节版本对不上,你面对的可能是编译到一半报错、rs-enumerate-devices找不到设备、或者 RViz2 里点云死活出不来。
我自己在 Orin Nano 和 Orin NX 上反复折腾过好几轮,从 JetPack 5.x 到 6.x,从 ROS2 Foxy 到 Humble,踩的坑基本能凑成一本小册子。这篇就把整个搭建链路拆开讲清楚:每一步为什么这么做、版本怎么选、报错怎么定位、哪些是 ARM 平台特有的坑。目标读者是刚拿到 Orin 开发板、想快速把 RealSense 跑进 ROS2 的工程师或者学生,有基本 Linux 命令基础就行,不需要你之前用过 ROS2。
需要先明确一个前提:Jetson 上的 RealSense 支持,核心难点不在 ROS2,而在 librealsense 这一层。ROS2 的realsense-ros包只是个封装,它调用的是底层 librealsense 的 SDK。如果 librealsense 在 ARM 上没编译对、没打上内核补丁,上层 ROS2 怎么配都是白搭。所以整篇文章的重心会放在 librealsense 的 ARM 编译和内核适配,ROS2 部分反而是相对标准化的流程。
另外提醒一句,Jetson 的 JetPack 版本决定了你的 Ubuntu 版本,Ubuntu 版本又决定了你能装哪个 ROS2 发行版,这是一条硬约束链,不能随意组合。下面先把这条链理清楚,再往下走。
2. 版本链条先锁死:JetPack、Ubuntu、ROS2 的对应关系
很多人一上来就apt install ros-humble-desktop,结果发现源里根本没有,或者装完和系统库冲突。根源就是没先确认版本对应关系。Jetson 不像普通 PC 可以随便换 Ubuntu,它的 Ubuntu 是随 JetPack 一起烧录的,你只能在这个基础上做选择。
2.1 JetPack 与 Ubuntu 的绑定
截至我写这篇时的实际情况,主流对应关系是这样的:
| JetPack 版本 | Ubuntu 版本 | 典型机型 | 推荐 ROS2 发行版 |
|---|---|---|---|
| JetPack 5.1.x | Ubuntu 20.04 | Orin Nano/NX/AGX | Foxy / Humble |
| JetPack 6.0/6.1 | Ubuntu 22.04 | Orin Nano/NX/AGX | Humble |
JetPack 5.x 基于 Ubuntu 20.04,官方 ROS2 支持到 Foxy 和 Humble(Humble 在 20.04 上属于非官方但可用)。JetPack 6.x 基于 Ubuntu 22.04,对应 ROS2 Humble,这是目前最省心的组合。如果你是新板子,我强烈建议直接上 JetPack 6.x + Humble,能避开一大堆依赖问题。
提示:先跑
cat /etc/nv_tegra_release确认 JetPack 版本,再跑lsb_release -a确认 Ubuntu 版本,两个都记下来再决定装哪个 ROS2。
2.2 为什么推荐 Humble 而不是 Foxy
Foxy 的生命周期在 2023 年就结束了,很多新包不再维护 Foxy 分支。而realsense-ros对 Humble 的支持最活跃,RealSense 官方仓库里 Humble 分支的更新频率明显高于 Foxy。如果你用的是 JetPack 6.x,那没得选,就是 Humble。如果是 JetPack 5.x,能上 Humble 就上 Humble,实在有历史项目依赖再退回 Foxy。
2.3 一个容易被忽略的约束:Python 版本
Ubuntu 20.04 默认 Python 3.8,Ubuntu 22.04 默认 Python 3.10。ROS2 的很多工具链(比如colcon、ros2cli)对 Python 版本敏感。如果你在 Orin 上装了 conda 或者自己编译过 Python,很容易出现ros2 command not found或者 import 报错。我的建议是:不要在系统 Python 上动刀,conda 环境要用就单独激活,别让它污染/usr/bin/python3。
3. librealsense 在 ARM64 上的编译:整个流程最容易翻车的地方
这是全文的核心章节,也是最容易卡住的地方。x86 上你可以直接apt install librealsense2-dev,但 ARM64 的 apt 源里要么没有,要么版本很老。所以基本都得从源码编译。而源码编译在 Jetson 上有几个特有的坑。
3.1 内核补丁:为什么 D435i 需要它
librealsense 要访问 RealSense 的深度流和 IMU,需要内核层面的支持。具体来说,它依赖几个内核模块(uvcvideo、hid_sensor_*等)的特定补丁,才能正确识别深度摄像头和 IMU 设备。x86 上 Ubuntu 官方内核已经打好了这些补丁,但 Jetson 用的是 NVIDIA 定制的 L4T 内核,默认不带这些补丁。
不打补丁会怎样?典型症状是:rs-enumerate-devices能看到设备,但只能出 RGB 流,深度流报错,IMU 完全找不到。或者干脆设备枚举都失败。
处理方式有两条路:
- 路线 A:打内核补丁重新编译内核模块。这是最彻底的做法,但耗时且风险高,编译内核模块在 Jetson 上可能要一两个小时,中途出错还可能影响系统启动。
- 路线 B:用
librealsense提供的patch-realsense-ubuntu-lts.sh脚本,它会自动下载对应内核版本的补丁并编译。但注意,这个脚本主要针对 Ubuntu 官方内核,Jetson 的 L4T 内核需要手动调整。
我的实际经验是:JetPack 6.x 的内核已经内置了大部分 RealSense 需要的支持,很多时候不打补丁也能跑起来深度流。所以建议先跳过补丁,直接编译 librealsense 测试,如果深度和 IMU 都正常,就不用折腾内核了。只有确实缺功能时再回头打补丁。
3.2 从源码编译 librealsense 的完整步骤
先装依赖。这一步在 ARM 上比 x86 多几个包,因为有些库 ARM 版本需要单独处理:
sudo apt-get update sudo apt-get install -y git cmake build-essential libssl-dev libusb-1.0-0-dev \ pkg-config libgtk-3-dev libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev \ libudev-dev libv4l-dev然后拉源码。关键点:选对版本 tag。不要直接 clone master,master 分支经常处于开发状态,编译失败率不低。选一个稳定的 release tag:
git clone https://github.com/IntelRealSense/librealsense.git cd librealsense git checkout v2.55.1 # 选一个稳定版本,别用 master编译配置。这里有个 ARM 特有的注意点:要显式指定不编译 CUDA 相关的东西(除非你确实要用),否则 CMake 可能去找 CUDA 路径然后报错:
mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release \ -DBUILD_EXAMPLES=true \ -DBUILD_GRAPHICAL_EXAMPLES=true \ -DFORCE_RSUSB_BACKEND=ON \ -DBUILD_WITH_CUDA=false关于FORCE_RSUSB_BACKEND这个选项,值得单独说一下。它让 librealsense 走 libusb 后端而不是 V4L2 后端。在没打内核补丁的情况下,这个选项往往是让深度流能跑起来的关键。代价是性能略低、CPU 占用略高,但换来的是不用折腾内核。对于开发和验证阶段,这个取舍完全值得。
编译。Jetson 的 CPU 核心数有限,Orin Nano 是 6 核,NX 是 8 核,AGX 是 12 核。用nproc看实际核心数:
make -j$(nproc) sudo make install sudo ldconfig编译时间参考:Orin Nano 上大约 20-40 分钟,NX 快一些。如果中途内存不够(Orin Nano 4GB 版本要注意),把-j后面的数字调小,比如-j4。
3.3 udev 规则:不装这个,普通用户权限访问不了设备
编译完别忘了装 udev 规则,否则每次都要 sudo 才能访问摄像头:
sudo cp config/99-realsense-libusb.rules /etc/udev/rules.d/ sudo udevadm control --reload-rules && sudo udevadm trigger装完拔插一次 USB,让规则生效。这一步很多人漏掉,然后抱怨"为什么 rs-enumerate-devices 要 sudo"。
3.4 验证 librealsense 是否真的装好了
在装 ROS2 之前,一定要先用rs-enumerate-devices验证底层。这是分界线:如果这一步不通,ROS2 那边一定不通,别浪费时间。
rs-enumerate-devices正常输出应该能看到 D435i 的型号、序列号、固件版本,以及支持的流配置。如果只看到设备但流列表为空,或者报No device connected,回到 3.1 和 3.2 检查。
还可以跑一下官方的 viewer 看实时画面:
realsense-viewer在 Jetson 上跑 viewer 需要接显示器或者用 VNC。如果 viewer 能出深度图和 RGB 图,说明底层完全 OK,可以进 ROS2 了。
注意:
realsense-viewer在 ARM 上启动可能比较慢,第一次加载要等十几秒,别以为卡死了。
4. ROS2 与 realsense-ros 的安装:标准化流程里的非标准细节
底层通了之后,ROS2 部分相对标准,但仍有几个 Jetson 特有的细节。
4.1 ROS2 Humble 的安装
如果 JetPack 6.x(Ubuntu 22.04),按官方流程装 Humble:
sudo apt install software-properties-common sudo add-apt-repository universe sudo apt update && sudo apt install curl -y sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \ -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \ http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | \ sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null sudo apt update sudo apt install ros-humble-desktop -y装完 source 一下:
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc验证:ros2 run demo_nodes_cpp talker能跑起来就说明 ROS2 本体没问题。
4.2 realsense-ros 的两种装法及取舍
方法一:apt 安装。Humble 的 apt 源里有ros-humble-realsense2-camera,装起来快:
sudo apt install ros-humble-realsense2-camera -y但问题在于,apt 版本依赖的 librealsense 版本可能和你源码编译的不一致,导致运行时找不到库或者 ABI 不匹配。如果你已经源码编译了 librealsense,apt 装 realsense-ros 有可能冲突。
方法二:源码编译 realsense-ros。这是我更推荐的方式,因为能保证和底层 librealsense 版本匹配:
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src git clone https://github.com/IntelRealSense/realsense-ros.git -b ros2-development cd ~/ros2_ws rosdep install -i --from-path src --rosdistro humble -y colcon build --symlink-install source install/setup.bashrosdep install这一步在 Jetson 上可能因为网络问题卡住,如果卡了可以跳过,手动装缺的依赖。colcon build在 Orin Nano 上大概 5-10 分钟。
4.3 启动相机节点并验证话题
启动:
ros2 launch realsense2_camera rs_launch.py然后在另一个终端看话题:
ros2 topic list正常应该能看到/camera/color/image_raw、/camera/depth/image_rect_raw、/camera/imu等话题。用ros2 topic hz /camera/color/image_raw看帧率是否正常。
如果话题列表里只有 color 没有 depth,回到第 3 章检查 librealsense 的深度流是否正常。如果话题都有但没数据,检查 USB 连接——D435i 一定要接 USB 3.0 口,接 USB 2.0 会导致带宽不足,深度流直接掉。
5. 那些让我熬夜的报错:完整排查链路复盘
这一章把几个最典型的报错按"现象—排查—根因—解决"的链路写出来,方便你对照复现。
5.1rs-enumerate-devices报 "No device connected"
现象:设备插着,lsusb能看到 Intel 的设备,但rs-enumerate-devices说没设备。
排查链路:先lsusb | grep Intel确认系统识别到 USB 设备。如果这里就没有,是物理连接或线缆问题,换线换口。如果有,但 librealsense 看不到,大概率是 udev 规则没装或者没生效。检查/etc/udev/rules.d/99-realsense-libusb.rules是否存在,然后sudo udevadm trigger重新触发。还不行就sudo rs-enumerate-devices试试,如果 sudo 下能识别,100% 是权限问题。
根因:udev 规则缺失或未生效,普通用户没有 USB 设备访问权限。
5.2 深度流报错 "Couldn't resolve requests"
现象:RGB 流正常,深度流一开就报错,或者 viewer 里深度图是黑的。
排查链路:先确认 USB 是不是 3.0。lsusb -t看设备挂在哪个速率下,5000M 才是 USB 3.0,480M 是 2.0。如果是 2.0,换口。如果已经是 3.0 还报错,检查 librealsense 编译时是否带了FORCE_RSUSB_BACKEND=ON。没带的话,在没打内核补丁的 Jetson 上深度流很容易失败。
根因:Jetson L4T 内核缺少 RealSense 深度流所需的 V4L2 补丁,或者 USB 带宽不足。
5.3 ROS2 节点启动后 RViz2 里看不到点云
现象:ros2 topic list有点云话题,ros2 topic hz也有数据,但 RViz2 里加了 PointCloud2 显示就是空的。
排查链路:先确认 RViz2 里的 Fixed Frame 设置对不对。RealSense 默认的 frame 是camera_link,如果 Fixed Frame 设成了map或者别的,点云不会显示。改成camera_link试试。然后检查话题的 QoS 设置,RealSense 的深度话题默认用的是SENSOR_DATAQoS,RViz2 默认可能是DEFAULT,两者不匹配会导致收不到数据。在 RViz2 里把话题的 QoS 改成Best Effort。
根因:坐标系不匹配或 QoS 策略不匹配。这是 ROS2 新手最容易踩的坑之一,因为话题有数据但显示不出来,很容易误判成驱动问题。
5.4colcon build报 "command not found"
现象:装完 ROS2 后colcon命令找不到。
排查链路:colcon是单独的一个包,ros-humble-desktop不一定带。sudo apt install python3-colcon-common-extensions装上。如果装完还找不到,检查~/.bashrc里有没有 source ROS2 的 setup.bash。
根因:colcon 未安装或环境变量未加载。
5.5 编译 librealsense 时 CMake 报 CUDA 相关错误
现象:cmake ..阶段报找不到 CUDA 或者 CUDA 版本不匹配。
排查链路:加-DBUILD_WITH_CUDA=false重新 cmake。如果你确实需要 CUDA 加速(比如跑 CUDA 版的点云处理),那要确保 JetPack 的 CUDA 路径在环境变量里,export PATH=/usr/local/cuda/bin:$PATH和export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH。
根因:CMake 自动探测 CUDA 失败,或者 JetPack 的 CUDA 路径没配好。
6. 让这套环境真正好用的几个实操心得
环境搭通只是第一步,下面这些是我用下来觉得能显著提升体验的细节。
6.1 用 launch 文件固化参数,别每次手敲
rs_launch.py支持大量参数,比如分辨率、帧率、是否开启 IMU、是否对齐深度到彩色。每次都手敲命令行参数很痛苦,写个自己的 launch 文件:
from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( package='realsense2_camera', executable='realsense2_camera_node', name='camera', parameters=[{ 'enable_color': True, 'enable_depth': True, 'enable_imu': True, 'align_depth.enable': True, 'rgb_camera.color_profile': '640x480x30', 'depth_module.depth_profile': '640x480x30', }] ) ])align_depth.enable这个参数特别有用,它把深度图对齐到彩色图坐标系,做 RGB-D 融合或者机械臂抓取时省掉一大堆坐标变换的麻烦。
6.2 USB 带宽是隐形瓶颈
D435i 同时开 RGB、深度、IMU,带宽需求不小。如果你还接了其他 USB 3.0 设备(比如另一个摄像头),很可能带宽不够导致掉帧。lsusb -t可以看到每个 USB 控制器下挂了什么设备。尽量把 RealSense 单独挂在一个 USB 控制器下,别和其他高带宽设备共享。
6.3 散热和功耗模式
Orin 在高负载下会降频,尤其是跑点云处理 + 相机采集同时进行时。用sudo nvpmodel -m 0切到最大性能模式(功耗换性能),配合sudo jetson_clocks锁定最高频率。但注意散热,Orin Nano 被动散热的话长时间高负载会烫,建议加个风扇。
6.4 固件版本别忽略
RealSense 的固件版本会影响功能稳定性。用rs-fw-update -l看当前固件版本,和 Intel 官网的推荐版本对比。固件太老可能出现 IMU 数据异常或者深度流不稳定。升级固件用rs-fw-update -f <固件文件>,升级过程中别断电。
6.5 备份你的工作环境
Jetson 上重装环境成本很高,编译一次 librealsense 就是半小时起。建议环境搭通后立刻用sudo apt install的包列表 + 自己的编译脚本做个记录,或者直接对系统盘做镜像备份。我吃过一次亏,系统更新后内核变了,librealsense 的模块加载失败,重编又花了一下午。
7. 从这套环境出发还能往哪走
环境通了之后,接下来通常是往具体应用走。如果你做机械臂抓取,align_depth对齐后的 RGB-D 数据可以直接喂给点云分割或者抓取检测网络。如果做 SLAM,RealSense 的 IMU + 深度可以跑 RTAB-Map 或者 VINS。如果做视频动作分类这类任务,RealSense 的 RGB 流可以作为数据源,配合 PyTorch 做时序建模。
我个人在 Orin NX 上跑过 RealSense + RTAB-Map 的建图,帧率稳定在 30fps 时 CPU 占用大概 40%,还有余量跑轻量级的检测网络。Orin Nano 的话建议把分辨率降到 640x480、帧率降到 15fps,给后续处理留出算力。
最后分享一个我踩过的坑:别在环境没验证通的情况下就急着上应用。我见过太多人 librealsense 的深度流还没确认正常,就开始配 SLAM,结果调了半天以为是算法问题,其实是底层驱动没通。按这篇文章的顺序,一层一层验证,rs-enumerate-devices通了再装 ROS2,ROS2 话题通了再上应用,能省掉大量无效排查时间。