Saturday, September 17, 2016

Arduino based Antenna Rotator Controller - Latest Code


Well,  I updated the source code of the antenna rotator controller with magnetic declination entry and UI modifications.

1) Set Point Entry (Press * then enter the set point value and press # to confirm)
2) Inflight ( Hold Key 6 until the inflight filed become empty, then enter the Inflight and press# to confirm
3)Magnetic Declination angle (Hold Key 7 then enter the Magnetic Declination angle then # to confirm)
4) Magnetic Declination minute  (Hold Key 8 then enter the Magnetic Declination minute then # to confirm)
 5)Magnetic Declination East/West  (Hold Key -9 then enter the Magnetic Declination East/West (Press 1 for East and 2 for West) then # to confirm)

Image :





Source Code:


/*
 * An Arduino code  of Antenna Rotator Controller.
 * Copyright (c) 2016 Vinod E S (VU3ESV) , Jayaprakash L V (VU2JLH)
 * Version 1.0 - initial release
 * Version 1.1 - Inflight Entry after holding the "*" Key for 3 seconds
 * Version 10.0 - Magnetic Declination and Display restructuring
 * Version 11.0 - Key pad Entry changes
                 1) Press * then enter the Set Pont then # to confirm
                 2) Hold 6 then enter the Inflight then # to confirm
                 3) Hold 7 then enter the Magnetic Declination angle then # to confirm
                 4) Hold 8 then enter the Magnetic Declination minute then # to confirm
                 5) Hold 9 then enter the Magnetic Declination East/West (Press 1 for East and 2 for West) then # to confirm

 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.


 Harware Information :-

 1) Arduino Mega 2560R3 or its clones
 2) HMC5883L Accelerometer
 3) I2C Expander (NXP) P82B715
 4) 3.2 Inch TFT Display
 5) Momentary push button switchs with 4K7 pull up Resistors
 6) 4K7 Potentiometer
 7) Controller Circuit for Driving Motors see documents attached in this blog for a possible configuration
 */
#include <Wire.h> //I2C Arduino Library
#include <UTFT.h> // UTFT Library from Henning Karlsen (http://www.rinkydinkelectronics.com/library.php)
#include <UTFT_Geometry.h> //UTFT Geometry Library from Henning Karlsen (http://www.rinkydinkelectronics.com/library.php)
#include <Keypad.h>
#include <EEPROM.h>
const int X  = 320;
const int Y  = 160;
const int dm  = 130;
const int x_Offset = 30;
const int y_Offset = 128;
const int z_Offset = 0;
const byte rows = 4; // Four rows
const byte cols = 3; // Three columns
const int maxDegreeDigits = 3; //maximum allowed input length
const int fixedInflight = 5;
const long maxInflight = 25;
const long maxDeclinationDegree = 99;
const long maxDeclinationMinute = 59;
extern uint8_t BigFont[];
extern uint8_t SmallFont[];
extern uint8_t SevenSegmentFull[];
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
#define ORANGE  0xFF00
#define address 0x1E //0011110b, I2C 7bit address of HMC5883
#define EEPROM_ModeStatus_Location         10     // The starting address of the EEPROM where the data is Stored (10.11.12.13)
#define EEPROMSetpointLocation                 14
#define EEPROM_ScaleMax_Location                18
#define EEPROMInflightLocation                 22
#define EEPROMMagDeclinationDegreeLocation 26
#define EEPROMMagDeclinationMinuteLocation 30
#define EEPROMMagDeclinationSignLocation 34
struct EEPROMValue   //EEPROM Data Structure : Taken from G0MGX DDS VFO Code 
{
  union{
    long Value;
    struct
    {
      unsigned char Byte1;
      unsigned char Byte2;
      unsigned char Byte3;
      unsigned char Byte4;
    }
    __attribute__((packed));
  }
  __attribute__((packed));
}
__attribute__((packed));
inline long ReadEEPROMValue(int16_t EEPROMStartAddress);              //Reads the values from EEPROM Like Calibration , set Parameters, etc
inline void SaveEEPROMValue(int16_t EEPROMStartAddress, long Value);  //Save the Value to EEPROM startingfrom the given StartAddress (4 Bytes of Data)
inline long ReadAngleFromAccelerometer(int x_Offset, int y_Offset);
inline void ResetInputBuffer(void);
inline void DrawHead(int x2, int y2, int x1, int y1, int h, int w);
inline void DisplayUserEntry(int x, int y, String userData);
// Define the Keymap
char keys[rows][cols] =
{
  {
    '1','2','3'                                                    }
  ,
  {
    '4','5','6'                                                    }
  ,
  {
    '7','8','9'                                                    }
  ,
  {
    '*','0','#'                                                    }
};
boolean UserEntryStarted = false;
boolean UserEntryFinished = true;
boolean InflightEntryStarted = false;
boolean InflightEntryFinished = true;
boolean DeclinationDegEntryStarted = false;
boolean DeclinationDegEntryFinished = true;
boolean DeclinationMinEntryStarted = false;
boolean DeclinationMinEntryFinished = true;
boolean East_WestEntryStarted = false;
boolean East_WestEntryFinished = true;
boolean stopFlag = true;
boolean modeValue = false;    // modeValue = false (Manual Mode), modeValue = true (Auto Mode)
int inputSelection = 0; // 0  =  SetPoint Input , 1 = inflight input, 2 = magneticDeclenationDegree, 3 = magneticDeclenationMinute ,4  = EAST/WEST
char KeyEntries[3];         //3 characters to store 0 to 360 Degrees
char dataBuffer[60];
char formattedDataBuffer[3];
int dx;
int dy;
int fdx;
int fdy;
int bufPtr = 0;
int CWMotor  =  10;
int CCWMotor = 11;
int Stop_ResumeSignal = 12;
int Manual_Auto_Mode = 13;
int ManualSpeedControl = 9;
long UserEntry = 0;
long DegreeInput = 0;
long Inflight = 0;
long storedModeValue = 0;
long scaleMax  = 0;
long angle = 0;
long previousAngle;
int dxOuter, dyOuter, dxinner, dyinner;
int magneticDeclinationDegree = 0;
int magneticDeclinationMinute = 0;
int magneticDeclinationSign = 0;
//Normal Keyboard Connected To Arduino
// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte rowPins[rows] = {
  8, 7, 6, 5 };
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[cols] = {
  4, 3, 2 };
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, rows, cols );
UTFT utftDisplay(ILI9481,38,39,40,41);
UTFT_Geometry geo(&utftDisplay);
#define  FormatData(x) strcpy_P(dataBuffer, PSTR(x))
void setup(){
  Serial.begin(9600);
  InitializeDisplay(); 
  InitializeKeypad(); 
  InitializeHMC5883();   
  delay(300);
  ConfigureIOPins();
  fdx = X;
  fdy = Y;
  previousAngle = 0;
  DrawInitialScreen();
  DegreeInput = ReadEEPROMValue(EEPROMSetpointLocation);
  Inflight = ReadEEPROMValue(EEPROMInflightLocation);
  if(Inflight<fixedInflight)
  {
    Inflight = fixedInflight;
  }
  storedModeValue = ReadEEPROMValue(EEPROM_ModeStatus_Location);
  scaleMax = ReadEEPROMValue(EEPROM_ScaleMax_Location);
  magneticDeclinationDegree = ReadEEPROMValue(EEPROMMagDeclinationDegreeLocation);
  magneticDeclinationMinute = ReadEEPROMValue(EEPROMMagDeclinationMinuteLocation);
  magneticDeclinationSign = ReadEEPROMValue(EEPROMMagDeclinationSignLocation);
  if (storedModeValue ==0)
  {
    modeValue = false; //Manual Mode
  }
  else if (storedModeValue == 1)
  {
    modeValue = true;  // AutoMode
  }
}
void loop()

  char key = keypad.getKey();
  angle = ReadAngleFromAccelerometer(x_Offset, y_Offset); 
  // 1 ArcMinute =  0.0166667 = Degrees
  if (magneticDeclinationSign == 1) // Magnetic Declination is POSITIVE (ie EAST)
  {
    angle = angle + ((magneticDeclinationDegree *60 + magneticDeclinationMinute)* 0.0166667) ;
  }
  else if(magneticDeclinationSign == 2)  // Magnetic Declination is NEGATIVE (ie WEST)
  {
    angle = angle -((magneticDeclinationDegree *60 *-1 + magneticDeclinationMinute)* 0.0166667) ;
  }
  if((digitalRead( Stop_ResumeSignal) == false)&& stopFlag == true)
  {
    stopFlag = false;
  }
  else if((digitalRead( Stop_ResumeSignal) == false)&& stopFlag == false)
  {   
    stopFlag = true;
  }
  if (stopFlag == true)
  {   
    digitalWrite(CWMotor,LOW);
    digitalWrite(CCWMotor,LOW);
    stopFlag = true;
    utftDisplay.setColor(0, 0, 0);
    utftDisplay.print("      ", RIGHT, 25);
  }
  else
  {
    if((angle< DegreeInput )&& stopFlag == false)
    {   
      digitalWrite(CWMotor,HIGH);
      digitalWrite(CCWMotor,LOW); 
      utftDisplay.setColor(0, 255, 255);
      utftDisplay.print("  CW ", RIGHT, 25);
    }
    if((angle >DegreeInput)&& stopFlag == false)
    {   
      digitalWrite(CWMotor,LOW);
      digitalWrite(CCWMotor,HIGH);
      utftDisplay.setColor(0, 255, 255);
      utftDisplay.print(" CCW ", RIGHT, 25);
    }
    if(( angle == DegreeInput)||
      ( angle > DegreeInput-Inflight)&&
      ( angle < DegreeInput+ Inflight ))  
    {   
      digitalWrite(CWMotor,LOW);
      digitalWrite(CCWMotor,LOW);
      stopFlag = true;
      utftDisplay.setColor(0, 0, 0);
      utftDisplay.print("      ", RIGHT, 25);
    }
  }
  if((digitalRead( Manual_Auto_Mode) == false) && modeValue == false )
  {
    modeValue = true;   
    SaveEEPROMValue(EEPROM_ModeStatus_Location, 1);
  }
  else if((digitalRead( Manual_Auto_Mode) == false) && modeValue == true )
  {
    modeValue = false;
    SaveEEPROMValue(EEPROM_ModeStatus_Location, 0);
  }
  if (modeValue ==  false)
  {
    if(stopFlag == false)
    {
      int spdValue = analogRead(A0);
      spdValue = map(spdValue, 0, 1023, 25 , 255);
      analogWrite(ManualSpeedControl, spdValue);
    }
    else
    {
      analogWrite(ManualSpeedControl, 0);
    }
    utftDisplay.setColor(0, 255, 255);
    utftDisplay.print("Manual ", RIGHT, 295);
  }
  else
  {
    if(stopFlag == false)
    {
      int rotationValue =(int)abs(DegreeInput-  angle); /* Irrespective of the Direction the difference in value needs to be considered for PWM
       // , Stoping is based on Cw/CCW outputs*/
      //Use Serial Print to check the value of rotationValue variable
      int scaleRotationValue =  rotationValue *8;
      int scaleMaxValue = scaleMax *8;
      int newSpeedValue = map(scaleRotationValue,0,scaleMaxValue, 30,255);   //The Scaling needs to be fine tuned based on the Test.     
      analogWrite(ManualSpeedControl, newSpeedValue);
    }
    else
    {
      analogWrite(ManualSpeedControl, 0);
    }
    utftDisplay.setColor(0, 255, 255);
    utftDisplay.print("    Auto ", RIGHT, 295);
  }
  utftDisplay.setFont(SevenSegmentFull);
  utftDisplay.setColor(255, 0, 127);
  int a = (int)angle;
  sprintf(formattedDataBuffer, FormatData("%03d"),a);
  utftDisplay.print(formattedDataBuffer, LEFT, 113);
  utftDisplay.setColor(RED);
  utftDisplay.drawCircle(320,160,9);
  utftDisplay.fillCircle(320,160,9);
  dx = (dm *.9 * cos((angle-90)*3.14/180)) + X;    // calculate X position
  dy = (dm *.9 * sin((angle-90)*3.14/180)) + Y;    // calculate Y position  
  utftDisplay.setColor(BLACK);
  DrawHead(fdx,fdy, X, Y, 10, 10);    // Erase Previous Head
  if( angle < (previousAngle + 2) && angle > (previousAngle - 2) )
  {
    delay(250);     
    angle = previousAngle;
  }
  utftDisplay.setColor(RED);
  DrawHead(dx,dy, X, Y, 10,10);       // Draw Head in new position
  fdx = dx;
  fdy = dy;
  previousAngle =  angle;
  if(UserEntryFinished == true)
  {
    utftDisplay.setFont(BigFont);
    utftDisplay.setColor(0, 255, 0);
    utftDisplay.printNumI(DegreeInput,100,175);
  } 
  if(InflightEntryFinished == true)
  {
    utftDisplay.setFont(BigFont);
    utftDisplay.setColor(0, 255, 0);
    utftDisplay.printNumI(Inflight,100,200);
  }
  if(DeclinationDegEntryFinished == true)
  {
    utftDisplay.setFont(BigFont);
    utftDisplay.setColor(0, 255, 0);
    utftDisplay.printNumI(magneticDeclinationDegree,100,230);
  } 
  if(DeclinationMinEntryFinished == true)
  {
    utftDisplay.setFont(BigFont);
    utftDisplay.setColor(0, 255, 0);
    utftDisplay.printNumI(magneticDeclinationMinute,142,230);
  }
  if(East_WestEntryFinished == true)
  {
    utftDisplay.setFont(BigFont);
    utftDisplay.setColor(0, 255, 0);
    if(magneticDeclinationSign == 1)
    {
      utftDisplay.print("E",180,230);
    }
    else if(magneticDeclinationSign == 2)
    {
      utftDisplay.print("W",180,230);
    }  
  }
  utftDisplay.setColor(0, 100, 255);
  if((angle < 22.5)  && (angle > 337.5 ))utftDisplay.print("     North", LEFT, 260);
  if((angle > 22.5)  && (angle < 67.5 )) utftDisplay.print("North-East", LEFT, 260);
  if((angle > 67.5)  && (angle < 112.5 ))utftDisplay.print("      East", LEFT, 260);
  if((angle > 112.5) && (angle < 157.5 ))utftDisplay.print("South-East", LEFT, 260);
  if((angle > 157.5) && (angle < 202.5 ))utftDisplay.print("     South", LEFT, 260);
  if((angle > 202.5) && (angle < 247.5 ))utftDisplay.print("South-West", LEFT, 260);
  if((angle > 247.5) && (angle < 292.5 ))utftDisplay.print("      West", LEFT, 260);
  if((angle > 292.5) && (angle < 337.5 ))utftDisplay.print("North-West", LEFT, 260);
}
void InitializeDisplay()
{
  utftDisplay.InitLCD();
  utftDisplay.InitLCD(LANDSCAPE);
  utftDisplay.clrScr(); 
  utftDisplay.setFont(BigFont);
  utftDisplay.setColor(255, 128, 0);
  utftDisplay.print("ANTENNA ROTATOR ", LEFT, 12);
  utftDisplay.print("CONTROLLER ", 40, 36);
  utftDisplay.drawLine(440, 160, 460, 160);
  utftDisplay.drawLine(180, 160, 200, 160);
  utftDisplay.drawLine(320, 20, 320, 40);
  utftDisplay.drawLine(320, 280, 320, 300);
  utftDisplay.drawCircle(320, 160, 130);
  utftDisplay.setColor(255, 255, 0);
  utftDisplay.print("BEAM DIR", LEFT, 75);
  utftDisplay.setFont(SmallFont);
  utftDisplay.setColor(255, 100, 100);
  utftDisplay.print("SET DIR", LEFT, 175);
  utftDisplay.print("INFLIGHT", LEFT, 200);
  utftDisplay.print("MAGNETIC",LEFT, 225);
  utftDisplay.print("DECLINATION",LEFT, 245);
  utftDisplay.setColor(255, 0, 0);
  utftDisplay.print("O", 130,  220); 
  utftDisplay.print("'", 175,  220);
  utftDisplay.setFont(BigFont); 
  utftDisplay.print("O", 95,  100);
  utftDisplay.setColor(255, 255, 255);
  utftDisplay.print("VU3ESV : VU2JLH",LEFT, 290); 
}
void InitializeKeypad()
{
  keypad.setDebounceTime(50);
  keypad.setHoldTime(3000);
  keypad.addEventListener(KeypadEventHandler); // Add an event listener for this keypad 
}
void InitializeHMC5883()
{
  // Initialize I2C communications
  Wire.begin();
  //Put the HMC5883 IC into the correct operating mode
  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.write(0x02); //select mode register
  Wire.write(0x00); //continuous measurement mode
  Wire.endTransmission();
}
void ConfigureIOPins()
{
  pinMode(ManualSpeedControl, OUTPUT);
  pinMode(CWMotor,OUTPUT);
  digitalWrite(CWMotor,LOW);
  pinMode(CCWMotor,OUTPUT);
  digitalWrite(CCWMotor,LOW);
  pinMode(Manual_Auto_Mode,INPUT);
  pinMode(Stop_ResumeSignal,INPUT);
  analogReference(DEFAULT);
}
void DrawInitialScreen()
{
  utftDisplay.setColor(0, 255, 0);
  utftDisplay.drawCircle(X,Y,dm); 
  for (float i = 0; i <360; i = i + 22.5 )
  {
    utftDisplay.setColor(255, 128, 0);
    dxOuter = dm * cos((i-90)*3.14/180);
    dyOuter = dm * sin((i-90)*3.14/180);
    dxinner = dxOuter * 0.97;
    dyinner = dyOuter * 0.97;
    utftDisplay.drawLine(dxOuter+X,dyOuter+Y,dxinner+X,dyinner+Y);
  }
  for (float i = 0; i <360; i = i + 45 )
  {
    utftDisplay.setColor(255, 128, 0);
    dxOuter = dm * cos((i-90)*3.14/180);
    dyOuter = dm * sin((i-90)*3.14/180);
    dxinner = dxOuter * 0.92;
    dyinner = dyOuter * 0.92;
    utftDisplay.drawLine(dxinner+X,dyinner+Y,dxOuter+X,dyOuter+Y);
    DisplayUserEntry((X-8),(Y-157),"N");
    DisplayUserEntry((X-8),(Y+145),"S");
    DisplayUserEntry((X+141),(Y-7),"E");
    DisplayUserEntry((X-160),(Y-7),"W");
  }
}
void KeypadEventHandler(KeypadEvent key)
{
  if (key != NO_KEY)
  {
    switch (keypad.getState())
    {
    case IDLE:
    case RELEASED:
      break;
    case HOLD:
      switch (key)
      {
      case '6':
        utftDisplay.setFont(BigFont);
        utftDisplay.setColor(255, 0, 127);
        ResetInputBuffer();
        UserEntry = 0;
        utftDisplay.print("   ",100,200);
        InflightEntryStarted = true;
        InflightEntryFinished = false;
        inputSelection =1  ;            // Inflight
        break;
      case '7':
        utftDisplay.setFont(BigFont);
        utftDisplay.setColor(255, 0, 127);
        ResetInputBuffer();
        UserEntry = 0;         
        utftDisplay.print("   ",100,230);
        DeclinationDegEntryStarted = true;
        DeclinationDegEntryFinished = false;
        inputSelection = 2;          //Declination Degree
        break;
      case '8':
        utftDisplay.setFont(BigFont);
        utftDisplay.setColor(255, 0, 127);
        ResetInputBuffer();
        UserEntry = 0;         
        utftDisplay.print("   ",142,230);
        DeclinationMinEntryStarted = true;
        DeclinationMinEntryFinished = false;
        inputSelection = 3;          //Declination Minute              
        break;
      case '9':
        utftDisplay.setFont(BigFont);
        utftDisplay.setColor(255, 0, 127);
        ResetInputBuffer();
        UserEntry = 0;         
        utftDisplay.print("  ",180,230);
        East_WestEntryStarted = true;
        East_WestEntryFinished = false;
        inputSelection = 4;          //Declinatiom EAST/WEST
        break;
      }
      break;
    case PRESSED:
      switch (key)
      {
      case '#':
        if (inputSelection == 0)
        {
          UserEntryFinished = true;
          UserEntryStarted = false;
          if((UserEntry < 360) )
          {
            //If the User SetPoint is less than Inflight then we can't accept the set point
            if(UserEntry> Inflight)
            {
              DegreeInput = UserEntry;
              SaveEEPROMValue(EEPROMSetpointLocation, DegreeInput);
              scaleMax = abs( (int)(DegreeInput- (long) angle));
              SaveEEPROMValue (EEPROM_ScaleMax_Location, scaleMax);
              utftDisplay.setFont(BigFont);
              utftDisplay.setColor(BLACK);
              utftDisplay.print("    ",100,175);
              stopFlag = false; 
            }
            else
            {
              //Show Error in UI
            }     
          }
          else
          {
            utftDisplay.print("    ",100,175);
            DegreeInput = ReadEEPROMValue(EEPROMSetpointLocation);
          } 
          inputSelection = 0;
        }
        else if (inputSelection == 1)
        {
          InflightEntryFinished = true;
          InflightEntryStarted = false;
          if((UserEntry < maxInflight) )
          {
            Inflight = UserEntry;
            SaveEEPROMValue(EEPROMInflightLocation, Inflight);
            utftDisplay.setFont(BigFont);
            utftDisplay.setColor(BLACK);
            utftDisplay.print("    ",100,200);
            stopFlag = false;
          }
          else
          {
            utftDisplay.print("    ",100,200);
            Inflight = ReadEEPROMValue(EEPROMInflightLocation);
          }
          inputSelection = 0;
        }
        else if (inputSelection == 2)
        {
          DeclinationDegEntryFinished = true;
          DeclinationDegEntryStarted = false;
          if((UserEntry < maxDeclinationDegree) )
          {
            magneticDeclinationDegree = UserEntry;
            SaveEEPROMValue(EEPROMMagDeclinationDegreeLocation, magneticDeclinationDegree);
            utftDisplay.setFont(BigFont);
            utftDisplay.setColor(BLACK);
            utftDisplay.print("    ",100,230);
            stopFlag = false;
          }
          else
          {
            utftDisplay.print("    ",100,230);
            magneticDeclinationDegree = ReadEEPROMValue(EEPROMMagDeclinationDegreeLocation);
          }
          inputSelection = 0;
        }
        else if (inputSelection == 3)
        {
          DeclinationMinEntryFinished = true;
          DeclinationMinEntryStarted = false;
          if((UserEntry < maxDeclinationMinute) )
          {
            magneticDeclinationMinute = UserEntry;
            SaveEEPROMValue(EEPROMMagDeclinationMinuteLocation, magneticDeclinationMinute);
            utftDisplay.setFont(BigFont);
            utftDisplay.setColor(BLACK);
            utftDisplay.print("   ",142,230);
            stopFlag = false;
          }
          else
          {
            utftDisplay.print("   ",142,230);
            magneticDeclinationMinute = ReadEEPROMValue(EEPROMMagDeclinationMinuteLocation);
          }
          inputSelection = 0;
        }
        else if (inputSelection == 4)
        {
          East_WestEntryFinished = true;
          East_WestEntryStarted = false;
          if((UserEntry  == 1)||(UserEntry  == 2) )
          {
            magneticDeclinationSign = UserEntry;
            SaveEEPROMValue(EEPROMMagDeclinationSignLocation, magneticDeclinationSign);
            utftDisplay.setFont(BigFont);
            utftDisplay.setColor(BLACK);
            utftDisplay.print(" ",180,230);
            stopFlag = false;
          }
          else
          {
            utftDisplay.print("x",180,230);
            magneticDeclinationSign = ReadEEPROMValue(magneticDeclinationSign);
          }
          inputSelection = 0;
        }
        break;       
      case '*':
        if (inputSelection ==0)
        {
          utftDisplay.setFont(BigFont);
          utftDisplay.setColor(255, 0, 127);
          utftDisplay.print("   ",100,175);
          ResetInputBuffer();
          UserEntry = 0;
          UserEntryStarted = true;
          UserEntryFinished = false;
        }       
        break;
      case '0':
      case '1':
      case '2': 
      case '3':  
      case '4':
      case '5':
      case '6':
      case '7': 
      case '8':  
      case '9':
        if (bufPtr < maxDegreeDigits)
        {
          KeyEntries[bufPtr] = key;
          bufPtr++;           
          UserEntry = atol (KeyEntries);
          utftDisplay.setFont(BigFont);
          utftDisplay.setColor(255, 0, 127);
          if (UserEntryStarted == true)
          {
            utftDisplay.printNumI(UserEntry,100,175);
          }
          if (InflightEntryStarted == true)
          {
            utftDisplay.printNumI(UserEntry,100,200);
          }
          if (DeclinationDegEntryStarted == true)
          {
            utftDisplay.printNumI(UserEntry,100,230);
          }
          if (DeclinationMinEntryStarted == true)
          {
            utftDisplay.printNumI(UserEntry,142,230);
          }
          if (East_WestEntryStarted == true)
          {
            if(UserEntry == 1)
            {
              utftDisplay.print("E",180,230);
            }
            else if(UserEntry == 2)
            {
              utftDisplay.print("W",180,230);
            } 
          }
        }
        break;   
      }
      break;
    }
  }
}
long ReadAngleFromAccelerometer(int x_Offset, int y_Offset)
{
  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.write(0x03); //select register 3, X MSB register
  Wire.endTransmission();
  //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
  int x,y,z; //triple axis data
  if(6<=Wire.available())
  {
    x = Wire.read() << 8 | Wire.read();
    z = Wire.read() << 8 | Wire.read();
    y = Wire.read() << 8 | Wire.read();
  }
  return atan2((double)y + y_Offset,(double)x + x_Offset)* (180 / 3.141592654) + 180;
}
void DisplayUserEntry(int x, int y, String userData)
{
  utftDisplay.setColor(RED);
  utftDisplay.setFont(BigFont);
  utftDisplay.print(userData,x,y);
}
void DrawHead(int x2, int y2, int x1, int y1, int h, int w)
{
  float dist;
  int dx, dy, x2a, y2a, x3, y3, x4, y4;
  dist = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2));
  dx = x1 + (w/6) * (x2 - x1) / h;
  dy = y1 + (w/6) * (y2 - y1) / h;
  x2a = x1 - dx;
  y2a = dy - y1;
  x3 = y2a + dx;
  y3 = x2a + dy;
  x4 = dx - y2a;
  y4 = dy - x2a;
  geo. drawTriangle(x2,y2,x3,y3,x4,y4);
  geo.fillTriangle(x2,y2,x3,y3,x4,y4);
}
void ResetInputBuffer()
{
  int length = sizeof(KeyEntries);
  for (int i = 0; i < length; i++)
  {
    KeyEntries[i] = '\0';
  }
  bufPtr = 0;
}
//Reads and returns the stored value specified in the EEPROM Start Address
long ReadEEPROMValue(int16_t EEPROMStartAddress)
{
  volatile EEPROMValue eepromVal;
  eepromVal.Byte1 = EEPROM.read(EEPROMStartAddress);
  eepromVal.Byte2 = EEPROM.read(EEPROMStartAddress+1);
  eepromVal.Byte3 = EEPROM.read(EEPROMStartAddress+2);
  eepromVal.Byte4 = EEPROM.read(EEPROMStartAddress+3);
  return eepromVal.Value;
}
/*Stores the specified value in the EEPROM  from Start Address
 EEPROM Write will only happens when the stored value and new value are different.
 This will save the number of Writes to the EEPROM.*/
