Bluetooth+ RX/TX + Arduino Uno

Bonjour tout le monde,

Je suis en train de travailler sur un Projet Arduino actuellement.

J’aimerai faire un truc qui semble assez simple mais sur lequel je suis bloquée depuis peu.
Je dois commander via une liaison Bluetooth un compas digital monté sur le premier Arduino, qui à son tour via une liaison RF commande un servomoteur monté sur le 2ème.

La liaison bluetooth se fait correctement, de l’émetteur au récepteur je pense que ça passe aussi vu que je visualise sur le moniteur série toutes les valeurs prises par le compas… Seulement le Servomoteur ne bouge pas comme je le souhaite, il réagit juste un peu au début puis rien après.

Voici le programme pour l’émetteur:

// Reference the I2C Library
#include <Wire.h>
#include <HMC5883L.h>
#include <VirtualWire.h>

const int led_pin = 13;
const int transmit_pin = 3;
const int receive_pin = 11;
const int transmit_en_pin = 12;
const int servo_pin=8;
// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;
char msg[6];

int x;

// Out setup routine, here we will configure the microcontroller and compass.
void setup()
{
  // Initialize the serial port.
  Serial.begin(9600);
   
  Serial.println("Starting the I2C interface.");
  Wire.begin(); // Start the I2C interface.

  Serial.println("Constructing new HMC5883L");
  compass = HMC5883L(); // Construct a new HMC5883 compass.
    
  Serial.println("Setting scale to +/- 1.3 Ga");
  error = compass.SetScale(1.3); // Set the scale of the compass.
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
  
  Serial.println("Setting measurement mode to continous.");
  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
    
    
    
   vw_setup(2000);
   vw_set_tx_pin(receive_pin);
   vw_set_tx_pin(transmit_pin);
}

// Our main program loop.
void loop()
{
  // Retrive the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();
  
  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);
 
  float declinationAngle = 0.0457;
  heading += declinationAngle;
  
  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;
    
  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;
   
  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 

  // Output the data via the serial port.
  Output(raw, scaled, heading, headingDegrees);

}
// Output the data down the serial port.
void Output(MagnetometerRaw raw, MagnetometerScaled scaled, float heading, float headingDegrees)
{
   
   Serial.print(headingDegrees);
   Serial.println(" Degrees   \t");
   
dtostrf(headingDegrees,6, 2, msg);
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx();
delay(200);
}

***Le programme suivant est celui du receveur:

#include <VirtualWire.h>
#include <ServoTimer2.h>

ServoTimer2 myservo;

void setup()
{
    Serial.begin(9600);	// Debugging only
    myservo.attach(9);
     Serial.println("setup");

    // Initialise the IO and ISR
    vw_set_ptt_inverted(true); // Required for DR3100
    vw_setup(2000);	 // Bits per sec

    vw_rx_start();       // Start the receiver PLL running
}

void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;

    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
	int i;

       
	Serial.print("Got: ");
	
	for (i = 0; i < buflen; i++)
	{
        Serial.print(buf[i]);
        Serial.print(" ");
      
        }
        Serial.println(" ");
        Serial.println(strtod ((char *) buf, NULL));
       
        delay(50);
        myservo.write(strtod ((char *) buf, NULL));
        

 }

}

Aurais-je fais une erreur dans mes codes?

Je dirai pour commencer que strtod ((char *) buf, NULL) ça devrait plutôt être strtod (buf, NULL)

Bonjour B@tto!

Il se trouve qu’auparavant j’avais également écris : strtod(buf,NULL)
Mais cela m’affiche cette erreur: invalid conversion from ‘uint8_t*’ to ‘const char*’

Bin normal : unint8_t == unsigned byte donc un "nombre" et char = un caractère. Donc :

uint8_t buf[VW_MAX_MESSAGE_LEN]; ==> char buf[VW_MAX_MESSAGE_LEN];

J’ai pris en compte votre suggestion, j’ai testé mon programme avec mais j’ai erreur cette fois-ci: invalid conversion from ‘char*’ to ‘uint8_t*’ …

Voici le code:

#include <VirtualWire.h>

const int led_pin = 13;
const int transmit_pin = 3;
const int receive_pin = 11;
const int transmit_en_pin = 12;

void setup()
{
    delay(1000);
    Serial.begin(9600);	// Debugging only
    Serial.println("setup");

    // Initialise the IO and ISR
    vw_set_tx_pin(transmit_pin);
    vw_set_rx_pin(receive_pin);
    vw_set_ptt_pin(transmit_en_pin);
    vw_set_ptt_inverted(true); // Required for DR3100
    vw_setup(2000);	 // Bits per sec

    vw_rx_start();       // Start the receiver PLL running

    pinMode(led_pin, OUTPUT);
}

void loop()
{
    char buf[VW_MAX_MESSAGE_LEN];
    char buflen = VW_MAX_MESSAGE_LEN;

    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
	int i;

        digitalWrite(led_pin, HIGH); // Flash a light to show received good message
	// Message with a good checksum received, dump it.
	Serial.print("Got: ");
	
	for (i = 0; i < buflen; i++)
	{
	    Serial.print(buf[i], HEX);
	    Serial.print(' ');
	}
	Serial.println(strtod(buf,NULL));
        digitalWrite(led_pin, LOW);
    }
}

Alors qu’avec mon ancienne structure strtod ((char *) buf, NULL), je parvenais quand même à visualiser toutes les valeurs que prennent le compas : de 0° à 360°.

Normal : char buflen = VW_MAX_MESSAGE_LEN; La c'est un nombre qu'il faut ....

Et je peux donc remplacer cette ligne par :uint8_t buflen = VW_MAX_MESSAGE_LEN ? p

Et oui, sinon tu utilise un char comme index de ton tableau

Merci B@tto pour ton aide,

Mais il n'y a toujours pas de changement par rapport au servomoteur, il bouge pas vraiment.

Ok bon je vois plein de choses, j’ai l’impression que t’as utilisé un char (pas un caractère hein, le truc avec un canon et des chenilles) pour tuer une mouche.

Déjà je vois pas bien l’intérêt de convertir un float en string pour à la réception faire un string to double … Mais bon !

Je te propose :

#include <VirtualWire.h>
#include <ServoTimer2.h>

ServoTimer2 myservo;

void setup()
{
    Serial.begin(9600);	// Debugging only
    myservo.attach(9);
     Serial.println("setup");

    // Initialise the IO and ISR
    vw_set_ptt_inverted(true); // Required for DR3100
    vw_setup(2000);	 // Bits per sec

    vw_rx_start();       // Start the receiver PLL running
}

void loop()
{
    char buf[VW_MAX_MESSAGE_LEN];
    byte buflen = VW_MAX_MESSAGE_LEN;

    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
	
        Serial.print("Got: ");
	
	for (int i = 0; i < buflen; i++)
	{
	    Serial.print(buf[i]);
	    Serial.print(' ');
	}

	Serial.println(atoi(buf));
        delay(50);
        myservo.write(atoi(buf));
       
    }
}
/ Reference the I2C Library
#include <Wire.h>
#include <HMC5883L.h>
#include <VirtualWire.h>

const int led_pin = 13;
const int transmit_pin = 3;
const int receive_pin = 11;
const int transmit_en_pin = 12;
const int servo_pin=8;

// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;
char msg[6];

int x;

// Out setup routine, here we will configure the microcontroller and compass.
void setup()
{
  // Initialize the serial port.
  Serial.begin(9600);
   
  Serial.println("Starting the I2C interface.");
  Wire.begin(); // Start the I2C interface.

  Serial.println("Constructing new HMC5883L");
  compass = HMC5883L(); // Construct a new HMC5883 compass.
    
  Serial.println("Setting scale to +/- 1.3 Ga");
  error = compass.SetScale(1.3); // Set the scale of the compass.
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
  
  Serial.println("Setting measurement mode to continous.");
  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
        
   vw_setup(2000);
   vw_set_tx_pin(receive_pin);
   vw_set_tx_pin(transmit_pin);
}

// Our main program loop.
void loop()
{
  // Retrive the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();
  
  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);
 
  float declinationAngle = 0.0457;
  heading += declinationAngle;
  
  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;
    
  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;
   
  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 

  // Output the data via the serial port.
  Output(raw, scaled, heading, headingDegrees);

}
// Output the data down the serial port.
void Output(MagnetometerRaw raw, MagnetometerScaled scaled, float heading, float headingDegrees)
{
     
msg=itoa(int(headingDegrees),10);
vw_send(msg, strlen(msg));
vw_wait_tx();
delay(200);
}

Je vous remercie vraiment de vous être penché sur mes programmes depuis le début :blush: Pour tout vous dire, les deux programmes initiaux m'ont été donné par mon professeur... Je suis juste chargée d'établir la liaison bluetooth et de rajouter un servomoteur au second Arduino (le faire tourner en fonction des valeurs prises par le compas se situant sur le 1er Arduino). En bonne paresseuse, je ne m'étais pas beaucoup posée de questions sur toutes ces variables du moment où mon prof l'avait fait et que la transmission et la réception étaient censées se faire "normalement". J'étais d'abord confrontée à une incompatibilité entre les librairies VIRTUALWIRE et SERVO, c'est la raison pour laquelle je l'ai remplacé par SERVOTIMER2. Mais j'ai l'impression que celle-là ne marche pas comme la précédente qui avec un simple programme me faisait des 1/2 tour de 180° facilement.

Ah bin tu as surement la source de ton problème. Je pensais que ServoTimer2 était juste une "copie" de servo.h sur le timer 2 mais il n'en est rien. Servo.write() ne demande pas l'angle en argument mais la largeur de l'impulsion à envoyer en microseconde. Regarde cette exemple : http://www.makehackvoid.com/pipermail/makers/2010-August/000115.html

En reprenant cette exemple il te suffira normalement de faire

myservo.write(map(atoi(buf), 0, 360, 750, 2250 ));

Thank you B@tto!

The servo is moving as I want it!

You save my life :)

You're welcome ;)