PX4 Firmware
PX4 Autopilot Software http://px4.io
LidarLiteI2C.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2014-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 
35 /**
36  * @file LidarLiteI2C.cpp
37  * @author Allyson Kreft
38  *
39  * Driver for the PulsedLight Lidar-Lite range finders connected via I2C.
40  */
41 
42 #include "LidarLiteI2C.h"
43 
44 LidarLiteI2C::LidarLiteI2C(const int bus, const uint8_t rotation, const int address) :
45  LidarLite(rotation),
46  I2C("LL40LS", nullptr, bus, address, 100000),
47  ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(get_device_id()))
48 {
49  // up the retries since the device misses the first measure attempts
50  _retries = 3;
51 }
52 
54 {
55  stop();
56 }
57 
58 int
60 {
61  // Perform I2C init (and probe) first.
62  if (I2C::init() != PX4_OK) {
63  return PX4_ERROR;
64  }
65 
66  return PX4_OK;
67 }
68 
69 int
70 LidarLiteI2C::read_reg(const uint8_t reg, uint8_t &val)
71 {
72  return lidar_transfer(&reg, 1, &val, 1);
73 }
74 
75 int
76 LidarLiteI2C::write_reg(const uint8_t reg, const uint8_t &val)
77 {
78  const uint8_t cmd[2] = { reg, val };
79  return transfer(&cmd[0], 2, nullptr, 0);
80 }
81 
82 int
83 LidarLiteI2C::lidar_transfer(const uint8_t *send, const unsigned send_len, uint8_t *recv, const unsigned recv_len)
84 {
85  if (send != nullptr && send_len > 0) {
86  int ret = transfer(send, send_len, nullptr, 0);
87 
88  if (ret != PX4_OK) {
89  return ret;
90  }
91  }
92 
93  if (recv != nullptr && recv_len > 0) {
94  return transfer(nullptr, 0, recv, recv_len);
95  }
96 
97  return PX4_ERROR;
98 }
99 
100 int
102 {
103  // cope with both old and new I2C bus address
104  const uint8_t addresses[2] = { LL40LS_BASEADDR, LL40LS_BASEADDR_OLD };
105 
106  uint8_t id_high = 0;
107  uint8_t id_low = 0;
108 
109  // more retries for detection
110  _retries = 10;
111 
112  for (uint8_t i = 0; i < sizeof(addresses); i++) {
113 
114  set_device_address(addresses[i]);
115 
116  /**
117  * The probing is divided into different cases. One to detect v2, one for v3 and v1 and one for v3HP.
118  * The reason for this is that registers are not consistent between different versions.
119  * The v3HP doesn't have the HW VERSION (or at least no version is specified),
120  * v1 and v3 don't have the unit id register while v2 has both.
121  * It would be better if we had a proper WHOAMI register.
122  */
125 
126  if (read_reg(LL40LS_UNIT_ID_HIGH, id_high) == OK &&
127  read_reg(LL40LS_UNIT_ID_LOW, id_low) == OK) {
128  _unit_id = (uint16_t)((id_high << 8) | id_low) & 0xFFFF;
129  }
130 
131  if (_hw_version > 0) {
132 
133  if (_unit_id > 0) {
134  // v2
135  PX4_INFO("probe success - hw: %u, sw:%u, id: %u", _hw_version, _sw_version, _unit_id);
137 
138  } else {
139  // v1 and v3
140  PX4_INFO("probe success - hw: %u, sw:%u", _hw_version, _sw_version);
141  }
142 
143  } else {
144 
145  if (_unit_id > 0) {
146  // v3hp
147  _is_v3hp = true;
148  PX4_INFO("probe success - id: %u", _unit_id);
149  }
150  }
151 
152  _retries = 3;
153  return OK;
154  }
155 
156  PX4_DEBUG("probe failed unit_id=0x%02x hw_version=0x%02x sw_version=0x%02x",
157  (unsigned)_unit_id,
158  (unsigned)_hw_version,
159  (unsigned)_sw_version);
160 
161  }
162 
163  // not found on any address
164  return -EIO;
165 }
166 
167 int
169 {
170  if (_pause_measurements) {
171  // we are in print_registers() and need to avoid
172  // acquisition to keep the I2C peripheral on the
173  // sensor active
174  return OK;
175  }
176 
177  // Send the command to begin a measurement.
179 
180  if (ret != PX4_OK) {
182  PX4_DEBUG("i2c::transfer returned %d", ret);
183 
184  // if we are getting lots of I2C transfer errors try
185  // resetting the sensor
186  if (perf_event_count(_comms_errors) % 10 == 0) {
188  reset_sensor();
189  }
190 
191  return ret;
192  }
193 
194  // remember when we sent the acquire so we can know when the
195  // acquisition has timed out
197 
198  return OK;
199 }
200 
201 int
203 {
204  px4_usleep(15000);
205 
207 
208  if (ret != PX4_OK) {
209  return ret;
210  }
211 
212  px4_usleep(15000);
214 
215 
216  if (ret != PX4_OK) {
217  uint8_t sig_cnt;
218 
219  px4_usleep(15000);
220  ret = read_reg(LL40LS_SIG_COUNT_VAL_REG, sig_cnt);
221 
222  if ((ret != PX4_OK) || (sig_cnt != LL40LS_SIG_COUNT_VAL_DEFAULT)) {
223  PX4_INFO("Error: ll40ls reset failure. Exiting!\n");
224  return ret;
225 
226  }
227  }
228 
229  // wait for sensor reset to complete
230  px4_usleep(50000);
232 
233  if (ret != PX4_OK) {
234  return ret;
235  }
236 
237  // wait for register write to complete
238  px4_usleep(1000);
239 
240  return OK;
241 }
242 
243 void
245 {
246  _pause_measurements = true;
247  PX4_INFO("registers");
248  // wait for a while to ensure the lidar is in a ready state
249  px4_usleep(50000);
250 
251  for (uint8_t reg = 0; reg <= 0x67; reg++) {
252  uint8_t val = 0;
253  int ret = lidar_transfer(&reg, 1, &val, 1);
254 
255  if (ret != OK) {
256  printf("%02x:XX ", (unsigned)reg);
257 
258  } else {
259  printf("%02x:%02x ", (unsigned)reg, (unsigned)val);
260  }
261 
262  if (reg % 16 == 15) {
263  printf("\n");
264  }
265  }
266 
267  printf("\n");
268  _pause_measurements = false;
269 }
270 
271 int
273 {
274  // read from the sensor
275  uint8_t val[2] {};
276 
278 
279  // read the high and low byte distance registers
280  uint8_t distance_reg = LL40LS_DISTHIGH_REG | LL40LS_AUTO_INCREMENT;
281  int ret = lidar_transfer(&distance_reg, 1, &val[0], sizeof(val));
282 
283  // if the transfer failed or if the high bit of distance is
284  // set then the distance is invalid
285  if (ret < 0 || (val[0] & 0x80)) {
287  /*
288  NACKs from the sensor are expected when we
289  read before it is ready, so only consider it
290  an error if more than 100ms has elapsed.
291  */
292  PX4_DEBUG("error reading from sensor: %d", ret);
294 
295  if (perf_event_count(_comms_errors) % 10 == 0) {
297  reset_sensor();
298  }
299  }
300 
302  // if we are getting lots of I2C transfer errors try
303  // resetting the sensor
304  return ret;
305  }
306 
307  uint16_t distance_cm = (val[0] << 8) | val[1];
308  const float distance_m = float(distance_cm) * 1e-2f;
309 
310  if (distance_cm == 0) {
311  _zero_counter++;
312 
313  if (_zero_counter == 20) {
314  /* we have had 20 zeros in a row - reset the
315  sensor. This is a known bad state of the
316  sensor where it returns 16 bits of zero for
317  the distance with a trailing NACK, and
318  keeps doing that even when the target comes
319  into a valid range.
320  */
321  _zero_counter = 0;
324  return reset_sensor();
325  }
326 
327  } else {
328  _zero_counter = 0;
329  }
330 
331  // this should be fairly close to the end of the measurement, so the best approximation of the time
332  const hrt_abstime timestamp_sample = hrt_absolute_time();
333 
334  // Relative signal strength measurement, i.e. the strength of
335  // the main signal peak compared to the general noise level.
336  uint8_t signal_strength_reg = LL40LS_SIGNAL_STRENGTH_REG;
337  ret = lidar_transfer(&signal_strength_reg, 1, &val[0], 1);
338 
339  // check if the transfer failed
340  if (ret < 0) {
342  /*
343  NACKs from the sensor are expected when we
344  read before it is ready, so only consider it
345  an error if more than 100ms has elapsed.
346  */
347  PX4_INFO("signal strength read failed");
348 
349  DEVICE_DEBUG("error reading signal strength from sensor: %d", ret);
351 
352  if (perf_event_count(_comms_errors) % 10 == 0) {
354  reset_sensor();
355  }
356  }
357 
359  // if we are getting lots of I2C transfer errors try
360  // resetting the sensor
361  return ret;
362  }
363 
364  uint8_t ll40ls_signal_strength = val[0];
365 
366  uint8_t signal_min = 0;
367  uint8_t signal_max = 0;
368  uint8_t signal_value = 0;
369 
370  // We detect if V3HP is being used
371  if (_is_v3hp) {
372  signal_min = LL40LS_SIGNAL_STRENGTH_MIN_V3HP;
373  signal_max = LL40LS_SIGNAL_STRENGTH_MAX_V3HP;
374  signal_value = ll40ls_signal_strength;
375 
376  } else {
377  // Absolute peak strength measurement, i.e. absolute strength of main signal peak.
378  uint8_t peak_strength_reg = LL40LS_PEAK_STRENGTH_REG;
379  ret = lidar_transfer(&peak_strength_reg, 1, &val[0], 1);
380 
381  // check if the transfer failed
382  if (ret < 0) {
384  /*
385  NACKs from the sensor are expected when we
386  read before it is ready, so only consider it
387  an error if more than 100ms has elapsed.
388  */
389  PX4_INFO("peak strength read failed");
390 
391  DEVICE_DEBUG("error reading peak strength from sensor: %d", ret);
393 
394  if (perf_event_count(_comms_errors) % 10 == 0) {
396  reset_sensor();
397  }
398  }
399 
401  // if we are getting lots of I2C transfer errors try
402  // resetting the sensor
403  return ret;
404  }
405 
406  uint8_t ll40ls_peak_strength = val[0];
407  signal_min = LL40LS_PEAK_STRENGTH_LOW;
408  signal_max = LL40LS_PEAK_STRENGTH_HIGH;
409 
410  // For v2 and v3 use ll40ls_signal_strength (a relative measure, i.e. peak strength to noise!) to reject potentially ambiguous measurements
411  if (ll40ls_signal_strength <= LL40LS_SIGNAL_STRENGTH_LOW) {
412  signal_value = 0;
413 
414  } else {
415  signal_value = ll40ls_peak_strength;
416  }
417  }
418 
419  // Final data quality evaluation. This is based on the datasheet and simple heuristics retrieved from experiments
420  // Step 1: Normalize signal strength to 0...100 percent using the absolute signal peak strength.
421  uint8_t signal_quality = 100 * math::max(signal_value - signal_min, 0) / (signal_max - signal_min);
422 
423  // Step 2: Filter physically impossible measurements, which removes some crazy outliers that appear on LL40LS.
424  if (distance_m < LL40LS_MIN_DISTANCE) {
425  signal_quality = 0;
426  }
427 
428  _px4_rangefinder.update(timestamp_sample, distance_m, signal_quality);
429 
431  return OK;
432 }
433 
435 {
436  // reset the report ring and state machine
437  _collect_phase = false;
438 
439  // schedule a cycle to start things
440  ScheduleNow();
441 }
442 
444 {
445  ScheduleClear();
446 }
447 
449 {
450  /* collection phase? */
451  if (_collect_phase) {
452 
453  /* try a collection */
454  if (OK != collect()) {
455  PX4_DEBUG("collection error");
456 
457  /* if we've been waiting more than 200ms then
458  send a new acquire */
460  _collect_phase = false;
461  }
462 
463  } else {
464  /* next phase is measurement */
465  _collect_phase = false;
466 
467  /*
468  * Is there a collect->measure gap?
469  */
471 
472  /* schedule a fresh cycle call when we are ready to measure again */
474 
475  return;
476  }
477  }
478  }
479 
480  if (_collect_phase == false) {
481  /* measurement phase */
482  if (OK != measure()) {
483  PX4_DEBUG("measure error");
484 
485  } else {
486  /* next phase is collection. Don't switch to
487  collection phase until we have a successful
488  acquire request I2C transfer */
489  _collect_phase = true;
490  }
491  }
492 
493  /* schedule a fresh cycle call when the measurement is done */
494  ScheduleDelayed(LL40LS_CONVERSION_INTERVAL);
495 }
void set_max_distance(const float distance)
int collect() override
static constexpr uint32_t LL40LS_CONVERSION_INTERVAL
Definition: LidarLite.h:55
static constexpr uint8_t LL40LS_MSRREG_RESET
Definition: LidarLiteI2C.h:59
static constexpr uint8_t LL40LS_SW_VERSION
Definition: LidarLiteI2C.h:64
uint8_t _hw_version
Definition: LidarLiteI2C.h:159
static constexpr uint8_t LL40LS_BASEADDR_OLD
Definition: LidarLiteI2C.h:54
int init() override
void * send(void *data)
LidarLiteI2C(const int bus, const uint8_t rotation=distance_sensor_s::ROTATION_DOWNWARD_FACING, const int address=LL40LS_BASEADDR)
uint8_t _sw_version
Definition: LidarLiteI2C.h:160
int write_reg(const uint8_t reg, const uint8_t &val)
int lidar_transfer(const uint8_t *send, const unsigned send_len, uint8_t *recv, const unsigned recv_len)
LidarLite specific transfer function.
static constexpr uint8_t LL40LS_MEASURE_REG
Definition: LidarLiteI2C.h:58
PX4Rangefinder _px4_rangefinder
Definition: LidarLite.h:88
static constexpr int LL40LS_SIGNAL_STRENGTH_MAX_V3HP
Definition: LidarLiteI2C.h:74
void Run() override
Perform a poll cycle; collect from the previous measurement and start a new one.
static constexpr uint8_t LL40LS_UNIT_ID_HIGH
Definition: LidarLiteI2C.h:67
bool _collect_phase
Definition: LidarLiteI2C.h:155
static constexpr uint8_t LL40LS_SIG_COUNT_VAL_MAX
Definition: LidarLiteI2C.h:71
void update(const hrt_abstime timestamp, const float distance, const int8_t quality=-1)
void perf_count(perf_counter_t handle)
Count a performance event.
static constexpr float LL40LS_MAX_DISTANCE_V2
Definition: LidarLite.h:52
void init()
Activates/configures the hardware registers.
uint32_t get_measure_interval() const
Definition: LidarLite.h:82
int reset_sensor() override
Reset the sensor to power on defaults plus additional configurations.
uint64_t _acquire_time_usec
Definition: LidarLiteI2C.h:165
virtual ~LidarLiteI2C()
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
static hrt_abstime hrt_elapsed_time(const hrt_abstime *then)
Compute the delta between a timestamp taken in the past and now.
Definition: drv_hrt.h:102
perf_counter_t _sensor_zero_resets
Definition: LidarLite.h:95
static constexpr uint8_t LL40LS_AUTO_INCREMENT
Definition: LidarLiteI2C.h:62
static constexpr uint8_t LL40LS_SIG_COUNT_VAL_DEFAULT
Definition: LidarLiteI2C.h:55
void perf_end(perf_counter_t handle)
End a performance event.
static constexpr int LL40LS_PEAK_STRENGTH_LOW
Definition: LidarLiteI2C.h:77
perf_counter_t _sample_perf
Definition: LidarLite.h:93
int measure() override
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
static constexpr uint8_t LL40LS_UNIT_ID_LOW
Definition: LidarLiteI2C.h:68
uint16_t _unit_id
Definition: LidarLiteI2C.h:162
uint16_t _zero_counter
Definition: LidarLiteI2C.h:163
static constexpr int LL40LS_SIGNAL_STRENGTH_LOW
Definition: LidarLiteI2C.h:76
void print_registers() override
Print sensor registers to console for debugging.
static constexpr uint8_t LL40LS_SIGNAL_STRENGTH_REG
Definition: LidarLiteI2C.h:65
int read_reg(const uint8_t reg, uint8_t &val)
static constexpr uint8_t LL40LS_BASEADDR
Definition: LidarLiteI2C.h:53
static constexpr int LL40LS_PEAK_STRENGTH_HIGH
Definition: LidarLiteI2C.h:78
void stop() override
Stop the automatic measurement state machine.
perf_counter_t _sensor_resets
Definition: LidarLite.h:94
static constexpr int LL40LS_SIGNAL_STRENGTH_MIN_V3HP
Definition: LidarLiteI2C.h:73
static constexpr uint8_t LL40LS_SIG_COUNT_VAL_REG
Definition: LidarLiteI2C.h:70
static constexpr uint8_t LL40LS_HW_VERSION
Definition: LidarLiteI2C.h:63
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
static constexpr uint8_t LL40LS_PEAK_STRENGTH_REG
Definition: LidarLiteI2C.h:66
uint64_t perf_event_count(perf_counter_t handle)
Return current event_count.
static constexpr uint8_t LL40LS_DISTHIGH_REG
Definition: LidarLiteI2C.h:61
static constexpr uint8_t LL40LS_MSRREG_ACQUIRE
Definition: LidarLiteI2C.h:60
Definition: bst.cpp:62
void start() override
Initialise the automatic measurement state machine and start it.
static constexpr float LL40LS_MIN_DISTANCE
Definition: LidarLite.h:50
perf_counter_t _comms_errors
Definition: LidarLite.h:92
static constexpr uint32_t LL40LS_CONVERSION_TIMEOUT
Definition: LidarLite.h:58
#define OK
Definition: uavcan_main.cpp:71
bool _pause_measurements
Definition: LidarLiteI2C.h:157
void perf_begin(perf_counter_t handle)
Begin a performance event.
#define DEVICE_DEBUG(FMT,...)
Definition: Device.hpp:52
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
int probe() override