33
33
.. warning::
34
34
35
35
The HC-SR04 uses 5V logic, so you will have to use a `level shifter
36
- <https://www.adafruit.com/product/2653?q=level%20shifter&>`_ between it
37
- and your CircuitPython board (which uses 3.3V logic).
36
+ <https://www.adafruit.com/product/2653?q=level%20shifter&>`_ or simple
37
+ voltage divider between it and your CircuitPython board (which uses 3.3V logic)
38
38
39
39
* Authors:
40
40
41
41
- Mike Mabey
42
42
- Jerry Needell - modified to add timeout while waiting for echo (2/26/2018)
43
+ - ladyada - compatible with `distance` property standard, renaming, Pi compat
43
44
"""
44
- import board
45
- from digitalio import DigitalInOut , DriveMode
46
- from pulseio import PulseIn
45
+
47
46
import time
47
+ import board
48
+ from digitalio import DigitalInOut , Direction
48
49
50
+ _USE_PULSEIO = False
51
+ try :
52
+ from pulseio import PulseIn
53
+ _USE_PULSEIO = True
54
+ except ImportError :
55
+ pass # This is OK, we'll try to bitbang it!
49
56
50
57
class HCSR04 :
51
58
"""Control a HC-SR04 ultrasonic range sensor.
@@ -54,39 +61,45 @@ class HCSR04:
54
61
55
62
::
56
63
57
- with HCSR04(trig, echo) as sonar:
64
+ import time
65
+ import board
66
+
67
+ import adafruit_hcsr04
68
+
69
+ sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.D2, echo_pin=board.D3)
70
+
71
+
72
+ while True:
58
73
try:
59
- while True:
60
- print(sonar.dist_cm())
61
- sleep(2)
62
- except KeyboardInterrupt:
74
+ print((sonar.distance,))
75
+ except RuntimeError:
76
+ print("Retrying!")
63
77
pass
78
+ time.sleep(0.1)
64
79
"""
65
- def __init__ (self , trig_pin , echo_pin , timeout_sec = .1 ):
80
+ def __init__ (self , trigger_pin , echo_pin , * , timeout = 0 .1 ):
66
81
"""
67
- :param trig_pin : The pin on the microcontroller that's connected to the
82
+ :param trigger_pin : The pin on the microcontroller that's connected to the
68
83
``Trig`` pin on the HC-SR04.
69
- :type trig_pin: str or microcontroller.Pin
84
+ :type trig_pin: microcontroller.Pin
70
85
:param echo_pin: The pin on the microcontroller that's connected to the
71
86
``Echo`` pin on the HC-SR04.
72
- :type echo_pin: str or microcontroller.Pin
73
- :param float timeout_sec : Max seconds to wait for a response from the
87
+ :type echo_pin: microcontroller.Pin
88
+ :param float timeout : Max seconds to wait for a response from the
74
89
sensor before assuming it isn't going to answer. Should *not* be
75
90
set to less than 0.05 seconds!
76
91
"""
77
- if isinstance (trig_pin , str ):
78
- trig_pin = getattr (board , trig_pin )
79
- if isinstance (echo_pin , str ):
80
- echo_pin = getattr (board , echo_pin )
81
- self .dist_cm = self ._dist_two_wire
82
- self .timeout_sec = timeout_sec
83
-
84
- self .trig = DigitalInOut (trig_pin )
85
- self .trig .switch_to_output (value = False , drive_mode = DriveMode .PUSH_PULL )
86
-
87
- self .echo = PulseIn (echo_pin )
88
- self .echo .pause ()
89
- self .echo .clear ()
92
+ self ._timeout = timeout
93
+ self ._trig = DigitalInOut (trigger_pin )
94
+ self ._trig .direction = Direction .OUTPUT
95
+
96
+ if _USE_PULSEIO :
97
+ self ._echo = PulseIn (echo_pin )
98
+ self ._echo .pause ()
99
+ self ._echo .clear ()
100
+ else :
101
+ self ._echo = DigitalInOut (echo_pin )
102
+ self ._echo .direction = Direction .INPUT
90
103
91
104
def __enter__ (self ):
92
105
"""Allows for use in context managers."""
@@ -98,18 +111,19 @@ def __exit__(self, exc_type, exc_val, exc_tb):
98
111
99
112
def deinit (self ):
100
113
"""De-initialize the trigger and echo pins."""
101
- self .trig .deinit ()
102
- self .echo .deinit ()
114
+ self ._trig .deinit ()
115
+ self ._echo .deinit ()
103
116
104
- def dist_cm (self ):
117
+ @property
118
+ def distance (self ):
105
119
"""Return the distance measured by the sensor in cm.
106
120
107
121
This is the function that will be called most often in user code. The
108
122
distance is calculated by timing a pulse from the sensor, indicating
109
123
how long between when the sensor sent out an ultrasonic signal and when
110
124
it bounced back and was received again.
111
125
112
- If no signal is received, the return value will be ``-1`` . This means
126
+ If no signal is received, we'll throw a RuntimeError exception . This means
113
127
either the sensor was moving too fast to be pointing in the right
114
128
direction to pick up the ultrasonic signal when it bounced back (less
115
129
likely), or the object off of which the signal bounced is too far away
@@ -119,51 +133,43 @@ def dist_cm(self):
119
133
:return: Distance in centimeters.
120
134
:rtype: float
121
135
"""
122
- # This method only exists to make it easier to document. See either
123
- # _dist_one_wire or _dist_two_wire for the actual implementation. One
124
- # of those two methods will be assigned to be used in place of this
125
- # method on instantiation.
126
- pass
136
+ return self ._dist_two_wire () # at this time we only support 2-wire meausre
127
137
128
138
def _dist_two_wire (self ):
129
- self .echo .clear () # Discard any previous pulse values
130
- self .trig .value = 1 # Set trig high
131
- time .sleep (0.00001 ) # 10 micro seconds 10/1000/1000
132
- self .trig .value = 0 # Set trig low
133
- timeout = time .monotonic ()
134
- self .echo .resume ()
135
- while len (self .echo ) == 0 :
136
- # Wait for a pulse
137
- if (time .monotonic () - timeout ) > self .timeout_sec :
138
- self .echo .pause ()
139
- return - 1
140
- self .echo .pause ()
141
- if self .echo [0 ] == 65535 :
142
- return - 1
143
-
144
- return (self .echo [0 ] / 2 ) / (291 / 10 )
145
-
146
-
147
- def test (trig , echo , delay = 2 ):
148
- """Create and get distances from an :class:`HCSR04` object.
149
-
150
- This is meant to be helpful when first setting up the HC-SR04. It will get
151
- a distance every ``delay`` seconds and print it to standard out.
152
-
153
- :param trig: The pin on the microcontroller that's connected to the
154
- ``Trig`` pin on the HC-SR04.
155
- :type trig: str or microcontroller.Pin
156
- :param echo: The pin on the microcontroller that's connected to the
157
- ``Echo`` pin on the HC-SR04.
158
- :type echo: str or microcontroller.Pin
159
- :param delay: Seconds to wait between triggers.
160
- :type delay: int or float
161
- :rtype: None
162
- """
163
- with HCSR04 (trig , echo ) as sonar :
164
- try :
165
- while True :
166
- print (sonar .dist_cm ())
167
- time .sleep (delay )
168
- except KeyboardInterrupt :
169
- pass
139
+ if _USE_PULSEIO :
140
+ self ._echo .clear () # Discard any previous pulse values
141
+ self ._trig .value = True # Set trig high
142
+ time .sleep (0.00001 ) # 10 micro seconds 10/1000/1000
143
+ self ._trig .value = False # Set trig low
144
+
145
+ pulselen = None
146
+ timestamp = time .monotonic ()
147
+ if _USE_PULSEIO :
148
+ self ._echo .resume ()
149
+ while len (self ._echo ) == 0 :
150
+ # Wait for a pulse
151
+ if (time .monotonic () - timestamp ) > self ._timeout :
152
+ self ._echo .pause ()
153
+ raise RuntimeError ("Timed out" )
154
+ self ._echo .pause ()
155
+ pulselen = self ._echo [0 ]
156
+ else :
157
+ # OK no hardware pulse support, we'll just do it by hand!
158
+ # hang out while the pin is low
159
+ while not self ._echo .value :
160
+ if time .monotonic () - timestamp > self ._timeout :
161
+ raise RuntimeError ("Timed out" )
162
+ timestamp = time .monotonic ()
163
+ # track how long pin is high
164
+ while self ._echo .value :
165
+ if time .monotonic () - timestamp > self ._timeout :
166
+ raise RuntimeError ("Timed out" )
167
+ pulselen = time .monotonic () - timestamp
168
+ pulselen *= 1000000 # convert to us to match pulseio
169
+ if pulselen >= 65535 :
170
+ raise RuntimeError ("Timed out" )
171
+
172
+ # positive pulse time, in seconds, times 340 meters/sec, then
173
+ # divided by 2 gives meters. Multiply by 100 for cm
174
+ # 1/1000000 s/us * 340 m/s * 100 cm/m * 2 = 0.017
175
+ return (pulselen * 0.017 )
0 commit comments