VL53L1X region of interest (ROI)

Hi,
I am trying to add the configurable region of interest from the ST API into your library. I’m hoping to use it to narrow the field of vision for a certain project that involves measuring inside a narrow tube. From what I understand this can be programmed to reduce the detection cone to a 15 degree field of vision.

However I think I bit off more than I can chew, I find the ST API really confusing and I need help as to how I can add this in.

This is from the ST API header file:

/** @defgroup VL53L1_ROI_group VL53L1 ROI Functions
 *  @brief    Functions used to select ROIs
 *  @{
 */

/**
 * @brief Set the ROI  to be used for ranging
 *
 * @par Function Description
 * The user defined ROI is a rectangle described as per the following system
 * from the Top Left corner to the Bottom Right corner.
 * <br>Minimal ROI size is 4x4 spads
 * @image html roi_coord.png
 *
 * @param   Dev                      Device Handle
 * @param   pUserROi                 Pointer to the Structure definining the ROI
 * @return  VL53L1_ERROR_NONE            Success
 * @return  "Other error code"           See ::VL53L1_Error
 */
VL53L1_Error VL53L1_SetUserROI(VL53L1_DEV Dev,
		VL53L1_UserRoi_t *pUserROi);

/**
 * @brief Get the ROI managed by the Device
 *
 * @par Function Description
 * Get the ROI managed by the Device
 *
 * @param   Dev                   Device Handle
 * @param   pUserROi                 Pointer to the Structure definining the ROI
 * @return  VL53L1_ERROR_NONE            Success
 * @return  "Other error code"           See ::VL53L1_Error
 */
VL53L1_Error VL53L1_GetUserROI(VL53L1_DEV Dev,
		VL53L1_UserRoi_t *pUserROi);

/** @} VL53L1_ROI_group */

This is from the ST API cpp file:

/* Group ROI Functions */

VL53L1_Error VL53L1_SetUserROI(VL53L1_DEV Dev,
		VL53L1_UserRoi_t *pRoi)
{
	VL53L1_Error Status = VL53L1_ERROR_NONE;
	VL53L1_user_zone_t user_zone;

	Status = CheckValidRectRoi(*pRoi);
	if (Status != VL53L1_ERROR_NONE)
		return VL53L1_ERROR_INVALID_PARAMS;

	user_zone.x_centre = (pRoi->BotRightX + pRoi->TopLeftX  + 1) / 2;
	user_zone.y_centre = (pRoi->TopLeftY  + pRoi->BotRightY + 1) / 2;
	user_zone.width =    (pRoi->BotRightX - pRoi->TopLeftX);
	user_zone.height =   (pRoi->TopLeftY  - pRoi->BotRightY);
	if ((user_zone.width < 3) || (user_zone.height < 3))
		Status = VL53L1_ERROR_INVALID_PARAMS;
	else
		Status =  VL53L1_set_user_zone(Dev, &user_zone);

	LOG_FUNCTION_END(Status);
	return Status;
}

VL53L1_Error VL53L1_GetUserROI(VL53L1_DEV Dev,
		VL53L1_UserRoi_t *pRoi)
{
	VL53L1_Error Status = VL53L1_ERROR_NONE;
	VL53L1_user_zone_t	user_zone;

	Status = VL53L1_get_user_zone(Dev, &user_zone);

	pRoi->TopLeftX =  (2 * user_zone.x_centre - user_zone.width) >> 1;
	pRoi->TopLeftY =  (2 * user_zone.y_centre + user_zone.height) >> 1;
	pRoi->BotRightX = (2 * user_zone.x_centre + user_zone.width) >> 1;
	pRoi->BotRightY = (2 * user_zone.y_centre - user_zone.height) >> 1;

	LOG_FUNCTION_END(Status);
	return Status;
}



/* End Group ROI Functions */

And:

/* Check Rectangle in user's coordinate system:
 *	15	TL(x,y) o-----*
 *   ^			|     |
 *   |			*-----o BR(x,y)
 *   0------------------------- >15
 *   check Rectangle definition conforms to the (0,15,15) coordinate system
 *   with a minimum of 4x4 size
 */
static VL53L1_Error CheckValidRectRoi(VL53L1_UserRoi_t ROI)
{
	VL53L1_Error Status = VL53L1_ERROR_NONE;

	LOG_FUNCTION_START("");

	/* Negative check are not necessary because value is unsigned */
	if ((ROI.TopLeftX > 15) || (ROI.TopLeftY > 15) ||
		(ROI.BotRightX > 15) || (ROI.BotRightY > 15))
		Status = VL53L1_ERROR_INVALID_PARAMS;

	if ((ROI.TopLeftX > ROI.BotRightX) || (ROI.TopLeftY < ROI.BotRightY))
		Status = VL53L1_ERROR_INVALID_PARAMS;

	LOG_FUNCTION_END(Status);
	return Status;
}

This is the type definition structure for User ROI:

/** @brief Defines User Zone(ROI) parameters
 *
 */
typedef struct {

	uint8_t   TopLeftX;   /*!< Top Left x coordinate:  0-15 range */
	uint8_t   TopLeftY;   /*!< Top Left y coordinate:  0-15 range */
	uint8_t   BotRightX;  /*!< Bot Right x coordinate: 0-15 range */
	uint8_t   BotRightY;  /*!< Bot Right y coordinate: 0-15 range */

} VL53L1_UserRoi_t;


/** @brief Defines ROI configuration parameters
 *
 *  Support up a max of 16 zones, Each Zone has the same size
 *
 */

This is from the user manual:

Hi, mica.

