Ricevere dati via Seriale da Stellarium dell'oggetto selezionato

Salve a tutti.
Per un progetto ancora in corso d'opera sto cercando di ricevere tramite seriale alcuni dati dal software Stellarium. Ho fatto una ricerca in rete, ma la maggior parte delle discussioni o blog parlavano di come inviare a Stellarium alcuni dati tramite seriale. A me interessa invece ricevere dei dati, in particolare ricevere quelli di Azimuth, Latitudine della mia posizione attuale (ma di questo ne potrei anche fare a meno dato che è un parametro che posso inserire manualmente e che non cambia nel tempo), e altitudine dell'oggetto selezionato. In pratica una volta effettuata la selezione dell'oggetto mi piacerebbe ricevere questi dati.
Sto effettuando alcune prove e da come ho capito, per comunicare con Stellarium ho bisogno del protocollo LX200 Meade. Attraverso il plugin "Controllo telescopio" ho pertanto collegato la COM dell'arduino al programma. Qui però vi era un problema: purtroppo la porta dell'arduino occupata da Stellarium non mi faceva leggere i dati dal Serial (errore di "busy").
Quindi ho pensato di servirmi della libreria SoftwareSerial per connettermi al telescopio, e di scrivere i dati ricevuti poi nel Serial monitor. Ho fatto giusto una prova inviando il comando ":Gr#" che sarebbe nel protocollo :Gr# Get current/target object RA
Returns: HH:MM.T# or HH:MM:SS
, ma il risultato è una semplice "e". Quindi in sostanza, c'è qualcuno che è riuscito a ricevere i dati che ho indicato sopra tramite Seriale?

Questo è il codice che ho provato:

#include <SoftwareSerial.h>
// software serial #1: RX = digital pin 10, TX = digital pin 11
SoftwareSerial portOne(3, 2);

String inputString = "";                   //dichiaro una stringa vuota per memorizzare i dati in entrata
String in;

void setup() {
  Serial.begin(9600);
  portOne.begin(9600);
}

void loop() {
      char a;
      portOne.listen();

      if(Serial.available()){
        a=Serial.read();
      }

      if(a == 'a'){
        portOne.write(":Gr#"); 
        in = portOne.readString(); 
        Serial.println(in);
      }
     
    
   
   }

Ma il pc "esce" con una seriale rs232 o con una usb?

Il pc esce con una USB; su Stellarium con il plugin "Controllo telescopio" collego la COM del TTL dell'Arduino e in contemporanea è collegato al PC un altro modulo TTL USB per leggere i dati nel Serial, perchè la Serial di Arduino viene occupata dal plugin di Stellarium (port busy).
Sto cercando qualcosa in rete. Ho trovato questo codice (che ho modificato, l'originale è nel link) che però serve per comandare un telescopio costruito con una montatura fai da te con stepper motor, quindi farlo diventare Go to grazie a Stellarium. Non proprio ciò che serve a me. Io vorrei solo ricevere via Seriale i dati di Azimut e altitudine e salvarli in due variabili. Ho provato sempre come pensato sopra, ossia di usare una doppia seriale, come già detto Tx Rx di Arduino da collegare a Stellarium con la sua COM e un'altra seriale con la lib SoftwareSerial, per stampare i dati di ascensione retta e declinazione (RA e SC indicati nello sketch) che non sono propriamente quelli che servono a me, ma li sto utilizzando come esempi di prova . Ma purtroppo non ne riesco a ricavare niente.
Questo è il codice che ho provato a modicare ma presumo sia no-sense:



#include <SoftwareSerial.h>


SoftwareSerial portOne(3, 2);

char datos[30];  //Datos leidos por el puerto serie

//Coordenadas del objetivo
char RA_objetivo[9];
char DEC_objetivo[10];

long RA_obj, DEC_obj;

//Inicializamos los datos
void setup() {
  Serial.begin(9600);    
  portOne.begin(9600);
  
}

void loop() {
  if(Serial.available()>0){
    leer_datos_serie();
  }
}


//Recoge los datos que haya en el puerto serie
void leer_datos_serie(){
  int i=0;
  datos[i++]=Serial.read();
  delay(5);
  while((datos[i++]=Serial.read())!='#'){       //Leo hasta el final del comando, que es un simbolo #
    delay(5);                                   //Espero 5ms por si aun no esta disponbile el siguiente dato
  }
  datos[i]='\0';                                //Completo la cadena con el simbolo de fin de cadena, cosas del C
  parsear_datos();                              //Llamo a la funcion que interpreta los datos recibidos
}

//Interpreta los datos que se han recibido en el puerto serie
void parsear_datos(){                                                        // <<<---- Esto hay que dejarlo bien

  // :Sr HH:MM:SS#  -> Direccion RA del objetivo
  if(datos[0]==':' && datos[1]=='S' && datos[2]=='r'){
    for(int i=0;i<8;i++)
    RA_objetivo[i]=datos[i+4];                                    
    RA_obj=long(atoi(datos+4))*long(3600)+long(atoi(datos+7))*long(60)+long(atoi(datos+10));
    portOne.print(RA_obj);
  }
  
  // :Sd sDD*MM:SS# ->Direccion DEC del objetivo
  if(datos[0]==':' && datos[1]=='S' && datos[2]=='d'){
    for(int i=0;i<9;i++)
      DEC_objetivo[i]=datos[i+4];                                        
    DEC_obj=long(atoi(datos+4))*long(3600)+long(atoi(datos+8))*long(60)+long(atoi(datos+11));
    portOne.print(DEC_obj);
  }
  
}

Di che scheda Arduino si tratta?

È un Arduino Uno

La scelta della software serial è quindi obbligata.

Per quanto riguarda il software, francamente l'implementazione ArduGoTo a me non piace per nulla: un parser bloccante per una comunicazione a 9600bps è qualcosa che mi disturba a livello concettuale per quanto semplice possa essere l'applicazione.

Con il codice che hai messo nel primo post invece, non capisco cosa volevi ottenere. Da quanto ho letto nel documento descrittivo del protocollo, il comando ":Gr#" è un comando di lettura del telescopio che ritorna il target corrente inviato dal software Stellarium e non viceversa.

Siccome l'argomento interessa anche a me, ho installato il software in questione.
Abilitando il plugin di controllo del telescopio, la sequenza di comandi che ricevo premendo il pulsante di Sync è:

  • Stellarium invia sulla seriale il comando #:GR# e si aspetta come risposta l'attuale ascensione retta del telescopio;
  • dopo aver inviato i valori dell'ascensione arriva il comando #:GD# ed in risposta si aspetta l'attuale declinazione del telescopio
  • a questo punto invia il comando #:Sr seguito dai valori target per l'ascensione retta, in risposta vuole un 1 in caso di acquisizione positiva (0 ovviamente se c'è un problema)
  • a seguire arriva il comando #:Sd con il target per l'ascensione e come prima si deve rispondere 0/1.

Ho provato a sviluppare un codice di prova, ma al momento l'ho solo simulato al pc inviando i comandi manualmente. Se ti interessa chiedi pure

Grazie mille per la risposta. Sì, in questi giorni sono arrivato anche io alle conclusioni da te citate, in particolare ce l'ho fatta a prendere dei dati come l'ascensione retta con #:Sr e la declinazione con #:Sd facendo rispondere sempre tramite seriale con "1" per far capire al software che i dati erano stati ricevuti. I dati li ho printati con un'altra serial creata con SoftwareSerial.h
Il problema resta che, in primis non sono purtroppo i dati che io cercavo ossia Azimuth e Altitudine, però ho visto che comunque da Dec e Ascensione è possibile ricavarli, solo che c'è la necessità del Tempo siderale locale. Dato che non c'è alcun riferimento nel protocollo LX200 per questo parametro (così come per l'AZ-AT), ho spulciato un po' in rete ed ho visto che c'è una possibilità di "convertire" l'ora locale, in ora locale siderale. Avevo pensato di farlo con un RTC. Anche se non so se tutte queste vie possano essere il massimo in termini di precisione di calcoli. Altro problema è che tali dati, ossia AT-AZ mi servirebbero aggiornati sempre, mentre con la soluzione sopra citata, i dati dell'oggetto selezionato mi arrivano solo dopo che ho cliccato su "oggetto corrente" e poi "punta l'oggetto" da Stellarium. Avevo pensato addirittura di fare un software che cliccasse da solo prima "Oggetto corrente" e poi "punta", almeno ogni secondo, però diciamo che sono delle vie un po' "accroccate". Se hai comunque suggerimenti in merito sono tutte orecchie. Grazie mille!

Ciao @morpheus1990
Scusa la risposta un po' tardiva, ma negli ultimi tempi non ho molto tempo libero purtroppo.

Per quanto riguarda l'eventuale conversione non credo ci siano grossi problemi di precisione.. in fondo di tratta di un po' di trigonometria o poco più.

Per il tuo problema specifico però, forse c'è un'altra strada. Ho visto che il software espone delle API attraverso un'interfaccia web (sempre usando un plugin).
A questo punto con un microcontrollore dotato di interfaccia WiFi o Ethernet potresti ottenere molte più informazioni (credo) senza dover simulare la risposta di un telescopio.

Non ho ancora approfondito il protocollo, appena riesco faccio due prove e ti tengo informato.

Ciao @cotestatnt
Grazie mille per quest'altra info. Sarebbe davvero l'ideale se si potessero prendere le coordinate azimuth e altitudine di un oggetto selezionato! Allora attendo tue notizie e intanto farò delle ricerche anche io in merito a questa API. Ti ringrazio ancora vivamente.

Buongiorno @morpheus1990
Come speravo, usando l'interfaccia web diventa tutto enormemente più semplice...
Inoltre dal software è anche possibile personalizzare quali dati ricevere ed in che formato: ad esempio io ho selezionato nella tab "strumenti" la visualizzazione dei gradi in notazione decimale cosi da facilitarmi la conversione in float e rimosso alcune informazioni di troppo.

Partendo dall'esempio JsonHttpClient.ino della libreria ArduinoJson (ho scelto questo esempio perché fa il parsing dei dati direttamente dallo stream http), l'ho modificato per compilare con un NodeMCU (ESP8266) usando il WiFi integrato ed ho ottenuto questo codice che funziona alla grande estrapolando una volta al secondo le informazioni di cui hai bisogno (e qualcuna in più) tra le tante disponibili.

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>

#define STASSID "xxxxxxxx"
#define STAPSK "xxxxxxxx"
#define STELLARIUM_HOST "192.168.152.245"
#define STELLARIUM_PORT 8090

float altitude, azimuth;
String type, name, sideralTime;

void getData() {
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  if (!client.connect(STELLARIUM_HOST, STELLARIUM_PORT)) {
    Serial.println("connection failed");
    delay(5000);
    return;
  }

  // Send HTTP request
  client.println(F("GET /api/objects/info?format=json HTTP/1.0"));
  client.print(F("Host: "));
  client.println(STELLARIUM_HOST);
  client.println(F("Connection: close"));
  client.println();

  // Check HTTP status
  char status[32] = { 0 };
  client.readBytesUntil('\r', status, sizeof(status));
  // It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
  if (strcmp(status + 9, "200 OK") != 0) {
    Serial.print(F("Unexpected response: "));
    Serial.println(status);
    client.stop();
    return;
  }

  // Skip HTTP headers
  const char endOfHeaders[] = "\r\n\r\n";
  if (!client.find(endOfHeaders)) {
    Serial.println(F("Invalid response"));
    client.stop();
    return;
  }

  /* Allocate the JSON document and parse the stream
  * Capacity calculated with https://arduinojson.org/v6/assistant/ (with all data selected)
  * Can be reduced, customizing Stellarium object informations
  */
  DynamicJsonDocument doc(3072);
  DeserializationError error = deserializeJson(doc, client);
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
    client.stop();
    return;
  }

  // Get actual values
  altitude = doc["altitude"].as<float>();  // Using decimal degrees
  azimuth = doc["azimuth"].as<float>();    // Using decimal degrees
  name = doc["name"].as<const char*>();
  type = doc["object-type"].as<const char*>();
  sideralTime = doc["meanSidTm"].as<const char*>();

  // Disconnect the client
  client.stop();
}

void setup() {
    // Initialize Serial port
  Serial.begin(9600);
  Serial.print(F("\n\nConnecting to "));
  Serial.println(STASSID);
  WiFi.mode(WIFI_STA);
  WiFi.begin(STASSID, STAPSK);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print(F("\nWiFi connected. IP address:"));  
  Serial.println(WiFi.localIP());
}

void loop() {
  static uint32_t getTime;
  if (millis() - getTime > 1000) {
    getTime = millis();
    getData();

    Serial.print(name);
    Serial.print(F(": "));
    Serial.print(type);
    Serial.print(F(".\t Azimuth "));
    Serial.print(azimuth, 4);
    Serial.print(F("° \tAltitude "));
    Serial.print(altitude, 4);
    Serial.print(F("° \tMean Sideral Time "));
    Serial.println(sideralTime);
  }
}

Caspita sei un grande @cotestatnt !!! Peccato che ora sono fuori per lavoro per 4 giorni e non posso provarlo ma questa soluzione sembra grandiosa! Ti ringrazio tanto! Il plugin da utilizzare è quello del "Controllo remoto" giusto?

Si esatto!
Il plugin necessario è "Controllo remoto"
L'unica cosa strana che ho trovato è che quando apri la finestra di configurazione del plugin non viene riportato l'indirizzo IP che è stato assegnato al PC dal router ma altri indirizzi (non ho verificato, ma credo siano quelli assegnati dal provider).

Se non sono indirizzi "privati", probabilmente si appoggia a server esterni.

Appena torno a casa ti dico, oppure vedrò di farmi arrivare una esp8266 qua dove mi trovo ora, perchè scalpito dalla voglia di provare! Comunque è possibile anche prelevare la latitudine locale che assegno io al software? Immagino però che l'api non riguarderà più gli "objects" ma qualcosa tipo "local info" giusto?

Si certo è possibile anche questo, ma è necessario fare una chiamata ad un endpoint diverso (dovrebbe essere /main/status ma vado a memoria) e gestire di conseguenza la risposta.

Appena ho un minuto verifico e aggiorno il codice.

Ciao @morpheus1990

Aggiungo il codice che consente di ottenere anche latidudine e longitudine (funzione usata solo nel setup).

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>

#define STASSID "xxxxxxxxx"
#define STAPSK "xxxxxxxxx"
#define STELLARIUM_HOST "192.168.152.245"
#define STELLARIUM_PORT 8090

float altitude, azimuth, latitude, longitude;
String type, name, sideralTime, locationName;

enum InfoType { INFO_STATUS, INFO_OBJECT };

void getData(uint8_t infoType) {
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  if (!client.connect(STELLARIUM_HOST, STELLARIUM_PORT)) {
    Serial.println("connection failed");
    delay(5000);
    return;
  }

  // Send HTTP request
  switch (infoType) {
    case InfoType::INFO_OBJECT:
      client.println(F("GET /api/objects/info?format=json HTTP/1.0"));
      break;
    case InfoType::INFO_STATUS:
      client.println(F("GET /api/main/status HTTP/1.0"));
      break;
  }
  client.print(F("Host: "));
  client.println(STELLARIUM_HOST);
  client.println(F("Connection: close"));
  client.println();

  // Check HTTP status and skip headers
  char status[32] = { 0 };
  client.readBytesUntil('\r', status, sizeof(status));
  // It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
  if (strcmp(status + 9, "200 OK") != 0) {
    Serial.print(F("Unexpected response: "));
    Serial.println(status);
    return;
  }

  // Skip HTTP headers
  const char endOfHeaders[] = "\r\n\r\n";
  if (!client.find(endOfHeaders)) {
    Serial.println(F("Invalid response"));
    return;
  }

  /* Allocate the JSON document and parse the stream
    * Capacity calculated with https://arduinojson.org/v6/assistant/ (with all data selected)
    * Can be reduced, customizing Stellarium object informations
    */
  DynamicJsonDocument doc(3072);
  DeserializationError error = deserializeJson(doc, client);
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
    client.stop();
    return;
  }

  // Get actual values
  switch (infoType) {
    case InfoType::INFO_OBJECT:
      altitude = doc["altitude"].as<float>();  // Using decimal degrees
      azimuth = doc["azimuth"].as<float>();    // Using decimal degrees
      name = doc["name"].as<const char*>();
      type = doc["object-type"].as<const char*>();
      sideralTime = doc["meanSidTm"].as<const char*>();
      break;
    case InfoType::INFO_STATUS:
      latitude = doc["location"]["latitude"].as<float>();
      longitude = doc["location"]["longitude"].as<float>();
      locationName = doc["location"]["name"].as<const char*>();
      break;
  }

  // Disconnect the client
  client.stop();
}


void printObjectData() {
  Serial.print(name);
  Serial.print(F(": "));
  Serial.print(type);
  Serial.print(F(".\t Azimuth "));
  Serial.print(azimuth, 4);
  Serial.print(F("° \tAltitude "));
  Serial.print(altitude, 4);
  Serial.print(F("° \tMean Sideral Time "));
  Serial.println(sideralTime);
}

void printLocationData() {
  Serial.print(locationName);
  Serial.print(F(", Latitude "));
  Serial.print(latitude, 4);
  Serial.print(F("°, Longitude "));
  Serial.print(longitude, 4);
  Serial.println(F("°"));
}

void setup() {
  // Initialize Serial port
  Serial.begin(9600);
  Serial.print(F("\n\nConnecting to "));
  Serial.println(STASSID);
  WiFi.mode(WIFI_STA);
  WiFi.begin(STASSID, STAPSK);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print(F("\nWiFi connected. IP address: "));
  Serial.println(WiFi.localIP());

  getData(InfoType::INFO_STATUS);
  printLocationData();
}

void loop() {
  static uint32_t getTime;
  if (millis() - getTime > 1000) {
    getTime = millis();
    getData(InfoType::INFO_OBJECT);
    printObjectData();
  }
}
1 Like

Comunque quel tipo di indirizzo ip credo sia un "classe c" ed è comunque "privato".
Ovvero è sul pc locale.
Se siete su pc Windows e date il comando ipconfig /all nel prompt dei comandi vi dice "morte e miracoli" delle vostre interfacce di rete!

