Basic Concepts
Understanding the core concepts of HID ROS 2 will help you make the most of the framework.
Architecture Overview
HID ROS 2 follows a schema-driven architecture where everything originates from a single YAML file:
YAML Schema (schema/hid_device.yaml)
│
├──> ROS 2 Files (auto-generated)
│ ├── URDF/Xacro
│ ├── Controller Configuration
│ └── Launch Files
│
└──> Firmware Files (auto-generated)
├── HID Descriptor
└── Report Structures
Single Source of Truth
The YAML schema is the only file you need to maintain. All other files are automatically generated during the build process, ensuring consistency between firmware and ROS 2.
Core Components
1. YAML Schema
Defines your device’s interface:
Device identification (VID/PID)
Report IDs
Data fields with types
ROS 2 configuration
2. Code Generator (hid_descriptor_generator)
Reads the YAML schema and generates:
C Headers: HID descriptors and structs for firmware
URDF: Robot description with state/command interfaces
Configuration: Controller parameters
Launch Files: Ready-to-use launch files
3. Hardware Interface (hid_hardware)
A ros2_control hardware interface plugin that:
Opens and manages USB HID device connection
Reads input reports from device
Writes output reports to device
Exposes state/command interfaces to controllers
4. Controllers
ROS 2 controllers that use the state/command interfaces:
hid_generic_broadcaster: Publishes sensor datahid_diagnostic_broadcaster: Monitors device healthsignal_command_controller: Example command controller
5. Developer Tools (hid_tools)
Command-line utilities for development:
validate_schema: Schema validationinspect_device: Live USB monitoringgenerate_hid_descriptor: Standalone descriptor generation
Data Flow
Input Reports (Device → ROS 2)
Firmware sends HID input report over USB
Hardware Interface reads report via hidapi
Hardware Interface converts bytes to typed values
Hardware Interface updates state interfaces
Controllers read state interfaces
Controllers publish to ROS 2 topics
Device → USB → Hardware Interface → State Interfaces → Controllers → Topics
Output Reports (ROS 2 → Device)
Controllers subscribe to ROS 2 topics
Controllers write to command interfaces
Hardware Interface reads command interfaces
Hardware Interface converts to bytes
Hardware Interface sends HID output report
Firmware receives and processes report
Topics → Controllers → Command Interfaces → Hardware Interface → USB → Device
Type System
HID ROS 2 provides native support for multiple data types with automatic conversion.
Supported Types
Type |
Size |
Range |
Use Case |
|---|---|---|---|
|
1 byte |
0 to 255 |
Bytes, small values |
|
1 byte |
-128 to 127 |
Small signed values |
|
2 bytes |
0 to 65,535 |
Medium unsigned values |
|
2 bytes |
-32,768 to 32,767 |
Sensor readings |
|
4 bytes |
0 to 4,294,967,295 |
Timestamps, counters |
|
4 bytes |
-2,147,483,648 to 2,147,483,647 |
Large signed values |
|
4 bytes |
±3.4e±38 (7 digits precision) |
Floating-point data |
|
8 bytes |
±1.7e±308 (15 digits) |
High-precision values |
Byte Order
All multi-byte values use little-endian byte order, which is standard for USB HID and most modern microcontrollers (ARM, x86).
Type Conversion
The hardware interface automatically handles conversion:
Reading: Bytes → Typed value →
double(ros2_control interface)Writing:
double→ Typed value → Bytes
Example for float32:
// Reading
uint8_t bytes[4] = {0x00, 0x00, 0x80, 0x3F}; // From USB
float value;
memcpy(&value, bytes, 4); // value = 1.0
double interface_value = static_cast<double>(value);
// Writing
double interface_value = 2.5;
float value = static_cast<float>(interface_value);
uint8_t bytes[4];
memcpy(bytes, &value, 4); // To USB
State and Command Interfaces
State Interfaces (Read-Only)
Represent sensor data coming from the device. Each field in your YAML schema creates a state interface.
Example schema:
fields:
- name: "temperature"
type: "float32"
- name: "pressure"
type: "int16"
Creates state interfaces:
sensor_name/temperaturesensor_name/pressure
Controllers can read these values but not modify them.
Command Interfaces (Write)
Represent commands going to the device. Created when you define output fields or use bidirectional mode.
Example schema with outputs:
outputs:
- name: "led_brightness"
type: "uint8"
- name: "motor_speed"
type: "int16"
Creates command interfaces:
actuator_name/led_brightnessactuator_name/motor_speed
Controllers write to these interfaces, and values are sent to the device.
Report IDs
HID supports multiple report types using report IDs (1-255).
Input Reports
Data from device to computer (sensors, buttons, etc.):
input_report_id: 2
Output Reports
Data from computer to device (commands, configuration, etc.):
output_report_id: 1
Why Different IDs?
Having separate IDs allows:
Different structures for input vs. output
Unambiguous report identification
Compliance with HID specification
Hardware Interface Lifecycle
The hardware interface follows the ros2_control lifecycle:
on_init: Parse parameters, validate configuration
on_configure: Open USB device connection
on_activate: Start reading/writing reports
read: Read input report, update state interfaces
write: Read command interfaces, send output report
on_deactivate: Stop communication
on_cleanup: Close USB device
Update Cycle
The read() and write() methods are called at the controller manager’s update rate:
┌─────────────────────────────────────┐
│ Controller Manager Loop │
│ │
│ 1. hardware_interface.read() │
│ 2. controllers.update() │
│ 3. hardware_interface.write() │
│ │
│ (Repeat at update_rate Hz) │
└─────────────────────────────────────┘
YAML Schema Structure
A complete schema has three main sections:
1. Device Identification
device_name: "my_device"
vendor_id: "0x1234"
product_id: "0x5678"
2. ROS 2 Configuration
sensor_name: "sensor"
frame_id: "sensor_frame"
update_rate: 250
3. Data Fields
fields:
- name: "field1"
type: "float32"
description: "Description"
Generated Files
For each schema, the build process generates:
For ROS 2
URDF (
urdf/hid_robot.urdf.xacro): Hardware descriptionConfig (
config/controllers.yaml): Controller parametersLaunch (
launch/hid.launch.py): Launch file with spawners
For Firmware
Header (
include/package/hid_descriptor.h): HID descriptor and structs
All files are generated in the build directory and installed to the install directory.
Integration with ros2_control
HID ROS 2 is built on top of ros2_control, the standard control framework for ROS 2.
Benefits
Standard Interface: Works with any ros2_control controller
Tool Support: Use
ros2 controlCLI commandsEcosystem: Compatible with existing controllers and tools
Architecture: Clean separation of hardware and control logic
ros2_control Components
Hardware Interface:
hid_hardware(this package)Controller Manager: Manages lifecycle and updates
Controllers: Read/write interfaces, publish topics
Resource Manager: Manages hardware resources
Next Steps
Learn about Schema Reference for detailed YAML syntax
Understand Code Generation process
Explore Hardware Interface implementation
Read about Controllers available