Seguimiento trayectoria con BWT901CL

Hace poco he llevado a cabo un proyecto que, si bien funciona, hay un par de puntos en los que he tenido que hacer un "bypass" por no encontrar realmente el porqué no funcionaba.
Se trata de gestionar un rotor de antena para hacer seguimiento de la trayectoria de satélites utilizados por radioaficionados.

Para saber los ángulos de elevación y ázimut de la antena utilizamos un sensor WBT901CL ubicado en la estructura de soporte de la antena. Se comunica con un Nano 33 Iot mediante bluetooth. Los datos de la órbita del satélite los suministra un programa (SatPc32) en un pc comunicado con el Nano mediante convertidor Usb-TTL FT232RL. Los dos motores utilizados para la movimentación son pilotados por un L298N. Por último, hay conectado un pequeño display Oled de 0.96" para ir indicando los ángulos de posición actual y de destino.
Como comento, el sistema hace correctamente el seguimiento, pero me he encontrado con que:

-Cuando intento conectar el sensor WBT901CL por mac, no me lo localiza.
Por tanto, jomtnego más remedio que hacer un scan de dispositivos y buscar hasta encontrar el del nombre del dispositivo, ¡que es HC-06, totalmente genérico!. He intentado cambiarle el nombre desde la aplicación que proporciona el fabricante, pero parece ser que para ese modelo no existe la opción.

-Al hacer giros "largos" en ázimut llega un punto en que el sensor continúa devolviendo la misma posición y no es hasta unos segundos después de que se haya parado que "se ajusta" y devuelve la posición correcta. Esto no afecta en el seguimiento pues los desplazamientos de ángulos son "lentos", pero cuando el satélite que se seguía queda fuera de rango y se pasa a seguir otro que obliga a desplazar bastantes grados(no pongo número porque no es fijo) se da esa situación. Y puede provocar que el rotor continue girando dando alguna vuelta.
El bypass hecho en este caso ha sido que si el desplazamiento en un eje lleva más de "x" segundos activo (con 5 funciona), se para el desplazamiento por "y" segundos (con 2 parece suficiente). Esto hemos podido hacerlo así porque no hace falta que el desplazamiento a posición inicial sea rápico, pero no deja de ser una "chapuza".

¿Alguien que haya utilizado el sensor WBT901CL conectado por bluetooth puede indicarme cómo cambiar el nombre o cómo localizarlo por mac?

¿Alguien que haya utilizado el sensor WBT901CL ha tenido el problema que comento del ángulo de ázimut (eje z) y ha podido solucionarlo actuando de algún modo sobre el sensor?

Otra cosa: quería detectar si se ha conectado el Usb de la FT232RL al Pc. Pensaba que con el típico "!Serial1" lo detectaría, pero siempre consta como conectado. Imagino que es porque lo que le consta conectado es el FT232RL al Serial1. ¿Hay alguna forma de verificar que se ha conectado el usb del FT232RL al Pc?

La libreria utilizada para conexión BlueTooth es ArduinoBLE.h.

El código de conexión al sensor y conexión al FT232RL es el siguiente. Si creeis que es necesario todo el código, ya lo pondré..


void IniciaConexionsSerie(){
  u_long millisAnt;

  Serial.begin(9600);
  millisAnt=millis();
  while (!Serial && (millis() <( millisAnt + SEGONS_ESPERA_CONEXIO_SERIE_DEBUG*1000))){
    strcpy(gTitol,"USB CONS.");
    strcpy(gDetall,"Inician ");
    GeneraPuntetsEnMissatge();
    DisplayMissatge();
    delay(500);
  }
  if(!Serial){
    strcpy(gTitol,"USB CONS.");
    strcpy(gDetall,"=== NO CONECTAT === ");
    DisplayMissatge();
    delay(2000);
  } else gConectatUsbConsola = true;

  Serial1.begin(9600);
  millisAnt=millis();
  while (!Serial1 && (millis() < (millisAnt + SEGONS_ESPERA_CONEXIO_SERIE_SATPC*1000))){
    strcpy(gTitol,"USB SATPC");
    strcpy(gDetall,"Inician ");
    GeneraPuntetsEnMissatge();
    DisplayMissatge();
    delay(200);
  }
  if(!Serial1){
    strcpy(gTitol,"USB SATPC");
    strcpy(gDetall,"=== NO CONECTAT === ");
    DisplayMissatge();
    delay(2000);
  } else { 
    gConectatUsbSatPC = true;
    strcpy(gTitol,"USB SATPC");
    strcpy(gDetall,"  CONECTAT  ");
    DisplayMissatge();
    delay(2000);

  }
}
// ======================= SENSOR =====================

bool InitzialitzarConexioSensor(){

bool _bRet = false;
  gCapceleraAnglesYaActivada=false;
  strcpy(gTitol,"SENSOR");
  strcpy(gDetall,"Inician Bluetooh");
  GeneraPuntetsEnMissatge();
  DisplayMissatge();

   // initialize the Bluetooth® Low Energy hardware
  if (!BLE.begin()) {
    if(gConectatUsbConsola) Serial.println("starting Bluetooth® Low Energy module failed!");
    return _bRet;
  }

  if(gConectatUsbConsola) Serial.println("Bluetooth® Low Energy Central inicializat.");
    
  BLE.scan();
  delay(250);
  sensorAngles = BLE.available();
  while (sensorAngles){
    if(sensorAngles.localName().startsWith("HC-06")){     
      break;
    }
    sensorAngles = BLE.available();
  }

/*
  BLE.scanForAddress("00:0c:bf:07:69:17");
  delay(100);
  sensorAngles = BLE.available();
  
*/

  if(!sensorAngles){
    if(gConectatUsbConsola) Serial.println("No trobat el sensor en sensorAngles.");
    return _bRet;
  }
  if(gConectatUsbConsola) Serial.print("Nom Device: ");
  if(gConectatUsbConsola) Serial.println(sensorAngles.localName());
  delay(250);
  BLE.stopScan();

  if (sensorAngles.connect()) {
    if(gConectatUsbConsola) Serial.println("Connected");
  } else {
    if(gConectatUsbConsola) Serial.println("Failed to connect!");
    return _bRet;
  }

 if(sensorAngles.discoverAttributes()) {
    if(gConectatUsbConsola) Serial.println("Attributes discovered");
  } else {
    if(gConectatUsbConsola) Serial.println("Attribute discovery failed!");
    sensorAngles.disconnect();
    return _bRet;
  }
  BLEService servei = sensorAngles.service("49535343-fe7d-4ae5-8fa9-9fafd205e455");
  if(!servei){
    if(gConectatUsbConsola) Serial.println("servei no trobat");
    return _bRet;
  }
 
  caracSensor = sensorAngles.characteristic("49535343-1e4d-4bd9-ba61-23c647249616");
  if(!caracSensor){
    if(gConectatUsbConsola) Serial.print("caracteristica no trobada");
    sensorAngles.disconnect();
    return _bRet;
  }
  
  caracSensor.subscribe();
  strcpy(gDetall,"Conectat                          ");
  DisplayMissatge();

  return true;
}

Es la primera vez que escribo un nuevo asunto y no sé si es correcto aquí, si lo he puesto bien, etc. Os agradeceré que me indiqueis si no lo he hecho correctamente.

¡Perdón! El sensor es BWT901CL, no WBT901CL.

Hoja de datos Sensor B01N99BUMR (siempre agrega toda la información).
https://www.amazon.com/-/es/BWT901CL-giroscopio-acelerómetro-Bluetooth-Aplicación/dp/B01N99BUMR

Yo creo que deberías postear todo.

Con respecto al puerto Serial, basta con que hagas una lectura en el puerto que te interesa, si recibe datos, es que esta activo. Esa lectura debería refrezcarse cada X tiempo.
Esto ya que !Serial1 no es suficiente. En realidad lo es pero cuando nada esta conectado.

Muchas gracias. Lo pondré todo. Y de hecho añadiré una pregunta más sobre alimentación del proyecto.
Voy a dar un vistazo al,link que me has pasado a ver si encuentro alto que me ayude. Gracias!

el código está dividio en varios files.


#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Adafruit_GFX.h>
#include <gfxfont.h>
#include <Wire.h>

#include <ArduinoBLE.h>

#include "Constans.h"
#include "VariablesGlobals.h"

// Per sensor BWT901, via bluetooth
BLEDevice sensorAngles;
BLECharacteristic caracSensor;

// Display oled
Adafruit_SSD1306 oled(ANCHO,ALTO,&Wire,OLED_RESET);

void Inicialitzar();
void DisplayInicial();
void DisplayMissatge();
void GeneraPuntetsEnMissatge(bool Reiniciar=false);
void CapceleraAngles();
void MostrarAngles(char _Tipus, int _AngAct, int _AngDest);
void Format3(int _Valor, char _cAux[]);
void DisplayOffsets();
void AssignaOffsets();
void LlegirDesti();
void TrevallaMissatge(char _Dades[], uint8_t _NumChars);
void CalculaSentits();
bool InitzialitzarConexioSensor();
void ObtenirAngles();
int AjustarAngle(int _AngleBrut);
void IniciaConexionsSerie();
void AssignaMotors();
void DesactivaMotorST(stMotor _Motor);
void ActuaMotorST(stMotor &_Motor, eSentit _Sentit, int _Velocitat);


void setup() {
  Wire.begin();
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
   
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENB, OUTPUT);

   estatActual = Inici;

}

