Skip to content

Commit c654e60

Browse files
committed
ahr_gizmo
1 parent 902be5a commit c654e60

File tree

19 files changed

+909
-971
lines changed

19 files changed

+909
-971
lines changed

examples/02.QuadcopterAdvanced/02.QuadcopterAdvanced.ino

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ Copyright (c) 2023-2025 https://madflight.com
4646

4747
//Vehicle specific madflight configuration
4848
#define VEH_TYPE VEH_TYPE_COPTER //set the vehicle type for logging and mavlink
49-
#define VEH_FLIGHTMODE_AP_IDS {AP_COPTER_FLIGHTMODE_STABILIZE, AP_COPTER_FLIGHTMODE_ACRO} //mapping of fightmode index to ArduPilot code for logging and mavlink
49+
#define VEH_FLIGHTMODE_AP_IDS {AP_COPTER_FLIGHTMODE_ACRO, AP_COPTER_FLIGHTMODE_STABILIZE} //mapping of fightmode index to ArduPilot code for logging and mavlink
5050
#define VEH_FLIGHTMODE_NAMES {"RATE", "ANGLE"} //fightmode names for telemetry
5151
enum flightmode_enum { RATE, ANGLE }; //the available flightmode indexes
52-
flightmode_enum rcin_to_flightmode_map[6] {RATE, RATE, RATE, ANGLE, ANGLE, ANGLE}; //flightmode mapping from 6 pos switch to flight mode (simulates a 2-pos switch: RATE/ANGLE)
52+
flightmode_enum rcin_to_flightmode_map[6] {RATE, RATE, RATE, RATE, ANGLE, ANGLE}; //flightmode mapping from 2/3/6 pos switch to flight mode (simulates a 2-pos switch: RATE/ANGLE)
5353

