Hello, Guest!
 
 

 
 
  Objects Tiiips Categories
Yaesu G-5500DC: progetto Arduino tracking satellitare - Parte 4
"Descrizione"
by Al222 (24916 pt)
2026-Jun-10 06:41

Yaesu G-5500DC: progetto Arduino tracking satellitare - Parte 4

Comandi Hamlib usati

Per avviare il server rotctld con Arduino collegato alla porta COM4:

cd "C:\Program Files\hamlib-w64-4.7.1\bin"
rotctld.exe -m 603 -r COM4 -s 9600 -T 127.0.0.1 -t 4533 -vvvv

Il modello 603 corrisponde all’interfaccia Yaesu GS-232B. La porta COM4 va sostituita con la porta reale assegnata ad Arduino dal sistema operativo.

Per verificare la comunicazione tramite Hamlib:

cd "C:\Program Files\hamlib-w64-4.7.1\bin"
rotctl.exe -m 2 -r 127.0.0.1:4533

All’interno di rotctl, i comandi principali sono:

p minuscola legge la posizione del rotore Azimut e del rotore Elevazione

con P maiuscola si scrivono le posizioni che i rotori raggiungeranno

Nel mio test, Hamlib ha letto correttamente la posizione del rotore e ha comandato il movimento tramite Arduino, confermando che la catena:

Gpredict → rotctld / Hamlib → Arduino Mega → PC817 → Yaesu G-5500DC

è operativa.

Configurazione Gpredict

In Gpredict, il rotore va collegato al server locale rotctld lasciato aperto in background.

Per ora l’azimut è limitato a 0–360°, perché la calibrazione iniziale è stata eseguita su questo intervallo. In seguito si potrà estendere la gestione fino a 450°, sfruttando tutta la corsa disponibile del G-5500DC. 

Il programma da caricare in Arduino per eseguire il tracking con Yaesu G-5500 è il seguente:

/*

  rotore_may15a.ino

  Arduino Mega 2560 -> Yaesu G-5500DC External Control DIN 8

  Emulazione Yaesu GS-232B per Hamlib rotctld model 603.


  Versione con movimento normale/continuo, non a impulsi.


  Pin:

    D8  RIGHT / CW

    D9  LEFT  / CCW

    D10 UP

    D11 DOWN

    A0  Azimuth feedback

    A1  Elevation feedback


  Risposte:

    C   -> AZ=aaa\r

    B   -> EL=eee\r

    C2  -> AZ=aaa  EL=eee\r


  Comandi:

    Waaa eee -> imposta target e muove continuo fino al target

    S        -> stop immediato


  Nessun debug sulla seriale.

*/


#include

#include


const unsigned long SERIAL_BAUD = 9600;


const uint8_t PIN_RIGHT = 8;

const uint8_t PIN_LEFT  = 9;

const uint8_t PIN_UP    = 10;

const uint8_t PIN_DOWN  = 11;


const uint8_t PIN_AZ = A0;

const uint8_t PIN_EL = A1;


// Cambia in false solo se il tuo modulo PC817 e' active-low.

const bool OUTPUT_ACTIVE_HIGH = true;

const uint8_t OUT_ON  = OUTPUT_ACTIVE_HIGH ? HIGH : LOW;

const uint8_t OUT_OFF = OUTPUT_ACTIVE_HIGH ? LOW  : HIGH;


// Calibrazione RAW

const int AZ_RAW_0   = 9;

const int AZ_RAW_180 = 411;

const int AZ_RAW_360 = 814;


const int EL_RAW_0   = 5;

const int EL_RAW_90  = 495;

const int EL_RAW_180 = 972;


// Sicurezze vicino ai fine corsa RAW

const int AZ_RAW_GUARD = 7;

const int EL_RAW_GUARD = 7;


// Tolleranza di arresto

const int AZ_TOL_DEG = 3;

const int EL_TOL_DEG = 2;


// Frequenza controllo movimento continuo

const unsigned long MOTION_UPDATE_MS = 40;


const uint8_t ANALOG_SAMPLES = 8;


char cmdBuf[40];

uint8_t cmdLen = 0;

bool overflow = false;


bool moveActive = false;


int targetAz = 0;

int targetEl = 0;


