3D visionTroubleshooting

RGB-D SLAM odometry drops to zero: fix ignored images and replay

Why RGB-D SLAM odometry drops to zero, why images are ignored, how fast to move the camera, enabling gyro and accel topics, and bag replay without TF errors.

LumaSpec Vision11 min read Share on LinkedIn

On this page 10 sections
  1. 01What the "image ignored" message actually means
  2. 02Causes in order of probability
  3. 03Worked example: walking speed at 30 fps at a 1 m standoff
  4. 04The fix sequence, in order
  5. 05Replaying the bag: sim time and the map frame
  6. 06Recording: RViz is optional, 89 GB is not
  7. 07When visual odometry keeps failing
  8. 08If the camera is the ceiling: parts to shortlist
  9. 09Checklist before the next mapping run
  10. 10Questions

Your mapping run starts well: odometry quality values scroll past, the cloud builds, then quality falls to 0 and the log repeats "RGB-D SLAM mode is enabled, memory is incremental but no odometry is provided. Image 76684 is ignored!" Later, the bag you recorded plays back into RViz with "Fixed Frame [map] does not exist". This guide treats the two as one chain of causes. The case behind it: a handheld stereo depth camera with a built-in IMU on a small embedded board, SDK 2.0, camera wrapper past version 2.2.15. You will read what the message means, the walking speed that keeps tracking alive, the launch arguments that restore odometry, and the replay sequence that publishes the map frame.

What the "image ignored" message actually means

RTAB-Map splits the work between two nodes. The odometry node tracks image features and publishes a pose; the mapping node turns accepted frames into a graph. In the odometry debug view, frame-to-frame links (F2F) are drawn green and frame-to-map matches (F2M) red. When matching fails, no usable pose goes out, quality reads 0, and the mapping node answers every new frame with "no odometry is provided", then drops it.

The ignored number (76684 here) is the image sequence counter, so a large value only means the session ran a long time before tracking died. "Memory is incremental" describes the graph's memory management; it is status text, not part of the fault. Odometry also resets each time a mapping session starts, so the first cloud of a handheld scan sitting misaligned against the map is normal, not damage.

Causes in order of probability

What you see Likely cause Quick test Fix
Quality falls during fast walking or a quick pivot Motion outruns feature matching at 30 fps Walk the same route at half speed Stay under about 0.5 m/s at 1 m (worked example below)
Quality 0 facing blank walls or a long corridor Too few corner features to match Feature overlay shows few, clustered dots Reroute past cluttered, textured surfaces
Quality 0 from the first image Gyro, accel and infrared streams never started (wrapper 2.2.15 and newer) rostopic list shows no gyro, accel or infra topics Relaunch with enable_gyro:=true enable_accel:=true enable_infra:=true
Tracking stalls in bursts, bag has time gaps The board drops frames, processing slower than acquisition rostopic hz on the depth topic shows dips Close RViz, drop resolution, fix the acquisition faster than processing gap
Live view smeared while moving Exposure too long, motion blur Freeze on a static target and check sharpness Cap exposure near 10 ms; see depth camera frame rate drops when exposure caps the FPS

The first row was confirmed in this case: walking the route again at half speed brought the quality values back and the sequence never broke. It is the cheapest test you can run, so run it first.

The second cause to rule out is the wrapper change. From ROS wrapper version 2.2.15 onward, the plain tracking launch no longer starts the gyro, accel and infrared streams, so the SLAM tutorial's launch line needs the three enable arguments appended, live and offline alike; on older wrappers they started with the plain launch. If the infrared streams stay absent even when enabled, the fault sits upstream of odometry, and stereo camera works for RGB but no depth: fix missing mono sensors covers that path.

Worked example: walking speed at 30 fps at a 1 m standoff

Inputs, each with its source:

  • Depth and infrared streams: 848 × 480 at 30 fps, the handheld-SLAM mode of compact stereo depth cameras (typical for this camera class).
  • Horizontal field of view: about 87°.
  • Scene standoff: 1 m, mid-range of the 0.5–2 m a corridor or room gives you.
  • Matching budget: keep feature displacement under about 1% of frame width per frame, 8 px on this sensor; a working rule of thumb, not a hard constant.
  • Exposure while walking indoors: about 10 ms.

The rule in words: convert field of view to a focal length in pixels, then convert camera motion into pixels of feature shift per frame.

