If you are interested on learning about LiDAR and how to use it with Arduino, you have come to the right place! In this post I will be going over a project I recently completed using LiDAR with Arduino. I used the Benewake TF-Luna as the basis for the application.
Project Description
This project is a fully rotating LiDAR scanner capable of mapping what surrounds it. I completed it mostly with 3D printed parts, and printed circuit board (PCB) that I designed, Arduino programming on a NodeMCU, and some other components (stepper motor, electrical slip ring, LiDAR sensor, etc). See the video above to get all the details on the project. Below are some files you might want to reference.
STL files for 3D Printing
Arduino Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#include <Arduino.h> #include <Wire.h> // Instantiate the Wire library #include <TFLI2C.h> // TFLuna-I2C Library v.0.1.1 #include <AccelStepper.h> TFLI2C tflI2C; //Stepper Motor Inputs int Step = 14; //GPIO14---D5 of Nodemcu--Step of stepper motor driver int Dire = 2; //GPIO2---D4 of Nodemcu--Direction of stepper motor driver int Sleep = 12; //GPIO12---D6 of Nodemcu-Control Sleep Mode on A4988 int n = 0; //Will be used to tell the motor how many steps to move int MS1 = 13; //GPIO13---D7 of Nodemcu--MS1 for A4988 int MS2 = 16; //GPIO16---D0 of Nodemcu--MS2 for A4988 int MS3 = 15; //GPIO15---D8 of Nodemcu--MS3 for A4988 #define motorInterfaceType 1 AccelStepper stepper = AccelStepper(motorInterfaceType, Step, Dire); //Motor Specs const float spr = 116.95; //Steps per revolution int Steps_per_sec = 1500; //Motor Speed in steps/sec //Lidar Sensor Inputs int16_t tfDist; // distance in centimeters int16_t tfAddr = TFL_DEF_ADR; // Use this default I2C address const float Pi = 3.14159; float angle=0; int pos2=0; void setup() { Serial.begin(115200); //Set Pin Modes pinMode(Step, OUTPUT); //Step pin as output pinMode(Dire, OUTPUT); //Direcction pin as output pinMode(Sleep, OUTPUT); //Set Sleep OUTPUT Control button as output //Set Pin setting for some pins digitalWrite(Step, LOW); // Currently no stepper motor movement digitalWrite(Dire, LOW); // Set stepper motor rotation direction (set to HIGH for opposite direction) digitalWrite(MS1, LOW); //Set MS1, MS2, and MS3 to LOW to enable full steps (no microstepping) digitalWrite(MS2, LOW); //Set MS1, MS2, and MS3 to LOW to enable full steps (no microstepping) digitalWrite(MS3, LOW); //Set MS1, MS2, and MS3 to LOW to enable full steps (no microstepping) //Wire begin Wire.begin(); // Initalize Wire library //Stepper Motor Info stepper.setMaxSpeed(3000); //Max speed in steps/sec stepper.setCurrentPosition(0); stepper.setSpeed(Steps_per_sec); } void loop() { digitalWrite(Sleep, HIGH); //A logic high allows normal operation of the A4988 by removing from sleep n=pos2; if (n >=spr){n = pos2 % int(spr);}//% operator provides the remainder, so this will provide the remainder after dividing pos2 by the number of steps per revolution angle = 360*(float(n)/spr); stepper.runSpeed(); pos2=stepper.currentPosition(); if(tflI2C.getData(tfDist, tfAddr)){Serial.println(String(angle*Pi/180)+"p"+String(tfDist)+"p"+String(n));} } |
Processing IDE Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
ArrayList <PVector> points = new ArrayList <PVector> (); import processing.serial.*; Serial myPort; // The serial port int lf = 10; // Linefeed in ASCII String myString = null; float x,y,angle,r,n; float f = 5; void setup() { // List all the available serial ports printArray(Serial.list()); // Open the port you are using at the rate you want: myPort = new Serial(this, Serial.list()[0], 115200); size(600,600); points.add(new PVector(0,0,0)); } void draw() { while (myPort.available() > 0){ myString = myPort.readStringUntil(10); if (myString != null) { String[] q = splitTokens(myString, "p"); if (q.length>1){ angle=float(q[0]); // Converts and prints float r = float(q[1]); // Converts and prints float n = float(q[2]); x = (f*sin(angle)*r + 300); y = (f*cos(angle)*r + 300); } } background(0); PVector p_last = points.get(points.size()-1); if (n != p_last.z){points.add(new PVector(x,y,n));} while (points.size() > 117) { points.remove(0); } for (int i=1; i<points.size(); i++) { PVector p1 = points.get(i-1); PVector p2 = points.get(i); stroke(0,255,0); // line color: no fill, green stroke strokeWeight(5); line(p1.x,p1.y, p2.x,p2.y); } PVector p3 = points.get(points.size()-1); stroke(255,0,0); // ellipse color: default white fill, red stroke strokeWeight(20); ellipse(p3.x,p3.y,15,15); } } |
Components used in this example
*As an Amazon & Ebay Associate I earn from qualifying purchases.
Component | Link |
LiDAR Sensor – Benewake TF-Luna | https://ebay.us/TB7e6a https://www.amazon.com/Benewake-TF-Luna-Single-Point-Ranging-Interface/dp/B086MJQSLR |
NodeMCU | https://ebay.us/q33b4R |
That’s awesome. Thank you so much. I’ve never heard of processing ide before. I won’t steal your code. It’s great but I won’t learn if I copy and paste haha
Can you share your pcb design?