void loop() {

  switch (estatActual){
    case Inici:
      Inicialitzar();
      IniciaConexionsSerie();
      estatSeguent = IniciConexioSensor;
      break;
    case IniciConexioSensor:
      if(InitzialitzarConexioSensor()) estatSeguent=LLegirAngles;
      else  estatSeguent = IniciConexioSensor;
      break;
    case LLegirAngles:
      ObtenirAngles();
      break;
    case CompararAngles:
      CalculaSentits(); 
      break;
    case MoureMotors:
      ActuaMotorST(MotorElevacio,SentitElevacio,VelRapida);
      ActuaMotorST(MotorAzimut,SentitAzimut,VelLenta);
      estatSeguent = LLegirAngles;
      break;
    default:
    Serial.println("==== ERROR: estat no definit. ====");
  }
  estatActual = estatSeguent;
  BLE.poll();

}

void IniciaConexionsSerie(){
  u_long millisAnt;

  Serial.begin(9600);
  millisAnt=millis();
  while (!Serial && (millis() <( millisAnt + SEGONS_ESPERA_CONEXIO_SERIE_DEBUG*1000))){
    strcpy(gTitol,"USB CONS.");
    strcpy(gDetall,"Inician ");
    GeneraPuntetsEnMissatge();
    DisplayMissatge();
    delay(500);
  }
  if(!Serial){
    strcpy(gTitol,"USB CONS.");
    strcpy(gDetall,"=== NO CONECTAT === ");
    DisplayMissatge();
    delay(2000);
  } else gConectatUsbConsola = true;

  Serial1.begin(9600);
  millisAnt=millis();
  while (!Serial1 && (millis() < (millisAnt + SEGONS_ESPERA_CONEXIO_SERIE_SATPC*1000))){
    strcpy(gTitol,"USB SATPC");
    strcpy(gDetall,"Inician ");
    GeneraPuntetsEnMissatge();
    DisplayMissatge();
    delay(200);
  }
  if(!Serial1){
    strcpy(gTitol,"USB SATPC");
    strcpy(gDetall,"=== NO CONECTAT === ");
    DisplayMissatge();
    delay(2000);
  } else { 
    gConectatUsbSatPC = true;
    strcpy(gTitol,"USB SATPC");
    strcpy(gDetall,"  CONECTAT  ");
    DisplayMissatge();
    delay(2000);

  }
}

void Inicialitzar(){
  AssignaMotors();
  DisplayInicial();
  // Per seguretat, sortides motors.
  DesactivaMotorST(MotorElevacio);
  DesactivaMotorST(MotorAzimut);
  delay(10000); 
  gCapceleraAnglesYaActivada=false;
}

void CalculaSentits(){

 // per probes, cada x cridades enviem resultats a pantalla.
  static int vegadaActual = NUM_VEGADES_ENVIAR;
  static unsigned long milIni;

  AngleX_Actual = AngXLlegit;
  AngleZ_Actual = AngZLlegit;
 // En cada loop verifiquem si ens ha arrivat alguna nova dada de destinacció
  LlegirDesti();

  AngleX_Desti = AjustarAngle(AngleX_Desti);
  AngleZ_Desti = AjustarAngle(AngleZ_Desti);

  MostrarAngles('A', AngleZ_Actual, AngleZ_Desti);
  MostrarAngles('E', AngleX_Actual, AngleX_Desti);
 
  if(gConectatUsbConsola){
    if(vegadaActual>=NUM_VEGADES_ENVIAR){
      Serial.print("Temps per ");Serial.print(vegadaActual);Serial.print(" : "); Serial.print(millis()-milIni);
      Serial.print("  Ang Z Actual: "); Serial.print(AngleZ_Actual);
      Serial.print("  AngZ Destí: "); Serial.print(AngleZ_Desti);
      Serial.print("    AngX Actual: "); Serial.print(AngleX_Actual);
      Serial.print("  AngX Destí: "); Serial.println(AngleX_Desti);
      vegadaActual = 0;
      milIni = millis();
    } 
    vegadaActual++;
  }
  
  /* El nou estat podra ser:
    .-Llegir angles.
    .-Moure motors. Aquest será assignat si un cuansevols del angles ho requereix. 
      El process de moure motors activará el que necessiti per cada motor,
      en funció del sentit calculat aqui.
    .-al mneys per proves, el igual ho fem amb un marge de MARGE_COMPARACIO_ANGLES º.
      ULL: si destí es entre 0 i MARGE, al comprobar respecte a 359 no es considera
      assolit. No crec que sigui problema, pero....
  */
  // ELEVACIO. Angle X

  if (abs(AngleX_Actual - AngleX_Desti) < MARGE_COMPARACIO_ANGLES){                                        // (Angle_Actual==Angle_Desti){
    DesactivaMotorST(MotorElevacio);
    SentitElevacio = Parat;
  } else if(AngleX_Actual>90 && AngleX_Actual < (ANGLE_DE_TALL_X  )){
    SentitElevacio= SentitEnrere;
  } else if (AngleX_Actual<=360 && AngleX_Actual >(ANGLE_DE_TALL_X )){
    SentitElevacio= SentitEndevant;
  } else if (AngleX_Actual<=90 && AngleX_Actual >= 0){
    if (AngleX_Desti>AngleX_Actual) {
      SentitElevacio= SentitEndevant;
    } else if (AngleX_Desti<AngleX_Actual) {
      SentitElevacio = SentitEnrere;
    } else { 
      SentitElevacio = Parat;  //no es donará el cas, pero...
    }
  } else { 
    SentitElevacio = Parat;  //no es donará el cas, pero...
  }

// Per Azimut, angle Z
if (abs(AngleZ_Actual - AngleZ_Desti) < MARGE_COMPARACIO_ANGLES){         
  DesactivaMotorST(MotorAzimut);
  SentitAzimut = Parat;
} else{
  if (AngleZ_Desti<=ANGLE_DE_TALL_Z){
    if (AngleZ_Actual>ANGLE_DE_TALL_Z){
      SentitAzimut= SentitEndevant;
    } else {
      if (AngleZ_Desti>AngleZ_Actual) {
        SentitAzimut = SentitEndevant;
      } else {
        SentitAzimut = SentitEnrere;
      }
    }
  } else {   //desti  >AngleDeTallZ
    if (AngleZ_Actual<ANGLE_DE_TALL_Z){
      SentitAzimut = SentitEnrere;
    } else {
      if (AngleZ_Desti>AngleZ_Actual){
        SentitAzimut = SentitEndevant;
      } else {
        SentitAzimut = SentitEnrere;
      }
    }

  }
}

 // Només si els dos motors estan en lloc ( i per tant el seu sentit es Parat), el estat seguent global será
 // llegir angles. Després de moure motors ja es fa la llegir angles.

  if(SentitElevacio==Parat&&SentitAzimut==Parat) estatSeguent = LLegirAngles;
  else estatSeguent = MoureMotors;

}


#include "SatPc.h"
#include "DisplayOled.h"
#include "Angles.h"
#include "Motors.h"

Constantes:

const char  VERSIO[] ="3.02";

// Per temps conexions serie
const uint8_t SEGONS_ESPERA_CONEXIO_SERIE_DEBUG = 10;
const uint8_t SEGONS_ESPERA_CONEXIO_SERIE_SATPC = 15;

// Per Display oled
const uint8_t ANCHO = 128;
const uint8_t ALTO = 64;
const uint8_t OLED_RESET = 4;

// Per sensor
const uint8_t NUM_MOSTRES = 3;
const uint8_t NUM_LECTURA_PER_ASSIGNA_OFFSET = 4;
const ulong MILLIS_PROVAN_CONEXIO = 1000;

// Pins conexió driver motor angle X-Elevacio
const int IN1 = 4; // Endevant
const int IN2 = 5; // Enrere
const int ENA = 6; // Enable
// Pins conexió driver motor angle Z-Azimut
const int IN3 = 7; // Endevent
const int IN4 = 8; // Enrere
const int ENB = 9; // Enable

// Valors per velocitat Lenta i Rapida 
const int VelRapida = 255;
const int VelLenta = 125;  
const int SEGONS_MAXIM_ACTIVACIO_MOTORS_SEGUIT = 5;
const int SEGONS_ESPERA_ENTRE_ACTIVACIO_MOTOR = 2;

// Per calculs sentit
const int MARGE_COMPARACIO_ANGLES = 5;
const int NUM_VEGADES_ENVIAR = 10;
const int ANGLE_DE_TALL_X = 180;
const int ANGLE_DE_TALL_Z = 180;

Variales globales

// Per Missatges. En lloc de passar per parametre, definim global. ho sento...
char gTitol[10]="blanc";
char gDetall[36]="blanc";
bool gCapceleraAnglesYaActivada =false;

// Indicadors si hi ha conexió per usb de consola i per usb del SatPC
bool gConectatUsbConsola = false;
bool gConectatUsbSatPC = false;

// ANGLES---
int AngXLlegit, AngYLlegit, AngZLlegit;
int AngleX_Actual;
int AngleX_Desti;
int AngleZ_Actual;
int AngleZ_Desti;
int OffsetX=0;
int OffsetZ=0;
// Indicador de offset assignats. Per seguretat ho farem a la NUM_LECTURA_PER_ASSIGNA_OFFSET.
uint8_t offsetsAssignats = 0;


// ENUMS----

// Sentit de gir del motor
enum eSentit {SentitEndevant=0,SentitEnrere=1,Parat=3};
eSentit SentitElevacio, SentitAzimut;

// ================== Maquina estats.
enum eEstats {Inici, IniciConexioSensor, LLegirAngles, CompararAngles, MoureMotors};
eEstats estatActual, estatSeguent, estatUltim;

// prova a fer servir estructures.
struct stMotor{
    char Codi;
    int8_t PinEndevant;
    int8_t PinEnrera;
    int8_t PinEnable;
    char Nom[9];
    eSentit UltimSentit;
    ulong MilisActivacioUltimSentit;
    byte EnEspera;
    ulong MilisIniciEspera;
};
stMotor MotorAzimut, MotorElevacio;

Angulos:

void ObtenirAngles(){

  int16_t iX, iY, iZ;
  int16_t iangle[3][NUM_MOSTRES];

  if (!sensorAngles.localName().startsWith("HC")){
    // per seguretat, si no hi ha conexio, desactivem motors
    DesactivaMotorST(MotorElevacio);
    DesactivaMotorST(MotorAzimut);
    strcpy(gTitol,"SENSOR");
    strcpy(gDetall,"Desconectat                       ");
    DisplayMissatge();
    GeneraPuntetsEnMissatge(true);
    gCapceleraAnglesYaActivada=false;
    delay(3000);
    estatSeguent = IniciConexioSensor;
    return;
  }
  for(uint8_t mAct=0;mAct<NUM_MOSTRES;mAct++){
    uint8_t valors[64];
    bool bTrobat = false;
    // possem un timer per verure si no hi ha conexio. No esperarem més de 1 segon.
    unsigned long inici = millis();
    while(!bTrobat ){
      // a lo bestiaaaa. Per el hipotetic cas de que estigués en marxa mes de no se quantes horas (crec dies), verifico millis no reiniciat.
       if((millis() - inici > MILLIS_PROVAN_CONEXIO ) || millis() < inici ){
            if(gConectatUsbConsola) Serial.print("Desconectem per timeout");
            BLE.disconnect();
            DesactivaMotorST(MotorElevacio);
            DesactivaMotorST(MotorAzimut);
            estatSeguent = IniciConexioSensor;
            return;
       }
      if (caracSensor.valueUpdated()){
        caracSensor.readValue(valors,20);
        for (int pos = 0;pos <10;pos++){
          if(valors[pos]==0x55&&valors[pos+1]==0x53){
            iangle[0][mAct] = (short(valors [pos+3]<<8| valors [pos+2]))*180/32768;
            iangle[1][mAct] = (short(valors [pos+5]<<8| valors [pos+4]))*180/32768;
            iangle[2][mAct] = (short(valors [pos+7]<<8| valors [pos+6]))*180/32768;
            bTrobat= true;
          }
        }
      }
    }
  }
  // tenim NUM_MOSTRES mostres.Calculemn la mitja i asignem a globals
  iX=0; for( int i=0;i<NUM_MOSTRES;i++) iX+=iangle[0][i];
  AngXLlegit = int(iX / NUM_MOSTRES);
  iY=0; for( int i=0;i<NUM_MOSTRES;i++) iY+=iangle[1][i];
  AngYLlegit = int(iY / NUM_MOSTRES);
  iZ=0; for( int i=0;i<NUM_MOSTRES;i++) iZ+=iangle[2][i];
  AngZLlegit = int(iZ / NUM_MOSTRES);

// Ajustar angle Z.
  AngZLlegit=-AngZLlegit;
  if(AngZLlegit<0) AngZLlegit+=360;
// Ajustar angle X;
  if(AngXLlegit<0) AngXLlegit+=360;

  AngXLlegit += OffsetX;
  AngZLlegit += OffsetZ;

  estatSeguent=CompararAngles;
// A les proves no estaba funcionan i diria que no es necessari..
/*
  if(offsetsAssignats<=NUM_LECTURA_PER_ASSIGNA_OFFSET)
    AssignaOffsets(); // internament assigna només en la segona lectura.
  else
    estatSeguent = CompararAngles; 
*/
// hem acabat.
}

// ======================= SENSOR =====================

