Using a stepper motor and a range finder (TFLuna), I am trying to build a "Lidar" (like a Radar, but with light). Here is the algorithm:
- Turn motor one step, calculate angle, measure distance to whatever it hits, giving polar coordinates;
- Calculate Cartesian coordinates and send to Python;
- Collect a few hundred measurements and show the scatter plot.
This works, but only if I restart the sketch and the Python routine at the same time. After I collected all the data for one plot, I cannot restart the Python script to collect another round of data - it shows that there is no data in waiting. Also, the Arduino script never hangs due to the buffer getting full (as Python has stopped reading).
How can I make it so that the Arduino and the motor do their thing (swinging back and forth 180º, looking at stuff), and I am able to collect an amount of data in Python intermittently -- whenever I choose to restart the script one more time?
Here is the code. First, Arduino. "count" is the number of steps by which the motor has rotated; tflI2C is the range-finder object.
#include <Stepper.h>
#include <Arduino.h>
#include <Wire.h> // Instantiate the Wire library
#include <TFLI2C.h> // TFLuna-I2C Library v.0.1.1
#include <math.h>
TFLI2C tflI2C;
int16_t tfDist; // distance in centimeters
int16_t tfAddr = TFL_DEF_ADR; // Use this default I2C address
const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution
// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);
int stepCount = 0; // number of steps the motor has taken
void serialFlush(){
while(Serial.available() > 0) {
char t = Serial.read();
}
}
void setup() {
// initialize the serial port:
Serial.begin(115200);
Wire.begin(); // Initalize Wire library
myStepper.setSpeed(10);
//myStepper.step(stepsPerRevolution/2);
//delay(1000);
//myStepper.step(-stepsPerRevolution/2);
}
void coordinates(int count){
struct Polar {
float angle;
int16_t distance;
} pPoint;
struct Cartesian {
float xCoord;
float yCoord;
} cPoint;
float angle = count*(2.0*PI)/stepsPerRevolution;
byte flag = 0;
//Serial.flush();
while (Serial.availableForWrite() < sizeof(struct Cartesian)){}
if(tflI2C.getData(tfDist, tfAddr)){
pPoint.angle = angle + PI/2.0;
pPoint.distance = tfDist;
cPoint.xCoord = pPoint.distance * cos(pPoint.angle);
cPoint.yCoord = pPoint.distance * sin(pPoint.angle);
if (pPoint.distance <= 50 ){
Serial.write((char*)&cPoint, sizeof(struct Cartesian));
}
}
return;
}
void loop() {
// step one step:
for (int k=0; k<stepsPerRevolution/4; k++){
myStepper.step(1);
coordinates(stepCount);
stepCount += 1;
delay(10);
}
for (int k=0; k<stepsPerRevolution/2; k++){
myStepper.step(-1);
coordinates(stepCount);
stepCount -= 1;
delay(10);
}
for (int k=0; k<stepsPerRevolution/4; k++){
myStepper.step(1);
coordinates(stepCount);
stepCount += 1;
delay(10);
}
delay(5000);
}
and here is Python:
ardu = serial.Serial('/dev/cu.usbserial-1460', baudrate=115200, timeout=.1)
radarImage = []
structSize = struct.calcsize("ff")
ardu.reset_input_buffer()
i = 0;
while True:
if ardu.in_waiting >= structSize:
arduRead = ardu.read(structSize)
point = list(struct.unpack("ff",arduRead))
if i <= 10:
print(point)
radarImage.append(point)
i += 1
else:
pass
if i > 2000:
break
ardu.close()
Here is a sample from a "first round" data collection. Yes, my desk is messy...