最近后台一直有人问我:能不能在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 Morenia | Ubuntu 18.04(Bionic) | 已停止维护 |
| ROS Noetic Ninjemys | Ubuntu 20.04(Focal) | 已停止维护 |
| ROS Humble Hawksbill | Ubuntu 22.04(Jammy) | 维护中 |
| ROS Iron Irwini | Ubuntu 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 installable20.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-fulldesktop-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 -yrosdep会去读取每个包的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桌面系统。祝你好运,有问题评论区聊。