Teensy 3.2 - I2C and PWM issues with Lidar Lite V3

Status
Not open for further replies.

Elbarfo

Member
Hello all,

I have 2 Lidar Lite v3's connected together in an attempt to make a spinning lidar using a teensy 3.2. I had originally tried this on an Arduino Nano, but it seemed to need a little more horsepower.

I can get the units to communicate, can readdress them and get telemetry via I2C, but I have 2 issues:

1st: I am using PWM to drive a MOSFET for the motor that spins the lidar. As soon as I activate PWM output on any pin (I say any but I tested 3) my I2C immediately goes all nacks. Pretty solid until I activate the PWM output, though it does eventually fail at some point much later.

2nd: I am getting rather slow results from the units, at around 100 reads\s from both units combined. Garmin says typical should be over 250/s (600/s with high speed) and I'd assume since I have 2 I'd get close to twice that. Is there some trick to getting these to update faster? I have tried standard mode and higher speed standard mode, but not full High speed as I need better longer range performance. I am using 400k I2C.

Code is below: (note: I have modified the lidar lite library to work with the i2c_t3 libraries.) This is just a basic sketch that addresses the two units and begins getting readings. I'ts nearly a copy of the default lidarLite sketch tests.

I'm hoping there are people here who have experience with both the lidar lites and teensy's. Any advice or help would be greatly appreciated. Thanks!

/*
Initial setup and port of testing routines to teensy 3.2
*/
#include <Arduino.h>
#include <i2c_t3.h>
#include <LIDARLite.h>

LIDARLite myLidarLite;
byte add1[1];
byte add2[1];
byte arr[1];


void setup() {

Serial.begin(115200); // Initialize serial connection to display distance readings
/*
begin(int configuration, bool fasti2c, char lidarliteAddress)
Starts the sensor and I2C.
Parameters
----------------------------------------------------------------------------
configuration: Default 0. Selects one of several preset configurations.
fasti2c: Default 100 kHz. I2C base frequency.
If true I2C frequency is set to 400kHz.
lidarliteAddress: Default 0x62. Fill in new address here if changed. See
operating manual for instructions.
*/
Wire.setDefaultTimeout(200);
myLidarLite.begin(2, true); // Set configuration to higher speed normal and I2C to 400 kHz
SetAddresses();
delay(2000);
runScan();
//delay(2000);
/*
configure(int configuration, char lidarliteAddress)
Selects one of several preset configurations.
Parameters
----------------------------------------------------------------------------
configuration: Default 0.
0: Default mode, balanced performance.
1: Short range, high speed. Uses 0x1d maximum acquisition count.
2: Default range, higher speed short range. Turns on quick termination
detection for faster measurements at short range (with decreased
accuracy)
3: Maximum range. Uses 0xff maximum acquisition count.
4: High sensitivity detection. Overrides default valid measurement detection
algorithm, and uses a threshold value for high sensitivity and noise.
5: Low sensitivity detection. Overrides default valid measurement detection
algorithm, and uses a threshold value for low sensitivity and noise.
lidarliteAddress: Default 0x62. Fill in new address here if changed. See
operating manual for instructions.
*/
//myLidarLite.configure(2); // Change this number to try out alternate configurations if not set at begin

// Motor speed control

// analogWrite(3, 80); / This command kills the I2C on pins 3, 22, and 23

}

void SetAddresses()
{
pinMode(14, OUTPUT); pinMode(15, OUTPUT);
LIDARLite myLidarLite;
delay(40);
digitalWrite(14, LOW); //Reset PW_En Pin top LL
Serial.println("top low");
delay(40);
digitalWrite(15, LOW); //Reset PW_EN Pin Bottom LL
Serial.println("bottom low");
delay(40);
digitalWrite(14, HIGH); //En top LL
delay(40);
myLidarLite.setI2Caddr(0x66, true, 0x62);Serial.println("address changed 66"); //Set Top LL Add to 0x66
delay(20);
digitalWrite(15, HIGH); //En bottom LL
delay(40);
myLidarLite.setI2Caddr(0x64, true, 0x62);Serial.println("address changed 64"); //Set Bottom LL Add to 0x64

}