bool InitzialitzarConexioSensor(){

bool _bRet = false;
  gCapceleraAnglesYaActivada=false;
  strcpy(gTitol,"SENSOR");
  strcpy(gDetall,"Inician Bluetooh");
  GeneraPuntetsEnMissatge();
  DisplayMissatge();

   // initialize the Bluetooth® Low Energy hardware
  if (!BLE.begin()) {
    if(gConectatUsbConsola) Serial.println("starting Bluetooth® Low Energy module failed!");
    return _bRet;
  }

  if(gConectatUsbConsola) Serial.println("Bluetooth® Low Energy Central inicializat.");
    
  BLE.scan();
  delay(250);
  sensorAngles = BLE.available();
  while (sensorAngles){
    if(sensorAngles.localName().startsWith("HC-06")){     
      break;
    }
    sensorAngles = BLE.available();
  }

/*
  BLE.scanForAddress("00:0c:bf:07:69:17");
  delay(100);
  sensorAngles = BLE.available();
  
*/

  if(!sensorAngles){
    if(gConectatUsbConsola) Serial.println("No trobat el sensor en sensorAngles.");
    return _bRet;
  }
  if(gConectatUsbConsola) Serial.print("Nom Device: ");
  if(gConectatUsbConsola) Serial.println(sensorAngles.localName());
  delay(250);
  BLE.stopScan();

  if (sensorAngles.connect()) {
    if(gConectatUsbConsola) Serial.println("Connected");
  } else {
    if(gConectatUsbConsola) Serial.println("Failed to connect!");
    return _bRet;
  }

 if(sensorAngles.discoverAttributes()) {
    if(gConectatUsbConsola) Serial.println("Attributes discovered");
  } else {
    if(gConectatUsbConsola) Serial.println("Attribute discovery failed!");
    sensorAngles.disconnect();
    return _bRet;
  }
  BLEService servei = sensorAngles.service("49535343-fe7d-4ae5-8fa9-9fafd205e455");
  if(!servei){
    if(gConectatUsbConsola) Serial.println("servei no trobat");
    return _bRet;
  }
 
  caracSensor = sensorAngles.characteristic("49535343-1e4d-4bd9-ba61-23c647249616");
  if(!caracSensor){
    if(gConectatUsbConsola) Serial.print("caracteristica no trobada");
    sensorAngles.disconnect();
    return _bRet;
  }
  
  caracSensor.subscribe();
  strcpy(gDetall,"Conectat                          ");
  DisplayMissatge();

  return true;
}

void AssignaOffsets(){
  // Asumim que el primer cop que es activat el processador (alimentació o reset)
  // l'antena está a 0º azimut i 0º elevació.
  offsetsAssignats++;
  if(offsetsAssignats>NUM_LECTURA_PER_ASSIGNA_OFFSET) return;
  if(offsetsAssignats==NUM_LECTURA_PER_ASSIGNA_OFFSET){
    OffsetX = -AngXLlegit;
    OffsetZ = -AngZLlegit;
    DisplayOffsets();
    gCapceleraAnglesYaActivada=false;
  }

}

int AjustarAngle(int _AngleBrut){
  // Ajustem angles a 0-359.
while (_AngleBrut < 0) _AngleBrut += 360;
if(_AngleBrut>=360) _AngleBrut %= 360;
return _AngleBrut;
}

Motores

void AssignaMotors(){
  MotorAzimut.Codi='Z';
  strcpy(MotorAzimut.Nom,"Azimut");
  MotorAzimut.PinEnable=ENB;
  MotorAzimut.PinEndevant=IN3;
  MotorAzimut.PinEnrera=IN4;
  MotorAzimut.UltimSentit=Parat;
  MotorAzimut.MilisActivacioUltimSentit=0;
  MotorAzimut.EnEspera=false;
  MotorAzimut.MilisIniciEspera=0;
  
  MotorElevacio.Codi = 'E';
  strcpy(MotorElevacio.Nom,"Elevacio");
  MotorElevacio.PinEnable=ENA;
  MotorElevacio.PinEndevant=IN1;
  MotorElevacio.PinEnrera=IN2;
  MotorElevacio.UltimSentit=Parat;
  MotorElevacio.MilisActivacioUltimSentit=0;
  MotorElevacio.EnEspera=false;
  MotorElevacio.MilisIniciEspera=0;
}

void DesactivaMotorST(stMotor _Motor){
//  Serial.print("DesactivaMotor------");
  digitalWrite(_Motor.PinEndevant,LOW);
  digitalWrite(_Motor.PinEnrera,LOW);
  analogWrite(_Motor.PinEnable,LOW);
  _Motor.UltimSentit=Parat;
}

