-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsonar.py
126 lines (105 loc) · 4.42 KB
/
sonar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import micropython
import temperature
# irq ISRs won't produce error reports unless
micropython.alloc_emergency_exception_buf(100)
from machine import Pin
import utime
INFINITY = micropython.const(float('inf'))
@micropython.native
class Ultrasonic():
# supports (only) the low voltage (simple, standard, non i2c breakouts) HC-SR04+ or HC-SR04p sensor
# https://shop.4tronix.co.uk/collections/sensors/products/hc-sr04p-low-voltage-ultrasonic-distance-sensor
RANGE = 450 # max range of this ultrasonic sensor in centimeters
# give it a name, vertical and horizontal field of view in degrees
(name, orientation, verticalFoV, horizontalFoV) = ("", {}, 15, 30)
# records stop/start micro ticks, plus last distance calculated
(start, stop, distance, calculated) = (0.0, 0.0, INFINITY, True)
@property
def cm(self):
# show all cases
if self.ranging:
return INFINITY
else:
if self.calculated:
return self.distance
else:
# time in microseconds spent by our ultrasound signal in the air
uticks = utime.ticks_diff(self.stop, self.start)
# speed of sound adjusted to (estimated) environment's temperature
speed = 331.36 + 0.6067 * self.temperature
# overwrite previously calculated distance only after doing ranging
# microseconds to seconds is / 1000000, then meters into cm is *100
# uticks could be a small number, better doing math * before / 10^4
self.distance = uticks * speed / 10000 / 2
self.calculated = True
return self.distance
@property
def mm(self): return self.cm * 10
@property
def temperature(self):
# leave room for (other) improvements
# https://en.wikipedia.org/wiki/List_of_weather_records
c = temperature.celsius()
if -40 < c < 60:
return c
else:
return 25
def __init__(self, triggerPin, echoPin):
# just being verbose
self.ranging = False
# serving infinity 1st
self.calculated = True
self.echo = Pin(echoPin, Pin.IN, Pin.PULL_DOWN)
self.trigger = Pin(triggerPin, Pin.OUT, Pin.PULL_DOWN)
# following the ISR rules for writting IRQ (class) handlers for MicroPython
# https://docs.micropython.org/en/latest/reference/isr_rules.html#isr-rules
self.refStop = self.handlerStop
self.refStart = self.handlerStart
# make sure is low
self.trigger.low()
utime.sleep_us(2)
# arming the IRQ (class) handlers
self.trigger.irq(self.handlerRanging, Pin.IRQ_RISING)
self.echo.irq(self.handlerStart, Pin.IRQ_RISING)
def measure(self):
if not self.ranging:
self.trigger.high()
utime.sleep_us(5)
self.trigger.low()
# now let the IRQs do the work
def handlerRanging(self, pin):
self.ranging = True
def handlerStart(self, pin):
# will NOT trigger unless all PINs are connected
if self.ranging:
self.start = utime.ticks_us()
# re-arm the irq handling for next iteration
# passing a handler* would be bad/allocation
self.echo.irq(self.refStop, Pin.IRQ_FALLING)
# ignore the previously (calculated) distance
self.calculated = False
def handlerStop(self, pin):
# will NOT trigger unless all PINs are connected
if self.ranging:
self.stop = utime.ticks_us()
self.ranging = False
# re-arm the irq handling for next iteration
# passing a handler* would be bad/allocation
self.echo.irq(self.refStart, Pin.IRQ_RISING)
if __name__ == '__main__':
# change to your actual HC-SR04p pins
uLeft=Ultrasonic(triggerPin=3, echoPin=2)
uRight=Ultrasonic(triggerPin=7, echoPin=6)
uCenter=Ultrasonic(triggerPin=11, echoPin=10)
# trigger
utime.sleep(0.100)
uLeft.measure()
utime.sleep(0.100)
uRight.measure()
utime.sleep(0.100)
uCenter.measure()
# wait for sonars
utime.sleep(0.050)
ucm = min(uLeft.cm, uCenter.cm, uRight.cm)
print("nearest obstacle detected at", ucm, "cm, air temperature cca", temperature.celsius(), "C")
print("measurements [in cm] from all existing sonars were", uLeft.cm, uCenter.cm, uRight.cm)