Modulos bluetooth, problemas para recibir varios datos a la vez, ayuda por favor

Llevo unos dias trabajando con el modulo HC-05 y HC-06
los tengo trabajando con arduinos Nano a ambos, de primeras puedo decir que la comunicacion entre los modulos es exitosa y no he tenido problemas con eso.
Mi dilema esta en que quiero enviar los datos de un joystick para hacer un control remoto, pero tengo problemas en como recibir los datos, ya que los leds que tengo para testear la salida no estan respondiendo como lo quise en las condicionales, y ya llevo vario rato tratando de ver soluciones para que los datos sean interpretados de forma correcta por mi receptor.

Este es el codigo del Maestro, o el control

const int X = A0;
const int Y = A1;
int valorX;
int valorY;

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

void loop() {
 valorX = analogRead(X);
 valorY = analogRead(Y);
 String datos = "*"+String(valorX)+"#"+String(valorY)+"@";
 Serial.print(datos);
 delay(30);
}

Este es codigo del esclavo, o receptor
Ahi se puede ver como esta comentado mi anterior intento para recibir los datos, y tambien las condicionales que menciono mas arriba estan comentadas porque ahora solo necesito saber si los datos llegan bien o no. Estuve informadome acerca de como funcionan los String y como leerlos y convertirlos a datos enteros otra vez, que es lo que necesito para que funcionen mis condicionales.

const int A = 2;
const int B = 3;
const int C = 4;
const int D = 5;
int valorX;
int valorY;
char datoX;
char datoY;
bool paqueteCompleto;
void setup() {
  Serial.begin(9600);
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
}

void loop() {
  String datos ="";
  while (Serial.available() > 0) {
    if(Serial.read() == '@') {
     paqueteCompleto = true;
    } else {
      datos += Serial.read();
    }
    datos ="";
    if(paqueteCompleto == true) {
      valorX = datos.substring('*','#').toInt();
      valorY = datos.substring('#','@').toInt();
    } 
    /* datoX = Serial.read();
    valorX = Serial.parseInt(); //Se recupera la siguente cantidad entera, despues del *
    datoY = Serial.read();
    valorY = Serial.parseInt(); */
    Serial.print(valorX);
    Serial.print(" X || ");
    Serial.println(valorY);
    ////////////////
    /* if (valorY >= 900) {
       digitalWrite(A, HIGH);
      } else {
       digitalWrite(A, LOW);
      }
      if (valorY <= 150) {
       digitalWrite(D, HIGH);
      } else {
       digitalWrite(D, LOW);
      }

      if (valorX >= 600) {
       digitalWrite(A, HIGH);
       digitalWrite(D, HIGH);
      } else {
       digitalWrite(A, LOW);
       digitalWrite(D, LOW);
      }
      if (valorX <= 300) {
       digitalWrite(B, HIGH);
       digitalWrite(C, HIGH);
      } else {
       digitalWrite(B, LOW);
       digitalWrite(C, LOW);
      }*/

  }
}

Espero puedan ayudarme con mi dilema, aclaro que todavia estoy novato para el tema de los string y la comunicacion serial, ya he investigado pero no lo termino de entender.
Saludos

Estas borrando el contenido de la variable cada vez que lees un caracter:

datos ="";

En que pines tienes conectado el bluetooth??

Anda ya
Los tengo conectados a los TX y RX normales, no estoy usando la librería del SoftwareSerial

Los tengo conectados a los TX y RX normales, no estoy usando la librería del SoftwareSerial

Pues eso es un problema si estas usando el monitor serial,deberias usar softwareserial para el bluetooth si quieres seguir usandolo.

Entonces eso es lo que está afectando a mi receptor?
Alguna otra sugerencia?
Edit: ya probé con eso pero es una condicional la que no quiere responder
Curiosamente origanizando de diferente forma mis if's, logré hacer que tres de cuatro direcciones sirvieran
Edit 2: olvidé mencionar que ya le he he hecho algunos cambios al código
Aqui esta lo que menciono
El condicional que no funciona es el primer if (valorX > 700)

#include <SoftwareSerial.h>
SoftwareSerial BT(7,8);  //7 --> RX     8 -->TX
const int A = 2;
const int B = 3;
const int C = 4;
const int D = 5;
int valorX;
int valorY;
char datoX;
char datoY;
bool paqueteCompleto;

