-
Notifications
You must be signed in to change notification settings - Fork 0
/
arduino-data-reading.ino
344 lines (297 loc) · 14.1 KB
/
arduino-data-reading.ino
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/**
* LiDAR microcontroller code
* By Alex Shuping
*
* OSLRF-01 reading code from berryjam.eu/2014/06/oslrf-01
*
* Note: Because this code averages readings, it really isn't suitable for our rapid-scanning applications
* (This might be why our readings looked terrible)
*
* LED codes (These come in the form of LongFlash -> (ShortFlash)*n -> LongFlash, where n is the message code
* 1 -- INFO -- Setup completed successfully
* 2 -- INFO -- Dry-run readings are being taken (waiting for readings to stabilize)
* 3 -- ERROR -- A control byte was received, but was not recognized
* 4 -- ERROR -- Control responded with invalid character while acknowledging connection
* 5 -- ERROR -- Control computer did not respond to synack within set timeout
*
* Last update: 5 August 2016
*/
#define MANUAL_READINGS // Uncomment this line to take manual (turntable) readings, comment out for MEMS mirror readings
//Pin definitions
#define ZERO_PIN A1 // Arduino pin tied to Zero pin on the OSLRF
#define RETURN_PIN A3 // Arduino pin tied to Return pin on the OSLRF
#define SYNC_PIN 2 // Arduino pin tied to Sync pin on the OSLRF
#define BUTN_PIN 3 // Arduino pin that can be connected to ground via a button to take manual readings if MANUAL_READINGS is defined (above)
#define INDC_PIN 13 // Arduino pin connected to an LED -- for state indication
//Constant definitions
#define pi 3.1415926535 // Approximation of pi -- for trig functions
//Control character definitions
const char CHAR_SYN = 0x01; // Connection test from control computer
const char CHAR_SYNACK = 0x02; // Response to connection test
const char CHAR_ACK = 0x03; // Conformation from control computer
const char CHAR_NAK = 0x04; // Invalid response from control computer
const char CHAR_DAT = 0x05; // Data request from control comptuer
const char CHAR_DRYRUN = 0x06; // Request to take dry-run measurements from control computer
//Timeout definitions
#define SYN_TIMEOUT 1000 // Number of milliseconds to wait for a connection ack from control computer
//Level / threshold definitions
#define MAX_MIRROR_VOLTAGE 6 // Max voltage to be applied to a micromirror
#define VOLTAGE_STEP 0.1 // Voltage step / resolution for the micromirror (Each cycle, voltage changes by this much)
#define VOLTAGE_STEP_MAN 2 // Voltage step / resolution to be used when manual control is enabled
//Library definitions
#define numReadings 1 // Number of distance readings to store for averaging (Library code)
#define numReadingsSync 20 // Number of sync readings to store for averaging (Library code)
/**
* Code from the OSLRF-01 Library
*
* Taken (with very slight alterations) from berryjam.eu/2014/06/oslrf-01/
*
* This code takes the average of a set number of readings of distances and sync times
* (set with numReadings and numReadingsSync respectively), averages them, and stores
* the averages in avgDist and avgSync respectively.
*/
int zero_val = 0; // Value of zero signal for current reading
int return_val = 0; // Value of return signal for current reading
int sync_val_1 = 0; // Values of sync signal for current reading
int sync_val_2 = 0; // See above
int amp = 0; //
int zero_thresh = 120; // Adjust these thresholds if readings are not being received or are clearly wrong
int return_thresh = 120; // See above
float raw_distance = 0.0; // Distance calcuated directly from equation in datasheet
float distance = 0.0; // Distance with slight adjustments
unsigned long zero_time; // Pulse time for zero signal
unsigned long zero_time1; //
unsigned long zero_time2; // This variable was declared, but never used...
unsigned long echo_time; // Pulse time for return signal
unsigned long echo_time1; // Time of echo signal rising-edge
unsigned long echo_time2; // Time of echo signal falling-edge
unsigned long sync_time_1;// Rise time for sync pin
unsigned long sync_time_2;// Fall time for sync pin
unsigned long sync_period;// Sync pin period
// Distance average variables
double readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
double total = 0; // the running total
double avgDist = 0; // the average
// Sync period average variables
unsigned long readings2[numReadingsSync]; // the readings from the analog input
int index2 = 0; // the index of the current reading
unsigned long total2 = 0; // the running total
unsigned long avgSync = 0; // the average
//End OSLRF-01 Library Code
double vVert = 0; // Voltage that is currently being applied to the vertical axis of the micromirror
double vHorz = 0; // Voltage that is currently being applied to the horizontal axis of the micromirror
void setup() {
Serial.begin(9600); // Begin communication with processing computer
pinMode(INDC_PIN, OUTPUT); // Initialize feedback pin (see LED codes at top of file for more info)
pinMode(SYNC_PIN, INPUT); // Initialize sync pin to take readings
digitalWrite(13, LOW);
#ifdef MANUAL_READINGS
pinMode(BUTN_PIN, INPUT_PULLUP); // Initialize manual input pin for taking manual readings, but only if MANUAL_READINGS is defined
#endif
//Libarary code
// Sync averaging itialize routine
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
// Distance averaging itialize routine
for (int thisReading2 = 0; thisReading2 < numReadingsSync; thisReading2++)
readings2[thisReading2] = 0;
flash(1, INDC_PIN); // To indicate setup completed successfully
}
void loop() {
if(Serial.available()){ // Wait for serial connection
char c = Serial.read(); // Read control character from serial
if(c==CHAR_SYN){ // This character indicates that the control computer is establishing / verifying connection
while(!doHandshake()){ // Complete the handshake (see function description for more info)
flash(5, INDC_PIN); // If the handshake times out, flash an errorcode and retry
serFlush();
}
}else if(c==CHAR_DAT){ // This character indicates a data request from the control computer
#ifdef MANUAL_READINGS
while(digitalRead(BUTN_PIN)==HIGH){}; // If manual control is set, wait for a button press to respond with data
#endif
Serial.println(vHorz); // Send horizontal-axis micromirror voltage
Serial.println(vVert); // Send vertical-axis micromirror voltage
#ifdef MANUAL_READINGS
vHorz += VOLTAGE_STEP_MAN; // If manual control is set, increment horizontal voltage by set amount (see #defines at top of file)
#else // If manual control is unset, do the following:
if(vVert == MAX_MIRROR_VOLTAGE){ // If vertical displacement is at maximum value
vVert = 0; // Set it to zero
vHorz = vHorz == MAX_MIRROR_VOLTAGE ? 0 : vHorz + VOLTAGE_STEP; // and increment the horizontal voltage (unless that is also maximum, in which case, set it to zero as well)
}else{
vVert += VOLTAGE_STEP; // Otherwise, increment vertical mirror voltage by set amount (see #defines at top of file
}
#endif
Serial.println(avgDist); // Send distance measure to control computer
#ifdef MANUAL_READINGS
delay(1000); // Limit manual readings to one per second
#endif
serFlush();
}else if(c==CHAR_DRYRUN){ // This character indicates a request for a "dry run" -- data are to be collected and processed from a single point (so the micromirror is not to be actuated)
Serial.println(vHorz); // Send horizontal-axis micromirror voltage
Serial.println(vVert); // Send vertical-axis micromirror voltage
Serial.println(avgDist); // Send distance reading
flash(2, INDC_PIN); // Flash an indication that this is a dry run.
serFlush();
vVert = 0; // Ensure that the micromirror voltages are set at zero
vHorz = 0; // See above
}else{
flash(3, INDC_PIN); // Flash an error message -- a character was received, but not recognized
serFlush();
}
}else{
//No control character received
}
doOSLRFLibraryLoop(); // Update the library code (take readings and update averaging table)
}
/**
* void serFlush()
*
* Flushes the serial input, discarding any messages present
*
* PARAMS:
* none
*
* RETURN:
* none
*/
void serFlush(){
while(Serial.available()){Serial.read();}
}
/**
* void flash(unsigned char code, int outPin)
*
* Uses the indicator LED to send a message (see top of file for LED codes)
*
* PARAMS:
* unsigned char code -- LED code to output
* int outPin -- Pin to output code on
*
* RETURN:
* none
*/
void flash(unsigned char code, int outPin){
digitalWrite(outPin, HIGH);
delay(500);
digitalWrite(outPin, LOW);
delay(500);
for(unsigned char i = 0; i < code; i++){
digitalWrite(outPin, HIGH);
delay(250);
digitalWrite(outPin, LOW);
delay(250);
}
digitalWrite(outPin, HIGH);
delay(500);
digitalWrite(outPin, LOW);
delay(500);
}
/**
* bool doHandshake()
*
* Three-way handshake function (Think TCP)
* Sends a synack and waits for an ack.
* Handshake structure is as follows:
* 1. Control computer sends "syn" signal to microcontroller
* 2. Microcontroller sends "synack" signal to control computer
* 3. Control computer sends "ack" to microcontroller
* This ensures that both components are responding and can communicate data.
*
* PARAMS:
* none
*
* RETURN:
* bool -- Connection state (successful / timed out)
*/
bool doHandshake(){
Serial.write(CHAR_SYNACK);
serFlush();
bool ack = false;
for(int i = 0; i < SYN_TIMEOUT; i++){
if(Serial.available()){
if(Serial.read() == CHAR_ACK){
ack = true;
break;
}else{
flash(4, INDC_PIN);
Serial.println(CHAR_NAK);
}
}
delay(1);
}
return ack;
}
/**
* void doOSLRFLibraryLoop()
*
* Performs library updates
* Takes measurements from OSLRF-01, and uses them to update the averaging table
* Code taken (with very slight alterations) from berryjam.eu/2014/06/oslrf-01/
*
* PARAMS:
* none
*
* RETURN:
* none
*/
void doOSLRFLibraryLoop(){
getSyncPeriod(); // This "Sync" period update can be done not on every loop cycle,
AverageSyncPeriod(); // as it takes time and loses some (3) distance measurements
// Detect Zero signal rising edge
while ((zero_val = analogRead(ZERO_PIN)) < zero_thresh)
zero_time1 = micros();
// Detect Return signal rising edge based on previous measurement amplitude
while ((return_val = analogRead(RETURN_PIN)) < return_thresh)
echo_time1 = micros();
// Get maximum height of Return pulse...
amp = 0;
while (amp <= return_val ) {
amp = return_val;
return_val = analogRead(RETURN_PIN);
}
// Detect Return signal falling edge
while ((return_val = analogRead(RETURN_PIN)) > return_thresh)
echo_time2 = micros();
// New Return signal threshold for next measurement, based on the new amplitude
return_thresh = 0.13 * (float)amp + 10; // Pure empiric, based on observations.
if (return_thresh < 18) return_thresh = 18; // Make sure that threshold is over the noise
zero_time = zero_time1 + 3500; // Midpoint of Zero. Full Zero signal width - 7000us, when threshold 40
echo_time = echo_time1 + ((float)echo_time2 - (float)echo_time1)/3.0;
raw_distance = (float)(echo_time - zero_time)/(float)avgSync * 1833.0;
if (raw_distance > 1000) {} // Just ignore this reading
else{
if (raw_distance < 220){ // RAW measure corrections if distance less than 100 cm
distance = 0.725 * raw_distance - 56.208;
}
else distance = 1.078 * raw_distance - 134.05; // Empiric correction for 100cm and up
}
AverageDistanceReadings();
}
/**
* All code below this line taken (with very slight alterations) from berryjam.eu/2014/06/oslrf-01/
*/
void getSyncPeriod(){
// sync_period = 2*pulseIn(SYNC_PIN, LOW); // was too big about 80us, because duty cycle not perfect 50%
// Need to optimize, as it takes full two clocks
unsigned long sync_period1 = pulseIn(SYNC_PIN, LOW);
unsigned long sync_period2 = pulseIn(SYNC_PIN, HIGH);
sync_period = sync_period1 + sync_period2;
}
void AverageSyncPeriod(){
total2 = total2 - readings2[index2]; // subtract the last reading
readings2[index2] = sync_period; // Get last measure
total2 = total2 + readings2[index2]; // add the reading to the total
index2 = index2 + 1; // advance to the next position in the array
if (index2 >= numReadingsSync) // if we're at the end of the array...
index2 = 0; // ...wrap around to the beginning
avgSync = total2 / numReadingsSync; // calculate the average
}
void AverageDistanceReadings(){
total = total - readings[index]; // subtract the last reading
readings[index] = distance; // Get last measure
total = total + readings[index]; // add the reading to the total
index = index + 1; // advance to the next position in the array
if (index >= numReadings) // if we're at the end of the array...
index = 0; // ...wrap around to the beginning
avgDist = total / numReadings; // calculate the average
}