void runScan()
{
byte error, address;
int nDevices;

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

nDevices = 0;
for(address = 1; address < 127; address++ )
{
//Serial.print(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 next scan
}



void loop() {
// put your main code here, to run repeatedly:

Serial.print(myLidarLite.distance(true,0x64));Serial.println(" bottom");
//delay(1);
Serial.print(myLidarLite.distance(true,0x66));Serial.println(" top");
//delay(1);
//Take 99 measurements without receiver bias correction and print to serial terminal
for(int i = 0; i < 99; i++)
{
Serial.println(myLidarLite.distance(false,0x64));
//delay(1);
Serial.println(myLidarLite.distance(false,0x66));
//delay(1);
}
//*/

}
 
I have changed my Lidar code, and still have the same problem.

I have isolated it a little further though. I can have i2C humming along giving me hudreds of measurements a second now, but as soon as I activate PWM on any pin, the I2C dies immediately. If the pin I'm activating is just floating, the I2C will be ok, but the second I try to do anything with the PWM signal, the I2C dies. I've tried using caps to filter the PWM line which cleans up the PWM, but i2C is still dead. Just putting a .1uF cap to ground on the PWM output pin kills the I2C. I have tried this on every 3.2 PWM pin with the same results.

I can either have one or the other so it seems - I2C comm, or a PWM output. I assume that I2C and PWM can be used at the same time on a teensy 3.2, so I'm curious as to what's causing this. Surely there's someone here who's used I2C and PWM at the same time?? At this point I'd just be happy to know they can coexist!
 
Hello Elbarfo,

Is it just the PWM output alone, or the PWM output when the motor is connected? I saw a post where the 680 uF cap on the LIDAR was omitted or wired poorly and caused I2C issues.

By the way, nice code snip......it would help if you'd post the lidarlite.h file I'm currently running a LIDAR Lite, one of the SEEED lidars, and an ultrasound detector on a Teensy 3.2 with no real issues. Though I must say I haven't found how the last parameter works in the Wire.requestFrom call.....
Code:
  nackack = 100;                                    // nackack was 0 after the last I2C transaction, reset it.
  while (nackack != 0) {   
    Wire.beginTransmission(LIDARLite_ADDRESS);
    Wire.write(RegisterHighLowB);                   // Set up Garmin to return data as two sequential I2C reads.
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
  }
  Wire.requestFrom(LIDARLite_ADDRESS, 2, I2C_STOP, 1000 ); //Request 2 bytes from slave (the LIDAR)
  int reading = Wire.readByte() ;
  reading = reading << 8;
  reading |= Wire.readByte();

The 680 uF cap issue is just a hint, in the event the I2C isn't being tested independently from the I2C-MOSFET-Motor combination. Motors are notorious for producing various noise which can (if not controlled through proper power supply wiring topology and adequate bypassing) interfere with I2C and other signals.
 
Last edited:
Thanks for the reply!

I have a 1000uF cap across the 5V power supply for the lidarlites. Didn't have a 680.

Sadly, the I2C dies when the PWM is activated while connected to anything. As long as the pin floats, the I2C will run. I'm getting excellent I2C comms otherwise. Over 1000 measurements a sec with the new Lidar Enhanced library I found. The second I connect the PWM pin to anything, i2C dies. The PWM output is working, and changes as I set it. It's not driving the motor directly. I'm using the PWM output to drive a 3.3-5V level shifter (using a 1n2007 mosfet) to drive a bigger mosfet thats running the motor (which is a small DC12V motor of maybe 20W or so). Just putting a filter cap on the PWM kills the I2C, let alone connecting it to anything else.

I am not using Garmin's Lidarlite.h library anymore, but still have the same problem. Here's the Lidarlite.h file if that helps anything though.

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

LIDARLite Arduino Library
LIDARLite.h

This library provides quick access to all the basic functions of LIDAR-Lite
via the Arduino interface. Additionally, it can provide a user of any
platform with a template for their own application code.

Copyright (c) 2016 Garmin Ltd. or its subsidiaries.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

------------------------------------------------------------------------------*/
#ifndef LIDARLite_h
#define LIDARLite_h

#define LIDARLITE_ADDR_DEFAULT 0x62

#include <Arduino.h>

class LIDARLite
{
public:
LIDARLite();
void begin(int = 0, bool = false, char = LIDARLITE_ADDR_DEFAULT);
void configure(int = 0, char = LIDARLITE_ADDR_DEFAULT);
void setI2Caddr(char, char, char = LIDARLITE_ADDR_DEFAULT);
void reset(char = LIDARLITE_ADDR_DEFAULT);
int distance(bool = true, char = LIDARLITE_ADDR_DEFAULT);
void write(char, char, char = LIDARLITE_ADDR_DEFAULT);
void read(char, int, byte*, bool, char);
void correlationRecordToSerial(char = '\n', int = 256, char = LIDARLITE_ADDR_DEFAULT);
};

#endif
 
"I2C dies" jumps out at me..... do waveforms go to heck? Perhaps you're running the I2C too fast for the pullups you have? With my particular prototype, I got as high as I2C_RATE_1000, which I think is 1MHZ. I'm putzing around here trying to capture what you see on the scope......rise-times (~ 0.4uS) show my pullups are a bit weak. Fall-times are well under 100nS, as they should be. You could possibly slow down the I2C, but if at all possible, get a scope on SCL & or SDA.
 
I'm running the I2C bus at 400KHz. All I'm using are the built in pullups on the LidarLites which are 3k. I haven't tried scoping the I2C lines, I suppose I should.

Here is the Clock prior to connecting the PWM:
BhJmVeL.jpg





Here's what it does after:
tTi54gv.jpg



There appears to be noise on the clock. The data line is pretty hard to lock onto. I'll admit I haven't had much of a need to scope I2C before now. I need to figure out how to lock onto it better. The effect on the data line is very similar. The spike is smaller.
 
This is the code I'm using now. That Enhanced lidar library is really nice compared to garmin's default libraries, btw. As long as PWM isn't connected this thing updates at whatever rate I set. Has no problem keeping up with 2000/s if I set it, but the accuracy is terrible. It tells me the I2C is pretty good, even though this is through a slip ring.

Sd38AFg.jpg



#include "LidarObject.h"
#include "LidarController.h"
#include "I2CFunctions.h"
#include <i2c_t3.h>

#define WIRE400K true
#define Z1_LASER_TRIG 29 // Top LL
#define Z1_LASER_EN 14
#define Z1_LASER_PIN 30
#define Z1_LASER_AD 0x60
#define Z2_LASER_TRIG 33 // Bottom LL
#define Z2_LASER_EN 15
#define Z2_LASER_PIN 32
#define Z2_LASER_AD 0x64
// 100Hz
#define DATARATE 720
#define DELAY_SEND_MICROS 1000000/DATARATE


static LidarController Controller;
static LidarObject LZ1;
static LidarObject LZ2;


// Delays
long now, last;


void initLidars() {
// Initialisation of the lidars objects
LZ1.begin(14,29,30,Z1_LASER_AD,5,DISTANCE,'a');
Serial.println("init 1");
LZ2.begin(15,32,33,Z2_LASER_AD,5,DISTANCE,'b');
Serial.println("init 2");
// Initialisation of the controller
Controller.begin(WIRE400K);
delay(100);
Controller.add(&LZ1, 0);
delay(100);
Controller.add(&LZ2, 1);
}

void setup() {
Serial.begin(57600);

while (!Serial); // for compatibility
initLidars();
last = micros();
pinMode(5,OUTPUT);
//analogWriteResolution(10); // Resolution for PWM is set to 0-1023
//analogWriteFrequency(3,1000);
//analogWrite(3,50); This kills the I2C
}

void loop() {

//Serial.println("in loop");
Controller.spinOnce(true);

now = micros();
if(now - last > DELAY_SEND_MICROS){
last = micros();
laserprint();
}
//I2C.scan();
}

void laserprint(){
Serial.print("Dist Top ");
Serial.println(LZ1.distance);
Serial.print("Dist Bottom ");
Serial.println(LZ2.distance);

}
 
Can't quite make out the horizontal us/div scale, but that's OK. The 1000 uF cap is way out at the end of the power distribution chain. I'd put it closer to the Garmin, right near the slip rings. Also, consider putting one inside the slip rings. They freak me out. Would consider putting the teensy inside the slip rings and RF the data back out.

You might also see if powering and driving the motor & MOSFET completely independently (like use a signal generator for now instead of the PWM out) will kill the I2C. The PWM out will drive a resistor, right? Or an opto-coupler?
 
It probably isnt a bad idea to put a cap on the spinner to keep the 5V level.

Initially I had been building this on a nano, who's I2C is measurably less sensitive than the Teensy's it seems. I could get both (i2c and PWM) to run on the nano, but any I2C failures on it kills everything. I needed more horsepower for an encoder though, and the Teensy has plenty for that. The teensy has run this through the slip ring 10X better than the nano. I did just verify this happens weather the slip rings are connected or not by bypassing them.

I can power the motor directly, the mosfet directly, or the level shifter mosfet triggering the bigger mosfet and the motor turns and I2C still flows freely even spinning. I do have an optocoupler around here that I could try, but my experience is connecting the PWM out line to anything kills the I2C. In normal operation I'm not expecting more than 60 or so RPM on the spinner.

I've got another teensy too. Maybe I damaged this one. I may try it too.
 
If the I2C running freely when the motor is running, but 'isolated', it's an indication of the "power supply topology / bypass caps" issue. If you put a resistive load, or an opto-coupler on the PWM out and the I2C stays OK, you can rule out damaged Teensy.

If/when you try the opto-coupler from PWM to motor drive, make that a completely independent power run back to your power supply. Big hairy caps on that line will not hurt a thing. All these little protoboard interconnects add DCR and inductance to your power distribution, so some nice 18AWG or so from motor controller (opto and MOSFET) back to the power supply would be pretty sweet.

I had a 'non issue' here that's related. The connection of a scope probe (10X mind you) was enough to generate I2C errors.
 
Still looking for a proper opto coupler. May have to settle for an opto inturrupter with nothing interrupting it. In the meantime I did attach the PWM output to a resistive load (an LED with 1K resistor) and to my amazement it ran. The I2C seems to fail faster than normal (I still havent implemented anything to catch that and restart it) but it does run dimming an LED. THE PWM output is really noisy though:
UbE9NRQ.jpg


If the I2C stops, the PWM wave cleans up perfectly. There's definitely some kind of interference there between the two. If I put a cap (100nF) to ground to clean it up it works but I2C dies and will not restart, even after a reload.



I'm not using USB power for the external components, I'm using a separate 5V supply with all grounds coupled. Same for the motor. it has its own supply as well. I'm finding that I get enough motor speed off of 5V, so I may and up using the 5V supply I have for both. It would simplify the final design, for sure.

I actually did try to see if my scope was affecting anything, and it didn't seem to be. I appear to have the same problem on a 2nd Teensy too, so no fried Teensy. That's good, I guess. This is after moving the 1000uF cap right to the input lines of the slip ring and adding an additional 470uF cap behind the slip ring directly on the LL's power lines.

Comparing my I2C lines to images I'm seeing on the internet I have LOT of noise. I need to hit it from that angle, I think.

EDIT: After looking at it further, I don't think I'm seeing noise on the I2C it's just the frequency shifting slightly. Different trigger methods yield much crisper readings. Especially at 100k
 
Last edited:
OK, here's a weird thing.

Somewhere along the way after so many resets, something went wrong with the serial port on the teensy. I reset it, power failed it, restarted the IDE and serial ports, but could not connect to it and program it as I had been, using just the serial port monitor in the arduino IDE using a COM port.

So I connect to it using raw HID. WHAM!

Readings appear to be coming in WAY faster now, and I now have no issues with using PWM and I2C at the same time. Have speed control over the motor and great readings as it spins. Clean signals on the PWM lines too now. No noise at all.

I am at a total loss to explain it.

Is there something in serial that would affect them both like that? It's working stellar now. Took over an hour of spinning before I got an I2C error. That was a few minutes before and a few seconds on the Nano.

The only thing I changed code wise was the com port rate (to 115200) but if I understand it correctly that's ignored with a teensy, especially in HID mode? I did that after I couldn't connect via COM port.

No matter what I try I can't get it to reconnect as a COM port.

But it's working! So weird.


#include "LidarObject.h"
#include "LidarController.h"
#include "I2CFunctions.h"
#include <i2c_t3.h>

#define WIRE400K true
#define Z1_LASER_TRIG 29 // Top LL
#define Z1_LASER_EN 14
#define Z1_LASER_PIN 30
#define Z1_LASER_AD 0x60
#define Z2_LASER_TRIG 33 // Bottom LL
#define Z2_LASER_EN 15
#define Z2_LASER_PIN 32
#define Z2_LASER_AD 0x64
// 720Hz
#define DATARATE 720
#define DELAY_SEND_MICROS 1000000/DATARATE


static LidarController Controller;
static LidarObject LZ1;
static LidarObject LZ2;


// Delays
long now, last;


void initLidars() {
// Initialisation of the lidars objects
LZ1.begin(14,29,30,Z1_LASER_AD,5,DISTANCE,'a');
Serial.println("init 1");
LZ2.begin(15,32,33,Z2_LASER_AD,5,DISTANCE,'b');
Serial.println("init 2");
// Initialisation of the controller
Controller.begin(WIRE400K);
delay(100);
Controller.add(&LZ1, 0);
delay(100);
Controller.add(&LZ2, 1);
}

void setup() {
Serial.begin(115200);

while (!Serial); // for compatibility
initLidars();
last = micros();
pinMode(3,OUTPUT);
//analogWriteResolution(10); // Resolution for PWM is set to 0-1023
analogWriteFrequency(3,1000);
analogWrite(3,180);
}

void loop() {

//Serial.println("in loop");
Controller.spinOnce(true);

now = micros();
if(now - last > DELAY_SEND_MICROS){
last = micros();
laserprint();
}
}

void laserprint(){
Serial.print("Dist Top ");
Serial.println(LZ1.distance);
Serial.print("Dist Bottom ");
Serial.println(LZ2.distance);
}
 
long should be unsigned long for now and last, as theyre unsigned 32 bits variables, not signed.

the negative effect of the rollover on signed variable can cause problems “over time”, and most likely the impact here.

try uint32_t now, last;

you might also want to use HEX in defines or suffix the actual value as UL for unsigned long, and use brackets for defines, especially when they include calculations, example:

DELAY_SEND_MICROS (1000000UL/DATARATE )
 
Elbarfo, the noise you may be just seeing could be artifacts of where your scope ground is referenced, how good the common mode rejection of the probe is, and that sort of 'instrumentation' issue. Sounds like the various power supply and return lines are reasonable.

The extra cap on the I2C lines isn't the way to go....it just makes it impossible to drive the I2C lines at high rates. tonton81 might be right about the rollover, but I'd be highly suspicious also of errors due to running I2C through slip rings. I see the LIDAR does have internal 3K internal pullups, but I would suggest an external set near the Teensy. You might want to write a little code to capture how long the unit runs before getting an I2C failure, and watch the return code from the Wire.endTransmission(I2C_STOP, 1000); calls. If it fails at totally random times, perhaps slip rings. It it's rollover, I'd expect the failure times to be consistent.

Not sure at all about the serial port monitor failing. Have never had that happen.
 
Elbarfo, the noise you may be just seeing could be artifacts of where your scope ground is referenced, how good the common mode rejection of the probe is, and that sort of 'instrumentation' issue. Sounds like the various power supply and return lines are reasonable.

It's weird. That all went away after not using serial drivers. I'm still using the Raw HID and it's humming along nicely now. Haven't changed a thing on my scopes, wiring or anything. I've now got an encoder and a index optointerrupter mixed in as well. The timing for all this is proving to be tricky. I'm having to learn a lot.

I'm expecting some I2C errors through the slip rings. I still haven't written any code to catch when it happens and timeout and/or reset the line. I believe the i2c_t3 library has the capability. The standard wire library is rather basic. Even without the slip rings the circuit wouldn't run forever. I have a hardware solution (a booster of sorts) that is supposed to help as well but I haven't tried it yet. This isn't a sparkfun or the like slip ring, either. It's from a high end PTZ camera and was designed to pass data. There's still other slip ring options too, but man they get pricey. I'm really trying to avoid having to spin the whole circuit...it's just a better design. I really wish they used a more robust protocol.


I haven't put a cap on the I2C lines, just the power for the LLites after the slip ring. It's probably is a good idea to help keep the power smoothed out for the LL's.

Not sure at all about the serial port monitor failing. Have never had that happen.

I'm at a loss to understand it myself. It now affects both of the 3.2's I have. I tried the other one just for giggles and it behaves the same way now. Perhaps it's something in the code. The funny part is this is all the behavior I was expecting to begin with. I can't get it to connect as a COM port at all now though on either. I'm ok with using raw HID, but I understand it's slower than the default serial which is supposed to be the speed uf the USB bus.

I set those variable settings as advised and it hasn't seemed to make a difference. It did make a difference when working with the encoder though! The test code I was using used a long and got weird once it rolled over.

I'd really like to know what I've done to kill the normal serial on these though. It seems really strange.

Thanks for your help through this.
 
I posted a thread this a.m. with a teensy bit of error checking which I'm trying to make a bit more elegant. Some I2C functions return an 'ack', and I'm mentally wrestling with how deep to go there in detecting errors. Though I have no slip rings, I'm running the LLs (two of them) at 1MHz, well above the 400KHz published in the Garmin spec. Will probably back that off, but before I do I'm thinking to take the clock back up to 1.5MHz where it fails and trigger the oscilloscope on an I2C error.

For the noise and COM errors you're getting, how about 'divide and conquer', i.e. isolate code segments and try them in combination? I really wouldn't expect this is any sort of internal issue, rather, (don't take offense) a bread-boarding or instrumentation issue. I'm just not sure where you are with understanding common mode noise and how misleading connection imperfections can be. As I said, please take no offense, this screws up a lot of projects.
Regards........
 
That's interesting you're pushing the LL's so fast. I had no idea they'd go so high. Makes me want to try. How many read/s are you getting that way, and does it still maintain accuracy? With this library I've been using I was able to pump the reads to 2000/s (even through the slip rings) but even in the best accuracy mode it was terrible at that speed. The drift from reading to reading was huge (10+cm). I would actually consider putting the whole shebang on the spinner (though I'd have to redesign everything) if I could get 5-6 accurate readings/degree. My spin rate is only 1-2 hz max. That would seriously improve the resolution.

Without the slip rings, I could get a day or two of running out of them both, but they'd still fail eventually. Without code to trap it, it would kill the main loop. One of the reasons I chose a Teensy was the better I2C library compared to to an Arduino Nano. The teensy runs it twice as long if not more, and fails much less often, and that's without any code changes.

Don't worry, I'm not offended. Admittedly, this breadboard is ancient. It's an artifact from my EE school days 25 years ago. Going through and testing it, I'm finding that some paths on it aren't complete shorts. I'm seeing as much as 2-3 ohms(!) from one side to the other just on the grounds. Guess it's time for a new board. I could shorten the leads to the slip ring by a few inches too and make an attempt at shielding them. I should also ground it. I have been pretty casual about the signal paths. I'm actually more hopeful now that's been a part of the problem. Time to tighten it all down. Thanks for that.

I don't really have any more noise though. Like I said, it all went away after the serial change. I mean like there's none now, anywhere. All the signals (PWM, I2C, and now encoder and index digital inputs) are clean now. Everything is working just like you'd expect it to except the serial. I really wish I could get it to reconnect as a serial device just to test if that's got something to do with it. It's boggling my mind. I'm going to completely default one and try a different sketch just to see if it's code related somehow. Haven't tried yet. I should reboot my PC too, just to see if that's got something to do with it. Hate doing that. :mad: :D
 
Thumbs up! Fellow EE here too..... Fortran and punch card era. I've seen a few posts by folks just getting started that sort of lead me to the instrumentation issues.

In any event, glad things are working well. So far, I've had the Teensy pushing the LIDAR at a total I2C read time of 250uS by running the I2C bus at 1MHz (400KHz is the spec on the data sheet), so if the teensy had nothing else to do, it could gather 4 reads in a millisecond....4KHz. But, that's projected at the white ceiling above my work bench, so perhaps that's why the distance is so clean. +/- just a few cm of jitter. Also, you have to take some time to do something with the data. So I'm really not sure where the 500Hz LIDAR limit is from. Well, the spec sheet obviously, but yes, they seem quite a bit speedier under these conditions.

My guess is it has to acquire a few hundred or so readings into the "correlation record" (Garmin term) before the internal algorithm figures signal-to-noise is good enough to report a distance. I'm kind of guessing here that in the downtime between these 250uS I2C cycles (4.75 mS in my case right now) that the 4.75mS is where the reading is happening. Will keep on this, as I'm very interested in reaching the 500Hz 'limit'.

By the way, are you using i2c_t3 with the Garmin LIDARLite library? I couldn't get that to compile.

Regards, John
 
My first post is using the Lidar Lite Library on Garmin's Github. It's the newest version. It appears they updated it after the new HP units were released.

I had to change every reference to wire in all the garmin files to i2c_t3, but it compiled.

A week or so after I wrote that post I found a different Library, The Enhanced Lidar Library that has a LOT more features for the lidars, turning them into objects, creates state machines for them, has a full API, and can automatically address up to 8 lidars at once. I'm not the greatest coder, so this has really helped me out a lot. You should check it out, it has a lot of nice routines. It seems to be a lot better than the garmin defaults.

If you do use it, this line "LZ1.begin(Z1_LASER_EN, Z1_LASER_PIN, Z1_LASER_AD, 2, 'a');" in their example code is bad. It doesn't have enough commas in it's line and the lidars all get set to address 2. just FYI. Took me a few to figure out what was happening. Look at the begin function in lidarcontroller.h to see what I mean. It's corrected in the code below. Just like with the garmin libraries, every reference to wire.h has to be changed to i2c_t3.h.

Regardless of which library I used, the I2C and PWM issues persisted until the serial died.

This is my current test code for the lidars. It nets around 750 reads/s (configurable using the DATARATE variable) with what seems to be acceptable accuracy. I have yet to do too serious testing. Setting that to 2000 netted a lot of inaccurate reads. 10-15cm of drift on a 45cm target. I could tolerate a cm or 3, but that's scary. I still have to dig deeper into how that library is calling for a read to determine how I can improve the accuracy at high speed.

#include "LidarObject.h"
#include "LidarController.h"
#include "I2CFunctions.h"
#include <i2c_t3.h>

#define WIRE400K true
#define Z1_LASER_TRIG 29 // Top LL
#define Z1_LASER_EN 14
#define Z1_LASER_PIN 30
#define Z1_LASER_AD 0x60
#define Z2_LASER_TRIG 33 // Bottom LL
#define Z2_LASER_EN 15
#define Z2_LASER_PIN 32
#define Z2_LASER_AD 0x64
// 720Hz
#define DATARATE 720
#define DELAY_SEND_MICROS (1000000/DATARATE)


static LidarController Controller;
static LidarObject LZ1;
static LidarObject LZ2;


// Delays
uint32_t now, last;


void initLidars() {
// Initialisation of the lidars objects
LZ1.begin(14,29,30,Z1_LASER_AD,5,DISTANCE,'a'); //This line is bad in the given example
Serial.println("init 1");
LZ2.begin(15,32,33,Z2_LASER_AD,5,DISTANCE,'b');
Serial.println("init 2");
// Initialisation of the controller
Controller.begin(WIRE400K);
delay(100);
Controller.add(&LZ1, 0);
delay(100);
Controller.add(&LZ2, 1);
}

void setup() {
Serial.begin(115200);

while (!Serial); // for compatibility
initLidars();
last = micros();
pinMode(3,OUTPUT);
//analogWriteResolution(10); // Resolution for PWM is set to 0-1023
analogWriteFrequency(3,1000);
analogWrite(3,180);
}

void loop() {

//Serial.println("in loop");
Controller.spinOnce(true);

now = micros();
if(now - last > DELAY_SEND_MICROS){
last = micros();
laserprint();
}
}

void laserprint(){
Serial.print("Dist Top ");
Serial.println(LZ1.distance);
Serial.print("Dist Bottom ");
Serial.println(LZ2.distance);
}
 
Last edited:
Now that I think about it, I had to change the name of one of the functions in the Garmin library too. IIRC they changed the name of the distance function.
 
Yay, new protoboard. This one is significantly tighter than the old one. I have around 3 feet less cabling now. Should help, I think. Now to figure out how to get consistent encoder readings....

s15xIbZ.jpg
 
So, it appears a PC reboot brought back the serial. It looks like something hosed the windows serial driver.

I must have cleared the noise issue coincidentally with the serial dying. Weird stuff. At least I know now. All is good now!

I'm very interested in the high speed work you're doing with these. I'm likely to start trying overclocking them now too.

Thanks again for all your help.
 
Status
Not open for further replies.
Back
Top