System designTroubleshooting

ROS Aravis camera reads properties but no video stream

An Aravis ROS node that reads camera properties but delivers no video stream has a dead data channel. Fix packet size, start order, callbacks and firewall.

LumaSpec Vision10 min read Share on LinkedIn

On this page 11 sections
  1. 01What the hang already tells you
  2. 02Turn the debug log on before you change code
  3. 03Cause 1: the packet size is bigger than the path carries
  4. 04Cause 2: the stream is never started, or never fed buffers
  5. 05Cause 3: callbacks that never fire
  6. 06Cause 4: the host is eating the data path
  7. 07Worked example: 5 MP Mono8, 1484-byte packets, one gigabit link
  8. 08Hardware that removes the variables
  9. 09When the stream is healthy and the image is black
  10. 10Checklist: the bring-up order that avoids the hang
  11. 11Questions

You built a ROS node around Aravis to publish image_raw and camera_info from a GigE Vision camera. The node compiles, finds the camera, prints every property it asks for — and then sits there, with no error and no topic. That silence is diagnostic. The GigE Vision control channel works, so discovery, the XML feature description and register access are all healthy; what is dead is the stream channel that carries image data as UDP packets. This guide works the fault in probability order — packet size, stream-start order, callback dispatch, host firewall — with a test and a fix for each, a worked bandwidth check for a 5 MP camera, and the bring-up order that keeps the hang from coming back.

What the hang already tells you

Reading properties takes three working pieces: device discovery over UDP, the camera's XML feature file parsed into the node, and register access on the control channel. Your node printed the proof of all three, so the fault sits later — between a successful arv_camera_new() and the first buffer arriving. Nodes that break earlier break loudly, with feature-access failures of the kind covered in GenICam node not existing: diagnose feature access errors or the readability checks in Camera feature node readability: check before reading. Yours breaks quietly, which points at transport.

Prove the camera once, outside ROS: run arv-camera-test, or arv-viewer with the reduced packet size that worked before. If either streams, the camera, cable and link are sound, and every remaining minute belongs to the node and the host.

Turn the debug log on before you change code

Aravis logs its own pipeline, and the switch is one environment variable set in the shell that launches the node:

export ARV_DEBUG=all:3

Run the node from that same shell. The output names the device as it is discovered, the XML file as it loads, the stream as it is created, and every GVSP packet as it lands. Read it top to bottom against this table:

Debug log shows Fault Fix in
No GVSP packets after acquisition starts Packet size or host blocking Cause 1, Cause 4
Packets arrive, buffers never consumed Start order or callbacks Cause 2, Cause 3
Buffers consumed, image still black Exposure, not transport Last section

The packet-level reading has a longer treatment in GigE Vision stream packet loss: diagnose blank frames.

One precondition before you trust the log: if the node is an old camera_aravis wrapper from the ROS Kinetic era, rebuild it against a current Aravis release instead of the 0.4.1-era API it was written for. The API moved after 0.4, and debugging through an outdated binding wastes the session.

Cause 1: the packet size is bigger than the path carries

Your viewer already gave the game away: if arv-viewer streams only after you drop the packet size to 1484 bytes, the camera default assumes jumbo frames and at least one hop on the path — network card, switch, or the PC's own MTU setting — carries only standard frames. Control packets are small and survive the mismatch; image packets are dropped without a word. The node inherits the camera default, so the hang carries no error, which is exactly what you see.

The fix is to set the viewer's working value in the node before the stream is created. The step-by-step, with the ordering argument, is in Set GigE camera packet size before starting acquisition, and the negotiation background is in GigE Vision packet size exceeds MTU: cap auto-negotiation.

Test the path independently of the camera:

ping -M do -s 1472 <camera-ip>

The 1472-byte payload plus 28 bytes of IP and ICMP header fill a standard frame exactly; a message-too-long reply means the path cannot carry anything larger, and the viewer's value is the right one. For the camera-side equivalent, use the test-packet exchange covered in GigE Vision test packet not received: fix packet size negotiation.

Cause 2: the stream is never started, or never fed buffers

The acquisition path is an ordered pipeline, and a node that reads properties and then waits has skipped the middle of it:

  1. Open the camera with arv_camera_new().
  2. Set the packet size that the link carries.
  3. Create the stream and queue buffers into it.
  4. Start acquisition on the camera.
  5. Wait on a buffer with a timeout, publish, return the buffer, repeat.

