dies und das
This commit is contained in:
@@ -427,6 +427,21 @@
|
|||||||
Für eine gute Fix-Qualität sind niedrige DOP-Werte und hohe, gleichmäßig verteilte Satelliten sinnvoll. Der Himmelsplot zeigt nur Satelliten, die der Empfänger per GSV mit Richtung und Höhe meldet.
|
Für eine gute Fix-Qualität sind niedrige DOP-Werte und hohe, gleichmäßig verteilte Satelliten sinnvoll. Der Himmelsplot zeigt nur Satelliten, die der Empfänger per GSV mit Richtung und Höhe meldet.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="p-hdr">
|
||||||
|
<div class="p-dot"></div>
|
||||||
|
<span class="p-lbl">GPS-Rohdaten</span>
|
||||||
|
<span class="p-tag">NMEA</span>
|
||||||
|
</div>
|
||||||
|
<div class="copy-text gps-copy gps-copy_compact">
|
||||||
|
Letzte direkt empfangene NMEA-Sätze des Empfängers. Die Ansicht scrollt intern und ist für Diagnose bei Abschattung, Drift und fehlerhaften Fixen gedacht.
|
||||||
|
</div>
|
||||||
|
<div class="neutral-toolbar">
|
||||||
|
<button class="button buttonA" onclick="copyGpsRawData()">Rohdaten kopieren</button>
|
||||||
|
</div>
|
||||||
|
<textarea id="gps_raw_output" class="gps-raw-output" readonly spellcheck="false">--</textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -663,6 +678,7 @@
|
|||||||
utcTime: null,
|
utcTime: null,
|
||||||
lastFixAgeS: null,
|
lastFixAgeS: null,
|
||||||
satellites: [],
|
satellites: [],
|
||||||
|
rawSentences: [],
|
||||||
selectedSatellitePrn: null,
|
selectedSatellitePrn: null,
|
||||||
plottedSatellites: []
|
plottedSatellites: []
|
||||||
};
|
};
|
||||||
@@ -734,6 +750,7 @@
|
|||||||
gpsDiagnosticsState.utcTime = null;
|
gpsDiagnosticsState.utcTime = null;
|
||||||
gpsDiagnosticsState.lastFixAgeS = null;
|
gpsDiagnosticsState.lastFixAgeS = null;
|
||||||
gpsDiagnosticsState.satellites = [];
|
gpsDiagnosticsState.satellites = [];
|
||||||
|
gpsDiagnosticsState.rawSentences = [];
|
||||||
updateGpsDiagnosticsPanel();
|
updateGpsDiagnosticsPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1003,9 +1020,47 @@
|
|||||||
setGpsQualityState('gps_diag_vdop', gpsDiagnosticsState.vdop);
|
setGpsQualityState('gps_diag_vdop', gpsDiagnosticsState.vdop);
|
||||||
setText('gps_diag_sat_used', gpsDiagnosticsState.satellitesUsed);
|
setText('gps_diag_sat_used', gpsDiagnosticsState.satellitesUsed);
|
||||||
setText('gps_diag_sat_visible', gpsDiagnosticsState.satellitesVisible);
|
setText('gps_diag_sat_visible', gpsDiagnosticsState.satellitesVisible);
|
||||||
|
setGpsRawOutput(gpsDiagnosticsState.rawSentences);
|
||||||
drawGpsSkyPlot();
|
drawGpsSkyPlot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setGpsRawOutput(sentences) {
|
||||||
|
var node = document.getElementById('gps_raw_output');
|
||||||
|
if (!node) return;
|
||||||
|
if (!Array.isArray(sentences) || !sentences.length) {
|
||||||
|
node.value = '--';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var wasNearBottom = (node.scrollTop + node.clientHeight + 24) >= node.scrollHeight;
|
||||||
|
node.value = sentences.join('\n');
|
||||||
|
if (wasNearBottom) node.scrollTop = node.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function copyGpsRawData() {
|
||||||
|
var node = document.getElementById('gps_raw_output');
|
||||||
|
if (!node) return;
|
||||||
|
var text = String(node.value || '').trim();
|
||||||
|
if (!text || text === '--') {
|
||||||
|
setAdminStatus('Keine GPS-Rohdaten zum Kopieren');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
} else {
|
||||||
|
node.focus();
|
||||||
|
node.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
node.setSelectionRange(node.value.length, node.value.length);
|
||||||
|
}
|
||||||
|
setAdminStatus('GPS-Rohdaten kopiert');
|
||||||
|
window.setTimeout(function() { setAdminStatus('Bereit'); }, 1800);
|
||||||
|
} catch (error) {
|
||||||
|
setAdminStatus('Kopieren fehlgeschlagen');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getSelectedSatellite() {
|
function getSelectedSatellite() {
|
||||||
if (!gpsDiagnosticsState.satellites.length) return null;
|
if (!gpsDiagnosticsState.satellites.length) return null;
|
||||||
var selected = gpsDiagnosticsState.satellites.find(function(item) {
|
var selected = gpsDiagnosticsState.satellites.find(function(item) {
|
||||||
@@ -1172,6 +1227,7 @@
|
|||||||
gpsDiagnosticsState.utcTime = data.utc_time || null;
|
gpsDiagnosticsState.utcTime = data.utc_time || null;
|
||||||
gpsDiagnosticsState.lastFixAgeS = typeof data.last_fix_age_s === 'number' ? data.last_fix_age_s : null;
|
gpsDiagnosticsState.lastFixAgeS = typeof data.last_fix_age_s === 'number' ? data.last_fix_age_s : null;
|
||||||
gpsDiagnosticsState.satellites = Array.isArray(data.satellites) ? data.satellites : [];
|
gpsDiagnosticsState.satellites = Array.isArray(data.satellites) ? data.satellites : [];
|
||||||
|
gpsDiagnosticsState.rawSentences = Array.isArray(data.raw_sentences) ? data.raw_sentences : [];
|
||||||
if (gpsDiagnosticsState.selectedSatellitePrn) {
|
if (gpsDiagnosticsState.selectedSatellitePrn) {
|
||||||
var stillExists = gpsDiagnosticsState.satellites.some(function(item) {
|
var stillExists = gpsDiagnosticsState.satellites.some(function(item) {
|
||||||
return item.prn === gpsDiagnosticsState.selectedSatellitePrn;
|
return item.prn === gpsDiagnosticsState.selectedSatellitePrn;
|
||||||
|
|||||||
@@ -1295,6 +1295,25 @@ body.page-admin .gps-copy{
|
|||||||
body.page-admin .gps-copy_compact{
|
body.page-admin .gps-copy_compact{
|
||||||
border-bottom:none;
|
border-bottom:none;
|
||||||
}
|
}
|
||||||
|
body.page-admin .gps-raw-output{
|
||||||
|
width:100%;
|
||||||
|
min-height:220px;
|
||||||
|
max-height:320px;
|
||||||
|
resize:vertical;
|
||||||
|
overflow:auto;
|
||||||
|
margin-top:14px;
|
||||||
|
padding:12px 14px;
|
||||||
|
border:1px solid rgba(0,255,145,.18);
|
||||||
|
border-radius:12px;
|
||||||
|
background:#07111c;
|
||||||
|
color:#b8ffe1;
|
||||||
|
font:12px/1.45 Consolas, "Courier New", monospace;
|
||||||
|
box-shadow:inset 0 0 0 1px rgba(255,255,255,.02);
|
||||||
|
}
|
||||||
|
body.page-admin .gps-raw-output:focus{
|
||||||
|
outline:none;
|
||||||
|
border-color:rgba(0,255,145,.28);
|
||||||
|
}
|
||||||
body.page-admin .gps-sky-stage{
|
body.page-admin .gps-sky-stage{
|
||||||
padding:18px;
|
padding:18px;
|
||||||
position:relative;
|
position:relative;
|
||||||
|
|||||||
@@ -285,6 +285,7 @@ var roverCommandListener = null;
|
|||||||
var motorCommandsListener = null;
|
var motorCommandsListener = null;
|
||||||
var gpsFixListener = null;
|
var gpsFixListener = null;
|
||||||
var gpsStatusListener = null;
|
var gpsStatusListener = null;
|
||||||
|
var gpsDiagnosticsListener = null;
|
||||||
var publishTimer = null;
|
var publishTimer = null;
|
||||||
var statusTimer = null;
|
var statusTimer = null;
|
||||||
var axes = [0, 0, 0, 0, 0, 0];
|
var axes = [0, 0, 0, 0, 0, 0];
|
||||||
@@ -294,6 +295,7 @@ var motorsEnabled = true;
|
|||||||
var inputMode = "joystick";
|
var inputMode = "joystick";
|
||||||
var metBase = Date.now();
|
var metBase = Date.now();
|
||||||
var dragging = false;
|
var dragging = false;
|
||||||
|
var lastGpsDiagnostics = null;
|
||||||
var REQUIRED_CALIBRATION_POINTS = [0, 20, 30, 40, 50, 60, 80, 100];
|
var REQUIRED_CALIBRATION_POINTS = [0, 20, 30, 40, 50, 60, 80, 100];
|
||||||
var driveEstimator = {
|
var driveEstimator = {
|
||||||
drivePwmNeutralAverage: 307,
|
drivePwmNeutralAverage: 307,
|
||||||
@@ -603,41 +605,86 @@ function updateAxesDisplay(x, y) {
|
|||||||
setText("dpy", formatAxis(y));
|
setText("dpy", formatAxis(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setGpsAccuracyDisplay(valueMeters) {
|
function setGpsAccuracyDisplay(label) {
|
||||||
var node = document.getElementById("gps-accuracy");
|
var node = document.getElementById("gps-accuracy");
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
node.classList.remove("gps-quality-good", "gps-quality-mid", "gps-quality-bad");
|
node.classList.remove("gps-quality-good", "gps-quality-mid", "gps-quality-bad");
|
||||||
if (typeof valueMeters !== "number" || isNaN(valueMeters) || valueMeters <= 0) {
|
if (typeof label !== "string" || !label) {
|
||||||
node.textContent = "--";
|
node.textContent = "--";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.textContent = formatNumber(valueMeters, 1) + " m";
|
node.textContent = label;
|
||||||
if (valueMeters <= 1.0) {
|
}
|
||||||
|
|
||||||
|
function setGpsAccuracyState(label, tone) {
|
||||||
|
var node = document.getElementById("gps-accuracy");
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
node.classList.remove("gps-quality-good", "gps-quality-mid", "gps-quality-bad");
|
||||||
|
node.textContent = label || "--";
|
||||||
|
if (tone === "good") {
|
||||||
node.classList.add("gps-quality-good");
|
node.classList.add("gps-quality-good");
|
||||||
} else if (valueMeters <= 3.0) {
|
} else if (tone === "mid") {
|
||||||
node.classList.add("gps-quality-mid");
|
node.classList.add("gps-quality-mid");
|
||||||
} else {
|
} else if (tone === "bad") {
|
||||||
node.classList.add("gps-quality-bad");
|
node.classList.add("gps-quality-bad");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateGpsAccuracyFromDiagnostics() {
|
||||||
|
if (!lastGpsDiagnostics || !lastGpsDiagnostics.connected || !lastGpsDiagnostics.valid) {
|
||||||
|
setGpsAccuracyState("--", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fixQuality = Number(lastGpsDiagnostics.fix_quality || 0);
|
||||||
|
var hdop = Number(lastGpsDiagnostics.hdop);
|
||||||
|
var pdop = Number(lastGpsDiagnostics.pdop);
|
||||||
|
var satellitesUsed = Number(lastGpsDiagnostics.satellites_used || 0);
|
||||||
|
var lastFixAge = Number(lastGpsDiagnostics.last_fix_age_s || 0);
|
||||||
|
|
||||||
|
if (fixQuality <= 0 || isNaN(hdop)) {
|
||||||
|
setGpsAccuracyState("schlecht", "bad");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var label = "schlecht";
|
||||||
|
var tone = "bad";
|
||||||
|
|
||||||
|
if (hdop <= 1.2 && (isNaN(pdop) || pdop <= 2.0) && satellitesUsed >= 10 && lastFixAge <= 2.0) {
|
||||||
|
label = "sehr gut";
|
||||||
|
tone = "good";
|
||||||
|
} else if (hdop <= 2.5 && (isNaN(pdop) || pdop <= 4.0) && satellitesUsed >= 6 && lastFixAge <= 4.0) {
|
||||||
|
label = "gut";
|
||||||
|
tone = "good";
|
||||||
|
} else if (hdop <= 4.5 && (isNaN(pdop) || pdop <= 7.0) && satellitesUsed >= 4 && lastFixAge <= 8.0) {
|
||||||
|
label = "mäßig";
|
||||||
|
tone = "mid";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (satellitesUsed < 5 || lastFixAge > 8.0) {
|
||||||
|
label = "schlecht";
|
||||||
|
tone = "bad";
|
||||||
|
}
|
||||||
|
|
||||||
|
setGpsAccuracyState(label, tone);
|
||||||
|
}
|
||||||
|
|
||||||
function updateGpsOverlayFromFix(message) {
|
function updateGpsOverlayFromFix(message) {
|
||||||
if (!message) return;
|
if (!message) return;
|
||||||
markGpsFresh();
|
markGpsFresh();
|
||||||
|
|
||||||
var hasFix = message.status && message.status.status >= 0;
|
var hasFix = message.status && message.status.status >= 0;
|
||||||
if (!hasFix) {
|
if (!hasFix) {
|
||||||
setGpsAccuracyDisplay(NaN);
|
setGpsAccuracyState("--", "");
|
||||||
setText("gps-lat", "--");
|
setText("gps-lat", "--");
|
||||||
setText("gps-lon", "--");
|
setText("gps-lon", "--");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var covariance = Array.isArray(message.position_covariance) ? Number(message.position_covariance[0]) : NaN;
|
updateGpsAccuracyFromDiagnostics();
|
||||||
var accuracyMeters = covariance > 0 ? Math.sqrt(covariance) : NaN;
|
|
||||||
setGpsAccuracyDisplay(accuracyMeters);
|
|
||||||
setText("gps-lat", formatNumber(Number(message.latitude || 0), 5));
|
setText("gps-lat", formatNumber(Number(message.latitude || 0), 5));
|
||||||
setText("gps-lon", formatNumber(Number(message.longitude || 0), 5));
|
setText("gps-lon", formatNumber(Number(message.longitude || 0), 5));
|
||||||
}
|
}
|
||||||
@@ -648,6 +695,15 @@ function updateGpsOverlayFromStatus(text) {
|
|||||||
setText("gps-state", value);
|
setText("gps-state", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateGpsOverlayFromDiagnostics(text) {
|
||||||
|
try {
|
||||||
|
lastGpsDiagnostics = JSON.parse(String(text || "{}"));
|
||||||
|
} catch (error) {
|
||||||
|
lastGpsDiagnostics = null;
|
||||||
|
}
|
||||||
|
updateGpsAccuracyFromDiagnostics();
|
||||||
|
}
|
||||||
|
|
||||||
function updateModeDisplay() {
|
function updateModeDisplay() {
|
||||||
var label = "Ackermann";
|
var label = "Ackermann";
|
||||||
if (driveMode === "turn-on-point") {
|
if (driveMode === "turn-on-point") {
|
||||||
@@ -748,7 +804,7 @@ function clearRosLiveDisplay() {
|
|||||||
liveIndicator.classList.add("is-offline");
|
liveIndicator.classList.add("is-offline");
|
||||||
}
|
}
|
||||||
setText("gps-state", "Offline");
|
setText("gps-state", "Offline");
|
||||||
setGpsAccuracyDisplay(NaN);
|
setGpsAccuracyState("--", "");
|
||||||
setText("gps-lat", "--");
|
setText("gps-lat", "--");
|
||||||
setText("gps-lon", "--");
|
setText("gps-lon", "--");
|
||||||
setText("overlay-speed", "--");
|
setText("overlay-speed", "--");
|
||||||
@@ -1226,6 +1282,15 @@ window.addEventListener("load", function () {
|
|||||||
updateGpsOverlayFromStatus(message.data);
|
updateGpsOverlayFromStatus(message.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gpsDiagnosticsListener = new ROSLIB.Topic({
|
||||||
|
ros: ros,
|
||||||
|
name: "/gps/diagnostics_json",
|
||||||
|
messageType: "std_msgs/String"
|
||||||
|
});
|
||||||
|
gpsDiagnosticsListener.subscribe(function (message) {
|
||||||
|
updateGpsOverlayFromDiagnostics(message.data);
|
||||||
|
});
|
||||||
|
|
||||||
var joySubscriber = new ROSLIB.Topic({
|
var joySubscriber = new ROSLIB.Topic({
|
||||||
ros: ros,
|
ros: ros,
|
||||||
name: "/joy",
|
name: "/joy",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import select
|
import select
|
||||||
import termios
|
import termios
|
||||||
|
from collections import deque
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import rospy
|
import rospy
|
||||||
@@ -86,6 +87,7 @@ class GpsState(object):
|
|||||||
self.visible_satellites = {}
|
self.visible_satellites = {}
|
||||||
self.visible_satellite_count = 0
|
self.visible_satellite_count = 0
|
||||||
self._gsv_groups = {}
|
self._gsv_groups = {}
|
||||||
|
self.raw_sentences = deque(maxlen=200)
|
||||||
|
|
||||||
def summary_text(self):
|
def summary_text(self):
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
@@ -334,6 +336,8 @@ def parse_sentence(sentence, state):
|
|||||||
if not verify_checksum(sentence):
|
if not verify_checksum(sentence):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
state.raw_sentences.append(sentence)
|
||||||
|
|
||||||
fields = sentence.split('*', 1)[0].split(',')
|
fields = sentence.split('*', 1)[0].split(',')
|
||||||
if not fields:
|
if not fields:
|
||||||
return False
|
return False
|
||||||
@@ -379,7 +383,8 @@ def build_diagnostics_payload(state, frame_id):
|
|||||||
'utc_time': state.utc_datetime.strftime('%H:%M:%S') if state.utc_datetime else None,
|
'utc_time': state.utc_datetime.strftime('%H:%M:%S') if state.utc_datetime else None,
|
||||||
'utc_date': state.utc_datetime.strftime('%Y-%m-%d') if state.utc_datetime else None,
|
'utc_date': state.utc_datetime.strftime('%Y-%m-%d') if state.utc_datetime else None,
|
||||||
'last_fix_age_s': last_fix_age,
|
'last_fix_age_s': last_fix_age,
|
||||||
'satellites': list(state.visible_satellites.values())
|
'satellites': list(state.visible_satellites.values()),
|
||||||
|
'raw_sentences': list(state.raw_sentences)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user