☰
Ubuntu20.04安装ROS Melodic:Docker容器方案与依赖避坑指南
2026/10/15 21:43:32 网站建设 项目流程

最近后台一直有人问我:能不能在Ubuntu20.04上装ros-Melodic?怎么我照着网上的教程搞了一晚上,最后还是包找不到?我把话放前面:ROS Melodic官方对应的系统是Ubuntu18.04(Bionic),不是20.04。你在一台20.04的机器上硬装,等待你的大概率是一堆依赖地狱。这篇文章记录的是我个人的完整安装过程——注意,不是“20.04直接apt装”那种骗自己操作,而是怎么在20.04上合法、稳定、可复现地把Melodic跑起来。

如果你现在正卡在“安装ros-melodic-desktop-full失败”这一步,或者还在纠结“为什么加了ROS源还是找不到包”,那这篇文章就是给你写的。我会把版本对应关系、失败根因、Docker曲线救国方案、源码硬核方案、后续环境配置踩坑一次讲透,全程是真实操作记录,不是复制官方文档。

1. ROS版本与Ubuntu版本强绑定:为什么20.04上直接装Melodic必炸

1.1 一张表看清ROS发行版和Ubuntu的对应关系

先看这张表,这是ROS入门第一课,也是大部分人装失败的第一原因:

ROS发行版对应Ubuntu版本官方支持状态
ROS Melodic MoreniaUbuntu 18.04(Bionic)已停止维护
ROS Noetic NinjemysUbuntu 20.04(Focal)已停止维护
ROS Humble HawksbillUbuntu 22.04(Jammy)维护中
ROS Iron IrwiniUbuntu 22.04维护中

Melodic发布那一年,官方直接声明“Targeted at Ubuntu 18.04”。这不是随口说说,ROS的二进制包在构建时就是链接了Ubuntu18.04的Python版本、Boost库、OpenCV版本和一堆系统C库。你把18.04的包扔进20.04,系统会告诉你:

The following packages have unmet dependencies: ros-melodic-desktop-full : Depends: libpython3.6 but it is not installable

20.04默认自带的是Python3.8。libpython3.6在标准源里根本没有,除非你手动添加旧的源,但那样又会把系统的Python依赖搞得乱七八糟。

1.2 我亲自踩过的“直接安装”失败现场

我最早也头铁,想着“都是Ubuntu,版本差一点点,装个低版本ROS应该没毛病”。于是照网上的老教程:

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

注意,lsb_release -sc在20.04上返回的是focal,ROS官方软件源里根本没有focal对应的Melodic仓库,所以apt update之后就出现了经典的:

E: Unable to locate package ros-melodic-desktop-full

我又自作聪明,把源列表里的focal改成bionic,强行去拉18.04的包。这次包是找到了,结果一眼望不到头的依赖冲突:python3.6缺失、libboost1.65没有、libyaml-cpp0.6版本不符,甚至还有libopencv3.2这种根本不可能装上的东西。折腾到凌晨两点,最后把系统搞坏了,只能重装。

所以,结论很简单:官方二进制源这条路,在Ubuntu20.04上走不通。想要用上Melodic,要么把系统降级成18.04,要么用容器虚拟出18.04环境,要么从源码搞一套Melodic自己编译。降系统不现实,源码编译坑又多,个人最推荐容器方案。

2. 最终落地:Docker容器内跑Ubuntu18.04 + ROS Melodic

2.1 为什么我最终选择Docker而不是虚拟机

有一说一,虚拟机也能装Melodic,但启动慢、占用大、跟宿主机共享摄像头/串口还要配一堆USB透传参数。Docker的优势在于它本质上不是一个完整系统,只是一个隔离的Linux环境,启动只要几秒,占用磁盘几百MB,关键是可以直接挂载宿主机的设备、网络、图形界面。

我用的是nvidia-docker的替代思路,不需要GPU的话普通Docker就够了。如果你只是做ROS学习、跑算法验证、调试节点通信,Docker完全够用。而且它不会把你20.04的系统弄脏,删掉容器一条命令就干净了。

唯一要提前说的是:Docker容器里跑图形界面(比如rqt、rviz)需要配置X11转发,后面我会详细写。

