核心概念
要理解Android和ROS机器人是如何通信的,它们通常不是直接连接的,而是通过网络(Wi-Fi)进行通信,通信模式主要有两种:

-
基于话题 的发布/订阅模式:
- Android端:作为 发布者,发布控制命令(如
geometry_msgs/Twist,用于控制线速度和角速度)。 - 机器人端:作为 订阅者,订阅这些话题,接收命令并转化为对电机的控制。
- 优点:这是ROS的标准通信方式,解耦性好,易于扩展(可以同时有多个控制端)。
- Android端:作为 发布者,发布控制命令(如
-
基于服务 的请求/响应模式:
- Android端:作为 客户端,发送一个请求(请求获取机器人当前电量)。
- 机器人端:作为 服务器,接收请求,执行操作并返回结果(返回当前电量百分比)。
- 优点:适用于需要明确请求和响应的场景,如查询状态、执行一次性任务。
使用现成的App(最快入门)
如果你只是想快速测试或演示,不想自己编写代码,可以使用一些现成的ROS控制App。
ROS Controller
一个非常流行的开源App,支持多种控制模式。

-
功能:
- 摇杆控制:虚拟摇杆控制机器人前进、后退、转向。
- 键盘控制:屏幕键盘控制(WASD或方向键)。
- 滑块控制:精确控制线速度和角速度。
- 按钮控制:执行预设动作(如启动、停止)。
- 话题/服务列表:可以查看和连接到机器人上的不同话题和服务。
- TF树显示:可视化机器人的TF关系。
- 传感器数据显示:显示摄像头图像、激光雷达数据等。
-
使用步骤:
- 确保手机和机器人在同一Wi-Fi网络下。
- 在机器人端:启动ROS核心,并运行一个简单的键盘或摇杆控制节点(
teleop_twist_keyboard)来测试网络是否通畅。 - 在Android手机上:下载并安装 "ROS Controller" App。
- 打开App,在设置中输入机器人的 IP地址 和 ROS Master URI(通常是
http://<机器人IP>:11311)。 - 连接:App会自动发现机器人上的话题和服务,选择你想控制的话题(如
/cmd_vel)即可开始。
使用ROSBridge(最主流、最灵活的方案)
这是目前最推荐、最灵活的方案,它通过一个名为 ROSBridge 的服务器,将ROS的通信协议(如rostopic)转换为标准的 WebSocket 协议,这样任何支持WebSocket的客户端(包括Android App、网页浏览器)都可以轻松地与ROS通信。
工作流程:
[Android App] <--(WebSocket协议)--> [ROSBridge Server] <--(ROS Topic/Service)--> [ROS Core] <--(ROS Topic/Service)--> [Robot Nodes]
实施步骤:
第一步:在机器人端设置ROSBridge
-
安装ROSBridge Suite: 在你的机器人PC上(通常是Ubuntu系统),运行以下命令安装:
(图片来源网络,侵删)sudo apt-get install ros-<your-ros-distro>-rosbridge-server
将
<your-ros-distro>替换为你的ROS版本,如noetic、melodic等。 -
启动ROSBridge Server: 最简单的方式是直接运行:
roslaunch rosbridge_server rosbridge_websocket.launch
这个命令会启动一个WebSocket服务器,默认监听端口 9090。
-
测试连接: 在同一网络下的电脑浏览器中,打开
http://<机器人IP>:9090/,如果看到{"op": "pong"}或类似信息,说明服务器运行正常。
第二步:在Android端实现App
你可以选择使用现成的库,也可以自己开发。
A. 使用现成的Android库
-
rosjava-android: 这是官方的ROS Java库,功能强大,但配置和使用相对复杂,适合开发复杂的原生应用。
-
Android WebSocket Client + JSON: 更简单的方式是使用任何标准的Android WebSocket库(如
OkHttp),然后手动构造和解析ROSBridge的JSON消息。
B. 手动实现一个简单的控制App(推荐入门)
这里我们使用 OkHttp 库来实现一个发布/cmd_vel消息的App。
-
添加依赖: 在你的
app/build.gradle文件中添加:dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.3' } -
添加网络权限: 在
app/AndroidManifest.xml中添加:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
编写代码:
- 布局文件 (
activity_main.xml): 添加一个摇杆控件,你可以使用现成的库如 Nubuy 或自己实现一个简单的。 - Java/Kotlin代码 (
MainActivity.kt):
import android.os.Bundle import android.widget.Button import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import okhttp3.* import org.json.JSONObject import java.io.IOException class MainActivity : AppCompatActivity() { private val client = OkHttpClient() private val robotIp = "192.168.1.100" // 替换为你的机器人IP private val rosbridgePort = "9090" // 摇杆的回调接口 private val joystickListener = object : JoystickView.JoystickListener { override fun onMove(angle: Float, strength: Float) { // 将摇杆数据转换为 Twist 消息 val linearVel = strength * Math.cos(Math.toRadians(angle.toDouble())) * 2.0 // 最大线速度2.0 val angularVel = strength * Math.sin(Math.toRadians(angle.toDouble())) * 2.0 // 最大角速度2.0 // 构建ROSBridge JSON消息 val json = JSONObject().apply { put("op", "publish") put("topic", "/cmd_vel") put("msg", JSONObject().apply { put("linear", JSONObject().apply { put("x", linearVel) put("y", 0.0) put("z", 0.0) }) put("angular", JSONObject().apply { put("x", 0.0) put("y", 0.0) put("z", angularVel) }) }) } // 发送消息 sendRosMessage(json.toString()) } override fun onTap() { // 发送停止命令 val stopJson = JSONObject().apply { put("op", "publish") put("topic", "/cmd_vel") put("msg", JSONObject().apply { put("linear", JSONObject().apply { put("x", 0.0) }) put("angular", JSONObject().apply { put("z", 0.0) }) }) } sendRosMessage(stopJson.toString()) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val joystick = findViewById<JoystickView>(R.id.joystick_view) joystick.setListener(joystickListener) } private fun sendRosMessage(message: String) { val url = "ws://$robotIp:$rosbridgePort/" val request = Request.Builder().url(url).build() val webSocket = client.newWebSocket(request, object : WebSocketListener() { override fun onOpen(webSocket: WebSocket, response: Response) { // 连接成功 runOnUiThread { Toast.makeText(this@MainActivity, "Connected to ROSBridge", Toast.LENGTH_SHORT).show() } } override fun onMessage(webSocket: WebSocket, text: String) { // 收到服务器消息,可以用来订阅传感器数据 runOnUiThread { // 显示接收到的消息 // tv_status.text = text } } override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { webSocket.close(1000, null) runOnUiThread { Toast.makeText(this@MainActivity, "Connection Closing", Toast.LENGTH_SHORT).show() } } override fun onFailure(webSocket: WebSocket - 布局文件 (
标签: Android手机控制ROS机器人教程 Android与ROS机器人通信方法 Android远程操控ROS机器人步骤