void setup() {
  //Serial.begin(9600);
  BT.begin(9600);
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
}

void loop() {
  String datos = "";
  if (BT.available() > 0) {
    if (BT.read() == '@') {
      paqueteCompleto = true;
    } else {
      datos += BT.read();
    } 
    if (paqueteCompleto == true) {
      valorX = datos.substring('*', '#').toInt();
      valorY = datos.substring('#', '@').toInt();
      valorX = BT.parseInt();
      valorY = BT.parseInt();
    }
    
    ////////////////
    if (valorX > 700) {
      digitalWrite(A, HIGH);
      digitalWrite(D, HIGH);
    } else {
      digitalWrite(A, LOW);
      digitalWrite(D, LOW);
    }
    
    if (valorY > 900) {
      digitalWrite(D, HIGH);
    } else {
      digitalWrite(D, LOW);
    }

    if (valorX < 300) {
      digitalWrite(B, HIGH);
      digitalWrite(C, HIGH);
    } else {
      digitalWrite(B, LOW);
      digitalWrite(C, LOW);
    }

    if (valorY < 150) {
      digitalWrite(A, HIGH);
    } else {
      digitalWrite(A, LOW);
    }
  }
}

1-Si usas el condicional if para comprobar si hay datos,no puedes borrar el contenido de la variable al inicio del loop,debes borrarla cuando hayas recibido el caracter de final,porque puede ser que cuando compruebes si hay datos disponibles, no hayan llegado todos justo en el momento de leer.

