How to detect Glass with vl53l8cx histogram data
Hello everyone,
I am currently working with the VL53L8CX sensor to explore solutions for a specific use case. In particular, I am trying to detect glass material using the CNH (Compacted Normalized Histogram) data—more about this can be found under the topic: Artificial Intelligence Enabler .
From my research, I understand that the sensor generates a total of 121 histogram bins. However, due to constraints such as memory limitations, only 18 or 24 bins can be accessed, depending on the configuration used.
I started by configuring the sensor to retrieve the first 24 bins and set the subsample value to "1", so that each bin corresponds to a single zone. Then, I attempted to determine the first significant return using an interpolation algorithm I found online. According to the documentation, I multiplied the resulting value by 3.75 to obtain the actual distance.
def interpolate_bin(signal_values, ambient_light_level):
for i in range(len(signal_values) - 1):
if signal_values[i] < ambient_light_level <= signal_values[i + 1]:
interpolated_bin = i +1+ (ambient_light_level - signal_values[i]) / (signal_values[i + 1] - signal_values[i])
return interpolated_bin
return NoneHowever, when I hold a glass material in front of the sensor and apply this method, I don’t get convincing results. Therefore, I would like to know if I might be missing some details, or perhaps I am using the wrong method to compute the First Significant Bin (FSB).
Below is my VL53L8CX code:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
//UartComm_Restart();
//__________MY CODE ___________
Reset_Sensor();
p_dev.platform.address = VL53LMZ_DEFAULT_I2C_ADDRESS;
if (status != VL53LMZ_STATUS_OK){
printf("vl53lmz_init failed : %d\n");
return status;
}
/* (Mandatory) Initialise the VL53LMZ sensor */
status = vl53lmz_init(&p_dev);
if(status)
{
printf("VL53LMZ ULD Loading failed\n");
return status;
}
printf("VL53LMZ ULD ready ! (Version : %s)\n",
VL53LMZ_API_REVISION);
status = vl53lmz_set_resolution(&p_dev, 16);
status |= vl53lmz_set_ranging_mode(&p_dev, VL53LMZ_RANGING_MODE_AUTONOMOUS);
status |= vl53lmz_set_ranging_frequency_hz(&p_dev, 5);
status |= vl53lmz_set_integration_time_ms(&p_dev, 100);
if(status)
{
printf("ERROR - Failed basic configuration sequence, status=%u\n", status);
return status;
}
status = vl53lmz_cnh_init_config( &cnh_config,
0, /* StartBin */
24, /* NumBins */
1); /* SubSample */
if (status != VL53LMZ_STATUS_OK){
printf("VL53LMZ CNH init config failed\n");
return status;
}
status = vl53lmz_cnh_create_agg_map( &cnh_config,
16, /* Resolution. Must match value used in vl53lmz_set_resolution() */
0, /* StartX */
0, /* StartY */
1, /* MergeX */
1, /* MergeY */
4, /* Cols */
4); /* Rows */
if (status != VL53LMZ_STATUS_OK){
printf("VL53LMZ CNH set aggregate map failed\n");
return status;
}
status = vl53lmz_cnh_calc_required_memory( &cnh_config, &cnh_data_size );
if (status != VL53LMZ_STATUS_OK){
printf("VL53LMZ CNH calc required memory failed\n");
if (cnh_data_size < 0){
printf("Required memory is too high : %d. Maximum is %d!\n", (int)-cnh_data_size, (int)VL53LMZ_CNH_MAX_DATA_BYTES);
}
return status;
}
/* Send this CNH configuration to the sensor. */
status = vl53lmz_cnh_send_config(&p_dev,&cnh_config);
if (status != VL53LMZ_STATUS_OK){
printf("VL53LMZ CNH send config failed\n");
return status;
}
/* First create the standard data upload(output) configuration. */
status = vl53lmz_create_output_config(&p_dev);
if (status != VL53LMZ_STATUS_OK){
printf("VL53LMZ CNH create output config failed\n");
return status;
}
/* Next, add the CNH data block, sized correctly for the configuration we are using. */
union Block_header cnh_data_bh;
cnh_data_bh.idx = VL53LMZ_CNH_DATA_IDX;
cnh_data_bh.type = 4;
cnh_data_bh.size = cnh_data_size / 4;
status = vl53lmz_add_output_block(&p_dev, cnh_data_bh.bytes);
if (status != VL53LMZ_STATUS_OK){
printf("VL53LMZ CNH add output block failed\n");
return status;
}
status = vl53lmz_send_output_config_and_start(&p_dev);
printf("Started ranging\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// __________________ MY CODE _______________
status = vl53lmz_check_data_ready(&p_dev, &isReady);
if (isReady)
{
vl53lmz_get_ranging_data(&p_dev, &Results);
wait_for_dma_to_complete();
printf("Print data no : %3u\n", p_dev.streamcount);
for (int i = 0; i < 16; i++) {
if (Results.target_status [VL53LMZ_NB_TARGET_PER_ZONE * i] != 0) {
printf("Zone : %3d, Status : %3u, Distance : %4d mm\n", i,
Results.target_status[VL53LMZ_NB_TARGET_PER_ZONE * i],
Results.distance_mm[VL53LMZ_NB_TARGET_PER_ZONE * i]);
}
else {
// Wenn keine Ziele erkannt wurden
printf("Zone %d: No target detected.\r\n", i);
}
}
status = vl53lmz_results_extract_block(&p_dev, VL53LMZ_CNH_DATA_IDX, (uint8_t *)cnh_data_buffer, cnh_data_size);
if (status != VL53LMZ_STATUS_OK)
{
printf("ERROR at %s(%d) : vl53lmz_results_extract_block failed : %d\n", __func__, __LINE__, status);
return status;
}
for (agg_id = 0; agg_id < cnh_config.nb_of_aggregates; agg_id++)
{
vl53lmz_cnh_get_block_addresses(&cnh_config,
agg_id,
cnh_data_buffer,
&(p_hist), &(p_hist_scaler),
&(p_ambient), &(p_ambient_scaler));
amb_value = ((float)*p_ambient) / (2 << *p_ambient_scaler);
printf("Agg, %2d, Ambient, % .1f, Bins, ", agg_id, amb_value);
for (bin_num = 0; bin_num < cnh_config.feature_length; bin_num++)
{
bin_value = ((float)p_hist[bin_num]) / (2 << p_hist_scaler[bin_num]);
printf("% .1f, ", bin_value);
}
printf("\n");
}
}
// Wait a few ms to avoid too high polling
WaitMs(&(p_dev.platform), 10);
}
}
Here is an example of my CNH data when I hold a glass sheet approximately 37 cm in front of the sensor. However, when I apply the method described above, I get a result between 34 cm and 35 cm—which is clearly inaccurate.
measurements2 = [
{"Agg": 0, "Ambient": 3.1, "Bins":[ -3.1, -3.1, -3.1, -3.1, -3.1, -3.1, -3.1, -1.4, -0.3, 26.8, 83.1, 105.6, 116.3, 122.1, 122.9, 125.4, 123.1, 73.9, 36.0, 22.9, 18.6, 16.3, 15.3, 12.6]},
{"Agg": 1, "Ambient": 3.6, "Bins":[ -3.6, -3.6, -3.6, -3.6, -3.6, -3.6, -3.6, -0.6, 3.8, 58.5, 108.8, 136.7, 147.8, 155.7, 159.4, 159.8, 137.5, 71.5, 36.0, 21.5, 12.6, 7.9, 5.9, 5.1 ]},
{"Agg": 2, "Ambient": 3.9, "Bins":[-3.9, -3.9, -3.9, -3.9, -3.9, -3.9, -2.4, 0.2, 5.9, 57.0, 103.1, 124.9, 140.1, 146.6, 152.9, 151.9, 126.5, 71.3, 40.0, 23.4, 13.6, 8.1, 5.6, 3.6]},
{"Agg": 3, "Ambient": 3.3, "Bins":[ -3.3, -3.3, -3.3, -3.3, -3.3, -3.3, -3.3, -1.0, 1.4, 13.8, 52.6, 81.1, 99.5, 109.1, 112.9, 115.5, 113.4, 87.0, 50.5, 29.7, 18.0, 10.3, 6.8, 3.6]},
{"Agg": 4, "Ambient": 4.5, "Bins":[ -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -4.5, -2.1, 1.9, 69.1, 137.8, 168.6, 181.0, 181.0, 181.4, 185.5, 162.3, 72.5, 28.1, 14.7, 8.5, 5.6, 4.0, 3.3]},
{"Agg": 5, "Ambient": 4.8, "Bins":[ -4.8, -4.8, -4.8, -4.8, -4.8, -4.8, -4.3, -1.6, 15.3, 141.9, 219.9, 256.7, 277.3, 272.9, 282.1, 274.0, 209.6, 81.4, 36.1, 17.5, 9.4, 6.6, 4.5, 4.2]},
{"Agg": 6, "Ambient": 4.9, "Bins":[ -4.9, -4.9, -4.9, -4.9, -4.9, -4.9, -2.5, -0.8, 16.5, 112.9, 175.8, 203.8, 217.5, 224.1, 223.2, 222.5, 166.6, 70.9, 31.5, 15.7, 9.4, 7.0, 5.2, 4.6]},
{"Agg": 7, "Ambient": 4.6, "Bins":[ -4.6, -4.6, -4.6, -4.6, -4.6, -4.6, -3.6, -0.9, -0.3, 34.1, 99.6, 134.6, 154.5, 158.8, 158.4, 158.0, 152.7, 94.3, 38.2, 17.1, 9.5, 6.1, 3.8, 3.3]},
{"Agg": 8, "Ambient": 4.7, "Bins":[ -4.7, -4.7, -4.7, -4.7, -4.7, -4.7, -4.5, -1.7, -0.8, 51.4, 119.6, 152.1, 161.1, 170.0, 170.2, 172.1, 153.9, 78.4, 29.1, 13.4, 7.4, 3.8, 2.8, 2.4]},
{"Agg": 9, "Ambient": 5.0, "Bins":[ -5.0, -5.0, -5.0, -5.0, -5.0, -5.0, -3.2, -1.0, 11.6, 107.0, 166.8, 195.9, 207.2, 213.8, 214.7, 213.7, 159.8, 65.6, 27.3, 13.4, 7.3, 4.9, 4.1, 3.2]},
{"Agg": 10, "Ambient": 5.1, "Bins":[ -5.1, -5.1, -5.1, -5.1, -5.1, -5.1, -2.8, -0.6, 8.6, 89.5, 150.3, 177.8, 189.4, 192.4, 191.4, 193.0, 151.9, 65.4, 27.6, 14.1, 7.7, 4.8, 3.6, 3.2]},
{"Agg": 11, "Ambient": 4.8, "Bins":[ -4.8, -4.8, -4.8, -4.8, -4.8, -4.8, -3.3, -0.8, -0.3, 22.7, 85.2, 119.6, 135.8, 141.8, 144.6, 144.7, 142.4, 94.7, 40.1, 18.0, 8.2, 4.8, 3.8, 3.1]},
{"Agg": 12, "Ambient": 5.2, "Bins":[ -5.2, -5.2, -5.2, -5.2, -5.2, -5.2, -4.0, -1.1, 0.2, 13.8, 72.1, 114.3, 131.4, 139.2, 138.8, 141.4, 135.3, 103.6, 44.3, 17.6, 8.9, 4.5, 2.7, 2.0]}]
I’m wondering if I might be missing a step in the CNH processing or if there’s a better approach to accurately detect transparent materials like glass using this sensor. Any insights, suggestions, or corrections would be greatly appreciated!
