GARMIN Lidar Lite V3HP

I have purchased the Lidar lite v3HP last week and I am testing it on Arduino code using the i2c , and I am getting a “nack”. (Device did not acknowledge). The wiring was done as mentioned in the Garmin datasheet. The green wire (SCL), blue wire (SDA), the red wire in +5V, and the black wire to GND. Also, I have a decoupling capacitor between the power wires. Here is the code I am using:

/*------------------------------------------------------------------------------

  LIDARLite Arduino Library
  v3HP/v3HP_I2C

  This example shows methods for running the LIDAR-Lite v3 HP in various
  modes of operation. To exercise the examples open a serial terminal
  program (or the Serial Monitor in the Arduino IDE) and send ASCII
  characters to trigger the commands. See "loop" function for details.

  Connections:
  LIDAR-Lite 5 Vdc (red) to Arduino 5v
  LIDAR-Lite I2C SCL (green) to Arduino SCL
  LIDAR-Lite I2C SDA (blue) to Arduino SDA
  LIDAR-Lite Ground (black) to Arduino GND

  (Capacitor recommended to mitigate inrush current when device is enabled)
  680uF capacitor (+) to Arduino 5v
  680uF capacitor (-) to Arduino GND

  See the Operation Manual for wiring diagrams and more information:
  http://static.garmin.com/pumac/LIDAR_Lite_v3HP_Operation_Manual_and_Technical_Specifications.pdf

------------------------------------------------------------------------------*/

#include <stdint.h>
#include <Wire.h>
#include <LIDARLite_v3HP.h>

LIDARLite_v3HP myLidarLite;

#define FAST_I2C

enum rangeType_T
{
    RANGE_NONE,
    RANGE_SINGLE,
    RANGE_CONTINUOUS,
    RANGE_TIMER
};

void setup()
{
    // Initialize Arduino serial port (for display of ASCII output to PC)
    Serial.begin(115200);

    // Initialize Arduino I2C (for communication to LidarLite)
    Wire.begin();
    #ifdef FAST_I2C
        #if ARDUINO >= 157
            Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
        #else
            TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
        #endif
    #endif

    // Configure the LidarLite internal parameters so as to lend itself to
    // various modes of operation by altering 'configure' input integer to
    // anything in the range of 0 to 5. See LIDARLite_v3HP.cpp for details.
    myLidarLite.configure(0);
}


void loop()
{
    uint16_t distance;
    uint8_t  newDistance = 0;
    uint8_t  c;
    rangeType_T rangeMode = RANGE_NONE;

    PrintMenu();

    // Continuous loop
    while (1)
    {
        // Each time through the loop, look for a serial input character
        if (Serial.available() > 0)
        {
            //  read input character ...
            c = (uint8_t) Serial.read();

            // ... and parse
            switch (c)
            {
                case 'S':
                case 's':
                    rangeMode = RANGE_SINGLE;
                    break;

                case 'C':
                case 'c':
                    rangeMode = RANGE_CONTINUOUS;
                    break;

                case 'T':
                case 't':
                    rangeMode = RANGE_TIMER;
                    break;

                case '.':
                    rangeMode = RANGE_NONE;
                    break;

                case 'D':
                case 'd':
                    rangeMode = RANGE_NONE;
                    dumpCorrelationRecord();
                    break;

                case 'P':
                case 'p':
                    rangeMode = RANGE_NONE;
                    peakStackExample();
                    break;

                case 0x0D:
                case 0x0A:
                    break;

                default:
                    rangeMode = RANGE_NONE;
                    PrintMenu();
                    break;
            }
        }

        switch (rangeMode)
        {
            case RANGE_NONE:
                newDistance = 0;
                break;

            case RANGE_SINGLE:
                newDistance = distanceSingle(&distance);
                break;

            case RANGE_CONTINUOUS:
                newDistance = distanceContinuous(&distance);
                break;

            case RANGE_TIMER:
                delay(250); // 4 Hz
                newDistance = distanceFast(&distance);
                break;

            default:
                newDistance = 0;
                break;
        }

        // When there is new distance data, print it to the serial port
        if (newDistance)
        {
            Serial.println(distance);
        }

        // Single measurements print once and then stop
        if (rangeMode == RANGE_SINGLE)
        {
            rangeMode = RANGE_NONE;
        }
    }
}