Se ti riferisci all'indirizzo che c'è nello sketch confermo che è locale.
Si tratta di quello che assegna Android quando abilito il tethering.

Buon pomeriggio @cotestatnt, ho provato il codice con ESP8266, funziona alla grande, sei un drago! Per quanto riguarda l'indirizzo locale generato dal plugin al momento della connessione al server (a me in questo caso 192.168.20.1) la prima volta mi è apparso, le altre volte per farlo apparire, ho dovuto abilitare il server,chiudere la finestra del plugin, e successivamente riaprendo la sua finestra di configurazione, mi è riapparso.

Comunque, prima di questa soluzione da te trovata, avevo fatto una app apk attraverso la quale, via bluetooth, inviavo all'arduino i dati di altitudine e Azimut, inserendoli di volta in volta manualmente in dei text box.
In pratica ti spiego cosa sto progettando. Sto cercando di fare un derotatore di campo, utilizzando uno stepper motor con driver A4988. Per determinare la velocità di rotazione del motore, mi servo di una formula trigonometrica che appunto con i dati AZ e AT imposta uno step (o meglio microstep, visto che li ho ridotti a 0.0022 gradi per step, anziché 1.8 gradi iniziali) ad ogni X millisecondi. In sintesi, determino ogni quanti millisecondi deve fare uno step per derotare l'oggetto puntato con il telescopio (ovviamente a derotare sarà la camera ASI con la quale faccio le acquisizioni).
Attraverso l'app, controllo anche l'on off del motore e altre cose tutto funziona bene.
Ovviamente all'Arduino i dati arrivano tramite SoftwareSerial con un modulo ble HC05.

