Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Contrôleur d'antenne rotatif compatible avec le logiciel de suivi

Composants et fournitures

Arduino UNO
Carte Arduino Uno
× 1
Potentiomètre rotatif (générique)
max. 1Kohm (500 Ohms fonctionnent mieux)
× 2
Encodeur rotatif avec bouton-poussoir
× 2
Planche à pain (générique)
× 1
Module relais (générique)
2 modules x 2 relais NO-Com-NC
× 2
Power MOSFET N-Channel
module d'alimentation mosfet (min 12V/3A)
× 2

Applications et services en ligne

Arduino IDE

À propos de ce projet

Dernière mise à jour novembre 2021

Ce projet a commencé comme un divertissement et est devenu un équipement sérieux.

Le contrôleur accepte le positionnement manuel de l'antenne, au moyen de deux encodeurs rotatifs, Azimut et Elévation. Il peut automatiquement suivre les satellites lorsqu'il est connecté par USB à un PC exécutant un logiciel de suivi des satellites.

Il est compatible avec tous les logiciels de suivi utilisant le protocole EasyComm2 / 9600 bauds. PstRotator, WXtrack, HRD, MacDoppler... Même WXtoIMG peut contrôler le rotateur.

Il fonctionne directement avec Orbitron, avec un plugin DDE de http://tripsintech.com/orbitron-dde-azimuth-elevation-to-serial/

Le contrôleur émet une réponse en série, pour que le logiciel de suivi affiche la position réelle de l'antenne sur l'écran. Jusqu'à présent, seul PstRotator a fait cela.

Le code n'utilise aucune bibliothèque (sauf pour l'écran LCD) et fonctionne exactement tel quel, avec des broches selon le schéma électrique ci-dessous. Si vous appuyez sur le bouton de l'encodeur d'azimut, tout mouvement d'antenne s'arrête immédiatement et la commande d'azimut peut être réglée sur 10 degrés. étapes.

Vous trouverez ici deux versions :une pour les moteurs à courant continu et une pour les moteurs à courant alternatif (uniquement des relais). Le dernier peut être interfacé avec les rotateurs d'antenne commerciaux existants.

La version avec moteurs à courant continu a l'avantage d'utiliser le PWM pour un mouvement d'antenne plus doux/plus fluide. Il délivre une réponse en puissance proportionnelle à l'erreur d'angle (Cible<->Antenne). Ainsi, lorsque l'antenne se met en mouvement, elle accélère progressivement et, en s'approchant de la position souhaitée, elle ralentit jusqu'à l'arrêt complet. Ceci est connu sous le nom de Soft-Start / Soft-Stop . Il y a une zone morte réglable, où l'antenne ne bouge pas pour le moindre décalage de cible.

J'ai une bêta version avec Soft-Start / Soft-Stop pour les moteurs à courant alternatif, profitant de ce module AC-Dimmer, mais pour le moment il ne fonctionne que pour l'azimut. Si vous voulez essayer, faites-le moi savoir par e-mail.

Si vous avez 180 degrés. système d'élévation, vous êtes bon, donnez-moi un e-mail. Il existe également une version avec 0.1deg. précision, mais je ne le recommanderais pas à moins que vous n'ayez une lecture de potentiomètre solide comme un roc et une conception de construction de contrôleur paranoïaque. Vous trouverez plus de versions sur ma page Web.

Après avoir terminé la construction, vous devez appliquer les procédures d'étalonnage .

  • Le calibrage du potentiomètre est obligatoire et assure une lecture correcte de 0-359deg. / 0-90deg., quel que soit le type de potentiomètre que vous utilisez.
  • Le étalonnage du moteur sert uniquement à régler le Soft-Start-Stop caractéristique. Ceci est nécessaire si vous n'aimez pas les paramètres par défaut.

Explications plus détaillées dans les vidéos. Parce que le code a été amélioré au fil du temps et que les vidéos ne peuvent plus être mises à jour, consultez ma page Web pour les dernières informations et l'expérience personnelle de la vie avec ce contrôleur. https://racov.ro/index.php/2020/12/09/arduino-based-antenna-rotator-part3-software-tracking-update/

Envoyez-moi un email si vous voulez en savoir plus, car cette plateforme ne m'informe pas des nouveaux commentaires, je ne sais pas pourquoi. Je vais essayer de résoudre les petits problèmes du mieux que je peux. [email protected]

