ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Jetson TX2安装ROS Melodic全流程避坑:ARM架构源配置与内存优化

Jetson TX2安装ROS Melodic全流程避坑:ARM架构源配置与内存优化

在TX2上装ROS melodic,表面上是跑一条教程,实际上是对ARM架构、定制系统、网络环境和资源边界的一次综合考验。我之前的ROS学习笔记一直没专门讲嵌入式平台,这次单独开一篇,是因为在PC x86上跑通的教程搬到NVIDIA JETSON TX2上,几乎每一步都可能报错:源里没有你的架构、公钥添加失败、rosdep卡在初始化、编译的时候内存被打爆。标题里写“规避踩坑”,真不是夸张,TX2和普通电脑从底层架构开始就是两个世界。

这篇笔记面向正在用TX2做机器人、SLAM、视觉方向的初学者。读完你拿到的是一套可以完整复现的安装流程,外加每个坑背后的原因和排查顺序。我会把Ubuntu18.04如何配源、ROS melodic如何选包、rosdep怎么绕过EOL问题、编译线程数怎么设置这类细节都拆开讲,尽量让你一次过,而不是反复重刷系统。

1. 安装前必须先搞懂的3个平台差异

1.1 arm64与x86的源头区别,决定你的源该怎么配

TX2最容易被忽略的一点:它使用的是ARM架构的CPU,不是PC上常见的x86_64。uname -m这条命令在普通PC上输出x86_64,在TX2上输出的是aarch64。这个差异直接决定了apt软件源的选择。

Ubuntu为不同的硬件架构维护了不同的软件仓库:ubuntu路径下放的是x86和amd64的包,而ubuntu-ports路径才是专门给arm64、armhf等架构服务的。大多数网上找的“Ubuntu18.04换源教程”给的都是deb http://.../ubuntu/ bionic main ...这种写法,直接照搬到TX2上,apt update会报404,或者干脆找不到任何软件包,因为arm64的包根本不在那个仓库里。

判断当前系统架构,三条命令就能确认:

uname -a dpkg --print-architecture dpkg --print-foreign-architectures

正常情况下dpkg --print-architecture会输出arm64。看到这个输出,心里就要有个底:所有源配置,必须走ubuntu-ports体系,而不是ubuntu体系。这一点是整个安装流程里最容易翻车的地方,我把话放在最前面。

1.2 JetPack定制系统:Ubuntu18.04里藏了哪些“官方附加项”

TX2的系统通常不是普通Ubuntu,而是NVIDIA基于Ubuntu18.04定制的镜像,内部预装了CUDA、cuDNN、TensorRT等一整套AI加速组件。这套东西在你刷机或者用官方镜像安装系统的时候就固化了,它和Ubuntu普通发行版之间有不少细节差异。

最直接的体现是/etc/nv_tegra_release这个文件,里面记录了当前L4T(Linux for Tegra)的版本号。系统更新时,apt会同时维护NVIDIA自己的软件源,所以你在sources.list里一般能看到deb https://repo.download.nvidia.com/...这类的条目。这些源不能随便删,删了之后后续想补装CUDA相关的依赖库会比较麻烦。

但同时也带来一个问题:TX2的定制系统里预装的库版本和ROS生态默认依赖的版本可能不一致。比如OpenCV,JetPack里预装的可能是4.x版本,而ROS melodic时代默认的OpenCV是3.2。这种“系统预装版本”和“ROS期望版本”的错位,在你安装ROS主体时不一定暴露,但后面编译cv_bridge的时候一定会炸。这个坑我会在第4部分专门讲。

1.3 为什么PC上的ROS安装教程在TX2上跑不通

很多初学者在PC上照着ROS官方教程装过一遍,觉得无非就是几行命令,换到TX2上应该一样。真上手才发现不是那么回事。除了源架构不同,还有几个细节是PC教程不会提到的:

第一,桌面版Ubuntu的镜像站基本都有完整的ubuntu仓库,而部分镜像站对ubuntu-ports的同步不一定及时,所以你需要确认自己选的镜像站支持arm64路径。选错了镜像站,安装到一半会出现部分包找不到的情况。

第二,TX2板的CPU虽然核心数不少,但内存只有8GB,而且eMMC存储空间有限。你的编译策略、安装包选型都要按嵌入式平台的资源标准来,不能照搬PC上的“无脑全装”。

第三,ROS melodic在2023年已经停止维护,属于EOL版本。这个看起来无关紧要的时间点,会在rosdep update阶段给你一记重锤:默认情况下rosdep会跳过EOL发行版的依赖规则,导致依赖解析失败。第3部分我会给出具体处理方式。

2. 环境准备:检查系统版本、备份源、配置镜像源

2.1 上电后先确认这4条命令的输出

先别急着改任何文件,开机后第一件事是确认系统状态。按顺序执行以下命令,把输出记下来:

lsb_release -a uname -m df -h free -h

前两条确认系统版本和架构,后面两条确认存储空间和内存。TX2的板载存储通常是32GB eMMC,如果你之前装过CUDA、Python深度学习环境,剩余空间可能已经不多。而ros-melodic-desktop-full装下来大概要占2.5到3GB,加上后续编译工作空间,建议预留至少10GB左右。如果空间紧张,后面可以选ros-melodic-ros-base,我在3.2节会对比说明。

另外检查一下当前系统是否已经配置了dirmngr,这个工具在后面添加ROS公钥时用得上:

which dirmngr

如果没有输出,先装一下:

sudo apt install dirmngr

这是很多人忽略的小依赖,公钥添加失败常常就是因为它。

2.2 备份并重写sources.list,注意选对ubuntu-ports

修改任何系统配置文件之前先备份,这是最基本的自我保护。TX2的源列表文件路径和普通Ubuntu一致:

sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

然后编辑该文件:

sudo nano /etc/apt/sources.list

对于arm64架构的Ubuntu18.04,源路径必须是ubuntu-ports。我建议保留NVIDIA官方的那几行L4T源不动,只替换Ubuntu系统仓库部分。替换后参考格式如下:

deb https://mirrors.example.com/ubuntu-ports/ bionic main restricted universe multiverse deb https://mirrors.example.com/ubuntu-ports/ bionic-updates main restricted universe multiverse deb https://mirrors.example.com/ubuntu-ports/ bionic-security main restricted universe multiverse deb https://mirrors.example.com/ubuntu-ports/ bionic-backports main restricted universe multiverse

注意这里的mirrors.example.com是占位符,你实际使用时需要替换成本地能流畅访问的国内镜像站地址,并且在镜像站页面确认它提供了ubuntu-ports目录。怎么确认?浏览器打开镜像站,看看它的路径下有没有ubuntu-ports这个文件夹,里面有没有dists/bionic目录。如果镜像站只提供ubuntu目录,那它同步的是x86架构仓库,不适用于TX2。

这里再说一个判断技巧:写完后先不急着apt update,用apt-cache policy验证仓库是否真的生效。后面3.1节会结合安装过程讲。

2.3 ROS apt源和公钥的添加,以及公钥超时的处理方法

ROS melodic的官方源地址是packages.ros.org,但国内访问速度不稳定。好在国内高校镜像站基本都同步了ROS仓库,ros/ubuntu目录在arm64架构下也是可用的。在/etc/apt/sources.list.d/下单独建一个文件,方便管理和后期清理:

sudo sh -c 'echo "deb https://mirrors.example.com/ros/ubuntu bionic main" > /etc/apt/sources.list.d/ros-latest.list'

同样,mirrors.example.com换成你实际选择的镜像站。注意ROS仓库使用的是bionic这个发行版代号,和Ubuntu18.04匹配,不要写成xenial或者其他代号。

添加ROS公钥的标准命令是:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

这条命令想把公钥从Ubuntu的keyserver拉取下来。如果执行后提示超时,或者gpg: keyserver receive failed: No dirmngr,先确认dirmngr是否安装。如果keyserver连不上,可以换一个公钥服务器重试,比如pgp.mit.edu:

sudo apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

keyserver超时的根因多半是网络握手不畅,跟架构无关。多试几个服务器,或者换一个网络时段再跑,大多数情况下能解决。

3. 正式安装ROS Melodic的完整操作记录

3.1 更新索引和基础依赖,先解决Python环境问题

源配好了,公钥也加了,接下来先更新软件索引:

sudo apt update

这一步如果报404,回第2部分检查源路径是不是ubuntu-ports;如果报签名错误,检查公钥是否添加成功。apt update干净通过之后,再安装ROS依赖的基础工具:

sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential

注意这里有一个Python版本的坑。Ubuntu18.04系统默认的python命令指向Python 2.7,ROS melodic的工具链也是围绕Python 2构建的。如果你之前为了跑深度学习,把系统默认Python改成了Python 3,或者装了miniconda并长期把conda环境放在PATH最前面,后面会出一堆莫名其妙的报错。我的建议是:安装ROS期间,不要动系统的Python软链,不要修改/usr/bin/python的指向。实在要用conda,单独在终端里激活,别把它写进.bashrc的全局PATH。

3.2 安装版本选型:desktop-full还是ros-base

这是TX2用户最容易纠结的问题。ROS melodic官方提供几个级别的安装包:

  • ros-melodic-ros-base:最小集,包含ROS核心通信框架、常用客户端库。
  • ros-melodic-desktop:在base基础上增加rviz、rqt等GUI工具。
  • ros-melodic-desktop-full:在desktop基础上再增加gazebo仿真、navigation导航栈等,体积最大。

对于做SLAM的TX2用户,desktop-full里的map_server、gmapping等导航相关包后续大概率用得到,直接装上能省去后面一个个补依赖的麻烦。但从资源角度看,TX2跑gazebo压力很大,8GB内存和板载GPU性能做不了太复杂的物理仿真,真到仿真环节,多数人还是会用PC。

我的建议是:如果存储空间充足(10GB以上),装desktop-full,省心;如果空间紧张,装ros-base,后续用时再单独apt install ros-melodic-xxx补包。安装命令:

sudo apt install ros-melodic-desktop-full

下载和安装过程会花一点时间,具体取决于你的网络和镜像站同步速度。插一句经验:如果你用的是ssh远程连接而不是桌面终端,安装过程中万一网络断开,进程不会因为桌面会话关闭被kill,更稳。

3.3 初始化rosdep并绕过EOL导致的skip问题

ROS安装完成后,接下来是让依赖管理工具跑起来。先初始化:

sudo rosdep init rosdep update

rosdep init会把rosdep的默认规则源写入/etc/ros/rosdep/sources.list.d/20-default.list。这一步常见的报错是网络连不上raw.githubusercontent.com,因为该文件里的URL默认指向GitHub。

如果网络条件确实不理想,给你一个亲测可行的离线方案。在能联网的机器上把ros/rosdistro这个仓库完整下载下来,拷贝到TX2任意目录,然后编辑/etc/ros/rosdep/sources.list.d/20-default.list,把里面所有https://raw.githubusercontent.com/ros/rosdistro/master/...开头的URL都改成对应的本地file://路径。比如仓库放在/home/你的用户名/rosdistro下,那么:

yaml file:///home/你的用户名/rosdistro/rosdep/osx-homebrew.yaml osx yaml file:///home/你的用户名/rosdistro/rosdep/base.yaml yaml file:///home/你的用户名/rosdistro/rosdep/python.yaml yaml file:///home/你的用户名/rosdistro/rosdep/ruby.yaml yaml file:///home/你的用户名/rosdistro/rosdep/nodejs.yaml