String datos = "";
  if (BT.available() > 0) {

2-Si un valor es mayor que 900,tambien es mayor que 700,se van a cumplir esas dos condiciones al mismo tiempo (idem si un valor es menor que 150,tambien es menor que 300),usa rangos: si a es > que 700 y a es menor que 900 ......
3-Esto no lo entiendo:

valorX = datos.substring('*', '#').toInt();
      valorY = datos.substring('#', '@').toInt();
      valorX = BT.parseInt();
      valorY = BT.parseInt();

Si se supone que tienes los valores que buscas,para que los machacas con valores que seguramente sean 0 ,puesto que ya has leido los datos?

Respondiendo al punto 3.-Es que si sólo usaba el toInt() no me convertía nada a enteros y solo había un buen de números aleatorios sin sentido, es por ellos que usé de nuevo el parseInt() ya que ese sí me devuelve los valores originales que les desde el otro Arduino
Del punto 1.- entonces qué haría? Cambio el if o cómo?
Del punto 2.- Lo tomaré en cuenta para arreglar esas condicionales, gracias

1-En tu codigo hay precisamente un condicional que detecta cuando has enviado el ultimo caracter :

if (BT.read() == '@') {
      paqueteCompleto = true;
    }

Y aqui estas cometiendo otro fallo ya que estas leyendo el caracter sin asignarlo a una variable.Si el valor no es '@' ,al siguiente BT.read() leeras el siguiente caracter,luego:

if (BT.available() > 0) {
    char caracter = BT.read();
    if (caracter == '@') {
      paqueteCompleto = true;
    } else {
      datos += caracter;
    }

Si solucionas eso,cuando recibas ultimo caracter ,entraras aqui:

if (paqueteCompleto == true) {

y es al final de este bloque ,una vez has sacado los datos que necesitas ,cuando puedes vaciar dato asignandole una cadena vacia y poner paqueteCompleto a false para empezar de nuevo.Todas las comparaciones de los datos recibidos deben tambien ir dentro de este bloque para que solo se ejecuten cuando se hayan recibido nuevos datos.
3-No te funciona porque estas usando substring() incorrectamente,repasa la referencia en esta misma web substring() - Arduino Reference y veras que los parametros que hay que pasarle a la funcion son el indice donde comienza la cadena y el indice del caracter posterior donde termina la cadena que quieres extraer.Recuerda que los indices empiezan por 0 y es de tipo int

 String datos = "";
  if (BT.available() > 0) {
    char caracter = BT.read();
    if (caracter == '@') {
      paqueteCompleto = true;
    } else {
      datos += caracter;
    }
    datos = "";
    if (paqueteCompleto == true) {
      valorX = datos.substring('*', '#').toInt();
      valorY = datos.substring('#', '@').toInt();
      //valorX = BT.parseInt();
      //valorY = BT.parseInt();
    }
  }

Ya arreglé el fallo del caracter y asi quedo esa parte del codigo

Lo que no termino de entender es a que te refieres con indices y son de tipo de int, ya he leido el link que pusiste pero no comprendo como aplicarlo a mi codigo

Estuve haciendo pruebas con las condicionales que habia dejado comentadas y no importa cuan bien esté mi rango con la variable, se rehusa a hacer lo que le le indico.
Por otra parte intente con dejar de encencer dos leds al mismo tiempo y ahi si me respeta la condicion, al mismo tiempo que estoy checando en el monitor serie los datos del joystick y estan bien, lo que me parece extraño es como agregar ese otro digitalWrite() hace que deje de funcionar

if (valorY < 335 && valorY > 270) { // Adelante
    digitalWrite(ledA, HIGH);
    digitalWrite(ledD, HIGH);
  } else {
    digitalWrite(ledA, LOW);
    digitalWrite(ledD, LOW);
  }
  if (valorY > 35 && valorY < 70) { // Atras
    digitalWrite(ledB, HIGH);
    digitalWrite(ledC, HIGH);
  } else {
    digitalWrite(ledB, LOW);
    digitalWrite(ledC, LOW);
  }

Por ejemplo, ahi no hay ningun problema, me respeta ambas condiciones

peero cuando agrego esto todo se jode y deja de funcionar el if de "adelante"

if (valorX > 35 && valorX < 70) { // Derecha
    digitalWrite(ledA, HIGH);
  } else {
    digitalWrite(ledA, LOW);
  }
  if (valorX < 335 && valorX > 270) { // Izquierda
    digitalWrite(ledD, HIGH);
  } else {
    digitalWrite(ledD, LOW);
  }

eso es algo que no habia comentado anteriormente

Edit: acabo de hacer una prueba usando otros pines que no son los de la funcion de adelante, en vez de ellos use el 10 y 11 y con eso ya podia ver reflejado lo que necesitaba, pero no entiendo por que usar pines extra para que pueda verlo funcionando como me agradaria

hola, yo una vez intente algo parecido pero quería enviar mas de 15 variables, me confundía mucho lo de String y todo eso así que lo hice mas fácil, espero que el vídeo sea entendible

Lo que no termino de entender es a que te refieres con indices y son de tipo de int, ya he leido el link que pusiste pero no comprendo como aplicarlo a mi codigo

Hay que aprender a "escarbar" en la informacion.Te puse este enlace:
substring() - Arduino Reference al final del documento hay un enlace : EXAMPLE String Tutorials que te lleva a un monton de ejemplos con todos los metodos de String,uno de ellos para el metodo substring() ,y si clicas ahi,te lleva a: https://www.arduino.cc/en/Tutorial/StringSubstring ,el segundo ejemplo es exactamente lo que estas buscando:

String stringOne = "Content-Type: text/html";

  // you can also look for a substring in the middle of a string:
  if (stringOne.substring(14,18) == "text") {

  }

como ves ,comprueba si "text" esta en el texto stringOne entre las posiciones 14 y 18 (recuerda en realidad es un array,por lo tanto la C esta en 0,la o en 1,la n en 2.....). Ahora esto aplicalo a lo que tu necesitas.

El_Xed:
hola, yo una vez intente algo parecido pero quería enviar mas de 15 variables, me confundía mucho lo de String y todo eso así que lo hice mas fácil, espero que el vídeo sea entendible
https://www.youtube.com/watch?v=YxTj3dMLwGw&t

Muchas gracias, ya he probado con el método que usas tú y también consigo ver qué los datos me llegan bien desde el monitor serie.
Ahora mi problema es que para la dirección de "adelante" los leds que deben encender al mismo tiempo no encienden del todo, tengo una lectura de como .5 volts en esas salidas, por otra parte las otras tres direcciones funcionan sin problema

Edit: He notado que si quitó la función de imprimir los valores en la computadora los leds como qué parpadean, lo hacen con un tiempo más o menos igual que con el que lo hace el LED de TX del Arduino transmisor