Files
grossanzeige/README.md
T
admin d8a9953b73 Niedrig-/Hochpraezision der Montierung + IP eingetragen
Die GM4000 laeuft in Niedrigpraezision (keine Sekunden): RA HH:MM.T,
DEC sDD°MM. Anzeige daran angepasst:
- config.HIGH_PRECISION (Vorgabe False) steuert die DEC-Darstellung:
  False -> ohne Sekunden (-00°55'), True -> mit Sekunden (+38°47'01)
- RA immer mit Sekunden (11h36m54s); bei Niedrigpraezision aus den
  Zehntel-Minuten abgeleitet (6-Sekunden-Schritte), kein Dezimalpunkt
  (der wirkt in der Sperrschrift zu luftig)
- coords.format_ra/format_dec nehmen high_precision=
- MOUNT_HOST auf die echte IP (192.168.1.115)

Hinweis: Das 'ß' in der Konsole ist nur der Rohwert (Grad-Byte 0xDF);
auf der Anzeige erscheint korrekt der Gradring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 23:07:22 +02:00

202 lines
10 KiB
Markdown
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.
# Großanzeige
Ansteuerung einer microSYST **migra SC/MC Seriell** LED-Großanzeige mit den
Koordinaten (Rektaszension / Deklination) einer 10Micron GM4000 HPS II.
Endziel ist ein XIAO ESP32-C3, der die Montierung per WLAN abfragt und die
Koordinaten über UART/RS232 auf die Anzeige schreibt. **Phase 1** (dieser Stand)
ist das Testprogramm auf dem Mac: Koordinaten von Hand übergeben, Ausgabe über
einen USB-RS232-Wandler.
## Benutzung
```bash
# Phase 1 -- Koordinaten von Hand:
python3 show_coords.py 12h34m56s +45d12m30s # Koordinaten anzeigen
python3 show_coords.py 12:34:56 -07:15:00 # Trennzeichen sind egal
python3 show_coords.py --clear # Anzeige löschen
python3 show_coords.py 12h34m56s +45d12m30s --dry-run # nur Telegramm als Hex
# Phase 2 -- Koordinaten von der Montierung (10Micron GM4000):
python3 run_display.py # Montierung aus config.py pollen
python3 run_display.py --host 10.0.0.42 # andere IP
python3 run_display.py --mock --move # ohne Teleskop: lokaler Mock, RA läuft
python3 run_display.py --mock --move --ldr 2000 # zusätzlich mit Helligkeitsregelung
python3 mount_mock.py --move # Mock separat starten
# Helligkeit aus einem LDR-Wert setzen:
python3 brightness.py --ldr 1500 # LDR-Rohwert -> Stufe/Prozent -> senden
python3 -m unittest test_migra test_lx200 test_brightness # alle Tests
python3 probe.py ruler # Geometrie der Anzeige ausmessen
```
Einzige Abhängigkeit auf dem Mac ist `pyserial`.
## Aufbau
| Datei | Zweck |
|---|---|
| `migra.py` | Protokoll: Telegrammrahmen, Prüfsumme, ESC-Sequenzen. Ohne Abhängigkeiten, **läuft unverändert unter MicroPython**. |
| `transport.py` | UART: `pyserial` (Mac), `machine.UART` (ESP32-C3), `FakeTransport` (Trockenlauf). |
| `display.py` | Treiber: Telegramm senden, Antwort auswerten. |
| `coords.py` | Koordinaten einlesen und auf die Zeilenbreite formatieren. |
| `config.py` | Port, Adresse, Geometrie, Helligkeit — alles an einer Stelle. |
| `show_coords.py` | Das Testprogramm (Koordinaten von Hand). |
| `brightness.py` | Helligkeitsregelung: LDR-Wert → Stufe/Prozent (portabel + CLI). |
| `run_display.py` | Hauptschleife Phase 2: Montierung pollen, anzeigen, Helligkeit regeln. |
| `mount_client.py` / `mount_mock.py` | TCP-Client zur GM4000 bzw. Simulator (LX200). |
| `lx200.py` | LX200-Kommandorahmen. |
| `probe.py` | Testmuster zum Ausmessen von Zeilenbreite und Zeilenposition. |
| `test_migra.py` / `test_lx200.py` / `test_brightness.py` | Tests. |
## Protokoll (Kurzfassung)
Referenz: Benutzerhandbuch `X-M31-9AXX5X-006 (V4.20)`, Kapitel 3.53.9.
**Schnittstelle:** 19200 Baud, 8 Datenbits, **Even Parity**, 1 Stopbit.
9-pol. Sub-D: Pin 2 = RxD, Pin 3 = TxD, Pin 5 = GND.
**Telegramm:**
```
STX | DA | SA | FC | [LEN-H LEN-L] | Data-Unit | [CHK-H CHK-L] | ETX
02 81 80 81 03
```
- `DA`/`SA`: Adressen mit gesetztem Bit 7 → Anzeige = 1 (`0x81`), Host = 0 (`0x80`).
- `FC`: Bit 7 fest 1, Bit 1 = Prüfsumme, Bit 0 = Antwort anfordern.
`0x81` = ohne Prüfsumme, mit Antwort (so fuhr auch das alte MSP430-Programm).
- Ohne Prüfsumme dürfen `LEN-H/L` und `CHK-H/L` **nicht** mitgesendet werden.
- Prüfsumme = Low-Byte der Summe aus `DA, SA, FC, LEN-H, LEN-L` und allen Datenbytes,
als zwei Nibbles mit gesetztem High-Nibble (`0xF0 | nibble`).
**Antwort:** `02 80 81 80 <Fehlercode> 03`, Fehlercode `'0'` = kein Fehler.
Nach Erhalt der Antwort darf sofort das nächste Telegramm folgen — das ist die
Flusskontrolle. Ohne Antwort muss zwischen den Telegrammen gewartet werden
(Empfangstimeout + ca. 150 ms).
**ESC-Sequenzen** (alle Zahlen ASCII-codiert, Position 123 → `'1' '2' '3'`):
| Sequenz | Bedeutung |
|---|---|
| `ESC z NN` / `ESC Z NN` | Zeichensatz NN (`z` = Sperrschrift, gleiche Zeichenbreite) |
| `ESC C xxxyyy` | Cursor auf **Pixel**position x/y, 0/0 ist links oben |
| `ESC A <fg><bg><blink>` | Attribute; Farbe 0 = schwarz, 1 = grün, 2 = rot, 3 = gelb |
| `ESC F <Farbe>` | Anzeige füllen; `ESC F 0` = löschen |
| `ESC H <Farbe><ppp>` | Helligkeit 0100 % |
| `ESC T <+/-><nnn>` | gespeicherten Text ein-/ausblenden |
Folgt auf eine ESC-Sequenz ein Online-Text, muss **`0x1F` als Trennzeichen**
dazwischen. Data-Unit max. 230 Zeichen. `migra.DataUnit` setzt das Trennzeichen
selbst.
## Offene Punkte
- **Echte Montierungs-IP:** In `config.py` steht `MOUNT_HOST` noch als Platzhalter.
Sobald die GM4000 im Netz erreichbar ist, dort die IP eintragen (Port 3490 ist
Vorgabe). Bis dahin läuft alles gegen den Mock (`run_display.py --mock`).
- Portierung auf den XIAO ESP32-C3 (MicroPython): `migra.py`, `lx200.py`,
`mount_client.py` sind bewusst abhängigkeitsfrei; nur `transport` (UART) und das
WLAN-Setup kommen hinzu.
## Gradzeichen
Der Standard-Zeichensatz 0 der Anzeige hat **kein** `°`. Der von der Sternwarte
geladene **Zeichensatz 1** enthält an Position `/` (0x2F) ein hochgestelltes
Gradzeichen (deckt sich mit dem alten Programm, `asciitaf.h`: Code 0xAF → per
`& 0x7F` = 0x2F in Zeichensatz 1). Zur Ausgabe wird für dieses eine Zeichen kurz
auf Zeichensatz 1 umgeschaltet und wieder zurück (`config.DEGREE_*`, `display._emit_degree`).
**Fallstrick:** Ein Zeichensatzwechsel mitten im Telegramm beschädigt die Home-Zelle
(0,0) — das erste Zeichen der obersten Zeile wird zerstört. Deshalb zeichnet
`show_lines` die Zeilen **von unten nach oben** (oberste Zeile zuletzt), damit sie
diese Zelle überschreibt.
## Geometrie und Darstellung
- **9 Zeichen pro Zeile** in Sperrschrift (`CHARSET_SPACED = True`, am Gerät
ausgemessen). `probe.py ruler` misst es nach.
- Die Deklination wird deshalb als **9-Zeichen-Form ohne abschließendes `"`**
ausgegeben (`+38°47'01`) — Gradzeichen und Bogenminuten bleiben, die Bogensekunden
stehen als Ziffern da. `coords.format_dec` wählt automatisch die breiteste Form,
die in `CHARS_PER_LINE` passt.
- **Zyklische Updates flimmerfrei:** `show_lines` löscht nicht bei jeder Aktualisierung,
sondern überschreibt die Zeilen an Ort und Stelle (auf volle Breite aufgefüllt).
`clear=True` nur beim ersten Bild. Wichtig: Zeilen dürfen **nicht breiter** als
`CHARS_PER_LINE` aufgefüllt werden, sonst bricht das Füll-Leerzeichen um und
beschädigt die andere Zeile.
## Präzision (Low / High)
Die GM4000 läuft standardmäßig in **Niedrigpräzision** und sendet keine Sekunden:
RA als `HH:MM.T` (Zehntel-Minuten), DEC als `sDD°MM` (ganze Bogenminuten). Das
Gradzeichen kommt als Byte `0xDF` — auf der Anzeige korrekt als Gradring dargestellt;
in der Terminal-Konsole erscheint der **Rohwert** dieses Bytes als `ß` (rein kosmetisch).
`config.HIGH_PRECISION` steuert die DEC-Darstellung:
- `False` (Vorgabe): DEC ohne Sekunden (`-00°55'`).
- `True`: DEC mit Sekunden (`+38°47'01`) — erst sinnvoll, wenn die Montierung per
`:U#` auf Hochpräzision gestellt ist (schreibendes Kommando, hier bewusst nicht
automatisch gesendet).
Die **RA** wird immer mit Sekunden gezeigt (`11h36m54s`); bei Niedrigpräzision
kommen die Sekunden aus den Zehntel-Minuten und springen daher in 6-Sekunden-Schritten
(kein Dezimalpunkt — der wirkt in der Sperrschrift zu luftig).
`coords.format_ra`/`format_dec` nehmen `high_precision=` als Parameter (Vorgabe aus
`config`). Die Montierungs-Rohwerte werden im `coords`-Parser unverändert korrekt
zerlegt (Trennzeichen `:`, `*`, `0xDF`, `'` sind alle egal).
## Helligkeitsregelung
Portiert aus dem alten MSP430-Programm (`DoDimmen_V`, Werte aus `main.h`). Ein
LDR-Rohwert (12-Bit-ADC, 04095: je heller die Umgebung, desto höher der Wert)
wird über einen gleitenden Mittelwert (8 Werte) geglättet und auf eine
Helligkeitsstufe mit Hysterese abgebildet:
| Stufe | Helligkeit | erreicht ab (hoch / runter) |
|------|-----------|------------------------------|
| 0 | 5 % | < 270 |
| 1 | 15 % | ≥ 330 / < 270 |
| 2 | 50 % | ≥ 2650 / < 2350 |
| 3 | 100 % | ≥ 3650 / < 3350 |
Schwellen-Mitten `300 / 2500 / 3500`, Hysterese `±30 / ±150 / ±150`. **300 und 2500
stammen aus dem alten Code**; die obere Grenze `HELL_MAX = 3500` für 100 % ist neu
(der alte Code hatte keine 4. Stufe) und in `brightness.py` anpassbar, sobald der
reale LDR-Wertebereich feststeht. Ein Helligkeitstelegramm wird nur bei
**Stufenwechsel** gesendet (`ESC H 2 <ppp>`), wie im Original.
Der LDR-Wert kommt derzeit per Kommandozeile (`--ldr`); auf dem ESP32-C3 liefert
ihn später der ADC. `run_display.py --ldr <wert>` bindet die Regelung in die
Hauptschleife ein (`BrightnessController`).
## Antwortleitung (RX)
Der Rückkanal ist verdrahtet und verifiziert (2026-07-16): Anzeige Pin 3 (TxD) →
MAX232-Empfängereingang (R_IN) → R_OUT → Adapter RxD. Die Anzeige quittiert jedes
Telegramm mit `02 80 81 80 30 03` (Fehlercode `0` = kein Fehler). `WANT_RESPONSE = True`
ist damit aktiv: Nach der Antwort darf sofort das nächste Telegramm folgen, der
Fehlercode wird ausgewertet. `resp_test.py` prüft den Rückweg (sendet mit Antwort-
Anforderung und zeigt die empfangenen Antworten).
Wichtig: `SerialTransport.write` leert vor jedem Senden den Empfangspuffer, damit
`read_response` nur die frische Antwort sieht (sonst können Störbytes zwischen den
Telegrammen das Parsen stören). `run_display` fängt Anzeige-Fehler ab und zeichnet
beim nächsten Durchlauf neu, statt abzustürzen.
Diagnose-Historie: Der Rückweg war anfangs falsch verdrahtet — Pin 3 lag an einem
MAX232-*Sender*ausgang statt einem Empfängereingang; zwei Ausgänge trieben
gegeneinander (verschliffener ~3-V-Pegel am Oszi). `loopback.py` grenzt so etwas ein.
## Erledigt
- **Phase 1 + 2 am Gerät bestätigt (2026-07-15/16):** Koordinaten erscheinen korrekt,
inkl. echtem Gradzeichen; im `run_display`-Betrieb aktualisieren beide Zeilen
laufend, sauber und ohne Flimmern, mit Antwort-Handshake der Anzeige. Protokoll,
19200 8E1, Zeichensatz und Zeilengeometrie stimmen.
- Schrift: Sperrschrift (`ESC z`, `CHARSET_SPACED = True`), 10 Zeichen/Zeile.
Die schmale `1` wirkt dadurch etwas luftig — Font-Eigenschaft, nur per eigenem
Font (microSYST-PC-Software) änderbar.