
上周帮一个刚入行的朋友远程看他的开发环境屏幕共享一打开终端里铺满了红色的E: 无法定位软件包 ros-jazzy-desktop。他说自己照着教程敲了整整两个小时从添加软件源到apt update全都跑了一遍最后一步死活装不上还以为是网络问题。我让他敲了lsb_release -a输出是 Ubuntu 22.04.3 LTS。问题瞬间就清楚了——他在 22.04 上装 Jazzy而 Jazzy 只认 24.04。这种差一个大版本号的错配是 ROS 2 安装环节里出现频率最高、也最容易被误判成网络问题的坑。这篇就把 Ubuntu 下装 ROS 2 这件事从头到尾拆一遍包括版本怎么选、三条安装路线怎么权衡、官方 apt 流程每一步在干什么、装完怎么验证以及那几种让人抓耳挠腮的报错到底卡在哪。不管你是刚接触 ROS 2 的新手还是已经能跑通小乌龟、但被环境问题反复折磨的老手下面这些内容应该都能省下你几个晚上的时间。1. 版本配对这一步没做对后面全是无用功1.1 一张表看懂 Ubuntu 代号和 ROS 2 发行版的绑定关系ROS 2 的每个发行版都严格绑定到特定的 Ubuntu LTS 上这不是官方偷懒而是绕不开的现实约束。ROS 2 底层大量依赖系统级的 C 运行库、Python 解释器版本以及 apt 仓库里的二进制依赖包跨 LTS 做兼容编译的成本高到不划算索性直接锁死。所以第一步永远是先确认你手上这台机器是哪个 Ubuntu 版本再反查该装哪个 ROS 2。ROS 2 发行版发布年份对应 Ubuntu支持状态Foxy Fitzroy202020.04 Focal已停止维护Humble Hawksbill202222.04 JammyLTS长期维护Iron Irwini202322.04 Jammy非 LTS已停止维护Jazzy Jalisco202424.04 NobleLTS长期维护Rolling滚动更新最新 LTS开发版不推荐生产用这里有个细节值得说一下Iron 和 Humble 都挂在 22.04 上但 Iron 是非 LTS 版本官方只维护大约一年半。很多教程因为发布时间的关系写的是 Iron你现在照着装过不了多久就会发现部分功能包已经不再更新。所以 22.04 上的选择其实很明确直接上 Humble24.04 上直接用 Jazzy。所谓装最新版总没错在 ROS 2 这里并不成立Rolling 分支是为框架开发者准备的接口变动频繁拿它学基础会平白增加很多挫败感。确认版本的三条命令我一般让新手一次性全敲一遍lsb_release -a cat /etc/os-release uname -mlsb_release -a看发行版号和代号/etc/os-release里的VERSION_CODENAME字段会直接给出jammy或noble这样的代号后面配软件源时要用它。uname -m是确认 CPU 架构普通电脑和服务器基本都是x86_64树莓派、部分国产开发板是aarch64。架构不对的话软件源里那些二进制包根本对不上apt update能过但apt install一定失败。顺便提醒一句如果你用的是 ARM 平台部分功能包的预编译版本可能缺失需要留出源码编译的时间预算。1.2 为什么该优先选 LTS 组合而不是能跑就行LTS 组合的价值在项目做到第二三个月才会体现出来。ROS 2 的生态里很多功能包导航、SLAM、机械臂驱动的版本是跟着发行版走的你选了一个非 LTS 的发行版过半年想装某个第三方包会发现它只发布了针对 Humble 或 Jazzy 的二进制版本而你手上这个版本既没有源码适配也没有二进制包只能自己啃编译错误。我见过太多人前期图快装了当时的最新版三个月后为了装一个激光雷达驱动不得不重装系统。所以如果这台机器是用来做长期项目的老老实实按 LTS 配对来代价是多花十分钟收益是后面几个月不折腾。2. 三条安装路线新手最该走哪一条2.1 官方 apt、一键脚本、源码编译的真实取舍市面上流传的安装方式主要三条官方 apt 二进制安装、国内社区的一键脚本、源码编译。它们的差别不只是快慢更关键的是出问题时你能不能自己定位。对比维度官方 apt一键脚本源码编译耗时10 到 30 分钟5 到 15 分钟2 到 6 小时可控性高每步可见低黑盒执行极高可复现性高中高出问题后定位难度低中高高适合人群新手首选赶时间的熟练用户需要改底层的开发者一键脚本比如社区里流传很广的那个鱼香 ROS 脚本确实好用它把换软件源、装依赖、初始化 rosdep、写环境变量这几件事打包成菜单让你选。它内部执行的其实还是官方那一套命令只是帮你把国内镜像源换好了。问题就在这里脚本报错的时候输出信息往往被菜单界面盖住你既不知道它换的是哪个源也不知道它卡在哪一步。我自己的习惯是第一次装 ROS 2 一定手动走一遍官方流程把每一步在干什么搞清楚等第二台、第三台机器再考虑用脚本提速。2.2 源码编译什么时候才值得碰源码编译不该出现在安装 ROS 2这个环节的讨论里。只有三种情况值得考虑一是你的架构官方没有提供二进制包二是你需要给 ROS 2 核心打补丁比如定制 DDS 实现三是你要做框架层面的二次开发。普通学习和项目开发完全没必要colcon build一个完整工作空间动辄几小时中间任何一个依赖缺失都会中断排查成本远高于收益。所以后面的内容全部围绕官方 apt 这条路线展开。3. 官方 apt 安装链路的完整拆解3.1 前置准备locale、universe 仓库和基础工具locale 这一步经常被跳过但它引发的报错很难一眼看出根因。ROS 2 的日志系统、节点命名、yaml 参数文件都按 UTF-8 编码处理如果系统的 locale 不是 UTF-8构建时会抛出编码相关的异常运行时中文日志会变成乱码某些 Python 节点甚至直接启动失败。sudo apt update sudo apt install -y locales curl gnupg lsb-release software-properties-common sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALLen_US.UTF-8 LANGen_US.UTF-8 export LANGen_US.UTF-8 locale最后那条locale是用来验证的输出里能看到LANGen_US.UTF-8和LC_ALLen_US.UTF-8就对了。export只对当前终端生效update-locale才是写进配置文件持久化的两者要一起用。software-properties-common是为了拿到add-apt-repository命令接着打开 universe 仓库sudo add-apt-repository universe sudo apt updateuniverse 里装着python3-vcstool、colcon这类工具ROS 2 的很多依赖会从这里拉。不开这个源后面装python3-colcon-common-extensions时会提示找不到包。3.2 软件源与签名密钥新版 ros2-apt-source 的做法几年前的标准做法是apt-key add加手写 sources.list现在官方已经改成了独立的 deb 包来管理软件源和密钥。改动的原因是apt-key会把密钥加到全局信任链里任何仓库都能用它签名安全边界很模糊新做法把密钥绑定到具体仓库上只有这个仓库的包才会被信任。sudo apt update sudo apt install -y curl export ROS_APT_SOURCE_VERSION$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F tag_name | awk -F\ {print $4}) curl -L -o /tmp/ros2-apt-source.deb https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release echo $VERSION_CODENAME)_all.deb sudo dpkg -i /tmp/ros2-apt-source.deb sudo apt update这里有个非常容易翻车的点第一行的 curl 是去问 GitHub 要最新版本号。这一步如果拿不到数据ROS_APT_SOURCE_VERSION就是空字符串后面拼接出来的下载地址会变成.../download//ros2-apt-source__noble_all.deb这种畸形链接dpkg报错说文件不存在。解决办法很直接手动打开那个 releases 页面看一眼版本号直接写死export ROS_APT_SOURCE_VERSION1.1.0版本号按你看到的实际值填。另外如果你的网络访问 GitHub 不稳定也可以走手工写源的老路子效果等价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注意这里用$UBUNTU_CODENAME而不是$VERSION_CODENAME。这两个变量在大多数情况下值相同但在某些定制镜像上会有差异ROS 官方文档明确要求用UBUNTU_CODENAME照着写就行。写完源之后如果 npm 速度慢把packages.ros.org换成国内镜像地址可以显著提升下载速度具体镜像地址以各镜像站当前的说明为准。3.3 装哪个包desktop、ros-base 和 ros-core 的差别apt install这一步涉及一个选择装哪个粒度的包。包名包含内容适用场景ros-jazzy-ros-base核心通信库、命令行工具、基础依赖机器人本体、服务器ros-jazzy-desktopros-base 加 rviz2、demo 节点、教程包桌面开发和学习ros-jazzy-desktop-fulldesktop 加仿真相关组件需要 Gazebo 仿真学基础阶段直接上 desktop因为你一定会用到 rviz2 做可视化用小乌龟做通信验证这些都在 desktop 里。机器人本体上部署时图形界面用不上装 ros-base 能省下不少磁盘空间。安装命令本身很简单sudo apt install ros-jazzy-desktop把jazzy换成你对应的发行版名即可比如 Humble 就写ros-humble-desktop。这一步的耗时取决于网络几百兆到一两个 G 的包慢的话可能要等十几分钟中途别关终端。如果卡在某个包上一直不动可以按一次 CtrlC 中断后重新执行sudo apt install ros-jazzy-desktopapt 会从缓存里续上不会从头再来。3.4 source 环境变量命令找不到的根因就在这里装完之后你敲ros2大概率会得到ros2: command not found。这不是安装失败而是安装的目录/opt/ros/jazzy/bin还没进 PATH。ROS 2 用一套 shell 脚本来做这件事source /opt/ros/jazzy/setup.bash执行完再敲ros2 --help应该就能看到命令列表了。但这条命令只对当前终端有效新开一个终端窗口又得重来一遍。所以需要写进 shell 的启动配置echo source /opt/ros/jazzy/setup.bash ~/.bashrc source ~/.bashrc这里要区分三个脚本setup.bash会先清理掉之前 source 过的其他 ROS 环境再加载当前这个适合在.bashrc里用local_setup.bash只加载当前这一层不清理上层适合在工作空间的叠加层里用setup.sh是给不支持 bash 的 shell 准备的。搞不清就用setup.bash出问题的概率最小。注意如果你用的是 zsh 而不是 bash写进.bashrc是无效的得写到~/.zshrc里而且要 source 的是 setup.zsh。这类配置写对了地方但是没用的情况在排查环境问题时占了相当大的比例。4. 装完别急着开项目先做这几步验证4.1 用 talker 和 listener 验证话题通信验证的第一步不是打开图形界面而是确认最底层的通信能不能跑起来。开两个终端分别 source 环境后执行ros2 run demo_nodes_cpp talker ros2 run demo_nodes_py listenertalker 会不停打印Publishing: Hello World: 1listener 那边同步打印I heard: [Hello World: 1]。两边都能看到输出说明 DDS 通信中间件、Python 和 C 两套客户端库、话题机制全部正常工作。这一步特别有价值因为它把图形环境、显卡驱动这些干扰因素全部排除了出问题就一定是核心通信层的事。如果 listener 没有任何输出先检查两个终端是不是都在同一个 ROS_DOMAIN_ID 下默认都是 0但如果你之前设置过这个环境变量两边不一致就会互相看不见。用echo $ROS_DOMAIN_ID可以确认。4.2 小乌龟和 rviz2图形链路的试金石通信没问题之后再验证图形界面sudo apt install ros-jazzy-turtlesim ros2 run turtlesim turtlesim_node弹出的蓝色窗口里有一只小乌龟。再开一个终端跑键盘控制ros2 run turtlesim turtle_teleop_key鼠标要点在运行 teleop 的那个终端上方向键才有反应这是新手最常见的困惑之一。小乌龟能跑起来说明图形渲染链路通了。接着试试 rviz2ros2 run rviz2 rviz2如果 rviz2 报错说无法创建 OpenGL 上下文那基本是显卡驱动或者虚拟机 3D 加速的问题跟 ROS 2 本身没关系需要去处理系统层面的图形环境。虚拟机里尤其容易出现这个情况后面会专门说。4.3 colcon 与 rosdep 的初始化这两个工具在你真正开始写代码之后会天天用所以装完 ROS 2 顺手把它们配好。colcon 是构建工具相当于 ROS 2 世界里的 cmake 加上 make 的封装sudo apt install python3-colcon-common-extensions echo source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash ~/.bashrc第二行是给 colcon 加命令补全写工作空间名的时候能省不少事。rosdep 负责在构建前把系统依赖装齐初始化分两步sudo apt install python3-rosdep sudo rosdep init rosdep updaterosdep init会在/etc/ros/rosdep/sources.list.d/下写一个默认源配置文件rosdep update去拉源数据缓存到本地。这两步在国内网络环境下经常卡住表现是长时间没有输出然后超时。这种情况可以换用社区提供的 rosdep 镜像源或者改用带国内加速的变体工具具体做法网上有现成说明核心就是把拉取地址换成能稳定访问的镜像。我自己的做法是初始化一次之后把本地缓存备份下来换机器的时候直接恢复省得每次重装都去跟网络较劲。5. 报错排查实录几个高频坑的定位链路5.1 ros2: command not found 的三层排查链路这个报错出现的频率最高但原因至少有三种得按顺序往下查。第一层当前终端是不是没 source。直接执行source /opt/ros/jazzy/setup.bash再试一次。能用了说明是环境变量没加载。第二层如果你已经写进了~/.bashrc但还是不行检查三件事~/.bashrc里那行有没有拼错比如版本名写成了 humble 但装的是 jazzy你用的是不是 zsh配置文件对不对.bashrc里有没有在 source ROS 之前就return掉了。第三件事很隐蔽有些配置会在.bashrc开头判断非交互式 shell 就直接 return如果你把 source 那行加在了 return 之后永远不会被执行。第三层如果手动 source 之后还是找不到命令那就是真没装上。执行ls /opt/ros/看目录在不在。目录空空如也说明之前那次apt install其实失败了只是被滚动的输出淹没了。回头看/var/log/apt/history.log能找到那次安装的完整记录和失败原因。5.2 依赖冲突与 Python 环境抢占装 ROS 2 相关包的时候偶尔会碰上依赖版本打架典型的输出是下列软件包有未满足的依赖关系。这种情况九成是因为系统里混入了第三方源或者之前手动pip install装过某个包版本比 apt 仓库里的还新。ROS 2 的 Python 生态高度依赖系统自带的 python3如果被 conda 或者其他 Python 发行版抢了优先级症状会更奇怪——ros2命令能用但一跑 Python 节点就报模块找不到或者版本不匹配。排查方式是确认which python3指向哪里。正常应该指向/usr/bin/python3。如果指向 conda 环境下的路径那么在跑 ROS 2 之前先执行conda deactivate或者干脆在.bashrc里把 conda 的自动激活关掉。我踩过这个坑当时是numpy版本被 conda 换成了更高的版本导致某个依赖它的功能包直接崩掉报的错误跟 numpy 一点关系都没有查了大半天才反应过来是环境隔离的问题。所以一个硬性建议不要在系统 Python 里用 pip 装 ROS 相关的包需要什么就用 apt 装对应的python3-xxx包。5.3 apt update 报 NO_PUBKEY 或 404NO_PUBKEY说明密钥没装上或者装错了。回头重新执行 3.2 节里的 keyring 那一步确认/usr/share/keyrings/ros-archive-keyring.gpg文件存在且不为空ls -l看一眼大小正常是几 KB。如果文件存在但还是报这个错检查 sources.list 里那行的签名参数路径有没有写错。404 通常有两种情况。一种是发行版代号写错了比如在 24.04 上写了jammy那个路径下确实没有对应的包索引apt 就会返回 404。另一种是没有对应发行版的预编译包这种情况只能退回源码编译。我建议在apt update之后留意一下有没有Err开头的行很多人只顾着看最后的E:报错忽略了中间那几行提示其实那才是根因。报错信息常见根因处理方向command not found环境变量未加载或安装失败先手动 source再查 /opt/ros 目录NO_PUBKEY密钥文件缺失或签名路径错误重装 keyring核对 sources.list 路径404 Not Found发行版代号与系统不匹配用 /etc/os-release 确认代号依赖关系未满足第三方源或 pip 版本冲突排查 which python3清理冲突包6. WSL2、虚拟机和多版本共存的处理方式6.1 WSL2 环境下的图形显示与网络在 Windows 上用 WSL2 装 Ubuntu 再装 ROS 2是很多人的选择因为能直接用 Windows 的编辑器写代码体验接近原生。核心难点在图形界面。较新的 Windows 版本自带图形支持装完 ROS 2 之后直接ros2 run rviz2 rviz2就能弹出窗口。老版本 Windows 需要额外配置显示服务把显示地址指向主机具体做法是设置DISPLAY环境变量。网络方面有一点要留意WSL2 用的是独立的虚拟网络和 Windows 主机不在同一个网段。如果你的机器人本体在局域网里WSL2 里的节点可能发现不了它。这时候需要调整网络模式或者做端口映射。另外 WSL2 里跑图形化的仿真会比较吃力如果主要做仿真和导航我还是推荐用双系统或者直接在 Ubuntu 物理机上做。6.2 虚拟机的资源分配与 3D 加速VMware 或者 VirtualBox 里装 Ubuntu最容易出的问题是内存和显存给得太少。ROS 2 加上 rviz2 跑起来内存占用轻松上 4 个 G虚拟机只给 2 个 G 的话会频繁卡顿甚至被系统杀掉进程。我的建议是内存至少 8 G硬盘 50 G 起步处理器核心数给到宿主机的一半。3D 加速要记得开。VirtualBox 需要装增强功能包并勾选 3D 加速VMware 需要确保显卡驱动是三D 版本。没开的话 rviz2 启动时会报无法创建 OpenGL 上下文。另外 Gazebo 这类仿真器在虚拟机里跑会非常吃力即便开了加速帧率也很难让人满意学习基础知识够用做正经的仿真项目还是要考虑物理机。6.3 多个发行版共存时的 source 顺序有时一台机器上会同时装 Humble 和 Jazzy用来做跨版本对比或者维护老项目。它们都装在/opt/ros/下面各占一个目录ls /opt/ros/切换的方式是在终端里 source 对应的setup.bash。关键点是.bashrc里不应该写死某一个版本否则每次开终端都会把另一个版本覆盖掉。更稳妥的做法是把两个版本写成别名或者函数需要哪个手动切alias ros2hsource /opt/ros/humble/setup.bash alias ros2jsource /opt/ros/jazzy/setup.bash还有一个隐含问题同一个工作空间用不同版本编译出来的产物不通用切换版本后需要重新colcon build而且最好先删掉旧的build和install目录否则会残留指向旧版本的缓存路径导致运行时报各种库找不到的错。我一般习惯在工作空间目录名里带上版本号比如ws_humble和ws_jazzy从源头上避免混淆。最后分享一个小习惯装完 ROS 2 之后我会立刻在系统里记一份环境档案把发行版名、Ubuntu 版本、安装日期、软件源地址、关键环境变量这几项写进一个文本文件放在家目录下。以后遇到问题时一看就知道当时是什么状态也不用去翻历史记录猜。这个动作花不到一分钟但在后期排查疑难杂症的时候价值远超那一分钟。