altos: Add nickle kalman implementation.
[fw/altos] / src / ao_flight.c
index c0f5683047b4d5e3e37dd6d28d14bb9de71295e2..493913b2c1b2a91732bde0fc9cbf407ee2609196 100644 (file)
 #include "ao.h"
 #endif
 
+#ifndef HAS_ACCEL
+#error Please define HAS_ACCEL
+#endif
+
+#ifndef HAS_GPS
+#error Please define HAS_GPS
+#endif
+
+#ifndef HAS_USB
+#error Please define HAS_USB
+#endif
+
+#ifndef USE_KALMAN
+#error Please define USE_KALMAN
+#endif
+
 /* Main flight thread. */
 
 __pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
 __pdata uint16_t               ao_flight_tick;         /* time of last data */
 __pdata uint16_t               ao_flight_prev_tick;    /* time of previous data */
-__pdata int16_t                        ao_flight_accel;        /* filtered acceleration */
 __pdata int16_t                        ao_flight_pres;         /* filtered pressure */
 __pdata int16_t                        ao_ground_pres;         /* startup pressure */
-__pdata int16_t                        ao_ground_accel;        /* startup acceleration */
 __pdata int16_t                        ao_min_pres;            /* minimum recorded pressure */
 __pdata uint16_t               ao_launch_tick;         /* time of launch detect */
 __pdata int16_t                        ao_main_pres;           /* pressure to eject main */
+#if HAS_ACCEL
+__pdata int16_t                        ao_flight_accel;        /* filtered acceleration */
+__pdata int16_t                        ao_ground_accel;        /* startup acceleration */
+#endif
 
 /*
  * track min/max data over a long interval to detect
  * resting
  */
 __pdata uint16_t               ao_interval_end;
-__pdata int16_t                        ao_interval_cur_min_accel;
-__pdata int16_t                        ao_interval_cur_max_accel;
 __pdata int16_t                        ao_interval_cur_min_pres;
 __pdata int16_t                        ao_interval_cur_max_pres;
-__pdata int16_t                        ao_interval_min_accel;
-__pdata int16_t                        ao_interval_max_accel;
 __pdata int16_t                        ao_interval_min_pres;
 __pdata int16_t                        ao_interval_max_pres;
+#if HAS_ACCEL
+__pdata int16_t                        ao_interval_cur_min_accel;
+__pdata int16_t                        ao_interval_cur_max_accel;
+__pdata int16_t                        ao_interval_min_accel;
+__pdata int16_t                        ao_interval_max_accel;
+#endif
 
 __data uint8_t ao_flight_adc;
-__pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres;
+__pdata int16_t ao_raw_pres;
+__xdata uint8_t ao_flight_force_idle;
+
+#if HAS_ACCEL
+__pdata int16_t ao_raw_accel, ao_raw_accel_prev;
+__pdata int16_t ao_accel_2g;
 
 /* Accelerometer calibration
  *
@@ -72,19 +97,17 @@ __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres;
 
 #define GRAVITY 9.80665
 /* convert m/s to velocity count */
-#define VEL_MPS_TO_COUNT(mps) ((int32_t) (((mps) / GRAVITY) * ACCEL_G * 100))
-
-#define ACCEL_G                265
-#define ACCEL_ZERO_G   16000
-#define ACCEL_NOSE_UP  (ACCEL_G * 2 /3)
-#define ACCEL_BOOST    ACCEL_G * 2
-#define ACCEL_INT_LAND (ACCEL_G / 10)
-#define ACCEL_VEL_LAND VEL_MPS_TO_COUNT(10)
+#define VEL_MPS_TO_COUNT(mps) (((int32_t) (((mps) / GRAVITY) * (AO_HERTZ/2))) * (int32_t) ao_accel_2g)
+
+#define ACCEL_NOSE_UP  (ao_accel_2g >> 2)
+#define ACCEL_BOOST    ao_accel_2g
+#define ACCEL_COAST    (ao_accel_2g >> 3)
+#define ACCEL_INT_LAND (ao_accel_2g >> 3)
 #define ACCEL_VEL_MACH VEL_MPS_TO_COUNT(200)
-#define ACCEL_VEL_APOGEE       VEL_MPS_TO_COUNT(2)
-#define ACCEL_VEL_MAIN VEL_MPS_TO_COUNT(100)
 #define ACCEL_VEL_BOOST        VEL_MPS_TO_COUNT(5)
 