void PrintMenu(void)
{
    Serial.println("=====================================");
    Serial.println("== Type a single character command ==");
    Serial.println("=====================================");
    Serial.println(" S - Single Measurement");
    Serial.println(" C - Continuous Measurement");
    Serial.println(" T - Timed Measurement");
    Serial.println(" . - Stop Measurement");
    Serial.println(" D - Dump Correlation Record");
    Serial.println(" P - Peak Stack Example");
}

//---------------------------------------------------------------------
// Read Single Distance Measurement
//
// This is the simplest form of taking a measurement. This is a
// blocking function as it will not return until a range has been
// taken and a new distance measurement can be read.
//---------------------------------------------------------------------
uint8_t distanceSingle(uint16_t * distance)
{
    // 1. Wait for busyFlag to indicate device is idle. This must be
    //    done before triggering a range measurement.
    myLidarLite.waitForBusy();

    // 2. Trigger range measurement.
    myLidarLite.takeRange();

    // 3. Wait for busyFlag to indicate device is idle. This should be
    //    done before reading the distance data that was triggered above.
    myLidarLite.waitForBusy();

    // 4. Read new distance data from device registers
    *distance = myLidarLite.readDistance();

    return 1;
}

//---------------------------------------------------------------------
// Read Continuous Distance Measurements
//
// The most recent distance measurement can always be read from
// device registers. Polling for the BUSY flag in the STATUS
// register can alert the user that the distance measurement is new
// and that the next measurement can be initiated. If the device is
// BUSY this function does nothing and returns 0. If the device is
// NOT BUSY this function triggers the next measurement, reads the
// distance data from the previous measurement, and returns 1.
//---------------------------------------------------------------------
uint8_t distanceContinuous(uint16_t * distance)
{
    uint8_t newDistance = 0;

    // Check on busyFlag to indicate if device is idle
    // (meaning = it finished the previously triggered measurement)
    if (myLidarLite.getBusyFlag() == 0)
    {
        // Trigger the next range measurement
        myLidarLite.takeRange();

        // Read new distance data from device registers
        *distance = myLidarLite.readDistance();

        // Report to calling function that we have new data
        newDistance = 1;
    }

    return newDistance;
}

//---------------------------------------------------------------------
// Read Distance Measurement, Quickly
//
// Read distance. The approach is to poll the status register until the device goes
// idle after finishing a measurement, send a new measurement command, then read the
// previous distance data while it is performing the new command.
//---------------------------------------------------------------------
uint8_t distanceFast(uint16_t * distance)
{
    // 1. Wait for busyFlag to indicate device is idle. This must be
    //    done before triggering a range measurement.
    myLidarLite.waitForBusy();

    // 2. Trigger range measurement.
    myLidarLite.takeRange();

    // 3. Read previous distance data from device registers.
    //    After starting a measurement we can immediately read previous
    //    distance measurement while the current range acquisition is
    //    ongoing. This distance data is valid until the next
    //    measurement finishes. The I2C transaction finishes before new
    //    distance measurement data is acquired.
    *distance = myLidarLite.readDistance();

    return 1;
}

//---------------------------------------------------------------------
// Print the correlation record for analysis
//---------------------------------------------------------------------
void dumpCorrelationRecord()
{
    myLidarLite.correlationRecordToSerial(256);
}

//---------------------------------------------------------------------
// Print peaks and calculated distances from the peak stack
//---------------------------------------------------------------------
void peakStackExample()
{
    int16_t   peakArray[8];
    int16_t   distArray[8];
    uint8_t   i;

    // - Read the Peak Stack.
    // - Peaks and calculated distances are returned in local arrays.
    // - See library function for details on the makeup of the stack
    //   and how distance data is created from the stack.
    myLidarLite.peakStackRead(peakArray, distArray);

    // Print peaks and calculated distances to the serial port.
    Serial.println();
    Serial.println("IDX PEAK DIST");
    for (i=0 ; i<8 ; i++)
    {
        Serial.print(i);
        Serial.print("   ");
        Serial.print(peakArray[i]);
        Serial.print("  ");
        Serial.print(distArray[i]);
        Serial.println();
    }
}

What I am getting is:

Also, I have tried using the PWM example code:

