ROS 2: thermal camera in RViz

Connect one Axiom with an AMG8833 8×8 thermal camera, request its measurements and display a heatmap with a temperature label for every pixel. This uses axiom_driver, axiom_thermal_viz and RViz. The dashboard is optional.

Expected display

RViz thermal heatmap and pixel temperatures

Illustrative 8×8 frame generated for this screenshot. The commands below use the measurements from your camera.

Before starting

Complete Install and connect. For Wi-Fi, set the axiom entry in boards.yaml to transport: ws and device_uri: ws://YOUR_AXIOM_IP/ws. Keep auto_connect, auto_reconnect and autosub false. Attach the camera to Axiom.

Build the supplied RViz configuration from the repository root:

source scripts/setup_env.sh
rosdep install --from-paths src examples/scenarios-dashboard/src --ignore-src -r -y
colcon build --base-paths src examples/scenarios-dashboard/src --symlink-install
source scripts/setup_env.sh

Open four terminals and source ~/Projects/axiom-ros2/scripts/setup_env.sh in each. If a driver is already running, use that session rather than starting a duplicate.

Terminal 1: start the driver

ros2 launch axiom_driver axiom_minimal_launch.py \
  namespace:=/axiom boards_file:="$AXIOM_ROS_BOARDS_FILE"

Leave it running. It reads the selected board's connection settings.

Terminal 2: connect and request data

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}'

ros2 topic list -t --no-daemon

Both service calls should return success: true. Find the topic ending in /thermal/grid, with type axiom_interfaces/msg/ThermalGrid. No thermal entry is required in the board file.

Set the exact discovered path; this is an example address:

THERMAL_TOPIC=/axiom/bus_1/device_169/thermal/grid
ros2 topic echo "$THERMAL_TOPIC" axiom_interfaces/msg/ThermalGrid \
  --qos-reliability best_effort --once

Expect width: 8, height: 8, 64 values in temperature_c and a nonempty header.frame_id. The prompt returns after one frame. Do not continue if no frame arrives.

Terminal 3: convert the grid to RViz markers

Variables belong to the terminal where you set them. Set the same camera topic here, replacing the example path with yours:

THERMAL_TOPIC=/axiom/bus_1/device_169/thermal/grid

ros2 run axiom_thermal_viz thermal_heatmap --ros-args \
  -r __ns:=/sensing \
  -p input_topic:="$THERMAL_TOPIC" \
  -p output_topic:=thermal_heatmap \
  -p use_dynamic_range:=false \
  -p min_temperature:=15.0 \
  -p max_temperature:=40.0

Keep it running. It subscribes to the grid and publishes /sensing/thermal_heatmap markers and /sensing/thermal_heatmap_labels temperature labels. The colour scale stays fixed at 15–40 °C.

Terminal 4: select the frame and open RViz

Use the actual camera topic in this terminal too:

THERMAL_TOPIC=/axiom/bus_1/device_169/thermal/grid

THERMAL_FRAME="$(ros2 topic echo "$THERMAL_TOPIC" \
  axiom_interfaces/msg/ThermalGrid --field header.frame_id \
  --qos-reliability best_effort --once | sed -n '1p')"

printf '%s\n' "$THERMAL_FRAME"

Once a frame name is printed, run RViz in this same terminal:

ros2 run rviz2 rviz2 \
  -d "$(ros2 pkg prefix --share axiom_marty_demo)/config/thermal.rviz" \
  -f "${THERMAL_FRAME:?No camera frame received}"

You should see an 8×8 heatmap with small temperatures in °C. Move your hand near the camera and watch the cells change. Marker size is a display layout; it is not a measurement of the object's physical size or position.

If RViz is empty

Check What to look for
Raw grid The Terminal 2 echo returns a frame. If not, check acquisition and whether the camera is online in /axiom/devices.
Adapter input input_topic exactly matches the discovered thermal topic.
Marker publisher ros2 topic info /sensing/thermal_heatmap --verbose reports a publisher.
Fixed Frame It matches header.frame_id from the camera message.
Displays Heatmap uses a Marker display on /sensing/thermal_heatmap; labels use MarkerArray on /sensing/thermal_heatmap_labels.
Colour saturation Temperatures outside 15–40 °C clip to the end colours. Adjust the limits or enable use_dynamic_range.

The heatmap can render in its own sensor frame without another TF node. RViz may still report a global warning that no TF data has been received. To place the camera in a robot's coordinate system, supply its actual mounting transform separately.

Clean up

Press Ctrl+C in Terminal 4, then Terminal 3. In Terminal 2:

ros2 service call /axiom/publish_data_subscription \
  axiom_interfaces/srv/PublishedDataSubscription '{rate_hz: 0.0}'
ros2 service call /axiom/disconnect axiom_interfaces/srv/Disconnect '{}'

Finally, press Ctrl+C in Terminal 1. Back to Axiom with ROS 2.

Task Runner