Разработка мобильного приложения для управления роботом
Управление роботом с телефона — это почти всегда задача реального времени с требованиями к задержке < 100 мс и надёжной обработкой разрыва соединения. Протокол связи, архитектура команд и схема восстановления после потери связи важнее UI. Разберём конкретные транспорты и паттерны, которые работают в продакшене.
Транспорт и протоколы
ROS 2 + rosbridge (WebSocket)
Самый распространённый стек для ROS-роботов: на роботе поднимается rosbridge_server, телефон подключается через WebSocket и публикует/подписывается на топики через JSON-протокол rosbridge_protocol. Для мобильных клиентов есть библиотека roslibjs-совместимые обёртки, но для нативного Android/iOS пишем клиент сами — это 300–400 строк кода с повторным подключением и очередью сообщений.
Проблема: rosbridge — JSON поверх WebSocket, это медленно для высокочастотных топиков. Топик /cmd_vel с Twist-командами на 20 Гц через JSON даёт ~40 кб/с трафика. Если робот находится за Wi-Fi с реальной пропускной способностью 1 Мбит/с — норм. Если через LTE с джиттером — пакеты приходят пачками, команды исполняются с задержкой. Решение: снижаем частоту команд до 10 Гц и добавляем watchdog: если от телефона нет команды 500 мс, робот переходит в safe_stop.
MQTT для лёгкого управления
Для IoT-роботов без ROS (AGV, сортировщики, кастомные платформы) — MQTT брокер (Mosquitto или EMQ X) плюс лёгкий протокол команд. Телефон публикует в robot/{id}/cmd, робот подписан на этот топик. Телеметрия в обратную сторону: robot/{id}/state, robot/{id}/battery.
QoS 1 (at least once) для команд управления — QoS 0 теряет пакеты при нестабильном Wi-Fi, QoS 2 создаёт лишние round-trips. Retained message для robot/{id}/state позволяет новому подключившемуся клиенту сразу получить актуальное состояние без ожидания следующего обновления.
UDP для реального времени (< 50 мс)
Если нужна минимальная задержка — прямой UDP-сокет на порт управления. На Android: DatagramSocket в CoroutineScope(Dispatchers.IO), отправка каждые 50 мс. Нет гарантий доставки — это плюс: старая команда не блокирует новую в очереди. Применяется для управления манипуляторами, где задержка команды важнее гарантии доставки.
Архитектура мобильного клиента
class RobotControlViewModel(
private val robotRepository: RobotRepository
) : ViewModel() {
private val _robotState = MutableStateFlow<RobotState>(RobotState.Disconnected)
val robotState: StateFlow<RobotState> = _robotState
fun sendVelocityCommand(linear: Float, angular: Float) {
viewModelScope.launch {
robotRepository.publishVelocity(
TwistCommand(linear = linear, angular = angular)
)
}
}
fun connect(robotIp: String) {
viewModelScope.launch {
robotRepository.connect(robotIp)
.onEach { state -> _robotState.value = state }
.launchIn(this)
}
}
}
RobotRepository инкапсулирует конкретный транспорт — WebSocket, MQTT или UDP. Смена транспорта не затрагивает ViewModel и UI. Это критично: в реальных проектах часто меняется железо или протокол между прототипом и продакшеном.
Виртуальный джойстик и обработка ввода
MotionEvent.ACTION_MOVE приходит до 60 раз в секунду при быстром движении пальца. Отправлять команду на каждый event — перегрузка канала. Используем throttleLatest(50) из Kotlin Coroutines Flow — берём последнее значение за 50 мс. Старые промежуточные значения отбрасываются, задержка ответа — не более 50 мс.
Деадзона (dead zone) в центре джойстика: 10–15% радиуса фильтруем до нуля. Без этого микротремор руки вызывает постоянные команды малой скорости, робот «дёргается» в покое.
Видеопоток с камеры робота
Для H.264-стримов с IP-камер на роботе используем ExoPlayer (Android) или AVPlayer с HLS (iOS). Задержка HLS — 5–30 секунд. Для управления это неприемлемо. Правильный путь: WebRTC (latency < 200 мс) или RTSP через LibVLC / ffmpeg в MediaCodec pipeline (latency 100–300 мс).
WebRTC сложнее в настройке (нужен STUN/TURN-сервер или P2P в одной сети), но даёт наименьшую задержку и адаптивный битрейт.
Безопасность и аварийные сценарии
- Watchdog на роботе: нет команды 1–2 секунды →
safe_stopили переход в автономный режим удержания позиции - PIN/QR-аутентификация для подключения к конкретному роботу (чтобы не управлять чужим)
- Отключение команд движения при открытом защитном кожухе (через MQTT-статус или GPIO)
Сроки
Базовый клиент с джойстиком, телеметрией и видеопотоком на одной платформе — 3–5 недель. Кроссплатформенное решение с поддержкой нескольких протоколов, картой помещения и автономными миссиями — 2–4 месяца. Оценка после изучения платформы робота и требований к задержке.







