---json
{"name": "Sensors and multiple boards"}
---
====== 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 [[:axiom:ros2:getting_started|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 =====
- Start with Axiom connected and acquisition running.
- Plug a supported sensor into Axiom. Its descriptor is resolved and its publishers and command services appear.
- Find its exact topic with ''ros2 topic list -t'' and start an echo with best-effort QoS.
- Unplug only that sensor, leaving Axiom powered. Its publishers and descriptor services are retired.
- 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 [[:axiom:device_library:start|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 [[:axiom:ros2:dashboard|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:ros2:start|Axiom with ROS 2]].