Donnerstag, 22 Januar, 2026

Senden von APRS Nachrichten mit CircuitPython und VHF-Modul

APRS gibt es im Amateurfunk bereits seit langer Zeit. Auf die Besonderheiten im speziellen gehe ich im weiteren Text ein. Zu jener Zeit gab es extra dafür konzipierte analoge integrierte Schaltungen (IC’s) welche die benötigte Modulation des Senders übernommen haben. Diese sind heute leider nicht mehr verfügbar. Ich möchte jetzt nicht allzu tief in das APRS-Protokoll eingehen, es existieren sehr viele Infoseiten im Web dazu (siehe unter Links).

Seit geraumer Zeit verwende ich ein 2m-Handfunkgerät um gelegentlich einige Fahrten im Auto per APRS zu loggen. Eigentlich ist es dafür viel zu schade. Warum es nicht gegen ein selbst gebautes Gerät ersetzen?

Beim Einlesen in das Thema APRS merkt man aber schnell, dass man die Thematik in verschiedene Bereiche aufteilen muss, um den Überblick zu bewahren.

Funktionsweise von APRS.

Welche Protokolle kommen für die Übertragung zur Anwendung?

APRS verwendet das übergeordnete Kommunikationsprotokoll AX.25. Dieses ist ein sehr mächtiges Protokoll und APRS verwendet nur einen winzig kleinen Teil davon. Was aber nicht bedeutet das es einfach zu verwenden ist. Genau genommen ist AX.25 in der Lage Informationen zielgerichtet weiterzuleiten. Dieses Routing wird im Amateurfunk-APRS aber kaum/nicht verwendet. Die Meldungen, welche versendet werden haben kein bestimmtes Ziel und sollen von verschieden Arten von Repeatern abgewickelt werden.

Wie wird moduliert?

Die Übertragung der Daten erfolgt über zwei Töne von 1200Hz und 2200Hz. Als Modulation kommt ein spezielles Verfahren zum Einsatz, welches mir Anfangs etwas Kopfzerbrechen bereitet hat.

Die Modulation verwendet eine Symbolrate von 1200 Baud. Das bedeutet, 1200 Datenwerte pro Sekunde gesendet werden. Mit den beiden Tonfrequenzen von 1200Hz und 2200Hz ergeben sich folgende Zusammenhänge:

Wird ein 1200Hz Ton gesendet entspricht der Zeitraum eines Symbols einer Wellenlänge von 1200 Hz. Ein 2200Hz Ton wird während dieser 1/1200 Sekunde mit 1,83333 Wellenlängen übertragen. Die Definition verlangt, dass die Phase beim Tonwechsel erhalten bleibt. Dazu muss die Phase natürlich bekannt sein und bei der Erzeugung des nächsten Tones berücksichtigt werden. Auch wichtig! Es wird NICHT für Bit=1 der eine Ton und für Bit=0 der andere verwendet. Das hier verwendete Verfahren heisst NRZI und steht für “Non Zero Return Inverted encoding”. Wird ein Bit=0 gesendet, erfolgt ein Tonwechsel. Für Bit=1 bleibt der Ton bestehen. Es spielt daher keine Rolle mit welchem Ton die Aussendung beginnt. Um die Synchronisation über mehrere 1-Bits zu erhalten, wird vom Sender nach dem fünften Bit=1 ein zusätzlicher Tonwechsel eingefügt. Dieser Wechsel, auch Bit-Stuffing genannt (würde einem Bit=0 entsprechen) wird vom mit zählendem Empfänger aber ignoriert. Er dient einzig dazu das Timing zu synchronisieren. Eine weitere Besonderheit besteht beim Beginn und Beenden einer Übertragung. Hier werden zur Signalisation am Anfang und Ende einer Nachricht mehrere gleiche Bytes (0×7E) übertragen, die nicht vom Bit-Stuffing verändert werden und daher vom Empfänger als Start und Endpunkt einer Nachricht erkannt werden können. Diese Bit-Kombination mit 6 x Bit=1 kommt somit in der eigentlichen Nachricht nicht vor.

Technische Umsetzung

Wie wird das modulierte Signal aufbereitet?