void ActuaMotorST(stMotor &_Motor, eSentit _Sentit, int _Velocitat){

  if(_Motor.EnEspera){
    if(millis() - _Motor.MilisIniciEspera > SEGONS_ESPERA_ENTRE_ACTIVACIO_MOTOR*1000ul){
      _Motor.EnEspera= false;
      _Motor.MilisIniciEspera=0;
      _Motor.MilisActivacioUltimSentit = millis();
    } else {
        _Motor.UltimSentit=_Sentit;
      return; // a esperar...
//=============
    }
  }
  // prova a optimitzar. Si el nou sentit es el que ja te actiu el motor,
  // no fem res.
  if(_Motor.UltimSentit==_Sentit){
    if( (_Motor.UltimSentit != Parat) && ((millis() - _Motor.MilisActivacioUltimSentit) 
            > SEGONS_MAXIM_ACTIVACIO_MOTORS_SEGUIT*1000ul)){
      _Motor.EnEspera=true;
      _Motor.MilisIniciEspera=millis();
      DesactivaMotorST(_Motor);
      return;
  //==============
    }
    
  } else {
    _Motor.MilisActivacioUltimSentit = millis();
  }

  switch (_Sentit) {
    case SentitEndevant:
      digitalWrite(_Motor.PinEndevant, HIGH);
      digitalWrite(_Motor.PinEnrera, LOW);
      analogWrite(_Motor.PinEnable, _Velocitat);
      break;

    case SentitEnrere:
      digitalWrite(_Motor.PinEndevant, LOW);
      digitalWrite(_Motor.PinEnrera, HIGH);
      analogWrite(_Motor.PinEnable, _Velocitat);
      break;
    default:
      // incluim tambe el sentit Parat.
      analogWrite(_Motor.PinEnable, LOW);
      digitalWrite(_Motor.PinEndevant, LOW);
      digitalWrite(_Motor.PinEnrera, LOW);
  }
  _Motor.UltimSentit=_Sentit;
}

SatPc

void LlegirDesti(){
 
  static  char DadesValides[10];
  static uint8_t NumCharsTractar=-1;
  char CharLlegit;

  if(!gConectatUsbSatPC){ //Si no está conectat, podem treballar igual per proves.
    AngleZ_Desti=0;
    AngleX_Desti=0;
    return;
  //=============
  }  

  if(!Serial1.available()) return;
  //==================
  /*
    A veure: Estem reben continuament el C2. Fa molta nosa. Em de fer un tractamente de Missatge per elimarho.
    De moment, ho deixem. Funciona prou be.
  */
  while (Serial1.available()){
    CharLlegit=Serial1.read();
    if(CharLlegit=='C' || CharLlegit=='W'){ // Si es inici de Missatge.
      NumCharsTractar=0;
      DadesValides[NumCharsTractar] = CharLlegit;
      NumCharsTractar++;
      continue;
    }

    if(CharLlegit=='\n' || ((DadesValides[0]=='W')&&NumCharsTractar>=8)) {   //Final Missatge
      TrevallaMissatge(DadesValides, NumCharsTractar);
      NumCharsTractar=-1;
      continue;
    }

    if(NumCharsTractar==-1) continue;     // Quansevol altre caracter, si estem al mitg de Missatge l'afegim; si no, es perd.
    DadesValides[NumCharsTractar] = CharLlegit;
    NumCharsTractar++;
  }
}

void TrevallaMissatge(char _Dades[], uint8_t _NumChars){
// Missatge que enviará el Sat32: “Waaa eee” a on “aaa” l'angle desviació azimut i “eee” l'angle d'elevació target.
  char caux[]= "000";
  switch (_Dades[0]) {
    case 'W':
      for (int8_t i=0;i<=3;i++) caux[i]=_Dades[i+1];
      AngleZ_Desti = atoi(caux);
      for (int8_t i=0;i<=3;i++) caux[i]=_Dades[i+5];
      AngleX_Desti = atoi(caux);
      break;
    default:
    // res
      break;
  }
}

DisplayOled


void DisplayInicial(){
  oled.clearDisplay();
  oled.setTextColor(WHITE);
  oled.setCursor(0,0);
  oled.setTextSize(2);
  oled.print("--INICI--");
  oled.setCursor(0, 30);
  oled.print("V: "); oled.print(VERSIO);
  oled.display();

}

void CapceleraAngles(){
  oled.clearDisplay();
  oled.setTextColor(WHITE);
  oled.setCursor(0,0);
  oled.setTextSize(2);
  oled.print("T Act Dest");
}

void MostrarAngles(char _Tipus, int _AngAct, int _AngDest){
  int _linea;
  char cAux[]="000";

 // oled.clearDisplay();
  if(!gCapceleraAnglesYaActivada){
    CapceleraAngles();
    gCapceleraAnglesYaActivada=true;
  }
  oled.setTextColor(WHITE,BLACK);
  if(_Tipus=='A') _linea = 21; else _linea = 41;
  oled.setCursor(0,_linea);
  oled.print(_Tipus);

  oled.setCursor(30,_linea);
  Format3(_AngAct,cAux);
  oled.print(cAux);

  eSentit _sentit;
  if(_Tipus=='A') _sentit = SentitAzimut; else _sentit = SentitElevacio;
  oled.setCursor(65, _linea);
  switch (_sentit){
    case SentitEndevant:
      oled.print('>');
      break;
    case SentitEnrere:
      oled.print('<');
      break;
    default:
      oled.print('=');
  }
 
  oled.setCursor(80, _linea);
  Format3(_AngDest,cAux);
  oled.print(cAux);
  oled.display();
}

