X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=altoslib%2FAltosState.java;h=fd2684db4c0ce6b06aa9392476b294a97ceb692d;hb=6804ead7f7e54ff34b257e10e381dc52d5a61b06;hp=758fd6366b7b7f40d1b3967bcc24bdcb8f4d9313;hpb=6b70b8b6bb4e8eae8159ec966847092d0b1deab3;p=fw%2Faltos diff --git a/altoslib/AltosState.java b/altoslib/AltosState.java index 758fd636..fd2684db 100644 --- a/altoslib/AltosState.java +++ b/altoslib/AltosState.java @@ -3,7 +3,8 @@ * * 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. + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,7 +20,9 @@ * Track flight state from telemetry or eeprom data stream */ -package org.altusmetrum.altoslib_3; +package org.altusmetrum.altoslib_11; + +import java.io.*; public class AltosState implements Cloneable { @@ -29,8 +32,9 @@ public class AltosState implements Cloneable { public int set; + static final double filter_len = 2.0; static final double ascent_filter_len = 0.5; - static final double descent_filter_len = 0.5; + static final double descent_filter_len = 5.0; /* derived data */ @@ -44,25 +48,28 @@ public class AltosState implements Cloneable { public int boost_tick; class AltosValue { - private double value; - private double prev_value; + double value; + double prev_value; private double max_value; private double set_time; private double prev_set_time; + boolean can_max() { return true; } + void set(double new_value, double time) { if (new_value != AltosLib.MISSING) { value = new_value; - if (max_value == AltosLib.MISSING || value > max_value) { + if (can_max() && (max_value == AltosLib.MISSING || value > max_value)) max_value = value; - } set_time = time; } } void set_filtered(double new_value, double time) { - if (prev_value != AltosLib.MISSING) - new_value = (prev_value * 15.0 + new_value) / 16.0; + if (prev_value != AltosLib.MISSING) { + double f = 1/Math.exp((time - prev_set_time) / filter_len); + new_value = f * new_value + (1-f) * prev_value; + } set(new_value, time); } @@ -108,7 +115,7 @@ public class AltosState implements Cloneable { void set_derivative(AltosValue in) { double n = in.rate(); - + if (n == AltosLib.MISSING) return; @@ -123,7 +130,7 @@ public class AltosState implements Cloneable { /* Clip changes to reduce noise */ double ddt = in.time() - pt; double ddv = (n - p) / ddt; - + final double max = 100000; /* 100gs */ @@ -176,11 +183,27 @@ public class AltosState implements Cloneable { prev_value = AltosLib.MISSING; max_value = AltosLib.MISSING; } + } class AltosCValue { - AltosValue measured; - AltosValue computed; + + class AltosIValue extends AltosValue { + boolean can_max() { + return c_can_max(); + } + + AltosIValue() { + super(); + } + }; + + public AltosIValue measured; + public AltosIValue computed; + + boolean can_max() { return true; } + + boolean c_can_max() { return can_max(); } double value() { double v = measured.value(); @@ -246,11 +269,11 @@ public class AltosState implements Cloneable { void set_integral(AltosValue in) { computed.set_integral(in); } - + void set_integral(AltosCValue in) { set_integral(in.altos_value()); } - + void copy(AltosCValue old) { measured.copy(old.measured); computed.copy(old.computed); @@ -261,15 +284,16 @@ public class AltosState implements Cloneable { computed.finish_update(); } - AltosCValue() { - measured = new AltosValue(); - computed = new AltosValue(); + public AltosCValue() { + measured = new AltosIValue(); + computed = new AltosIValue(); } } - public int state; + private int state; public int flight; public int serial; + public int altitude_32; public int receiver_serial; public boolean landed; public boolean ascent; /* going up? */ @@ -311,6 +335,10 @@ public class AltosState implements Cloneable { pad_alt = value(); gps_altitude.set_gps_height(); } + + AltosGpsGroundAltitude() { + super(); + } } private AltosGpsGroundAltitude gps_ground_altitude; @@ -334,10 +362,14 @@ public class AltosState implements Cloneable { super.set_measured(p, time); ground_altitude.set_computed(pressure_to_altitude(p), time); } + + AltosGroundPressure () { + super(); + } } private AltosGroundPressure ground_pressure; - + public double ground_pressure() { return ground_pressure.value(); } @@ -364,6 +396,10 @@ public class AltosState implements Cloneable { set_speed(measured); set |= set_position; } + + AltosAltitude() { + super(); + } } private AltosAltitude altitude; @@ -384,10 +420,19 @@ public class AltosState implements Cloneable { super.set(a, t); set_gps_height(); } + + AltosGpsAltitude() { + super(); + } } private AltosGpsAltitude gps_altitude; + private AltosValue gps_ground_speed; + private AltosValue gps_ascent_rate; + private AltosValue gps_course; + private AltosValue gps_speed; + public double altitude() { double a = altitude.value(); if (a != AltosLib.MISSING) @@ -418,6 +463,34 @@ public class AltosState implements Cloneable { gps_altitude.set(new_gps_altitude, time); } + public double gps_ground_speed() { + return gps_ground_speed.value(); + } + + public double max_gps_ground_speed() { + return gps_ground_speed.max(); + } + + public double gps_ascent_rate() { + return gps_ascent_rate.value(); + } + + public double max_gps_ascent_rate() { + return gps_ascent_rate.max(); + } + + public double gps_course() { + return gps_course.value(); + } + + public double gps_speed() { + return gps_speed.value(); + } + + public double max_gps_speed() { + return gps_speed.max(); + } + class AltosPressure extends AltosValue { void set(double p, double time) { super.set(p, time); @@ -426,6 +499,10 @@ public class AltosState implements Cloneable { double a = pressure_to_altitude(p); altitude.set_computed(a, time); } + + AltosPressure() { + super(); + } } private AltosPressure pressure; @@ -438,11 +515,7 @@ public class AltosState implements Cloneable { pressure.set(p, time); } - public double height() { - double k = kalman_height.value(); - if (k != AltosLib.MISSING) - return k; - + public double baro_height() { double a = altitude(); double g = ground_altitude(); if (a != AltosLib.MISSING && g != AltosLib.MISSING) @@ -450,6 +523,18 @@ public class AltosState implements Cloneable { return AltosLib.MISSING; } + public double height() { + double k = kalman_height.value(); + if (k != AltosLib.MISSING) + return k; + + double b = baro_height(); + if (b != AltosLib.MISSING) + return b; + + return gps_height(); + } + public double max_height() { double k = kalman_height.max(); if (k != AltosLib.MISSING) @@ -459,7 +544,7 @@ public class AltosState implements Cloneable { double g = ground_altitude(); if (a != AltosLib.MISSING && g != AltosLib.MISSING) return a - g; - return AltosLib.MISSING; + return max_gps_height(); } public double gps_height() { @@ -481,7 +566,11 @@ public class AltosState implements Cloneable { } class AltosSpeed extends AltosCValue { - + + boolean can_max() { + return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless; + } + void set_accel() { acceleration.set_derivative(this); } @@ -500,6 +589,10 @@ public class AltosState implements Cloneable { super.set_measured(new_value, time); set_accel(); } + + AltosSpeed() { + super(); + } } private AltosSpeed speed; @@ -508,22 +601,43 @@ public class AltosState implements Cloneable { double v = kalman_speed.value(); if (v != AltosLib.MISSING) return v; - return speed.value(); + v = speed.value(); + if (v != AltosLib.MISSING) + return v; + v = gps_speed(); + if (v != AltosLib.MISSING) + return v; + return AltosLib.MISSING; } public double max_speed() { double v = kalman_speed.max(); if (v != AltosLib.MISSING) return v; - return speed.max(); + v = speed.max(); + if (v != AltosLib.MISSING) + return v; + v = max_gps_speed(); + if (v != AltosLib.MISSING) + return v; + return AltosLib.MISSING; } class AltosAccel extends AltosCValue { + + boolean can_max() { + return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless; + } + void set_measured(double a, double time) { super.set_measured(a, time); if (ascent) speed.set_integral(this.measured); } + + AltosAccel() { + super(); + } } AltosAccel acceleration; @@ -536,10 +650,10 @@ public class AltosState implements Cloneable { return acceleration.max(); } - public AltosValue orient; + public AltosCValue orient; public void set_orient(double new_orient) { - orient.set(new_orient, time); + orient.set_measured(new_orient, time); } public double orient() { @@ -604,11 +718,15 @@ public class AltosState implements Cloneable { public double ground_accel_avg; public int log_format; + public int log_space; + public String product; public AltosMs5607 baro; public AltosCompanion companion; + public int pyro_fired; + public void set_npad(int npad) { this.npad = npad; gps_waiting = MIN_PAD_SAMPLES - npad; @@ -646,7 +764,7 @@ public class AltosState implements Cloneable { pressure = new AltosPressure(); speed = new AltosSpeed(); acceleration = new AltosAccel(); - orient = new AltosValue(); + orient = new AltosCValue(); temperature = AltosLib.MISSING; battery_voltage = AltosLib.MISSING; @@ -666,7 +784,24 @@ public class AltosState implements Cloneable { gps_pending = false; imu = null; + last_imu_time = AltosLib.MISSING; + rotation = null; + ground_rotation = null; + mag = null; + accel_zero_along = AltosLib.MISSING; + accel_zero_across = AltosLib.MISSING; + accel_zero_through = AltosLib.MISSING; + + accel_ground_along = AltosLib.MISSING; + accel_ground_across = AltosLib.MISSING; + accel_ground_through = AltosLib.MISSING; + + pad_orientation = AltosLib.MISSING; + + gyro_zero_roll = AltosLib.MISSING; + gyro_zero_pitch = AltosLib.MISSING; + gyro_zero_yaw = AltosLib.MISSING; set_npad(0); ngps = 0; @@ -682,11 +817,16 @@ public class AltosState implements Cloneable { gps_altitude = new AltosGpsAltitude(); gps_ground_altitude = new AltosGpsGroundAltitude(); + gps_ground_speed = new AltosValue(); + gps_speed = new AltosValue(); + gps_ascent_rate = new AltosValue(); + gps_course = new AltosValue(); speak_tick = AltosLib.MISSING; speak_altitude = AltosLib.MISSING; callsign = null; + firmware_version = null; accel_plus_g = AltosLib.MISSING; accel_minus_g = AltosLib.MISSING; @@ -696,11 +836,16 @@ public class AltosState implements Cloneable { ground_accel_avg = AltosLib.MISSING; log_format = AltosLib.MISSING; + log_space = AltosLib.MISSING; + product = null; serial = AltosLib.MISSING; receiver_serial = AltosLib.MISSING; + altitude_32 = AltosLib.MISSING; baro = null; companion = null; + + pyro_fired = 0; } void finish_update() { @@ -729,7 +874,7 @@ public class AltosState implements Cloneable { time = old.time; time_change = old.time_change; prev_time = old.time; - + tick = old.tick; prev_tick = old.tick; boost_tick = old.boost_tick; @@ -747,7 +892,7 @@ public class AltosState implements Cloneable { apogee_delay = old.apogee_delay; main_deploy = old.main_deploy; flight_log_max = old.flight_log_max; - + set = 0; ground_pressure.copy(old.ground_pressure); @@ -785,6 +930,27 @@ public class AltosState implements Cloneable { imu = old.imu.clone(); else imu = null; + last_imu_time = old.last_imu_time; + + if (old.rotation != null) + rotation = new AltosRotation (old.rotation); + + if (old.ground_rotation != null) { + ground_rotation = new AltosRotation(old.ground_rotation); + } + + accel_zero_along = old.accel_zero_along; + accel_zero_across = old.accel_zero_across; + accel_zero_through = old.accel_zero_through; + + accel_ground_along = old.accel_ground_along; + accel_ground_across = old.accel_ground_across; + accel_ground_through = old.accel_ground_through; + pad_orientation = old.pad_orientation; + + gyro_zero_roll = old.gyro_zero_roll; + gyro_zero_pitch = old.gyro_zero_pitch; + gyro_zero_yaw = old.gyro_zero_yaw; if (old.mag != null) mag = old.mag.clone(); @@ -808,6 +974,10 @@ public class AltosState implements Cloneable { gps_altitude.copy(old.gps_altitude); gps_ground_altitude.copy(old.gps_ground_altitude); + gps_ground_speed.copy(old.gps_ground_speed); + gps_ascent_rate.copy(old.gps_ascent_rate); + gps_course.copy(old.gps_course); + gps_speed.copy(old.gps_speed); pad_lat = old.pad_lat; pad_lon = old.pad_lon; @@ -817,6 +987,7 @@ public class AltosState implements Cloneable { speak_altitude = old.speak_altitude; callsign = old.callsign; + firmware_version = old.firmware_version; accel_plus_g = old.accel_plus_g; accel_minus_g = old.accel_minus_g; @@ -825,28 +996,33 @@ public class AltosState implements Cloneable { ground_accel_avg = old.ground_accel_avg; log_format = old.log_format; + log_space = old.log_space; + product = old.product; serial = old.serial; receiver_serial = old.receiver_serial; + altitude_32 = old.altitude_32; baro = old.baro; companion = old.companion; + + pyro_fired = old.pyro_fired; } - + void update_time() { } void update_gps() { - elevation = 0; - range = -1; + elevation = AltosLib.MISSING; + range = AltosLib.MISSING; if (gps == null) return; if (gps.locked && gps.nsat >= 4) { /* Track consecutive 'good' gps reports, waiting for 10 of them */ - if (state == AltosLib.ao_flight_pad) { + if (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_stateless) { set_npad(npad+1); - if (pad_lat != AltosLib.MISSING) { + if (pad_lat != AltosLib.MISSING && (npad < 10 || state == AltosLib.ao_flight_pad)) { pad_lat = (pad_lat * 31 + gps.lat) / 32; pad_lon = (pad_lon * 31 + gps.lon) / 32; gps_ground_altitude.set_filtered(gps.alt, time); @@ -858,6 +1034,15 @@ public class AltosState implements Cloneable { gps_ground_altitude.set(gps.alt, time); } gps_altitude.set(gps.alt, time); + if (gps.climb_rate != AltosLib.MISSING) + gps_ascent_rate.set(gps.climb_rate, time); + if (gps.ground_speed != AltosLib.MISSING) + gps_ground_speed.set(gps.ground_speed, time); + if (gps.climb_rate != AltosLib.MISSING && gps.ground_speed != AltosLib.MISSING) + gps_speed.set(Math.sqrt(gps.ground_speed * gps.ground_speed + + gps.climb_rate * gps.climb_rate), time); + if (gps.course != AltosLib.MISSING) + gps_course.set(gps.course, time); } if (gps.lat != 0 && gps.lon != 0 && pad_lat != AltosLib.MISSING && @@ -895,6 +1080,10 @@ public class AltosState implements Cloneable { return AltosLib.state_name(state); } + public void set_product(String product) { + this.product = product; + } + public void set_state(int state) { if (state != AltosLib.ao_flight_invalid) { this.state = state; @@ -902,18 +1091,42 @@ public class AltosState implements Cloneable { state <= AltosLib.ao_flight_coast); boost = (AltosLib.ao_flight_boost == state); } + } + public int state() { + return state; } public void set_device_type(int device_type) { this.device_type = device_type; + switch (device_type) { + case AltosLib.product_telegps: + this.state = AltosLib.ao_flight_stateless; + break; + } } - public void set_config(int major, int minor, int apogee_delay, int main_deploy, int flight_log_max) { - config_major = major; - config_minor = minor; + public void set_log_format(int log_format) { + this.log_format = log_format; + switch (log_format) { + case AltosLib.AO_LOG_FORMAT_TELEGPS: + this.state = AltosLib.ao_flight_stateless; + break; + } + } + + public void set_log_space(int log_space) { + this.log_space = log_space; + } + + public void set_flight_params(int apogee_delay, int main_deploy) { this.apogee_delay = apogee_delay; this.main_deploy = main_deploy; + } + + public void set_config(int major, int minor, int flight_log_max) { + config_major = major; + config_minor = minor; this.flight_log_max = flight_log_max; } @@ -925,15 +1138,27 @@ public class AltosState implements Cloneable { firmware_version = version; } + public int compare_version(String other_version) { + if (firmware_version == null) + return AltosLib.MISSING; + return AltosLib.compare_version(firmware_version, other_version); + } + + private void re_init() { + int bt = boost_tick; + int rs = receiver_serial; + init(); + boost_tick = bt; + receiver_serial = rs; + } + public void set_flight(int flight) { /* When the flight changes, reset the state */ - if (flight != AltosLib.MISSING && flight != 0) { + if (flight != AltosLib.MISSING) { if (this.flight != AltosLib.MISSING && this.flight != flight) { - int bt = boost_tick; - init(); - boost_tick = bt; + re_init(); } this.flight = flight; } @@ -944,9 +1169,7 @@ public class AltosState implements Cloneable { if (serial != AltosLib.MISSING) { if (this.serial != AltosLib.MISSING && this.serial != serial) { - int bt = boost_tick; - init(); - boost_tick = bt; + re_init(); } this.serial = serial; } @@ -957,6 +1180,15 @@ public class AltosState implements Cloneable { receiver_serial = serial; } + public boolean altitude_32() { + return altitude_32 == 1; + } + + public void set_altitude_32(int altitude_32) { + if (altitude_32 != AltosLib.MISSING) + this.altitude_32 = altitude_32; + } + public int rssi() { if (rssi == AltosLib.MISSING) return 0; @@ -983,16 +1215,170 @@ public class AltosState implements Cloneable { } } + + public double accel_zero_along; + public double accel_zero_across; + public double accel_zero_through; + + public AltosRotation rotation; + public AltosRotation ground_rotation; + + public void set_accel_zero(double zero_along, double zero_across, double zero_through) { + if (zero_along != AltosLib.MISSING) { + accel_zero_along = zero_along; + accel_zero_across = zero_across; + accel_zero_through = zero_through; + } + } + + public int pad_orientation; + + public double accel_ground_along, accel_ground_across, accel_ground_through; + + void update_pad_rotation() { + if (pad_orientation != AltosLib.MISSING && accel_ground_along != AltosLib.MISSING) { + rotation = new AltosRotation(AltosIMU.convert_accel(accel_ground_across - accel_zero_across), + AltosIMU.convert_accel(accel_ground_through - accel_zero_through), + AltosIMU.convert_accel(accel_ground_along - accel_zero_along), + pad_orientation); + ground_rotation = rotation; + orient.set_computed(rotation.tilt(), time); + } + } + + public void set_accel_ground(double ground_along, double ground_across, double ground_through) { + accel_ground_along = ground_along; + accel_ground_across = ground_across; + accel_ground_through = ground_through; + update_pad_rotation(); + } + + public void set_pad_orientation(int pad_orientation) { + this.pad_orientation = pad_orientation; + update_pad_rotation(); + } + + public double gyro_zero_roll; + public double gyro_zero_pitch; + public double gyro_zero_yaw; + + public void set_gyro_zero(double roll, double pitch, double yaw) { + if (roll != AltosLib.MISSING) { + gyro_zero_roll = roll; + gyro_zero_pitch = pitch; + gyro_zero_yaw = yaw; + } + } + + public double last_imu_time; + + private double radians(double degrees) { + if (degrees == AltosLib.MISSING) + return AltosLib.MISSING; + return degrees * Math.PI / 180.0; + } + + private void update_orient() { + if (last_imu_time != AltosLib.MISSING) { + double t = time - last_imu_time; + + double pitch = radians(gyro_pitch()); + double yaw = radians(gyro_yaw()); + double roll = radians(gyro_roll()); + + if (t > 0 & pitch != AltosLib.MISSING && rotation != null) { + rotation.rotate(t, pitch, yaw, roll); + orient.set_computed(rotation.tilt(), time); + } + } + last_imu_time = time; + } + public void set_imu(AltosIMU imu) { if (imu != null) imu = imu.clone(); this.imu = imu; + update_orient(); + } + + private double gyro_zero_overflow(double first) { + double v = first / 128.0; + if (v < 0) + v = Math.ceil(v); + else + v = Math.floor(v); + return v * 128.0; + } + + public void check_imu_wrap(AltosIMU imu) { + if (this.imu == null) { + gyro_zero_roll += gyro_zero_overflow(imu.gyro_roll); + gyro_zero_pitch += gyro_zero_overflow(imu.gyro_pitch); + gyro_zero_yaw += gyro_zero_overflow(imu.gyro_yaw); + } + } + + public double accel_along() { + if (imu != null && accel_zero_along != AltosLib.MISSING) + return AltosIMU.convert_accel(imu.accel_along - accel_zero_along); + return AltosLib.MISSING; + } + + public double accel_across() { + if (imu != null && accel_zero_across != AltosLib.MISSING) + return AltosIMU.convert_accel(imu.accel_across - accel_zero_across); + return AltosLib.MISSING; + } + + public double accel_through() { + if (imu != null && accel_zero_through != AltosLib.MISSING) + return AltosIMU.convert_accel(imu.accel_through - accel_zero_through); + return AltosLib.MISSING; + } + + public double gyro_roll() { + if (imu != null && gyro_zero_roll != AltosLib.MISSING) { + return AltosIMU.convert_gyro(imu.gyro_roll - gyro_zero_roll); + } + return AltosLib.MISSING; + } + + public double gyro_pitch() { + if (imu != null && gyro_zero_pitch != AltosLib.MISSING) { + return AltosIMU.convert_gyro(imu.gyro_pitch - gyro_zero_pitch); + } + return AltosLib.MISSING; + } + + public double gyro_yaw() { + if (imu != null && gyro_zero_yaw != AltosLib.MISSING) { + return AltosIMU.convert_gyro(imu.gyro_yaw - gyro_zero_yaw); + } + return AltosLib.MISSING; } public void set_mag(AltosMag mag) { this.mag = mag.clone(); } + public double mag_along() { + if (mag != null) + return AltosMag.convert_gauss(mag.along); + return AltosLib.MISSING; + } + + public double mag_across() { + if (mag != null) + return AltosMag.convert_gauss(mag.across); + return AltosLib.MISSING; + } + + public double mag_through() { + if (mag != null) + return AltosMag.convert_gauss(mag.through); + return AltosLib.MISSING; + } + public AltosMs5607 make_baro() { if (baro == null) baro = new AltosMs5607(); @@ -1017,11 +1403,6 @@ public class AltosState implements Cloneable { } } - public void make_companion (int nchannels) { - if (companion == null) - companion = new AltosCompanion(nchannels); - } - public void set_companion(AltosCompanion companion) { this.companion = companion; } @@ -1104,6 +1485,10 @@ public class AltosState implements Cloneable { this.ignitor_voltage = voltage; } + public void set_pyro_fired(int fired) { + this.pyro_fired = fired; + } + public double time_since_boost() { if (tick == AltosLib.MISSING) return 0.0; @@ -1139,6 +1524,31 @@ public class AltosState implements Cloneable { public AltosState clone() { AltosState s = new AltosState(); s.copy(this); + + /* Code to test state save/restore. Enable only for that purpose + */ + if (false) { + AltosJson json = new AltosJson(this); + String onetrip = json.toPrettyString(); + AltosJson back = AltosJson.fromString(onetrip); + AltosState tripstate = (AltosState) back.make(this.getClass()); + AltosJson tripjson = new AltosJson(tripstate); + String twotrip = tripjson.toPrettyString(); + + if (!onetrip.equals(twotrip)) { + try { + FileWriter one_file = new FileWriter("one.json", true); + one_file.write(onetrip); + one_file.flush(); + FileWriter two_file = new FileWriter("two.json", true); + two_file.write(twotrip); + two_file.flush(); + } catch (Exception e) { + } + System.out.printf("json error\n"); + System.exit(1); + } + } return s; }