Das Herz der Schaltung ist ein Adafruit Feather-M4 Mikrokontroller mit 2MB Speicher, 192kB RAM und diverser Schnittstellen. Darunter auch ein zweikanaliger DAC mit bis zu 1Mbit Sampling-Rate. Der Feather M4 Mikrocontroller stellt einige interessante Funktionen bereit. So lassen sich zum Beispiel gespeicherte MP3 oder WAV-Dateien über den DAC auszugeben. Ebenso kann man eigene Signale als Array erzeugen und vom DAC mit der gewünschten Samplinmgrate ausgeben lassen. Das geschieht ohne CPU direkt über interne DMA Funktionen.

Wie bereits erwähnt, muss beim Tonwechsel die Phase fortgeführt werden. Ein einfaches Abspielen von Tönen gelingt hier nicht, da der Kontroller jeweils seinen Ton bei Phase = 0 Grad beginnt. Bei diesem Mikrokontroller wird das über die Funktion mit dem Abspielen eines Arrays genutzt. Der DAC hat eine Auflösung von 12bit. Um Speicher zu sparen werden nur 8bit verwendet. Somit passt ein Sample in ein Byte.

Für die weitere Vorgehensweise braucht es zuerst noch etwas Theorie. Um eine Sinuswelle ausgeben zu können muss man sich darauf festlegen, aus wie vielen Samples (Datenpunkten) diese bestehen soll. Bei xx Datenpunkten entsprächen für den 1200Hz Ton ein Sample jeweils eine Phasenverschiebung von 360 / xx. Für den 2200Hz Ton sind es 360 / xx * 2200 / 1200. Mit einem kleinen Tabellenprogramm lässt sich in Kürze eine passende Kombination herausfinden. Bei 30 Samples pro Symbol kommt man auf folgende Werte:

Bitrate 1200
Samples pro Bit 30
Samplingrate = 36000

Phasenwinkel:
Mark 1200Hz => 360 / 30 = 12 Grad
Space 2200Hz => 360 / 30 * (2200/1200) = 22 Grad

Da hier beide Phasenwinkel ganzzahlig sind, lassen sich die Sinuswerte für 0-359 Grad einfach vorberechnen und als statisches Array im Speicher ablegen. Für jedes Sample wird dann dessen Phasenversatz addiert und daraus der passende Sinuswert aus dem Array ausgelesen.

Update (13.03.2021)
Circuitpython hat im Feather-M4-Express ca. 160 kB RAM zur Verfügung. Es hat sich herausgestellt, dass bei 30 Samples pro Bit der Speicher nicht immer ausreicht. Da Circuitpython eine interpretierte Sprache ist, sind keine genauen Voraussagen zum Speichermanagement möglich. Die Reduzierung auf 15 Samples pro Bit haben soweit keine Einbussen bezüglich Detektierbarkeit gezeigt. Es empfiehlt sich auch die Komprimierung der Dateien mit dem MPY-CROSS Tool um unnötigen Balast aus den Dateien zu entfernen. Das Sendemodul DRA818V weist zudem einige Nachteile auf. So benötigt das Modul nach Setzen des PTT-Signals ca. 1 Sekunde bis das Audiosignal stabil ausgesendet wird. Nach dem Lösen der PTT sendet es noch einen niederfrequenten Zweiton aus (Roger-Beep?). Dieser lässt sich unterdrücken, wenn das Module in den Powersafe Modus versetzt wird. Die aktuelle Software berücksichtigt diese Umstände. Leider dauern die Aussendungen dadurch länger als nötig (ca. 1.5 Sekunden für den Vorlauf).

Welche Funktionen des Protokolls werden in der Software implementiert?

Da das Modul nur im Fahrzeug verwendet wird, werden nur Positions- und Umweltdaten versendet.

Wie wird das Signal ausgesendet?

Für die Aussendung wird das 2m HF-Modul DRA818V eingesetzt.

Hardware / Software

Der Prototyp enthält folgende Module

- Spannungswandler von 12V auf 3.3V. Die finale Version wird dann über 5V versorgt, damit der Akkulader benutzt werden kann und eine Bufferung möglich ist (mit Auto-PowerOff).
- Adafruit Feather M4 Express
- GPS Modul (Adafruit Ultimate GPS Breakout) mit Antennenanschluss
- Temperatur, Höhensensor (Adafruit BMP 280)
- Beschleunigungssensor (Adafruit LIS3DH)
- SD-Kartenmodul (Adafruit Micro-SD Breakout Board)
Die Software basiert komplett auf CircuitPython. Die Bibliotheken für die Sensoren stammen von Adafruit.

Update

14.03.2021

Die Software hat seit dem letzten Post zahlreiche Verbesserungen erfahren. Besondere Aufmerksamkeit musste dem RAM Speicherbedarf gewidmet werden. Das Array für das Senden der Daten wird intern berechnet und hat bei einer Samplingrate von 36′000 nicht (immer) genügend Speicher zur Verfügung. Eine Analyse der Kurvenform mit reduzierter Rate auf 18′000 Punkte / Sekunde zeigte keine Schwierigkeiten beim Dekodieren. Für noch mehr freies RAM sorgt die Komprimierung der .py Dateien in .mpy mit dem MPY-CROSS Tool.

Weitere Bytes im RAM lassen sich gewinnen, wenn klasseninterne Variablen nicht über getter/setter Funktionen angesprochen werden. Python kennt keine lokal geschützen klasseninternen Variablen. Wenn man deren Namen kennt, kann man darauf zugreifen. Einzig die Namenskonvention deutet auf die gedachte Verwendung hin. Variablen die als __var1 deklariert sind, werden von Python aber etwas versteckt. Variablennamen wie _var2 sind frei zugänglich, sollen aber dem Programmierer auf die private Eigenschaft derer hinweisen. Daher sind im aktuellen Quellcode alle öffentlichen Variablen einer Klasse direkt ohne getter/setter abrufbar. Das gilt natürlich nur für solche Variablen, die keine Berechnungen oder zusätzliche Bearbeitung benötigen.

Source

siehe Codeberg Repository

Links

APRS Dokumentation
Gute Dokumentation über die Eigenheiten von APRS

Bilder

prototype.jpg

Mittwoch, 21 Januar, 2026

VHF-UHF Dualband Antenne für den Balkon

Wer in einem urbanen Wohnungsgebiet wohnt, kennt das Problem. Die Antenne sollte so klein und unsichtbar wie möglich sein und trotzdem gut funktionieren. Wohnt man in einem mehrstöckigen Gebäude eignen sich Antennen mit Magnetfuss nur bedingt, da Balkone kaum grosse magnetische Flächen haben und die Geländer meist aus rundem, kaum magnetischem Chromstahl bestehen.

Eine kurze Recherche im Internet bringt diverse Antennenvarianten hervor. Ich habe mir eine Variante von DK7ZB abgekupfert und mit einem 3D-Druck Gehäuse nachgebaut.

Das Prinzip ist ganz einfach. Es wird ein normaler 2m Dipol konstruiert dem in nächster Nähe ein passives Element für das 70 cm Band hinzugefügt wird. Das funktioniert, weil das 70 cm Band ein Drittel der Wellenlänge vom 2m hat und ebenfalls resonant sein kann.

Mit dieser Antenne gelingt eine Verbindung zur 92km entfernten Relaisstation DB0XR ohne Probleme. Die Station selbst wird mit S7 empfangen.

Als echter Dipol kann diese Antenne auch in horizontaler Polarisation problemlos betrieben werden.

Aufbau

Die Antenne ist so konstruiert, dass beide Strahler für das 2 m Band zum Transport abgeschraubt werden können.

Strahlerelemente

Die Strahler bestehen aus 10mm eloxiertem Alumminiumrohr welches im Baumarkt zu finden ist. Zwei Stück à 1m reichen für eine Antenne. Ein Rohr wird genau mittig geteilt. Jeweils ein Ende wird an der Drehbank gerade gedreht und die erstem 20mm auf 8.5mm aufgebohrt. Das entfernt gleichzeitig die innere Eloxalschicht die bekanntlich nicht leitet. Dazu fertigt man zwei 15mm lange Metallzylinder mit 8.8 - 8.7mm Aussendurchmesser und einem durchgehenden M3 Gewinde im Zentrum. Die Zylinder werden dann in das aufgebohrte Rohrende bündig eingepresst. Zur Sicherheit kann man auf den letzten 5mm der Aufbohrung etwas Klebstoff auftragen. Das Rohrende wird dann nochmals überdreht und die Kante gebrochen. Damit das Abstimmen nachher gut klappt, sollten beide Rohre gleich lang sein. Ein weiteres 310mm langes Rohr wird für das 70cm Element benötigt.

Gehäuse

Zentrales Element im Gehäuse sind die beiden Gewindeblöcke die auf jeder Seite ein bis zwei M3 Gewinde enthalten. Damit lassen sie sich einfach im Gehäuse befestigen und halten gleichzeitig die M3 Schrauben für das befestigen der Stahlerelemente in Position. Dank 3D-Druck lässt sich das Gehäuse sehr präzise fertigen und es sind keine Nacharbeiten nötig. Ebenfalls direkt im Gehäuse ist eine Mantelwellensperre realisiert. Dazu wird von der BNC-Buchse aus ein RG-174 Koaxialkabel mehrmals um das runde Zentrum gewickelt. An der Stelle wo das Koaxialkabel dann aufgetrennt wird kommt eine Markierung. Zum einfacheren Auftrennen wickelt man das Kabel wieder ab und schneidet das Kabel 2-3cm hinter der Markierung ab. Nach dem vorsichtigen Entfernen des Mantels wird mit einer Nadel der Schirm geteilt und verdrillt.

Zum Verbinden des Koaxialkabel mit den Gewindeblöcke verwende ich ringförmige Kabelschuhe aus dem KFZ-Bereich. Die Kunststoffisolation wurde vorgängig entfernt.

Die Gewindeblöcke werden ebenfalls mit M3 Schrauben befestigt. Das Gehäuse besitzt dazu zwei Löcher mit 2.7mm Durchmesser. Beim Einschrauben werden die Platten platt im Gehäuse eingesetzt und die M3 Schraube presst beim Eindrehen im Plastik gleichzeitig ein M3 Gewinde ein. Die lange M3 Schraube für die Stahlerelemente muss zwingend eingeklebt werden. Dazu reicht ein hochfester Schraubenlack oder etwas Sofortkleber aus.

Der Deckel (hier nicht dargestellt, aber in der CAD-Datei vorhanden) wird mit Schrauben befestigt. Eine dünne Schicht Silikondichtmasse dazwischen ergibt ein wasserdichtes Gehäuse.

CAD

Abstimmen

Das Abstimmen erfolgt für jedes Band getrennt. Dazu werden zuerst nur die beiden Strahlerelemente für das 2m Band eingesetzt. Zur Ermittlung der Frequenz mit den tiefsten SWR verwende ich einen Antennenanalysator der Firma RigExpert. Da die beiden Stahlerelemente noch etwas zu lang sind, wird die Resonanzfrequenz rund 10-15 MHz tiefer ausfallen als gewünscht. Das hat auch damit zu tun, dass die Länge der Zuleitung nach der Auftrennungsstelle des Koaxialkabels bereits zum Strahler gehört.

Man kann jetzt die beiden Strahler solange kürzen bis das tiefste SWR an der gewünschten Stelle zu liegen kommt. Einfacher und sicherer ist es mit dem Antennensimulationsprogramm EZNEC. Dazu wird die Antenne im Simulator nachgebildet und mit passenden Strahlerlängen für die gewünschten Frequenzen konfiguriert. Dies sind die theoretischen Längen bei einer idealen Antenne. Messen wir jetzt an der noch nicht abgestimmten Antenne das beste SWR wird es zum Beispiel bei 126 MHz liegen. Bevor wir die Enden kürzen, verlängern wir im Simulator die Strahlerlängen soweit bis sich die gleiche Frequenz für das beste SWR einstellt. Jetzt hat man die Differenz um welche beide Strahler zu lang sind. Das funktioniert erstaunlich genau. Sicherheitshalber macht man einen Zwischenschritt und lässt erstmal noch 3-5mm stehen. Für den 70cm Strahler gilt das gleiche. Hier gilt es jedoch auf den halben Millimeter genau zu arbeiten. Da dieses Element nicht geteilt ist, muss man nur ein Ende bearbeiten. Es wird anschliessend mittig eingebaut und mit einer M3 Madenschraube festgeklemmt.

Montage

