Files
appRobotDriver/EmergencyStopButton/eStopESP32.tex
2026-06-25 18:58:55 +02:00

263 lines
7.9 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.
\documentclass[a4paper,11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage{geometry}
\usepackage{amsmath}
\usepackage{booktabs}
\usepackage{listings}
\usepackage{xcolor}
\usepackage[unicode=true]{hyperref}
\usepackage{enumitem}
\lstset{
basicstyle=\ttfamily\small,
keywordstyle=\color{blue},
commentstyle=\color{gray},
stringstyle=\color{orange},
backgroundcolor=\color{gray!10},
frame=single,
breaklines=true,
columns=fullflexible
}
\title{\textbf{Emergency Stop Button -- ESP32}\\
\large Technische Dokumentation}
\author{}
\date{Juni 2026}
\begin{document}
\maketitle
\tableofcontents
\newpage
% -----------------------------------------------
\section{Ziel und Anforderungen}
Ein physischer Notaus-Taster soll beim Drücken so schnell wie möglich einen
API-Call absetzen. Der ESP32 befindet sich im Ruhezustand und wird durch den
Tastendruck geweckt.
\begin{itemize}
\item Latenz Knopfdruck $\rightarrow$ API-Call: \textbf{< 250\,ms}
\item Stromversorgung: LiPo 2000\,mAh (kabellos, batteriebetrieben)
\item Möglichst lange Akkulaufzeit (Taster wird selten gedrückt, $\leq$1\,×/h)
\item Einfache, wartungsarme Architektur
\end{itemize}
% -----------------------------------------------
\section{Architekturentscheidung}
\subsection{Bewertete Optionen}
\begin{center}
\begin{tabular}{lllll}
\toprule
Option & Latenz & Ø Strom & Gateway nötig & Komplexität \\
\midrule
Deep Sleep + WiFi (RTC-Memory) & 600--1300\,ms & $\approx$0{,}02\,mA & nein & niedrig \\
\textbf{WiFi Light Sleep (DTIM=10)} & \textbf{150--250\,ms} & \textbf{0{,}5--1\,mA} & \textbf{nein} & \textbf{niedrig} \\
BLE Light Sleep + Gateway & 100--300\,ms & 0{,}5--2\,mA & ja & hoch \\
\bottomrule
\end{tabular}
\end{center}
\subsection{Entscheidung: WiFi Light Sleep}
WiFi Light Sleep erfüllt alle Anforderungen ohne zusätzliche Infrastruktur:
\begin{itemize}
\item Der ESP32 hält die WiFi-Verbindung aufrecht und schläft nur die CPU
\item Ein GPIO-Interrupt weckt den ESP32 sofort beim Tastendruck
\item Der API-Call geht direkt vom ESP32 -- kein Container, kein Gateway
\end{itemize}
\textbf{Warum nicht BLE?} Bluetooth LE wäre minimal sparsamer
($\approx$0{,}5\,mA vs. $\approx$1\,mA), erfordert aber ein dauerhaft laufendes
Gateway-Gerät (Raspberry Pi, PC), das seinerseits Strom verbraucht und eine
Fehlerquelle darstellt.
\textbf{Warum nicht Deep Sleep?} Deep Sleep braucht beim Aufwachen
600--1300\,ms (WiFi-Reconnect), was die Latenzanforderung von 250\,ms
verfehlt.
% -----------------------------------------------
\section{WiFi Light Sleep -- Funktionsprinzip}
Im WiFi Light Sleep (Modem Sleep) schläft die CPU, während der WiFi-Stack
aktiv bleibt. Der Router sendet alle 100\,ms einen Beacon; mit DTIM=10 wacht
der ESP32 automatisch alle $\approx$1000\,ms für 1--2\,ms auf, um gepufferte
Pakete abzuholen. Die Verbindungsassoziation bleibt dabei erhalten.
\subsection{DTIM-Einstellung und Stromverbrauch}
\begin{center}
\begin{tabular}{lll}
\toprule
DTIM & Wakeup-Intervall & Ø Strom \\
\midrule
1 & 100\,ms & 5--10\,mA \\
3 & 300\,ms & 2--4\,mA \\
10 & 1000\,ms & 0{,}5--1\,mA \\
\bottomrule
\end{tabular}
\end{center}
Empfohlen: \texttt{DTIM=10} -- sparsamste Option, Verbindung bleibt stabil.
\subsection{Akkulaufzeit (2000 mAh LiPo)}
Bei $\approx$1\,mA Durchschnittsstrom (DTIM=10, selten gedrückt) und 80\,\% nutzbarer Kapazität:
\[
t = \frac{1600~\mathrm{mAh}}{1~\mathrm{mA}} \approx 67\text{--}80~\mathrm{Tage}
\]
Die \textbf{Latenz von 250\,ms} hat Vorrang vor maximaler Akkulaufzeit -- Deep Sleep scheidet
daher aus (WiFi-Reconnect 600--1300\,ms). Mit 2000\,mAh und WiFi Light Sleep sind
ca.\ 2,5 Monate Betrieb ohne Laden realistisch.
% -----------------------------------------------
\section{Latenzbudget}
\begin{center}
\begin{tabular}{ll}
\toprule
Schritt & Zeit \\
\midrule
ESP32 Wakeup aus Light Sleep & 1--5\,ms \\
WiFi-Verbindung prüfen (bereits aktiv) & 0\,ms \\
HTTP-Request aufbauen & 20--50\,ms \\
TLS-Handshake (HTTPS) & 50--150\,ms \\
Server-Antwort & 20--50\,ms \\
\midrule
\textbf{Gesamt} & \textbf{$\approx$100--250\,ms} \\
\bottomrule
\end{tabular}
\end{center}
% -----------------------------------------------
\section{Hardware}
\subsection{Empfohlene Boards}
\begin{center}
\begin{tabular}{llll}
\toprule
Board & Lader & Preis & Bemerkung \\
\midrule
\textbf{FireBeetle ESP32-E} (DFRobot) & integriert & 8--12\,& Low-Power optimiert \\
LOLIN D32 (Wemos) & TP4054 & 5--8\,& günstig, bewährt \\
Adafruit HUZZAH32 Feather & MCP73831 & $\approx$20\,& gute Dokumentation \\
\bottomrule
\end{tabular}
\end{center}
\subsection{Akku-Spezifikation}
Für den FireBeetle\,2 wird ein \textbf{1S LiPo mit JST-PH-2,0-Stecker und BMS} benötigt:
\begin{center}
\begin{tabular}{ll}
\toprule
Merkmal & Wert \\
\midrule
Typ & LiPo / Li-Polymer, 1 Zelle (1S) \\
Nennspannung & 3{,}7\,V (voll: 4{,}2\,V) \\
Stecker & JST PH, 2{,}0\,mm Raster, 2-polig \\
Schutzschaltung & Ja (BMS/PCM) -- Pflicht bei Deep-Sleep-Betrieb \\
Kapazität & 2000\,mAh \\
\bottomrule
\end{tabular}
\end{center}
\textbf{Achtung Polarität:} JST-PH-Stecker sind nicht normiert -- Polung vor dem
Einstecken mit Multimeter prüfen. Sicherste Quelle: Akku direkt bei DFRobot kaufen.
\subsection{Schaltung}
\begin{lstlisting}
ESP32 Taster
GPIO 9 ---- [Taster] ---- GND
(interner Pull-Up aktiv: HIGH = offen, LOW = gedrueckt)
LiPo 2000mAh (JST PH 2.0, mit BMS) ---- BAT+ / BAT- des Boards
\end{lstlisting}
Kein weiteres Bauteil nötig -- der interne Pull-Up des ESP32 reicht.
% -----------------------------------------------
\section{Software}
\subsection{Abhängigkeiten (Arduino IDE)}
\begin{itemize}
\item Board-Package: \texttt{esp32} by Espressif (Boards Manager)
\item Bibliotheken: \texttt{WiFi.h}, \texttt{HTTPClient.h} (im esp32-Package enthalten)
\end{itemize}
\subsection{Konfiguration in \texttt{EmergencyStopButton.ino}}
\begin{lstlisting}[language=C]
#define BUTTON_PIN 9
#define WIFI_SSID "DEIN_SSID"
#define WIFI_PASSWORD "DEIN_PASSWORT"
#define API_URL "https://deine-api.example.com/emergency-stop"
#define API_TOKEN "DEIN_API_TOKEN"
\end{lstlisting}
\subsection{Ablauf}
\begin{enumerate}
\item \texttt{setup()}: WiFi verbinden, \texttt{WIFI\_PS\_MAX\_MODEM} aktivieren
\item \texttt{loop()}: \texttt{esp\_light\_sleep\_start()} -- CPU schläft, WiFi aktiv
\item Tastendruck löst GPIO-Interrupt aus -- ESP32 wacht auf
\item \texttt{sendEmergencyStop()} sendet HTTP-POST an API
\item Warten bis Taster losgelassen, zurück zu Schritt 2
\end{enumerate}
\subsection{Kritische API-Funktion}
\begin{lstlisting}[language=C]
void sendEmergencyStop() {
HTTPClient http;
http.begin(API_URL);
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", "Bearer " API_TOKEN);
http.setTimeout(3000);
String body = "{\"event\":\"emergency_stop\",\"device\":\"esp32-estop\"}";
int httpCode = http.POST(body);
http.end();
}
\end{lstlisting}
% -----------------------------------------------
\section{Deployment-Hinweise}
\begin{itemize}
\item \textbf{HTTPS}: TLS-Handshake kostet 50--150\,ms. Falls die Latenz
kritisch ist und das Netz vertrauenswürdig, kann HTTP verwendet werden
(dann $\approx$50--100\,ms Gesamt).
\item \textbf{DTIM am Router}: Manche Router ignorieren den DTIM-Wunsch des
Clients. Im Zweifelsfall DTIM=3 am Router einstellen.
\item \textbf{API-Token}: Nicht im Quellcode einchecken -- z.\,B. in eine
separate \texttt{secrets.h} auslagern, die im \texttt{.gitignore} steht.
\item \textbf{Watchdog}: Bei produktivem Einsatz einen Hardware-Watchdog
aktivieren, damit der ESP32 sich bei WiFi-Verlust selbst neu startet.
\end{itemize}
% -----------------------------------------------
\section{Dateien}
\begin{center}
\begin{tabular}{ll}
\toprule
Datei & Beschreibung \\
\midrule
\texttt{EmergencyStopButton.ino} & Arduino-Sketch (Hauptprogramm) \\
\texttt{eStopESP32.tex} & Diese Dokumentation \\
\bottomrule
\end{tabular}
\end{center}
\end{document}