Ubuntu 24.04 上运行 ROS Noetic:Docker 兼容方案全解析
发布时间:2026/10/20 4:57:15 锦皓数字建站

ROS Noetic 想跑在 Ubuntu 24.04 上这事听起来有点拧巴但现实中确实有不少人这么干。我最早接触这个需求是因为有朋友新买了一台预装 24.04 的笔记本手头又有一堆 ROS 1 的老项目要维护既不想装双系统又不想开虚拟机非要让我帮忙想办法。折腾了几天之后我最大的感受是这条路能走但绝对不能按官方文档走。官方那条路只通到 20.04剩下的都得自己想办法。这篇文章就把我当时的完整思路、踩过的坑、最后定下来的稳定方案写出来。内容适合三种人刚接触 ROS 1、被 24.04 系统绑住手脚的新手需要同时维护 ROS 1 和 ROS 2 两套环境的开发者以及纯粹想搞清楚“系统版本与软件版本兼容性到底是怎么一回事”的爱好者。我会把为什么出现这种组合、有哪些可行路径、每条的取舍逻辑、以及我实测下来的完整操作步骤都讲清楚水平有限的地方也尽量说人话。1. 先搞清楚问题ROS Noetic 和 Ubuntu 24.04 到底差在哪在动手之前有必要把“兼容性问题”这件事掰开揉碎讲清楚。很多人以为 ROS Noetic 装不上 24.04 仅仅是因为“还没适配”其实不是这里面有几层原因叠加在一起理解了这些你后面选择方案才会自己做判断而不是听别人说哪个好就无脑用。1.1 官方支持矩阵的边界ROS Noetic 是 ROS 1 的最后一站官方在发布时明确把它绑定在 Ubuntu 20.04 上全名就叫“Noetic Ninjemys”。ROS 1 的发行策略一直是“一个发行版对应一个主推系统版本”它不像普通软件那样靠一套源码兼容所有平台而是直接依赖系统底层的 Python 版本、编译器版本、Boost 库版本、OpenCV 版本等一大堆系统组件。Ubuntu 20.04 默认的 Python 是 3.8而 Ubuntu 24.04 默认的 Python 已经推进到了 3.12。这玩意儿对 ROS Noetic 来说不是简单的“换个版本号”而是底下依赖链的根基全变了。Python 3.12 移除了不少老接口、修改了包结构ROS Noetic 的很多核心工具链压根没跟上这个变化节奏。1.2 系统库层面的隐性冲突除了 Python还有几个关键的底层库会直接崩Boost 库Noetic 依赖的 Boost 版本在 20.04 的仓库里是 1.7124.04 的环境已经是 1.83接口变化不少。OpenCV20.04 自带 OpenCV 4.224.04 的仓库版本很高而 ROS 里很多视觉包的编译需要针对特定 OpenCV 版本做适配。PCL 点云库依赖链更复杂版本错位会导致编译时的各种符号找不到。GazeboNoetic 配套的 Gazebo 11 在 24.04 上会碰到一堆图形和渲染相关的库问题。换句话说你在 24.04 上直接用 apt 装 ROS Noetic 的二进制包大概率会失败因为软件源里的依赖根本对不上。强行编译源码你还要解决“编译工具链版本太新老代码出现新警告甚至报错”的兼容问题。1.3 需求端的真实场景既然这么麻烦为什么还有人要这么干我接触下来主要有三类需求场景手头有现成的 ROS 1 项目算法代码、自定义消息、通信逻辑全是 ROS 1 写的短期内不会迁移到 ROS 2但手边只有 24.04 的新机器。新机器硬件比较新比如新发布的显卡、新网卡装 20.04 反而遇到驱动不识别的问题逼着你留在 24.04。做一个长期项目主系统必须保持更新获取安全补丁ROS Noetic 只是其中的一个运行环境模块不能因为一个模块绑定整个系统版本。1.4 正确看待“兼容”想清楚一个问题ROS Noetic 只是你项目里的一个“运行环境”它不是必须跟宿主机直接打交道。它要的是一套稳定的依赖库组合这套组合最适合在 20.04 里跑并不代表它在别处就跑不起来只要你能给它一个“看起来像 20.04”的环境里面跑好好的外面系统是 24.04 还是别的什么版本根本没有关系。这个认知是整个方案的核心后面所有做法都围绕它展开。2. 四条可选路径我最后选了哪条网上讨论这个组合能搜出一堆方法但大部分都太乐观。我把能走通的主流方案整理成了一张对比表先直观看看差距再讲我为什么最终选了 Docker。方案实现难度系统隔离性图形界面支持性能损耗维护成本适合的人群直接 apt 安装低无好无高基本装不上不推荐源码编译安装极高无好无极高研究者、极客虚拟机装 20.04中好中较高中新手、图形化需求多Docker 容器中好可通过 X11 转发低低开发者、项目集成2.1 直接 apt 安装碰都不要碰单纯运行apt install ros-noetic-desktop-full能装上吗在 24.04 上添加 ROS 官方软件源后apt 会尝试解析依赖你会看到一堆“无法定位软件包”或者“依赖冲突”的报错。这是因为官方仓库为 Noetic 构建的二进制包只针对 focal20.04 的开发代号编译。你硬要用的话还得想办法把 20.04 的软件源混进 24.04 里那后果轻则依赖崩溃重则整个系统图形界面都受影响。2.2 源码编译能通但性价比太低ROS Noetic 源码编译到 24.04 并非不可能官方源码在较新系统上还是能编译的但需要处理的问题太多了。首先你要用rosdep安装大量依赖而不少依赖在 24.04 里的版本和 Noetic 期望的版本不一致需要手动打补丁。其次Python 3.12 会导致一些工具链直接挂掉比如rosbag的 Python 接口。再次你自己写的老代码里的编译参数可能也会因为 GCC 版本变化而报错。一套流程走下来运气好两三天运气不好一周都在填坑而且整个环境只有你自己知道是怎么搭出来的换个机器或者加入新同事一切重来。2.3 虚拟机最朴素但不是最优解虚拟机装一个完整的 20.04再把 ROS Noetic 当成“正常安装”来用思路最朴素也最稳几乎不会遇到兼容性问题。缺点也很明显资源开销大共享内存、GPU 直通尤其是 NVIDIA 显卡和 CUDA 结合的场合配置繁琐传感器设备映射到虚拟机里需要额外的 USB 转发多人开发时多个虚拟机同步困难。对我这种更看重效率的开发者来说太笨重。2.4 Docker干净、可复制、最贴近工程化Docker 容器本质上是“一个进程级别的沙箱”共享宿主机的内核但拥有独立的文件系统、网络栈和进程空间。它的核心优势在于镜像内完全可以装一套官方 20.04 版本的依赖环境ROS Noetic 在容器内部就像在自己家一样舒服而宿主机依然是 24.04 干干净净。容器性能接近裸机启动只需几秒环境配置写成 Dockerfile 后可以版本化管理任何同事拉下来都能复现同一套环境。这在团队协作里的价值远大于个人使用也是我最终选择它的核心原因。3. 实操全流程在 Ubuntu 24.04 上跑一个像样的 ROS Noetic 容器下面这部分是我实测过的完整流程。我以“在 24.04 宿主机上通过 Docker 运行 ROS Noetic 桌面完整版并能在容器里打开 Rviz、跑起仿真、访问摄像头”为目标把每一步都写清楚并解释每一步为什么要这么做。3.1 宿主机 Docker 环境准备先确认系统里有没有装过旧版 Docker如果装过卸干净再重装避免残留配置干扰。# 卸载可能存在的旧版本 sudo apt remove docker docker-engine docker.io containerd runc # 安装基础依赖 sudo apt update sudo apt install ca-certificates curl gnupg lsb-release # 添加 Docker 官方仓库墙内用户注意镜像源问题 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io安装之后建议把当前用户加入docker用户组免得每次敲命令都加sudosudo usermod -aG docker $USER newgrp docker这一步之后记得退出终端重新登录用户组权限才会生效。提示如果你在公司网络环境里Docker 源拉不动可以用国内的镜像加速器。修改/etc/docker/daemon.json填入镜像地址重启 Docker 服务即可sudo systemctl restart docker。3.2 镜像选择与拉取镜像的选择有讲究。Docker Hub 上官方的ros:noetic-ros-core-focal只有核心库没有图形工具ros:noetic-ros-base-focal包含基础通信与常用库而我们要跑 Rviz、Gazebo 这类图形界面需要desktop-full级别的东西。官方没有发布完整的 desktop-full 的 Docker 镜像但社区有现成的比较稳定的是docker pull ros:noetic-ros-base-focal这个镜像只有 ROS 基础跑rviz不行。想省事的话可以用我后面分享的 Dockerfile 自己构建一个带桌面组件的镜像或者拉取社区镜像# 社区中较常用的带桌面的 noetic 镜像以 osrf 组织的仿真镜像为例 docker pull osrf/ros:noetic-desktop-full这个osrf/ros:noetic-desktop-full是 ROS 官方维护者组织发布的包含完整桌面工具链我用它实测下来整体稳定。实际项目里我建议以它为基础镜像再定制而不是直接拿来做日常开发镜像。3.3 打通图形界面X11 转发容器是隔离环境里面跑的 GUI 程序怎么显示到宿主机屏幕上是新手最常卡住的一道坎。原理其实不复杂Linux 的图形显示走 X11 协议宿主机上有 X Server容器里只需要把要显示的窗口信息通过环境变量告诉系统并把宿主机 X Server 的通信 socket 映射进容器即可。先确保宿主机装了 X11 相关的客户端库默认 24.04 桌面版一般都有sudo apt install x11-xserver-utils启动容器时需要挂载两个东西宿主机/tmp/.X11-unix目录和设置DISPLAY环境变量。如果涉及 OpenGL 硬件加速还需要把宿主机的 GPU 设备映射进去。docker run -it \ --name ros_noetic_env \ --network host \ --privileged \ -e DISPLAY$DISPLAY \ -v /tmp/.X11-unix:/tmp/.X11-unix:rw \ -v /dev:/dev \ osrf/ros:noetic-desktop-full \ bash这条命令里几个参数的作用--network host让容器直接使用宿主机网络ROS 的多机通信、话题传输零障碍不用做端口映射。--privileged给容器访问宿主机设备的完整权限摄像头、串口、雷达这类传感器设备就不用手动一个个映射了。-v /tmp/.X11-unix:/tmp/.X11-unix:rw把图形通信 socket 传进去。-v /dev:/dev把宿主机所有设备节点直接暴露给容器。进入容器之后验证一下 GUI 能不能用# 容器内执行 export DISPLAY:0 # 如果上面启动时已设置就跳过 rviz能看到 Rviz 窗口弹出就说明图形链路通了一半。如果遇到权限问题常见于 Wayland 会话的宿主机需要在宿主机上执行xhost local:开放本地访问权限。这个命令只是测试用正式使用更推荐做 ACL 控制但不是这篇的重点先跑通再说。3.4 用户权限与工作区持久化容器默认用 root 用户这会导致两个问题一是容器内生成的文件 owner 是 root在宿主机上用普通用户改起来很别扭二是很多 IDE、编辑器连容器内部做远程开发时权限不匹配会有麻烦。我的做法是启动容器时指定普通用户的 UID 和 GID用宿主机当前用户身份运行容器docker run -it \ --name ros_noetic_env \ --user $(id -u):$(id -g) \ -e DISPLAY$DISPLAY \ -e QT_X11_NO_MITSHM1 \ --network host \ --privileged \ -v /tmp/.X11-unix:/tmp/.X11-unix:rw \ -v /home/你的名字/ros_ws:/home/dev/ros_ws \ -v /dev:/dev \ osrf/ros:noetic-desktop-full \ bash--user $(id -u):$(id -g)让容器进程以宿主机当前用户的权限运行文件读写权限统一了。-v /home/你的名字/ros_ws:/home/dev/ros_ws把宿主机的工作目录挂载进去代码、编译产物都保存在宿主机上容器删了重建工作区还在。有个细节需要注意挂载目录在容器里的路径不要放在 root 的家目录下否则非 root 用户可能没有写权限。我在容器里统一把工作区放在/home/dev下简单又直接。3.5 定制镜像把常用依赖一次性焊死每次启动容器后都要手动apt-get install一堆包太原始了。更工程化的做法是把所有依赖写进 Dockerfile构建成项目专用镜像。这是我的参考模板FROM osrf/ros:noetic-desktop-full # 使用非交互模式避免 apt 等待确认 ENV DEBIAN_FRONTENDnoninteractive # 更新源并安装常用开发工具 RUN apt-get update apt-get install -y \ vim \ git \ ssh \ curl \ wget \ terminator \ python3-pip \ python3-catkin-tools \ ros-noetic-cv-bridge \ ros-noetic-image-transport \ ros-noetic-camera-calibration \ ros-noetic-gazebo-ros-pkgs \ ros-noetic-robot-state-publisher \ ros-noetic-joint-state-publisher-gui \ rm -rf /var/lib/apt/lists/* # 创建非 root 用户 RUN useradd -m -u 1000 dev echo dev:dev | chpasswd # 配置 ROS 环境 RUN echo source /opt/ros/noetic/setup.bash /home/dev/.bashrc USER dev WORKDIR /home/dev/ros_ws CMD [bash]构建命令docker build -t ros_noetic_custom .之后启动时直接用这个自定义镜像。每次环境变更都更新 Dockerfile 并重新 build这样做的好处是环境变更是可追溯的新同事加入时拉一份 Dockerfile 自己构建五分钟内拥有和别人一模一样的开发环境。3.6 一次成型完整启动脚本我把日常启动封装成了一个 shell 脚本每次开工作环境执行一行就行#!/bin/bash container_nameros_noetic_dev image_nameros_noetic_custom # 如果容器已经存在直接进入 if [ $(docker ps -aq -f name$container_name) ]; then docker start -ai $container_name else docker run -it \ --name $container_name \ --user $(id -u):$(id -g) \ -e DISPLAY$DISPLAY \ -e QT_X11_NO_MITSHM1 \ --network host \ --privileged \ -v /tmp/.X11-unix:/tmp/.X11-unix:rw \ -v /home/你的名字/ros_ws:/home/dev/ros_ws \ -v /dev:/dev \ $image_name \ bash fi脚本逻辑很简单第一次运行创建容器之后直接docker start -ai进之前保留的容器状态。容器里的终端配置、已安装的工具、环境变量都还在体验比每次都重新docker run顺滑得多。3.7 摄像头与串口的设备访问做机器人开发离不开传感器。--privileged加-v /dev:/dev是最省事的挂法容器内直接能看到/dev/video0、/dev/ttyUSB0这些设备。但有些场景不想用这么宽的权限可以只映射特定设备docker run -it \ --device /dev/video0 \ --device /dev/ttyUSB0 \ ...这里有一个我踩过的坑容器里访问摄像头时会报VIDIOC_QUERYCAP权限错误。这时需要检查宿主机上摄像头设备的权限组一般是video组如果你的用户不在video组里设备节点权限不够容器里也拿不到权限。解决办法sudo usermod -aG video $USER newgrp video还有一些 USB 转串口芯片要检查宿主机是否识别到lsusb dmesg | grep ttyUSB识别不到的话先从宿主机排查驱动别在容器里耗时间。容器对设备来说就是一个普通进程宿主机都看不到设备容器里肯定看不到。3.8 用 VSCode 连进容器做开发日常开发如果只在终端里敲命令总归不够顺我习惯用 VSCode 的 Remote Development 插件直接连接运行中的容器。步骤如下安装 VSCode 的Dev Containers扩展。在容器运行时左侧 Docker 面板找到容器名右键选择 “Attach Visual Studio Code”。VSCode 会自动在容器内安装服务器组件随后打开容器内的/home/dev/ros_ws工作区。容器里也有必要装一套 Python 插件和 C 插件IDE 的代码补全、跳转、调试功能都能用。注意容器内的环境是隔离的VSCode 的扩展需要单独安装它跟宿主机的扩展列表不互通。4. 实际运行中的常见问题与排查技巧方案再好实战中依然会遇到各种小毛病。我把自己和同事在 24.04 Docker Noetic 的组合下遇到过的问题整理成一份速查表每个问题都附上原因和解决办法建议收藏备查。现象根本原因解决办法容器里打开 rviz 报 “cannot connect to display”DISPLAY 环境变量没生效或 X11 socket 没挂载检查-e DISPLAY$DISPLAY和-v /tmp/.X11-unix:/tmp/.X11-unix:rwGUI 能打开但画面撕裂/黑屏OpenGL 硬件加速未启用添加-e LIBGL_ALWAYS_SOFTWARE1先软件渲染或映射宿主机 GPU摄像头画面全黑或打不开设备权限不对检查宿主机video用户组并确认/dev/video0已映射容器内 ping 不通其他机器容器网络模式用了 bridge改用--network host容器里能 ping 通但 ROS 话题通信失败ROS 的ROS_MASTER_URI设置不一致多机通信时所有机器统一ROS_MASTER_URI指向运行 roscore 的主机编译 catkin 项目时找不到某个依赖包容器内未安装对应 ros 包apt-cache search ros-noetic-包名搜一下装对应的 noetic 版本每次进容器都要重新 source setup.bash启动时用的是/bin/bash没有自动 source把source /opt/ros/noetic/setup.bash写进镜像里的.bashrc容器内创建的文件夹在宿主机上是 root 所有容器用户与宿主机 UID 不一致启动时加--user $(id -u):$(id -g)4.1 GUI 不通的深度排查GUI 打不开是最常见的第一个关口。我每次排查的思路是固定的# 宿主机执行确认当前的 DISPLAY echo $DISPLAY # 检查 X socket 是否存在 ls /tmp/.X11-unix/然后进容器echo $DISPLAY ls -la /tmp/.X11-unix/如果宿主机有值、容器里为空或者路径不对先把挂载参数改对。如果两边都有X0注意数字可能不一样再试xhost local:开放权限。还在 24.04 上需要注意会话类型如果用的是 WaylandX11 转发会兼容性差一些建议在登录界面切到 “Ubuntu on Xorg” 会话模式我实测切到 Xorg 后图形问题少了一大半。4.2 构建速度优化的两个小技巧容器内编译速度是很多人的痛点特别是在老笔记本上。第一个技巧是给 Docker 分配更多资源。如果你用 Docker Desktop 就在设置里调 CPU 和内存如果用的是原生命令行版那么容器本来就共享宿主机资源。第二个技巧是把catkin的编译缓存放在宿主机挂载目录里通过-v挂载工作区时编译中间文件不会因容器重建而丢失。# 容器内第一次编译时指定 catkin config --buildspace /home/dev/ros_ws/build --develspace /home/dev/ros_ws/devel --installspace /home/dev/ros_ws/install注意挂载目录虽然能持久化但大项目频繁读写会略慢于容器本地磁盘。工程实践里我通常会把build文件夹再排除出挂载范围用 Docker volume 存用一定空间的牺牲换速度。4.3 多机通信配置实录拿两台电脑组 ROS 分布式通信假设 A 机跑 roscoreB 机跑订阅节点。A 机 IP 为192.168.1.100B 机 IP 为192.168.1.101。两边的容器都必须是host网络模式然后A 机容器内export ROS_MASTER_URIhttp://192.168.1.100:11311 export ROS_HOSTNAME192.168.1.100 roscoreB 机容器内export ROS_MASTER_URIhttp://192.168.1.100:11311 export ROS_HOSTNAME192.168.1.101 rosrun rospy_tutorials listener.py关键点在于ROS_HOSTNAME必须是本机实际可被对方访问到的 IP不能是localhost。我见过很多人在容器里不设ROS_HOSTNAME导致话题数据传不过去设完之后立刻正常。4.4 性能对比与额外建议我拿同样的一个点云处理节点在三种环境里跑过对比裸机 20.04、虚拟机里的 20.04、Docker 里的 Noetic。结果是 Docker 和裸机性能几乎一致虚拟机大概有 10%-20% 的性能折损主要损失在 CPU 和 PCIe 数据传输上。如果你的项目里有实时的传感器数据流处理Docker 是明显更稳的选择。如果你的 GPU 是 NVIDIA 且需要跑视觉模型在 24.04 宿主机上给容器传 GPU 需要额外配置 NVIDIA Container Toolkit。装完后在docker run里加--gpus all和-e NVIDIA_DRIVER_CAPABILITIESall才能让容器里的 CUDA 程序认到显卡。这个配置我单独写出来因为它真的特别容易漏不小心就白折腾一晚上。5. 从“能用”到“好用”的几个心得流程走通之后我复盘了一下整个实践过程有几个心得值得单独拿出来说。第一能写进 Dockerfile 的环境配置千万别用命令行手动装。以前我也图省事进了容器直接apt install装到后面容器一删全没了又得从头来一遍。改成 Dockerfile 构建之后环境重建只需一条命令痛苦程度直线下降。第二容器也好、虚拟机也好它们都只是工具。ROS Noetic 和 Ubuntu 24.04 的组合本质上是在处理“旧软件依赖旧系统新硬件需要新系统”的矛盾。理解了“环境隔离”这个思路以后遇到 ROS 1 的程序想在更新的系统上跑或者任何一个老软件想在新系统里运行你都可以参考这个模式把兼容性问题嵌套在容器里解决而不是让宿主机迁就老软件。第三关于 ROS 1 的剩余价值多说一句经验。Noetic 已经是 ROS 1 的最后一个版本官方已经停止更新新项目能上 ROS 2 就上 ROS 2没必要再主动拥抱 ROS 1。但如果你的项目体量很大迁移成本高那用容器把 Noetic 环境“关押”在一层稳定隔离带里让它退休前安安稳稳把活干完反而是最务实的策略。最后分享一个小技巧。如果你经常在宿主机和容器之间来回切文件可以考虑在宿主机上用sshfs把远程服务器的工作区挂载到本地再通过同一路径挂载进容器里这样本地和远程开发体验都能统一起来。这个方法不是必须的但确实能在多机协作时让环境体验上一个台阶。做技术方案不一定要追求最“新”稳定可复现、自己驾驭得住才是第一原则。希望这篇实践记录能给你省下几天自己摸索的时间。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。