+#endif
+
 /*
  * Barometer calibration
  *
@@ -118,6 +141,7 @@ __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres;
 
 #define BOOST_TICKS_MAX        AO_SEC_TO_TICKS(15)
 
+#if HAS_ACCEL
 /* This value is scaled in a weird way. It's a running total of accelerometer
  * readings minus the ground accelerometer reading. That means it measures
  * velocity, and quite accurately too. As it gets updated 100 times a second,
@@ -127,12 +151,71 @@ __pdata int32_t   ao_flight_vel;
 __pdata int32_t ao_min_vel;
 __pdata int32_t        ao_old_vel;
 __pdata int16_t ao_old_vel_tick;
-__xdata int32_t ao_raw_accel_sum, ao_raw_pres_sum;
+__xdata int32_t ao_raw_accel_sum;
+#endif
+
+#if USE_KALMAN
+__pdata int16_t                        ao_ground_height;
+__pdata int32_t                        ao_k_max_height;
+__pdata int32_t                        ao_k_height;
+__pdata int32_t                        ao_k_speed;
+__pdata int32_t                        ao_k_accel;
+
+#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
+#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
+
+#define from_fix(x)    ((x) >> 16)
+
+#define AO_K0_100      to_fix16(0.05680323)
+#define AO_K1_100      to_fix16(0.16608182)
+#define AO_K2_100      to_fix16(0.24279580)
+
+#define AO_K_STEP_100          to_fix16(0.01)
+#define AO_K_STEP_2_2_100      to_fix16(0.00005)
+
+#define AO_K0_10       to_fix16(0.23772023)
+#define AO_K1_10       to_fix16(0.32214149)
+#define AO_K2_10       to_fix16(0.21827159)
+
+#define AO_K_STEP_10           to_fix16(0.1)
+#define AO_K_STEP_2_2_10       to_fix16(0.005)
+
+static void
+ao_kalman_baro(void)
+{
+       int16_t err = ((ao_pres_to_altitude(ao_raw_pres) - ao_ground_height))
+               - (int16_t) (ao_k_height >> 16);
+
+#ifdef AO_FLIGHT_TEST
+       if (ao_flight_tick - ao_flight_prev_tick > 5) {
+               ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_10 +
+                               (ao_k_accel >> 16) * AO_K_STEP_2_2_10);
+               ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_10;
+
+               /* correct */
+               ao_k_height += (int32_t) AO_K0_10 * err;
+               ao_k_speed += (int32_t) AO_K1_10 * err;
+               ao_k_accel += (int32_t) AO_K2_10 * err;
+               return;
+       }
+#endif
+       ao_k_height += ((ao_k_speed >> 16) * AO_K_STEP_100 +
+                       (ao_k_accel >> 16) * AO_K_STEP_2_2_100);
+       ao_k_speed += (ao_k_accel >> 16) * AO_K_STEP_100;
+
+       /* correct */
+       ao_k_height += (int32_t) AO_K0_100 * err;
+       ao_k_speed += (int32_t) AO_K1_100 * err;
+       ao_k_accel += (int32_t) AO_K2_100 * err;
+}
+#endif
+
+__xdata int32_t ao_raw_pres_sum;
 
 /* Landing is detected by getting constant readings from both pressure and accelerometer
  * for a fairly long time (AO_INTERVAL_TICKS)
  */
-#define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(20)
+#define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(5)
 
 #define abs(a) ((a) < 0 ? -(a) : (a))
 
@@ -142,26 +225,119 @@ ao_flight(void)
        __pdata static uint16_t nsamples = 0;
 
        ao_flight_adc = ao_adc_head;
+       ao_raw_pres = 0;
+#if HAS_ACCEL
        ao_raw_accel_prev = 0;
        ao_raw_accel = 0;
