From 1855a2446bcf9db2d3ff0e778ebea769bc06dcee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 25 May 2026 14:41:15 +0200 Subject: [PATCH] dies und das --- ExoMy_Software-master/gui/admin.html | 56 +++++++++++++++++ ExoMy_Software-master/gui/app.css | 19 ++++++ ExoMy_Software-master/gui/index.html | 87 +++++++++++++++++++++++---- ExoMy_Software-master/src/gps_node.py | 7 ++- 4 files changed, 157 insertions(+), 12 deletions(-) diff --git a/ExoMy_Software-master/gui/admin.html b/ExoMy_Software-master/gui/admin.html index 95842b1..4b82cfd 100644 --- a/ExoMy_Software-master/gui/admin.html +++ b/ExoMy_Software-master/gui/admin.html @@ -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. + +
+
+
+ GPS-Rohdaten + NMEA +
+
+ 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. +
+
+ +
+ +
@@ -663,6 +678,7 @@ utcTime: null, lastFixAgeS: null, satellites: [], + rawSentences: [], selectedSatellitePrn: null, plottedSatellites: [] }; @@ -734,6 +750,7 @@ gpsDiagnosticsState.utcTime = null; gpsDiagnosticsState.lastFixAgeS = null; gpsDiagnosticsState.satellites = []; + gpsDiagnosticsState.rawSentences = []; updateGpsDiagnosticsPanel(); } @@ -1003,9 +1020,47 @@ setGpsQualityState('gps_diag_vdop', gpsDiagnosticsState.vdop); setText('gps_diag_sat_used', gpsDiagnosticsState.satellitesUsed); setText('gps_diag_sat_visible', gpsDiagnosticsState.satellitesVisible); + setGpsRawOutput(gpsDiagnosticsState.rawSentences); 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() { if (!gpsDiagnosticsState.satellites.length) return null; var selected = gpsDiagnosticsState.satellites.find(function(item) { @@ -1172,6 +1227,7 @@ gpsDiagnosticsState.utcTime = data.utc_time || 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.rawSentences = Array.isArray(data.raw_sentences) ? data.raw_sentences : []; if (gpsDiagnosticsState.selectedSatellitePrn) { var stillExists = gpsDiagnosticsState.satellites.some(function(item) { return item.prn === gpsDiagnosticsState.selectedSatellitePrn; diff --git a/ExoMy_Software-master/gui/app.css b/ExoMy_Software-master/gui/app.css index 3ff9903..92b1bd9 100644 --- a/ExoMy_Software-master/gui/app.css +++ b/ExoMy_Software-master/gui/app.css @@ -1295,6 +1295,25 @@ body.page-admin .gps-copy{ body.page-admin .gps-copy_compact{ 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{ padding:18px; position:relative; diff --git a/ExoMy_Software-master/gui/index.html b/ExoMy_Software-master/gui/index.html index 3ac7641..4d21960 100644 --- a/ExoMy_Software-master/gui/index.html +++ b/ExoMy_Software-master/gui/index.html @@ -285,6 +285,7 @@ var roverCommandListener = null; var motorCommandsListener = null; var gpsFixListener = null; var gpsStatusListener = null; +var gpsDiagnosticsListener = null; var publishTimer = null; var statusTimer = null; var axes = [0, 0, 0, 0, 0, 0]; @@ -294,6 +295,7 @@ var motorsEnabled = true; var inputMode = "joystick"; var metBase = Date.now(); var dragging = false; +var lastGpsDiagnostics = null; var REQUIRED_CALIBRATION_POINTS = [0, 20, 30, 40, 50, 60, 80, 100]; var driveEstimator = { drivePwmNeutralAverage: 307, @@ -603,41 +605,86 @@ function updateAxesDisplay(x, y) { setText("dpy", formatAxis(y)); } -function setGpsAccuracyDisplay(valueMeters) { +function setGpsAccuracyDisplay(label) { var node = document.getElementById("gps-accuracy"); if (!node) return; 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 = "--"; return; } - node.textContent = formatNumber(valueMeters, 1) + " m"; - if (valueMeters <= 1.0) { + node.textContent = label; +} + +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"); - } else if (valueMeters <= 3.0) { + } else if (tone === "mid") { node.classList.add("gps-quality-mid"); - } else { + } else if (tone === "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) { if (!message) return; markGpsFresh(); var hasFix = message.status && message.status.status >= 0; if (!hasFix) { - setGpsAccuracyDisplay(NaN); + setGpsAccuracyState("--", ""); setText("gps-lat", "--"); setText("gps-lon", "--"); return; } - var covariance = Array.isArray(message.position_covariance) ? Number(message.position_covariance[0]) : NaN; - var accuracyMeters = covariance > 0 ? Math.sqrt(covariance) : NaN; - setGpsAccuracyDisplay(accuracyMeters); + updateGpsAccuracyFromDiagnostics(); setText("gps-lat", formatNumber(Number(message.latitude || 0), 5)); setText("gps-lon", formatNumber(Number(message.longitude || 0), 5)); } @@ -648,6 +695,15 @@ function updateGpsOverlayFromStatus(text) { setText("gps-state", value); } +function updateGpsOverlayFromDiagnostics(text) { + try { + lastGpsDiagnostics = JSON.parse(String(text || "{}")); + } catch (error) { + lastGpsDiagnostics = null; + } + updateGpsAccuracyFromDiagnostics(); +} + function updateModeDisplay() { var label = "Ackermann"; if (driveMode === "turn-on-point") { @@ -748,7 +804,7 @@ function clearRosLiveDisplay() { liveIndicator.classList.add("is-offline"); } setText("gps-state", "Offline"); - setGpsAccuracyDisplay(NaN); + setGpsAccuracyState("--", ""); setText("gps-lat", "--"); setText("gps-lon", "--"); setText("overlay-speed", "--"); @@ -1226,6 +1282,15 @@ window.addEventListener("load", function () { 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({ ros: ros, name: "/joy", diff --git a/ExoMy_Software-master/src/gps_node.py b/ExoMy_Software-master/src/gps_node.py index 7d91624..7dcce5d 100644 --- a/ExoMy_Software-master/src/gps_node.py +++ b/ExoMy_Software-master/src/gps_node.py @@ -4,6 +4,7 @@ import json import os import select import termios +from collections import deque from datetime import datetime import rospy @@ -86,6 +87,7 @@ class GpsState(object): self.visible_satellites = {} self.visible_satellite_count = 0 self._gsv_groups = {} + self.raw_sentences = deque(maxlen=200) def summary_text(self): if not self.connected: @@ -334,6 +336,8 @@ def parse_sentence(sentence, state): if not verify_checksum(sentence): return False + state.raw_sentences.append(sentence) + fields = sentence.split('*', 1)[0].split(',') if not fields: 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_date': state.utc_datetime.strftime('%Y-%m-%d') if state.utc_datetime else None, '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) }