1. 为什么这个安装方案值得单独拿出来讲
ROS Melodic 是 ROS1 生态里相当特殊的一个版本,它官方绑定的系统就是 Ubuntu 18.04,两者之间的依赖关系咬得很死。很多人第一次装 ROS,卡住的地方根本不是编译报错,而是rosdep update这一步反复超时、反复重试、最后直接放弃。我自己前前后后在不同机器上装过不下十次 Melodic,踩过的坑基本都集中在网络环节,所以这套“先把压缩包拉到本地,再离线喂给 rosdep”的思路,是我目前最推荐给新手的做法。
先说清楚这套方案适合谁。如果你手上是一台刚装好的 Ubuntu 18.04,网络环境不太理想,或者你希望整个安装过程可控、可复现、不依赖实时网络,那这套流程就是为你准备的。它解决的核心问题有三个:一是apt安装阶段因为源的问题卡住,二是rosdep init和rosdep update因为访问外部资源失败而中断,三是整个安装过程不可重复,换台机器就得重新赌一次网络。
需要提前说明的是,本文讲的“网络原因”指的是访问软件源和依赖索引时的连通性问题,处理思路是提前把需要的资源下载到本地,再让安装程序从本地读取。这是纯粹的工程做法,和任何特定网络工具无关,你只需要有一台能正常下载文件的机器即可。
整套流程我拆成四块:环境确认与源配置、核心包安装、rosdep 离线处理、验证与收尾。每一块我都会把“为什么这么做”讲透,因为只照着命令敲,遇到变体情况你还是会懵。
2. 装之前必须确认的几件事
2.1 系统版本和架构别搞错
ROS Melodic 只认 Ubuntu 18.04,代号 bionic。你可以在终端里跑一句确认:
lsb_release -a输出里Release必须是18.04,Codename必须是bionic。我见过有人拿 20.04 硬装 Melodic,apt阶段就开始报一堆依赖冲突,最后装出来的东西半死不活。架构方面,Melodic 官方支持 amd64 和 arm64,用uname -m看一眼,x86_64对应 amd64,aarch64对应 arm64。这个信息后面配源的时候要用到。
还有一点容易被忽略:确认你的系统是全新安装还是已经装过别的 ROS 版本。如果之前装过 Noetic 或者别的版本,/opt/ros目录下可能已经有残留,apt源列表里也可能有旧条目。我的建议是,装 Melodic 之前先把旧的 ROS 相关源清理干净,避免版本串味。
2.2 磁盘空间和权限
ROS Melodic 的桌面完整版装下来大概要占 2 到 3 GB,加上你后面要放的离线压缩包,建议预留至少 10 GB 空闲空间。用df -h看一下根分区。权限方面,全程需要 sudo,确认你的账号在 sudoers 里,这个一般没问题。
2.3 先把系统自带源理顺
这一步是很多人跳过、但后面会反复回来补的。Ubuntu 18.04 默认的软件源在国内访问速度参差不齐,装 ROS 之前先把系统源换成响应快的镜像,能省掉大量等待时间。具体换哪个镜像,你根据自己实际能访问的来选,这里不指定具体地址,只讲方法:编辑/etc/apt/sources.list,把archive.ubuntu.com和security.ubuntu.com替换成你手头可用的镜像域名,然后:
sudo apt update sudo apt upgrade -yupgrade这一步别省,把系统补丁打齐,后面装 ROS 依赖时能少一堆版本冲突。我实测下来,系统本身没更新干净,是后面apt install报依赖错误的常见原因之一。
提示:换源之后如果
apt update报 GPG 签名错误,说明镜像的公钥没导入,先解决签名问题再往下走,不要带着报错硬装。
3. 配置 ROS 软件源的正确姿势
3.1 添加源和密钥
ROS 的软件源和系统源是分开的。官方文档给的命令是往/etc/apt/sources.list.d/ros-latest.list里写一条源地址,然后导入密钥。这里的关键在于,源地址里的packages.ros.org如果访问不畅,apt update就会卡住。处理办法是提前把这条源也指向你能访问的镜像。
添加源的命令长这样:
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu bionic main" > /etc/apt/sources.list.d/ros-latest.list'如果你要用镜像,把packages.ros.org/ros/ubuntu换成镜像对应的路径即可。密钥导入用:
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654密钥服务器如果连不上,可以换一个 keyserver 地址,或者提前把密钥文件下载到本地再用apt-key add导入。这一步失败的话,后面apt update会直接报NO_PUBKEY,装不了任何 ROS 包。
3.2 更新索引并确认源生效
sudo apt update更新完之后,用下面这条命令确认 ROS 源已经被识别:
apt-cache policy ros-melodic-desktop-full如果能看到候选版本号,说明源配好了。看不到的话,回头检查源文件路径和密钥,别急着往下装。
3.3 为什么建议先下载压缩包到本地
标题里特别强调了“先将所需压缩包下载到本地”,这个思路的价值在于把不可控的实时网络访问,变成可控的本地文件操作。具体来说,有两类东西适合提前下载:
第一类是 ROS 的核心 deb 包。如果你担心apt install过程中断,可以用apt-get install --download-only先把包下到/var/cache/apt/archives/,再离线安装。命令是:
sudo apt-get install --download-only ros-melodic-desktop-full这样包会先落到本地缓存,网络断了也不影响已经下好的部分,重试时只补缺的。
第二类就是 rosdep 需要的索引文件,这个放到下一节重点讲。把这两类资源都本地化之后,整个安装过程就变成“本地文件搬运”,稳定性完全不一样。
4. 核心包安装与依赖处理
4.1 安装桌面完整版
sudo apt install ros-melodic-desktop-full这一步会拉一大堆依赖,包括 Gazebo、RViz、各种感知和仿真库。如果前面源配好了,这一步通常能顺利跑完。中途如果报某个依赖找不到,大概率是系统源和 ROS 源没同步好,先apt update再重试。
装完之后,环境变量要配一下:
echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc source ~/.bashrc这一步别偷懒用setup.sh之外的写法,Melodic 的setup.bash是标准入口。配好之后新开终端会自动加载,echo $ROS_DISTRO应该输出melodic。
4.2 安装构建工具和依赖
sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential这几个包是后面编译工作空间和跑 rosdep 的基础。python-rosdep尤其关键,它就是接下来离线处理的主角。装的时候如果提示某个包已经是最新版,正常,跳过即可。
4.3 初始化 rosdep 的坑点
sudo rosdep init这条命令做的事情是从网上拉一个20-default.list文件放到/etc/ros/rosdep/sources.list.d/。问题就出在这里,它访问的地址经常连不上,报错通常是ERROR: cannot download default sources list from...。
处理办法有两个方向。方向一是换一个能访问的镜像地址,把rosdep init实际访问的 URL 替换掉。方向二是干脆手动创建这个文件,把内容写进去,绕过init的网络请求。我一般用方向二,因为最可控:
sudo mkdir -p /etc/ros/rosdep/sources.list.d/ sudo tee /etc/ros/rosdep/sources.list.d/20-default.list << 'EOF' # os-specific listings first yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/osx-homebrew.yaml osx # generic yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/base.yaml yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/python.yaml yaml https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/ruby.yaml gbpdistro https://raw.githubusercontent.com/ros/rosdistro/master/releases/fuerte.yaml fuerte EOF注意,这里写进去的 URL 是 rosdep 后续update时要访问的。如果你网络访问这些地址不畅,就要在下一步做本地化替换。
5. rosdep update 离线化处理全流程
5.1 理解 rosdep update 到底在干什么
rosdep update的本质是把一堆 YAML 索引文件下载到本地~/.ros/rosdep/sources.cache/目录下,然后建立缓存。它要下载的文件包括base.yaml、python.yaml、ruby.yaml以及各个 rosdistro 的distribution.yaml。这些文件加起来体积不大,但数量多,逐个下载时任何一个超时都会导致整个 update 失败。
所以离线化的思路很直接:在一台能正常访问的机器上,把这些文件全部下载下来,打包拷到目标机器,然后让 rosdep 从本地读取。这里有两种实现路径,我都讲一下。
5.2 路径一:手动下载并替换缓存
先在一台网络正常的机器上,把 rosdep 需要的文件结构完整拉下来。最省事的办法是在那台机器上正常跑一次rosdep update,然后把~/.ros/rosdep/sources.cache/整个目录打包。这个目录的结构大致是:
sources.cache/ ├── index └── ...(各个 yaml 文件按 hash 命名)把打包好的sources.cache拷到目标机器的~/.ros/rosdep/下,覆盖同名目录。然后关键一步,修改/etc/ros/rosdep/sources.list.d/20-default.list,把里面的 URL 全部改成file://开头的本地路径,指向你放好的文件。比如:
yaml file:///home/yourname/rosdep_local/base.yaml这样rosdep update就只读本地文件,不再发起网络请求。实测下来,这种方式最稳,因为完全绕开了网络。
5.3 路径二:用本地 HTTP 服务模拟源
如果你不想改20-default.list里的 URL 结构,可以在本地起一个简单的 HTTP 服务,把下载好的文件目录暴露出去,然后把20-default.list里的域名换成127.0.0.1加端口。比如用 Python 自带的:
cd /path/to/rosdep_files python -m SimpleHTTPServer 8000然后把源地址改成http://127.0.0.1:8000/...。这种方式的好处是 URL 结构不用大改,rosdep 以为自己在访问网络,实际走的是本地回环。缺点是每次 update 前都要先把服务起起来。
5.4 两种路径的对比
| 对比项 | 手动替换缓存 | 本地 HTTP 服务 |
|---|---|---|
| 网络依赖 | 完全无 | 仅本地回环 |
| 操作复杂度 | 中,需改配置文件 | 低,改域名即可 |
| 可重复性 | 高,一次配好长期用 | 中,每次要起服务 |
| 适合场景 | 长期固定机器 | 临时调试 |
我个人更推荐路径一,配好之后一劳永逸。路径二适合你只是想快速验证一下,不想动配置文件的情况。
5.5 执行 update 并验证
配置好之后执行:
rosdep update如果一切正常,你会看到它逐个读取本地文件并建立缓存,最后输出updated cache in ...。这时候可以跑一句验证:
rosdep resolve roscpp能正常输出依赖解析结果,就说明 rosdep 已经可用了。
注意:
rosdep update默认会检查文件的时间戳和 hash,如果你手动替换的缓存和20-default.list里声明的对不上,它会重新尝试下载。所以替换缓存和改 URL 这两步要配套做,不能只做一半。
6. 常见问题与排查速查
6.1 apt 阶段典型报错
| 报错信息 | 原因 | 处理办法 |
|---|---|---|
NO_PUBKEY | ROS 源密钥没导入 | 重新导入密钥,或换 keyserver |
404 Not Found | 源地址路径写错 | 核对 bionic 和 main 是否拼对 |
| 依赖冲突 | 系统源没更新或混入旧 ROS 源 | 清理旧源,apt update后重试 |
| 下载中断 | 网络不稳 | 用--download-only先下到本地 |
6.2 rosdep 阶段典型报错
| 报错信息 | 原因 | 处理办法 |
|---|---|---|
cannot download default sources list | init 访问网络失败 | 手动创建 20-default.list |
ERROR: unable to process source | 某个 yaml 下载失败 | 本地化该文件并改 URL |
update timeout | 逐个下载超时 | 整体替换 sources.cache |
no rosdep cache | 缓存目录权限不对 | 检查 ~/.ros 属主 |
6.3 几个我踩过的坑
第一个坑是rosdep init和rosdep update用的不是同一个用户。init是 sudo 跑的,写的是/etc/ros/;update是普通用户跑的,写的是~/.ros/。如果你用 sudo 跑update,缓存会写到 root 的 home 下,普通用户读不到。这个错误很隐蔽,表现是 update 显示成功,但编译时 rosdep 又说没缓存。
第二个坑是手动替换缓存后忘了改文件权限。~/.ros/rosdep/sources.cache/如果属主是 root,普通用户 update 时会报权限错误。用chown -R $USER:$USER ~/.ros修一下。
第三个坑是20-default.list里的 URL 改了,但缓存里的 index 文件还指向旧地址,导致 update 时又去访问网络。解决办法是改完 URL 后把sources.cache整个删掉,重新 update 一次让它重建。
7. 安装后的验证与工作空间初始化
7.1 基础验证
装完之后跑几个命令确认环境正常:
roscore新开一个终端:
rosrun turtlesim turtlesim_node再开一个:
rosrun turtlesim turtle_teleop_key能看到小乌龟窗口并且键盘能控制它动,说明核心环境没问题。这一步别跳过,它是判断整个安装是否成功的黄金标准。
7.2 初始化工作空间
mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ catkin_makecatkin_make第一次跑会编译一堆东西,如果 rosdep 配好了,依赖解析会很快。编译完成后:
source devel/setup.bash echo $ROS_PACKAGE_PATH能看到~/catkin_ws/src在路径里,就说明工作空间配好了。
7.3 用 rosdep 装依赖的实战
在工作空间里,如果你 clone 了一个需要额外依赖的包,标准做法是:
rosdep install --from-paths src --ignore-src -r -y这条命令会扫描src下所有包的package.xml,解析出缺失依赖并安装。如果前面 rosdep 离线化做得好,这一步会非常顺。我实测下来,离线化之后这条命令的失败率从大概三成降到了接近零。
8. 一些让流程更顺的补充经验
8.1 把整个流程脚本化
这套步骤我建议写成一个 shell 脚本,把源配置、密钥导入、包安装、rosdep 本地化串起来。这样换机器时直接跑脚本,不用回忆每一步。脚本里对每个可能失败的点加判断,比如密钥导入失败就提示手动处理,而不是直接往下走。
8.2 离线资源的版本管理
你下载的 rosdep 索引文件是有时效性的,rosdistro 会更新。建议每隔一段时间重新拉一次最新文件,替换本地的旧版本。可以在脚本里加一个日期标记,方便你知道当前用的是哪一版。
8.3 关于镜像选择
镜像的选择没有绝对最优,取决于你实际能访问哪个。我的做法是准备两三个候选,哪个快用哪个。配源的时候把候选都写进注释,切换时改一行就行。
8.4 编译大型包时的内存问题
Melodic 上编译一些大型包,比如带大量模板的 C++ 项目,可能会因为内存不足被 OOM killer 干掉。表现是编译到一半突然中断,日志里没有明显错误。处理办法是加 swap,或者用catkin_make -j2限制并行编译数。这个坑我在小内存机器上遇到过好几次,一开始还以为是代码问题。
8.5 环境变量的加载顺序
如果你同时装了多个 ROS 版本,~/.bashrc里 source 的顺序很重要。后 source 的会覆盖前面的。确认echo $ROS_DISTRO输出的是你当前想用的版本。这个细节在多版本共存时特别容易出问题。
整套流程走下来,核心就一句话:把不可控的网络访问,变成可控的本地文件操作。apt 阶段用--download-only预下载,rosdep 阶段用本地缓存加 file URL 替换,两步做完,Melodic 的安装就从“看运气”变成了“按步骤执行”。我在几台网络条件各异的机器上都用这套方法装过,成功率很稳定。如果你在替换缓存那一步遇到 index 对不上的问题,把sources.cache删干净重新 update 一次,基本都能解决。