Yesterday I was able to install the SRF-02 ultrasonic sensor on my quadrocopter.
Range: approx. 15 cm – 6m
Speed: up to 15.38 measurements per second (65ms between measurements)
Connectivity: i2c or UART
Up to 16 SRF-02 can be combined in one i2c bus.
The SRF-02 is the cheapest (around 16 Euros) ultrasonic sensor I could get with an own clock, as the Raspberry Pi (especially with a non-realtime OS) is really bad at measuring the ultrasonic times accurately. I demonstrated this earlier on my blog. This new sensor takes a command to start a measurement, measures on its own and then stores the result in a register for the Raspberry Pi to read through i2c (specification). Additionally, it automatically adjusts an estimation of the current minimum range.
Read more to see what problems I faced when trying to use it…
Because I was feeling lazy, I first wired the SRF-02 directly to the i2c of the Raspberry Pi without a level shifter, although it uses 5V and the Raspberry Pi 3.3V.
The code is inspired from different sources online (here and there and this and that). I mostly extended it so that the code not only does some measurements with sleeps in between, but so that it can be run in a bigger, continuous loop that collects multiple sensor readings, not just from the range finder. You can find the code on GitHub.
400 kHz i2c baudrate too high for SRF-02
One problem I faced was that the first i2c command for the SRF02 failed in a unit test reproducibly. However, when executing the very same commands in the Python3 interpreter, they worked perfectly.
First I had no idea how this could happen: it is the same machine, same Python, same code. I played around with sleep commands as I suspected the timing, but even sleeping seconds after every command did not work. After some thinking I checked the i2c baudrate: for a faster IMU polling with RTIMULib I had encreased it to 400kHz. Now I decreased it to 200kHz (“dtparam=i2c1_baudrate=200000” in /boot/config.txt) and my test worked! So my SRF-02 is not able to operate at 400kHz.
Checking if the measurement is completed leads to IOErrors
According to the specification, every i2c request will lead to a 0xFF (255) result while the sensor is taking a measurement. It seems to be common to query the software version (register 0, which for me normally has the value 6) to check if the measurement is completed (255 = working, 6 = completed). For me, this doesn’t work. Instead of 255, I always get an IOError from the smbus library until the measurement is completed.Then the result is accessible as normal.
What made me a bit nervous is the part in the specification that says that the SDA connection is pulled High (so probably 5V) while a measurement is working. This could mean that the Raspberry Pi would have to cope with 5V signals in that time. Maybe this is worse for bigger distances as then the Raspberry Pi is exposed to the high-volt signal for a longer time.
Using a level converter
To check whether the IOErrors are issued by the 5V vs 3.3V problematic and because I wasn’t sure about the consequences of running i2c in 5V, I added a bidirectional I2C Logic Level Converter to my setup, just to find out that this does not make any difference 😦
If someone has an idea on what might be wrong, please share.
As a workaround, now I start to read values from the sensor at 65ms after sending the pings. This means that the measurement has stopped, so I don’t get any more IOErrors.
Future improvement: temperature compensation
At the moment I am directly using the centimeters that the ultrasonic sensor gives me. However, it can also be configured to hand over the ultrasonic time of flight. This might be better suited for the quadrocopter use case because then I can compensate for the environment temperature as measured by a pressure/temperature sensor like BMP180 or MS5611 (I have a board that combines an MPU9150 with MS5611). Wikipedia gives a handy approximation for the speed of sound in air in relation to the air temperature:
where is the air temperature in degrees Celsius. One could also go further and factor in the humidity, as the above formula only holds for dry air. However, I could not find such a handy formula that also uses humidity.