很多刚入坑ROS的朋友,第一次跑到rosdep update这一步时,心里都是一万个问号:明明前面装得好好的,怎么偏偏在这里卡住?网络也试了,代理也配了,源也换了,结果还是红字报错。更难受的是,这个问题在不同机器上表现还不一样,台式机上折腾一下能过,树莓派上又给你变个花样出来。我自己从ROS1的Kinetic一路用到ROS2的Humble,前后装过不下二十次系统,每次重装都要跟rosdep斗智斗勇。后来接触到fishros这套一键配置脚本,算是彻底把这块心病治好了。这篇文章就把我这几年的安装经验做个总结,重点聊聊rosdep update为什么会失败、fishros脚本到底做了什么,以及树莓派和Jetson这类ARM平台上安装ROS/ROS2时那些文档里查不到的坑。
这篇文章适合所有被ROS安装折磨过的人,不管你是刚接触ROS的新手,还是已经被rosdep搞到没脾气的老人,只要你手上有Ubuntu系统的电脑、树莓派或者Jetson开发板,想快速跑起来一个能用的ROS环境,这篇内容都能帮你省下至少半天时间。
1. 先搞清楚为什么rosdep update总爱失败
1.1 rosdep到底在干什么
要理解rosdep update失败的根源,得先知道这个命令的职责。rosdep是ROS的依赖管理工具,它的作用是告诉你某个功能包还缺哪些系统级的依赖库,然后帮你把这些依赖装好。比如你编译一个包,它提示需要libopencv-dev,rosdep就能根据当前Ubuntu版本自动解析出对应的安装包名并完成安装。
而rosdep update做的事情,是从ros/rosdistro这个GitHub仓库拉取全量索引数据,把这些数据缓存在本地。这个索引记录了每个ROS发行版里所有功能包对应的系统依赖关系。所以当你执行rosdep install --from-paths src --ignore-src -r -y时,rosdep要先去查本地缓存,如果缓存里没有某个包的数据,就会请求远端仓库把缺失的部分补上。
问题就出在这里:rosdep跟GitHub之间的通信,夹着一层并不稳定的网络环境。时区、运营商防火墙策略、DNS解析结果,任何一个环节抽风,都会导致rosdep update卡住或者直接超时。很多人在这一步反复重试,运气好能过去一次,运气不好就一直卡在那。
1.2 失败的原因,其实就那么三类
我把这几年遇到过的rosdep update失败情况归了个类,主要有三类。
第一类是单纯的网络超时。rosdep update默认去访问raw.githubusercontent.com和github.com,这些域名在国内网络环境下响应很不稳定。表现就是卡在reading in raw list...或者Hit https://raw.githubusercontent.com/...之后长时间没有动静,最后报一个连接超时的错误。这种情况在晚上的高峰时段尤其明显,同一个命令,早上跑可能就成功了。
第二类是指纹验证失败。rosdep在拉取数据时需要校验GPG key,如果你的rosdep或者ros-keyring版本太老,本地的公钥过期了,服务器返回的新公钥又没法通过校验,就会报类似W: GPG error: ... The repository ... is not signed的错。这类错误跟网络无关,纯粹是密钥同步问题,网上不少教程会教你直接从某个key server导入公钥,这确实能解决,但每次重装系统都得再来一遍,挺烦的。
第三类是ROS发行版与Ubuntu版本匹配错乱。ubuntu的软件源里有ROS源,如果你装的是Ubuntu 24.04却用了旧版ROS1的源,或者装ROS2的时候不小心把ROS1的源也加进去了,rosdep update在合并索引时就会因为版本不匹配而中断。这类错误最迷惑,因为报错信息看起来像网络问题,实际是源配置写错了。
2. fishros脚本是干什么的
2.1 fishros脚本的定位与原理
fishros是社区开发者"小鱼"维护的一套开源配置工具,官方名我就不去考据了,大家平时都叫它"鱼香ROS一键安装"。它本质上是一个封装好的shell脚本,把ROS安装过程中所有容易出错的环节都做成了自动化操作。这个脚本下载后直接执行,不需要手动配源、不需要手动加key、不需要手动写~/.rosdep配置。
很多人一听到"一键脚本"就觉得不够专业,觉得还是手动敲命令靠谱。这个观点我部分同意,对于纯学习目的、想要搞懂底层原理的人,手动安装确实能让你理解ROS的依赖体系。但如果你是想快速搭好环境、把时间花在算法和功能开发上,那fishros这类工具的性价比就非常高。它帮你省去的不是几条命令,而是排查网络故障、GPG key同步、依赖冲突这些无底洞式的调试时间。
脚本的原理其实不复杂,它做的事情就是把你手动安装时的所有步骤集中起来,通过判断当前系统的架构、Ubuntu版本、网络状况,选择合适的镜像源和依赖版本。特别值得表扬的是它对Arm64架构的适配做得很好,树莓派和Jetson都能正确识别,不会像很多通用教程那样默认你是x86_64然后装出个不能用的环境。
2.2 一条命令背后的流程拆解
fishros最核心的使用方式就是这一条命令:
wget http://fishros.com/install -o fishros && . fishros执行之后,脚本会先检测当前系统的发行版信息,然后显示一个交互式菜单,里面包含换源、安装ROS1、安装ROS2、安装rosdep等多个选项。选择对应的功能后,脚本会按顺序执行以下动作:
- 更新apt源列表,将默认源替换为公司维护的镜像源(或者你手动指定的其他源)
- 安装ROS仓库签名用的GPG key
- 添加ROS软件源到apt源列表
- 执行
apt update并安装ros-<distro>-desktop或ros-<distro>-ros-base - 初始化rosdep并完成
rosdep update - 配置ROS环境变量到
~/.bashrc
这里面最关键的其实是换源这一步。脚本会把packages.ros.org替换为一个国内可达性更好的镜像地址,同时也处理了raw.githubusercontent.com的访问问题。镜像源的数据同步做得比较及时,所以rosdep在后续使用中基本不会再遇到索引缺失的问题。
2.3 为什么很多老手也愿意用它
你可能觉得这种脚本是给新手偷懒用的,但我认识的好几个做了三四年ROS项目的工程师,重装系统时也会用fishros来搭基础环境。原因很简单:省事且稳定。
手动安装最大的问题是每个环节都有潜在的"环境依赖"。比如你在一台新机器上装ROS2 Humble,需要先确认Ubuntu是22.04版本,然后添加ROS2的apt源,再手动安装python3-vcstool等多个工具包,最后初始化rosdep。任何一步的网络都可能导致后续安装失败,而脚本因为有重试机制和更稳定的源,整个过程的可靠性高很多。
还有一个实用场景是批量部署。比如实验室里要给十台机器人统一装环境,手动一台台敲命令是非常低效的。用fishros的话,每台机器只要执行那一条命令,然后选同样的选项,十分钟左右就能把环境统一好。对于做多机协作、分布式SLAM这类项目的团队来说,这算刚需了。
3. 实操:从零到ROS2跑通全家桶
3.1 环境准备:一台干净系统是最省心的
不管你是用电脑、树莓派还是Jetson,装ROS之前系统本身要干净,这是我最想强调的一点。很多人喜欢在已经用了一段时间、装过很多软件的系统上直接装ROS,结果经常遇到Python版本冲突、OpenCV版本不匹配、或者cmake版本过旧导致的编译失败。
所以我的建议是准备一块单独的分区或者一张新SD卡来装系统。如果你用的是树莓派4B/5,可以直接用树莓派官方镜像工具烧录Ubuntu Server 22.04 LTS,注意要选64位版本,因为从Ubuntu 22.04开始,树莓派官方对64位系统的支持已经很完善了,没必要再折腾32位那套。
对于Jetson系列,系统烧录稍麻烦一些。Jetson不像树莓派那样可以随便刷第三方Ubuntu镜像,它需要借助NVIDIA官方提供的JetPack SDK进行烧录,JetPack里面自带了一套深度定制过的Ubuntu系统,内核和驱动都是和硬件绑定的。我在Jetson Orin Nano上用的JetPack 5.1.2,对应的就是Ubuntu 20.04,这个版本搭配ROS2 Foxy比较合适。如果你拿到的是更新版本的JetPack 6.0,底层Ubuntu版本会变成22.04,就可以直接上ROS2 Humble。
3.2 安装过程实录(含命令输出解读)
假设你现在是一台干净的Ubuntu 22.04系统,架构是x86_64或者aarch64都行。打开终端,执行:
wget http://fishros.com/install -o fishros && . fishros脚本下载完成后会自动运行,你会看到类似下面的交互界面输出:
[INFO] 检测到系统为 Ubuntu 22.04.3 LTS [INFO] 架构为 x86_64 [INFO] 是否更换系统源? [y/N]这里建议选y,因为默认源在国内的下载速度实在太感人了,尤其是装desktop版需要拉取大量软件包时,镜像源能帮你省下大量时间。选完之后,脚本会继续询问:
[INFO] 是否安装rosdep? [y/N]这里也必须选y。rosdep是后续编译功能包时绕不开的工具,你现在不装,等后面编译别人的包时再回来装就麻烦了。
接下来是功能选择菜单,不同版本的脚本菜单项可能略有差异,大致是:
[1] 一键安装ROS1 Noetic [2] 一键安装ROS2 Humble [3] 安装rosdep [4] 配置rosdep如果你需要ROS1和ROS2共存,建议先装ROS1 Noetic再装ROS2 Humble。共存时需要注意环境变量的切换,不过这是后话,后面会单独讲。
整个过程大约需要5到15分钟,取决于你的网络速度和选择的软件包规模。装完之后,脚本会提示你执行:
source /opt/ros/humble/setup.bash然后你就可以用ros2 --version验证安装结果了。如果输出类似ros2 2.6.x这样的版本号,说明核心安装成功。
3.3 装完之后必须做的验证
环境装好了不等于万事大吉,我强烈建议你跑一遍最基础的功能验证,确保系统是真正可用的。先验证ROS2的核心通信:
ros2 run demo_nodes_cpp talker开一个新终端,跑:
ros2 run demo_nodes_py listener两个终端都能正常运行且listener能收到talker发过来的消息,说明底层DDS通信正常。这一步非常重要,因为很多人在跑功能包之前根本不知道自己的ROS环境有问题,等编译大工程时才突然报错,那时候排查的复杂度就高多了。
再来验证一下rosdep是否好用:
cd ~/your_ros2_ws rosdep install --from-paths src --ignore-src -r -y正常情况下,这个命令会提示没有缺失的依赖包,或者自动安装几个缺失的库。如果它卡住或者超时,那就是rosdep的配置还有问题,可以继续用fishros的rosdep修复功能再处理一波。
4. 树莓派和Jetson平台单独说
4.1 ARM平台的共性问题
树莓派和Jetson虽然都是嵌入式平台,但它们的共同点是CPU架构都是ARM,前者根据型号不同可能是armhf或arm64,后者则统一是arm64。这个架构差异带来了一系列连锁反应。
第一点是软件包兼容性。很多ROS生态里的二进制包是x86架构编译好的,在ARM平台上根本装不上,只能从源码编译。这也是为什么同一个ROS功能包,在苹果笔记本上装可能只需要apt install一条命令,在树莓派上却要编译半小时的直观原因。
第二点是性能瓶颈。ARM平台普遍内存小、CPU弱,编译大包时经常内存耗尽。我自己的经验是树莓派4B编译稍微大一点的包时,最好先增加swap空间,不然编到一半进程被杀是常有的事。Jetson虽然性能好一些,但Jetson Nano那种2GB内存的老型号同样面临这个问题。
第三点是ROS发行版的选择空间被压缩。Jetson的JetPack版本和Ubuntu版本是绑定的,而ROS对Ubuntu版本又有严格要求,所以你能选择的ROS发行版其实是有限的。比如JetPack 4.x自带Ubuntu 18.04,那ROS2就只能装Dashing或者Eloquent,这两者都比较老,很多新功能包已经不再支持。如果你跟不上NVIDIA的更新节奏,还是老老实实先确认清楚系统版本再规划。
4.2 树莓派4B:系统选型与摄像头驱动
树莓派4B是目前最便宜的ROS学习平台之一,性能虽然不能说强,但跑跑基础SLAM和导航仿真还是够的。选系统时首推Ubuntu Server 22.04 LTS的64位版本,原因有两个:一是Ubuntu Server比Raspberry Pi OS更接近PC端Linux环境,很多ROS教程里写的依赖包在Ubuntu源里都能直接找到;二是64位系统能用完整内存寻址,对于树莓派4B的4GB/8GB内存版本来说是必要选项。
树莓派上另一个常见需求是接入OV5647摄像头模块做视觉应用。在树莓派官方系统里,摄像头驱动是整合在固件里的,到了Ubuntu Server上就要另想办法。比较通用的方案是使用raspicam库的ROS封装包raspicam_node,这个包可以通过源码编译安装。需要提前安装libraspberrypi-dev等底层依赖库,否则编译时会报找不到头文件的错。
我实测下来的流程是,先在系统里安装gstreamer相关插件,然后克隆raspicam_node仓库到ROS2工作空间,编译后通过raspicam_node/camera话题发布图像。虽然配置过程有点繁琐,但效果比用ROS的usb_cam驱动模拟摄像头要好很多,延迟更低,帧率也稳定。
4.3 Jetson系列:从烧录到spconv的典型坑
Jetson系列因为自带GPU,在机器人视觉和深度学习推理方面有明显优势,很多做目标检测的ROS项目都会优先选它。但Jetson的软件栈比树莓派复杂得多。首先是烧录系统,不是简单往SD卡里写镜像就行的,必须用JetPack SDK通过host machine进行烧录,整个过程涉及多个组件的刷写,耗时还挺长。
另一个高频需求是在Jetson上部署力控相关的深度学习库,比如涉及点云的spconv库。这个库在Jetson上编译时需要手动指定GPU的算力代际,不同的Jetson型号对应不同的算力值。我在Jetson Orin上编译时,需要在CMakeLists.txt或环境变量里设置TORCH_CUDA_ARCH_LIST参数,比如Jetson Orin系列对应的是8.7或8.9,如果是Jetson Nano则对应5.3,设置不对就会在编译时直接报不支持。
这类算力适配问题,fishros脚本没法直接帮你解决,因为涉及的是第三方库跟硬件底层的交互。但好消息是,只要ROS基础环境和CUDA环境能正常共存,这类问题一般都有迹可循,多看看编译日志就能定位。
5. 常见问题与排查技巧实录
5.1 高频报错排查速查表
这几年来实际遇到并且帮人排查过的报错实在太多,我整理一个高频问题速查表,按出现频率排序,方便你遇到问题时先对着查一遍。
| 报错信息 | 可能原因 | 解决方法 |
|---|---|---|
ERROR: cannot download from ... | 网络访问不了GitHub源 | 换镜像源后重试,或使用fishros修复rosdep |
W: GPG error: The repository ... is not signed | GPG key过期或导入不全 | 重新导入ROS仓库公钥 |
rosdep: command not found | python3-rosdep未安装 | 安装python3-rosdep后再执行sudo rosdep init |
ERROR: Rosdep experienced an error: ... | rosdep数据源配置损坏 | 删除~/.ros/rosdep缓存后重新update |
Package 'ros-<distro>-desktop' has no installation candidate | 软件源未添加或版本不匹配 | 检查Ubuntu版本与ROS发行版对应关系 |
fatal error: xxx.h: No such file or directory | 缺少系统级依赖库 | 用rosdep install或apt安装对应dev包 |
/usr/bin/ld: cannot find -lxxx | 链接库文件缺失 | 安装对应库的开发包,一般为libxxx-dev |
特别注意第一行这个报错,绝大多数rosdep update失败都落在这个类别里。如果你用了fishros的换源功能还是失败,可以试试清理本地缓存后再跑一次,有时候是之前残留的半截索引把新数据挤掉了。
5.2 不小心装坏了怎么恢复
我见过不少同学在安装过程中因为命令执行到一半Ctrl+C中断,或者改源改到一半把系统搞坏了,结果想重来又不知道从哪里下手。这里分享两个恢复技巧。
第一个技巧是清理rosdep缓存。如果你只是rosdep出问题,但ROS主包没问题,那不用重装系统,只需要把缓存目录删干净再重新初始化:
rm -rf ~/.ros/rosdep sudo rm -rf /etc/ros/rosdep sudo rosdep init rosdep update第二个技巧是卸载ROS相关包。如果你装的版本不对或者想换发行版,可以直接用apt把ROS系列包全卸掉:
sudo apt purge ros-* sudo apt autoremove卸载之后再把/etc/apt/sources.list.d/ros*.list里的软件源删掉或者注释掉,然后apt update一下,系统就基本回到没装ROS的状态了。
这两个技巧配合fishros脚本,基本上可以应对95%的ROS安装失败场景。我自己的原则是:能局部修复就局部修复,不要动不动就重装系统,重装虽然干净,但代价是时间成本太高。
5.3 几个值得记住的小习惯
最后分享几个平常不太容易在教程里看到的习惯,都是我踩过坑之后慢慢养成的。
第一个习惯是每次重装完系统,先把fishros脚本下载到本地存一份。虽然官方链接很稳定,但保不齐哪天网络抽风下载不了,本地有一份总归心里有底。而且脚本更新频率不高,存一份用上一年完全没问题。
第二个习惯是ROS2环境变量的切换要小心。如果你的机器上同时装了ROS1和ROS2,环境变量会在source的时候互相覆盖。我的方案是分别写两个别名命令,一个source /opt/ros/noetic/setup.bash,一个source /opt/ros/humble/setup.bash,平时用哪个就source哪个,不混用。
第三个习惯是如果你要在树莓派5这类新硬件上编译大量功能包,建议先加大swap空间再开工。树莓派5的内存虽然最大有16GB版本,但只靠内存编译很多大包还是会撞到墙。加一个8GB的swap文件能有效避免编译进程被OOM杀掉。
6. 写在最后的一点实际体会
从ROS1的Kinetic一路到ROS2的Jazzy,我自己经历过完全手动安装、半自动脚本安装、以及现在的fishros全流程安装三个阶段。早期手动安装的时候,每次成功都很有成就感,但次次都被rosdep update折磨一遍之后,我才意识到工具的作用不是让你变懒,而是帮你把精力花在更有价值的事情上。
现在的做法是,拿到一台新设备,先用fishros把基础环境和rosdep配好,然后花十分钟手动过一遍验证命令,确认无误之后再开始折腾具体功能。这套流程看起来简单,但帮我省下的时间实在太多了。如果你也在被ROS安装问题折磨,或者正准备给树莓派/Jetson搭环境,不妨试试这个方案,实测下来确实稳。