diff --git a/README.md b/README.md index 813c409..abac2b9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,69 @@ -# micropython-hcsr04 -Micropython driver for ultrasonic sensor HC-SR04 +#HC-SR04 Sensor driver in micropython + +Micropython driver for the well-known untrasonic sensor [HC-SR04](http://www.micropik.com/PDF/HCSR04.pdf) + +The driver has been tested on Wemos D1 mini PRO, but It should work on whatever other micropython board, +if anyone find problems in other boards, please open an issue and We'll see. + +##Motivation + +The existing drivers in micropython are a bit old and they don't use the relatively new method `machine.time_pulse_us()` which +Is more accurate that whatever other method using pure python, besides the code is compliant with "standard" micropython, +there is no code for specific boards. + +Finally I've added a method, `distance_mm()` that don't use floating point operations, for environments where there is no +floating point capabilities. + +##Examples of use: + +###How to get the distance + +The `distance_cm()` method returns a `float` with the distance measured by the sensor. + +```python +from hcsr04 import HCSR04 + +sensor = HCSR04(trigger_pin=16, echo_pin=0) + +distance = sensor.distance_cm() + +print('Distance:', distance, 'cm') +``` + +There is another method, `distance_mm()`, that returns the distance in milimeters (`int` type) and **no floating point is used**, designed +for environments that doesn't support floating point operations. + +```python +distance = sensor.distance_mm() + +print('Distance:', distance, 'mm') +``` + +We can also define a different timeout, passing the new value in microseconds to the constructor + +```python +from hcsr04 import HCSR04 + +sensor = HCSR04(trigger_pin=16, echo_pin=0, echo_timeout_us=1000000) + +distance = sensor.distance_cm() + +print('Distance:', distance, 'cm') +``` + +###Error management + +When the driver reaches the timeout while is listening the echo pin the error is converted to `OSError('Out of range')` + +```python +from hcsr04 import HCSR04 + +sensor = HCSR04(trigger_pin=16, echo_pin=0, echo_timeout_us=10000) + +try: + distance = sensor.distance_cm() + print('Distance:', distance, 'cm') +except OSError as ex: + print('ERROR getting distance:', ex) + +``` diff --git a/hcsr04.py b/hcsr04.py new file mode 100644 index 0000000..df7f1fe --- /dev/null +++ b/hcsr04.py @@ -0,0 +1,79 @@ +import machine, time +from machine import Pin + +__version__ = '0.1.0' +__author__ = 'Roberto Sánchez' +__license__ = "Apache License 2.0. https://www.apache.org/licenses/LICENSE-2.0" + +class HCSR04: + """ + Driver to use the untrasonic sensor HC-SR04. + The sensor range is between 2cm and 4m. + + The timeouts received listening to echo pin are converted to OSError('Out of range') + + """ + # Timeout is based in chip range limit (400cm) + TIMEOUT_US = 500*2*30 + def __init__(self, trigger_pin, echo_pin, echo_timeout_us=HCSR04.TIMEOUT_US): + """ + trigger_pin: Output pin to send pulses + echo_pin: Readonly pin to measure the distance. The pin should be protected with 1k resistor + echo_timeout_us: Timeout in microseconds to listen to echo pin. + By default is based in sensor limit range (4m) + """ + self.echo_timeout_us = echo_timeout_us + # Init trigger pin (out) + self.trigger = Pin(trigger_pin, mode=Pin.OUT, pull=None) + self.trigger.low() + + # Init echo pin (in) + self.echo = Pin(echo_pin, mode=Pin.IN, pull=None) + + def _send_pulse_and_wait(self): + """ + Send the pulse to trigger and listen on echo pin. + We use the method `machine.time_pulse_us()` to get the microseconds until the echo is received. + """ + self.trigger.low() # Stabilize the sensor + time.sleep_us(5) + self.trigger.high() + # Send a 10us pulse. + time.sleep_us(10) + self.trigger.low() + try: + pulse_time = machine.time_pulse_us(self.echo, 1, self.echo_timeout_us) + return pulse_time + except OSError as ex: + if ex.args[0] == 110: # 110 = ETIMEDOUT + raise OSError('Out of range') + raise ex + + def distance_mm(self): + """ + Get the distance in milimeters without floating point operations. + """ + pulse_time = self._send_pulse_and_wait() + + # To calculate the distance we get the pulse_time and divide it by 2 + # (the pulse walk the distance twice) and by 29.1 becasue + # the sound speed on air (343.2 m/s), that It's equivalent to + # 0.34320 mm/us that is 1mm each 2.91us + # pulse_time // 2 // 2.91 -> pulse_time // 5.82 -> pulse_time * 100 // 582 + mm = pulse_time * 100 // 582 + return mm + + def distance_cm(self): + """ + Get the distance in centimeters with floating point operations. + It returns a float + """ + pulse_time = self._send_pulse_and_wait() + + # To calculate the distance we get the pulse_time and divide it by 2 + # (the pulse walk the distance twice) and by 29.1 becasue + # the sound speed on air (343.2 m/s), that It's equivalent to + # 0.034320 cm/us that is 1cm each 29.1us + cms = (pulse_time / 2) / 29.1 + return cms +