LIDAR lite with Beaglebone Black and Arch Linux

Its been a few months now since I received my new LIDAR lite from the crowd funded campaign on Dragon Innovation but only now I have some time to play with it. I got interested in range finder hardware after doing this great Udacity course on Artificial Intelligence for Robotics by Sebastian Thrun (the new one is here). One of the key hardware components is a good inexpensive range finder and Pulsedlight is doing it.

I want to try it out on my Beaglebone Black, the first challenge are the data pins voltage, the LIDAR is working at 5V and the Beaglebone at 3V3.

(EDIT) Well, figures out that I was wrong about LIDAR lite I2C levels, even thought it works with the logic levels converter, it is not necessary to use it, check my new post here.

I have hanging around a 4-channel I2C-safe Bi-directional Logic Level Converter – BSS138 from Adafruit. It is perfect for this. Here are some photos of the connections, I’ll publish the wiring in a few days when I have more time:

lidarlitewiringConnection to the Beaglebone via ssh.
The Beaglebone is running Arch Linux, to install the i2c tools:

# pacman -S i2c-tools

Check if the LIDAR is there:

# i2cdetect -r -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- --
60: -- -- 62 -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Looking good! LIDAR Light detected at address 0x62.  Now, from its manual, we need to write 0x04 at its address 0x00 to make a measurement:

# i2cset -y 1 0x62 0x00 0x04

and wait for a couple of seconds to make sure the measuring is finished, then read the measured value:

# i2cget -y 1 0x62 0x8f w
0x7500

so I’m getting 117cm. It works! And the distance from it to my wall is around that value. Can’t find my meter so I can’t check its precision right now. I made a simple script to make it run for a while and save the measuring in a file, I’ll let you know my findings about repeatability later. Here is the script:

#!/bin/sh
date >> lidar.txt

while :
do
i2cset -y 1 0x62 0x00 0x04

sleep 2

i2cget -y 1 0x62 0x8f w
i2cget -y 1 0x62 0x8f w >> lidar.txt
done

I couldn’t use the i2cdump command. Each time I do:

# i2cdump -y 1 0x62

I get an answer the first time with some values but if I do the i2cdump again the result is all zeros, it looks like something gets stuck and the LIDAR no longer responds. The only way to make it work again is to power down / up the LIDAR. I’ll investigate this another day.

Advertisements

Author: pedro_nf

Independent contractor on IT solutions and automation