2.2 宿主机安装Docker的完整流程

这里分成两步:先装Docker引擎,再配用户权限。

sudo apt update sudo apt install docker.io

安装完验证:

docker --version

然后把自己加入docker用户组,这样不用每次sudo:

sudo usermod -aG docker $USER newgrp docker

注意,执行完usermod之后最好注销重新登录一次,否则newgrp只在当前终端生效,新开终端还是会提示权限不足。

2.3 创建Ubuntu18.04容器并安装ROS Melodic

拉取镜像:

docker pull ubuntu:18.04

启动并进入容器:

docker run -it --name ros_melodic \ --network=host \ -e DISPLAY=$DISPLAY \ -v /tmp/.X11-unix:/tmp/.X11-unix \ ubuntu:18.04 \ /bin/bash

参数解释:

  • --name ros_melodic:给容器起名,后续好管理。
  • --network=host:直接用宿主机网络,ROS的master节点通信就不用额外做端口映射了。
  • -e DISPLAY=$DISPLAY:把宿主机的显示环境变量传进去。
  • -v /tmp/.X11-unix:/tmp/.X11-unix:挂载X11的socket,这是GUI界面能弹出的关键。

进入容器之后,第一件事换源。18.04自带的archive.ubuntu.com在国内经常龟速,我用的是清华源:

sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list apt update

然后安装基础的依赖和工具:

apt install -y lsb-release gnupg curl

注意,18.04的源现在还有但已是EOL状态,部分包可能迁移到old-releases。如果后面遇到404 Not Found,把sources.list里archive.ubuntu.com替换成old-releases.ubuntu.com,再把security.ubuntu.com也换掉。

接着添加ROS官方源并安装Melodic:

sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' curl -sSL 'https://raw.githubusercontent.com/ros/rosdistro/master/ros.key' | apt-key add - apt update

如果apt-key add提示key过期,用新版方式:

curl -sSL 'https://raw.githubusercontent.com/ros/rosdistro/master/ros.key' -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros/ubuntu bionic main" | tee /etc/apt/sources.list.d/ros-latest.list

这里字源地址直接写bionic,比$(lsb_release -sc)保险,因为容器里的lsb_release -sc会返回bionic,其实一样。

然后正式安装:

apt update apt install -y ros-melodic-desktop-full

desktop-full包含ROS、rqt、rviz、gazebo这些常用工具,大约要下2GB左右,耐心等就行。装完初始化rosdep:

apt install -y python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential rosdep init rosdep update

这里有个坑:18.04默认的Python还是2.7,rosdep对应的是python-rosdep这个包。如果你在容器里先装了什么奇怪的东西把Python改到3了,后面会各种报错。保持容器干净最好。

2.4 在容器里初始化工作空间并验证安装

装完环境,建一个catkin工作空间测试:

mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_init_workspace cd ~/catkin_ws catkin_make

然后source环境变量:

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

验证ROS能否正常启动:

roscore

看到started core service [/rosout]基本就成功了。再新开一个终端进同一个容器,跑小乌龟测试:

rosrun turtlesim turtlesim_node

如果窗口能弹出,说明GUI环境配置成功。

2.5 容器日常操作与宿主机交互

容器退出后再进去的命令:

docker start ros_melodic docker exec -it ros_melodic /bin/bash

想把宿主机的摄像头或串口映射进容器,在docker run时加:

--device=/dev/video0 \ --device=/dev/ttyUSB0

最好在run的时候就规划好,后面docker exec没法动态加设备,除非用docker commit重新生成镜像。这部分我后面还会细说。

3. 不装Docker的硬核路线:在Ubuntu20.04上源码编译安装Melodic

3.1 源码编译到底比二进制安装难在哪

如果因为公司要求、离线环境或其他原因,必须直接在宿主机20.04上“原生”跑Melodic,也不是完全没戏,但你要做好打持久战的准备。Melodic的源码可以在GitHub上找到,核心问题在于:它当年是按Ubuntu18.04的依赖版本写的,你现在用20.04的工具链编译,会出现大量的API或ABI不兼容。

