Android + ROS 2: Building a Robot Control App with Kotlin A developer demonstrates how to build an Android robot control app in Kotlin that communicates with a ROS 2 robot, using a bridge or gateway to expose only necessary topics. The app uses Jetpack Compose for the UI, Kotlin coroutines and StateFlow for telemetry, and includes a command watchdog for safety. The tutorial emphasizes testing against a simulator before deploying to physical hardware. Physical AI is bringing together robotics, edge computing, computer vision, and intelligent mobile interfaces. Android is a useful companion platform because modern phones and tablets provide touch interfaces, cameras, sensors, networking, and strong edge-computing capabilities. In this tutorial, we will design an Android application in Kotlin that communicates with a ROS 2 robot. The app will provide a simple control interface for sending movement commands and receiving robot telemetry. A practical architecture can look like this: Android App | | ROS 2 bridge / WebSocket / MQTT v ROS 2 Middleware | +---- /cmd vel ---- Robot Base | +---- /odom ------- Telemetry | +---- /battery ---- Battery Status The Android application should not directly control motors. Instead, it communicates with a ROS 2 node or bridge responsible for validating commands and interfacing with the robot. Create a Kotlin Android project using Android Studio. A clean package structure is: com.example.robotcontroller ├── ui ├── ros ├── model ├── network └── MainActivity.kt Keep the ROS communication layer separate from the Compose UI so that the application can later switch between a simulator, development robot, or production robot. Create a simple command model: data class VelocityCommand val linearX: Double, val angularZ: Double The UI can map buttons or a virtual joystick to these values. For example: fun moveForward = VelocityCommand linearX = 0.5, angularZ = 0.0 fun stop = VelocityCommand linearX = 0.0, angularZ = 0.0 The communication layer then converts the command into the message format expected by your ROS 2 bridge. A simple control panel can be created with Jetpack Compose: php @Composable fun RobotControls onForward: - Unit, onBackward: - Unit, onLeft: - Unit, onRight: - Unit, onStop: - Unit { Column { Button onClick = onForward { Text "Forward" } Row { Button onClick = onLeft { Text "Left" } Button onClick = onStop { Text "Stop" } Button onClick = onRight { Text "Right" } } Button onClick = onBackward { Text "Backward" } } } For a real robot, replace these buttons with a joystick or gesture-based controller. The Android app needs a communication mechanism between the mobile device and ROS 2. A common architecture is to expose selected ROS 2 topics through a bridge or gateway. The Android client can then publish commands such as: /cmd vel and subscribe to telemetry topics such as: /odom /battery state /robot status Avoid exposing the entire ROS graph directly to an untrusted mobile client. Expose only the topics and services required by the application. Represent telemetry in Kotlin: data class RobotTelemetry val battery: Float, val x: Double, val y: Double, val connected: Boolean Use Kotlin coroutines and StateFlow to expose updates to Compose: private val telemetry = MutableStateFlow RobotTelemetry 0f, 0.0, 0.0, false val telemetry: StateFlow