Skip to content

Commit db6fb6b

Browse files
committed
Revert nonblocking rangefinder code to prevent race condition
1 parent 523720f commit db6fb6b

File tree

1 file changed

+26
-35
lines changed

1 file changed

+26
-35
lines changed

XRPLib/rangefinder.py

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import time
2-
from machine import Pin, Timer
1+
import machine, time
2+
from machine import Pin
33

44
class Rangefinder:
55

66
"""
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.
88
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.
1010
"""
1111

1212
_DEFAULT_RANGEFINDER_INSTANCE = None
@@ -38,53 +38,44 @@ def __init__(self, trigger_pin:int, echo_pin:int, timeout_us:int=500*2*30):
3838
self._trigger.value(0)
3939
self.MAX_VALUE = 65535
4040

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
4841
# 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)
5243

53-
def _send_pulse(self):
44+
def _send_pulse_and_wait(self):
5445
"""
5546
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.
5748
"""
5849
self._trigger.value(0) # Stabilize the sensor
5950
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)
6354
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
7960

8061
def distance(self) -> float:
8162
"""
8263
Get the distance in centimeters by measuring the echo pulse time
8364
"""
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
8475

8576
# To calculate the distance we get the pulse_time and divide it by 2
8677
# (the pulse walk the distance twice) and by 29.1 becasue
8778
# the sound speed on air (343.2 m/s), that It's equivalent to
8879
# 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
9081
return cms

0 commit comments

Comments
 (0)