Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Antenne Rotator-controller compatibel met trackingsoftware

Componenten en benodigdheden

Arduino UNO
Arduino Uno-bord
× 1
Draaipotentiometer (generiek)
max. 1Kohm (500 Ohm werkt beter)
× 2
Roterende encoder met drukknop
× 2
Broodplank (algemeen)
× 1
Relaismodule (algemeen)
2 modules x 2 relais NO-Com-NC
× 2
Power MOSFET N-kanaal
power mosfet-module (min 12V/3A)
× 2

Apps en online services

Arduino IDE

Over dit project

Laatste update november 2021

Dit project begon als entertainment en werd een serieus apparaat.

De Controller accepteert handmatige positionering van de antenne, door middel van twee roterende encoders, Azimuth en Elevation. Het kan automatisch satellieten volgen wanneer het via USB is aangesloten op een pc waarop software voor het volgen van satellieten draait.

Het is compatibel met alle trackingsoftware die gebruikmaakt van het EasyComm2-protocol / 9600 bauds. PstRotator, WXtrack, HRD, MacDoppler... Zelfs WXtoIMG kan de rotator besturen.

Het werkt rechtstreeks met Orbitron, met een DDE-plug-in van http://tripsintech.com/orbitron-dde-azimuth-elevation-to-serial/

De controller voert een serieel antwoord uit, zodat de trackingsoftware de echte antennepositie op het scherm weergeeft. Tot nu toe deed alleen PstRotator dat.

De code gebruikt geen enkele bibliotheek (behalve het LCD-scherm) en werkt precies zoals het is, met pinnen volgens het onderstaande elektrische diagram. Als u op de knop van de azimut-encoder drukt, stopt alle beweging van de antenne onmiddellijk en kan het azimut-commando worden ingesteld op 10 graden. stappen.

U vindt hier twee versies:een voor gelijkstroommotoren en een voor wisselstroommotoren (alleen relais). De laatste kan worden gekoppeld aan bestaande commerciële antennerotators.

De versie met gelijkstroommotoren heeft het voordeel dat PWM wordt gebruikt voor een zachtere/soepelere antennebeweging. Het geeft een vermogensrespons af die evenredig is met de hoekfout (doel<->antenne). Daarom, wanneer de antenne begint te bewegen, versnelt deze geleidelijk, en bij het naderen van de gewenste positie, vertraagt ​​hij tot hij volledig stopt. Dit staat bekend als Soft-Start / Soft-Stop . Er is een instelbare dode zone, waar de antenne niet beweegt voor de geringste doeloffset.

Ik heb een bèta versie met Soft-Start / Soft-Stop voor AC-motoren, profiterend van deze AC-dimmermodule, maar op dit moment werkt het alleen voor azimut. Als je het eens wilt proberen, laat het me dan per e-mail weten.

Als je 180 graden hebt. hoogte systeem, je bent goed, geef me een e-mail. Er is ook een versie met 0.1deg. precisie, maar ik zou het niet aanraden, tenzij je een verdomde rotsvaste potentiometerlezing en een paranoïde controllerconstructie hebt. U vindt meer versies op mijn webpagina.

Na het voltooien van de constructie moet u de kalibratieprocedures . toepassen .

  • De potmeterkalibratie is verplicht en zorgt voor een correcte aflezing van 0-359deg. / 0-90deg., het maakt niet uit wat voor potentiometer je gebruikt.
  • De motorkalibratie is alleen voor het afstemmen van de Soft-Start-Stop voorzien zijn van. Dit is nodig als u niet tevreden bent met de standaardinstellingen.

Meer gedetailleerde uitleg in de video's. Omdat de code in de loop van de tijd is verbeterd en de video's niet meer kunnen worden bijgewerkt, kijk je op mijn webpagina voor de laatste informatie en persoonlijke ervaringen met deze controller. https://racov.ro/index.php/2020/12/09/arduino-based-antenna-rotator-part3-software-tracking-update/

Stuur me een e-mail als je meer wilt weten, want dit platform informeert me niet over nieuwe reacties, weet niet waarom. Ik zal proberen om kleine problemen zo goed mogelijk op te lossen. [email protected]