unsigned long lastMotionUpdate = 0;


void setOut(uint8_t pin, bool on) {

  digitalWrite(pin, on ? OUT_ON : OUT_OFF);

}


void outputsOff() {

  setOut(PIN_RIGHT, false);

  setOut(PIN_LEFT, false);

  setOut(PIN_UP, false);

  setOut(PIN_DOWN, false);

}


int readRawAvg(uint8_t pin) {

  long sum = 0;

  for (uint8_t i = 0; i < ANALOG_SAMPLES; i++) {

    sum += analogRead(pin);

  }

  return (int)((sum + (ANALOG_SAMPLES / 2)) / ANALOG_SAMPLES);

}


int interpDeg(int raw, int rawA, int rawB, int degA, int degB) {

  if (rawB == rawA) return degA;

  long num = (long)(raw - rawA) * (degB - degA);

  long den = rawB - rawA;

  return degA + (int)((num + (den / 2)) / den);

}


int rawToAz(int raw) {

  if (raw <= AZ_RAW_0) return 0;

  if (raw >= AZ_RAW_360) return 360;


  if (raw <= AZ_RAW_180) {

    return interpDeg(raw, AZ_RAW_0, AZ_RAW_180, 0, 180);

  }


  return interpDeg(raw, AZ_RAW_180, AZ_RAW_360, 180, 360);

}


int rawToEl(int raw) {

  if (raw <= EL_RAW_0) return 0;

  if (raw >= EL_RAW_180) return 180;


  if (raw <= EL_RAW_90) {

    return interpDeg(raw, EL_RAW_0, EL_RAW_90, 0, 90);

  }


  return interpDeg(raw, EL_RAW_90, EL_RAW_180, 90, 180);

}


void put3(char *p, int value) {

  value = constrain(value, 0, 999);

  p[0] = (char)('0' + (value / 100) % 10);

  p[1] = (char)('0' + (value / 10) % 10);

  p[2] = (char)('0' + value % 10);

}


void sendAz() {

  int az = rawToAz(readRawAvg(PIN_AZ));

  char out[7] = {'A', 'Z', '=', '0', '0', '0', '\r'};

  put3(out + 3, az);

  Serial.write((const uint8_t *)out, sizeof(out));

}


void sendEl() {

  int el = rawToEl(readRawAvg(PIN_EL));

  char out[7] = {'E', 'L', '=', '0', '0', '0', '\r'};

  put3(out + 3, el);

  Serial.write((const uint8_t *)out, sizeof(out));

}


void sendAzEl() {

  int az = rawToAz(readRawAvg(PIN_AZ));

  int el = rawToEl(readRawAvg(PIN_EL));


  char out[15] = {

    'A', 'Z', '=', '0', '0', '0',

    ' ', ' ',

    'E', 'L', '=', '0', '0', '0',

    '\r'

  };


  put3(out + 3, az);

  put3(out + 11, el);


  Serial.write((const uint8_t *)out, sizeof(out));

}


void sendError() {

  const char out[] = {'?', '>', '\r'};

  Serial.write((const uint8_t *)out, sizeof(out));

}


bool digit(char c) {

  return c >= '0' && c <= '9';

}


void skipSpaces(const char *&p) {

  while (*p == ' ' || *p == '\t') p++;

}


bool readNumber(const char *&p, int &value) {

  if (!digit(*p)) return false;


  int v = 0;

  uint8_t n = 0;


  while (digit(*p)) {

    v = (v * 10) + (*p - '0');

    p++;

    n++;

    if (n > 3) return false;

  }


  value = v;

  return true;

}


bool parseW(const char *cmd, int &az, int &el) {

  const char *p = cmd + 1;


  skipSpaces(p);

  if (!readNumber(p, az)) return false;


  skipSpaces(p);

  if (!readNumber(p, el)) return false;


  skipSpaces(p);

  return *p == '\0';

}


void stopMotion() {

  moveActive = false;

  outputsOff();

}


void startMove(int az, int el) {

  targetAz = constrain(az, 0, 360);

  targetEl = constrain(el, 0, 180);


  moveActive = true;

  lastMotionUpdate = 0;

}


