├── .gitattributes ├── .gitignore ├── LICENSE ├── README.rst ├── hcsr04.py ├── sample └── main.py ├── spi1.png ├── spi2.png ├── ultrasonic.png └── us100_bb.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 fizban99 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Basic micropython library for the micro:bit to read the distance from an ultrasonic sensor 2 | ########################################################################################## 3 | 4 | This library allows the micro:bit to read the distance from an ultrasonic sensor HCSR04 or similar. 5 | 6 | It uses the SPI hardware internal device to measure the length of the returning echo, so by default you should connect the sonar echo pin to micro:bit pin 14 and the sonar trigger pin to micro:bit pin 15. The HC-SR04 works with 5V, so you should protect the micro:bit input with a couple of resistors to create a voltage divider (see, e.g. http://www.raspberrypi-spy.co.uk/2012/12/ultrasonic-distance-measurement-using-python-part-1/). Note that you can use a US-100 with this library as well. The US-100 has the advantage that works directly with 3V, so it does not require a voltage divider and you can connect it directly to the micro:bit. Note that the US-100 has a serial mode that provides better readings, so it is better to use the `other library`_ with it. 7 | 8 | .. _other library: https://github.com/fizban99/microbit_us100 9 | 10 | .. image:: ultrasonic.png 11 | :width: 100% 12 | :align: center 13 | 14 | These sensors look like robot eyes. In fact, one eye is an emitter and the other is a receiver. The sensor is triggered with a pulse of around 10 microseconds. When it gets the pulse from the micro:bit, it sends an ultrasonic tone through one of the "eyes". The other eye detects the reflection of the sound. The sensor generates a pulse as wide as the time it took for the frequency to be detected. So the width of the "echo" pulse is equivalent to the time it takes the sound to reach the object and come back, which is twice as much as the distance to the object. 15 | 16 | .. image:: spi1.png 17 | :width: 100% 18 | :align: center 19 | 20 | The library uses the internal hardware spi device to measure the echo. SPI works by using one pin to set the clock speed, with pulses at the required frequency. Another pin is used to transmit bits at each clock cycle and the last pin is used to receive the bits from the other device. The library sends a pulse through MOSI and waits to receive something through MISO. Then, it measures the length of the returning pulse by counting the equivalent "bits". 21 | 22 | .. image:: spi2.png 23 | :width: 100% 24 | :align: center 25 | 26 | 27 | Since the information is actually grouped in bytes, we need to identify the first time we receive something different than 0x00 and count its bits (our "preamble"), then wait until we receive something different than 0xFF (hexadecimal for the binary 11111111), which will be our "postamble" and then count the total nomber of bits as preamble + 8 x bytes in the middle + postamble. 28 | 29 | .. contents:: 30 | 31 | .. section-numbering:: 32 | 33 | 34 | Main features 35 | ============= 36 | 37 | * Get the distance in cm from the sonar to an object. 38 | * Sample program. 39 | 40 | 41 | Library usage 42 | ============= 43 | 44 | 45 | distance_cm() 46 | +++++++++++++++++++++++ 47 | 48 | 49 | Get the distance in mm. 50 | 51 | 52 | .. code-block:: python 53 | 54 | from hcsr04 import HCSR04 55 | from microbit import sleep 56 | 57 | 58 | sonar=HCSR04() 59 | while True: 60 | print('%.1f' % (sonar.distance_mm()/10)) 61 | sleep(1000) 62 | 63 | -------------------------------------------------------------------------------- /hcsr04.py: -------------------------------------------------------------------------------- 1 | from microbit import spi 2 | from microbit import pin13, pin14, pin15 3 | 4 | 5 | class HCSR04: 6 | 7 | def __init__(self, tpin=pin15, epin=pin14, spin=pin13): 8 | self.trigger_pin = tpin 9 | self.echo_pin = epin 10 | self.sclk_pin = spin 11 | 12 | def distance_mm(self): 13 | spi.init(baudrate=125000, sclk=self.sclk_pin, 14 | mosi=self.trigger_pin, miso=self.echo_pin) 15 | pre = 0 16 | post = 0 17 | k = -1 18 | length = 500 19 | resp = bytearray(length) 20 | resp[0] = 0xFF 21 | spi.write_readinto(resp, resp) 22 | # find first non zero value 23 | try: 24 | i, value = next((ind, v) for ind, v in enumerate(resp) if v) 25 | except StopIteration: 26 | i = -1 27 | if i > 0: 28 | pre = bin(value).count("1") 29 | # find first non full high value afterwards 30 | try: 31 | k, value = next((ind, v) 32 | for ind, v in enumerate(resp[i:length - 2]) if resp[i + ind + 1] == 0) 33 | post = bin(value).count("1") if k else 0 34 | k = k + i 35 | except StopIteration: 36 | i = -1 37 | dist= -1 if i < 0 else round(((pre + (k - i) * 8. + post) * 8 * 0.172) / 2) 38 | return dist 39 | -------------------------------------------------------------------------------- /sample/main.py: -------------------------------------------------------------------------------- 1 | from hcsr04 import HCSR04 2 | from microbit import sleep, button_a, display 3 | 4 | 5 | sonar = HCSR04() 6 | while True: 7 | if button_a.is_pressed(): 8 | distance = round(sonar.distance_mm()/10) 9 | if distance < 10: 10 | display.show(str(distance)) 11 | else: 12 | display.scroll(str(distance)) 13 | while button_a.is_pressed(): 14 | sleep(100) 15 | sleep(100) 16 | -------------------------------------------------------------------------------- /spi1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fizban99/microbit_hcsr04/e33543034852f8028de13621d799398910bbf2b7/spi1.png -------------------------------------------------------------------------------- /spi2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fizban99/microbit_hcsr04/e33543034852f8028de13621d799398910bbf2b7/spi2.png -------------------------------------------------------------------------------- /ultrasonic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fizban99/microbit_hcsr04/e33543034852f8028de13621d799398910bbf2b7/ultrasonic.png -------------------------------------------------------------------------------- /us100_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fizban99/microbit_hcsr04/e33543034852f8028de13621d799398910bbf2b7/us100_bb.png --------------------------------------------------------------------------------