Allow for slower ADC operation. Add power saving code.
authorKeith Packard <keithp@keithp.com>
Sat, 25 Apr 2009 21:44:33 +0000 (14:44 -0700)
committerKeith Packard <keithp@keithp.com>
Sat, 25 Apr 2009 21:44:33 +0000 (14:44 -0700)
This tries to make the flight computer use less power by disabling USB in
flight mode, lowering the telemetry rate after ascent. It also disables the
RDF beacon during ascent and re-enables it once descent has started.

ao_flight.c
ao_flight_test.c

index bd361b6..1f56dab 100644 (file)
@@ -23,6 +23,7 @@
 
 __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 */
@@ -79,6 +80,9 @@ __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres;
 #define ACCEL_BOOST    ACCEL_G * 2
 #define ACCEL_INT_LAND (ACCEL_G / 10)
 #define ACCEL_VEL_LAND VEL_MPS_TO_COUNT(10)
+#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)
 
 /*
  * Barometer calibration
@@ -105,7 +109,7 @@ __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres;
 #define BARO_COAST     (BARO_kPa * 5)  /* 5kpa, or about 500m */
 #define BARO_MAIN      (BARO_kPa)      /* 1kPa, or about 100m */
 #define BARO_INT_LAND  (BARO_kPa / 20) /* .05kPa, or about 5m */
-#define BARO_LAND      (BARO_kPa * 5)  /* 5kPa or about 1000m */
+#define BARO_LAND      (BARO_kPa * 10) /* 10kPa or about 1000m */
 
 /* We also have a clock, which can be used to sanity check things in
  * case of other failures
@@ -119,7 +123,7 @@ __pdata int16_t ao_raw_accel, ao_raw_accel_prev, ao_raw_pres;
  * it's scaled by 100
  */
 __pdata int32_t        ao_flight_vel;
-__pdata int32_t ao_max_vel;
+__pdata int32_t ao_min_vel;
 __xdata int32_t ao_raw_accel_sum, ao_raw_pres_sum;
 
 /* Landing is detected by getting constant readings from both pressure and accelerometer
@@ -127,6 +131,8 @@ __xdata int32_t ao_raw_accel_sum, ao_raw_pres_sum;
  */
 #define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(20)
 
