|
1 |
| -import time |
2 |
| -from machine import Pin, Timer |
| 1 | +import machine, time |
| 2 | +from machine import Pin |
3 | 3 |
|
4 | 4 | class Rangefinder:
|
5 | 5 |
|
6 | 6 | """
|
7 |
| - A class for using the HC-SR04 Ultrasonic Rangefinder that uses timers and interrupts to measure distance in a non-blocking way. |
| 7 | + A basic class for using the HC-SR04 Ultrasonic Rangefinder. |
8 | 8 | The sensor range is between 2cm and 4m.
|
9 |
| - Timeouts will return the previous legal value instead of raising an exception. |
| 9 | + Timeouts will return a MAX_VALUE (65535) instead of raising an exception. |
10 | 10 | """
|
11 | 11 |
|
12 | 12 | _DEFAULT_RANGEFINDER_INSTANCE = None
|
@@ -38,53 +38,44 @@ def __init__(self, trigger_pin:int, echo_pin:int, timeout_us:int=500*2*30):
|
38 | 38 | self._trigger.value(0)
|
39 | 39 | self.MAX_VALUE = 65535
|
40 | 40 |
|
41 |
| - self.trigger_timer = Timer(-1) |
42 |
| - # Set a new timer to send a pulse every 5ms |
43 |
| - self.trigger_timer.init(period=100, mode=Timer.PERIODIC, callback=lambda t:self._send_pulse()) |
44 |
| - |
45 |
| - # Init pulse tracking |
46 |
| - self._last_pulse_time = 0 |
47 |
| - self.last_pulse_len = 0 |
48 | 41 | # Init echo pin (in)
|
49 |
| - self._echo = Pin(echo_pin, mode=Pin.IN) |
50 |
| - self._echo.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=lambda pin:self._pulse_heard()) |
51 |
| - |
| 42 | + self.echo = Pin(echo_pin, mode=Pin.IN, pull=None) |
52 | 43 |
|
53 |
| - def _send_pulse(self): |
| 44 | + def _send_pulse_and_wait(self): |
54 | 45 | """
|
55 | 46 | Send the pulse to trigger and listen on echo pin.
|
56 |
| - When called on its own, blocks for 15us. |
| 47 | + We use the method `machine.time_pulse_us()` to get the microseconds until the echo is received. |
57 | 48 | """
|
58 | 49 | self._trigger.value(0) # Stabilize the sensor
|
59 | 50 | time.sleep_us(5)
|
60 |
| - self._trigger.value(1) # Send the pulse |
61 |
| - |
62 |
| - time.sleep_us(10) # 10us wide pulse |
| 51 | + self._trigger.value(1) |
| 52 | + # Send a 10us pulse. |
| 53 | + time.sleep_us(10) |
63 | 54 | self._trigger.value(0)
|
64 |
| - |
65 |
| - def _pulse_heard(self): |
66 |
| - """ |
67 |
| - Interrupt handler that records the time of the echo pulse and computes the length of the pulse |
68 |
| - """ |
69 |
| - pulse_time = time.ticks_us() |
70 |
| - if self._echo.value(): |
71 |
| - # Rising edge of the pulse |
72 |
| - self._last_pulse_time = time.ticks_us() |
73 |
| - else: |
74 |
| - # Falling edge of the pulse |
75 |
| - pulse_len = time.ticks_diff(pulse_time, self._last_pulse_time) |
76 |
| - if pulse_len < self.timeout_us: |
77 |
| - self.last_pulse_len = pulse_len |
78 |
| - |
| 55 | + try: |
| 56 | + pulse_time = machine.time_pulse_us(self.echo, 1, self.timeout_us) |
| 57 | + return pulse_time |
| 58 | + except OSError as exception: |
| 59 | + raise exception |
79 | 60 |
|
80 | 61 | def distance(self) -> float:
|
81 | 62 | """
|
82 | 63 | Get the distance in centimeters by measuring the echo pulse time
|
83 | 64 | """
|
| 65 | + try: |
| 66 | + pulse_time = self._send_pulse_and_wait() |
| 67 | + if pulse_time <= 0: |
| 68 | + return self.MAX_VALUE |
| 69 | + except OSError as exception: |
| 70 | + # We don't want programs to crash if the HC-SR04 doesn't see anything in range |
| 71 | + # So we catch those errors and return 65535 instead |
| 72 | + if exception.args[0] == 110: # 110 = ETIMEDOUT |
| 73 | + return self.MAX_VALUE |
| 74 | + raise exception |
84 | 75 |
|
85 | 76 | # To calculate the distance we get the pulse_time and divide it by 2
|
86 | 77 | # (the pulse walk the distance twice) and by 29.1 becasue
|
87 | 78 | # the sound speed on air (343.2 m/s), that It's equivalent to
|
88 | 79 | # 0.034320 cm/us that is 1cm each 29.1us
|
89 |
| - cms = (self.last_pulse_len / 2) / 29.1 |
| 80 | + cms = (pulse_time / 2) / 29.1 |
90 | 81 | return cms
|
0 commit comments