Commande de servos comme moteurs d'aiguillage

Bonjour,
Mon projet global consiste à commander des moteurs d'aiguillages d'un réseau de train miniature depuis une appli Android sur mon smartphone. Les commandes sont émises en bluetotooth sur un module HC06 à un Arduino Uno. Celui-ci communique avec deux Arduino Mega via i2c. Pour tout cela, tout est OK, cela fonctionne comme je veux.
Sur chacun de mes Mega, je reçois les ordres de façon numérique : le(s) chiffres des dizaines correspondent un numéro du servo, les unités à la position (0 pour gauche, 5 pour droite, 9 = pas de mouvement, juste retour sur la position actuelle).
Pour chaque moteur, j'ai une position gauche et une position droite définie par l'angle, dans des tableaux.
Au démarrage du sketch, je mets mes servos dans une position initiale. Cela fonctionne, les servos fonctionnent pour basculer dans la position initiale voulue.
En revanche, je reçois bien les commandes, mais il n'y a pas de mouvement ! C'est sûrement une petite erreur... Mais je ne la vois pas ! Auriez-vous une idée ?

[code]
/*
  Pour un Arduino Mega
*/

#include <Wire.h>                                                               // On ajoute la bibliothèque Wire.h qui permet la communication i2c
#include <Servo.h>                                                              // On ajoute la bibliothèque Servo.h qui permet la commande des servos

#define I2C_SLAVE_ADDRESS_MODULE_A_11 11                                        // On définit sous le nom "I2C_SLAVE_ADDRESS_MODULE_A_11" et la valeur 11 l'adresse de l'Arduino esclave du module A

const byte PIN_MOTEUR[16] = {0, 2, 0, 3, 0, 5, 0, 7, 0, 9, 0, 0, 0, 0, 10, 12}; // On définit une liste qui constient les numéros des pins des commandes des (servo)moteurs du module A
Servo servo_moteur[16];                                                         // On définit une liste d'objets (servo)moteurs

// Pour les moteurs  :           1         3         5        7*          9                        14    15
word gauche_moteur[16] = { 0 ,  60 , 2 ,  60 , 4 ,  60 , 6 ,  30 ,  8 , 150 , 10 , 11 , 12 , 13 , 140 , 120 };     // Définit un tableau de 16 valeurs de positions "gauche_moteur" pour les servos (le paramétrage correspond à la réalité des moteurs DLY2 du réseau)
word droite_moteur[16] = { 0 , 140 , 2 , 140 , 4 , 140 , 6 , 160 ,  8 ,  70 , 10 , 11 , 12 , 13 ,  50 ,  40 };     // Définit un tableau de 16 valeurs de positions "droite_moteur" pour les servos (le paramétrage correspond à la réalité des moteurs DLY2 du réseau)

int angle_avant, angle_commande, angle_final;                                   // On définit les variables dans lesquelles on va stocker l'angle des servo(moteurs) avant, après mouvement, et l'angle de commande
int gauche_droite_info_moteur, num_moteur;                                      // On définit les variables dans lesquelles on va stocker la commande (0 pour gauche, 5 pour droite, 9 pour demande position) et le numéro de moteur
int valeur_recue, valeur_a_transmettre;                                         // On définit les variables dans lesquelles on va stocker la commande recue et la réponse à transmettre



void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS_MODULE_A_11);                                    // On démarre la communication i2c en tant qu'esclave sous l'adresse "I2C_SLAVE_ADDRESS_MODULE_A_11"
  Serial.begin(9600);                                                           // On démarre la liaison série à 9600 baud
  Serial.println("-------------------------------------");
  Serial.println("     Je suis l'Ardunion esclave 1");                          // On écrit "Je suis l'Arduino esclave 1" sur le moniteur série
  Serial.println("-------------------------------------");

  delay(100);                                                                   // On attend 100 ms
  Wire.onRequest(requestEvents);                                                // On indique que c'est "requestEvents" qui est exécutée en cas de demande de l'Arduino maître
  Wire.onReceive(receiveEvents);                                                // On indique que c'est "receiveEvents" qui est exécutée en cas de réception de données de l'Arduino maître

  initialisation_moteurs();                                                     // On bascule les moteurs dans la position initiale
}



void loop()
{

}                                                                               // Boucle loop vide


void requestEvents()                                                            // Fonction "requestEvents" qui est exécutée en cas de demande de l'Arduino maître
{
  Serial.println(F("(Requête reçue)"));                                         // On écrit "---> requête reçue" sur le moniteur série
  Serial.print(F(">> Envoi de la valeur : "));                                  // On écrit "Envoi de la valeur : " sur le moniteur série
  Serial.println(valeur_a_transmettre);                                         // On écrit valeur_a_transmettre sur le moniteur série
  Serial.println("-------------------------------------");

  Wire.write(valeur_a_transmettre);                                             // On envoie valeur_a_transmettre sur la liaison i2c
}



void receiveEvents(int numBytes)                                                // Fonction "receiveEvents" qui est exécutée en cas de réception de données de l'Arduino maître et les stocke dans la variable numBytes
{
  Serial.println(F("(Réception de données)"));                                  // On écrit "---> réception de données" sur le moniteur série
  Serial.print(F(">> "));
  valeur_recue = Wire.read();                                                   // On met la valeur reçue de la liaison i2c dans valeur_recue
  Serial.print(numBytes);                                                       // On écrit numBytes sur le moniteur série
  Serial.println(F(" octets reçus"));                                           // On écrit " octets reçus" sur le moniteur série
  Serial.print(F(">> Valeur reçue : "));                                        // On écrit "valeur reçue : " sur le moniteur série
  Serial.println(valeur_recue);                                                 // On écrit valeur_recue sur le moniteur série
  Serial.println("- - - - - - - - - - - - - - - - - - -");

  num_moteur = valeur_recue / 10;                                               // On met dans "num_moteur" le chiffre des dizaines de "valeur_recue"
  gauche_droite_info_moteur = valeur_recue % 10;                                // On met dans "gauche_droite_info_moteur" le chiffre de commande (0,5 ou 9)

  if (gauche_droite_info_moteur == 0)                                           // Si "gauche_droite_info_moteur" = 0
  {
    attach_servos();                                                            // On attache les (servo)moteurs
    mouvement_servo(num_moteur, gauche_moteur[num_moteur]);                     // On bascule le moteur numéro "num_moteur" dans la position d'angle "gauche_moteur[num_moteur]"
    detach_servos();                                                            // On détache les (servo)moteurs
  }
  else if (gauche_droite_info_moteur == 5)                                      // Sinon si "gauche_droite_info_moteur" = 5
  {
    attach_servos();                                                            // On attache les (servo)moteurs
    mouvement_servo(num_moteur, droite_moteur[num_moteur]);                     // On bascule le moteur numéro "num_moteur" dans la position d'angle "droite_moteur[num_moteur]"
    detach_servos();                                                            // On détache les (servo)moteurs
  }
  Serial.print(F(">> Angle du moteur "));                                       // On écrit ">> Angle du moteur " sur le moniteur série
  Serial.print(num_moteur);                                                     // On écrit le numéro de moteur sur le moniteur série
  Serial.print(F(" : "));                                                       // On écrit ">> : " sur le moniteur série
  Serial.println(angle_final);                                                  // On écrit la valeur de l'angle de commande demandé
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  delay(1000);                                                                  // On attend 1 seconde

  // Puis on construit la valeur à renvoyer vers le Master et le téléphione, on la mettra dans valeur_a_transmettre
  valeur_a_transmettre = valeur_recue + 100;                                    // ----------> SERA A ENLEVER          On fixe à valeur_recue + 100 la valeur à transmettre
}


void mouvement_servo(int num_moteur, int angle_commande)                        // ----------> A COMPLETER          Fonction mouvement_servo, prend pour arguments le numéro de moteur et l'angle de commande
{
  Serial.print(F(">> Mouvement fictif du moteur "));                            // On écrit ">> Mouvement fictif du moteur " sur le moniteur série
  Serial.print(num_moteur);                                                     // On écrit le numéro de moteur sur le moniteur série
  Serial.print(F(" vers l'angle "));                                            // On écrit ">> vers l'angle " sur le moniteur série
  Serial.println(angle_commande);                                               // On écrit l'angle de commande demandé
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  servo_moteur[num_moteur].write(angle_commande);                               // On bascule le (servo)moteur 15 dans la position angle_commande
}



void prepare_reponse_au_Master(int num_moteur, int angle_commande)              // ----------> VERIFIER LES ARGUMENTS ET ECRIRE
{

}



int mesure_angle_servo(int num_moteur)                                          // ----------> A MODIFIER POUR SEPARER "mesure_angle_servo" ET "prepare_reponse_au_Master" ET AJOUTER LES COMMENTAIRES         La fonction prend pour argument le numéro de moteur et donne sa position en angle
{
  int valeur_a_retourner, position_moteur;                                      // On crée une variable locale "position_moteur"
  servo_moteur[num_moteur].attach(PIN_MOTEUR[num_moteur]);                      // On attache le (servo)moteur pour le numéro de moteur demandé
  position_moteur = servo_moteur[num_moteur].read();                            // On lit la position du (servo)moteur demandé et on l'écrit dans "position_moteur"
  servo_moteur[num_moteur].detach();                                            // On détache le (servo)moteur
  return position_moteur;                                                       // On demande à la fonction de retourner la position du moteur


  if (position_moteur == gauche_moteur[num_moteur])
  {
    valeur_a_retourner = 100 + 10 * num_moteur + 0;
  }
  else if (position_moteur == droite_moteur[num_moteur])
  {
    valeur_a_retourner = 100 + 10 * num_moteur + 5;
  }
  else valeur_a_retourner = 100 + 10 * num_moteur + 9;
  return valeur_a_retourner;
}


void initialisation_moteurs()                                                   // Fonction qui initialise les moteurs dans la position de départ
{
  attach_servos();                                                              // On attache les (servo)moteurs
  mouvement_servo(1, droite_moteur[1]);                                         // On bascule le (servo)moteur 1 dans la position droite_moteur[1]
  Serial.println(">> Moteur 1 initialisé à droite");                            // On écrit ">> Moteur 1 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(3, droite_moteur[3]);                                         // On bascule le (servo)moteur 3 dans la position droite_moteur[3]
  Serial.println(">> Moteur 3 initialisé à droite");                            // On écrit ">> Moteur 3 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(5, droite_moteur[5]);                                         // On bascule le (servo)moteur 5 dans la position droite_moteur[5]
  Serial.println(">> Moteur 5 initialisé à droite");                            // On écrit ">> Moteur 5 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(7, droite_moteur[7]);                                         // On bascule le (servo)moteur 7 dans la position droite_moteur[7]
  Serial.println(">> Moteur 7 initialisé à gauche");                            // On écrit ">> Moteur 7 initialisé à gauche" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(9, gauche_moteur[9]);                                         // On bascule le (servo)moteur 9 dans la position gauche_moteur[9]
  Serial.println(">> Moteur 9 initialisé à gauche");                            // On écrit ">> Moteur 9 initialisé à gauche" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(14, droite_moteur[14]);                                       // On bascule le (servo)moteur 14 dans la position droite_moteur[14]
  Serial.println(">> Moteur 14 initialisé à droite");                           // On écrit ">> Moteur 14 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(15, droite_moteur[15]);                                       // On bascule le (servo)moteur 15 dans la position droite_moteur[15]
  Serial.println(">> Moteur 15 initialisé à droite");                           // On écrit ">> Moteur 15 initialisé à droite" sur le moniteur série
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  delay(100);                                                                   // On attend 100 ms
  detach_servos();                                                              // On détache les (servo)moteurs
  Serial.println("-------------------------------------");
}

void attach_servos()                                                            // Fonction qui attache les (servo)moteurs
{
  servo_moteur[1].attach(PIN_MOTEUR[1]);                                        // On attache le (servo)moteur 1
  servo_moteur[3].attach(PIN_MOTEUR[3]);                                        // On attache le (servo)moteur 3
  servo_moteur[5].attach(PIN_MOTEUR[5]);                                        // On attache le (servo)moteur 5
  servo_moteur[7].attach(PIN_MOTEUR[7]);                                        // On attache le (servo)moteur 7
  servo_moteur[9].attach(PIN_MOTEUR[9]);                                        // On attache le (servo)moteur 9
  servo_moteur[14].attach(PIN_MOTEUR[14]);                                      // On attache le (servo)moteur 14
  servo_moteur[15].attach(PIN_MOTEUR[15]);                                      // On attache le (servo)moteur 15
}

void detach_servos()                                                            // Fonction qui détache les (servo)moteurs
{
  servo_moteur[1].detach();                                                     // On détache le (servo)moteur 1
  servo_moteur[3].detach();                                                     // On détache le (servo)moteur 3
  servo_moteur[5].detach();                                                     // On détache le (servo)moteur 5
  servo_moteur[7].detach();                                                     // On détache le (servo)moteur 7
  servo_moteur[9].detach();                                                     // On détache le (servo)moteur 9
  servo_moteur[14].detach();                                                    // On détache le (servo)moteur 14
  servo_moteur[15].detach();                                                    // On détache le (servo)moteur 15
}
[/code]

Bonjour babskwal

Joli projet :wink:

Est ce que cette séquence affiche les bonnes valeurs?

  Serial.println(F(" octets reçus"));                                           // On écrit " octets reçus" sur le moniteur série
  Serial.print(F(">> Valeur reçue : "));                                        // On écrit "valeur reçue : " sur le moniteur série
  Serial.println(valeur_recue);                                                 // On écrit valeur_recue sur le moniteur série

A+
Cordialement
jpbbricole

Bonjour jpbbricole,

Joli projet :wink:

Merci !!!

Et oui, la séquence donne les bonnes valeurs.

Ce qui me surprend, c'est que les servos bougent à l'initialisation, mais pas lors de commandes, pourtant bien reçues, via i2c. Je pense que c'est un sujet attacher / bouger / détacher ; je n'ai pas précisé, mais je préfère détacher mes servos après chaque mouvement pour leur éviter de faire du bruit.

Concernant ton problème, On attache les servos une fois dans le setup() et on ne les détache pas.
Si tu fais :

    attach_servos();                                                            // On attache les (servo)moteurs
    mouvement_servo(num_moteur, gauche_moteur[num_moteur]);                     // On bascule le moteur numéro "num_moteur" dans la position d'angle "gauche_moteur[num_moteur]"
    detach_servos();                                                            // On détache les (servo)moteurs

Tu détaches le servo avant qu'il ne soit arrivé à la position demandée.


Si tu n'envoies pas les servos dans leurs butées ils ne devraient pas faire du bruit. Le même problème peut survenir si le servo ne peut pas atteindre sa position. Ce qui se produit par exemple si on a une liaison rigide avec l'organe commandé et que celui-ci est lui-même en buté.
D'ailleurs pour éviter ce genre de problème il est préférable de les piloter en envoyant une durée d'impulsion plutôt qu'un angle ce qui permet un positionnement plus précis.


Il faudrait passer à un débit un peu plus élevé.
Parce que les infos arrive sur le bus I2C à 100kHz ce qui peut faire au maximum 1 octet toutes les 100μs et derrière, tu fais des Serial.print() assez nombreux à 9600bauds ce qui fait un caractère toutes les 1ms, ce qui te donne l'occasion de perdre des infos au passage si plusieurs commandes sont envoyées à la suite.
Quelques bonnes habitudes à prendre:

  • Serial.begin(115200); pour soritr les caractères plus rapidement et éviter le risque de bloquer le programme si tu satures le buffer de transmission.
  • pour le debug, des messages courts. Par exemple, receiveEvents() ne traite que la lecture d'une donnée donc il est inutile de dire combien de données ont été reçues puisque tu vas n'en traiter qu'une. Donc tu peux te contenter de mettre "R-" suivi de l'octet reçu.

Autre chose, dans ta messagerie tu encodes les informations en base 10 et tu extrais en utilisant les opérateurs division et modulo. Ce qui est assez lent Il serait plus simple et plus rapide de modifier légèrement l'encodage pour faire des opérations logiques sur les octets reçus.
Un octet c'est 8 bits, tu peux par exemple dire que tu utilises 5 bits pour encoder le numéro de l'élément et 3 bits pour le mouvement (ce qui permettrait de gérer autre chose que des aiguillages).
L'encodage se ferait ainsi

uint8_t data = (numElem << 3) | mouvement & 0x07;

Pour décoder

numElem = (data & 0xf8) >> 3;
mouvement = data & 0x07

Plein d'infos, merci beaucoup !
Je vais essayer d'attacher "une fois pour toutes", et voir ce qui peut causer du bruit... et travailler le pilotage en durée d'impulsion.
Pour les infos sur le moniteur série, c'est que du débug, tous les infos réellement utiles transitent via i2c avec l'Arduino maître. Je vais tenir compte de tes remarques, ne serait-ce que pour progresser !
Et de même pour les commandes en octets au lieu de la base 10. Mais pour ça, il va falloir que je modifie non seulement entre le maître et l'esclave, mais aussi entre l'appli Android et le maître :wink:

Oui mais le problème c'est que si le buffer d'émission de la liaison série est saturé le programme se bloque jusqu'à ce que le buffer dispose de place pour accueillir de nouveaux caractères. La transmission série fonctionnant sous interruption si le programme se bloque en attendant de la place dans le buffer les interruptions sont masquées et l'I2C n'est plus géré non plus.
Donc dans ce cas tes informations de debug bloquent l'application que tu veux mettre au point.

Bonjour babskwal

Tu pourrais trèe bien avoir un timer qui est "rechargé" à chaque réception. S'il n'y a pas de réception pendant 5 secondes, par exemple, tu fais le detach_servos() de tout les servo.
Ca se fait avec millis().
Si tu veux un exemple ...

A+
jpbbricole

Il n'y a aucune raison de faire ce genre de truc alambiqué.
Un servo fait du bruit si:

  • sa commande change en permanence ou si elle change plus vite qu'il ne se déplace
  • si le servo ne peut pas atteindre sa position, on rencontre ce cas si on essaie d'aller au-delà de la butée du servo ou au-delà de la butée de l'organe commandé
  • si le servo ne peut pas garder sa position, on rencontre ce cas si le servo est soumis à un couple antagoniste.

Edit: et j'avais oublié, il faut prévoir une alimentation stable capable de fournir le courant nécessaire.

Vous essayez de faire bouger le servo dans le callback I2C receiveEvents()
Cette fonction est appelée dans le contexte de l'interruption I2C et donc les interruptions sont désactivées. Vous appelez mouvement_servo() qui fait le write() mais comme les interruptions sont désactivées, ça doit bloquer et ensuite vous détachez le servo donc ça arrête le mouvement qui aurait pu se produire.

Vous voyez les print car la bibliothèque pour Serial sait fonctionner même si les interruptions sont désactivées (et il y a un buffer, donc ça continuerait quand vous sortez du callback)

il faudrait noter dans le callback() qu'il faut bouger et traiter cela dans la loop().

@ fdufnews je suis en train de régler les positions extrêmes de mes moteurs pour éviter le bruit (c'est-à-dire les valeurs de mes tableaux droite_moteur[] et gauche_moteur[]), il y a du mieux. J'ai effectivement une alimentation des servos stable, pas fournie par l'Arduino.

@ J-M-L Je vais regarder cela, cela doit effectivement être un pb, que je décide de maintenir les detach ou que je les enlève.

si vous les enlevez partout (mettez juste le attach() dans le setup) ça devrait bouger car le write se mettra en route une fois sorti du callback

Bonsoir babskwal

"Pour le sport", j'ai ajouté une temporisation de 5 secondes:
const unsigned long servoDetachTempo = 5000; // Temps d'inaction des servo pour les détacher
à ton programme, sans réception sur le bus i2C, il est fait un detach_servos()
Je te laisse regarder:

/*
  Pour un Arduino Mega
*/

#include <Wire.h>                                                               // On ajoute la bibliothèque Wire.h qui permet la communication i2c
#include <Servo.h>                                                              // On ajoute la bibliothèque Servo.h qui permet la commande des servos

#define I2C_SLAVE_ADDRESS_MODULE_A_11 11                                        // On définit sous le nom "I2C_SLAVE_ADDRESS_MODULE_A_11" et la valeur 11 l'adresse de l'Arduino esclave du module A

const byte PIN_MOTEUR[16] = {0, 2, 0, 3, 0, 5, 0, 7, 0, 9, 0, 0, 0, 0, 10, 12}; // On définit une liste qui constient les numéros des pins des commandes des (servo)moteurs du module A
Servo servo_moteur[16];                                                         // On définit une liste d'objets (servo)moteurs

// Pour les moteurs  :           1         3         5        7*          9                        14    15
word gauche_moteur[16] = { 0 ,  60 , 2 ,  60 , 4 ,  60 , 6 ,  30 ,  8 , 150 , 10 , 11 , 12 , 13 , 140 , 120 };     // Définit un tableau de 16 valeurs de positions "gauche_moteur" pour les servos (le paramétrage correspond à la réalité des moteurs DLY2 du réseau)
word droite_moteur[16] = { 0 , 140 , 2 , 140 , 4 , 140 , 6 , 160 ,  8 ,  70 , 10 , 11 , 12 , 13 ,  50 ,  40 };     // Définit un tableau de 16 valeurs de positions "droite_moteur" pour les servos (le paramétrage correspond à la réalité des moteurs DLY2 du réseau)

int angle_avant, angle_commande, angle_final;                                   // On définit les variables dans lesquelles on va stocker l'angle des servo(moteurs) avant, après mouvement, et l'angle de commande
int gauche_droite_info_moteur, num_moteur;                                      // On définit les variables dans lesquelles on va stocker la commande (0 pour gauche, 5 pour droite, 9 pour demande position) et le numéro de moteur
int valeur_recue, valeur_a_transmettre;                                         // On définit les variables dans lesquelles on va stocker la commande recue et la réponse à transmettre

const unsigned long servoDetachTempo = 5000; // Temps d'inaction des servo pour les détacher
unsigned long servoDetachMillis = 0; // Temps d'inaction des servo pour les détacher, chrono

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS_MODULE_A_11);                                    // On démarre la communication i2c en tant qu'esclave sous l'adresse "I2C_SLAVE_ADDRESS_MODULE_A_11"
  Serial.begin(9600);                                                           // On démarre la liaison série à 9600 baud
  Serial.println("-------------------------------------");
  Serial.println("     Je suis l'Ardunion esclave 1");                          // On écrit "Je suis l'Arduino esclave 1" sur le moniteur série
  Serial.println("-------------------------------------");

  delay(100);                                                                   // On attend 100 ms
  Wire.onRequest(requestEvents);                                                // On indique que c'est "requestEvents" qui est exécutée en cas de demande de l'Arduino maître
  Wire.onReceive(receiveEvents);                                                // On indique que c'est "receiveEvents" qui est exécutée en cas de réception de données de l'Arduino maître

  initialisation_moteurs();                                                     // On bascule les moteurs dans la position initiale
}



void loop()
{
	if (servoDetachMillis > 0 && (millis() - servoDetachMillis >= servoDetachTempo)) // Si plus d'activité
	{
		detach_servos();
		servoDetachMillis = 0; // Arrêt du chrono
		Serial.println("DETACH");
	}
}                                                                               // Boucle loop vide


void requestEvents()                                                            // Fonction "requestEvents" qui est exécutée en cas de demande de l'Arduino maître
{
  Serial.println(F("(Requête reçue)"));                                         // On écrit "---> requête reçue" sur le moniteur série
  Serial.print(F(">> Envoi de la valeur : "));                                  // On écrit "Envoi de la valeur : " sur le moniteur série
  Serial.println(valeur_a_transmettre);                                         // On écrit valeur_a_transmettre sur le moniteur série
  Serial.println("-------------------------------------");

  Wire.write(valeur_a_transmettre);                                             // On envoie valeur_a_transmettre sur la liaison i2c
}



void receiveEvents(int numBytes)                                                // Fonction "receiveEvents" qui est exécutée en cas de réception de données de l'Arduino maître et les stocke dans la variable numBytes
{
  Serial.println(F("(Réception de données)"));                                  // On écrit "---> réception de données" sur le moniteur série
  Serial.print(F(">> "));
  valeur_recue = Wire.read();                                                   // On met la valeur reçue de la liaison i2c dans valeur_recue
  Serial.print(numBytes);                                                       // On écrit numBytes sur le moniteur série
  Serial.println(F(" octets reçus"));                                           // On écrit " octets reçus" sur le moniteur série
  Serial.print(F(">> Valeur reçue : "));                                        // On écrit "valeur reçue : " sur le moniteur série
  Serial.println(valeur_recue);                                                 // On écrit valeur_recue sur le moniteur série
  Serial.println("- - - - - - - - - - - - - - - - - - -");

  num_moteur = valeur_recue / 10;                                               // On met dans "num_moteur" le chiffre des dizaines de "valeur_recue"
  gauche_droite_info_moteur = valeur_recue % 10;                                // On met dans "gauche_droite_info_moteur" le chiffre de commande (0,5 ou 9)

  servoDetachMillis = millis(); // On démarre le chrono                                                           // On attache les (servo)moteurs

  if (gauche_droite_info_moteur == 0)                                           // Si "gauche_droite_info_moteur" = 0
  {
    attach_servos();                                                            // On attache les (servo)moteurs
    mouvement_servo(num_moteur, gauche_moteur[num_moteur]);                     // On bascule le moteur numéro "num_moteur" dans la position d'angle "gauche_moteur[num_moteur]"
    detach_servos();                                                            // On détache les (servo)moteurs
  }
  else if (gauche_droite_info_moteur == 5)                                      // Sinon si "gauche_droite_info_moteur" = 5
  {
    attach_servos();                                                            // On attache les (servo)moteurs
    mouvement_servo(num_moteur, droite_moteur[num_moteur]);                     // On bascule le moteur numéro "num_moteur" dans la position d'angle "droite_moteur[num_moteur]"
    //detach_servos();                                                            // On détache les (servo)moteurs
  }
  Serial.print(F(">> Angle du moteur "));                                       // On écrit ">> Angle du moteur " sur le moniteur série
  Serial.print(num_moteur);                                                     // On écrit le numéro de moteur sur le moniteur série
  Serial.print(F(" : "));                                                       // On écrit ">> : " sur le moniteur série
  Serial.println(angle_final);                                                  // On écrit la valeur de l'angle de commande demandé
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  delay(1000);                                                                  // On attend 1 seconde

  // Puis on construit la valeur à renvoyer vers le Master et le téléphione, on la mettra dans valeur_a_transmettre
  valeur_a_transmettre = valeur_recue + 100;                                    // ----------> SERA A ENLEVER          On fixe à valeur_recue + 100 la valeur à transmettre
}


void mouvement_servo(int num_moteur, int angle_commande)                        // ----------> A COMPLETER          Fonction mouvement_servo, prend pour arguments le numéro de moteur et l'angle de commande
{
  Serial.print(F(">> Mouvement fictif du moteur "));                            // On écrit ">> Mouvement fictif du moteur " sur le moniteur série
  Serial.print(num_moteur);                                                     // On écrit le numéro de moteur sur le moniteur série
  Serial.print(F(" vers l'angle "));                                            // On écrit ">> vers l'angle " sur le moniteur série
  Serial.println(angle_commande);                                               // On écrit l'angle de commande demandé
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  servo_moteur[num_moteur].write(angle_commande);                               // On bascule le (servo)moteur 15 dans la position angle_commande
}



void prepare_reponse_au_Master(int num_moteur, int angle_commande)              // ----------> VERIFIER LES ARGUMENTS ET ECRIRE
{

}



int mesure_angle_servo(int num_moteur)                                          // ----------> A MODIFIER POUR SEPARER "mesure_angle_servo" ET "prepare_reponse_au_Master" ET AJOUTER LES COMMENTAIRES         La fonction prend pour argument le numéro de moteur et donne sa position en angle
{
  int valeur_a_retourner, position_moteur;                                      // On crée une variable locale "position_moteur"
  servo_moteur[num_moteur].attach(PIN_MOTEUR[num_moteur]);                      // On attache le (servo)moteur pour le numéro de moteur demandé
  position_moteur = servo_moteur[num_moteur].read();                            // On lit la position du (servo)moteur demandé et on l'écrit dans "position_moteur"
  servo_moteur[num_moteur].detach();                                            // On détache le (servo)moteur
  return position_moteur;                                                       // On demande à la fonction de retourner la position du moteur


  if (position_moteur == gauche_moteur[num_moteur])
  {
    valeur_a_retourner = 100 + 10 * num_moteur + 0;
  }
  else if (position_moteur == droite_moteur[num_moteur])
  {
    valeur_a_retourner = 100 + 10 * num_moteur + 5;
  }
  else valeur_a_retourner = 100 + 10 * num_moteur + 9;
  return valeur_a_retourner;
}


void initialisation_moteurs()                                                   // Fonction qui initialise les moteurs dans la position de départ
{
  attach_servos();                                                              // On attache les (servo)moteurs
  mouvement_servo(1, droite_moteur[1]);                                         // On bascule le (servo)moteur 1 dans la position droite_moteur[1]
  Serial.println(">> Moteur 1 initialisé à droite");                            // On écrit ">> Moteur 1 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(3, droite_moteur[3]);                                         // On bascule le (servo)moteur 3 dans la position droite_moteur[3]
  Serial.println(">> Moteur 3 initialisé à droite");                            // On écrit ">> Moteur 3 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(5, droite_moteur[5]);                                         // On bascule le (servo)moteur 5 dans la position droite_moteur[5]
  Serial.println(">> Moteur 5 initialisé à droite");                            // On écrit ">> Moteur 5 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(7, droite_moteur[7]);                                         // On bascule le (servo)moteur 7 dans la position droite_moteur[7]
  Serial.println(">> Moteur 7 initialisé à gauche");                            // On écrit ">> Moteur 7 initialisé à gauche" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(9, gauche_moteur[9]);                                         // On bascule le (servo)moteur 9 dans la position gauche_moteur[9]
  Serial.println(">> Moteur 9 initialisé à gauche");                            // On écrit ">> Moteur 9 initialisé à gauche" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(14, droite_moteur[14]);                                       // On bascule le (servo)moteur 14 dans la position droite_moteur[14]
  Serial.println(">> Moteur 14 initialisé à droite");                           // On écrit ">> Moteur 14 initialisé à droite" sur le moniteur série
  delay(100);                                                                   // On attend 100 ms
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  mouvement_servo(15, droite_moteur[15]);                                       // On bascule le (servo)moteur 15 dans la position droite_moteur[15]
  Serial.println(">> Moteur 15 initialisé à droite");                           // On écrit ">> Moteur 15 initialisé à droite" sur le moniteur série
  Serial.println("- - - - - - - - - - - - - - - - - - -");
  delay(100);                                                                   // On attend 100 ms
  detach_servos();                                                              // On détache les (servo)moteurs
  Serial.println("-------------------------------------");
}

void attach_servos()                                                            // Fonction qui attache les (servo)moteurs
{
  servo_moteur[1].attach(PIN_MOTEUR[1]);                                        // On attache le (servo)moteur 1
  servo_moteur[3].attach(PIN_MOTEUR[3]);                                        // On attache le (servo)moteur 3
  servo_moteur[5].attach(PIN_MOTEUR[5]);                                        // On attache le (servo)moteur 5
  servo_moteur[7].attach(PIN_MOTEUR[7]);                                        // On attache le (servo)moteur 7
  servo_moteur[9].attach(PIN_MOTEUR[9]);                                        // On attache le (servo)moteur 9
  servo_moteur[14].attach(PIN_MOTEUR[14]);                                      // On attache le (servo)moteur 14
  servo_moteur[15].attach(PIN_MOTEUR[15]);                                      // On attache le (servo)moteur 15
}

void detach_servos()                                                            // Fonction qui détache les (servo)moteurs
{
  servo_moteur[1].detach();                                                     // On détache le (servo)moteur 1
  servo_moteur[3].detach();                                                     // On détache le (servo)moteur 3
  servo_moteur[5].detach();                                                     // On détache le (servo)moteur 5
  servo_moteur[7].detach();                                                     // On détache le (servo)moteur 7
  servo_moteur[9].detach();                                                     // On détache le (servo)moteur 9
  servo_moteur[14].detach();                                                    // On détache le (servo)moteur 14
  servo_moteur[15].detach();                                                    // On détache le (servo)moteur 15
}

Bonne soirée
jpbbricole

Bonsoir,

J'ai bien avancé, cela fonctionne correctement, les moteurs basculent quand il faut, merci beaucoup pour votre aide. Il restera à passer les commande sous forme d'octets au lieu de la base 10...
Question complémentaire : je veux faire un mouvement lent, progressif. Et mon code ne fonctionne pas comme ça, ça reste un basculement "d'un coup". Avez-vous l'explication ? Mon code :

/*
  Pour un Arduino Mega

  Reste à faire :
  - les retours de positions d'aiguille, y compris lors de l'inialisation
  - les mouvements lents
  - les ajustements de positions gauches et droites
*/

