diff --git a/conf/airframes/examples/quadrotor_lisa_m_2_pwm_spektrum_geo_mag.xml b/conf/airframes/examples/quadrotor_lisa_m_2_pwm_spektrum_geo_mag.xml new file mode 100755 index 0000000000..5a8df52553 --- /dev/null +++ b/conf/airframes/examples/quadrotor_lisa_m_2_pwm_spektrum_geo_mag.xml @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + +
+ +
+ + + +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + + +
+ +
diff --git a/conf/modules/geo_mag.xml b/conf/modules/geo_mag.xml new file mode 100755 index 0000000000..bcae9b0c48 --- /dev/null +++ b/conf/modules/geo_mag.xml @@ -0,0 +1,20 @@ + + + + + +
+ +
+ + + + + + + + +
diff --git a/sw/airborne/math/pprz_algebra_double.h b/sw/airborne/math/pprz_algebra_double.h index d712ae2f5f..cdcc260162 100644 --- a/sw/airborne/math/pprz_algebra_double.h +++ b/sw/airborne/math/pprz_algebra_double.h @@ -92,6 +92,10 @@ struct DoubleRates { (_vout).z = rint((_vin).z); \ } +#define DOUBLE_VECT3_ASSIGN(_a, _x, _y, _z) VECT3_ASSIGN(_a, _x, _y, _z) + +#define DOUBLE_VECT3_COPY(_a, _b) VECT3_COPY(_a, _b) + #define DOUBLE_VECT3_SUM(_c,_a,_b) { \ (_c).x = (_a).x + (_b).x; \ (_c).y = (_a).y + (_b).y; \ diff --git a/sw/airborne/modules/geo_mag/geo_mag.c b/sw/airborne/modules/geo_mag/geo_mag.c new file mode 100755 index 0000000000..759f44794b --- /dev/null +++ b/sw/airborne/modules/geo_mag/geo_mag.c @@ -0,0 +1,49 @@ +/* + * + * Copyright (C) 2012 Sergey Krukowski . + * + * This module based on the WMM2010 modell (http://www.ngdc.noaa.gov/geomag/models.shtml). + * + */ + +#include "modules/geo_mag/geo_mag.h" +#include "modules/geo_mag/wmm2010.h" +#include "math/pprz_algebra_double.h" +#include "subsystems/gps.h" +#include "autopilot.h" +#include "subsystems/ahrs/ahrs_int_cmpl_quat.h" // in AHRS subsystem ahrs_h is DoubleVect3 variable + +bool_t calc_flag; +struct GeoMagVect geo_mag_vect; + +void geo_mag_init(void) { + calc_flag = FALSE; + geo_mag_vect.ready = FALSE; +} + +void geo_mag_periodic(void) { + if(gps.fix == GPS_FIX_3D && !geo_mag_vect.ready && !autopilot_motors_on) + calc_flag = TRUE; +} + +void geo_mag_event(void) { + + if(calc_flag) { + double gha[MAXCOEFF]; // Geomag global variables + int32_t nmax; + double sdate = GPS_EPOCH_BEGIN + (double)gps.week/WEEKS_IN_YEAR + // Current date in decimal year, for example 2012.68 + (double)gps.tow/1000/SECS_IN_YEAR; + double latitude = DegOfRad((double)gps.lla_pos.lat / 1e7); // LLA Position latitude in decimal degree + double longitude = DegOfRad((double)gps.lla_pos.lon / 1e7); // LLA Position longtitude in decimal degree + double alt = (double)gps.lla_pos.alt / 1e6; // LLA Altitude in km + + nmax = extrapsh(sdate, GEO_EPOCH, NMAX_1, NMAX_2, gha); // Calculates additional coeffs + mag_calc(1, latitude, longitude, alt, nmax, gha, &geo_mag_vect.x, &geo_mag_vect.y, &geo_mag_vect.z, // Calculates absolute magnet fields + IEXT, EXT_COEFF1, EXT_COEFF2, EXT_COEFF3); + FLOAT_VECT3_NORMALIZE(geo_mag_vect); // Normalizes mag vector + DOUBLE_VECT3_COPY(ahrs_h, geo_mag_vect); // Copy to ahrs_h Vector + geo_mag_vect.ready = TRUE; + + } + calc_flag = FALSE; +} diff --git a/sw/airborne/modules/geo_mag/geo_mag.h b/sw/airborne/modules/geo_mag/geo_mag.h new file mode 100755 index 0000000000..b0a17b56b4 --- /dev/null +++ b/sw/airborne/modules/geo_mag/geo_mag.h @@ -0,0 +1,28 @@ +/* + * + * Copyright (C) 2012 Sergey Krukowski . + * + * This module based on the WMM2010 modell (http://www.ngdc.noaa.gov/geomag/models.shtml). + * + */ + +#ifndef GEO_MAG_H +#define GEO_MAG_H + +#include "std.h" +#include "wmm2010.h" + +struct GeoMagVect { + double x; + double y; + double z; + bool_t ready; +}; + +extern void geo_mag_init(void); +extern void geo_mag_periodic(void); +extern void geo_mag_event(void); + +extern struct GeoMagVect geo_mag_vect; + +#endif diff --git a/sw/airborne/modules/geo_mag/wmm2010.c b/sw/airborne/modules/geo_mag/wmm2010.c new file mode 100755 index 0000000000..e1d83c592d --- /dev/null +++ b/sw/airborne/modules/geo_mag/wmm2010.c @@ -0,0 +1,240 @@ +/* + * + * Copyright (C) 2012 Sergey Krukowski . + * + * This module based on the WMM2010 modell (http://www.ngdc.noaa.gov/geomag/models.shtml). + * + */ + +#include "std.h" +#include "wmm2010.h" + +const double gh1[MAXCOEFF] = { +0.0,-29496.6,-1586.3,4944.4, +-2396.6,3026.1,-2707.7, 1668.6,-576.1, +1340.1,-2326.2,-160.2, 1231.9,251.9, 634,-536.6, +912.6,808.9,286.4,166.7,-211.2,-357.1,164.3,89.4,-309.1, +-230.9,357.2,44.6,200.3,188.9,-141.1,-118.2,-163.0, 0.0,-7.8,100.9, +72.8,68.6,-20.8,76.0,44.1,-141.4,61.5,-22.8,-66.3,13.2,3.1,-77.9,55.0, +80.5,-75.1,-57.9,-4.7,-21.1,45.3,6.5,13.9,24.9,10.4,7.0,1.7,-27.7,4.9,-3.3, +24.4,8.1,11.0,-14.5,-20.0,-5.6,11.9,-19.3,-17.4,11.5,16.7,10.9,7.0,-14.1,-10.8,-3.7,1.7, +5.4,9.4,-20.5,3.4,11.5,-5.2,12.8,3.1,-7.2,-12.4,-7.4,-0.7,8.0,8.4,2.1,-8.5,-6.1,-10.1,7.0, +-2.0,-6.3,2.8,0.9,-0.1,-1.1,4.7,-0.2,4.4,2.5,-7.2,-0.3,-1.0,2.2,-3.9,3.1,-2.0,-1.0,-2.0,-2.8,-8.3, +3.0,-1.5,0.2,-2.1,1.7,1.7,-0.6,-0.5,-1.8,0.5,0.9,-0.8,-0.4,0.4,-2.5,1.8,-1.3,0.1,-2.1,0.7,-1.9,3.8,-1.8, +-2.2,-0.2,-0.9,0.3,0.3,1.0,2.1,-0.6,-2.5,0.9,0.5,-0.1,0.6,0.5,0.0,-0.4,0.1,-0.4,0.3,0.2,-0.9,-0.8,-0.2,0.0,0.9 +}; + +const double gh2[MAXCOEFF] = { +0.0,11.6,16.5,-25.9, +-12.1,-4.4,-22.5,1.9,-11.8, +0.4,-4.1,7.3,-2.9,-3.9,-7.7,-2.6, +-1.8,2.3,1.1,-8.7,2.7,4.6,3.9,-2.1,-0.8, +-1.0,0.6,0.4,-1.8,1.8,-1.0,1.2,0.9,4.0,1.0,-0.6, +-0.2,-0.2,-0.2,-0.1,-2.1,2.0,-0.4,-1.7,-0.6,-0.3,0.5,1.7,0.9, +0.1,-0.1,0.7,-0.6,0.3,1.3,-0.1,0.4,-0.1,0.3,-0.8,-0.7,-0.3,0.6,0.3, +-0.1,0.1,-0.1,-0.6,0.2,0.2,0.4,-0.2,0.4,0.3,0.1,0.3,-0.1,-0.6,0.4,0.2,0.3, +0.0,-0.1,0.0,0.0,-0.2,0.3,0.0,-0.4,-0.1,-0.3,0.1,0.1,0.0,-0.1,-0.2,-0.4,0.3,-0.2,0.2, +0.0,0.0,0.1,-0.1,-0.1,0.2,0.0,0.0,-0.1,-0.1,-0.1,-0.2,0.0,0.0,-0.1,-0.1,-0.2,-0.2,0.0,-0.2,-0.1, +0.0,0.0,0.0,0.0,0.1,0.1,0.0,0.0,0.1,0.0,0.0,0.0,0.1,0.0,0.0,0.0,-0.1,0.0,-0.1,-0.1,0.0,0.0,-0.1, +0.0,0.0,0.0,0.1,0.0,0.1,0.0,-0.1,0.0,0.0,0.0,0.0,0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.1,0.0,0.1,0.0 +}; + +int16_t extrapsh(double date, double dte1, int16_t nmax1, int16_t nmax2, double *gh) { + + int16_t nmax; + int16_t k, l; + int16_t ii; + double factor; + + factor = date - dte1; + if (nmax1 == nmax2) { + k = nmax1 * (nmax1 + 2); + nmax = nmax1; + } + else { + if (nmax1 > nmax2) { + k = nmax2 * (nmax2 + 2); + l = nmax1 * (nmax1 + 2); + + for ( ii = k + 1; ii <= l; ++ii) { + gh[ii] = gh1[ii]; + } + + nmax = nmax1; + } + else { + k = nmax1 * (nmax1 + 2); + l = nmax2 * (nmax2 + 2); + + for ( ii = k + 1; ii <= l; ++ii) { + gh[ii] = factor * gh2[ii]; + } + + nmax = nmax2; + } + } + + for ( ii = 1; ii <= k; ++ii) { + gh[ii] = gh1[ii] + factor * gh2[ii]; + } + + return(nmax); +} + +int16_t mag_calc(int16_t igdgc, double flat, double flon, double elev, int16_t nmax, double *gh, double *geo_mag_x, double *geo_mag_y, double *geo_mag_z, int16_t iext, double ext1, double ext2, double ext3) { + + double earths_radius = 6371.2; + double dtr = 0.01745329; + double slat; + double clat; + double ratio; + double aa, bb, cc, dd; + double sd; + double cd; + double r; + double a2; + double b2; + double rr = 0; + double fm,fn = 0; + double sl[14]; + double cl[14]; +#ifdef GEO_MAG_DOUBLE + double p[119]; + double q[119]; +#else + float p[119]; + float q[119]; +#endif + int ii,j,k,l,m,n; + int npq; + int ios; + double argument; + double power; + a2 = 40680631.59; /* WGS84 */ + b2 = 40408299.98; /* WGS84 */ + ios = 0; + r = elev; + argument = flat * dtr; + slat = sinf( argument ); + if ((90.0 - flat) < 0.001) { + aa = 89.999; /* 300 ft. from North pole */ + } + else { + if ((90.0 + flat) < 0.001) { + aa = -89.999; /* 300 ft. from South pole */ + } + else { + aa = flat; + } + } + argument = aa * dtr; + clat = cosf( argument ); + argument = flon * dtr; + sl[1] = sinf( argument ); + cl[1] = cosf( argument ); + + *geo_mag_x = 0; + *geo_mag_y = 0; + *geo_mag_z = 0; + + sd = 0.0; + cd = 1.0; + l = 1; + n = 0; + m = 1; + npq = (nmax * (nmax + 3)) / 2; + + if (igdgc == 1) { + aa = a2 * clat * clat; + bb = b2 * slat * slat; + cc = aa + bb; + argument = cc; + dd = sqrt( argument ); + argument = elev * (elev + 2.0 * dd) + (a2 * aa + b2 * bb) / cc; + r = sqrt( argument ); + cd = (elev + dd) / r; + sd = (a2 - b2) / dd * slat * clat / r; + aa = slat; + slat = slat * cd - clat * sd; + clat = clat * cd + aa * sd; + } + + ratio = earths_radius / r; + argument = 3.0; + aa = sqrt( argument ); + p[1] = 2.0 * slat; + p[2] = 2.0 * clat; + p[3] = 4.5 * slat * slat - 1.5; + p[4] = 3.0 * aa * clat * slat; + q[1] = -clat; + q[2] = slat; + q[3] = -3.0 * clat * slat; + q[4] = aa * (slat * slat - clat * clat); + + for ( k = 1; k <= npq; ++k) { + if (n < m) { + m = 0; + n = n + 1; + argument = ratio; + power = n + 2; + rr = pow(argument,power); + fn = n; + } + fm = m; + if (k >= 5) { + if (m == n) { + argument = (1.0 - 0.5/fm); + aa = sqrt( argument ); + j = k - n - 1; + p[k] = (1.0 + 1.0/fm) * aa * clat * p[j]; + q[k] = aa * (clat * q[j] + slat/fm * p[j]); + sl[m] = sl[m-1] * cl[1] + cl[m-1] * sl[1]; + cl[m] = cl[m-1] * cl[1] - sl[m-1] * sl[1]; + } + else { + argument = fn*fn - fm*fm; + aa = sqrt( argument ); + argument = ((fn - 1.0)*(fn-1.0)) - (fm * fm); + bb = sqrt( argument )/aa; + cc = (2.0 * fn - 1.0)/aa; + ii = k - n; + j = k - 2 * n + 1; + p[k] = (fn + 1.0) * (cc * slat/fn * p[ii] - bb/(fn - 1.0) * p[j]); + q[k] = cc * (slat * q[ii] - clat/fn * p[ii]) - bb * q[j]; + } + } + + aa = rr * gh[l]; + + if (m == 0) { + *geo_mag_x = *geo_mag_x + aa * q[k]; + *geo_mag_z = *geo_mag_z - aa * p[k]; + l = l + 1; + } + else { + bb = rr * gh[l+1]; + cc = aa * cl[m] + bb * sl[m]; + *geo_mag_x = *geo_mag_x + cc * q[k]; + *geo_mag_z = *geo_mag_z - cc * p[k]; + if (clat > 0) { + *geo_mag_y = *geo_mag_y + (aa * sl[m] - bb * cl[m]) * + fm * p[k]/((fn + 1.0) * clat); + } + else { + *geo_mag_y = *geo_mag_y + (aa * sl[m] - bb * cl[m]) * q[k] * slat; + } + l = l + 2; + } + m = m + 1; + } + if (iext != 0) { + aa = ext2 * cl[1] + ext3 * sl[1]; + *geo_mag_x = *geo_mag_x - ext1 * clat + aa * slat; + *geo_mag_y = *geo_mag_y + ext2 * sl[1] - ext3 * cl[1]; + *geo_mag_z = *geo_mag_z + ext1 * slat + aa * clat; + } + aa = *geo_mag_x; + *geo_mag_x = *geo_mag_x * cd + *geo_mag_z * sd; + *geo_mag_z = *geo_mag_z * cd - aa * sd; + return(ios); +} diff --git a/sw/airborne/modules/geo_mag/wmm2010.h b/sw/airborne/modules/geo_mag/wmm2010.h new file mode 100755 index 0000000000..6448ba690a --- /dev/null +++ b/sw/airborne/modules/geo_mag/wmm2010.h @@ -0,0 +1,43 @@ +/* + * + * Copyright (C) 2012 Sergey Krukowski . + * + * This module based on the WMM2010 modell (http://www.ngdc.noaa.gov/geomag/models.shtml). + * + */ + +#ifndef WMM2010_H +#define WMM2010_H + +#define WMM2010_FRAC 12 +#define N_MAX_OF_GH 12 + +#define GEO_EPOCH 2010. // Geo mag current observation epoch begin +#define YR_MIN 2010. +#define YR_MAX 2015. +#define NMAX_1 12 +#define NMAX_2 12 + +#define IEXT 0 +#define EXT_COEFF1 (double)0 +#define EXT_COEFF2 (double)0 +#define EXT_COEFF3 (double)0 + +#define GPS_EPOCH_BEGIN (double)1980.016393442623 // Begin of the GPS epoch +#define GPS_EPOCH_YEAR 1980 +#define GPS_EPOCH_MONTH 1 +#define GPS_EPOCH_DAY 6 + +#define WEEKS_IN_YEAR 52.143 +#define SECS_IN_YEAR 31536000 + +#define MAXDEG 13 +#define MAXCOEFF (MAXDEG*(MAXDEG+2)+1) + +extern const double gh1[]; +extern const double gh2[]; + +int16_t extrapsh(double date, double dte1, int16_t nmax1, int16_t nmax2, double *gh); +int16_t mag_calc(int16_t igdgc, double flat, double flon, double elev, int16_t nmax, double *gh, double *geo_mag_x, double *geo_mag_y, double *geo_mag_z, int16_t iext, double ext1, double ext2, double ext3); + +#endif diff --git a/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.c b/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.c index c021a0832a..19c984b973 100644 --- a/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.c +++ b/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.c @@ -32,6 +32,9 @@ #endif #include "math/pprz_trig_int.h" #include "math/pprz_algebra_int.h" +#ifdef USE_GEO_MAG +#include "math/pprz_algebra_double.h" +#endif #include "generated/airframe.h" @@ -68,6 +71,10 @@ float ins_pitch_neutral = INS_PITCH_NEUTRAL_DEFAULT; static inline void set_body_state_from_quat(void); +#ifdef USE_GEO_MAG +struct DoubleVect3 ahrs_h; +#endif + void ahrs_init(void) { ahrs.status = AHRS_UNINIT; @@ -94,6 +101,10 @@ void ahrs_init(void) { ahrs_impl.use_gravity_heuristic = FALSE; #endif +#ifdef USE_GEO_MAG + VECT3_ASSIGN(ahrs_h, AHRS_H_X, AHRS_H_Y, AHRS_H_Z); +#endif + } void ahrs_align(void) { @@ -256,9 +267,15 @@ static inline void ahrs_update_mag_full(void) { struct Int32RMat ltp_to_imu_rmat; INT32_RMAT_OF_QUAT(ltp_to_imu_rmat, ahrs_impl.ltp_to_imu_quat); +#ifndef USE_GEO_MAG const struct Int32Vect3 expected_ltp = {MAG_BFP_OF_REAL(AHRS_H_X), MAG_BFP_OF_REAL(AHRS_H_Y), MAG_BFP_OF_REAL(AHRS_H_Z)}; +#else + const struct Int32Vect3 expected_ltp = {MAG_BFP_OF_REAL(ahrs_h.x), + MAG_BFP_OF_REAL(ahrs_h.y), + MAG_BFP_OF_REAL(ahrs_h.z)}; +#endif struct Int32Vect3 expected_imu; INT32_RMAT_VMULT(expected_imu, ltp_to_imu_rmat, expected_ltp); @@ -284,8 +301,14 @@ static inline void ahrs_update_mag_2d(void) { struct Int32RMat ltp_to_imu_rmat; INT32_RMAT_OF_QUAT(ltp_to_imu_rmat, ahrs_impl.ltp_to_imu_quat); +#ifndef USE_GEO_MAG const struct Int32Vect2 expected_ltp = {MAG_BFP_OF_REAL(AHRS_H_X), MAG_BFP_OF_REAL(AHRS_H_Y)}; +#else + const struct Int32Vect2 expected_ltp = {MAG_BFP_OF_REAL(ahrs_h.x), + MAG_BFP_OF_REAL(ahrs_h.y)}; +#endif + struct Int32Vect3 measured_ltp; INT32_RMAT_TRANSP_VMULT(measured_ltp, ltp_to_imu_rmat, imu.mag); diff --git a/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.h b/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.h index c9d3581794..82e37e5ae5 100644 --- a/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.h +++ b/sw/airborne/subsystems/ahrs/ahrs_int_cmpl_quat.h @@ -42,6 +42,9 @@ struct AhrsIntCmpl { }; extern struct AhrsIntCmpl ahrs_impl; +#ifdef USE_GEO_MAG +extern struct DoubleVect3 ahrs_h; +#endif /** Update yaw based on a heading measurement.