Drogheda/06-Testing-Validation/2026-06-20_Drogheda_GNSS-Findings_v1.0.tex

264 lines
12 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

% Project Drogheda — GNSS / Log Analysis findings (Helgen Beamer / Metropolis)
% Built from the helgen-beamer template. Compile: latexmk -xelatex <file>.tex
\documentclass[10pt,aspectratio=169]{beamer}
\usetheme[progressbar=frametitle, numbering=fraction, block=fill]{metropolis}
% ---------- Helgen official palette (Guia de Identidad v1.5, 2026) ----------
\definecolor{HelgenIndigo}{HTML}{2C3C5B}
\definecolor{HelgenCyan}{HTML}{51F3DA}
\definecolor{HelgenTeal}{HTML}{17A08C}
\definecolor{HelgenMist}{HTML}{EFF1F5}
\setbeamercolor{normal text}{fg=HelgenIndigo, bg=white}
\setbeamercolor{alerted text}{fg=HelgenTeal}
\setbeamercolor{frametitle}{bg=HelgenIndigo, fg=white}
\setbeamercolor{progress bar}{fg=HelgenCyan, bg=HelgenMist}
\setbeamercolor{title separator}{fg=HelgenCyan}
\setbeamercolor{block title}{bg=HelgenMist, fg=HelgenIndigo}
% ---------- Fonts: XeLaTeX + bundled brand fonts, clean fallback otherwise ----------
\usepackage{iftex}
\ifXeTeX
\usepackage{fontspec}
\IfFontExistsTF{League Spartan}{%
\newfontfamily\helgentitle{League Spartan}[BoldFont={* Bold}]
\setbeamerfont{title}{family=\helgentitle, series=\bfseries}
\setbeamerfont{frametitle}{family=\helgentitle, series=\bfseries}
\setbeamerfont{section title}{family=\helgentitle, series=\bfseries}
\setbeamerfont{standout}{family=\helgentitle, series=\bfseries}
}{}
\IfFontExistsTF{MADE Evolve Sans}{\setsansfont{MADE Evolve Sans}}{}
\else
\usepackage[T1]{fontenc}
\fi
\usepackage{booktabs}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, positioning, shapes.misc, fit}
\usepackage{listings}
\lstset{
basicstyle=\ttfamily\scriptsize,
keywordstyle=\color{HelgenIndigo}\bfseries,
commentstyle=\color{gray},
stringstyle=\color{HelgenTeal},
showstringspaces=false, breaklines=true, frame=single,
framerule=0.2pt, rulecolor=\color{HelgenMist}
}
% Reusable block / arrow styles (Helgen palette)
\tikzset{
blk/.style={rounded rectangle, draw=HelgenIndigo, fill=HelgenMist, font=\scriptsize,
minimum height=8mm, inner xsep=2.4mm, align=center},
acc/.style={rounded rectangle, draw=HelgenTeal, fill=white, font=\scriptsize,
minimum height=8mm, inner xsep=2.4mm, align=center},
arr/.style={-{Stealth}, thick, HelgenTeal},
arrx/.style={-{Stealth}, thick, red!70!black, dashed},
}
% ---------- Footer ----------
\setbeamertemplate{frame footer}{%
\scriptsize\color{gray}\insertshortauthor\ · \insertshorttitle\ · Confidencial — Helgen Servicios Especializados}
% ---------- Metadata ----------
\title[Drogheda · GNSS/Logs]{Project Drogheda — GNSS \& Log Analysis}
\subtitle{HBOX RTK fleet: bench triage, healthy baseline, and observability}
\author[Helgen]{Helgen Technologies — CTO/CSO}
\date{20 June 2026}
\titlegraphic{}
\begin{document}
\maketitle
\begin{frame}{Agenda}
\tableofcontents
\end{frame}
% =====================================================================
\section{Context}
\begin{frame}{Where we are}
\begin{columns}[T]
\column{0.58\textwidth}
\begin{itemize}
\item HBOX RTK trackers on Hutchison Ports heavy equipment (ICAVE, Veracruz) — worked, then failed.
\item Three independent failure fronts, fixed in parallel:
\begin{itemize}\footnotesize
\item \textbf{Backend} (retranslator) — could drop the fleet / black-hole a unit
\item \textbf{Thermal} — PLA box in a sealed cabinet (heat trap)
\item \textbf{Prototype HW + observability} — hand-wired; logs untrustworthy
\end{itemize}
\item Field units pulled $\rightarrow$ bench triage in Querétaro (firmware v1, no thermal log).
\end{itemize}
\column{0.4\textwidth}
\begin{alertblock}{Invariant}
Corrections ride the \textbf{4G modem}, not the GNSS — recover the link by power-cycling the stack.
\end{alertblock}
\end{columns}
\end{frame}
\begin{frame}{The signal chain}
\centering
\begin{tikzpicture}[node distance=7mm and 13mm]
\node[blk] (f9p) {ZED-F9P\\(GNSS)};
\node[blk, right=of f9p] (mas) {4G NTRIP\\Master};
\node[blk, right=of mas] (ret) {retranslator\\(htracker)};
\node[blk, right=of ret] (wial) {Wialon};
\node[acc, above=10mm of mas] (cas) {NTRIP caster\\(rtk2go)};
\draw[arr] (f9p) -- node[above, font=\tiny]{UART2: GGA} (mas);
\draw[arr] (mas) -- node[above, font=\tiny]{UDP} (ret);
\draw[arr] (ret) -- (wial);
\draw[arr] (cas) -- node[right, font=\tiny]{RTCM in} (mas);
\end{tikzpicture}
\vfill
\footnotesize Corrections come \emph{down} from the caster over 4G; position goes \emph{out} by UDP to the retranslator. The GNSS receiver never talks to the network directly.
\end{frame}
% =====================================================================
\section{Backend (retranslator)}
\begin{frame}{Backend — hardened \& deployed to prod}
\begin{itemize}
\item \textbf{Head-of-line blocking removed:} a \texttt{WialonForwarder} thread pool does all Wialon TCP I/O \emph{off} the UDP receive loop — one slow upstream no longer drops the fleet.
\item \textbf{Anti-jump now time-aware + self-healing:} re-anchors after rejects, clears on disconnect — a unit is never permanently black-holed.
\item \textbf{Identity keyed by \texttt{cell\_id}} (CGNAT-safe), not \texttt{(ip,port)}.
\item Monitor gained a \textbf{backend-victim} KPI; logs ship to Grafana Loki. \alert{Live in production.}
\end{itemize}
\begin{alertblock}{Free triage}
ONLINE in htracker + OFFLINE in Wialon = \textbf{backend victim}, not a dead radio.
\end{alertblock}
\end{frame}
% =====================================================================
\section{GNSS log findings}
\begin{frame}{What we analyzed}
\begin{itemize}
\item \textbf{7 swap-matrix bench captures} (RTK board $\times$ NTRIP master) + one healthy baseline.
\item \textbf{Three views per unit:} u-blox \texttt{.ubx} (receiver), 4G-NTRIP console \texttt{.log}, server retranslator \texttt{tcpdump}.
\item Decoded the NTRIP-caster and ZED-F9P configuration files.
\item Built local tooling so this is repeatable (explorer + analyzer + dashboard).
\end{itemize}
\end{frame}
\begin{frame}{Headline: receivers are fine — RTK is not being achieved}
\begin{itemize}
\item Every board emits \textbf{valid NMEA} (6–12 sats, good HDOP). The ZED-F9P is \emph{not} the failure.
\item But \textbf{every epoch is SPS (quality 1)} — zero RTK (4/5). Centimetre position never delivered.
\item \textbf{Why:} free public \textbf{rtk2go} caster (no SLA) + F9P config saved to \textbf{RAM only} + indoor/bench sky.
\item The F9P message config itself is \textbf{correct} — GGA on UART2 @ 1\,Hz.
\end{itemize}
\end{frame}
\begin{frame}{Every unit is SPS — none reached RTK}
\centering
\includegraphics[width=0.88\textwidth]{fig/fig_fix_compare.pdf}\\[2mm]
\footnotesize Max GGA fix quality per capture (7 bench + baseline) — all flat at 1 (SPS); the RTK line (4) is never reached.
\end{frame}
\begin{frame}{Why: the corrections never settle}
\centering
\includegraphics[width=0.82\textwidth]{fig/fig_ntrip_delay.pdf}\\[2mm]
\footnotesize Even on a healthy unit the NTRIP correction delay sawtooths up to the 300\,s restart watchdog — the free rtk2go feed is intermittent.
\end{frame}
\begin{frame}{Healthy baseline — \texttt{RTK14\_440} (three views agree)}
\begin{columns}[T]
\column{0.56\textwidth}
\begin{itemize}\small
\item \textbf{Receiver:} 341 epochs, 100\% valid, 12 sats, HDOP 0.75 — SPS.
\item \textbf{Server:} 984 packets, steady 1\,Hz, \textbf{zero dropouts}, live in Wialon.
\item \textbf{Console:} ``registered'' only — no forwarding lines.
\end{itemize}
\column{0.4\textwidth}
\begin{alertblock}{The trap}
Healthy \textbf{delivery} $\neq$ \textbf{RTK}. Baseline = healthy SPS + reliable delivery.
\end{alertblock}
\end{columns}
\end{frame}
\begin{frame}{Baseline receiver — healthy geometry, stuck at SPS}
\centering
\includegraphics[width=0.93\textwidth]{fig/fig_baseline_gnss.pdf}\\[1mm]
\footnotesize \texttt{RTK14\_440} u-blox capture: 12 sats, HDOP 0.75, C/N0 $\sim$20 dB-Hz — but the fix never leaves 1 (SPS).
\end{frame}
\begin{frame}{Baseline delivery — healthy end-to-end}
\centering
\includegraphics[width=0.93\textwidth]{fig/fig_delivery.pdf}\\[1mm]
\footnotesize Server-side tcpdump: 984 datagrams, steady $\sim$1\,Hz, max gap 0.86\,s — the unit is genuinely reporting (live in Wialon).
\end{frame}
\begin{frame}{The console blind spot — and a retraction}
\begin{itemize}
\item The \emph{provably-healthy} unit logs the \textbf{same sparse console} as units that looked ``failed''.
\item $\Rightarrow$ the 4G-NTRIP console \textbf{cannot prove forwarding}. Absence of lines $\neq$ failure.
\item \alert{Retraction:} the earlier ``master-14 ingest fault'' is \textbf{withdrawn}.
\item Only \textbf{master 21} is a confirmed fault: modem won't register (\texttt{0xFFFFF} + 511 AT-parser errors).
\end{itemize}
\end{frame}
\begin{frame}{Per-master verdict}
\centering
\begin{tabular}{ll}
\toprule
\textbf{NTRIP master} & \textbf{Result} \\
\midrule
\#04 · \#17 · \#24 · \#25 & Healthy — registered + forwarding \\
\#14 & \alert{Indeterminate} — console can't confirm; baseline proves it forwards \\
\#21 & \alert{Failed} — modem won't register (\texttt{0xFFFFF} + 511 AT errors) \\
\bottomrule
\end{tabular}
\vfill
\footnotesize Confirm a unit only from a \texttt{.ubx} (fix), the Blackpill, or a server delivery capture — never the console alone.
\end{frame}
\begin{frame}{Heat — not implicated (by these logs)}
\begin{itemize}
\item Room-temperature bench captures, \textbf{no thermal channel} (firmware v1).
\item The hard faults reproduce \textbf{cold} $\Rightarrow$ heat is \emph{not} the cause of what we see here.
\item The \textbf{field} thermal hypothesis stays open — needs a thermocouple cabinet soak and/or v2 MCU-temp logging.
\end{itemize}
\end{frame}
% =====================================================================
\section{Changes \& tooling}
\begin{frame}{Observability — the real fix}
\begin{itemize}
\item The Blackpill watchdog already computes fix, packets, state, battery, MCU temp.
\item \textbf{v2.1 logging spec:} replace the self-overwriting ANSI dashboard with a \textbf{structured, timestamped, parseable} stream (+ decoded reset cause).
\item \textbf{\texttt{hbox-log-tools}} repo: in-browser Log Explorer (parse + plot + compare to baseline, offline), batch analyzer, dashboard, manual.
\end{itemize}
\end{frame}
\begin{frame}[fragile]{The new per-unit log line (v2.1)}
\begin{lstlisting}
BOOT,32,fw=2.1,reset=POR
COLS,ms,state,link,fix,sat,rx,rate,vbat,v5v,veh,ign,tc,tmax,der,rec,limp,nmea_age
TLM,190000,RUN,OK,4,12,340,1HZ,5.01,1,1,48,49,0,0,0,310
EVT,490000,RUN,DEGR,RTK lost -> recycle 4G/NTRIP
\end{lstlisting}
\footnotesize Fix + packets + state + reset cause $\Rightarrow$ per-unit health is unambiguous from the unit's own log — no server tcpdump needed.
\end{frame}
% =====================================================================
\section{Next steps}
\begin{frame}{Next steps}
\begin{enumerate}
\item Save the F9P config to \textbf{FLASH} + verify (RAM-only is a power-cycle risk); check the simpleRTK2B Pro \texttt{XBEE$\leftrightarrow$UART2} switch.
\item Move corrections off rtk2go $\rightarrow$ a \textbf{dedicated caster} (HelgenSRV) with uptime.
\item \textbf{Open-sky RTK retest} with a verified caster $\rightarrow$ confirm fix $\geq 4$.
\item Connect the \textbf{Blackpill} with v2.1 logging; modem-triage master 21; thermal soak.
\end{enumerate}
\end{frame}
\begin{frame}[standout]
The radios work.\\
We deliver \textbf{SPS} reliably — \textbf{not RTK}.\\[2mm]
{\normalsize The blockers are \textbf{corrections} and \textbf{observability} — both now addressed.}
\end{frame}
\end{document}