ROS 可以说是目前机器人领域绕不开的一套基础设施。不管你是做机械臂、做小车、做SLAM导航,还是做室内服务机器人,只要想真正上手机器人开发,几乎都要跟它打交道。这篇ROS快速入门基础使用教程(1),我会从安装环境、工作空间、第一个节点程序到turtlesim通信实验,把入门阶段最核心的链路完整走一遍,并把你大概率会踩的坑提前摆出来。内容以ROS 1 Noetic为主线,兼顾ROS 2选型建议,适合刚装好Ubuntu、还没搞懂ROS到底怎么玩的新手,也适合已经装过但没系统梳理过命令逻辑的同学。
1. 先搞清楚这些再动手
1.1 ROS到底是什么,能干什么
我习惯把ROS理解成“机器人的操作系统骨架”,它本身不是像Windows那样管理硬件设备的操作系统,而是一套运行在Linux之上的分布式通信框架。它把传感器、底盘、机械臂、导航算法、视觉处理这些模块拆成一个个独立程序,再通过话题、服务、动作等机制让它们互相通信。
这些独立程序在ROS里叫节点,每个节点只负责一件事。比如一个节点读激光雷达数据,另一个节点处理SLAM建图,还有一个节点控制电机。节点之间不直接调用函数,而是通过“话题”发布和订阅数据,这种设计最大的好处是模块解耦。以后你想换掉某个算法模块,只需要保证话题接口一致,其他部分完全不用动。
如果不用ROS,自己做机器人开发就得自己定义一套模块间通信协议。你会遇到线程管理、消息序列化、进程间通信、多机协同等问题,每个都是不小的体力活。ROS把这些通用的东西全封装好了,你只管写业务逻辑。这也是为什么现在招聘机器人工程师时,ROS能力几乎成了硬指标。
1.2 ROS 1 Noetic和ROS 2 Humble怎么选
很多新手一上来就纠结学ROS 1还是ROS 2。我的建议是:如果你用的是Ubuntu 20.04,直接学ROS 1 Noetic;如果你用的是Ubuntu 22.04或24.04,直接学ROS 2 Humble或Jazzy。不要为了学ROS 1去把系统重装成旧版本,也不要硬在旧系统上折腾ROS 2,版本对应关系在后面会给出表格。
为什么现在还要学ROS 1?因为存量代码、资料教程,尤其是机械臂、SLAM、自主导航相关的方案,很多仍然基于ROS 1。特别多实验室和工业项目在运行着Noetic,相关Bug解决方案也都沉淀得比较完整。ROS 2的优势是原生支持多机通信、实时性更好、安全性更强,但入门资料和学习曲线目前还是比ROS 1陡一些。
我从近期的热搜词里看到,大家对“ros安装”“ubuntu哪个版本好”“鱼香ros一键安装”的关注度非常高。可见对多数人来说,卡住他们的往往不是概念,而是环境。所以我这篇教程仍然以ROS 1 Noetic为主线,同时会在关键位置指出ROS 2对应的操作方式。当你理解了ROS 1这套通信逻辑,切换到ROS 2只是命令和包管理习惯的改变,核心概念是互通的。
1.3 操作系统与ROS版本的对应关系
再看一遍,ROS不同版本绑定的Ubuntu版本很严格,装错了基本等于白折腾。我把常见的对应关系列成一张表,你可以直接对照。
| Ubuntu版本 | 推荐ROS版本 | 维护状态 | 适用场景 |
|---|---|---|---|
| 18.04 Bionic | ROS Melodic | 已停止维护 | 旧项目,不推荐新学 |
| 20.04 Focal | ROS 1 Noetic | 社区维护,稳定 | 新人学习ROS 1首选 |
| 20.04 Focal | ROS 2 Foxy | 已停止维护 | 旧ROS 2项目 |
| 22.04 Jammy | ROS 2 Humble | 长期维护 | 新人学习ROS 2首选 |
| 24.04 Noble | ROS 2 Jazzy | 长期维护 | 最新设备新装机首选 |
需要特别提醒的是,ROS 1 Noetic只支持Ubuntu 20.04,不会官方适配22.04。网上虽然有在Ubuntu 22.04上装Noetic的折腾方法,但很容易遇到依赖地狱,新手不建议碰。如果你手头是ARM架构的设备,比如树莓派、某些国产ARM开发板,安装思路和x86稍有区别,建议优先查找对应架构的镜像或使用鱼香ROS提供的检测方案。
2. 安装ROS:把最劝退的一步走完
2.1 一键安装脚本为什么值得用
新手安装ROS遇到的最大痛点并不是命令多,而是软件源配置和依赖冲突。官方安装流程需要先配置ROS软件源、添加密钥,然后安装一大堆依赖包,中间还会遇到rosdep init和rosdep update,这两步因为网络和官方服务器不稳定的原因,卡住过很多人。
国内社区用“一键安装”来解决这个问题的思路是,帮你自动完成系统版本检测、软件源切换、ROS软件源配置、依赖安装、环境变量写入。这样确实省掉了很多新手自己排错的时间。鱼香ROS一键安装脚本就是这类工具里被讨论最多、更新也比较勤快的一个,在热词里反复出现,可见实际使用人群不小。
我在新装机或帮朋友配置环境时,也经常用这类脚本做基础环境安装,然后再手动补充自己需要的功能包。对入门教学来说,这种方式能让新手先跑起来,不被环境劝退。这就好比你学做饭,第一步是先把火点着,而不是先研究燃气管道是怎么铺设的。
2.2 鱼香ROS一键安装实操
在终端里依次执行下面的命令:
wget http://fishros.com/install -O fishros && . fishros执行时会需要输入sudo密码,然后它会弹出一个图形化的选择菜单。不同时期的脚本菜单会有些差异,但基本都会包含“安装ROS”、“配置环境”、“安装依赖”等选项。选择对应你Ubuntu版本的ROS 1 Noetic或ROS 2 Humble即可。
这里有个重要的点,脚本执行完并不代表你立刻就能用ROS,它一般会在末尾提示你重新打开终端,或者手动执行:
source ~/.bashrc安装完成后,我建议你再执行一次脚本,把“ROS环境配置”相关选项也跑一遍,确保ROS_DISTRO、ROS_MASTER_URI这些环境变量被正确写入了~/.bashrc。
提示:一键安装脚本会修改系统软件源,如果你之后不想用它了,可以先备份
/etc/apt/sources.list再执行。实际生产环境或公司内网服务器,我仍然建议使用官方手动流程,方便定位问题。
如果你是离线环境,或者公司内网无法访问外网,一键脚本也用不了,只能找台能联网的电脑把离线依赖包都下载好再迁移。这个属于特殊情况,不展开讲了。
2.3 手动安装的完整流程(以Noetic为例)
虽然推荐了脚本,但手动流程你还是应该完整走一遍,这样才能真正理解ROS安装的每一步在做什么。这里以Ubuntu 20.04安装ROS Noetic为例,给出可以直接复制的命令。
第一步,配置/etc/apt/sources.list里的ROS软件源,并添加ROS的GPG密钥:
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt install curl curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add - sudo apt update第二步,安装完整桌面版,包含Gazebo、RViz、turtlesim和大量常用库:
sudo apt install ros-noetic-desktop-full这一步体积比较大,依赖几百个包,耗时取决于网络。看到进度条走完基本就成功了一半。
第三步,初始化rosdep:
sudo rosdep init rosdep update依赖管理工具会处理功能包之间的依赖关系,新手如果跳过这步,后面编译别人的代码时经常报找不到依赖。然后安装构建工具链:
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential第四步,把ROS环境变量写进bashrc,让每次打开终端自动加载:
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrcROS 2 Humble的安装流程类似,区别是把noetic替换成humble,并且环境配置要改为:
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc2.4 安装完之后必须做的验证
安装完成不要急着写代码,先做三个基本验证。
验证版本:
rosversion -d如果输出noetic,说明ROS 1环境变量生效了。再验证核心服务是否可以正常启动:
roscoreroscore是ROS 1所有节点的运行基础,相当于通信中枢。启动后能看到一堆日志输出,最后保持前台运行不要关。新开一个终端,输入:
rosnode list如果能看到/rosout,说明你的ROS环境已经可以正常通信了。到这一步,安装工作才算真正结束。
注意:
roscore启动后占住当前终端,每次使用都要开新终端。很多新手卡在这里很久,搞不清楚为什么命令会“卡住不动”,其实那是程序在正常运行。
3. 建立工作空间并运行你的第一个节点
3.1 先理解catkin工作空间
工作空间可以理解成你所有ROS项目代码的存放目录。它规定了源码、编译产物、环境脚本的固定结构,CMake负责底层编译,catkin负责管理多个ROS功能包之间的依赖。
进入工作空间目录后,你会看到三个子目录:src放源码,devel放编译生成的可执行文件和setup脚本,build放中间编译文件。对新手来说,你只需要记住自己写的代码放src,编译之后执行source devel/setup.bash。
ROS 2对应的工作空间构建工具改成了colcon,命令从catkin_make变成colcon build。二者逻辑类似,但产物目录结构不同,ROS 2会生成install目录。如果你是从ROS 2入门,把下面命令里的catkin_make替换成colcon build即可。
3.2 创建工作空间和功能包
先把工作空间建起来:
mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_init_workspace这一步会在src目录下生成一个CMakeLists.txt链接文件。然后编译空的工作空间:
cd ~/catkin_ws catkin_make第一次编译只是生成环境,没有什么业务代码,所以速度很快。编译完成后,工作空间里就会出现devel和build目录。接着把当前工作空间的环境加载到ROS环境中:
source devel/setup.bash这个命令很重要,如果你以后运行自己的节点提示找不到包,99%是没执行这一步。执行完可以用echo $ROS_PACKAGE_PATH验证,输出里应当包含/home/你的用户名/catkin_ws/src。
再创建功能包:
cd ~/catkin_ws/src catkin_create_pkg beginner_tutorials std_msgs rospy roscpp这条命令会生成beginner_tutorials功能包目录,并且自动在package.xml里记录依赖关系。名字里的std_msgs是标准消息包,rospy和roscpp分别是Python和C++的客户端库。
3.3 写一个会说话的发布订阅程序
在beginner_tutorials目录下新建scripts文件夹,放一个最简单的Python发布节点talker.py:
#!/usr/bin/env python3 import rospy from std_msgs.msg import String def talker(): pub = rospy.Publisher('chatter', String, queue_size=10) rospy.init_node('talker', anonymous=True) rate = rospy.Rate(1) while not rospy.is_shutdown(): hello_str = "hello world %s" % rospy.get_time() rospy.loginfo(hello_str) pub.publish(hello_str) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass再写一个订阅节点listener.py:
#!/usr/bin/env python3 import rospy from std_msgs.msg import String def callback(data): rospy.loginfo("I heard %s", data.data) def listener(): rospy.init_node('listener', anonymous=True) rospy.Subscriber('chatter', String, callback) rospy.spin() if __name__ == '__main__': listener()这两个程序就是ROS最经典的发布订阅通信模型。发布节点创建了一个叫chatter的话题,以1Hz的频率发布字符串消息;订阅节点监听同一个话题,收到消息后触发callback回调。消息传递的载体是std_msgs/String,ROS里每一种消息类型都有严格定义,新手可以把它理解成函数调用里的参数类型。
3.4 编译并运行talker和listener
给两个Python文件加可执行权限:
chmod +x ~/catkin_ws/src/beginner_tutorials/scripts/talker.py chmod +x ~/catkin_ws/src/beginner_tutorials/scripts/listener.py标准做法是修改功能包里的CMakeLists.txt,取消注释catkin_install_python区域,把脚本安装到devel目录。新手图省事也可以直接从scripts目录用python命令运行,但不规范,我建议还是按标准流程来。
在CMakeLists.txt中找到并修改下面这段:
catkin_install_python(PROGRAMS scripts/talker.py scripts/listener.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )然后回到工作空间根目录编译:
cd ~/catkin_ws catkin_make source devel/setup.bash开三个终端,第一个运行roscore,第二个运行:
rosrun beginner_tutorials talker.py第三个运行:
rosrun beginner_tutorials listener.py如果看到listener终端持续打印I heard hello world ...,说明你的第一个ROS程序已经跑通了。这套流程从创建工作空间到编译运行,是整个ROS开发的基本功,后面所有功能包开发都是在这个模式上叠加功能。
4. 用turtlesim把通信机制玩明白
4.1 启动小乌龟需要哪几个命令
turtlesim是ROS自带的小乌龟仿真器,特别适合用来理解节点、话题、服务这些抽象概念。它自带一个蓝色窗口,里面有一只小乌龟,可以通过键盘控制它在画布上移动。
先确保roscore在运行,然后开两个新终端。第一个终端启动小乌龟节点:
rosrun turtlesim turtlesim_node第二个终端启动键盘控制节点:
rosrun turtlesim turtle_teleop_key这时有个特别容易栽跟头的地方:焦点要停在键盘控制终端上,按方向键乌龟才会动。如果你点了小乌龟窗口再按键盘,控制终端没收到按键,乌龟不会反应。我第一次跑这个实验时就在这卡了一分钟,以为程序出了问题。
4.2 用rosnode和rostopic观察通信
小乌龟跑起来后,打开新终端执行:
rosnode list会看到/rosout、/turtlesim和/teleop_turtle这几个节点。再执行:
rostopic list会看到大量话题,其中核心的是:
/turtle1/cmd_vel,键盘节点发布速度指令的话题/turtle1/pose,小乌龟发布自身位姿的话题
用下面这条命令可以实时打印话题内容:
rostopic echo /turtle1/pose控制乌龟移动一下,你会看到终端刷出一串坐标和角度。这里能非常直观地理解发布订阅机制:/turtlesim节点一边接收cmd_vel指令,一边发布pose位置,两个方向的数据流互不干扰。
想要可视化看节点和话题之间的连线拓扑,可以运行:
rqt_graph它会弹出一个图形窗口,展示当前所有节点和话题的关系。这个工具写复杂项目时非常有用,能一眼看出节点之间的连接是否正常。
4.3 rostopic pub手动发布速度指令
不依赖键盘节点,直接用命令行给小乌龟发指令,更能体会话题的本质。执行:
rostopic pub -r 1 /turtle1/cmd_vel geometry_msgs/Twist "linear: x: 2.0 y: 0.0 z: 0.0 angular: x: 0.0 y: 0.0 z: 1.8"-r 1表示以1Hz频率连续发布,geometry_msgs/Twist是消息类型,linear和angular分别对应线速度和角速度。执行后你会看到小乌龟开始绕圈。这就是ROS通信机制的核心:不管数据是来自键盘、代码还是命令行,只要往cmd_vel话题上发标准Twist消息,小乌龟就会动。
再试一下只发布一条的服务类指令:
rosservice call /turtle1/teleport_absolute "x: 5.5 y: 5.5 theta: 0.0"小乌龟会瞬间跳到指定坐标,这个话题和服务的区别就在这:话题是持续的数据流,适合传感器数据;服务是一问一答的请求响应,适合临时指令。
4.4 话题、服务、动作的区别(附对比表)
ROS里三种主流通信机制,入门时容易混淆,我用表格把它们的区别理清楚:
| 通信机制 | 通信方向 | 是否持续 | 典型场景 | 举例 |
|---|---|---|---|---|
| 话题 | 单向数据流,一发布多订阅 | 持续不断 | 传感器数据采集、状态发布 | 激光雷达点云、IMU数据 |
| 服务 | 一问一答,客户端请求服务端响应 | 一次性 | 开关控制、参数查询 | 拍照指令、调用机械臂动作 |
| 动作 | 客户端发送目标,服务端反馈进度和结果 | 长时执行 | 导航、机械臂运动规划 | 走到某个目标点,反馈路径进度 |
ROS 2中的通信模型更加统一,底层通信框架从ROS 1的自研TCPROS/UDPROS换成了DDS,节点发现、服务质量QoS这些概念都变得更强大,但话题、服务、动作的分类思想没有变。先把ROS 1这套玩熟练,再切换到ROS 2不会感到陌生。
5. 入门阶段最容易踩的坑
5.1 环境变量没生效,ros命令找不到
新手最常遇到的问题是明明装了ROS,打开终端输入rosversion却提示命令不存在。原因是/opt/ros/noetic/setup.bash没有写入~/.bashrc,或者当前终端还没有重新加载配置。
排查时先手动执行:
source /opt/ros/noetic/setup.bash如果命令能用了,说明是环境变量没有自动加载。检查~/.bashrc末尾有没有这一行,没有就手动加,然后重新打开终端。再检查echo $ROS_DISTRO是否输出noetic。
还有一种情况是你自己创建的工作空间里的包找不到,这是没有执行:
source ~/catkin_ws/devel/setup.bash建议把工作空间的环境加载也写入~/.bashrc,放在ROS系统环境变量后面:
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc source ~/.bashrc5.2 rosdep update失败和依赖缺失
rosdep update是新手最常跪的一步。如果提示网络错误或无法连接,可以先检查/etc/hosts配置,或者换一个网络环境重试。如果实在更新不了,对纯学习来说可以先跳过。后续编译某些包时如果提示缺依赖,再回头单独安装对应依赖。
实际开发中更常见的问题是:从GitHub上下载了一个功能包,编译时报错Could not find the required component xxx。这说明你的系统缺少对应的ROS依赖包。查找方法很简单,用apt search ros-noetic-xxx,找到后直接sudo apt install ros-noetic-xxx。
还有一种让新手摸不着头脑的情况,就是明明rosdep update成功了,但rosdep install时还是报错某条规则过时。这通常是rosdistro缓存太旧,执行:
rosdep update刷新一下再试,不行就把/etc/ros/rosdep/sources.list.d/20-default.list删掉重新rosdep init。
5.3 Python版本引发的问题
ROS Noetic官方推荐Python 3,而很多网上教程的代码还是Python 2写法,直接复制运行会报语法错误或except导入错误。比如有些老代码里写#!/usr/bin/env python,在只装了Python 3的纯净系统上会找不到解释器,要把第一行改成#!/usr/bin/env python3。
另一个和Python相关的坑是装了多个Python版本,比如系统自带Python 3.8,你又用conda创建了Python 3.10的环境,导致ROS相关python包路径错乱。ROSn依赖于系统Python路径,如果你在conda环境里跑rosnode,经常会崩。最简单的方法是:日常ROS开发时先退出conda环境,或者不要忘记用conda deactivate。
ROS 2还存在rclpy与Fast DDS的兼容问题,某些环境下节点反复重启,多半是rmw_implementation和Python版本不匹配,这个进阶一点,先记下来遇到再查。
5.4 硬件与仿真设备怎么接(预告)
很多人的目标是机械臂控制和SLAM导航,装完ROS就会问下一个问题,我的机器人怎么连上来。其实不管是真实设备还是仿真,走的都是同一套接口逻辑。真实传感器通过驱动节点把数据发布到对应话题,比如激光雷达的点云话题;仿真环境则用Gazebo模拟传感器,再发布同样话题。
我看到热词里“gazebo安装ros环境ubuntu22”“ros小车自主导航仿真”“ros仿真中常用的传感器激光雷达”这些词热度很高,说明大家到后期都会往仿真和导航走。Gazebo在Noetic里是随desktop-full一起装的,启动命令是:
roslaunch gazebo_ros empty_world.launch激光雷达、摄像头这些传感器在仿真里都有现成的模型,可以先把仿真跑起来,再慢慢接真实驱动。这是本系列后续内容要去深入的部分,你只需要知道:前面所有打基础的操作,都是为了后面接真实机器人做铺垫。
写给你我这样的初学者
这套流程我陪朋友和环境折腾过很多次,最大的体会是ROS入门不要追求一次看懂所有概念,关键是先让代码跑起来。装好环境,跑通turtlesim,再用自己的程序实现一次话题收发,成就感上来了,后面学起来就有足够动力。如果有人在你第一次运行roscore时告诉你,你已经在运行一个分布式通信系统了,你可能觉得有点抽象,但等你自己把发布的节点和订阅的节点跑通,那种“通了”的感觉会帮你记住整个机制。
最后再分享一个小技巧:把常用命令写进终端别名。你可以这样配置:
alias cm='cd ~/catkin_ws && catkin_make && source devel/setup.bash'之前每次编译完都要手动source,写进去之后每天能少敲十几下键盘,专注力也能放在更有价值的地方。