Waiting at step 5 with steps 2 to 4 missing or out of order hangs silently, because the wait is where the node stops and nothing before it has errored. Queue at least four buffers; eight is a sound default, since one free buffer stalls the camera the moment your publisher is busy. Give every wait a timeout of 1 to 2 seconds and log each one — a bounded wait is a message, an unbounded one is an afternoon. The same discipline closes the session at the other end, as Camera SDK hangs on exit: shut down streams in the right order shows, and the GigE-side detail on buffers and timeouts is in GigE Vision stream timeout: check packets, buffers and MTU.

Cause 3: callbacks that never fire

Aravis hands stream events to your code through its own event loop. arv-viewer keeps that loop running for you; a typical ROS node spins the ROS callback queue instead, and nothing services the library's loop. Frames reach the driver, the registered callback never fires, and the node waits for a signal that was delivered into an empty room. Choose one of two fixes: pull buffers straight from the stream queue in a thread of your own, which needs no event loop and keeps frame timing in your hands, or run the library's loop beside the ROS spinner. Polling is the simpler and more controllable design for a camera publisher.

Cause 4: the host is eating the data path

Discovery and streaming ride different UDP ports: the control protocol on 3956, the image stream on a port negotiated when the stream is created. A host firewall that allowed discovery can still drop the stream — on Windows this is the classic reason a camera streams in one application and not another, and the mirror-image symptom is covered in Camera connected but viewer shows no video: GStreamer missing plugins. Three host checks, in order of pay-off:

  • Close arv-viewer and every other tool before starting the node; the stream channel is exclusive.
  • Allow UDP from the camera, or disable the firewall for the duration of the test.
  • With more than one network card, bind the node to the interface that can actually reach the camera.

For probing the control side from your own code while you are here, Access GigE camera registers at runtime from your control code covers the ground.

Inputs, each taken from the failure itself:

  • Sensor: 2592 × 1944 px — 5,038,848 px, the standard 5 MP geometry — in Mono8, one byte per pixel.
  • Packet size: 1484 bytes, the value the viewer needed.
  • Frame-rate target: 15 fps, with the question of how much higher the link allows.
  • Cable: a 15 m screw-lock run such as the LS-CBL-0117.

The rule in words: each packet carries the setting minus about 36 bytes of GVSP, IP and UDP header; packets per frame follow from the frame size; the wire rate follows from the frame rate.

frame_bytes = width × height × bytes_per_pixel payload = packet_size - 36 B packets = frame_bytes / payload wire_rate = frame_bytes × fps × 8

Worked through:

  • frame_bytes = 2592 × 1944 × 1 B = 5,038,848 B
  • payload = 1484 - 36 = 1448 B per packet (the header split is an estimate of a few bytes)
  • packets = 5,038,848 / 1448 ≈ 3,480 data packets per frame
  • at 15 fps: 3,480 × 15 ≈ 52,200 packets per second
  • wire_rate = 5,038,848 B × 15 fps × 8 = 604,661,760 bit/s ≈ 0.60 Gbit/s

A gigabit link carries 1,000,000,000 bit/s, so the ceiling is 1,000,000,000 / 40,310,784 ≈ 24.8 fps, and 15 fps uses 60% of the line — comfortable, even shared. Ask for 25 fps and the demand is 5,038,848 × 25 × 8 ≈ 1.01 Gbit/s, past the physical line rate; packets drop and the node looks broken again. The decision: below roughly 0.8 Gbit/s of demand a shared gigabit port is fine, at or above it dedicate the port, and above the ~24.8 fps ceiling enable jumbo frames end to end or move to a 10GigE camera.

Hardware that removes the variables

Intermittent versions of this fault — a hang that comes and goes with vibration — are connector problems, not code problems. A screw-lock cable removes that variable:

The locking hardware is the point; browse the camera cable range for other lengths and connector styles. For the camera, match the sensor to what one link can carry — a small global-shutter camera for quick bring-up and moving parts, a 6 MP mono camera when pixels matter more than frame rate:

Specification MV-CU020-90GC MV-CT0MG0060/R/NN/NN
Sensor type CMOS, global shutter CMOS, rolling shutter
Sensor model GMAX4002 Sony IMX178
Pixel size 4 μm × 4 μm 2.4 μm × 2.4 μm
Sensor size 1/1.7" 1/1.8"
Resolution 2048 × 1200 3072 × 2048
Max. frame rate 49 fps @ 2048 × 1200 Bayer GB 8 19.5 fps @ 3072 × 2048 Mono 8
Dynamic range 66.9 dB 71.3 dB
SNR 40.8 dB 41.3 dB
Gain 0 dB to 11.1 dB 0 dB to 24 dB
Exposure time 4 μs to 10 sec 25 μs to 3.1 sec
Exposure mode Off/Once/Continuous exposure mode Off/Once/Continuous exposure mode, supports Rolling and Global Reset
Pixel format Bayer GB 8/10/10Packed/12/12Packed Mono 8/10/10Packed/12/12Packed
Price $309.00 $909.00

