ROS 2: sensors and multiple boards

Axiom's firmware descriptors drive ROS sensor discovery. You do not need to list every sensor in boards.yaml. Follow Install and connect first and leave acquisition running.

Discover interfaces

ros2 topic list -t --no-daemon
ros2 service list -t
ros2 topic echo /axiom/devices --qos-durability transient_local

Stop the inventory echo with Ctrl+C before entering another command. Sensor topics live beneath the board namespace, for example:

Topic suffix ROS type
…/imu/data_raw sensor_msgs/msg/Imu
…/range sensor_msgs/msg/Range; metres, with NaN for invalid readings
…/temperature sensor_msgs/msg/Temperature; °C
…/humidity sensor_msgs/msg/RelativeHumidity; fraction from 0 to 1
…/thermal/grid axiom_interfaces/msg/ThermalGrid; dimensions and pixel temperatures
…/sample axiom_interfaces/msg/DeviceSample; decoded values, validity and timing information

The canonical path contains the firmware bus and normalised hexadecimal device address, such as /axiom/bus_1/device_76a/…. Use the inventory or topic list instead of assuming an address from the connector number.

Plug, unplug and reconnect

  1. Start with Axiom connected and acquisition running.
  2. Plug a supported sensor into Axiom. Its descriptor is resolved and its publishers and command services appear.
  3. Find its exact topic with ros2 topic list -t and start an echo with best-effort QoS.
  4. Unplug only that sensor, leaving Axiom powered. Its publishers and descriptor services are retired.
  5. Reconnect it. Supported interfaces and measurements return without restarting the driver or sending another acquisition request.

A subscriber can keep a topic name in the graph after its publisher disappears. Check publisher count, not just whether the name is listed:

ros2 topic info /axiom/bus_1/device_129/range --verbose

Replace this example with the actual sensor topic. A waiting echo does not mean the publisher is still connected.

Firmware must recognise the device and supply a compatible descriptor. For a new sensor type, start with the Device Library. Standard descriptor profiles need no per-sensor ROS configuration; unsupported custom binary formats or ROS mappings can require driver changes.

Optional topic aliases

Aliases provide preferred names for application code while preserving the identity-based topics. Add rules to a board entry only when you want an alias:

axioms:
  axiom:
    transport: ws
    device_uri: ws://192.168.1.20/ws
    auto_connect: false
    auto_reconnect: false
    autosub: false
    topic_aliases:
      imu/data_raw: {type: LSM6DS, source: imu/data_raw}
      range: {type: VL53L4CD, source: range}

These rules can add /axiom/imu/data_raw and /axiom/range. They are not a sensor support list. An alias binds only when exactly one matching device is online, resolved and fresh. If several sensors match, add the desired string bus and address selectors from the inventory, or use a canonical topic. Relaunch the driver after changing aliases.

Descriptor-defined services

Descriptors can expose configuration and output operations as services beneath:

/axiom/bus_BUS/device_ADDRESS/commands/COMMAND

Find the real paths with ros2 service list -t. Inspect argument order, units and permitted values in /axiom/device_metadata or the dashboard's information dialogs.

ros2 topic echo /axiom/device_metadata --qos-durability transient_local --once

For example, an LSM6DS descriptor may expose this sample-rate service:

ros2 service call /axiom/bus_1/device_76a/commands/set_sample_rate \
  axiom_interfaces/srv/DeviceCommand '{values: [52.0]}'

Use the discovered path and a rate advertised by that device. Numeric values follow descriptor argument order. No-argument commands use {values: []}. A successful reply confirms firmware acknowledgement; it does not prove physical completion of an actuator movement. Unsupported custom value formats are not advertised as callable services.

Multiple Axioms

Add a separate namespace and endpoint for each board. This manual example uses one Linux USB connection and one Wi-Fi connection:

axioms:
  axiom/front:
    transport: serial
    serial.port: /dev/serial/by-id/REPLACE_WITH_FRONT_AXIOM
    auto_connect: false
    auto_reconnect: false
    autosub: false
  axiom/rear:
    transport: ws
    device_uri: ws://192.168.1.21/ws
    auto_connect: false
    auto_reconnect: false
    autosub: false

Save it in the board file selected by machine.env. In Terminal 1:

ros2 launch axiom_driver multi_axiom.launch.py \
  boards_file:="$AXIOM_ROS_BOARDS_FILE"

In Terminal 2, connect and enable acquisition for each board separately:

ros2 service call /axiom/front/connect axiom_interfaces/srv/Connect '{device_uri: ""}'
ros2 service call /axiom/front/publish_data_subscription \
  axiom_interfaces/srv/PublishedDataSubscription '{rate_hz: 20.0}'

ros2 service call /axiom/rear/connect axiom_interfaces/srv/Connect '{device_uri: ""}'
ros2 service call /axiom/rear/publish_data_subscription \
  axiom_interfaces/srv/PublishedDataSubscription '{rate_hz: 20.0}'

Each driver has its own connection, metadata, queues, aliases and frame prefix. Topics and services live under /axiom/front or /axiom/rear, so identical sensor addresses on different boards do not conflict. Duplicate namespaces, frame IDs and endpoints are rejected.

For an unattended application, auto_connect: true and autosub: true combine the connection and acquisition steps at startup. auto_reconnect: true separately enables retries after an unexpected connection loss. The manual example above enables none of these.

Stop acquisition and disconnect both boards using their respective service namespaces before stopping the launch process.

Back to Axiom with ROS 2.

Task Runner