void Format3(int _Valor, char _cAux[]){

  int ind = 0;
  char buff[]="000";
  char buffFin[]="  0";
  if(_Valor!=0){
    itoa(_Valor,buff,10);
    while(pow(10,ind) <= _Valor) ind++;
    for (int i = 0; i< 3; i++){
      if(3-i >ind) buffFin[i]=' '; else buffFin[i]=buff[i -(3-ind)];
    }
  }
  memmove(_cAux,&buffFin,3);
}


void DisplayMissatge(){
  oled.clearDisplay();
  oled.setTextColor(WHITE);
  oled.setCursor(0,0);
  oled.setTextSize(2);
  oled.print(gTitol);
  oled.setCursor(0,22);
  oled.setTextSize(1);
  char caux[18]="                 ";
  //memmove(msg, &msg[1], displayWidth - 1);
  memmove(caux,&gDetall,18);
  oled.print(caux);
  //caux[0]=' ';
  //memset(hyphen, '-', sizeof(hyphen));
  memset(caux,' ',18);
  memmove(caux,&gDetall[18],18);
  oled.setCursor(0,42);
  oled.print(caux);
  oled.display();

}

void GeneraPuntetsEnMissatge(bool _Reiniciar){
  static byte index=0;
  if(_Reiniciar){
    index=0;
    return;
  }
  if(index>=17){
    index=0;
    strcpy(&gDetall[18],"                 "); 
  }  
  strcpy(&gDetall[18 + index],".");
  index++;
}

void DisplayOffsets(){
  strcpy(gTitol," OFFSETS ");
  strcpy(gDetall,"Elev.             Azim.           ");
  Format3(OffsetX,&gDetall[6]);
  Format3(OffsetZ,&gDetall[24]);
  DisplayMissatge();
  delay(3000);
}

Este es el esquema:

Y la nueva pregunta es respecto a cómo alimentar el conjunto. Actualmente se alimenta todo (menos el FT232) con la entrada de USB del Nano que utilizamos para las pruebas, pero la idea es no utilizar ese USB normalmente. El L298N creo que suministra 5V, pero el Nano funciona a 3.3. El FT232 puede suministrar 3.3 pero según el datasheet sólo 50ma. Sería suficiente?

Otra duda: Si alimento el Nano externamente via VIN y conecto para hacer pruebas el conector USB, genera algún problema?

Adjunto datos de FT232:
FT232RL-USB-TO-TTL-Converter-Datasheet.pdf (89.7 KB)

Y del BWT901:
wt901blecl_50.pdf (1.2 MB)

De hecho veo que ya queda controlado con Serial1.available. Como ya tengo conemplado que si no envía nada continuo normalmente, realmente tanto me da que sea por no conexión o porque en ese momento no tiene nada a enviar el pc. Muchas gracias por tu repuesta.

No, claro que no.

No. No debería generar ningún problema.

Consejo: Te aconsejo igual que armes un cable especial donde elimines el terminal +5V del cable que viene de la PC. coloca un switch y lo usas cuando lo necesites.

Muchas gracias por tus ideas, Subyte.
Al final, mi hermano (él es el radioaficionado y "manitas"; de hecho el rotor lo ha montado él) ha montado todo el circuito dentro una caja y las primeras pruebas está funcionando bien. Como es para utilizar en desplazamientos, la alimentación será mediante un powerbank en el usb del Nano. Si hacemos una versión posterior miraremos de hacerlo con los 12v de los motores y algún regulador a 3.3.
Si bien los problemas con el BWT901CL continuan, con los bypass efectuados podemos utilizarlo. ¿Doy por cerrado el tema o lo dejo por si alguien tiene alguna solución para lo del BWT901CL? Lo pero es lo del nombre: si alguna vez hay cerca otro dispositivo bluetooth con nombre HC-06, habrá posible conflicto.

Vi que el BWT901CL permite conexión Serial, evidentemente no has optado en usarlo de ese modo por comodidad, es así?

Sí. Va bien porque así queda sujeto en la estructura de la antena y no necesita ningún cable. Es para utilizarlo cuando se hacen salidas a ciertos lugares que permiten mejor recepción que el balcón de una casa:) El rotor está sobre un trípode y el equipo de radio creo en una mesa plegable o en el coche. Los cables de antena y de los motores pueden ser largos, pero creímos que mejor que el sensor fuese inalámbrico para evitar problemas de cable largo. También estuvimos pensando si hacer el aparato en sí en la base del rotor y así poder utilizar sensor con conexión cable, pero parecía más pulido así, además de que ha de conectarse a un pc donde está el programa que va indicando las coordenadas por donde pasan los satélites. Digamos que queda "una central" donde está el equipo radio, el Pc y este controlador. De aquí salen los cables de antena y de los motores (son muy pequeños, con mucha reducción, y consumen muy poco. Unos cables de una cierta sección permite no tener prácticamente caida de tensión). Gracias de nuevo!