-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathultrasonic_senor.py
161 lines (126 loc) · 5.48 KB
/
ultrasonic_senor.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
'''Measure the distance or depth with an HCSR04 Ultrasonic sound
sensor and a Raspberry Pi. Imperial and Metric measurements are available'''
# Al Audet
# MIT License
import time
import math
import RPi.GPIO as GPIO
import numpy as np
class Measurement(object):
'''Create a measurement using a HC-SR04 Ultrasonic Sensor connected to
the GPIO pins of a Raspberry Pi.
Metric values are used by default. For imperial values use
unit='imperial'
temperature=<Desired temperature in Fahrenheit>
'''
def __init__(self,
trig_pin,
echo_pin,
temperature=20,
unit='metric',
round_to=1
):
self.trig_pin = trig_pin
self.echo_pin = echo_pin
self.temperature = temperature
self.unit = unit
self.round_to = round_to
def __reject_outliers(self, data, m=2):
return data[abs(data - np.mean(data)) < m * np.std(data)]
def removeOutliers(sefl, x, outlierConstant):
a = np.array(x)
upper_quartile = np.percentile(a, 75)
lower_quartile = np.percentile(a, 25)
IQR = (upper_quartile - lower_quartile) * outlierConstant
quartileSet = (lower_quartile - IQR, upper_quartile + IQR)
resultList = []
for y in a.tolist():
if y >= quartileSet[0] and y <= quartileSet[1]:
resultList.append(y)
return resultList
def raw_distance(self, sample_size=11, sample_wait=0.1):
'''Return an error corrected unrounded distance, in cm, of an object
adjusted for temperature in Celcius. The distance calculated
is the median value of a sample of `sample_size` readings.
Speed of readings is a result of two variables. The sample_size
per reading and the sample_wait (interval between individual samples).
Example: To use a sample size of 5 instead of 11 will increase the
speed of your reading but could increase variance in readings;
value = sensor.Measurement(trig_pin, echo_pin)
r = value.raw_distance(sample_size=5)
Adjusting the interval between individual samples can also
increase the speed of the reading. Increasing the speed will also
increase CPU usage. Setting it too low will cause errors. A default
of sample_wait=0.1 is a good balance between speed and minimizing
CPU usage. It is also a safe setting that should not cause errors.
e.g.
r = value.raw_distance(sample_wait=0.03)
'''
if self.unit == 'imperial':
self.temperature = (self.temperature - 32) * 0.5556
elif self.unit == 'metric':
pass
else:
raise ValueError(
'Wrong Unit Type. Unit Must be imperial or metric')
speed_of_sound = 331.3 * math.sqrt(1 + (self.temperature / 273.15))
sample = []
# setup input/output pins
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.trig_pin, GPIO.OUT)
GPIO.setup(self.echo_pin, GPIO.IN)
for distance_reading in range(sample_size):
too_long = False
sonar_signal_off = 0
sonar_signal_on = 0
GPIO.output(self.trig_pin, GPIO.LOW)
time.sleep(sample_wait)
GPIO.output(self.trig_pin, True)
time.sleep(0.00001)
GPIO.output(self.trig_pin, False)
start = time.time()
while GPIO.input(self.echo_pin) == 0:
sonar_signal_off = time.time()
if time.time() - start > 0.23:
too_long = True
break
if sonar_signal_off == 0 or too_long:
continue
start = time.time()
while GPIO.input(self.echo_pin) == 1:
sonar_signal_on = time.time()
if time.time() - start > 0.23:
too_long = True
break
if too_long or sonar_signal_on == 0:
continue
time_passed = sonar_signal_on - sonar_signal_off
distance_cm = time_passed * ((speed_of_sound * 100) / 2)
if distance_cm < 200:
sample.append(int(distance_cm))
else:
sample.append(200)
if len(sample) == 1:
return sample[0]
elif len(sample) < 1:
return 200
if len(sample) > 0:
sample = self.removeOutliers(sample, 2)
return np.mean(sample)
def depth_metric(self, median_reading, hole_depth):
'''Calculate the rounded metric depth of a liquid. hole_depth is the
distance, in cm's, from the sensor to the bottom of the hole.'''
return round(hole_depth - median_reading, self.round_to)
def depth_imperial(self, median_reading, hole_depth):
'''Calculate the rounded imperial depth of a liquid. hole_depth is the
distance, in inches, from the sensor to the bottom of the hole.'''
return round(hole_depth - (median_reading * 0.394), self.round_to)
def distance_metric(self, median_reading):
'''Calculate the rounded metric distance, in cm's, from the sensor
to an object'''
return round(median_reading, self.round_to)
def distance_imperial(self, median_reading):
'''Calculate the rounded imperial distance, in inches, from the sensor
to an oject.'''
return round(median_reading * 0.394, self.round_to)