Skip to content

Commit 4069536

Browse files
authored
Merge pull request #20 from johnrbnsn/main
Added Support for v3HP and Other Read Registers (common to v3 and v3HP)
2 parents 9d728cf + 2147cd7 commit 4069536

File tree

2 files changed

+151
-19
lines changed

2 files changed

+151
-19
lines changed

README.rst

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ To install in a virtual environment in your current project:
5353
source .env/bin/activate
5454
pip3 install adafruit-circuitpython-lidarlite
5555
56-
Usage Example
57-
=============
56+
Usage Examples
57+
==============
58+
59+
V3 Example
60+
----------
5861

5962
.. code-block:: python
6063
@@ -78,6 +81,43 @@ Usage Example
7881
print(e)
7982
time.sleep(0.01) # you can remove this for ultra-fast measurements!
8083
84+
85+
V3 HP Example
86+
-------------
87+
88+
.. code-block:: python
89+
90+
import time
91+
import busio
92+
import board
93+
import adafruit_lidarlite
94+
95+
i2c = busio.I2C(board.SCL, board.SDA)
96+
97+
sensor = adafruit_lidarlite.LIDARLite(i2c, sensor_type=adafruit_lidarlite.TYPE_V3HP)
98+
99+
while True:
100+
try:
101+
print(f"Sensor ID#: {sensor.unit_id}")
102+
print(f"Distance = {sensor.distance}")
103+
print(f" Strength: {sensor.signal_strength}")
104+
except RuntimeError as e:
105+
print(e)
106+
try:
107+
print(f"Status: 0b{sensor.status:b}")
108+
print(f" Busy: {bool(sensor.status & adafruit_lidarlite.STATUS_BUSY_V3HP)}")
109+
print(f" Overflow: {bool(sensor.status & adafruit_lidarlite.STATUS_SIGNAL_OVERFLOW_V3HP)}")
110+
print(f" Health: 0b{sensor.health_status:b}")
111+
print(f" Power Control: 0b{sensor.power_control:b}")
112+
print(f" I2C Config: 0b{sensor.i2c_config:b}")
113+
print(f" Test Command: 0b{sensor.test_command:b}")
114+
print(f" Correlation: 0b{sensor.correlation_data}")
115+
except RuntimeError as e:
116+
print(e)
117+
118+
print()
119+
time.sleep(1)
120+
81121
Documentation
82122
=============
83123

adafruit_lidarlite.py

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# SPDX-FileCopyrightText: 2018 ladyada for Adafruit Industries
2+
# SPDX-FileCopyrightText: 2022 johnrbnsn
23
#
34
# SPDX-License-Identifier: MIT
45

@@ -8,7 +9,7 @@
89
910
A CircuitPython & Python library for Garmin LIDAR Lite sensors over I2C
1011
11-
* Author(s): ladyada
12+
* Author(s): ladyada, johnrbnsn
1213
1314
Implementation Notes
1415
--------------------
@@ -37,9 +38,29 @@
3738

3839
_ADDR_DEFAULT = const(0x62)
3940
_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"
4364

4465
CONFIG_DEFAULT = 0
4566
CONFIG_SHORTFAST = 1
@@ -48,6 +69,8 @@
4869
CONFIG_HIGHSENSITIVE = 4
4970
CONFIG_LOWSENSITIVE = 5
5071

72+
"""Status Registers"""
73+
# v3
5174
STATUS_BUSY = 0x01
5275
STATUS_REF_OVERFLOW = 0x02
5376
STATUS_SIGNAL_OVERFLOW = 0x04
@@ -56,6 +79,10 @@
5679
STATUS_HEALTHY = 0x20
5780
STATUS_SYS_ERROR = 0x40
5881

82+
# v3 HP
83+
STATUS_BUSY_V3HP = 0x01
84+
STATUS_SIGNAL_OVERFLOW_V3HP = 0x02
85+
5986
# The various configuration register values, from arduino library
6087
_LIDAR_CONFIGS = (
6188
(0x80, 0x08, 0x00), # default
@@ -92,7 +119,8 @@ def __init__(
92119
*,
93120
reset_pin=None,
94121
configuration=CONFIG_DEFAULT,
95-
address=_ADDR_DEFAULT
122+
address=_ADDR_DEFAULT,
123+
sensor_type=TYPE_V3,
96124
):
97125
self.i2c_device = I2CDevice(i2c_bus, address)
98126
self._buf = bytearray(2)
@@ -101,6 +129,7 @@ def __init__(
101129
time.sleep(0.5)
102130
self.configure(configuration)
103131
self._status = self.status
132+
self._sensor_type = sensor_type
104133

105134
def reset(self):
106135
"""Hardware reset (if pin passed into init) or software reset. Will take
@@ -116,51 +145,114 @@ def reset(self):
116145
try:
117146
self._write_reg(_REG_ACQ_COMMAND, _CMD_RESET)
118147
except OSError:
119-
pass # it doesnt respond well once reset
148+
print("OSError")
120149
time.sleep(1)
121150
# take 100 readings to 'flush' out sensor!
122151
for _ in range(100):
123152
try:
124-
self.read_distance(True)
153+
self.read_distance_v3(True)
125154
except RuntimeError:
126-
pass
155+
print("RuntimeError")
127156

128157
def configure(self, config):
129158
"""Set the LIDAR desired style of measurement. There are a few common
130159
configurations Garmin suggests: CONFIG_DEFAULT, CONFIG_SHORTFAST,
131160
CONFIG_DEFAULTFAST, CONFIG_MAXRANGE, CONFIG_HIGHSENSITIVE, and
132161
CONFIG_LOWSENSITIVE."""
133162
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])
137166

138-
def read_distance(self, bias=False):
167+
def read_distance_v3(self, bias=False):
139168
"""Perform a distance reading with or without 'bias'. It's recommended
140169
to take a bias measurement every 100 non-bias readings (they're slower)"""
141170
if bias:
142171
self._write_reg(_REG_ACQ_COMMAND, _CMD_DISTANCEWITHBIAS)
143172
else:
144173
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)
146175
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+
148182
if (self._status & STATUS_SYS_ERROR) or (not self._status & STATUS_HEALTHY):
149183
raise RuntimeError("System failure")
150184
return dist[0] << 8 | dist[1]
151185

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+
152211
@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
154239
"""The measured distance in cm. Will take a bias reading every 100 calls"""
155240
self._bias_count -= 1
241+
156242
if self._bias_count < 0:
157243
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
159251

160252
@property
161253
def status(self):
162254
"""The status byte, check datasheet for bitmask"""
163-
buf = bytearray([0x1])
255+
buf = bytearray([_REG_STATUS])
164256
with self.i2c_device as i2c:
165257
i2c.write_then_readinto(buf, buf)
166258
return buf[0]

0 commit comments

Comments
 (0)