Skip to content

Add waybionic_sensors IMU package with correct raw sensor semantics and diagnostics - #11

Open
khuzaymahbinharis-jpg wants to merge 1 commit into
mainfrom
feature/imu-rviz-integration-v2
Open

Add waybionic_sensors IMU package with correct raw sensor semantics and diagnostics#11
khuzaymahbinharis-jpg wants to merge 1 commit into
mainfrom
feature/imu-rviz-integration-v2

Conversation

@khuzaymahbinharis-jpg

Copy link
Copy Markdown
Contributor

Summary

Adds waybionic_sensors: an IMU publisher with honest raw-sensor semantics, /diagnostics health reporting, and a documented boundary for the hardware driver that does not exist yet.

Branched from current main, carrying over only the waybionic_sensors directory from feature/imu-rviz-integration. That branch predated the merged foundation, so replaying it would have reverted CI, CONTRIBUTING.md, and other files that landed since. Nothing outside waybionic_sensors is touched, so this does not depend on and does not conflict with #10.

What changed relative to the old IMU branch

Old behaviour Problem Now
Synthetic quaternion on data_raw Presented generated data as measurement Raw topic sets orientation_covariance[0] = -1; synthetic orientation moved to /waybionic/imu/data_demo, off by default
Rotating TF always broadcast Implied the sensor knows its own attitude publish_demo_tf, default false; enabled only by imu_demo.launch.py
Covariances all zero Zero reads as "perfectly certain" to a consumer Diagonal covariances from parameterised standard deviations, documented as placeholders
No /diagnostics output Panel could not show IMU health imu.heartbeat plus rate and telemetry at 2 Hz
One 120-line node Serial work would be bolted into the publisher Six modules with independent responsibilities
3 metadata tests No behavioural coverage 83 tests including a runtime suite that spins the node
serial_port with no reader Suggested a driver existed Documented interface plus a stub that makes the absence visible in diagnostics

Raw versus fused orientation

An accelerometer and a gyroscope cannot observe absolute heading. Publishing a generated quaternion on the raw topic would let a future fusion or localisation node consume invented data as though it were measured.

/waybionic/imu/data_raw always sets orientation_covariance[0] = -1, the standard sensor_msgs/msg/Imu marker for absent orientation, and leaves the quaternion at identity as a placeholder. The synthetic orientation lives on /waybionic/imu/data_demo, is off by default, and is named so it cannot be mistaken for a measurement.

imu.roll, imu.pitch, and imu.yaw from the backend integration doc are deliberately not published for the same reason. They belong to a real fusion source.

Module boundaries

mock_source.py  ─┐
                 ├─> ImuReading ─┬─> imu_messages.py     -> sensor_msgs/Imu, TF
hardware_reader.py ─┘            └─> imu_diagnostics.py  -> DiagnosticArray
                                       imu_publisher_node.py wires them together
Module Responsibility
imu_reading.py Hardware-independent sample type: the contract between producers and consumers
mock_source.py Synthetic generation, no ROS types
hardware_reader.py Driver interface plus an unimplemented stub
imu_messages.py sensor_msgs/Imu and TF construction, covariance rules
imu_diagnostics.py DiagnosticArray construction, freshness logic
imu_publisher_node.py Parameters, timers, publishers only

Two structural tests keep this from collapsing back: the node must not construct Imu() or DiagnosticStatus itself.

Diagnostics

Names, value/unit keys, and level mapping follow waybionic_rviz_plugins/docs/DIAGNOSTICS_BACKEND_INTEGRATION.md, so the merged panel renders these with no IMU-specific code.

Signal Unit Levels
imu.heartbeat s OK, STALE
imu.rate Hz OK, WARN, STALE
imu.angular_velocity rad/s OK
imu.linear_acceleration m/s^2 OK

Addresses the imu.heartbeat half of #4.

Hardware handoff

No serial protocol is implemented, because the sensor model, transport, and packet format are unconfirmed. docs/HARDWARE_INTERFACE.md carries 18 numbered questions for electrical across sensor, transport, data format, and integration, plus the known unknowns and the recipe for adding the driver.

A structural test asserts nothing was invented (import serial, baudrate, struct.unpack).

Live mode is still useful today: with use_mock:=false the node publishes no samples and imu.heartbeat reports STALE, which is what an absent sensor should look like.

Runtime evidence (Ubuntu 24.04 / ROS 2 Jazzy / WSL2)

ros2 topic hz /waybionic/imu/data_raw:

average rate: 49.988
	min: 0.019s max: 0.021s std dev: 0.00030s window: 51

ros2 topic echo /waybionic/imu/data_raw --once:

