3D visionTroubleshooting

Thermal camera node starts but publishes no topics: diagnose it

A thermal camera node that publishes no topics usually runs an outdated driver. Rank the causes, run the tests, and fix the dead ROS 2 stream in minutes.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01What the symptom already tells you
  2. 02Cause 1: the driver package is out of date
  3. 03Cause 2: the node publishes under a different topic name
  4. 04Cause 3: Chunk data the driver needs is disabled or missing
  5. 05Cause 4: incomplete GigE frames
  6. 06The ten-minute check sequence
  7. 07Prove it and keep it publishing
  8. 08When every software check passes
  9. 09Questions

A thermal camera node that starts cleanly, lists image_raw and camera_info in ros2 topic list, and then never fills them is failing on the driver side, not in the camera: discovery succeeded, the stream opened, and the vendor viewer still shows live frames. The causes, in order of how often they close the case, are an outdated driver package, a topic-name mismatch, disabled GenICam Chunk data, and incomplete GigE frames. Work through them in that order with the tests below and most cases close inside ten minutes — the majority close with nothing more than a package update and a relaunch.

What the symptom already tells you

Three facts narrow the fault before you run a single test. The node process is alive and the topics are advertised, so camera discovery and driver startup succeeded — a boot-order or discovery failure looks different, with no node at all, and has its own fix plan in GigE camera not discovered on startup. The vendor viewer shows a live image, so the sensor, the lens and the physical link work. And the node did not reject the pixel format: a Mono16 request the camera cannot honour fails loudly at open time, which is the territory of unknown pixel format: diagnose missing depth streams, not a silence. What is left is frame assembly inside the driver — the code path that turns arriving packets into published messages — and that path fails in four ways.

Cause 1: the driver package is out of date

Start here, because it is the most common cause and the quickest decisive test. In the largest share of reports with this exact signature — node up, topics advertised, echo silent, viewer happy — the installed driver predates the fix. Older releases cannot request or parse the Chunk data they need, so the driver waits for frames that never assemble and publishes nothing, while the viewer's own transfer path keeps working. Update the package to the maintainer's current release, rebuild if you run from source, and relaunch the driver's launch file unchanged.

A borrowed parameter file with most entries commented out is not the problem: a sparse file that sets only pixel_format to Mono16 is a valid configuration. The tell is history, not settings — the camera and the viewer never changed, only the age of the package did.

If the update is not enough and you build from source, some drivers keep frame-status diagnostics behind a preprocessor guard: flipping the #if 0 to #if 1 around that block and overlaying the rebuilt workspace prints exactly why frames are rejected.

Cause 2: the node publishes under a different topic name

The graph can mislead in two directions: the CLI can hold a stale graph, and your pipeline can listen on a name the driver never uses. Two commands settle it:

ros2 topic list -t
ros2 topic info /image_raw

Publisher count: 1 means the node created the publisher on that exact name; count 0 means it publishes elsewhere or under a namespace such as /my_camera/image_raw. Then read the node side:

ros2 node info /camera

The Publications list is the authoritative name. If the graph looks frozen — topics still listed from a node you killed — reset the CLI cache with ros2 daemon stop and run topic list again. Fix every mismatch with a remap in the launch file, so your pipeline keeps its own names and the driver keeps the ones it was built with.

Cause 3: Chunk data the driver needs is disabled or missing

The driver builds each image message from the GenICam Chunk data — or the GenDC container on some transports — attached to every frame. If the camera's feature tree does not expose those settings, or they are disabled, the node waits on data that never arrives and the topics stay empty while packets flow. Open the feature tree in the vendor viewer, find the Chunk settings, and enable chunk mode. If the category is missing entirely, the camera firmware is older than the driver expects, and you are back at Cause 1. Enable the settings, store them in a user set if the camera supports one, then relaunch the node.

This is also the point to separate "no frames" from "wrong frames": if echo starts printing but the image decodes to flat gray noise, the stream lives and the format is the fault, which is covered step by step in camera preview shows a gray image.

Cause 4: incomplete GigE frames

If echo prints occasionally rather than never, or the driver log reports incomplete frames, the stream is arriving damaged. This shows up on GigE cameras almost exclusively. The instinct is to blame bandwidth, so run the arithmetic first:

frame size = 640 px x 512 px x 2 B/px (Mono16) = 655,360 B data rate = 655,360 B x 50 fps = 32.8 MB/s ≈ 262 Mbit/s

A 640 x 512 thermal stream at 50 Hz needs about 262 Mbit/s — a quarter of a GigE link — so raw bandwidth is almost never the cause. Packets are:

packets per frame at MTU 1500: 655,360 B ÷ 1,472 B ≈ 445 packets per frame at MTU 9000: 655,360 B ÷ 8,972 B ≈ 73 packets per second at 50 fps: ≈ 22,250 vs ≈ 3,650

One dropped packet kills a whole frame, and 22,250 chances per second is six times the exposure of 3,650. The payload figures assume standard UDP header overhead of 28 B, so treat the packet counts as close estimates. The fix set, in order of payoff: enable jumbo frames end to end — NIC, switch and camera all at MTU 9000, because one link left at 1500 undoes the rest — then give the camera a dedicated NIC, raise the kernel's socket receive buffers, and shorten the cable. The full measurement procedure lives in GigE Vision stream packet loss: diagnose blank frames.

To separate a camera fault from a network fault, bench the same resolution over USB3 next to the GigE camera:

