ArduCAM B0410 ToF depth readings unstable at 2m on Raspberry Pi 3B+

Hi all, I’m evaluating the ArduCAM ToF Camera B0410 for Raspberry Pi / Jetson Nano on a Raspberry Pi 3B+ using the provided ./compile.sh program. I need to check depth measurement stability on a static scene, but the device is intermittent and unstable. Total pixels are reported as 43200. Has anyone else worked with this camera and seen unstable depth values?

Welcome to the forum. Can you describe exactly how the demo is taking the depth measurement? In the compile.sh program, the depth is usually averaged over an 8x8 pixel area when the left-click mouse event is true and the cursor is inside the preview image. Also, what actual distance is your target at?

Right, that matches what I see. The program obtains the average depth value of 8x8 pixels when the left click is true and the cursor is in the preview image. I’m measuring a static target at a real effective distance of 2 m. Over 465 measurements I got min 1.1 m, max 1.977 m, average 1.500 m. The documented precision is +/-2 cm, so this is way off and the readings jump around. I’ve attached the test results document and two result screenshots.

Thanks for the data. A few things to check: which working range is the camera currently using? The default is often 4 m. Also, what does your call to getPreview() look like - are you using the preview pointer, phase image, or amplitude image? And what RequestFrame delay are you using? The 200 ms value is mentioned in the docs.

I have the same questions. The range seems to be set to 4 m by default, but I can’t find where to configure that parameter in the online git code. The call is getPreview(uint8_t *preview_ptr, float *phase_image_ptr, float *amplitude_image_ptr). Does it discriminate pixels that return wrong depth information? Also, what happens if I shorten the RequestFrame delay below the 200 ms stated in the docs?

Can you share the test program you’re using? That will help with the acceptance threshold and the stability calculation. The getPreview function gives you the preview, phase, and amplitude buffers, but it doesn’t by itself mark bad depth pixels - you usually have to use the amplitude buffer for that.

I’ve attached Static_acquisition.c. It first acquires an initial static environment, then does real-time acquisition of the same environment. It uses while loops with iteration count ITER_NB varied between 30 and 600. For each pixel it compares an acceptance margin against the absolute difference between the two acquisitions, and increments a counter when the absolute difference is greater than the acceptance margin. Stability (%) = counter / 43200. I’m trying to find the correct acceptance threshold, number of iterations, and RequestFrame time for reliability and speed.

That helps. How are you using AMPLITUDE_FRAME in this code? And what detection range are you currently averaging over - still 8x8?

AMPLITUDE_FRAME looks like a measure of the confidence level of the obtained data, so I’m trying to filter dirty data by judging the size of that value. The detection range is currently 8x8; increasing it to 16x16 makes the data more stable. For the general measurement method, I remove the maximum and minimum values and then take the average.

Good. What did you find when you changed the RequestFrame timeout and the acquisition times?

The RequestFrame timeout of 200 ms seems to be a reference only. The fixed frame rate is 30 fps, so it requires a minimum of about 34 ms waiting time. If the request time is too short, it can return nullptr because there isn’t enough time to collect and process frames. I also tried lengthening the acquisition times of the starting reference frame and the real-time acquisition and then averaging, but that was too time-consuming. For measuring an object at 2 m, I found the 4 m working range should be used.

Based on all of that, the large difference between the actual 2 m distance and the measured values is likely related to the material of the object being tested and the camera’s working range. If the request time is too short, it can return nullptr because there isn’t enough time to collect and process frames. The camera’s imaging can also receive interfered data, and AMPLITUDE_FRAME is the confidence level of the obtained data, so low-confidence pixels should be filtered.

Thanks. So should I set the working range to 4 m and switch the detection area to 16x16? Any guidance on how to combine the amplitude filtering with the trimmed average?

To summarize the current workaround: 1) check the material of the object being tested; 2) set/consider a 4 m working range when measuring at 2 m; 3) don’t treat the 200 ms timeout as a hard minimum - the camera is fixed at 30 fps and needs at least about 34 ms, but too short a request can return nullptr; 4) remove the maximum and minimum values and average the rest; 5) filter dirty/interfered data by judging the AMPLITUDE_FRAME value; 6) increase the detection range from 8x8 to 16x16 to make the data more stable. Try those together and report back with the stability numbers you get.