Use the host firmware variant and complete Install and connect first. The ROS driver runs on the Linux host. No Zenoh router is needed with normal DDS middleware.
From the repository root in a prepared ROS terminal:
source scripts/setup_env.sh
ros2 launch axiom_driver axiom.launch.py
By default, discovery finds USB and Wi-Fi Axioms, verifies their firmware, starts one host driver per physical board, connects and enables sensor streaming. No board file, USB path or IP address is required. With no candidates, it waits for a board. USB enumeration and reconciliation run every two seconds; failed probes retry after five seconds on the next scan. An unreachable configured endpoint can produce a warning and retries.
USB discovery checks supported Espressif serial candidates. Your account must have permission to open the port; close updaters, monitors and other clients using it. Wi-Fi discovery listens for the firmware's HTTP service advertisements using mDNS and verifies candidates through /api/v. The board must already be configured for Wi-Fi and reachable on the same multicast-capable local network. Discovery does not set Wi-Fi credentials or scan IP subnets.
| Mode | Behaviour |
|---|---|
| Automatic USB and Wi-Fi | The default. All verified boards visible to this host are eligible. |
| USB only | Enumerate USB candidates without mDNS browsing or explicit Wi-Fi endpoints. |
| Wi-Fi only | Browse mDNS without enumerating USB ports. |
| Selected boards | Keep discovery, but start acquisition drivers only for board IDs or endpoints listed in a file. |
| Explicit endpoints | Use configured USB paths or Wi-Fi addresses. mDNS browsing can be disabled. |
| Manual connection and acquisition | Verify/select boards, but wait for Connect and acquisition service calls. |
Discovery and automatic connection are separate settings. A board found at a configured IP has connected automatically, but that alone does not prove mDNS discovery worked.
Leave discovery running. In another prepared terminal:
ros2 topic echo /axiom_discovery/boards std_msgs/msg/String \
--qos-reliability reliable \
--qos-durability transient_local \
--qos-depth 1 --full-length --once
ros2 topic list -t --no-daemon
The retained JSON inventory reports each board's firmware MAC id, namespace, transport, address and connected state. It is published when the inventory changes. Request both reliable delivery and transient-local durability to receive the cached inventory after startup. connected: true confirms a session; inspect a sensor topic as well to confirm measurements are arriving.
Unconfigured boards use /axiom_<12-digit-firmware-MAC>, for example /axiom_001122334455. Names do not depend on discovery order, the IP address or /dev/ttyACM numbering. Use the firmware ID from this inventory, which can differ from the USB adapter's serial number. The default sensor frame prefix derives from the board namespace.
Automatic discovery requires a valid firmware MAC, a successful rslt and an Axiom SystemName. Firmware without a valid MAC needs an explicit standalone bridge launch rather than discovery.
Board discovery assigns the board namespace; sensor descriptors and locations determine the rest of each measurement path. For example, a configured /robot/front board can publish /robot/front/lsm6ds_b1_76a/data_raw and /robot/front/amg8833_b1_169/image. These identities are illustrative: inspect the actual topic list and devices inventory for your board.
An optional alias named imu/data_raw uses source: data_raw; the chosen alias path is separate from the generated sensor name. Neither board namespaces nor aliases change the firmware bus/address or rotate the sensor frame. See sensor naming and updating older configuration.
Board discovery and measurement mapping are separate. The host driver chooses sensor message types from decoded attributes; devices.public_topics and devices.output_info identify the resulting canonical paths, message types and units. Illuminance/scalar outputs need no per-sensor board entry. The optional ROS mapping preview belongs in a device descriptor's devInfoJson, not in the discovery configuration. See Standard messages and mappings for defaults and preview availability.
Each YAML block below is a complete example unless labelled as a fragment. Replace illustrative IDs, paths and addresses with values for your own hardware. Save your chosen configuration as config/boards.yaml, or select another file explicitly:
ros2 launch axiom_driver axiom.launch.py boards_file:=/absolute/path/boards.yaml
scripts/setup_env.sh loads the optional config/machine.env. AXIOM_ROS_BOARDS_FILE can select a board file; when unset, the setup script selects an existing config/boards.yaml. Explicit boards_file:=... overrides that selection. Restart discovery after editing its startup settings. Stop the old launch before starting another mode.
The usb, wifi and include_unconfigured settings belong under discovery in the board file. They are not launch arguments of axiom.launch.py; that launch exposes boards_file.
discovery:
usb: true
wifi: false
include_unconfigured: true
This complete file has no Wi-Fi endpoints. It waits for USB boards, verifies them and starts acquisition automatically. wifi: false disables mDNS browsing, not explicit WebSocket entries: remove such entries or restrict them to serial if you need strict USB-only operation.
The compatibility executable ros2 run axiom_driver axiom_usb_discovery also defaults to mDNS browsing off, but still reads a selected board file and honours explicit Wi-Fi endpoints. Its inventory is /axiom_usb_discovery/boards. Use the same reliable/transient-local echo settings with that topic.
discovery:
usb: false
wifi: true
include_unconfigured: true
This discovers already networked boards through mDNS and does not enumerate USB ports. USB preference and transport switching do not apply in this mode.
discovery:
usb: true
wifi: true
include_unconfigured: false
axioms:
robot/front:
id: '001122334455'
publish_rate_hz: 20.0
topic_aliases:
imu/data_raw: {type: LSM6DS, source: data_raw}
range: {type: VL53L4CD, source: range}
robot/rear:
id: 'aabbccddeeff'
The matching boards use /robot/front and /robot/rear. IDs need no USB path or IP address. include_unconfigured: false excludes other verified boards from acquisition; adding an axioms mapping alone does not exclude other boards. The default is true.
Discovery may read version information before learning whether a board is selected. A single entry can use either verified transport. Add transport: serial to make that board USB-only, or transport: ws to make it Wi-Fi-only. This restricts that entry, not all boards on the host.
Namespaces, configured IDs, endpoints and sensor frame prefixes must be unique within a configuration. Ambiguous rules are reported and that board is not started. Keep names and optional sensor aliases in one entry per physical board.
discovery:
usb: false
wifi: false
include_unconfigured: false
axioms:
axiom:
id: '001122334455'
transport: ws
device_uri: ws://192.0.2.10/ws
Replace both the example ID and address. The configured Wi-Fi endpoint is still verified and connected with wifi: false. The ID ensures that the address must present the intended board. This mode works when multicast is blocked, provided HTTP and WebSocket traffic to the board is allowed. It does not bypass Wi-Fi client isolation or make an unreachable address reachable.
For an explicitly selected USB path, use usb: true, wifi: false, include_unconfigured: false and an entry with transport: serial and serial.port. Keep usb: true because discovery must enumerate the port. Use a persistent /dev/serial/by-id/... path where available. Other candidates can be probed, but only matching entries acquire.
discovery:
include_unconfigured: false
axioms:
axiom:
id: '001122334455'
auto_connect: false
auto_reconnect: false
autosub: false
This still discovers and verifies the selected board; its persistent acquisition session starts only when requested. With discovery running and the verified driver's services present:
ros2 service call /axiom/connect axiom_interfaces/srv/Connect '{device_uri: ""}'
ros2 service call /axiom/publish_data_subscription \
axiom_interfaces/srv/PublishedDataSubscription '{rate_hz: 20.0}'
These three flags default to true. An intentional Disconnect disables automatic reconnect. A subscription rate of zero stops acquisition while leaving the connection open. Discovery preserves explicit connection and rate choices over transport changes and reappearance during that process; restarting discovery reapplies the startup configuration.
axiom_minimal_launch.py and multi_axiom.launch.py are separate explicit endpoint launches. They do not run discovery, scan for additional boards or switch between USB and Wi-Fi. They use the legacy endpoint-only board-file format: do not pass discovery settings or id rules to them. Their connection, recovery and acquisition flags also default to enabled. The manual multiple-board walkthrough disables all three explicitly.
Discovery runs one bridge per physical board, deduplicating verified USB and Wi-Fi endpoints by firmware MAC. With both transports allowed and available, USB is preferred, including when USB appears after a Wi-Fi connection. If USB disappears and a verified Wi-Fi endpoint remains available, the replacement bridge uses the same board namespace over Wi-Fi. Switching transport involves reconnecting; a short gap in measurements is expected. Other boards continue independently.
A reappearing endpoint is verified again, and a different physical identity is checked before acquisition. A board that loses its only power source cannot fall back to Wi-Fi: unplugging a USB-powered board powers it off unless it has another supported supply.
Use both board selection and a ROS domain for each independent demo:
| Setting | Demo A | Demo B |
|---|---|---|
| Board selection | Only board A's firmware ID | Only board B's firmware ID |
| Namespace | /demo_a/axiom | /demo_b/axiom |
| ROS_DOMAIN_ID | 42 | 43 |
With DDS, domains separate ROS discovery and messages; they do not select Axioms or prevent another computer opening a connection to the same board. Axiom mDNS discovery and its serial/WebSocket connections are independent of ROS domains. Namespaces organise ROS names; they are not ownership controls. See the ROS domain documentation.
All boards managed by one discovery process share its ROS domain. Two isolated demos on one computer need separate processes with separate board files and environments; a per-board domain setting is not provided. Stop and restart affected ROS processes after changing the environment. Reused tmux panes also need their environment reloaded. Domain IDs and demo membership are not allocated automatically.
Run one acquisition owner per physical board and let other consumers subscribe to ROS topics. Current host-driver sessions take nonblocking per-user endpoint and firmware-ID locks on the same computer, including across domains. A competing session reports ownership and retries. These advisory locks do not coordinate different computers, different users, older drivers, browsers or native Zenoh routers. There is no cross-computer ownership reservation: use distinct board selections for independent demos.
Stop viewers and discovery with Ctrl+C when finished. Discovery closes its managed bridges and transports and releases worker threads. Detaching tmux or stopping an echo leaves discovery and acquisition running.
If the inventory is silent, check ros2 node list --no-daemon and ros2 topic info /axiom_discovery/boards --verbose. With discovery running, retry the inventory command above with both QoS options. If a board is absent, check its power, permissions or network reachability, firmware identity and selection rules; if it is connected but sensor data is absent, inspect the discovered sensor topic and acquisition settings.