AZ/EL Controller for Satellite Antenna Tracking

I am currently working on a Azimuth and Elevation controller to accept the output from the Linux program "Predict" by KD2BD. I have got a working system but I am sure it needs some tweaking to make it more efficient.

A couple of problems that I seem to have is: Sometimes the rate exceeds that "decoding" process. Meaning the servos move to a random position then back again. Also I need to figure out how to make the AZ 360 degrees with a modified servo.

Some tweaking that it needs is: The code is probably an inefficient way to capture and determine the AZ/EL. Problem is "Predict" shifts the bytes when the AZ drops below 100 degrees. That causes the array to shift one byte which throws off the EL reading. The code I wrote works, but I am sure there is a better way to do it.

Sample "Predict" on the serial line: AZ351.0 EL103.0

When this project is compete it will be a benefit to all amateurs that are looking to EME (Earth Moon Earth), and Satellite tracking. Any help would be greatly appreciated!

#include <Servo.h> 
#include <stdlib.h>
int pinArray[2] = {2, 3};       // digital pins for the servos
int minPulse = 600;             // minimum servo position
int maxPulse = 2400;           // maximum servo position
int refreshTime =  20;          // time (ms) between pulses (50Hz)
int i;                                // iterator
int s;                              //SERIAL byte data
int servoPin;                 // control pin for current servo
int predictInput[12];     // raw input from serial buffer, min 12 bytes
int pulseWidth;            // servo pulse width
int azpulseWidth;        //Azimuth pulse width
int elpulseWidth;        //Elevation pulse width
int servoPosition;       // commanded servo position, 0-180 degrees
int pulseRange;         // maxPulse - minPulse
int centerServo;         // servo starting point
long lastPulse = 0;   // recorded time (ms) of the last pulse
int servo;                    // which servo to pulse? 1-2
int servo1[2];             // servo #1 array{pin, pulsewidth}
int servo2[2];             // servo #2 array{pin, pulsewidth}
int pin;                        // digital pin for pulse() function
int puls;                     // pulsewidth for pulse() function
int startbyte;              // start byte, begin reading input
void setup() {
  // loop through both servo pins
  // and set them as OUTPUT
  for (i=0;i<2;i++) {
    pinMode(pinArray[i], OUTPUT);
  }  
  // servo starting point (center)
  pulseRange  = maxPulse - minPulse;
  centerServo = maxPulse - ((pulseRange)/2);
  pulseWidth  = centerServo;
  // map pins to servos
  servo1[0] = pinArray[0];  // servo #1 is pin 2
  servo2[0] = pinArray[1];  // servo #2 is pin 3
  // center all servos
  servo1[1] = centerServo;
  servo2[1] = centerServo;
  // open serial connection
  Serial.begin(9600); //Predicts default serial baud rate
   Serial.flush();    //Flush extraneous serial data
}
void loop() {
  // wait for serial input full serial line data (min 12 bytes in buffer)
   if (Serial.available() > 12) {
    //read the first byte
    startbyte = Serial.read();
    // check for the start of the serial string (65) ASCII (A)
    if (startbyte == 65) {    
     // then get the whole line serial input line
      for (s=0;s<12;s++) {  
        predictInput[s] = Serial.read();
      }
  char az[4] = { predictInput[1], predictInput[2], predictInput[3] }; 
  char el[3] = { predictInput[9], predictInput[10] };
 char els[3] = { predictInput[8], predictInput[9] };
int az_i = atoi(az);  //Convert azimuth char string to integer
int el_i =  atoi(el);  //Convert elevation char string to integer
int els_i = atoi(els); 
if (els_i > el_i ) {
elpulseWidth = minPulse + (els_i * (pulseRange/180));
elpulseWidth = minPulse + (els_i * (pulseRange/180));
}  else {
   elpulseWidth = minPulse + (el_i * (pulseRange/180));
   elpulseWidth = minPulse + (el_i * (pulseRange/180));
}
    // compute pulseWidth from Predict Input for Azimuth
     azpulseWidth = minPulse + (az_i * (pulseRange/180));
     azpulseWidth = minPulse + (az_i * (pulseRange/180));
      if (pulseWidth > maxPulse) { 
        pulseWidth = maxPulse; 
      }
      if (pulseWidth < minPulse) { 
        pulseWidth = minPulse; 
      }
      // assign new pulsewidth to appropriate servo
        servo1[1] = azpulseWidth;
        servo2[1] = elpulseWidth;
         }
  }
  // pulse each servo
  if (millis() - lastPulse >= refreshTime) {
    pulse(servo1[0], servo1[1]);
    pulse(servo2[0], servo2[1]);
    // save the time of the last pulse
    lastPulse = millis();
  }
}
  void pulse(int pin, int puls) {
  digitalWrite(pin, HIGH); // start the pulse
  delayMicroseconds(puls); // pulse width
  digitalWrite(pin, LOW);  // stop the pulse
 delay(30);
 Serial.flush();
}

Nice. Is this driving standard hobby servos with PWM, or is it driving some sort of standard (e.g. Yaesu) AZ/EL rotator?

One of the (many) projects in the back of my mind is an antenna pointing system that tracks a target based on its APRS position report (and hopefully, using ded reckoning, a continuous track, not just updating when it gets a packet). As an added twist, I want to do it from a moving vehicle. :slight_smile:

-j

It is currently driving hobby servos. This is more a less a small scale version that I want to upscale to larger servo motors or DIY servo with potentiometers. The target for this project is to point small 70cm or 2 meter yagis to the correct satellite position.

As far as your APRS idea goes that would be really cool to do. Something like a track finder. I can see some "Fox hunting" type projects like that too. Poking around I have seen some electronic compass projects that would fit nicely in that project.

I am a first time programmer/arduino user so this is a challenge for me, although an enjoyable one.

I think the typical rotator is just a geared motor with a pot for feedback, so you are on the right track.

The azimuth for the moving version is pretty simple - just use a compass (or GPS heading) and do a bit of math to get the azimuth to the target.

Determining the tilt of the vehicle in order to get the elevation correct could be a bit more challenging; I'm thinking 3 axis accelerometer (and more math).

The antenna I want to drive is a small 900MHz yagi; a couple of hefty hobby servos, one capable of 360 degree rotation, may be all it takes.

-j

Ive been searching the internet for days looking for just this. I work on a ship and really would like to build a SAT tracker. Very accurate gyro input is available. So is GPS.
I am new to Arduino and programming. But I am building a CNC plasma cutter and refitting a CNC mill. So at least i have a starting point to work from and can make some cool brackets etc.

hi blazer34i,

nice project you have here, i will like to know how far did you went? im thinking on building up a similar system using step motors. But, only until i get the structure for AZ/EL working, i will began wiring things up to the arduino.

please let me know or share picts of your set up, my antenna is a 4 elements yagi that will be easy to drive with such a DIY solution.

regards,
/a