website logo

Arduino : commande de 8 servomoteurs sur la même platine (la suite)

vendredi 25 décembre 2020 @ 11:43:08

Sujet : Les servomoteurs commandés par Arduino

J'ai bien avancé dans cette partie qui semble fonctionnelle. 

CIMG9313.JPG



CIMG9312.JPG


et voici le code

//*************************************************************************
// GESTION DE 8 AIGUILLAGES PAR SERVOMOTEURS
//*************************************************************************
// le 25/12/2020 à 00:09
// fonctionnement testé le 25/12/2020  à 06:22 => OK
//=========================================================================
// I) Détection du mode de fonctionnement par BP permanent connecté sur A0
//      I-a le BP est enfoncé en position basse => mode "REGLAGE"
//          - sélection du servomoteur concerné 
//                  sélecteur rotatif 8 positions sur A5 => à faire
//          - positionnement du servo concerné au point milieu
//          - RV butée gauche sur A3
//          - RV butée droite sur A4
//          - 1 BP enregistrement sur eeprom
//      I-b le BP reste en position haute => mode "COMMANDE"
//          - sélection du BP enfoncé sur A1
//          - connection du servomoteur concerné au pin+2
//          - lecture des données de ce servomoteur
//          - basculement de la position
//          - enregistrement en eeprom
//  II) Gestion des 16 leds (bicolores) concernées
//=========================================================================

#include 
#include 
Servo servoAiguillage[8];

const int limitAngleMin = 1250;
const int limitAngleMax = 1750;
const int PointMilieu = 1500;

int angleMin[8] = {1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250};                      // à initialiser dans l'eeprom
int angleMax[8] = {1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750};                      // à initialiser dans eeprom
int angleIntermediaire[8] = {PointMilieu, PointMilieu, PointMilieu, PointMilieu, PointMilieu, PointMilieu, PointMilieu, PointMilieu}; // valeur de l'angle intermédiaire pendant le mouvement
int DernierePositionServo[8];                                                            // PointMilieu = milieu, angleMin[0] = gauche, angleMax[0] = droite => à lire dans eeprom
int sensMouvement[8];
const byte vitesse = 1;                                                                  // multiplicateur permettant de régler la vitesse de déplacement
int Limite[8];

int valeurLectureButee;                                                                  // valeur de la résistance variable trascrite en mS 

const byte pinBPMode = 0;                                                                // le BP de sélection de mode est connecté sur A0 => A3 en production
const byte pinBPAiguillages = 1;                                                         // les 8 BP de choix d'aiguillage en fonctionnement sont connectés sur A1 => A4 en production
const byte pinRVButees = 2;                                                              // la résistance variable de réglage des butées est connecté sur A2 => A5 en production
const byte pinSwitchSelecteurServo = 3;                                                  // les 8 switches de sélection du servo à régler sont connectés sur A3 => A6 en production
const byte pinBPValidationReglage = 4;                                                   // le BP de validation des réglages est connecté sur A4 => A7 en production
const byte pinServo =  2;                                                                // les servos sont connectés à partir de D2 

byte numPoussoir;                                             
const byte Temporisation = 3;  

byte CalculLimite(){
  if (DernierePositionServo[numPoussoir] == PointMilieu){                                 // le servo est au PointMilieu, il doit regagner angleMin[0]
          sensMouvement[numPoussoir] = -1;
          Limite[numPoussoir] = angleMin[numPoussoir];
          DernierePositionServo[numPoussoir] = angleMin[numPoussoir];
  } else if (DernierePositionServo[numPoussoir] == angleMin[numPoussoir]){                // le servo est en butée gauche, il doit regagner angleMax[0]
          sensMouvement[numPoussoir] = 1;
          Limite[numPoussoir] = angleMax[numPoussoir];
          DernierePositionServo[numPoussoir] = angleMax[numPoussoir];
   } else {                                                                               // le servo est en butée droite (ou autre), il doit regagner angleMin[0]
          sensMouvement[numPoussoir] = -1;                                             
          Limite[numPoussoir] = angleMin[numPoussoir];
          DernierePositionServo[numPoussoir] = angleMin[numPoussoir];
  }                                       
}

