8
8
9
9
A CircuitPython & Python library for Garmin LIDAR Lite sensors over I2C
10
10
11
- * Author(s): ladyada
11
+ * Author(s): ladyada, johnrbnsn
12
12
13
13
Implementation Notes
14
14
--------------------
37
37
38
38
_ADDR_DEFAULT = const (0x62 )
39
39
_REG_ACQ_COMMAND = const (0x00 )
40
- _CMD_RESET = const (0 )
41
- _CMD_DISTANCENOBIAS = const (3 )
42
- _CMD_DISTANCEWITHBIAS = const (4 )
40
+ _REG_DIST_MEAS_V3 = const (0x8F )
41
+ _REG_DIST_MEAS_V3HP = const (0x0F )
42
+ _REG_SIG_COUNT_VAL = const (0x02 )
43
+ _REG_ACQ_CONFIG_REG = const (0x04 )
44
+ _REG_THRESHOLD_BYPASS = const (0x1C )
45
+ _REG_STATUS = const (0x01 )
46
+ _REG_UNIT_ID_HIGH = const (0x16 )
47
+ _REG_UNIT_ID_LOW = const (0x17 )
48
+ _REG_SIGNAL_STRENGTH = const (0x0E )
49
+ _REG_HEALTH_STATUS_V3HP = const (0x48 )
50
+ _REG_POWER_CONTROL = const (0x65 )
51
+ _REG_I2C_CONFIG = const (0x1E )
52
+ _REG_TEST_COMMAND = const (0x40 )
53
+ _REG_CORR_DATA = const (0x52 )
54
+
55
+ _CMD_RESET = const (0x00 )
56
+ _CMD_DISTANCENOBIAS = const (0x03 )
57
+ _CMD_DISTANCEWITHBIAS = const (0x04 )
58
+ _CMD_DISTANCE_V3HP = const (0x03 )
59
+ _NUM_DIST_BYTES = 2 # How many bytes is the returned distance measurement?
60
+
61
+ TYPE_V3 = 'V3'
62
+ TYPE_V3HP = 'V3HP'
43
63
44
64
CONFIG_DEFAULT = 0
45
65
CONFIG_SHORTFAST = 1
48
68
CONFIG_HIGHSENSITIVE = 4
49
69
CONFIG_LOWSENSITIVE = 5
50
70
71
+ """Status Registers"""
72
+ # v3
51
73
STATUS_BUSY = 0x01
52
74
STATUS_REF_OVERFLOW = 0x02
53
75
STATUS_SIGNAL_OVERFLOW = 0x04
56
78
STATUS_HEALTHY = 0x20
57
79
STATUS_SYS_ERROR = 0x40
58
80
81
+ # v3 HP
82
+ STATUS_BUSY_V3HP = 0x01
83
+ STATUS_SIGNAL_OVERFLOW_V3HP = 0x02
84
+
59
85
# The various configuration register values, from arduino library
60
86
_LIDAR_CONFIGS = (
61
87
(0x80 , 0x08 , 0x00 ), # default
@@ -92,7 +118,8 @@ def __init__(
92
118
* ,
93
119
reset_pin = None ,
94
120
configuration = CONFIG_DEFAULT ,
95
- address = _ADDR_DEFAULT
121
+ address = _ADDR_DEFAULT ,
122
+ sensor_type = TYPE_V3 ,
96
123
):
97
124
self .i2c_device = I2CDevice (i2c_bus , address )
98
125
self ._buf = bytearray (2 )
@@ -101,6 +128,7 @@ def __init__(
101
128
time .sleep (0.5 )
102
129
self .configure (configuration )
103
130
self ._status = self .status
131
+ self ._sensor_type = sensor_type
104
132
105
133
def reset (self ):
106
134
"""Hardware reset (if pin passed into init) or software reset. Will take
@@ -116,13 +144,15 @@ def reset(self):
116
144
try :
117
145
self ._write_reg (_REG_ACQ_COMMAND , _CMD_RESET )
118
146
except OSError :
147
+ print ('OSError' )
119
148
pass # it doesnt respond well once reset
120
149
time .sleep (1 )
121
150
# take 100 readings to 'flush' out sensor!
122
151
for _ in range (100 ):
123
152
try :
124
- self .read_distance (True )
153
+ self .read_distance_v3 (True )
125
154
except RuntimeError :
155
+ print ('RuntimeError' )
126
156
pass
127
157
128
158
def configure (self , config ):
@@ -131,36 +161,97 @@ def configure(self, config):
131
161
CONFIG_DEFAULTFAST, CONFIG_MAXRANGE, CONFIG_HIGHSENSITIVE, and
132
162
CONFIG_LOWSENSITIVE."""
133
163
settings = _LIDAR_CONFIGS [config ]
134
- self ._write_reg (0x02 , settings [0 ])
135
- self ._write_reg (0x04 , settings [1 ])
136
- self ._write_reg (0x1C , settings [2 ])
164
+ self ._write_reg (_REG_SIG_COUNT_VAL , settings [0 ])
165
+ self ._write_reg (_REG_ACQ_CONFIG_REG , settings [1 ])
166
+ self ._write_reg (_REG_THRESHOLD_BYPASS , settings [2 ])
137
167
138
- def read_distance (self , bias = False ):
168
+ def read_distance_v3 (self , bias = False ):
139
169
"""Perform a distance reading with or without 'bias'. It's recommended
140
170
to take a bias measurement every 100 non-bias readings (they're slower)"""
141
171
if bias :
142
172
self ._write_reg (_REG_ACQ_COMMAND , _CMD_DISTANCEWITHBIAS )
143
173
else :
144
174
self ._write_reg (_REG_ACQ_COMMAND , _CMD_DISTANCENOBIAS )
145
- dist = self ._read_reg (0x8F , 2 )
175
+ dist = self ._read_reg (_REG_DIST_MEAS_V3 , _NUM_DIST_BYTES )
146
176
if self ._status & (STATUS_NO_PEAK | STATUS_SECOND_RETURN ):
147
- raise RuntimeError ("Measurement failure" )
177
+ if self ._status & STATUS_NO_PEAK :
178
+ raise RuntimeError ("Measurement failure STATUS_NO_PEAK" )
179
+ elif self ._status & STATUS_SECOND_RETURN :
180
+ raise RuntimeError ("Measurement failure STATUS_NO_PEAK" )
181
+ else :
182
+ raise RuntimeError ("Some other runtime error" )
183
+
148
184
if (self ._status & STATUS_SYS_ERROR ) or (not self ._status & STATUS_HEALTHY ):
149
185
raise RuntimeError ("System failure" )
150
186
return dist [0 ] << 8 | dist [1 ]
151
187
188
+ def read_distance_v3hp (self ):
189
+ """Perform a distance measurement for the v3 HP sensor
190
+ """
191
+ # Any non-zero value written to _REG_ACQ_COMMAND will start a reading on v3HP, no bias vs. non-bias
192
+ self ._write_reg (_REG_ACQ_COMMAND , _CMD_DISTANCEWITHBIAS )
193
+ dist = self ._read_reg (_REG_DIST_MEAS_V3HP , _NUM_DIST_BYTES )
194
+ return dist [0 ] << 8 | dist [1 ]
195
+
196
+ @property
197
+ def correlation_data (self ):
198
+ """Reads correlation data"""
199
+ # TODO: How to translate correlation data property?
200
+ corr_data = self ._read_reg (_REG_CORR_DATA , 2 )
201
+ return corr_data [0 ] << 8 | corr_data [1 ]
202
+
203
+ @property
204
+ def test_command (self ):
205
+ """Reads the test command"""
206
+ return self ._read_reg (_REG_TEST_COMMAND , 1 )[0 ]
207
+
208
+ @property
209
+ def i2c_config (self ):
210
+ """Reads the I2C config"""
211
+ return self ._read_reg (_REG_I2C_CONFIG , 1 )[0 ]
212
+
213
+ @property
214
+ def power_control (self ):
215
+ """Reads the power control register"""
216
+ return self ._read_reg (_REG_POWER_CONTROL , 1 )[0 ]
217
+
218
+ @property
219
+ def health_status (self ):
220
+ """Reads health status for v3HP (not available on v3, will return -1)"""
221
+ if self ._sensor_type == TYPE_V3HP :
222
+ return self ._read_reg (_REG_HEALTH_STATUS_V3HP , 1 )[0 ]
223
+ else :
224
+ return - 1
225
+
226
+ @property
227
+ def signal_strength (self ):
228
+ """Reads the signal strength of the last measurement"""
229
+ return self ._read_reg (_REG_SIGNAL_STRENGTH , 1 )[0 ]
230
+
231
+ @property
232
+ def unit_id (self ):
233
+ """Reads the serial number of the unit"""
234
+ high_byte = self ._read_reg (_REG_UNIT_ID_HIGH , 1 )
235
+ low_byte = self ._read_reg (_REG_UNIT_ID_LOW , 1 )
236
+
237
+ return high_byte [0 ] << 8 | low_byte [0 ]
238
+
152
239
@property
153
240
def distance (self ):
154
241
"""The measured distance in cm. Will take a bias reading every 100 calls"""
155
242
self ._bias_count -= 1
243
+
156
244
if self ._bias_count < 0 :
157
245
self ._bias_count = 100 # every 100 reads, check bias
158
- return self .read_distance (self ._bias_count <= 0 )
246
+ if self ._sensor_type == TYPE_V3 :
247
+ return self .read_distance_v3 (self ._bias_count <= 0 )
248
+ elif self ._sensor_type == TYPE_V3HP :
249
+ return self .read_distance_v3hp ()
159
250
160
251
@property
161
252
def status (self ):
162
253
"""The status byte, check datasheet for bitmask"""
163
- buf = bytearray ([0x1 ])
254
+ buf = bytearray ([_REG_STATUS ])
164
255
with self .i2c_device as i2c :
165
256
i2c .write_then_readinto (buf , buf )
166
257
return buf [0 ]
0 commit comments