Die Antenne wird mit einem 12mm Glasfaserrohr vom Befestigungspunkt abgesetzt. Ein passendes Rohrendstück, dass mit einer Flügelschraube am Gehäuse festgemacht wird, hält das ganze fest. Das Glasfaserrohr ist ca. 60cm lang. Eine passende Klemme für ein Balkongeländer oder Abflussrohr ist schnell gemacht. Die hier gezeigte Variante hat ein quadratisches eingesetztes Rohrendstück. Es wird in der Klemme mit einem Querstift gegen Herausfallen gesichert. So kann die Antenne ohne Werkzeug entfernt werden. Die Klemme selbst kann am Geländer verbleiben.

Source

siehe Codeberg Repository

Links

EZNEC Antennen-Simulator
Vormast-Dipol von DK7ZB
RigExpert Antennenanalyzer
Gewindeblock M3

Software

FreeCAD Open Source

Universelles Maststativ für Alu und GFK-Maste

Wer einen Metall- oder GFK-Masten Indoor aufstellen möchte, braucht ein Stativ. Leider ist auf dem freien Markt kaum brauchbares zu finden. Zu unterschiedlich sind Durchmesser und Rohrlängen. Was liegt näher als selbermachen?

Das Hauptrohr des hier verwendeten Mastes hat eine Länge von ca. 1.6m und einen Aussendurchmesser von 51mm. Der Einfachheit halber kommen Aluprofile aus dem Baumarkt zur Anwendung. Beim Durchstreifen der Regale sind mir Vierkant-Alurohre aufgefallen die 25×25mm breit sind und einen Meter Länge haben. Dazu kommen drei Flachprofile 16×2mm für die Streben, ebenfalls 1m lang. Ebenso Schrauben und Muttern. Sie sind auf Github aufgeführt.

Die Grundidee ist ganz simpel. Zwei Scheiben werden am Mast festgeklemmt. An der oberen Scheibe sind die Stativbeine befestigt. An der unteren Scheibe die Streben. An einer geometrisch praktikablen Stelle werde Beine und Streben miteinander verbunden. Idealerweise stehen die Streben waagrecht, wenn die Beine ihre maximale Ausbreitung erreichen. Der Mast selbst kann dann entweder fest auf dem Boden stehen oder etwas davon enfernt, um das Gewicht auf das Stativ zu übertragen. Die beste Position wird erreicht, wenn die untere Scheibe fast am Ende des Mastfusses festgeklemmt wird. Die obere Scheibe wird dann entsprechen den Bedürfnissen positioniert. In zusammen geklappten Zustand (obere Scheibe maximal nach oben verschieben) liegen die Beine dicht am Hauptrohr und stehen nicht ab.

In der ersten Version wurden die Querlöcher direkt in die Alubeine gebohrt. In der aktuellen Version kommen 3D gedruckte Teile zum Einsatz. Es benötigt lediglich zwei mittig gebohrte 2.5mm Löcher in den Beinen um die Endstücke festzuschrauben. Das hat den Vorteil, dass die Endstücke dem Einsatzzweck angepasst werden können und leicht zu ersetzen sind.

In der aktuellen Version werden 4-kant Muttern verwendet. Diese sind technisch einfacher in 3D zu verwenden und benötigen ausserdem weniger Platz. Auch ist das Montieren so viel einfacher.

Um verschiedene Mastdurchmesser verwenden zu können erfolgt die Klemmung über drei Schrauben. Diese werden in der oberen Scheibe zusammen mit einen Knauf eingesetzt um ohne Werkzeug hantieren zu können. Darin wird eine Sicherungsmutter eingesetzt. Ansonsten reicht auch eine normale Mutter mit Sicherungslack.

Die Beine erhalten je eine Bohrung von 2.5mm mittig auf einer Rohrseite jeweils 1cm vom Ende entfernt. Die 1m langen Profile für die Streben werden genau mittig geteilt und deren Endkanten gebrochen. Um für alle Streben die gleichen Lochabstände zu erhalten werden alle sechs Streben übereinander gelegt, mit Zwingen zusammengehalten und gebohrt. Der Abstand der beiden Löcher beträgt 480mm. Dieses Mass ist unkritisch. Wichtig ist, dass alle Streben den gleichen Lochabstand haben. Sonst wird der Mast nicht rechtwinklig zum Boden stehen.

Dateien

3D Druckdaten auf Dreibein Mast

Bilder

Administration

Archiv

Datenschutz

Erklärung