kopia lustrzana https://github.com/cyoung/stratux
Merge remote-tracking branch 'origin/master' into ahrs_dev_protocolfun
commit
fcf524b03c
10
README.md
10
README.md
|
@ -13,9 +13,6 @@ Raspberry Pi 2 with the Edimax EW-7811Un Wi-Fi dongle is supported but not recom
|
||||||
|
|
||||||
Tested and works well with most common R820T and R820T2 RTL-SDR devices.
|
Tested and works well with most common R820T and R820T2 RTL-SDR devices.
|
||||||
|
|
||||||
Tested with and preliminary support added for [uAvionix pingEFB dual-link ADS-B receiver](http://www.uavionix.com/products/pingefb/).
|
|
||||||
|
|
||||||
|
|
||||||
Apps with stratux recognition/support:
|
Apps with stratux recognition/support:
|
||||||
* Seattle Avionics FlyQ EFB 2.1.1+.
|
* Seattle Avionics FlyQ EFB 2.1.1+.
|
||||||
* AvNav EFB 2.0.0+.
|
* AvNav EFB 2.0.0+.
|
||||||
|
@ -31,10 +28,17 @@ Tested weather/traffic displays:
|
||||||
* ForeFlight 7+ - weather, traffic. AHRS not functional.
|
* ForeFlight 7+ - weather, traffic. AHRS not functional.
|
||||||
* Avare
|
* Avare
|
||||||
|
|
||||||
|
Other EFBs? See the [app vendor integration guide](https://github.com/cyoung/stratux/blob/master/notes/app-vendor-integration.md).
|
||||||
|
|
||||||
|
Dangerzone builds (AHRS display):
|
||||||
|
* ForeFlight 7+ - weather, traffic, AHRS.
|
||||||
|
|
||||||
Questions? [See the FAQ](https://github.com/cyoung/stratux/wiki/FAQ)
|
Questions? [See the FAQ](https://github.com/cyoung/stratux/wiki/FAQ)
|
||||||
|
|
||||||
http://stratux.me/
|
http://stratux.me/
|
||||||
|
|
||||||
|
http://slack.stratux.me/
|
||||||
|
|
||||||
https://www.reddit.com/r/stratux
|
https://www.reddit.com/r/stratux
|
||||||
|
|
||||||
Jet tests (high gain antennas):
|
Jet tests (high gain antennas):
|
||||||
|
|
|
@ -18,3 +18,6 @@ deployment:
|
||||||
branch: master
|
branch: master
|
||||||
commands:
|
commands:
|
||||||
- yes | ssh -i ~/.ssh/id_updates.stratux.me stratux-updates@updates.stratux.me "touch queue/`git log -n 1 --pretty=%H`"
|
- yes | ssh -i ~/.ssh/id_updates.stratux.me stratux-updates@updates.stratux.me "touch queue/`git log -n 1 --pretty=%H`"
|
||||||
|
branch: ahrs_dev
|
||||||
|
commands:
|
||||||
|
- yes | ssh -i ~/.ssh/id_updates.stratux.me stratux-updates@updates.stratux.me "touch queue/`git log -n 1 --pretty=%H`"
|
||||||
|
|
2
goflying
2
goflying
|
@ -1 +1 @@
|
||||||
Subproject commit 083dd940f35eed0505f3cded7d8b6aa5f70b4e35
|
Subproject commit a9f32832e8fd8cac2b2e10cf673f0b79e1cec67d
|
|
@ -1,6 +1,8 @@
|
||||||
auto lo
|
auto lo
|
||||||
|
|
||||||
iface lo inet loopback
|
iface lo inet loopback
|
||||||
|
|
||||||
|
allow-hotplug eth0
|
||||||
iface eth0 inet dhcp
|
iface eth0 inet dhcp
|
||||||
|
|
||||||
allow-hotplug wlan0
|
allow-hotplug wlan0
|
||||||
|
|
|
@ -108,6 +108,65 @@ var maxSignalStrength int
|
||||||
var stratuxBuild string
|
var stratuxBuild string
|
||||||
var stratuxVersion string
|
var stratuxVersion string
|
||||||
|
|
||||||
|
var product_name_map = map[int]string{
|
||||||
|
0: "METAR",
|
||||||
|
1: "TAF",
|
||||||
|
2: "SIGMET",
|
||||||
|
3: "Conv SIGMET",
|
||||||
|
4: "AIRMET",
|
||||||
|
5: "PIREP",
|
||||||
|
6: "Severe Wx",
|
||||||
|
7: "Winds Aloft",
|
||||||
|
8: "NOTAM", //"NOTAM (Including TFRs) and Service Status";
|
||||||
|
9: "D-ATIS", //"Aerodrome and Airspace – D-ATIS";
|
||||||
|
10: "Terminal Wx", //"Aerodrome and Airspace - TWIP";
|
||||||
|
11: "AIRMET", //"Aerodrome and Airspace - AIRMET";
|
||||||
|
12: "SIGMET", //"Aerodrome and Airspace - SIGMET/Convective SIGMET";
|
||||||
|
13: "SUA", //"Aerodrome and Airspace - SUA Status";
|
||||||
|
20: "METAR", //"METAR and SPECI";
|
||||||
|
21: "TAF", //"TAF and Amended TAF";
|
||||||
|
22: "SIGMET", //"SIGMET";
|
||||||
|
23: "Conv SIGMET", //"Convective SIGMET";
|
||||||
|
24: "AIRMET", //"AIRMET";
|
||||||
|
25: "PIREP", //"PIREP";
|
||||||
|
26: "Severe Wx", //"AWW";
|
||||||
|
27: "Winds Aloft", //"Winds and Temperatures Aloft";
|
||||||
|
51: "NEXRAD", //"National NEXRAD, Type 0 - 4 level";
|
||||||
|
52: "NEXRAD", //"National NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
|
||||||
|
53: "NEXRAD", //"National NEXRAD, Type 2 - 8 level";
|
||||||
|
54: "NEXRAD", //"National NEXRAD, Type 3 - 16 level";
|
||||||
|
55: "NEXRAD", //"Regional NEXRAD, Type 0 - low dynamic range";
|
||||||
|
56: "NEXRAD", //"Regional NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
|
||||||
|
57: "NEXRAD", //"Regional NEXRAD, Type 2 - 8 level";
|
||||||
|
58: "NEXRAD", //"Regional NEXRAD, Type 3 - 16 level";
|
||||||
|
59: "NEXRAD", //"Individual NEXRAD, Type 0 - low dynamic range";
|
||||||
|
60: "NEXRAD", //"Individual NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
|
||||||
|
61: "NEXRAD", //"Individual NEXRAD, Type 2 - 8 level";
|
||||||
|
62: "NEXRAD", //"Individual NEXRAD, Type 3 - 16 level";
|
||||||
|
63: "NEXRAD Regional", //"Global Block Representation - Regional NEXRAD, Type 4 – 8 level";
|
||||||
|
64: "NEXRAD CONUS", //"Global Block Representation - CONUS NEXRAD, Type 4 - 8 level";
|
||||||
|
81: "Tops", //"Radar echo tops graphic, scheme 1: 16-level";
|
||||||
|
82: "Tops", //"Radar echo tops graphic, scheme 2: 8-level";
|
||||||
|
83: "Tops", //"Storm tops and velocity";
|
||||||
|
101: "Lightning", //"Lightning strike type 1 (pixel level)";
|
||||||
|
102: "Lightning", //"Lightning strike type 2 (grid element level)";
|
||||||
|
151: "Lightning", //"Point phenomena, vector format";
|
||||||
|
201: "Surface", //"Surface conditions/winter precipitation graphic";
|
||||||
|
202: "Surface", //"Surface weather systems";
|
||||||
|
254: "G-AIRMET", //"AIRMET, SIGMET: Bitmap encoding";
|
||||||
|
351: "Time", //"System Time";
|
||||||
|
352: "Status", //"Operational Status";
|
||||||
|
353: "Status", //"Ground Station Status";
|
||||||
|
401: "Imagery", //"Generic Raster Scan Data Product APDU Payload Format Type 1";
|
||||||
|
402: "Text",
|
||||||
|
403: "Vector Imagery", //"Generic Vector Data Product APDU Payload Format Type 1";
|
||||||
|
404: "Symbols",
|
||||||
|
405: "Text",
|
||||||
|
411: "Text", //"Generic Textual Data Product APDU Payload Format Type 1";
|
||||||
|
412: "Symbols", //"Generic Symbolic Product APDU Payload Format Type 1";
|
||||||
|
413: "Text", //"Generic Textual Data Product APDU Payload Format Type 2";
|
||||||
|
}
|
||||||
|
|
||||||
// CRC16 table generated to use to work with GDL90 messages.
|
// CRC16 table generated to use to work with GDL90 messages.
|
||||||
var Crc16Table [256]uint16
|
var Crc16Table [256]uint16
|
||||||
|
|
||||||
|
@ -795,6 +854,15 @@ func updateStatus() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
globalStatus.Logfile_Size = fileInfo.Size()
|
globalStatus.Logfile_Size = fileInfo.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ahrsLogSize int64
|
||||||
|
ahrsLogFiles, _ := ioutil.ReadDir("/var/log")
|
||||||
|
for _, f := range ahrsLogFiles {
|
||||||
|
if v, _ := filepath.Match("sensors_*.csv", f.Name()); v {
|
||||||
|
ahrsLogSize += f.Size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalStatus.AHRS_LogFiles_Size = ahrsLogSize
|
||||||
}
|
}
|
||||||
|
|
||||||
type WeatherMessage struct {
|
type WeatherMessage struct {
|
||||||
|
@ -963,65 +1031,6 @@ func parseInput(buf string) ([]byte, uint16) {
|
||||||
return frame, msgtype
|
return frame, msgtype
|
||||||
}
|
}
|
||||||
|
|
||||||
var product_name_map = map[int]string{
|
|
||||||
0: "METAR",
|
|
||||||
1: "TAF",
|
|
||||||
2: "SIGMET",
|
|
||||||
3: "Conv SIGMET",
|
|
||||||
4: "AIRMET",
|
|
||||||
5: "PIREP",
|
|
||||||
6: "Severe Wx",
|
|
||||||
7: "Winds Aloft",
|
|
||||||
8: "NOTAM", //"NOTAM (Including TFRs) and Service Status";
|
|
||||||
9: "D-ATIS", //"Aerodrome and Airspace – D-ATIS";
|
|
||||||
10: "Terminal Wx", //"Aerodrome and Airspace - TWIP";
|
|
||||||
11: "AIRMET", //"Aerodrome and Airspace - AIRMET";
|
|
||||||
12: "SIGMET", //"Aerodrome and Airspace - SIGMET/Convective SIGMET";
|
|
||||||
13: "SUA", //"Aerodrome and Airspace - SUA Status";
|
|
||||||
20: "METAR", //"METAR and SPECI";
|
|
||||||
21: "TAF", //"TAF and Amended TAF";
|
|
||||||
22: "SIGMET", //"SIGMET";
|
|
||||||
23: "Conv SIGMET", //"Convective SIGMET";
|
|
||||||
24: "AIRMET", //"AIRMET";
|
|
||||||
25: "PIREP", //"PIREP";
|
|
||||||
26: "Severe Wx", //"AWW";
|
|
||||||
27: "Winds Aloft", //"Winds and Temperatures Aloft";
|
|
||||||
51: "NEXRAD", //"National NEXRAD, Type 0 - 4 level";
|
|
||||||
52: "NEXRAD", //"National NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
|
|
||||||
53: "NEXRAD", //"National NEXRAD, Type 2 - 8 level";
|
|
||||||
54: "NEXRAD", //"National NEXRAD, Type 3 - 16 level";
|
|
||||||
55: "NEXRAD", //"Regional NEXRAD, Type 0 - low dynamic range";
|
|
||||||
56: "NEXRAD", //"Regional NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
|
|
||||||
57: "NEXRAD", //"Regional NEXRAD, Type 2 - 8 level";
|
|
||||||
58: "NEXRAD", //"Regional NEXRAD, Type 3 - 16 level";
|
|
||||||
59: "NEXRAD", //"Individual NEXRAD, Type 0 - low dynamic range";
|
|
||||||
60: "NEXRAD", //"Individual NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
|
|
||||||
61: "NEXRAD", //"Individual NEXRAD, Type 2 - 8 level";
|
|
||||||
62: "NEXRAD", //"Individual NEXRAD, Type 3 - 16 level";
|
|
||||||
63: "NEXRAD Regional", //"Global Block Representation - Regional NEXRAD, Type 4 – 8 level";
|
|
||||||
64: "NEXRAD CONUS", //"Global Block Representation - CONUS NEXRAD, Type 4 - 8 level";
|
|
||||||
81: "Tops", //"Radar echo tops graphic, scheme 1: 16-level";
|
|
||||||
82: "Tops", //"Radar echo tops graphic, scheme 2: 8-level";
|
|
||||||
83: "Tops", //"Storm tops and velocity";
|
|
||||||
101: "Lightning", //"Lightning strike type 1 (pixel level)";
|
|
||||||
102: "Lightning", //"Lightning strike type 2 (grid element level)";
|
|
||||||
151: "Lightning", //"Point phenomena, vector format";
|
|
||||||
201: "Surface", //"Surface conditions/winter precipitation graphic";
|
|
||||||
202: "Surface", //"Surface weather systems";
|
|
||||||
254: "G-AIRMET", //"AIRMET, SIGMET: Bitmap encoding";
|
|
||||||
351: "Time", //"System Time";
|
|
||||||
352: "Status", //"Operational Status";
|
|
||||||
353: "Status", //"Ground Station Status";
|
|
||||||
401: "Imagery", //"Generic Raster Scan Data Product APDU Payload Format Type 1";
|
|
||||||
402: "Text",
|
|
||||||
403: "Vector Imagery", //"Generic Vector Data Product APDU Payload Format Type 1";
|
|
||||||
404: "Symbols",
|
|
||||||
405: "Text",
|
|
||||||
411: "Text", //"Generic Textual Data Product APDU Payload Format Type 1";
|
|
||||||
412: "Symbols", //"Generic Symbolic Product APDU Payload Format Type 1";
|
|
||||||
413: "Text", //"Generic Textual Data Product APDU Payload Format Type 2";
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProductNameFromId(product_id int) string {
|
func getProductNameFromId(product_id int) string {
|
||||||
name, present := product_name_map[product_id]
|
name, present := product_name_map[product_id]
|
||||||
if present {
|
if present {
|
||||||
|
@ -1050,6 +1059,7 @@ type settings struct {
|
||||||
AHRSLog bool
|
AHRSLog bool
|
||||||
IMUMapping [2]int // Map from aircraft axis to sensor axis: accelerometer
|
IMUMapping [2]int // Map from aircraft axis to sensor axis: accelerometer
|
||||||
SensorQuaternion [4]float64 // Quaternion mapping from sensor frame to aircraft frame
|
SensorQuaternion [4]float64 // Quaternion mapping from sensor frame to aircraft frame
|
||||||
|
C, D [3]float64 // IMU Accel, Gyro zero bias
|
||||||
PPM int
|
PPM int
|
||||||
OwnshipModeS string
|
OwnshipModeS string
|
||||||
WatchList string
|
WatchList string
|
||||||
|
@ -1100,6 +1110,7 @@ type status struct {
|
||||||
UAT_OTHER_total uint32
|
UAT_OTHER_total uint32
|
||||||
Errors []string
|
Errors []string
|
||||||
Logfile_Size int64
|
Logfile_Size int64
|
||||||
|
AHRS_LogFiles_Size int64
|
||||||
BMPConnected bool
|
BMPConnected bool
|
||||||
IMUConnected bool
|
IMUConnected bool
|
||||||
}
|
}
|
||||||
|
@ -1122,7 +1133,7 @@ func defaultSettings() {
|
||||||
globalSettings.DisplayTrafficSource = false
|
globalSettings.DisplayTrafficSource = false
|
||||||
globalSettings.ReplayLog = false //TODO: 'true' for debug builds.
|
globalSettings.ReplayLog = false //TODO: 'true' for debug builds.
|
||||||
globalSettings.AHRSLog = false
|
globalSettings.AHRSLog = false
|
||||||
globalSettings.IMUMapping = [2]int{-1, -3} // OpenFlightBox AHRS normal mapping
|
globalSettings.IMUMapping = [2]int{-1, 0}
|
||||||
globalSettings.OwnshipModeS = "F00000"
|
globalSettings.OwnshipModeS = "F00000"
|
||||||
globalSettings.DeveloperMode = false
|
globalSettings.DeveloperMode = false
|
||||||
globalSettings.StaticIps = make([]string, 0)
|
globalSettings.StaticIps = make([]string, 0)
|
||||||
|
|
|
@ -26,6 +26,8 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
"archive/zip"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SettingMessage struct {
|
type SettingMessage struct {
|
||||||
|
@ -387,10 +389,28 @@ func doReboot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDeleteLogFile(w http.ResponseWriter, r *http.Request) {
|
func handleDeleteLogFile(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Printf("handleDeleteLogFile called!!!\n")
|
log.Println("handleDeleteLogFile called!!!")
|
||||||
clearDebugLogFile()
|
clearDebugLogFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleDeleteAHRSLogFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
files, err := ioutil.ReadDir("/var/log")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("error deleting AHRS logs: %s", err), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var fn string
|
||||||
|
for _, f := range files {
|
||||||
|
fn = f.Name()
|
||||||
|
if v, _ := filepath.Match("sensors_*.csv", fn) ; v {
|
||||||
|
os.Remove("/var/log/" + fn)
|
||||||
|
log.Printf("Deleting AHRS log file %s\n", fn)
|
||||||
|
}
|
||||||
|
analysisLogger = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handleDevelModeToggle(w http.ResponseWriter, r *http.Request) {
|
func handleDevelModeToggle(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Printf("handleDevelModeToggle called!!!\n")
|
log.Printf("handleDevelModeToggle called!!!\n")
|
||||||
globalSettings.DeveloperMode = true
|
globalSettings.DeveloperMode = true
|
||||||
|
@ -410,8 +430,6 @@ func handleRebootRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
go delayReboot()
|
go delayReboot()
|
||||||
}
|
}
|
||||||
|
|
||||||
var f int // We need this to be global to handle successive calls to handleOrientAHRS.
|
|
||||||
|
|
||||||
func handleOrientAHRS(w http.ResponseWriter, r *http.Request) {
|
func handleOrientAHRS(w http.ResponseWriter, r *http.Request) {
|
||||||
// define header in support of cross-domain AJAX
|
// define header in support of cross-domain AJAX
|
||||||
setNoCache(w)
|
setNoCache(w)
|
||||||
|
@ -425,7 +443,6 @@ func handleOrientAHRS(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method == "POST" {
|
if r.Method == "POST" {
|
||||||
var (
|
var (
|
||||||
action []byte = make([]byte, 1)
|
action []byte = make([]byte, 1)
|
||||||
u int
|
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -436,38 +453,22 @@ func handleOrientAHRS(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
switch action[0] {
|
switch action[0] {
|
||||||
case 'f': // Set sensor "forward" direction (toward nose of airplane).
|
case 'f': // Set sensor "forward" direction (toward nose of airplane).
|
||||||
if f, err = getMinAccelDirection(); err != nil {
|
f, err := getMinAccelDirection()
|
||||||
|
if err != nil {
|
||||||
log.Printf("AHRS Error: sensor orientation: couldn't read accelerometer: %s\n", err)
|
log.Printf("AHRS Error: sensor orientation: couldn't read accelerometer: %s\n", err)
|
||||||
http.Error(w, fmt.Sprintf("couldn't read accelerometer: %s\n", err), http.StatusBadRequest)
|
http.Error(w, fmt.Sprintf("couldn't read accelerometer: %s\n", err), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("AHRS Info: sensor orientation: received forward direction %d\n", f)
|
log.Printf("AHRS Info: sensor orientation success! forward axis is %d\n", f)
|
||||||
case 'u': // Set sensor "up" direction (toward top of airplane).
|
globalSettings.IMUMapping = [2]int{f, 0}
|
||||||
if u, err = getMinAccelDirection(); err != nil {
|
case 'd': // Set sensor "up" direction (toward top of airplane).
|
||||||
log.Printf("AHRS Error: sensor orientation: couldn't read accelerometer: %s\n", err)
|
globalSettings.SensorQuaternion = [4]float64{0, 0, 0, 0}
|
||||||
http.Error(w, fmt.Sprintf("couldn't read accelerometer: %s\n", err), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("AHRS Info: sensor orientation: received up direction %d\n", u)
|
|
||||||
|
|
||||||
if f == u || f == -u {
|
|
||||||
log.Printf("AHRS Error: sensor orientation: up (%d) and forward (%d) axes cannot be the same\n", u, f)
|
|
||||||
http.Error(w, fmt.Sprintf("up (%d) and forward (%d) axes cannot be the same", u, f),
|
|
||||||
http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
globalSettings.IMUMapping = [2]int{f, u}
|
|
||||||
saveSettings()
|
saveSettings()
|
||||||
myIMUReader.Close()
|
myIMUReader.Close()
|
||||||
globalStatus.IMUConnected = false // restart the processes depending on the orientation
|
globalStatus.IMUConnected = false // restart the processes depending on the orientation
|
||||||
CageAHRS()
|
ResetAHRSGLoad()
|
||||||
log.Printf("AHRS Info: sensor orientation success! forward: %d; up: %d\n", f, u)
|
time.Sleep(2000 * time.Millisecond)
|
||||||
default: // Cancel the sensor calibration.
|
|
||||||
f = 0
|
|
||||||
log.Println("AHRS Info: sensor orientation: canceled")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,6 +487,21 @@ func handleCageAHRS(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleCalibrateAHRS(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// define header in support of cross-domain AJAX
|
||||||
|
setNoCache(w)
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Method", "GET, POST, OPTIONS")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
|
||||||
|
|
||||||
|
// For an OPTION method request, we return header without processing.
|
||||||
|
// This ensures we are recognized as supporting cross-domain AJAX REST calls.
|
||||||
|
if r.Method == "POST" {
|
||||||
|
CalibrateAHRS()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handleResetGMeter(w http.ResponseWriter, r *http.Request) {
|
func handleResetGMeter(w http.ResponseWriter, r *http.Request) {
|
||||||
// define header in support of cross-domain AJAX
|
// define header in support of cross-domain AJAX
|
||||||
setNoCache(w)
|
setNoCache(w)
|
||||||
|
@ -528,13 +544,63 @@ func delayReboot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDownloadLogRequest(w http.ResponseWriter, r *http.Request) {
|
func handleDownloadLogRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "applicaiton/zip")
|
w.Header().Set("Content-Type", "application/zip")
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename='stratux.log'")
|
w.Header().Set("Content-Disposition", "attachment; filename='stratux.log'")
|
||||||
http.ServeFile(w, r, "/var/log/stratux.log")
|
http.ServeFile(w, r, "/var/log/stratux.log")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleDownloadAHRSLogsRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Common error handler
|
||||||
|
httpErr := func(w http.ResponseWriter, e error) {
|
||||||
|
http.Error(w, fmt.Sprintf("error zipping AHRS logs: %s", e), http.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir("/var/log")
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
z := zip.NewWriter(w)
|
||||||
|
defer z.Close()
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
fn := f.Name()
|
||||||
|
v1, _ := filepath.Match("sensors_*.csv", fn)
|
||||||
|
v2, _ := filepath.Match("stratux.log", fn)
|
||||||
|
if !(v1 || v2) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
unzippedFile, err := os.Open("/var/log/" + fn)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fh, err := zip.FileInfoHeader(f)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
zippedFile, err := z.CreateHeader(fh)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(zippedFile, unzippedFile)
|
||||||
|
if err != nil {
|
||||||
|
httpErr(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/zip")
|
||||||
|
w.Header().Set("Content-Disposition", "attachment; filename=\"ahrs_logs.zip\"")
|
||||||
|
}
|
||||||
|
|
||||||
func handleDownloadDBRequest(w http.ResponseWriter, r *http.Request) {
|
func handleDownloadDBRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "applicaiton/zip")
|
w.Header().Set("Content-Type", "application/zip")
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename='stratux.sqlite'")
|
w.Header().Set("Content-Disposition", "attachment; filename='stratux.sqlite'")
|
||||||
http.ServeFile(w, r, "/var/log/stratux.sqlite")
|
http.ServeFile(w, r, "/var/log/stratux.sqlite")
|
||||||
}
|
}
|
||||||
|
@ -747,13 +813,14 @@ func managementInterface() {
|
||||||
http.HandleFunc("/updateUpload", handleUpdatePostRequest)
|
http.HandleFunc("/updateUpload", handleUpdatePostRequest)
|
||||||
http.HandleFunc("/roPartitionRebuild", handleroPartitionRebuild)
|
http.HandleFunc("/roPartitionRebuild", handleroPartitionRebuild)
|
||||||
http.HandleFunc("/develmodetoggle", handleDevelModeToggle)
|
http.HandleFunc("/develmodetoggle", handleDevelModeToggle)
|
||||||
|
|
||||||
http.HandleFunc("/orientAHRS", handleOrientAHRS)
|
http.HandleFunc("/orientAHRS", handleOrientAHRS)
|
||||||
|
http.HandleFunc("/calibrateAHRS", handleCalibrateAHRS)
|
||||||
http.HandleFunc("/cageAHRS", handleCageAHRS)
|
http.HandleFunc("/cageAHRS", handleCageAHRS)
|
||||||
http.HandleFunc("/resetGMeter", handleResetGMeter)
|
http.HandleFunc("/resetGMeter", handleResetGMeter)
|
||||||
|
|
||||||
http.HandleFunc("/deletelogfile", handleDeleteLogFile)
|
http.HandleFunc("/deletelogfile", handleDeleteLogFile)
|
||||||
http.HandleFunc("/downloadlog", handleDownloadLogRequest)
|
http.HandleFunc("/downloadlog", handleDownloadLogRequest)
|
||||||
|
http.HandleFunc("/deleteahrslogfiles", handleDeleteAHRSLogFiles)
|
||||||
|
http.HandleFunc("/downloadahrslogs", handleDownloadAHRSLogsRequest)
|
||||||
http.HandleFunc("/downloaddb", handleDownloadDBRequest)
|
http.HandleFunc("/downloaddb", handleDownloadDBRequest)
|
||||||
|
|
||||||
err := http.ListenAndServe(managementAddr, nil)
|
err := http.ListenAndServe(managementAddr, nil)
|
||||||
|
|
169
main/sensors.go
169
main/sensors.go
|
@ -5,6 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"../goflying/ahrs"
|
"../goflying/ahrs"
|
||||||
|
@ -16,16 +17,17 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
numRetries uint8 = 5
|
numRetries uint8 = 5
|
||||||
|
calCLimit = 0.15
|
||||||
|
calDLimit = 10.0
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
i2cbus embd.I2CBus
|
i2cbus embd.I2CBus
|
||||||
myPressureReader sensors.PressureReader
|
myPressureReader sensors.PressureReader
|
||||||
myIMUReader sensors.IMUReader
|
myIMUReader sensors.IMUReader
|
||||||
s ahrs.AHRSProvider
|
cal chan (string)
|
||||||
cal chan (bool)
|
|
||||||
analysisLogger *ahrs.AHRSLogger
|
analysisLogger *ahrs.AHRSLogger
|
||||||
ahrsCalibrating, needsCage bool // Does the sensor orientation matrix need to be recalculated?
|
ahrsCalibrating bool
|
||||||
logMap map[string]interface{}
|
logMap map[string]interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,7 +46,6 @@ func pollSensors() {
|
||||||
|
|
||||||
// If it's not currently connected, try connecting to pressure sensor
|
// If it's not currently connected, try connecting to pressure sensor
|
||||||
if globalSettings.BMP_Sensor_Enabled && !globalStatus.BMPConnected {
|
if globalSettings.BMP_Sensor_Enabled && !globalStatus.BMPConnected {
|
||||||
log.Println("AHRS Info: attempting pressure sensor connection.")
|
|
||||||
globalStatus.BMPConnected = initPressureSensor() // I2C temperature and pressure altitude.
|
globalStatus.BMPConnected = initPressureSensor() // I2C temperature and pressure altitude.
|
||||||
go tempAndPressureSender()
|
go tempAndPressureSender()
|
||||||
}
|
}
|
||||||
|
@ -125,39 +126,31 @@ func tempAndPressureSender() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initIMU() (ok bool) {
|
func initIMU() (ok bool) {
|
||||||
log.Println("AHRS Info: attempting to connect to MPU9250")
|
|
||||||
imu, err := sensors.NewMPU9250()
|
imu, err := sensors.NewMPU9250()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
myIMUReader = imu
|
myIMUReader = imu
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
log.Println("AHRS Info: Successfully connected MPU9250")
|
log.Println("AHRS Info: Successfully connected MPU9250")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO westphae: try to connect to MPU9150 or other IMUs.
|
// TODO westphae: try to connect to MPU9150 or other IMUs.
|
||||||
|
|
||||||
log.Println("AHRS Error: couldn't initialize MPU9250")
|
log.Println("AHRS Error: couldn't initialize an IMU")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func sensorAttitudeSender() {
|
func sensorAttitudeSender() {
|
||||||
var (
|
var (
|
||||||
roll, pitch, heading float64
|
|
||||||
t time.Time
|
t time.Time
|
||||||
m *ahrs.Measurement
|
roll, pitch, heading float64
|
||||||
a, b, c, d, mm [3]float64 // IMU measurements: accel, gyro, accel bias, gyro bias, magnetometer
|
|
||||||
f [4]float64 // Sensor orientation quaternion
|
|
||||||
ff [3][3]float64 // Sensor orientation matrix
|
|
||||||
cc float64
|
|
||||||
mpuError, magError error
|
mpuError, magError error
|
||||||
failNum uint8
|
failNum uint8
|
||||||
)
|
)
|
||||||
|
|
||||||
log.Println("AHRS Info: initializing new Simple AHRS")
|
log.Println("AHRS Info: initializing new Simple AHRS")
|
||||||
s = ahrs.InitializeSimple()
|
s := ahrs.NewSimpleAHRS()
|
||||||
m = ahrs.NewMeasurement()
|
m := ahrs.NewMeasurement()
|
||||||
cal = make(chan (bool), 1)
|
cal = make(chan (string), 1)
|
||||||
needsCage = true
|
|
||||||
|
|
||||||
// Set up loggers for analysis
|
// Set up loggers for analysis
|
||||||
ahrswebListener, err := ahrsweb.NewKalmanListener()
|
ahrswebListener, err := ahrsweb.NewKalmanListener()
|
||||||
|
@ -171,74 +164,81 @@ func sensorAttitudeSender() {
|
||||||
// Need a sampling freq faster than 10Hz
|
// Need a sampling freq faster than 10Hz
|
||||||
timer := time.NewTicker(50 * time.Millisecond) // ~20Hz update.
|
timer := time.NewTicker(50 * time.Millisecond) // ~20Hz update.
|
||||||
for {
|
for {
|
||||||
|
// Set sensor gyro calibrations
|
||||||
|
if c, d := &globalSettings.C, &globalSettings.D; d[0]*d[0] + d[1]*d[1] + d[2]*d[2] > 0 {
|
||||||
|
s.SetCalibrations(c, d)
|
||||||
|
log.Printf("AHRS Info: IMU Calibrations read from settings: accel %6f %6f %6f; gyro %6f %6f %6f\n",
|
||||||
|
c[0], c[1], c[2], d[0], d[1], d[2])
|
||||||
|
} else {
|
||||||
// Do an initial calibration
|
// Do an initial calibration
|
||||||
select { // Don't block if cal isn't receiving: only need one calibration in the queue at a time.
|
select { // Don't block if cal isn't receiving: only need one calibration in the queue at a time.
|
||||||
case cal <- true:
|
case cal <- "cal":
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set sensor rotation matrix / quaternion
|
// Set sensor quaternion
|
||||||
f[0] = globalSettings.SensorQuaternion[0]
|
if f := &globalSettings.SensorQuaternion; f[0]*f[0] + f[1]*f[1] + f[2]*f[2] + f[3]*f[3] > 0 {
|
||||||
f[1] = globalSettings.SensorQuaternion[1]
|
s.SetSensorQuaternion(f)
|
||||||
f[2] = globalSettings.SensorQuaternion[2]
|
} else {
|
||||||
f[3] = globalSettings.SensorQuaternion[3]
|
select { // Don't block if cal isn't receiving: only need one calibration in the queue at a time.
|
||||||
if f[0]*f[0]+f[1]*f[1]+f[2]*f[2]+f[3]*f[3] > 0.5 {
|
case cal <- "level":
|
||||||
// Use the sensor rotation quaternion from config.
|
default:
|
||||||
ff = *ahrs.QuaternionToRotationMatrix(f[0], f[1], f[2], f[3])
|
}
|
||||||
needsCage = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
failNum = 0
|
failNum = 0
|
||||||
<-timer.C
|
<-timer.C
|
||||||
|
time.Sleep(950 * time.Millisecond)
|
||||||
for globalSettings.IMU_Sensor_Enabled && globalStatus.IMUConnected {
|
for globalSettings.IMU_Sensor_Enabled && globalStatus.IMUConnected {
|
||||||
<-timer.C
|
<-timer.C
|
||||||
|
|
||||||
|
// Process calibration and level requests
|
||||||
select {
|
select {
|
||||||
case <-cal:
|
case action := <-cal:
|
||||||
log.Println("AHRS Info: Calibrating IMU")
|
log.Printf("AHRS Info: cal received action %s\n", action)
|
||||||
ahrsCalibrating = true
|
ahrsCalibrating = true
|
||||||
//TODO westphae: check for errors when reading IMU
|
|
||||||
myIMUReader.Read() // Clear out the averages
|
myIMUReader.Read() // Clear out the averages
|
||||||
|
var (
|
||||||
|
nTries uint8
|
||||||
|
cc, dd float64
|
||||||
|
)
|
||||||
|
for (math.Abs(cc-1) > calCLimit || dd > calDLimit) && nTries < numRetries {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
_, d[0], d[1], d[2], c[0], c[1], c[2], _, _, _, _, _ = myIMUReader.Read()
|
_, d1, d2, d3, c1, c2, c3, _, _, _, mpuError, _ := myIMUReader.Read()
|
||||||
log.Printf("AHRS Info: IMU Calibrated: accel %6f %6f %6f; gyro %6f %6f %6f\n",
|
cc = math.Sqrt(c1*c1 + c2*c2 + c3*c3)
|
||||||
c[0], c[1], c[2], d[0], d[1], d[2])
|
dd = math.Sqrt(d1*d1 + d2*d2 + d3*d3)
|
||||||
ahrsCalibrating = false
|
nTries++
|
||||||
cc = math.Sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2])
|
log.Printf("AHRS Info: IMU calibration attempt #%d\n", nTries)
|
||||||
|
if mpuError != nil {
|
||||||
|
log.Printf("AHRS Info: Error reading IMU while calibrating: %s\n", mpuError)
|
||||||
|
} else {
|
||||||
|
if strings.Contains(action, "cal") { // Calibrate gyros
|
||||||
|
globalSettings.D = [3]float64{d1, d2, d3}
|
||||||
|
s.SetCalibrations(nil, &globalSettings.D)
|
||||||
|
log.Printf("AHRS Info: IMU gyro calibration: %3f %3f %3f\n", d1, d2, d3)
|
||||||
|
}
|
||||||
|
if strings.Contains(action, "level") { // Calibrate accel / level
|
||||||
|
globalSettings.C = [3]float64{c1, c2, c3}
|
||||||
|
s.SetCalibrations(&globalSettings.C, nil)
|
||||||
|
globalSettings.SensorQuaternion = *makeOrientationQuaternion(globalSettings.C)
|
||||||
|
s.SetSensorQuaternion(&globalSettings.SensorQuaternion)
|
||||||
s.Reset()
|
s.Reset()
|
||||||
|
log.Printf("AHRS Info: IMU accel calibration: %3f %3f %3f\n", c1, c2, c3)
|
||||||
|
log.Printf("AHRS Info: Caged to quaternion %v\n", globalSettings.SensorQuaternion)
|
||||||
|
}
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ahrsCalibrating = false
|
||||||
|
<-timer.C // Make sure we get data for the actual algorithm
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
if needsCage {
|
// Make the IMU sensor measurements.
|
||||||
log.Println("AHRS Info: Caging")
|
|
||||||
ff = *makeSensorRotationMatrix([3]float64{c[0], c[1], c[2]})
|
|
||||||
f[0], f[1], f[2], f[3] = ahrs.RotationMatrixToQuaternion(ff)
|
|
||||||
globalSettings.SensorQuaternion[0] = f[0]
|
|
||||||
globalSettings.SensorQuaternion[1] = f[1]
|
|
||||||
globalSettings.SensorQuaternion[2] = f[2]
|
|
||||||
globalSettings.SensorQuaternion[3] = f[3]
|
|
||||||
saveSettings()
|
|
||||||
needsCage = false
|
|
||||||
}
|
|
||||||
|
|
||||||
t = stratuxClock.Time
|
t = stratuxClock.Time
|
||||||
m.T = float64(t.UnixNano()/1000) / 1e6
|
m.T = float64(t.UnixNano()/1000) / 1e6
|
||||||
|
_, m.B1, m.B2, m.B3, m.A1, m.A2, m.A3, m.M1, m.M2, m.M3, mpuError, magError = myIMUReader.Read()
|
||||||
_, b[0], b[1], b[2], a[0], a[1], a[2], mm[0], mm[1], mm[2], mpuError, magError = myIMUReader.Read()
|
|
||||||
a[0] /= cc
|
|
||||||
a[1] /= cc
|
|
||||||
a[2] /= cc
|
|
||||||
b[0] -= d[0]
|
|
||||||
b[1] -= d[1]
|
|
||||||
b[2] -= d[2]
|
|
||||||
m.A1 = -(ff[0][0]*a[0] + ff[0][1]*a[1] + ff[0][2]*a[2])
|
|
||||||
m.A2 = -(ff[1][0]*a[0] + ff[1][1]*a[1] + ff[1][2]*a[2])
|
|
||||||
m.A3 = -(ff[2][0]*a[0] + ff[2][1]*a[1] + ff[2][2]*a[2])
|
|
||||||
m.B1 = ff[0][0]*b[0] + ff[0][1]*b[1] + ff[0][2]*b[2]
|
|
||||||
m.B2 = ff[1][0]*b[0] + ff[1][1]*b[1] + ff[1][2]*b[2]
|
|
||||||
m.B3 = ff[2][0]*b[0] + ff[2][1]*b[1] + ff[2][2]*b[2]
|
|
||||||
m.M1 = ff[0][0]*mm[0] + ff[0][1]*mm[1] + ff[0][2]*mm[2]
|
|
||||||
m.M2 = ff[1][0]*mm[0] + ff[1][1]*mm[1] + ff[1][2]*mm[2]
|
|
||||||
m.M3 = ff[2][0]*mm[0] + ff[2][1]*mm[1] + ff[2][2]*mm[2]
|
|
||||||
m.SValid = mpuError == nil
|
m.SValid = mpuError == nil
|
||||||
m.MValid = magError == nil
|
m.MValid = magError == nil
|
||||||
if mpuError != nil {
|
if mpuError != nil {
|
||||||
|
@ -254,11 +254,13 @@ func sensorAttitudeSender() {
|
||||||
}
|
}
|
||||||
failNum = 0
|
failNum = 0
|
||||||
if magError != nil {
|
if magError != nil {
|
||||||
|
if globalSettings.DEBUG {
|
||||||
log.Printf("AHRS Magnetometer Error, not using for this run: %s\n", magError)
|
log.Printf("AHRS Magnetometer Error, not using for this run: %s\n", magError)
|
||||||
|
}
|
||||||
m.MValid = false
|
m.MValid = false
|
||||||
// Don't necessarily disconnect here, unless AHRSProvider deeply depends on magnetometer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make the GPS measurements.
|
||||||
m.TW = float64(mySituation.GPSLastGroundTrackTime.UnixNano()/1000) / 1e6
|
m.TW = float64(mySituation.GPSLastGroundTrackTime.UnixNano()/1000) / 1e6
|
||||||
m.WValid = isGPSGroundTrackValid()
|
m.WValid = isGPSGroundTrackValid()
|
||||||
if m.WValid {
|
if m.WValid {
|
||||||
|
@ -271,10 +273,10 @@ func sensorAttitudeSender() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the AHRS calcs
|
// Run the AHRS calculations.
|
||||||
s.Compute(m)
|
s.Compute(m)
|
||||||
|
|
||||||
// If we have valid AHRS info, then update mySituation
|
// If we have valid AHRS info, then update mySituation.
|
||||||
mySituation.muAttitude.Lock()
|
mySituation.muAttitude.Lock()
|
||||||
if s.Valid() {
|
if s.Valid() {
|
||||||
roll, pitch, heading = s.RollPitchHeading()
|
roll, pitch, heading = s.RollPitchHeading()
|
||||||
|
@ -296,7 +298,6 @@ func sensorAttitudeSender() {
|
||||||
|
|
||||||
mySituation.AHRSLastAttitudeTime = t
|
mySituation.AHRSLastAttitudeTime = t
|
||||||
} else {
|
} else {
|
||||||
s.Reset()
|
|
||||||
mySituation.AHRSRoll = ahrs.Invalid
|
mySituation.AHRSRoll = ahrs.Invalid
|
||||||
mySituation.AHRSPitch = ahrs.Invalid
|
mySituation.AHRSPitch = ahrs.Invalid
|
||||||
mySituation.AHRSGyroHeading = ahrs.Invalid
|
mySituation.AHRSGyroHeading = ahrs.Invalid
|
||||||
|
@ -307,28 +308,27 @@ func sensorAttitudeSender() {
|
||||||
mySituation.AHRSGLoadMin = ahrs.Invalid
|
mySituation.AHRSGLoadMin = ahrs.Invalid
|
||||||
mySituation.AHRSGLoadMax = 0
|
mySituation.AHRSGLoadMax = 0
|
||||||
mySituation.AHRSLastAttitudeTime = time.Time{}
|
mySituation.AHRSLastAttitudeTime = time.Time{}
|
||||||
|
s.Reset()
|
||||||
}
|
}
|
||||||
mySituation.muAttitude.Unlock()
|
mySituation.muAttitude.Unlock()
|
||||||
|
|
||||||
makeAHRSGDL90Report() // Send whether or not valid - the function will invalidate the values as appropriate
|
makeAHRSGDL90Report() // Send whether or not valid - the function will invalidate the values as appropriate
|
||||||
// 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.
|
|
||||||
|
|
||||||
// Send to AHRS debugging server:
|
// Send to AHRS debugging server.
|
||||||
if ahrswebListener != nil {
|
if ahrswebListener != nil {
|
||||||
if err = ahrswebListener.Send(s.GetState(), m); err != nil {
|
if err = ahrswebListener.Send(s.GetState(), m); err != nil {
|
||||||
log.Printf("Error writing to ahrsweb: %s\n", err)
|
log.Printf("AHRS Error: couldn't write to ahrsweb: %s\n", err)
|
||||||
ahrswebListener = nil
|
ahrswebListener = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log it to csv for analysis
|
// Log it to csv for later analysis.
|
||||||
if globalSettings.AHRSLog && usage.Usage() < 0.95 {
|
if globalSettings.AHRSLog && usage.Usage() < 0.95 {
|
||||||
if analysisLogger == nil {
|
if analysisLogger == nil {
|
||||||
analysisFilename := filepath.Join(logDirf, fmt.Sprintf("sensors_%s.csv",
|
analysisFilename := fmt.Sprintf("sensors_%s.csv", time.Now().Format("20060102_150405"))
|
||||||
time.Now().Format("20060102_150405")))
|
|
||||||
logMap = s.GetLogMap()
|
logMap = s.GetLogMap()
|
||||||
updateExtraLogging()
|
updateExtraLogging()
|
||||||
analysisLogger = ahrs.NewAHRSLogger(analysisFilename, logMap)
|
analysisLogger = ahrs.NewAHRSLogger(filepath.Join(logDirf, analysisFilename), logMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
if analysisLogger != nil {
|
if analysisLogger != nil {
|
||||||
|
@ -353,10 +353,9 @@ func updateExtraLogging() {
|
||||||
logMap["BaroVerticalSpeed"] = float64(mySituation.BaroVerticalSpeed)
|
logMap["BaroVerticalSpeed"] = float64(mySituation.BaroVerticalSpeed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeSensorRotationMatrix(g [3]float64) (rotmat *[3][3]float64) {
|
func makeOrientationQuaternion(g [3]float64) (f *[4]float64) {
|
||||||
if globalSettings.IMUMapping[0] == 0 { // if unset, default to some standard orientation
|
if globalSettings.IMUMapping[0] == 0 { // if unset, default to some standard orientation
|
||||||
globalSettings.IMUMapping[0] = -1 // +2 for RY836AI
|
globalSettings.IMUMapping[0] = -1 // +2 for RY836AI
|
||||||
globalSettings.IMUMapping[1] = -3 // +3 for RY836AI
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the "forward direction" chosen during the orientation process.
|
// This is the "forward direction" chosen during the orientation process.
|
||||||
|
@ -370,8 +369,10 @@ func makeSensorRotationMatrix(g [3]float64) (rotmat *[3][3]float64) {
|
||||||
// Normalize the gravity vector to be 1 G.
|
// Normalize the gravity vector to be 1 G.
|
||||||
z, _ := ahrs.MakeUnitVector(g)
|
z, _ := ahrs.MakeUnitVector(g)
|
||||||
|
|
||||||
rotmat, _ = ahrs.MakeHardSoftRotationMatrix(*z, *x, [3]float64{0, 0, 1}, [3]float64{1, 0, 0})
|
rotmat, _ := ahrs.MakeHardSoftRotationMatrix(*z, *x, [3]float64{0, 0, 1}, [3]float64{1, 0, 0})
|
||||||
return rotmat
|
f = new([4]float64)
|
||||||
|
f[0], f[1], f[2], f[3] = ahrs.RotationMatrixToQuaternion(*rotmat)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used in the orientation process where the user specifies the forward and up directions.
|
// This is used in the orientation process where the user specifies the forward and up directions.
|
||||||
|
@ -407,10 +408,14 @@ func getMinAccelDirection() (i int, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// CageAHRS sends a signal to the AHRSProvider that it should be reset.
|
// CageAHRS sends a signal to the AHRSProvider that it should recalibrate and reset its level orientation.
|
||||||
func CageAHRS() {
|
func CageAHRS() {
|
||||||
needsCage = true
|
cal <- "level"
|
||||||
cal <- true
|
}
|
||||||
|
|
||||||
|
// CageAHRS sends a signal to the AHRSProvider that it should recalibrate and reset its level orientation.
|
||||||
|
func CalibrateAHRS() {
|
||||||
|
cal <- "cal"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetAHRSGLoad resets the min and max to the current G load value.
|
// ResetAHRSGLoad resets the min and max to the current G load value.
|
||||||
|
|
|
@ -91,7 +91,7 @@ Stratux makes available a webserver to retrieve statistics which may be useful t
|
||||||
|
|
||||||
* `http://192.168.10.1/getStatus` - device status and statistics. Example output (commented JSON):
|
* `http://192.168.10.1/getStatus` - device status and statistics. Example output (commented JSON):
|
||||||
|
|
||||||
```json
|
```javascript
|
||||||
{
|
{
|
||||||
"Version": "v0.5b1", // Software version.
|
"Version": "v0.5b1", // Software version.
|
||||||
"Devices": 0, // Number of radios connected.
|
"Devices": 0, // Number of radios connected.
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
package sensors
|
package sensors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"../goflying/mpu9250"
|
"../goflying/mpu9250"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,21 +26,16 @@ func NewMPU9250() (*MPU9250, error) {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
log.Println("AHRS Info: Making new MPU9250")
|
|
||||||
mpu, err = mpu9250.NewMPU9250(gyroRange, accelRange, updateFreq, true, false)
|
mpu, err = mpu9250.NewMPU9250(gyroRange, accelRange, updateFreq, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Gyro (Accel) LPFs to 20 (21) Hz to filter out prop/glareshield vibrations above 1200 (1260) RPM
|
// Set Gyro (Accel) LPFs to 20 (21) Hz to filter out prop/glareshield vibrations above 1200 (1260) RPM
|
||||||
log.Println("AHRS Info: Setting MPU9250 LPF")
|
|
||||||
mpu.SetGyroLPF(21)
|
mpu.SetGyroLPF(21)
|
||||||
mpu.SetAccelLPF(21)
|
mpu.SetAccelLPF(21)
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
m.mpu = mpu
|
m.mpu = mpu
|
||||||
|
|
||||||
log.Println("AHRS Info: monitoring IMU")
|
|
||||||
return &m, nil
|
return &m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,13 @@ var URL_SHUTDOWN = "http://" + URL_HOST_BASE + "/shutdown";
|
||||||
var URL_RESTARTAPP = "http://" + URL_HOST_BASE + "/restart";
|
var URL_RESTARTAPP = "http://" + URL_HOST_BASE + "/restart";
|
||||||
var URL_DEV_TOGGLE_GET = "http://" + URL_HOST_BASE + "/develmodetoggle";
|
var URL_DEV_TOGGLE_GET = "http://" + URL_HOST_BASE + "/develmodetoggle";
|
||||||
var URL_AHRS_ORIENT = "http://" + URL_HOST_BASE + "/orientAHRS";
|
var URL_AHRS_ORIENT = "http://" + URL_HOST_BASE + "/orientAHRS";
|
||||||
|
var URL_AHRS_CAL = "http://" + URL_HOST_BASE + "/calibrateAHRS";
|
||||||
var URL_AHRS_CAGE = "http://" + URL_HOST_BASE + "/cageAHRS";
|
var URL_AHRS_CAGE = "http://" + URL_HOST_BASE + "/cageAHRS";
|
||||||
var URL_GMETER_RESET = "http://" + URL_HOST_BASE + "/resetGMeter";
|
var URL_GMETER_RESET = "http://" + URL_HOST_BASE + "/resetGMeter";
|
||||||
var URL_DELETELOGFILE = "http://" + URL_HOST_BASE + "/deletelogfile";
|
var URL_DELETELOGFILE = "http://" + URL_HOST_BASE + "/deletelogfile";
|
||||||
var URL_DOWNLOADLOGFILE = "http://" + URL_HOST_BASE + "/downloadlog";
|
var URL_DOWNLOADLOGFILE = "http://" + URL_HOST_BASE + "/downloadlog";
|
||||||
|
var URL_DELETEAHRSLOGFILES = "http://" + URL_HOST_BASE + "/deleteahrslogfiles";
|
||||||
|
var URL_DOWNLOADAHRSLOGFILES = "http://" + URL_HOST_BASE + "/downloadahrslogs";
|
||||||
var URL_DOWNLOADDB = "http://" + URL_HOST_BASE + "/downloaddb";
|
var URL_DOWNLOADDB = "http://" + URL_HOST_BASE + "/downloaddb";
|
||||||
|
|
||||||
// define the module with dependency on mobile-angular-ui
|
// define the module with dependency on mobile-angular-ui
|
||||||
|
@ -91,7 +94,7 @@ app.controller('MainCtrl', function ($scope, $http) {
|
||||||
// any logic global logic
|
// any logic global logic
|
||||||
$http.get(URL_SETTINGS_GET)
|
$http.get(URL_SETTINGS_GET)
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
settings = angular.fromJson(response.data);
|
var settings = angular.fromJson(response.data);
|
||||||
$scope.DeveloperMode = settings.DeveloperMode;
|
$scope.DeveloperMode = settings.DeveloperMode;
|
||||||
}, function(response) {
|
}, function(response) {
|
||||||
//Second function handles error
|
//Second function handles error
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="panel-group col-sm-6">
|
<div class="panel-group col-sm-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
|
@ -8,9 +8,8 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="form-group reset-flow" align="center">
|
<div class="form-group reset-flow" align="center">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<a ng-click="postRestart()" class=
|
<a ng-click="postRestart()" class="btn btn-primary btn-block"
|
||||||
"btn btn-primary btn-block" style=
|
style="margin-bottom:1em;">Restart Application</a>
|
||||||
"margin-bottom:1em;">Restart Application</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,26 +19,48 @@
|
||||||
<div class="panel-group col-sm-6">
|
<div class="panel-group col-sm-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
Logfile (Size: {{Logfile_Size}} bytes)
|
Logfile (Size: {{Logfile_Size}})
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<a href="./downloadlog" ng-click="postDownloadLog()"
|
<a href="./downloadlog" ng-click="postDownloadLog()"
|
||||||
class="btn btn-primary btn-block" style=
|
class="btn btn-primary btn-block"
|
||||||
"margin-bottom:0.5em;">Download Logfile</a>
|
style="margin-bottom:0.5em">Download Logfile</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<a ng-click="postDeleteLog()" class=
|
<a ng-click="postDeleteLog()"
|
||||||
"btn btn-primary btn-block" style=
|
class="btn btn-primary btn-block"
|
||||||
"margin-bottom:0.5em;">Delete Logfile</a>
|
style="margin-bottom:0.5em">Delete Logfile</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel-group col-sm-6" style="float:right;">
|
<div class="panel-group col-sm-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
AHRS Log Files (Size: {{AHRS_LogFiles_Size}})
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<a href="./downloadahrslogs" download="ahrs_logs.zip" ng-click="postDownloadAHRSLogs()"
|
||||||
|
class="btn btn-primary btn-block"
|
||||||
|
style="margin-bottom:0.5em">Download AHRS Logs</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<a ng-click="postDeleteAHRSLogs()"
|
||||||
|
class="btn btn-primary btn-block"
|
||||||
|
style="margin-bottom:0.5em">Delete AHRS Logs</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-group col-sm-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
Database
|
Database
|
||||||
|
@ -47,13 +68,11 @@
|
||||||
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
|
|
||||||
<a href="./downloaddb" ng-click="postDownloadDB()"
|
<a href="./downloaddb" ng-click="postDownloadDB()"
|
||||||
class="btn btn-primary btn-block" style=
|
class="btn btn-primary btn-block"
|
||||||
"margin-bottom:0.5em;">Download Database</a>
|
style="margin-bottom:0.5em;">Download Database</a>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@ function AHRSRenderer(locationId) {
|
||||||
this.height = -1;
|
this.height = -1;
|
||||||
|
|
||||||
this.locationId = locationId;
|
this.locationId = locationId;
|
||||||
this.canvas = document.getElementById(locationId);
|
this.canvas = document.getElementById(this.locationId);
|
||||||
this.resize();
|
this.resize();
|
||||||
|
|
||||||
// State variables
|
// State variables
|
||||||
|
@ -13,7 +13,7 @@ function AHRSRenderer(locationId) {
|
||||||
this.slipSkid = 0;
|
this.slipSkid = 0;
|
||||||
this.altitude = 0;
|
this.altitude = 0;
|
||||||
|
|
||||||
var display = SVG(locationId).viewbox(-200, -200, 400, 400).group();
|
var display = SVG(this.locationId).viewbox(-200, -200, 400, 400).group();
|
||||||
|
|
||||||
this.ai = display.group().addClass('ai');
|
this.ai = display.group().addClass('ai');
|
||||||
|
|
||||||
|
@ -26,26 +26,24 @@ function AHRSRenderer(locationId) {
|
||||||
this.ai = this.ai.clipWith(screenClip).group();
|
this.ai = this.ai.clipWith(screenClip).group();
|
||||||
|
|
||||||
// card is the earth+sky+pitch marks, moves with both pitch and roll.
|
// card is the earth+sky+pitch marks, moves with both pitch and roll.
|
||||||
|
this.pitchScale = 0.5;
|
||||||
this.card = this.ai.group();
|
this.card = this.ai.group();
|
||||||
this.card.circle(2400).cx(0).cy(0).addClass('sky'); // Sky
|
this.card.circle(2400).cx(0).cy(0).addClass('sky'); // Sky
|
||||||
this.card.line(-1200, 0, 1200, 0).addClass('marks'); // Horizon line
|
this.card.line(-1200, 0, 1200, 0).addClass('marks'); // Horizon line
|
||||||
this.card.circle(2400).cx(0).cy(0).addClass('earth').clipWith(earthClip); // Earth
|
this.card.circle(2400).cx(0).cy(0).addClass('earth').clipWith(earthClip); // Earth
|
||||||
|
|
||||||
var pitchMarks = this.card.group().addClass('marks').clipWith(this.pitchClip);
|
var pitchMarks = this.card.group().addClass('marks').clipWith(this.pitchClip);
|
||||||
for (i = -1050; i <= 1050; i+=25) {
|
var y;
|
||||||
switch (i%100) {
|
for (var i = -1050; i <= 1050; i+=50) {
|
||||||
case 0:
|
y = i * this.pitchScale;
|
||||||
pitchMarks.line(-40, i, 40, i);
|
if (i%100 === 0) {
|
||||||
|
pitchMarks.line(-30, y, 30, y);
|
||||||
if (i !== 0) {
|
if (i !== 0) {
|
||||||
pitchMarks.text(Math.abs(i) <= 900 ? Math.abs(i / 10).toString() : '80').x(-55).cy(i).addClass('markText');
|
pitchMarks.text(Math.abs(i) <= 900 ? Math.abs(i / 10).toString() : '80').x(-55).cy(y).addClass('markText');
|
||||||
pitchMarks.text(Math.abs(i) <= 900 ? Math.abs(i / 10).toString() : '80').x(+55).cy(i).addClass('markText');
|
pitchMarks.text(Math.abs(i) <= 900 ? Math.abs(i / 10).toString() : '80').x(+55).cy(y).addClass('markText');
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
case 50:
|
pitchMarks.line(-15, y, 15, y);
|
||||||
pitchMarks.line(-20, i, 20, i);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pitchMarks.line(-10, i, 10, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,10 +117,10 @@ AHRSRenderer.prototype = {
|
||||||
this.slipSkid = +10;
|
this.slipSkid = +10;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pitchClip.translate(0, -10 * this.pitch);
|
this.pitchClip.translate(0, -10 * this.pitch * this.pitchScale);
|
||||||
this.rollClip.rotate(this.roll, 0, 0);
|
this.rollClip.rotate(this.roll, 0, 0);
|
||||||
this.card.rotate(0, 0, 0).translate(0, 10 * this.pitch);
|
this.card.rotate(0, 0, 0).translate(0, 10 * this.pitch * this.pitchScale);
|
||||||
this.card.rotate(-this.roll, 0, -10 * this.pitch);
|
this.card.rotate(-this.roll, 0, -10 * this.pitch * this.pitchScale);
|
||||||
this.rollMarks.rotate(-this.roll, 0, 0);
|
this.rollMarks.rotate(-this.roll, 0, 0);
|
||||||
this.headingMarks.translate(-2 * (this.heading % 360), 0);
|
this.headingMarks.translate(-2 * (this.heading % 360), 0);
|
||||||
this.skidBar.translate(-2 * this.slipSkid, 0);
|
this.skidBar.translate(-2 * this.slipSkid, 0);
|
||||||
|
@ -157,7 +155,7 @@ function GMeterRenderer(locationId, nlim, plim, resetCallback) {
|
||||||
this.height = -1;
|
this.height = -1;
|
||||||
|
|
||||||
this.locationId = locationId;
|
this.locationId = locationId;
|
||||||
this.canvas = document.getElementById(locationId);
|
this.canvas = document.getElementById(this.locationId);
|
||||||
this.resize();
|
this.resize();
|
||||||
|
|
||||||
// State variables
|
// State variables
|
||||||
|
@ -166,7 +164,7 @@ function GMeterRenderer(locationId, nlim, plim, resetCallback) {
|
||||||
this.max = 1;
|
this.max = 1;
|
||||||
|
|
||||||
// Draw the G Meter using the svg.js library
|
// Draw the G Meter using the svg.js library
|
||||||
var gMeter = SVG(locationId).viewbox(-200, -200, 400, 400).group().addClass('gMeter');
|
var gMeter = SVG(this.locationId).viewbox(-200, -200, 400, 400).group().addClass('gMeter');
|
||||||
|
|
||||||
var el, card = gMeter.group().addClass('card');
|
var el, card = gMeter.group().addClass('card');
|
||||||
card.circle(390).cx(0).cy(0);
|
card.circle(390).cx(0).cy(0);
|
||||||
|
|
|
@ -10,7 +10,7 @@ function DeveloperCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||||
return; // we are getting called once after clicking away from the status page
|
return; // we are getting called once after clicking away from the status page
|
||||||
|
|
||||||
if (($scope.socket === undefined) || ($scope.socket === null)) {
|
if (($scope.socket === undefined) || ($scope.socket === null)) {
|
||||||
socket = new WebSocket(URL_STATUS_WS);
|
var socket = new WebSocket(URL_STATUS_WS);
|
||||||
$scope.socket = socket; // store socket in scope for enter/exit usage
|
$scope.socket = socket; // store socket in scope for enter/exit usage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +36,9 @@ function DeveloperCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onmessage = function (msg) {
|
socket.onmessage = function (msg) {
|
||||||
console.log('Received status update.')
|
console.log('Received status update.');
|
||||||
|
|
||||||
var status = JSON.parse(msg.data)
|
var status = JSON.parse(msg.data);
|
||||||
// Update Status
|
// Update Status
|
||||||
$scope.Version = status.Version;
|
$scope.Version = status.Version;
|
||||||
$scope.Build = status.Build.substr(0, 10);
|
$scope.Build = status.Build.substr(0, 10);
|
||||||
|
@ -62,7 +62,8 @@ function DeveloperCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||||
$scope.UAT_PIREP_total = status.UAT_PIREP_total;
|
$scope.UAT_PIREP_total = status.UAT_PIREP_total;
|
||||||
$scope.UAT_NOTAM_total = status.UAT_NOTAM_total;
|
$scope.UAT_NOTAM_total = status.UAT_NOTAM_total;
|
||||||
$scope.UAT_OTHER_total = status.UAT_OTHER_total;
|
$scope.UAT_OTHER_total = status.UAT_OTHER_total;
|
||||||
$scope.Logfile_Size = status.Logfile_Size;
|
$scope.Logfile_Size = humanFileSize(status.Logfile_Size);
|
||||||
|
$scope.AHRS_LogFiles_Size = humanFileSize(status.AHRS_LogFiles_Size);
|
||||||
// Errors array.
|
// Errors array.
|
||||||
if (status.Errors.length > 0) {
|
if (status.Errors.length > 0) {
|
||||||
$scope.visible_errors = true;
|
$scope.visible_errors = true;
|
||||||
|
@ -70,7 +71,7 @@ function DeveloperCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var uptime = status.Uptime;
|
var uptime = status.Uptime;
|
||||||
if (uptime != undefined) {
|
if (uptime !== undefined) {
|
||||||
var up_d = parseInt((uptime/1000) / 86400),
|
var up_d = parseInt((uptime/1000) / 86400),
|
||||||
up_h = parseInt((uptime/1000 - 86400*up_d) / 3600),
|
up_h = parseInt((uptime/1000 - 86400*up_d) / 3600),
|
||||||
up_m = parseInt((uptime/1000 - 86400*up_d - 3600*up_h) / 60),
|
up_m = parseInt((uptime/1000 - 86400*up_d - 3600*up_h) / 60),
|
||||||
|
@ -80,7 +81,7 @@ function DeveloperCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||||
// $('#Uptime').text('unavailable');
|
// $('#Uptime').text('unavailable');
|
||||||
}
|
}
|
||||||
var boardtemp = status.CPUTemp;
|
var boardtemp = status.CPUTemp;
|
||||||
if (boardtemp != undefined) {
|
if (boardtemp !== undefined) {
|
||||||
/* boardtemp is celcius to tenths */
|
/* boardtemp is celcius to tenths */
|
||||||
$scope.CPUTemp = String(boardtemp.toFixed(1) + 'C / ' + ((boardtemp * 9 / 5) + 32.0).toFixed(1) + 'F');
|
$scope.CPUTemp = String(boardtemp.toFixed(1) + 'C / ' + ((boardtemp * 9 / 5) + 32.0).toFixed(1) + 'F');
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,6 +126,26 @@ function DeveloperCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.postDeleteAHRSLogs = function () {
|
||||||
|
$http.post(URL_DELETEAHRSLOGFILES).
|
||||||
|
then(function (response) {
|
||||||
|
// do nothing
|
||||||
|
// $scope.$apply();
|
||||||
|
}, function (response) {
|
||||||
|
// do nothing
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.postDownloadAHRSLogs = function () {
|
||||||
|
$http.post(URL_DOWNLOADAHRSLOGFILES).
|
||||||
|
then(function (response) {
|
||||||
|
// do nothing
|
||||||
|
// $scope.$apply();
|
||||||
|
}, function (response) {
|
||||||
|
// do nothing
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.postDownloadDB = function () {
|
$scope.postDownloadDB = function () {
|
||||||
$http.post(URL_DOWNLOADDB).
|
$http.post(URL_DOWNLOADDB).
|
||||||
then(function (response) {
|
then(function (response) {
|
||||||
|
@ -137,4 +158,13 @@ function DeveloperCtrl($rootScope, $scope, $state, $http, $interval) {
|
||||||
|
|
||||||
connect($scope); // connect - opens a socket and listens for messages
|
connect($scope); // connect - opens a socket and listens for messages
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function humanFileSize(size) {
|
||||||
|
if (size === 0) {
|
||||||
|
return '0 B'
|
||||||
|
} else {
|
||||||
|
var i = Math.floor(Math.log(size) / Math.log(1024));
|
||||||
|
return ( size / Math.pow(1024, i) ).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
angular.module('appControllers').controller('GPSCtrl', GPSCtrl); // get the main module contollers set
|
angular.module('appControllers').controller('GPSCtrl', GPSCtrl); // get the main module controllers set
|
||||||
GPSCtrl.$inject = ['$rootScope', '$scope', '$state', '$http', '$interval']; // Inject my dependencies
|
GPSCtrl.$inject = ['$rootScope', '$scope', '$state', '$http', '$interval']; // Inject my dependencies
|
||||||
|
|
||||||
// create our controller function with all necessary logic
|
// create our controller function with all necessary logic
|
||||||
|
|
|
@ -156,7 +156,7 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
|
||||||
newsettings = {
|
newsettings = {
|
||||||
"GLimits": settings["GLimits"]
|
"GLimits": settings["GLimits"]
|
||||||
};
|
};
|
||||||
console.log(angular.toJson(newsettings));
|
// console.log(angular.toJson(newsettings));
|
||||||
setSettings(angular.toJson(newsettings));
|
setSettings(angular.toJson(newsettings));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -228,22 +228,29 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.setOrientation = function(action) {
|
$scope.setOrientation = function(action) {
|
||||||
console.log("sending " + action + " message.");
|
// console.log("sending " + action + " message.");
|
||||||
$http.post(URL_AHRS_ORIENT, action).
|
$http.post(URL_AHRS_ORIENT, action).
|
||||||
then(function (response) {
|
then(function (response) {
|
||||||
console.log("sent " + action + " message.");
|
// console.log("sent " + action + " message.");
|
||||||
}, function(response) {
|
}, function(response) {
|
||||||
// failure: cancel the calibration
|
// failure: cancel the calibration
|
||||||
console.log(response.data);
|
// console.log(response.data);
|
||||||
$scope.Orientation_Failure_Message = response.data;
|
$scope.Orientation_Failure_Message = response.data;
|
||||||
switch (action) {
|
|
||||||
case "forward":
|
|
||||||
$scope.Ui.turnOff("modalCalibrateUp");
|
|
||||||
break;
|
|
||||||
case "up":
|
|
||||||
$scope.Ui.turnOff('modalCalibrateDone');
|
$scope.Ui.turnOff('modalCalibrateDone');
|
||||||
}
|
|
||||||
$scope.Ui.turnOn("modalCalibrateFailed");
|
$scope.Ui.turnOn("modalCalibrateFailed");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.calibrateGyros = function() {
|
||||||
|
console.log("sending calibrate message.");
|
||||||
|
$http.post(URL_AHRS_CAL).
|
||||||
|
then(function(response) {
|
||||||
|
console.log("Sent calibrate message.");
|
||||||
|
}, function(response) {
|
||||||
|
console.log(response.data);
|
||||||
|
$scope.Calibration_Failure_Message = response.data;
|
||||||
|
$scope.Ui.turnOff("modalCalibrateGyros");
|
||||||
|
$scope.Ui.turnOn("modalCalibrateGyrosFailed");
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="panel-group col-sm-6">
|
<div class="panel-group col-sm-6">
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Hardware</div>
|
<div class="panel-heading">Hardware</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
@ -82,20 +81,26 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<span style="position:relative; overflow: hidden;">
|
<span style="position:relative; overflow: hidden;">
|
||||||
<button class="btn btn-primary btn-block" ui-turn-on="modalCalibrateForward">
|
<button class="btn btn-primary btn-block" ui-turn-on="modalCalibrateForward"
|
||||||
Set AHRS Sensor Orientation
|
ng-disabled="!IMU_Sensor_Enabled">Set AHRS Sensor Orientation</button>
|
||||||
</button>
|
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group reset-flow">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<button class="btn btn-primary btn-block" ui-turn-on="modalCalibrateGyros"
|
||||||
|
ng-disabled="!IMU_Sensor_Enabled">Calibrate Gyros</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group reset-flow">
|
<div class="form-group reset-flow">
|
||||||
<label class="control-label col-xs-5">G Limits</label>
|
<label class="control-label col-xs-5">G Limits</label>
|
||||||
<form name="GLimitForm" ng-submit="updateGLimits()" novalidate>
|
<form name="GLimitForm" ng-submit="updateGLimits()" novalidate ng-disabled="!IMU_Sensor_Enabled">
|
||||||
<input class="col-xs-7" type="string" required ng-model="GLimits" placeholder="Space-separated negative and positive G meter limits" ng-blur="updateGLimits()" />
|
<input class="col-xs-7" type="string" required ng-model="GLimits" ng-blur="updateGLimits()"
|
||||||
|
placeholder="Space-separated negative and positive G meter limits"/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
|
@ -167,7 +172,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Developer mode area -->
|
<!-- Developer mode area -->
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div ng-show="DeveloperMode" class="panel-group col-sm-6">
|
<div ng-show="DeveloperMode" class="panel-group col-sm-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
@ -261,31 +266,14 @@
|
||||||
<h4 class="modal-title">Set AHRS Sensor Orientation: Forward Direction</h4>
|
<h4 class="modal-title">Set AHRS Sensor Orientation: Forward Direction</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>Point the Stratux/sensor box so that the end that will be pointing toward the <strong>nose</strong> of the airplane is pointing toward the sky and press the <strong>Set Forward Direction</strong> button.</p>
|
<p>Point the Stratux so that the end that will be pointing toward the
|
||||||
|
<strong>nose</strong> of the airplane is pointing toward the sky and press the
|
||||||
|
<strong>Set Forward Direction</strong> button.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a ui-turn-off="modalCalibrateForward" ui-turn-on="modalCalibrateCanceled" class="btn btn-default">Cancel</a>
|
<a ui-turn-off="modalCalibrateForward" class="btn btn-default">Cancel</a>
|
||||||
<a ng-click="setOrientation('forward')" ui-turn-off="modalCalibrateForward" ui-turn-on="modalCalibrateUp" class="btn btn-default btn-primary">Set Forward Direction</a>
|
<a ng-click="setOrientation('forward')" ui-turn-off="modalCalibrateForward"
|
||||||
</div>
|
ui-turn-on="modalCalibrateDone" class="btn btn-default btn-primary">Set Forward Direction</a>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal" ui-if="modalCalibrateUp" ui-state="modalCalibrateUp">
|
|
||||||
<div class="modal-overlay "></div>
|
|
||||||
<div class="vertical-alignment-helper center-block">
|
|
||||||
<div class="modal-dialog vertical-align-center">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button class="close" ui-turn-off="modalCalibrateUp"></button>
|
|
||||||
<h4 class="modal-title">Set AHRS Sensor Orientation: Up Direction</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>Place the Stratux/sensor box in the orientation it will be in during flight and press the <strong>Set Up Direction</strong> button.</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<a ui-turn-off="modalCalibrateUp" ui-turn-on="modalCalibrateCanceled" class="btn btn-default">Cancel</a>
|
|
||||||
<a ng-click="setOrientation('up')" ui-turn-off="modalCalibrateUp" ui-turn-on="modalCalibrateDone" class="btn btn-default btn-primary">Set Up Direction</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -301,10 +289,13 @@
|
||||||
<h4 class="modal-title">Set AHRS Sensor Orientation: Finished</h4>
|
<h4 class="modal-title">Set AHRS Sensor Orientation: Finished</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>The sensors are calibrated. These settings will be saved for future flights.</p>
|
<p>The sensor orientation is set. These settings will be saved for future flights.
|
||||||
|
Place the Stratux in its in-flight orientation and keep it stationary for 5 seconds
|
||||||
|
after you press the <strong>Done</strong> button.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a ui-turn-off="modalCalibrateDone" class="btn btn-default btn-primary">OK</a>
|
<a ng-click="setOrientation('done')" ui-turn-off="modalCalibrateDone"
|
||||||
|
class="btn btn-default btn-primary">Done</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -322,7 +313,7 @@
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>There was an error: {{Orientation_Failure_Message}}</p>
|
<p>There was an error: {{Orientation_Failure_Message}}</p>
|
||||||
<p><div id="orientationFailureMessage"></div></p>
|
<p><div id="orientationFailureMessage"></div></p>
|
||||||
<p>The calibration failed.</p>
|
<p>The orientation failed. Please try again.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a ui-turn-off="modalCalibrateFailed" class="btn btn-default btn-primary">OK</a>
|
<a ui-turn-off="modalCalibrateFailed" class="btn btn-default btn-primary">OK</a>
|
||||||
|
@ -331,25 +322,27 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal" ui-if="modalCalibrateCanceled" ui-state="modalCalibrateCanceled">
|
|
||||||
|
<div class="modal" ui-if="modalCalibrateGyros" ui-state="modalCalibrateGyros">
|
||||||
<div class="modal-overlay "></div>
|
<div class="modal-overlay "></div>
|
||||||
<div class="vertical-alignment-helper center-block">
|
<div class="vertical-alignment-helper center-block">
|
||||||
<div class="modal-dialog vertical-align-center">
|
<div class="modal-dialog vertical-align-center">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button class="close" ui-turn-off="modalCalibrateCanceled"></button>
|
<button class="close" ui-turn-off="modalCalibrateGyros"></button>
|
||||||
<h4 class="modal-title">Set AHRS Sensor Orientation: Canceled</h4>
|
<h4 class="modal-title">Calibrate MPU Gyros</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>Calibration canceled.</p>
|
<p>Press <b>Calibrate</b> and keep the Stratux as stationary as possible for the next second.
|
||||||
|
You should only do this in calm air as turbulence will throw off the calibrations.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a ui-turn-off="modalCalibrateCanceled" class="btn btn-default btn-primary">OK</a>
|
<a ui-turn-off="modalCalibrateGyros" class="btn btn-default">Cancel</a>
|
||||||
|
<a ng-click="calibrateGyros()" ui-turn-off="modalCalibrateGyros"
|
||||||
|
class="btn btn-default btn-primary">Calibrate</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue