Optimizing on the speed of reading the ultrasonic sensor
Posted: 15 Aug 2011, 14:26
In this thread https://sourceforge.net/apps/phpbb/mind ... ?f=3&t=976 linusa wrote:
The suggested algorithm probably only works if you are sending a command to the sensor and expect exactly 1 byte in reply. Reading the distance from the ultrasonic sensor is such a case, but other commands like “Read product ID†and “Read sensor type†will return more bytes. But, since we are most interested in reading the distance we are in luck.
The first problem you encounter is that you get error on the LwRead() from the I2C bus when you try this. I encountered 2 types:
The first one was 0x20 (Pending communication transaction in progress). No problem, you can just ignore this and try to redo the LsRead() after a short pause.
The second, 0xDD (Communication buss error), is a bit more problematic. If the bus ends up in this state it will just continue to fail until the error is cleared. It is easy enough to solve this; you just need to do a LsWrite(). Any LsWrite() should do, and I simply chose to resend the original one (from step 1).
After that the algorithm was stable (but I am keeping it beta until I am 100% sure).
I also introduced a small wait-period in the algorithm. Having sent the LsWrite(), the data will not be ready in the sensor right way, so why not wait until the chances are better that it is before calling the LsRead()? The wait should not be too short, and not be too long either, but in between there is probably an optimal value.
I made some measurements and in my case about 22 milliseconds turned out to be the optimal length – other implementations may have another value. I will not say I am totally happy about this solution as the value may depend on a lot of variable circumstances e.g. the quality of the Bluetooth signal.
Anyway, adding this pause greatly reduced the calls to LsRead() which ended in an error and a second LsRead() a bit later.
The final algorithm ended up looking like this:
1. Use LsWrite() to tell the sensor which I2C register you need
2. Pause 22 ms.
3. Call LsRead() to get the value.
3a. If error == PendingCommunicationTransactionInProgress repeat from step 2.
3b. If error == CommunicationBusError repeat from step 1.
3c. If error == unknown Fail.
4. Return the value from LsRead.
Improvements:
Response-time: 104 ms -> 81 ms
Commands: 3.9 -> 2.1
I have now tried this in my MindSqualls library (http://mindsqualls.net/) and here are my observations…linusa wrote:Do you have the feeling that "I2C is slow", as in "the ultrasonic sensor could really be faster, especially via Bluetooth"? I'm not sure how exactly you request input data from digital sensors using direct commands, but there might be a way for you to save 1 packet on average (which could be as much as 30ms gain in performance, depending on statistics). I suggested this for nxt-python a while ago: https://code.google.com/p/nxt-python/is ... tail?id=11
Short summary: Instead of doing it like this:Now, maybe you've noticed, you already get a statusbyte with LSRead, too. So you can completely omit the LSGetStatus command. The optimized version looks like this:Code: Select all
1. Use LSWrite to tell the sensor which I2C register you need 2. In a loop, keep polling LSGetStatus until I2C is not busy anymore (no error is detected, statusbyte == 0). 3. Use LSRead to retrieve the sensor data.
In regular cases, this can save 1 direct command out of 3.Code: Select all
1. Use LSWrite to tell the sensor which I2C register you need 2. In a loop, keep polling LSRead until I2C is not busy anymore (no error is detected, statusbyte == 0). 3. Once the loop is done, you already have the sensor's answer (payload of last LSRead command with statusbyte == 0).
The suggested algorithm probably only works if you are sending a command to the sensor and expect exactly 1 byte in reply. Reading the distance from the ultrasonic sensor is such a case, but other commands like “Read product ID†and “Read sensor type†will return more bytes. But, since we are most interested in reading the distance we are in luck.
The first problem you encounter is that you get error on the LwRead() from the I2C bus when you try this. I encountered 2 types:
The first one was 0x20 (Pending communication transaction in progress). No problem, you can just ignore this and try to redo the LsRead() after a short pause.
The second, 0xDD (Communication buss error), is a bit more problematic. If the bus ends up in this state it will just continue to fail until the error is cleared. It is easy enough to solve this; you just need to do a LsWrite(). Any LsWrite() should do, and I simply chose to resend the original one (from step 1).
After that the algorithm was stable (but I am keeping it beta until I am 100% sure).
I also introduced a small wait-period in the algorithm. Having sent the LsWrite(), the data will not be ready in the sensor right way, so why not wait until the chances are better that it is before calling the LsRead()? The wait should not be too short, and not be too long either, but in between there is probably an optimal value.
I made some measurements and in my case about 22 milliseconds turned out to be the optimal length – other implementations may have another value. I will not say I am totally happy about this solution as the value may depend on a lot of variable circumstances e.g. the quality of the Bluetooth signal.
Anyway, adding this pause greatly reduced the calls to LsRead() which ended in an error and a second LsRead() a bit later.
The final algorithm ended up looking like this:
1. Use LsWrite() to tell the sensor which I2C register you need
2. Pause 22 ms.
3. Call LsRead() to get the value.
3a. If error == PendingCommunicationTransactionInProgress repeat from step 2.
3b. If error == CommunicationBusError repeat from step 1.
3c. If error == unknown Fail.
4. Return the value from LsRead.
Improvements:
Response-time: 104 ms -> 81 ms
Commands: 3.9 -> 2.1