Control velocidad motor Bluetooth

Quiero controlar el sentido de giro y la velocidad de un motor mediante un comunicación Bluetooth , consta de un mando formado por una placa Arduino Nano, un Joystick y un modulo Bluetooth HC05 como maestro previamente configurado mediante comandos AT.
Como receptor una placa Arduino Mega, un modulo Bluetooth HC05 ( esclavo) y un puente H BTS7960

Código del mando:


int xAxis, yAxis;

void setup() {
  Serial.begin(38400); // Tasa de comunicación predeterminada del módulo Bluetooth
}

void loop() {
  xAxis = analogRead(A0); // Leer Joysticks eje X
  yAxis = analogRead(A1); // Leer Joysticks eje Y
  
  // Enviar los valores a través del puerto serie al dispositivo Bluetooth esclavo HC-05
  Serial.write(xAxis/4); // Dividir por 4 para convertir de 0-1023 a 0-256, rango (1 byte)
  Serial.write(yAxis/4);
  delay(20);
}

Código del receptor:

#define enA 9 // Salida PWM = MotorSpeedA
#define enB 10 // Salida PWM = MotorSpeedB

int xAxis, yAxis;
unsigned int  x = 0;
unsigned int  y = 0;

int motorSpeedA = 0;
int motorSpeedB = 0;

void setup() {
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
 
  Serial.begin(38400); // Tasa de comunicación predeterminada del módulo Bluetooth
}

void loop() {
  // Valor predeterminado: sin movimiento cuando el joystick permanece en el centro
  x = 510 / 4;
  y = 510 / 4;

  // Leer los datos entrantes del Joystick o del dispositivo Bluetooth maestro
  while (Serial.available() >= 2) {
    x = Serial.read();
    delay(10);
    y = Serial.read();
  }
  delay(10);
  // Convierta de nuevo el rango 0-255 a 0-1023, adecuado para el código de control del motor a continuación
  xAxis = x*4;
  yAxis = y*4;

  // Eje Y utilizado para control hacia adelante y hacia atrás
  if (yAxis < 470) {
    // Pon el motor A hacia atrás
    // Convierta las lecturas decrecientes del eje Y para retroceder de 470 a 0 en un valor de 0 a 255 para la señal PWM para aumentar la velocidad del motor
    motorSpeedA = map(yAxis, 470, 0, 0, 255);
    motorSpeedB = 0;
  }
  else if (yAxis > 550) {
    // Pon el motor A hacia adelante
    // Convierta las lecturas crecientes del eje Y para avanzar de 550 a 1023 en un valor de 0 a 255 para la señal PWM para aumentar la velocidad del motor
    motorSpeedA = 0;
    motorSpeedB = map(yAxis, 550, 1023, 0, 255);
  }
  // Si el joystick permanece en el medio, los motores no se mueven
  else {
    motorSpeedA = 0;
    motorSpeedB = 0;
  }
  analogWrite(enA, motorSpeedA); // Send PWM signal to motor A
  analogWrite(enB, motorSpeedB); // Send PWM signal to motor B
  
  }

NOTA:

xAxis = analogRead(A0); // Leer Joysticks eje X

Lo usare en un futuro para controlar un servomotor, si logro solucionar el problema del control de velocidad del motor.

Resultado:
El motor responde correctamente a lo enviado por el mando, es decir sentido de giro y control de velocidad correcto pero va a tirones ( hace pequeñas interrupciones cuando gira )
¿Veis algún fallo en los códigos?
¿Alguna idea de lo que pueda estar sucediendo?
Gracias.

Su publicacion se MUEVE a su ubicacion actual ya que es mas adecuada.

En el loop() código del receptor tienes

// Valor predeterminado: sin movimiento cuando el joystick permanece en el centro
x = 510 / 4;
y = 510 / 4;

Si no recibes nada

// Si el joystick permanece en el medio, los motores no se mueven 
else { 
  motorSpeedA = 0; 
  motorSpeedB = 0; 
}

Entonces, arranca con velocidad 0, llegan valores, y actúa en consecuencia, vuelve al principio del loop() y si no llegan nuevos valores vuelve a asignar velocidad 0, y vuelta a empezar.
Como resultado: mueve, frena, mueve, frena... o sea, va a los saltos.

Prueba colocar

// Valor predeterminado: sin movimiento cuando el joystick permanece en el centro
x = 510 / 4;
y = 510 / 4;

en setup() no en loop(), así una vez iniciado solo responde a lo que recibe.

Saludos

Mis observaciones del código:
Para qué envias xAxis y yAxis / 4 y luego los multiplicas x 4 en el receptor?
Para hacer eso no hagas nada y envíalos normales o crees que no se puede hacer? Supongo que si pero te resultó mas simple asi no es cierto?
Claro que hay que modificar como recibes los datos porque ya serán 2 bytes para cada uno pero es posible.
Otra cosa. envias todo lo que leen el ADC en A0 y A1 cuando lo lógico es enviar solo datos distintos del anterior, dandole respiro al sistema y no tan rápido como cada 20mseg
Finalmente, envias x e y pero solo usas yAxis, entonces elimina xAxis y usa lo que necesitas.

https://youtu.be/2OXczE6VkUs

Pues a funcionado, ya no se corta.
Gracias por la ayuda.

Hoy he decidido modificar el receptor cambiando el Arduino Mega por un Arduino Nano.
El Nano lo he programado con el mismo código que programe el Mega:

#include <Servo.h> //Libreria para Servomotor

 Servo servo1; //Creo un Servomotor
 
#define enA 9// Pin 9 para retoceder
#define enB 10 // Pin 10 para avanzar

int xAxis, yAxis;//Traccion
unsigned int  x = 0;//Traccion
unsigned int  y = 0;//Traccion

int RETROCEDER = 0;//Traccion
int AVANZAR = 0;//Traccion
int PINSERVO = 2;//Salida por el pin 2 Servomotor
int PULSOMIN = 500;//Servomotor
int PULSOMAX = 2500;//Servomotor
int VALORPOT;//Servomotor
int ANGULO;//Servomotor
int POT = 0;//Servomotor


void setup() {

  servo1.attach (PINSERVO, PULSOMIN, PULSOMAX); //Servomotor
  pinMode(enA, OUTPUT);//Traccion
  pinMode(enB, OUTPUT);//Traccion
  
// Valor predeterminado: sin movimiento cuando el joystick permanece en el centro
  x = 510 / 4;//Traccion
  y = 510 / 4;//Traccion
 
  Serial.begin(38400); // Tasa de comunicación predeterminada del módulo Bluetooth
}

void loop() {
  
  // Leer los datos entrantes del Joystick o del dispositivo Bluetooth maestro
  while (Serial.available() >= 2) {
    x = Serial.read();
    delay(10);
    y = Serial.read();
  }
  delay(10);
  // Convierta de nuevo el rango 0-255 a 0-1023, adecuado para el código de control del motor a continuación
  xAxis = x*4;
  yAxis = y*4;

  // Eje Y utilizado para control hacia adelante y hacia atrás
  if (yAxis < 470) {
    // Pon el motor hacia atrás
    // Convierta las lecturas decrecientes del eje Y para retroceder de 470 a 0 en un valor de 0 a 255 para la señal PWM para aumentar la velocidad del motor
    RETROCEDER = map(yAxis, 470, 0, 0, 255);
    AVANZAR = 0;
  }
  else if (yAxis > 550) {
    // Pon el motor hacia adelante
    // Convierta las lecturas crecientes del eje Y para avanzar de 550 a 1023 en un valor de 0 a 255 para la señal PWM para aumentar la velocidad del motor
    RETROCEDER = 0;
    AVANZAR = map(yAxis, 550, 1023, 0, 255);
  }
  // Si el joystick permanece en el medio, los motores no se mueven
  else {
    RETROCEDER = 0;
    AVANZAR = 0;
  }

  VALORPOT = xAxis;
  ANGULO = map(VALORPOT,0, 1023, 0, 180);
  servo1.write(ANGULO);

  analogWrite(enA, RETROCEDER); // Envia señal PWM en pin 9 para retoceder
  analogWrite(enB, AVANZAR); // Envia señal PWM en pin 10 para avanzar
  
  }

Sorpresa la mía que solo responde cuando llevo el Joystick hacia delante y en su posición máxima el motor gira al máximo, lo demás nada.

¿Quizás debería de modificar algo del código, ya que estoy usando un Arduino Nano?

Gracias por su ayuda.

Aprende a debuggear o sea entender que pasa.
cuando llevas el joystick para adelante yAxis es >550 hasta 1023
Empieza viendo que valores estas leyendo para eso usa Serial.println( datos)
En tu caso esos datos los lees por puerto serie. Entonces asegúrate de recibir lo que crees.

 while (Serial.available() >= 2) {
    x = Serial.read();
    delay(10);
    y = Serial.read();
  }

Acá recibes x e y. Muestra por Serial que estas recibiendo.

No puedo mostrar por serial ya que estoy usando los pines TX , RX con el modulo Bluetooth

Usa SoftwareSerial y maneja el bluetooth con otros pines, cuando todo queda como debe vuelves a la configuración actual. :wink:

1 Like

Si cambio el código por este otro:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(4, 5);

int xAxis, yAxis;
unsigned int  x = 0;
unsigned int  y = 0;

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

void loop() {

  while (mySerial.available() >= 2) {
    x = mySerial.read();
    delay(10);
    y = mySerial.read();
    delay(10);
  }
  Serial.println(x);
  Serial.println(y);
    
}

¿podre ver lo que recibo del Bluetooth?
La idea seria conectar los pines TX , RX del Bluetooth a los pines 4 y 5 del Nano y que me los envié por el puerto serie al Monitor Serie para así poder ver lo que recibo del mando.
Gracias.

Así sí pero te aconsejo que setees ambos puertos a la misma velocidad.

Lo acabo de probar y veo los datos recibidos en el monitor serie:
Joystick en el centro:


Joystick hacia delante:

Joystick hacia tras:

El Joystick que controla la dirección también varia ( no pongo imagen porque la dirección si me funciona)

Visto lo cual, alguna idea de porque la tracción no me funciona

Hacé unas impresiones de los valores de RETROCEDER, AVANZAR, VALORPOT y ANGULO así vemos que pasa por ahí.

1 Like

Para ello tendría que modificar el código del post #6 para incluir el softwareSerial del post #10 de tal manera que pueda enviar los valores de RETROCEDER y AVANZAR al monitor serie.
VALORPOT y ANGULO no los veo necesario verlos, ya que el servo de la direccion si me responde.

Bueno, a ver como hago la modificación siendo novato en Arduino.
Cualquier duda os doy la lata.........

Post #11 El Bluetooth lo tengo configurado a 38400, si pongo mySerial.begin a 9600 no creo que funcione.

No, poné Serial a 38400!

Y sí

Entendí que pusiese 9600 a mySerial. Ya te entendí te referías a que ponga en Serial. 38400 también. Entendido y modificado.

Respecto al código ya lo he modificado:

#include <SoftwareSerial.h>
#include <Servo.h> //Libreria para Servomotor

 Servo servo1; //Creo un Servomotor
 SoftwareSerial mySerial(4, 5);
 
#define enA 9// Pin 9 para retoceder
#define enB 10 // Pin 10 para avanzar

int xAxis, yAxis;//Traccion
unsigned int  x = 0;//Traccion
unsigned int  y = 0;//Traccion

int RETROCEDER = 0;//Traccion
int AVANZAR = 0;//Traccion
int PINSERVO = 3;//Salida por el pin 3 Servomotor
int PULSOMIN = 500;//Servomotor
int PULSOMAX = 2500;//Servomotor
int VALORPOT;//Servomotor
int ANGULO;//Servomotor
int POT = 0;//Servomotor


void setup() {

  servo1.attach (PINSERVO, PULSOMIN, PULSOMAX); //Servomotor
  pinMode(enA, OUTPUT);//Traccion
  pinMode(enB, OUTPUT);//Traccion
  
// Valor predeterminado: sin movimiento cuando el joystick permanece en el centro
  x = 510 / 4;//Traccion
  y = 510 / 4;//Traccion
 
  Serial.begin(38400); // Tasa de comunicación MONITOR SERIE
  mySerial.begin(38400);
}

void loop() {
  
  // Leer los datos entrantes del Joystick o del dispositivo Bluetooth maestro
  while (mySerial.available() >= 2) {
    x = mySerial.read();
    delay(10);
    y = mySerial.read();
  }
  delay(10);
  // Convierta de nuevo el rango 0-255 a 0-1023, adecuado para el código de control del motor a continuación
  xAxis = x*4;
  yAxis = y*4;

  // Eje Y utilizado para control hacia adelante y hacia atrás
  if (yAxis < 470) {
    // Pon el motor hacia atrás
    // Convierta las lecturas decrecientes del eje Y para retroceder de 470 a 0 en un valor de 0 a 255 para la señal PWM para aumentar la velocidad del motor
    RETROCEDER = map(yAxis, 470, 0, 0, 255);
    AVANZAR = 0;
  }
  else if (yAxis > 550) {
    // Pon el motor hacia adelante
    // Convierta las lecturas crecientes del eje Y para avanzar de 550 a 1023 en un valor de 0 a 255 para la señal PWM para aumentar la velocidad del motor
    RETROCEDER = 0;
    AVANZAR = map(yAxis, 550, 1023, 0, 255);
  }
  // Si el joystick permanece en el medio, los motores no se mueven
  else {
    RETROCEDER = 0;
    AVANZAR = 0;
  }

  VALORPOT = xAxis;
  ANGULO = map(VALORPOT,0, 1023, 0, 180);
  servo1.write(ANGULO);

  analogWrite(enA, RETROCEDER); // Envia señal PWM en pin 9 para retoceder
  analogWrite(enB, AVANZAR); // Envia señal PWM en pin 10 para avanzar
 Serial.print("X=");
  Serial.print(x);
    Serial.println(" ");
Serial.print("Y=");
  Serial.print(y);
    Serial.println(" ");
Serial.print("RETROCEDER=");
 Serial.print(RETROCEDER);
   Serial.println(" ");
Serial.print("AVANZAR="); 
 Serial.print(AVANZAR);
   Serial.println(" ");
Serial.print("VALORPOT=");
 Serial.print(VALORPOT);
   Serial.println(" ");
Serial.print("ANGULO=");
 Serial.print(ANGULO);
 Serial.println(" ");
 Serial.println(" ");
 delay(500);

Estos son los resultados:

Si muevo el Joystick hacia delante:

Si muevo el Joystick hacia detras:

Van al revés porque tengo el Joystick al revés en el mando ( tendré que modificar el código)
Pero el problema no es ese.
El problema es que solo responde cuando llevo el Joystick hacia delante y en su posición máxima el motor gira al máximo, lo demás nada ( excepto el Servo que si funciona)

Estoy utilizando un puente H en concreto el BTS7960 el cual esta conectado a estos pines del Nano:

9 10 Nano

¿Alguna idea?
Gracias.

En resumen viendo los resultados el problema tiene que estar en esta linea de codigo:

Ya que los valores de las variables: RETROCEDER y AVANZAR no las envia por los pines 9 y 10 del Nano.
¿Veis algún error?
¿Alguna idea de que podría probar?

Estuve haciendo unas pruebas en wokwi y lo que está interfiriendo es la librería Servo.
Luego, mirando la documentación (Servo - Arduino Reference) encuentro:

On boards other than the Mega, use of the library disables (PWM) functionality on pins 9 and 10, whether or not there is a Servo on those pins.

"En placas que no sean Mega, el uso de la biblioteca deshabilita la funcionalidad PWM en los pines 9 y 10, haya o no un servo en esos pines."

Ahí está el problema.

Saludos

Agrego: Podrías usar los pines 5 y 6 (cambiando los pines para SoftwareSerial si es que la sigues usando).

1 Like