We’re hoping to add that functionality to the library soon, but we don’t have any specific timeline for it. If the ROI is important, is using the API directly an option for you?

Kevin

Hi @kevin , apologies for the late reply and thanks for the response.
I don’t think I’ll be able to compile the entire API on my arduino, however I may give it a try

In case you haven’t seen it, we already have a version of the API adapted for the Arduino platform with an example sketch ready to compile and upload. It should easily fit on a standard Arduino like an Uno.

Kevin

I’ll give it a try, I actually hadn’t noticed that you’ve adapted the full API
Thanks

Hey,
how can I use the ROI in the ST API?
I have tried adding the following code from the Datasheet. But it doesnt work :frowning:

VL53L1_UserRoi_t roiConfig;
roiConfig.TopLeftX = 9;
roiConfig.TopLeftY = 13;
roiConfig.BotRightX = 14;
roiConfig.BotRightY = 10;
status = VL53L1_SetUserROI(&VL53L1Dev, &roiConfig);

Thank you! :slight_smile:

Hi, steevie.

We haven’t done much with setting up a ROI in the API, so if you still haven’t been able to get it to work, you might consider posting a question on the ST community site.

Kevin

Hi Kevin,
I still have not solved the Problem. To be honest my programming skills are not good enough to understand, what the ST API is doing. I just want to get it to work :wink:

Hi, mica, I would like to know if you could reduce the angle using Arduino, I’m trying the same. But it is a little confuse thank you

I recently got ROI working and wanted to share my experience in case someone finds it helpful. Start with https://github.com/pololu/vl53l1x-st-api-arduino as Kevin suggested–Pololu and ST have done 99.9% of the work for you. The code snippet quoted by steevie is correct, except that you have to modify the first argument to match Pololu’s VL53L1_Dev_t pointer variable name “Dev”–in fact the compiler complains about that when you try to compile it unaltered and you can see examples of “Dev” being used many times in the vl53l1x-st-api.ino setup code. That code snippet comes from pg 14 of ST’s API documentation https://www.st.com/content/ccc/resource/technical/document/user_manual/group0/98/0d/38/38/5d/84/49/1f/DM00474730/files/DM00474730.pdf/jcr:content/translations/en.DM00474730.pdf. Reading that doc while looking at vl53l1x-st-api.ino pretty much explains the ST library, which is not as insane as many make it out to be.

Note that the smallest legal ROI is 4X4, so that example isn’t the narrowest. Another subtlety is that you may be interested in narrowing the region of interest while having it remain aligned with the optical center, in which case you want to insert the following code snippet to find out what that is:

  VL53L1_CalibrationData_t calibrationData;
  status = VL53L1_GetCalibrationData(Dev, &calibrationData);
  Serial.print("VL53L1_GetCalibrationData returns ");
  Serial.println(status);
  Serial.print("Optical Center (x,y): ");
  Serial.print(calibrationData.optical_centre.x_centre/16.0);  //8 bit fixed point
  Serial.print(", ");
  Serial.println(calibrationData.optical_centre.y_centre/16.0);

Pick your ROI with that (x,y) close to the middle (note that it can’t be exactly in the middle unless both ROI dimensions are odd).

Yet another subtlety is that the lens flips the image (like a camera) and so you may be wondering where (0,0) is. If you are looking at printed side of the carrier with Pololu logo and pad labels right side up, then (0,0) is in the lower right of the field of vision. This orientation is horizontally flipped from the orientation you use to specify the ROIs top left and bottom right points; again, see page 14 in STs API doc. TopLeft has to be above and left of BottomRight or else VL53L1_SetUserROI does nothing and returns -4/illegal parameters.

Finally, in Pololu’s sketch’s loop, note that VL53L1_WaitMeasurementDataReady(Dev) blocks until data is ready, so you can’t do anything else in the loop while you’re waiting. Consider replacing it with:

  static uint8_t dataReady;

  status = VL53L1_GetMeasurementDataReady(Dev, &dataReady);
  if(dataReady == 1)
  {

which will make it behave more like Serial.available();

3 Likes

Well that’s really cool.

But I don’t understand what the first line of the snippet does (VL53L1_CalibrationData_t calibrationData;)

Really, I’m looking for code to extract all calibration data, save it to host, and load it back to the sensor would be ideal.

I’m wearing myself out and I know it can’t be that hard, not much experience with data structures.

Thanks a bunch
Randy

Just as int robotCount; declares a variable of type int named robotCount, VL53L1_CalibrationData_t calibrationData; declares a variable of type VL53L1_CalibrationData_t named calibrationData. That type is a struct that is defined in vl53l1_def.h. A struct is just a compound variable composed of other named variables called fields. You access each field of a struct using the dot notation shown in that snippet. Read up on c or c++ structs; for your purposes they’re the same in both languages and not so hard. They’re certainly easier than data structures (lists, trees, stacks, hashmaps…) which are a different thing.

Whenever you see a function named getBlahDeBlah() there is likely a sibling function named setBlahDeBlah(). You can read about the use of the calibration data getter and setter in chapter 3 of STs API documentation, linked above.

1 Like

Thanks jlo,

I thought that’s what that first line was doing. It would be easier for me to recognize by having it prefixed with the keyword “static”. But it works either way.

Hi, can some one share the link of Arduino API for VL53L0x.

Hello.

We do not have a port of ST’s API available, but we have written a basic Arduino library for the VL53L0X, which can be used as an alternative to ST’s official API for interfacing this sensor with an Arduino or Arduino-compatible controller. The library makes it simple to configure the VL53L0X and read the distance data through I2C. It also includes example sketches that show you how to use the library.

Brandon