Neato Lidar sensor and reading the serial data and making sense of it.

edited January 2018 in Arduino

As a complete nube to arduino and processing i need some on to explain what all this means.

I have the Lidar sensor off a Neato vacuum basically it a spinning laser that measures distance.

This is the info i have about the data coming from the sensor.

I can do the part were i get the serial port and set the baud rate and on some of the serial libary examples the get a lot of data but none of it make sense.

if someone could explain to me on how to separate all this data i would really be grateful.

I don't want you to write the program for me cause i need to learn how to do this but i just don't know were to start

A full revolution will yield 90 packets, containing 4 consecutive readings each. The length of a packet is 22 bytes. This amounts to a total of 360 readings (1 per degree) on 1980 bytes.

Each packet is organized as follows: (start) (index) (speed_L) (speed_H) [Data 0] [Data 1] [Data 2] [Data 3] (checksum_L) (checksum_H)

where:

start is always 0xFA index is the index byte in the 90 packets, going from 0xA0 (packet 0, readings 0 to 3) to 0xF9 (packet 89, readings 356 to 359). speed is a two-byte information, little-endian. It represents the speed, in 64th of RPM (aka value in RPM represented in fixed point, with 6 bits used for the decimal part). [Data 0] to [Data 3] are the 4 readings. Each one is 4 bytes long, and organized as follows.

byte 0 : <distance 7:0> byte 1 : <"invalid data" flag> <"strength warning" flag> <distance 13:8> byte 2 : <signal strength 7:0> byte 3 : <signal strength 15:8>

As chenglung points out, the distance information is in mm, and coded on 14 bits. This puts the tests made by Sparkfun in a room of around 3.3m x 3.9m (11ft x 13 ft ?), which seems reasonable. The minimum distance is around 15cm, and the maximum distance is around 6m.

When bit 7 of byte 1 is set, it indicates that the distance could not be calculated. When this bit is set, it seems that byte 0 contains an error code. Examples of error code are 0x02, 0x03, 0x21, 0x25, 0x35 or 0x50... When it's 21, then the whole block is 21 80 XX XX, but for all the other values it's the data block is YY 80 00 00...

The bit 6 of byte 1 is a warning when the reported strength is greatly inferior to what is expected at this distance. This may happen when the material has a low reflectance (black material...), or when the dot does not have the expected size or shape (porous material, transparent fabric, grid, edge of an object...), or maybe when there are parasitic reflections (glass... ).

Byte 2 and 3 are the LSB and MSB of the strength indication. This value can get very high when facing a retroreflector.

