From: Keith Packard Date: Fri, 27 Aug 2010 17:58:55 +0000 (-0700) Subject: altosui: add elevation and range information X-Git-Tag: debian/0.6+373+gcf65c6b~3 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=63bd34cd1b5a411489e8c3ab377f0fe0eec11f67;hp=2923cf5057f9cef110dd547d8677ea5b60e00796 altosui: add elevation and range information Signed-off-by: Keith Packard --- diff --git a/ao-tools/altosui/AltosCSV.java b/ao-tools/altosui/AltosCSV.java index db50e7a2..4ce8e30e 100644 --- a/ao-tools/altosui/AltosCSV.java +++ b/ao-tools/altosui/AltosCSV.java @@ -76,7 +76,9 @@ public class AltosCSV { * minute (0-59) * second (0-59) * from_pad_dist (m) - * from_pad_dir (deg true) + * from_pad_azimuth (deg true) + * from_pad_range (m) + * from_pad_elevation (deg from horizon) * * GPS Sat data * hdop @@ -121,7 +123,7 @@ public class AltosCSV { } void write_gps_header() { - out.printf("connected locked nsat latitude longitude altitude year month day hour minute second pad_dist pad_dir"); + out.printf("connected locked nsat latitude longitude altitude year month day hour minute second pad_dist pad_range pad_az pad_el"); } void write_gps(AltosRecord record) { @@ -133,7 +135,7 @@ public class AltosCSV { if (from_pad == null) from_pad = new AltosGreatCircle(); - out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%4.0f", + out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f", gps.connected?1:0, gps.locked?1:0, gps.nsat, @@ -147,7 +149,9 @@ public class AltosCSV { gps.minute, gps.second, from_pad.distance, - from_pad.bearing); + state.range, + from_pad.bearing, + state.elevation); } void write_header() { diff --git a/ao-tools/altosui/AltosEepromReader.java b/ao-tools/altosui/AltosEepromReader.java index 3f2d4c62..0705d44e 100644 --- a/ao-tools/altosui/AltosEepromReader.java +++ b/ao-tools/altosui/AltosEepromReader.java @@ -42,7 +42,7 @@ import altosui.AltosEepromMonitor; */ class AltosOrderedRecord extends AltosEepromRecord implements Comparable { - int index; + public int index; public AltosOrderedRecord(String line, int in_index, int prev_tick) throws ParseException { @@ -56,6 +56,11 @@ class AltosOrderedRecord extends AltosEepromRecord implements Comparable> Altos.AO_GPS_NUM_SAT_SHIFT; + System.out.printf("GPS %2d:%02d:%02d%s%s%s %d\n", + state.gps.hour, state.gps.minute, state.gps.second, + state.gps.connected ? " connected" : "", + state.gps.locked ? " locked" : "", + state.gps.date_valid ? " date_valid" : "", + state.gps.nsat); break; case Altos.AO_LOG_GPS_LAT: int lat32 = record.a | (record.b << 16); @@ -267,6 +282,38 @@ public class AltosEepromReader extends AltosReader { } } + /* + * Given an AO_LOG_GPS_TIME record with correct time, and one + * missing time, rewrite the missing time values with the good + * ones, assuming that the difference between them is 'diff' seconds + */ + void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) { + + int diff = (bad.tick - good.tick + 50) / 100; + + int hour = (good.a & 0xff); + int minute = (good.a >> 8); + int second = (good.b & 0xff); + int flags = (good.b >> 8); + int seconds = hour * 3600 + minute * 60 + second; + + int new_seconds = seconds + diff; + if (new_seconds < 0) + new_seconds += 24 * 3600; + int new_second = (new_seconds % 60); + int new_minutes = (new_seconds / 60); + int new_minute = (new_minutes % 60); + int new_hours = (new_minutes / 60); + int new_hour = (new_hours % 24); + + System.out.printf("Synthesizing time good %2d:%02d:%02d bad %2d:%02d:%02d\n", + hour, minute, second, + new_hour, new_minute, new_second); + + bad.a = new_hour + (new_minute << 8); + bad.b = new_second + (flags << 8); + } + /* * Read the whole file, dumping records into a RB tree so * we can enumerate them in time order -- the eeprom data @@ -282,9 +329,13 @@ public class AltosEepromReader extends AltosReader { seen = 0; records = new TreeSet(); + AltosOrderedRecord last_gps_time = null; + int index = 0; int tick = 0; + boolean missing_time = false; + try { for (;;) { String line = AltosRecord.gets(input); @@ -300,6 +351,52 @@ public class AltosEepromReader extends AltosReader { saw_boost = true; boost_tick = tick; } + + /* Two firmware bugs caused the loss of some GPS data. + * The flight date would never be recorded, and often + * the flight time would get overwritten by another + * record. Detect the loss of the GPS date and fix up the + * missing time records + */ + if (record.cmd == Altos.AO_LOG_GPS_DATE) + saw_gps_date = true; + + /* go back and fix up any missing time values */ + if (record.cmd == Altos.AO_LOG_GPS_TIME) { + last_gps_time = record; + if (missing_time) { + System.out.printf("Going back to clean up broken GPS time records\n"); + Iterator iterator = records.iterator(); + while (iterator.hasNext()) { + AltosOrderedRecord old = iterator.next(); + if (old.cmd == Altos.AO_LOG_GPS_TIME) { + System.out.printf("Old time record %d, %d\n", old.a, old.b); + } + if (old.cmd == Altos.AO_LOG_GPS_TIME && + old.a == -1 && old.b == -1) + { + update_time(record, old); + } + } + missing_time = false; + } + } + + if (record.cmd == Altos.AO_LOG_GPS_LAT) { + if (last_gps_time == null || last_gps_time.tick != record.tick) { + AltosOrderedRecord add_gps_time = new AltosOrderedRecord(Altos.AO_LOG_GPS_TIME, + record.tick, + -1, -1, index-1); + if (last_gps_time != null) + update_time(last_gps_time, add_gps_time); + else { + System.out.printf("early GPS missing time\n"); + missing_time = true; + } + records.add(add_gps_time); + record.index = index++; + } + } records.add(record); } } catch (IOException io) { diff --git a/ao-tools/altosui/AltosEepromRecord.java b/ao-tools/altosui/AltosEepromRecord.java index 86ac1fd2..4d0817ab 100644 --- a/ao-tools/altosui/AltosEepromRecord.java +++ b/ao-tools/altosui/AltosEepromRecord.java @@ -44,7 +44,7 @@ public class AltosEepromRecord { public int tick; public int a; public int b; - String data; + public String data; public boolean tick_valid; public AltosEepromRecord (String line) throws ParseException { @@ -107,4 +107,11 @@ public class AltosEepromRecord { } } + public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) { + tick_valid = true; + cmd = in_cmd; + tick = in_tick; + a = in_a; + b = in_b; + } } diff --git a/ao-tools/altosui/AltosState.java b/ao-tools/altosui/AltosState.java index c13dfe68..3ef00f35 100644 --- a/ao-tools/altosui/AltosState.java +++ b/ao-tools/altosui/AltosState.java @@ -64,6 +64,8 @@ public class AltosState { boolean gps_ready; AltosGreatCircle from_pad; + double elevation; /* from pad */ + double range; /* total distance */ double gps_height; @@ -124,7 +126,7 @@ public class AltosState { } if (state == Altos.ao_flight_pad) { - if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) { + if (data.gps != null && data.gps.locked) { npad++; if (npad > 1) { /* filter pad position */ @@ -161,11 +163,18 @@ public class AltosState { if (data.gps != null) { if (gps == null || !gps.locked || data.gps.locked) gps = data.gps; - if (npad > 0 && gps.locked) + if (npad > 0 && gps.locked) { from_pad = new AltosGreatCircle(pad_lat, pad_lon, gps.lat, gps.lon); + } } + elevation = 0; + range = -1; if (npad > 0) { gps_height = gps.alt - pad_alt; + if (from_pad != null) { + elevation = Math.atan2(height, from_pad.distance) * 180 / Math.PI; + range = Math.sqrt(height * height + from_pad.distance * from_pad.distance); + } } else { gps_height = 0; } diff --git a/ao-tools/altosui/AltosUI.java b/ao-tools/altosui/AltosUI.java index 4f3b5dde..5b48e26f 100644 --- a/ao-tools/altosui/AltosUI.java +++ b/ao-tools/altosui/AltosUI.java @@ -264,7 +264,7 @@ public class AltosUI extends JFrame { private AltosState state; int reported_landing; - public void report(boolean last) { + public synchronized void report(boolean last) { if (state == null) return; @@ -278,7 +278,16 @@ public class AltosUI extends JFrame { } /* If the rocket isn't on the pad, then report height */ - if (state.state > Altos.ao_flight_pad) { + if (Altos.ao_flight_drogue <= state.state && + state.state < Altos.ao_flight_landed && + state.range >= 0) + { + voice.speak("Height %d, bearing %d, elevation %d, range %d.\n", + (int) (state.height + 0.5), + (int) (state.from_pad.bearing + 0.5), + (int) (state.elevation + 0.5), + (int) (state.range + 0.5)); + } else if (state.state > Altos.ao_flight_pad) { voice.speak("%d meters", (int) (state.height + 0.5)); } else { reported_landing = 0; @@ -288,7 +297,7 @@ public class AltosUI extends JFrame { * either we've got a landed report or we haven't heard from it in * a long time */ - if (!state.ascent && + if (state.state >= Altos.ao_flight_drogue && (last || System.currentTimeMillis() - state.report_time >= 15000 || state.state == Altos.ao_flight_landed)) @@ -298,7 +307,7 @@ public class AltosUI extends JFrame { else voice.speak("rocket may have crashed"); if (state.from_pad != null) - voice.speak("bearing %d degrees, range %d meters", + voice.speak("Bearing %d degrees, range %d meters.", (int) (state.from_pad.bearing + 0.5), (int) (state.from_pad.distance + 0.5)); ++reported_landing; @@ -311,7 +320,7 @@ public class AltosUI extends JFrame { state = null; try { for (;;) { - Thread.sleep(10000); + Thread.sleep(20000); report(false); } } catch (InterruptedException ie) { @@ -319,7 +328,10 @@ public class AltosUI extends JFrame { } public void notice(AltosState new_state) { + AltosState old_state = state; state = new_state; + if (old_state != null && old_state.state != state.state) + report(false); } }