-
Notifications
You must be signed in to change notification settings - Fork 64
Expand file tree
/
Copy pathmadflight.h
More file actions
421 lines (358 loc) · 15.8 KB
/
madflight.h
File metadata and controls
421 lines (358 loc) · 15.8 KB
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
/*==========================================================================================
MIT License
Copyright (c) 2023-2026 https://madflight.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
===========================================================================================*/
//madflight.h - Flight Controller for ESP32 / ESP32-S3 / RP2350 / RP2040 / STM32
//#pragma once //don't use here, we want to get an error if this file is included twice
#include "madflight_modules.h"
#include "mag/MagGizmoIMU.h"
extern const char madflight_config[];
#ifdef MF_BOARD
//the board header file must define const char madflight_board[] and should define MF_BOARD_NAME, MF_MCU_NAME
#include MF_BOARD
#else
const char madflight_board[] = "";
#endif
//===============================================================================================
// madflight_setup()
//===============================================================================================
// vehicle setup by defines VEH_TYPE, VEH_FLIGHTMODE_AP_IDS, VEH_FLIGHTMODE_NAMES
#ifndef VEH_TYPE
#define VEH_TYPE VEH_TYPE_GENERIC
#endif
#ifndef VEH_FLIGHTMODE_AP_IDS
#define VEH_FLIGHTMODE_AP_IDS {0,1,2,3,4,5}
#endif
#ifndef VEH_FLIGHTMODE_NAMES
#define VEH_FLIGHTMODE_NAMES {"FM0","FM1","FM2","FM3","FM4","FM5"}
#endif
const uint8_t Veh::mav_type = VEH_TYPE; //mavlink vehicle type
const uint8_t Veh::flightmode_ap_ids[6] = VEH_FLIGHTMODE_AP_IDS; //mapping from flightmode to ArduPilot flight mode id
const char* Veh::flightmode_names[6] = VEH_FLIGHTMODE_NAMES; //define flightmode name strings for telemetry
//=============================================================================
// Tasks
//=============================================================================
void rcl_task(void *pvParameters) {
(void)pvParameters;
for(;;) {
rcl.update(); // get rc radio commands
out.update(); // stop motors on timeout
portYIELD();
}
}
void cli_task(void *pvParameters) {
(void)pvParameters;
cli.begin();
for(;;) {
cli.update(); // process CLI commands
portYIELD();
}
}
struct {
ScheduleFreq sys_schedule = ScheduleFreq(10); // System log (10Hz)
//ahr
ScheduleFreq ahr_schedule = ScheduleFreq(cfg.bbx_log_ahr);
MsgSubscription<AhrState> ahr_sub = MsgSubscription<AhrState>("log_ahr", &ahr.topic);
AhrState ahr_state;
//imu
ScheduleFreq imu_schedule = ScheduleFreq(cfg.bbx_log_imu);
MsgSubscription<ImuState> imu_sub = MsgSubscription<ImuState>("log_imu", &imu.topic);
ImuState imu_state;
//out
ScheduleFreq out_schedule = ScheduleFreq(cfg.bbx_log_out);
MsgSubscription<OutState> out_sub = MsgSubscription<OutState>("log_out", &out.topic);
OutState out_state;
//rcl
ScheduleFreq rcl_schedule = ScheduleFreq(cfg.bbx_log_rcl);
MsgSubscription<RclState> rcl_sub = MsgSubscription<RclState>("log_rcl", &rcl.topic);
RclState rcl_state;
} g_sensor_task;
void sensor_task(void *pvParameters) {
(void)pvParameters;
for(;;) {
//sensors
if(bar.update()) bbx.log_baro(); // barometer
mag.update(); // magnetometer (logging is done with imu together)
if(gps.update()) bbx.log_gps(); // gps
if(bat.update()) bbx.log_bat(); // battery consumption
if(rdr.update()) bbx.log_rdr(); // radar
if(ofl.update()) bbx.log_ofl(); // optical flow
//logging
if(g_sensor_task.sys_schedule.expired()) {
bbx.log_sys();
}
if(g_sensor_task.imu_schedule.expired() && g_sensor_task.imu_sub.pull_updated(&g_sensor_task.imu_state)) {
bbx.log_imu(&g_sensor_task.imu_state);
}
if(g_sensor_task.ahr_schedule.expired() && g_sensor_task.ahr_sub.pull_updated(&g_sensor_task.ahr_state)) {
bbx.log_ahr(&g_sensor_task.ahr_state);
}
if(g_sensor_task.out_schedule.expired() && g_sensor_task.out_sub.pull_updated(&g_sensor_task.out_state)) {
bbx.log_out(&g_sensor_task.out_state);
}
if(g_sensor_task.rcl_schedule.expired() && g_sensor_task.rcl_sub.pull_updated(&g_sensor_task.rcl_state)) {
bbx.log_rcl(&g_sensor_task.rcl_state);
}
portYIELD();
}
}
#define mf_xstr(s) #s
#define mf_str(s) mf_xstr(s)
void madflight_setup() {
// HAL - Detach USB to until SDCARD is setup
hal_startup();
// CFG - Configuration parameters (execute before delay to start LED + SDCARD)
cfg.begin();
#ifdef MF_CONFIG_CLEAR
cfg.clear();
cfg.writeToEeprom();
madflight_panic("Config cleared. comment out '#define MF_CONFIG_CLEAR' and upload again.");
#endif
cfg.loadFromEeprom(); //load parameters from EEPROM
cfg.load_madflight(madflight_board, madflight_config); //load config
// LED - Setup LED (execute before delay to turn it on)
led.config.gizmo = (Cfg::led_gizmo_enum)cfg.led_gizmo;
led.config.pin = cfg.pin_led;
led.setup();
led.color(0x0000ff); //turn on blue to signal startup
led.enabled = false; //do not change state until setup compled
// BBX - Black Box (execute before delay to start USB-MSC if card is inserted)
bbx.config.gizmo = (Cfg::bbx_gizmo_enum)cfg.bbx_gizmo; //the gizmo to use
bbx.config.spi_bus = hal_get_spi_bus(cfg.bbx_spi_bus); //SPI bus
bbx.config.spi_cs = cfg.pin_bbx_cs; //SPI select pin
bbx.config.pin_mmc_dat = cfg.pin_mmc_dat;
bbx.config.pin_mmc_clk = cfg.pin_mmc_clk;
bbx.config.pin_mmc_cmd = cfg.pin_mmc_cmd;
bbx.config.bbx_ser_bus = cfg.bbx_ser_bus;
bbx.config.bbx_baud = cfg.bbx_baud;
bbx.setup();
// USB - Start USB-CDC (Serial) and USB-MSC (if sdcard is inserted)
hal_usb_setup();
// Serial - Start USB serial console
Serial.begin(115200);
// CLI - Start CLI (Serial) task early in setup, allows for CLI commands while booting
#if defined ARDUINO_ARCH_RP2040 && defined USE_TINYUSB
// Hack for Adafruit TinyUSB in combination with FreeRTOS: use core1
int cli_core = 1;
#else
// ESP32: use core0 otherwise Serial output drops a lot of characters
// RP2350 with Pico SDK USB: use core0
// Other platforms: use core0
int cli_core = 0;
#endif
hal_xTaskCreate(cli_task, "mf_CLI", 2 * MF_FREERTOS_DEFAULT_STACK_SIZE, NULL, uxTaskPriorityGet(NULL), NULL, cli_core);
// Delay - 6 second startup delay
for(int i = 12; i > 0; i--) {
Serial.printf(MADFLIGHT_VERSION " starting %d ...\n", i);
Serial.flush();
#ifndef MF_DEBUG
delay(500);
#else
delay(100);
#endif
}
Serial.println("Arduino library: " HAL_ARDUINO_STR);
#ifdef MF_BOARD_NAME
Serial.println("Board: " MF_BOARD_NAME);
#endif
#ifdef MF_MCU_NAME
Serial.println("Processor: " MF_MCU_NAME);
#endif
//arduino defines
#ifdef ARDUINO_BOARD
Serial.println("-D ARDUINO_BOARD=" ARDUINO_BOARD );
#endif
#ifdef ARDUINO_VARIANT
Serial.println("-D ARDUINO_VARIANT=" ARDUINO_VARIANT );
#endif
#ifdef ARDUINO_HOST_OS
Serial.println("-D ARDUINO_HOST_OS=" ARDUINO_HOST_OS ); //only arduino IDE, not PlatformIO
#endif
#ifdef ARDUINO_FQBN
Serial.println("-D ARDUINO_FQBN=" ARDUINO_FQBN ); //only arduino IDE, not PlatformIO
#endif
#ifdef ARDUINO
Serial.println("-D ARDUINO=" mf_str(ARDUINO));
#endif
#ifdef CORE_DEBUG_LEVEL
Serial.println("-D CORE_DEBUG_LEVEL=" mf_str(CORE_DEBUG_LEVEL));
#endif
#ifdef ARDUINO_RUNNING_CORE
Serial.println("-D ARDUINO_RUNNING_CORE=" mf_str(ARDUINO_RUNNING_CORE));
#endif
#ifdef ARDUINO_EVENT_RUNNING_CORE
Serial.println("-D ARDUINO_EVENT_RUNNING_CORE=" mf_str(ARDUINO_EVENT_RUNNING_CORE));
#endif
#ifdef ARDUINO_USB_MODE
Serial.println("-D ARDUINO_USB_MODE=" mf_str(ARDUINO_USB_MODE));
#endif
#ifdef ARDUINO_USB_CDC_ON_BOOT
Serial.println("-D ARDUINO_USB_CDC_ON_BOOT=" mf_str(ARDUINO_USB_CDC_ON_BOOT));
#endif
#ifdef ARDUINO_USB_MSC_ON_BOOT
Serial.println("-D ARDUINO_USB_MSC_ON_BOOT=" mf_str(ARDUINO_USB_MSC_ON_BOOT));
#endif
#ifdef ARDUINO_USB_DFU_ON_BOOT
Serial.println("-D ARDUINO_USB_DFU_ON_BOOT=" mf_str(ARDUINO_USB_DFU_ON_BOOT));
#endif
// INFO - Rerun CFG to show output after startup delay
cfg.clear();
cfg.loadFromEeprom(); //load parameters from EEPROM
cfg.load_madflight(madflight_board, madflight_config); //load config
// HAL - Hardware abstraction layer setup: serial, spi, i2c (see hal.h)
hal_setup();
// I2C - Show i2c devices
cli.print_i2cScan(); //print i2c scan
// LED and BBX summary
cfg.printModule("led");
bbx.printSummary();
// RCL - Radio Control Link
rcl.config.gizmo = (Cfg::rcl_gizmo_enum)cfg.rcl_gizmo; //the gizmo to use
rcl.config.ser_bus_id = cfg.rcl_ser_bus; //serial bus id
rcl.config.baud = cfg.rcl_baud; //baud rate
rcl.config.ppm_pin = cfg.getValue("pin_ser" + String(cfg.rcl_ser_bus) + "_rx", -1);
rcl.setup(); //Initialize radio communication.
// RCL - Start RCL task on core0
hal_xTaskCreate(rcl_task, "mf_RCL", 2 * MF_FREERTOS_DEFAULT_STACK_SIZE, NULL, uxTaskPriorityGet(NULL), NULL, 0);
// BAR - Barometer
bar.config.gizmo = (Cfg::bar_gizmo_enum)cfg.bar_gizmo; //the gizmo to use
bar.config.i2c_bus = hal_get_i2c_bus(cfg.bar_i2c_bus); //i2c bus
bar.config.i2c_adr = cfg.bar_i2c_adr; //i2c address. 0=default address
bar.config.sample_rate = 100; //sample rate [Hz]
bar.setup();
// MAG - External Magnetometer
mag.config.gizmo = (Cfg::mag_gizmo_enum)cfg.mag_gizmo; //the gizmo to use
mag.config.i2c_bus = hal_get_i2c_bus(cfg.mag_i2c_bus); //i2c bus
mag.config.i2c_adr = cfg.mag_i2c_adr; //i2c address. 0=default address
mag.config.sample_rate = 100; //sample rate [Hz]
mag.setup();
// BAT - Battery Monitor
bat.config.gizmo = (Cfg::bat_gizmo_enum)cfg.bat_gizmo; //the gizmo to use
bat.config.i2c_bus = hal_get_i2c_bus(cfg.bat_i2c_bus); //i2c bus
bat.config.i2c_adr = cfg.bat_i2c_adr; //i2c address. 0=default address
bat.config.sample_rate = 100; //sample rate [Hz]
bat.config.adc_pin_v = cfg.pin_bat_v;
bat.config.adc_pin_i = cfg.pin_bat_i;
bat.config.adc_cal_v = cfg.bat_cal_v;
bat.config.adc_cal_i = cfg.bat_cal_i;
bat.config.rshunt = cfg.bat_cal_i;
bat.setup();
// RDR - Radar/Lidar/Sonar sensors
rdr.config.gizmo = (Cfg::rdr_gizmo_enum)cfg.rdr_gizmo; //the gizmo to use
rdr.config.rdr_ser_bus = cfg.rdr_ser_bus; //serial bus
rdr.config.rdr_baud = cfg.rdr_baud; //baud rate
rdr.config.pin_rdr_trig = cfg.pin_rdr_trig;
rdr.config.pin_rdr_echo = cfg.pin_rdr_echo;
rdr.config.rdr_i2c_bus = cfg.rdr_i2c_bus;
rdr.config.rdr_i2c_adr = cfg.rdr_i2c_adr;
rdr.setup();
// OFL - Optical flow sensor
ofl.config.ofl_gizmo = (Cfg::ofl_gizmo_enum)cfg.ofl_gizmo; //the gizmo to use
ofl.config.ofl_spi_bus = cfg.ofl_spi_bus; // spi bus
ofl.config.pin_ofl_cs = cfg.pin_ofl_cs; // spi cs pin
ofl.config.ofl_ser_bus = cfg.ofl_ser_bus; // serial bus
ofl.config.ofl_baud = cfg.ofl_baud; // baud rate (0 = default)
ofl.config.ofl_align = (Cfg::ofl_align_enum)cfg.ofl_align; // xy-axis orientation. Example: ES means positive x-axis points East (right) and positive y-axis points South (back)
ofl.config.ofl_cal_rad = cfg.ofl_cal_rad; // manual calibration factor from pixels to radians, leave at 0 to use calibration from gizmo
ofl.setup();
// GPS
gps.config.gizmo = (Cfg::gps_gizmo_enum)cfg.gps_gizmo; //the gizmo to use
gps.config.ser_bus_id = cfg.gps_ser_bus; //serial bus id
gps.config.baud = cfg.gps_baud; //baud rate
gps.setup();
// OUT - Set GPIOs
for(int i = 0; i < 16; i++) {
int pin = (&cfg.pin_out0)[i]; //pin_out0..15
out.set_pin(i, pin);
}
// Start Sensor task on core0 after all sensor (except IMU) have been initialized
hal_xTaskCreate(sensor_task, "mf_SENSOR", 2 * MF_FREERTOS_DEFAULT_STACK_SIZE, NULL, uxTaskPriorityGet(NULL), NULL, 0);
// ALT - Altitude Estimator
if(rdr.installed()) {
alt.setup(rdr.dist);
}else{
alt.setup(bar.alt);
}
// AHR - setup low pass filters for AHRS filters
ahr.config.gizmo = (Cfg::ahr_gizmo_enum)cfg.ahr_gizmo; //the gizmo to use
ahr.config.gyrLpFreq = cfg.imu_gyr_lp; //gyro low pass filter freq [Hz]
ahr.config.accLpFreq = cfg.imu_acc_lp; //accelerometer low pass filter freq [Hz]
ahr.config.magLpFreq = cfg.mag_lp; //magnetometer low pass filter freq [Hz]
ahr.config.pimu = &imu; //pointer to Imu to use
ahr.config.pmag = &mag; //pointer to Mag to use
ahr.config.gyr_offset = &(cfg.imu_cal_gx); //gyro offset[3] [deg/sec]
ahr.config.acc_offset = &(cfg.imu_cal_ax); //acc offset[3] [G]
ahr.config.mag_offset = &(cfg.mag_cal_x); //mag offset[3] [adc_lsb]
ahr.config.mag_scale = &(cfg.mag_cal_sx); //mag scale[3] [uT/adc_lsb]
ahr.setup();
// IMU - Intertial Measurement Unit (gyro/acc/mag)
imu.config.sample_rate_requested = cfg.imu_rate; //sample rate [Hz]
imu.config.pin_int = cfg.pin_imu_int; //IMU data ready interrupt pin
imu.config.gizmo = (Cfg::imu_gizmo_enum)cfg.imu_gizmo; //the gizmo to use
imu.config.spi_bus = hal_get_spi_bus(cfg.imu_spi_bus); //SPI bus
imu.config.spi_cs = cfg.pin_imu_cs; //SPI select pin
imu.config.i2c_bus = hal_get_i2c_bus(cfg.imu_i2c_bus); //I2C bus (only used if spi_bus==nullptr)
imu.config.i2c_adr = cfg.imu_i2c_adr; //i2c address. 0=default address
imu.config.uses_i2c = ((Cfg::imu_bus_type_enum)cfg.imu_bus_type == Cfg::imu_bus_type_enum::mf_I2C);
imu.config.pin_clkin = cfg.pin_imu_clkin; //CLKIN pin for ICM-42866-P - only tested for RP2 targets
// IMU - Some IMU sensors need a couple of tries...
int tries = 10;
while(true) {
int rv = imu.setup(); //request 1000 Hz sample rate, returns 0 on success, positive on error, negative on warning
if(rv<=0) break;
tries--;
Serial.printf("IMU: WARNING init failed rv=%d\n", rv);
}
if(!imu.installed() && (Cfg::imu_gizmo_enum)cfg.imu_gizmo != Cfg::imu_gizmo_enum::mf_NONE) {
madflight_panic("IMU install failed.");
}
// IMU - Connect imu internal magnetometer to mag
if(imu.config.has_mag && !mag.gizmo) {
mag.gizmo = new MagGizmoIMU((MagState*)&mag);
imu.config.pmag = &mag;
Serial.println("IMU: magnetometer installed");
}
// IMU - Start IMU update handler
if(imu.installed()) {
ahr.setInitalOrientation(); //do this before IMU update handler is started
if(imu.topic.get_generation() == 0) {
madflight_panic(String("IMU interrupt not firing. Is pin_imu_int GPIO" + String(cfg.pin_imu_int) + String(" connected?")));
}
if(!imu_loop) Serial.println("IMU: WARNING 'void imu_loop()' not defined.");
imu.onUpdate = imu_loop;
#ifndef MF_DEBUG
// Switch off LED to signal calibration
led.enabled = true;
led.off();
led.enabled = false;
// Calibrate for zero gyro readings, assuming vehicle not moving when powered up. Comment out to only use cfg values. (Use CLI to calibrate acc.)
cli.calibrate_gyro();
#endif
}
// LUA - Start Lua task and read script /madflight.lua from SDCARD (when #define MF_LUA_ENABLE 1)
lua.begin();
// INFO - Command Line Interface banner
cli.banner();
// LED - Enable and switch it to green to signal end of startup.
led.enabled = true;
led.color(0x00ff00); //switch color to green
led.on();
// STATS - Reset
MsgBroker::reset_stats();
RuntimeTraceGroup::reset();
}