В статье подробно рассматривается опыт интеграции высокоточных тактильных перчаток в VR‑окружение при помощи ROS 2. Автор делится практическими наблюдениями, описывает архитектуру системы, принципы синхронизации данных и пример реализации на C++ и Python. Материал будет интересен тем, кто хочет заглянуть «под капот» реального прототипа мультисенсорного взаимодействия и избежать типичных ловушек в организации низкоуровневой передачи тактильных сигналов.

Введение
Погружение в виртуальную реальность давно вышло за рамки простых визуальных ощущений. Тактильные перчатки позволяют «потрогать» виртуальные объекты и получить мгновенную обратную связь — от легкого давления до вибраций переменной частоты. Однако нелинейность аппаратного тракта и требования к детерминированности требуют продуманного подхода к обмену сообщениями и времени выполнения. В этой статье исследуется, как применить ROS 2 для подключения и синхронизации таких перчаток, преодолевая задержки и рассогласования.
Немного контекста и личный опыт
В первый прототип автор внедрял перчатки “XGlove” без какой‑либо middleware — получалось слишком много «подергиваний» и артефактов. Переключение на ROS 2 с DDS‑бэкендом сразу дало стабильность и гибкость перенастройки QoS в полёте. К тому же, появилось ощущение единой «системной магистрали», куда легко подключать новые сенсоры: от IMU до камер.
Архитектура системы
Аппаратный уровень
-
Гаптические перчатки (актуаторы, сенсоры силы)
-
Контроллеры (STM32 с USB или UART)
Прослойка связи
-
ROS 2 (Foxy / Humble)
-
DDS (Fast-RTPS / CycloneDDS)
VR‑движок
-
Unity с ROS 2 Bridge или Unreal Engine + Custom Plugin
Узел синхронизации времени
-
ros2 topic pub /clockи режимuse_sim_time=true
Весь обмен происходит через ROS‑топики: сенсорные данные (GloveState), команды к актуаторам (HapticCommand), а также временные метки для синхронизации.
Подключение тактильных перчаток к ROS 2

Драйвер для контроллера
На контроллере STM32 реализован USB‑CDC интерфейс, передающий сэмплы силы и положения пальцев. По умолчанию данные идут пакетом по 40 байт с частотой 1 кГц.
ROS 2‑нод на C++: публикация сырых данных
// glove_publisher.cpp #include <rclcpp/rclcpp.hpp> #include <std_msgs/msg/float32_multi_array.hpp> #include <boost/asio.hpp> class GlovePublisher : public rclcpp::Node { public: GlovePublisher() : Node("glove_publisher"), serial(io, "/dev/ttyUSB0") { pub = this->create_publisher<std_msgs::msg::Float32MultiArray>("glove_state", 10); timer = this->create_wall_timer( std::chrono::microseconds(1000), std::bind(&GlovePublisher::readAndPublish, this)); } private: void readAndPublish() { GloveRaw raw; boost::asio::read(serial, boost::asio::buffer(&raw, sizeof(raw))); auto msg = std_msgs::msg::Float32MultiArray(); msg.data.insert(msg.data.end(), raw.pressure, raw.pressure + 5); msg.data.insert(msg.data.end(), raw.bend, raw.bend + 5); msg.layout.dim.resize(2); pub->publish(msg); } rclcpp::Publisher<std_msgs::msg::Float32MultiArray>::SharedPtr pub; rclcpp::TimerBase::SharedPtr timer; boost::asio::io_service io; boost::asio::serial_port serial; }; int main(int argc, char** argv) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<GlovePublisher>()); rclcpp::shutdown(); return 0; }
Синхронизация данных через ROS 2
Чтобы визуальная и тактильная части не «расходились во времени», важно единообразно распространить метки времени. Здесь помогает режим use_sim_time и собственный брокер времени:
# Запуск ноды симуляции времени ros2 run ros2_control_node clock_publisher --ros-args -p use_sim_time:=true
В каждом сообщении к тактильным актуаторам указывается метка header.stamp, совпадающая с меткой визуального рендера.
// Пример: HapticCommand.msg std_msgs/Header header float32[5] amplitudes
А в подписчике:
// haptic_actuator.cpp void callback(const HapticCommand::SharedPtr msg) { auto now = this->get_clock()->now(); auto delay = msg->header.stamp - now; if (delay > rclcpp::Duration(0)) { // Ждем до нужного момента std::this_thread::sleep_for(delay.nanoseconds()); } driveActuators(msg->amplitudes); }
Интеграция с VR‑движком
Unity + ROS 2 Bridge
Автор использовал пакет ROS‑TCP-Connector. Настройка сводится к созданию C#-скрипта:
using Unity.Robotics.ROSTCPConnector; using RosMessageTypes.Std; public class VRGloveReceiver : MonoBehaviour { ROSConnection ros; void Start() { ros = ROSConnection.GetOrCreateInstance(); ros.Subscribe<Float32MultiArrayMsg>("glove_state", OnGloveStateReceived); } void OnGloveStateReceived(Float32MultiArrayMsg msg) { // Привязка усилий к физике пальцев модели for (int i = 0; i < 5; i++) { float pressure = msg.data[i]; HandSimulator.SetFingerForce(i, pressure); } } }
Unreal Engine + Custom Plugin
В UE пришлось писать C++‑плагин, заворачивающий rclcpp::Subscription. Понадобилось учитывать особенности рендер‑треда и многопоточности движка.
Обработка и фильтрация тактильных сигналов
Сырые данные от перчаток могут содержать шум. Используются простейшие фильтры Скользящего среднего:
# smoothing.py import numpy as np class MovingAverage: def __init__(self, window_size=5): self.window = [] self.k = window_size def filter(self, value): self.window.append(value) if len(self.window) > self.k: self.window.pop(0) return np.mean(self.window) # ROS‑subscriber в Python import rclpy from std_msgs.msg import Float32MultiArray filterers = [MovingAverage(10) for _ in range(5)] def callback(msg): raw = msg.data[:5] smooth = [filterers[i].filter(raw[i]) for i in range(5)] apply_haptics(smooth)
Тестирование и отладка
-
ros2 topic echo и rviz2 для визуальной инспекции меток времени.
-
Инструменты DDS (например, rtps_deploy) для мониторинга сетевых задержек.
-
Логирование профилей в реальном времени: автор ловил «подвисания» при большой частоте через ros2 trace.
Выводы и рекомендации
-
ROS 2 + DDS — отличная связка для VR‑систем с жёсткими требованиями к латентности.
-
Всегда проверяйте QoS‑профили: лучший вариант для haptics — Reliable + Deadline.
-
Не бойтесь гибридных решений: часть логики можно вынести на Python для быстрой правки, а часть на C++ для производительности.
-
Полезно заводить «виртуальные часы» через
use_sim_time, тогда латентность отладки и воспроизведения воспоминаний станет более предсказуемой.
ссылка на оригинал статьи https://habr.com/ru/articles/927908/
Добавить комментарий