Dato che te ora hai trovato questa soluzione, ovviamente inserire i dati manualmente tramite l'app non mi serve più, visto che è tutto automatico con stellarium. Però comunque non mi voglio disfare dell'app che ho creato perché almeno con essa posso arrestare e avviare il motore, farlo girare in senso orario o antiorario velocemente per raddrizzare la camera, cambiare direzione ect.

Ho pensato pertanto di usare la ESP8266 con il solo compito di prendere i dati da stellarium, e inviarli ad Arduino tramite seriale. E questo avviene. Infatti sugli stessi pin RX e TX (softwareserial) del bluetooth ho messo quelli della ESP8266 che attraverso lo stesso metodo utilizzato per l'app, riesce a mandare i dati ad arduino e quindi salvarli in delle variabili float create su quest'ultimo.
Il metodo utilizzato è il seguente.

Il tuo codice ho cambiato la parte del loop dove printa i dati, così:
(PS. la latitudine 40.92 l'avevo messa per il momento manualmente in attesa del secondo sketch che hai poi inserito)

 if (millis() - getTime > 1000) {
    getTime = millis();
    getData();
    Serial.print(F("z:"));
    Serial.println(azimuth);
    Serial.print(F("b:"));
    Serial.println(altitude);
    Serial.print(F("n:"));
    Serial.println("40.92");
  }

Mentre nell'arduino questi dati vengono prelevati con questo metodo :

#include <SoftwareSerial.h>

SoftwareSerial s(2,3);
float latitudine, azimut, altitudine;

String str = "";

void setup() {
  Serial.begin(9600);
  s.begin(9600);
  
}

void loop() {
   
  if(s.available()){
    char ch = s.read();
    if ( (ch == '\n') || (ch == '\r') ) { 
      cmd(str);
      str = "";
    } else {
      str += ch;
    }
  }
}

void cmd(String str) {

  char c = str.charAt(0);

  if (c == 'z' ) {
    String n = str.substring(2);
    float dati1 = n.toFloat();
    azimut=dati1;
    Serial.print(F("Az:"));
    Serial.println(azimut);
  
  } else if (c == 'b') {
    String n = str.substring(2);
    float dati2 = n.toFloat();
    altitudine=dati2;
    Serial.print(F("At:"));
    Serial.println(altitudine);

  
  } else if (c == 'n') {
    String n = str.substring(2);
    float dati3 = n.toFloat();
    latitudine=dati3;
    Serial.print(F("Lat:"));
    Serial.println(latitudine);
     } 
   }   
 

I dati vengono presi senza problemi e salvati nelle variabili float.
Il problema si ha con il motore: infatti ogni volta che ricevo un dato dal esp8266 mentre il motore sta girando questo si frena, o meglio fa un disturbo che posso tradurti come una forte vibrazione ogni volta che l'arduino riceve i dati dalla ESP. Ho pensato quindi che si trattasse di un problema dovuto al fatto che sia la seriale del bluetooth e sia quella della ESP erano messe assieme sugli stessi pin 2 e 3 del software Serial. Quindi elimino la sezione del controllo tramite bluetooth, e con il metodo che ti ho indicato sopra faccio prelevare solo i dati dalla ESP. Ma niente, con il motore che gira tenendo premuto un pulsante, ogni volta che ricevo i dati dalla esp sulla seriale, mi fa questo disturbo di vibrazione al motore (sembra stopparsi in quel frangente in cui ricevo i dati per ripartire subito).

Il fatto è che solo con i dati ricevuti dall esp8266 mi fa questo disturbo, mentre se i dati li invio tramite l'app citata, non c'è alcun distrubo e il motore va liscio.
Non so da cosa possa dipendere questo disturbo. Ne ho provate di tutti i colori.

Qui c'è il codice completo, cercando di far coesistere sia i comandi dall'app citata, e sia i dati prelevati dall'esp8266 (inviati sempre sulla stessa seriale con i char z per azimut, b per altitudine, n per latitudine):

#include <SoftwareSerial.h>

SoftwareSerial s(2,3);

const int dirPin = 7;
const int stepPin = 8;
const int MS1 =9;
const int MS2 =12;
const int MS3 =4;

float velocita, latitudine, azimuth, altitudine, velocitarotazione;
float radiansLat, radiansAz, radiansAl;
uint32_t tempo2, tempoveloce, tempo;

bool superveloceorario,superveloceanti, controlloorario;

String str = "";

void setup() {
  Serial.begin(9600);
  s.begin(9600);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(MS1, OUTPUT);
  pinMode(MS2, OUTPUT);
  pinMode(MS3, OUTPUT);

}

void loop() {
  
  if(s.available()){
    char ch = s.read();
    if ( (ch == '\n') || (ch == '\r') ) { 
      cmd(str);
      str = "";
    } else {
      str += ch;
    }
  }

    radiansLat = latitudine*(3.14/180);
    radiansAz = azimuth*(3.14/180);
    radiansAl = altitudine*(3.14/180);
  
   velocita = (-15*cos(radiansLat)*cos(radiansAz)/cos(radiansAl)); //questa verrà moltplicata x -1 per farla diventare positiva
   velocitarotazione = (-15*cos(radiansLat)*cos(radiansAz)/cos(radiansAl)); //questa mi serve per sapere se dalla formula il numero è positivo o negativo per deteminare il senso di rotazione
   
   if(velocita < 0){
    velocita = velocita*(-1);
   }
   tempo = ((3600000*0.00221043443)/velocita);

if(!superveloceorario && !superveloceanti){  
  if(velocitarotazione>=0){
    digitalWrite(dirPin, LOW); //se il numero ricavato dalla formula è positivo gira in questa direzione   
  } else{
    digitalWrite(dirPin,HIGH); //altrimenti deve girare in questo altro senso (ricorda che deve DEROTARE, quindi girare nella direzione opposta a ciò che ricavi dalla formula)
  }
    digitalWrite(MS1, HIGH) ;
    digitalWrite(MS2, HIGH);
    digitalWrite(MS3, HIGH);
   if(millis()-tempo2>=(tempo/2)){
    if(controlloorario){ //se il tasto ON sull'app è stato premuto
    digitalWrite(stepPin, digitalRead(stepPin) ^ 1);
  } else {
    digitalWrite(stepPin, LOW);
  }
    tempo2+=(tempo/2);
   } 
    
  }else if (superveloceorario){ //se premo dall'app il tasto ">" mi gira veloce in senso orario
    digitalWrite(MS1, LOW);
    digitalWrite(MS2, LOW);
    digitalWrite(MS3, LOW);
    digitalWrite(dirPin, HIGH);
     if(millis()-tempoveloce>=0.1){
      digitalWrite(stepPin, digitalRead(stepPin) ^ 1);
      tempoveloce+=0.1;
    }  
  } else if (superveloceanti){  //se premo dall'app il tasto "<" mi gira veloce in senso antiorario
    digitalWrite(MS1, LOW);
    digitalWrite(MS2, LOW);
    digitalWrite(MS3, LOW);
    digitalWrite(dirPin, LOW);
     if(millis()-tempoveloce>=0.1){
      digitalWrite(stepPin, digitalRead(stepPin) ^ 1);
      tempoveloce+=0.1;
    }  
  }

}



void cmd(String str) {

  char c = str.charAt(0);
  
   if (c == 'a') { //tasto ON sull'app
    controlloorario=true;
  } else if (c == 's') { //tasto OFF sull'app
    controlloorario=false;
  }else if (c == 'k') { //tasto sull'app tenuto premuto per girare veloce in senso orario
    superveloceorario=true;
  }else if (c == 'v') {  //tasto sull'app tenuto premuto per girare veloce in senso antiorario
    superveloceanti=true;
  }else if (c == 'm') {  //quando il tasto che invia il char 'k' o 'v' viene rilasciato ferma la rotazione
    superveloceorario=false;
    superveloceanti=false;
    
  }else if (c == 'z' ) { //azimut stellarium da esp tramite seriale
    String n = str.substring(2);
    float pwm = n.toFloat();
    azimuth=pwm;
    Serial.print("AZ: ");
    Serial.println(azimuth);
     
  } else if (c == 'b') { //altitudine stellarium da esp tramite seriale
    String n = str.substring(2);
    float pwm2 = n.toFloat();
    altitudine=pwm2;
    Serial.print("AT: ");
    Serial.println(altitudine);
  
  } else if (c == 'n') { //latitudine stellarium tramite seriale 
    String n = str.substring(2);
    float pwm3 = n.toFloat();
    latitudine=pwm3;
    Serial.print("LAT: ");
    Serial.println(latitudine);
    Serial.print("VELOCITA' ROT: ");
    Serial.println(velocitarotazione);
    Serial.print("VELOCITA': ");
    Serial.println(velocita);
    Serial.println();
     }
   } 
   
   
 


Ovviamente quella di far coesistere sullaa stessa Seriale l'HC05 e i dati del ESP8266 non sarà propriamente corretto, però i dati arrivano senza problemi. Ripeto che il problema ce l'ho solo quando dalla ESP ricevo i dati di az, at e alt. Cioè anche sopprimendo tutti i char che invio tramite app per comandare il motore e lasciando la sola ESP portando il suo RX e il suo TX sui pin 2 e 3 dell'arduino, e facendo avviare e girare il motore con un pulsante, mi fa sempre questo problema.