Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Antennen-Rotator-Controller kompatibel mit Tracking-Software

Komponenten und Verbrauchsmaterialien

Arduino UNO
Arduino Uno-Board
× 1
Drehpotentiometer (allgemein)
max. 1Kohm (500 Ohm funktionieren besser)
× 2
Drehgeber mit Druckknopf
× 2
Breadboard (generisch)
× 1
Relaismodul (generisch)
2 Module x 2 Relais NO-Com-NC
× 2
Leistungs-MOSFET N-Kanal
Power-Mosfet-Modul (min. 12V/3A)
× 2

Apps und Onlinedienste

Arduino-IDE

Über dieses Projekt

Letztes Update November 2021

Dieses Projekt begann als Unterhaltung und wurde zu einem ernsthaften Gerät.

Der Controller akzeptiert die manuelle Positionierung der Antenne mittels zweier Drehgeber, Azimut und Elevation. Es kann automatisch Satelliten verfolgen, wenn es über USB mit einem PC verbunden ist, auf dem eine Satelliten-Tracking-Software läuft.

Es ist mit jeder Tracking-Software kompatibel, die das EasyComm2-Protokoll / 9600 Baud verwendet. PstRotator, WXtrack, HRD, MacDoppler... Sogar WXtoIMG kann den Rotator steuern.

Es funktioniert direkt mit Orbitron, mit einem DDE-Plugin von http://tripsintech.com/orbitron-dde-azimuth-elevation-to-serial/

Der Controller gibt eine serielle Antwort aus, damit die Tracking-Software die tatsächliche Antennenposition auf dem Bildschirm anzeigt. Bisher hat das nur PstRotator gemacht.

Der Code verwendet keine Bibliothek (außer dem LCD) und läuft genau so, wie er ist, mit Pins gemäß dem folgenden Schaltplan. Wenn Sie die Taste des Azimut-Encoders drücken, werden alle Antennenbewegungen sofort gestoppt und der Azimut-Befehl kann in 10 Grad eingestellt werden. Schritte.

Sie finden hier zwei Versionen:Eine für Gleichstrommotoren und eine für Wechselstrommotoren (nur Relais). Letzterer kann mit bestehenden kommerziellen Antennenrotatoren verbunden werden.

Die Version mit Gleichstrommotoren hat den Vorteil, dass PWM für eine weichere/glattere Antennenbewegung verwendet wird. Es gibt eine zum Winkelfehler proportionale Leistungsantwort aus (Target<->Antenne). Daher beschleunigt die Antenne, wenn sie sich zu bewegen beginnt, progressiv und verlangsamt sich bei Annäherung an die gewünschte Position bis zum vollständigen Stillstand. Dies ist bekannt als Soft-Start / Soft-Stop . Es gibt eine einstellbare Totzone, in der sich die Antenne beim geringsten Zielversatz nicht bewegt.

Ich habe eine Beta Ausführung mit Soft-Start / Soft-Stop für AC-Motoren, die dieses AC-Dimmer-Modul nutzen, aber im Moment funktioniert es nur für Azimut. Wenn du es ausprobieren möchtest, lass es mich per E-Mail wissen.

Wenn Sie 180 Grad haben. Höhensystem, du bist gut, gib mir eine E-Mail. Es gibt auch eine Version mit 0.1deg. Präzision, aber ich würde es nicht empfehlen, es sei denn, Sie haben einen gottverdammten grundsoliden Potentiometerwert und ein paranoisches Controller-Konstruktionsdesign. Weitere Versionen finden Sie auf meiner Webseite.

Nach Abschluss der Konstruktion müssen Sie die Kalibrierungsverfahren anwenden .

  • Die Potentiometer-Kalibrierung ist obligatorisch und gewährleistet das korrekte Ablesen von 0-359deg. / 0-90deg., egal welche Art von Potentiometer Sie verwenden.
  • Die Motorkalibrierung dient nur zum Abstimmen des Soft-Start-Stop Merkmal. Dies ist notwendig, wenn Ihnen die Standardeinstellungen nicht gefallen.

Genauere Erklärungen in den Videos. Da der Code im Laufe der Zeit verbessert wurde und die Videos nicht mehr aktualisiert werden können, besuchen Sie meine Webseite für die neuesten Informationen und persönlichen Erfahrungen mit diesem Controller. https://racov.ro/index.php/2020/12/09/arduino-based-antenna-rotator-part3-software-tracking-update/

Schicken Sie mir eine E-Mail, wenn Sie mehr wissen möchten, denn diese Plattform informiert mich nicht über neue Kommentare, keine Ahnung warum. Ich werde versuchen, kleine Probleme so gut wie möglich zu lösen. [email protected]

Vielen Dank an alle, die mir Feedback geschickt haben, um dieses Projekt zuverlässiger zu machen. Jedes Feedback wird sehr geschätzt.

Code

  • ant-rot-DC-nov2021
  • ant-rot-AC-aug2021
  • Potentiometer-Kalibrierungsverfahren
  • Motorkalibrierungsverfahren