void setup() {
    Serial.begin(9600);                                                                   // connexion au moniteur série de l'ordinateur 

        /* lecture des derniers réglages dans l'eeprom */
        /* Initialisation si première utilisation */
        /* les informations du servo 1 sont dans les bytes 0 à 9, ceux du servo 2 de 10 à 19 ... and so on ... */
        for(byte i = 0; i < 8; i++)
        {
          
            angleMin[i] = EEPROM.read(i * 10) | ((int)EEPROM.read((i * 10) + 1)) << 8;    // lecture des 2 bytes pour int angleMin[]
            if (angleMin[i] > 1500 || angleMin[i] < 256){                                 // si incohérence de valeur ou initialisation (=255) 
              angleMin[i] = limitAngleMin;                                                // on enregistre la limite pour angleMin 
              EEPROM.update((i * 10), angleMin[i] & 0xFF);                                // écrit le premier byte de la valeur int
              EEPROM.update((i * 10) + 1, angleMin[i] >> 8);                              // écrit le second byte de la valeur int
            } // fin de if (angleMin[i] > 1500 || angleMin[i] < 256)
          
            angleMax[i] = EEPROM.read((i * 10) + 2) | ((int)EEPROM.read((i * 10) + 3)) << 8;// lecture des 2 bytes pour int angleMax[]
            if (angleMax[i] < 1500) {                                                      // si incohérence de valeur ou initialisation (=255)
              angleMax[i] = limitAngleMax;                                                 // on enregistre la limite pour angleMax
              EEPROM.update((i * 10) + 2, angleMax[i] & 0xFF);                             // écrit le premier byte de la valeur int
              EEPROM.update((i * 10) + 3, angleMax[i] >> 8);                               // écrit le second byte de la valeur int
            } // fin de if (angleMax[i] == 0)
          
            DernierePositionServo[i] = EEPROM.read((i * 10) + 4) | ((int)EEPROM.read((i * 10) + 5)) << 8;
            if (DernierePositionServo[i] < angleMin[i] || DernierePositionServo[i] > angleMax[i]){
              DernierePositionServo[i] = PointMilieu;
              EEPROM.update((i * 10) + 4, DernierePositionServo[i] & 0xFF);                // écrit le premier byte de la valeur int
              EEPROM.update((i * 10) + 5, DernierePositionServo[i] >> 8);                  // écrit le second byte de la valeur int
            } // if (DernierePositionServo[i] == 0
            
        /* fin de lecture des données et d'initialisation de l'eeprom */
                    
            angleIntermediaire[i] = DernierePositionServo[i];                              // on met le servo à sa dernière position
            servoAiguillage[i].attach(i + pinServo);
            servoAiguillage[i].writeMicroseconds(angleIntermediaire[i]);
            delay(150);
            servoAiguillage[i].detach();
        
        } // fin de for
        
} // fin de setup