void SaveEEPROMValue(int16_t EEPROMStartAddress, long Value)
{
  volatile EEPROMValue eepromVal;
  eepromVal.Value = ReadEEPROMValue(EEPROMStartAddress);
  if(eepromVal.Value != Value)
  {
    eepromVal.Value = Value;
    EEPROM.write(EEPROMStartAddress,eepromVal.Byte1);
    EEPROM.write(EEPROMStartAddress+1,eepromVal.Byte2);
    EEPROM.write(EEPROMStartAddress+2,eepromVal.Byte3);
    EEPROM.write(EEPROMStartAddress+3,eepromVal.Byte4);
  }
}

Hope this project helps :)

73's
DE VU3ESV
 

23 comments:

  1. Hi Vinod,

    Great development again from you. Code works great with me. The Arrow head flikkering problem is avoided by modifying.....

    dx = (dm *.9 * cos((angle-90)*3.14/180)) + X; // calculate X position
    dy = (dm *.9 * sin((angle-90)*3.14/180)) + Y; // calculate Y position
    utftDisplay.setColor(BLACK);
    DrawHead(fdx,fdy, X, Y, 10, 10); // Erase Previous Head
    if( angle < (previousAngle + 2) && angle > (previousAngle - 2) )
    {
    delay(250);
    angle = previousAngle;
    }
    utftDisplay.setColor(RED);
    DrawHead(dx,dy, X, Y, 10,10); // Draw Head in new position
    fdx = dx;
    fdy = dy;
    previousAngle = angle;
    if(UserEntryFinished == true)

    ................ to


    dx = (dm *.9 * cos((angle-90)*3.14/180)) + X; // calculate X position
    dy = (dm *.9 * sin((angle-90)*3.14/180)) + Y; // calculate Y position

    if(a != previousAngle)
    {
    utftDisplay.setColor(BLACK);
    DrawHead(fdx,fdy, X, Y, 10, 10); // Erase Previous Head
    utftDisplay.setColor(RED);
    DrawHead(dx,dy, X, Y, 10,10); // Draw Head in new position
    fdx = dx;
    fdy = dy;
    previousAngle = a;
    }

    if(UserEntryFinished == true)
    .....................

    Thanks for sharing. 73

    SHAJI. VU2WJ

    ReplyDelete
    Replies
    1. Hi,

      Thanks for the suggestion. I will try your suggestion and revert with my findings, now I am happy to see that people are interested to tweak the code and refine it

      73's
      VU3ESV

      Delete
  2. Thank you for sharing this code ! 73 YO8SCT.

    ReplyDelete
  3. Hi Vinod,
    Great work on this project!
    I am having some trouble with the Mode Manual/Auto button as the voltage seems to sit at 2.33V instead of 5V when the button is not pressed. I have the pullup resistor as per the circuit but the voltage never seems to go above 2.33V. Is this possibly caused by the fact that this is on pin 13 which has the in-built resistor and LED on the board? The Arduino site discusses this: "NOTE: Digital pin 13 is harder to use as a digital input than the other digital pins because it has an LED and resistor attached to it that's soldered to the board on most boards. If you enable its internal 20k pull-up resistor, it will hang at around 1.7V instead of the expected 5V because the onboard LED and series resistor pull the voltage level down, meaning it always returns LOW. If you must use pin 13 as a digital input, set its pinMode() to INPUT and use an external pull down resistor. "
    Any assistance is greatly appreciated.
    Lino VK3EI

    ReplyDelete
    Replies
    1. Hi Lino,

      I have configured the PINMODE of all the IO pins in the below function
      void ConfigureIOPins()
      {
      pinMode(ManualSpeedControl, OUTPUT);
      pinMode(CWMotor,OUTPUT);
      digitalWrite(CWMotor,LOW);
      pinMode(CCWMotor,OUTPUT);
      digitalWrite(CCWMotor,LOW);
      pinMode(Manual_Auto_Mode,INPUT);
      pinMode(Stop_ResumeSignal,INPUT);
      analogReference(DEFAULT);
      }

      Manual_Auto_Mode is the PIN number 13 and it is configured as INPUT. For the board which I am using works fine with the PULL UP resistor, I will try the PULL DOWN way and see the behavior.
      If the PULL DOWN is working for you then you may have to change the code where the MANUAL and AUTO mode functions are configured.

      ie

      if((digitalRead( Manual_Auto_Mode) == false) && modeValue == false )
      {
      modeValue = true;
      SaveEEPROMValue(EEPROM_ModeStatus_Location, 1);
      }
      else if((digitalRead( Manual_Auto_Mode) == false) && modeValue == true )
      {
      modeValue = false;
      SaveEEPROMValue(EEPROM_ModeStatus_Location, 0);
      }
      to

      if((digitalRead( Manual_Auto_Mode) == true) && modeValue == false )
      {
      modeValue = true;
      SaveEEPROMValue(EEPROM_ModeStatus_Location, 1);
      }
      else if((digitalRead( Manual_Auto_Mode) == true) && modeValue == true )
      {
      modeValue = false;
      SaveEEPROMValue(EEPROM_ModeStatus_Location, 0);
      }
      Hope this helps. If you still find issues in this then please revert with the arduino board information , I will try to check with a different board. I am using the Arduino Mega from Arduino.CC and not checked the behavior with the clones.

      73's
      VU3ESV

      Delete
  4. Hi Vinod,
    Thanks for the feedback.
    I think that I may have had a flaky Arduino board as I swapped it with another one and it came good. All working fine except for one thing.
    Because of the way that I have had to mount my compass, it is giving a reading that is always 180 degrees in error. That is, when the compass is showing North, the rotator is pointing South and similarly East is shown as West. Is there an easy way to change this in the software?
    Any help would be greatly appreciated.
    Cheers
    Lino VK3EI

    ReplyDelete
  5. Hello friend is there any way that i can put this in my Yaesu G-400 rotor controler all I need is that display remains the same as yours (Because I like it weary much). My rotor works an the buttons work but the indicator is dead so can i replace yours digital compas and yust somehow read the voltage directly from rotor an make it work. thenks in advance.
    73s YU5KBM

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hello
      I did the editing and everything works fine
      It is possible to add to the program in manual mode a setpoint potentiometer which replaces the value entered by the keyboard and which corresponds to the 360 ° image which makes it possible to run the engine and to read the position of the compass
      Thank you for your work
      A Frenchman from Paris

      Delete
  7. Great job Vinod!
    I am working in order to use your project using the AC motors employed in the cheapest and smallest rotators and saving the speed control in an easy way. (I will inform you...)
    Those rotors were used for tv antennas, but their are enough for a v/uhf yagis or a little hf beam. Thank to your project, the final result will be very useful because they have not a real direction index on the control box.
    You could easily (for you) modify the project replaying it also for an ELEVATION rotor (with an acceleration sensor, on the display just half circle... 0 - 90 - 0 degrees...):in fact, adding another cheap used rotator, it is possibile to get a complete A/Z rotator for 100 Euros !!!
    So...thank you in advance for the ELEVATION version.
    73s.
    Pino.

    ReplyDelete
    Replies
    1. hello i have just started doing the same thing with cheap 3 wire ac motor rotators have you had any luck with coding my skill are novice at best but hardware wise i am ok regards steve

      Delete
  8. GS-232 protocol.
    Have any of your colleagues managed to add support for the YAESU GS-232 or other similar protocol?

    ReplyDelete
  9. There is no doubt. Impressive product
    Although there is a slight problem in my product
    Colors differ from what is defined
    For example, the background color is white
    "ANTENNA ROTATOR" appears in bright blue
    "VU3ESV: VU2JLH" appears in black

    And so on..

    What do you think is the problem?
    I would be very happy to repair and use this amazing product

    Thanks in advance
    Note - I have not yet connected I2C EXTENDER

    Yoram

    ReplyDelete
  10. Hello yoram shalom
    It seems to me that your screen is a Chinese product ili9481 driver
    inverted colors and also the image in mirror mode
    the library is different
    here is a link to update your library
    http://www.raspberrypiwiki.com/download/arduino/
    have already tried the examples and change the compass code
    in
    #include // UTFT Library
    #include // UTFT geometry library

    ReplyDelete
  11. Hi Vinod,
    My name is Frik, ZS6FZ from South Africa.
    Very nice project most impressive.
    I sit with one problem, I cannot get the specified TFT display here in SA but got hold of a similar 3.2 display for the Mega with HX8357C driver at 480x320 resolution. I am very new to Arduino programming and I am unsuccessful in my attempt to change the code to accommodate this screen. Can you help me please!!!!!!!!!!!!!!

    73
    Frik Wolff ZS6FZ
    email = zs6fz@webmail.co.za

    ReplyDelete
    Replies
    1. Hi,

      The UTFT library from Henning Karlsen supports some specific display drivers and the same can be viewed from the library folder.

      In the Rotator controller program I have used a TFT display with ILI9481, and the definition looks like this in the code.

      UTFT utftDisplay(ILI9481,38,39,40,41);

      You may try the HX8357C in place of ILI9481, but this works only of the UTFT library supports the chip.

      VU3ESV

      Delete
    2. Thanks Vinod I will give it a go and give you feedback
      73
      Frik

      Delete
  12. Hi Vinod,

    Very nice project :)

    Curious on how to calibrate the unit. No matter what orientation of the compass module, it does not point North. Then if I turn 180°, the reading on the display does not correspond. I do see a full range of readings, so I know the compass works, just no face/edge points North.
    Any ideas please?

    Rick VK6RK

    ReplyDelete
  13. Last times I founded Your project. I would like to replace my controller from Speed Electronic. Looks fine but how I set CW and CCW not blinking... Make me nervous :) :)

    ReplyDelete
  14. This comment has been removed by the author.

    ReplyDelete
  15. Hi Vindod,

    Is there a parts list earlier in the post? I am very interest in the rotator controller. I have an M2 Orion rotator that uses a reed switch and counter to indicate direction. The compass would work well for that rotator. Has any one written detailed instructions for the controller?

    ReplyDelete
  16. Hello Vinod..

    nice to build your amazing project
    i use GY271 module with HMC5883L chipset
    it's not work for me, LCD not showing current potition
    can you give me some update for GY271 compass module?
    help me, please

    my email: alviennocornelius@gmail.com


    regards
    73 YC3MES

    ReplyDelete
  17. Good day to all
    I have built the controller but I have a bug. Arrow on direction display completely dissapears when pointing north 0 degrees

    ReplyDelete