Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

mechatronik:sose24:radioantenne_ausrichten

Dies ist eine alte Version des Dokuments!




Dokumentation Antirector

Einführung:

Antirector (kurz für „Antenna-Director“) richtet eine Antenne so aus, dass die von ihr empfangene Signalstärke maximal ist. Hierzu wird die Umgebung der Antenne in eine feste Zahl an Positionen unterteilt, an denen jeweils die Signalstärke gemessen und in Form eines Durchschnittswertes gespeichert wird. Sobald die Umgebung in allen gegebenen Positionen gescannt wurde, fährt die Antenne zu jener Position zurück, an der die gemessene Signalstärke am höchsten ausgefallen ist.

Verwendete Bauelemente:

  • Funduino Uno
  • ESP-32-Wroom-32
  • Servomotor
  • Nema-17 Schrittmotor
  • DRV8825 Schrittmotortreiber
  • 100µF Kondensator
  • Photowiderstand
  • Breadboard
  • Kabel
  • 3D-Druck-Teile

Schaltplan:


Bild 1

Das Herzstück unserer Schaltung ist der Arduino Uno. Er gibt Befehle an die jeweiligen Motoren und verarbeitet die Messdaten des ESP32. Folgende Pins werden verwendet: Pin 2 für die serielle Kommunikation mit dem ESP32, Pin 3 für die Richtungssteuerung des Servomotors, Pin 5 für die Richtungssteuerung des Schrittmotors und Pin 6 für dessen Schrittweite.
Das ESP32 ist ein Mikrocontroller, der über eine eingebaute/angebaute (je nach Bauart) Antenne verfügt und es ermöglicht, sich über WLAN oder Bluetooth mit anderen Geräte zu vernetzen. In unserem Fall ist es mit einem mobilen Hotspot verbunden, dessen Signalstärke gemessen werden soll. Um die Messwerte an den Arduino Uno zu senden, ist der TX-Pin (T für „Transmit“) des ESP32 mit dem RX-Pin (R für „Receive“) des Arduinos verbunden. Auf diese Weise kann serielle Kommunikation zwischen den beiden Mikrocontrollern stattfinden.
Der Nema 17 ist für das Azimut zuständig, also für die Drehung der Antenne in der horizontalen Ebene. Jeder Schritt entspricht einem Drehwinkel von 1,8 Grad. Der Nema 17 kann aber auch Halbschritte ausführen, was 800 Schritte auf 360 Grad ergibt. Das ermöglicht eine präzise Ausrichtungsveränderung der Antenne, die wir für unser Projekt längst nicht voll ausgenutzt haben. Für die Steuerung des Nema 17 haben wir einen DRV8825-Schrittmotortreiber verwendet. Dieser bestimmt die Richtung ,in die sich der Schrittmotor dreht.
Zuletzt ist da noch der Servomotor für die Elevation, also die Drehbewegung in der vertikalen Ebene. Zwei Kabel bilden die Pole für die Spannungsversorgung, ein drittes gibt die Drehrichtung an.
Die 12V-Spannungsquelle versorgt den Schrittmotor, die 5V-Spannungsquelle den Servomotor über den Schrittmotortreiber.

Code:

// Libraries
#include <SoftwareSerial.h>
#include <Servo.h>
#include <Stepper.h>

// Pins
const byte rxPin = 2;
const byte servoPin = 3;
const byte stepperStepPin = 5;
const byte stepperDirPin = 6;

const byte ledRSSIPin = 8;
const byte ledRSSI2Pin = 9;
const byte ledRSSI3Pin = 10;

const byte buttonScanPin = 4;

//config
SoftwareSerial SerialESP(rxPin, -1); 

Servo servoX;
Stepper stepperZ(800, stepperStepPin, stepperDirPin);

//Servo
int currentPositionX = 90;
int bestPositionX = 90;
float bestSignalX = 1000;

//Stepper
int currentPositionZ = 0;
int bestPositionZ = 9;
float bestSignalZ = 1000;

//RSSI-Reading
int rssi = 0;
const int numReadings = 5;
int rssiArray[numReadings];
int readIndex = 0;
int readCount = 0;

//Steuerbedingungen
bool scanningCompleteZ = false;
bool scanningCompleteX = false;
bool scanEnabled = false;
bool scanButtonPressed = false;

//Entprellen
unsigned long lastButtonPressTime = 0;
const int debounceDelay = 50;

//Serieller Befehl
String command = "";

void setup() {
//pins
  pinMode(rxPin, INPUT);
  pinMode(servoPin, OUTPUT);
  pinMode(ledRSSIPin, OUTPUT);
  pinMode(ledRSSI2Pin, OUTPUT);
  pinMode(ledRSSI3Pin, OUTPUT);
  pinMode(buttonScanPin, INPUT_PULLUP);
//Serielle Verbindungen
  Serial.begin(9600);
  SerialESP.begin(9600);
//Servo Setup
  servoX.attach(servoPin);
  servoX.write(90);
//Stepper Setup
  stepperZ.setSpeed(100); //
//Initialisieren des Read Arrays
  for (int i = 0; i < numReadings; i++) {
    rssiArray[i] = 0;
  }
//Wartezeit und Bereitschaft
  delay(500);
  Serial.println();
  Serial.println("Hello There!");
  delay(500);
  Serial.println(F("E.R.O.S. ready"));
}

void loop() {
//Lesen des Seriellen Befehls
if (Serial.available() > 0) {
  command = Serial.readStringUntil('\n');
  command.trim();
}
//Starten des Scans durch Button oder Befehl
if ((digitalRead(buttonScanPin) == LOW && !scanButtonPressed && millis() - lastButtonPressTime > debounceDelay) || (command.equalsIgnoreCase("scan"))) {
//Entprellen und einmaliges Drücken
  lastButtonPressTime = millis();
  scanButtonPressed = true;

  Serial.println(F("starting SCAN"));
//Stepper zurück auf 0 (falls bereits gescant)
  stepperZ.step(-currentPositionZ); //
  currentPositionZ = 0;
  bestPositionZ = 0;
//Servo zurück auf 90 (falls bereits gescant)
  currentPositionX = 90;
  bestPositionX = 90;
  servoX.write(90);
  delay(500); //Wartezeit während sich der Servo bewegt (nach jedem servo.write)
//Aktivieren der Bedingung fürs Scannen und Zurücksetzen der Ergebnisse
  scanEnabled = true;
  scanningCompleteX = false;
  scanningCompleteZ = false;
  bestSignalX = 1000;
  bestSignalZ = 1000;
//Rücksetzen und Initialisieren der Readings
  readIndex = 0;
  readCount = 0;
  for (int i = 0; i < numReadings; i++) {
    rssiArray[i] = 0;
  }
//Ausgeben der ersten (Start) Position
  Serial.print(F("Z: "));
  Serial.print(currentPositionZ);
  Serial.print(F(" | X: "));
  Serial.println(currentPositionX);
//Leerung des Seriellen Befehls
  command = "";
} else if (digitalRead(buttonScanPin) == HIGH) {
//Reset des Buttons, sobald nicht mehr gedrückt (gegen Gedrückthalten)
  scanButtonPressed = false;
}

//Scan Programm (wird durch das obere aktiviert, nur wenn Signal vorhanden)
if (scanEnabled && !scanningCompleteX && rssi != 0) {
//Empfang des Signals durch ESP jede Sekunde als Trigger
  if (SerialESP.available() > 0) {
//Einlesen des Signals
    String rssiRX = SerialESP.readStringUntil('\n');
    rssi = rssiRX.toInt();
    Serial.print(F("RSSI: -"));
    Serial.println(rssi);

    rssiArray[readIndex] = rssi;
    readIndex = (readIndex + 1) % numReadings;
    if (readCount < numReadings) {
      readCount++;
    }
//Auswertung wenn 5 Signale empfangen wurden
    if (readCount == numReadings) {
      int sum = 0;
      for (int i = 0; i < numReadings; i++) {
        sum += rssiArray[i];
      }
//Durchschnitt aus den Signalen
      float average = (float)sum / numReadings;

      Serial.print(F("⌀ RSSI: -"));
      Serial.println(average);
      Serial.println();
//nur während Stepper Drehung
      if (!scanningCompleteZ) {
        if (average < bestSignalZ) {
//Speichern des besten Signals und der entsprechenden Stepper Position
          bestSignalZ = average;
          bestPositionZ = currentPositionZ;
        }
//Einstellen der nächsten Stepper Position
        currentPositionZ += 100;
      }
//nur während Servo Drehung
      if (scanningCompleteZ) {
        if (average < bestSignalX) {
//Speichern des besten Signals und der entsprechenden Servo Position
          bestSignalX = average;
          bestPositionX = currentPositionX;
        }
//Einstellen der nächsten Servo Position
        currentPositionX += 15;
      }
//Prüfung ob Stepper einmal durch ist
      if (currentPositionZ > 700 && !scanningCompleteZ) {
//Übermitteln der besten gemessenen Stepper Position
        Serial.print(F("best Z: "));
        Serial.print(bestPositionZ);
        Serial.print(F(" | best ⌀ RSSI: -"));
        Serial.println(bestSignalZ);
//Anfahren und Einstellen der besten Stepper Position
        stepperZ.step(-(700-bestPositionZ)); //
        currentPositionZ = bestPositionZ;
//Reset der Readings
        readIndex = 0;
        readCount = 0;
        for (int i = 0; i < numReadings; i++) {
          rssiArray[i] = 0;
        }
//Servo auf Startposition für Servo Drehung
        currentPositionX = 45;
        servoX.write(45);
        delay(500);
//Bedingungen, dass der Stepper fertig ist
        scanningCompleteZ = true;
//Prüfung ob Stepper noch nicht fertig ist
      } else if (!scanningCompleteZ){
//Anfahren der nächsten Stepper Position
        stepperZ.step(100);
//Reset der Readings
        readIndex = 0;
        readCount = 0;
        for (int i = 0; i < numReadings; i++) {
          rssiArray[i] = 0;
        }
//Übermitteln der Position
        Serial.print(F("Z: "));
        Serial.print(currentPositionZ);
        Serial.print(F(" | X: "));
        Serial.println(currentPositionX);
      }
//Prüfung ob Servo fertig ist
      if (currentPositionX > 135) {
//Bedingungen, dass der Scan nicht weiterläuft
        scanningCompleteX = true;
        scanEnabled = false;
//Übermitteln der besten Positionen
        Serial.println(F("SCAN completed:"));
        Serial.print(F("best Z: "));
        Serial.print(bestPositionZ);
        Serial.print(F(" | best X: "));
        Serial.print(bestPositionX);
        Serial.print(F(" | best ⌀ RSSI: -"));
        Serial.println(bestSignalX);
//Einstellen und Anfahren der besten Servo Position
        currentPositionX = bestPositionX;
        servoX.write(bestPositionX);
        delay(500);
//Prüfung ob Servo noch nicht fertig ist
      } else if (scanningCompleteZ) {
//Anfahren der nächsten Servo Position
          servoX.write(currentPositionX);
          delay(500);
//Reset der Readings
          readIndex = 0;
          readCount = 0;
          for (int i = 0; i < numReadings; i++) {
            rssiArray[i] = 0;
          }
//Übermitteln der Position
          Serial.print(F("Z: "));
          Serial.print(currentPositionZ);
          Serial.print(F(" | X: "));
          Serial.println(currentPositionX);
      }
    }
  }
} else {
//Aktualisierung des Signals während Scan nicht läuft für LEDs
    if (SerialESP.available() > 0) {
      String rssiRX = SerialESP.readStringUntil('\n');
      rssi = rssiRX.toInt();
    }
}

}