-       ao_raw_pres = 0;
+#endif
        ao_flight_tick = 0;
        for (;;) {
-               ao_sleep(&ao_adc_ring);
+               ao_wakeup(DATA_TO_XDATA(&ao_flight_adc));
+               ao_sleep(DATA_TO_XDATA(&ao_adc_head));
                while (ao_flight_adc != ao_adc_head) {
+#if HAS_ACCEL
                        __pdata uint8_t ticks;
                        __pdata int16_t ao_vel_change;
+#endif
+                       __xdata struct ao_adc *ao_adc;
                        ao_flight_prev_tick = ao_flight_tick;
 
                        /* Capture a sample */
-                       ao_raw_accel = ao_adc_ring[ao_flight_adc].accel;
-                       ao_raw_pres = ao_adc_ring[ao_flight_adc].pres;
-                       ao_flight_tick = ao_adc_ring[ao_flight_adc].tick;
+                       ao_adc = &ao_adc_ring[ao_flight_adc];
+                       ao_flight_tick = ao_adc->tick;
+                       ao_raw_pres = ao_adc->pres;
+                       ao_flight_pres -= ao_flight_pres >> 4;
+                       ao_flight_pres += ao_raw_pres >> 4;
+
+#if HAS_ACCEL
+                       ao_raw_accel = ao_adc->accel;
+#if HAS_ACCEL_REF
+                       /*
+                        * Ok, the math here is a bit tricky.
+                        *
+                        * ao_raw_accel:  ADC output for acceleration
+                        * ao_accel_ref:  ADC output for the 5V reference.
+                        * ao_cook_accel: Corrected acceleration value
+                        * Vcc:           3.3V supply to the CC1111
+                        * Vac:           5V supply to the accelerometer
+                        * accel:         input voltage to accelerometer ADC pin
+                        * ref:           input voltage to 5V reference ADC pin
+                        *
+                        *
+                        * Measured acceleration is ratiometric to Vcc:
+                        *
+                        *     ao_raw_accel   accel
+                        *     ------------ = -----
+                        *        32767        Vcc
+                        *
+                        * Measured 5v reference is also ratiometric to Vcc:
+                        *
+                        *     ao_accel_ref    ref
+                        *     ------------ = -----
+                        *        32767        Vcc
+                        *
+                        *
+                        *      ao_accel_ref = 32767 * (ref / Vcc)
+                        *
+                        * Acceleration is measured ratiometric to the 5V supply,
+                        * so what we want is:
+                        *
+                        *      ao_cook_accel    accel
+                        *      ------------- =  -----
+                        *          32767         ref
+                        *
+                        *
+                        *                      accel    Vcc
+                        *                    = ----- *  ---
+                        *                       Vcc     ref
+                        *
+                        *                      ao_raw_accel       32767
+                        *                    = ------------ *  ------------
+                        *                         32737        ao_accel_ref
+                        *
+                        * Multiply through by 32767:
+                        *
+                        *                      ao_raw_accel * 32767
+                        *      ao_cook_accel = --------------------
+                        *                          ao_accel_ref
+                        *
+                        * Now, the tricky part. Getting this to compile efficiently
+                        * and keeping all of the values in-range.
+                        *
+                        * First off, we need to use a shift of 16 instead of * 32767 as SDCC
+                        * does the obvious optimizations for byte-granularity shifts:
+                        *
+                        *      ao_cook_accel = (ao_raw_accel << 16) / ao_accel_ref
+                        *
+                        * Next, lets check our input ranges:
+                        *
+                        *      0 <= ao_raw_accel <= 0x7fff             (singled ended ADC conversion)
+                        *      0x7000 <= ao_accel_ref <= 0x7fff        (the 5V ref value is close to 0x7fff)
+                        *
+                        * Plugging in our input ranges, we get an output range of 0 - 0x12490,
+                        * which is 17 bits. That won't work. If we take the accel ref and shift
+                        * by a bit, we'll change its range:
+                        *
+                        *      0xe000 <= ao_accel_ref<<1 <= 0xfffe
+                        *
+                        *      ao_cook_accel = (ao_raw_accel << 16) / (ao_accel_ref << 1)
+                        *
+                        * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It
+                        * is, however, one bit too large for our signed computations. So, we
+                        * take the result and shift that by a bit:
+                        *
+                        *      ao_cook_accel = ((ao_raw_accel << 16) / (ao_accel_ref << 1)) >> 1
+                        *
+                        * This finally creates an output range of 0 - 0x4924. As the ADC only
+                        * provides 11 bits of data, we haven't actually lost any precision,
+                        * just dropped a bit of noise off the low end.
+                        */
+                       ao_raw_accel = (uint16_t) ((((uint32_t) ao_raw_accel << 16) / (ao_accel_ref[ao_flight_adc] << 1))) >> 1;
+                       ao_adc->accel = ao_raw_accel;
+#endif
 
                        ao_flight_accel -= ao_flight_accel >> 4;
                        ao_flight_accel += ao_raw_accel >> 4;
-                       ao_flight_pres -= ao_flight_pres >> 4;
-                       ao_flight_pres += ao_raw_pres >> 4;
                        /* Update velocity
                         *
                         * The accelerometer is mounted so that
@@ -170,20 +346,26 @@ ao_flight(void)
                         * so subtract instead of add.
                         */
                        ticks = ao_flight_tick - ao_flight_prev_tick;
-                       ao_vel_change = (((ao_raw_accel >> 1) + (ao_raw_accel_prev >> 1)) - ao_ground_accel);
+                       ao_vel_change = ao_ground_accel - (((ao_raw_accel + 1) >> 1) + ((ao_raw_accel_prev + 1) >> 1));
                        ao_raw_accel_prev = ao_raw_accel;
 
                        /* one is a common interval */
                        if (ticks == 1)
-                               ao_flight_vel -= (int32_t) ao_vel_change;
+                               ao_flight_vel += (int32_t) ao_vel_change;
                        else
-                               ao_flight_vel -= (int32_t) ao_vel_change * (int32_t) ticks;
+                               ao_flight_vel += (int32_t) ao_vel_change * (int32_t) ticks;
+#endif
 
+#if USE_KALMAN
+                       if (ao_flight_state > ao_flight_idle)
+                               ao_kalman_baro();
+#endif
                        ao_flight_adc = ao_adc_ring_next(ao_flight_adc);
                }
 
                if (ao_flight_pres < ao_min_pres)
                        ao_min_pres = ao_flight_pres;
+#if HAS_ACCEL
                if (ao_flight_vel >= 0) {
                        if (ao_flight_vel < ao_min_vel)
                            ao_min_vel = ao_flight_vel;
@@ -191,59 +373,99 @@ ao_flight(void)
                        if (-ao_flight_vel < ao_min_vel)
                            ao_min_vel = -ao_flight_vel;
                }
+#endif
 
                switch (ao_flight_state) {
                case ao_flight_startup:
 
                        /* startup state:
                         *
-                        * Collect 1000 samples of acceleration and pressure
+                        * Collect 512 samples of acceleration and pressure
                         * data and average them to find the resting values
                         */
-                       if (nsamples < 1000) {
+                       if (nsamples < 512) {
+#if HAS_ACCEL
                                ao_raw_accel_sum += ao_raw_accel;
+#endif
                                ao_raw_pres_sum += ao_raw_pres;
                                ++nsamples;
                                continue;
                        }
-                       ao_ground_accel = (ao_raw_accel_sum / nsamples);
-                       ao_ground_pres = (ao_raw_pres_sum / nsamples);
+#if HAS_ACCEL
+                       ao_ground_accel = ao_raw_accel_sum >> 9;
+#endif
+                       ao_ground_pres = ao_raw_pres_sum >> 9;
                        ao_min_pres = ao_ground_pres;
                        ao_config_get();
+#if USE_KALMAN
+                       ao_ground_height = ao_pres_to_altitude(ao_ground_pres);
+#endif
                        ao_main_pres = ao_altitude_to_pres(ao_pres_to_altitude(ao_ground_pres) + ao_config.main_deploy);
+#if HAS_ACCEL
+                       ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
                        ao_flight_vel = 0;
                        ao_min_vel = 0;
                        ao_old_vel = ao_flight_vel;
                        ao_old_vel_tick = ao_flight_tick;
+#endif
 
-                       /* Go to launchpad state if the nose is pointing up */
+                       /* Check to see what mode we should go to.
+                        *  - Invalid mode if accel cal appears to be out
+                        *  - pad mode if we're upright,
+                        *  - idle mode otherwise
+                        */
                        ao_config_get();
-                       if (ao_flight_accel < ao_config.accel_zero_g - ACCEL_NOSE_UP) {
+#if HAS_ACCEL
+                       if (ao_config.accel_plus_g == 0 ||
+                           ao_config.accel_minus_g == 0 ||
+                           ao_flight_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP ||
+                           ao_flight_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP)
+                       {
+                               /* Detected an accel value outside -1.5g to 1.5g
+                                * (or uncalibrated values), so we go into invalid mode
+                                */
+                               ao_flight_state = ao_flight_invalid;
 
+                       } else
+#endif
+                               if (!ao_flight_force_idle
+#if HAS_ACCEL
+                                   && ao_flight_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP
+#endif
+                                       )
+                       {
+                               /* Set pad mode - we can fly! */
+                               ao_flight_state = ao_flight_pad;
+#if HAS_USB
                                /* Disable the USB controller in flight mode
                                 * to save power
                                 */
                                ao_usb_disable();
+#endif
 
-                               /* Turn on telemetry system
-                                */
+                               /* Disable packet mode in pad state */
+                               ao_packet_slave_stop();
+
+                               /* Turn on telemetry system */
+                               ao_rdf_set(1);
                                ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
 
-                               ao_flight_state = ao_flight_launchpad;
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               /* signal successful initialization by turning off the LED */
+                               ao_led_off(AO_LED_RED);
                        } else {
-                               ao_flight_state = ao_flight_idle;
-
-                               /* Turn on the Green LED in idle mode
-                                */
-                               ao_led_on(AO_LED_GREEN);
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               /* Set idle mode */
+                               ao_flight_state = ao_flight_idle;
+                               /* signal successful initialization by turning off the LED */
+                               ao_led_off(AO_LED_RED);
                        }
-                       /* signal successful initialization by turning off the LED */
-                       ao_led_off(AO_LED_RED);
+                       /* wakeup threads due to state change */
+                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+
                        break;
-               case ao_flight_launchpad:
+               case ao_flight_pad:
 
+#if HAS_ACCEL
                        /* Trim velocity
                         *
                         * Once a second, remove any velocity from
@@ -254,6 +476,7 @@ ao_flight(void)
                                ao_flight_vel -= ao_old_vel;
                                ao_old_vel = ao_flight_vel;
                        }
+#endif
                        /* pad to boost:
                         *
                         * accelerometer: > 2g AND velocity > 5m/s
@@ -264,11 +487,35 @@ ao_flight(void)
                         * the barometer, but we use both to make sure this
                         * transition is detected
                         */
-                       if ((ao_flight_accel < ao_ground_accel - ACCEL_BOOST &&
-                            ao_flight_vel > ACCEL_VEL_BOOST) ||
+#if USE_KALMAN
+#if HAS_ACCEL
+                       /*
+                        * With an accelerometer, either to detect launch
+                        */
+                       if ((ao_k_accel > to_fix32(20) &&
+                            ao_k_speed > to_fix32(5)) ||
+                           ao_k_height > to_fix32(20))
+#else
+                       /*
+                        * Without an accelerometer, the barometer is far too
+                        * noisy to rely on speed or acceleration data
+                        */
+                       if (ao_k_height > to_fix32(20))
+#endif
+#else
+                       if (
+#if HAS_ACCEL
+                               (ao_flight_accel < ao_ground_accel - ACCEL_BOOST &&
+                                ao_flight_vel > ACCEL_VEL_BOOST) ||
+#endif
                            ao_flight_pres < ao_ground_pres - BARO_LAUNCH)
+#endif
                        {
+#if HAS_ACCEL || USE_KALMAN
                                ao_flight_state = ao_flight_boost;
+#else
+                               ao_flight_state = ao_flight_coast;
+#endif
                                ao_launch_tick = ao_flight_tick;
 
                                /* start logging data */
@@ -277,13 +524,23 @@ ao_flight(void)
                                /* Increase telemetry rate */
                                ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT);
 
+                               /* disable RDF beacon */
+                               ao_rdf_set(0);
+
+#if HAS_GPS
+                               /* Record current GPS position by waking up GPS log tasks */
+                               ao_wakeup(&ao_gps_data);
+                               ao_wakeup(&ao_gps_tracking_data);
+#endif
+
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                                break;
                        }
                        break;
+#if HAS_ACCEL || USE_KALMAN
                case ao_flight_boost:
 
-                       /* boost to coast:
+                       /* boost to fast:
                         *
                         * accelerometer: start to fall at > 1/4 G
                         *              OR
@@ -293,17 +550,22 @@ ao_flight(void)
                         * deceleration, or by waiting until the maximum burn duration
                         * (15 seconds) has past.
                         */
-                       if (ao_flight_accel > ao_ground_accel + (ACCEL_G >> 2) ||
+#if USE_KALMAN
+                       if ((ao_k_accel < to_fix32(-10) && ao_k_height > to_fix32(100)) ||
+                           (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX)
+#else
+                       if (ao_flight_accel > ao_ground_accel + ACCEL_COAST ||
                            (int16_t) (ao_flight_tick - ao_launch_tick) > BOOST_TICKS_MAX)
+#endif
                        {
-                               ao_flight_state = ao_flight_coast;
+                               ao_flight_state = ao_flight_fast;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                                break;
                        }
                        break;
-               case ao_flight_coast:
+               case ao_flight_fast:
 
-                       /* coast to apogee detect:
+                       /* fast to coast:
                         *
                         * accelerometer: integrated velocity < 200 m/s
                         *               OR
@@ -318,34 +580,46 @@ ao_flight(void)
                         * how big a pressure change the mach transition
                         * generates would be useful here.
                         */
+#if USE_KALMAN
+                       if (ao_k_speed < to_fix32(200) ||
+                           ao_k_height < ao_k_max_height - to_fix32(500))
+#else
                        if (ao_flight_vel < ACCEL_VEL_MACH ||
                            ao_flight_pres > ao_min_pres + BARO_COAST)
+#endif
                        {
+#if HAS_ACCEL
                                /* set min velocity to current velocity for
                                 * apogee detect
                                 */
                                ao_min_vel = abs(ao_flight_vel);
-                               ao_flight_state = ao_flight_apogee;
+#endif
+                               ao_flight_state = ao_flight_coast;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
                        break;
-               case ao_flight_apogee:
+#endif /* HAS_ACCEL */
+               case ao_flight_coast:
 
-                       /* apogee detect to drogue deploy:
+#if USE_KALMAN
+                       /* apogee detect: coast to drogue deploy:
+                        *
+                        * speed: < 0
+                        */
+                       if (ao_k_speed < 0)
+#else
+                       /* apogee detect: coast to drogue deploy:
                         *
-                        * accelerometer: abs(velocity) > min_velocity + 2m/s
-                        *               OR
                         * barometer: fall at least 10m
                         *
-                        * If the barometer saturates because the flight
-                        * goes over its measuring range (about 53k'),
-                        * requiring a 10m fall will avoid prematurely
-                        * detecting apogee; the accelerometer will take
-                        * over in that case and the integrated velocity
-                        * measurement should suffice to find apogee
+                        * It would be nice to use the accelerometer
+                        * to detect apogee as well, but tests have
+                        * shown that flights far from vertical would
+                        * grossly mis-detect apogee. So, for now,
+                        * we'll trust to a single sensor for this test
                         */
-                       if (/* abs(ao_flight_vel) > ao_min_vel + ACCEL_VEL_APOGEE || */
-                           ao_flight_pres > ao_min_pres + BARO_APOGEE)
+                       if (ao_flight_pres > ao_min_pres + BARO_APOGEE)
+#endif
                        {
                                /* ignite the drogue charge */
                                ao_ignite(ao_igniter_drogue);
@@ -353,8 +627,10 @@ ao_flight(void)
                                /* slow down the telemetry system */
                                ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
 
+#if !USE_KALMAN
                                /* slow down the ADC sample rate */
                                ao_timer_set_adc_interval(10);
+#endif
 
                                /*
                                 * Start recording min/max accel and pres for a while
@@ -363,8 +639,10 @@ ao_flight(void)
                                /* Set the 'last' limits to max range to prevent
                                 * early resting detection
                                 */
+#if HAS_ACCEL
                                ao_interval_min_accel = 0;
                                ao_interval_max_accel = 0x7fff;
+#endif
                                ao_interval_min_pres = 0;
                                ao_interval_max_pres = 0x7fff;
 
@@ -372,7 +650,9 @@ ao_flight(void)
                                ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS;
 
                                ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres;
+#if HAS_ACCEL
                                ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel;
+#endif
 
                                /* and enter drogue state */
                                ao_flight_state = ao_flight_drogue;
@@ -394,7 +674,11 @@ ao_flight(void)
                         * at that point. Perhaps also use the drogue sense lines
                         * to notice continutity?
                         */
+#if USE_KALMAN
+                       if (from_fix(ao_k_height) < ao_config.main_deploy)
+#else
                        if (ao_flight_pres >= ao_main_pres)
+#endif
                        {
                                ao_ignite(ao_igniter_main);
                                ao_flight_state = ao_flight_main;
@@ -415,31 +699,40 @@ ao_flight(void)
                                ao_interval_cur_min_pres = ao_flight_pres;
                        if (ao_flight_pres > ao_interval_cur_max_pres)
                                ao_interval_cur_max_pres = ao_flight_pres;
+#if HAS_ACCEL
                        if (ao_flight_accel < ao_interval_cur_min_accel)
                                ao_interval_cur_min_accel = ao_flight_accel;
                        if (ao_flight_accel > ao_interval_cur_max_accel)
                                ao_interval_cur_max_accel = ao_flight_accel;
+#endif
 
                        if ((int16_t) (ao_flight_tick - ao_interval_end) >= 0) {
                                ao_interval_max_pres = ao_interval_cur_max_pres;
                                ao_interval_min_pres = ao_interval_cur_min_pres;
+                               ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres;
+#if HAS_ACCEL
                                ao_interval_max_accel = ao_interval_cur_max_accel;
                                ao_interval_min_accel = ao_interval_cur_min_accel;
-                               ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS;
-                               ao_interval_cur_min_pres = ao_interval_cur_max_pres = ao_flight_pres;
                                ao_interval_cur_min_accel = ao_interval_cur_max_accel = ao_flight_accel;
-                       }
-
-                       if ((uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND &&
-                           ao_flight_pres > ao_ground_pres - BARO_LAND &&
-                           (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND)
-                       {
-                               ao_flight_state = ao_flight_landed;
-
-                               /* turn off the ADC capture */
-                               ao_timer_set_adc_interval(0);
+#endif
+                               ao_interval_end = ao_flight_tick + AO_INTERVAL_TICKS;
 
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               if (
+#if HAS_ACCEL
+                                       (uint16_t) (ao_interval_max_accel - ao_interval_min_accel) < (uint16_t) ACCEL_INT_LAND &&
+#endif
+                                   ao_flight_pres > ao_ground_pres - BARO_LAND &&
+                                   (uint16_t) (ao_interval_max_pres - ao_interval_min_pres) < (uint16_t) BARO_INT_LAND)
+                               {
+                                       ao_flight_state = ao_flight_landed;
+
+                                       /* turn off the ADC capture */
+                                       ao_timer_set_adc_interval(0);
+                                       /* Enable RDF beacon */
+                                       ao_rdf_set(1);
+
+                                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               }
                        }
                        break;
                case ao_flight_landed:
@@ -448,37 +741,11 @@ ao_flight(void)
        }
 }
 
-#define AO_ACCEL_COUNT_TO_MSS(count)   ((count) / 27)
-#define AO_VEL_COUNT_TO_MS(count)      ((int16_t) ((count) / 2700))
-
-static void
-ao_flight_status(void)
-{
-       printf("STATE: %7s accel: %d speed: %d altitude: %d main: %d\n",
-              ao_state_names[ao_flight_state],
-              AO_ACCEL_COUNT_TO_MSS(ACCEL_ZERO_G - ao_flight_accel),
-              AO_VEL_COUNT_TO_MS(ao_flight_vel),
-              ao_pres_to_altitude(ao_flight_pres),
-              ao_pres_to_altitude(ao_main_pres));
-}
-
 static __xdata struct ao_task  flight_task;
 
-__code struct ao_cmds ao_flight_cmds[] = {
-       { 'f', ao_flight_status,        "f                                  Display current flight state" },
-       { 0, ao_flight_status, NULL }
-};
-
 void
 ao_flight_init(void)
 {
        ao_flight_state = ao_flight_startup;
-       ao_interval_min_accel = 0;
-       ao_interval_max_accel = 0x7fff;
-       ao_interval_min_pres = 0;
-       ao_interval_max_pres = 0x7fff;
-       ao_interval_end = AO_INTERVAL_TICKS;
-
        ao_add_task(&flight_task, ao_flight, "flight");
-       ao_cmd_register(&ao_flight_cmds[0]);
 }