1. 为什么要在 Ubuntu 18.04 上折腾 ROS2 Eloquent
ROS2 的版本迭代节奏跟 ROS1 完全不是一个玩法。ROS1 是"一个版本管好几年",ROS2 则是"半年一版,两年一停维护"。Eloquent Eloquent(代号 Eloquent Elusor)是 2019 年 11 月发布的第七个 ROS2 正式版,它的官方支持周期到 2020 年 11 月就结束了。按理说现在没人应该碰它,但现实情况是——不少工业设备、教学实验平台、老旧的工控机还锁死在 Ubuntu 18.04 上,而 Ubuntu 18.04 能装的 ROS2 版本里,Eloquent 是最后一个官方提供二进制包的(再往后的 Foxy 要求 Ubuntu 20.04)。这就导致一个很尴尬的局面:你想用 ROS2,系统又不能升级,那 Eloquent 就是唯一的选择。
我自己就遇到过这种情况。某实验室的一批工控机跑的是定制化的 Ubuntu 18.04 镜像,上面绑了一堆驱动和采集卡,重装系统意味着重新适配所有硬件,成本太高。但项目又要求用 ROS2 做多机通信和实时控制,绕不开。最后硬着头皮在 18.04 上把 Eloquent 装起来,中间踩了不少坑,这里把完整过程和我自己的经验整理出来。
这篇文章适合三类人看:一是手上确实有 Ubuntu 18.04 环境、不得不装 ROS2 的开发者;二是想了解 ROS2 早期版本安装逻辑、做版本对比的技术人员;三是刚接触 ROS2、想搞清楚"装一个 ROS2 到底涉及哪些环节"的新手。我会从方案选型讲到实操步骤,再到问题排查,尽量把每个"为什么这么做"讲清楚,而不是甩几条命令让你复制粘贴。
需要先说明一点:Eloquent 已经停止官方维护,二进制包源虽然还在,但不再更新安全补丁。如果是新项目,强烈建议直接上 Ubuntu 20.04 + Foxy 或更高版本。本文的场景限定在"系统动不了、只能用 18.04"这个前提下。
2. 安装前的整体方案设计与选型考量
2.1 二进制包安装 vs 源码编译,怎么选
装 ROS2 有两条路:一是用 apt 从官方源装二进制包,二是下载源码自己编译。很多人一上来就想源码编译,觉得"可控性强",但实际上对绝大多数人来说这是给自己找麻烦。
二进制包安装的优势非常直接:快、省事、依赖自动处理。官方已经把 Eloquent 在 Ubuntu 18.04(Bionic)上的依赖关系打包好了,你只要配好源、敲一条apt install,十几分钟就能跑起来。源码编译呢?光是拉取代码、装编译工具链、处理各种依赖冲突,顺利的话两三个小时,不顺利的话一整天都搭进去,而且编译过程中任何一个依赖版本不对,报错信息能让你怀疑人生。
那什么时候才需要源码编译?只有两种情况:一是你要改 ROS2 的底层源码(比如做通信中间件的定制),二是官方二进制包在你的架构上不存在(比如某些 ARM 平台)。普通开发、学习、做应用层的东西,二进制包完全够用。
所以本文的方案就是:apt 二进制包安装。这是最稳妥、最省时间的路径。
2.2 安装源的选择与区域考量
ROS2 的 apt 源官方主站访问速度在国内往往不理想,下载几百兆的包可能要等很久甚至超时。常见的做法是换用国内镜像源。这里我不点名具体镜像站,只讲选择逻辑:优先选你所在网络环境下延迟低、同步及时的镜像。判断一个镜像好不好用,看两点——一是它同步官方源的频率(最好每天同步),二是它是否完整保留了dists/bionic/main这个目录结构。
配置源的时候有个细节容易被忽略:ROS2 的源和 ROS1 的源是分开的,包名也不一样。ROS1 的包叫ros-<distro>-xxx,ROS2 的包叫ros-<distro>-xxx,但 distro 名字不同(ROS1 是 melodic,ROS2 是 eloquent)。如果你机器上同时装了 ROS1 和 ROS2,两个源都要配,但要注意环境变量别冲突,这个后面会讲。
2.3 依赖环境的预判
Ubuntu 18.04 默认的 Python 版本是 3.6,这个版本对 Eloquent 来说是够用的(Eloquent 要求 Python 3.6+)。但有几个坑要提前知道:
- locale 设置:ROS2 对系统 locale 有要求,必须是 UTF-8。如果 locale 没设对,
ros2命令会直接报错退出。这是新手最容易卡住的地方。 - apt 依赖:需要确保
curl、gnupg、lsb-release这些基础工具都在,一般系统自带,但精简安装的镜像可能缺。 - 磁盘空间:完整装下来大概占 1.5 到 2 GB,留够空间。
把这些想清楚再动手,能省掉后面一半的排查时间。
3. 核心安装步骤的逐环节拆解
3.1 系统 locale 的检查与修正
这一步很多人会跳过,然后被ros2命令的报错搞得莫名其妙。ROS2 内部大量使用 UTF-8 编码处理字符串,如果系统 locale 是POSIX或者C,运行时会直接抛异常。
先检查当前 locale:
locale看输出里的LANG和LC_ALL。如果显示的是C或POSIX,就得改。修正方法是设置成en_US.UTF-8:
sudo apt update sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8这里解释一下为什么选en_US.UTF-8而不是中文 locale。ROS2 的日志和错误信息都是英文的,用英文 locale 能保证终端输出不乱码,排查问题时也方便搜索。中文 locale 在某些终端下会导致日志里的字符显示异常,反而添乱。
改完之后再跑一次locale,确认LANG=en_US.UTF-8生效。注意export那条命令只对当前终端会话有效,要永久生效得写进~/.bashrc,或者靠update-locale写入系统配置。
提示:如果你是在 Docker 容器里装,locale 问题更常见,因为很多基础镜像默认就是
POSIX。容器里记得把locale-gen和update-locale都跑一遍。
3.2 配置 apt 软件源
先确保curl和gnupg可用:
sudo apt update && sudo apt install curl gnupg2 lsb-release然后添加 ROS2 的 GPG 密钥。密钥的作用是验证包的签名,防止下载到被篡改的包。命令是:
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc -o /usr/share/keyrings/ros-archive-keyring.gpg如果这条命令因为网络原因拉不下来,可以换用镜像站提供的密钥文件,或者手动下载后放到/usr/share/keyrings/目录下。
接着把源地址写进 apt 的源列表:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null这里$(lsb_release -cs)会自动替换成bionic(Ubuntu 18.04 的代号),$(dpkg --print-architecture)会替换成amd64。用变量而不是写死,是为了命令在不同机器上都能用。
如果你要用国内镜像,把上面那条命令里的http://packages.ros.org/ros2/ubuntu换成镜像站地址即可,其余部分不变。换完之后跑sudo apt update,看看能不能正常拉到 ROS2 的包索引。如果报NO_PUBKEY错误,说明密钥没配对,回头检查密钥文件路径。
3.3 安装 ROS2 Eloquent 主体包
源配好之后,安装就一条命令的事。Eloquent 提供两种安装规格:
- ros-eloquent-ros-base:基础版,只含核心通信库、命令行工具,不含 GUI 工具和仿真。
- ros-eloquent-desktop:桌面版,在 base 基础上加了 rviz2、demo 节点、教程等。
选哪个看需求。如果你只是做无界面的机器人控制、跑在工控机上,base 版就够了,体积小、依赖少。如果你要可视化调试、跑示例,那就装 desktop。我一般建议新手先装 desktop,把示例跑通了再考虑精简。
sudo apt update sudo apt install ros-eloquent-desktop安装过程中 apt 会自动处理一大堆依赖,包括python3-colcon、python3-rosdep这些构建工具。整个下载量在 500 MB 到 1 GB 之间,取决于你之前装过多少相关包。网速正常的话十几分钟能装完。
装完之后可以验证一下包是否注册成功:
apt list --installed | grep ros-eloquent应该能看到一长串已安装的包。
3.4 环境变量的加载与验证
装完不代表能用,还得让 shell 知道 ROS2 装在哪了。ROS2 提供了一个 setup 脚本,source 一下就行:
source /opt/ros/eloquent/setup.bash这条命令只对当前终端有效。要每次开终端都自动加载,得写进~/.bashrc:
echo "source /opt/ros/eloquent/setup.bash" >> ~/.bashrc source ~/.bashrc验证安装是否成功,最直接的办法是跑一个 talker 和一个 listener。开两个终端,都 source 好环境,一个跑:
ros2 run demo_nodes_cpp talker另一个跑:
ros2 run demo_nodes_py listener如果 listener 终端能持续打印出I heard: [Hello World: N],说明通信链路是通的,安装成功。这个测试同时验证了 C++ 和 Python 两种节点的互操作,比只跑一个节点更有说服力。
注意:如果你机器上同时装了 ROS1,
~/.bashrc里可能已经有source /opt/ros/melodic/setup.bash。两个都 source 会导致环境变量冲突,ros2命令可能找不到。解决办法是别把两个都写进 bashrc,用的时候手动 source,或者写个切换脚本。
4. 实操过程中的关键细节与参数说明
4.1 关于 rosdep 的初始化
rosdep是 ROS 用来管理系统依赖的工具,编译工作空间时经常用到。装完 ROS2 后建议顺手初始化一下:
sudo rosdep init rosdep updaterosdep init会从网上拉一个默认的源列表文件放到/etc/ros/rosdep/,rosdep update则把依赖数据库缓存到本地。这两步在国内网络下经常失败,因为要访问的源在国外。如果卡住,可以配置镜像或者手动下载缓存文件。
这里有个经验:rosdep update失败不一定是网络问题,也可能是权限问题。如果你之前用sudo跑过rosdep,缓存目录的属主可能变成 root,普通用户再跑就写不进去。检查~/.ros/rosdep/目录的权限,必要时chown回来。
4.2 colcon 构建工具的配置
Eloquent 默认装的是python3-colcon-common-extensions,这是 colcon 的常用扩展集合。colcon 是 ROS2 的构建工具,相当于 ROS1 里的 catkin。用之前建议确认版本:
colcon version-check构建工作空间的标准流程是:
mkdir -p ~/ros2_ws/src cd ~/ros2_ws colcon build --symlink-install--symlink-install这个参数值得说一下。它让安装目录里的文件用符号链接指向源码,而不是复制。好处是你改了 Python 脚本或者配置文件,不用重新 build 就能生效,调试时特别省时间。缺点是如果源码目录被移动或删除,链接就断了。开发阶段强烈建议加上,发布时去掉。
4.3 环境变量叠加的正确姿势
当你有了自己的工作空间后,source 顺序很重要。必须先 source 系统级的/opt/ros/eloquent/setup.bash,再 source 工作空间的install/setup.bash。顺序反了的话,工作空间里的包会被系统包覆盖,你改的代码不生效。
source /opt/ros/eloquent/setup.bash source ~/ros2_ws/install/setup.bash工作空间的 setup 脚本其实会自动去 source 它依赖的底层环境,但显式写出来更保险,尤其是多个工作空间叠加的时候。
4.4 网络通信的默认配置
ROS2 默认用 DDS 做通信,Eloquent 默认的 DDS 实现是 Fast RTPS。单机通信不用管,但多机通信时要配置ROS_DOMAIN_ID。同一个域 ID 的节点才能互相发现,不同域之间隔离。
export ROS_DOMAIN_ID=42域 ID 的取值范围是 0 到 232,但建议避开 0(默认值,容易和别人的冲突)。多机场景下,所有机器设成同一个域 ID,并且要在同一网段、关闭防火墙对多播的拦截。DDS 的节点发现依赖多播,如果网络设备禁了多播,节点之间就发现不了,这是多机调试时最常见的坑。
5. 常见问题与排查技巧实录
5.1 安装与运行阶段的典型报错
下面这张表是我在实际操作中整理出来的高频问题,按出现频率排序:
| 问题现象 | 可能原因 | 排查与解决 |
|---|---|---|
ros2: command not found | 环境变量没 source | 检查~/.bashrc是否 source 了 setup.bash,或手动 source |
| 运行节点报 locale 相关异常 | 系统 locale 非 UTF-8 | 按 3.1 节重新生成并设置 locale |
apt update报 NO_PUBKEY | GPG 密钥未正确导入 | 重新下载密钥到/usr/share/keyrings/ |
| talker/listener 互相发现不了 | 域 ID 不一致或防火墙拦截多播 | 统一ROS_DOMAIN_ID,检查防火墙 |
colcon build报缺依赖 | rosdep 未初始化或依赖未安装 | 跑rosdep install补依赖 |
| 同时装 ROS1 后 ros2 命令失效 | 环境变量冲突 | 分开 source,或写切换脚本 |
5.2 多播与防火墙的排查思路
多机通信失败,九成出在多播上。排查步骤是这样的:先确认两台机器能互相 ping 通,这是基础。然后在两台机器上分别跑ros2 node list,看能不能看到对方的节点。如果看不到,用ros2 multicast receive和ros2 multicast send做专门的多播测试——一个终端收,一个终端发,能收到说明多播通,收不到就是网络层拦了。
Ubuntu 默认的 ufw 防火墙如果开着,可能会拦多播。临时关掉测试:
sudo ufw disable确认是多播问题后,再针对性放行,而不是一直关着防火墙。另外有些企业网络或者虚拟化平台的虚拟交换机默认禁多播,这种情况得找网络管理员开,本地怎么调都没用。
5.3 版本混装的避坑经验
ROS1 和 ROS2 装在同一台机器上很常见,尤其是做迁移过渡的阶段。核心原则是:不要同时 source 两个环境。ROS1 的setup.bash和 ROS2 的setup.bash都会往PATH、PYTHONPATH、LD_LIBRARY_PATH里塞东西,同时生效必然冲突。
我的做法是写两个别名函数放在~/.bashrc里:
alias ros1env='source /opt/ros/melodic/setup.bash' alias ros2env='source /opt/ros/eloquent/setup.bash'需要哪个就手动切,虽然麻烦一点,但不会出玄学问题。另外,ROS1 的rosrun、roscore和 ROS2 的ros2 run、ros2 daemon是两套完全独立的命令,别混着用。
提示:如果你在同一个终端里先 source 了 ROS1 又 source 了 ROS2,最干净的办法是关掉终端重开,而不是试图"反向 source"去清理环境,后者基本清不干净。
5.4 停止维护带来的实际影响
Eloquent 停止维护后,最直接的影响是 apt 源里的包不再更新。这意味着如果某个依赖爆出安全漏洞,官方不会给 Eloquent 打补丁。对于联网的生产环境,这是个真实风险。我的建议是:如果设备必须联网,尽量把 ROS2 相关的通信限制在内网,不要暴露到公网;如果只是离线运行,风险相对可控。
另一个影响是社区支持变少。遇到问题时,搜到的答案大多是针对 Foxy 或 Humble 的,命令和配置可能有差异。这时候要学会看官方文档的历史版本——ROS2 的文档站保留了每个版本的快照,Eloquent 的文档还在,只是入口藏得比较深。
6. 装完之后值得做的几件事
安装只是起点,装完能跑 demo 不代表环境就配好了。我一般会再做几件事来验证环境的完整性。
第一件是跑一遍官方的示例包。Eloquent 自带了不少 demo,比如demo_nodes_cpp、demo_nodes_py,还有turtlesim。turtlesim 是个画乌龟的小程序,能验证图形界面和话题通信:
ros2 run turtlesim turtlesim_node ros2 run turtlesim turtle_teleop_key在 teleop 终端按方向键,乌龟能动,说明 GUI、话题、键盘输入这条链路都通了。
第二件是建一个最小工作空间,写一个自己的节点编译跑通。这一步能验证 colcon、编译工具链、依赖管理是否正常。很多人卡在"demo 能跑但自己写的编译不过",问题往往出在package.xml或CMakeLists.txt的依赖声明上。
第三件是记录下当前环境的版本信息,方便以后排查:
ros2 doctor --reportros2 doctor会输出系统信息、ROS2 版本、DDS 配置、网络状态等,出问题时把这份报告贴出来,别人帮你排查会快很多。
最后分享一个我自己的习惯:把整个安装过程写成一个 shell 脚本,包括 locale 设置、源配置、安装、环境变量。这样下次在别的 18.04 机器上部署,直接跑脚本就行,不用重新回忆每一步。脚本里加上错误检查和日志输出,哪一步失败一目了然。这个习惯在批量部署工控机的时候特别有用,省下的时间远超写脚本的成本。