/*------------------------------------------------------------------------------

  LIDARLite Arduino Library
  v3HP/v3HP_PWM

  This example shows how to read distance from a LIDAR-Lite connected over the
  PWM interface.

  Connections:
  LIDAR-Lite 5 Vdc (red) to Arduino 5v
  LIDAR-Lite Ground (black) to Arduino GND
  LIDAR-Lite Mode control (yellow) to Arduino digital input (pin 3)
  LIDAR-Lite Mode control (yellow) to 1 kOhm resistor lead 1
  1 kOhm resistor lead 2 to Arduino digital output (pin 2)

  Optional Connections -
      LIDAR-Lite I2C SCL (green) to Arduino SCL
      LIDAR-Lite I2C SDA (blue) to Arduino SDA

  (Capacitor recommended to mitigate inrush current when device is enabled)
  680uF capacitor (+) to Arduino 5v
  680uF capacitor (-) to Arduino GND

  See the Operation Manual for wiring diagrams and more information:
  http://static.garmin.com/pumac/LIDAR-Lite_v3HP_Instructions_EN.pdf
------------------------------------------------------------------------------*/

#include <stdint.h>
#include <Wire.h>
#include "LIDARLite_v3HP.h"

LIDARLite_v3HP myLidarLite;

#define MonitorPin    5
#define TriggerPin    2

uint32_t distance;
uint32_t startTime;
uint32_t endTime;
bool     newDistance = false;
bool     measuring   = false;

// -----------------------------------------
// Add in the #define below to illustrate
// optional use of I2C during PWM mode
// -----------------------------------------
//#define USE_I2C

void setup()
{
    Serial.begin(115200); // Start serial communications

    #ifdef USE_I2C
        // Initialize Arduino I2C (for communication to LidarLite)
        Wire.begin();
        Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
    #endif

    pinMode(MonitorPin, INPUT);
    pinMode(TriggerPin, OUTPUT);
    digitalWrite(TriggerPin, LOW); // Set trigger LOW for continuous read

    startTime = micros();
    endTime   = startTime;
}

void loop()
{
    if (digitalRead(MonitorPin))
    {
        if (measuring == false)
        {
            startTime   = micros();
            measuring   = true;
        }
    }
    else
    {
        if (measuring == true)
        {
            endTime     = micros();
            measuring   = false;
            newDistance = true;
        }
    }

    // If we get a new reading, print it
    if (newDistance == true)
    {
        distance = (endTime - startTime) / 10; // 10usec = 1 cm of distance
        Serial.println(distance); // Print measured distance

        #ifdef USE_I2C
            uint8_t  signalStrength = 0;
            myLidarLite.read(0x0e, &signalStrength, 1);
            Serial.print("SS = ");
            Serial.println(signalStrength, DEC);
            Serial.println();
        #endif

        newDistance = false;
    }
}

Here, I got interesting results as shown:

I don’t know what is going on.

Your help is highly appreciated

Did you also include the pull-up resistors on SDA and SCL line ?

No, I did not add the pull-up resistors. I thought it is optional!

You always need pull-up with I2C, but sometimes they are already on the board. I have to agree it is a little confusing the way is described in the operating manual and hookup guide. Anything between 4K7 to 10K will do. Both on SDA and SCL to 5V, unless you CPU board can handle only 3V3 on the pins, than they need to be to 3V3.

Thanks, Paul for responding,

I have added two pull-ups (5K each) but the results were the same “nack” as you can see in the attached image(lidar1.png).


I tried also using the pwm method, I was running the pwm example code that comes with the Lidar Lite v3HP library, and the results were very strange. Please have a look at the attached image Lidar2.png.

Now I am wondering about the firmware of the sensor itself!

I don’t know what to do!

can you share some pictures… this looks to me as basic connection / cabling.

Hi Paul,

I have prepared two sets of pictures. The first is for I2C wiring, and screen pics for code runs. The second is for the PWM wiring and also a screen pic for the code run and an excel graph for the results.

Here is the general wiring and the cap to the unit:

In this picture, you will see the wiring and the pull-ups

These are screenshots for running two example codes (v3HP_I2C and v3HP_MONITOR) that are in the Lidar_lite library:


The second set will be in another post because we are limited to only three attachments!

Best Regards,

Wael

For the PWM here are the pics. The first and second pics are self explanatory.

The screenshots for running the example code, and an excel chart for the results:


The lidar was pointing to the ceiling of my homeoffice, which is at 189cm. The numbers in the screen are strange but it contains the correct value in the second of third reading!

I would appreciate your help on that.

Thanks

Wael

Verify with an ohmmeter that those are really 1k resistors. It may be the camera but they look more like 100 ohms. 1k would be brown-black-red. For I2C, I would usually use 4.7k or 2.2k resistors.

/mike

Hi Mike,

The resistors are 5.1k (Green, Brown, Red, Gold).

