Android 开发者搞 ROS2(一):环境部署

一、为什么一个 Android 开发要去搞 ROS2

先交代身份:我是 Android 开发,Kotlin 写了几年,Gradle、OkHttp、JNI 这套东西天天摸。机器人对我来说一直是个"想碰但没入口"的领域——直到工作里真的撞上了:端侧设备要跟一台跑 ROS2 的上位机通信,我写的 Android 端要对上人家的话题和消息格式。那一刻我发现,不懂 ROS2 的 Android 开发者,在机器人团队里就是个"只会写 App 的外设"。

而且这两个领域的相似度比想象中高。ROS2 的节点像 Android 的组件,话题像广播,服务像 AIDL 接口,launch 文件像 Gradle 任务图——概念几乎可以一一映射。真正的差异不在编程,而在生态:Android 有一套 IDE 帮你包办环境,ROS2 的环境全要自己懂。这个系列就是把这个"懂环境"的过程掰开写,给同路人的 Android 开发者省点时间。

写作约定:本系列假设你会 Java/Kotlin 和 Linux 基本命令,其他从零讲。

二、环境选择:Ubuntu 版本 + ROS2 版本

新人第一懵:ROS2 一堆版本名(Foxy、Humble、Jazzy、Kilted……),每个还绑死一个 Ubuntu 版本。先说结论,别纠结:

  • 2026 年 10 月这个时间点,选 Jazzy + Ubuntu 24.04。理由三条:LTS 对 LTS(支持到 2029)、生态包最全、教程和第三方库基本都跟进完了。
  • Humble(22.04)是存量最大的老 LTS,公司老项目多用它——遇到再装,不作为起点。
  • Kilted 太新,包不全,除非你要追特性,否则不推荐入门用。

一条铁律记下来:ROS2 版本和 Ubuntu 版本是绑死的,Jazzy 只能装在 24.04 上。装错系统的唯一解是重装或虚拟机,没有"跨版本装"这回事——这是官方 apt 源的硬约束,不是建议。

安装就用官方一条龙脚本(ros-jazzy-desktop 完整版,含 RViz 和演示):

# 官方 apt 源 + 密钥
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl -y
sudo curl -LsS https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
  -o /usr/share/keyrings/ros-archive-keyring.gpg

# 加源(一行)
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \
  http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" \
  | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

# 安装桌面完整版
sudo apt update
sudo apt install ros-jazzy-desktop -y

装完先别高兴——最大的坑就在下一步。

三、踩坑:command not found

这是全文最想让你绕开的一坑,我在这上面耗过一个多小时。

装完 ROS2,兴冲冲敲第一条命令:

$ ros2 topic list
ros2: command not found

第一反应是"装失败了吧",卸了重装,还是 not found。又怀疑 apt 源有问题,换了镜像,还是不行。其实 ROS2 装得好好的,问题在于它没把自己交给你——ROS2 的所有命令行工具不在系统默认 PATH 里,每次开新终端,你必须先手动"激活"一下它的工作环境,这个动作叫 source:

source /opt/ros/jazzy/setup.bash

跑完这一句,ros2 topic list 立刻活了。为什么这么设计?因为一台机器可能同时装多个 ROS 版本(比如老的 Humble 和新的 Jazzy 共存),靠 source 哪个版的 setup.bash 来切换,互不干扰——这是多版本共存的设计代价,不是 bug。

但每次开终端都手敲一遍肯定受不了,Android 开发者的直觉马上出来了:这就像每次打开 Android Studio 都要手动 export ANDROID_HOME。解法也一样——写进 shell 配置,全局自动生效:

# 一劳永逸:追加到 ~/.bashrc,每次开终端自动 source
echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc
source ~/.bashrc

# 验证:这个能出版本号就成了
ros2 --help

一个排坑技巧送给你:如果 source 之后还是 not found,九成是 setup.bash 的路径敲错了(版本名要对上,Humble 就是 /opt/ros/humble/setup.bash)。用 ls /opt/ros/ 看一眼你实际装了哪个版本,比瞎猜快得多。

四、turtlesim:你的第一只乌龟

环境通了,用 ROS2 界的 "Hello World" 验收——turtlesim,一只能用键盘遥控的小乌龟。它丑得经典,但一只乌龟背后是一整套节点、话题、消息的运转,跑通了它你就摸到了 ROS2 的全部基本概念。

# 终端 1:启动乌龟仿真器
ros2 run turtlesim turtlesim_node

弹出蓝底窗口、中间一只乌龟,成功。再开一个终端让它动起来:

# 终端 2:键盘遥控(光标必须停在这个终端里才有输入)
ros2 run turtlesim turtle_teleop_key

用方向键开一圈,乌龟身后会拖出轨迹线——这已经是"发布/订阅"在工作了:遥控节点往 /turtle1/cmd_vel 话题发速度消息,仿真节点订阅它并更新乌龟位置。你在 Android 里写的 LiveData/Flow 观察者模式,到这里就是 topic 的 pub/sub,一个意思。

五、关窗杀节点 + topic echo 刷屏

两个 5 分钟小实验,帮你建立"节点生死"和"消息流动"的手感。

实验一:关窗 = 杀节点? 直接点掉乌龟窗口,然后在终端里看:

# 乌龟窗口关掉后,查看还活着的话题
ros2 topic list

你会发现 /turtle1/cmd_vel 之类的话题还在列表里——窗口没了,节点不一定立刻死透(遥控节点还活着,它还在发布)。这个"UI 消失 ≠ 进程退出"的错觉,Android 开发者应该秒懂:跟 Activity 销毁了但 Service 还在跑是一个道理。想干净杀掉,回到对应终端按 Ctrl+C。

实验二:亲眼看消息流。 开着乌龟和遥控,再来一个终端:

# 订阅速度话题,消息会实时刷屏
ros2 topic echo /turtle1/cmd_vel

然后按方向键——终端里 [x: 2.0, y: 0.0, z: 0.0] 这样的消息按你按键的节奏疯狂滚动。你亲眼看到的就是"发布/订阅"的本体:遥控节点每秒发 N 条 geometry_msgs/Twist,echo 只是又一个订阅者。以后调试任何话题,第一反应就是 topic echo 挂上看一眼——这是 ROS2 开发者的 logcat。

六、小结 + 下篇预告

这一篇干了三件事:选对版本(Jazzy + Ubuntu 24.04,绑死关系记牢)、跨过第一个大坑(command not found 的真相是 source 机制,不是安装失败)、用一只乌龟摸到了 pub/sub(turtlesim + topic echo 就是你的 Hello World 加 logcat)。

下一篇我们干 Android 开发者最舒服的事:把 ROS2 装进 Android Studio 的工作流——用 workspace 组织代码(类比 Gradle 工程)、colcon 编译(类比 gradle build)、写第一个 Python 节点(类比写一个 BroadcastReceiver)。工具链一通,后面的概念都能落到你熟悉的开发节奏里。

系列目录:

  1. 环境部署(本文)
  2. 工作空间与第一个节点(写作中)

参考资料