-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPerseguidor_VESPA.ino
291 lines (231 loc) · 7.48 KB
/
Perseguidor_VESPA.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
/****************************************************************
* Folow Line - Perseguidor
* Garagino - CESAR School
*
* Line Follower PID with the microcontroller Vespa
* from RoboCore and the Pololu's QTR-8RC sensor
****************************************************************/
#define DEBUG
#define BT_NAME "Motoneta"
// Names: Mutuca | Motoneta | Van Dyne
#ifdef DEBUG
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
BluetoothSerial SerialBT; // Bluetooth Serial instance
#endif
#include <RoboCore_Vespa.h> // Library for the Vespa microcontroller
#include <QTRSensors.h> // Library for the QTR-8A or the QTR-8RC
VespaMotors motor; // Vespa Motor Object
QTRSensors qtr; // QTR Sensor
// Set button and led pins
const uint8_t PIN_BUTTON = 35;
const uint8_t PIN_LED = 15;
const uint8_t PIN_MARKER_SENSOR = 36;
//Setup of the module of sensors
const uint8_t SENSOR_COUNT = 8; // The number of sensors, which should match the length of the pins array
uint16_t sensorValues[SENSOR_COUNT]; // An array in which to store the calibrated sensor readings
// Maximum line position, considering the amount of sensors.
const long MAX_POSITION = (SENSOR_COUNT - 1) * 1000;
//Marker sensor variables
unsigned long startMakerChecker = 39500L;
unsigned long initialTime;
// Limit value of the margin of error
int marginError = 20;
bool firstRun = true;
//------------------PID Control-------------------
float p = 0, i = 0, d = 0, pid = 0, error = 0, lastError = 0;
float Kp = 0.3;
float Ki = 0.0001;
float Kd = 3.5;
int maxSpeed = 100;
int lSpeed, rSpeed;
const bool LINE_BLACK = false;
//-------------------------------------------------
void setup() {
qtr.setTypeRC(); // For QTR-8RC Sensor pins:
qtr.setSensorPins((const uint8_t[]){ 21, 19, 5, 16, 22, 23, 18, 17 }, SENSOR_COUNT);
pinMode(PIN_BUTTON, INPUT);
pinMode(PIN_MARKER_SENSOR, INPUT);
pinMode(PIN_LED, OUTPUT);
#ifdef DEBUG
if (firstRun) {
Serial.begin(115200);
delay(100);
SerialBT.begin(BT_NAME); // Bluetooth device name
firstRun = false;
}
SerialBT.println("Start BT communication");
String btMessage;
String prefix;
while (prefix != "end" && digitalRead(PIN_BUTTON) == HIGH) {
btMessage = receiveBtMessage();
prefix = getPrefix(btMessage);
if (prefix == "pid") {
Kp = getNumber(btMessage, 1);
Ki = getNumber(btMessage, 2);
Kd = getNumber(btMessage, 3);
} else if (prefix == "spe") {
maxSpeed = getNumber(btMessage, 1);
} else if (prefix == "tim") {
startMakerChecker = getNumber(btMessage, 1);
} else if (prefix == "err") {
marginError = getNumber(btMessage, 1);
} else if (prefix == "pri") {
printParameters();
} else if (prefix == "end") {
break;
} else {
SerialBT.println("This command doesn't exists!");
}
}
printParameters();
SerialBT.println("Start Calibration...");
delay(500);
#endif
// Calibration
digitalWrite(PIN_LED, HIGH);
while (digitalRead(PIN_BUTTON) == HIGH) { // Calibrates until the button is pressed
qtr.calibrate();
}
digitalWrite(PIN_LED, LOW);
SerialBT.println("Wating command ...");
while( prefix != "go"){
btMessage = receiveBtMessage();
prefix = getPrefix(btMessage);
}
#ifdef DEBUG
// Print the calibration minimum values measured when emitters were on
for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
SerialBT.print(qtr.calibrationOn.minimum[i]);
SerialBT.print(' ');
}
SerialBT.println();
// Print the calibration maximum values measured when emitters were on
for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
SerialBT.print(qtr.calibrationOn.maximum[i]);
SerialBT.print(' ');
}
SerialBT.println();
#endif
delay(2000); // Start loop after 2 seconds
initialTime = millis();
}
void loop() {
// readSensors() returns the line position between 0 and `MAX_POSITION`.
// error is a re-map from -1000 to 1000 range.
error = map(readSensors(), 0, MAX_POSITION, -1000, 1000);
// Calculate PID
p = error;
i = i + error;
d = error - lastError;
pid = (Kp * p) + (Ki * i) + (Kd * d);
lastError = error;
// Control Motors
lSpeed = maxSpeed + pid;
rSpeed = maxSpeed - pid;
lSpeed = constrain(lSpeed, -maxSpeed, maxSpeed);
rSpeed = constrain(rSpeed, -maxSpeed, maxSpeed);
if (markerChecker()) { // Count the markers and stop the robot when reach a certain number
motor.stop();
#ifdef DEBUG
SerialBT.print(">> Timelapse: ");
SerialBT.print(millis() - initialTime);
SerialBT.println(" seconds");
#endif
setup();
} else if (error >= -marginError && error <= marginError) { // If the error is within the MARGIN_ERROR, move on
motor.turn(maxSpeed, maxSpeed);
} else { // If the error is outside the error range, continue doing PID
motor.turn( rSpeed, lSpeed);
}
}
int readSensors() {
if (LINE_BLACK) {
return qtr.readLineBlack(sensorValues);
} else {
return qtr.readLineWhite(sensorValues);
}
}
/**
Verifies if there is a end line after a set time
@return `true` if the end line was detected.
*/
bool markerChecker() {
static int i = 0;
if (startMakerChecker < millis() - initialTime) {
if (analogRead(PIN_MARKER_SENSOR) < 2000) {
return true;
}
}
return false;
}
#ifdef DEBUG
/**
Returns all stream of data sent over bluetooth until the
button is pressed.
@return `String` with the message sent by the bluetooth device
*/
String receiveBtMessage() {
String message;
char incomingChar;
digitalWrite(PIN_LED, HIGH);
while (digitalRead(PIN_BUTTON) == HIGH) {
if (SerialBT.available()) {
incomingChar = SerialBT.read();
if (incomingChar == '\n') break;
message += String(incomingChar);
}
}
digitalWrite(PIN_LED, LOW);
message.trim();
return message;
}
String getPrefix(String data) {
return getElement(data, 0);
}
double getNumber(String data, int index) {
return atof(getElement(data, index).c_str());
}
/**
Returns a sub-string in the `String` data, in the index
position.
@param `data` String with the message
@param `index` Position of the element to be returned
@return `String` sub-string in the indicated position. If there is
no value at this position, it returns empty string.
*/
String getElement(String data, int index) {
char separator = ' ';
int found = 0;
int startIndex = 0, endIndex = -1;
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
startIndex = endIndex + 1;
endIndex = (i == maxIndex) ? i + 1 : i;
}
}
if (found <= index) {
return "";
}
return data.substring(startIndex, endIndex);
}
void printParameters() {
SerialBT.println("Configured parameters:");
SerialBT.print(">> P: ");
SerialBT.print(Kp, 4);
SerialBT.print(" | I: ");
SerialBT.print(Ki, 4);
SerialBT.print(" | Kd: ");
SerialBT.println(Kd, 4);
SerialBT.print(">> Speed: ");
SerialBT.println(maxSpeed);
SerialBT.print(">> Time delay: ");
SerialBT.println(startMakerChecker);
SerialBT.print(">> Margin Error: ");
SerialBT.println(marginError);
}
#endif