Infrared cameras640 x 512 thermal camera, 8-14 μm, 50 Hz, GigE, FOV 88.5° × 73.2°, 9-24 V DC (LS-IRC-0044)LS-IRC-0044
Lens mount
C-mount
Interface
GigE
$5,885.00 · quotedView and quote
Infrared camerasLWIR thermal camera module, USB3, 640×512 resolution (LS-IRC-0016)LS-IRC-0016
Interface
USB3
$3,999.00 · quotedView and quote

The LS-IRC-0044 covers the GigE path at 640 x 512 and 50 Hz, and the LS-IRC-0016 module outputs 640 x 512 over USB3, which removes the switch, the NIC and the jumbo-frame configuration from the equation entirely. If USB3 publishes and GigE does not, stop debugging the driver — the network path is the fault.

The ten-minute check sequence

Run the tests in this order; each one either fixes the case or eliminates a cause.

  1. ros2 topic list -t — confirm image_raw and camera_info exist and note their types.
  2. ros2 topic info /image_raw — Publisher count: 0 means fix the topic name (Cause 2); count 1 means the publisher exists, move on.
  3. ros2 node info /camera — confirm the driver's Publications list matches the name you watch.
  4. ros2 daemon stop, then ros2 topic list again — rules out a stale CLI graph.
  5. Update the driver package to the current release and rebuild — this alone closes Cause 1 and usually Cause 3 together.
  6. ros2 topic hz /image_raw — a steady rate at the camera's rated frame rate proves the fix; leave it running a full minute to catch intermittent drops.
  7. Still silent: enable Chunk mode in the vendor viewer and relaunch (Cause 3).
  8. Rate present but erratic, or echo sparse: MTU 9000 end to end and a dedicated NIC (Cause 4).
Cause Fastest test Fix Typical time
Outdated driver package Installed version against the maintainer's current release Update, rebuild, relaunch 10 min
Topic-name mismatch ros2 topic info publisher count Remap in the launch file 2 min
Chunk data disabled or missing Chunk settings in the feature tree Enable chunk mode, store user set 5 min
Incomplete GigE frames Sparse echo, incomplete-frame log lines Jumbo frames end to end, dedicated NIC 15 min

Prove it and keep it publishing

Once hz holds steady, confirm the content, not just the count: ros2 topic echo /image_raw --field header prints only the header, so you watch stamps advance without flooding the terminal. A raw thermal stream arrives as Mono16 — the sensor's 14-bit radiometric counts travel in 16-bit words — so decide deliberately what happens downstream. Export the full bit depth when the data matters, following export high bitdepth grayscale images from thermal cameras, and combine with RGB without flattening the counts, as in thermal RGB image fusion without losing temperature data.

For prevention, pin the driver version and the camera firmware as a pair in your deployment notes, and re-run the hz check after any update on either side. A 3D or depth pipeline that also consumes this stream adds alignment pitfalls of its own; the 3D topic guides collect the ones that bite at integration time.

When every software check passes

If Publisher count is 1, hz prints nothing, the driver is current and Chunk is enabled, move down the stack. Put the camera on a different NIC or PC first — a marginal NIC that carries the viewer's short bursts but starves a sustained stream is not rare. If a known-good PC still shows nothing, the camera is the remaining suspect, and the decision is service or replacement.

If you are selecting hardware for a new cell instead of reviving an old one, start from the infrared cameras and area scan cameras categories, filter by interface and resolution in the camera finder, and let the camera configurator pair the camera with a matched lens and cable. When the node finally publishes, the rest of the integration is ordinary vision engineering — the hard part was one stale package.

Questions

Why does the camera work in the vendor viewer but publish nothing in ROS 2?

The viewer and the driver node use different transfer paths. The viewer talks to the camera with its own SDK and tolerates a stream the driver cannot assemble; the node depends on GenICam features such as Chunk data being available in the installed package. A camera that displays fine can therefore still starve the node. Update the driver package first — this exact combination of symptoms resolves there more often than anywhere else.

What should ros2 topic info show for image_raw when the driver is healthy?

Type: sensor_msgs/msg/Image, Publisher count: 1, Subscription count: 0 or more. Publisher count 0 means no node ever created that publisher — you are watching the wrong name, so fix the remap first. Count 1 with nothing on ros2 topic hz means the publisher exists and frames are dying inside the driver: move to the package version and the Chunk checks, in that order.

How much GigE bandwidth does a 640 x 512 Mono16 thermal stream need?

Multiply it out: 640 x 512 pixels x 2 bytes = 655,360 bytes per frame; at 50 frames per second that is 32.8 MB/s, about 262 Mbit/s, roughly a quarter of one GigE link. Four such cameras saturate a dedicated link, so leave headroom for discovery traffic and bursts. Bandwidth is almost never what fails first — per-packet handling is, which is why jumbo frames beat a faster switch.

Should pixel_format stay Mono16 for a thermal camera?

Yes, for a raw radiometric stream. Most industrial LWIR sensors carry 14-bit data in 16-bit Mono16 words, and the low bits hold the temperature gradients you bought the camera for. Converting to Mono8 at the driver halves the bandwidth and throws that resolution away. Convert downstream, after the nodes that need the counts, and only if bandwidth truly becomes the constraint.

Can the thermal camera share a NIC with other GigE cameras?

It can: a 640 x 512 Mono16 stream needs only about 262 Mbit/s. The catch is discovery and packet timing, not bandwidth. GigE Vision discovery broadcasts reach every link in the subnet, so a camera that stalls packet timing can delay discovery of its neighbours. Past two cameras per NIC, give each camera its own NIC or its own subnet; that cost is small next to a stalled cell.