Answers

  • Answer ✓

    Do you have any code that reads the input stream? You need to check first if you are getting packages continuously. You need to store all the bytes in the order they arrive. Before doing anything fancy, try to read and process 22 bytes at a time. For the first 22, you check the header is correct, then you read the id number. Next, you need to verified the check sum. If the check sum fails, then either you drop the package and try again.

    So the first task consist in:

    1. Verify your check sum is correct (and you are accessing the 22 bytes associated to the package)
    2. Verify you are receiving and processing all the 90 packages per rotation. This is important check to make sure your connection is not dropping packages. If it does, then you need to account them properly.

    Kf

  • edited February 2018

    I have data coming from the sensor.

    I'm using a small interface board that has a Arduino Mini to control the RPM. And passes through the serial data.

    (http://www.getsurreal.com/product/xv-lidar-controller-v1-2

    I can see the 22 bytes beginning with FA. I'm using coolterm to view the datastream

    data

  • Answer ✓

    get a lot of data but none of it make sense

    Ok, from coolterm you can see you are receiving packages and that they are coming in order. The next step is to post the code that receives this same data in Processing. Process the 22 bytes in order. What you want to do is to get the 90 packages, extract each of those four readings that comes in each package, and group all that data together in an array so it stores all the reading from a single revolution. Then you want to store the revolutions in another array structure so you can access it.

    Are you familiar with classes?

    What do you want to do with this data?

    Kf

  • Right now it's a learning exercise. But eventually the sensor will be used for my Robot. I like processing because it allows a lot of ways to display data.

    Never workd with classes but ill try more this weekend

    thanks, john

    so i get this

    I'm assuming its garbage because its not in the right format?

    data

  • Answer ✓

    If you check the coolterm window in your previous post, on the right column you see about the same characters. What you are getting is raw data. This code shows you are getting data and now you need to process it. So all good so far.

    One thing: When it comes to code, please don't use pictures but copy and paste directly into the forum. Make sure you format your code by selecting the code and pressing ctrl+o. You need to make sure there is an empty line above and below your code block.

    Related to classes, check the following tutorial: https://processing.org/tutorials/objects/

    I recommend for the next part of your code, while you become familiar with classes, that you don't use data directly from your serial stream. Instead, use an array of bytes containing fake data. For instance:

    final int PKG_SIZE=22;
    final int N_PKG=3;
    bytes[] testData=new bytes[PKG_SIZE,N_PKG];
    

    Now fill testData array with some information following:

    Each packet is organized as follows: (start) (index) (speed_L) (speed_H) [Data 0] [Data 1] [Data 2] [Data 3] (checksum_L) (checksum_H)

    So for instance:

    testData[0]=0xFA;   //Begin package 1 out of 3
    testData[1]=0xA0;   //Index 0
    testData[2]=0xFF;  //Speed_L
    testData[3]=0x00;  //Speed_H
    testData[4]=0x00;  //DATA1: distance 0:7
    testData[5]=0x00;  //DATA1: invalid flag, strength warning, distance 15:8
    testData[6]=0x00;  //DATA1: Signal strength 7:0
    testData[7]=0x00;  //DATA1: Signal strength 15:8  
    testData[8]=0x00;  //DATA2: distance 0:7
    testData[9]=0x00;  //DATA2: invalid flag, strength warning, distance 15:8
    testData[10]=0x00;  //DATA2: Signal strength 7:0
    testData[11]=0x00;  //DATA2: Signal strength 15:8 
    testData[12]=0x00;  //DATA3: distance 0:7
    testData[13]=0x00;  //DATA3: invalid flag, strength warning, distance 15:8
    testData[14]=0x00;  //DATA3: Signal strength 7:0
    testData[15]=0x00;  //DATA3: Signal strength 15:8 
    testData[16]=0x00;  //DATA4: distance 0:7
    testData[17]=0x00;  //DATA4: invalid flag, strength warning, distance 15:8
    testData[18]=0x00;  //DATA4: Signal strength 7:0
    testData[19]=0x00;  //DATA4: Signal strength 15:8 
    testData[20]=0x00;  //checksum_L
    testData[21]=0x00;  //checksum_H
    testData[22]=0xFA; //Begin package 2 out of 3
    testData[23]=...
    ...
    testData[43]=0xFA; //Begin package 3 out of 3
    ...
    testData[65]=...
    

    Notice I only filled the first package out of three. The idea is that you become familiar with the data structure by generating your own data first. Then, you create some code that process this data as if it were real data. I have created a repo with some data to get you started. You are very welcome to use it or to generate your own. Notice my solution is just a demo and there is further room for improvement in the actual class layout and code design.

    The code can be run but most of the core needed functions still need to be implemented. Check this repo: https://github.com/kfrajer/lidarDemo

    Last thing: From you prev post, you provided a link: http://www.getsurreal.com/product/xv-lidar-controller-v1-2/ and it seems that if you load the provided firmware, you should be able to inquire your device for data. So instead of processing raw data, you just need to send requests as described in that website.

    Kf

  • When I try to run your program I get an error.

    byte[] current_package=new byte[LidarDataPackage.PKG_SIZE];

    LidarDataPackage cannot be resolved to a variable.

    thanks,john

  • Answer ✓

    Your sketch has two files: lidarDemo.pde and LidarDataPackage.java, right? Just checking...

    Kf

  • edited February 2018

    i don't know what that means.

    Maybe i shouldn't of picked such a big project to learn on.

    after i highlight my code and press ctrl-O

    how do i paste it in the comment?

  • Answer ✓

    Ok, for this code to work, you need to download the code directly from github. You will get a zip folder. You extract its content and then click on the pde file. Notice that you will find a java file (a file with a .java extension) in the same folder as your pde. Processing will load both files the pde and the java file.

    If you do this, you should be able to run it. On a side note, how did you access the code? Did you copy and past it from the github link?

    how do i paste it in the comment?

    Not sure what you mean with comment. Anyways, to post code formatted in the forum, copy and paste your code here and then select your code and hit ctrl+o. Ensure there is an empty line above and below your code.

    Kf

  • Yes i cut/paste the first time.

    This time i did like you said and downloades the zip and that opened and ran fine.

    I've seen that before when you copy and paste code why does that happen? Do you know?

    Please explain why the two programs? PDE is the processing program and what is the Java program?

  • edited February 2018

    In the data packages The first byte (begin package) 0XFA that address stays the same for all 89 packets? Identifies the start of a new package?

    So the next Byte (index) that counts up for all the 89 packages ending in 0XF9 and identifies the individual packages. So that is different for each package.

    Then whats left is the 20 bytes of data? how are those numbered and starting at what? Or are the now called testData [1] thru the total testData [1958]? 22x 89= 1958?

  • edited February 2018

    Thanks for the personal lessons in programming.

  • Delayed response, sorry, busy these days...

    Yes, every package starts with 0xFA. However, it is not enough to check for this for the start of a package. It is simply not reliable. The reason is that you could find this byte inside your data stream. The proper way to handle the package is to extract 22 bytes each time starting with the 0xFA byte and then process the 22 data bytes by first checking the check sum of the package. Only after this check you know you have a valid package.

    So the next Byte (index) that counts up for all the 89 packages ending in 0XF9 and identifies the individual packages. So that is different for each package.

    Yes. For every rotation, you get 90 packages. If you process all the data with id==0xF9 for instance, then you are extracting the same angles for every rotation.

    Your job is to process 90 packages associated to one rotation. If you extract the four readings in each package, then you get all the 360 readings per rotation. You final goal is to be able to process each rotation independently. You should get a table of rotations like this:

    • Rotation 1: 360 readings
    • Rotation 2: 360 readings
    • Rotation 3: 360 readings
    • ...
    • Rotation n: 360readings

    Also I suggest you read over a tutorial about bi shifting and bit masking as you will needed for processing your packages.

    Related to the java tab, check the following forum post: https://forum.processing.org/two/discussion/comment/116668/#Comment_116668. I believe GoToLoop does a good job explaining the difference between a pde and a java tab. The reason I had to use a java class is bc I needed a top class to work with static functions.

    Kf

  • edited February 2018

    Sorry i'm still confused by the bytes addresses.

      testData[0]=byte(0xFA);   //Begin package 1 out of 3
    This identifies the start of each package. same for all packages.
    
      testData[1]=byte(0xA0);   //Index 0
    This counts up and identifies each packagae.
    
    
    So then how is the rest of these bytes identified?
    
      testData[2]=byte(0xFF);  //Speed_L
      testData[3]=byte(0x00);  //Speed_H
      testData[4]=byte(0x00);  //DATA1: distance 0:7
      testData[5]=byte(0x00);  //DATA1: invalid flag, strength warning, distance 15:8
      testData[6]=byte(0x00);  //DATA1: Signal strength 7:0
      testData[7]=byte(0x00);  //DATA1: Signal strength 15:8  
      testData[8]=byte(0x00);  //DATA2: distance 0:7
      testData[9]=byte(0x00);  //DATA2: invalid flag, strength warning, distance 15:8
      testData[10]=byte(0x00);  //DATA2: Signal strength 7:0
      testData[11]=byte(0x00);  //DATA2: Signal strength 15:8 
      testData[12]=byte(0x00);  //DATA3: distance 0:7
      testData[13]=byte(0x00);  //DATA3: invalid flag, strength warning, distance 15:8
      testData[14]=byte(0x00);  //DATA3: Signal strength 7:0
      testData[15]=byte(0x00);  //DATA3: Signal strength 15:8 
      testData[16]=byte(0x00);  //DATA4: distance 0:7
      testData[17]=byte(0x00);  //DATA4: invalid flag, strength warning, distance 15:8
      testData[18]=byte(0x00);  //DATA4: Signal strength 7:0
      testData[19]=byte(0x00);  //DATA4: Signal strength 15:8 
      testData[20]=byte(0x01);  //checksum_L
      testData[21]=byte(0x00);  //checksum_H
    
  • Also in your program do i have to add the serial libary and the port data because i dont see it.

  • Answer ✓

    I ran out of time today... before we continue, do you know how to capture data using coolterm? You need to capture some data and save it either as binary or even better if you can save it in ascii or csv format.

    If you check your post back in Feb 1, you can clearly identify the 0xFA token(s). Find one and then count 22 bytes to find the next one. You can easily see there is a pattern. The next byte after 0xFA is the id. If you compared consecutive packets, you see that the ID increases by 1.

    I do not load the serial library in my github demo because... hmmmm... I do not have your device or any hardware associated to your project. What I did instead, is to create a class that spits out data simulating your device. This data can be replaced by ether capture data obtained from coolterm or using data directly from your device via serial.

    Kf

  • I didn't forget about this just busy.

  • Can we do this one step a a time? I'm still having a hard time understanding this. I guessing this is the correct order.

    1 We open the serial port? 2 Create an array to store the incoming data? 3 Separate the date into each package starting at 0XFA? 4 Organize the packages into order starting with the first packag 0XA0?

  • I can look more into this in the weekend. Can you save some data from your unit using coolterm and share it?

    3 Separate the date into each package starting at 0XFA?

    There is a technicality here. We assume 0xFA is the header of each package. However, you can have a byte with the value of 0xFA as well inside the data stream of any package. To extract the data, there are the easy, the proper and the ugly way to do this. I have explained the proper way to do it above using the check sum. The easy way to do it is this:

    • Read if a byte is 0xFA
    • Read 22 bytes (or 21?) and check if the next byte is 0xFA. If true, then you have capture a proper package. Otherwise discard and try again.

    The reason I am cautious about this step of capturing each package is that potentially your system might have a deadtime processing the incoming data. This depends on the incoming data rate from your sensor and if the arduino can handle it (or if it is handling it properly) and data transfer between arduino and PC is properly setup (Proper bps). If you are able to collect data and test that you have zero package drop rate, then it is very likely you have an optimal configuration. However, I do not know many details about your project and I can only suggest you do it the proper way. If you provide some data, I can provide you a simple test program building from the repo I made for ya.

    Kf

Sign In or Register to comment.