5454
#include "madflight_config.h" //Edit this header file to setup the pins, hardware, radio, etc. for madflight
5555
#include <madflight.h>
@@ -131,7 +131,11 @@ void loop() {
131131

132132
mag.update();
133133

134-
if(gps.update()) {bbx.log_gps(); bbx.log_att();} //update gps (and log GPS and ATT for plot.ardupilot.org visualization)
134+
//update gps (and log GPS and ATT for plot.ardupilot.org visualization)
135+
if(gps.update()) {
136+
bbx.log_gps();
137+
bbx.log_att();
138+
}
135139

136140
//logging
137141
static uint32_t log_ts = 0;
@@ -157,7 +161,9 @@ void imu_loop() {
157161

158162
//Get radio commands - Note: don't do this in loop() because loop() is a lower priority task than imu_loop(), so in worst case loop() will not get any processor time.
159163
rcl.update();
160-
veh.setFlightmode( rcin_to_flightmode_map[rcl.flightmode] ); //map rcl.flightmode (0 to 5) to vehicle flightmode
164+
if(rcl.connected() && veh.setFlightmode( rcin_to_flightmode_map[rcl.flightmode] )) { //map rcl.flightmode (0 to 5) to vehicle flightmode
165+
Serial.printf("Flightmode:%s\n",veh.flightmode_name());
166+
}
161167

162168
//PID Controller
163169
switch( veh.getFlightmode() ) {

src/madflight.h

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2626
SOFTWARE.
2727
===========================================================================================*/
2828

29-
//#pragma once //don't use here, we want to get an error if included twice
30-
31-
// madflight config string
32-
#ifndef MADFLIGHT_BOARD
33-
#define MADFLIGHT_BOARD ""
34-
#endif
35-
#ifndef MADFLIGHT_CONFIG
36-
#define MADFLIGHT_CONFIG ""
37-
#endif
38-
const char* madflight_config = MADFLIGHT_BOARD MADFLIGHT_CONFIG;
29+
//#pragma once //don't use here, we want to get an error if this file is included twice
3930

4031
// bus abstraction
4132
#include "madflight/hal/MF_Serial.h"
4233
#include "madflight/hal/MF_I2C.h"
4334

4435
// include all "_cpp.h" modules which have compile time config options
4536
#define MF_ALLOW_INCLUDE_CCP_H
46-
#include "madflight/ahr/ahr_cpp.h" //TODO - convert to use gizmos
4737
#include "madflight/alt/alt_cpp.h" //TODO - convert to use gizmos
4838
#include "madflight/hal/hal_cpp.h"
4939
#include "madflight/imu/imu_cpp.h" //for IMU_EXEC
5040
#undef MF_ALLOW_INCLUDE_CCP_H
5141

5242
// include all other modules without compile time config options
43+
#include "madflight/ahr/ahr.h"
5344
#include "madflight/cfg/cfg.h"
5445
#include "madflight/cli/cli.h"
5546
#include "madflight/bar/bar.h"
@@ -76,6 +67,29 @@ void madflight_warn_or_die(String msg, bool die);
7667
// madflight_setup()
7768
//===============================================================================================
7869

70+
// madflight config string by defines MADFLIGHT_BOARD, MADFLIGHT_CONFIG
71+
#ifndef MADFLIGHT_BOARD
72+
#define MADFLIGHT_BOARD ""
73+
#endif
74+
#ifndef MADFLIGHT_CONFIG
75+
#define MADFLIGHT_CONFIG ""
76+
#endif
77+
const char* madflight_config = MADFLIGHT_BOARD MADFLIGHT_CONFIG;
78+
79+
// vehicle setup by defines VEH_TYPE, VEH_FLIGHTMODE_AP_IDS, VEH_FLIGHTMODE_NAMES
80+
#ifndef VEH_TYPE
81+
#define VEH_TYPE VEH_TYPE_GENERIC
82+
#endif
83+
#ifndef VEH_FLIGHTMODE_AP_IDS
84+
#define VEH_FLIGHTMODE_AP_IDS {0,1,2,3,4,5}
85+
#endif
86+
#ifndef VEH_FLIGHTMODE_NAMES
87+
#define VEH_FLIGHTMODE_NAMES {"FM0","FM1","FM2","FM3","FM4","FM5"}
88+
#endif
89+
const uint8_t Veh::mav_type = VEH_TYPE; //mavlink vehicle type
90+
const uint8_t Veh::flightmode_ap_ids[6] = VEH_FLIGHTMODE_AP_IDS; //mapping from flightmode to ArduPilot flight mode id
91+
const char* Veh::flightmode_names[6] = VEH_FLIGHTMODE_NAMES; //[6] define flightmode name strings for telemetry
92+
7993
void madflight_setup() {
8094
Serial.begin(115200); //start console serial
8195

@@ -176,7 +190,6 @@ void madflight_setup() {
176190
rdr.config.baud = cfg.rdr_baud; //baud rate
177191
rdr.setup();
178192

179-
180193
// GPS
181194
gps.config.gizmo = (Cfg::gps_gizmo_enum)cfg.gps_gizmo; //the gizmo to use
182195
gps.config.ser_bus_id = cfg.gps_ser_bus; //serial bus id
@@ -194,9 +207,19 @@ void madflight_setup() {
194207

195208
// ALT - Altitude Estimator
196209
alt.setup(bar.alt);
197-
210+
198211
// AHR - setup low pass filters for AHRS filters
199-
ahr.setup(cfg.imu_gyr_lp, cfg.imu_acc_lp, cfg.mag_lp);
212+
ahr.config.gizmo = (Cfg::ahr_gizmo_enum)cfg.ahr_gizmo; //the gizmo to use
213+
ahr.config.gyrLpFreq = cfg.imu_gyr_lp; //gyro low pass filter freq [Hz]
214+
ahr.config.accLpFreq = cfg.imu_acc_lp; //accelerometer low pass filter freq [Hz]
215+
ahr.config.magLpFreq = cfg.mag_lp; //magnetometer low pass filter freq [Hz]
216+
ahr.config.pimu = &imu; //pointer to Imu to use
217+
ahr.config.pmag = &mag; //pointer to Mag to use
218+
ahr.config.gyr_offset = &(cfg.imu_cal_gx); //gyro offset[3] [deg/sec]
219+
ahr.config.acc_offset = &(cfg.imu_cal_ax); //acc offset[3] [G]
220+
ahr.config.mag_offset = &(cfg.mag_cal_x); //mag offset[3] [adc_lsb]
221+
ahr.config.mag_scale = &(cfg.mag_cal_sx); //mag scale[3] [uT/adc_lsb]
222+
ahr.setup();
200223

201224
// IMU - Intertial Measurement Unit (gyro/acc/mag)
202225
imu.config.sampleRate = cfg.imu_rate; //sample rate [Hz]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
3+
#include "ahr.h"
4+
#include "Madgwick/Madgwick.h"
5+
6+
class AhrGizmoMadgwick : public AhrGizmo {
7+
private:
8+
AhrConfig *config;
9+
AhrState *state;
10+
Madgwick ahrs;
11+
12+
public:
13+
AhrGizmoMadgwick(Ahr *ahr) {
14+
this->config = &(ahr->config);
15+
this->state = (AhrState*)ahr;
16+
}
17+
18+
void setInitalOrientation(float *qnew) {
19+
ahrs.q0 = qnew[0];
20+
ahrs.q1 = qnew[1];
21+
ahrs.q2 = qnew[2];
22+
ahrs.q3 = qnew[3];
23+
}
24+
25+
bool update() {
26+
ahrs.update(
27+
state->gx * Ahr::deg_to_rad, state->gy * Ahr::deg_to_rad, state->gz * Ahr::deg_to_rad,
28+
state->ax, state->ay, state->az,
29+
state->mx, state->my, state->mz,
30+
state->dt
31+
);
32+
state->q[0] = ahrs.q0;
33+
state->q[1] = ahrs.q1;
34+
state->q[2] = ahrs.q2;
35+
state->q[3] = ahrs.q3;
36+
37+
return true;
38+
}
39+
};

src/madflight/ahr/AhrGizmoMahony.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#pragma once
2+
3+
#include "ahr.h"
4+
#include "Mahony/Mahony.h"
5+
6+
class AhrGizmoMahony : public AhrGizmo {
7+
private:
8+
AhrConfig *config;
9+
AhrState *state;
10+
Mahony ahrs;
11+
12+
public:
13+
AhrGizmoMahony(Ahr *ahr, bool update_1g_only) {
14+
this->config = &(ahr->config);
15+
this->state = (AhrState*)ahr;
16+
17+
//Betaflight flavored version, only update if acc is between 0.9 and 1.1 G
18+
if(update_1g_only) {
19+
ahrs.config_alen2_min = 0.81;
20+
ahrs.config_alen2_max = 1.21;
21+
}
22+
}
23+
24+
void setInitalOrientation(float *qnew) {
25+
ahrs.q0 = qnew[0];
26+
ahrs.q1 = qnew[1];
27+
ahrs.q2 = qnew[2];
28+
ahrs.q3 = qnew[3];
29+
}
30+
31+
bool update() {
32+
ahrs.update(
33+
state->gx * Ahr::deg_to_rad, state->gy * Ahr::deg_to_rad, state->gz * Ahr::deg_to_rad,
34+
state->ax, state->ay, state->az,
35+
state->mx, state->my, state->mz,
36+
state->dt
37+
);
38+
state->q[0] = ahrs.q0;
39+
state->q[1] = ahrs.q1;
40+
state->q[2] = ahrs.q2;
41+
state->q[3] = ahrs.q3;
42+
43+
return true;
44+
}
45+
};

src/madflight/ahr/AhrGizmoVqf.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//=================================================================================================
2+
// VQF - see https://github.com/dlaidig/vqf
3+
//=================================================================================================
4+
5+
//NOTE: only one AhrGizmoVqf instance is allowed
6+
7+
//NOTE: do not use filter for VQF, feed the data directly into the filter, i.e. set gyrLpFreq, accLpFreq, magLpFreq to 1e10
8+
9+
#pragma once
10+
11+
#include "ahr.h"
12+
#include "vqf/vqf.h"
13+
14+
class AhrGizmoVqf : public AhrGizmo {
15+
private:
16+
AhrConfig *config;
17+
AhrState *state;
18+
19+
public:
20+
AhrGizmoVqf(Ahr *ahr) {
21+
this->config = &(ahr->config);
22+
this->state = (AhrState*)ahr;
23+
24+
initVqf(1.0/config->pimu->getSampleRate(), 1.0/config->pimu->getSampleRate(), 1.0/config->pimu->getSampleRate());
25+
}
26+
27+
void setInitalOrientation(float *qnew) {
28+
//TODO (?)
29+
}
30+
31+
bool update() {
32+
//convert to ENU from NED: xE = yE, yN = xE, zU = -zD
33+
float gyr[3] = {state->gy * Ahr::deg_to_rad, state->gx * Ahr::deg_to_rad, -state->gz * Ahr::deg_to_rad}; //gyr in rad/sec
34+
float acc[3] = {state->ay * 9.81f, state->ax * 9.81f, -state->az * 9.81f}; //acc in m/s/s - acc[] horizontal: [0, 0, -9.81], nose down:[0, 9.81, 0], right down: [9.81, 0, 0]
35+
float mag[3] = {state->mx, -state->my, state->mz}; //mag no unit - mag[] horizontal pointing north: [15, 0, 40], east: [0,15,40]
36+
37+
//get fused q_enu in ENU frame
38+
float q_enu[4];
39+
if (state->mx==0 && state->my==0 && state->mz==0) {
40+
updateGyr(gyr);
41+
updateAcc(acc);
42+
getQuat6D(q_enu);
43+
}else{
44+
updateGyr(gyr);
45+
updateAcc(acc);
46+
updateMag(mag);
47+
getQuat9D(q_enu);
48+
}
49+
50+
//convert q_enu to NED reference frame
51+
float q_trans[4] = {0,M_SQRT2/2,M_SQRT2/2,0}; //ENU to NED
52+
quatMultiply(q_enu, q_trans, state->q);
53+
54+
return true;
55+
}
56+
57+
static void quatMultiply(const vqf_real_t q1[4], const vqf_real_t q2[4], vqf_real_t out[4])
58+
{
59+
vqf_real_t w = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3];
60+
vqf_real_t x = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2];
61+
vqf_real_t y = q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
62+
vqf_real_t z = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
63+
out[0] = w; out[1] = x; out[2] = y; out[3] = z;
64+
}
65+
66+
};

0 commit comments

Comments
 (0)