f_px = (W / 2) / tan(HFOV / 2) shift_px = v × f_px / (rate × Z) v_max = shift_max × rate × Z / f_px

The arithmetic:

  • f_px = (848 / 2) / tan(87° / 2) = 424 / tan(43.5°) = 424 / 0.949 ≈ 447 px, call it 450 px.
  • v_max = 8 × 30 × 1.0 / 450 = 240 / 450 ≈ 0.53 m/s.
  • Travel per frame at that speed: 0.53 / 30 ≈ 0.018 m, about 18 mm.
  • Blur at 10 ms exposure: 0.5 m/s × 0.010 s = 5 mm of travel in one exposure, which smears features by 5 / 1000 × 450 ≈ 2.3 px.

The decision: walk at half a metre per second or slower at 1 m standoff. The limit scales with distance, so 8 × 30 × 0.5 / 450 ≈ 0.27 m/s at 0.5 m, and 8 × 30 × 2.0 / 450 ≈ 1.1 m/s at 2 m. It scales with frame rate, not resolution: 60 fps would double every speed above. A pivot is pure rotation and has no distance term, so the same 8 px budget caps turning at 8 × 30 / 450 ≈ 0.5 rad/s, about 30°/s. For why the depth image sees less ground than the RGB frame at these angles, read depth image field of view: why stereo coverage is smaller.

The fix sequence, in order

  1. Relaunch the tracking launch (opensource_tracking.launch in this setup) with enable_gyro:=true enable_accel:=true enable_infra:=true appended. Required from wrapper 2.2.15 onward.
  2. Confirm the streams exist: rostopic list should show gyro, accel and both infrared topics, and rostopic hz on one infrared topic should read about 30 Hz.
  3. Walk the route at the speed limit from the worked example while a second person watches the quality values; they should recover and stay non-zero.
  4. If quality still collapses at one spot, change the route past doors, shelves and posters rather than blank corridor walls.
  5. On an embedded board, close RViz while mapping. It is only a subscriber, and every subscriber costs CPU.
  6. Record the bag with only the topics the SLAM node consumes, so replay carries the same streams.

Replaying the bag: sim time and the map frame

Replay publishes recorded topics, and nodes in offline mode consume them on simulated time. Set use_sim_time before playing and pass --clock so the bag publishes /clock; without it every node believes time is frozen and nothing processes.

roscore >/dev/null 2>&1 &
rosparam set use_sim_time true
rosbag play my_bagfile_1.bag --clock

Then start the same tracking launch you used live, adding offline:=true enable_gyro:=true enable_accel:=true enable_infra:=true.

The map frame does not exist until the SLAM node publishes the map → odom → camera transforms, which needs working odometry. A "Fixed Frame [map] does not exist" warning for the first seconds of replay is normal; one that persists means the inputs never started, and the most common reason is the enable arguments missing from the offline launch, row 3 of the table again. If the wrapper publishes the streams but odometry still never starts, the bag itself may not contain what you enabled, and no launch line can repair a recording: re-record with the streams running. For the wider diagnosis, read RViz fixed frame does not exist: pick a real TF frame, and for what replay timing does to trajectories, the motion replay timing and odometry walkthrough is a solid reference.

Recording: RViz is optional, 89 GB is not

rosbag record writes whatever is published; RViz only subscribes. Recording with RViz open adds CPU load on the board and nothing else, so close it. The size math for the streams this node consumes: 848 × 480 px × 2 B = 0.81 MB per depth frame, × 30 fps ≈ 24 MB/s; each 8-bit infrared stream adds about 12 MB/s; the total is roughly 49 MB/s, about 176 GB per hour. The 89 GB file from this case is half an hour at full rate. Record depth, both infrared streams, gyro, accel and the camera TF, and leave colour out unless the pipeline uses it.

Two deeper references: ROS image transport recording: keep depth data reliable for keeping depth intact through transport, and stereo camera recording for visual SLAM: the offline workflow for a full capture-to-replay routine. If frames drop while the SDK writes its own bag, the frame drops inside .bag recordings guide covers where they go and how to spot them.

When visual odometry keeps failing

If the route forces fast motion or long featureless views, stop asking the camera for odometry. RTAB-Map accepts an external source: a wheel-encoder /odom, with visual odometry disabled, lets the node build a 2D (3-DoF) map from loop closure and image features alone. Publish the encoder pose as TF from odom to base_link and let the images carry appearance, not motion. The wheel encoder odometry feeding SLAM guide walks through that configuration end to end. If instead your odometry node starts and then starves, RGB-D odometry stuck waiting for the IMU covers the missing-message case.