If I look at a picture (PWM_PIC2), it seems that 3V3 is used for power connection. According to the datasheet “The sensor operates at 4.75 through 5.5 Vdc, with a max. of 6 Vdc”. Could that be the issue ?

For I2C try to use the I2C scanner and see whether the Lidar is detected (https://playground.arduino.cc/Main/I2cScanner/)

Hi Paul,

I think this a visual effect due to the camera pointing angle. If look carefully at the pic before you can see that it is connected to the 5V pin.

I have added the same pic with clarification.

Thanks that is better to see.

Did you try the I2C scanner. Nack on I2C is a very basic protocol error. It could be a incorrect I2C address that is used or still a pull-up issue. Also check that the SDA and SCL line are 5V when NO communication is happening… it could still be an issue with the Lidar…

I tried to measure the voltage on the SDA & SLA without connecting the Lidar and the pullups while running the code. The readings on both were 4.94V (~ 5V).

I did not get a chance to run the I2C scanner, I think it might be an I2C address issue. I will try and let you know the results.

I have connected the Lidar again with the pull-ups and used the following I2C scanning code:

// ---------------------------------------------------------------- /
// Arduino I2C Scanner
// Re-written by Arbi Abdul Jabbar
// Using Arduino IDE 1.8.7
// Using GY-87 module for the target
// Tested on 10 September 2019
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
// ---------------------------------------------------------------- /

#include <Wire.h> //include Wire.h library

void setup()
{
  Wire.begin(); // Wire communication begin
  Serial.begin(9600); // The baudrate of Serial monitor is set in 9600
  while (!Serial); // Waiting for Serial Monitor
  Serial.println("\nI2C Scanner");
}

void loop()
{
  byte error, address; //variable for error and I2C address
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");
      nDevices++;
    }
    else if (error == 4)
    {
      Serial.print("Unknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000); // wait 5 seconds for the next I2C scan
}

The results are shown in the following screenshots:

and here is another screenshot,

Now, I don’t know what is causing this problem?

Is it the Lidar itself? The firmware? Or what?

Thanks, Paul for your patience and Best Regards

Wael

Honestly… if the connected power is good, the pull-up’s is good and it can not be detected… I am concerned about the Hardware.

If you have any other I2C sensor, try that with I2Cdetect on your board.

Maybe you know someone that has another MCU board and you can try to connect the Lidar and detect with I2Cdetect.

Hmm, that seems odd. Here are some of my thoughts.

I agree with “paulvha.” You seem to be approaching it correctly to troubleshoot the issue by adding pull-up resistors, using a capacitor, scanning the I2C bus to see if the LIDAR is connected, and soldering to the LIDAR-Lite’s wires. The next step in troubleshooting that I would try is to:

  • use another microcontroller with ATmega328P (the one that you are using seems to be a generic Arduino Uno that I have not seen before?)

  • adjusting the pull-up resistor values (this can vary depending on your cable capacitance and devices on the I2C bus)

  • trying a different breadboard

  • check your soldered connections to ensure that it is sufficiently spliced and soldered to the wires

  • ensure that your power supply is sufficient

I did notice that your are inserting the female sockets into male header pins. If you are using the [straight male header pins [PRT-00116], you may have an issue with the connection. While the longer side is connecting, the shorter side of the header might not be fully inserted into the breadboard or jumper wire’s socket? You may want to consider [longer centered headers [PRT-12693] . You can also try adding another M/M jumper wire instead of the header pin (since you probably have that available).](https://www.sparkfun.com/products/12693)](Break Away Headers - Straight - PRT-00116 - SparkFun Electronics)

Hi, bboyhu,

Thanks for your input and sorry for the delay in getting back to you, I was busy with other tasks.

Ok regarding your suggestions:

1- I have tried using another MCUs with ATmega328P and using mega2560, as seen in the pictures below, note: the run results screenshots are attached to the same picture.

The results in both cases were the same “nack”

2- I tried another breadboard as shown

3-I check my connections using the Avometer before connecting and everything is ok

4- The power supply is reading 5.0v

The header pins I am using are the long ones.

If you look at my try using the PWM example, the Lidar is working but there is something seriously wrong with. Look at the results, it is increasing exponentially, then it halts for a while(self reboot) then it starts giving values again. Look at the results I have obtained in an earlier trial:


Then, as Paul said, the only thing left is that the Lidar unit might be defective!

What do you think?

I think you should request a replacement for the LIdar unit

hi Paul,

I have submitted an RMA, is this the correct action?