d8a9953b73
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>
202 lines
10 KiB
Markdown
202 lines
10 KiB
Markdown
# 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.5–3.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 0–100 % |
|
||
| `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, 0–4095: 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.
|