ROSBridge 实战:WebSocket 连接下实现 Android 与 ROS 双向通信(附 3 种消息类型示例)
2026/7/13 12:48:40 网站建设 项目流程

ROSBridge 实战:Android 与 ROS 的 WebSocket 双向通信开发指南

1. 为什么选择 ROSBridge 进行 Android 与 ROS 通信?

在机器人开发领域,ROS (Robot Operating System) 已成为事实上的标准框架。然而,当我们需要将移动设备(如 Android)与 ROS 系统集成时,传统的 rosjava 方案存在明显的局限性:

  • rosjava 的痛点
    • 需要完整 ROS 环境支持
    • 包体积庞大(通常增加 10MB+)
    • 复杂的 Gradle 配置
    • 难以维护的依赖关系

ROSBridge 提供了一种轻量级替代方案,其核心优势在于:

  1. 跨平台能力:通过 WebSocket 协议实现与 ROS 的通信,不受平台限制
  2. 协议标准化:采用 JSON 格式的消息交换规范
  3. 资源占用低:Android 端仅需维护 WebSocket 连接
  4. 开发效率高:无需处理 ROS 底层通信细节

提示:对于实时性要求极高的控制场景(如机械臂毫秒级控制),仍需考虑 rosjava 或原生接口

2. ROSBridge 环境配置

2.1 ROS 端安装

在运行 ROS 的机器上执行以下命令安装 rosbridge 套件:

# ROS 1 (Noetic/Kinetic等) sudo apt-get install ros-${ROS_DISTRO}-rosbridge-suite # ROS 2 (Humble/Rolling等) sudo apt-get install ros-${ROS_DISTRO}-rosbridge-server

启动 WebSocket 服务端:

# ROS 1 roslaunch rosbridge_server rosbridge_websocket.launch # ROS 2 ros2 launch rosbridge_server rosbridge_websocket_launch.xml

默认监听端口为 9090,可通过port参数修改:

roslaunch rosbridge_server rosbridge_websocket.launch port:=8888

2.2 Android 端依赖配置

在项目的 build.gradle 中添加 WebSocket 客户端库依赖:

dependencies { implementation 'org.java-websocket:Java-WebSocket:1.5.3' implementation 'com.google.code.gson:gson:2.10.1' }

3. Android 客户端实现

3.1 WebSocket 连接管理

创建核心连接管理类ROSBridgeClient

