-
Notifications
You must be signed in to change notification settings - Fork 7
/
SerialControl.pde
438 lines (384 loc) · 13.5 KB
/
SerialControl.pde
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
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/*
SerialControl.pde - Library for controlling my Quadcopter via the serial connection
Created by Myles Grant <[email protected]>
See also: https://github.com/grantmd/QuadCopter
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//
// NB: We follow the AeroQuad serial control protocol: http://aeroquad.com/wiki/index.php/AeroQuad_Serial_Commands
// Interop FTW.
//
byte _queryType;
void readSerialCommand(){
// Check for serial message
if (Serial.available()){
_queryType = Serial.read(); // Read the command first
switch (_queryType){
case 'A': // TODO: Receive roll and pitch gyro PID
//readSerialPID(ROLL);
//readSerialPID(PITCH);
//float minAcro = readFloatSerial();
break;
case 'C': // TODO: Receive yaw PID
/*readSerialPID(YAW);
readSerialPID(HEADING);
headingHoldConfig = readFloatSerial();
heading = 0;
relativeHeading = 0;
headingHold = 0;*/
break;
case 'E': // TODO: Receive roll and pitch auto level PID
readSerialPID(levelRollPID);
readSerialPID(levelPitchPID);
//readSerialPID(LEVELGYROROLL);
//readSerialPID(LEVELGYROPITCH);
//windupGuard = readFloatSerial(); // defaults found in setup() of AeroQuad.pde
break;
case 'G': // Receive auto level configuration
break;
case 'I': // Receive altitude hold PID
break;
case 'K': // Receive data filtering values
break;
case 'M': // Receive transmitter smoothing values
break;
case 'O': // Receive transmitter calibration values
break;
case 'W': // Write all user configurable values to EEPROM
eeprom_write_all();
break;
case 'Y': // Initialize EEPROM with default values
eeprom_read_all();
break;
case '1': // Calibrate ESCS's by setting Throttle high on all channels
engines.disarm();
engines.arm(1);
break;
case '2': // Calibrate ESC's by setting Throttle low on all channels
engines.disarm();
engines.arm(2);
break;
case '3': // Test ESC calibration
engines.disarm();
engines.setThrottle(constrain(readFloatSerial(), 1000, 1200));
break;
case '4': // Turn off ESC calibration
engines.disarm();
break;
case '5': // Send individual motor commands (motor, command)
engines.disarm();
engines.setThrottle(constrain(readFloatSerial(), 1000, 1200));
// HOW DOES THIS DIFFER FROM 3!?
break;
case 'a': // fast telemetry transfer
// IGNORED
break;
case 'b': // calibrate gyros
gyro.autoZero();
break;
case 'c': // calibrate accels
accel.autoZero();
break;
case 'd': // send aref
// IGNORED
break;
case 'f': // calibrate magnetometer
// IGNORED
break;
case '~': // read Camera values
// IGNORED
break;
// The following modes are my own
case '$': // Set throttle
engines.setThrottle(readIntSerial());
break;
case 's': // Set system mode
systemMode = readIntSerial();
_queryType = 'X';
break;
}
}
}
void sendSerialTelemetry(){
switch (_queryType){
case '=': // Reserved debug command to view any variable from Serial Monitor
//_queryType = 'X';
break;
case 'B': // Send roll and pitch gyro PID values
//serialPrintPID(ROLL);
//serialPrintPID(PITCH);
Serial.println(1300); // TODO: Read from EEPROM
_queryType = 'X';
break;
case 'D': // Send yaw PID values
//serialPrintPID(YAW);
serialPrintPID(headingHoldPID);
Serial.println(0, BIN);
_queryType = 'X';
break;
case 'F': // Send roll and pitch auto level PID values
serialPrintPID(levelRollPID);
serialPrintPID(levelPitchPID);
//serialPrintPID(6); // TODO: LEVELGYROROLL
serialPrintValueComma(0.00);
serialPrintValueComma(0.00);
serialPrintValueComma(0.00);
//serialPrintPID(7); // TODO: LEVELGYROPITCH
serialPrintValueComma(0.00);
serialPrintValueComma(0.00);
serialPrintValueComma(0.00);
Serial.println(WINDUP_GUARD_GAIN); // TODO: windup guard
_queryType = 'X';
break;
case 'H': // Send auto level configuration values
serialPrintValueComma(500.0); // TODO: Read this from EEPROM
Serial.println(150.0); // TODO: Read this from EEPROM
_queryType = 'X';
break;
case 'J': // Altitude Hold
for(byte i=0; i<9; i++) {
serialPrintValueComma(0);
}
Serial.println('0');
_queryType = 'X';
break;
case 'L': // Send data filtering values
serialPrintValueComma(1.0);
serialPrintValueComma(accel.getSmoothFactor());
Serial.println(7.0); // TODO: Read this from EEPROM
_queryType = 'X';
break;
case 'N': // Send transmitter smoothing values
serialPrintValueComma(0); // TODO? receiver transmit factor
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
Serial.println(0.0); // TODO?
_queryType = 'X';
break;
case 'P': // Send transmitter calibration data
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
serialPrintValueComma(0.0); // TODO?
Serial.println(0.0); // TODO?
_queryType = 'X';
break;
case 'Q': // Send sensor data
serialPrintValueComma(gyro.getRoll());
serialPrintValueComma(gyro.getPitch());
serialPrintValueComma(gyro.getYaw());
serialPrintValueComma(accel.getRoll());
serialPrintValueComma(accel.getPitch());
serialPrintValueComma(accel.getYaw());
serialPrintValueComma(mag.getRaw(XAXIS));
serialPrintValueComma(mag.getRaw(YAXIS));
serialPrintValueComma(mag.getRaw(ZAXIS));
serialPrintValueComma(imu.getRoll());
serialPrintValueComma(imu.getPitch());
Serial.println(imu.getHeading());
break;
case 'R': // *** Spare ***
break;
case 'S': // Send all flight data
serialPrintValueComma(deltaTime);
// TODO: These are "raw" in the aeroquad version, but that's pretty useless
serialPrintValueComma(gyro.getRawRoll());
serialPrintValueComma(gyro.getRawPitch());
serialPrintValueComma(gyro.getRawYaw());
serialPrintValueComma(accel.getRawRoll());
serialPrintValueComma(accel.getRawPitch());
serialPrintValueComma(accel.getRawYaw());
serialPrintValueComma(battery.getData()); // Battery monitor
serialPrintValueComma(0); // TODO: Motor axis commands
serialPrintValueComma(0); // TODO: Motor axis commands
serialPrintValueComma(0); // TODO: Motor axis commands
serialPrintValueComma(0); // TODO: Motor axis commands
Serial.print(engines.isArmed(), BIN);
serialComma();
serialPrintValueComma(2000); // Always stable mode
serialPrintValueComma(imu.getHeading()); // Heading
serialPrintValueComma(baro.getRawAltitude()); // Alt hold data
Serial.println(0); // Alt hold on
break;
case 'T': // Send processed transmitter values
serialPrintValueComma(0); // TODO? receiver transmit factor
serialPrintValueComma(0); // TODO? receiver roll
serialPrintValueComma(0); // TODO? receiver pitch
serialPrintValueComma(0); // TODO? receiver yaw
serialPrintValueComma(0.0); // TODO? level adjust roll
serialPrintValueComma(0.0); // TODO? level adjust pitch
serialPrintValueComma(0); // TODO: motor axis roll
serialPrintValueComma(0); // TODO: motor axis pitch
Serial.println(0); // TODO: motor axis yaw
break;
case 'U': // Send smoothed receiver with Transmitter Factor applied values
serialPrintValueComma(0); // TODO?
serialPrintValueComma(0); // TODO?
serialPrintValueComma(0); // TODO?
serialPrintValueComma(0); // TODO?
serialPrintValueComma(0); // TODO?
Serial.println(0); // TODO?
break;
case 'V': // Send receiver status
serialPrintValueComma(receiver.getChannel(ROLL_CHANNEL));
serialPrintValueComma(receiver.getChannel(PITCH_CHANNEL));
serialPrintValueComma(receiver.getChannel(YAW_CHANNEL));
serialPrintValueComma(receiver.getChannel(THROTTLE_CHANNEL));
serialPrintValueComma(receiver.getChannel(GEAR_CHANNEL));
Serial.println(receiver.getChannel(AUX_CHANNEL));
break;
case 'X': // Stop sending messages
break;
case 'Z': // Send heading
serialPrintValueComma(0); // TODO: receiver.getData(YAW)
serialPrintValueComma(0.0); // TODO: headingHold
serialPrintValueComma(0.0); // TODO: setHeading
Serial.println(0.0); // TODO: relativeHeading
break;
case '6': // Report remote commands
for (byte engine = 0; engine < ENGINE_COUNT-1; engine++){
serialPrintValueComma(engines.getEngineSpeed(engine)); // TODO: These should be "remote commands"
}
Serial.println(engines.getEngineSpeed(ENGINE_COUNT-1)); // TODO: These should be "remote commands"
break;
case '!': // Send flight software version
Serial.println(VERSION, 1);
_queryType = 'X';
break;
case '#': // Send software configuration
serialPrintValueComma(2); // Emulate AeroQuad_v18
Serial.print('1'); // X-config
Serial.println();
_queryType = 'X';
break;
case 'e': // Send AREF value
Serial.println(5.0);
_queryType = 'X';
break;
case 'g': // Send magnetometer cal values
// IGNORED
_queryType = 'X';
break;
case '`': // Send Camera values
// IGNORED
break;
// The following modes are my own
case '&':
serialPrintValueComma(deltaTime);
serialPrintValueComma(imu.getRoll());
serialPrintValueComma(imu.getPitch());
serialPrintValueComma(imu.getHeading());
serialPrintValueComma(accel.getXAngle());
serialPrintValueComma(accel.getYAngle());
serialPrintValueComma(accel.getZAngle());
serialPrintValueComma(gyro.getRoll());
serialPrintValueComma(gyro.getPitch());
serialPrintValueComma(gyro.getYaw());
serialPrintValueComma(mag.getRaw(XAXIS));
serialPrintValueComma(mag.getRaw(YAXIS));
serialPrintValueComma(mag.getRaw(ZAXIS));
serialPrintValueComma(baro.getRawAltitude());
serialPrintValueComma(battery.getData());
serialPrintValueComma(engines.getThrottle());
for (byte engine = 0; engine < ENGINE_COUNT; engine++){
serialPrintValueComma(engines.getEngineSpeed(engine));
}
serialPrintValueComma(engines.isArmed());
Serial.println(systemMode, DEC);
break;
}
}
// Used to read floating point values from the serial port
float readFloatSerial(){
#define SERIALFLOATSIZE 10
byte index = 0;
byte timeout = 0;
char data[SERIALFLOATSIZE] = "";
do {
if (Serial.available() == 0) {
delay(10);
timeout++;
}
else {
data[index] = Serial.read();
timeout = 0;
index++;
}
}
while ((index == 0 || data[index-1] != ';') && (timeout < 5) && (index < sizeof(data)-1));
data[index] = '\0';
return atof(data);
}
// Used to read integer values from the serial port
int readIntSerial(){
#define SERIALINTSIZE 7
byte index = 0;
byte timeout = 0;
char data[SERIALINTSIZE] = "";
do {
if (Serial.available() == 0) {
delay(10);
timeout++;
}
else {
data[index] = Serial.read();
timeout = 0;
index++;
}
}
while ((index == 0 || data[index-1] != ';') && (timeout < 5) && (index < sizeof(data)-1));
data[index] = '\0';
return atoi(data);
}
void serialPrintValueComma(float val){
Serial.print(val);
serialComma();
}
void serialPrintValueComma(double val){
Serial.print(val);
serialComma();
}
void serialPrintValueComma(char val){
Serial.print(val);
serialComma();
}
void serialPrintValueComma(int val){
Serial.print(val);
serialComma();
}
void serialPrintValueComma(unsigned long val){
Serial.print(val);
serialComma();
}
void serialComma(){
Serial.print(',');
}
void serialPrintPID(PID pid){
serialPrintValueComma(pid.getP());
serialPrintValueComma(pid.getI());
serialPrintValueComma(pid.getD());
}
void readSerialPID(PID &pid) {
pid.setP(readFloatSerial());
pid.setI(readFloatSerial());
pid.setD(readFloatSerial());
}