说实话,每年我带过的新人里,十个有八个不是被 ROS 难倒的,而是被安装和一堆莫名其妙的概念劝退的。他们第一天翻开教程,看到三四个终端窗口、一堆没见过的命令,心里就开始打鼓。这期内容我想把这些拦路石先搬掉。它是 ROS 系列的第一篇,覆盖最基础的三件事:ROS 在整个机器人学习路径里到底处于什么位置、怎么用最省力的方式装好一套可用的环境、以及如何通过小乌龟经典 Demo 和手写节点把发布订阅通信跑通。内容适合完全没接触过 ROS 的同学,也适合装了好几次都没跑起来、想回头补基础的人。
1. ROS到底是什么:学机器人为什么绕不开它
1.1 一个让机器“长脑子”的软件框架
很多人第一次听"ROS"这个名字,以为它是一个操作系统,跟 Windows、Ubuntu 一样装在电脑里。实际上完全不是一回事。ROS(Robot Operating System)是一个机器人软件框架,它寄生在 Ubuntu 这类操作系统之上,干的事情更像一个"神经系统"——把机器人身上的摄像头、激光雷达、电机、机械臂这些硬件,通过统一的通信机制连接起来,让不同模块之间能互相喊话、传数据。
你可能会问:我写程序直接调硬件不行吗?行,但问题很快就会来。比如你要做一个自主导航小车,需要同时处理激光雷达数据、控制电机、做路径规划、跑可视化界面,每个模块如果各写各的,接口五花八门,联调的时候就是一场灾难。ROS 提供了一个公共的"消息总线",让所有模块按统一格式收发数据,还附带了一堆现成的算法包,不用每次从零造轮子。这才是它流行的根本原因。
所以更准确的理解是:ROS = 通信框架 + 算法工具箱 + 仿真调试生态。它让机器人开发从"一个人从驱动写到决策"变成了"很多人各自写一个节点,最后拼起来跑"。
1.2 高频关键词背后对应着哪些实用功能
你在搜索框里输入 ROS,跟着蹦出来的词往往是:SLAM、Navigation、Gazebo、MoveIt、相机标定、机械臂。这些不是炒作,它们对应着 ROS 生态里最能落地的那几块领域:
- SLAM 建图:让小车边走路边画地图,解决"我在哪、周围长什么样"的问题,最常用的是 gmapping、cartographer 这些包。
- Navigation 导航:地图有了之后规划路线并避障,核心是 move_base、amcl 这一套。
- Gazebo 仿真:在没有真机的时候,用三维物理环境跑机器人和传感器,相当于机器人的"驾校练车场"。
- MoveIt:机械臂的规划与控制框架,用于做抓取、运动规划。
- 相机标定:把摄像头拍出来的图像和真实世界的坐标对应起来,是视觉识别和深度相机使用的前置步骤。
这些听着很高级,但它们的共同底层都是发布订阅通信。你只要把节点、话题、消息这三样基础吃透,后面学什么都是顺水推舟。反过来,一上来就想去跑导航仿真,多半会被一堆 bug 按在地上摩擦。
1.3 哪些人不适合现在学ROS
话虽这么说,我也想泼点冷水。ROS 不是"今天装上明天就能做机器人"的速成工具。它适合已经有 Python 或 C++ 基础、了解 Linux 基本命令、对机器人运动学或传感器有初步概念的人。如果你连终端是什么都还没搞懂,建议先花一周时间熟悉 Ubuntu 和 Linux 文件操作,再回来学 ROS,效率会高很多。
2. 安装前的版本选择题:Ubuntu和ROS的搭配关系
2.1 版本对应关系与LTS选择
ROS 安装这件事,第一道门槛不是命令,而是版本对应。ROS 每个版本都有固定的 Ubuntu 搭配,不能随便混装。我整理了一张表,可以直接照抄:
| ROS版本 | 对应Ubuntu版本 | 类型说明 | 适合谁 |
|---|---|---|---|
| ROS Noetic | Ubuntu 20.04 | ROS1最后一个长期支持版 | 课程教材、论文复现、存量项目 |
| ROS2 Humble | Ubuntu 22.04 | ROS2长期支持版 | 新项目、新同学首选 |
| ROS2 Foxy | Ubuntu 20.04 | ROS2早期版,已逐步淡出 | 老设备兼容 |
| ROS2 Rolling | 滚动更新 | 尝鲜版 | 不建议新手碰 |
我给新人的建议很直接:没有特殊理由,直接上 ROS2 Humble + Ubuntu 22.04。ROS1 确实还有大量教程和比赛在用,但已经不再新增功能,新项目再用它等于给未来埋坑。如果你的毕业设计或实验室代码是基于 Noetic 的,那老老实实装 ROS1 也是合理的;两条路走通一条,之后迁移概念并不难。
2.2 双系统、虚拟机还是直接用Ubuntu
定好 ROS 版本之后,还有一个环境选择问题。常见的方案有三种:
- 双系统:在电脑上同时装 Windows 和 Ubuntu,开机时选择进哪个。好处是性能完整,USB 设备、显卡直通都没问题,适合要接真机、跑仿真、用视觉库的同学。坏处是安装步骤稍微复杂,要会分磁盘。
- 虚拟机:在 Windows 里用 VirtualBox 或 VMware 装一个 Ubuntu。胜在方便,随时可以删了重来,适合前期熟悉 Linux 和 ROS 命令。短板是 3D 加速和 USB 设备透传有时折腾人,Gazebo 这类重仿真会卡。
- WSL2:Windows 自带的 Linux 子系统。轻量,但图形界面和串口设备支持不够省心,入门阶段不建议选这条路,容易在环境问题上消耗掉学习热情。
我的建议是分阶段走:第一周先用虚拟机把 ROS 环境和小乌龟 Demo 跑通,确认自己确实对这东西感兴趣,再腾出一块磁盘装双系统,把仿真和真机流程接上。别一开始就纠结"我要不要直接重装成 Ubuntu",省下的焦虑可以留给后面的 bug。
2.3 系统装好后先做这几件小事
不管用哪种方案,全新 Ubuntu 系统到手后,建议先完成四件小事:
- 把 Ubuntu 软件源替换成国内镜像源,否则 apt 下载软件会慢到怀疑人生。
- 安装基础工具:
sudo apt install git vim curl wget terminator,Terminator 可以分屏开多个终端,后面跑 ROS 会非常常用。 - 确认 Python 版本:Ubuntu 20.04 和 22.04 自带的 Python3 都是可用的,Noetic 和 Humble 也都以 Python3 为基础,不用另装。
- 检查磁盘空间和内存:建议至少 40GB 空闲磁盘、8GB 以上内存。装完 ROS 桌面完整版之后,磁盘会被吃掉十几个 G。
3. 装ROS的两种路线:一键脚本和手工安装的完整流程
3.1 为什么一键脚本能流行起来
以前装 ROS 是一件相当劝退的事:先配源、再加秘钥、然后 apt 更新、装一堆依赖包,最后还要初始化 rosdep。任何一个环节卡住,新手就没了。所以当社区里出现"鱼香ROS一键安装脚本"这种东西时,我一点都不意外它会火——它把上面的繁琐步骤写成了交互式菜单,让你选择要装 ROS1 还是 ROS2,然后自动换源、装依赖、初始化环境。
如果你只是为了快速获得一个能用的 ROS 环境,用一键脚本完全没问题。但我也得提醒一句:脚本只是工具,不是银弹。它帮你跳过了手工步骤,也会让你跳过对目录结构、软件源、环境变量这些底层机制的理解。所以我建议的路线是:新手用脚本,装好后再花一小时看看手工安装流程到底做了什么;基础比较稳的同学,直接手工安装,一次把体系摸透。
3.2 鱼香ROS一键安装脚本的使用方式
这个脚本更新频率挺高,所以我习惯的做法是:先去项目主页复制当前版本的安装命令,而不是依赖网上几年前的帖子。我印象里的命令是:
wget http://fishros.com/install -O fishros && . fishros执行后会进入一个交互式菜单,里面可以选:
- 安装 ROS1(Noetic)还是 ROS2(Humble)
- 是否更换软件源为国内镜像
- 是否初始化 rosdep/rosdepc
- 是否安装常用开发工具
脚本运行过程中会让你输几次密码,其他基本全自动。装完之后它会提示你source /opt/ros/xxx/setup.bash或者帮你写入~/.bashrc,按提示操作就行。
如果你在搜索时看到别人贴的命令,但脚本已经换了新版本,不要慌,去官方项目页面找最新命令,通常比旧帖子可靠。社区维护的脚本有个特点:版本迭代快,网上转载容易过期。
3.3 手工安装ROS Noetic的标准流程
如果你更想把手动流程完整走一遍,下面这套是 ROS Noetic 在 Ubuntu 20.04 上的标准安装流程。先把软件源换成国内镜像,这里以中科大源为例:
sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list'然后添加秘钥并更新索引:
sudo apt update && sudo apt install curl -y curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add - sudo apt update接着安装完整桌面版,这一步包含 Gazebo、RViz、常用可视化工具等,体积比较大,耐心等:
sudo apt install ros-noetic-desktop-full -y最后是初始化 rosdep 和写入环境变量:
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential -y sudo rosdep init rosdep update echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrcROS2 Humble 的手工安装也类似,只是源和包名不同,核心思路是一样的。这里不展开全部命令,因为对于零基础读者,我反而建议先通过一键脚本跑通环境,再回来看手工流程理解原理。
3.4 安装完成后的环境“体检”命令
装完先别急着兴奋,用一组体检命令确认一下环境:
source /opt/ros/noetic/setup.bash echo $ROS_DISTRO如果输出noetic,说明 ROS 环境变量正常。再输入:
roscore这条命令会启动 ROS 的核心调度节点,如果出现一堆类似started core service [/rosout]的日志,那就说明核心通信机制正常,可以 Ctrl+C 停掉。对于 ROS2,可以用ros2 run demo_nodes_cpp talker做类似体检。
假如roscore提示找不到命令,多半是环境变量没生效,重新source ~/.bashrc,或者手动执行source /opt/ros/noetic/setup.bash就好。
4. 核心机制的直觉化理解:节点、话题、服务、参数
4.1 source命令和roscore分别做了什么
很多人把source /opt/ros/noetic/setup.bash当成"每次开终端都要敲一次的咒语",但不理解它到底干了什么。其实它就是把 ROS 的安装路径、可执行文件路径、库文件路径写入当前终端的环境变量。每个终端是独立的环境,所以你新开的窗口不 source 就找不到rosrun、rostopic这些命令。
roscore则是启动一个"通信中枢"。ROS1 里面,节点之间互相不认识,它们都先去roscore那里报个到,再通过它牵线搭桥交换数据。所以那个跑着roscore的终端窗口不要轻易关掉,一旦关了,整个系统就瘫痪了。ROS2 不再需要单独跑roscore,但它没出现在终端里不代表不存在,它把发现机制做进了每个节点的底层,对使用者来说反而更省心。
4.2 用一家餐厅理解四个核心概念
ROS 最核心的四个概念是节点、话题、服务和参数。这些名词单独看很抽象,我用餐厅来打比方,你品一下:
- 节点:是程序里的一个独立模块,可以理解成餐厅里的一个员工。有人负责炒菜,有人负责传菜,有人负责收银。每个节点干一件事,可以独立启动和关闭。对应到命令里就是
rosrun启动的东西。 - 话题:是节点之间单向传递数据的"传菜窗口"。后厨做好菜放到窗口,服务员取走,双方不用直接认识。发布数据的一方叫发布者,接收的一方叫订阅者。比如雷达节点持续发布距离数据,导航节点订阅这些数据,双方通过话题名对接。
- 服务:需要"一问一答"的场景,比如你向地图节点请求"从 A 点到 B 点的路径",它计算后返回结果。跟话题的区别是:话题是持续流动的广播,服务是一次性的请求响应,更像顾客点餐、后厨出品的交互。
- 参数:相当于贴在墙上的配置表。比如把机器人的速度上限、摄像头分辨率写进参数服务器,多个节点启动时去读,不用把配置写死在代码里。
4.3 前期还常遇到的名词:tf、msg、bag、launch
除了四大核心概念,你翻教程时还会高频碰到几个词,这里提前扫个盲:
| 名词 | 含义 | 入门期你需要知道的事 |
|---|---|---|
| msg | 消息格式定义 | 比如std_msgs/String表示一个字符串消息,通信时数据都按 msg 格式打包 |
| tf | 坐标变换树 | 描述机器人各部件之间的相对位置,后面学导航和机械臂躲不开 |
| bag | 数据包记录 | 把话题数据录下来回放,可以理解为"行车记录仪" |
| launch | 启动文件 | 一次性启动多个节点的"脚本",免去手动开一堆窗口 |
入门阶段你只需要知道它们的存在,不用急着深究。真正要先掌握的,是节点和话题的通信逻辑。
5. 小乌龟Demo:用一支会跑的乌龟建立第一直觉
5.1 启动模拟器的三个经典窗口
ROS 自带一个经典到不能再经典的 Demo——小乌龟模拟器,它有窗口、有动画、有键盘控制,简直是为零基础入门量身定做的。
先开一个终端跑roscore(ROS1 需要),再开第二个终端启动乌龟窗口:
rosrun turtlesim turtlesim_node然后第三个终端启动键盘控制节点:
rosrun turtlesim turtle_teleop_key这时候点一下第三个终端窗口,按方向键,就能看到窗口里的小乌龟动起来。整个过程看起来平平无奇,但背后其实是两个节点通过话题通信:一个节点监听键盘按键,把速度指令发布出去;另一个节点接收速度指令并驱动画面里的乌龟移动。
5.2 键盘遥控与通信可视化
从这一步开始,我就鼓励你带着"看通信"的眼光去玩,而不是当游戏玩。再开一个终端,输入:
rqt_graph屏幕上会出现一张连线图:/teleop_turtle(键盘节点)通过/turtle1/cmd_vel话题连接到/turtlesim(乌龟窗口节点)。看到这张图,你就直观理解了"节点 + 话题 = 数据流动"。
顺手再敲一个命令看看当前系统里有几个话题:
rostopic list你会看到/turtle1/cmd_vel、/turtle1/pose、/rosout等话题名。刚接触时不要追求全部明白,先盯住cmd_vel这一个:它是速度控制话题,所有想遥控乌龟的消息都要往它上面发。
5.3 用命令行发消息:rostopic pub的实战
如果不想用键盘,也能直接用命令给乌龟发指令:
rostopic pub /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这条命令的含义是:以每秒 1 次的频率,向/turtle1/cmd_vel话题循环发布一个速度消息,让乌龟直线前进并旋转。如果你想让乌龟停下来,就把linear.x和angular.z都改成 0。这个练习的意义是:你会意识到,给机器人发指令本质上就是往特定话题上"塞"一条符合格式的数据,跟 ROS 的概念模型完全对应。
5.4 把Demo当成概念对照练习
我建议你在跑通小乌龟后,把下面的对照表过一遍:
| 你在Demo里看到的 | 对应的ROS概念 |
|---|---|
| 键盘节点、乌龟节点 | 节点 |
/turtle1/cmd_vel | 话题 |
| 键盘节点往话题里发速度 | 发布者 |
| 乌龟节点读取并执行 | 订阅者 |
rqt_graph里的连线 | 话题通信关系 |
跑 Demo 跑出"哦,原来通信是这么回事"的感觉,比背十页概念强得多。
6. 第一个Python节点:手写发布订阅通信
6.1 先确定用rospy还是rclpy
看完小乌龟,你可以试着写第一个自己的节点了。这里先要分清语言接口:ROS1 对应rospy,ROS2 对应rclpy,两者 API 看起来很像,但不能混用。
有人问:入门先用 Python 还是 C++?我的建议很明确:先用 Python。它写起来直观,不用跟编译较劲,适合理解概念。等你把通信机制玩熟了,再切 C++ 去追求性能和实时性,会轻松很多。下面的代码基于 ROS1 Noetic 的rospy,因为 ROS1 教程体系成熟、资料最多,用它入门最不折腾;如果你装的是 Humble,把思路平移给rclpy即可。
6.2 工作空间与功能包结构
ROS 代码的组织单位叫"功能包"(package),多个功能包放在一个"工作空间"(workspace)里。先创建目录并生成功能包:
mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_create_pkg beginner_tutorials std_msgs rospy cd ~/catkin_ws catkin_make source devel/setup.bashcatkin_create_pkg后面跟着的std_msgs和rospy是声明本包依赖的消息库和 Python 接口库。catkin_make编译整个工作空间,ROS2 里对应的是colcon build,思路相仿。
6.3 完整代码:发布者和订阅者
在~/catkin_ws/src/beginner_tutorials/scripts/目录下新建talker.py:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import rospy from std_msgs.msg import String def talker(): # 初始化名为 talker 的节点 rospy.init_node('talker') # 在 chatter 话题上创建一个发布者,缓存队列长度10 pub = rospy.Publisher('chatter', String, queue_size=10) rate = rospy.Rate(1) # 每秒1次 while not rospy.is_shutdown(): msg = String() msg.data = "hello ROS %s" % rospy.get_time() rospy.loginfo(msg.data) pub.publish(msg) rate.sleep() if __name__ == '__main__': try: talker() except rospy.ROSInterruptException: pass再在同目录下创建listener.py:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import rospy from std_msgs.msg import String def callback(data): rospy.loginfo("I heard: %s", data.data) def listener(): rospy.init_node('listener') # 订阅 chatter 话题,来一条消息就回调一次 rospy.Subscriber('chatter', String, callback) rospy.spin() # 保持节点不退出 if __name__ == '__main__': listener()不要忘记给两个文件加执行权限:
chmod +x ~/catkin_ws/src/beginner_tutorials/scripts/talker.py chmod +x ~/catkin_ws/src/beginner_tutorials/scripts/listener.py6.4 编译、运行与查看日志
回到工作空间根目录重新编译:
cd ~/catkin_ws catkin_make source devel/setup.bash然后打开终端跑核心(ROS1):
roscore新终端里运行发布者:
rosrun beginner_tutorials talker.py再开终端运行订阅者:
rosrun beginner_tutorials listener.py如果一切正常,订阅者终端里会持续打印I heard: hello ROS ...。你甚至可以再开一个rqt_graph,会看到talker和listener通过/chatter话题连起来。
再顺手试一个调试神器:
rqt_console它专门收集节点打出的日志。后面系统里节点一多,靠它过滤错误信息会高效得多。
6.5 构建系统的基本操作
这里插一句构建系统的细节,新手最容易搞混。ROS1 里最常用的是catkin_make,每次改了代码都要在工作空间根目录重新执行一次,再用source devel/setup.bash刷新环境。ROS2 里换成了colcon build,刷新用的是source install/setup.bash。命令不一样,但逻辑一样:改了代码先编译、再刷新环境、再运行。很多"代码改了没生效"的报错,根因都是忘了刷新环境。
7. 入门期高频坑位:我先帮你踩过了
7.1 source和终端复用带来的环境问题
入门最经典的坑就是:明明装好了,新开一个终端却提示rosrun: command not found。原因前面说过——每个终端的环境是独立的,没执行source就找不到命令。解决方案是把source /opt/ros/noetic/setup.bash和source ~/catkin_ws/devel/setup.bash都写进~/.bashrc,这样每次开终端自动加载。
还有一个操作习惯问题:我见过不少人开一堆终端,每个窗口还都是一样的白底,跑起来一片混乱。建议把终端换成 Terminator 并给不同窗口设置不同背景色,或者养成分屏的习惯,避免把roscore不小心关掉。
7.2 rosdep、Python版本和权限问题
另一个高频坑是sudo rosdep init卡住或报网络错误。这是环境初始化阶段最磨人的问题之一。我的处理方式是:优先用一键脚本自带的rosdepc或者手动把 rosdep 的索引源指向国内镜像,实在不行就先跳过 rosdep,把它留到真正编译第三方包需要时再处理。对入门阶段跑小乌龟和自写节点来说,它并不影响核心功能。
Python 版本也有讲究。ROS Noetic 明确基于 Python3,所以不要再写 Python2 的rospy代码,否则各种语法错误和兼容问题会把你逼疯。另外,代码文件一定要加chmod +x或者在脚本开头写清#!/usr/bin/env python3,否则rosrun会直接拒绝执行。
7.3 学习路线的克制:别急着追视觉和导航
我看过太多人装上 ROS 第二天就去找"yolov5 ros无人小车"、"ros slam建图和自主导航"的教程,结果被环境依赖、算法包编译、摄像头驱动拖得身心俱疲。不是不能追,而是要有个顺序:先把小乌龟和手写节点这种基础通信玩熟,再去碰坐标变换、再上传感器驱动、最后才是导航和视觉。现在的热搜词里那些高难度方向,本质上都是靠通信把各模块串起来的。基础不牢,后面每一步都是坑。
7.4 搜资料的正确姿势
最后分享一个很实际的搜索技巧:搜 ROS 报错时,不要只搜"ROS 报错"这种模糊词,要把完整报错信息 + 版本号放进去,比如ROS Noetic roscore command not found。另外,先确定你看的教程是基于 ROS1 还是 ROS2,两个版本的命令很多对不上,照着 ROS1 教程在 ROS2 里敲roscore,当然找不到命令。
我在实际带人过程中还发现一个规律:那些入门快的人,不是更聪明,而是更愿意正视报错信息,愿意把"命令为什么这么写"搞清楚。ROS 学习本质上就是一个不断跟终端对话的过程,这个系列的第一篇到这里,正好够你搭好环境、看懂通信、跑起第一个节点。接下来可以把工作空间的组织方式、launch 启动文件、自定义消息格式这些内容一步步加进来,让系统慢慢变得丰满。