Heel erg bedankt aan iedereen die me feedback heeft gestuurd, waardoor dit project betrouwbaarder is geworden. Elke feedback wordt zeer op prijs gesteld.

Code

  • ant-rot-DC-nov2021
  • ant-rot-AC-aug2021
  • Kalibratieprocedure voor potentiometer
  • Motorkalibratieprocedure
ant-rot-DC-nov2021Arduino
Deze code is voor DC-motoren, met zachte start-stop PWM-uitgang
/* AZ/EL Antenne Rotator-controller voor Arduino - DC-motoren * ========================================================* Gebruikt EasyComm-protocol voor computer - Trackingsoftware * Handmatige opdracht door middel van twee roterende encoders AZ - EL * * Viorel Racoviteannu * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https://racov.ro * [email protected] * * Ik kan geen verantwoordelijkheid nemen voor misbruik van deze code * of enige vorm van schade die kan ontstaan ​​door het gebruik van deze code. * * dec 2020 v2 - verbeterde seriële communicatiestabiliteit * jan 2021 - verbeterde nabije dode zone, waarvoor de antenne niet beweegt * april 2021 - verbeterde seriële communicatiestabiliteit * jun 2021 - foutproportioneel vermogen voor het volgen van beweging. Real Soft-Stop * aug 2021 - snellere USB-update, koude omschakeling Az/El-richting, kleine optimalisaties in de code * nov 2021 - kraakte het geheim van Soft-Start. Het was niet moeilijk. Daar heb je het */ #include  // Bibliotheek voor I2C-communicatie#include  // Bibliotheek voor LCD// Bedrading:SDA-pin is aangesloten op A4 en SCL-pin op A5.// Connect naar LCD via I2C, standaardadres 0x27 (A0-A2 niet overbrugd) LiquidCrystal_I2C lcd (0x27, 16, 2); // adres, tekens, rijen.// declareren van aangepast symbool voor omhoog/omlaag pijlbyte DownArrow [8] ={B00000, B00100, B00100, B00100, B10101, B01110, B00100, B00000}; byte pijl-omhoog [8] ={ B00000, B00100, B01110, B10101, B00100, B00100, B00100, B00000};/************************* ********** DIT IS WAAR JE DE ANTENNEBEWEGING ECHT TWEAKT***************/// ANTENNE potentiometers KALIBRATIE int AzMin =1; //begin van de potentiometer int AzMax =1023; // einde van de potentiometer int ElMin =1; int ElMax =1023;// Toegestane fout waarvoor antenne niet beweegt int AzErr =8; int ElErr =4;// Hoekverschil waar softstop begint int Amax =25; //azimut int Emax =15; //elevatie// min en max vermogen voor motoren, procenten; int PwAzMin =30; // minimaal vermogen waarvoor de motor niet afslaat en start onder belasting int PwAzMax =100; //vol vermogen voor de hoogste snelheid int PwElMin =30; int PwElMax =100; int PwAz =0; //berekend vermogen dat naar de motor moet worden overgebracht (in procenten); int PwEl =0;/********************************************* ********************************************** *****/// Encodervariabelen enum AzPinAssignments { AzEncoderPinA =2, // Az encoder rechts AzEncoderPinB =3, // encoder links AzClearButton =4, // encoder push ElEncoderPinA =6, // El encoder rechts ElEncoderPinB =5 }; // encoder left // interrupt service routine vars unsigned int lastReportedPos =1; // verandermanagement statisch boolean roteren =false; // debounce management boolean A_set =false; boolean B_set =onwaar; int een Staat; int aLastState; // andere variabelen int AzPotPin =A0; // selecteer de invoerpin voor de azim. potentiometer int AzRotPin =12; // selecteer de uit pin voor draairichting int AzPWMPin =11; // selecteer de uit-pin voor azimuth PWM-opdracht int TruAzim =0; // berekende reële azimutwaarde int ComAzim =0; // opgedragen azimutwaarde int OldTruAzim =0; // om de vorige azimutwaarde op te slaan int OldComAzim =0; char AzDir; // symbool voor azim rot display int AzEncBut =1; // variabele om te schakelen met encoder-drukknop int ElPotPin =A1; // selecteer de invoerpin voor de elev. potentiometer int ElRotPin =13; // selecteer de uit pin voor hoogte rotatierichting int ElPWMPin =10; // selecteer de uit-pin voor hoogterotatie PWM-opdracht int TruElev =0; // berekende werkelijke hoogtewaarde int ComElev =0; // opgedragen hoogtewaarde int OldTruElev =0; // om de vorige hoogtewaarde op te slaan int OldComElev =0; char ElDir; // symbool voor hoogte. rot display // vlaggen voor AZ, EL toleranties bool AzStop =false; bool ElStop =false; int ElUp =1; // 1 - Hoogte Dn, 0 - Hoogte STOP, 2 - Hoogte omhoog int StaAzim =0; // Start Azimuthoek voor motor Soft-Start int PwAzStop =0; // berekende PWM (procent) voor soft-stop int PwAzStar =0; // berekende PWM (percentage) voor soft-start int StaElev =0; // Start Elevatiehoek voor motor Soft-Start int PwElStop =0; // berekende PWM (procent) voor soft-stop int PwElStar =0; // berekende PWM (percentage) voor soft-start //middeling loop const int numReadings =25; int readIndex =0; // de index van de huidige waarde int azimuth [numReadings]; // de metingen van de analoge ingang int elevatie [numReadings]; int totaalAz =0; // het lopende totaal int totalEl =0;// variabelen voor seriële comm String Azimuth =""; Stringhoogte =""; String ComputerLezen; String ComputerWrite; bool AZser =false; bool ELser =false; bool ANTser =false;/*************** EINDE VARIABELE VERKLARING ***********/void setup() {Serial.begin(9600); Serial.setTimeout(50); // milliseconden om te wachten op USB sata. Standaard 1000// Start de LCD:// lcd.begin (16,2); //selecteer deze als de pijlen niet correct worden weergegeven lcd.init(); lcd.backlight();// schrijf op weergavenaam en versie lcd.setCursor(0, 0); // Zet de cursor op de eerste rij van de eerste kolom (tellen begint bij 0!) lcd.print("EasyCom AntRotor"); // toon "..." lcd.setCursor (0, 1); // Zet de cursor op de eerste kolom, de tweede rij lcd.print("*Racov* Nov.2021");//aangepast symbool maken voor pijl omhoog/omlaag lcd.createChar(1, DownArrow); lcd.createChar(2, pijl-omhoog); // pinverklaring pinMode (AzRotPin, OUTPUT); // azim verklaren. draairichting Pin als OUTPUT pinMode (AzPWMPin, OUTPUT); // azimut PWM-opdracht Pin verklaren als OUTPUT pinMode (ElRotPin, OUTPUT); //declareren van hoogte. draairichting Pin als OUTPUT pinMode (ElPWMPin, OUTPUT); pinMode (AzPotPin, INPUT); pinMode (ElPotPin, INPUT); pinMode (AzEncoderPinA, INPUT); pinMode (AzEncoderPinB, INPUT); pinMode (AzClearButton, INPUT); pinMode (ElEncoderPinA, INPUT); pinMode (ElEncoderPinB, INPUT);// AzEncoder-pin op interrupt 0 (pin A) attachInterrupt (0, doEncoderA, CHANGE);// AzEncoder-pin op interrupt 1 (pin B) attachInterrupt (1, doEncoderB, CHANGE);// Leest de beginstatus van de ElEncoderPinA aLastState =digitalRead(ElEncoderPinA);/* initialisatie van de middelingslus */ TruAzim =(map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); // azimutwaarde 0-359 if (TruAzim<0) {TruAzim=0;} if (TruAzim>359) {TruAzim=359;} // waarden tussen limieten houden TruElev =(map(analogRead(ElPotPin), ElMin, ElMax , 0, 90)); // elev-waarde 0-90 if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev=90;} // houd waarden tussen limieten voor (int thisReading =0; thisReading 359) {TruAzim=359;} if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev =90;} // ga door naar de volgende positie in de array:readIndex =readIndex + 1; // als we aan het einde van de array zijn, ga dan terug naar het begin:if (readIndex>=numReadings) {readIndex =0;} // dit is om de opdracht te lezen van encoder ReadAzimEncoder(); ReadElevEncoder(); if (Serial.available()) {SerComm();} // lees USB-gegevens// update antennepositieweergave alleen als waarde verandert als ((millis()%500)<10){ // niet om het scherm te flikkeren als (OldTruAzim!=TruAzim) { DisplAzim(TruAzim,4,0); OldTruAzim =TruAzim; } if (OldTruElev!=TruElev) { DisplElev(TruElev,5,1); OldTruElev =TruElev; } }// werk de weergave van de doelpositie alleen bij als de waarde verandert als (OldComAzim!=ComAzim) { DisplAzim(ComAzim,12,0); OldComAzim =ComAzim; } if (OldComElev!=ComElev) { DisplElev(ComElev,13,1); OldComElev =ComElev; }// dit is om in azimut te roteren if (TruAzim ==ComAzim) { // indien gelijk, stop met bewegen AzStop =true; analoogWrite(AzPWMPin, 0); // Az motorvermogen =0 StaAzim =TruAzim; // dit zal de startazimut zijn voor soft-start lcd.setCursor (8, 0); lcd.print("="); } else if ((abs(TruAzim - ComAzim)<=AzErr)&&(AzStop ==false)) { // if in tolerantie, maar het was niet gelijk, draai AzimRotate();} else if (abs(TruAzim - ComAzim)>AzErr){ // als doel buiten tolerantie is AzStop =false; // het is niet gelijk AzimRotate(); // roteren }// dit is om in hoogte te roteren als (TruElev ==ComElev) { // indien gelijk, stop met bewegen ElStop =true; analogWrite(ElPWMPin, 0); // El motorvermogen =0 StaElev =TruElev; // dit wordt de starthoogte voor soft-start lcd.setCursor (8, 1); lcd.print("="); ElUp =0; // vlag voor hoogte STOP } else if ((abs(TruElev - ComElev)<=ElErr)&&(ElStop ==false)) { // als in tolerantie, maar het was niet gelijk, draai ElevRotate();} else if (abs(TruElev - ComElev)>ElErr){ // als doel buiten tolerantie is ElStop =false; // het is niet gelijk aan ElevRotate(); // roteren} // dit is om Az-encoder x10 vermenigvuldiging te interpreteren terwijl (AzEncBut ==10) {// terwijl geschakeld naar x10 analogWrite (AzPWMPin, 0); // STOP antennerotatie StaAzim =TruAzim; // dit zal de startazimut zijn voor soft-start analogWrite (ElPWMPin, 0); lcd.setCursor(8, 0); lcd.print("*"); ReadAzimEncoder(); if (OldComAzim !=ComAzim) {// update weergave alleen als nummers veranderen DisplAzim (ComAzim, 12, 0); OldComAzim =ComAzim; } vertraging (100); }}// end main LOOP//____________________________________________________// ___________definities van procedures__________________void DisplAzim(int x, int y, int z) { char displayString[7] =""; sprintf(displayString, "%03d", x); // voert een getal met een vaste lengte uit (3 geheel getal) lcd.setCursor (y, z); // voor geen voorloopnullen "__7" gebruik "%3d" lcd.print(displayString); // *************** VOOR KALIBRATIEDOELEINDEN ***************// Serial.print ("Az");// Serial.println ( analogRead(AzPotPin));}void DisplElev(int x, int y, int z){ char displayString[7] =""; sprintf(displayString, "%02d", x); // voert een getal met een vaste lengte uit (2 geheel getal) lcd.setCursor (y, z); // voor geen voorloopnullen "_7" gebruik "%2d" lcd.print(displayString);// *************** VOOR KALIBRATIEDOELEINDEN ********** ****// Serial.print ("El ");// Serial.println (analogRead(ElPotPin));}void ReadElevEncoder() { aState =digitalRead(ElEncoderPinA); // Leest de "huidige" status van de ElEncoderPinA // Als de vorige en de huidige status van de ElEncoderPinA verschillend zijn, betekent dit dat er een puls is opgetreden als (aState !=aLastState){ // Als de ElEncoderPinB-status anders is dan de ElEncoderPinA staat, dat betekent dat de encoder rechtsom draait if (digitalRead(ElEncoderPinB) !=aState) { ComElev ++;} else { ComElev --;} if (ComElev <0) {ComElev =0;} if (ComElev>90 ) {ComElev =90;} } aLastState =aState; // Werkt de vorige staat van de ElEncoderPinA bij met de huidige staat}void ReadAzimEncoder() {rotating =true; // reset de debouncer if (lastReportedPos! =ComAzim) { lastReportedPos =ComAzim; } vertraging(10); if (digitalRead (AzClearButton) ==LAAG) {// als de encoderschakelaar vertraging heeft ingedrukt (250); // debounce-schakelaar if (AzEncBut ==1) { AzEncBut =10; ComAzim =int(ComAzim/10)*10; // ComAzim in 10deg. stappen } else { AzEncBut =1; } }} // end ReadAzimEncoder () // Interrupt op een veranderende statevoid doEncoderA () { // debounce als (roterende) vertraging (1); // wacht een beetje tot het stuiteren is gedaan // Test overgang, zijn de dingen echt veranderd? if (digitalRead(AzEncoderPinA)!=A_set) {// debounce nogmaals A_set =!A_set; // teller aanpassen + als A leidt tot B if (A_set &&!B_set) ComAzim +=AzEncBut; ComAzim =((ComAzim + 360) % 360); // encoderPos tussen 0 en 359 graden. roterend =onwaar; // niet meer debouncen totdat loop() weer toeslaat }}// Interrupt bij verandering van B status, hetzelfde als A hierbovenvoid doEncoderB() { if (roterende) vertraging (1); if (digitalRead(AzEncoderPinB)!=B_set) { B_set =!B_set; // teller aanpassen - 1 als B leidt tot A if ( B_set &&!A_set ) ComAzim -=AzEncBut; ComAzim =((ComAzim + 360) % 360); // encoderPos tussen 0 en 359 graden. roterend =onwaar; } }void AzimRotate() { if (ComAzim> TruAzim) { // dit om de draairichting te bepalen// koud schakelen - stop motor voordat van richting verandert - om mechanische en elektrische onderdelen te beschermen if (AzDir ==char(127)) { // indien eerder in de tegenovergestelde richting gedraaid analogWrite (AzPWMPin, 0); // STOP de motor StaAzim =TruAzim; // dit wordt de startazimut voor soft-startvertraging (200); // pre-switch vertraging digitalWrite (AzRotPin, LOW); // deactiveer rotatiepin - draai rechtsvertraging (200); // vertraging na schakelaar} else {// dezelfde richting, geen stop, geen vertraging digitalWrite (AzRotPin, LOW); // deactiveer rotatiepin - draai naar rechts} AzDir =char (126); // "->" } else { if (AzDir ==char (126)) { // indien eerder in de tegenovergestelde richting geroteerd analogWrite (AzPWMPin, 0); // STOP de motor StaAzim =TruAzim; // dit wordt de startazimut voor soft-startvertraging (200); // pre-switch vertraging digitalWrite (AzRotPin, HIGH); // activeer rotatiepin - draai links vertraging (200); // vertraging na schakelaar} else {// zelfde richting, geen stop, geen vertraging digitalWrite (AzRotPin, HIGH); // activeer rotatiepin - draai naar links} AzDir =char (127); // "<-" } lcd.setCursor (8, 0); lcd.print(String(AzDir)); // dit activeert azim PWM pin proportioneel met hoekfout (berekend in procenten %) PwAzStop =PwAzMin + round((abs(ComAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); // formule die een vermogen levert dat evenredig is met het hoekverschil voor Soft-Stop PwAzStar =PwAzMin + round((abs(StaAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); // formule die een vermogen levert dat evenredig is met het hoekverschil voor Soft-Start als (PwAzStar> PwAzStop) {PwAz =PwAzStop; //kies welke waarde het kleinst is} else {PwAz =PwAzStar;} if (PwAz> PwAzMax) {PwAz =PwAzMax;} analogWrite (AzPWMPin, round (2.55*PwAz)); // activeer Azim drive PWM-pin}// end AzimRotate()void ElevRotate() {// dit om de draairichting te bepalen if (ComElev> TruElev) {if (ElUp ==1) {// als eerder in de tegenovergestelde richting draait richting analogWrite (ElPWMPin, 0); // STOP de motor StaElev =TruElev; // dit is de starthoogte voor softstartvertraging (200); // voorschakelvertraging digitalWrite (ElRotPin, LOW); // deactiveer rotatiepin - draai OMHOOG vertraging (200); // vertraging na schakelaar} else {// zelfde richting, geen stop, geen vertraging digitalWrite (ElRotPin, LOW); // deactiveer rotatiepin - draai OMHOOG } lcd.setCursor (8, 1); lcd.schrijven(2); // pijl omhoog ElUp =2; // vlag voor hoogte OMHOOG } else { if (ElUp ==2) { // indien eerder in de tegenovergestelde richting gedraaid analogWrite (ElPWMPin, 0); // STOP de motor StaElev =TruElev; // dit is de starthoogte voor softstartvertraging (200); // voorschakelvertraging digitalWrite (ElRotPin, HIGH); // deactiveer rotatiepin - draai OMHOOG vertraging (200); // vertraging na schakelaar} else {// zelfde richting, geen stop, geen vertraging digitalWrite (ElRotPin, HIGH); // deactiveer rotatiepin - draai OMHOOG } lcd.setCursor (8, 1); lcd.schrijven(1); // pijl omlaag ElUp =1; // vlag voor hoogte DN } // dit activeert azim PWM pin proportioneel met hoekfout (berekend in procenten %) PwElStop =PwElMin + round((abs(ComElev-TruElev))*(PwElMax-PwElMin)/Emax); // formule die een vermogen levert dat evenredig is met het hoekverschil voor Soft-Stop PwElStar =PwElMin + round((abs(StaElev-TruElev))*(PwElMax-PwElMin)/Emax); // formule die een vermogen levert dat evenredig is met het hoekverschil voor Soft-Start als (PwElStar> PwElStop) {PwEl =PwElStop; //kies welke waarde het kleinst is } else {PwEl =PwElStar;} if (PwEl> PwElMax) {PwEl =PwElMax;} analogWrite (ElPWMPin, round (2.55*PwEl)); // activeer Elev drive PWM pin}// end ElevRotate () void SerComm () {// initialiseer metingen ComputerRead =""; Azimut =""; Hoogte =""; while(Serial.available()) { ComputerRead=Serial.readString(); // lees de binnenkomende gegevens als string// Serial.println (ComputerRead); // echo de ontvangst voor testdoeleinden} // zoek naar opdracht  voor (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))) {// als het teken nummer is Azimuth =Azimuth + ComputerRead.charAt(j); } else {break;} } } } // op zoek naar commando  for (int i =0; i <=(ComputerRead.length()-2); i++) { if ((ComputerRead.charAt(i ) =='E')&&(ComputerRead.charAt(i+1) =='L')){ // indien gelezen EL if ((ComputerRead.charAt(i+2)) =='-') { ComElev =0; // als hoogteverschil negatief is; } for (int j =i+2; j <=ComputerRead.length(); j++) {if (isDigit(ComputerRead.charAt(j))) { // als het teken nummer is Elevation =Elevation + ComputerRead.charAt( J); } else {break;} } } } // if  ontvangen if (Azimuth !=""){ ComAzim =Azimuth.toInt(); ComAzim =ComAzim%360; // waarden tussen limieten houden (voor trackers met een rotatie van meer dan 360 graden) }// if  ontvangen if (Elevation !=""){ ComElev =Elevation.toInt(); if (ComElev>180) {ComElev =0;} if (ComElev>90) {//indien ontvangen meer dan 90deg. (voor trackers met een hoogte van 180 graden) ComElev =180-ComElev; // blijf onder de 90 graden. ComAzim =(ComAzim+180)%360; // en draai de antenne aan de achterkant } }// zoek naar  interogation voor antennepositie voor (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')){ // stuur de antennepositie terug <+xxx.x xx.x> ComputerWrite ="+"+String(TruAzim)+".0 "+String(TruElev)+". 0"; Serial.println(ComputerWrite); } }}// einde SerComm()
ant-rot-AC-aug2021Arduino
Zorg ervoor dat u het elektrische schema voor wisselstroommotoren gebruikt
Biedt droge contacten (AAN/UIT). Het kan eenvoudig worden gekoppeld aan commerciële rotators.
/* AZ/EL Antenne Rotator-controller voor Arduino - AC-motoren * ========================================================* Maakt gebruik van EasyComm protocol voor computer - Tracking Software * Handmatige bediening door middel van twee roterende encoders AZ - EL * * compatibel met schakelkastrotators * of AC-motoren * droge contacten voor links-rechts, omhoog-omlaag * * Viorel Racoviteannu / * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https://racov.ro * [email protected] * * Ik kan geen verantwoordelijkheid nemen voor misbruik van deze code * of enige vorm van schade die kan ontstaan ​​door het gebruik van deze code. * * dec 2020 v2 - verbeterde seriële comm-stabiliteit * jan 2021 - vaste AZ, EL-toleranties voor motoractivering * apr 2021 - verbeterde seriële comm-stabiliteit * aug 2021 - snellere USB-update, koude omschakeling Az/El-richting, kleine optimalisaties in de code */ #include  // Bibliotheek voor I2C-communicatie#include  // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c (Bibliotheek voor LCD)// Bedrading:SDA-pin is aangesloten op A4 en SCL-pin op A5.// Verbind met LCD via I2C, standaardadres 0x27 (A0-A2 niet doorverbonden) LiquidCrystal_I2C lcd (0x27, 16, 2); // adres, tekens, rijen.// declareren van aangepast symbool voor omhoog/omlaag pijlbyte DownArrow [8] ={B00000, B00100, B00100, B00100, B10101, B01110, B00100, B00000}; byte UpArrow [8] ={ B00000, B00100, B01110, B10101, B00100, B00100, B00100, B00000};// ANTENNE-potentiometers KALIBRATIE int AzMin =1; //begin van de potentiometer int AzMax =1023; // einde van de potentiometer int ElMin =1; int ElMax =1023;// Toegestane fout waarvoor antenne niet beweegt int AzErr =8; int ElErr =4;// Azim-encodervariabelen enum AzPinAssignments { AzEncoderPinA =2, // encoder rechts AzEncoderPinB =3, // encoder links AzClearButton =4}; // encoder push unsigned int lastReportedPos =1; // verandermanagement statisch boolean roteren =false; // debounce management // interrupt service routine vars boolean A_set =false; boolean B_set =onwaar; // Elev-encodervariabelen enum ElPinAssignments {ElEncoderPinA =6, // encoder rechts ElEncoderPinB =5, // encoder links ElClearButton =7}; // encoder push int aStat; int aLastState; // andere variabelen int AzPotPin =A0; // selecteer de invoerpin voor de azim. potentiometer int AzRotPinR =13; // selecteer de uit pin voor draairichting int AzRotPinL =12; int TruAzim =0; // berekende reële azimutwaarde int ComAzim =0; // opgedragen azimutwaarde int OldTruAzim =0; // om de vorige azimutwaarde op te slaan int OldComAzim =0; char AzDir; // symbool voor azim rot display int AzEncBut =1; // variable to toggle with encoder push button 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; } vertraging(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; } vertraging(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;/****************************************************************************/

Schema's

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.

Productieproces

  1. Licht dimmen met PWM met drukknop
  2. Arduino-gyroscoopspel met MPU-6050
  3. DHT11-sensor met LED's en een piëzo-luidspreker
  4. Unopad - Arduino MIDI-controller met Ableton
  5. Iron Man
  6. Eenvoudige obstakelsensor met Arduino
  7. Vind mij
  8. Arduino-luchtbevochtigerbediening
  9. 4x4x4 LED-kubus met Arduino Uno en 1sheeld
  10. Arduino-joystick
  11. Stappenteller (Arduino 101)