这里osx-homebrew.yaml是给macOS平台用的,Linux下可以不关心,但保留也不影响。改完再执行rosdep update就能从本地规则完成初始化。

还有一个EOL问题,必须单独拎出来说。ROS melodic已经停止维护,新版rosdep在解析EOL发行版时会直接跳过它的依赖规则。跳过之后的表现是:rosdep update不报错,但后续在做rosdep install时告诉你找不到当前发行版的依赖定义。处理办法是在update时加一个参数保留EOL发行版:

rosdep update --include-eol-distros

如果嫌每次敲参数麻烦,也可以直接修改rosdep配置,把include_eol_distros设为true。这一步是我在2024年之后反复遇到的坑,单独写出来就是希望你别卡在这里。

3.4 写入bashrc与多终端环境一致性

ROS的环境变量需要注册到shell启动文件里,否则新开的终端敲roscore会提示找不到命令:

echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc source ~/.bashrc

这里只讲了bash的情况。如果你习惯用zsh,对应修改~/.zshrc,但TX2默认镜像通常不带zsh,多数人直接在bash下工作就行。

有个细节值得注意:source只对当前终端生效,新开终端还会依赖.bashrc。所以我倾向于在.bashrc里保留一行显式的source,而不是把环境变量塞到~/.profile里。另外,如果你在.bashrc里写入了export ROS_MASTER_URI=http://localhost:11311这类自定义变量,注意别覆盖了ROS默认的ROS_HOSTNAME,否则后续多机通信时会莫名其妙连不上。

测试一下安装结果:

rosversion -d

输出melodic,说明ROS主体已经就位。

4. 安装后的烧机验证与资源体检

4.1 三连测试:rosversion -d、roscore、turtlesim

环境变量配好后,第一件事是启动roscore,验证ROS主节点能否正常运行:

roscore

看到started core service [/rosout]这类日志,说明主节点没问题。接着新开一个终端,跑一下ROS自带的小乌龟例子,验证话题通信和GUI功能:

rosrun turtlesim turtlesim_node

再开一个终端:

rosrun turtlesim turtle_teleop_key

按住键盘方向键,如果屏幕上的小乌龟动了,说明ROS的节点通信是通的。这里有一个TX2特有的小坑:如果你是ssh远程连接,没有本地图形界面,直接跑turtlesim_node会报cannot connect to X server。解决办法是把DISPLAY环境变量指向TX2的本地显示器,常见值是:0:

export DISPLAY=:0

如果你根本不想接显示器,那这一步跳过也行,不影响后续使用。

4.2 内存、换区和磁盘空间:嵌入式平台必须做的体检

ROS装上之后,TX2在跑roscore和rviz时内存占用会明显上升。建议你先看一眼当前的内存压力:

free -h

如果available长期低于1GB,后续编译大包时八成会被系统OOM killer干掉。TX2默认没有配置swap分区,这是一个不小的隐患。我试过在内存不足时直接跑catkin_make -j4,进程直接卡死,然后被内核杀掉,报错信息只有一行Killed,没有其他任何提示。

两个缓解方案:一是编译时限制并行度:

catkin_make -j2

TX2有6个CPU核心,但内存才是真正的瓶颈,-j2虽然慢一点,但稳。第二个方案是给系统增加swap。创建一个4GB的swapfile,部署在外部SSD上更理想(别放eMMC,读写压力大):

sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile

要让开机自动挂载,需要在/etc/fstab里追加一行/swapfile none swap sw 0 0。有了这4GB swap,即使内存紧张,编译也只是变慢,不至于直接被kill。

4.3 提前预告OpenCV版本冲突,避免后续编译踩坑

JetPack系统里预装的OpenCV版本和ROS melodic默认依赖的OpenCV版本不一致,这是TX2玩家迟早要面对的问题。ROS里的vision_opencv功能包(比如cv_bridge)在编译时会去找系统里的OpenCV,如果找到的是JetPack的OpenCV 4.x,很多在老版本OpenCV下编译正常的代码会报出各种奇怪的API错误。

我见过最常见的是编译cv_bridge时报找不到CV_LOAD_IMAGE_COLOR这类宏,因为OpenCV 4移除了这些老接口。规避思路有两个方向。

方向一:在工作空间里显式指定ROS自带的OpenCV版本。ROS melodic的cv_bridge源码里,可以通过CMake参数指定OpenCV版本,强制它使用Ubuntu系统仓库安装的OpenCV 3.2。方向二:干脆把vision_opencv整个包换成支持OpenCV 4的分支,社区里有不少维护者做了兼容修复,搜索关键字就能找到。

这个话题可以单独写一篇,这里只提一个结论:先把你用的OpenCV版本和ROS期望的版本查清楚,再用pkg-config --modversion opencv4和pkg-config --modversion opencv对比,避免在编译现场才发现问题。

5. TX2装ROS期间的高频报错与排查速查

5.1 高频报错速查表(含规避型技巧)

下面这个表是我整理的在TX2平台上装ROS melodic最常见的报错,最后一列是我实操验证过的处理方式。

报错现象直接原因快速处理
apt update404 /Unable to locate package源路径用了ubuntu而不是ubuntu-ports,或镜像站没有arm64同步检查sources.list中的所有主源路径,确认是ubuntu-ports体系
gpg: keyserver receive failed: No dirmngr缺少dirmngr工具sudo apt install dirmngr,再重试公钥添加
sudo rosdep init: file already exists初始化重复执行,或上次中断残留了配置文件删除/etc/ros/rosdep/sources.list.d/20-default.list后重新初始化
rosdep update超时或连接失败默认规则源指向境外服务器,网络不稳定使用本地克隆的rosdistro仓库,将URL改为file://
rosdep update不报错但后续解析失败melodic已经EOL,规则默认被跳过加参数--include-eol-distros,或配置include_eol_distros
catkin_make进程被Killed内存不足被OOM killer终止降并行度-j2,配置swapFile
roscore: command not foundROS环境变量没有生效执行source /opt/ros/melodic/setup.bash并写入.bashrc

表格里列的每一条背后都有实际操作的影子。特别是file already exists那个问题,很多人在rosdep init失败之后习惯性重试,却不清理旧文件,结果一直卡在同一个报错,误以为是网络问题。

5.2 遇到报错后的标准排查顺序

有个回报率很高的经验:不要盯着报错信息最后一行猜,按下面这个顺序排查,能解决绝大多数TX2上的安装问题。

第一层,架构对不对。执行dpkg --print-architecture,如果是arm64,所有源路径必须是ubuntu-ports,所有镜像站必须支持arm64。架构错了,后续的一切都是空中楼阁。

第二层,网络通不通。apt update能否成功、公钥能否拉取、rosdep规则能否下载,这些步骤对网络要求不同。如果是断断续续的失败,多半是网络问题,换时段或者换镜像站是最直接的解法。

第三层,依赖全不全。ROS安装在build-essential、python-rosdep这些基础包缺失时,会在安装中段报错。安装之前先补全基础依赖,能少走一半弯路。

第四层,资源够不够。内存是否充足、swap是否配置、磁盘空间是否预留够。TX2的硬件规格注定了它不能像PC那样无脑并行编译,资源规划本身就是整个流程的一部分。

按这个顺序排查,绝大多数问题都能被快速定位。而不是看到报错就去搜索,搜索出来的一堆答案又不知道哪个适合自己的架构。

我个人的体会是,在TX2上装ROS melodic,本质上是你和这台嵌入式平台的一次资源管理对话。命令都不复杂,复杂的是理解每一行命令背后为什么是这个架构、为什么是这个源、为什么限线程数。把这些问题一次性弄明白,后面编译SLAM包、跑视觉程序时能少受很多罪。装完ROS只是第一步,记得做个干净的系统镜像备份,之后再怎么折腾都有后悔药吃。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进