| "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 -vvvvIl 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:4533All’interno di rotctl, i comandi principali sono:
p minuscola legge la posizione del rotore Azimut e del rotore Elevazionecon 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 |