All 2 share: Binning Supports 1 × 1, 2 × 2, 4 × 4; Decimation Supports 1 × 1, 2 × 2, 4 × 4; Lens mount C-mount; Humidity 20% RH to 95% RH (no condensation); Compatibility GigE Vision V2.0, GenICam; Certification CE, RoHS, KC. Values as printed in each product's data sheet; open a part for its drawing and full specifications.

At 6 MP you already sit near the single-link ceiling from the worked example, so filter the area scan cameras by interface — the camera finder lists 10GigE and CoaXPress models — or let the system configurator walk camera, lens and light in one pass.

When the stream is healthy and the image is black

After the hang is fixed, frames can flow with image_raw still dark. Read the exposure before touching anything else. A 20 µs shutter tuned for a strobed light collects almost nothing under room lighting, so the published frame is black and correct. Either open the exposure into milliseconds under continuous light, or keep the short exposure and fire a strobed light inside the window, driven from a strobe-capable controller:

Light controllersDigital control box, 4 ch, 200 W, RS232 (LS-CTL-0070)LS-CTL-0070
Output
Constant voltage 24 V
Channels
4 channels
Control
Digital
Feature
Strobe
$549.00View partBuild a system with it

The exposure-control corner cases are covered from both ends by Cap the maximum auto exposure time to stop motion blur and Camera has no software exposure control: what to do instead; the strobing hardware sits in the light controllers range.

Checklist: the bring-up order that avoids the hang

  • Close arv-viewer and anything else holding the camera.
  • Launch the node with the debug variable already in its environment.
  • Set the viewer's working packet size before the stream is created.
  • Prove the path with ping -M do -s 1472 <camera-ip>.
  • Create the stream, queue buffers, then start acquisition — in that order.
  • Wait with a 1 to 2 second timeout and log every timeout.
  • Pull buffers from the queue in your own thread, or service the library's event loop.
  • Allow UDP 3956 and the negotiated stream port through the firewall.
  • Cap a 5 MP Mono8 stream at 20 fps on one gigabit link.

More integration-fault patterns are collected on the systems topic page. If the debug log still shows zero packets with every box ticked, send it through the contact page and the applications team will read it with you.

Questions

Why does arv-viewer show video when my ROS node hangs?

The viewer quietly does three jobs your node must do itself: it negotiates a packet size the link can carry, it keeps the library's event loop running so stream callbacks fire, and it takes the device exclusively. If arv-viewer only streamed after you lowered the packet size, set that same value in the node before the stream is created. Copy the viewer's working configuration rather than trusting camera defaults.

What packet size should a GigE camera use on a standard network?

1484 bytes on a standard network with the default MTU. That value leaves room for the GVSP, IP and UDP headers inside a standard Ethernet frame, and it is what the viewer accepted in this failure. Raise the packet size only when the camera, the switch and the PC network card all carry jumbo frames end to end, and prove the new path with the GigE Vision test-packet exchange first.

How many buffers should the ROS node queue on the stream?

Start at 8. One buffer proves a frame, but the camera stalls the moment your publisher thread is busy, and a stalled camera looks like the original hang again. Eight buffers of a 5 MP Mono8 frame hold about 0.4 s of images at 20 fps, enough slack for a slow subscriber without hiding real faults. Never queue zero buffers: with nowhere to write, the camera sends nothing.

Frames arrive but image_raw is black. Is that the same fault?

No. If the debug log shows buffers being consumed, transport is proven and the exposure is wrong. A 20 µs shutter tuned for a strobed light gives a black frame under room lighting, because the sensor integrates almost nothing during the cycle. Open the exposure into milliseconds with continuous light, or keep it short and fire a strobed light inside the exposure window instead.

When does the camera need a dedicated network card?

Above roughly 80% of the link rate. One 5 MP Mono8 camera at 15 fps draws about 0.6 Gbit/s and can share an office network; at 20 fps it reaches about 0.8 Gbit/s and every co-tenant starts costing you frames. Give two cameras, or any 10GigE camera, a dedicated card and switch port from the start.