diff --git a/conf/firmwares/rotorcraft.makefile b/conf/firmwares/rotorcraft.makefile
index bc6345b920..40a88da4a0 100644
--- a/conf/firmwares/rotorcraft.makefile
+++ b/conf/firmwares/rotorcraft.makefile
@@ -167,8 +167,10 @@ ap.CFLAGS += -DUSE_ADC
ap.srcs += $(SRC_ARCH)/mcu_periph/adc_arch.c
ap.srcs += subsystems/electrical.c
# baro has variable offset amplifier on booz board
+ifeq ($(BOARD), booz)
ap.CFLAGS += -DUSE_DAC
ap.srcs += $(SRC_ARCH)/mcu_periph/dac_arch.c
+endif
else ifeq ($(ARCH), stm32)
ap.CFLAGS += -DUSE_ADC
ap.CFLAGS += -DUSE_AD1 -DUSE_AD1_1 -DUSE_AD1_2 -DUSE_AD1_3 -DUSE_AD1_4
@@ -208,19 +210,16 @@ ap.CFLAGS += -DUSE_NAVIGATION
ap.srcs += $(SRC_FIRMWARE)/guidance/guidance_h.c
ap.srcs += $(SRC_FIRMWARE)/guidance/guidance_v.c
-ap.srcs += $(SRC_SUBSYSTEMS)/ins.c
-
#
# INS choice
#
-# include subsystems/rotorcraft/ins_hff.makefile
+# include subsystems/rotorcraft/ins.makefile
# or
-# nothing
+# include subsystems/rotorcraft/ins_extended.makefile
+#
+# extra:
+# include subsystems/rotorcraft/ins_hff.makefile
#
-
-# vertical filter float version
-ap.srcs += $(SRC_SUBSYSTEMS)/ins/vf_float.c
-ap.CFLAGS += -DUSE_VFF -DDT_VFILTER='(1./$(PERIODIC_FREQUENCY).)'
ap.srcs += $(SRC_FIRMWARE)/navigation.c
ap.srcs += subsystems/navigation/common_flight_plan.c
diff --git a/conf/firmwares/subsystems/rotorcraft/ins.makefile b/conf/firmwares/subsystems/rotorcraft/ins.makefile
new file mode 100644
index 0000000000..7fb608ffef
--- /dev/null
+++ b/conf/firmwares/subsystems/rotorcraft/ins.makefile
@@ -0,0 +1,10 @@
+#
+# simple INS with float vertical filter
+#
+
+ap.srcs += $(SRC_SUBSYSTEMS)/ins.c
+
+# vertical filter float version
+ap.srcs += $(SRC_SUBSYSTEMS)/ins/vf_float.c
+ap.CFLAGS += -DUSE_VFF -DDT_VFILTER='(1./$(PERIODIC_FREQUENCY).)'
+
diff --git a/conf/firmwares/subsystems/rotorcraft/ins_extended.makefile b/conf/firmwares/subsystems/rotorcraft/ins_extended.makefile
new file mode 100644
index 0000000000..f1cd021b44
--- /dev/null
+++ b/conf/firmwares/subsystems/rotorcraft/ins_extended.makefile
@@ -0,0 +1,10 @@
+#
+# extended INS with vertical filter using sonar in a better way (flap ground)
+#
+
+ap.srcs += $(SRC_SUBSYSTEMS)/ins_extended.c
+
+# vertical filter float version
+ap.srcs += $(SRC_SUBSYSTEMS)/ins/vf_extended_float.c
+ap.CFLAGS += -DUSE_VFF_EXTENDED -DDT_VFILTER='(1./$(PERIODIC_FREQUENCY).)'
+
diff --git a/conf/messages.xml b/conf/messages.xml
index cf25f32bc5..1139d855af 100644
--- a/conf/messages.xml
+++ b/conf/messages.xml
@@ -1334,6 +1334,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/settings/estimation/ins_sonar.xml b/conf/settings/estimation/ins_sonar.xml
new file mode 100644
index 0000000000..0c016fa593
--- /dev/null
+++ b/conf/settings/estimation/ins_sonar.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/sw/airborne/firmwares/rotorcraft/telemetry.h b/sw/airborne/firmwares/rotorcraft/telemetry.h
index 80502d42de..28901e5288 100644
--- a/sw/airborne/firmwares/rotorcraft/telemetry.h
+++ b/sw/airborne/firmwares/rotorcraft/telemetry.h
@@ -495,6 +495,21 @@
#define PERIODIC_SEND_VFF(_trans, _dev) {}
#endif
+#if USE_VFF_EXTENDED
+#include "subsystems/ins/vf_extended_float.h"
+#define PERIODIC_SEND_VFF_EXTENDED(_trans, _dev) { \
+ DOWNLINK_SEND_VFF_EXTENDED(_trans, _dev, \
+ &vff_z_meas, \
+ &vff_z_meas_baro, \
+ &vff_z, \
+ &vff_zdot, \
+ &vff_bias, \
+ &vff_offset); \
+ }
+#else
+#define PERIODIC_SEND_VFF_EXTENDED(_trans, _dev) {}
+#endif
+
#if USE_HFF
#include "subsystems/ins/hf_float.h"
#define PERIODIC_SEND_HFF(_trans, _dev) { \
diff --git a/sw/airborne/subsystems/ins.h b/sw/airborne/subsystems/ins.h
index 83bb470096..a3f876031d 100644
--- a/sw/airborne/subsystems/ins.h
+++ b/sw/airborne/subsystems/ins.h
@@ -33,7 +33,7 @@ extern struct NedCoor_i ins_gps_pos_cm_ned;
extern struct NedCoor_i ins_gps_speed_cm_s_ned;
/* barometer */
-#if USE_VFF
+#if USE_VFF || USE_VFF_EXTENDED
extern int32_t ins_baro_alt;
extern int32_t ins_qfe;
extern bool_t ins_baro_initialised;
diff --git a/sw/airborne/subsystems/ins/vf_extended_float.c b/sw/airborne/subsystems/ins/vf_extended_float.c
new file mode 100644
index 0000000000..4013c4fd59
--- /dev/null
+++ b/sw/airborne/subsystems/ins/vf_extended_float.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2008-2009 Antoine Drouin
+ * Copyright (C) 2012 Gautier Hattenberger
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi 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 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi 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 paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "subsystems/ins/vf_extended_float.h"
+
+#define DEBUG_VFF_EXTENDED 1
+
+#if DEBUG_VFF_EXTENDED
+#include "mcu_periph/uart.h"
+#include "messages.h"
+#include "subsystems/datalink/downlink.h"
+#endif
+
+/*
+
+X = [ z zdot accel_bias baro_offset ]
+
+temps :
+ propagate 86us
+ update 46us
+
+*/
+/* initial covariance diagonal */
+#define INIT_PXX 1.
+/* process noise */
+#define ACCEL_NOISE 0.5
+#define Qzz ACCEL_NOISE/512./512./2.
+#define Qzdotzdot ACCEL_NOISE/512.
+#define Qbiasbias 1e-7
+#define Qoffoff 1e-4
+#define R_BARO 1.
+#define R_ALT 0.1
+#define R_OFFSET 1.
+
+float vff_z;
+float vff_zdot;
+float vff_bias;
+float vff_offset;
+float vff_zdotdot;
+
+float vff_P[VFF_STATE_SIZE][VFF_STATE_SIZE];
+
+float vff_z_meas;
+float vff_z_meas_baro;
+
+void vff_init(float init_z, float init_zdot, float init_accel_bias, float init_baro_offset) {
+ vff_z = init_z;
+ vff_zdot = init_zdot;
+ vff_bias = init_accel_bias;
+ vff_offset = init_baro_offset;
+ int i, j;
+ for (i=0; i
+ * Copyright (C) 2012 Gautier Hattenberger
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi 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 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi 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 paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef VF_EXTENDED_FLOAT_H
+#define VF_EXTENDED_FLOAT_H
+
+#define VFF_STATE_SIZE 4
+
+extern float vff_z;
+extern float vff_zdot;
+extern float vff_bias;
+extern float vff_offset;
+extern float vff_P[VFF_STATE_SIZE][VFF_STATE_SIZE];
+extern float vff_zdotdot;
+
+extern float vff_z_meas;
+extern float vff_z_meas_baro;
+
+extern void vff_init(float z, float zdot, float accel_bias, float baro_offset);
+extern void vff_propagate(float accel);
+extern void vff_update_baro(float z_meas);
+extern void vff_update_alt(float z_meas);
+extern void vff_update_offset(float offset);
+extern void vff_update_baro_conf(float z_meas, float conf);
+extern void vff_update_alt_conf(float z_meas, float conf);
+//extern void vff_update_vz_conf(float vz_meas, float conf);
+extern void vff_realign(float z_meas);
+
+#endif /* VF_EXTENDED_FLOAT_H */
diff --git a/sw/airborne/subsystems/ins_extended.c b/sw/airborne/subsystems/ins_extended.c
new file mode 100644
index 0000000000..98ee7d53cd
--- /dev/null
+++ b/sw/airborne/subsystems/ins_extended.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2008-2010 The Paparazzi Team
+ * Copyright (C) 2012 Gautier Hattenberger
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi 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 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi 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 paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "subsystems/ins.h"
+
+#include "subsystems/imu.h"
+#include "subsystems/sensors/baro.h"
+#include "subsystems/gps.h"
+
+#include "generated/airframe.h"
+#include "math/pprz_algebra_int.h"
+#include "math/pprz_algebra_float.h"
+
+#include "subsystems/ahrs.h"
+
+#if USE_VFF_EXTENDED
+#include "subsystems/ins/vf_extended_float.h"
+#endif
+
+#if USE_HFF
+#include "subsystems/ins/hf_float.h"
+#endif
+
+#ifdef SITL
+#include "nps_fdm.h"
+#include
+#endif
+
+
+#include "math/pprz_geodetic_int.h"
+
+#include "generated/flight_plan.h"
+
+/* gps transformed to LTP-NED */
+struct LtpDef_i ins_ltp_def;
+ bool_t ins_ltp_initialised;
+struct NedCoor_i ins_gps_pos_cm_ned;
+struct NedCoor_i ins_gps_speed_cm_s_ned;
+#if USE_HFF
+/* horizontal gps transformed to NED in meters as float */
+struct FloatVect2 ins_gps_pos_m_ned;
+struct FloatVect2 ins_gps_speed_m_s_ned;
+#endif
+bool_t ins_hf_realign;
+
+/* barometer */
+#if USE_VFF_EXTENDED
+int32_t ins_qfe;
+bool_t ins_baro_initialised;
+int32_t ins_baro_alt;
+#include "filters/median_filter.h"
+struct MedianFilterInt baro_median;
+#if USE_SONAR
+bool_t ins_update_on_agl;
+int32_t ins_sonar_offset;
+struct MedianFilterInt sonar_median;
+#define VFF_R_SONAR_0 0.1
+#define VFF_R_SONAR_OF_M 0.2
+#endif
+#endif
+bool_t ins_vf_realign;
+
+/* output */
+struct NedCoor_i ins_ltp_pos;
+struct NedCoor_i ins_ltp_speed;
+struct NedCoor_i ins_ltp_accel;
+struct EnuCoor_i ins_enu_pos;
+struct EnuCoor_i ins_enu_speed;
+struct EnuCoor_i ins_enu_accel;
+
+
+void ins_init() {
+#if USE_INS_NAV_INIT
+ ins_ltp_initialised = TRUE;
+
+ /** FIXME: should use the same code than MOVE_WP in firmwares/rotorcraft/datalink.c */
+ struct LlaCoor_i llh_nav0; /* Height above the ellipsoid */
+ llh_nav0.lat = INT32_RAD_OF_DEG(NAV_LAT0);
+ llh_nav0.lon = INT32_RAD_OF_DEG(NAV_LON0);
+ /* NAV_ALT0 = ground alt above msl, NAV_MSL0 = geoid-height (msl) over ellipsoid */
+ llh_nav0.alt = NAV_ALT0 + NAV_MSL0;
+
+ struct EcefCoor_i ecef_nav0;
+ ecef_of_lla_i(&ecef_nav0, &llh_nav0);
+
+ ltp_def_from_ecef_i(&ins_ltp_def, &ecef_nav0);
+ ins_ltp_def.hmsl = NAV_ALT0;
+#else
+ ins_ltp_initialised = FALSE;
+#endif
+#if USE_VFF_EXTENDED
+ ins_baro_initialised = FALSE;
+ init_median_filter(&baro_median);
+#if USE_SONAR
+ ins_update_on_agl = FALSE;
+ init_median_filter(&sonar_median);
+ ins_sonar_offset = 0;
+#endif
+ vff_init(0., 0., 0., 0.);
+#endif
+ ins_vf_realign = FALSE;
+ ins_hf_realign = FALSE;
+#if USE_HFF
+ b2_hff_init(0., 0., 0., 0.);
+#endif
+ INT32_VECT3_ZERO(ins_ltp_pos);
+ INT32_VECT3_ZERO(ins_ltp_speed);
+ INT32_VECT3_ZERO(ins_ltp_accel);
+ INT32_VECT3_ZERO(ins_enu_pos);
+ INT32_VECT3_ZERO(ins_enu_speed);
+ INT32_VECT3_ZERO(ins_enu_accel);
+}
+
+void ins_periodic( void ) {
+}
+
+#if USE_HFF
+void ins_realign_h(struct FloatVect2 pos, struct FloatVect2 speed) {
+ b2_hff_realign(pos, speed);
+}
+#else
+void ins_realign_h(struct FloatVect2 pos __attribute__ ((unused)), struct FloatVect2 speed __attribute__ ((unused))) {}
+#endif /* USE_HFF */
+
+
+void ins_realign_v(float z) {
+#if USE_VFF_EXTENDED
+ vff_realign(z);
+#endif
+}
+
+void ins_propagate() {
+ /* untilt accels */
+ struct Int32Vect3 accel_meas_body;
+ INT32_RMAT_TRANSP_VMULT(accel_meas_body, imu.body_to_imu_rmat, imu.accel);
+ struct Int32Vect3 accel_meas_ltp;
+ INT32_RMAT_TRANSP_VMULT(accel_meas_ltp, ahrs.ltp_to_body_rmat, accel_meas_body);
+
+#if USE_VFF_EXTENDED
+ float z_accel_meas_float = ACCEL_FLOAT_OF_BFP(accel_meas_ltp.z);
+ if (baro.status == BS_RUNNING && ins_baro_initialised) {
+ vff_propagate(z_accel_meas_float);
+ ins_ltp_accel.z = ACCEL_BFP_OF_REAL(vff_zdotdot);
+ ins_ltp_speed.z = SPEED_BFP_OF_REAL(vff_zdot);
+ ins_ltp_pos.z = POS_BFP_OF_REAL(vff_z);
+ }
+ else { // feed accel from the sensors
+ // subtract -9.81m/s2 (acceleration measured due to gravity, but vehivle not accelerating in ltp)
+ ins_ltp_accel.z = accel_meas_ltp.z + ACCEL_BFP_OF_REAL(9.81);
+ }
+#if !USE_SONAR
+ vff_update_offset(vff_offset);
+#endif
+#else
+ ins_ltp_accel.z = accel_meas_ltp.z + ACCEL_BFP_OF_REAL(9.81);
+#endif /* USE_VFF_EXTENDED */
+
+#if USE_HFF
+ /* propagate horizontal filter */
+ b2_hff_propagate();
+#else
+ ins_ltp_accel.x = accel_meas_ltp.x;
+ ins_ltp_accel.y = accel_meas_ltp.y;
+#endif /* USE_HFF */
+
+ INT32_VECT3_ENU_OF_NED(ins_enu_pos, ins_ltp_pos);
+ INT32_VECT3_ENU_OF_NED(ins_enu_speed, ins_ltp_speed);
+ INT32_VECT3_ENU_OF_NED(ins_enu_accel, ins_ltp_accel);
+}
+
+void ins_update_baro() {
+#if USE_VFF_EXTENDED
+ int32_t baro_pressure = update_median_filter(&baro_median, baro.absolute);
+ if (baro.status == BS_RUNNING) {
+ if (!ins_baro_initialised) {
+ ins_qfe = baro_pressure;
+ ins_baro_initialised = TRUE;
+ }
+ if (ins_vf_realign) {
+ ins_vf_realign = FALSE;
+ ins_qfe = baro.absolute;
+#if USE_SONAR
+ // FIXME should use an averaged value
+ //ins_sonar_offset = sonar_meas;
+#endif
+ vff_realign(0.);
+ ins_ltp_accel.z = ACCEL_BFP_OF_REAL(vff_zdotdot);
+ ins_ltp_speed.z = SPEED_BFP_OF_REAL(vff_zdot);
+ ins_ltp_pos.z = POS_BFP_OF_REAL(vff_z);
+ ins_enu_pos.z = -ins_ltp_pos.z;
+ ins_enu_speed.z = -ins_ltp_speed.z;
+ ins_enu_accel.z = -ins_ltp_accel.z;
+ }
+ else { /* not realigning, so normal update with baro measurement */
+ ins_baro_alt = ((baro_pressure - ins_qfe) * INS_BARO_SENS_NUM)/INS_BARO_SENS_DEN;
+ float alt_float = POS_FLOAT_OF_BFP(ins_baro_alt);
+ vff_update_baro(alt_float);
+ }
+ }
+#endif
+}
+
+
+void ins_update_gps(void) {
+#if USE_GPS
+ if (gps.fix == GPS_FIX_3D) {
+ if (!ins_ltp_initialised) {
+ ltp_def_from_ecef_i(&ins_ltp_def, &gps.ecef_pos);
+ ins_ltp_def.lla.alt = gps.lla_pos.alt;
+ ins_ltp_def.hmsl = gps.hmsl;
+ ins_ltp_initialised = TRUE;
+ }
+ ned_of_ecef_point_i(&ins_gps_pos_cm_ned, &ins_ltp_def, &gps.ecef_pos);
+ ned_of_ecef_vect_i(&ins_gps_speed_cm_s_ned, &ins_ltp_def, &gps.ecef_vel);
+#if USE_HFF
+ VECT2_ASSIGN(ins_gps_pos_m_ned, ins_gps_pos_cm_ned.x, ins_gps_pos_cm_ned.y);
+ VECT2_SDIV(ins_gps_pos_m_ned, ins_gps_pos_m_ned, 100.);
+ VECT2_ASSIGN(ins_gps_speed_m_s_ned, ins_gps_speed_cm_s_ned.x, ins_gps_speed_cm_s_ned.y);
+ VECT2_SDIV(ins_gps_speed_m_s_ned, ins_gps_speed_m_s_ned, 100.);
+ if (ins_hf_realign) {
+ ins_hf_realign = FALSE;
+#ifdef SITL
+ struct FloatVect2 true_pos, true_speed;
+ VECT2_COPY(true_pos, fdm.ltpprz_pos);
+ VECT2_COPY(true_speed, fdm.ltpprz_ecef_vel);
+ b2_hff_realign(true_pos, true_speed);
+#else
+ const struct FloatVect2 zero = {0.0, 0.0};
+ b2_hff_realign(ins_gps_pos_m_ned, zero);
+#endif
+ }
+ b2_hff_update_gps();
+#if !USE_VFF_EXTENDED /* vff not used */
+ ins_ltp_pos.z = (ins_gps_pos_cm_ned.z * INT32_POS_OF_CM_NUM) / INT32_POS_OF_CM_DEN;
+ ins_ltp_speed.z = (ins_gps_speed_cm_s_ned.z * INT32_SPEED_OF_CM_S_NUM) INT32_SPEED_OF_CM_S_DEN;
+#endif /* vff not used */
+#endif /* hff used */
+
+
+#if !USE_HFF /* hff not used */
+#if !USE_VFF_EXTENDED /* neither hf nor vf used */
+ INT32_VECT3_SCALE_3(ins_ltp_pos, ins_gps_pos_cm_ned, INT32_POS_OF_CM_NUM, INT32_POS_OF_CM_DEN);
+ INT32_VECT3_SCALE_3(ins_ltp_speed, ins_gps_speed_cm_s_ned, INT32_SPEED_OF_CM_S_NUM, INT32_SPEED_OF_CM_S_DEN);
+#else /* only vff used */
+ INT32_VECT2_SCALE_2(ins_ltp_pos, ins_gps_pos_cm_ned, INT32_POS_OF_CM_NUM, INT32_POS_OF_CM_DEN);
+ INT32_VECT2_SCALE_2(ins_ltp_speed, ins_gps_speed_cm_s_ned, INT32_SPEED_OF_CM_S_NUM, INT32_SPEED_OF_CM_S_DEN);
+#endif
+
+#if USE_GPS_LAG_HACK
+ VECT2_COPY(d_pos, ins_ltp_speed);
+ INT32_VECT2_RSHIFT(d_pos, d_pos, 11);
+ VECT2_ADD(ins_ltp_pos, d_pos);
+#endif
+#endif /* hff not used */
+
+ INT32_VECT3_ENU_OF_NED(ins_enu_pos, ins_ltp_pos);
+ INT32_VECT3_ENU_OF_NED(ins_enu_speed, ins_ltp_speed);
+ INT32_VECT3_ENU_OF_NED(ins_enu_accel, ins_ltp_accel);
+ }
+#endif /* USE_GPS */
+}
+
+void ins_update_sonar() {
+#if USE_SONAR && USE_VFF_EXTENDED
+ static int32_t last_offset = 0;
+ //static int32_t sonar_filtered = 0;
+ int32_t sonar_filtered = update_median_filter(&sonar_median, sonar_meas);
+ //sonar_filtered = (sm + 2*sonar_filtered) / 3;
+ float sonar = (sonar_filtered - ins_sonar_offset) * INS_SONAR_SENS;
+ /* update filter assuming a flat ground */
+ if (sonar < INS_SONAR_MAX_RANGE && ins_update_on_agl && baro.status == BS_RUNNING) {
+ vff_update_alt_conf(-sonar, VFF_R_SONAR_0 + VFF_R_SONAR_OF_M * fabs(sonar));
+ last_offset = vff_offset;
+ }
+ else {
+ /* update offset with last value to avoid divergence */
+ vff_update_offset(last_offset);
+ }
+#endif
+}