void loop() {

   if (analogRead(pinBPMode) <= 512) {                                                   // le bouton MODE est connecté à la broche A0
    
        //Serial.print("Bouton : ");                 // Debug
        //Serial.print(pinChoixMode);                // Debug
        //Serial.print(" en mode REGLAGE : ");       // Debug
        //Serial.println(analogRead(pinChoixMode));  // Debug 
        //*************************
        // mode REGLAGE
        //*************************
        
        /* Détermination de l'aiguillage en cours */
        byte ServoEnCours = (analogRead(pinSwitchSelecteurServo) + 64) / 128;            // retourne le n° du servo à régler sélectionné par switches
        delay(25);                                                                       // pour éviter les rebonds
        ServoEnCours = 0; //Débug 
        if (ServoEnCours < 8) {
            
            servoAiguillage[ServoEnCours].attach(pinServo + ServoEnCours);               // on connecte le servo à régler au pin correspondant à partir de D2 
            if (byte j = 0){
              j += 1;  
              servoAiguillage[ServoEnCours].writeMicroseconds(PointMilieu);              // positionne le servo au point milieu        
            } else {
                valeurLectureButee = analogRead(pinRVButees);                            // Lecture de la résistance variable sur le pin A2 => valeurs de 0 à 1023)
                delay(25);                                                               // pour éviter les rebonds ... utilité à vérifier
                valeurLectureButee = map(valeurLectureButee, 0, 1023, 0, 2500);          // conversion en microsecondes
            
                if (valeurLectureButee > limitAngleMax) {                                // on reste dans les limites
                    valeurLectureButee = limitAngleMax;
                } else if (valeurLectureButee < limitAngleMin){
                    valeurLectureButee = limitAngleMin;
                } // fin de if (valeurLectureButee > limitAngleMax)
                
                Serial.print("Réglage aiguillage N° ");
                Serial.println(ServoEnCours); //Débug
                Serial.println(valeurLectureButee); //Débug
                servoAiguillage[ServoEnCours].writeMicroseconds(valeurLectureButee);     // positionne le servomoteur
                delay(Temporisation);                                                    // repos
            
                /* on enregistre le réglage par l'action d'un bouton */
                int validation = analogRead(pinBPValidationReglage);                     // on détecte si le bouton poussoir de validation a été appuyé
                delay(25);                                                               // pour éviter les rebonds ... utilité à vérifier
            
                if ( validation < 513) {
              
                    // si valeurLectureButee < PointMilieu c'est la butée gauche qui a été réglée => angleMin[ServoEnCours] = valeurLectureButee 
                    // sinon c'est la butée droite qui a été réglée => angleMax[ServoEnCours] = valeurLectureButee
                    Serial.print(validation); // débug
                
                    if (valeurLectureButee < PointMilieu){
                        angleMin[ServoEnCours] = valeurLectureButee;                   
                        Serial.print("Angle mini N° "); //Débug
                        Serial.println(ServoEnCours);           //Débug
                        Serial.print("réglé à ");               //Débug
                        Serial.println(angleMin[ServoEnCours]); //Débug
                        EEPROM.update((ServoEnCours * 10), angleMin[ServoEnCours] & 0xFF);   // écrit le premier byte de la valeur int angleMin
                        EEPROM.update((ServoEnCours * 10) + 1, angleMin[ServoEnCours] >> 8); // écrit le second byte de la valeur int angleMin
                    } else {
                        angleMax[ServoEnCours] = valeurLectureButee;
                        Serial.print("Angle maxi N° ");         //Débug
                        Serial.println(ServoEnCours);           //Débug
                        Serial.print("réglé à ");               //Débug
                        Serial.println(angleMax[ServoEnCours]); //Débug
                        EEPROM.update((ServoEnCours * 10) + 2, angleMax[ServoEnCours] & 0xFF);     // écrit le premier byte de la valeur int angleMax
                        EEPROM.update((ServoEnCours * 10) + 3, angleMax[ServoEnCours] >> 8);       // écrit le second byte de la valeur int angleMax
                    } // fin de (valeurLectureButee < PointMilieu)
                
                    angleIntermediaire[ServoEnCours] = valeurLectureButee;
                
                } // fin de if (validation < 513)
                
            } // fin de if (byte j = 0)   
            
        } // fin de if (ServoEnCours < 8)
         
    } else {
      
        //Serial.print("Bouton : ");                // Debug
        //Serial.print(pinChoixMode);               // Debug
        //Serial.print(" en mode COMMANDE : ");      // Debug
        //Serial.println(analogRead(pinChoixMode)); // Debug 
        //*************************
        // mode COMMANDE
        //*************************
        
        if (analogRead(pinBPAiguillages) <1023) {                                              // on a appuyé sur un des BP de commande des aiguillages
            
            // on passe en mode "COMMANDE" des servos
            Serial.println("Mode commande des servos"); // Débug
            
            numPoussoir = (analogRead(pinBPAiguillages) + 64) / 128;                           // retourne le n° du poussoir activé pour 8 poussoirs
            // numPoussoir = (analogRead(pinBPAiguillages) + 256) / 512;                       // retourne le n° du poussoir activé pour 2 poussoirs 
            delay(25);                                                                         // pour éviter les rebonds ... utilité à vérifier
            // Serial.println(analogRead(pinBPAiguillages)); // Débug
            Serial.print("Poussoir N° "); // Débug                                    
            Serial.println(numPoussoir); // Débug

            if (numPoussoir < 8) {
              
                servoAiguillage[numPoussoir].attach(numPoussoir + pinServo);                   // on connecte le servomoteur correspondant au BP      
                CalculLimite();
                Serial.println(Limite[numPoussoir]);
                Serial.println(sensMouvement[numPoussoir]);
                Serial.println(DernierePositionServo[numPoussoir]);
           
                do {
                  
                    angleIntermediaire[numPoussoir] = angleIntermediaire[numPoussoir] + (sensMouvement[numPoussoir] * vitesse);
                    servoAiguillage[numPoussoir].writeMicroseconds(angleIntermediaire[numPoussoir]);     
                    if(angleIntermediaire[numPoussoir] == Limite[numPoussoir]){ 
                        EEPROM.update((numPoussoir * 10) + 4, angleIntermediaire[numPoussoir] & 0xFF); // écrit le premier byte de la valeur int
                        EEPROM.update((numPoussoir * 10) + 5, angleIntermediaire[numPoussoir] >> 8);   // écrit le premier byte de la valeur int     
                        Serial.print("Dernière position : "); // Débug
                        Serial.println(angleIntermediaire[numPoussoir]); // Débug
                        break;      
                    } // fin de if(angleIntermediaire[numPoussoir] == Limite[numPoussoir])
                    delay(Temporisation);  
                } 
                while(1); // fin de do

                delay(150);
                servoAiguillage[numPoussoir].detach();

            } // fin de if (numPoussoir < 8)
       
        } // fin de (analogRead(pinBPAiguillages) <1023)
   
    } // (analogRead(pinBPMode) > 512)

}// fin de loop

 