#include <Wire.h>                                                               // On ajoute la bibliothèque Wire.h qui permet la communication i2c
#include <Servo.h>                                                              // On ajoute la bibliothèque Servo.h qui permet la commande des servos

#define I2C_SLAVE_ADDRESS_MODULE_A_11 11                                        // On définit sous le nom "I2C_SLAVE_ADDRESS_MODULE_A_11" et la valeur 11 l'adresse de l'Arduino esclave du module A

const byte PIN_MOTEUR[16] = {0, 2, 0, 3, 0, 5, 0, 7, 0, 9, 0, 0, 0, 0, 10, 12}; // On définit une liste qui constient les numéros des pins des commandes des (servo)moteurs du module A
Servo servo_moteur[16];                                                         // On définit une liste d'objets (servo)moteurs

// Pour les moteurs  :           1         3         5        7*          9                        14    15
word gauche_moteur[16] = { 0 ,  60 , 2 ,  60 , 4 ,  70 , 6 ,  30 ,  8 , 140 , 10 , 11 , 12 , 13 , 140 , 120 };     // Définit un tableau de 16 valeurs de positions "gauche_moteur" pour les servos (le paramétrage correspond à la réalité des moteurs DLY2 du réseau)
word droite_moteur[16] = { 0 , 125 , 2 , 140 , 4 , 110 , 6 , 160 ,  8 ,  70 , 10 , 11 , 12 , 13 ,  50 ,  50 };     // Définit un tableau de 16 valeurs de positions "droite_moteur" pour les servos (le paramétrage correspond à la réalité des moteurs DLY2 du réseau)

int angle_avant, angle_final;                                                   // On définit les variables dans lesquelles on va stocker l'angle des servo(moteurs) avant, après mouvement, et l'angle de commande
int gauche_droite_info_moteur, num_moteur;                                      // On définit les variables dans lesquelles on va stocker la commande (0 pour gauche, 5 pour droite, 9 pour demande position) et le numéro de moteur
int valeur_recue, valeur_a_transmettre;                                         // On définit les variables dans lesquelles on va stocker la commande recue et la réponse à transmettre
byte vitesse_moteur = 1;                                                            // On définit la vitesse des (servo)moteurs



void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS_MODULE_A_11);                                    // On démarre la communication i2c en tant qu'esclave sous l'adresse "I2C_SLAVE_ADDRESS_MODULE_A_11"
  Serial.begin(115200);                                                         // On démarre la liaison série à 115200 baud

  delay(100);                                                                   // On attend 100 ms
  Wire.onRequest(requestEvents);                                                // On indique que c'est "requestEvents" qui est exécutée en cas de demande de l'Arduino maître
  Wire.onReceive(receiveEvents);                                                // On indique que c'est "receiveEvents" qui est exécutée en cas de réception de données de l'Arduino maître

  servo_moteur[1].write(droite_moteur[1]);                                      // Position initiale du (servo)moteur 1 : à droite
  servo_moteur[1].attach(PIN_MOTEUR[1]);                                        // On attache le (servo)moteur 1

  servo_moteur[3].write(droite_moteur[3]);                                      // Position initiale du (servo)moteur 3 : à droite
  servo_moteur[3].attach(PIN_MOTEUR[3]);                                        // On attache le (servo)moteur 3

  servo_moteur[5].write(droite_moteur[5]);                                      // Position initiale du (servo)moteur 5 : à droite
  servo_moteur[5].attach(PIN_MOTEUR[5]);                                        // On attache le (servo)moteur 5

  servo_moteur[7].write(gauche_moteur[7]);                                      // Position initiale du (servo)moteur 7 : à gauche
  servo_moteur[7].attach(PIN_MOTEUR[7]);                                        // On attache le (servo)moteur 7

  servo_moteur[9].write(gauche_moteur[9]);                                      // Position initiale du (servo)moteur 9 : à gauche
  servo_moteur[9].attach(PIN_MOTEUR[9]);                                        // On attache le (servo)moteur 9

  servo_moteur[14].write(droite_moteur[14]);                                    // Position initiale du (servo)moteur 14 : à droite
  servo_moteur[14].attach(PIN_MOTEUR[14]);                                      // On attache le (servo)moteur 14

  servo_moteur[15].write(droite_moteur[15]);                                    // Position initiale du (servo)moteur 15 : à droite
  servo_moteur[15].attach(PIN_MOTEUR[15]);                                      // On attache le (servo)moteur 15
}



void loop()
{
}


void requestEvents()                                                            // Fonction "requestEvents" qui est exécutée en cas de demande de l'Arduino maître
{
  Wire.write(valeur_a_transmettre);                                             // On envoie valeur_a_transmettre sur la liaison i2c
}



void receiveEvents(int numBytes)                                                // Fonction "receiveEvents" qui est exécutée en cas de réception de données de l'Arduino maître et les stocke dans la variable numBytes
{
  valeur_recue = Wire.read();                                                   // On met la valeur reçue de la liaison i2c dans valeur_recue

  num_moteur = valeur_recue / 10;                                               // On met dans "num_moteur" le chiffre des dizaines de "valeur_recue"
  gauche_droite_info_moteur = valeur_recue % 10;                                // On met dans "gauche_droite_info_moteur" le chiffre de commande (0,5 ou 9)

  if (gauche_droite_info_moteur == 0)                                           // Si "gauche_droite_info_moteur" = 0
  {
    mouvement_servo(num_moteur, gauche_moteur[num_moteur]);                     // On bascule le moteur numéro "num_moteur" dans la position d'angle "gauche_moteur[num_moteur]"
  }
  else if (gauche_droite_info_moteur == 5)                                      // Sinon si "gauche_droite_info_moteur" = 5
  {
    mouvement_servo(num_moteur, droite_moteur[num_moteur]);                     // On bascule le moteur numéro "num_moteur" dans la position d'angle "droite_moteur[num_moteur]"
  }
  delay(1000);                                                                  // On attend 1 seconde
  
  valeur_a_transmettre = prepare_reponse_au_Master(num_moteur);                 // Puis on construit la valeur à renvoyer vers le Master et le téléphone, on la mettra dans valeur_a_transmettre
}



void mouvement_servo(int num_moteur, int angle_commande)                        // Fonction mouvement_servo, prend pour arguments le numéro de moteur et l'angle de commande   ______________Reste à finir le mouvement lent
{
  angle_avant = mesure_angle_servo(num_moteur);                                 // On vérifie l'angle du (servo)moteur avant mouvement et on met la valeur dans "angle_avant"
  if (angle_avant < angle_commande)                                             // Si l'angle avant mouvement est inférieur à celui de la commande
  {
    for (int angle = angle_avant; angle <= angle_commande; angle++)             // Boucle sur un "angle" allant de "angle_avant" à "angle_commande" et on incrémente "angle" (de 1)
    {
      int microseconds = map(angle, 0, 180, 544, 2400);                         // Convertit l'angle en microsecondes
      servo_moteur[num_moteur].writeMicroseconds(microseconds);                 // On envoie la commande au servomoteur sous forme de microsecondes
      delay(10000);                                                               // On attend 300 ms pour un mouvement lent
    }
  }
  else if (angle_avant > angle_commande)                                        // Sinon, si l'angle avant mouvement est supérieur à celui de la commande
  {
    for (int angle = angle_avant; angle >= angle_commande; angle--)             // Boucle sur un "angle" allant de "angle_avant" à "angle_commande" et on décrémente "angle" (de 1)
    {
      int microseconds = map(angle, 0, 180, 544, 2400);                         // Convertit l'angle en microsecondes
      servo_moteur[num_moteur].writeMicroseconds(microseconds);                 // On envoie la commande au servomoteur sous forme de microsecondes
      delay(10000);                                                               // On attend 300 ms pour un mouvement lent
    }
  }
}



int prepare_reponse_au_Master(int num_moteur)                                   // La fonction prend pour argument le numéro de moteur et retourne la valeur à renvoyer à l'Arduino maître et au téléphone
{
  int valeur_a_retourner, angle_moteur;                                         // On crée deux variables locales "valeur_a_retourner" et "position_moteur"
  angle_moteur = mesure_angle_servo(num_moteur);                                // On récupère la position actuelle du moteur et on la stocke dans "angle_moteur"
  if (angle_moteur == gauche_moteur[num_moteur])                                // Si c'est l'angle de position gauche
  {
    valeur_a_retourner = 100 + 10 * num_moteur + 0;                             // On met dans "valeur_a_retourner" le calcul avec un 0 en fin
  }
  else if (angle_moteur == droite_moteur[num_moteur])                           // Sinon si c'est l'angle de position droite
  {
    valeur_a_retourner = 100 + 10 * num_moteur + 5;                             // On met dans "valeur_a_retourner" le calcul avec un 5 en fin
  }
  else valeur_a_retourner = 100 + 10 * num_moteur + 9;                          // Sinon on met dans "valeur_a_retourner" le calcul avec un 9 en fin (ne devrait pas arriver)
  return valeur_a_retourner;                                                    // La fonction retourne "valeur_a_retourner"
}



int mesure_angle_servo(int num_moteur)                                          // La fonction prend pour argument le numéro de moteur et retourne sa position en angle
{
  int position_moteur;                                                          // On crée une variable locale "position_moteur"
  position_moteur = servo_moteur[num_moteur].read();                            // On lit la position du (servo)moteur demandé et on l'écrit dans "position_moteur"
  return position_moteur;                                                       // On demande à la fonction de retourner la position du moteur
}



[/code]
saisissez ou collez du code ici

Bonjour,
ça serait pour aller + vite , alors que :

donc amha tu peux continuer à transmettre les valeurs sous forme de caractères

ce qui m'étonne , c'est l'incrémentation par tranches de 10 secondes dans ta boucle de progression : il ne faut pas vouloir faire trop fin , mais là ...
n'y a-t-il pas une bibliothèque pour cela , genre slow servo ou accel servo ?

Bonjour,
Oui, effectivement, ça a l'air bizarre ! Mais est-ce lié ? D'un côté je cherche juste à optimiser mon code sur les conseils de fdufnews ; de l'autre, j'ai un mouvement qui devrait être progressif et qui ne l'est pas.
Oui, mon 10000 est totally provoc, mais c'était pour voir si en changeant la valeur du delay, cela avait bien un effet sur le mouvement. Et bien non ! Et c'est là que je ne comprends pas...

Concernant la progressivité , notons qu'elle est intrinsèque , du fait de la conversion d'un mouvement rotatif vers un mouvement linéaire : c'est donc au centre qu'il y a le + de vitesse , et aux extrémités qu'il y a le + de couple : pas belle la vie ?
Il n'y a donc , si ne ne m'abuse , plus qu'à ralentir le mouvement : vois la bibliothèque SlowMotionServo , qui a été créée pour cela

Bonjour babskwal

En plus de la proposition de @trimarco232, il y a la bibliothèque VarspeedServo, qui a plein de possibilités, comme le réglage de la vitesse, la possibilité de rotation du servo bloquante ou pas, entre autres.

Cordialement
jpbbricole

Bonjour et merci de vos réponses,
Je commence à creuser la piste de SlowMotionServo, je vous tiens au courant. Je ne connaissais pas VarspeedServo...

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.