Skip to content

*updated* Add .data_ready property to VL53L0X allowing end-users to predict if calls to .range will block #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 9, 2022

Conversation

whogben
Copy link
Contributor

@whogben whogben commented Mar 8, 2022

UPDATED PR DESCRIPTION

Adds a .data_ready property to VL53L0X so end-users can avoid calling .range and getting blocked on the sensor's next reading.

Test results (Feather S2, 400khz I2C frequency, 200ms sensor:

  • 200ms max block time on reading .range w/o change
  • 1.8ms max block time on reading .range after waiting for .data_ready to be true

Notes:

  • .data_ready adds approx 1ms performing the i2c check when called.
  • at the default 100khz I2c rate, everything is approximately 20x slower, but still significantly faster than without the .data_ready check for larger measurement_timing_budgets. Definitely use 400khz if available.

ORIGINAL OUT OF DATE DESCRIPTION - IGNORE

Add a timeout to read_range to reduce block time when sensor data is not available

Previously in continuous mode the read_range function would wait until new sensor data was available to return. This meant that when the sensor measurement timing budget was large, the return would take similarly long and blocked program execution.

This change introduces max_ready_wait_us, an optional parameter that will cause read_range to return -1 after waiting this length of time. The calling function can then ignore the result, and call read_range again in the future to see if data is available then.

Test results (Feather S2, I2C rate 400khz, measurement_timing_budget 200ms, read_range called every 50ms):
- 145ms max block time without specifying max_ready_wait_us
- 2.2ms max block time when specifying max_ready_wait_us = 1

As this is an optional parameter where there was no parameter before, this change should be backwards compatible for all existing users of the driver.

This change should enable the use of this sensor for realtime applications where block time needs to be minimized like a balancing bot.  Related issue: https://github.com/adafruit/Adafruit_CircuitPython_VL53L0X/issues/34

whogben added 3 commits March 8, 2022 11:53
…not available

Previously in continuous mode the read_range function would wait until new sensor data was available to return. This meant that when the sensor measurement timing budget was large, the return would take similarly long and blocked program execution.

This change introduces max_ready_wait_us, an optional parameter that will cause read_range to return -1 after waiting this length of time. The calling function can then ignore the result, and call read_range again in the future to see if data is available then.

Test results (Feather S2, I2C rate 400khz, measurement_timing_budget 200ms):
- without max_ready_wait_us: 145ms avg block time
- with max_ready_wait_us = 1: 2.2ms avg block time
@caternuson
Copy link
Contributor

It looks like this library generally does not expect one to call read_range directly:

Note: Avoid calling this directly. If you do single mode, you need
to call `do_range_measurement` first. Or your program will stuck or
timeout occurred.

The VL53L1X and VL53L4CD drivers provide a data_ready property which could provide this same capability, instead of altering a timeout. User code could check that before calling distance. I'd suggest that approach as a better way to provide this capability. Here's the Arduino version for reference:
https://github.com/stm32duino/VL53L0X/blob/49f877aa99664ac0c4275368235f11c4f0c3faf9/src/vl53l0x_class.cpp#L1789

An even better approach, which could be done with current driver code, would be to use the interrupt pin GPIO1 of the VL53L0X. It looks like the library enables it by default:

self._write_u8(_SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04)

with the 0x04 setting being VL53L0X_GPIOFUNCTIONALITY_NEW_MEASURE_READY [ref], so it will fire when new data is ready. And it gets cleared when distance is read:
self._write_u8(_SYSTEM_INTERRUPT_CLEAR, 0x01)

You'd need to connect GPIO1 back to an available GPIO pin on your controller. There you could either poll the pin or let it trigger an actual interrupt. The time savings result from not needing to do an I2C transaction to determine if data is ready.

@whogben
Copy link
Contributor Author

whogben commented Mar 8, 2022

Thanks for these suggestions.

There is still a use case for being able to read the VL53L0X without blocking because:

  • Not using an interrupt pin allows the functionality to be used with StemmaQT alone
  • The noted limitation of the read_range function is that it will block indefinitely if there's no data, however:
    • In our use case the sensor is in continuous mode, so there will always be data eventually
    • The new parameter can be used to prevent block in the case of no data, too

However, if the goal is to keep users from calling read_range directly, the max_ready_wait_us could be added as a property of the class itself, such that a call to .range could return -1 if the range wasn't available within the max block time. Thoughts on whether that's better?

@caternuson
Copy link
Contributor

Would still recommend adding a data_ready property to do this. Its return of False would be equivalent to what you're suggesting for having the timeout return -1.

@whogben
Copy link
Contributor Author

whogben commented Mar 8, 2022

The data_ready check is a big portion of the overall read_range check, so I would cache the result and clear the cached result after every actual read. If that sounds good to you I can add it, lmk.

@caternuson
Copy link
Contributor

That would save some time by not needing to do an I2C transaction every data ready check? Seems OK. Can put in a PR and can take a look.

@whogben whogben changed the title Add a timeout to read_range to reduce block time when sensor data is … Add .data_available property to VL53L0X allowing end-users to predict if calls to .range will block Mar 8, 2022
@whogben whogben changed the title Add .data_available property to VL53L0X allowing end-users to predict if calls to .range will block Add .data_ready property to VL53L0X allowing end-users to predict if calls to .range will block Mar 8, 2022
@whogben
Copy link
Contributor Author

whogben commented Mar 8, 2022

OK, updated the PR - works just as well as before and the .data_ready is much nicer and apparently in-line with the other VL sensors, thanks!

@whogben whogben changed the title Add .data_ready property to VL53L0X allowing end-users to predict if calls to .range will block *updated* Add .data_ready property to VL53L0X allowing end-users to predict if calls to .range will block Mar 8, 2022
@caternuson
Copy link
Contributor

Based on the Arduino driver:
https://github.com/stm32duino/VL53L0X/blob/49f877aa99664ac0c4275368235f11c4f0c3faf9/src/vl53l0x_class.cpp#L1789
it looks like data ready can depend on either the _RESULT_INTERRUPT_STATUS register or the _RESULT_RANGE_STATUS register, depending on configuration. Do we need to cover both scenarios?

@whogben
Copy link
Contributor Author

whogben commented Mar 9, 2022

The condition of the while loop in read_range was directly extracted to the data_ready method so the overall behavior should be identical. There is a reference to _RESULT_RANGE_STATUS still in read_range unchanged, and it's not causing me any slow calls if I wait until data_ready to call it.

@caternuson
Copy link
Contributor

OK, fair enough. Let's go with this and see how it works out for everybody.

@caternuson caternuson merged commit cd61394 into adafruit:main Mar 9, 2022
adafruit-adabot added a commit to adafruit/Adafruit_CircuitPython_Bundle that referenced this pull request Mar 18, 2022
Updating https://github.com/adafruit/Adafruit_CircuitPython_APDS9960 to 3.1.0 from 3.0.1:
  > Merge pull request adafruit/Adafruit_CircuitPython_APDS9960#42 from bablokb/4upstream
  > Fixed readthedocs build
  > Post-patch cleanup

Updating https://github.com/adafruit/Adafruit_CircuitPython_LSM6DS to 4.4.1 from 4.3.1:
  > Merge pull request adafruit/Adafruit_CircuitPython_LSM6DS#52 from jerryneedell/jerryn_mlc

Updating https://github.com/adafruit/Adafruit_CircuitPython_ST7789 to 1.5.6 from 1.5.5:
  > Merge pull request adafruit/Adafruit_CircuitPython_ST7789#30 from makermelissa/master

Updating https://github.com/adafruit/Adafruit_CircuitPython_VL53L0X to 3.6.0 from 3.5.1:
  > Merge pull request adafruit/Adafruit_CircuitPython_VL53L0X#35 from whogben/main
  > Fixed readthedocs build
  > Consolidate Documentation sections of README

Updating https://github.com/adafruit/Adafruit_CircuitPython_Wiznet5k to 1.12.3 from 1.12.2:
  > Merge pull request adafruit/Adafruit_CircuitPython_Wiznet5k#54 from masgari/main

Updating https://github.com/adafruit/Adafruit_CircuitPython_BLE to 8.2.2 from 8.2.1:
  > Merge pull request adafruit/Adafruit_CircuitPython_BLE#159 from dhalbert/nus-doc-fix

Updating https://github.com/adafruit/Adafruit_CircuitPython_BLE_LYWSD03MMC to 1.0.6 from 1.0.5:
  > Fixed readthedocs build

Updating https://github.com/adafruit/Adafruit_CircuitPython_MagTag to 2.1.8 from 2.1.7:
  > Merge pull request adafruit/Adafruit_CircuitPython_MagTag#82 from makermelissa/main
  > Merge pull request adafruit/Adafruit_CircuitPython_MagTag#81 from makermelissa/main
  > Fixed readthedocs build

Updating https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT to 5.3.0 from 5.2.3:
  > Merge pull request adafruit/Adafruit_CircuitPython_MiniMQTT#106 from dgriswo/subscription_logging

Updating https://github.com/adafruit/Adafruit_CircuitPython_PortalBase to 1.11.1 from 1.11.0:
  > Merge pull request adafruit/Adafruit_CircuitPython_PortalBase#64 from makermelissa/main

Updating https://github.com/adafruit/Adafruit_CircuitPython_WSGI to 1.1.9 from 1.1.8:
  > Merge pull request adafruit/Adafruit_CircuitPython_WSGI#13 from tekktrik/dev/clearer-bad-return
  > Fixed readthedocs build
  > Post-patch cleanup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants