Components and supplies
Rotary Encoder with Push-Button
Relay Module (Generic)
Breadboard (generic)
Rotary potentiometer (generic)
Arduino UNO
Power MOSFET N-Channel
Apps and platforms
Arduino IDE
Project description
Code
Potentiometer calibration procedure
arduino
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 :)
1AZ / EL Potentiometers limit calibration PROCEDURE ( 0-359ᴼ / 0-90ᴼ) 2 31. Open the code in Arduino and 4- Look for: 5 6// ************** FOR CALIBRATION PURPOSES ************** 7/* 8 Serial.print ("Az "); 9 Serial.println (analogRead(AzPotPin)); 10 Serial.print ("El "); 11 Serial.println (analogRead(ElPotPin)); 12*/ 13 14- Eliminate the simbols /* and */ 15- The text above should turn from gray into black and coloured. 16 17 182. Upload the code and open the serial monitor. There you will see a lot of numbers; 19 203. With the help of the encoders, move the antenna to minimum values, 0ᴼ in azimuth and 0ᴼ in elevation. 21- Write down the values for Azimuth and Elevation. (in my case it was AzMin=90, ElMin=10) 22- These are the input values read by Arduino, not the real angles; 23 244. Move the antenna again to maximum values, 359ᴼ in azimuth and 90ᴼ in elevation. 25- Again, write down the values for Azimuth and Elevation. (in my case it was AzMax=1000, ElMax=992); 26 275. Look in the code, at the beginning, for the section 28 29// ANTENNA potentiometers CALIBRATION 30 int AzMin = 1; 31 int AzMax = 1023; 32 int ElMin = 1; 33 int ElMax = 1023; 34 35- Here input the values you wrote down earlier, like 36 int AzMin = 90; 37 int AzMax = 1000; 38 int ElMin = 10; 39 int ElMax = 992; 40 416. Now it is no longer necessary to send this on serial, so you have to comment back these lines, like this: 42/* 43 Serial.print ("Az "); 44 Serial.println (analogRead(AzPotPin)); 45 Serial.print ("El "); 46 Serial.println (analogRead(ElPotPin)); 47*/ 48- The text above should turn gray 49 507. Upload again the code. 51 52That's all. Now, in the serial monitor, there should be no more numbers.
Motor calibration procedure
arduino
This procedure sets the parameters for the Antenna Speed-Up / Slow-Down Zone. This is plain text, not a code :)
1Motor Calibration Procedure For Soft-Start / Soft-Stop feature. 2This procedure sets the parameters for the Antenna Speed-Up / Slow-Down and the Dead-Zone. 3You 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. 4It’s not strictly necessary, only if you don’t like the default settings. 5Make sure you first apply the Potentiometer Calibration Procedure !!! That one is strictly necessary. 6Look at the power diagram for a better understanding. 7 8***For Azimuth movement*** 9-As the antenna starts to move towards the target, is picking up speed, reaching full power after <Amax> degrees difference. 10-As the antenna closes in to the target, below <Amax> degrees difference, it starts to slow down. <Amax> should be higher for heavier antennas. 11-The power starts to decrease from <PwAzMax> to <PwAzMin> until the angle difference becomes zero. 12 <PwAzMax> (in percents %) should be 100 for full speed. If you ever think your antenna rotates too fast, you can set a smaller <PwAzMax>. 13 <PwAzMin> (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. 14-Once the antenna reaches the target position (zero degrees error), it stops and doesn’t move again until the target travels more than <AzErr> degrees. 15 This is a dead zone, to prevent continuously shaking the antenna for the smallest target movement, or potentiometer position jitter. 16 The smaller the <AzErr>, the more precise tracking, the more frequent shacking of the motors. 17 18***For Elevation movement*** 19Exactly as for the Azimuth. 20 21Look at the beginning of the code for this section. Here you can input your desired values. 22 23/**************THIS IS WHERE YOU REALY TWEAK THE ANTENNA MOVEMENT************/ 24... 25 26// Allowed error for which antennna won't move. 27 int AzErr = 8; 28 int ElErr = 4; 29 30// Angle difference where soft stop begins 31 int Amax = 25; //azimuth 32 int Emax = 15; //elevation 33 34// min and max power for motors, percents; 35 int PwAzMin = 30; //minimum power for which the motor doesn't stall and starts under load 36 int PwAzMax = 100; //full power for the fastest speed 37 int PwElMin = 30; 38 int PwElMax = 100; 39/****************************************************************************/
ant-rot-DC-aug2022
arduino
This code is for DC motors, with soft start/stop PWM output. Use electric diagram for DC motors.
1/* AZ/EL Antenna Rotator controller for Arduino - DC motors - PWM output 2 * ===================================================================== 3 * Uses EasyComm protocol for computer - Tracking Software 4 * Manual command by means of two rotary encoders AZ - EL 5 * 6 * Viorel Racoviteannu 7 * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA 8 * https://racov.ro 9 * YO3RAK@gmail.com 10 * 11 * I cannot take any responsibility for missuse of this code 12 * or any kind of damage it may occur from using this code. 13 * 14 * dec 2020 v2 - improved serial comm stability 15 * jan 2021 - improved near target dead-zone, for which antenna won't move 16 * apr 2021 - improved serial comm stability 17 * jun 2021 - error proportional power for tracking movement. Real Soft-Stop 18 * aug 2021 - faster USB update, cold switching Az/El direction, small optimizations in the code 19 * nov 2021 - cracked the secret of Soft-Start. It wasn't hard. There you have it 20 * aug 2022 - improved EL encoder functionality, electric diagram modified - encoders connections 21 */ 22 23#include <Wire.h> // Library for I2C communication 24#include <LiquidCrystal_I2C.h> // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c (Library for LCD) 25// Wiring: SDA pin is connected to A4 and SCL pin to A5. 26// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered) 27LiquidCrystal_I2C lcd(0x27, 16, 2); // address, chars, rows. 28 29// declaring custom symbol for up/down arrow 30 byte DownArrow[8] = { 31 B00000, 32 B00100, 33 B00100, 34 B00100, 35 B10101, 36 B01110, 37 B00100, 38 B00000 39}; 40 byte UpArrow[8] = { 41 B00000, 42 B00100, 43 B01110, 44 B10101, 45 B00100, 46 B00100, 47 B00100, 48 B00000 49}; 50 51/***********************************THIS IS WHERE YOU REALY TWEAK THE ANTENNA MOVEMENT***************/ 52// ANTENNA potentiometers CALIBRATION 53 int AzMin = 1; //begining of the potentiometer 54 int AzMax = 1023; //end of the potentiometer 55 int ElMin = 1; 56 int ElMax = 1023; 57 58// Allowed error for which antennna won't move 59 int AzErr = 8; 60 int ElErr = 4; 61 62// Angle difference where soft stop begins 63 int Amax = 25; //azimuth 64 int Emax = 15; //elevation 65 66// min and max power for motors, percents; 67 int PwAzMin = 30; //minimum power for which the motor doesn't stall and starts under load 68 int PwAzMax = 100; //full power for the fastest speed 69 int PwElMin = 30; 70 int PwElMax = 100; 71 72/***************************************************************************************************/ 73 74 enum PinAssignments { 75 AzPotPin = A0, // input pin for the azim. potentiometer 76 ElPotPin = A1, // input pin for the elev. potentiometer 77 AzEncoderPinA = 2, // Az encoder right 78 AzEncoderPinB = 4, // Az encoder left 79 AzClearButton = 5, // Az encoder push 80 ElEncoderPinA = 3, // El encoder right 81 ElEncoderPinB = 6, // El encoder left 82 ElClearButton = 7, // El encoder push 83 ElPWMPin = 9, // out pin for elevation rotation PWM command 84 AzPWMPin = 10, // out pin for azimuth PWM command 85 AzRotPin = 11, // out pin for Az rotation direction 86 ElRotPin = 12, // out pin for El rotation direction 87 }; 88 89// Az encoder variables 90 int AzEncBut = 1; // variable to toggle with encoder push button 91 volatile boolean AzEncRot; // if rotation occured 92 volatile boolean AzEncUp; // direction of rotation 93 94// El encoder variables 95 int ElEncBut = 1; 96 volatile boolean ElEncRot; 97 volatile boolean ElEncUp; 98 99// movement variables 100 int TruAzim = 0; // calculated real azimuth value 101 int ComAzim = 0; // commanded azimuth value 102 int TruElev = 0; // calculated real elevation value 103 int ComElev = 0; // commanded elevation value 104 int OldTruAzim = 0; // to store previous azimuth value 105 int OldComAzim = 0; 106 int OldTruElev = 0; // to store previous elevation value 107 int OldComElev = 0; 108 int StaAzim = 0; // Start Azimuth angle for motor Soft-Start 109 int StaElev = 0; // Start Elevation angle for motor Soft-Start 110 int PwAzStop = 0; // calculated PWM (percent) for soft-stop 111 int PwAzStar = 0; // calculated PWM (percent) for soft-start 112 int PwElStop = 0; // calculated PWM (percent) for soft-stop 113 int PwElStar = 0; // calculated PWM (percent) for soft-start 114 int PwAz = 0; //calculated power to be transmitted to motor (percents); 115 int PwEl = 0; 116 char AzDir; // symbol for azim rot display 117 char ElDir; // symbol for elev. rot display 118 unsigned long NowTime; // store the current millis() for timing purposes 119 120// flags for AZ, EL tolerances 121 bool AzStop = false; 122 bool ElStop = false; 123 int ElUp = 1; // 1 - Elevation Dn, 0 - Elevation STOP, 2 - Elevation Up 124 125//averaging loop 126 const int numReadings = 25; 127 int readIndex = 0; // the index of the current reading 128 int azimuth[numReadings]; // the readings from the analog input 129 int elevation[numReadings]; 130 int totalAz = 0; // the running total 131 int totalEl = 0; 132 133// variables for serial comm 134 String Azimuth = ""; 135 String Elevation = ""; 136 String ComputerRead; 137 String ComputerWrite; 138 bool AZser = false; 139 bool ELser = false; 140 bool ANTser = false; 141 142/*************** END VARIABLE DECLARATION ************/ 143 144void setup() { 145 Serial.begin(9600); 146 Serial.setTimeout(50); // miliseconds to wait for USB sata. Default 1000 147// Initiate the LCD: 148// lcd.begin(16,2); //select this one if the arrows are not displayed correctly 149 lcd.init(); 150 lcd.backlight(); 151 152// write on display name and version 153 lcd.setCursor(0, 0); // Set the cursor on the first column first row.(counting starts at 0!) 154 lcd.print("EasyCom AntRotor"); // display "..." 155 lcd.setCursor(0, 1); // Set the cursor on the first column the second row 156 lcd.print("*Racov* Aug.2022"); 157 158//creating custom symbol for up/dwn arrow 159 lcd.createChar(1, DownArrow); 160 lcd.createChar(2, UpArrow); 161 162// pin declaration 163 pinMode(AzRotPin, OUTPUT); //declaring azim. rotation direction Pin as OUTPUT 164 pinMode(AzPWMPin, OUTPUT); //declaring azimuth PWM command Pin as OUTPUT 165 pinMode(ElRotPin, OUTPUT); //declaring elev. rotation direction Pin as OUTPUT 166 pinMode(ElPWMPin, OUTPUT); 167 pinMode(AzPotPin, INPUT); 168 pinMode(ElPotPin, INPUT); 169 pinMode(AzEncoderPinA, INPUT); 170 pinMode(AzEncoderPinB, INPUT); 171 pinMode(AzClearButton, INPUT); 172 pinMode(ElEncoderPinA, INPUT); 173 pinMode(ElEncoderPinB, INPUT); 174 175// Interrupt Service Routine for Az and El encoder 176 attachInterrupt(0, doAzEnc, CHANGE); // Az encoder 177 attachInterrupt(1, doElEnc, CHANGE); // El Encoder 178 179/* initialization of the averaging loop 180 this is to set Az/El-command the same value as real, not to jerk the antenna at start-up */ 181 TruAzim = (map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); // transforms potentiometer voltage into azimuth angle 182 TruElev = (map(analogRead(ElPotPin), ElMin, ElMax, 0, 90)); // transforms potentiometer voltage into elevation angle 183 184 for (int thisReading = 0; thisReading < numReadings; thisReading++) { 185 azimuth[thisReading] = TruAzim; 186 elevation[thisReading] = TruElev; 187 } 188 totalAz = TruAzim * numReadings; 189 totalEl = TruElev * numReadings; 190 191/* keep command values in range */ 192 ComAzim = constrain(TruAzim, 0, 359); 193 ComElev = constrain(TruElev, 0, 90); 194 OldTruAzim = TruAzim; 195 OldComAzim = ComAzim; 196 OldTruElev = TruElev; 197 OldComElev = TruElev; 198 199 delay(1500); // keep for 1.5 seconds 200// display Azim. and Elev. values 201 lcd.setCursor(0, 0); 202 lcd.print("Azm.---" + String(char(223)) + "=Cd.---" + String(char(223))); // char(223) is degree symbol 203 lcd.setCursor(0, 1); 204 lcd.print("Elv. --" + String(char(223)) + "=Cd. --" + String(char(223))); 205 DisplValue(TruAzim, 4,0); 206 DisplValue(ComAzim,12,0); 207 DisplValue(TruElev, 4,1); 208 DisplValue(ComElev,12,1); 209} 210// end SETUP 211 212void loop() { 213/************** FYI, this loop repeats 500 times per second !!! **************/ 214// AZIMUTH/ELEVATION AVERAGING LOOP 215 // subtract the oldest value 216 totalAz = totalAz - azimuth[readIndex]; 217 totalEl = totalEl - elevation[readIndex]; 218 // read from the sensor: 219 azimuth[readIndex] = (map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); 220 elevation[readIndex] = (map(analogRead(ElPotPin), ElMin, ElMax, 0, 90)); 221 // add the reading to the total: 222 totalAz = totalAz + azimuth[readIndex]; 223 totalEl = totalEl + elevation[readIndex]; 224 // do the average 225 TruAzim = totalAz / numReadings; 226 TruElev = totalEl / numReadings; 227/* keep values in range 228 TruAzim = constrain(TruAzim, 0, 359); 229 TruElev = constrain(TruElev, 0, 90); */ 230 // advance to the next position in the array 231 // if we're at the end of the array, wrap around to the beginning: 232 readIndex = (readIndex + 1) % numReadings; 233 234// read the command from encoder 235 ReadAzimEncoder(); 236 ReadElevEncoder(); 237 238 if (Serial.available()) {SerComm();} // read USB data 239 240// update antenna position display only if value change 241 if ((millis() - NowTime) > 300){ //every 0.3 seconds, not to flicker the display 242 if (OldTruAzim!=TruAzim) { 243 DisplValue(TruAzim,4,0); 244 OldTruAzim = TruAzim; 245 } 246 if (OldTruElev!=TruElev) { 247 DisplValue(TruElev,4,1); 248 OldTruElev = TruElev; 249 } 250 NowTime = millis(); 251 } 252 253// update target position display only if value change 254 if (OldComAzim != ComAzim) { 255 DisplValue(ComAzim,12,0); 256 OldComAzim = ComAzim; 257 } 258 if (OldComElev != ComElev) { 259 DisplValue(ComElev,12,1); 260 OldComElev = ComElev; 261 } 262 263// this is to rotate in azimuth 264 if (TruAzim == ComAzim) { // if equal, stop moving 265 AzStop = true; 266 analogWrite(AzPWMPin, 0); // Az motor power = 0 267 StaAzim = TruAzim; // this will be the start azimuth for soft-start 268 lcd.setCursor(8, 0); 269 lcd.print("="); 270 } 271 else if ((abs(TruAzim - ComAzim)<=AzErr)&&(AzStop == false)) { // if in tolerance, but it wasn't an equal, rotate 272 AzimRotate();} 273 else if (abs(TruAzim - ComAzim)>AzErr){ // if target is off tolerance 274 AzStop = false; // it's not equal 275 AzimRotate(); // rotate 276 } 277 278// this is to rotate in elevation 279 if (TruElev == ComElev) { // if equal, stop moving 280 ElStop = true; 281 analogWrite(ElPWMPin, 0); // El motor power = 0 282 StaElev = TruElev; // this will be the start elevation for soft-start 283 lcd.setCursor(8, 1); 284 lcd.print("="); 285 ElUp = 0; // flag for elevation STOP 286 } 287 else if ((abs(TruElev - ComElev)<=ElErr)&&(ElStop == false)) { // if in tolerance, but it wasn't an equal, rotate 288 ElevRotate();} 289 else if (abs(TruElev - ComElev)>ElErr){ // if target is off tolerance 290 ElStop = false; // it's not equal 291 ElevRotate(); // rotate 292 } 293 294 // this is to interpret Az encoder x10 multiplication 295 while (AzEncBut == 10) { // while toggled to x10 296 analogWrite(AzPWMPin, 0); // STOP antenna rotation 297 StaAzim = TruAzim; // this will be the start azimuth for soft-start 298 analogWrite(ElPWMPin, 0); 299 lcd.setCursor(8, 0); 300 lcd.print("*"); 301 ReadAzimEncoder(); 302 if (OldComAzim != ComAzim){ // update display only if numbers change 303 DisplValue(ComAzim, 12, 0); 304 OldComAzim = ComAzim; 305 } 306 delay (100); 307 } 308} // end main LOOP 309 310//____________________________________________________ 311// ___________procedures definitions__________________ 312 313void DisplValue(int x, int y, int z) { 314 char displayString[7] = ""; 315 sprintf(displayString, "%3d", x); // outputs a fixed lenght number (3 integer) 316 lcd.setCursor(y, z); // for leading zeros '007' use "%03d" 317 lcd.print(displayString); 318 319// ************** FOR CALIBRATION PURPOSES ************** 320/* 321 Serial.print ("Az "); 322 Serial.println (analogRead(AzPotPin)); 323 Serial.print ("El "); 324 Serial.println (analogRead(ElPotPin)); 325*/ 326} // end DisplValue() 327 328void ReadAzimEncoder() { 329 if (digitalRead(AzClearButton) == LOW ) { // if encoder switch depressed 330 delay (250); // debounce switch 331 lcd.setCursor(0, 0); // refresh all the writings on the screen 332 lcd.print("Azm.---" + String(char(223)) + "=Cd.---" + String(char(223))); 333 lcd.setCursor(0, 1); 334 lcd.print("Elv. --" + String(char(223)) + "=Cd. --" + String(char(223))); 335 DisplValue(TruAzim, 4,0); 336 DisplValue(ComAzim,12,0); 337 DisplValue(TruElev, 4,1); 338 DisplValue(ComElev,12,1); 339 if (AzEncBut == 1){ 340 AzEncBut = 10; // increment by 10 degrees 341 ComAzim = int(ComAzim/10)*10; // ComAzim in 10deg. steps 342 } 343 else 344 AzEncBut = 1; 345 } 346 347 if (AzEncRot){ 348 delay(20); // debouncing 349 if (AzEncUp) 350 ComAzim += AzEncBut; 351 else 352 ComAzim -= AzEncBut; 353 ComAzim = ((ComAzim + 360) % 360); // Az Cmd between 0 and 359 deg continuous 354 AzEncRot = false; 355 } 356} //end ReadAzimEncoder() 357 358void ReadElevEncoder() { 359 if (digitalRead(ElClearButton) == LOW ) { // set Park Position Command Az/El 360 delay(250); // debounce switch 361 ComAzim = 260; 362 ComElev = 0; 363 } 364 365 if (ElEncRot){ 366 delay(20); // debouncing 367 if (ElEncUp) 368 ComElev ++; 369 else 370 ComElev --; 371 ComElev = constrain(ComElev, 0, 90); // keep El Cmd value in range 372 ElEncRot = false; 373 } 374} // end of ReadElevEncoder() 375 376// Interrupt Service Routine for a change to encoder pin A and B 377void doAzEnc () 378{ 379 if (digitalRead (AzEncoderPinA)) 380 AzEncUp = digitalRead (AzEncoderPinB); 381 else 382 AzEncUp = !digitalRead (AzEncoderPinB); 383 AzEncRot = true; 384} // end of doAzEnc 385 386void doElEnc () 387{ 388 if (digitalRead (ElEncoderPinA)) 389 ElEncUp = digitalRead (ElEncoderPinB); 390 else 391 ElEncUp = !digitalRead (ElEncoderPinB); 392 ElEncRot = true; 393} // end of doElEnc 394 395void AzimRotate() { 396 if (ComAzim > TruAzim) { // this to determine direction of rotation 397// cold switching - stop motor before changing direction - to protect mechanic and electric parts 398 if (AzDir == char(127)) { // if previously rotating in the oposite direction 399 analogWrite(AzPWMPin, 0); // STOP the motor 400 StaAzim = TruAzim; // this will be the start azimuth for soft-start 401 delay(200); // pre-switch delay 402 digitalWrite(AzRotPin, LOW); // deactivate rotation pin - rotate right 403 delay(200); // post-switch delay 404 } 405 else { // same directin, no Stop, no delay 406 digitalWrite(AzRotPin, LOW); // deactivate rotation pin - rotate right 407 } 408 AzDir = char(126); // "->" 409 } 410 else { 411 if (AzDir == char(126)) { // if previously rotating in the oposite direction 412 analogWrite(AzPWMPin, 0); // STOP the motor 413 StaAzim = TruAzim; // this will be the start azimuth for soft-start 414 delay(200); // pre-switch delay 415 digitalWrite(AzRotPin, HIGH); // activate rotation pin - rotate left 416 delay(200); // post-switch delay 417 } 418 else { // same directin, no Stop, no delay 419 digitalWrite(AzRotPin, HIGH); // activate rotation pin - rotate left 420 } 421 AzDir = char(127); // "<-" 422 } 423 lcd.setCursor(8, 0); 424 lcd.print(String(AzDir)); 425 // this activates azim PWM pin proportional with angle error (calculated in percents %) 426 PwAzStop = PwAzMin + round((abs(ComAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); //formula which outputs a power proportional with angle difference for Soft-Stop 427 PwAzStar = PwAzMin + round((abs(StaAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); //formula which outputs a power proportional with angle difference for Soft-Start 428 if (PwAzStar > PwAzStop){ 429 PwAz = PwAzStop; //choose whichever value is smallest 430 } 431 else {PwAz = PwAzStar;} 432 if (PwAz > PwAzMax) {PwAz = PwAzMax;} 433 analogWrite(AzPWMPin, round(2.55*PwAz)); // activate Azim drive PWM pin 434} // end AzimRotate() 435 436void ElevRotate() { 437// this to determine direction of rotation 438 if (ComElev > TruElev) { 439 if (ElUp == 1) { // if previously rotating in the oposite direction 440 analogWrite(ElPWMPin, 0); // STOP the motor 441 StaElev = TruElev; // this will be the start elevation for soft-start 442 delay(200); // pre-switch delay 443 digitalWrite(ElRotPin, LOW); // deactivate rotation pin - rotate UP 444 delay(200); // post-switch delay 445 } 446 else { // same directin, no Stop, no delay 447 digitalWrite(ElRotPin, LOW); // deactivate rotation pin - rotate UP 448 } 449 lcd.setCursor(8, 1); 450 lcd.write(2); // arrow up 451 ElUp = 2; // flag for elevation UP 452 } 453 else { 454 if (ElUp == 2) { // if previously rotating in the oposite direction 455 analogWrite(ElPWMPin, 0); // STOP the motor 456 StaElev = TruElev; // this will be the start elevation for soft-start 457 delay(200); // pre-switch delay 458 digitalWrite(ElRotPin, HIGH); // deactivate rotation pin - rotate UP 459 delay(200); // post-switch delay 460 } 461 else { // same directin, no Stop, no delay 462 digitalWrite(ElRotPin, HIGH); // deactivate rotation pin - rotate UP 463 } 464 lcd.setCursor(8, 1); 465 lcd.write(1); // arrow down 466 ElUp = 1; // flag for elevation DN 467 } 468 // this activates azim PWM pin proportional with angle error (calculated in percents %) 469 PwElStop = PwElMin + round((abs(ComElev-TruElev))*(PwElMax-PwElMin)/Emax); //formula which outputs a power proportional with angle difference for Soft-Stop 470 PwElStar = PwElMin + round((abs(StaElev-TruElev))*(PwElMax-PwElMin)/Emax); //formula which outputs a power proportional with angle difference for Soft-Start 471 if (PwElStar > PwElStop){ 472 PwEl = PwElStop; //choose whichever value is smallest 473 } 474 else {PwEl = PwElStar;} 475 if (PwEl > PwElMax) {PwEl = PwElMax;} 476 analogWrite(ElPWMPin, round(2.55*PwEl)); // activate Elev drive PWM pin 477} // end ElevRotate() 478 479void SerComm() { 480 // initialize readings 481 ComputerRead = ""; 482 Azimuth = ""; 483 Elevation = ""; 484 485 while(Serial.available()) { 486 ComputerRead= Serial.readString(); // read the incoming data as string 487// Serial.println(ComputerRead); // echo the reception for testing purposes 488 } 489 490// looking for command <AZxxx.x> 491 for (int i = 0; i <= ComputerRead.length(); i++) { 492 if ((ComputerRead.charAt(i) == 'A')&&(ComputerRead.charAt(i+1) == 'Z')){ // if read AZ 493 for (int j = i+2; j <= ComputerRead.length(); j++) { 494 if (isDigit(ComputerRead.charAt(j))) { // if the character is number 495 Azimuth = Azimuth + ComputerRead.charAt(j); 496 } 497 else {break;} 498 } 499 } 500 } 501 502// looking for command <ELxxx.x> 503 for (int i = 0; i <= (ComputerRead.length()-2); i++) { 504 if ((ComputerRead.charAt(i) == 'E')&&(ComputerRead.charAt(i+1) == 'L')){ // if read EL 505 if ((ComputerRead.charAt(i+2)) == '-') { 506 ComElev = 0; // if elevation negative 507 break; 508 } 509 for (int j = i+2; j <= ComputerRead.length(); j++) { 510 if (isDigit(ComputerRead.charAt(j))) { // if the character is number 511 Elevation = Elevation + ComputerRead.charAt(j); 512 } 513 else {break;} 514 } 515 } 516 } 517 518// if <AZxx> received 519 if (Azimuth != ""){ 520 ComAzim = Azimuth.toInt(); 521 ComAzim = ComAzim%360; // keeping values between limits(for trackers with more than 360 deg. rotation) 522 } 523 524// if <ELxx> received 525 if (Elevation != ""){ 526 ComElev = Elevation.toInt(); 527 if (ComElev>180) { ComElev = 0;} 528 if (ComElev>90) { //if received more than 90deg. (for trackers with 180deg. elevation) 529 ComElev = 180-ComElev; //keep below 90deg. 530 ComAzim = (ComAzim+180)%360; //and rotate the antenna on the back 531 } 532 } 533 534// looking for <AZ EL> interogation for antenna position 535 for (int i = 0; i <= (ComputerRead.length()-4); i++) { 536 if ((ComputerRead.charAt(i) == 'A')&&(ComputerRead.charAt(i+1) == 'Z')&&(ComputerRead.charAt(i+3) == 'E')&&(ComputerRead.charAt(i+4) == 'L')){ 537 // send back the antenna position <+xxx.x xx.x> 538 ComputerWrite = "+"+String(TruAzim)+".0 "+String(TruElev)+".0"; 539 //ComputerWrite = "AZ"+String(TruAzim)+".0 EL"+String(TruElev)+".0"; //that's for Gpredict and HamLib 540 Serial.println(ComputerWrite); 541 } 542 } 543} // end SerComm() 544
ant-rot-AC-aug2022
arduino
This code is for relay output or AC motors. Use electric diagram for AC motors.
1/* AZ/EL Antenna Rotator controller for Arduino - relay output 2 * =========================================================== 3 * Uses EasyComm protocol for computer - Tracking Software 4 * Manual command by means of two rotary encoders AZ - EL 5 * 6 * compatible with switch-box rotators 7 * or AC motors 8 * dry contatcts for Left-Right, Up-Down 9 * 10 * Viorel Racoviteannu / 11 * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA 12 * https://racov.ro 13 * YO3RAK@gmail.com 14 * 15 * I cannot take any responsibility for missuse of this code 16 * or any kind of damage it may occur from using this code. 17 * 18 * dec 2020 v2 - improved serial comm stability 19 * jan 2021 - fixed AZ, EL tolerances for motor activation 20 * apr 2021 - improved serial comm stability 21 * aug 2021 - faster USB update, cold switching Az/El direction, small optimizations in the code 22 * ian 2022 - small optimizations 23 * aug 2022 - improved EL encoder functionality, electric diagram modified - encoders connections 24 */ 25 26#include <Wire.h> // Library for I2C communication 27#include <LiquidCrystal_I2C.h> // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c (Library for LCD) 28// Wiring: SDA pin is connected to A4 and SCL pin to A5. 29// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered) 30LiquidCrystal_I2C lcd(0x27, 16, 2); // address, chars, rows. 31 32// declaring custom symbol for up/down arrow 33 byte DownArrow[8] = { 34 B00000, 35 B00100, 36 B00100, 37 B00100, 38 B10101, 39 B01110, 40 B00100, 41 B00000 42}; 43 byte UpArrow[8] = { 44 B00000, 45 B00100, 46 B01110, 47 B10101, 48 B00100, 49 B00100, 50 B00100, 51 B00000 52}; 53 54// ANTENNA potentiometers CALIBRATION 55 int AzMin = 1; //begining of the potentiometer 56 int AzMax = 1023; //end of the potentiometer 57 int ElMin = 1; 58 int ElMax = 1023; 59 60// Allowed error for which antenna won't move 61 int AzErr = 8; 62 int ElErr = 4; 63 64// PIN assignement 65 enum PinAssignment { 66 AzPotPin = A0, // input pin for the azim. potentiometer 67 ElPotPin = A1, // input pin for the elev. potentiometer 68 AzEncoderPinA = 2, // Az encoder right 69 AzEncoderPinB = 4, // Az encoder left 70 AzClearButton = 5, // Az encoder push 71 ElEncoderPinA = 3, // El encoder right 72 ElEncoderPinB = 6, // El encoder left 73 ElClearButton = 7, // El encoder push 74 ElRotPinD = 8, 75 ElRotPinU = 9, // out pin for elevation rotation direction 76 AzRotPinL = 10, 77 AzRotPinR = 11 // out pin for rotation direction 78 }; 79 80// Az encoder variables 81 int AzEncBut = 1; // variable to toggle with encoder push button 82 volatile boolean AzEncRot; // if rotation occured 83 volatile boolean AzEncUp; // direction of rotation 84 85// El encoder variables 86 int ElEncBut = 1; 87 volatile boolean ElEncRot; 88 volatile boolean ElEncUp; 89 90// movement variables 91 int TruAzim = 0; // calculated real azimuth value 92 int ComAzim = 0; // commanded azimuth value 93 int TruElev = 0; // calculated real elevation value 94 int ComElev = 0; // commanded elevation value 95 int OldTruAzim = 0; // store previous azimuth values 96 int OldComAzim = 0; 97 int OldTruElev = 0; // store previous elevation values 98 int OldComElev = 0; 99 char AzDir; // symbol for azim rot display 100 char ElDir; // symbol for elev. rot display 101 unsigned long NowTime; // store the current millis() for timing purposes 102 103// flags for AZ, EL tolerances 104 bool AzStop = false; 105 bool ElStop = false; 106 int ElUp = 0; // 1 = Elevation Dn, 0 = Elevation STOP, 2 = Elevation Up 107 108// averaging loop 109 const int numReadings = 25; 110 int readIndex = 0; // the index of the current reading 111 int azimuth[numReadings]; // the readings from the analog input 112 int elevation[numReadings]; 113 int totalAz = 0; // the running total 114 int totalEl = 0; 115 116// variables for serial comm 117 String Azimuth = ""; 118 String Elevation = ""; 119 String ComputerRead; 120 String ComputerWrite; 121 bool AZser = false; 122 bool ELser = false; 123 bool ANTser = false; 124 125/*************** END VARIABLE DECLARATION ************/ 126 127void setup() { 128 Serial.begin(9600); 129 Serial.setTimeout(50); // miliseconds to wait for USB sata. Default 1000 130// Initiate the LCD: 131// lcd.begin(16,2); //select this one if the arrows are not displayed correctly 132 lcd.init(); 133 lcd.backlight(); 134 135// write on display name and version 136 lcd.setCursor(0, 0); // Set the cursor on the first column first row.(counting starts at 0!) 137 lcd.print("EasyCom AntRotor"); 138 lcd.setCursor(0, 1); // Set the cursor on the first column the second row 139 lcd.print("*Racov* Aug.2022"); 140 141// creating custom symbol for up/dwn arrow 142 lcd.createChar(1, DownArrow); 143 lcd.createChar(2, UpArrow); 144 145// pin declaration 146 pinMode(AzRotPinR, OUTPUT); //declaring azim. rotation direction Pin as OUTPUT 147 pinMode(AzRotPinL, OUTPUT); 148 pinMode(ElRotPinD, OUTPUT); //declaring elev. rotation direction Pin as OUTPUT 149 pinMode(ElRotPinU, OUTPUT); 150 pinMode(AzPotPin, INPUT); 151 pinMode(ElPotPin, INPUT); 152 pinMode(AzEncoderPinA, INPUT); 153 pinMode(AzEncoderPinB, INPUT); 154 pinMode(AzClearButton, INPUT); 155 pinMode(ElEncoderPinA, INPUT); 156 pinMode(ElEncoderPinB, INPUT); 157 pinMode(ElClearButton, INPUT); 158 159// deactivate rotation pins 160 digitalWrite(AzRotPinL, LOW); 161 digitalWrite(AzRotPinR, LOW); 162 digitalWrite(ElRotPinD, LOW); 163 digitalWrite(ElRotPinU, LOW); 164 165// Interrupt Service Routine for Az and El encoder 166 attachInterrupt(0, doAzEnc, CHANGE); // Az encoder 167 attachInterrupt(1, doElEnc, CHANGE); // El Encoder 168 169/* initialization of the averaging loop 170 this is to set Az/El-command the same value as real, not to jerk the antenna at start-up */ 171 TruAzim = (map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); // transforms potentiometer voltage into azimuth angle 172 TruElev = (map(analogRead(ElPotPin), ElMin, ElMax, 0, 90)); // transforms potentiometer voltage into elevation angle 173 174 for (int thisReading = 0; thisReading < numReadings; thisReading++) { 175 azimuth[thisReading] = TruAzim; 176 elevation[thisReading] = TruElev; 177 } 178 totalAz = TruAzim * numReadings; 179 totalEl = TruElev * numReadings; 180 181/* keep command values in range */ 182 ComAzim = constrain(TruAzim, 0, 359); 183 ComElev = constrain(TruElev, 0, 90); 184 OldTruAzim = TruAzim; 185 OldComAzim = ComAzim; 186 OldTruElev = TruElev; 187 OldComElev = TruElev; 188 189 delay(1500); // wait 1.5 seconds 190// display Azim. and Elev. values 191 lcd.setCursor(0, 0); 192 lcd.print("Azm.---" + String(char(223)) + "=Cd.---" + String(char(223))); // char(223) is degree symbol 193 lcd.setCursor(0, 1); 194 lcd.print("Elv. --" + String(char(223)) + "=Cd. --" + String(char(223))); 195 DisplValue(TruAzim, 4,0); 196 DisplValue(ComAzim,12,0); 197 DisplValue(TruElev, 4,1); 198 DisplValue(ComElev,12,1); 199} 200// end SETUP 201 202void loop() { /************** FYI, this loop repeats 500 times per second !!! **************/ 203 204// AZIMUTH/ELEVATION AVERAGING LOOP 205 // subtract the oldest value 206 totalAz = totalAz - azimuth[readIndex]; 207 totalEl = totalEl - elevation[readIndex]; 208 // read from the sensor: 209 azimuth[readIndex] = (map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); 210 elevation[readIndex] = (map(analogRead(ElPotPin), ElMin, ElMax, 0, 90)); 211 // add the reading to the total: 212 totalAz = totalAz + azimuth[readIndex]; 213 totalEl = totalEl + elevation[readIndex]; 214 // do the average 215 TruAzim = totalAz / numReadings; 216 TruElev = totalEl / numReadings; 217/* keep values in range 218 TruAzim = constrain(TruAzim, 0, 359); 219 TruElev = constrain(TruElev, 0, 90); */ 220 // advance to the next position in the array 221 // if we're at the end of the array, wrap around to the beginning: 222 readIndex = (readIndex + 1) % numReadings; 223 224// read the command from encoder 225 ReadAzimEncoder(); 226 ReadElevEncoder(); 227 228// read the command from computer 229 if (Serial.available()) {SerComm();} // read USB data 230 231// update antenna position display only if value change 232 if ((millis() - NowTime) > 300){ //every 0.3 seconds, not to flicker the display 233 if (OldTruAzim!=TruAzim) { 234 DisplValue(TruAzim,4,0); 235 OldTruAzim = TruAzim; 236 } 237 if (OldTruElev!=TruElev) { 238 DisplValue(TruElev,4,1); 239 OldTruElev = TruElev; 240 } 241 NowTime = millis(); 242 } 243 244// update target position display only if value change 245 if (OldComAzim != ComAzim) { 246 DisplValue(ComAzim,12,0); 247 OldComAzim = ComAzim; 248 } 249 if (OldComElev != ComElev) { 250 DisplValue(ComElev,12,1); 251 OldComElev = ComElev; 252 } 253 254// this is to rotate in azimuth 255 if (TruAzim == ComAzim) { // if equal, stop moving 256 AzStop = true; 257 digitalWrite(AzRotPinL, LOW); // deactivate rotation pin 258 digitalWrite(AzRotPinR, LOW); 259 lcd.setCursor(8, 0); 260 lcd.print("="); 261 } 262 else if ((abs(TruAzim - ComAzim)<=AzErr)&&(AzStop == false)) { // if in tolerance, but it wasn't an equal, rotate 263 AzimRotate();} 264 else if (abs(TruAzim - ComAzim)>AzErr){ // if target is off tolerance 265 AzStop = false; // it's not equal 266 AzimRotate(); // rotate 267 } 268 269// this is to rotate in elevation 270 if (TruElev == ComElev) { // if equal, stop moving 271 ElStop = true; 272 digitalWrite(ElRotPinD, LOW); // deactivate elevator pin 273 digitalWrite(ElRotPinU, LOW); 274 lcd.setCursor(8, 1); 275 lcd.print("="); 276 ElUp = 0; // flag for elevation STOP 277 } 278 else if ((abs(TruElev - ComElev)<=ElErr)&&(ElStop == false)) { // if in tolerance, but it wasn't an equal, rotate 279 ElevRotate();} 280 else if (abs(TruElev - ComElev)>ElErr){ // if target is off tolerance 281 ElStop = false; // it's not equal 282 ElevRotate(); // rotate 283 } 284 285// this is to interpret x10 AZ ENC multiplication 286 while (AzEncBut == 10) { // while toggled to x10 287 digitalWrite(AzRotPinL, LOW); // deactivate rotation pin 288 digitalWrite(AzRotPinR, LOW); 289 digitalWrite(ElRotPinD, LOW); // deactivate elevator pin 290 digitalWrite(ElRotPinU, LOW); 291 lcd.setCursor(8, 0); 292 lcd.print("*"); 293 ReadAzimEncoder(); 294 if (OldComAzim != ComAzim){ // update display only if numbers change 295 DisplValue(ComAzim, 12, 0); 296 OldComAzim = ComAzim; 297 } 298 ReadElevEncoder(); 299 if (OldComElev != ComElev){ // update display only if numbers change 300 DisplValue(ComElev, 12, 1); 301 OldComElev = ComElev; 302 } 303 delay(100); 304 } 305} 306// end main LOOP 307 308//____________________________________________________ 309// ___________procedures definitions__________________ 310 311void DisplValue(int x, int y, int z) { 312 char displayString[7] = ""; 313 sprintf(displayString, "%3d", x); // outputs a fixed lenght number (3 integer) 314 lcd.setCursor(y, z); // for leading zeros '007' use "%03d" 315 lcd.print(displayString); 316 317// ************** FOR CALIBRATION PURPOSES ************** 318/* 319 Serial.print ("Az "); 320 Serial.println (analogRead(AzPotPin)); 321 Serial.print ("El "); 322 Serial.println (analogRead(ElPotPin)); 323*/ 324} // end DisplValue() 325 326void ReadAzimEncoder() { 327 if (digitalRead(AzClearButton) == LOW ) { // if encoder switch depressed 328 delay (250); // debounce switch 329 lcd.setCursor(0, 0); // refresh all the writings on the screen 330 lcd.print("Azm.---" + String(char(223)) + "=Cd.---" + String(char(223))); 331 lcd.setCursor(0, 1); 332 lcd.print("Elv. --" + String(char(223)) + "=Cd. --" + String(char(223))); 333 DisplValue(TruAzim, 4,0); 334 DisplValue(ComAzim,12,0); 335 DisplValue(TruElev, 4,1); 336 DisplValue(ComElev,12,1); 337 if (AzEncBut == 1){ 338 AzEncBut = 10; // increment by 10 degrees 339 ComAzim = int(ComAzim/10)*10; // ComAzim in 10deg. steps 340 } 341 else 342 AzEncBut = 1; 343 } 344 345 if (AzEncRot){ 346 delay(20); // debouncing 347 if (AzEncUp) 348 ComAzim += AzEncBut; 349 else 350 ComAzim -= AzEncBut; 351 ComAzim = ((ComAzim + 360) % 360); // Az Cmd between 0 and 359 deg continuous 352 AzEncRot = false; 353 } 354} //end ReadAzimEncoder() 355 356void ReadElevEncoder() { 357 if (digitalRead(ElClearButton) == LOW ) { // set Park Position Command Az/El 358 delay(250); // debounce switch 359 ComAzim = 260; 360 ComElev = 0; 361 } 362 363 if (ElEncRot){ 364 delay(20); // debouncing 365 if (ElEncUp) 366 ComElev ++; 367 else 368 ComElev --; 369 ComElev = constrain(ComElev, 0, 90); // keep El Cmd value in range 370 ElEncRot = false; 371 } 372} // end of ReadElevEncoder() 373 374// Interrupt Service Routine for a change to encoder pin A and B 375void doAzEnc () 376{ 377 if (digitalRead (AzEncoderPinA)) 378 AzEncUp = digitalRead (AzEncoderPinB); 379 else 380 AzEncUp = !digitalRead (AzEncoderPinB); 381 AzEncRot = true; 382} // end of doAzEnc 383 384void doElEnc () 385{ 386 if (digitalRead (ElEncoderPinA)) 387 ElEncUp = digitalRead (ElEncoderPinB); 388 else 389 ElEncUp = !digitalRead (ElEncoderPinB); 390 ElEncRot = true; 391} // end of doElEnc 392 393void AzimRotate() { 394 if (ComAzim > TruAzim) { // this to determine direction of rotation 395// cold switching - stop motor before changing direction, to protect mechanic and electric parts 396 digitalWrite(AzRotPinL, LOW); // deactivate rotation pin Left 397 if (AzDir == char(127)) {delay(1000);} // if previously rotating in the oposite direction, wait 1 second 398 digitalWrite(AzRotPinR, HIGH); // activate rotation pin Right 399 AzDir = char(126); // "->" 400 } 401 else { 402 digitalWrite(AzRotPinR, LOW); 403 if (AzDir == char(126)) {delay(1000);} 404 digitalWrite(AzRotPinL, HIGH); 405 AzDir = char(127); // "<-" 406 } 407 lcd.setCursor(8, 0); 408 lcd.print(String(AzDir)); 409} // end AzimRotate() 410 411void ElevRotate() { 412// this to determine direction of rotation 413 if (ComElev > TruElev) { 414 digitalWrite(ElRotPinD, LOW); 415 if (ElUp == 1) {delay(1000);} 416 digitalWrite(ElRotPinU, HIGH); 417 lcd.setCursor(8, 1); 418 lcd.write(2); // arrow up 419 ElUp = 2; 420 } 421 else { 422 digitalWrite(ElRotPinU, LOW); 423 if (ElUp == 2) {delay(1000);} 424 digitalWrite(ElRotPinD, HIGH); 425 lcd.setCursor(8, 1); 426 lcd.write(1); // arrow down 427 ElUp = 1; 428 } 429} // end ElevRotate() 430 431void SerComm() { 432 // initialize readings 433 ComputerRead = ""; 434 Azimuth = ""; 435 Elevation = ""; 436 437 while(Serial.available()) { 438 ComputerRead= Serial.readString(); // read the incoming data as string 439// Serial.println(ComputerRead); // echo the reception for testing purposes 440 } 441 442// looking for command <AZxxx.x> 443 for (int i = 0; i <= ComputerRead.length(); i++) { 444 if ((ComputerRead.charAt(i) == 'A')&&(ComputerRead.charAt(i+1) == 'Z')){ // if read AZ 445 for (int j = i+2; j <= ComputerRead.length(); j++) { 446 if (isDigit(ComputerRead.charAt(j))) { // if the character is number 447 Azimuth = Azimuth + ComputerRead.charAt(j); 448 } 449 else {break;} 450 } 451 } 452 } 453 454// looking for command <ELxxx.x> 455 for (int i = 0; i <= (ComputerRead.length()-2); i++) { 456 if ((ComputerRead.charAt(i) == 'E')&&(ComputerRead.charAt(i+1) == 'L')){ // if read EL 457 if ((ComputerRead.charAt(i+2)) == '-') { // if received elevation negative 458 ComElev = 0; // keep antenna to zero 459 break; 460 } 461 for (int j = i+2; j <= ComputerRead.length(); j++) { 462 if (isDigit(ComputerRead.charAt(j))) { // if the character is number 463 Elevation = Elevation + ComputerRead.charAt(j); 464 } 465 else {break;} 466 } 467 } 468 } 469 470// if <AZxx> received 471 if (Azimuth != ""){ 472 ComAzim = Azimuth.toInt(); 473 ComAzim = ComAzim%360; // keeping values in range 474 } 475 476// if <ELxx> received 477 if (Elevation != ""){ 478 ComElev = Elevation.toInt(); 479 if (ComElev>180) { ComElev = 0;} 480 if (ComElev>90) { // if received more than 90deg. (for trackers with 180deg. elevation) 481 ComElev = 180-ComElev; //keep below 90deg. 482 ComAzim = (ComAzim+180)%360; //and rotate the antenna on the back 483 } 484 } 485 486// looking for <AZ EL> interogation for antenna position 487 for (int i = 0; i <= (ComputerRead.length()-4); i++) { 488 if ((ComputerRead.charAt(i) == 'A')&&(ComputerRead.charAt(i+1) == 'Z')&&(ComputerRead.charAt(i+3) == 'E')&&(ComputerRead.charAt(i+4) == 'L')){ 489 // send back the antenna position <+xxx.x xx.x> 490 ComputerWrite = "+"+String(TruAzim)+".0 "+String(TruElev)+".0"; 491 //ComputerWrite = "AZ"+String(TruAzim)+".0 EL"+String(TruElev)+".0"; //that's for Gpredict and HamLib 492 Serial.println(ComputerWrite); 493 } 494 } 495} // end SerComm() 496
Potentiometer calibration procedure
arduino
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 :)
1AZ / EL Potentiometers limit calibration PROCEDURE ( 0-359ᴼ / 0-90ᴼ) 2 31. Open the code in Arduino and 4- Look for: 5 6// ************** FOR CALIBRATION PURPOSES ************** 7/* 8 Serial.print ("Az "); 9 Serial.println (analogRead(AzPotPin)); 10 Serial.print ("El "); 11 Serial.println (analogRead(ElPotPin)); 12*/ 13 14- Eliminate the simbols /* and */ 15- The text above should turn from gray into black and coloured. 16 17 182. Upload the code and open the serial monitor. There you will see a lot of numbers; 19 203. With the help of the encoders, move the antenna to minimum values, 0ᴼ in azimuth and 0ᴼ in elevation. 21- Write down the values for Azimuth and Elevation. (in my case it was AzMin=90, ElMin=10) 22- These are the input values read by Arduino, not the real angles; 23 244. Move the antenna again to maximum values, 359ᴼ in azimuth and 90ᴼ in elevation. 25- Again, write down the values for Azimuth and Elevation. (in my case it was AzMax=1000, ElMax=992); 26 275. Look in the code, at the beginning, for the section 28 29// ANTENNA potentiometers CALIBRATION 30 int AzMin = 1; 31 int AzMax = 1023; 32 int ElMin = 1; 33 int ElMax = 1023; 34 35- Here input the values you wrote down earlier, like 36 int AzMin = 90; 37 int AzMax = 1000; 38 int ElMin = 10; 39 int ElMax = 992; 40 416. Now it is no longer necessary to send this on serial, so you have to comment back these lines, like this: 42/* 43 Serial.print ("Az "); 44 Serial.println (analogRead(AzPotPin)); 45 Serial.print ("El "); 46 Serial.println (analogRead(ElPotPin)); 47*/ 48- The text above should turn gray 49 507. Upload again the code. 51 52That's all. Now, in the serial monitor, there should be no more numbers.
Motor calibration procedure
arduino
This procedure sets the parameters for the Antenna Speed-Up / Slow-Down Zone. This is plain text, not a code :)
1Motor Calibration Procedure For Soft-Start / Soft-Stop feature. 2This procedure sets the parameters for the Antenna Speed-Up / Slow-Down and the Dead-Zone. 3You 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. 4It’s not strictly necessary, only if you don’t like the default settings. 5Make sure you first apply the Potentiometer Calibration Procedure !!! That one is strictly necessary. 6Look at the power diagram for a better understanding. 7 8***For Azimuth movement*** 9-As the antenna starts to move towards the target, is picking up speed, reaching full power after <Amax> degrees difference. 10-As the antenna closes in to the target, below <Amax> degrees difference, it starts to slow down. <Amax> should be higher for heavier antennas. 11-The power starts to decrease from <PwAzMax> to <PwAzMin> until the angle difference becomes zero. 12 <PwAzMax> (in percents %) should be 100 for full speed. If you ever think your antenna rotates too fast, you can set a smaller <PwAzMax>. 13 <PwAzMin> (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. 14-Once the antenna reaches the target position (zero degrees error), it stops and doesn’t move again until the target travels more than <AzErr> degrees. 15 This is a dead zone, to prevent continuously shaking the antenna for the smallest target movement, or potentiometer position jitter. 16 The smaller the <AzErr>, the more precise tracking, the more frequent shacking of the motors. 17 18***For Elevation movement*** 19Exactly as for the Azimuth. 20 21Look at the beginning of the code for this section. Here you can input your desired values. 22 23/**************THIS IS WHERE YOU REALY TWEAK THE ANTENNA MOVEMENT************/ 24... 25 26// Allowed error for which antennna won't move. 27 int AzErr = 8; 28 int ElErr = 4; 29 30// Angle difference where soft stop begins 31 int Amax = 25; //azimuth 32 int Emax = 15; //elevation 33 34// min and max power for motors, percents; 35 int PwAzMin = 30; //minimum power for which the motor doesn't stall and starts under load 36 int PwAzMax = 100; //full power for the fastest speed 37 int PwElMin = 30; 38 int PwElMax = 100; 39/****************************************************************************/
ant-rot-DC-aug2022
arduino
This code is for DC motors, with soft start/stop PWM output. Use electric diagram for DC motors.
1/* AZ/EL Antenna Rotator controller for Arduino - DC motors - PWM output 2 * ===================================================================== 3 * Uses EasyComm protocol for computer - Tracking Software 4 * Manual command by means of two rotary encoders AZ - EL 5 * 6 * Viorel Racoviteannu 7 * https://www.youtube.com/channel/UCiRLZX0bV9rS04BGAyUf-fA 8 * https://racov.ro 9 * YO3RAK@gmail.com 10 * 11 * I cannot take any responsibility for missuse of this code 12 * or any kind of damage it may occur from using this code. 13 * 14 * dec 2020 v2 - improved serial comm stability 15 * jan 2021 - improved near target dead-zone, for which antenna won't move 16 * apr 2021 - improved serial comm stability 17 * jun 2021 - error proportional power for tracking movement. Real Soft-Stop 18 * aug 2021 - faster USB update, cold switching Az/El direction, small optimizations in the code 19 * nov 2021 - cracked the secret of Soft-Start. It wasn't hard. There you have it 20 * aug 2022 - improved EL encoder functionality, electric diagram modified - encoders connections 21 */ 22 23#include <Wire.h> // Library for I2C communication 24#include <LiquidCrystal_I2C.h> // https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c (Library for LCD) 25// Wiring: SDA pin is connected to A4 and SCL pin to A5. 26// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered) 27LiquidCrystal_I2C lcd(0x27, 16, 2); // address, chars, rows. 28 29// declaring custom symbol for up/down arrow 30 byte DownArrow[8] = { 31 B00000, 32 B00100, 33 B00100, 34 B00100, 35 B10101, 36 B01110, 37 B00100, 38 B00000 39}; 40 byte UpArrow[8] = { 41 B00000, 42 B00100, 43 B01110, 44 B10101, 45 B00100, 46 B00100, 47 B00100, 48 B00000 49}; 50 51/***********************************THIS IS WHERE YOU REALY TWEAK THE ANTENNA MOVEMENT***************/ 52// ANTENNA potentiometers CALIBRATION 53 int AzMin = 1; //begining of the potentiometer 54 int AzMax = 1023; //end of the potentiometer 55 int ElMin = 1; 56 int ElMax = 1023; 57 58// Allowed error for which antennna won't move 59 int AzErr = 8; 60 int ElErr = 4; 61 62// Angle difference where soft stop begins 63 int Amax = 25; //azimuth 64 int Emax = 15; //elevation 65 66// min and max power for motors, percents; 67 int PwAzMin = 30; //minimum power for which the motor doesn't stall and starts under load 68 int PwAzMax = 100; //full power for the fastest speed 69 int PwElMin = 30; 70 int PwElMax = 100; 71 72/***************************************************************************************************/ 73 74 enum PinAssignments { 75 AzPotPin = A0, // input pin for the azim. potentiometer 76 ElPotPin = A1, // input pin for the elev. potentiometer 77 AzEncoderPinA = 2, // Az encoder right 78 AzEncoderPinB = 4, // Az encoder left 79 AzClearButton = 5, // Az encoder push 80 ElEncoderPinA = 3, // El encoder right 81 ElEncoderPinB = 6, // El encoder left 82 ElClearButton = 7, // El encoder push 83 ElPWMPin = 9, // out pin for elevation rotation PWM command 84 AzPWMPin = 10, // out pin for azimuth PWM command 85 AzRotPin = 11, // out pin for Az rotation direction 86 ElRotPin = 12, // out pin for El rotation direction 87 }; 88 89// Az encoder variables 90 int AzEncBut = 1; // variable to toggle with encoder push button 91 volatile boolean AzEncRot; // if rotation occured 92 volatile boolean AzEncUp; // direction of rotation 93 94// El encoder variables 95 int ElEncBut = 1; 96 volatile boolean ElEncRot; 97 volatile boolean ElEncUp; 98 99// movement variables 100 int TruAzim = 0; // calculated real azimuth value 101 int ComAzim = 0; // commanded azimuth value 102 int TruElev = 0; // calculated real elevation value 103 int ComElev = 0; // commanded elevation value 104 int OldTruAzim = 0; // to store previous azimuth value 105 int OldComAzim = 0; 106 int OldTruElev = 0; // to store previous elevation value 107 int OldComElev = 0; 108 int StaAzim = 0; // Start Azimuth angle for motor Soft-Start 109 int StaElev = 0; // Start Elevation angle for motor Soft-Start 110 int PwAzStop = 0; // calculated PWM (percent) for soft-stop 111 int PwAzStar = 0; // calculated PWM (percent) for soft-start 112 int PwElStop = 0; // calculated PWM (percent) for soft-stop 113 int PwElStar = 0; // calculated PWM (percent) for soft-start 114 int PwAz = 0; //calculated power to be transmitted to motor (percents); 115 int PwEl = 0; 116 char AzDir; // symbol for azim rot display 117 char ElDir; // symbol for elev. rot display 118 unsigned long NowTime; // store the current millis() for timing purposes 119 120// flags for AZ, EL tolerances 121 bool AzStop = false; 122 bool ElStop = false; 123 int ElUp = 1; // 1 - Elevation Dn, 0 - Elevation STOP, 2 - Elevation Up 124 125//averaging loop 126 const int numReadings = 25; 127 int readIndex = 0; // the index of the current reading 128 int azimuth[numReadings]; // the readings from the analog input 129 int elevation[numReadings]; 130 int totalAz = 0; // the running total 131 int totalEl = 0; 132 133// variables for serial comm 134 String Azimuth = ""; 135 String Elevation = ""; 136 String ComputerRead; 137 String ComputerWrite; 138 bool AZser = false; 139 bool ELser = false; 140 bool ANTser = false; 141 142/*************** END VARIABLE DECLARATION ************/ 143 144void setup() { 145 Serial.begin(9600); 146 Serial.setTimeout(50); // miliseconds to wait for USB sata. Default 1000 147// Initiate the LCD: 148// lcd.begin(16,2); //select this one if the arrows are not displayed correctly 149 lcd.init(); 150 lcd.backlight(); 151 152// write on display name and version 153 lcd.setCursor(0, 0); // Set the cursor on the first column first row.(counting starts at 0!) 154 lcd.print("EasyCom AntRotor"); // display "..." 155 lcd.setCursor(0, 1); // Set the cursor on the first column the second row 156 lcd.print("*Racov* Aug.2022"); 157 158//creating custom symbol for up/dwn arrow 159 lcd.createChar(1, DownArrow); 160 lcd.createChar(2, UpArrow); 161 162// pin declaration 163 pinMode(AzRotPin, OUTPUT); //declaring azim. rotation direction Pin as OUTPUT 164 pinMode(AzPWMPin, OUTPUT); //declaring azimuth PWM command Pin as OUTPUT 165 pinMode(ElRotPin, OUTPUT); //declaring elev. rotation direction Pin as OUTPUT 166 pinMode(ElPWMPin, OUTPUT); 167 pinMode(AzPotPin, INPUT); 168 pinMode(ElPotPin, INPUT); 169 pinMode(AzEncoderPinA, INPUT); 170 pinMode(AzEncoderPinB, INPUT); 171 pinMode(AzClearButton, INPUT); 172 pinMode(ElEncoderPinA, INPUT); 173 pinMode(ElEncoderPinB, INPUT); 174 175// Interrupt Service Routine for Az and El encoder 176 attachInterrupt(0, doAzEnc, CHANGE); // Az encoder 177 attachInterrupt(1, doElEnc, CHANGE); // El Encoder 178 179/* initialization of the averaging loop 180 this is to set Az/El-command the same value as real, not to jerk the antenna at start-up */ 181 TruAzim = (map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); // transforms potentiometer voltage into azimuth angle 182 TruElev = (map(analogRead(ElPotPin), ElMin, ElMax, 0, 90)); // transforms potentiometer voltage into elevation angle 183 184 for (int thisReading = 0; thisReading < numReadings; thisReading++) { 185 azimuth[thisReading] = TruAzim; 186 elevation[thisReading] = TruElev; 187 } 188 totalAz = TruAzim * numReadings; 189 totalEl = TruElev * numReadings; 190 191/* keep command values in range */ 192 ComAzim = constrain(TruAzim, 0, 359); 193 ComElev = constrain(TruElev, 0, 90); 194 OldTruAzim = TruAzim; 195 OldComAzim = ComAzim; 196 OldTruElev = TruElev; 197 OldComElev = TruElev; 198 199 delay(1500); // keep for 1.5 seconds 200// display Azim. and Elev. values 201 lcd.setCursor(0, 0); 202 lcd.print("Azm.---" + String(char(223)) + "=Cd.---" + String(char(223))); // char(223) is degree symbol 203 lcd.setCursor(0, 1); 204 lcd.print("Elv. --" + String(char(223)) + "=Cd. --" + String(char(223))); 205 DisplValue(TruAzim, 4,0); 206 DisplValue(ComAzim,12,0); 207 DisplValue(TruElev, 4,1); 208 DisplValue(ComElev,12,1); 209} 210// end SETUP 211 212void loop() { 213/************** FYI, this loop repeats 500 times per second !!! **************/ 214// AZIMUTH/ELEVATION AVERAGING LOOP 215 // subtract the oldest value 216 totalAz = totalAz - azimuth[readIndex]; 217 totalEl = totalEl - elevation[readIndex]; 218 // read from the sensor: 219 azimuth[readIndex] = (map(analogRead(AzPotPin), AzMin, AzMax, 0, 359)); 220 elevation[readIndex] = (map(analogRead(ElPotPin), ElMin, ElMax, 0, 90)); 221 // add the reading to the total: 222 totalAz = totalAz + azimuth[readIndex]; 223 totalEl = totalEl + elevation[readIndex]; 224 // do the average 225 TruAzim = totalAz / numReadings; 226 TruElev = totalEl / numReadings; 227/* keep values in range 228 TruAzim = constrain(TruAzim, 0, 359); 229 TruElev = constrain(TruElev, 0, 90); */ 230 // advance to the next position in the array 231 // if we're at the end of the array, wrap around to the beginning: 232 readIndex = (readIndex + 1) % numReadings; 233 234// read the command from encoder 235 ReadAzimEncoder(); 236 ReadElevEncoder(); 237 238 if (Serial.available()) {SerComm();} // read USB data 239 240// update antenna position display only if value change 241 if ((millis() - NowTime) > 300){ //every 0.3 seconds, not to flicker the display 242 if (OldTruAzim!=TruAzim) { 243 DisplValue(TruAzim,4,0); 244 OldTruAzim = TruAzim; 245 } 246 if (OldTruElev!=TruElev) { 247 DisplValue(TruElev,4,1); 248 OldTruElev = TruElev; 249 } 250 NowTime = millis(); 251 } 252 253// update target position display only if value change 254 if (OldComAzim != ComAzim) { 255 DisplValue(ComAzim,12,0); 256 OldComAzim = ComAzim; 257 } 258 if (OldComElev != ComElev) { 259 DisplValue(ComElev,12,1); 260 OldComElev = ComElev; 261 } 262 263// this is to rotate in azimuth 264 if (TruAzim == ComAzim) { // if equal, stop moving 265 AzStop = true; 266 analogWrite(AzPWMPin, 0); // Az motor power = 0 267 StaAzim = TruAzim; // this will be the start azimuth for soft-start 268 lcd.setCursor(8, 0); 269 lcd.print("="); 270 } 271 else if ((abs(TruAzim - ComAzim)<=AzErr)&&(AzStop == false)) { // if in tolerance, but it wasn't an equal, rotate 272 AzimRotate();} 273 else if (abs(TruAzim - ComAzim)>AzErr){ // if target is off tolerance 274 AzStop = false; // it's not equal 275 AzimRotate(); // rotate 276 } 277 278// this is to rotate in elevation 279 if (TruElev == ComElev) { // if equal, stop moving 280 ElStop = true; 281 analogWrite(ElPWMPin, 0); // El motor power = 0 282 StaElev = TruElev; // this will be the start elevation for soft-start 283 lcd.setCursor(8, 1); 284 lcd.print("="); 285 ElUp = 0; // flag for elevation STOP 286 } 287 else if ((abs(TruElev - ComElev)<=ElErr)&&(ElStop == false)) { // if in tolerance, but it wasn't an equal, rotate 288 ElevRotate();} 289 else if (abs(TruElev - ComElev)>ElErr){ // if target is off tolerance 290 ElStop = false; // it's not equal 291 ElevRotate(); // rotate 292 } 293 294 // this is to interpret Az encoder x10 multiplication 295 while (AzEncBut == 10) { // while toggled to x10 296 analogWrite(AzPWMPin, 0); // STOP antenna rotation 297 StaAzim = TruAzim; // this will be the start azimuth for soft-start 298 analogWrite(ElPWMPin, 0); 299 lcd.setCursor(8, 0); 300 lcd.print("*"); 301 ReadAzimEncoder(); 302 if (OldComAzim != ComAzim){ // update display only if numbers change 303 DisplValue(ComAzim, 12, 0); 304 OldComAzim = ComAzim; 305 } 306 delay (100); 307 } 308} // end main LOOP 309 310//____________________________________________________ 311// ___________procedures definitions__________________ 312 313void DisplValue(int x, int y, int z) { 314 char displayString[7] = ""; 315 sprintf(displayString, "%3d", x); // outputs a fixed lenght number (3 integer) 316 lcd.setCursor(y, z); // for leading zeros '007' use "%03d" 317 lcd.print(displayString); 318 319// ************** FOR CALIBRATION PURPOSES ************** 320/* 321 Serial.print ("Az "); 322 Serial.println (analogRead(AzPotPin)); 323 Serial.print ("El "); 324 Serial.println (analogRead(ElPotPin)); 325*/ 326} // end DisplValue() 327 328void ReadAzimEncoder() { 329 if (digitalRead(AzClearButton) == LOW ) { // if encoder switch depressed 330 delay (250); // debounce switch 331 lcd.setCursor(0, 0); // refresh all the writings on the screen 332 lcd.print("Azm.---" + String(char(223)) + "=Cd.---" + String(char(223))); 333 lcd.setCursor(0, 1); 334 lcd.print("Elv. --" + String(char(223)) + "=Cd. --" + String(char(223))); 335 DisplValue(TruAzim, 4,0); 336 DisplValue(ComAzim,12,0); 337 DisplValue(TruElev, 4,1); 338 DisplValue(ComElev,12,1); 339 if (AzEncBut == 1){ 340 AzEncBut = 10; // increment by 10 degrees 341 ComAzim = int(ComAzim/10)*10; // ComAzim in 10deg. steps 342 } 343 else 344 AzEncBut = 1; 345 } 346 347 if (AzEncRot){ 348 delay(20); // debouncing 349 if (AzEncUp) 350 ComAzim += AzEncBut; 351 else 352 ComAzim -= AzEncBut; 353 ComAzim = ((ComAzim + 360) % 360); // Az Cmd between 0 and 359 deg continuous 354 AzEncRot = false; 355 } 356} //end ReadAzimEncoder() 357 358void ReadElevEncoder() { 359 if (digitalRead(ElClearButton) == LOW ) { // set Park Position Command Az/El 360 delay(250); // debounce switch 361 ComAzim = 260; 362 ComElev = 0; 363 } 364 365 if (ElEncRot){ 366 delay(20); // debouncing 367 if (ElEncUp) 368 ComElev ++; 369 else 370 ComElev --; 371 ComElev = constrain(ComElev, 0, 90); // keep El Cmd value in range 372 ElEncRot = false; 373 } 374} // end of ReadElevEncoder() 375 376// Interrupt Service Routine for a change to encoder pin A and B 377void doAzEnc () 378{ 379 if (digitalRead (AzEncoderPinA)) 380 AzEncUp = digitalRead (AzEncoderPinB); 381 else 382 AzEncUp = !digitalRead (AzEncoderPinB); 383 AzEncRot = true; 384} // end of doAzEnc 385 386void doElEnc () 387{ 388 if (digitalRead (ElEncoderPinA)) 389 ElEncUp = digitalRead (ElEncoderPinB); 390 else 391 ElEncUp = !digitalRead (ElEncoderPinB); 392 ElEncRot = true; 393} // end of doElEnc 394 395void AzimRotate() { 396 if (ComAzim > TruAzim) { // this to determine direction of rotation 397// cold switching - stop motor before changing direction - to protect mechanic and electric parts 398 if (AzDir == char(127)) { // if previously rotating in the oposite direction 399 analogWrite(AzPWMPin, 0); // STOP the motor 400 StaAzim = TruAzim; // this will be the start azimuth for soft-start 401 delay(200); // pre-switch delay 402 digitalWrite(AzRotPin, LOW); // deactivate rotation pin - rotate right 403 delay(200); // post-switch delay 404 } 405 else { // same directin, no Stop, no delay 406 digitalWrite(AzRotPin, LOW); // deactivate rotation pin - rotate right 407 } 408 AzDir = char(126); // "->" 409 } 410 else { 411 if (AzDir == char(126)) { // if previously rotating in the oposite direction 412 analogWrite(AzPWMPin, 0); // STOP the motor 413 StaAzim = TruAzim; // this will be the start azimuth for soft-start 414 delay(200); // pre-switch delay 415 digitalWrite(AzRotPin, HIGH); // activate rotation pin - rotate left 416 delay(200); // post-switch delay 417 } 418 else { // same directin, no Stop, no delay 419 digitalWrite(AzRotPin, HIGH); // activate rotation pin - rotate left 420 } 421 AzDir = char(127); // "<-" 422 } 423 lcd.setCursor(8, 0); 424 lcd.print(String(AzDir)); 425 // this activates azim PWM pin proportional with angle error (calculated in percents %) 426 PwAzStop = PwAzMin + round((abs(ComAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); //formula which outputs a power proportional with angle difference for Soft-Stop 427 PwAzStar = PwAzMin + round((abs(StaAzim-TruAzim))*(PwAzMax-PwAzMin)/Amax); //formula which outputs a power proportional with angle difference for Soft-Start 428 if (PwAzStar > PwAzStop){ 429 PwAz = PwAzStop; //choose whichever value is smallest 430 } 431 else {PwAz = PwAzStar;} 432 if (PwAz > PwAzMax) {PwAz = PwAzMax;} 433 analogWrite(AzPWMPin, round(2.55*PwAz)); // activate Azim drive PWM pin 434} // end AzimRotate() 435 436void ElevRotate() { 437// this to determine direction of rotation 438 if (ComElev > TruElev) { 439 if (ElUp == 1) { // if previously rotating in the oposite direction 440 analogWrite(ElPWMPin, 0); // STOP the motor 441 StaElev = TruElev; // this will be the start elevation for soft-start 442 delay(200); // pre-switch delay 443 digitalWrite(ElRotPin, LOW); // deactivate rotation pin - rotate UP 444 delay(200); // post-switch delay 445 } 446 else { // same directin, no Stop, no delay 447 digitalWrite(ElRotPin, LOW); // deactivate rotation pin - rotate UP 448 } 449 lcd.setCursor(8, 1); 450 lcd.write(2); // arrow up 451 ElUp = 2; // flag for elevation UP 452 } 453 else { 454 if (ElUp == 2) { // if previously rotating in the oposite direction 455 analogWrite(ElPWMPin, 0); // STOP the motor 456 StaElev = TruElev; // this will be the start elevation for soft-start 457 delay(200); // pre-switch delay 458 digitalWrite(ElRotPin, HIGH); // deactivate rotation pin - rotate UP 459 delay(200); // post-switch delay 460 } 461 else { // same directin, no Stop, no delay 462 digitalWrite(ElRotPin, HIGH); // deactivate rotation pin - rotate UP 463 } 464 lcd.setCursor(8, 1); 465 lcd.write(1); // arrow down 466 ElUp = 1; // flag for elevation DN 467 } 468 // this activates azim PWM pin proportional with angle error (calculated in percents %) 469 PwElStop = PwElMin + round((abs(ComElev-TruElev))*(PwElMax-PwElMin)/Emax); //formula which outputs a power proportional with angle difference for Soft-Stop 470 PwElStar = PwElMin + round((abs(StaElev-TruElev))*(PwElMax-PwElMin)/Emax); //formula which outputs a power proportional with angle difference for Soft-Start 471 if (PwElStar > PwElStop){ 472 PwEl = PwElStop; //choose whichever value is smallest 473 } 474 else {PwEl = PwElStar;} 475 if (PwEl > PwElMax) {PwEl = PwElMax;} 476 analogWrite(ElPWMPin, round(2.55*PwEl)); // activate Elev drive PWM pin 477} // end ElevRotate() 478 479void SerComm() { 480 // initialize readings 481 ComputerRead = ""; 482 Azimuth = ""; 483 Elevation = ""; 484 485 while(Serial.available()) { 486 ComputerRead= Serial.readString(); // read the incoming data as string 487// Serial.println(ComputerRead); // echo the reception for testing purposes 488 } 489 490// looking for command <AZxxx.x> 491 for (int i = 0; i <= ComputerRead.length(); i++) { 492 if ((ComputerRead.charAt(i) == 'A')&&(ComputerRead.charAt(i+1) == 'Z')){ // if read AZ 493 for (int j = i+2; j <= ComputerRead.length(); j++) { 494 if (isDigit(ComputerRead.charAt(j))) { // if the character is number 495 Azimuth = Azimuth + ComputerRead.charAt(j); 496 } 497 else {break;} 498 } 499 } 500 } 501 502// looking for command <ELxxx.x> 503 for (int i = 0; i <= (ComputerRead.length()-2); i++) { 504 if ((ComputerRead.charAt(i) == 'E')&&(ComputerRead.charAt(i+1) == 'L')){ // if read EL 505 if ((ComputerRead.charAt(i+2)) == '-') { 506 ComElev = 0; // if elevation negative 507 break; 508 } 509 for (int j = i+2; j <= ComputerRead.length(); j++) { 510 if (isDigit(ComputerRead.charAt(j))) { // if the character is number 511 Elevation = Elevation + ComputerRead.charAt(j); 512 } 513 else {break;} 514 } 515 } 516 } 517 518// if <AZxx> received 519 if (Azimuth != ""){ 520 ComAzim = Azimuth.toInt(); 521 ComAzim = ComAzim%360; // keeping values between limits(for trackers with more than 360 deg. rotation) 522 } 523 524// if <ELxx> received 525 if (Elevation != ""){ 526 ComElev = Elevation.toInt(); 527 if (ComElev>180) { ComElev = 0;} 528 if (ComElev>90) { //if received more than 90deg. (for trackers with 180deg. elevation) 529 ComElev = 180-ComElev; //keep below 90deg. 530 ComAzim = (ComAzim+180)%360; //and rotate the antenna on the back 531 } 532 } 533 534// looking for <AZ EL> interogation for antenna position 535 for (int i = 0; i <= (ComputerRead.length()-4); i++) { 536 if ((ComputerRead.charAt(i) == 'A')&&(ComputerRead.charAt(i+1) == 'Z')&&(ComputerRead.charAt(i+3) == 'E')&&(ComputerRead.charAt(i+4) == 'L')){ 537 // send back the antenna position <+xxx.x xx.x> 538 ComputerWrite = "+"+String(TruAzim)+".0 "+String(TruElev)+".0"; 539 //ComputerWrite = "AZ"+String(TruAzim)+".0 EL"+String(TruElev)+".0"; //that's for Gpredict and HamLib 540 Serial.println(ComputerWrite); 541 } 542 } 543} // end SerComm() 544
Downloadable files
Electric Diagram for AC motors
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.
Electric Diagram for AC motors
Electric Diagram for DC motors
Make sure you use this diagram with the code for DC motors. PWM output, Smoother antenna movement
Electric Diagram for DC motors
Electric Diagram for DC motors
Make sure you use this diagram with the code for DC motors. PWM output, Smoother antenna movement
Electric Diagram for DC motors
Electric Diagram for AC motors
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.
Electric Diagram for AC motors
Comments
Only logged in users can leave comments
viorelracoviteanu
0 Followers
•0 Projects
Table of contents
Intro
34
0