ant-rot-DC-nov2021Arduino
Dieser Code gilt für DC-Motoren mit Soft-Start-Stop-PWM-Ausgang
/* AZ/EL-Antennen-Rotator-Controller für Arduino - DC-Motoren * =======================================================* Verwendet EasyComm-Protokoll für Computer - Tracking-Software * Manueller Befehl von mittels zweier Drehgeber AZ - EL * * Viorel Racoviteannu * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https://racov.ro * [email protected] * * Ich übernehme keine Verantwortung für Missbrauch dieses Codes * oder Schäden jeglicher Art, die durch die Verwendung dieses Codes entstehen können. * * dec 2020 v2 - verbesserte Stabilität der seriellen Kommunikation * jan 2021 - verbesserte tote Zone in der Nähe des Ziels, für die sich die Antenne nicht bewegt * apr 2021 - verbesserte Stabilität der seriellen Kommunikation * jun 2021 - fehlerproportionale Leistung für die Verfolgungsbewegung. Real Soft-Stop * Aug 2021 - Schnelleres USB-Update, Kaltschaltende Az/El-Richtung, Kleine Optimierungen im Code * Nov 2021 - Das Geheimnis von Soft-Start gelüftet. Es war nicht schwer. Da hast du es */ #include  // Bibliothek für I2C-Kommunikation#include  // Bibliothek für LCD// Verdrahtung:SDA-Pin ist mit A4 und SCL-Pin mit A5 verbunden.// Connect zum LCD über I2C, Standardadresse 0x27 (A0-A2 nicht gebrückt)LiquidCrystal_I2C lcd(0x27, 16, 2); // Adresse, Zeichen, Zeilen. // Deklarieren eines benutzerdefinierten Symbols für das Byte mit dem Aufwärts-/Abwärtspfeil DownArrow[8] ={ B00000, B00100, B00100, B00100, B10101, B01110, B00100, B00000}; Byte Pfeil nach oben[8] ={ B00000, B00100, B01110, B10101, B00100, B00100, B00100, B00000};/************************ **********DAS IST, WO SIE WIRKLICH AN DER ANTENNENBEWEGUNG Optimieren ************** /// ANTENNEN-Potentiometer KALIBRIERUNG int AzMin =1; // Beginn des Potentiometers Int AzMax =1023; // Ende des Potentiometers Int ElMin =1; int ElMax =1023; // Erlaubter Fehler, bei dem sich die Antenne nicht bewegt int AzErr =8; int ElErr =4; // Winkeldifferenz, bei der der Softstop beginnt int Amax =25; // Azimut Int Emax =15; // Höhe // Min. und Max. Leistung für Motoren, Prozent; int PwAzMin =30; // minimale Leistung, bei der der Motor nicht blockiert und unter Last startet Int PwAzMax =100; // volle Leistung für die schnellste Geschwindigkeit int PwElMin =30; int PwElMax =100; int PwAz =0; // berechnete Leistung, die an den Motor übertragen werden soll (Prozent); int PwEl =0;/************************************************ ************************************************* *****/// Encodervariablen enum AzPinAssignments { AzEncoderPinA =2, // Az Encoder rechts AzEncoderPinB =3, // Encoder links AzClearButton =4, // Encoder push ElEncoderPinA =6, // El Encoder rechts ElEncoderPinB =5 }; // Encoder links // Serviceroutine unterbrechen vars unsigned int lastReportedPos =1; // Änderungsverwaltung Static Boolean Rotating =false; // Management entprellen Boolean A_set =false; boolesch B_set =false; int aState; int aLastState; // andere Variablen int AzPotPin =A0; // Wählen Sie den Eingangspin für das Azim. Potentiometer int AzRotPin =12; // Wählen Sie den Out-Pin für die Drehrichtung aus Int AzPWMPin =11; // Wählen Sie den Out-Pin für den Azimut-PWM-Befehl aus Int TruAzim =0; // berechneter echter Azimutwert int ComAzim =0; // befohlener Azimutwert int OldTruAzim =0; // um den vorherigen Azimutwert zu speichern Int OldComAzim =0; char AzDir; // Symbol für Azimrot-Anzeige int AzEncBut =1; // Variable zum Umschalten mit Encoder-Taster Int ElPotPin =A1; // Wählen Sie den Eingangspin für die Höhe aus. Potentiometer int ElRotPin =13; // Wählen Sie den Out-Pin für die Höhendrehrichtung aus Int ElPWMPin =10; // Wählen Sie den Ausgangsstift für den PWM-Befehl für die Höhendrehung aus Int TruElev =0; // berechneter realer Höhenwert int ComElev =0; // befohlener Höhenwert int OldTruElev =0; // um den vorherigen Höhenwert zu speichern Int OldComElev =0; char ElDir; // Symbol für Elev. rot display // Flags für AZ, EL Toleranzen bool AzStop =false; bool ElStop =false; int ElUp =1; // 1 - Elevation Dn, 0 - Elevation STOP, 2 - Elevation Up int StaAzim =0; // Start-Azimutwinkel für Motor-Soft-Start int PwAzStop =0; // berechnete PWM (Prozent) für Soft-Stopp Int PwAzStar =0; // berechnete PWM (Prozent) für Sanftanlauf Int StaElev =0; // Start Elevationswinkel für Motor-Soft-Start int PwElStop =0; // berechnete PWM (Prozent) für Soft-Stopp Int PwElStar =0; // berechnete PWM (Prozent) für Softstart // Mittelungsschleife const int numReadings =25; int readIndex =0; // der Index des aktuellen Messwerts int azimuth[numReadings]; // die Messwerte vom analogen Eingang int height[numReadings]; int totalAz =0; // die laufende Summe int totalEl =0; // Variablen für serielle Kommunikation String Azimuth =""; Zeichenfolgenhöhe =""; Zeichenfolge ComputerRead; Zeichenfolge ComputerWrite; bool AZser =false; bool ELser =false; bool ANTser =false;/*************** END VARIABLE DECLARATION ************/void setup () { Serial.begin (9600); Serial.setTimeout(50); // Millisekunden, um auf USB-Sata zu warten. Standard 1000// Initiieren von LCD:// lcd.begin(16,2); // Wählen Sie diesen aus, wenn die Pfeile nicht richtig angezeigt werden lcd.init(); lcd.backlight (); // Schreibe auf Anzeigename und Version lcd.setCursor (0, 0); // Setzen Sie den Cursor auf die erste Zeile der ersten Spalte. (Zählung beginnt bei 0!) lcd.print("EasyCom AntRotor"); // "..." anzeigen lcd.setCursor(0, 1); // Setzen Sie den Cursor auf die erste Spalte der zweiten Zeile lcd.print("*Racov* Nov.2021"); //Erstellen eines benutzerdefinierten Symbols für den Pfeil nach oben/unten lcd.createChar(1, DownArrow); lcd.createChar(2, Pfeil nach oben); // Pin-Deklaration PinMode (AzRotPin, OUTPUT); //Azim deklarieren. Drehrichtung Pin als OUTPUT pinMode(AzPWMPin, OUTPUT); // Deklaration des Azimut-PWM-Befehls-Pins als OUTPUT pinMode (ElRotPin, OUTPUT); //elev. Drehrichtung Pin als OUTPUT pinMode(ElPWMPin, OUTPUT); pinMode (AzPotPin, EINGANG); pinMode (ElPotPin, EINGANG); pinMode (AzEncoderPinA, EINGANG); pinMode (AzEncoderPinB, INPUT); pinMode (AzClearButton, INPUT); pinMode (ElEncoderPinA, INPUT); pinMode (ElEncoderPinB, INPUT); // AzEncoder-Pin auf Interrupt 0 (Pin A) attachInterrupt (0, doEncoderA, CHANGE); // AzEncoder-Pin auf Interrupt 1 (Pin B) attachInterrupt (1, doEncoderB, CHANGE); // Liest der Anfangszustand des ElEncoderPinA aLastState =digitalRead(ElEncoderPinA);/* Initialisierung der Mittelungsschleife */ TruAzim =(map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); // Azimutwert 0-359 if (TruAzim<0) {TruAzim=0;} if (TruAzim>359) {TruAzim=359;} // Werte zwischen Grenzen halten TruElev =(map(analogRead(ElPotPin), ElMin, ElMax , 0, 90)); // Höhenwert 0-90 if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev=90;} // Werte zwischen Grenzen halten für (int thisReading =0; thisReading 359) {TruAzim=359;} if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev =90;} // Weiter zur nächsten Position im Array:readIndex =readIndex + 1; // Wenn wir am Ende des Arrays sind, springen Sie zum Anfang:if (readIndex>=numReadings) {readIndex =0;} // Dies ist das Lesen des Befehls vom Encoder ReadAzimEncoder(); ReadElevEncoder(); if (Serial.available()) {SerComm();} // USB-Daten lesen // Antennenpositionsanzeige nur aktualisieren, wenn sich der Wert ändert if ((millis()%500)<10) {//die Anzeige nicht flackern if (OldTruAzim!=TruAzim) { DisplAzim(TruAzim,4,0); OldTruAzim =TruAzim; } if (OldTruElev!=TruElev) { DisplElev(TruElev,5,1); OldTruElev =TrueElev; } } // Zielpositionsanzeige nur aktualisieren, wenn sich der Wert ändert if (OldComAzim !=ComAzim) { DisplAzim(ComAzim,12,0); OldComAzim =ComAzim; } if (OldComElev !=ComElev) { DisplElev(ComElev,13,1); OldComElev =ComElev; } // Dies ist eine Drehung im Azimut if (TruAzim ==ComAzim) { // wenn gleich, stoppen Sie die Bewegung AzStop =true; analogWrite(AzPWMPin, 0); // Az-Motorleistung =0 StaAzim =TruAzim; // Dies ist der Startazimut für den Softstart lcd.setCursor (8, 0); lcd.print("="); } else if ((abs(TruAzim - ComAzim)<=AzErr)&&(AzStop ==false)) { // wenn in der Toleranz, aber es war nicht gleich, drehe AzimRotate();} else if (abs(TruAzim - ComAzim)>AzErr){// wenn das Ziel außerhalb der Toleranz liegt AzStop =false; // es ist nicht gleich AzimRotate(); // rotieren } // dies ist eine Drehung in der Höhe if (TruElev ==ComElev) { // wenn gleich, stoppen Sie die Bewegung ElStop =true; analogWrite (ElPWMPin, 0); // El-Motorleistung =0 StaElev =TruElev; // Dies ist die Starthöhe für Softstart lcd.setCursor (8, 1); lcd.print("="); ElUp =0; // Flag für Elevation STOP } else if ((abs(TruElev - ComElev)<=ElErr)&&(ElStop ==false)) { // wenn in Toleranz, aber es war nicht gleich, rotiere ElevRotate();} else if (abs(TruElev - ComElev)>ElErr){// wenn das Ziel außerhalb der Toleranz liegt ElStop =false; // es ist nicht gleich ElevRotate(); // Rotieren} // Dies dient zur Interpretation der x10-Multiplikation des Az-Encoders while (AzEncBut ==10) {// während auf x10 umgeschaltet analogWrite (AzPWMPin, 0); // Antennendrehung stoppen StaAzim =TruAzim; // Dies ist der Startazimut für den Softstart analogWrite (ElPWMPin, 0); lcd.setCursor(8, 0); lcd.print("*"); ReadAzimEncoder(); if (OldComAzim !=ComAzim){// Anzeige nur aktualisieren, wenn sich Zahlen ändern DisplAzim(ComAzim, 12, 0); OldComAzim =ComAzim; } Verzögerung (100); }}// end main LOOP//______________________________________// ___________Prozedurendefinitionen__________________void DisplAzim(int x, int y, int z) { char displayString[7] =""; sprintf(displayString, "%03d", x); // gibt eine Zahl mit fester Länge aus (3 Integer) lcd.setCursor(y, z); // für keine führenden Nullen "__7" verwenden "%3d" lcd.print(displayString); // ************** FÜR KALIBRIERUNGSZWECKE ************** // Serial.print ("Az"); // Serial.println ( analogRead(AzPotPin));}void DisplElev(int x, int y, int z){ char displayString[7] =""; sprintf(displayString, "%02d", x); // gibt eine Zahl mit fester Länge aus (2 Integer) lcd.setCursor(y, z); // für keine führenden Nullen "_7" verwenden Sie "%2d" lcd.print(displayString); // ************** FÜR KALIBRIERUNGSZWECKE ********** **** // Serial.print ("El"); // Serial.println (analogRead (ElPotPin));}void ReadElevEncoder () { aState =digitalRead (ElEncoderPinA); // Liest den "aktuellen" Zustand des ElEncoderPinA // Wenn der vorherige und der aktuelle Zustand des ElEncoderPinA unterschiedlich sind, bedeutet dies, dass ein Puls aufgetreten ist if (aState !=aLastState){ // Wenn der ElEncoderPinB-Zustand anders ist als der ElEncoderPinA-Zustand, dh der Encoder dreht sich im Uhrzeigersinn if (digitalRead(ElEncoderPinB) !=aState) { ComElev ++;} else { ComElev --;} if (ComElev <0) {ComElev =0;} if (ComElev>90 ) {ComElev =90;} } aLastState =aState; // Aktualisiert den vorherigen Zustand von ElEncoderPinA mit dem aktuellen Zustand}void ReadAzimEncoder() { rotierende =true; // Debouncer zurücksetzen if (lastReportedPos !=ComAzim) { lastReportedPos =ComAzim; } Verzögerung(10); if (digitalRead (AzClearButton) ==LOW) {// wenn Encoder-Schalter gedrückt Verzögerung (250); // Entprellschalter if (AzEncBut ==1) { AzEncBut =10; ComAzim =int(ComAzim/10)*10; // ComAzim in 10deg. Schritte} else { AzEncBut =1; aufrechtzuerhalten. // Warten Sie ein wenig, bis das Springen abgeschlossen ist // Testen Sie den Übergang, haben sich die Dinge wirklich geändert? if ( digitalRead(AzEncoderPinA) !=A_set ) {// erneut entprellen A_set =!A_set; // Zähler anpassen + wenn A B führt if ( A_set &&!B_set ) ComAzim +=AzEncBut; ComAzim =((ComAzim + 360) % 360); // EncoderPos zwischen 0 und 359 Grad. rotierend =falsch; // kein Entprellen mehr, bis loop() wieder trifft }} // Interrupt bei Zustandsänderung von B, wie bei A obenvoid doEncoderB() { if (rotating) delay (1); if (digitalRead(AzEncoderPinB) !=B_set) { B_set =!B_set; // Zähler anpassen - 1 wenn B A führt if ( B_set &&!A_set ) ComAzim -=AzEncBut; ComAzim =((ComAzim + 360) % 360); // EncoderPos zwischen 0 und 359 Grad. rotierend =falsch; } }void AzimRotate() { if (ComAzim> TruAzim) {// dies um die Drehrichtung zu bestimmen // Kaltschaltung - Motor vor Richtungswechsel stoppen - zum Schutz mechanischer und elektrischer Teile if (AzDir ==char(127)) { // wenn zuvor in die entgegengesetzte Richtung gedreht wurde analogWrite (AzPWMPin, 0); // STOPP den Motor StaAzim =TruAzim; // Dies ist der Startazimut für die Softstartverzögerung (200); // Vorschaltverzögerung digitalWrite (AzRotPin, LOW); // Rotationsstift deaktivieren - nach rechts drehen Verzögerung (200); // Verzögerung nach dem Umschalten aufrechtzuerhalten. Else {// gleiche Richtung, kein Stopp, keine Verzögerung digitalWrite (AzRotPin, LOW); // Rotationsstift deaktivieren - nach rechts drehen} AzDir =char(126); // "->" } else { if (AzDir ==char(126)) { // wenn vorher in die entgegengesetzte Richtung gedreht analogWrite(AzPWMPin, 0); // STOPP den Motor StaAzim =TruAzim; // Dies ist der Startazimut für die Softstartverzögerung (200); // Vorschaltverzögerung digitalWrite (AzRotPin, HIGH); // Rotationsstift aktivieren - links drehen Verzögerung (200); // Verzögerung nach dem Umschalten aufrechtzuerhalten. Else {// gleiche Richtung, kein Stopp, keine Verzögerung digitalWrite (AzRotPin, HIGH); // Rotationsstift aktivieren - nach links drehen} AzDir =char(127); // "<-" } lcd.setCursor(8, 0); lcd.print (String (AzDir)); // dies aktiviert den Azim-PWM-Pin proportional zum Winkelfehler (berechnet in Prozent %) PwAzStop =PwAzMin + round((abs(ComAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); //Formel, die eine Leistung proportional zur Winkeldifferenz für Soft-Stop ausgibt PwAzStar =PwAzMin + round((abs(StaAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); // Formel, die eine Leistung proportional zur Winkeldifferenz für Soft-Start ausgibt if (PwAzStar> PwAzStop) { PwAz =PwAzStop; // den kleinsten Wert auswählen} else {PwAz =PwAzStar;} if (PwAz> PwAzMax) {PwAz =PwAzMax;} analogWrite (AzPWMPin, round (2.55 * PwAz)); // Azim-Antriebs-PWM-Pin aktivieren} // AzimRotate ()void ElevRotate () {// dies, um die Drehrichtung zu bestimmen if (ComElev> TruElev) { if (ElUp ==1) { // wenn zuvor im Gegenteil gedreht Richtung analogWrite (ElPWMPin, 0); // STOPPEN Sie den Motor StaElev =TruElev; // Dies ist die Starthöhe für die Softstartverzögerung (200); // Vorschaltverzögerung digitalWrite (ElRotPin, LOW); // Rotationsstift deaktivieren - UP-Verzögerung (200) drehen; // Verzögerung nach dem Umschalten} else {// gleiche Richtung, kein Stopp, keine Verzögerung digitalWrite (ElRotPin, LOW); // Rotationsstift deaktivieren - NACH OBEN drehen} lcd.setCursor (8, 1); lcd.write(2); // Pfeil nach oben ElUp =2; // Flag für Elevation UP} else { if (ElUp ==2) { // wenn vorher in die entgegengesetzte Richtung gedreht analogWrite(ElPWMPin, 0); // STOPPEN Sie den Motor StaElev =TruElev; // Dies ist die Starthöhe für die Softstartverzögerung (200); // Vorschaltverzögerung digitalWrite (ElRotPin, HIGH); // Rotationsstift deaktivieren - UP-Verzögerung (200) drehen; // Verzögerung nach dem Umschalten} else {// gleiche Richtung, kein Stopp, keine Verzögerung digitalWrite (ElRotPin, HIGH); // Rotationsstift deaktivieren - NACH OBEN drehen} lcd.setCursor (8, 1); lcd.write(1); // Pfeil nach unten ElUp =1; // Flag für Elevation DN } // dies aktiviert Azim PWM Pin proportional mit Winkelfehler (berechnet in Prozent %) PwElStop =PwElMin + round((abs(ComElev-TruElev))*(PwElMax-PwElMin)/Emax); //Formel, die eine Leistung proportional zur Winkeldifferenz für Soft-Stop ausgibt PwElStar =PwElMin + round((abs(StaElev-TruElev))*(PwElMax-PwElMin)/Emax); // Formel, die eine Leistung proportional zur Winkeldifferenz für Sanftanlauf ausgibt if (PwElStar> PwElStop) { PwEl =PwElStop; // den kleinsten Wert auswählen} else {PwEl =PwElStar;} if (PwEl> PwElMax) {PwEl =PwElMax;} analogWrite(ElPWMPin, round(2.55*PwEl)); // Elev-Antrieb PWM-Pin aktivieren} // ElevRotate ()void SerComm () beenden {// Messwerte initialisieren ComputerRead =""; Azimut =""; Höhe =""; while (Serial.available ()) { ComputerRead =Serial.readString (); // die eingehenden Daten als String lesen // Serial.println (ComputerRead); // Empfang zu Testzwecken echoen } // Suche nach Befehl  for (int i =0; i <=ComputerRead.length(); i++) { if ((ComputerRead.charAt(i) ==' A')&&(ComputerRead.charAt(i+1) =='Z')){// wenn AZ gelesen für (int j =i+2; j <=ComputerRead.length(); j++) { if (isDigit (ComputerRead.charAt(j))) {// wenn das Zeichen eine Zahl ist Azimut =Azimut + ComputerRead.charAt(j); } else {break;} } } } // Suche nach Befehl  for (int i =0; i <=(ComputerRead.length()-2); i++) { if ((ComputerRead.charAt(i ) =='E')&&(ComputerRead.charAt(i+1) =='L')){ // wenn EL gelesen if ((ComputerRead.charAt(i+2)) =='-') { ComElev =0; // wenn Elevation negativer Bruch; } for (int j =i+2; j <=ComputerRead.length(); j++) { if (isDigit(ComputerRead.charAt(j))) {// wenn das Zeichen eine Zahl ist Elevation =Elevation + ComputerRead.charAt( J); } else {break;} } } } // if  empfangen if (Azimut !=""){ ComAzim =Azimut.toInt(); ComAzim =ComAzim%360; // Werte zwischen Grenzen halten (für Tracker mit mehr als 360 Grad Drehung) } // if  empfangen if (Elevation !=""){ ComElev =Elevation.toInt(); if (ComElev>180) { ComElev =0;} if (ComElev>90) { //wenn mehr als 90deg empfangen wurde. (für Tracker mit 180 Grad Höhe) ComElev =180-ComElev; // unter 90 Grad halten. ComAzim =(ComAzim+180)%360; // und drehen Sie die Antenne auf der Rückseite}} // Suche nach  Abfrage der Antennenposition für (int i =0; i <=(ComputerRead.length()-4); i++) { if ((ComputerRead .) .charAt(i) =='A')&&(ComputerRead.charAt(i+1) =='Z')&&(ComputerRead.charAt(i+3) =='E')&&(ComputerRead.charAt(i +4) =='L')){ // sende die Antennenposition zurück <+xxx.x xx.x> ComputerWrite ="+"+String(TruAzim)+".0 "+String(TruElev)+". 0"; Serial.println (ComputerWrite); } }} // SerComm() beenden
ant-rot-AC-aug2021Arduino
Stellen Sie sicher, dass Sie das elektrische Diagramm für AC-Motoren verwenden
Bietet potentialfreie Kontakte (ON/OFF). Es kann leicht mit kommerziellen Rotatoren verbunden werden.
/* AZ/EL-Antennen-Rotator-Controller für Arduino - AC-Motoren * ========================================================* Verwendet EasyComm-Protokoll für Computer - Tracking-Software * Manueller Befehl mittels zweier Drehgeber AZ - EL * * kompatibel mit Schaltkastenrotatoren * oder AC-Motoren * Trockenkontakte für Links-Rechts, Oben-Unten * * Viorel Racoviteannu / * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https://racov.ro * [email protected] * * Ich übernehme keine Verantwortung für die missbräuchliche Verwendung dieses Codes * oder jegliche Art von Schäden, die durch die Verwendung dieses Codes entstehen können. * * Dez 2020 v2 - verbesserte Stabilität der seriellen Kommunikation * Jan 2021 - AZ, EL-Toleranzen für die Motoraktivierung behoben * Apr 2021 - verbesserte Stabilität der seriellen Kommunikation * Aug 2021 - schnelleres USB-Update, Kaltumschaltung der Az/El-Richtung, kleine Optimierungen im Code */ #include  // Bibliothek für I2C-Kommunikation#include  // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c (Bibliothek für LCD)// Verdrahtung:SDA-Pin ist mit A4 und SCL-Pin mit A5 verbunden. // Verbindung mit LCD über I2C, Standardadresse 0x27 (A0-A2 nicht überbrückt)LiquidCrystal_I2C lcd(0x27, 16, 2); // Adresse, Zeichen, Zeilen. // Deklarieren eines benutzerdefinierten Symbols für das Byte mit dem Aufwärts-/Abwärtspfeil DownArrow[8] ={ B00000, B00100, B00100, B00100, B10101, B01110, B00100, B00000}; byte UpArrow[8] ={ B00000, B00100, B01110, B10101, B00100, B00100, B00100, B00000}; // ANTENNEN-Potentiometer CALIBRATION int AzMin =1; // Beginn des Potentiometers Int AzMax =1023; // Ende des Potentiometers Int ElMin =1; int ElMax =1023; // Erlaubter Fehler, bei dem sich die Antenne nicht bewegt int AzErr =8; int ElErr =4; // Azim-Encodervariablen enum AzPinAssignments { AzEncoderPinA =2, // Encoder rechts AzEncoderPinB =3, // Encoder links AzClearButton =4}; // Encoder-Push unsigned int lastReportedPos =1; // Änderungsverwaltung Static Boolean Rotating =false; // Management entprellen // Serviceroutine unterbrechen vars boolean A_set =false; boolesch B_set =false; //Elev-Encoder-Variablen enum ElPinAssignments{ ElEncoderPinA =6, // Encoder rechts ElEncoderPinB =5, // Encoder links ElClearButton =7}; // Encoder push int aState; int aLastState; // andere Variablen int AzPotPin =A0; // Wählen Sie den Eingangspin für das Azim. Potentiometer int AzRotPinR =13; // Wählen Sie den Out-Pin für die Drehrichtung aus Int AzRotPinL =12; int TruAzim =0; // berechneter echter Azimutwert int ComAzim =0; // befohlener Azimutwert int OldTruAzim =0; // um den vorherigen Azimutwert zu speichern Int OldComAzim =0; char AzDir; // Symbol für Azimrot-Anzeige int AzEncBut =1; // Variable zum Umschalten mit Encoder-Taster Int ElPotPin =A1; // select the input pin for the elev. potentiometer int ElRotPinD =11; // select the out pin for elevation rotation direction int ElRotPinU =10; int TruElev =0; // calculated real elevation value int ComElev =0; // commanded elevation value int OldTruElev =0; // to store previous elevation value int OldComElev =0; char ElDir; // symbol for elev. rot display int ElEncBut =1; // variable to toggle with encoder push button // flags for AZ, EL tolerances bool AzStop =false; bool ElStop =false; int ElUp =0; // 1 =Elevation Dn, 0 =Elevation STOP, 2 =Elevation Up //averaging loop const int numReadings =25; int readIndex =0; // the index of the current reading int azimuth[numReadings]; // the readings from the analog input int elevation[numReadings]; int totalAz =0; // the running total int totalEl =0;// variables for serial comm String Azimuth =""; String Elevation =""; String ComputerRead; String ComputerWrite; bool AZser =false; bool ELser =false; bool ANTser =false;/*************** END VARIABLE DECLARATION ************/ void setup() { Serial.begin(9600); Serial.setTimeout(50); // miliseconds to wait for USB sata. Default 1000// Initiate the LCD:// lcd.begin(16,2); //select this one if the arrows are not displayed correctly lcd.init(); lcd.backlight();// write on display name and version lcd.setCursor(0, 0); // Set the cursor on the first column first row.(counting starts at 0!) lcd.print("EasyCom AntRotor"); lcd.setCursor(0, 1); // Set the cursor on the first column the second row lcd.print("*Racov* Aug.2021 ");//creating custom symbol for up/dwn arrow lcd.createChar(1, DownArrow); lcd.createChar(2, UpArrow); // pin declaration pinMode(AzRotPinR, OUTPUT); //declaring azim. rotation direction Pin as OUTPUT pinMode(AzRotPinL, OUTPUT); pinMode(ElRotPinD, OUTPUT); //declaring elev. rotation direction Pin as OUTPUT pinMode(ElRotPinU, OUTPUT); pinMode(AzPotPin, INPUT); pinMode(ElPotPin, INPUT); pinMode(AzEncoderPinA, INPUT); pinMode(AzEncoderPinB, INPUT); pinMode(AzClearButton, INPUT); pinMode(ElEncoderPinA, INPUT); pinMode(ElEncoderPinB, INPUT); pinMode(ElClearButton, INPUT);// AzEncoder pin on interrupt 0 (pin A) attachInterrupt(0, doEncoderA, CHANGE);// AzEncoder pin on interrupt 1 (pin B) attachInterrupt(1, doEncoderB, CHANGE);// Reads the initial state of the ElEncoderPinA aLastState =digitalRead(ElEncoderPinA);/* initialization of the averaging loop */ TruAzim =(map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); // azimuth value 0-359 if (TruAzim<0) {TruAzim=0;} if (TruAzim>359) {TruAzim=359;} // keep values between limits TruElev =(map(analogRead(ElPotPin), ElMin, ElMax, 0, 90)); // elev value 0-90 if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev=90;} // keep values between limits for (int thisReading =0; thisReading 359) {TruAzim=359;} if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev=90;} // advance to the next position in the array:readIndex =readIndex + 1; // if we're at the end of the array, wrap around to the beginning:if (readIndex>=numReadings) {readIndex =0;} // this is to read the command from encoder ReadAzimEncoder(); ReadElevEncoder(); if (Serial.available()) {SerComm();} // read USB data// update antenna position display only if value change if ((millis()%500)<10){ //not to flicker the display if (OldTruAzim!=TruAzim) { DisplAzim(TruAzim,4,0); OldTruAzim =TruAzim; } if (OldTruElev!=TruElev) { DisplElev(TruElev,5,1); OldTruElev =TruElev; } }// update target position display only if value change if (OldComAzim !=ComAzim) { DisplAzim(ComAzim,12,0); OldComAzim =ComAzim; } if (OldComElev !=ComElev) { DisplElev(ComElev,13,1); OldComElev =ComElev; }// this is to rotate in azimuth if (TruAzim ==ComAzim) { // if equal, stop moving AzStop =true; digitalWrite(AzRotPinL, LOW); // deactivate rotation pin digitalWrite(AzRotPinR, LOW); lcd.setCursor(8, 0); lcd.print("="); } else if ((abs(TruAzim - ComAzim)<=AzErr)&&(AzStop ==false)) { // if in tolerance, but it wasn't an equal, rotate AzimRotate();} else if (abs(TruAzim - ComAzim)>AzErr){ // if target is off tolerance AzStop =false; // it's not equal AzimRotate(); // rotate }// this is to rotate in elevation if (TruElev ==ComElev) { // if equal, stop moving ElStop =true; digitalWrite(ElRotPinD, LOW); // deactivate elevator pin digitalWrite(ElRotPinU, LOW); lcd.setCursor(8, 1); lcd.print("="); ElUp =0; // flag for elevation STOP } else if ((abs(TruElev - ComElev)<=ElErr)&&(ElStop ==false)) { // if in tolerance, but it wasn't an equal, rotate ElevRotate();} else if (abs(TruElev - ComElev)>ElErr){ // if target is off tolerance ElStop =false; // it's not equal ElevRotate(); // rotate }// this is to interpret x10 AZ ENC multiplication while (AzEncBut ==10) { // while toggled to x10 digitalWrite(AzRotPinL, LOW); // deactivate rotation pin digitalWrite(AzRotPinR, LOW); digitalWrite(ElRotPinD, LOW); // deactivate elevator pin digitalWrite(ElRotPinU, LOW); lcd.setCursor(8, 0); lcd.print("*"); ReadAzimEncoder(); if (OldComAzim !=ComAzim){ // update display only if numbers change DisplAzim(ComAzim, 12, 0); OldComAzim =ComAzim; } delay(100); }}// end main LOOP//____________________________________________________// ___________procedures definitions__________________void DisplAzim(int x, int y, int z) { char displayString[7] =""; sprintf(displayString, "%03d", x); //outputs a fixed lenght number (3 integer) lcd.setCursor(y, z); // for no leading zeros "__7" use "%3d" lcd.print(displayString); // ************** FOR CALIBRATION PURPOSES **************// Serial.print ("Az ");// Serial.println (analogRead(AzPotPin));}void DisplElev(int x, int y, int z){ char displayString[7] =""; sprintf(displayString, "%02d", x); //outputs a fixed lenght number (2 integer) lcd.setCursor(y, z); // for no leading zeros "_7" use "%2d" lcd.print(displayString);// ************** FOR CALIBRATION PURPOSES **************// Serial.print ("El ");// Serial.println (analogRead(ElPotPin));}void ReadElevEncoder() { aState =digitalRead(ElEncoderPinA); // Reads the "current" state of the ElEncoderPinA // If the previous and the current state of the ElEncoderPinA are different, that means a Pulse has occured if (aState !=aLastState){ // If the ElEncoderPinB state is different to the ElEncoderPinA state, that means the encoder is rotating clockwise if (digitalRead(ElEncoderPinB) !=aState) { ComElev ++;} else { ComElev --;} if (ComElev <0) {ComElev =0;} if (ComElev>90) {ComElev =90;} } aLastState =aState; // Updates the previous state of the ElEncoderPinA with the current state}void ReadAzimEncoder() { rotating =true; // reset the debouncer if (lastReportedPos !=ComAzim) { lastReportedPos =ComAzim; } Verzögerung(10); if (digitalRead(AzClearButton) ==LOW ) { // if encoder switch depressed delay (250); // debounce switch if (AzEncBut ==1){ AzEncBut =10; ComAzim =int(ComAzim/10)*10; // ComAzim in 10deg. steps } else { AzEncBut =1; } }} //end ReadAzimEncoder()// Interrupt on A changing statevoid doEncoderA() { // debounce if ( rotating ) delay (1); // wait a little until the bouncing is done // Test transition, did things really change? if ( digitalRead(AzEncoderPinA) !=A_set ) { // debounce once more A_set =!A_set; // adjust counter + if A leads B if ( A_set &&!B_set ) ComAzim +=AzEncBut; ComAzim =((ComAzim + 360) % 360); // encoderPos between 0 and 359 deg. rotating =false; // no more debouncing until loop() hits again }}// Interrupt on B changing state, same as A abovevoid doEncoderB() { if ( rotating ) delay (1); if ( digitalRead(AzEncoderPinB) !=B_set ) { B_set =!B_set; // adjust counter - 1 if B leads A if ( B_set &&!A_set ) ComAzim -=AzEncBut; ComAzim =((ComAzim + 360) % 360); // encoderPos between 0 and 359 deg. rotating =false; } }void AzimRotate() { if ((ComAzim-TruAzim)> (TruAzim-ComAzim)) { // this to determine direction of rotation// cold switching - stop motor before changing direction - to protect mechanic and electric parts digitalWrite(AzRotPinL, LOW); // deactivate rotation pin Left if (AzDir ==char(127)) {delay(500);} // if previously rotating in the oposite direction, wait 0.5 seconds digitalWrite(AzRotPinR, HIGH); // activate rotation pin Right AzDir =char(126); // "->" } else { digitalWrite(AzRotPinR, LOW); if (AzDir ==char(126)) {delay(500);} digitalWrite(AzRotPinL, HIGH); AzDir =char(127); // "<-" } lcd.setCursor(8, 0); lcd.print(String(AzDir));}void ElevRotate() {// this to determine direction of rotation if ((ComElev-TruElev)> (TruElev-ComElev)) { digitalWrite(ElRotPinD, LOW); if (ElUp ==1) {delay(500);} digitalWrite(ElRotPinU, HIGH); lcd.setCursor(8, 1); lcd.write(2); // arrow up ElUp =2; } else { digitalWrite(ElRotPinU, LOW); if (ElUp ==2) {delay(500);} digitalWrite(ElRotPinD, HIGH); lcd.setCursor(8, 1); lcd.write(1); // arrow down ElUp =1; }}void SerComm() { // initialize readings ComputerRead =""; Azimuth =""; Elevation =""; while(Serial.available()) { ComputerRead=Serial.readString(); // read the incoming data as string Serial.println(ComputerRead); // echo the reception for testing purposes } // looking for command  for (int i =0; i <=ComputerRead.length(); i++) { if ((ComputerRead.charAt(i) =='A')&&(ComputerRead.charAt(i+1) =='Z')){ // if read AZ for (int j =i+2; j <=ComputerRead.length(); j++) { if (isDigit(ComputerRead.charAt(j))) { // if the character is number Azimuth =Azimuth + ComputerRead.charAt(j); } else {break;} } } } // looking for command  for (int i =0; i <=(ComputerRead.length()-2); i++) { if ((ComputerRead.charAt(i) =='E')&&(ComputerRead.charAt(i+1) =='L')){ // if read EL if ((ComputerRead.charAt(i+2)) =='-') { ComElev =0; // if elevation negative break; } for (int j =i+2; j <=ComputerRead.length(); j++) { if (isDigit(ComputerRead.charAt(j))) { // if the character is number Elevation =Elevation + ComputerRead.charAt(j); } else {break;} } } } // if  received if (Azimuth !=""){ ComAzim =Azimuth.toInt(); ComAzim =ComAzim%360; // keeping values between limits }// if  received if (Elevation !=""){ ComElev =Elevation.toInt(); if (ComElev>180) { ComElev =0;} if (ComElev>90) { //if received more than 90deg. (for trackers with 180deg. elevation) ComElev =180-ComElev; //keep below 90deg. ComAzim =(ComAzim+180)%360; //and rotate the antenna on the back } }// looking for  interogation for antenna position for (int i =0; i <=(ComputerRead.length()-4); i++) { if ((ComputerRead.charAt(i) =='A')&&(ComputerRead.charAt(i+1) =='Z')&&(ComputerRead.charAt(i+3) =='E')&&(ComputerRead.charAt(i+4) =='L')){ // send back the antenna position <+xxx.x xx.x> ComputerWrite ="+"+String(TruAzim)+".0 "+String(TruElev)+".0"; Serial.println(ComputerWrite); } }}// end SerComm()
Potentiometer calibration procedureArduino
AZ / EL Potentiometers limit calibration PROCEDURE for displaying the correct antenna angles and rotation limits ( 0-359ᴼ / 0-90ᴼ)
This is plain text, not a code :)
AZ / EL Potentiometers limit calibration PROCEDURE ( 0-359ᴼ / 0-90ᴼ)This might seem complicated, but it only has to be done once.1. Open the code in Arduino and - Look for void DisplAzim(int x, int y, int z) {...// Serial.print ("Az ");// Serial.println (analogRead(AzPotPin)); - Uncoment these lines. Should look like this:Serial.print ("Az "); Serial.println (analogRead(AzPotPin)); - Look for void DisplElev(int x, int y, int z){...// Serial.print ("El ");// Serial.println (analogRead(ElPotPin));Uncoment these lines, too. Should look like this:Serial.print ("El "); Serial.println (analogRead(ElPotPin));2. Upload the code and open the Serial Monitor. There you will see a lot of numbers;3. With the help of the encoders, move the antenna to minimum values, 0ᴼ in azimuth and 0ᴼ in elevation.- Write down the values for Azimuth and Elevation. (in my case it was AzMin=90, ElMin=10)- These are the input values read by Arduino, not the real angles;4. Move the antenna again to maximum values, 359ᴼ in azimuth and 90ᴼ in elevation.- Again, write down the values for Azimuth and Elevation. (in my case it was AzMax=1000, ElMax=992);5. Look in the code, at the beginning, for the section// ANTENNA potentiometers CALIBRATION int AzMin =1; int AzMax =1023; int ElMin =1; int ElMax =1023;- Here input the values you wrote down for each situation;6. Now it is no longer necessary to send this on serial, so you have to comment back these lines, like this:// Serial.print ("Az "); // Serial.println (analogRead(AzPotPin));... // Serial.print ("El "); // Serial.println (analogRead(ElPotPin));7. Upload again the code.That's all.Now, in the serial monitor, there should be no more numbers, and the true antenna position is read correctly.
Motor calibration procedureArduino
This procedure sets the parameters for the Antenna Speed-Up / Slow-Down Zone.
This is plain text, not a code :)
Motor Calibration Procedure For Soft-Start / Soft-Stop feature.This procedure sets the parameters for the Antenna Speed-Up / Slow-Down and the Dead-Zone.You basically set how fast and how slow you want the antenna to start and to stop. You also set much the target can move, before the antenna will adjust again.It’s not strictly necessary, only if you don’t like the default settings.Make sure you first apply the Potentiometer Calibration Procedure !!! That one is strictly necessary.Look at the power diagram for a better understanding.***For Azimuth movement***-As the antenna starts to move towards the target, is picking up speed, reaching full power after  degrees difference. -As the antenna closes in to the target, below  degrees difference, it starts to slow down.  should be higher for heavier antennas.-The power starts to decrease from  to  until the angle difference becomes zero.  (in percents %) should be 100 for full speed. If you ever think your antenna rotates too fast, you can set a smaller .  (in percents %) is the minimum power for which your motor doesn’t stall and can start under load. The power output never falls below this value.-Once the antenna reaches the target position (zero degrees error), it stops and doesn’t move again until the target travels more than  degrees. This is a dead zone, to prevent continuously shaking the antenna for the smallest target movement, or potentiometer position jitter. The smaller the , the more precise tracking, the more frequent shacking of the motors.***For Elevation movement***Exactly as for the Azimuth.Look at the beginning of the code for this section. Here you can input your desired values./**************THIS IS WHERE YOU REALY TWEAK THE ANTENNA MOVEMENT************/...// Allowed error for which antennna won't move. int AzErr =8; int ElErr =4;// Angle difference where soft stop begins int Amax =25; //azimuth int Emax =15; //elevation// min and max power for motors, percents; int PwAzMin =30; //minimum power for which the motor doesn't stall and starts under load int PwAzMax =100; //full power for the fastest speed int PwElMin =30; int PwElMax =100;/****************************************************************************/

Schaltpläne

Make sure you use this diagram with the code for DC motors.
Connection of all the modules, encoders, LCD, relays, MosFet etc, Make sure you use this diagram with the code for AC motors.
Offers dry contacts (ON/OFF). It can be easily interfaced with commercial rotators.

Herstellungsprozess

  1. Dimmen von Lichtern mit PWM über Drucktasten
  2. Arduino-Gyroskop-Spiel mit MPU-6050
  3. DHT11-Sensor mit LEDs und einem Piezo-Lautsprecher
  4. Unopad - Arduino MIDI-Controller mit Ableton
  5. Iron Man
  6. Einfacher Hindernissensor mit Arduino
  7. Finde mich
  8. Arduino-Befeuchtersteuerung
  9. 4x4x4 LED-Würfel mit Arduino Uno und 1sheeld
  10. Arduino-Joystick