- Remote ultrasonic sensor for EV3 with micro:bit
Been testing the micro:bit BLE Uart service. It’s a service that uses Nordic chipset features to deliver a simple TX/RX mechanism so we talk with the micro:bit without having to create our own BLE services.
Someone offered me a ultrasonic sensor this week. It’s a HC-SR04, very common with Arduino projects but can also be used with the micro:bit, there’s even a “sonar” extension available in the Makecode editor.
So I added the BLE Uart service and started writing the distance values to the TX characteristic every second:
Nordic nRF Connect App reads them fine but gatttool doesn’t… except when in Interactive mode. Strange!
After a while, I found out a note that explains that the way the TX characteristic works forces us to keep the connection or reset the micro:bit regularly. That’s why Interactive mode works (it keeps the connection). So I have to forget gatttool for a while and use something better like python.
On Ubuntu, my scripts worked fine. Latest version of pygatt (4.0.3) allow me to subscribe to the TX Characterist (in “Indication” mode only – almost the same as notifications but with an extra acknowledge step) and I was getting distance values on my laptop through BLE.
But on the EV3 the scripts failed because “No characteristic found matching”. Why? I’m using same version of pygatt and don’t think that kernel version make much difference now that pybluez has settled.
I was almost giving up when something worked: decided to use the python exception mechanism to retry several times the subscribing step.
So instead of just
device.subscribe("6e400002-b5a3-f393-e0a9-e50e24dcca9e", callback=handle_data, indication=True)
I included the subscribe command in a loop that only ends when the command completes:
while True: try: device.subscribe("6e400002-b5a3-f393-e0a9-e50e24dcca9e", callback=handle_data, indication=True) break except pygatt.exceptions.BLEError: print("unknown characteristic")
And it works?! Usually just retrying once:
Dist = 1.19 m
Dist = 1.19 m
Dist = 1.18 m
My micro:bit github page now includes the python script used on the above video
If you wonder about the format of the data, the micro:bit sends the distance value as a string of bytes, each byte being the ASCII code of the character, so 40 cm is sent as a “4” followed by a “0”: