kopia lustrzana https://github.com/cyoung/stratux
Merge branch 'ahrs_dev'
commit
a998ede17b
|
@ -247,11 +247,11 @@ func makeOwnshipReport() bool {
|
|||
msg[9] = tmp[1] // Longitude.
|
||||
msg[10] = tmp[2] // Longitude.
|
||||
} else {
|
||||
tmp = makeLatLng(mySituation.Lat)
|
||||
tmp = makeLatLng(mySituation.GPSLatitude)
|
||||
msg[5] = tmp[0] // Latitude.
|
||||
msg[6] = tmp[1] // Latitude.
|
||||
msg[7] = tmp[2] // Latitude.
|
||||
tmp = makeLatLng(mySituation.Lng)
|
||||
tmp = makeLatLng(mySituation.GPSLongitude)
|
||||
msg[8] = tmp[0] // Longitude.
|
||||
msg[9] = tmp[1] // Longitude.
|
||||
msg[10] = tmp[2] // Longitude.
|
||||
|
@ -267,9 +267,9 @@ func makeOwnshipReport() bool {
|
|||
if selfOwnshipValid {
|
||||
altf = float64(curOwnship.Alt)
|
||||
} else if isTempPressValid() {
|
||||
altf = float64(mySituation.Pressure_alt)
|
||||
altf = float64(mySituation.BaroPressureAltitude)
|
||||
} else {
|
||||
altf = float64(mySituation.Alt) //FIXME: Pass GPS altitude if PA not available. **WORKAROUND FOR FF**
|
||||
altf = float64(mySituation.GPSAltitudeMSL) //FIXME: Pass GPS altitude if PA not available. **WORKAROUND FOR FF**
|
||||
}
|
||||
|
||||
altf = (altf + 1000) / 25
|
||||
|
@ -282,13 +282,13 @@ func makeOwnshipReport() bool {
|
|||
msg[12] = msg[12] | 0x09 // "Airborne" + "True Track"
|
||||
}
|
||||
|
||||
msg[13] = byte(0x80 | (mySituation.NACp & 0x0F)) //Set NIC = 8 and use NACp from gps.go.
|
||||
msg[13] = byte(0x80 | (mySituation.GPSNACp & 0x0F)) //Set NIC = 8 and use NACp from gps.go.
|
||||
|
||||
gdSpeed := uint16(0) // 1kt resolution.
|
||||
if selfOwnshipValid && curOwnship.Speed_valid {
|
||||
gdSpeed = curOwnship.Speed
|
||||
} else if isGPSGroundTrackValid() {
|
||||
gdSpeed = uint16(mySituation.GroundSpeed + 0.5)
|
||||
gdSpeed = uint16(mySituation.GPSGroundSpeed + 0.5)
|
||||
}
|
||||
|
||||
// gdSpeed should fit in 12 bits.
|
||||
|
@ -306,7 +306,7 @@ func makeOwnshipReport() bool {
|
|||
if selfOwnshipValid {
|
||||
groundTrack = float32(curOwnship.Track)
|
||||
} else if isGPSGroundTrackValid() {
|
||||
groundTrack = mySituation.TrueCourse
|
||||
groundTrack = mySituation.GPSTrueCourse
|
||||
}
|
||||
|
||||
tempTrack := groundTrack + TRACK_RESOLUTION/2 // offset by half the 8-bit resolution to minimize binning error
|
||||
|
@ -356,10 +356,10 @@ func makeOwnshipGeometricAltitudeReport() bool {
|
|||
}
|
||||
msg := make([]byte, 5)
|
||||
// See p.28.
|
||||
msg[0] = 0x0B // Message type "Ownship Geo Alt".
|
||||
alt := int16(mySituation.Alt / 5) // GPS Altitude, encoded to 16-bit int using 5-foot resolution
|
||||
msg[1] = byte(alt >> 8) // Altitude.
|
||||
msg[2] = byte(alt & 0x00FF) // Altitude.
|
||||
msg[0] = 0x0B // Message type "Ownship Geo Alt".
|
||||
alt := int16(mySituation.GPSAltitudeMSL / 5) // GPS Altitude, encoded to 16-bit int using 5-foot resolution
|
||||
msg[1] = byte(alt >> 8) // Altitude.
|
||||
msg[2] = byte(alt & 0x00FF) // Altitude.
|
||||
|
||||
//TODO: "Figure of Merit". 0x7FFF "Not available".
|
||||
msg[3] = 0x00
|
||||
|
@ -425,7 +425,7 @@ func makeStratuxStatus() []byte {
|
|||
// Valid and enabled flags.
|
||||
// Valid/Enabled: GPS portion.
|
||||
if isGPSValid() {
|
||||
switch mySituation.Quality {
|
||||
switch mySituation.GPSFixQuality {
|
||||
case 1: // 1 = 3D GPS.
|
||||
msg[13] = 1
|
||||
case 2: // 2 = DGPS (SBAS /WAAS).
|
||||
|
@ -753,13 +753,13 @@ func cpuMonitor() {
|
|||
}
|
||||
|
||||
func updateStatus() {
|
||||
if mySituation.Quality == 2 {
|
||||
if mySituation.GPSFixQuality == 2 {
|
||||
globalStatus.GPS_solution = "GPS + SBAS (WAAS)"
|
||||
} else if mySituation.Quality == 1 {
|
||||
} else if mySituation.GPSFixQuality == 1 {
|
||||
globalStatus.GPS_solution = "3D GPS"
|
||||
} else if mySituation.Quality == 6 {
|
||||
} else if mySituation.GPSFixQuality == 6 {
|
||||
globalStatus.GPS_solution = "Dead Reckoning"
|
||||
} else if mySituation.Quality == 0 {
|
||||
} else if mySituation.GPSFixQuality == 0 {
|
||||
globalStatus.GPS_solution = "No Fix"
|
||||
} else {
|
||||
globalStatus.GPS_solution = "Unknown"
|
||||
|
@ -767,22 +767,22 @@ func updateStatus() {
|
|||
|
||||
if !(globalStatus.GPS_connected) || !(isGPSConnected()) { // isGPSConnected looks for valid NMEA messages. GPS_connected is set by gpsSerialReader and will immediately fail on disconnected USB devices, or in a few seconds after "blocked" comms on ttyAMA0.
|
||||
|
||||
mySituation.mu_Satellite.Lock()
|
||||
mySituation.muSatellite.Lock()
|
||||
Satellites = make(map[string]SatelliteInfo)
|
||||
mySituation.mu_Satellite.Unlock()
|
||||
mySituation.muSatellite.Unlock()
|
||||
|
||||
mySituation.Satellites = 0
|
||||
mySituation.SatellitesSeen = 0
|
||||
mySituation.SatellitesTracked = 0
|
||||
mySituation.Quality = 0
|
||||
mySituation.GPSSatellites = 0
|
||||
mySituation.GPSSatellitesSeen = 0
|
||||
mySituation.GPSSatellitesTracked = 0
|
||||
mySituation.GPSFixQuality = 0
|
||||
globalStatus.GPS_solution = "Disconnected"
|
||||
globalStatus.GPS_connected = false
|
||||
}
|
||||
|
||||
globalStatus.GPS_satellites_locked = mySituation.Satellites
|
||||
globalStatus.GPS_satellites_seen = mySituation.SatellitesSeen
|
||||
globalStatus.GPS_satellites_tracked = mySituation.SatellitesTracked
|
||||
globalStatus.GPS_position_accuracy = mySituation.Accuracy
|
||||
globalStatus.GPS_satellites_locked = mySituation.GPSSatellites
|
||||
globalStatus.GPS_satellites_seen = mySituation.GPSSatellitesSeen
|
||||
globalStatus.GPS_satellites_tracked = mySituation.GPSSatellitesTracked
|
||||
globalStatus.GPS_position_accuracy = mySituation.GPSHorizontalAccuracy
|
||||
|
||||
// Update Uptime value
|
||||
globalStatus.Uptime = int64(stratuxClock.Milliseconds)
|
||||
|
@ -1214,14 +1214,14 @@ func printStats() {
|
|||
log.Printf(" - UAT/min %s/%s [maxSS=%.02f%%], ES/min %s/%s, Total traffic targets tracked=%s", humanize.Comma(int64(globalStatus.UAT_messages_last_minute)), humanize.Comma(int64(globalStatus.UAT_messages_max)), float64(maxSignalStrength)/10.0, humanize.Comma(int64(globalStatus.ES_messages_last_minute)), humanize.Comma(int64(globalStatus.ES_messages_max)), humanize.Comma(int64(len(seenTraffic))))
|
||||
log.Printf(" - Network data messages sent: %d total, %d nonqueueable. Network data bytes sent: %d total, %d nonqueueable.\n", globalStatus.NetworkDataMessagesSent, globalStatus.NetworkDataMessagesSentNonqueueable, globalStatus.NetworkDataBytesSent, globalStatus.NetworkDataBytesSentNonqueueable)
|
||||
if globalSettings.GPS_Enabled {
|
||||
log.Printf(" - Last GPS fix: %s, GPS solution type: %d using %d satellites (%d/%d seen/tracked), NACp: %d, est accuracy %.02f m\n", stratuxClock.HumanizeTime(mySituation.LastFixLocalTime), mySituation.Quality, mySituation.Satellites, mySituation.SatellitesSeen, mySituation.SatellitesTracked, mySituation.NACp, mySituation.Accuracy)
|
||||
log.Printf(" - GPS vertical velocity: %.02f ft/sec; GPS vertical accuracy: %v m\n", mySituation.GPSVertVel, mySituation.AccuracyVert)
|
||||
log.Printf(" - Last GPS fix: %s, GPS solution type: %d using %d satellites (%d/%d seen/tracked), NACp: %d, est accuracy %.02f m\n", stratuxClock.HumanizeTime(mySituation.GPSLastFixLocalTime), mySituation.GPSFixQuality, mySituation.GPSSatellites, mySituation.GPSSatellitesSeen, mySituation.GPSSatellitesTracked, mySituation.GPSNACp, mySituation.GPSHorizontalAccuracy)
|
||||
log.Printf(" - GPS vertical velocity: %.02f ft/sec; GPS vertical accuracy: %v m\n", mySituation.GPSVerticalSpeed, mySituation.GPSVerticalAccuracy)
|
||||
}
|
||||
if globalSettings.IMU_Sensor_Enabled {
|
||||
log.Printf(" - Last IMU read: %s\n", stratuxClock.HumanizeTime(mySituation.LastAttitudeTime))
|
||||
log.Printf(" - Last IMU read: %s\n", stratuxClock.HumanizeTime(mySituation.AHRSLastAttitudeTime))
|
||||
}
|
||||
if globalSettings.BMP_Sensor_Enabled {
|
||||
log.Printf(" - Last BMP read: %s\n", stratuxClock.HumanizeTime(mySituation.LastTempPressTime))
|
||||
log.Printf(" - Last BMP read: %s\n", stratuxClock.HumanizeTime(mySituation.BaroLastMeasurementTime))
|
||||
}
|
||||
// Check if we're using more than 95% of the free space. If so, throw a warning (only once).
|
||||
if !diskUsageWarning && usage.Usage() > 0.95 {
|
||||
|
@ -1334,11 +1334,11 @@ func main() {
|
|||
stratuxClock = NewMonotonic() // Start our "stratux clock".
|
||||
|
||||
// Set up mySituation, do it here so logging JSON doesn't panic
|
||||
mySituation.mu_GPS = &sync.Mutex{}
|
||||
mySituation.mu_GPSPerf = &sync.Mutex{}
|
||||
mySituation.mu_Attitude = &sync.Mutex{}
|
||||
mySituation.mu_Pressure = &sync.Mutex{}
|
||||
mySituation.mu_Satellite = &sync.Mutex{}
|
||||
mySituation.muGPS = &sync.Mutex{}
|
||||
mySituation.muGPSPerformance = &sync.Mutex{}
|
||||
mySituation.muAttitude = &sync.Mutex{}
|
||||
mySituation.muBaro = &sync.Mutex{}
|
||||
mySituation.muSatellite = &sync.Mutex{}
|
||||
|
||||
// Set up status.
|
||||
globalStatus.Version = stratuxVersion
|
||||
|
|
316
main/gps.go
316
main/gps.go
|
@ -50,51 +50,51 @@ type SatelliteInfo struct {
|
|||
|
||||
type SituationData struct {
|
||||
// From GPS.
|
||||
mu_GPS *sync.Mutex
|
||||
mu_GPSPerf *sync.Mutex
|
||||
mu_Satellite *sync.Mutex
|
||||
LastFixSinceMidnightUTC float32
|
||||
Lat float32
|
||||
Lng float32
|
||||
Quality uint8
|
||||
HeightAboveEllipsoid float32 // GPS height above WGS84 ellipsoid, ft. This is specified by the GDL90 protocol, but most EFBs use MSL altitude instead. HAE is about 70-100 ft below GPS MSL altitude over most of the US.
|
||||
GeoidSep float32 // geoid separation, ft, MSL minus HAE (used in altitude calculation)
|
||||
Satellites uint16 // satellites used in solution
|
||||
SatellitesTracked uint16 // satellites tracked (almanac data received)
|
||||
SatellitesSeen uint16 // satellites seen (signal received)
|
||||
Accuracy float32 // 95% confidence for horizontal position, meters.
|
||||
NACp uint8 // NACp categories are defined in AC 20-165A
|
||||
Alt float32 // Feet MSL
|
||||
AccuracyVert float32 // 95% confidence for vertical position, meters
|
||||
GPSVertVel float32 // GPS vertical velocity, feet per second
|
||||
LastFixLocalTime time.Time
|
||||
TrueCourse float32
|
||||
GPSTurnRate float64 // calculated GPS rate of turn, degrees per second
|
||||
GroundSpeed float64
|
||||
LastGroundTrackTime time.Time
|
||||
GPSTime time.Time
|
||||
LastGPSTimeTime time.Time // stratuxClock time since last GPS time received.
|
||||
LastValidNMEAMessageTime time.Time // time valid NMEA message last seen
|
||||
LastValidNMEAMessage string // last NMEA message processed.
|
||||
muGPS *sync.Mutex
|
||||
muGPSPerformance *sync.Mutex
|
||||
muSatellite *sync.Mutex
|
||||
GPSLastFixSinceMidnightUTC float32
|
||||
GPSLatitude float32
|
||||
GPSLongitude float32
|
||||
GPSFixQuality uint8
|
||||
GPSHeightAboveEllipsoid float32 // GPS height above WGS84 ellipsoid, ft. This is specified by the GDL90 protocol, but most EFBs use MSL altitude instead. HAE is about 70-100 ft below GPS MSL altitude over most of the US.
|
||||
GPSGeoidSep float32 // geoid separation, ft, MSL minus HAE (used in altitude calculation)
|
||||
GPSSatellites uint16 // satellites used in solution
|
||||
GPSSatellitesTracked uint16 // satellites tracked (almanac data received)
|
||||
GPSSatellitesSeen uint16 // satellites seen (signal received)
|
||||
GPSHorizontalAccuracy float32 // 95% confidence for horizontal position, meters.
|
||||
GPSNACp uint8 // NACp categories are defined in AC 20-165A
|
||||
GPSAltitudeMSL float32 // Feet MSL
|
||||
GPSVerticalAccuracy float32 // 95% confidence for vertical position, meters
|
||||
GPSVerticalSpeed float32 // GPS vertical velocity, feet per second
|
||||
GPSLastFixLocalTime time.Time
|
||||
GPSTrueCourse float32
|
||||
GPSTurnRate float64 // calculated GPS rate of turn, degrees per second
|
||||
GPSGroundSpeed float64
|
||||
GPSLastGroundTrackTime time.Time
|
||||
GPSTime time.Time
|
||||
GPSLastGPSTimeStratuxTime time.Time // stratuxClock time since last GPS time received.
|
||||
GPSLastValidNMEAMessageTime time.Time // time valid NMEA message last seen
|
||||
GPSLastValidNMEAMessage string // last NMEA message processed.
|
||||
|
||||
// From pressure sensor.
|
||||
mu_Pressure *sync.Mutex
|
||||
Temp float64
|
||||
Pressure_alt float64
|
||||
RateOfClimb float64
|
||||
LastTempPressTime time.Time
|
||||
muBaro *sync.Mutex
|
||||
BaroTemperature float64
|
||||
BaroPressureAltitude float64
|
||||
BaroVerticalSpeed float64
|
||||
BaroLastMeasurementTime time.Time
|
||||
|
||||
// From AHRS source.
|
||||
mu_Attitude *sync.Mutex
|
||||
Pitch float64
|
||||
Roll float64
|
||||
Gyro_heading float64
|
||||
Mag_heading float64
|
||||
SlipSkid float64
|
||||
RateOfTurn float64
|
||||
GLoad float64
|
||||
LastAttitudeTime time.Time
|
||||
AHRSStatus uint8
|
||||
muAttitude *sync.Mutex
|
||||
AHRSPitch float64
|
||||
AHRSRoll float64
|
||||
AHRSGyroHeading float64
|
||||
AHRSMagHeading float64
|
||||
AHRSSlipSkid float64
|
||||
AHRSTurnRate float64
|
||||
AHRSGLoad float64
|
||||
AHRSLastAttitudeTime time.Time
|
||||
AHRSStatus uint8
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -417,7 +417,7 @@ func validateNMEAChecksum(s string) (string, bool) {
|
|||
//TODO: Some more robust checking above current and last speed.
|
||||
//TODO: Dynamic adjust for gain based on groundspeed
|
||||
func setTrueCourse(groundSpeed uint16, trueCourse float64) {
|
||||
if mySituation.GroundSpeed >= 7 && groundSpeed >= 7 {
|
||||
if mySituation.GPSGroundSpeed >= 7 && groundSpeed >= 7 {
|
||||
// This was previously used to filter small ground speed spikes caused by GPS position drift.
|
||||
// It was passed to the previous AHRS heading calculator. Currently unused, maybe in the future it will be.
|
||||
_ = trueCourse
|
||||
|
@ -439,8 +439,8 @@ the LICENSE file, herein included as part of this header.
|
|||
|
||||
func calcGPSAttitude() bool {
|
||||
// check slice length. Return error if empty set or set zero values
|
||||
mySituation.mu_GPSPerf.Lock()
|
||||
defer mySituation.mu_GPSPerf.Unlock()
|
||||
mySituation.muGPSPerformance.Lock()
|
||||
defer mySituation.muGPSPerformance.Unlock()
|
||||
length := len(myGPSPerfStats)
|
||||
index := length - 1
|
||||
|
||||
|
@ -822,13 +822,13 @@ return is true if parse occurs correctly and position is valid.
|
|||
*/
|
||||
|
||||
func processNMEALine(l string) (sentenceUsed bool) {
|
||||
mySituation.mu_GPS.Lock()
|
||||
mySituation.muGPS.Lock()
|
||||
|
||||
defer func() {
|
||||
if sentenceUsed || globalSettings.DEBUG {
|
||||
registerSituationUpdate()
|
||||
}
|
||||
mySituation.mu_GPS.Unlock()
|
||||
mySituation.muGPS.Unlock()
|
||||
}()
|
||||
|
||||
// Local variables for GPS attitude estimation
|
||||
|
@ -844,8 +844,8 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
}
|
||||
x := strings.Split(l_valid, ",")
|
||||
|
||||
mySituation.LastValidNMEAMessageTime = stratuxClock.Time
|
||||
mySituation.LastValidNMEAMessage = l
|
||||
mySituation.GPSLastValidNMEAMessageTime = stratuxClock.Time
|
||||
mySituation.GPSLastValidNMEAMessage = l
|
||||
|
||||
if x[0] == "PUBX" { // UBX proprietary message
|
||||
if x[1] == "00" { // Position fix.
|
||||
|
@ -868,16 +868,16 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
// field 8 = nav status
|
||||
// DR = dead reckoning, G2= 2D GPS, G3 = 3D GPS, D2= 2D diff, D3 = 3D diff, RK = GPS+DR, TT = time only
|
||||
if x[8] == "D2" || x[8] == "D3" {
|
||||
tmpSituation.Quality = 2
|
||||
tmpSituation.GPSFixQuality = 2
|
||||
} else if x[8] == "G2" || x[8] == "G3" {
|
||||
tmpSituation.Quality = 1
|
||||
tmpSituation.GPSFixQuality = 1
|
||||
} else if x[8] == "DR" || x[8] == "RK" {
|
||||
tmpSituation.Quality = 6
|
||||
tmpSituation.GPSFixQuality = 6
|
||||
} else if x[8] == "NF" {
|
||||
tmpSituation.Quality = 0 // Just a note.
|
||||
tmpSituation.GPSFixQuality = 0 // Just a note.
|
||||
return false
|
||||
} else {
|
||||
tmpSituation.Quality = 0 // Just a note.
|
||||
tmpSituation.GPSFixQuality = 0 // Just a note.
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -886,17 +886,17 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.Accuracy = float32(hAcc * 2) // UBX reports 1-sigma variation; NACp is 95% confidence (2-sigma)
|
||||
tmpSituation.GPSHorizontalAccuracy = float32(hAcc * 2) // UBX reports 1-sigma variation; NACp is 95% confidence (2-sigma)
|
||||
|
||||
// NACp estimate.
|
||||
tmpSituation.NACp = calculateNACp(tmpSituation.Accuracy)
|
||||
tmpSituation.GPSNACp = calculateNACp(tmpSituation.GPSHorizontalAccuracy)
|
||||
|
||||
// field 10 = vertical accuracy, m
|
||||
vAcc, err := strconv.ParseFloat(x[10], 32)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.AccuracyVert = float32(vAcc * 2) // UBX reports 1-sigma variation; we want 95% confidence
|
||||
tmpSituation.GPSVerticalAccuracy = float32(vAcc * 2) // UBX reports 1-sigma variation; we want 95% confidence
|
||||
|
||||
// field 2 = time
|
||||
if len(x[2]) < 8 {
|
||||
|
@ -909,8 +909,8 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
tmpSituation.LastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
thisGpsPerf.nmeaTime = tmpSituation.LastFixSinceMidnightUTC
|
||||
tmpSituation.GPSLastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
thisGpsPerf.nmeaTime = tmpSituation.GPSLastFixSinceMidnightUTC
|
||||
|
||||
// field 3-4 = lat
|
||||
if len(x[3]) < 10 {
|
||||
|
@ -923,9 +923,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
tmpSituation.Lat = float32(hr) + float32(minf/60.0)
|
||||
tmpSituation.GPSLatitude = float32(hr) + float32(minf/60.0)
|
||||
if x[4] == "S" { // South = negative.
|
||||
tmpSituation.Lat = -tmpSituation.Lat
|
||||
tmpSituation.GPSLatitude = -tmpSituation.GPSLatitude
|
||||
}
|
||||
|
||||
// field 5-6 = lon
|
||||
|
@ -938,9 +938,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
tmpSituation.Lng = float32(hr) + float32(minf/60.0)
|
||||
tmpSituation.GPSLongitude = float32(hr) + float32(minf/60.0)
|
||||
if x[6] == "W" { // West = negative.
|
||||
tmpSituation.Lng = -tmpSituation.Lng
|
||||
tmpSituation.GPSLongitude = -tmpSituation.GPSLongitude
|
||||
}
|
||||
|
||||
// field 7 = height above ellipsoid, m
|
||||
|
@ -951,20 +951,20 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
}
|
||||
|
||||
// the next 'if' statement is a workaround for a ubx7 firmware bug:
|
||||
// PUBX,00 reports HAE with a floor of zero (i.e. negative altitudes are set to zero). This causes GPS altitude to never read lower than -GeoidSep,
|
||||
// PUBX,00 reports HAE with a floor of zero (i.e. negative altitudes are set to zero). This causes GPS altitude to never read lower than -GPSGeoidSep,
|
||||
// placing minimum GPS altitude at about +80' MSL over most of North America.
|
||||
//
|
||||
// This does not affect GGA messages, so we can just rely on GGA to set altitude in these cases. It's a slower (1 Hz vs 5 Hz / 10 Hz), less precise
|
||||
// (0.1 vs 0.001 mm resolution) report, but in practice the accuracy never gets anywhere near this resolution, so this should be an acceptable tradeoff
|
||||
|
||||
if hae != 0 {
|
||||
alt := float32(hae*3.28084) - tmpSituation.GeoidSep // convert to feet and offset by geoid separation
|
||||
tmpSituation.HeightAboveEllipsoid = float32(hae * 3.28084) // feet
|
||||
tmpSituation.Alt = alt
|
||||
alt := float32(hae*3.28084) - tmpSituation.GPSGeoidSep // convert to feet and offset by geoid separation
|
||||
tmpSituation.GPSHeightAboveEllipsoid = float32(hae * 3.28084) // feet
|
||||
tmpSituation.GPSAltitudeMSL = alt
|
||||
thisGpsPerf.alt = alt
|
||||
}
|
||||
|
||||
tmpSituation.LastFixLocalTime = stratuxClock.Time
|
||||
tmpSituation.GPSLastFixLocalTime = stratuxClock.Time
|
||||
|
||||
// field 11 = groundspeed, km/h
|
||||
groundspeed, err := strconv.ParseFloat(x[11], 32)
|
||||
|
@ -972,7 +972,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
groundspeed = groundspeed * 0.540003 // convert to knots
|
||||
tmpSituation.GroundSpeed = groundspeed
|
||||
tmpSituation.GPSGroundSpeed = groundspeed
|
||||
thisGpsPerf.gsf = float32(groundspeed)
|
||||
|
||||
// field 12 = track, deg
|
||||
|
@ -984,22 +984,22 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if groundspeed > 3 { //TODO: use average groundspeed over last n seconds to avoid random "jumps"
|
||||
trueCourse = float32(tc)
|
||||
setTrueCourse(uint16(groundspeed), tc)
|
||||
tmpSituation.TrueCourse = trueCourse
|
||||
tmpSituation.GPSTrueCourse = trueCourse
|
||||
thisGpsPerf.coursef = float32(tc)
|
||||
} else {
|
||||
thisGpsPerf.coursef = -999.9 // regression will skip negative values
|
||||
// Negligible movement. Don't update course, but do use the slow speed.
|
||||
//TODO: use average course over last n seconds?
|
||||
}
|
||||
tmpSituation.LastGroundTrackTime = stratuxClock.Time
|
||||
tmpSituation.GPSLastGroundTrackTime = stratuxClock.Time
|
||||
|
||||
// field 13 = vertical velocity, m/s
|
||||
vv, err := strconv.ParseFloat(x[13], 32)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.GPSVertVel = float32(vv * -3.28084) // convert to ft/sec and positive = up
|
||||
thisGpsPerf.vv = tmpSituation.GPSVertVel
|
||||
tmpSituation.GPSVerticalSpeed = float32(vv * -3.28084) // convert to ft/sec and positive = up
|
||||
thisGpsPerf.vv = tmpSituation.GPSVerticalSpeed
|
||||
|
||||
// field 14 = age of diff corrections
|
||||
|
||||
|
@ -1008,13 +1008,13 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.Satellites = uint16(sat) // this seems to be reliable. UBX,03 handles >12 satellites solutions correctly.
|
||||
tmpSituation.GPSSatellites = uint16(sat) // this seems to be reliable. UBX,03 handles >12 satellites solutions correctly.
|
||||
|
||||
// We've made it this far, so that means we've processed "everything" and can now make the change to mySituation.
|
||||
mySituation = tmpSituation
|
||||
updateGPSPerf = true
|
||||
if updateGPSPerf {
|
||||
mySituation.mu_GPSPerf.Lock()
|
||||
mySituation.muGPSPerformance.Lock()
|
||||
myGPSPerfStats = append(myGPSPerfStats, thisGpsPerf)
|
||||
lenGPSPerfStats := len(myGPSPerfStats)
|
||||
// log.Printf("GPSPerf array has %n elements. Contents are: %v\n",lenGPSPerfStats,myGPSPerfStats)
|
||||
|
@ -1022,7 +1022,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
myGPSPerfStats = myGPSPerfStats[(lenGPSPerfStats - 299):] // remove the first n entries if more than 300 in the slice
|
||||
}
|
||||
|
||||
mySituation.mu_GPSPerf.Unlock()
|
||||
mySituation.muGPSPerformance.Unlock()
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -1050,7 +1050,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
mySituation.SatellitesTracked = uint16(satTracked) // requires UBX M8N firmware v3.01 or later to report > 20 satellites
|
||||
mySituation.GPSSatellitesTracked = uint16(satTracked) // requires UBX M8N firmware v3.01 or later to report > 20 satellites
|
||||
|
||||
// fields 3-8 are repeated block
|
||||
|
||||
|
@ -1096,7 +1096,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
var thisSatellite SatelliteInfo
|
||||
|
||||
// START OF PROTECTED BLOCK
|
||||
mySituation.mu_Satellite.Lock()
|
||||
mySituation.muSatellite.Lock()
|
||||
|
||||
// Retrieve previous information on this satellite code.
|
||||
if val, ok := Satellites[svStr]; ok { // if we've already seen this satellite identifier, copy it in to do updates
|
||||
|
@ -1156,7 +1156,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
|
||||
Satellites[thisSatellite.SatelliteID] = thisSatellite // Update constellation with this satellite
|
||||
updateConstellation()
|
||||
mySituation.mu_Satellite.Unlock()
|
||||
mySituation.muSatellite.Unlock()
|
||||
// END OF PROTECTED BLOCK
|
||||
|
||||
// end of satellite iteration loop
|
||||
|
@ -1196,10 +1196,10 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
gpsTime, err := time.Parse("020106 15:04:05.000", gpsTimeStr)
|
||||
if err == nil {
|
||||
// We only update ANY of the times if all of the time parsing is complete.
|
||||
mySituation.LastGPSTimeTime = stratuxClock.Time
|
||||
mySituation.GPSLastGPSTimeStratuxTime = stratuxClock.Time
|
||||
mySituation.GPSTime = gpsTime
|
||||
stratuxClock.SetRealTimeReference(gpsTime)
|
||||
mySituation.LastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
mySituation.GPSLastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
// log.Printf("GPS time is: %s\n", gpsTime) //debug
|
||||
if time.Since(gpsTime) > 3*time.Second || time.Since(gpsTime) < -3*time.Second {
|
||||
setStr := gpsTime.Format("20060102 15:04:05.000") + " UTC"
|
||||
|
@ -1227,7 +1227,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.GroundSpeed = groundspeed
|
||||
tmpSituation.GPSGroundSpeed = groundspeed
|
||||
|
||||
trueCourse := float32(0)
|
||||
tc, err := strconv.ParseFloat(x[1], 32)
|
||||
|
@ -1237,12 +1237,12 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if groundspeed > 3 { //TODO: use average groundspeed over last n seconds to avoid random "jumps"
|
||||
trueCourse = float32(tc)
|
||||
setTrueCourse(uint16(groundspeed), tc)
|
||||
tmpSituation.TrueCourse = trueCourse
|
||||
tmpSituation.GPSTrueCourse = trueCourse
|
||||
} else {
|
||||
// Negligible movement. Don't update course, but do use the slow speed.
|
||||
//TODO: use average course over last n seconds?
|
||||
}
|
||||
tmpSituation.LastGroundTrackTime = stratuxClock.Time
|
||||
tmpSituation.GPSLastGroundTrackTime = stratuxClock.Time
|
||||
|
||||
// We've made it this far, so that means we've processed "everything" and can now make the change to mySituation.
|
||||
mySituation = tmpSituation
|
||||
|
@ -1260,12 +1260,12 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
globalStatus.GPS_detected_type = GPS_TYPE_NMEA
|
||||
}
|
||||
|
||||
// Quality indicator.
|
||||
// GPSFixQuality indicator.
|
||||
q, err1 := strconv.Atoi(x[6])
|
||||
if err1 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.Quality = uint8(q) // 1 = 3D GPS; 2 = DGPS (SBAS /WAAS)
|
||||
tmpSituation.GPSFixQuality = uint8(q) // 1 = 3D GPS; 2 = DGPS (SBAS /WAAS)
|
||||
|
||||
// Timestamp.
|
||||
if len(x[1]) < 7 {
|
||||
|
@ -1278,9 +1278,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
tmpSituation.LastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
tmpSituation.GPSLastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
if globalStatus.GPS_detected_type != GPS_TYPE_UBX {
|
||||
thisGpsPerf.nmeaTime = tmpSituation.LastFixSinceMidnightUTC
|
||||
thisGpsPerf.nmeaTime = tmpSituation.GPSLastFixSinceMidnightUTC
|
||||
}
|
||||
|
||||
// Latitude.
|
||||
|
@ -1294,9 +1294,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
tmpSituation.Lat = float32(hr) + float32(minf/60.0)
|
||||
tmpSituation.GPSLatitude = float32(hr) + float32(minf/60.0)
|
||||
if x[3] == "S" { // South = negative.
|
||||
tmpSituation.Lat = -tmpSituation.Lat
|
||||
tmpSituation.GPSLatitude = -tmpSituation.GPSLatitude
|
||||
}
|
||||
|
||||
// Longitude.
|
||||
|
@ -1309,9 +1309,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
|
||||
tmpSituation.Lng = float32(hr) + float32(minf/60.0)
|
||||
tmpSituation.GPSLongitude = float32(hr) + float32(minf/60.0)
|
||||
if x[5] == "W" { // West = negative.
|
||||
tmpSituation.Lng = -tmpSituation.Lng
|
||||
tmpSituation.GPSLongitude = -tmpSituation.GPSLongitude
|
||||
}
|
||||
|
||||
// Altitude.
|
||||
|
@ -1319,9 +1319,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.Alt = float32(alt * 3.28084) // Convert to feet.
|
||||
tmpSituation.GPSAltitudeMSL = float32(alt * 3.28084) // Convert to feet.
|
||||
if globalStatus.GPS_detected_type != GPS_TYPE_UBX {
|
||||
thisGpsPerf.alt = float32(tmpSituation.Alt)
|
||||
thisGpsPerf.alt = float32(tmpSituation.GPSAltitudeMSL)
|
||||
}
|
||||
|
||||
// Geoid separation (Sep = HAE - MSL)
|
||||
|
@ -1331,11 +1331,11 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.GeoidSep = float32(geoidSep * 3.28084) // Convert to feet.
|
||||
tmpSituation.HeightAboveEllipsoid = tmpSituation.GeoidSep + tmpSituation.Alt
|
||||
tmpSituation.GPSGeoidSep = float32(geoidSep * 3.28084) // Convert to feet.
|
||||
tmpSituation.GPSHeightAboveEllipsoid = tmpSituation.GPSGeoidSep + tmpSituation.GPSAltitudeMSL
|
||||
|
||||
// Timestamp.
|
||||
tmpSituation.LastFixLocalTime = stratuxClock.Time
|
||||
tmpSituation.GPSLastFixLocalTime = stratuxClock.Time
|
||||
|
||||
if globalStatus.GPS_detected_type != GPS_TYPE_UBX {
|
||||
updateGPSPerf = true
|
||||
|
@ -1346,14 +1346,14 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
mySituation = tmpSituation
|
||||
|
||||
if updateGPSPerf {
|
||||
mySituation.mu_GPSPerf.Lock()
|
||||
mySituation.muGPSPerformance.Lock()
|
||||
myGPSPerfStats = append(myGPSPerfStats, thisGpsPerf)
|
||||
lenGPSPerfStats := len(myGPSPerfStats)
|
||||
// log.Printf("GPSPerf array has %n elements. Contents are: %v\n",lenGPSPerfStats,myGPSPerfStats)
|
||||
if lenGPSPerfStats > 299 { //30 seconds @ 10 Hz for UBX, 30 seconds @ 5 Hz for MTK or SIRF with 2x messages per 200 ms)
|
||||
myGPSPerfStats = myGPSPerfStats[(lenGPSPerfStats - 299):] // remove the first n entries if more than 300 in the slice
|
||||
}
|
||||
mySituation.mu_GPSPerf.Unlock()
|
||||
mySituation.muGPSPerformance.Unlock()
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -1386,7 +1386,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
}
|
||||
|
||||
if x[2] != "A" { // invalid fix
|
||||
tmpSituation.Quality = 0 // Just a note.
|
||||
tmpSituation.GPSFixQuality = 0 // Just a note.
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -1400,9 +1400,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil || err2 != nil || err3 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.LastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
tmpSituation.GPSLastFixSinceMidnightUTC = float32(3600*hr+60*min) + float32(sec)
|
||||
if globalStatus.GPS_detected_type != GPS_TYPE_UBX {
|
||||
thisGpsPerf.nmeaTime = tmpSituation.LastFixSinceMidnightUTC
|
||||
thisGpsPerf.nmeaTime = tmpSituation.GPSLastFixSinceMidnightUTC
|
||||
}
|
||||
|
||||
if len(x[9]) == 6 {
|
||||
|
@ -1410,7 +1410,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
gpsTimeStr := fmt.Sprintf("%s %02d:%02d:%06.3f", x[9], hr, min, sec)
|
||||
gpsTime, err := time.Parse("020106 15:04:05.000", gpsTimeStr)
|
||||
if err == nil && gpsTime.After(time.Date(2016, time.January, 0, 0, 0, 0, 0, time.UTC)) { // Ignore dates before 2016-JAN-01.
|
||||
tmpSituation.LastGPSTimeTime = stratuxClock.Time
|
||||
tmpSituation.GPSLastGPSTimeStratuxTime = stratuxClock.Time
|
||||
tmpSituation.GPSTime = gpsTime
|
||||
stratuxClock.SetRealTimeReference(gpsTime)
|
||||
if time.Since(gpsTime) > 3*time.Second || time.Since(gpsTime) < -3*time.Second {
|
||||
|
@ -1434,9 +1434,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil || err2 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.Lat = float32(hr) + float32(minf/60.0)
|
||||
tmpSituation.GPSLatitude = float32(hr) + float32(minf/60.0)
|
||||
if x[4] == "S" { // South = negative.
|
||||
tmpSituation.Lat = -tmpSituation.Lat
|
||||
tmpSituation.GPSLatitude = -tmpSituation.GPSLatitude
|
||||
}
|
||||
// Longitude.
|
||||
if len(x[5]) < 5 {
|
||||
|
@ -1447,19 +1447,19 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil || err2 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.Lng = float32(hr) + float32(minf/60.0)
|
||||
tmpSituation.GPSLongitude = float32(hr) + float32(minf/60.0)
|
||||
if x[6] == "W" { // West = negative.
|
||||
tmpSituation.Lng = -tmpSituation.Lng
|
||||
tmpSituation.GPSLongitude = -tmpSituation.GPSLongitude
|
||||
}
|
||||
|
||||
tmpSituation.LastFixLocalTime = stratuxClock.Time
|
||||
tmpSituation.GPSLastFixLocalTime = stratuxClock.Time
|
||||
|
||||
// ground speed in kts (field 7)
|
||||
groundspeed, err := strconv.ParseFloat(x[7], 32)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.GroundSpeed = groundspeed
|
||||
tmpSituation.GPSGroundSpeed = groundspeed
|
||||
if globalStatus.GPS_detected_type != GPS_TYPE_UBX {
|
||||
thisGpsPerf.gsf = float32(groundspeed)
|
||||
}
|
||||
|
@ -1473,7 +1473,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if groundspeed > 3 { //TODO: use average groundspeed over last n seconds to avoid random "jumps"
|
||||
trueCourse = float32(tc)
|
||||
setTrueCourse(uint16(groundspeed), tc)
|
||||
tmpSituation.TrueCourse = trueCourse
|
||||
tmpSituation.GPSTrueCourse = trueCourse
|
||||
if globalStatus.GPS_detected_type != GPS_TYPE_UBX {
|
||||
thisGpsPerf.coursef = float32(tc)
|
||||
}
|
||||
|
@ -1488,20 +1488,20 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
updateGPSPerf = true
|
||||
thisGpsPerf.msgType = x[0]
|
||||
}
|
||||
tmpSituation.LastGroundTrackTime = stratuxClock.Time
|
||||
tmpSituation.GPSLastGroundTrackTime = stratuxClock.Time
|
||||
|
||||
// We've made it this far, so that means we've processed "everything" and can now make the change to mySituation.
|
||||
mySituation = tmpSituation
|
||||
|
||||
if updateGPSPerf {
|
||||
mySituation.mu_GPSPerf.Lock()
|
||||
mySituation.muGPSPerformance.Lock()
|
||||
myGPSPerfStats = append(myGPSPerfStats, thisGpsPerf)
|
||||
lenGPSPerfStats := len(myGPSPerfStats)
|
||||
// log.Printf("GPSPerf array has %n elements. Contents are: %v\n",lenGPSPerfStats,myGPSPerfStats)
|
||||
if lenGPSPerfStats > 299 { //30 seconds @ 10 Hz for UBX, 30 seconds @ 5 Hz for MTK or SIRF with 2x messages per 200 ms)
|
||||
myGPSPerfStats = myGPSPerfStats[(lenGPSPerfStats - 299):] // remove the first n entries if more than 300 in the slice
|
||||
}
|
||||
mySituation.mu_GPSPerf.Unlock()
|
||||
mySituation.muGPSPerformance.Unlock()
|
||||
}
|
||||
|
||||
setDataLogTimeWithGPS(mySituation)
|
||||
|
@ -1520,7 +1520,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
|
||||
/*
|
||||
if (x[1] != "A") && (x[1] != "M") { // invalid fix ... but x[2] is a better indicator of fix quality. Deprecating this.
|
||||
tmpSituation.Quality = 0 // Just a note.
|
||||
tmpSituation.GPSFixQuality = 0 // Just a note.
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
@ -1528,7 +1528,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
// field 2: solution type
|
||||
// 1 = no solution; 2 = 2D fix, 3 = 3D fix. WAAS status is parsed from GGA message, so no need to get here
|
||||
if (x[2] == "") || (x[2] == "1") { // missing or no solution
|
||||
tmpSituation.Quality = 0 // Just a note.
|
||||
tmpSituation.GPSFixQuality = 0 // Just a note.
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -1563,7 +1563,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
var thisSatellite SatelliteInfo
|
||||
|
||||
// START OF PROTECTED BLOCK
|
||||
mySituation.mu_Satellite.Lock()
|
||||
mySituation.muSatellite.Lock()
|
||||
|
||||
// Retrieve previous information on this satellite code.
|
||||
if val, ok := Satellites[svStr]; ok { // if we've already seen this satellite identifier, copy it in to do updates
|
||||
|
@ -1582,15 +1582,15 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
|
||||
Satellites[thisSatellite.SatelliteID] = thisSatellite // Update constellation with this satellite
|
||||
updateConstellation()
|
||||
mySituation.mu_Satellite.Unlock()
|
||||
mySituation.muSatellite.Unlock()
|
||||
// END OF PROTECTED BLOCK
|
||||
|
||||
}
|
||||
}
|
||||
if sat < 12 || tmpSituation.Satellites < 13 { // GSA only reports up to 12 satellites in solution, so we don't want to overwrite higher counts based on updateConstellation().
|
||||
tmpSituation.Satellites = uint16(sat)
|
||||
if (tmpSituation.Quality == 2) && !svSBAS && !svGLONASS { // add one to the satellite count if we have a SBAS solution, but the GSA message doesn't track a SBAS satellite
|
||||
tmpSituation.Satellites++
|
||||
if sat < 12 || tmpSituation.GPSSatellites < 13 { // GSA only reports up to 12 satellites in solution, so we don't want to overwrite higher counts based on updateConstellation().
|
||||
tmpSituation.GPSSatellites = uint16(sat)
|
||||
if (tmpSituation.GPSFixQuality == 2) && !svSBAS && !svGLONASS { // add one to the satellite count if we have a SBAS solution, but the GSA message doesn't track a SBAS satellite
|
||||
tmpSituation.GPSSatellites++
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1600,14 +1600,14 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil {
|
||||
return false
|
||||
}
|
||||
if tmpSituation.Quality == 2 {
|
||||
tmpSituation.Accuracy = float32(hdop * 4.0) // Rough 95% confidence estimate for WAAS / DGPS solution
|
||||
if tmpSituation.GPSFixQuality == 2 {
|
||||
tmpSituation.GPSHorizontalAccuracy = float32(hdop * 4.0) // Rough 95% confidence estimate for WAAS / DGPS solution
|
||||
} else {
|
||||
tmpSituation.Accuracy = float32(hdop * 8.0) // Rough 95% confidence estimate for 3D non-WAAS solution
|
||||
tmpSituation.GPSHorizontalAccuracy = float32(hdop * 8.0) // Rough 95% confidence estimate for 3D non-WAAS solution
|
||||
}
|
||||
|
||||
// NACp estimate.
|
||||
tmpSituation.NACp = calculateNACp(tmpSituation.Accuracy)
|
||||
tmpSituation.GPSNACp = calculateNACp(tmpSituation.GPSHorizontalAccuracy)
|
||||
|
||||
// field 17: VDOP
|
||||
// accuracy estimate
|
||||
|
@ -1615,7 +1615,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
if err1 != nil {
|
||||
return false
|
||||
}
|
||||
tmpSituation.AccuracyVert = float32(vdop * 5) // rough estimate for 95% confidence
|
||||
tmpSituation.GPSVerticalAccuracy = float32(vdop * 5) // rough estimate for 95% confidence
|
||||
|
||||
// We've made it this far, so that means we've processed "everything" and can now make the change to mySituation.
|
||||
mySituation = tmpSituation
|
||||
|
@ -1649,7 +1649,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
}
|
||||
*/
|
||||
|
||||
//mySituation.SatellitesTracked = uint16(satTracked) // Replaced with parsing of 'Satellites' data structure
|
||||
//mySituation.GPSSatellitesTracked = uint16(satTracked) // Replaced with parsing of 'Satellites' data structure
|
||||
|
||||
// field 4-7 = repeating block with satellite id, elevation, azimuth, and signal strengh (Cno)
|
||||
|
||||
|
@ -1687,7 +1687,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
var thisSatellite SatelliteInfo
|
||||
|
||||
// START OF PROTECTED BLOCK
|
||||
mySituation.mu_Satellite.Lock()
|
||||
mySituation.muSatellite.Lock()
|
||||
|
||||
// Retrieve previous information on this satellite code.
|
||||
if val, ok := Satellites[svStr]; ok { // if we've already seen this satellite identifier, copy it in to do updates
|
||||
|
@ -1729,7 +1729,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
// hack workaround for GSA 12-sv limitation... if this is a SBAS satellite, we have a SBAS solution, and signal is greater than some arbitrary threshold, set InSolution
|
||||
// drawback is this will show all tracked SBAS satellites as being in solution.
|
||||
if thisSatellite.Type == SAT_TYPE_SBAS {
|
||||
if mySituation.Quality == 2 {
|
||||
if mySituation.GPSFixQuality == 2 {
|
||||
if thisSatellite.Signal > 16 {
|
||||
thisSatellite.InSolution = true
|
||||
thisSatellite.TimeLastSolution = stratuxClock.Time
|
||||
|
@ -1750,7 +1750,7 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
|
||||
Satellites[thisSatellite.SatelliteID] = thisSatellite // Update constellation with this satellite
|
||||
updateConstellation()
|
||||
mySituation.mu_Satellite.Unlock()
|
||||
mySituation.muSatellite.Unlock()
|
||||
// END OF PROTECTED BLOCK
|
||||
}
|
||||
|
||||
|
@ -1794,7 +1794,7 @@ func gpsSerialReader() {
|
|||
}
|
||||
|
||||
func makeFFAHRSSimReport() {
|
||||
s := fmt.Sprintf("XATTStratux,%f,%f,%f", mySituation.Gyro_heading, mySituation.Pitch, mySituation.Roll)
|
||||
s := fmt.Sprintf("XATTStratux,%f,%f,%f", mySituation.AHRSGyroHeading, mySituation.AHRSPitch, mySituation.AHRSRoll)
|
||||
|
||||
sendMsg([]byte(s), NETWORK_AHRS_FFSIM, false)
|
||||
}
|
||||
|
@ -1817,16 +1817,16 @@ func makeAHRSGDL90Report() {
|
|||
palt := uint16(0xFFFF)
|
||||
vs := int16(0x7FFF)
|
||||
if isAHRSValid() {
|
||||
pitch = roundToInt16(mySituation.Pitch * 10)
|
||||
roll = roundToInt16(mySituation.Roll * 10)
|
||||
hdg = roundToInt16(mySituation.Gyro_heading * 10) // TODO westphae: switch to Mag_heading?
|
||||
slip_skid = roundToInt16(mySituation.SlipSkid * 10)
|
||||
yaw_rate = roundToInt16(mySituation.RateOfTurn * 10)
|
||||
g = roundToInt16(mySituation.GLoad * 10)
|
||||
pitch = roundToInt16(mySituation.AHRSPitch * 10)
|
||||
roll = roundToInt16(mySituation.AHRSRoll * 10)
|
||||
hdg = roundToInt16(mySituation.AHRSGyroHeading * 10) // TODO westphae: switch to AHRSMagHeading?
|
||||
slip_skid = roundToInt16(mySituation.AHRSSlipSkid * 10)
|
||||
yaw_rate = roundToInt16(mySituation.AHRSTurnRate * 10)
|
||||
g = roundToInt16(mySituation.AHRSGLoad * 10)
|
||||
}
|
||||
if isTempPressValid() {
|
||||
palt = uint16(mySituation.Pressure_alt + 5000.5)
|
||||
vs = roundToInt16(mySituation.RateOfClimb)
|
||||
palt = uint16(mySituation.BaroPressureAltitude + 5000.5)
|
||||
vs = roundToInt16(mySituation.BaroVerticalSpeed)
|
||||
}
|
||||
|
||||
// Roll.
|
||||
|
@ -1880,22 +1880,22 @@ func gpsAttitudeSender() {
|
|||
for !(globalSettings.IMU_Sensor_Enabled && globalStatus.IMUConnected) && (globalSettings.GPS_Enabled && globalStatus.GPS_connected) {
|
||||
<-timer.C
|
||||
|
||||
if mySituation.Quality == 0 || !calcGPSAttitude() {
|
||||
if mySituation.GPSFixQuality == 0 || !calcGPSAttitude() {
|
||||
if globalSettings.DEBUG {
|
||||
log.Printf("Couldn't calculate GPS-based attitude statistics\n")
|
||||
}
|
||||
} else {
|
||||
mySituation.mu_GPSPerf.Lock()
|
||||
mySituation.muGPSPerformance.Lock()
|
||||
index := len(myGPSPerfStats) - 1
|
||||
if index > 1 {
|
||||
mySituation.Pitch = myGPSPerfStats[index].gpsPitch
|
||||
mySituation.Roll = myGPSPerfStats[index].gpsRoll
|
||||
mySituation.Gyro_heading = float64(mySituation.TrueCourse)
|
||||
mySituation.LastAttitudeTime = stratuxClock.Time
|
||||
mySituation.AHRSPitch = myGPSPerfStats[index].gpsPitch
|
||||
mySituation.AHRSRoll = myGPSPerfStats[index].gpsRoll
|
||||
mySituation.AHRSGyroHeading = float64(mySituation.GPSTrueCourse)
|
||||
mySituation.AHRSLastAttitudeTime = stratuxClock.Time
|
||||
|
||||
makeAHRSGDL90Report()
|
||||
}
|
||||
mySituation.mu_GPSPerf.Unlock()
|
||||
mySituation.muGPSPerformance.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1903,7 +1903,7 @@ func gpsAttitudeSender() {
|
|||
|
||||
/*
|
||||
updateConstellation(): Periodic cleanup and statistics calculation for 'Satellites'
|
||||
data structure. Calling functions must protect this in a mySituation.mu_Satellite.
|
||||
data structure. Calling functions must protect this in a mySituation.muSatellite.
|
||||
|
||||
*/
|
||||
|
||||
|
@ -1928,47 +1928,47 @@ func updateConstellation() {
|
|||
}
|
||||
}
|
||||
|
||||
mySituation.Satellites = uint16(sats)
|
||||
mySituation.SatellitesTracked = uint16(tracked)
|
||||
mySituation.SatellitesSeen = uint16(seen)
|
||||
mySituation.GPSSatellites = uint16(sats)
|
||||
mySituation.GPSSatellitesTracked = uint16(tracked)
|
||||
mySituation.GPSSatellitesSeen = uint16(seen)
|
||||
}
|
||||
|
||||
func isGPSConnected() bool {
|
||||
return stratuxClock.Since(mySituation.LastValidNMEAMessageTime) < 5*time.Second
|
||||
return stratuxClock.Since(mySituation.GPSLastValidNMEAMessageTime) < 5*time.Second
|
||||
}
|
||||
|
||||
/*
|
||||
isGPSValid returns true only if a valid position fix has been seen in the last 15 seconds,
|
||||
and if the GPS subsystem has recently detected a GPS device.
|
||||
|
||||
If false, 'Quality` is set to 0 ("No fix"), as is the number of satellites in solution.
|
||||
If false, 'GPSFixQuality` is set to 0 ("No fix"), as is the number of satellites in solution.
|
||||
*/
|
||||
|
||||
func isGPSValid() bool {
|
||||
isValid := false
|
||||
if (stratuxClock.Since(mySituation.LastFixLocalTime) < 15*time.Second) && globalStatus.GPS_connected && mySituation.Quality > 0 {
|
||||
if (stratuxClock.Since(mySituation.GPSLastFixLocalTime) < 15*time.Second) && globalStatus.GPS_connected && mySituation.GPSFixQuality > 0 {
|
||||
isValid = true
|
||||
} else {
|
||||
mySituation.Quality = 0
|
||||
mySituation.Satellites = 0
|
||||
mySituation.GPSFixQuality = 0
|
||||
mySituation.GPSSatellites = 0
|
||||
}
|
||||
return isValid
|
||||
}
|
||||
|
||||
func isGPSGroundTrackValid() bool {
|
||||
return stratuxClock.Since(mySituation.LastGroundTrackTime) < 15*time.Second
|
||||
return stratuxClock.Since(mySituation.GPSLastGroundTrackTime) < 15*time.Second
|
||||
}
|
||||
|
||||
func isGPSClockValid() bool {
|
||||
return stratuxClock.Since(mySituation.LastGPSTimeTime) < 15*time.Second
|
||||
return stratuxClock.Since(mySituation.GPSLastGPSTimeStratuxTime) < 15*time.Second
|
||||
}
|
||||
|
||||
func isAHRSValid() bool {
|
||||
return stratuxClock.Since(mySituation.LastAttitudeTime) < 1*time.Second // If attitude information gets to be over 1 second old, declare invalid.
|
||||
return stratuxClock.Since(mySituation.AHRSLastAttitudeTime) < 1*time.Second // If attitude information gets to be over 1 second old, declare invalid.
|
||||
}
|
||||
|
||||
func isTempPressValid() bool {
|
||||
return stratuxClock.Since(mySituation.LastTempPressTime) < 15*time.Second
|
||||
return stratuxClock.Since(mySituation.BaroLastMeasurementTime) < 15*time.Second
|
||||
}
|
||||
|
||||
func pollGPS() {
|
||||
|
|
|
@ -222,13 +222,13 @@ func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
|
|||
func handleSatellitesRequest(w http.ResponseWriter, r *http.Request) {
|
||||
setNoCache(w)
|
||||
setJSONHeaders(w)
|
||||
mySituation.mu_Satellite.Lock()
|
||||
mySituation.muSatellite.Lock()
|
||||
satellitesJSON, err := json.Marshal(&Satellites)
|
||||
if err != nil {
|
||||
log.Printf("Error sending GNSS satellite JSON data: %s\n", err.Error())
|
||||
}
|
||||
fmt.Fprintf(w, "%s\n", satellitesJSON)
|
||||
mySituation.mu_Satellite.Unlock()
|
||||
mySituation.muSatellite.Unlock()
|
||||
}
|
||||
|
||||
// AJAX call - /getSettings. Responds with all stratux.conf data.
|
||||
|
|
112
main/sensors.go
112
main/sensors.go
|
@ -105,7 +105,7 @@ func tempAndPressureSender() {
|
|||
press, err = myPressureReader.Pressure()
|
||||
if err != nil {
|
||||
log.Printf("AHRS Error: Couldn't read pressure from sensor: %s", err)
|
||||
failnum += 1
|
||||
failnum++
|
||||
if failnum > numRetries {
|
||||
log.Printf("AHRS Error: Couldn't read pressure from sensor %d times, closing BMP: %s", failnum, err)
|
||||
myPressureReader.Close()
|
||||
|
@ -115,17 +115,17 @@ func tempAndPressureSender() {
|
|||
}
|
||||
|
||||
// Update the Situation data.
|
||||
mySituation.mu_Pressure.Lock()
|
||||
mySituation.LastTempPressTime = stratuxClock.Time
|
||||
mySituation.Temp = temp
|
||||
mySituation.muBaro.Lock()
|
||||
mySituation.BaroLastMeasurementTime = stratuxClock.Time
|
||||
mySituation.BaroTemperature = temp
|
||||
altitude = CalcAltitude(press)
|
||||
mySituation.Pressure_alt = altitude
|
||||
mySituation.BaroPressureAltitude = altitude
|
||||
if altLast < -2000 {
|
||||
altLast = altitude // Initialize
|
||||
}
|
||||
// Assuming timer is reasonably accurate, use a regular ewma
|
||||
mySituation.RateOfClimb = u*mySituation.RateOfClimb + (1-u)*(altitude-altLast)/(float64(dt)/60)
|
||||
mySituation.mu_Pressure.Unlock()
|
||||
mySituation.BaroVerticalSpeed = u*mySituation.BaroVerticalSpeed + (1-u)*(altitude-altLast)/(float64(dt)/60)
|
||||
mySituation.muBaro.Unlock()
|
||||
altLast = altitude
|
||||
}
|
||||
}
|
||||
|
@ -142,11 +142,10 @@ func initIMU() (ok bool) {
|
|||
log.Println("AHRS Info: Successfully calibrated MPU9250")
|
||||
ahrsCalibrating = false
|
||||
return true
|
||||
} else {
|
||||
log.Println("AHRS Info: couldn't calibrate MPU9250")
|
||||
ahrsCalibrating = false
|
||||
return false
|
||||
}
|
||||
log.Println("AHRS Info: couldn't calibrate MPU9250")
|
||||
ahrsCalibrating = false
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO westphae: try to connect to MPU9150
|
||||
|
@ -182,28 +181,7 @@ func sensorAttitudeSender() {
|
|||
// Need a sampling freq faster than 10Hz
|
||||
timer := time.NewTicker(50 * time.Millisecond) // ~20Hz update.
|
||||
for {
|
||||
if globalSettings.IMUMapping[0] == 0 { // if unset, default to RY836AI
|
||||
globalSettings.IMUMapping[0] = -1 // +2
|
||||
globalSettings.IMUMapping[1] = -3 // +3
|
||||
saveSettings()
|
||||
}
|
||||
f := globalSettings.IMUMapping
|
||||
|
||||
// Set up orientation matrix; a bit ugly for now
|
||||
ff = new([3][3]float64)
|
||||
if f[0] < 0 {
|
||||
ff[0][-f[0]-1] = -1
|
||||
} else {
|
||||
ff[0][+f[0]-1] = +1
|
||||
}
|
||||
if f[1] < 0 {
|
||||
ff[2][-f[1]-1] = -1
|
||||
} else {
|
||||
ff[2][+f[1]-1] = +1
|
||||
}
|
||||
ff[1][0] = ff[2][1]*ff[0][2] - ff[2][2]*ff[0][1]
|
||||
ff[1][1] = ff[2][2]*ff[0][0] - ff[2][0]*ff[0][2]
|
||||
ff[1][2] = ff[2][0]*ff[0][1] - ff[2][1]*ff[0][0]
|
||||
ff = makeSensorRotationMatrix(m)
|
||||
|
||||
failnum = 0
|
||||
<-timer.C
|
||||
|
@ -214,6 +192,8 @@ func sensorAttitudeSender() {
|
|||
ahrsCalibrating = true
|
||||
if err := myIMUReader.Calibrate(1, 1); err == nil {
|
||||
log.Println("AHRS Info: Successfully recalibrated MPU9250")
|
||||
ff = makeSensorRotationMatrix(m)
|
||||
|
||||
} else {
|
||||
log.Println("AHRS Info: couldn't recalibrate MPU9250")
|
||||
}
|
||||
|
@ -247,7 +227,7 @@ func sensorAttitudeSender() {
|
|||
m.MValid = magError == nil
|
||||
if mpuError != nil {
|
||||
log.Printf("AHRS Gyro/Accel Error: %s\n", mpuError)
|
||||
failnum += 1
|
||||
failnum++
|
||||
if failnum > numRetries {
|
||||
log.Printf("AHRS Gyro/Accel Error: failed to read %d times, restarting: %s\n",
|
||||
failnum-1, mpuError)
|
||||
|
@ -263,15 +243,15 @@ func sensorAttitudeSender() {
|
|||
// Don't necessarily disconnect here, unless AHRSProvider deeply depends on magnetometer
|
||||
}
|
||||
|
||||
m.TW = float64(mySituation.LastGroundTrackTime.UnixNano()/1000) / 1e6
|
||||
m.WValid = t.Sub(mySituation.LastGroundTrackTime) < 3000*time.Millisecond
|
||||
m.TW = float64(mySituation.GPSLastGroundTrackTime.UnixNano()/1000) / 1e6
|
||||
m.WValid = t.Sub(mySituation.GPSLastGroundTrackTime) < 3000*time.Millisecond
|
||||
if m.WValid {
|
||||
m.W1 = mySituation.GroundSpeed * math.Sin(float64(mySituation.TrueCourse)*ahrs.Deg)
|
||||
m.W2 = mySituation.GroundSpeed * math.Cos(float64(mySituation.TrueCourse)*ahrs.Deg)
|
||||
m.W1 = mySituation.GPSGroundSpeed * math.Sin(float64(mySituation.GPSTrueCourse)*ahrs.Deg)
|
||||
m.W2 = mySituation.GPSGroundSpeed * math.Cos(float64(mySituation.GPSTrueCourse)*ahrs.Deg)
|
||||
if globalSettings.BMP_Sensor_Enabled && globalStatus.BMPConnected {
|
||||
m.W3 = mySituation.RateOfClimb * 60 / 6076.12
|
||||
m.W3 = mySituation.BaroVerticalSpeed * 60 / 6076.12
|
||||
} else {
|
||||
m.W3 = float64(mySituation.GPSVertVel) * 3600 / 6076.12
|
||||
m.W3 = float64(mySituation.GPSVerticalSpeed) * 3600 / 6076.12
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,20 +262,20 @@ func sensorAttitudeSender() {
|
|||
|
||||
// If we have valid AHRS info, then update mySituation
|
||||
if s.Valid() {
|
||||
mySituation.mu_Attitude.Lock()
|
||||
mySituation.muAttitude.Lock()
|
||||
|
||||
roll, pitch, heading = s.RollPitchHeading()
|
||||
mySituation.Roll = roll / ahrs.Deg
|
||||
mySituation.Pitch = pitch / ahrs.Deg
|
||||
mySituation.Gyro_heading = heading / ahrs.Deg
|
||||
mySituation.AHRSRoll = roll / ahrs.Deg
|
||||
mySituation.AHRSPitch = pitch / ahrs.Deg
|
||||
mySituation.AHRSGyroHeading = heading / ahrs.Deg
|
||||
|
||||
mySituation.Mag_heading = s.MagHeading()
|
||||
mySituation.SlipSkid = s.SlipSkid()
|
||||
mySituation.RateOfTurn = s.RateOfTurn()
|
||||
mySituation.GLoad = s.GLoad()
|
||||
mySituation.AHRSMagHeading = s.MagHeading()
|
||||
mySituation.AHRSSlipSkid = s.SlipSkid()
|
||||
mySituation.AHRSTurnRate = s.RateOfTurn()
|
||||
mySituation.AHRSGLoad = s.GLoad()
|
||||
|
||||
mySituation.LastAttitudeTime = t
|
||||
mySituation.mu_Attitude.Unlock()
|
||||
mySituation.AHRSLastAttitudeTime = t
|
||||
mySituation.muAttitude.Unlock()
|
||||
|
||||
// makeFFAHRSSimReport() // simultaneous use of GDL90 and FFSIM not supported in FF 7.5.1 or later. Function definition will be kept for AHRS debugging and future workarounds.
|
||||
} else {
|
||||
|
@ -328,6 +308,34 @@ func sensorAttitudeSender() {
|
|||
}
|
||||
}
|
||||
|
||||
func makeSensorRotationMatrix(mCal *ahrs.Measurement) (ff *[3][3]float64) {
|
||||
if globalSettings.IMUMapping[0] == 0 { // if unset, default to RY836AI in standard orientation
|
||||
globalSettings.IMUMapping[0] = -1 // +2
|
||||
globalSettings.IMUMapping[1] = -3 // +3
|
||||
saveSettings()
|
||||
}
|
||||
f := globalSettings.IMUMapping
|
||||
ff = new([3][3]float64)
|
||||
// TODO westphae: remove the projection on the measured gravity vector so it's orthogonal.
|
||||
if f[0] < 0 { // This is the "forward direction" chosen for the sensor.
|
||||
ff[0][-f[0]-1] = -1
|
||||
} else {
|
||||
ff[0][+f[0]-1] = +1
|
||||
}
|
||||
//TODO westphae: replace "up direction" with opposite of measured gravity.
|
||||
if f[1] < 0 { // This is the "up direction" chosen for the sensor.
|
||||
ff[2][-f[1]-1] = -1
|
||||
} else {
|
||||
ff[2][+f[1]-1] = +1
|
||||
}
|
||||
// This specifies the "left wing" direction for a right-handed coordinate system.
|
||||
ff[1][0] = ff[2][1]*ff[0][2] - ff[2][2]*ff[0][1]
|
||||
ff[1][1] = ff[2][2]*ff[0][0] - ff[2][0]*ff[0][2]
|
||||
ff[1][2] = ff[2][0]*ff[0][1] - ff[2][1]*ff[0][0]
|
||||
return ff
|
||||
}
|
||||
|
||||
// This is used in the orientation process where the user specifies the forward and up directions.
|
||||
func getMinAccelDirection() (i int, err error) {
|
||||
_, _, _, _, a1, a2, a3, _, _, _, err, _ := myIMUReader.Read()
|
||||
if err != nil {
|
||||
|
@ -379,8 +387,8 @@ func updateAHRSStatus() {
|
|||
msg = 0
|
||||
|
||||
// GPS valid
|
||||
if stratuxClock.Time.Sub(mySituation.LastGroundTrackTime) < 3000*time.Millisecond {
|
||||
msg += 1
|
||||
if stratuxClock.Time.Sub(mySituation.GPSLastGroundTrackTime) < 3000*time.Millisecond {
|
||||
msg++
|
||||
}
|
||||
// IMU is being used
|
||||
imu = globalSettings.IMU_Sensor_Enabled && globalStatus.IMUConnected
|
||||
|
|
|
@ -187,7 +187,7 @@ func sendTrafficUpdates() {
|
|||
for icao, ti := range traffic { // ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering.
|
||||
if isGPSValid() {
|
||||
// func distRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
|
||||
dist, bearing := distance(float64(mySituation.Lat), float64(mySituation.Lng), float64(ti.Lat), float64(ti.Lng))
|
||||
dist, bearing := distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||
ti.Distance = dist
|
||||
ti.Bearing = bearing
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ func parseDownlinkReport(s string, signalLevel int) {
|
|||
ti.Lat = lat
|
||||
ti.Lng = lng
|
||||
if isGPSValid() {
|
||||
ti.Distance, ti.Bearing = distance(float64(mySituation.Lat), float64(mySituation.Lng), float64(ti.Lat), float64(ti.Lng))
|
||||
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||
}
|
||||
ti.Last_seen = stratuxClock.Time
|
||||
ti.ExtrapolatedPosition = false
|
||||
|
@ -772,7 +772,7 @@ func esListen() {
|
|||
ti.Lat = lat
|
||||
ti.Lng = lng
|
||||
if isGPSValid() {
|
||||
ti.Distance, ti.Bearing = distance(float64(mySituation.Lat), float64(mySituation.Lng), float64(ti.Lat), float64(ti.Lng))
|
||||
ti.Distance, ti.Bearing = distance(float64(mySituation.GPSLatitude), float64(mySituation.GPSLongitude), float64(ti.Lat), float64(ti.Lng))
|
||||
}
|
||||
ti.Position_valid = true
|
||||
ti.ExtrapolatedPosition = false
|
||||
|
@ -976,8 +976,8 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
|
|||
lat := 43.99
|
||||
lng := -88.56
|
||||
if isGPSValid() {
|
||||
lat = float64(mySituation.Lat)
|
||||
lng = float64(mySituation.Lng)
|
||||
lat = float64(mySituation.GPSLatitude)
|
||||
lng = float64(mySituation.GPSLongitude)
|
||||
}
|
||||
traffRelLat := y / 60
|
||||
traffRelLng := -x / (60 * math.Cos(lat*math.Pi/180.0))
|
||||
|
@ -1010,7 +1010,7 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
|
|||
|
||||
ti.Position_valid = true
|
||||
ti.ExtrapolatedPosition = false
|
||||
ti.Alt = int32(mySituation.Alt + relAlt)
|
||||
ti.Alt = int32(mySituation.GPSAltitudeMSL + relAlt)
|
||||
ti.Track = uint16(hdg)
|
||||
ti.Speed = uint16(gs)
|
||||
if hdg >= 240 && hdg < 270 {
|
||||
|
|
|
@ -101,62 +101,61 @@ function GPSCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
// consider using angular.extend()
|
||||
$scope.raw_data = angular.toJson(data, true); // makes it pretty
|
||||
|
||||
|
||||
$scope.Satellites = situation.Satellites;
|
||||
$scope.GPS_satellites_tracked = situation.SatellitesTracked;
|
||||
$scope.GPS_satellites_seen = situation.SatellitesSeen;
|
||||
$scope.Quality = situation.Quality;
|
||||
|
||||
$scope.Satellites = situation.GPSSatellites;
|
||||
$scope.GPS_satellites_tracked = situation.GPSSatellitesTracked;
|
||||
$scope.GPS_satellites_seen = situation.GPSSatellitesSeen;
|
||||
$scope.Quality = situation.GPSFixQuality;
|
||||
|
||||
var solutionText = "No Fix";
|
||||
if (situation.Quality === 2) {
|
||||
if (situation.GPSFixQuality === 2) {
|
||||
solutionText = "GPS + SBAS (WAAS / EGNOS)";
|
||||
} else if (situation.Quality === 1) {
|
||||
} else if (situation.GPSFixQuality === 1) {
|
||||
solutionText = "3D GPS"
|
||||
}
|
||||
$scope.SolutionText = solutionText;
|
||||
|
||||
$scope.gps_accuracy = situation.Accuracy.toFixed(1);
|
||||
$scope.gps_vert_accuracy = (situation.AccuracyVert*3.2808).toFixed(1); // accuracy is in meters, need to display in ft
|
||||
|
||||
$scope.gps_horizontal_accuracy = situation.GPSHorizontalAccuracy.toFixed(1);
|
||||
$scope.gps_vertical_accuracy = (situation.GPSVerticalAccuracy*3.2808).toFixed(1); // accuracy is in meters, need to display in ft
|
||||
|
||||
|
||||
// NACp should be an integer value in the range of 0 .. 11
|
||||
// var accuracies = ["≥ 10 NM", "< 10 NM", "< 4 NM", "< 2 NM", "< 1 NM", "< 0.5 NM", "< 0.3 NM", "< 0.1 NM", "< 100 m", "< 30 m", "< 10 m", "< 3 m"];
|
||||
// $scope.gps_accuracy = accuracies[status.NACp];
|
||||
// $scope.gps_horizontal_accuracy = accuracies[status.NACp];
|
||||
// "LastFixLocalTime":"2015-10-11T16:47:03.523085162Z"
|
||||
|
||||
$scope.gps_lat = situation.Lat.toFixed(5); // result is string
|
||||
$scope.gps_lon = situation.Lng.toFixed(5); // result is string
|
||||
$scope.gps_alt = situation.Alt.toFixed(1);
|
||||
$scope.gps_track = situation.TrueCourse.toFixed(1);
|
||||
$scope.gps_speed = situation.GroundSpeed.toFixed(1);
|
||||
$scope.gps_vert_speed = situation.GPSVertVel.toFixed(1);
|
||||
$scope.gps_lat = situation.GPSLatitude.toFixed(5); // result is string
|
||||
$scope.gps_lon = situation.GPSLongitude.toFixed(5); // result is string
|
||||
$scope.gps_alt = situation.GPSAltitudeMSL.toFixed(1);
|
||||
$scope.gps_track = situation.GPSTrueCourse.toFixed(1);
|
||||
$scope.gps_speed = situation.GPSGroundSpeed.toFixed(1);
|
||||
$scope.gps_vert_speed = situation.GPSVerticalSpeed.toFixed(1);
|
||||
|
||||
// "LastGroundTrackTime":"0001-01-01T00:00:00Z"
|
||||
|
||||
/* not currently used
|
||||
$scope.ahrs_temp = status.Temp;
|
||||
*/
|
||||
$scope.press_time = Date.parse(situation.LastTempPressTime);
|
||||
$scope.gps_time = Date.parse(situation.LastGPSTimeTime);
|
||||
$scope.ahrs_temp = status.Temp;
|
||||
*/
|
||||
$scope.press_time = Date.parse(situation.BaroLastMeasurementTime);
|
||||
$scope.gps_time = Date.parse(situation.GPSLastGPSTimeStratuxTime);
|
||||
if ($scope.gps_time - $scope.press_time < 1000) {
|
||||
$scope.ahrs_alt = Math.round(situation.Pressure_alt);
|
||||
$scope.ahrs_alt = Math.round(situation.BaroPressureAltitude);
|
||||
} else {
|
||||
$scope.ahrs_alt = "---";
|
||||
}
|
||||
|
||||
$scope.ahrs_heading = Math.round(situation.Gyro_heading);
|
||||
$scope.ahrs_heading = Math.round(situation.AHRSGyroHeading);
|
||||
// pitch and roll are in degrees
|
||||
$scope.ahrs_pitch = Math.round(situation.Pitch*10)/10;
|
||||
$scope.ahrs_roll = Math.round(situation.Roll*10)/10;
|
||||
$scope.ahrs_slip_skid = Math.round(situation.SlipSkid*10)/10;
|
||||
$scope.ahrs_pitch = Math.round(situation.AHRSPitch*10)/10;
|
||||
$scope.ahrs_roll = Math.round(situation.AHRSRoll*10)/10;
|
||||
$scope.ahrs_slip_skid = Math.round(situation.AHRSSlipSkid*10)/10;
|
||||
ahrs.update($scope.ahrs_pitch, $scope.ahrs_roll, $scope.ahrs_heading, $scope.ahrs_slip_skid);
|
||||
|
||||
$scope.ahrs_heading_mag = Math.round(situation.Mag_heading);
|
||||
$scope.ahrs_gload = Math.round(situation.GLoad*100)/100;
|
||||
$scope.ahrs_heading_mag = Math.round(situation.AHRSMagHeading);
|
||||
$scope.ahrs_gload = Math.round(situation.AHRSGLoad*100)/100;
|
||||
gMeter.update($scope.ahrs_gload);
|
||||
|
||||
if (situation.RateOfTurn > 1) {
|
||||
$scope.ahrs_turn_rate = Math.round(360/situation.RateOfTurn/60*10)/10; // minutes/turn
|
||||
if (situation.AHRSTurnRate> 0.25) {
|
||||
$scope.ahrs_turn_rate = Math.round(360/situation.AHRSTurnRate/60*10)/10; // minutes/turn
|
||||
} else {
|
||||
$scope.ahrs_turn_rate = '---'
|
||||
}
|
||||
|
@ -202,7 +201,7 @@ function GPSCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
}
|
||||
// "LastAttitudeTime":"2015-10-11T16:47:03.534615187Z"
|
||||
|
||||
setGeoReferenceMap(situation.Lat, situation.Lng);
|
||||
setGeoReferenceMap(situation.GPSLatitude, situation.GPSLongitude);
|
||||
}
|
||||
|
||||
function resetSituation() { // mySituation
|
||||
|
@ -246,12 +245,11 @@ function GPSCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
new_satellite.InSolution = obj.InSolution; // is this satellite in the position solution
|
||||
}
|
||||
|
||||
function loadSatellites(data) {
|
||||
function loadSatellites(satellites) {
|
||||
if (($scope === undefined) || ($scope === null))
|
||||
return; // we are getting called once after clicking away from the status page
|
||||
|
||||
var satellites = data; // it seems the json was already converted to an object list by the http request
|
||||
$scope.raw_data = angular.toJson(data, true);
|
||||
$scope.raw_data = angular.toJson(satellites, true);
|
||||
|
||||
$scope.data_list.length = 0; // clear array
|
||||
// we need to use an array so AngularJS can perform sorting; it also means we need to loop to find a tower in the towers set
|
||||
|
@ -264,11 +262,9 @@ function GPSCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
}
|
||||
// $scope.$apply();
|
||||
}
|
||||
|
||||
var updateSatellites = $interval(function () {
|
||||
// refresh satellite info once each second (aka polling)
|
||||
getSatellites();
|
||||
}, 1000, 0, false);
|
||||
|
||||
// refresh satellite info once each second (aka polling)
|
||||
var updateSatellites = $interval(getSatellites, 1000, 0, false);
|
||||
|
||||
$state.get('gps').onEnter = function () {
|
||||
// everything gets handled correctly by the controller
|
||||
|
|
Ładowanie…
Reference in New Issue