最典型的有这么几个:

  • OpenCV:20.04默认OpenCV 4.2,Melodic源码很多模块依赖OpenCV 3.x的接口。
  • Boost:20.04是1.71,Melodic有些包在1.65上测过,新版也能过,但个别旧接口被移除了。
  • Python:20.04默认Python3.8,Melodic的rospy等模块对Python3.6有隐式依赖。
  • log4cxx:这个在20.04上经常编译失败,因为新版gcc对旧代码的检查更严。

所以源码编译不是一个“照着catkin_make”就能跑通的流程,更像是在做移植。

3.2 源码安装的整体流程与关键步骤

我可以说一下大致的流程,但请不要指望像Docker那样一条命令走下去。不同版本、不同时间点拉到的代码可能都不一样,遇到具体错误还得现场修。

第一步,安装基础系统依赖:

sudo apt update sudo apt install -y python3-rosdep python3-rosinstall-generator python3-wstool build-essential cmake python3-catkin-pkg-modules python3-vcstool

第二步,拉取Melodic的元包源码。用vcstool按rosdistro里的配置拉全量代码:

mkdir ~/ros_melodic_src cd ~/ros_melodic_src vcs import src < ~/melodic.rosinstall

这个melodic.rosinstall文件需要先从rosdistro仓库获取。拉完之后,src下面可能是几十个核心包,不是全部(全部几千个包没必要编译,你只需要ros_comm、roscpp、rospy、std_msgs这些核心)。

第三步,设置ROS_DISTRO=melodic,运行rosdep安装依赖:

export ROS_DISTRO=melodic rosdep install --from-paths src --ignore-src -r -y

rosdep会去读取每个包的package.xml,给出当前系统下缺失的依赖。这一步通常能装掉80%的系统包,剩下的就是编译坑。

第四步,编译核心包。建议只编ros_comm这一组,先不要碰desktop-full:

catkin config --install catkin build

我第一次编译挂在roscpp上,报错是一堆log4cxx头文件找不到。后来手动装了liblog4cxx-dev,又出现fmt版本冲突。最后是把系统自带fmt降到5.x才继续走。

第五步,编译过程中可能还需要手动打补丁。比如python3.8兼容性,Melodic的rospy源码里有几处用了imp模块,而Python3.8移除了imp,需要改成importlib。这种patch通常要自己去ROS社区翻issue。我只能说,如果排错经验不够,这条路很容易走了一半就放弃。

3.3 为什么我最终没有在宿主机上原生编译Melodic

写这段不是劝你放弃源码编译,而是给你算一笔时间账。我自己在20.04上编译Melodic核心包,不算拉代码和装依赖,光编译roscpp、rospy、rosconsole这几个基础包就花了大概5个小时。期间改了4个文件的源码,手动降级了fmt库,最后虽然跑起来了,但一跑rosrun turtlesim turtlesim_node,链接的是系统OpenCV 4.2,和Melodic里某个旧库冲突,直接段错误退出。

后来我把容器方案跑通,前后也就20分钟。你说哪个划算?如果你不是做ROS源码级二次开发,只是正常写节点、跑仿真、做算法验证,Docker容器比源码编译香太多了。如果未来有硬性需求必须在宿主机上原生跑Melodic,那建议直接重装成18.04系统,也别编译了,省心。

4. 安装完成后必踩的坑:环境变量、GUI显示、设备映射与通信配置

4.1 环境变量source顺序的坑

很多人装完ROS一打开新终端就提示command not found: rosrun,原因就是.bashrc里的source没有生效。在Docker容器里,如果用的是docker run直接执行/bin/bash,那~/.bashrc默认不会自动加载(因为是非交互式shell)。我习惯在docker run时直接加-it并且进入后手动source,或者干脆在容器里执行:

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

如果用了zsh,记得把~/.bashrc改成~/.zshrc。另外注意,如果之前装过Anaconda,conda的环境变量可能会把Python路径指向conda的base环境,导致rospy依赖的Python库版本错乱。这个特别隐蔽,症状是roscore能起,但一import rospy就报一堆缺模块。解决办法是在source ROS之前先conda deactivate,或者修改PATH顺序。

4.2 GUI程序显示不出来的排查链路