33 thoughts on “LIDAR lite with Beaglebone Black and Arch Linux”

  1. i have no luck getting it to respond quickly using the linux commands or in c code using sm_bus commands, the data rate is like 1hz. However, the arduino code seems to work. I have no idea why, i suspect that the i2c that is implemented on the lidar lite does not work with the standard linux libraries

    1. I think there are some timing issues on the lidar side. .. try waiting for a couple of seconds between each i2c command. If it works ok them decrease the waiting time until it breaks again. This way you can find the fastest command rate. .. With that info try discussing the issue with the lidar support.

  2. Hi,

    I’m having a lot of trouble getting better that 1.8 seconds/sample from the device.
    The lidar-lite does not respond to i2c commands when its is making a measurement.
    This should be 20mSec. But, I find that I must delay 1.8 seconds before reading the data. If you get a read failure the driver seems to take about 1 second to recover and dump a log.

    Has anyone gotten any kind of response from lidar support on this problem?
    With the processing required to use this thing an arduino is not the best way to go.

    1. I’m quite busy lately, still no time to do some testing… I’ll send an email to lidar support with a link to your comment. ..

  3. Hi,
    I’m dealing with them already and am gathering info about the problem.
    So far this is the only site I have found an identical problem.

    I sent them a link to this page.

    1. We nned to look on the BeagleBone side, this is the PulsedLight email reply:

      Hi Pedro,
      We’ve become aware of a problem with Beaglebone Black controllers’ Linux drivers where they do not properly handle I2C communications (specifically, they don’t recover quickly from NACK conditions among other things).
      This is best taken up with the Beaglebone community to update their drivers to conform to I2C protocol standards.
      Best,
      Bob E.
      Ticket: https://kb.pulsedlight3d.com/helpdesk/tickets/364

  4. Hi

    I have been looking at the BeagleBone Black i2c code.

    I should mention that
    – I’m not an expert in i2c. I do not understand the spec.
    – I do not understand the driver in any detail at this time.

    The BBB driver (linux/drivers/i2c/busses/i2c-omap.c) has a 1 second
    timeout when it gets a ‘NACK’ ( #define OMAP_I2C_PM_TIMEOUT 1000 /* ms */)

    After that resets and initializes the port.

    The ‘NACK’ seems to be considered an error condition when it happens.
    A ‘NACK’ seems to mean that the slave never indicated that it received
    a message or was too busy to respond. If there were nothing listening on the bus then a ‘NACk’ would happen when the master tried to communicate with anything.

    So, ‘too busy to respond’ and ‘not there’ look the same to the master. It calls both an error.

    I’m running a 3.14.26 kernel but the same code exists in the 4.1 kernel
    (Just in case there was a fix)/.

    As an aside I would like to test this on the Raspberry Pi to see if its not
    specific to the BBB.

    As an experiment I reduced OMAP_I2C_PM_TIMEOUT to 10mSec and
    did some testing (This is is hack! Breaks other things) and I managed
    to get the time per measurement down to 32->40 mSec. Note that the driver still resets/initializes things and dumps an error log.

    The lidar-lite should be able to measure at at least 50Hz or 20mSec/sample.

    As a summary I need to understand the i2c spec wrt NACK and the implications wrt reducing the wait time upon receiving a NACK.

  5. Nice! I can look into it in a couple of weeks, thanks for this info. Meanwhile please post everything you find out in here, it would be great that we can work out a solution for this.

    1. Hi,

      Well, you asked for it.

      Here is a synopsis of what my testing has uncovered.
      I must state that I have a single lidar-lite and have nothing to
      compare it to.. with the exception of post by benjaminhon86 on May 28, 2015.
      This means that my lidar-lite may be broken and these results are bogus.

      The lidar-lite can make a distance measurement in 20mSec max or 50 samples/second.

      The lidar-lite documents documents state that the:
      “unit responds to read or write requests with a NACK when the sensor
      is busy processing a command or performing a measurement. For proper operation the I2C peripheral
      driver needs to handle the NACK condition without producing an error condition.”

      What this means is that when you trigger a measurement the lidar-lite becomes
      very busy and will not respond to i2c commands. It also means that the
      driver has to recover quickly to have a 50 samples/second sample rate.

      This “not responding” behaviour is allowed in the i2c spec.

      What happens on the BBB is the lack of response to a read command after triggering a measurement
      is perceived as an error condition. The driver waits/times out in 1 second and then resets things to recover.
      You can then preform another read and you will get a response.

      The problem is that with the 1 second timeout you cannot achieve 50 samples/second,

      A possible workarond for this is to wait the 20mSec worst case for the lidar-lite to
      make its measurement and not be busy.

      This does not work. My lidar-lite does not seem to respond to the i2c bus for about 1.7 seconds from
      a measurement command being issued. This is confirmed by the post of benjaminhon86. He noted
      that he had to add a delay of 2 seconds before reading the lidar-lite after triggering a
      measurement. The delay is in 1 second increments. My testing indicated about 1.7 seconds.

      I have a problem report on this behaviour to the lidar-lite support team.

      Next I hacked the i2c driver for the omap device to reduce the timeout from NACK/no response to
      10 mSec. This resulted in the linux driver handling the NACK much faster. I managed to get valid
      samples 33mSec range.

      Now, this is strange. I’m triggering a read that fails with a NACK and a second read is ok
      and I’m getting 33mSec response time. This seems to contradict the 1.7 second sample time above.

      Here is where I’m speculating: I think the decice needs a request from the i2c bus to
      bring it out of some kind of reclusive state. If not kicked it will leave this state in 1.7 seconds or so.
      The first access will fail but the second access will pass.. unless you try and read it
      while its in the first 20mSec or so when its making the measurement (speculation: not tested).

      Again, this is the behavoir of my lidar-lite.

      Note that the device does provide accurate measurements.. but my testing is limited on this.

      Ideas for a workaround/fix.
      —————————

      All these *unusual* i2c behavoirs seem to be called quirks in the 12c driver world. Lots of devices seem
      have them (it seems? google seemed to find some).

      Possible solutions:

      1. Change the Linix driver. This means that it must ignore the first read to the device and keep going
      without timing out. To support this there is an ioctl interface that sets flags. Two of the
      flags are I2C_M_IGNORE_NAK and I2C_M_NO_RD_ACK. Also look at functions called i2c_write_ignore_nack() and
      i2c_read_no_ack().

      I’m not having much success with this btw. Using some sample code I found I cannot even get the BBB to attempt an i2c read.

      2. Fix the lidar-lite so that it responds to the i2c bus as soon as the measurement is completed. This will
      result in the driver making a short delay to account for the busy-making-the-measurement-time and
      having a sucessful read. If the drivers delay is worst case then we should never get an NACK.

      I’m puttering around with possible solution #1.
      I no not think very many people are using this lidar-lite on the BBB. Either that or I’m missing a software fix!

      1. Ho my stars! You really got me now :-)
        Great job, I’ll try to find some time in a couple of weeks to help you on this.

      2. Well.. I have more progress.

        I connected my lidar-lite to a RaspberryPi. It worked perfectly. No joke!
        I wanted to see if the same behaviour I saw on the BBB was present on the Pi.

        On the Pi I was getting a measurement every 10.5 mSec or so. On occasion I got a read error but the driver just kept on going.

        In 1000 reads I got 29 read errors that caused a successful re-read.
        Note that I was not delaying 20mSec but 10 and was expecting
        re-reads.

        So, there is a night and day difference between the Pi and the BBB.

        This command line test also works fine:

        i2cset -y 1 0x62 0x00 0x04; ls;i2cget -y 1 0x62 0x8f w
        (the ls is a short delay… i2cget does not like a read failure).

        These tests sent me back to the BBB to verify that it was still not working.
        I also had to bring in the digital oscilloscope to see the bus.

        Ok.. its unusual.

        1. The trigger command is fine. Easy to spot and decode.

        2. The next read command is utter crap. There is no scl. It looks like
        its trying to go low but not really. I do not even think the lidar-lite would register it happening.The sda is one low pulse.

        3. After the timeout and the subsequent reset of the i2c controller the
        next read is fine.

        So, the first read after the trigger-a-measurement is utter garbage and
        subsequent read after the i2c controller reset seems ok (we do get a valid measurement).

        No idea what the cause of this is yet.

        Please pass this along to the lidar-lite folks. I do not have their e-mail address..

      3. Hi.
        I seem have my lidar-lite working on my BBB. I do not quite understand it
        all yet.

        Looking at the scope I see a lot of -ve spikes on the scl line from the
        BBB. I’ve seen -1.25 V spikes without a load (ie the lidar-;ite).
        The spikes are less with the lidar-lite.

        I installed a 4.7k resistor from scl to gnd. The spikes are now -430mV.
        Two 4.7k resistors and nothing works.
        No resistor and its -720mV spikes.

        And the thing works much better… most of the time (vs never).
        I also installed a 470uF capacitor on the 5V supply to the lidar-lite.

        I get a measurement in 10.6 mSec.

        I can still see some odd things on the bus but I do seem to be getting a valid
        measure in 10ish mSec.

        I’m also not getting the “controller timed out” logs as much.
        In 100 iterations I got 1 “controller timed out” log which implies
        the i2c controller was reset.

        1000 iterations: 19 timeouts and i2c resets, 29 reads that failed and caused
        a re-read.

        I will continue testing…..

  6. Hi,

    This will be my last update for awhile.
    I have had time to reflect on what I have been able to discover.

    1. I do not think the statement that he Linux driver does not handle NACKs
    properly is correct. I can reproduce a NACK simply by disconnecting the scl signal to the slave device and then attempt to read from it. The Linux driver attempts the read and gets a nack (no-one is there) and returns -1 to the caller.
    My simple code keeps trying and never gets a timeout or a log.

    2. I think the timeout log is just what it says. I also think that it indicates that the i2c state machine is corrupt. It got triggered and is waiting for info that never comes and it times out after 1 second while waiting.

    3. I think this is the same or very similar problem that was fixed before.

    4. It does not happen on the Pi.

    5. Adding the resistor to ground seems to do something that makes it work a bit better. One guess might be that there is noise and along with pulling the rest of the signal lower the noise gets pulled low enough to be below some threshold.

    6. When I used the scope to look at the i2c bus the BBB read after the message to trigger the measurement was not an i2c signal. There was only a partial dip in the clock.Sda was a bigger dip.

    7. When the BBB driver times out it resets the i2c device. This resets the
    state machine and then the next i2c operation works fine.

    I am going to re-try the fix for the documented problem talking to the
    pixhawk. I will install 47pf capacitors to ground on the scl and sda lines.

  7. Hi,
    I kinda has an idea ;)

    I suspect that the glitch at 10.2 mSec is not from the BBB but the lidar-lite. It causes the BBB i2c device to hang.

    I modified my test code to read the lidar-lite every 270uSec after triggering
    a measurement. I see lots of nack’s and the driver keeps going. I was trying to pinpoint where the BBB’s i2c device stopped working.
    I see a read that results in a nack… then the “glitch” and no more reads.

    The glitch does not correspond to the expected next read operation.
    I always thought it was from the BBB but now I suspect its from the lidar-lite.

    The glitch is a small bump in scl and a low going pulse on sda. The bump and
    low going pulse are about 5.6 uSec in duration,

    I suspect that this glitch is hanging the BBB’s i2c device.

  8. and if you are lucky and your flood of reads lands right in the glitch then it
    works… I get a sample back in 8.9 mSec… ;)

  9. I wonder if the new “blue label” version fixes these i2c glitches… Hey Peter… I am working on processing the Lidar Lite for PixHawk too… A scanning rangefinder… I just started on the LidarLite side an am running to similar problems… Are you satisfied that smoothing out the buss with capacitors is a suitable approach or should I show for a RPi? :) Do you have any working code you are willing to share?

    Jeff

  10. Hi Jeff,

    I have no info on the blue label lidar lite. I’m sure it fixes something.

    I was under the impression that the PixHawk/lidar-lite problem was
    solved. I suspect that there are more users of PixHawk/lidar-lite then
    BBB/lidar-lite.

    I never worked with the PixHawk. I was using the BeagleBone Black.
    I bailed on the lidar-lite and returned it. I bought a rplidar instead.
    Lots of the tests were guesses until I got access to a digital oscilloscope and
    could see exactly what was happening on the i2c bus.

    None of the workarounds really worked.

    I suspect that the lidar-lite was glitching the i2c bus and i2c controllers that support multi-master i2c were hanging as a result.

    One idea was to disable the i2c pins on the BBB after issuing a measurement command for about 10mSec, thus preventing any glitch from the lidar-lite from hanging the i2c controller.

    That was about the time I descended to return the lidar-lite and
    get the rplidar.

    The code I have is just test code for the BBB. It generates i2c commands
    to the lidar-lite and then delays a bit and then tries to read the results. I can send it but I’m not sure it will help you much. I does not have the disable-the-i2c-pins stuff in it.

    The Raspberry Pi had no problem with the lidar-lite. Measurements were
    in the 10mSec range. I wish the lidar-lite people would publish what devices
    they have tested their product with.

    1. Peter, Thanks so much for sharing your experiences. I am going to give this another go on the RPi and see how things work out. Again, thanks for taking the time to respond. – Jeff

  11. Any Luck getting V2 to work with Rev C BBB???

    I have been trying all week to get the BBB to receive data from the Lidar. So far i2cget & i2cset do NOT work. Using i2cdump seems to crash the sensor after one listing.

    I have tried both smbus commands aswell as regular file read/writes to see if it could be a protocol problem. Some of the suggestions here make me think its a board problem but no one has tried the V2. Any results?

    1. I only tried v1.
      i2cdump did not work for me either. But i2cget and i2cset worked. They are probably using the same i2c transceiver with the same issues as v1…

  12. LIDAR lite doesn’t support repeated start as normal I2c device does.
    When you read data from it use
    i2cget -y 1 0x62 0x90 c
    The “c” is very important because instead of sending repeated start, it will send stop-start. From there Lidar will answer fast

    1. Hi Simon, thank you for sharing this info, so it looks like you found a work around to this slow reply issue. I’ve been busy with other projects so I didn’t have the time to retest this. I’ll try it out one these days… weeks… :-)

  13. Im looking to recreate this project myself and it seems relatively straight forward however i am unable to find the LIDAR lite drivers for Arch Linux, am i doing something wrong or were you able to locate them? Thanks.

    1. I Isaac, I’m using the I2C tools to drive the Lidar directly. I don’t know if there is a driver for it, I don’t think so. Anyway all you need is to send a couple of commands via I2C.

    2. Thanks to this post, it helped to figure out how to connect LidarLite V3 (garmin edition) to BBB. I’m using bonescript/i2c and it works for me. If you need i can send you a short js example.

      1. Hi hpilka, thanks for your feedback :-) Yes it would be nice that you post your js example as a reply so others can also see it.
        Cheers
        Pedro

    3. here we go:

      // i2c lib comes with BBB, couldn't make i2c-bus lib to work (sync calls, so you don't need promises)
      // most likely a start/stop issue. The lidar manual says it has to be start/stop and it doesn't work with start/start
      var i2c = require('/usr/local/lib/node_modules/bonescript/node_modules/i2c');
      var Q = require('q'); // npm install q
      var LIDAR_ADDR = 0x62;
      var device = {device: '/dev/i2c-1', debug: false};
      var wire = new i2c(LIDAR_ADDR, device);

      // reset
      wire.write([0x00,0x00], function (err){
      if (err != null )
      console.log(err)
      else
      {
      // wait for reset to finish and start the program
      setTimeout(startReads, 200);
      }
      });

      function startReads()
      {
      Q.fcall(function() {
      var deferred = Q.defer();
      wire.write([0x00,0x04], function (err) // write command to start a distance acquisition
      {
      if (err != null)
      {
      deferred.reject(err);
      return;
      }
      deferred.resolve();
      });
      return deferred.promise;
      })
      .then(function(){ // write command to read the status of the lidar reading (should be in a loop write/read for status checking)
      var deferred = Q.defer();
      wire.write([0x04], function(err)
      {
      if (err != null)
      {
      deferred.reject(err);
      return;
      }
      deferred.resolve();
      });
      return deferred.promise;
      })
      .then(function(){ // read and check the status
      var deferred = Q.defer();
      wire.read(1, function(err, res)
      {
      if (err != null )
      {
      deferred.reject(err);
      return;
      }
      else
      {
      if ( (res & 0x01) == 0x00 )
      deferred.resolve();
      else
      deferred.reject("not ready");
      }
      });
      return deferred.promise;
      })
      .then (function(){ // write address of the lower byte to read
      var deferred = Q.defer();

      wire.write([0x90], function(err){
      if (err != null )
      {
      deferred.reject(err);
      return;
      }
      deferred.resolve();
      });
      return deferred.promise;
      })
      .then(function(){ // read lower byte
      var deferred = Q.defer();
      wire.read(1, function(err, res){
      // console.log("err="+err);
      // console.log("res1="+res);
      deferred.resolve(res);
      });
      return deferred.promise;
      })
      .then(function(res){ // write addres of the higher byte to read
      var deferred = Q.defer();
      wire.write([0x0f], function(err){
      if (err != null )
      {
      deferred.reject(err);
      return;
      }
      deferred.resolve(res);
      });
      return deferred.promise;
      })
      .then(function(r0){ // read higher byte and compute the distance
      var deferred = Q.defer();
      wire.read(1, function(err, res){
      if (err != null)
      {
      console.log("err="+err);
      deferred.reject(err);
      }
      var d = res<<8 | r0;
      if (d < 170)
      console.log("d="+d);
      deferred.resolve();
      });
      return deferred.promise;
      })
      .fail(function(err) {
      console.log(err);
      });
      setTimeout(startReads, 50);
      }

  14. Ive managed to enable I2C tools by creating a uEnv.txt file in the uboot directory (as per http://beaglebone.cameon.net/home/i2c-devices). It seems to recognize i2c-0 and i2c-1 as recognized devices, as shown by i2cdetect;

    (my output is as follows)
    root@beaglebone:~# i2cdetect -l
    i2c-0 i2c OMAP I2C adapter I2C adapter
    i2c-1 i2c OMAP I2C adapter I2C adapter

    however, i2cdetect -r -y 1 (and 0) do not show anything to be connected (as shown below).

    root@beaglebone:~# i2cdetect -r -y 1
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: — — — — — — — — — — — — —
    10: — — — — — — — — — — — — — — — —
    20: — — — — — — — — — — — — — — — —
    30: — — — — — — — — — — — — — — — —
    40: — — — — — — — — — — — — — — — —
    50: — — — — UU UU UU UU — — — — — — — —
    60: — — — — — — — — — — — — — — — —
    70: — — — — — — — —
    root@beaglebone:~# i2cdetect -r -y 0
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: — — — — — — — — — — — — —
    10: — — — — — — — — — — — — — — — —
    20: — — — — UU — — — — — — — — — — —
    30: — — — — UU — — — — — — — — — — —
    40: — — — — — — — — — — — — — — — —
    50: UU — — — — — — — — — — — — — — —
    60: — — — — — — — — — — — — — — — —
    70: UU — — — — — — —

    I am wondering if i have missed a step, or if i didn’t properly follow the steps of enabling the i2c tools.

    Note, i have my Garmin Lidar Lite V3 connected to pins 1 for ground, 5 for power, 19 and 20 for i2c, however I have also tried 17 and 18 for i2c which was unsuccessful and would require changing modes of the pins.

    Any ideas or advice would be appreciated, thanks,
    Isaac.

    1. I just edited the original post to include a pin-out picture. I don’t know about the new LIDAR version pins but if its identical you need to use pins 1 and 6 for power, pin 2 for enable (otherwise it stays in low power mode) and pins 4 and 5 for I2C. Did you forget the pin 2 enable? Did you invert the I2C pins?

  15. I just checked the operation manual of the new LIDAR, the wiring diagrams are terrible, they have different numbers in each of the diagrams… but I see the connector is exactly the same as before. So, if its not working you might want to check:
    – check I2C pins, are they correctly connected to the beagle bone, no inversion between SDA and SCL?
    – try some pull-up resistors on the I2C bus, look around internet how it works
    – check your I2C pins with an oscilloscope
    – check I2C settings frequency of your BeagleBone
    – if all fails you will have to connect a different I2C device to your BeagleBone, if you also can’t make it work then its something wrong with your BeagleBone

    This video from Derek about I2C is great:
    http://derekmolloy.ie/beaglebone/beaglebone-an-i2c-tutorial-interfacing-to-a-bma180-accelerometer/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s