Reste à déterminer si je gère les leds témoins par programmation ou par un des micro-contacts des moteurs d'aiguillages comme prévu initialement. Le choix du servomoteur en cours de réglage se fera au plus simple, soit par un sélecteur rotatif si j'en trouve des minis à 8 positions, soit tout simplement par un jeu de cavaliers.

Il va falloir créer une platine qui va regrouper tous ces éléments en ajoutant un témoin de mode de fonctionnement (Vert = COMMANDE, bleu = REGLAGE), éventuellement un petit buzer pour "marquer" les actions du bouton de validation de réglages et, ce serait l'idéal, un petit écran pour visualiser les valeurs des réglages.

J'ai commencé à étudier ce PCB

SupportLes essais avec un montage réel d'aiguillage sur mon plateau de test met en évidence un point faible de mon système. En raison des fixations mécaniques des moteurs d'aiguillages, il est très difficile, voire quasiment impossible, de faire correspondre le point milieu théorique du servomoteur (1500 mS) avec celui des aiguillages. Il faudra donc définir et enregistrer le point milieu de chaque aiguillage. Ce qui m'oblige à modifier ma procédure de réglage pour qu'elle tienne compte de cette valeur. Il faudra donc un ordre précis des réglages.
A noter que l'espace entre les deux positions gauche et droite est tres faible de l'ordre de 75mS, il faut donc augmenter la sensibilité de la résistance variable ... à bientôt pour la suite.

 

 

 




Cet article provient de Le réseau du Mesnil-sur-Jorg
L'url pour cet article est : http://wgnt-train.fr/article.php?sid=153