Foxglove sensor dashboards
Use the host ROS driver with either USB or Wi-Fi. Foxglove displays ROS topics through foxglove_bridge; it does not connect directly to Axiom or start firmware acquisition. Complete the host setup first, using host firmware and the setup-file path for your installed ROS distribution.
Ready-made layouts:
| Layout | Display |
|---|---|
| one-axiom-thermal.json | One AMG8833 8×8 thermal Image panel |
| two-axiom-imu.json | Acceleration and angular velocity plots for two boards |
| one-axiom-sound.json | Sound scalars and nine-band spectrum; embedded user script, no extension required |
| one-axiom-spectrum.json | Frequency-labelled coloured bars; install the optional Axiom Spectrum extension first |
Generated sensor topics use model/location roots, for example /axiom1/amg8833_b1_169/image for a thermal camera and /axiom1/lsm6ds_b1_76a/data_raw for an IMU. The supplied layouts instead use explicit convenience aliases /axiom1/thermal/image and /axiom1/imu/data_raw. These are user-chosen destinations, not automatic legacy topics. Set their sources to image and data_raw as shown below, or select the actual canonical topics in the imported panels.
The bundled layouts use example board namespaces. Match those namespaces/aliases in your board configuration, or select your actual topics in the imported panel settings.
Install the bridge and connect a viewer
In a prepared terminal at the repository root, install the bridge once for the loaded distribution:
source scripts/setup_env.sh
sudo apt install "ros-${ROS_DISTRO}-foxglove-bridge"
Installation uses the ROS package repositories configured for that distribution. See the official ROS bridge guide for package availability and source-build options. Start the bridge after the driver is running with the same ROS domain and middleware settings. For multiple independent demos, start each bridge in its demo's domain and connect its viewer to that bridge. If bridges run on one host, give them different listening ports and use the matching port in each viewer. Select physical boards separately; see shared-network discovery and board selection:
ros2 launch foxglove_bridge foxglove_bridge_launch.xml
Leave it running. Open app.foxglove.dev in Chrome or the Foxglove desktop app on a supported computer. Choose Open connection from the dashboard or top-left app menu, then Foxglove WebSocket:
- Viewer on the bridge host: ws://localhost:8765.
- Viewer on another computer: ws://ROS_HOST_IP:8765, replacing ROS_HOST_IP with the bridge host's reachable address, not Axiom's Wi-Fi address.
Select Open and check that the Axiom topics appear. localhost means the computer running the viewer. For a remote viewer, the bridge's TCP port 8765 must be reachable; browser/OS local-network permissions may also need to be allowed.
You need account access to direct connections and layout import/editing. Foxglove currently specifies a developer seat for direct connections and editing layouts; see its live connection and layout documentation. The web viewer needs internet to load and sign in. The direct measurement stream travels between the local bridge and viewer. Desktop offline use depends on standalone licensing. RViz provides a local thermal-display alternative.
Illuminance and scalar plots
Illuminance and numeric scalar topics can be plotted directly through the same bridge. First inspect ros2 topic list -t --no-daemon and the board's devices inventory, then use the actual topic paths. See Standard messages and mappings for software availability, units, invalid readings and descriptor mapping requirements. No optional descriptor mapping is needed for the normal LTR-390 outputs.
In the connected Foxglove viewer:
- Add a Plot panel and open its settings.
- Add a series using your Illuminance topic's .illuminance field. An illustrative path is /axiom/ltr_2d390_b1_53/ambient.illuminance.
- Label the panel/series Illuminance and the vertical axis lux.
- Add a second Plot panel for the UVI topic's .data field, for example /axiom/ltr_2d390_b1_53/UVI.data. Label its axis UV index. Keep unlike units on separate plots.
- Use Log time for headerless Float64 data. For a live connection this is reception time; it is not the original measurement timestamp. Illuminance also provides header.stamp if measurement-time plotting is required.
The example namespace, bus and sensor address are illustrative. Copy complete paths from the viewer rather than assuming /axiom or address 53. A headerless scalar carries no units; use inventory output_info to choose the axis label. sample retains timing and validity, while device_metadata supplies the descriptor.
| Message type | Numeric field for a Plot series |
|---|---|
| sensor_msgs/msg/Illuminance | .illuminance; lux |
| sensor_msgs/msg/Temperature | .temperature; °C |
| sensor_msgs/msg/RelativeHumidity | .relative_humidity; fraction |
| std_msgs/msg/Float64 | .data; unit from output_info |
These numeric fields do not require parsing the JSON data topic. A separate sensor output named UVI is a Float64 topic even though each message's numeric field is also called data. Bool and scalar text outputs can be inspected in Raw Messages; their invalid readings are omitted, so a panel may still show its last received value. Check freshness and validity rather than treating a retained display as a new reading.
Save the layout after choosing the correct topics and units; it can be reopened without rebuilding each series. The bundled layouts include thermal, two-board IMU and sound displays. The sound walkthrough also covers an optional custom coloured-bar spectrum extension and synthetic recording. See the official Plot panel guide for series settings and timestamp sources.
Thermal camera on one Axiom
The single-camera layout subscribes to /axiom1/thermal/image. Its Image panel is titled Axiom 1: Thermal (°C) and uses Turbo with a fixed 15–40 °C scale. Values beyond the colour limits clip to the end colours; ROS measurements retain their original values. The native 8×8 grid is not an interpolated camera image.
Update and configure
For an existing clone already on main with no local source changes, stop acquisition, disconnect and stop affected ROS processes before updating. From the repository root:
git pull --ff-only origin main
source scripts/setup_env.sh
rosdep install --from-paths src --ignore-src -r -y
colcon build --base-paths src --symlink-install
source scripts/setup_env.sh
For first setup, use Install and connect. When updating older settings, follow the naming migration too: local alias selectors and exact QoS keys are not updated by Git. A layout-only update needs a pull and reimport, without a rebuild. Changing driver code requires a rebuild and restart.
In config/boards.yaml, use board key axiom1 for this example. If renaming the earlier axiom key, stop its driver first, preserve the USB or Wi-Fi settings, and use automatic startup: remove explicit false overrides for auto_connect, auto_reconnect and autosub. An identity rule can select the board without a USB path or IP; see automatic startup. Merge this alias into the board's existing topic_aliases mapping:
topic_aliases:
thermal/image: {type: AMG8833, source: image}
This is a fragment, not a replacement board file. It binds to exactly one online, resolved and fresh AMG8833; use inventory bus and address selectors if several cameras match. An alias names ROS output rather than installing a device profile. The canonical model/location sensor topic remains available. For another namespace, substitute it throughout the commands and select its image topic in the panel.
If you do not already have a board file, this is a complete single-board example. Replace the illustrative id with your board's firmware ID from /axiom_discovery/boards, then save it as config/boards.yaml. If a file already exists, edit its existing entry instead of overwriting the file or adding a second entry for the same board:
discovery:
include_unconfigured: false
axioms:
axiom1:
id: '001122334455'
topic_aliases:
thermal/image: {type: AMG8833, source: image}
Stop any existing discovery launch before restarting with this file. The Terminal 1 command below explicitly selects config/boards.yaml; if your file is elsewhere, substitute its path.
Start the session
The tmux helper opens four empty panes with the environment preloaded. Use Terminal 1 for the driver, Terminal 2 for services/inspection, Terminal 3 for the bridge, and Terminal 4 for optional checks. In separate windows or reused panes after a rebuild, source scripts/setup_env.sh first.
Terminal 1:
ros2 launch axiom_driver axiom.launch.py boards_file:=config/boards.yaml
Terminal 2:
ros2 topic list -t --no-daemon
ros2 topic info /axiom1/thermal/image
ros2 topic echo /axiom1/thermal/image --once --qos-reliability best_effort
Discovery connects and acquires automatically. Expect the topic to be sensor_msgs/msg/Image with one publisher. A frame has width/height 8, encoding 32FC1, is_bigendian: 0, step: 32, and 256 bytes representing 64 little-endian float32 temperatures in °C. Its header has the sample timestamp and sensor frame. The camera's canonical grid topic, for example /axiom1/amg8833_b1_169/grid, remains available for the RViz Marker visualiser.
The camera must be connected with a supported firmware profile. The publication rate controls delivery, not camera sampling. An echo or viewer alone does not enable acquisition.
In Terminal 3, run the bridge command from the section above, then connect the viewer.
Import and check
- Click the layout name/dropdown in the top toolbar to open Layouts.
- Choose Import from file… and select examples/foxglove/one-axiom-thermal.json on the viewer computer.
- Open the newly imported layout and save it as Axiom: thermal camera.
If the checkout is on another computer, download the thermal JSON to the viewer computer, or copy it there. For example, run from the checkout on the source computer, replacing the login/address of the viewer computer:
scp examples/foxglove/one-axiom-thermal.json USER@VIEWER_HOST:~/one-axiom-thermal.json
Import the copied file from the viewer computer's home directory. The supplied layout has one thermal panel. Move a hand in front of the camera to see warmer pixels change colour. Pixel order follows firmware; adjust the panel's rotation or flip controls for mounting. Enlarging the display adds no measured pixels. This 2D heatmap needs no TF tree or camera calibration. A spatial 3D projection requires a separate calibration and frame contract.
Replacing a JSON file does not update a saved Foxglove layout. Import it again and open the new layout after a layout change.
Troubleshoot and finish
| Symptom | Check |
|---|---|
| No Axiom topics | Driver running, acquisition enabled, matching ROS domain/middleware |
| Viewer cannot connect | Bridge running, correct host address/port, local-network permission and direct-connection entitlement |
| No image publisher | Camera online in /axiom1/devices, correct alias/type/namespace |
| Canonical image exists, alias absent | Resolve an ambiguous match with bus/address, or select the canonical sensor topic |
| Grid exists, image absent | Build/source/restart the current host driver; Image output needs known Celsius units |
| One colour | Inspect temperatures and adjust Value min / Value max |
| Extra panels | Open the newly imported one-axiom-thermal.json layout |
Stop the bridge in Terminal 3. In Terminal 2:
ros2 service call /axiom1/publish_data_subscription \
axiom_interfaces/srv/PublishedDataSubscription '{rate_hz: 0.0}'
ros2 service call /axiom1/disconnect axiom_interfaces/srv/Disconnect '{}'
Then stop the driver. Published walkthrough: Thermal camera in Foxglove. See the Image panel documentation for display controls.
Two-board IMU plots
two-axiom-imu.json plots X/Y/Z acceleration and angular velocity for /axiom1/imu/data_raw and /axiom2/imu/data_raw. Use board keys axiom1 and axiom2, each with its firmware id or explicit endpoint and this alias fragment:
topic_aliases:
imu/data_raw: {type: LSM6DS, source: data_raw}
Each alias needs exactly one matching online IMU; use bus/address selectors if needed. Follow the multi-board workflow with those namespace names and automatic startup. Both boards connect and acquire automatically; explicit manual control remains available. Use a single Foxglove bridge for the ROS session.
Import examples/foxglove/two-axiom-imu.json on the viewer computer using the same Layouts menu. For a remote checkout, download the IMU JSON or copy that file to the viewer computer before import.
| Position | Panel title | Units |
|---|---|---|
| Top left | Axiom 1: Acceleration | m/s² |
| Bottom left | Axiom 1: Gyroscope | rad/s |
| Top right | Axiom 2: Acceleration | m/s² |
| Bottom right | Axiom 2: Gyroscope | rad/s |
The plots have a rolling 30-second window, automatic vertical scaling, and X red, Y green, Z blue. They use log/receipt time; aligned axes do not synchronise hardware clocks. At rest, acceleration includes about 9.8 m/s² of gravity in total, and angular velocity should be near zero. Tilt/rotate each board to check its own column. These are raw sensor-axis values, not fused orientation or speed.
For empty plots, check actual publisher counts, the inventory, acquisition and alias ambiguity. For different namespaces, select those topics in the panel settings. Stop the bridge, then stop acquisition and disconnect both drivers using their respective namespaces before stopping the multi-board launch.
Layout configuration and automated image-output evidence are recorded in validation.md. Those dated checks do not establish physical mounting orientation or rendering on every workstation.
Multizone distance images
A supported VL53L5CX descriptor publishes sensor_msgs/msg/Image directly, using 32FC1 distances in metres. The driver handles supported distance/status arrays; invalid zones are NaN. Select the actual canonical image topic from devices.public_topics or the topic list. A single-zone Range sensor is a scalar plot; it does not produce the same multizone image.
# Select the discovered VL53L5CX Image topic, not a scalar range topic.
RANGE_IMAGE_TOPIC='PASTE_FULL_MULTIZONE_IMAGE_TOPIC_HERE'
# Inspect the type and publisher before opening an Image panel.
ros2 topic info "$RANGE_IMAGE_TOPIC" --verbose
# Read one frame's dimensions, encoding and data-array size.
ros2 topic echo "$RANGE_IMAGE_TOPIC" sensor_msgs/msg/Image \
--qos-reliability best_effort --no-arr --once
In the connected viewer, add an Image panel and select that topic. Use a colour map and numeric min/max appropriate to distances in metres. Dimensions come from the descriptor/frame; the display does not add resolution or reconstruct a calibrated 3D point cloud. A descriptor providing both thermal and range grids uses distinct thermal/image and range/image outputs beneath the sensor root.
The bundled thermal layout is deliberately a single AMG8833 camera, with Celsius labels and a 15–40 °C scale. For a distance image, create an Image panel or reconfigure its topic, labels and scale rather than reusing those thermal limits. A 2D heatmap needs no TF projection. To relate pixels to a physical 3D scene, supply separate calibration and transforms.
Sound and custom spectrum bars
Follow Sound sensor and spectrum for the 15 scalar plots, built-in nine-band spectrum layout, or optional Axiom Spectrum custom panel. The custom panel reads the existing DeviceSample topic directly and includes frequency labels, coloured bars, invalid/stale indications and a configurable scale. It requires installing a .foxe extension on the viewer computer; a layout JSON alone does not install the panel. Both spectrum options use existing decoded samples and need no separate ROS bands publisher.
For local Matplotlib plots or rosbag recording without Foxglove, use Inspect, plot and record.