Merci beaucoup à tous ceux qui m'ont envoyé des commentaires, aidant à rendre ce projet plus fiable. Tout commentaire est très apprécié.

Code

  • ant-rot-DC-nov2021
  • ant-rot-AC-août 2021
  • Procédure d'étalonnage du potentiomètre
  • Procédure d'étalonnage du moteur
ant-rot-DC-nov2021Arduino
Ce code est pour les moteurs à courant continu, avec sortie PWM démarrage-arrêt progressif/* Contrôleur de rotateur d'antenne AZ/EL pour Arduino - moteurs à courant continu * ==========================================================* Utilise le protocole EasyComm pour ordinateur - Logiciel de suivi * Commande manuelle par moyen de deux encodeurs rotatifs AZ - EL * * Viorel Racoviteannu * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https://racov.ro * [email protected] * * Je ne peux prendre aucune responsabilité pour mauvaise utilisation de ce code * ou tout autre type de dommage pouvant résulter de l'utilisation de ce code. * * décembre 2020 v2 - amélioration de la stabilité de la communication série * janvier 2021 - amélioration de la zone morte proche de la cible, pour laquelle l'antenne ne bougera pas * avril 2021 - amélioration de la stabilité de la communication série * juin 2021 - puissance proportionnelle d'erreur pour le suivi du mouvement. Real Soft-Stop * août 2021 - mise à jour USB plus rapide, direction de commutation à froid Az/El, petites optimisations dans le code * nov 2021 - percé le secret du Soft-Start. Ce n'était pas difficile. Voilà */ #include // Bibliothèque pour la communication I2C#include // Bibliothèque pour LCD// Câblage :la broche SDA est connectée à A4 et la broche SCL à A5.// Connectez-vous vers LCD via I2C, adresse par défaut 0x27 (A0-A2 non ponté)LiquidCrystal_I2C lcd (0x27, 16, 2); // adresse, caractères, lignes.// déclaration d'un symbole personnalisé pour l'octet de flèche haut/bas DownArrow[8] ={ B00000, B00100, B00100, B00100, B10101, B01110, B00100, B00000} ; octet Flèche vers le haut[8] ={ B00000, B00100, B01110, B10101, B00100, B00100, B00100, B00000} ;/****************************** ********** C'EST LÀ O VOUS AJUSTEZ VRAIMENT LE MOUVEMENT DE L'ANTENNE****************** /// CALIBRATION des potentiomètres de l'ANTENNE int AzMin =1; //début du potentiomètre int AzMax =1023; //fin du potentiomètre int ElMin =1; int ElMax =1023;// Erreur autorisée pour laquelle l'antenne ne bougera pas int AzErr =8; int ElErr =4;// Différence d'angle où l'arrêt progressif commence int Amax =25; //entier azimut Emax =15; //élévation// puissances min et max pour les moteurs, pourcentages ; int PwAzMin =30 ; //puissance minimale pour laquelle le moteur ne cale pas et démarre en charge int PwAzMax =100; //pleine puissance pour la vitesse la plus rapide int PwElMin =30; int PwElMax =100 ; int PwAz =0 ; //puissance calculée à transmettre au moteur (pourcentages) ; int PwEl =0;/************************************************ ******************************************************** *****/// Encodeur variables enum AzPinAssignments { AzEncoderPinA =2, // Az encodeur droit AzEncoderPinB =3, // encodeur gauche AzClearButton =4, // encodeur push ElEncoderPinA =6, // El encodeur droit ElEncoderPinB =5 } ; // encodeur à gauche // routine de service d'interruption vars unsigned int lastReportedPos =1; // gestion des changements statique booléen rotation =false; // gestion anti-rebond booléen A_set =false; booléen B_set =faux ; int aState; int aLastState; // autres variables int AzPotPin =A0; // sélectionnez la broche d'entrée pour l'azim. potentiomètre int AzRotPin =12 ; // sélection de la broche de sortie pour le sens de rotation int AzPWMPin =11; // sélectionnez la broche de sortie pour la commande PWM d'azimut int TruAzim =0; // valeur d'azimut réelle calculée int ComAzim =0; // valeur d'azimut commandée int OldTruAzim =0; // pour stocker la valeur d'azimut précédente int OldComAzim =0; caractère AzDir; // symbole pour azim rot display int AzEncBut =1; // variable à basculer avec le bouton poussoir de l'encodeur int ElPotPin =A1; // sélectionnez la broche d'entrée pour l'elev. potentiomètre int ElRotPin =13 ; // sélectionnez la broche de sortie pour le sens de rotation d'élévation int ElPWMPin =10; // sélectionnez la broche de sortie pour la commande PWM de rotation d'élévation int TruElev =0; // valeur d'élévation réelle calculée int ComElev =0; // valeur d'élévation commandée int OldTruElev =0; // pour stocker la valeur d'élévation précédente int OldComElev =0; char ElDir; // symbole pour elev. rot display // indicateurs pour les tolérances AZ, EL bool AzStop =false; bool ElStop =faux ; int ElUp =1 ; // 1 - Elévation Dn, 0 - Elevation STOP, 2 - Elevation Up int StaAzim =0; // Start Angle d'azimut pour le moteur Soft-Start int PwAzStop =0; // PWM calculé (pourcentage) pour l'arrêt progressif int PwAzStar =0 ; // PWM calculé (pourcentage) pour le démarrage progressif int StaElev =0 ; // Début Angle d'élévation du moteur Soft-Start int PwElStop =0; // PWM calculé (pourcentage) pour l'arrêt progressif int PwElStar =0 ; // PWM calculé (pourcentage) pour le démarrage progressif // boucle de moyenne const int numReadings =25; int readIndex =0; // l'index de la lecture en cours int azimut[numReadings]; // les lectures de l'entrée analogique int altitude[numReadings] ; int totalAz =0 ; // le total courant int totalEl =0;// les variables pour la communication sérielle String Azimuth =""; Élévation de la chaîne ="" ; Chaîne ComputerRead; Chaîne ComputerWrite; bool AZser =faux ; bool ELser =faux; bool ANTser =false;/****************** END VARIABLE DECLARATION ************/void setup() { Serial.begin(9600); Serial.setTimeout(50); // millisecondes d'attente pour le sata USB. Par défaut 1000// Lancer le LCD://lcd.begin (16,2) ; //sélectionnez celui-ci si les flèches ne s'affichent pas correctement lcd.init(); lcd.backlight();// écriture sur le nom d'affichage et la version lcd.setCursor(0, 0); // Place le curseur sur la première colonne de la première ligne. (le comptage commence à 0 !) lcd.print("EasyCom AntRotor"); // affiche "..." lcd.setCursor(0, 1); // Placer le curseur sur la première colonne la deuxième ligne lcd.print("*Racov* Nov.2021"); // création d'un symbole personnalisé pour la flèche haut/bas lcd.createChar(1, DownArrow); lcd.createChar(2, UpArrow); // déclaration de broche pinMode(AzRotPin, OUTPUT); //déclarer l'azim. sens de rotation Pin comme OUTPUT pinMode (AzPWMPin, OUTPUT); //déclarer la broche de commande PWM d'azimut comme OUTPUT pinMode (ElRotPin, OUTPUT); //déclarant elev. sens de rotation Pin comme 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); // Broche AzEncoder sur interruption 0 (broche A) attachInterrupt (0, doEncoderA, CHANGE); // Broche AzEncoder sur interruption 1 (broche B) attachInterrupt (1, doEncoderB, CHANGE); // Lit l'état initial du ElEncoderPinA aLastState =digitalRead(ElEncoderPinA);/* initialisation de la boucle de moyennage */ TruAzim =(map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); // valeur d'azimut 0-359 if (TruAzim<0) {TruAzim=0;} if (TruAzim>359) {TruAzim=359;} // garde les valeurs entre les limites TruElev =(map(analogRead(ElPotPin), ElMin, ElMax , 0, 90)); // elev valeur 0-90 if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev=90;} // garde les valeurs entre les limites pour (int thisReading =0; thisReading 359) {TruAzim=359;} if (TruElev<0) {TruElev=0;} if (TruElev>90) {TruElev =90;} // avance à la position suivante dans le tableau :readIndex =readIndex + 1; // si nous sommes à la fin du tableau, retournez au début :if (readIndex>=numReadings) {readIndex =0;} // il s'agit de lire la commande de l'encodeur ReadAzimEncoder(); ReadElevEncoder(); if (Serial.available()) {SerComm();} // lecture des données USB// mise à jour de l'affichage de la position de l'antenne uniquement si la valeur change if ((millis()%500)<10){ //pour ne pas faire clignoter l'affichage si (VieuxTruAzim!=TruAzim) { DisplAzim(TruAzim,4,0); OldTruAzim =TruAzim; } if (OldTruElev!=TruElev) { DisplElev(TruElev,5,1) ; OldTruElev =TrueElev; } }// mettre à jour l'affichage de la position cible uniquement si la valeur change if (OldComAzim !=ComAzim) { DisplAzim(ComAzim,12,0) ; OldComAzim =ComAzim ; } if (OldComElev !=ComElev) { DisplElev(ComElev,13,1) ; OldComElev =ComElev; }// c'est pour tourner en azimut if (TruAzim ==ComAzim) { // si égal, arrêter de bouger AzStop =true; analogWrite(AzPWMPin, 0); // Puissance moteur Az =0 StaAzim =TruAzim; // ce sera l'azimut de démarrage pour le démarrage progressif lcd.setCursor(8, 0); lcd.print("="); } else if ((abs(TruAzim - ComAzim)<=AzErr)&&(AzStop ==false)) { // si dans la tolérance, mais ce n'était pas égal, faites pivoter AzimRotate();} else if (abs(TruAzim - ComAzim)>AzErr){ // si la cible est hors tolérance AzStop =false; // ce n'est pas égal à AzimRotate(); // faire pivoter }// il s'agit de faire pivoter en élévation if (TruElev ==ComElev) { // si égal, arrêter de bouger ElStop =true; analogWrite(ElPWMPin, 0); // El puissance moteur =0 StaElev =TruElev; // ce sera l'élévation de départ pour le démarrage progressif lcd.setCursor(8, 1); lcd.print("="); ElUp =0 ; // indicateur pour l'élévation STOP } else if ((abs(TruElev - ComElev)<=ElErr)&&(ElStop ==false)) { // si dans la tolérance, mais ce n'était pas égal, faites pivoter ElevRotate();} else if (abs(TruElev - ComElev)>ElErr){ // si la cible est hors tolérance ElStop =false ; // ce n'est pas égal à ElevRotate(); // rotation } // il s'agit d'interpréter la multiplication x10 de l'encodeur Az while (AzEncBut ==10) { // lors du basculement sur x10 analogWrite(AzPWMPin, 0); // ARRÊTER la rotation de l'antenne StaAzim =TruAzim; // ce sera l'azimut de démarrage pour le démarrage progressif analogWrite(ElPWMPin, 0); lcd.setCursor(8, 0); lcd.print("*"); ReadAzimEncoder(); if (OldComAzim !=ComAzim){ // mettre à jour l'affichage uniquement si les nombres changent DisplAzim(ComAzim, 12, 0); OldComAzim =ComAzim ; } retard (100); }}// fin de la BOUCLE principale//________________________________________________________// ___________définitions des procédures__________________void DisplAzim(int x, int y, int z) { char displayString[7] =""; sprintf(displayString, "%03d", x); //sort un nombre de longueur fixe (3 entiers) lcd.setCursor(y, z); // pour aucun zéro non significatif "__7" utilisez "%3d" lcd.print(displayString); // ************** À DES FINS DE CALIBRAGE **************// Serial.print ("Az "); // Serial.println ( analogRead(AzPotPin));}void DisplElev(int x, int y, int z){ char displayString[7] =""; sprintf(displayString, "%02d", x); //sort un nombre de longueur fixe (2 entiers) lcd.setCursor(y, z); // pour aucun zéro non significatif "_7" utilisez "%2d" lcd.print(displayString); // ************** À DES FINS DE CALIBRAGE ********** ****// Serial.print ("El "); // Serial.println (analogRead(ElPotPin));}void ReadElevEncoder() { aState =digitalRead(ElEncoderPinA); // Lit l'état "actuel" de l'ElEncoderPinA // Si l'état précédent et l'état actuel de l'ElEncoderPinA sont différents, cela signifie qu'une impulsion s'est produite si (aState !=aLastState){ // Si l'état ElEncoderPinB est différent de État ElEncoderPinA, cela signifie que l'encodeur tourne dans le sens des aiguilles d'une montre if (digitalRead(ElEncoderPinB) !=aState) { ComElev ++;} else { ComElev --;} if (ComElev <0) {ComElev =0;} if (ComElev>90 ) {ComElev =90;} } aLastState =aState; // Met à jour l'état précédent de ElEncoderPinA avec l'état actuel}void ReadAzimEncoder() { rotation =true; // réinitialiser le debouncer if (lastReportedPos !=ComAzim) { lastReportedPos =ComAzim; } délai(10) ; if (digitalRead(AzClearButton) ==LOW ) { // si le commutateur d'encodeur est enfoncé delay (250); // anti-rebond du commutateur if (AzEncBut ==1){ AzEncBut =10; ComAzim =entier(ComAzim/10)*10 ; // ComAzim en 10deg. étapes } else { AzEncBut =1; } }} //fin de ReadAzimEncoder()// Interruption sur un changement d'état doEncoderA() { // anti-rebond si (rotation) délai (1) ; // attendez un peu que le rebond soit terminé // Testez la transition, les choses ont-elles vraiment changé ? if ( digitalRead(AzEncoderPinA) !=A_set ) { // anti-rebond A_set =!A_set; // ajuste le compteur + si A mène B if ( A_set &&!B_set ) ComAzim +=AzEncBut; ComAzim =((ComAzim + 360) % 360); // encoderPos entre 0 et 359 deg. rotation =faux ; // plus d'anti-rebond jusqu'à ce que loop() frappe à nouveau }}// Interruption sur B changeant d'état, comme A ci-dessusvoid doEncoderB() { if (rotation) delay (1); if ( digitalRead(AzEncoderPinB) !=B_set ) { B_set =!B_set; // ajuste le compteur - 1 si B mène A if ( B_set &&!A_set ) ComAzim -=AzEncBut; ComAzim =((ComAzim + 360) % 360); // encoderPos entre 0 et 359 deg. rotation =faux ; } } void AzimRotate() { if (ComAzim> TruAzim) { // ceci pour déterminer le sens de rotation// commutation à froid - arrêter le moteur avant de changer de direction - pour protéger les pièces mécaniques et électriques if (AzDir ==char(127)) { // si précédemment tourné dans le sens opposé analogWrite(AzPWMPin, 0); // ARRÊTER le moteur StaAzim =TruAzim; // ce sera l'azimut de démarrage pour le délai de démarrage progressif (200); // délai de pré-commutation digitalWrite(AzRotPin, LOW); // désactiver la broche de rotation - rotation à droite délai (200); // délai post-commutation } else { // même direction, pas d'arrêt, pas de délai digitalWrite(AzRotPin, LOW); // désactiver la broche de rotation - tourner à droite } AzDir =char(126); // "->" } else { if (AzDir ==char(126)) { // si précédemment tourné dans le sens opposé analogWrite(AzPWMPin, 0); // ARRÊTER le moteur StaAzim =TruAzim; // ce sera l'azimut de démarrage pour le délai de démarrage progressif (200); // délai de pré-commutation digitalWrite(AzRotPin, HIGH); // activer la broche de rotation - faire pivoter le délai à gauche (200); // délai post-commutation } else { // même direction, pas d'arrêt, pas de délai digitalWrite(AzRotPin, HIGH); // activer la broche de rotation - tourner à gauche } AzDir =char(127); // "<-" } lcd.setCursor(8, 0); lcd.print(String(AzDir)); // cela active la broche azim PWM proportionnelle avec erreur d'angle (calculée en pourcentages %) PwAzStop =PwAzMin + round((abs(ComAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); //formule qui produit une puissance proportionnelle avec différence d'angle pour Soft-Stop PwAzStar =PwAzMin + round((abs(StaAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); //formule qui génère une puissance proportionnelle avec différence d'angle pour Soft-Start if (PwAzStar> PwAzStop){ PwAz =PwAzStop; //choisissez la valeur la plus petite } else {PwAz =PwAzStar;} if (PwAz> PwAzMax) {PwAz =PwAzMax;} analogWrite(AzPWMPin, round(2.55*PwAz)); // activer la broche PWM du lecteur Azim }// fin AzimRotate() void ElevRotate() {// ceci pour déterminer le sens de rotation if (ComElev> TruElev) { if (ElUp ==1) { // si précédemment tourné dans le sens opposé direction analogWrite(ElPWMPin, 0); // ARRÊTER le moteur StaElev =TruElev; // ce sera l'élévation de départ pour le délai de démarrage progressif (200); // délai de pré-commutation digitalWrite(ElRotPin, LOW); // désactiver la broche de rotation - faire pivoter le délai vers le haut (200); // délai post-commutation } else { // même direction, pas d'arrêt, pas de délai digitalWrite(ElRotPin, LOW); // désactiver la goupille de rotation - tourner vers le HAUT } lcd.setCursor(8, 1); lcd.write(2); // flèche vers le haut ElUp =2; // indicateur pour l'élévation UP } else { if (ElUp ==2) { // si précédemment tourné dans le sens opposé analogWrite(ElPWMPin, 0); // ARRÊTER le moteur StaElev =TruElev; // ce sera l'élévation de départ pour le délai de démarrage progressif (200); // délai de pré-commutation digitalWrite(ElRotPin, HIGH); // désactiver la broche de rotation - faire pivoter le délai vers le haut (200); // délai post-commutation } else { // même direction, pas d'arrêt, pas de délai digitalWrite(ElRotPin, HIGH); // désactiver la goupille de rotation - tourner vers le HAUT } lcd.setCursor(8, 1); lcd.write(1); // flèche vers le bas ElUp =1; // indicateur pour l'élévation DN } // ceci active la broche azim PWM proportionnelle à l'erreur d'angle (calculée en pourcentages %) PwElStop =PwElMin + round((abs(ComElev-TruElev))*(PwElMax-PwElMin)/Emax); //formule qui délivre une puissance proportionnelle à la différence d'angle pour Soft-Stop PwElStar =PwElMin + round((abs(StaElev-TruElev))*(PwElMax-PwElMin)/Emax); //formule qui génère une puissance proportionnelle à la différence d'angle pour Soft-Start if (PwElStar> PwElStop){ PwEl =PwElStop; //choisissez la valeur la plus petite } else {PwEl =PwElStar;} if (PwEl> PwElMax) {PwEl =PwElMax;} analogWrite(ElPWMPin, round(2.55*PwEl)); // active la broche PWM du lecteur Elev}// end ElevRotate() void SerComm() { // initialise les lectures ComputerRead =""; Azimut ="" ; Élévation ="" ; while(Serial.available()) { ComputerRead=Serial.readString(); // lit les données entrantes sous forme de chaîne // Serial.println(ComputerRead); // renvoie la réception à des fins de test } // recherche de la commande pour (int i =0; i <=ComputerRead.length(); i++) { if ((ComputerRead.charAt(i) ==' A')&&(ComputerRead.charAt(i+1) =='Z')){ // si lu AZ pour (int j =i+2; j <=ComputerRead.length(); j++) { if (isDigit (ComputerRead.charAt(j))) { // si le caractère est un nombre Azimut =Azimut + ComputerRead.charAt(j); } else {break;} } } } // recherche de la commande pour (int i =0; i <=(ComputerRead.length()-2); i++) { if ((ComputerRead.charAt(i ) =='E')&&(ComputerRead.charAt(i+1) =='L')){ // si lu EL if ((ComputerRead.charAt(i+2)) =='-') { ComElev =0 ; // si coupure d'altitude négative ; } for (int j =i+2; j <=ComputerRead.length(); j++) { if (isDigit(ComputerRead.charAt(j))) { // si le caractère est un nombre Elevation =Elevation + ComputerRead.charAt( j); } else {break;} } } } // si reçu if (Azimut !=""){ ComAzim =Azimuth.toInt(); ComAzim =ComAzim%360 ; // conserver les valeurs entre les limites (pour les trackers avec une rotation de plus de 360 ​​degrés) }// si reçu if (Elevation !=""){ ComElev =Elevation.toInt(); if (ComElev>180) { ComElev =0;} if (ComElev>90) { //si reçu plus de 90deg. (pour les trackers avec une élévation de 180 degrés) ComElev =180-ComElev ; //rester en dessous de 90deg. ComAzim =(ComAzim+180)%360 ; //et faites pivoter l'antenne à l'arrière } }// à la recherche de l'interrogation pour la position de l'antenne pour (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')){ // renvoie la position de l'antenne <+xxx.x xx.x> ComputerWrite ="+"+String(TruAzim)+".0 "+String(TruElev)+". 0" ; Serial.println(ComputerWrite); } }}// fin SerComm()
ant-rot-AC-août2021Arduino
Assurez-vous d'utiliser le schéma électrique pour les moteurs à courant alternatif
Offre des contacts secs (ON/OFF). Il peut être facilement interfacé avec des rotateurs commerciaux./* Contrôleur de rotateur d'antenne AZ/EL pour Arduino - moteurs à courant alternatif ================================* Utilise le protocole EasyComm pour ordinateur - Logiciel de suivi * Commande manuelle au moyen de deux encodeurs rotatifs AZ - EL * * compatible avec les rotateurs de coffret électrique * ou les moteurs à courant alternatif * contacts secs pour gauche-droite, haut-bas * * Viorel Racoviteannu / * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA * https ://racov.ro * [email protected] * * Je ne peux assumer aucune responsabilité en cas d'utilisation abusive de ce code * ou de tout type de dommage pouvant résulter de l'utilisation de ce code. * * décembre 2020 v2 - amélioration de la stabilité de la communication série * janvier 2021 - tolérances AZ, EL fixes pour l'activation du moteur * avril 2021 - amélioration de la stabilité de la communication série * août 2021 - mise à jour USB plus rapide, commutation à froid direction Az/El, petites optimisations dans le code */ #include // Bibliothèque pour la communication I2C#include // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c (Bibliothèque pour LCD)// Câblage : la broche SDA est connectée à A4 et la broche SCL à A5.// Connectez-vous à l'écran LCD via I2C, adresse par défaut 0x27 (A0-A2 non ponté)LiquidCrystal_I2C lcd (0x27, 16, 2); // adresse, caractères, lignes.// déclaration d'un symbole personnalisé pour l'octet de flèche haut/bas DownArrow[8] ={ B00000, B00100, B00100, B00100, B10101, B01110, B00100, B00000} ; octet Flèche vers le haut[8] ={ B00000, B00100, B01110, B10101, B00100, B00100, B00100, B00000} ;// CALIBRATION des potentiomètres ANTENNE int AzMin =1 ; //début du potentiomètre int AzMax =1023; //fin du potentiomètre int ElMin =1; int ElMax =1023;// Erreur autorisée pour laquelle l'antenne ne bougera pas int AzErr =8; int ElErr =4;// variables d'encodeur Azim enum AzPinAssignments { AzEncoderPinA =2, // encodeur droit AzEncoderPinB =3, // encodeur gauche AzClearButton =4}; // encodeur push unsigned int lastReportedPos =1; // gestion des modifications statique booléen rotation =false; // gestion anti-rebond // routine de service d'interruption vars boolean A_set =false; booléen B_set =faux ; //Elev encodeur variables enum ElPinAssignments{ ElEncoderPinA =6, // encodeur droit ElEncoderPinB =5, // encodeur gauche ElClearButton =7} ; // encodeur push int aState; int aLastState; // autres variables int AzPotPin =A0; // sélectionnez la broche d'entrée pour l'azim. potentiomètre int AzRotPinR =13; // sélection de la broche de sortie pour le sens de rotation int AzRotPinL =12; int TruAzim =0 ; // valeur d'azimut réelle calculée int ComAzim =0; // valeur d'azimut commandée int OldTruAzim =0; // pour stocker la valeur d'azimut précédente int OldComAzim =0; caractère AzDir; // symbole pour azim rot display int AzEncBut =1; // variable à basculer avec le bouton poussoir de l'encodeur 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; } délai(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;/****************************************************************************/

Schémas

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.

Processus de fabrication

  1. Variation des lumières avec PWM à l'aide du bouton-poussoir
  2. Jeu de gyroscope Arduino avec MPU-6050
  3. Capteur DHT11 avec LED et haut-parleur piézo
  4. Unopad - Contrôleur MIDI Arduino avec Ableton
  5. Iron Man
  6. Capteur d'obstacles simple avec Arduino
  7. Trouvez-moi
  8. Contrôle de l'humidificateur Arduino
  9. cube LED 4x4x4 avec Arduino Uno et 1sheeld