int azDir(int currentDeg, int currentRaw) {

  int err = targetAz - currentDeg;


  if (abs(err) <= AZ_TOL_DEG) return 0;


  if (err > 0) {

    if (currentRaw >= AZ_RAW_360 - AZ_RAW_GUARD) return 0;

    return 1;   // RIGHT / CW

  }


  if (currentRaw <= AZ_RAW_0 + AZ_RAW_GUARD) return 0;

  return -1;    // LEFT / CCW

}


int elDir(int currentDeg, int currentRaw) {

  int err = targetEl - currentDeg;


  if (abs(err) <= EL_TOL_DEG) return 0;


  if (err > 0) {

    if (currentRaw >= EL_RAW_180 - EL_RAW_GUARD) return 0;

    return 1;   // UP

  }


  if (currentRaw <= EL_RAW_0 + EL_RAW_GUARD) return 0;

  return -1;    // DOWN

}


void applyMove(int aDir, int eDir) {

  outputsOff();


  if (aDir > 0) {

    setOut(PIN_RIGHT, true);

  } else if (aDir < 0) {

    setOut(PIN_LEFT, true);

  }


  if (eDir > 0) {

    setOut(PIN_UP, true);

  } else if (eDir < 0) {

    setOut(PIN_DOWN, true);

  }

}


void updateMotion() {

  if (!moveActive) {

    outputsOff();

    return;

  }


  unsigned long now = millis();

  if ((unsigned long)(now - lastMotionUpdate) < MOTION_UPDATE_MS) return;

  lastMotionUpdate = now;


  int azRaw = readRawAvg(PIN_AZ);

  int elRaw = readRawAvg(PIN_EL);


  int currentAz = rawToAz(azRaw);

  int currentEl = rawToEl(elRaw);


  int aDir = azDir(currentAz, azRaw);

  int eDir = elDir(currentEl, elRaw);


  if (aDir == 0 && eDir == 0) {

    stopMotion();

    return;

  }


  applyMove(aDir, eDir);

}


void upperCase(char *s) {

  while (*s) {

    if (*s >= 'a' && *s <= 'z') {

      *s = (char)(*s - 'a' + 'A');

    }

    s++;

  }

}


void trimCommand(char *&cmd) {

  while (*cmd == ' ' || *cmd == '\t') cmd++;


  char *end = cmd + strlen(cmd);

  while (end > cmd && (end[-1] == ' ' || end[-1] == '\t')) {

    end--;

    *end = '\0';

  }

}


void handleCommand(char *buf) {

  char *cmd = buf;

  trimCommand(cmd);

  upperCase(cmd);


  if (cmd[0] == '\0') return;


  if (strcmp(cmd, "C2") == 0) {

    sendAzEl();

    return;

  }


  if (strcmp(cmd, "C") == 0) {

    sendAz();

    return;

  }


  if (strcmp(cmd, "B") == 0) {

    sendEl();

    return;

  }


  if (strcmp(cmd, "S") == 0) {

    stopMotion();

    return;

  }


  if (cmd[0] == 'W') {

    int az = 0;

    int el = 0;


    if (!parseW(cmd, az, el)) {

      sendError();

      return;

    }


    startMove(az, el);

    return;

  }


  sendError();

}


void pollSerial() {

  while (Serial.available() > 0) {

    char ch = (char)Serial.read();


    if (ch == '\r' || ch == '\n') {

      if (overflow) {

        overflow = false;

        cmdLen = 0;

        sendError();

      } else if (cmdLen > 0) {

        cmdBuf[cmdLen] = '\0';

        handleCommand(cmdBuf);

        cmdLen = 0;

      }

      continue;

    }


    if (overflow) continue;


    if (cmdLen < sizeof(cmdBuf) - 1) {

      cmdBuf[cmdLen++] = ch;

    } else {

      overflow = true;

      cmdLen = 0;

    }

  }

}


void setup() {

  pinMode(PIN_RIGHT, OUTPUT);

  pinMode(PIN_LEFT, OUTPUT);

  pinMode(PIN_UP, OUTPUT);

  pinMode(PIN_DOWN, OUTPUT);


  outputsOff();

  Serial.begin(SERIAL_BAUD);

}


void loop() {

  pollSerial();

  updateMotion();

}


Questo sketch comanda il G-5500 tramite Gpredict.



Evaluate