Neat. I'm curious about why the sensor init code looks the way it does though. It's a very long sequence of repetitive register writes. Why not do it like this instead? Table-driven code is underappreciated, I think.
Indeed, their init routine seriously violates the DRY principle. At the very least, each section could be implemented by a macro, but I prefer your 'table-driven' implementation.
I have a feeling writing is that way is mostly habit because you often end up with init routines where the device barfs during init for various reasons[1] and you need to execute 'plan b'. That said I'd consider using macro's to be a distant third option.
[1] Classic is the uP resets and re-runs the init code on I2C bus peripherals that have already been configured.
That change would decrease the repeated code, but I think it would also make the code more brittle. What if the requirements were very slightly different, and you needed to do something different in the middle of the sequence, like writing a register of a different size or sleeping for a millisecond?
> What if the requirements were very slightly different, and you needed to do something different in the middle of the sequence, like writing a register of a different size or sleeping for a millisecond?
Interestingly, I'd argue this is actually a great argument for brittleness in this case. The table oriented code makes it clear to the reader that no such subtle edge cases exist, improving the readability of the code.
Although a local macro or better error handling system would also make such things a bit clearer too.
A friend and myself were talking about this exact same thing the other day (he works in the web / desktop app space and I work in the embedded space). We were working on an embedded project a while back and he didn't like seeing "bit magic" sprinkled throughout the code and I completely agree.
I approach this issue in 3 different ways: #define what those series of addresses and values mean, have a function that calls each one semantically, or a function that wraps all of them (what OP is doing).
I was going to show an example specific to this, but unfortunately ST did a poor job this time documenting this specific init sequence. If you look at those application notes linked in the tutorial, they just state they are mandatory private registers, which is disheartening. Looking at the example code that ST provides with their Nucleo boards for the evaluation kit of this module, it doesn't shed much more light, except that it seems to be something to do with ranging, tuning, and up-scaling of the data. They have two functions VL6180x_RangeStaticInit() and VL6180x_UpscaleRegInit() that call this sequence, depending on if up-scaling was defined.
At this point, if I was actually working with this part, I would contact a ST rep and ask them what is up, because it seems weird they are forcing you to write to "private" registers.
If you look at the OP's code, you will see that he does wrap this series of code with VL_InitDevice(), and since ST does not have it documented any better than "These settings should be applied in this order with no substitutions", this is what you get. Doing what is suggested, I don't think really gets you much further, imo, but does condense your code, for what it is worth.
Range is 10/40/60cm with accuracy 1/2/3mm (apparently there is some kind of scaling factor). I wonder where such short range measurements with such a low accuracy are useful.
The 3m range with ~3mm accuracy is more than enough for large object alignment as well. I've got the VL53L0X being used as a car park sensor in my garage, it's a very complicated version of a tennis ball on a string.
> Range is 10/40/60cm with accuracy 1/2/3mm (apparently there is some kind of scaling factor).
The "accuracy" you mention is really what they call "Range Resolution", which is more a measure of precision than accuracy. The range (as well as this resolution) is determined by the modulation frequency of the device, which I presume is the setting you switch to change modes.
> I wonder where such short range measurements with such a low accuracy are useful.
Another commenter mentioned autonomous vehicles (small vaccum robot), however I think outside of that use case there's really not much. Honestly for most things at that kind of range, I'd probably prefer to use a PMD camera like the Pico Flexx [1][2]. It's a lot more expensive, but you get a much better range, higher frame rate, and takes full images instead of just a single range in front of whatever it is you're building. Granted the range is 0.1-4m because the modulation frequency is fixed, but for most applications where you want autonomous ranging I can't see this being too much of a problem.
The sensors are great for dynamic alignment and calibration. There are plenty of situations where ~3mm accuracy is perfectly fine. In many situations if you can get parts with-in 3mm of one another, mechanical self alignment mechanisms can take you the rest of the way.
That's comparable to (and probably more precise than) cheap ultrasonic sensors or traditional optical distance sensors, so probably as a different choice or optimization everywhere those are used.
10cm range with 1mm accuracy is 1%. That's plenty for many applications. I can immediately think of one where an ultrasonic distance sensor is being used and far less resolution is required. In fact, were it not for the dirty environment that the ultrasonic sensor is working in (under a vehicle), I'd think this would be a good replacement.
That's neat! Regarding your temp sensor issues, I used the same sensor for beer monitoring. Not sure if is is the same issue, but I was able to resolve it[1].
I know. I went through the hell of trying to build one in the 1990s. I've used the huge SICK LMS line scanner. Now these things are tiny and cheap, at least for short range.
I have a couple of the SICK LMS units (picked them up cheap off ebay) - while I like the fact that these tiny and low cost sensors are available (and great for small-scale robotics) - they won't match up to a SICK unit in the near term.
There's nothing like the range, 180 deg scanning speed, and general industrial robustness of the SICK LIDARs.
Then again, these chips aren't the size of a small coffee maker, and don't weigh a ton, either.
I think these devices will occupy a nice niche for when you want something with a better resolution than either the Sharp IR sensors or some ultrasonic pinger - but don't mind the limited range.
The data sheet is frustrating. It's not clear whether this device is a carrier-modulated device or a pulse timing device. I think it's carrier-modulated, like most low-end LIDAR devices. Multiple carrier-modulated devices in the same space can interfere. Pulse timing devices, not so much, especially if you randomize the pulse schedule a bit.
25 comments
[ 3.3 ms ] story [ 66.4 ms ] thread[1] Classic is the uP resets and re-runs the init code on I2C bus peripherals that have already been configured.
This situation is crying out for either exception handling, or Go's "errors are values" pattern. (https://blog.golang.org/errors-are-values)
Interestingly, I'd argue this is actually a great argument for brittleness in this case. The table oriented code makes it clear to the reader that no such subtle edge cases exist, improving the readability of the code.
Although a local macro or better error handling system would also make such things a bit clearer too.
As an occasional embedded systems programmer, initialization code without subtle edge cases only exists in artificial examples like this one.
I approach this issue in 3 different ways: #define what those series of addresses and values mean, have a function that calls each one semantically, or a function that wraps all of them (what OP is doing).
I was going to show an example specific to this, but unfortunately ST did a poor job this time documenting this specific init sequence. If you look at those application notes linked in the tutorial, they just state they are mandatory private registers, which is disheartening. Looking at the example code that ST provides with their Nucleo boards for the evaluation kit of this module, it doesn't shed much more light, except that it seems to be something to do with ranging, tuning, and up-scaling of the data. They have two functions VL6180x_RangeStaticInit() and VL6180x_UpscaleRegInit() that call this sequence, depending on if up-scaling was defined.
Software for Nucleo Board for the VL6180X: http://www.st.com/content/st_com/en/products/embedded-softwa...
At this point, if I was actually working with this part, I would contact a ST rep and ask them what is up, because it seems weird they are forcing you to write to "private" registers.
If you look at the OP's code, you will see that he does wrap this series of code with VL_InitDevice(), and since ST does not have it documented any better than "These settings should be applied in this order with no substitutions", this is what you get. Doing what is suggested, I don't think really gets you much further, imo, but does condense your code, for what it is worth.
The "accuracy" you mention is really what they call "Range Resolution", which is more a measure of precision than accuracy. The range (as well as this resolution) is determined by the modulation frequency of the device, which I presume is the setting you switch to change modes.
> I wonder where such short range measurements with such a low accuracy are useful.
Another commenter mentioned autonomous vehicles (small vaccum robot), however I think outside of that use case there's really not much. Honestly for most things at that kind of range, I'd probably prefer to use a PMD camera like the Pico Flexx [1][2]. It's a lot more expensive, but you get a much better range, higher frame rate, and takes full images instead of just a single range in front of whatever it is you're building. Granted the range is 0.1-4m because the modulation frequency is fixed, but for most applications where you want autonomous ranging I can't see this being too much of a problem.
[1] http://pmdtec.com/picoflexx/downloads/PMD_RD_Brief_CB_pico_f... [2] http://pmdtec.com/picoflexx/
A VR headset?
Tesla's model X gull wing doors?
https://github.com/pololu/vl53l0x-arduino https://github.com/pololu/vl6180x-arduino
I've been playing around with the VL53L0X.
http://i.imgur.com/KFezaqU.jpg http://i.imgur.com/YM5KLRw.jpg
https://www.sparkfun.com/products/12784 - Is the little board I used, and used a logic level converter.
I attached a little polystyrene circle to the top of the hydrometer, for the IR to bounce off.
Unfortunately the approach didn't work too well because of yeast krausen pushing the hydrometer about.
[1] http://www.blog.pyoung.net/2015/01/28/ds18b20-crc-check-code...
There's nothing like the range, 180 deg scanning speed, and general industrial robustness of the SICK LIDARs.
Then again, these chips aren't the size of a small coffee maker, and don't weigh a ton, either.
I think these devices will occupy a nice niche for when you want something with a better resolution than either the Sharp IR sensors or some ultrasonic pinger - but don't mind the limited range.
[1] http://www.st.com/content/ccc/resource/technical/document/da...