ao-load ao-telem ao-send-telem ao-sky-flash \
ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex \
ao-flash ao-usbload ao-test-igniter ao-test-baro \
- ao-test-flash ao-cal-accel ao-test-gps ao-usbtrng \
+ ao-test-flash ao-cal-accel ao-fakeflight ao-test-gps ao-usbtrng \
ao-cal-freq ao-chaosread ao-makebin
if LIBSTLINK
SUBDIRS += ao-stmload
--- /dev/null
+bin_PROGRAMS=ao-fakeflight
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) -I$(top_srcdir)/src/drivers -O0 -g
+AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_fakeflight_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
+
+ao_fakeflight_LDADD=$(AO_POSTFLIGHT_LIBS)
+
+LIBS=-lm
+
+ao_fakeflight_SOURCES = \
+ ao-fakeflight.c \
+ ao-fakeflight.h \
+ ao-fake-convert.c \
+ ao-fake-log.c \
+ ao-physics.c \
+ ao-rocket.c
+
+clean-local:
+ $(RM) $(BUILT_SOURCES)
+
+ALTOS=$(top_srcdir)/src
+DRIVERS=$(ALTOS)/drivers
+KERNEL=$(ALTOS)/kernel
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+#include <ao-fakeflight.h>
+#include <stdio.h>
+#include <math.h>
+
+/* From mega serial 1246 */
+
+struct ao_ms5607_prom ao_ms5607_prom = {
+ .reserved = 156,
+ .sens = 44229,
+ .off = 38634,
+ .tcs = 27789,
+ .tco = 25015,
+ .tref = 32003,
+ .tempsens = 27647,
+ .crc = 50256,
+};
+
+struct ao_config {
+ int16_t accel_plus_g;
+ int16_t accel_minus_g;
+};
+
+struct ao_config ao_config = {
+ .accel_plus_g = 2028,
+ .accel_minus_g = 2065
+};
+
+#define MIN_VALUE 0
+#define MAX_VALUE 16777216
+#define MID_VALUE ((MAX_VALUE - MIN_VALUE) / 2)
+
+static void
+ao_ms5607_search (struct ao_ms5607_value *goal_value,
+ struct ao_ms5607_sample *goal_sample,
+ int search_temp)
+{
+ struct ao_ms5607_sample sample;
+ struct ao_ms5607_value value;
+ uint32_t hi, lo, mid;
+ int32_t goal;
+ int32_t result;
+
+ if (search_temp) {
+ sample.pres = MID_VALUE;
+ goal = goal_value->temp;
+ } else {
+ sample.temp = goal_sample->temp;
+ goal = goal_value->pres;
+ }
+
+ lo = MIN_VALUE;
+ hi = MAX_VALUE;
+ for (;;) {
+ mid = (hi + lo) >> 1;
+
+ if (mid == lo)
+ break;
+
+ if (search_temp)
+ sample.temp = mid;
+ else
+ sample.pres = mid;
+
+ ao_ms5607_convert(&sample, &value);
+
+ if (search_temp)
+ result = value.temp;
+ else
+ result = value.pres;
+
+ if (result == goal)
+ break;
+
+ if (result < goal)
+ lo = mid;
+ else
+ hi = mid;
+ }
+ *goal_sample = sample;
+}
+
+void
+ao_ms5607_unconvert(double altitude,
+ struct ao_ms5607_sample *ret)
+{
+ double pressure = cc_altitude_to_pressure(altitude);
+ double temperature = cc_altitude_to_temperature(altitude);
+
+ struct ao_ms5607_value value;
+
+ value.pres = floor (pressure + 0.5);
+ value.temp = floor (temperature * 100 + 0.5);
+
+ /* First back-convert temperature; that's independent of pressure */
+
+ ao_ms5607_search(&value, ret, 1);
+
+ /* Now search for pressure */
+
+ ao_ms5607_search(&value, ret, 0);
+}
+
+int16_t
+ao_accel_unconvert(double accel)
+{
+ int16_t ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
+ double ao_accel_0g = (ao_config.accel_minus_g + ao_config.accel_plus_g) / 2.0;
+ double ao_accel_scale = GRAVITY * 2.0 / ao_accel_2g;
+
+ int16_t ao_sample_accel = ao_accel_0g - accel/ao_accel_scale;
+
+ return ao_sample_accel;
+}
+
+static void
+ao_ms5607_show(FILE *f, struct rocket *r)
+{
+ fprintf(f, "ms5607 reserved: %u\n", ao_ms5607_prom.reserved);
+ fprintf(f, "ms5607 sens: %u\n", ao_ms5607_prom.sens);
+ fprintf(f, "ms5607 off: %u\n", ao_ms5607_prom.off);
+ fprintf(f, "ms5607 tcs: %u\n", ao_ms5607_prom.tcs);
+ fprintf(f, "ms5607 tco: %u\n", ao_ms5607_prom.tco);
+ fprintf(f, "ms5607 tref: %u\n", ao_ms5607_prom.tref);
+ fprintf(f, "ms5607 tempsens: %u\n", ao_ms5607_prom.tempsens);
+ fprintf(f, "ms5607 crc: %u\n", ao_ms5607_prom.crc);
+}
+
+static void
+ao_config_show(FILE *f, struct rocket *r)
+{
+ fprintf(f, "Config version: 1.18\n");
+ fprintf(f, "Accel cal +1g: %d -1g: %d\n",
+ ao_config.accel_plus_g, ao_config.accel_minus_g);
+ fprintf(f, "Main deploy: %d meters\n", (int) r->main_deploy);
+}
+
+#include "config.h"
+
+void
+ao_show_header(FILE *f, struct rocket *r)
+{
+ ao_config_show(f, r);
+ ao_ms5607_show(f, r);
+ fprintf(f, "serial-number 1\n");
+ fprintf(f, "current-flight 1\n");
+ fprintf(f, "log-format %u\n", AO_LOG_FORMAT_TELEMETRUM);
+ fprintf(f, "altitude-32 1\n");
+ fprintf(f, "software-version %s\n", PACKAGE_VERSION);
+}
+
+#include "ao_ms5607_convert.c"
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+static uint8_t
+ao_log_csum(uint8_t *b)
+{
+ uint8_t sum = 0x5a;
+ uint8_t i;
+
+ for (i = 0; i < sizeof (struct ao_log_metrum); i++)
+ sum += *b++;
+ return -sum;
+}
+
+void
+ao_log_metrum(FILE *file, struct ao_log_metrum *log)
+{
+ uint8_t *d;
+
+ /* set checksum */
+ log->csum = 0;
+ log->csum = ao_log_csum((uint8_t *) log);
+ int i;
+
+ fprintf (file, "%c %04x", log->type, log->tick);
+ d = (void *) &log->u;
+ for (i = 0; i < sizeof (log->u); i++)
+ fprintf(file, " %02x", d[i]);
+ fprintf (file, "\n");
+}
+
+void
+ao_log_flight(FILE *file, struct flight *f, struct rocket *r)
+{
+ static struct ao_log_metrum log;
+
+ log.type = AO_LOG_FLIGHT;
+ log.tick = (f->time * 100);
+ log.u.flight.ground_accel = ao_accel_unconvert(GRAVITY);
+ log.u.flight.ground_pres = cc_altitude_to_pressure(f->altitude);
+ log.u.flight.flight = 1;
+ ao_log_metrum(file, &log);
+}
+
+void
+ao_log_sensor(FILE *file, struct flight *f, struct rocket *r)
+{
+ static struct ao_log_metrum log;
+ struct ao_ms5607_sample sample_baro;
+ int16_t sample_accel;
+
+ ao_ms5607_unconvert(f->altitude, &sample_baro);
+ sample_accel = ao_accel_unconvert(f->accel);
+
+ log.type = AO_LOG_SENSOR;
+ log.tick = (f->time * 100);
+ log.u.sensor.pres = sample_baro.pres;
+ log.u.sensor.temp = sample_baro.temp;
+ log.u.sensor.accel = sample_accel;
+ ao_log_metrum(file, &log);
+}
+
+void
+ao_log_gps(FILE *file, struct flight *f, struct rocket *r)
+{
+ static struct ao_log_metrum log;
+ static double gps_time;
+ static int been_here;
+ int32_t altitude;
+ int32_t seconds;
+
+ if (been_here && (f->time - gps_time) < 1)
+ return;
+ been_here = 1;
+ gps_time = f->time;
+
+ altitude = f->altitude;
+ seconds = f->time;
+
+ log.type = AO_LOG_GPS_POS;
+ log.tick = (f->time * 100);
+ log.u.gps.latitude = 45 * 1e7;
+ log.u.gps.longitude = -121 * 1e7;
+ log.u.gps.altitude_low = altitude;
+ log.u.gps.altitude_high = altitude >> 16;
+ ao_log_metrum(file, &log);
+
+ log.type = AO_LOG_GPS_TIME;
+ log.tick = (f->time * 100);
+ log.u.gps_time.hour = seconds / 3600;
+ log.u.gps_time.minute = (seconds / 60) % 60;
+ log.u.gps_time.second = seconds % 60;
+ log.u.gps_time.flags = AO_GPS_VALID | AO_GPS_RUNNING | AO_GPS_DATE_VALID | AO_GPS_COURSE_VALID | (12 << AO_GPS_NUM_SAT_SHIFT);
+ log.u.gps_time.year = 114;
+ log.u.gps_time.month = 7;
+ log.u.gps_time.day = 1;
+ log.u.gps_time.pdop = 1;
+
+ ao_log_metrum(file, &log);
+}
+
+void
+ao_log_state(FILE *file, struct flight *f, struct rocket *r)
+{
+ static struct ao_log_metrum log;
+ static int log_state = ao_flight_startup;
+ int flight_state;
+
+ switch (f->state) {
+ case state_ascent:
+ if (f->speed == 0 && f->altitude == 0)
+ flight_state = ao_flight_pad;
+ else if (f->accel > 0)
+ flight_state = ao_flight_boost;
+ else if (f->speed > 300)
+ flight_state = ao_flight_fast;
+ else
+ flight_state = ao_flight_coast;
+ break;
+ case state_drogue:
+ flight_state = ao_flight_drogue;
+ break;
+ case state_main:
+ flight_state = ao_flight_main;
+ break;
+ case state_landed:
+ flight_state = ao_flight_landed;
+ break;
+ }
+ if (flight_state != log_state) {
+ log.type = AO_LOG_STATE;
+ log.tick = (f->time * 100);
+ log.u.state.state = flight_state;
+ log.u.state.reason = 0;
+ ao_log_metrum(file, &log);
+ log_state = flight_state;
+ }
+}
+
+void
+ao_log(FILE *file, struct flight *f, struct rocket *r)
+{
+ static int been_here = 0;
+
+ if (!been_here) {
+ been_here = 1;
+ ao_log_flight(file, f, r);
+ }
+ ao_log_sensor(file, f, r);
+ ao_log_state(file, f, r);
+ ao_log_gps(file, f, r);
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+char *state_name[] = {
+ [state_ascent] = "ascent",
+ [state_drogue] = "drogue",
+ [state_main] = "main",
+ [state_landed] = "landed",
+};
+
+struct rocket o5778 = {
+ .models = {
+ [state_ascent] = {
+ .cd = 0.5,
+ .diameter = .100
+ },
+ [state_drogue] = {
+ .cd = 1.3,
+ .diameter = .300
+ },
+ [state_main] = {
+ .cd = 1.3,
+ .diameter = 1.0
+ },
+ },
+ .empty_mass = 15.0,
+ .main_deploy = 250,
+ .motors = {
+ [0] = {
+ .fuel_mass = 18.021,
+ .average_thrust = 5778.0,
+ .burn_time = 8.52,
+ .delay = 0.0,
+ },
+ [1] = {
+ .fuel_mass = 18.021,
+ .average_thrust = 5778.0,
+ .burn_time = 0, /* 17.04 */
+ .delay = 18.0,
+ },
+ },
+};
+
+struct rocket n5778 = {
+ .models = {
+ [state_ascent] = {
+ .cd = 0.5,
+ .diameter = .100
+ },
+ [state_drogue] = {
+ .cd = 1.3,
+ .diameter = .300
+ },
+ [state_main] = {
+ .cd = 1.3,
+ .diameter = 1.0
+ },
+ },
+ .empty_mass = 15.0,
+ .main_deploy = 250,
+ .motors = {
+ [0] = {
+ .fuel_mass = 9.0105,
+ .average_thrust = 5778.0,
+ .burn_time = 4.26,
+ .delay = 0.0,
+ },
+ },
+};
+
+/*
+ * Move the flight one tick forward
+ */
+void
+step(struct flight *f, struct rocket *r)
+{
+ double drag = rocket_drag(f, r);
+ double thrust = rocket_thrust(f, r);
+ double gravity = rocket_gravity(f, r);
+ double mass = rocket_mass(f, r);
+ double accel;
+
+ /* This is our acceleration relative to the earth */
+ accel = (drag + thrust - gravity) / mass;
+
+ /* Because the accelerometer is also affected by gravity, it
+ * only measures *other* forces applied to the rocket
+ */
+ f->accel = (drag + thrust) / mass;
+
+ f->altitude += f->speed * STEP + 0.5 * (accel * STEP) * (accel * STEP);
+ f->speed += accel * STEP;
+ f->time += STEP;
+}
+
+void
+init(struct flight *f, struct rocket *r)
+{
+ double gravity = rocket_gravity(f, r);
+
+ /* The pad is pushing up on the rocket to counter
+ * gravity, so the accelerometer, which only measures
+ * forces other than gravity, sees only this
+ */
+ f->accel = gravity / rocket_mass(f, r);
+ f->speed = 0;
+ f->altitude = 0;
+ f->time += STEP;
+}
+
+void
+fly(FILE *file, struct rocket *r)
+{
+ struct flight f = {
+ .time = -1,
+ .altitude = 0,
+ .speed = 0,
+ .accel = 0,
+ .state = state_ascent,
+ };
+
+ double max_speed = 0;
+ double max_alt = 0;
+ double max_accel = 0;
+
+
+ ao_show_header(file, r);
+ while (f.time < 0) {
+ init(&f, r);
+ ao_log(file, &f, r);
+ }
+ while (f.altitude >= 0) {
+ step(&f, r);
+ switch (f.state) {
+ case state_ascent:
+ if (f.speed >= 0)
+ break;
+ f.state = state_drogue;
+ /* fall through */
+ case state_drogue:
+ if (f.altitude > o5778.main_deploy)
+ break;
+ f.state = state_main;
+ /* fall through */
+ case state_main:
+ break;
+ }
+ ao_log(file, &f, r);
+ max_speed = fmax(max_speed, f.speed);
+ max_accel = fmax(max_accel, f.accel);
+ max_alt = fmax(max_alt, f.altitude);
+ }
+ fprintf(stderr, "max alt %9.1f speed %9.1f accel %9.1f\n",
+ max_alt, max_speed, max_accel);
+}
+
+int
+main(int argc, char **argv)
+{
+ fly(stdout, &o5778);
+// fly(stdout, &n5778);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_FAKEFLIGHT_H_
+#define _AO_FAKEFLIGHT_H_
+
+#define __xdata
+#include <stdint.h>
+#include <ao_ms5607.h>
+#include <math.h>
+#include <stdio.h>
+#include "cc.h"
+
+#define GAS_CONSTANT 287.05
+#define STEP 0.01
+#define GRAVITATIONAL_CONSTANT 6.67384e-11
+#define GRAVITY 9.807
+#define EARTH_MASS 5.9726e24
+#define EARTH_RADIUS 6375313
+
+enum flight_state {
+ state_ascent,
+ state_drogue,
+ state_main,
+ state_landed,
+ state_num
+};
+
+extern char *state_name[];
+
+struct model {
+ double cd;
+ double diameter;
+};
+
+struct motor {
+ double fuel_mass;
+ double average_thrust;
+ double burn_time;
+ double delay;
+};
+
+#define MAX_MOTORS 12
+
+struct rocket {
+ struct model models[state_num];
+ double empty_mass;
+ double main_deploy;
+ struct motor motors[MAX_MOTORS];
+};
+
+/* Flight state */
+
+struct flight {
+ double time;
+ double altitude;
+ double speed;
+ double accel;
+ enum flight_state state;
+};
+
+/* ao-physics.c */
+
+/* Density of dry air in kg/m³ for a given pressure and temperature. */
+/* Density of dry air in kg/m³ for a given pressure and temperature. */
+double
+density_air(double pressure, /* Pa */
+ double temperature); /* °C */
+
+/* Area of a circle */
+double
+area_circle(double diameter);
+
+/* Force due to drag (N) */
+double
+force_drag(double speed, /* m/s */
+ double rho, /* kg/m³ */
+ double cd, /* unitless */
+ double area); /* m² */
+
+/* Force due to gravity (N) */
+double
+force_gravity(double mass, /* kg */
+ double altitude); /* m */
+
+/* ao-rocket.c */
+
+/* Mass (kg) of the airframe */
+double
+rocket_mass(struct flight *f, struct rocket *r);
+
+/* Force (N) due to thrust */
+double
+rocket_thrust(struct flight *f, struct rocket *r);
+
+/* Drag (N) due to air resistance */
+double
+rocket_drag(struct flight *f, struct rocket *r);
+
+/* Force (N) due to gravity */
+double
+rocket_gravity(struct flight *f, struct rocket *r);
+
+/* ao-fake-convert.c */
+void
+ao_ms5607_unconvert(double altitude,
+ struct ao_ms5607_sample *ret);
+
+int16_t
+ao_accel_unconvert(double accel);
+
+void
+ao_show_header(FILE *f, struct rocket *r);
+
+/* ao-fake-log.c */
+
+void
+ao_log_flight(FILE *file, struct flight *f, struct rocket *r);
+
+void
+ao_log_sensor(FILE *file, struct flight *f, struct rocket *r);
+
+void
+ao_log_state(FILE *file, struct flight *f, struct rocket *r);
+
+#endif
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+/* Density of dry air in kg/m³ for a given pressure and temperature. */
+double
+density_air(double pressure, /* Pa */
+ double temperature) /* °C */
+{
+ return pressure / (GAS_CONSTANT * (temperature + 273.15));
+}
+
+/* Area of a circle */
+double
+area_circle(double diameter)
+{
+ double radius = diameter / 2;
+ return M_PI * radius * radius;
+}
+
+/* Force due to drag (N) */
+double
+force_drag(double speed, /* m/s */
+ double rho, /* kg/m³ */
+ double cd, /* unitless */
+ double area) /* m² */
+{
+ return 0.5 * rho * (speed * speed) * cd * area;
+}
+
+/* Force due to gravity (N) */
+double
+force_gravity(double mass, /* kg */
+ double altitude) /* m */
+{
+ double distance = altitude + EARTH_RADIUS;
+ return GRAVITATIONAL_CONSTANT * EARTH_MASS * mass / (distance * distance);
+}
--- /dev/null
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+/* Mass (kg) of the airframe */
+double
+rocket_mass(struct flight *f, struct rocket *r)
+{
+ double time = f->time;
+ double m = r->empty_mass;
+ int n;
+
+ for (n = 0; n < MAX_MOTORS; n++) {
+ struct motor *motor = &r->motors[n];
+ if (motor->burn_time) {
+ double fuel_time_remain = fmin (motor->burn_time, fmax(motor->burn_time - (time - motor->delay), 0.0));
+ double fuel_fraction = fuel_time_remain / motor->burn_time;
+ m += fuel_fraction * motor->fuel_mass;
+ }
+ }
+ return m;
+}
+
+/* Force (N) due to thrust */
+double
+rocket_thrust(struct flight *f, struct rocket *r)
+{
+ double time = f->time;
+ double thrust = 0.0;
+ int n;
+
+ for (n = 0; n < MAX_MOTORS; n++) {
+ struct motor *motor = &r->motors[n];
+ if (motor->burn_time) {
+ if (motor->delay <= time && time < motor->delay + motor->burn_time)
+ thrust += motor->average_thrust;
+ }
+ }
+ return thrust;
+}
+
+/* Drag (N) due to air resistance */
+double
+rocket_drag(struct flight *f, struct rocket *r)
+{
+ double pressure = cc_altitude_to_pressure(f->altitude);
+ double temperature = cc_altitude_to_temperature(f->altitude);
+ double drag = force_drag(f->speed, density_air(pressure, temperature),
+ r->models[f->state].cd,
+ area_circle(r->models[f->state].diameter));
+
+ /* drag operates in opposition to motion through air */
+ if (f->speed >= 0)
+ drag = -drag;
+
+ return drag;
+}
+
+/* Force (N) due to gravity */
+double
+rocket_gravity(struct flight *f, struct rocket *r)
+{
+ double gravity = force_gravity(rocket_mass (f, r), f->altitude);
+}
ao-tools/ao-usbtrng/Makefile
ao-tools/ao-chaosread/Makefile
ao-tools/ao-makebin/Makefile
+ao-tools/ao-fakeflight/Makefile
ao-utils/Makefile
src/Version
])