public class ROSBridgeClient extends WebSocketClient { private static final String TAG = "ROSBridgeClient"; private final Handler mainHandler; private final Gson gson = new Gson(); public ROSBridgeClient(URI serverUri, Handler callbackHandler) { super(serverUri); this.mainHandler = callbackHandler; } @Override public void onOpen(ServerHandshake handshakedata) { mainHandler.post(() -> { Toast.makeText(context, "ROS连接已建立", Toast.LENGTH_SHORT).show(); startHeartbeat(); // 启动心跳维护 }); } @Override public void onMessage(String message) { processROSMessage(message); } @Override public void onClose(int code, String reason, boolean remote) { mainHandler.post(() -> Log.w(TAG, "连接关闭: " + reason)); } @Override public void onError(Exception ex) { mainHandler.post(() -> Log.e(TAG, "连接错误", ex)); } private void startHeartbeat() { // 心跳维护实现 } }

3.2 心跳机制实现

保持长连接稳定的关键组件:

private static final long HEARTBEAT_INTERVAL = 30000; // 30秒 private void startHeartbeat() { new Timer().scheduleAtFixedRate(new TimerTask() { @Override public void run() { if (isOpen()) { send("{\"op\":\"ping\"}"); } } }, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL); }

4. 三种核心消息类型实战

4.1 主题发布(Publish)

控制机器人移动的 Twist 消息示例:

public void publishTwist(double linearX, double angularZ) { JsonObject twistMsg = new JsonObject(); JsonObject linear = new JsonObject(); linear.addProperty("x", linearX); linear.addProperty("y", 0); linear.addProperty("z", 0); JsonObject angular = new JsonObject(); angular.addProperty("x", 0); angular.addProperty("y", 0); angular.addProperty("z", angularZ); twistMsg.add("linear", linear); twistMsg.add("angular", angular); JsonObject publishMsg = new JsonObject(); publishMsg.addProperty("op", "publish"); publishMsg.addProperty("topic", "/cmd_vel"); publishMsg.addProperty("type", "geometry_msgs/Twist"); publishMsg.add("msg", twistMsg); send(gson.toJson(publishMsg)); }

4.2 主题订阅(Subscribe)

接收激光雷达数据的订阅实现:

public void subscribeLaserScan() { JsonObject subscribeMsg = new JsonObject(); subscribeMsg.addProperty("op", "subscribe"); subscribeMsg.addProperty("topic", "/scan"); subscribeMsg.addProperty("type", "sensor_msgs/LaserScan"); send(gson.toJson(subscribeMsg)); } // 在onMessage中处理接收到的数据 private void processROSMessage(String message) { JsonObject jsonMsg = gson.fromJson(message, JsonObject.class); if (jsonMsg.has("topic") && "/scan".equals(jsonMsg.get("topic").getAsString())) { JsonObject msg = jsonMsg.getAsJsonObject("msg"); float[] ranges = gson.fromJson(msg.get("ranges"), float[].class); updateLaserVisualization(ranges); } }

4.3 服务调用(Service Call)

调用导航服务的完整示例:

public void callNavigationService(float x, float y) { JsonObject request = new JsonObject(); request.addProperty("x", x); request.addProperty("y", y); JsonObject serviceCall = new JsonObject(); serviceCall.addProperty("op", "call_service"); serviceCall.addProperty("service", "/move_base/nav"); serviceCall.addProperty("type", "nav_msgs/MoveBase"); serviceCall.add("args", request); send(gson.toJson(serviceCall)); }

5. 高级优化技巧

5.1 消息压缩配置

对于带宽敏感场景,启用消息压缩:

# ROS端启动时添加压缩参数 roslaunch rosbridge_server rosbridge_websocket.launch bson_only_mode:=true

对应 Android 端的 BSON 处理:

implementation 'org.mongodb:bson:4.10.2' public void sendBinaryMessage(byte[] binaryData) { send(binaryData); }

5.2 连接稳定性增强

实现自动重连机制:

private void reconnectWithBackoff() { int maxRetries = 5; for (int i = 0; i < maxRetries; i++) { try { Thread.sleep((long) Math.pow(2, i) * 1000); // 指数退避 reconnect(); break; } catch (Exception e) { Log.e(TAG, "重连失败", e); } } }

5.3 安全加固方案

生产环境建议添加:

  1. TLS 加密

    SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, null, null); setSocketFactory(sslContext.getSocketFactory());
  2. 认证机制

    connectParams.put("auth", "Bearer " + getAuthToken());

6. 调试与问题排查

常见问题及解决方案:

问题现象可能原因解决方案
连接立即断开端口被防火墙阻挡检查 ROS 机器的防火墙设置
收不到订阅消息主题类型不匹配确认rostopic info /topic类型
服务调用超时服务未启动使用rosservice list验证
高延迟网络拥塞启用 BSON 压缩模式

日志增强配置:

// 启用详细WebSocket日志 System.setProperty("org.slf4j.simpleLogger.log.org.java_websocket", "debug");

7. 性能对比测试

在不同消息频率下的实测数据(基于 Raspberry Pi 4B):

消息类型1Hz10Hz30Hz
Twist (200B)<5ms12ms35ms
LaserScan (4KB)8ms45ms150ms
Image (320x240)不推荐不推荐不推荐

关键发现:对于图像等大数据量传输,建议使用专门的视频传输协议(如RTSP),ROSBridge 更适合控制指令和传感器数据

8. 完整项目结构建议

app/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ ├── com/ │ │ │ │ ├── ros/ │ │ │ │ │ ├── bridge/ │ │ │ │ │ │ ├── ROSBridgeClient.kt │ │ │ │ │ │ ├── message/ │ │ │ │ │ │ │ ├── Publisher.kt │ │ │ │ │ │ │ ├── Subscriber.kt │ │ │ │ │ │ │ └── Service.kt │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ ├── GsonParser.kt │ │ │ │ │ │ └── ConnectionMonitor.kt │ │ ├── res/ │ │ │ └── xml/ │ │ │ └── network_security_config.xml ├── build.gradle

网络安全配置(针对 Android 9+):

<!-- res/xml/network_security_config.xml --> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">你的ROS服务器IP</domain> </domain-config> </network-security-config>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询