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