Hi All
just received my Lidar lite V4 LED and im struggling to get this device up and running on my ESP32 (lilygo Oled Lora board). Lidar unit is supplied 3.3v and tried adapting some very basic code i found on internet (was for Arduino’s) even tried recruiting ChatGPT (sorry im a complete newbie), but wondering if anyone has some very basic code that will work with my ESP32 and LIdar just to show on serial monitor so i can branch out from there. My limited experience in coding has me going around in circles and down rabbit holes at the moment. Thanks in advance.
Hi @Phil210256
Welcome to the forum!
I’ve had a play around with one of these sensors from our shelf stock and I didn’t have any luck using the Arduino libraries from Garmin’s github. I was though able to put together a very basic library in Micropython that work for getting distances, if you copy the below code into thonny, save it to your esp32 and name it lidar.py it will work as a library.
class LidarLiteV4LED:
def __init__(self, i2c, address=0x62):
self.i2c = i2c
self.address = address
def _write_register(self, register, value):
self.i2c.writeto_mem(self.address, register, bytearray([value]))
def _read_register(self, register, num_bytes=1):
return self.i2c.readfrom_mem(self.address, register, num_bytes)
def begin(self):
"""Initializes the sensor to default settings."""
# Optionally implement any initialization routines here
pass
def start_measurement(self):
"""Initiates a distance measurement."""
ACQ_COMMAND = 0x00
MEASURE_COMMAND = 0x03
self._write_register(ACQ_COMMAND, MEASURE_COMMAND)
def read_distance(self):
"""Reads distance data from the sensor."""
DISTANCE_MSB = 0x10
DISTANCE_LSB = 0x11
msb = self._read_register(DISTANCE_MSB, 1)[0]
lsb = self._read_register(DISTANCE_LSB, 1)[0]
distance = (msb << 4) + lsb
return distance
def get_status(self):
"""Reads the status register."""
STATUS = 0x01
return self._read_register(STATUS, 1)
This example code will work for measuring distance and output to serial with a measurement in millimeters.
from machine import I2C, Pin
from lidar import LidarLiteV4LED
import time
# Initialize I2C interface
i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=400000) # Change the specific pins to match your device
# Initialize the sensor
lidar = LidarLiteV4LED(i2c)
# Main loop to read distance continuously
while True:
lidar.start_measurement()
time.sleep(0.02) # Give some time for the measurement to be taken
distance = lidar.read_distance()
print(f"Distance: {distance} mm")
time.sleep(1)
Awesome thanks so much for your effort and help, i’ll give that a try tonight and report back cheers
Hey Dan I have converted to work with Arduino IDE and i now have reading on the Serial monitor although distances in “mm” are not close to what ‘actual’ distances are … is that a result of my converting or perhaps the original code/library wasnt actually setup to read the ‘actual’ distances themselves.
Here is my .h code:
#ifndef LIDARLITEV4LED_H
#define LIDARLITEV4LED_H
#include <Wire.h>
class LidarLiteV4LED {
public:
LidarLiteV4LED(uint8_t address = 0x62); // Constructor with default I2C address
void begin(); // Initialize the sensor
void startMeasurement(); // Start a distance measurement
uint16_t readDistance(); // Read the distance in mm
uint8_t getStatus(); // Get the sensor status
private:
uint8_t _address; // I2C address
void writeRegister(uint8_t reg, uint8_t value); // Write to a register
uint8_t readRegister(uint8_t reg); // Read a single byte from a register
uint16_t readRegister16(uint8_t reg); // Read a 16-bit value from two registers
};
#endif
and the .cpp file:
#include "LidarLiteV4LED.h"
LidarLiteV4LED::LidarLiteV4LED(uint8_t address) {
_address = address;
}
void LidarLiteV4LED::begin() {
Wire.begin(); // Initialize I2C
}
void LidarLiteV4LED::startMeasurement() {
const uint8_t ACQ_COMMAND = 0x00;
const uint8_t MEASURE_COMMAND = 0x03;
writeRegister(ACQ_COMMAND, MEASURE_COMMAND);
}
uint16_t LidarLiteV4LED::readDistance() {
const uint8_t DISTANCE_MSB = 0x10;
const uint8_t DISTANCE_LSB = 0x11;
uint8_t msb = readRegister(DISTANCE_MSB);
uint8_t lsb = readRegister(DISTANCE_LSB);
return (msb << 8) | lsb;
}
uint8_t LidarLiteV4LED::getStatus() {
const uint8_t STATUS_REG = 0x01;
return readRegister(STATUS_REG);
}
void LidarLiteV4LED::writeRegister(uint8_t reg, uint8_t value) {
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}
uint8_t LidarLiteV4LED::readRegister(uint8_t reg) {
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.endTransmission(false); // Send repeated start condition
Wire.requestFrom(_address, (uint8_t)1);
if (Wire.available()) {
return Wire.read();
}
return 0;
}
uint16_t LidarLiteV4LED::readRegister16(uint8_t reg) {
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.endTransmission(false); // Send repeated start condition
Wire.requestFrom(_address, (uint8_t)2);
if (Wire.available() >= 2) {
uint8_t msb = Wire.read();
uint8_t lsb = Wire.read();
return (msb << 8) | lsb;
}
return 0;
}
Hey @Phil210256,
Thats some great progress!
Would you be able to share the output of this code as well as the distance the output is meant to represent so we can help you figure this out?
here is some code that displays the distance on little Lilygo Lora with Oled, ended up with some calibration weird number to get it around about what it should read as i wasnt sure what your library, code and the Lidar was actually supposed to output.
#include <Wire.h>
#include "LidarLiteV4LED.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
LidarLiteV4LED lidar;
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
// Initialize I2C for Lidar and OLED
Wire.begin(21, 22); // SDA -> GPIO 21, SCL -> GPIO 22
// Initialize the OLED display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64
Serial.println("OLED initialization failed!");
while (true);
}
// Clear the display buffer
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Initializing LIDAR...");
display.display();
// Initialize the Lidar sensor
lidar.begin();
display.clearDisplay();
display.setCursor(0, 0);
display.println("LIDAR initialized.");
display.display();
Serial.println("LIDAR initialized.");
}
// Function to get smoothed distance
float getSmoothedDistance(int samples) {
float totalDistance = 0;
int validSamples = 0;
for (int i = 0; i < samples; i++) {
lidar.startMeasurement();
delay(20); // Wait for the measurement to complete
uint16_t rawDistance = lidar.readDistance();
if (rawDistance > 0) {
totalDistance += rawDistance;
validSamples++;
} else {
Serial.println("Invalid measurement, skipping...");
}
delay(10); // Short delay between samples
}
return (validSamples > 0) ? (totalDistance / validSamples) / 233.5 : -1; // Average and scale
}
void loop() {
float smoothedDistance = getSmoothedDistance(5); // Average over 5 samples
// Display distance on Serial Monitor
if (smoothedDistance > 0) {
Serial.print("Smoothed Distance: ");
Serial.print(smoothedDistance, 1); // Display one decimal place
Serial.println(" cm");
} else {
Serial.println("Failed to obtain a valid smoothed distance.");
}
// Display distance on OLED
display.clearDisplay();
// Display "Distance" label on top line
display.setTextSize(1); // Small font size
display.setCursor((SCREEN_WIDTH - 7 * 8) / 2, 0); // Center "Distance"
display.println("Distance");
// Display the distance value in a larger font below
display.setTextSize(2); // Large font size
if (smoothedDistance > 0) {
String distanceStr = String(smoothedDistance, 1) + " cm";
int16_t x = (SCREEN_WIDTH - (distanceStr.length() * 12)) / 2; // Center the text
display.setCursor(x, 24);
display.println(distanceStr);
} else {
String errorStr = "Invalid";
int16_t x = (SCREEN_WIDTH - (errorStr.length() * 12)) / 2; // Center the text
display.setCursor(x, 24);
display.println(errorStr);
}
display.display();
delay(500); // Delay for readability
}
Hi @Phil210256
Glad to hear that you got the sensor working.
raw values were around 48000 and known distance was 195cm
Hi @Phil210256
With this one it will depend, if the results are linear you should be able to divide the raw output by 246 to get the value in cm. If it isn’t linear it may require so more math to make it work.
Easiest way to determine if it is linear or not would be to take another known distance measurement and see if you get the correct result by dividing by 246.
Hi All
Just noticed these last couple of posts
Pretty suspicious.
now 4800 / 246 results in 19.5cm
This is an error of 10X.
2 things spring to mind here.
One is the number of 246 maybe should be 24.6.
Second is if the actual distance was 195mm (19.5cm)
Worth thinking about. A bit much of a coincidence I think.
Cheers Bob
While I’m going with Bob on this one… I like it when numbers look good.
IF you find it does note make sense then you could try some math.
If we go with an assumption of a curve you would have the equation of
y = ax^2 + bx +c
Where y is the actual distance and x is the value read from the unit.
That leaves 3 unknowns, a, b and c.
So to solve you need 3 samples of x and y.
So if you can take 3 readings of x and record the actual distance y, then with the use of simultaneous equations math you should be able to derive a b and c
Even if linear you should get the equation.
Im happy to have a go at the math if needed, just supply the values
Hi Bob,
Is the change from 48,000 (forty-eight thousand) to 4,800 (four thousand eight hundred) intentional?
Looks to me like that missing zero may be the culprit.
Either way @Dan’s advice to test a few different distances is still a good idea to better understand what the raw data represents.
Hope this helps!
Hi All
Oops, sorry, my stupid mistake.Just got new spectacles too can I blame them.
My apologies to all. This accounts for the X 10 error. 48000/246 does equal 195 so once again sorry for any trouble caused.
Cheers Bob
Hi Phil.
As posted earlier I apologised for the missing “0”.
I just had a look at the data sheet for that device and noted the following.
And the data sheet. A section of the first table
And on the same page
I don’t know what you make of that but I would interpret that to mean the operating voltage or power input (Normally VIN) would be 5V and the logic 3.3V but the first table says VIN 3.3V. Hard to make out what is correct here as the first table says Power (operating voltage) 4.75V to 5.25V.
this should be clarified.
Maybe you need to power this device with 5V. The way I read your post you are powering with 3.3V.
Cheers Bob
According to the schematic it is designed to be run from the 3.3V at the Qwiic connector. U1 is the 5V boost for the Lidar chip. AFAICT the 5V is not brought out to any pins.
Hi Jeff
That might be so for the Qwiic version. But the part number supplied in the original post comes up as the NON Qwiic version and I have not seen anything to change this.
Don’t know. But those tables strike me as being a bit odd anyway.
Cheers Bob
Then you have the advantage of me because I can’t see a part number in the original post. Do you have a link to the page for that part number?
Hi Jeff
Not the SKU number but the model. In the very first line.
I just looked up the bit “Lidar lite V4 LED” and only came up with the version without the Qwiic which looks like an add on. I was just assuming it is not on the version in question as I think the qwiic version has the suffix “Qwiic” attached to the end of the type number.
This also appears on the Core product text.
“The LIDAR-Lite v4 requires an external 5VDC power source and soldering is required.”
So unless I am really going senile I think 5V is required.
Cheers Bob
hi there, running 3.3v on the unit, it has the small add on board that has the step up to run then unit. i am getting some values out of it i;ll have to do some testing over linear distances to see if they are linear values. Seems there isnt any ESP32 libaries for this devices so with the help of this forum was able to get some assistnace to at least get some values flowing . Cheers