header:
  stamp: {sec: 1785808547, nanosec: 917613821}
  frame_id: imu_link
orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
orientation_covariance: [-1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
angular_velocity: {x: -0.0736, y: -0.0383, z: -0.1473}
angular_velocity_covariance: [0.0001, 0.0, 0.0, 0.0, 0.0001, 0.0, 0.0, 0.0, 0.0001]
linear_acceleration: {x: -0.0368, y: -0.0153, z: 9.80665}
linear_acceleration_covariance: [0.0025, ...]

ros2 topic hz /diagnostics reports average rate: 2.000, above the 1 Hz requirement.

Heartbeat while streaming:

name: imu.heartbeat
message: IMU streaming from mock generator
values: [{key: value, value: '0.00'}, {key: unit, value: s}]

Heartbeat after mock_stall_after_sec:=3.0:

name: imu.heartbeat
message: No IMU sample for 6.64 s (timeout 1.00 s)
values: [{key: value, value: '6.64'}, {key: unit, value: s}]

Heartbeat with use_mock:=false:

name: imu.heartbeat
message: No IMU samples received from unconfigured IMU driver; awaiting sensor
         model, transport and packet format from electrical
values: [{key: value, value: never}, {key: unit, value: s}]

/waybionic/imu/data_demo does not appear in ros2 topic list on a default launch, confirming the demo output stays off unless requested.

Tests

colcon test --packages-select waybionic_sensors
83 passed

Full workspace (waybionic_description, waybionic_bringup, waybionic_rviz_plugins, waybionic_sensors) builds and tests with zero failures.

Suite Count Covers
test_imu_messages.py 15 Frame, timestamp, orientation-unavailable marker, covariance diagonal and cross terms, demo message, demo TF
test_imu_diagnostics.py 16 Heartbeat OK/STALE, custom timeout, never-received, age units, rate WARN, telemetry units, absence of roll/pitch/yaw
test_imu_publisher_node.py 14 Runtime: rate follows the parameter, monotonic timestamps, frame IDs, demo defaults off, demo TF on request, heartbeat OK then STALE, live mode without hardware
test_mock_source.py 13 Determinism, gravity, amplitude bounds, stalling, quaternion normalisation
test_hardware_reader.py 9 Interface surface, stub behaviour, a custom reader satisfying the boundary
test_package_metadata.py 14 Module separation, node delegation, launch defaults, docs, entry point, no invented protocol
test_flake8.py, test_pep257.py 2 Style and docstrings, both clean under the ROS 2 defaults

How to review

colcon build --packages-select waybionic_sensors --symlink-install
source install/setup.bash

# Defaults: raw only, no demo outputs
ros2 launch waybionic_sensors imu_publisher.launch.py
ros2 topic hz /waybionic/imu/data_raw
ros2 topic echo /diagnostics --once

# Visual walkthrough with demo orientation and demo TF
ros2 launch waybionic_sensors imu_demo.launch.py

# Watch the heartbeat go stale
ros2 launch waybionic_sensors imu_publisher.launch.py mock_stall_after_sec:=5.0

To see it in the panel, run the publisher alongside ros2 launch waybionic_rviz_plugins engineer_view.launch.py use_mock_diagnostics:=false.

Known limitations

  • No physical IMU driver. Blocked on docs/HARDWARE_INTERFACE.md.
  • Covariance values are documented placeholders, not measured noise.
  • The demo orientation and demo TF are visualisation aids, not estimates.
  • The base_link to imu_link offset in the demo TF is a placeholder 0.1 m, not a mounting claim.

Adds an IMU publisher built from current main, carrying over only the
waybionic_sensors directory from the earlier IMU branch. That branch predated
the merged foundation, so replaying it would have reverted CI and other files
that landed since.

The publisher no longer presents generated data as measurement. An
accelerometer and a gyroscope cannot observe absolute heading, so the raw topic
sets orientation_covariance[0] = -1 and the synthetic orientation moved to its
own data_demo topic, off by default. The rotating TF became opt-in for the same
reason. Covariances are populated from parameterised standard deviations rather
than left at zero, which a consumer would read as perfect certainty.

Sensor health now reaches the merged diagnostics panel: imu.heartbeat publishes
at 2 Hz and reports STALE past a configurable sample age, including when live
mode runs with no hardware attached.

The node is split into a hardware-independent reading type, a mock source, a
driver interface, a message builder, and a diagnostics builder, so adding a
real sensor means implementing one interface rather than editing the publisher.
No serial protocol is invented; docs/HARDWARE_INTERFACE.md records the open
questions for electrical.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant