Автор Тема: Контроллер антенной поворотки на Arduino  (Прочитано 16865 раз)

Оффлайн ES1LL

  • Администратор
  • Member
  • *****
  • Сообщений: 1643
  • ex. ES1ACS
    • Радиолюбители Эстонии
Доступно только для пользователейArduino Mega2560 based Antenna Rotator Controller

Well after a long time I am back with a new project !

This is an attempt to build an Antenna rotator controller using Arduino
Mega 2560 with a nice user interface showing the actual position of the
antenna.

Idea of building a rotator controller is from my brother VU2JLH.

Following features are added in the controller project

1) Collect the Antenna position using HMC5883 Digital Compas
2) Auto/Manual mode operation . A potentiometer is used to control the speed in manual mode.
3) Stop/Resume inputs to pause the rotation and continue from that point.
4) 3.2 Inch TFT display
5) 3X4 Keypad for entering the target values.
6) Inflight entry to compensate the antenna rotation due to inertia.
7) I2C extender for long cable usage between shack and antenna.

HMC5883 will be attached to the antenna and a pair of I2C extenders are
 used between the Arduino and HMC5883 . Use of I2C Extenders allow usage
 of long cable between shack and antenna tower.

3.2 inch TFT display is used for the UI. User can enter the Set point using the 3X4 Keypad.

Sequence to enter set-point is

1) Press the * key
2) Key in the  set-point value (0-360 deg)
3) Press the  # key

Controller will decide the rotation mode (clockwise or counter clockwise) based on the current position and set-point

An inflight value can be entered for stopping the Antenna before
reaching the set point. This is applicable in case heavy antennas are
controlled using this controller .

Sequence to enter inflight is hold the * key for 3 seconds, enter the inflight value , press the  # key.

Screen Shots





Schematics



Schematics of Motor Control Board






Source code of the Controller 

/*
 * An Arduino code  of Antenna Rotator Controller.
 * Copyright © 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

  * 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) HMC5883 Accelerometer
 3) I2C Expander (NXP)
 4) 2.8Inch TFT Display
 5) Momentary push button switchs
 6) Potentiometer
 7) H-Bridge for driving the Motors
 */

#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 centreX  = 320;
const int centreY  = 160;
const int diameter = 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;

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

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 double ReadAngleFromAccelerometer(int x_Offset, int y_Offset);
inline void ResetInputBuffer(void);

// 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 stopFlag = true;
boolean modeValue = false;    // modeValue = false (Manual Mode), modeValue = true (Auto Mode)
boolean inputSelection = false; // false  =  SetPoint Input , True = inflight input

char KeyEntries[3];        //3 characters to store 0 to 360 Degrees
char dataBuffer[60];
char formattedDataBuffer[3];

int dx;
int dy;
int last_dx;
int last_dy;
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;

double angle = 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);

#define  FormatData(x) strcpy_P(dataBuffer, PSTR(x))

void setup(){
  Serial.begin(9600);
  utftDisplay.InitLCD();
  utftDisplay.InitLCD(LANDSCAPE);
  utftDisplay.clrScr();
  utftDisplay.setFont(BigFont);
  utftDisplay.setColor(255, 0, 0);
  utftDisplay.print("ANTENNA ROTATOR ", LEFT, 16);
  utftDisplay.print("CONTROLLER ", 40, 40);
  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.setColor(255, 255, 0);
  utftDisplay.print("BEAM DIR", LEFT, 87);
  utftDisplay.setFont(SmallFont);
  utftDisplay.setColor(255, 100, 100);
  utftDisplay.print("SET DIR", LEFT, 210);
  utftDisplay.print("INFLIGHT", LEFT, 230);
  utftDisplay.setFont(BigFont);
  utftDisplay.setColor(255, 0, 0);
  utftDisplay.print("O", 95,  115);
  utftDisplay.setColor(255, 255, 255);
  utftDisplay.print("VU3ESV : VU2JLH",LEFT, 290);
  // 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();
  delay(300);
  last_dx = centreX;
  last_dy = centreY;

  DegreeInput = ReadEEPROMValue(EEPROMSetpointLocation);
  Inflight = ReadEEPROMValue(EEPROMInflightLocation);
  if(Inflight<fixedInflight)
  {
    Inflight = fixedInflight;
  }
  storedModeValue = ReadEEPROMValue(EEPROM_ModeStatus_Location);
  scaleMax = ReadEEPROMValue(EEPROM_ScaleMax_Location);
  if (storedModeValue ==0)
  {
    modeValue = false; //Manual Mode
  }
  else if (storedModeValue == 1)
  {
    modeValue = true;  // AutoMode
  }
  keypad.setDebounceTime(50);
  keypad.setHoldTime(3000);
  keypad.addEventListener(KeypadEventHandler); // Add an event listener for this keypad

  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);
}
double 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();
  }
  DrawRotatorPosition();
  return atan2((double)y + y_Offset,(double)x + x_Offset)* (180 / 3.141592654) + 180;
}
void loop()
{
  char key = keypad.getKey();
  angle = ReadAngleFromAccelerometer(y_Offset, x_Offset);
  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(((long)angle< DegreeInput )&& stopFlag == false)
    {  
      digitalWrite(CWMotor,HIGH);
      digitalWrite(CCWMotor,LOW);
      utftDisplay.setColor(0, 255, 255);
      utftDisplay.print("  CW ", RIGHT, 25);
    }
    if(((long)angle >DegreeInput)&& stopFlag == false)
    {  
      digitalWrite(CWMotor,LOW);
      digitalWrite(CCWMotor,HIGH);
      utftDisplay.setColor(0, 255, 255);
      utftDisplay.print(" CCW ", RIGHT, 25);
    }
    if(((long) angle == DegreeInput)||
      ((long) angle > DegreeInput-Inflight)&&
      ((long) 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, 0 , 255);
      analogWrite(ManualSpeedControl, spdValue);
    }
    else
    {
      analogWrite(ManualSpeedControl, 0);
    }
    utftDisplay.setColor(0, 255, 255);
    utftDisplay.print("Manual ", RIGHT, 295);
  }
  else
  {
    if(stopFlag == false)
    {
      int rotationValue =abs( (int)(DegreeInput- (long) 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 *4;
      int scaleMaxValue = scaleMax *4;
      int newSpeedValue = map(scaleRotationValue,0,scaleMaxValue,
0,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);
  }
  dx = (diameter * cos((angle-90)*3.14/180)) + centreX;    // calculate X position
  dy = (diameter * sin((angle-90)*3.14/180)) + centreY;    // calculate Y position
  utftDisplay.setColor(BLACK);
  DrawArrow(last_dx,last_dy, centreX, centreY, 8, 8);        // Erase last arrow    
  utftDisplay.setColor(GREEN);
  DrawArrow(dx,dy, centreX, centreY, 8, 8);                  // Draw arrow in new position
  last_dx = dx;
  last_dy = dy;
  delay(25);
  utftDisplay.setFont(SevenSegmentFull);
  utftDisplay.setColor(255, 0, 127);
  int a =(int)angle;
  sprintf(formattedDataBuffer, FormatData("%03d"),a);
  utftDisplay.print(formattedDataBuffer, LEFT, 135);
  if(UserEntryFinished == true)
  {
    utftDisplay.setFont(BigFont);
    utftDisplay.setColor(0, 255, 0);
    utftDisplay.printNumI(DegreeInput,80,205);
  }
  if(InflightEntryFinished == true)
  {
    utftDisplay.setFont(BigFont);
    utftDisplay.setColor(0, 255, 0);
    utftDisplay.printNumI(Inflight,80,225);
  }
  utftDisplay.setFont(BigFont);
  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 KeypadEventHandler(KeypadEvent key)
{
  if (key != NO_KEY)
  {
    switch (keypad.getState())
    {
    case IDLE:
    case RELEASED:
      break;
    case HOLD:
      switch (key)
      {
        case '*':      
        if (inputSelection == true)
        {
          utftDisplay.setFont(BigFont);
          utftDisplay.setColor(255, 0, 127);
          utftDisplay.print("   ",80,225);
          ResetInputBuffer();
          UserEntry = 0;
          InflightEntryStarted = true;
          InflightEntryFinished = false;
        }
        break;
      }
      break;
    case PRESSED:
      switch (key)
      {
      case '#':
        if (inputSelection == false)
        {
          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("    ",80,205);
              stopFlag = false;
            }
            else
            {
              //Show Error in UI
            }    
          }
          else
          {
            utftDisplay.print("    ",80,205);
            DegreeInput = ReadEEPROMValue(EEPROMSetpointLocation);
          }
          inputSelection = true;
        }
        else
        {
          InflightEntryFinished = true;
          InflightEntryStarted = false;
          if((UserEntry < maxInflight) )
          {
            Inflight = UserEntry;
            SaveEEPROMValue(EEPROMInflightLocation, Inflight);
            utftDisplay.setFont(BigFont);
            utftDisplay.setColor(BLACK);
            utftDisplay.print("    ",80,225);
            stopFlag = false;
          }
          else
          {
            utftDisplay.print("    ",80,225);
            Inflight = ReadEEPROMValue(EEPROMInflightLocation);
          }
          inputSelection = false;
        }
        break;      
      case '*':
        if (inputSelection ==false)
        {
          utftDisplay.setFont(BigFont);
          utftDisplay.setColor(255, 0, 127);
          utftDisplay.print("   ",80,205);
          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,80,205);
          }
          if (InflightEntryStarted == true)
          {
            utftDisplay.printNumI(UserEntry,80,225);
          }
        }
        break;  
      }
      break;
    }
  }
}

void DisplayUserEntry(int x, int y, String userData)
{
  utftDisplay.setColor(RED);
  utftDisplay.setFont(BigFont);
  utftDisplay.print(userData,x,y);
}

void DrawArrow(int x2, int y2, int x1, int y1, int arrowLength, int arrowWidth)
{
  float distance;
  int dx, dy, x2Outer,y2Outer,x3,y3,x4,y4,k;
  distance = sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2));
  dx = x2 + (x1 - x2) * arrowLength / distance;
  dy = y2 + (y1 - y2) * arrowLength / distance;
  k = arrowWidth / arrowLength;
  x2Outer = x2 - dx;
  y2Outer = dy - y2;
  x3 = y2Outer * k + dx;
  y3 = x2Outer * k + dy;
  x4 = dx - y2Outer * k;
  y4 = dy - x2Outer * k;
  utftDisplay.drawLine(x1, y1, x2, y2);
  utftDisplay.drawLine(x1, y1, dx, dy);
  utftDisplay.drawLine(x3, y3, x4, y4);
  utftDisplay.drawLine(x3, y3, x2, y2);
  utftDisplay.drawLine(x2, y2, x4, y4);
}

void DrawRotatorPosition()
{
  int dxOuter, dyOuter, dxi, dyi;
  utftDisplay.setColor(255, 128, 0);
  utftDisplay.drawCircle(centreX,centreY,diameter);  // Draw compass circle
  for (float i = 0; i <360; i = i + 22.5) {
    utftDisplay.setColor(255, 128, 0);
    dxOuter = diameter * cos((i-90)*3.14/180);
    dyOuter = diameter * sin((i-90)*3.14/180);
    dxi = dxOuter * 0.98;
    dyi = dyOuter * 0.98;
    utftDisplay.drawLine(dxi+centreX,dyi+centreY,dxOuter+centreX,dyOuter+centreY);
  }
  DisplayUserEntry((centreX-8),(centreY-157),"N");
  DisplayUserEntry((centreX-8),(centreY+145),"S");
  DisplayUserEntry((centreX+141),(centreY-7),"E");
  DisplayUserEntry((centreX-160),(centreY-7),"W");
}

void ResetInputBuffer()
{
  int length = sizeof(KeyEntries);
  for (int i = 0; i < length; i++)
  {
    KeyEntries = '\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);
  }
}

I have used the UTFT library from Henning Karlsen  (Rinky-Dink
Electronics) and the same has to be downloaded before compiling the
sketch.

Please note : This code is not meant for any commercial use.

http://100nf.blogspot.com.ee/2016....or.html
Yaesu FT-450D. Clubs: EPC#24320 DMC#07765 RDRC#902 WCAG#203

UK8AIM

  • Гость
Re: Контроллер антенной поворотки на Arduino
« Ответ #1 : Октябрь 18, 2019, 15:05:55 »
Доброго времени суток!
Где то года полтора назад решился попробовать работать через спутники. Собрал двухдиапазонную антенну 144-430  4х6 элементов, поработал, понравилось.
Одно плохо - антенна установлена фиксировано и имеет возможность крутить по азимуту вручную  (закреплена на балконе)
в секторе 300-40 градусов, а теперь и того меньше - кондиционер поставили, внешний блок мешает.
Естественно и связей со странами не богато.
Решил соорудить поворотное устройство. Порылся в сети, наткнулся на проект индийских радиолюбителей,
Vinod E S (VU3ESV) , Jayaprakash L V (VU2JLH) (http://100nf.blogspot.com.ee/2016....or.html) предложили реализовать
контроллер управления и отображение азимута на базе Ардуино Мега 2650. Сейчас эта страница уже недоступна.
Составил список необходимых деталей, не стал заморачиваться с аналогами и искать их в Ташкенте (оно ещё и дороже будет),
заказал почти всё на Алиэкспресс.
Пока ждал посылок (уж больно долго, от месяца до двух, а TFT 3,2 так и не приехал, пришлось заново заказывать комплектно со второй Мегой),
так вот - пока ждал, нарисовал платки блока реле и удлинителя шины I2C.



Приобрел комплектующие, собрал макет, залил скетч "Arduino based Antenna Rotator Controller - Latest Code" - результат нулевой.
Долго ковырялся (программер ещё тот!), лазал в сети пока на наткнулся на Ваш сайт.
Скопировал текст программы, прошил и... ЗАРАБОТАЛО!!!
Единственное НО, при проверке скетча в Ардуино ИДЕ выскакивала ошибка:

In function 'void ResetInputBuffer()':

NEW_Rotator:516:16: error: incompatible types in assignment of 'char' to 'char [3]'

     KeyEntries = '\0';

После того как я её за//ил , ошибка пропала. Скетч прописался и индикатор ожил. Вводятся параметры с клавиатуры, отрабатываются команды
на включение привода, отображается направление...И опять НО - азимут показывается случайный, нет информации с акселерометра.
Его я проверил отдельно, он работает, правда не калибровал. А под прогой контроллера - молчит. В порту ни чего не видно.
Исходя из сказанного выше встал вопрос:
Как побороть //   KeyEntries = '\0'; и заставить читать акселерометр GY-271? (адрес акселерометра я заменил на отсканированный I2C сканером).
KeyEntries = '\0' одолел на следующий день после возникновения вопроса который встал  ;) . Поневоле, ковыряясь в коде программы и поиске
инфы по теме программирования на С++ (ардуиновский язык похож, ну о-о-очень!) приобретаешь какие то знания. Так вот они (ковыряния) и помогли
поставить между "KeyEntries" и  "= '\0'" скобочки с i  " [ i ] " !!! Всего то!!! Ну, как говорится: "Век живи, век учись". Правда я не понял почему в скопированном
из статьи авторов тексте прошивки пропал этот фрагмент. Ну да ладно, проехали!
Свой вопрос "Как побороть..." я в личном обращении адресовал Сергею ES1ACS. На что он посоветовал использовать магнетометр HMC5883L на плате изображенной
на схеме соединений узлов контроллера. И прислал ссылку  https://www.youtube.com/watch?v=twirOS1tPvU .
У меня вот такая плата:

Она собрана на чипе DB5883L, а он оказался ваще-е-е капризный.
 Буду заказывать https://ru.aliexpress.com/item/32912371637.html?spm=a2g0o.productlist.0.0.9e0f566fzX6lHh&algo_pvid=e1520f7d-e53c-4b35-a5c0-cfc051346049&algo_expid=e1520f7d-e53c-4b35-a5c0-cfc051346049-0&btsid=6f43fc24-7f7f-480b-89bf-b9d67ee1b21f&ws_ab_test=searchweb0_0,searchweb201602_7,searchweb201603_55

Ну, а по поводу привода: есть два, один из бортовой механизации самолета (я в него уже многооборотный резистор вмонтировал с парой шестерен). Там стоит
двигатель постоянного тока с двумя обмотками "по часовой" и "против часовой" с общим " - ". Блок реле упрощается.
И второй:


Ну, пока будет приезжать магнетометр, буду собирать платки.
О полученном результате сообщу дополнительно.

P.S.
По информации, почерпнутой из Веб, для более надежного отображения азимута стоит использовать связку HMC5883L + MPU6050 (акселерометр).
Правда придется править программу, тут уж сам точно не справлюсь. Хотя...

UK8AIM

  • Гость
Re: Контроллер антенной поворотки на Arduino
« Ответ #2 : Январь 30, 2020, 09:34:17 »
Здравствуйте коллеги!
Так и не дождался от продавца на Алиэкспресс нужного магнетометра.
Долго отписывался о том , что у него проблемы с таможней и тд. и т.п.
В конце концов сказал - кончились платки.
Сегодня решил заказать заново у другого продавца. Полез искать нужную платку,
нашел:
https://aliexpress.ru/item/32607602280.html?spm=a2g0o.productlist.0.0.7ab862493JdXKF&algo_pvid=f80fbd01-39dc-4aab-ae06-d52400c4487f&algo_expid=f80fbd01-39dc-4aab-ae06-d52400c4487f-2&btsid=b55c8c59-2a0a-4016-9937-073d905b48e4&ws_ab_test=searchweb0_0,searchweb201602_8,searchweb201603_53

Ради любопытства почитал отзывы. Один из них (от индийского покупателя) заставил призадуматься:

Доставка: 菜鸟超级经济-燕文
Получен в хорошем состоянии и в ближайшее время через бесплатную доставку. Это для уточнения некоторых мелких деталей. Продукт 100% работает и совместим, но, пожалуйста, обратите внимание, что это чип QMC588L, а не чип HMC5883L от Honeywell, как положено Adafruit версии. Но никакого вреда. Он имеет все функции, как HMC5883L, но только другой IPC адрес, который вам, возможно, придется изменить в ariyumo header файл для этой библиотеки. В противном случае библиотеки adafriuit и HMC5883L не работают. Поэтому, прежде чем вы совершите ошибку для неисправного чипа, пожалуйста, позаботьтесь о вышеуказанных. Если бы я сделал много отладок и погуглил, прежде чем узнать это. Я рекомендую Mecha_QMC5883L Library. Он работает как шарм. Спасибо за хорошее предложение. 12 Sep 2019 02:02

Решил следовать совету. Поколдовал со скетчем, взял фрагмент записи и чтения регистров магнетометра из примеров идущих вместе с библиотекой. И... ЗАРАБОТАЛО!!!
Правда на экранчик выводится не позиция оси Х, а как бы ось Z. И показания сильно зависят от наклона по другим осям.
К тому же в Нете говорят о необходимости калибровки компаса, чего я еще не сделал.
Ну, будем разбираться дальше. (До этого было не до поделок, сильно болела супруга UK8AKO и её нет теперь рядом  :'( :'( :'(  )

UK8AIM

  • Гость
Re: Контроллер антенной поворотки на Arduino
« Ответ #3 : Январь 30, 2020, 12:43:29 »
Два фрагмента измененных в тексте программы:

строки 152 - 157:
  Wire.write(0x0B); // Tell the HMC5883 to Continuously Measure
  Wire.write(0x01); // Set the Register
  Wire.endTransmission();
  Wire.beginTransmission(address); //start talking
  Wire.write(0x09); // Tell the HMC5883 to Continuously Measure
  Wire.write(0x1D); // Set the Register

строки 194 - 208:
int x,y,z; //triple axis data
  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.write(0x00); //select register 3, X MSB register
  Wire.endTransmission();
  //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
    if(6<=Wire.available()) {
    x = Wire.read(); //MSB  x
    x |= Wire.read() << 8; //LSB  x
    z = Wire.read(); //MSB  z
    z |= Wire.read() << 8; //LSB z
    y = Wire.read(); //MSB y
    y |= Wire.read() << 8; //LSB y
  }

UK8AIM

  • Гость
Re: Контроллер антенной поворотки на Arduino
« Ответ #4 : Февраль 05, 2020, 11:59:40 »
Два фрагмента измененных в тексте программы:

строки 152 - 157: МОЖНО УДАЛИТЬ ИЗ ТЕКСТА ПРОГРАММЫ
  Wire.write(0x0B); // Tell the HMC5883 to Continuously Measure
  Wire.write(0x01); // Set the Register
  Wire.endTransmission();
  Wire.beginTransmission(address); //start talking
  Wire.write(0x09); // Tell the HMC5883 to Continuously Measure
  Wire.write(0x1D); // Set the Register


строки 194 - 208:
int x,y,z; //triple axis data
  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.write(0x00); //select register 3, X MSB register
  Wire.endTransmission();
  //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
    if(6<=Wire.available()) {
    x = Wire.read(); //MSB  x
    x |= Wire.read() << 8; //LSB  x
    z = Wire.read(); //MSB  z
    z |= Wire.read() << 8; //LSB z
    y = Wire.read(); //MSB y
    y |= Wire.read() << 8; //LSB y
  }

UK8AIM

  • Гость
Re: Контроллер антенной поворотки на Arduino
« Ответ #5 : Февраль 05, 2020, 12:02:16 »
Продолжаю разбираться с регистрами м/сх QMC5883.
Адреса регистров сильно отличаются от м/сх HMC5883.

Оффлайн ES1LL

  • Администратор
  • Member
  • *****
  • Сообщений: 1643
  • ex. ES1ACS
    • Радиолюбители Эстонии
Re: Контроллер антенной поворотки на Arduino
« Ответ #6 : Февраль 05, 2020, 16:10:03 »
Искренние соболезнования всвязи с утратой родного человека :(

Насчёт китайцев - у них порой такого навертят, что приходится звново создавать велосипед...
Yaesu FT-450D. Clubs: EPC#24320 DMC#07765 RDRC#902 WCAG#203