Following up with a live capture. The short version is that this is not a depth-mode
problem at all, and both of the hypotheses in your last reply are ruled out by the same
measurement. I owe you a correction on one of my own claims too.
Setup unchanged: ZED Box Mini (Orin NX, JetPack 6.2 / L4T 36.4), ZED 2i over USB,
pyzed, SDK 5.2.3, HD1080@30, DEPTH_MODE.NEURAL, positional tracking
set_as_static=True, object detection MULTI_CLASS_BOX_FAST.
We caught it at 05:18 on 2026-09-09 and deliberately let it run for 3 hours 40 minutes
with our auto-restart disabled, so everything below is from a single sustained occurrence
rather than inference after the fact.
The image buffers come back zero-filled
The left image, written by the SDK itself via Mat::write() rather than by any code of
ours, is uniform RGB(0,134,0) across all 2,073,600 pixels. Not one pixel differs.
That value is the giveaway: an all-zero YUV frame (Y=U=V=0) converted through BT.601 gives
R=0, G=135, B=0. So what we are being handed is an uninitialised image buffer, while
grab() continues to return SUCCESS.
retrieve_measure(MEASURE::DEPTH) at the same moment is 99.94% NaN. The 0.06% that is
finite all sits between 0.39 m and 0.88 m, which is noise rather than scene.
Depth is therefore not falling back to a cheaper mode. There is no image behind it. And the
frame rate rises (14.9 to 25) for the same reason: processing nothing is fast.
Every other signal reads healthy, and the camera goes blind
Throughout the whole 3h40m, with a person standing in view:
grab() returns SUCCESS, grab_errors 0
retrieve_objects() returns SUCCESS, od_errors 0
- positional tracking state OK, floor plane still locked
camera_ok true, camera still enumerated normally as 2b03:f880
- object detection returned nothing at all: our raw pre-filter detection counter sat
frozen for the entire period while somebody stood in front of the camera
So the practical consequence is total blindness with no error surfaced anywhere. That also
resolves an inconsistency in my own reports: my July description (zero people detected
while people are present) was correct, and a later message where I said object detection
kept working normally was wrong.
Your two hypotheses, both ruled out
Not a video-mode renegotiation. We now log
get_camera_information().camera_configuration at open and re-read it every 2 s. At
bring-up: 1920x1080 @ 30. During the fault: 1920x1080 @ 30, unchanged. No
renegotiation occurred.
Not duplicated or stale frames. get_timestamp(TIME_REFERENCE::IMAGE) deltas went from
67 ms healthy to 34 ms during the fault, with zero repeated timestamps across the
sampling window. The pipeline genuinely is producing more frames. They are just empty.
The trigger, three for three
async_grab_camera_recovery=True made this observable in-band, which was the single most
useful suggestion from your last reply. The sequence is now identical on all three
occurrences we have instrumented:
05:18:21 grab() returns CAMERA_REBOOTING
05:18:22 [Grab] Camera module reset
05:18:27 [Grab] Automatic recovery from image capture failure succeeded.
05:18:28 frame rate jumps; every frame from here is blank
Underneath it, the kernel shows a full re-enumeration, with the HID interface dropping
before the video interface:
05:18:22 usb 1-2.2: USB disconnect, device number 11 (HID, 12 Mbps, bus 1)
05:18:23 usb 2-1: USB disconnect, device number 10 (video, 5 Gbps, bus 2)
05:18:23 usb 2-1: new SuperSpeed USB device number 11 using tegra-xusb
05:18:26 uvcvideo 2-1:1.1: Non-zero status (-71) in video completion handler
So the shape of it is: USB re-enumeration, your internal recovery reports success, and from
that moment the capture buffers are zero-filled. Our reading is that the recovery re-opens
the device but the image buffers are never re-bound to the new handle. You will know
whether that is plausible.
A correction: enable_image_validity_check DOES catch this
In my first post I said it does not. That was wrong, and I want to withdraw it clearly
because it matters. With enable_image_validity_check = 1, at the exact fault boundary:
05:18:00 low_image_quality=false low_depth_reliability=false
05:19:00 low_image_quality=TRUE low_depth_reliability=TRUE (held for 3h40m)
low_lighting stayed false throughout, correctly. So your own diagnostic flags this
within a minute. We had been journalling those fields for months without alerting on them.
We now restart on it and the fault self-heals in about a minute.
The cure is a process restart, nothing more
Restarting our process clears it completely, and all five signals return together: frame
rate 25 to 14.9, valid depth pixels 0.001 to 0.912, image timestamp interval 34 ms to
67 ms, and both validity flags back to false. We have never needed
sl::Camera::reboot(), usbreset, a power cycle or physical access for this fault.
Questions
- Why does the internal recovery leave the image buffers zero-filled? If the recovery
re-opens the device without re-binding capture buffers, that would explain everything
here, and it sounds fixable.
- Can
grab() be made to report this? Right now an application has no return code to
act on: SUCCESS with an empty buffer is indistinguishable from SUCCESS with a picture.
Given the validity check already knows, could that state surface as an ERROR_CODE, or
is polling get_health_status() after every grab the intended pattern?
- Is this the same root cause as the ZED X frozen-frame report linked in my first post?
Both are the image pipeline returning invalid frames while reporting success. Ours are
blank rather than stale, but the family looks the same.
- Would you like the artifacts? We have the SDK-written left image and depth map, the raw
depth array, lsusb -t, the kernel window and the service journal across the boundary.
Finally, this thread’s title is now misleading. Nothing about the depth mode changes.
Happy to open a new thread with an accurate title if that helps the SDK team, or to leave
this one as the record. Your call.