If the camera is the ceiling: parts to shortlist

When the sensor, not the software, sets the limit (a fixed projector-camera cycle, an IMU the wrapper exposes poorly), a structured-light stereo camera is the natural replacement class for handheld mapping. The MV-DPS200P-02 is a projected structured-light 3D camera, the MV-DLS300P-04 a laser galvanometer stereo camera, and the MV-DT01WMU a Time-of-Flight camera for depth at ranges where stereo texture fades:

3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote
3D sensorsHikrobot MV-DLS300P-04 Laser galvanometer stereo cameraMV-DLS300P-04
Type
Stereo / structured light
$16,579.00 · quotedView and quote
3D sensorsHikrobot MV-DT01WMU ToF sensing cameraMV-DT01WMU
Type
Depth / ToF camera
Price on requestView and quote

Browse 3D sensors or the camera finder for the full range. Remember the depth stream is already near-infrared: surfaces that look blank in visible light often carry texture in the infra image, one more reason those topics matter. For imaging beyond the visible band, see infrared cameras.

To measure your own speed limit on the bench instead of by feel, mount the camera on the LS-MNT-0040, a professional slide-table stand with height 700 mm and a 400 x 450 mm base. Slide it a known distance in a timed pass and watch the quality value; that pass is your calibration. More options in camera stands or through the stand configurator step.

Camera standsMachine vision camera stand, professional slide-table type, height 700 mm, 400 x 450 mm base (LS-MNT-0040)LS-MNT-0040
Type
Camera stands
$629.00View partBuild a system with it

Checklist before the next mapping run

  • enable_gyro:=true enable_accel:=true enable_infra:=true in the launch, live and offline, from wrapper 2.2.15 onward.
  • Speed under about 0.5 m/s at 1 m standoff, scaled by distance; pivots under about 30°/s.
  • Route past textured surfaces, with a fallback plan for blank corridors.
  • Exposure capped near 10 ms so motion smear stays around 2 px.
  • RViz closed during mapping and recording; it is a viewer, not a participant.
  • Bag records only the consumed topics: depth, both infra streams, gyro, accel, TF.
  • use_sim_time true and --clock on the play command before the launch starts.

If quality still collapses with all of this in place, record 30 seconds of depth, both infrared streams, gyro and accel, and send the bag with your launch line through the contact page. More depth-camera debugging lives on the 3D vision topic page.

Questions

How do I keep the recorded bag from reaching 89 GB?

Record only the topics the node consumes (both infrared streams, depth, gyro, accel and the camera transforms) and use rosbag record --split with a duration such as 5m, so one long session becomes several files you can delete independently. Leave colour out unless the pipeline uses it. A 16-bit 848 × 480 depth stream alone runs about 24 MB/s, so one five-minute split file is roughly 7 GB.

Why does tracking fail part-way through a run instead of at the start?

Because the loss is progressive, not binary. Frame-to-frame matching holds while features overlap between views; a fast pivot or a featureless stretch starves it, quality decays to 0 and the mapper starts ignoring frames. Recovery does not need a relaunch: frame-to-map matching relocalizes against the local map and resets odometry when the view matches again, so stop moving, let the scene settle, then continue at half speed.

Should I raise the resolution to get more features?

No. Raise the frame rate first, because the safe speed scales with rate and not with resolution. More pixels raise per-frame processing cost on an embedded board, which can lower the effective rate, and pixel displacement grows with focal length, so your speed limit drops. If a high-resolution mode is unavoidable, increase GFTT/MinDistance so detected corners stay spread across the frame instead of clustering in one textured patch.

Why does replay fail when the live run worked?

Because replay can only publish streams the bag contains. The enable arguments turn on the wrapper's gyro, accel and infrared outputs, but if those topics were never recorded there is nothing to republish: odometry never starts and the map frame never exists. Run rosbag info on the file before debugging RViz frames, confirm every topic the launch expects is listed, and re-record with the streams running if any are missing.

Is a quick turn as bad as walking too fast?

Worse. Translation shifts features by speed × focal length / (rate × distance), so standoff protects you; a pivot has no distance term at all. At 450 px focal length and 30 fps, the 8 px per-frame budget caps rotation near 0.5 rad/s, about 30 degrees per second, at any range. Pivot slowly, or step around corners instead of spinning on the spot.