Architecture
Threading model, data flow, and class internals for extreme3dpro_driver
Architecture
Extreme3DProDriver is a single rclcpp::Node that separates hardware I/O from publishing using two concurrent execution contexts.
Data Flow
Threading Model
Read Thread
Runs continuously in the background with the device opened in O_NONBLOCK mode:
js_eventavailable → updateaxes_[]orbuttons_[], setfresh_ = true- No data (
EAGAIN) → sleep 1 ms to avoid busy-waiting - Read error → set
running_ = falseand exit
The JS_EVENT_INIT flag is stripped so initialisation events don't incorrectly mark data as fresh.
Timer Callback
Fires at publish_rate Hz on the main thread:
- Skip if
!fresh_ && !autorepeat_ publish_joy()— copy axes/buttons with deadzone appliedpublish_twist()— non-zero only when deadman held- Publish deadman state
- Clear
fresh_
Shared state (axes_, buttons_, fresh_) is accessed from both threads. Safe in practice at ≤200 Hz publish rates, but a future improvement could wrap access in a std::mutex.
Lifecycle
If open_device() fails, the node calls rclcpp::shutdown() immediately rather than spinning with no hardware.
Axis Normalisation
Raw int16_t from the kernel → float in [−1.0, +1.0]:
float centre = (max_val + min_val) / 2.0f;
float range = (max_val - min_val) / 2.0f;
return std::clamp((raw - centre) / range, -1.0f, 1.0f);