容器里跑rosrun rviz rviz,窗口弹不出来的情况非常常见。我遇到过一次,排查完发现是DISPLAY变量没传进去。

在宿主机上先确认:

echo $DISPLAY

正常输出是:0或:1。然后进容器里:

echo $DISPLAY

如果为空,说明docker run时-e DISPLAY=$DISPLAY没生效。还有刚才挂载/tmp/.X11-unix也要检查:

ls -la /tmp/.X11-unix/

宿主机上这个目录下应该有个X0文件,容器里也要能看到同样的文件。如果用的是xhost授权,需要先在宿主机执行:

xhost +local:

这样容器内的X11客户端才能连上宿主机的X server。跑GUI前先看一下xeyes这类简单程序能不能显示,能显示就说明X转发OK,再跑rviz就顺理成章了。

4.3 宿主机设备映射:摄像头、串口、激光雷达

做机器人开发,容器里跑ROS node,上个摄像头和雷达基本是刚需。这里有一个容易忽略的点:docker run时就要把设备映射进去,因为docker exec不能动态添加设备。

摄像头:

docker run -it --name ros_melodic \ --network=host \ -e DISPLAY=$DISPLAY \ -v /tmp/.X11-unix:/tmp/.X11-unix \ --device=/dev/video0:/dev/video0 \ ubuntu:18.04 \ /bin/bash

串口设备(比如USB转串口、下位机):

--device=/dev/ttyUSB0:/dev/ttyUSB0

有时候设备名不固定,插拔后从video0变成video1,建议在宿主机里用udev规则固定设备符号链接。比如新建/etc/udev/rules.d/99-usb-cam.rules,内容是按厂商ID和产品ID映射到/dev/my_camera。这样容器里映射--device=/dev/my_camera就稳了。

设备权限也是个坑:即使映射进去,容器里如果对/dev/ttyUSB0没有权限,还是打不开。在容器里执行:

sudo chmod 666 /dev/ttyUSB0

或者给dialout用户组加权限。

4.4 ROS Master和节点通信的hostname问题

容器用了--network=host,ROS节点通信一般没问题。但如果你为了让容器和宿主机同时跑不同ROS版本(比如宿主机Noetic,容器Melodic),这时候ROS_MASTER_URI要指向同一个master。

简单做法:全部在容器里跑。但如果要跨容器和宿主机通信,必须保证:

  • ROS_MASTER_URI两边一致,比如都指向http://localhost:11311。
  • ROS_HOSTNAME和ROS_IP设置正确,千万别留空或设置成容器的内部IP。

不然会出现:

[ERROR] [wall time]: ROS_HOSTNAME is not set! ROS_IP is not set!

其实很多“节点找不到master”的报错,不是ROS没装好,是网络变量没配对。我个人建议:不是特别需要就别跨容器通信,直接在容器里把master和所有节点都跑起来,干净利落。

5. 个人体会与后续扩展

这套流程真正用顺之后,对我来说收益最大的是“环境隔离”这件事。以前要跑一个旧项目,往往是装一堆旧库、改一堆系统配置,把新项目也带崩了。现在我把Melodic关在容器里,宿主机的20.04该干嘛干嘛,Noetic也可以同时装着,两个版本互不干扰。偶尔需要给某个传感器写驱动,容器里直接apt install测试,不行就删容器重建,完全不敢动宿主机一针一线。

最后分享一个小技巧:容器里的环境配置好之后,不要在docker run进去手动装一堆东西,而是把刚才所有的步骤写成一个Dockerfile,比如在Dockerfile里先拉ubuntu:18.04,然后一键执行换源、装ROS、初始化rosdep。这样以后换电脑、换服务器,只要build一次镜像,5分钟就复现一套一模一样的Melodic环境。我就因为这个习惯,帮一个同事省下了大半天时间。

如果你现在还纠结“Ubuntu20.04能不能装ros-melodic”,我的答案可以总结成三句话:二进制直接装不行;源码编译能装但性价比太低;Docker容器是目前最稳定、最可控、最适合个人开发者的方案。按本文的方法走下来,你手上会有一套可以随时删除重建的Melodic环境,还能保留一个干净的20.04桌面系统。祝你好运,有问题评论区聊。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询