+#define abs(a) ((a) < 0 ? -(a) : (a))
+
 void
 ao_flight(void)
 {
@@ -140,15 +146,36 @@ ao_flight(void)
        ao_interval_cur_max_pres = -0x7fff;
        ao_interval_cur_min_accel = 0x7fff;
        ao_interval_cur_max_accel = -0x7fff;
+       ao_flight_tick = 0;
        for (;;) {
                ao_sleep(&ao_adc_ring);
                while (ao_flight_adc != ao_adc_head) {
+                       __pdata uint8_t ticks;
+                       __pdata int16_t ao_vel_change;
+                       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;
-                       /* all of our accelerations are negative, so subtract instead of add to get speed */
-                       ao_flight_vel -= (int32_t) (((ao_raw_accel + ao_raw_accel_prev) >> 1) - ao_ground_accel);
+
+                       /* Update velocity
+                        *
+                        * The accelerometer is mounted so that
+                        * acceleration yields negative values
+                        * while deceleration yields positive values,
+                        * so subtract instead of add.
+                        */
+                       ticks = ao_flight_tick - ao_flight_prev_tick;
+                       ao_vel_change = (((ao_raw_accel + ao_raw_accel_prev) >> 1) - ao_ground_accel);
                        ao_raw_accel_prev = ao_raw_accel;
+
+                       /* one is a common interval */
+                       if (ticks == 1)
+                               ao_flight_vel -= (int32_t) ao_vel_change;
+                       else
+                               ao_flight_vel -= (int32_t) ao_vel_change * (int32_t) ticks;
+
                        ao_flight_adc = ao_adc_ring_next(ao_flight_adc);
                }
                ao_flight_accel -= ao_flight_accel >> 4;
@@ -158,8 +185,13 @@ ao_flight(void)
 
                if (ao_flight_pres < ao_min_pres)
                        ao_min_pres = ao_flight_pres;
-               if (ao_flight_vel > ao_max_vel)
-                       ao_max_vel = ao_flight_vel;
+               if (ao_flight_vel >= 0) {
+                       if (ao_flight_vel < ao_min_vel)
+                           ao_min_vel = ao_flight_vel;
+               } else {
+                       if (-ao_flight_vel < ao_min_vel)
+                           ao_min_vel = -ao_flight_vel;
+               }
 
                if (ao_flight_pres < ao_interval_cur_min_pres)
                        ao_interval_cur_min_pres = ao_flight_pres;
@@ -199,12 +231,23 @@ ao_flight(void)
                        ao_min_pres = ao_ground_pres;
                        ao_main_pres = ao_ground_pres - BARO_MAIN;
                        ao_flight_vel = 0;
-                       ao_max_vel = 0;
+                       ao_min_vel = 0;
 
                        ao_interval_end = ao_flight_tick;
 
                        /* Go to launchpad state if the nose is pointing up */
                        if (ao_flight_accel < ACCEL_NOSE_UP) {
+
+                               /* Disable the USB controller in flight mode
+                                * to save power
+                                */
+                               ao_usb_disable();
+
+                               /* Turn on telemetry system
+                                */
+                               ao_rdf_set(1);
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT);
+
                                ao_flight_state = ao_flight_launchpad;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        } else {
@@ -236,7 +279,13 @@ ao_flight(void)
                        {
                                ao_flight_state = ao_flight_boost;
                                ao_launch_tick = ao_flight_tick;
+
+                               /* start logging data */
                                ao_log_start();
+
+                               /* disable RDF beacon */
+                               ao_rdf_set(0);
+
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                                break;
                        }
@@ -260,33 +309,40 @@ ao_flight(void)
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                                break;
                        }
-                       /* fall through ... */
+                       break;
                case ao_flight_coast:
 
-                       /* boost/coast to apogee detect:
+                       /* coast to apogee detect:
                         *
-                        * accelerometer: integrated velocity < 200 m/s AND < max_vel - 50m/s
+                        * accelerometer: integrated velocity < 200 m/s
                         *               OR
                         * barometer: fall at least 500m from max altitude
                         *
                         * This extra state is required to avoid mis-detecting
-                        * apogee due to mach transitions. For slow flights (<200m/s)
-                        * we expect to transition right through this stage to
-                        * apogee detect.
+                        * apogee due to mach transitions.
+                        *
+                        * XXX this is essentially a single-detector test
+                        * as the 500m altitude change would likely result
+                        * in a loss of the rocket. More data on precisely
+                        * how big a pressure change the mach transition
+                        * generates would be useful here.
                         */
-                       if ((ao_flight_vel < VEL_MPS_TO_COUNT(200) &&
-                            ao_flight_vel < ao_max_vel - VEL_MPS_TO_COUNT(50)) ||
+                       if (ao_flight_vel < ACCEL_VEL_MACH ||
                            ao_flight_pres > ao_min_pres + BARO_COAST)
                        {
+                               /* set min velocity to current velocity for
+                                * apogee detect
+                                */
+                               ao_min_vel = ao_flight_vel;
                                ao_flight_state = ao_flight_apogee;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
                        break;
                case ao_flight_apogee:
 
-                       /* apogee to drogue deploy:
+                       /* apogee detect to drogue deploy:
                         *
-                        * accelerometer: integrated velocity < 10m/s
+                        * accelerometer: abs(velocity) > min_velocity + 2m/s
                         *               OR
                         * barometer: fall at least 10m
                         *
@@ -297,10 +353,18 @@ ao_flight(void)
                         * over in that case and the integrated velocity
                         * measurement should suffice to find apogee
                         */
-                       if (ao_flight_vel < VEL_MPS_TO_COUNT(-10) ||
-                           ao_flight_pres - BARO_APOGEE > ao_min_pres)
+                       if (abs(ao_flight_vel) > ao_min_vel + ACCEL_VEL_APOGEE ||
+                           ao_flight_pres > ao_min_pres + BARO_APOGEE)
                        {
+                               /* ignite the drogue charge */
                                ao_ignite(ao_igniter_drogue);
+
+                               /* slow down the telemetry system */
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
+
+                               /* Enable RDF beacon */
+                               ao_rdf_set(1);
+
                                ao_flight_state = ao_flight_drogue;
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
@@ -309,12 +373,12 @@ ao_flight(void)
 
                        /* drogue to main deploy:
                         *
-                        * accelerometer: abs(velocity) > 50m/s
+                        * accelerometer: abs(velocity) > 100m/s (in case the drogue failed)
                         *               OR
                         * barometer: reach main deploy altitude
                         */
-                       if (ao_flight_vel < VEL_MPS_TO_COUNT(-50) ||
-                           ao_flight_vel > VEL_MPS_TO_COUNT(50) ||
+                       if (ao_flight_vel < -ACCEL_VEL_MAIN ||
+                           ao_flight_vel > ACCEL_VEL_MAIN ||
                            ao_flight_pres >= ao_main_pres)
                        {
                                ao_ignite(ao_igniter_main);
@@ -328,19 +392,25 @@ ao_flight(void)
                         *
                         * accelerometer: value stable and velocity less than 10m/s
                         *                           OR
-                        * barometer: altitude stable and within 500m of the launch altitude
+                        * barometer: altitude stable and within 1000m of the launch altitude
                         */
-                       if ((ao_flight_vel < ACCEL_VEL_LAND &&
+                       if ((abs(ao_flight_vel) < ACCEL_VEL_LAND &&
                             (ao_interval_max_accel - ao_interval_min_accel) < ACCEL_INT_LAND) ||
                            (ao_flight_pres > ao_ground_pres - BARO_LAND &&
                             (ao_interval_max_pres - ao_interval_min_pres) < BARO_INT_LAND))
                        {
                                ao_flight_state = ao_flight_landed;
+
+                               /* turn off the ADC capture */
+                               ao_timer_set_adc_interval(0);
+
+                               /* stop logging data */
+                               ao_log_stop();
+
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
                        }
                        break;
                case ao_flight_landed:
-                       ao_log_stop();
                        break;
                }
        }
@@ -349,7 +419,7 @@ ao_flight(void)
 #define AO_ACCEL_COUNT_TO_MSS(count)   ((count) / 27)
 #define AO_VEL_COUNT_TO_MS(count)      ((int16_t) ((count) / 2700))
 
-void
+static void
 ao_flight_status(void)
 {
        printf("STATE: %7s accel: %d speed: %d altitude: %d\n",
index 2cd7c81..0b18969 100644 (file)
@@ -63,6 +63,9 @@ uint8_t ao_adc_head;
 #define ao_timer_set_adc_interval(i)
 #define ao_wakeup(wchan) ao_dump_state()
 #define ao_cmd_register(c)
+#define ao_usb_disable()
+#define ao_telemetry_set_interval(x)
+#define ao_rdf_set(rdf)
 
 enum ao_igniter {
        ao_igniter_drogue = 0,
@@ -201,7 +204,7 @@ ao_dump_state(void)
 {
        if (ao_flight_state == ao_flight_startup)
                return;
-       printf ("\t%s accel %g vel %g alt %d\n",
+       printf ("\t\t\t\t\t%s accel %g vel %g alt %d\n",
                ao_state_names[ao_flight_state],
                (ao_flight_accel - ao_ground_accel) / COUNTS_PER_G * GRAVITY,
                (double) ao_flight_vel / 100 / COUNTS_PER_G * GRAVITY,