3D-Druck:

Ein weiterführendes Ziel des Projektes war es, eine Yagi-Antenne selbst zu bauen und diese mit Hilfe von zwei Motoren zu bewegen. Um die gesamte Umgebung scannen zu können, haben wir uns für die Kombination aus einem Schrittmotor für die horizontale, und einem Servomotor für die vertikale Drehung entschieden. Die Yagi-Antenne soll dann an dem Servomotor befestigt werden und beides zusammen auf dem Schrittmotor.

Dafür haben wir die nötigen Verbindungselemente in Solid-Edge und Inventor konstruiert und anschließend 3D-gedruckt. Die Halterung für den Servomotor besteht aus zwei Teilen: zum einen die Hülse, die auf die Welle des Schrittmotors gesteckt wird und einem U-förmigen Stück, dass an den Servomotor geschraubt wird. Da sich ein Gewinde für die Schrauben schlecht drucken lässt, haben wir vorgefertigte Gewinde in den 3D-Druck geschmolzen. Die beiden Teile haben wir anschließend mit möglichst großer Auflagefläche zusammengeklebt, um mögliches Kippen oder Abbrechen zu vermeiden.

Auch die Antenne selbst soll zum Teil gedruckt werden, da das Material nicht leitend und leicht ist. Dazu haben wir zum einen eine Halterung für die Antenne konstuiert, die genau auf den Servomotor passt und den nötigen Abstand zu diesem gewährleistet. Der Abstand ist wichtig, damit die Antenne beim Drehen nicht mit Ihren Direktoren an dem Servo- oder Schrittmoter hängen bleibt.

Servo-Halterug und Halterung für den Boom der Antenne

Bild 3: Servo-Motor in Halterung auf Schrittmotor und Halterung für den Boom der Antenne

Durchlauf:


Bitte ignoriert die LEDs und Taster auf dem Breadboard. Das Video zeigt eine Vorversion, in welcher noch Statusanzeige und Knöpfe für bestimmte Befehle integriert waren. Erst nach der Aufnahme haben wir die Schaltung reduziert. Das Prinzip bleibt aber dasselbe.

Fazit:

Dass Antirector ein cooles System mit Realitätsnutzen ist, sehen wir nach wie vor so. (Beispiel: Starlink). Die Zusammensetzung unserer Gruppe war relativ gut, da wir für jeden Teilbereich des Systems jemanden hatten, der/die sich gerne damit beschäftigte und somit kein Bereich unterbesetzt blieb.
In seiner jetzigen Form stellt Antirector eine absolute Basis dar, die noch um einiges erweitert werden müsste. Natürlich war es nicht der Plan unserer Gruppe, ein marktreifes Produkt auf die Beine zu stellen. Nichtsdestotrotz besteht bei den Themen Zeitmanagement und Kommunikation für das nächste Projekt noch Luft nach oben. Es wäre sinnvoll gewesen, sich zuallererst ausführlich damit auseinanderzusetzen, welche genauen Anforderungen man an das fertige System stellt. Auf diese Art und Weise ließen sich Aufgabenpakete mit Deadlines leichter erstellen.
Von dieser kleinen Kritik abgesehen, hat es uns dennoch Spaß gemacht, an diesem Projekt zu arbeiten und einige Ideen in die Tat umzusetzen.

Quellen:
Bild 2

mechatronik/sose24/radioantenne_ausrichten.1722769337.txt.gz · Zuletzt geändert: 2024/08/04 13:02 von Jonny5