Auteur Sujet: commande servo par inter  (Lu 24624 fois)

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
commande servo par inter
« le: décembre 14, 2015, 02:54:03 pm »
Bonjour ,
comme indiqué dans ma présentation, je cherche à piloter des servos . J'ai honteusement copié les fichiers de jlb ( que je remercie et félicite pour la qualité de son travail )
J'ai 2 options :
soit piloter par attiny 45, 1 servo par 1 inter suivant le programme de jlb que j'ai trouvé sur le site de LR
soit piloter par carte NANO , 4 servos par 4 inters suivant le programme ( 8 servos 8 inters )
dans les 2 cas je n'y arrive pas
pour le pilotage par NANO , je ne veux pas 8 inters sur une entrée mais 1 entrée pour chaque inter . J'ai essayé de modifié sur le programme  la structure(Lire poussoir) par un semblant de descripteur clavier . Malgré le nombre d'heures à chercher  (je ne suis pas programmeur ) ,je ne vous dit pas le résultat . Vous avez compris .
Pour le pilotage par attiny , j'arrive à transférer le programme cité ci dessus en modifiant la bibliothèque servo par servo8Bit 2 Mais le servo ne répond pas à la commande de l'inter. Sur la carte NANO j'utilise les bornes AO pour l'inter et 2 pour le servo( comme le logiciel ) . Quand je le transpose sur attiny ,j'utilise la pin 3 soit la patte 2 pour l'inter et la pin 2 soit la patte 7
Dans les 2 cas , j'aimerai de l'aide de votre part
Cordialement
Philippe



DDEFF

  • Hero Member
  • *****
  • Messages: 738
    • Voir le profil
Re : commande servo par inter
« Réponse #1 le: décembre 15, 2015, 09:24:32 am »
Bonjour,
C'est bien de se lancer... ;)

Sur ATTiny, je ne comprends pas ce que tu entends par "modifier la bibliothèque".
Normalement, une bibliothèque, ça ne se modifie pas.
D'autre part, le nom "servoBit 2" est étrange : on ne met pas de blanc dans un nom. A minima, l'appeler "servo8bits_2".

Sur NANO, tu t'attaques à un programme assez costaud pour un débutant.
Dans ce programme, on entre sur une entrée analogique et on divise les 5V en 1024/8 parties.
C'est très bien expliqué par Jean-Luc http://modelleisenbahn.triskell.org/spip.php?article59
Si tu veux 4 poussoirs, il faut diviser par 4 (et plus par 8 ) puis adapter les résistances.

Ma question est : pour quelle raison voudrais-tu 4 poussoirs distincts ?
Une spécificité de ton clavier ?

Denis

"Ce n'est pas le puits qui est trop profond, c'est ta corde qui est trop courte" (proverbe chinois)

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
Re : commande servo par inter
« Réponse #2 le: décembre 16, 2015, 10:07:24 pm »
Merci pour ta réponse
Sur Attiny
La bibliothèque Servo ne marche quà 16 MHZ. Les Attiny fonctionnent à 8MHZ. Donc si on veut commander un servo par un Attiny , il faut une autre bibliothèque qui est Servo8Bit2  . A priori , j'ai réglé le problème , je commande un servo par un inter avec recopie sur TCO par Led avec la commande writMicroseconds .
J'ai utilisé le sketch  de jlb (un servo par un inter )
Sur Nano
Le blog de jlb est mon livre de chevet ( je suis impressionné par la pédagogie de ce monsieur et sa compétence en programmation ).Mon but est d'utilisé le sketch " 8 servos par 8 inters écrit en C et non en c++( je ne souhaite pas le réglage des butées , je le fais directement sur le réseau avec une carte uno et un afficheur ). Le programme de jlb est 8 inters sur une seule entrée , il utilise un pont diviseur  . Je le cite
"""""""""""""""""""""
int lirePoussoirs()
{
    int resultat;
    int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;
   
    int nouvelEtatPoussoir = etatPoussoir; /* à priori rien ne change */
"""""""""""""""""""""""
De cette manière , on ne peut lire qu'un seul inter à la fois
Mon but est d'avoir 4 inters sur les bornes par ex  (AO , A3 ). Je souhaite modifier la fonction"LirePoussoirs() " pour savoir quel inter est activé . Et la je bloque
La raison est que je pilote les commandes aiguilles ou accessoire  par RRTC et des décodeurs LTD TYPE SA DEC 4 (4 sorties bistable C R T ) . Si j'avais cette fonction , je pourrai utilisé le T( contact travail)  du décodeur sur la borne AO, A3 et avoir un mouvement lent des aiguilles PECO code 55 ( je fais du N)et tout cela un moindre coût par rapport à d'autres commandes  moteur (type tortoi... , etc....)
Le logiciel de jlb est parfait pour mes besoins , reste à modifier cette ""maudite"" fonction
D'ou mon appel à l'aide
Cordialement
Philippe

DDEFF

  • Hero Member
  • *****
  • Messages: 738
    • Voir le profil
Re : commande servo par inter
« Réponse #3 le: décembre 17, 2015, 04:05:42 pm »
Bonjour Philippe,

Pour NANO, il te faut définir les 4 entrées A0 à A3 comme digitales et en entrées dans le setup().
Sur un NANO, pour A0 à A3, c'est faisable.
Note que ce ne serait pas faisable pour A6 et A7 qui ne peuvent être qu'analogiques.

On va donc avoir dans le setup :
    pinMode(A0, INPUT_PULLUP);    //  BP 0
    pinMode(A1, INPUT_PULLUP);    //  BP 1
    pinMode(A2, INPUT_PULLUP);    //  BP 2
    pinMode(A3, INPUT_PULLUP);    //  BP 3

On utilise la résistance interne de l'Arduino pour tirer la tension vers le +5V (d'où le terme "pull_up").
Ton BP ou ton inter sera donc entre la masse (GND = ground) et la broche A0, A1...A3.

Jusque là, je pense que je ne t'apprends rien, mais on ne sait jamais.

Passons maintenant à la modification du programme lui-même.

La ligne
int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;n'a maintenant plus de raison d'être.

A quoi servait-elle ?

C'est là qu'on voit un programme bien fait :
Le nom de la variable donne la solution : elle donne le numéro du poussoir.

Les numéros vont de 0 à 7 et quand le numéro vaut 8, c'est qu'aucun bouton n'est appuyé.
C'est très bien expliqué dans l'article cité précédemment.

Deux choses restent à faire :
1°) trouver numPoussoir quand on appuie sur un bouton
2°) passer à 4 au lieu de 8 puisque tu n'as que 4 boutons. A plusieurs endroits.

Le module "lirePoussoirs" est au pluriel parce qu'il cherche quel est le bouton appuyé dans la chaîne de poussoirs.
Mais il ne lit qu'un bouton.

En fait, c'est dans le loop() qu'on balaye les boutons, dans la boucle :
for (numServo = 0; numServo < 8; numServo++) gereServo(numServo);
Et donc, là aussi, il faudra mettre 4 au lieu de 8.

Donc, reste à lire tes 4 boutons.
Voyons quelles sont les difficultés (outre le problème des rebonds) :

La première idée qui vient serait d'écrire :
numPoussoir = 4;
if (digitalRead(A0) == LOW)
{
  numPoussoir = 0;
}
if (digitalRead(A1) == LOW)
{
  numPoussoir = 1;
}
if (digitalRead(A2) == LOW)
{
  numPoussoir = 2;
}
if (digitalRead(A3) == LOW)
{
  numPoussoir = 3;
}

On note qu'on cherche un LOW et pas un HIGH, puisqu'on à par défaut un HIGH (pull_up) et qu'on met à LOW en appuyant sur le bouton.

Si on n'appuie sur rien, il sort bien numPoussoir = 4. OK.
Si on n'appuie que sur un seul bouton, numPoussoir va bien donner 0, 1, 2 ou 3 suivant le bouton appuyé. OK.

Mais si on appuie sur plusieurs boutons, le programme ne va retenir que le dernier appuyé.

Par exemple 2 et 3 :
numPoussoir va passer successivement par 4 (au départ), puis 2, puis 3, effaçant 2... complètement oublié dans l'histoire.

Si on imbriquait les if(...) {...} avec des if(...){...}else{...}, ça ne changerait pas grand chose : on obtiendrait le premier bouton appuyé et on sortirait des tests.
Cette fois, ce serait 3 qui serait oublié et numPoussoir vaudrait 2.
numPoussoir = 4;
if (digitalRead(A0) == LOW)
{
    numPoussoir = 0;
}
else
{
    if (digitalRead(A1) == LOW)
    {
         numPoussoir = 1;
    }
    else
    {
        if (digitalRead(A2) == LOW)
        {
            numPoussoir = 2;
        }
        else
        {
            if (digitalRead(A3) == LOW)
            {
                numPoussoir = 3;
            }
        }
    }
}

On gagne juste un peu de temps : on ne fait en moyenne que 2 tests alors qu'avant on en faisait forcément 4.
Gain quasi nul et sans intérêt : le problème n'est pas là.

Ce qu'il faudrait, c'est mémoriser la position des 4 boutons et de ne retenir pour numPoussoir que pour le bouton qui a changé d'état.
Même si deux ont changé d'état en même temps, on traitera le premier, puis le deuxième au tour suivant.

Il faut donc 8 variables supplémentaires : ancienA0, nouveauA0, ancienA1, nouveauA1 ... nouveauA3.

Je n'ai pas la solution tout de suite, mais je te la donne dès que j'ai vérifié. Je ne voudrais pas écrire des bêtises.  ;)








« Modifié: décembre 18, 2015, 05:07:21 pm par DDEFF »
"Ce n'est pas le puits qui est trop profond, c'est ta corde qui est trop courte" (proverbe chinois)

DDEFF

  • Hero Member
  • *****
  • Messages: 738
    • Voir le profil
Re : commande servo par inter
« Réponse #4 le: décembre 18, 2015, 06:02:24 pm »
Suite

On commence par déclarer les variables (avant le setup() )

boolean ancienA0  = HIGH;
boolean nouveauA0 = HIGH;
boolean ancienA1  = HIGH;
boolean nouveauA1 = HIGH;
boolean ancienA2  = HIGH;
boolean nouveauA2 = HIGH;
boolean ancienA3  = HIGH;
boolean nouveauA3 = HIGH;

Puis, en replacement de la ligne de lecture des 8 boutons :

    numPoussoir = 4;

    nouveauA0 = digitalRead(A0);   
    if (ancienA0 != nouveauA0)
    {
        ancienA0 = nouveauA0;
        numPoussoir = 0;
    }
    else
    {
        nouveauA1 = digitalRead(A1);
        if  (ancienA1 != nouveauA1)
        {
            ancienA1 = nouveauA1;
            numPoussoir = 1;
        }
        else
        {
            nouveauA2 = digitalRead(A2);
            if  (ancienA2 != nouveauA2)
            {
                ancienA2 = nouveauA2;
                numPoussoir = 2;
            }
            else
            {
                nouveauA3 = digitalRead(A3);
                if  (ancienA3 != nouveauA3)
                {
                    ancienA3 = nouveauA3;
                    numPoussoir = 3;
                }                                 
            }
        }
    }

Le but est toujours d'avoir le numéro de bouton sur lequel on a appuyé.

Au début, tous les poussoirs sont à HIGH.
Quand on lit les nouveaux poussoirs, on retrouve évidemment HIGH puisqu'on n'a appuyé sur rien.
Tous les tests sont négatifs et donc numPoussoir reste à 4.

Si on appuie, par exemple, sur 2, on passe les tests A0 et A1 par la négative, mais pas A2 parce que ancienA2 est à HIGH et que le nouveauA2 vient d'être à LOW.

On sort des boucles avec numPoussoir à 2, mais on a mis ancienA2 à LOW.
Et il y reste.
Au prochain passage, si le poussoir est toujours activé, on ignorera le test en A2 car ancienA2 = nouveauA2 = LOW.
Et donc, on retrouvera numPoussoir = 4.

Mais on aura traité le cas A2 car on traite dans la foulée. Et traité le cas du troisième Servo (hé oui, 3ème, puisqu'on démarre à 0...)

Donc, tout va bien pour un seul poussoir qu'on détecte bien.
On avait déjà atteint ce point avec le tout premier programme. C'était bien la peine ... :D

Mais là où ça change complètement, c'est si on appuie sur plusieurs boutons.
Mettons qu'on appuie sur tous les boutons en même temps.

Premier test (A0) : on trouve ancienA0 = HIGH et nouveauA0 = LOW et donc on sort des tests directement avec numPoussoir à 0.
Mais on a mis ancienA0 à LOW.

Ce qui fait que quand on passe au tour suivant, on saute le test A0 et en testant A1, on trouve ancienA1 = HIGH et nouveauA1 = LOW et donc on sort des tests directement avec numPoussoir à 1.

Au passage d'après, on a 2 et au passage d'après on aura 3.
Chaque passage a donné son numPoussoir.
Puis retour à numPoussoir = 4 tant que les boutons n'ont pas évolué.

Il reste un problème, que j'ai laissé exprès. Je te laisse le découvrir.
Mais tu va pouvoir le contourner facilement.

C'est toujours plus agréable d'avoir cherché et trouvé soi-même la solution. C'est comme ça qu'on progresse.
Mais si tu ne trouves pas, je suis toujours là.

"Ce n'est pas le puits qui est trop profond, c'est ta corde qui est trop courte" (proverbe chinois)

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
Re : commande servo par inter
« Réponse #5 le: décembre 18, 2015, 08:49:34 pm »
Merci DDEF pour ton aide et ta pédagogie .

Je pars pour deux semaines et ne sait pas si j'aurai internet . J'ai donc imprimer tout le sujet.

J'espère , à mon retour , avoir réussi le challenge .

Bonnes fêtes

Cordialement

Philippe

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
Re : commande servo par inter
« Réponse #6 le: décembre 19, 2015, 11:21:56 am »
Je n'ai pas tout compris , mais je pense  qu'il devrait avoir 2 tests : le numéro de l'inter et son état  . Donc la fonction LirePoussoirs n'est pas suffisante.
Je suis part du sketch de jlb que je remercie ( je lui dois des droits d'auteurs !!!!! ) : "huit boutons  huit servos détach .
j'ai fait des modifications afin d' avoir 4 inters ( pin AO ,A3) pour 4 servos (pin 2,5);
Je compile ce sketch , il n'indique aucune erreur . Par contre , je ne peux pas faire d'essais réels d'ou je suis .
J'attends avec impatience tes critiques et conseils
Bonnes fêtes
Philippe

#include <Servo.h>

// Déclaration des constantes spécifiques aux servos
const byte SERVO_A_ANGLE_MIN = 0;
const byte SERVO_A_ANGLE_MAX = 1;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3;
 
const int angleMin = 1250;
const int angleMax = 1750;
 
struct DescripteurServo {
  Servo objetServo;
  int vitesse;
  int angle;
  int pin;
  byte etatServo;
};
 
struct DescripteurServo servoMoteur[4];

const byte NON_PRESSE=0;
const byte ENFONCE = 1;
const byte PRESSE =2;

byte etatAutomate = NON_PRESSE;
int etatPoussoir = -1;
 
const byte AUCUN_EVENEMENT = 0;
const byte EVENEMENT_PRESSE = 1;
const byte EVENEMENT_RELACHE = 2;
 
          const int pinPoussoirs = 0;
 
// Déclaration des variables spécifiques aux inters
boolean ancienA0  = HIGH;
boolean nouveauA0 = HIGH;
boolean ancienA1  = HIGH;
boolean nouveauA1 = HIGH;
boolean ancienA2  = HIGH;
boolean nouveauA2 = HIGH;
boolean ancienA3  = HIGH;
boolean nouveauA3 = HIGH;
int numPoussoir ;

// Calcul du numéro du poussoir
int lirePoussoirs()
{
  int nouvelEtatPoussoir = etatPoussoir; /* à priori rien ne change */
   
  numPoussoir = 4;
 
    nouveauA0 = digitalRead(A0);   
    if (ancienA0 != nouveauA0)
    {
        ancienA0 = nouveauA0;
        numPoussoir = 0;
    }
    else
    {
        nouveauA1 = digitalRead(A1);
        if  (ancienA1 != nouveauA1)
        {
            ancienA1 = nouveauA1;
            numPoussoir = 1;
        }
        else
        {
            nouveauA2 = digitalRead(A2);
            if  (ancienA2 != nouveauA2)
            {
                ancienA2 = nouveauA2;
                numPoussoir = 2;
            }
            else
            {
                nouveauA3 = digitalRead(A3);
                if  (ancienA3 != nouveauA3)
                {
                    ancienA3 = nouveauA3;
                    numPoussoir = 3;
                }                                 
            }
        }
    }
    return nouvelEtatPoussoir;   
}

byte lireEvenement(int *numPoussoir)
{
    byte evenement;
    int nouvelEtatPoussoir = lirePoussoirs();
   
    if (nouvelEtatPoussoir == etatPoussoir)
        evenement = AUCUN_EVENEMENT;
    if (nouvelEtatPoussoir >= 0 && etatPoussoir == -1)
        evenement = EVENEMENT_PRESSE;
    if (nouvelEtatPoussoir == -1 && etatPoussoir >= 0)
        evenement = EVENEMENT_RELACHE;
 
    etatPoussoir = nouvelEtatPoussoir;
    *numPoussoir = etatPoussoir;
   
    return evenement;
}

void setup()
{
// Initialisation des inters
pinMode(A0, INPUT_PULLUP);    //  BP 0
pinMode(A1, INPUT_PULLUP);    //  BP 1
pinMode(A2, INPUT_PULLUP);    //  BP 2
pinMode(A3, INPUT_PULLUP);    //  BP 3

// Initialisation des servos
int numServo;
for (numServo = 0; numServo < 4; numServo++)    {
      servoMoteur[numServo].angle = angleMin;
      servoMoteur[numServo].vitesse = 0;
      servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
      servoMoteur[numServo].pin = numServo + 2;    // pin 2,3,4,5 de la carte NANO
      servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
                                                }
}

void gereServo(int numServo)  // pas de modification !!!!!
{
    servoMoteur[numServo].objetServo.writeMicroseconds(servoMoteur[numServo].angle);
 
    servoMoteur[numServo].angle += servoMoteur[numServo].vitesse;
 
    if (servoMoteur[numServo].angle > angleMax)     {
      servoMoteur[numServo].angle = angleMax;
      servoMoteur[numServo].vitesse = 0;
      servoMoteur[numServo].objetServo.detach();
      servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX;
                                                     }
    else if (servoMoteur[numServo].angle < angleMin) {
      servoMoteur[numServo].angle = angleMin;
      servoMoteur[numServo].vitesse = 0;
      servoMoteur[numServo].objetServo.detach();
      servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
                                                     }
}

void evenementServo(int numServo) // pas de modification !!!!!
{
    switch (servoMoteur[numServo].etatServo) {
      case SERVO_A_ANGLE_MIN:
        servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
        servoMoteur[numServo].vitesse =  1;
        servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
        break;
      case SERVO_A_ANGLE_MAX:
        servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
        servoMoteur[numServo].vitesse = -1;
        servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
        break;
                                             }
}
 
void loop() // pas de modification !!!!!!
{
    int numServo;
 
    for (numServo = 0; numServo < 8; numServo++) gereServo(numServo);
 
    byte evenement = lireEvenement(&numServo);
 
    if (evenement == EVENEMENT_PRESSE) {
        evenementServo(numServo);
    }
 
    delay(3);
}


« Modifié: décembre 28, 2015, 08:13:26 pm par phillippe 31 »

DDEFF

  • Hero Member
  • *****
  • Messages: 738
    • Voir le profil
Re : commande servo par inter
« Réponse #7 le: décembre 19, 2015, 02:29:44 pm »
Aïe !

Bien sûr, il faut le numéro du poussoir et son état...
Mais tu as supprimé l'état !...  :( :(

Le numPoussoir tient une seule ligne dans la programme de Jean-Luc : celle cité au début (voir réponse du 17/12).
Et ma proposition vise à changer uniquement cette ligne.
Mais pas à supprimer justement le test d'état, sinon, le "return nouvelEtatPoussoir;" n'est jamais mis à jour.

Regarde comment c'était avant et compare avec le tien :
int lirePoussoirs()
{
    int resultat;
    int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;
   
    int nouvelEtatPoussoir = etatPoussoir; /* à priori rien ne change */
 
    switch (etatAutomate) {
        case NON_PRESSE:
            if (numPoussoir < 8)
                etatAutomate = ENFONCE;
            break;
        case ENFONCE:
            if (numPoussoir < 8) {
                etatAutomate = PRESSE;
                nouvelEtatPoussoir = numPoussoir;
            }
            else {
                etatAutomate = NON_PRESSE;
            }
            break;
        case PRESSE:
            if (numPoussoir == 8) {
                etatAutomate = NON_PRESSE;
                nouvelEtatPoussoir = -1;
            }
            break;
    }
   
    return nouvelEtatPoussoir;
}
Il n'y a qu'une seule ligne à changer.
Et à modifier les 8 en 4 dans le switch{...}

Ce n'était donc pas ça que j'ai laissé comme problème à trouver.

Autre chose : tu mets, en face du loop() "aucune modification".
Si, il y en a. Je t'ai même dit laquelle.

Dernière remarque : quand tu cites du code Arduino, il y a un bouton au dessus du texte (celui avec un #) qui permet d'insérer du code sans prendre toute la place.
Tu as un autre bouton, au dessus de ta réponse, qui te permettra de modifier ton message pour remettre tout le code dans une fenêtre.
Cela sera ainsi plus lisible pour tout le monde.

Bonne vacances !

« Modifié: décembre 19, 2015, 02:32:54 pm par DDEFF »
"Ce n'est pas le puits qui est trop profond, c'est ta corde qui est trop courte" (proverbe chinois)

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
Re : commande servo par inter
« Réponse #8 le: décembre 28, 2015, 08:18:27 pm »
Bonnes fêtes de fin d'année à tous les membres

 Désolé pour les désagréments de présentation sur le forum

DDEF , j’ai travaillé sur le projet mais je n’ai guère avancé . Je n’ai pas trouvé le problème à résoudre

J’utilise le sketch « Programme Arduino avec coupure de la commande PWM » que je copie sur le blog de jlb

Je ne comprends pas les fonctions « LirePoussoir » et « Lire evenement »

Afin de voir le fonctionnement, j’ai réalisé le schéma du blog de jlb « Plusieurs boutons poussoir sur une entrée analogique »

Et là , je me rends compte que ce n’est pas vraiment le fonctionnement que je désire ( en plus des 4 inters )

Le sketch que je souhaite est :
-   Déclarations des constantes nécessaires

-   Void setup :
Initialisation des servos   ( angle min  , vitesse nulle , état à angle min , affectation de la pin( numservo+2) , attache à la pin )
Initialisation des inters (pullup sur A0 ,A1,A2,A3 )

-   Void événément servo P   : on attache le servo
                            : on impose la vitesse à 1
                            : on impose l’état Servo en movement vers angle max
             
-   Void événement servo NP    : on attache le servo
                            : on impose la vitesse à 1
                            : on impose l’état Servo en movement vers angle min

-   Fonction à étudier    : Lit l’inter qui a changé de position (O ou F)
                          : test changement d’état (pressé , non pressé )

Void gerer servo    : permet le mouvement de servo ( writMicroseconds
                 : test la valeur de l’angle
                        : positionne à Max ou Min
                 : désactive la connection
                 : modifie l’angle , état du servo , et la vitesse

-   Void loop

Du servo 0 à servo 3 donc <4 ,
on va dans « gerer servo »    
on va dans « fonction à étudier »   
-   Test l’inter et son état :   Si pressé on va dans « événement Servo P                
                                           Si non pressé on va dans « événement Servo NP
Tempo


Je pense pouvoir créer «  événément servo P » et » « en événément servo NP »   en modifiant modifier « évènement servo » . Je mettrai le sketch  la semaine prochaine

Mon énorme problème est de :
    trouver l’inter concerné ( 0 ,1 , 2 ou 3) : tu m’as résolu cette difficulté
    de savoir son état ( repos ou travail ) (contact permanent)
    déclaré 2 variables ( pressé ) et ( non pressé )

Merci d’avance pour ton aide

Cordialement
Philippe
« Modifié: décembre 28, 2015, 08:22:11 pm par phillippe 31 »

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
Re : commande servo par inter
« Réponse #9 le: décembre 31, 2015, 01:19:37 pm »
J’ai chargé ce skecth avec 4 inters afin de voir le fonctionnement, et bien sur, je ne peux lire le numéro du poussoir
J’ai fait plusieurs manipulations : suppression de la fonction  « LirePoussoirs », de la variable resultat , déplacement des variables « resultat » , « numPoussoir » dans setup , loop .

Je ne maitrise pas la programmation pour résoudre seul ce problème

boolean ancienA0  = HIGH;
boolean nouveauA0 = HIGH;
boolean ancienA1  = HIGH;
boolean nouveauA1 = HIGH;
boolean ancienA2  = HIGH;
boolean nouveauA2 = HIGH;
boolean ancienA3  = HIGH;
boolean nouveauA3 = HIGH;

int lirePoussoirs()
 {
 int resultat;
     int numPoussoir=4;

    nouveauA0 = digitalRead(A0);   
    if (ancienA0 != nouveauA0)
    {
        ancienA0 = nouveauA0;
        numPoussoir = 0;
    }
    else
    {
        nouveauA1 = digitalRead(A1);
        if  (ancienA1 != nouveauA1)
        {
            ancienA1 = nouveauA1;
            numPoussoir = 1;
        }
        else
        {
            nouveauA2 = digitalRead(A2);
            if  (ancienA2 != nouveauA2)
            {
                ancienA2 = nouveauA2;
                numPoussoir = 2;
            }
            else
            {
                nouveauA3 = digitalRead(A3);
                if  (ancienA3 != nouveauA3)
                {
                    ancienA3 = nouveauA3;
                    numPoussoir = 3;
                }                                 
            }
        }
    }
    return resultat;
    }
void setup()
{
 
     Serial.begin(9600);
}

void loop()
{

  byte evenement = lirePoussoirs();
 
Serial.print("N° inter : ");

Serial.println(lirePoussoirs());

Serial.println(resultat);

delay(100);
}
J’ai réalisé , en modifiant celui de jlb «  un servo un inter » , un programme que j’installe sur des ATtiny 85
Ce programme est superbe , cela crée un mouvement très réaliste de l’aiguille
#include "Servo8Bit2.h"

const byte SERVO_A_ANGLE_MIN = 0;     
const byte SERVO_A_ANGLE_MAX = 1;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3;

const boolean DROIT = true;         
const boolean DEVIE = false;

Servo8Bit2 monServo;
int vitesse = 1;
int angle;
byte etatServo = SERVO_A_ANGLE_MIN;   

const int angleMin = 1250;
const int angleMax = 1720;

boolean etatInter = DEVIE;           
int Led = 3;                           // Led TCO sur patte 2 ATtiny 85
int pinInter = 0;                      // Interrupteur sur patte 5 ATtiny 85
int etatcontact;

boolean lireInter()                   
{
  boolean resultat ;                 
  etatcontact = digitalRead(pinInter);

  if (etatcontact == HIGH) {           
    resultat = DROIT;                 
  }
  else  resultat = DEVIE;             
}
void setup()
{
  pinMode(Led,OUTPUT);                 
  monServo.attach(1);                   // Servo sur patte 6 ATtiny 85
  angle = angleMin;
  vitesse = 1;
}

void loop()
{
  monServo.writeMicroseconds(angle);
  /* calcule le nouvel angle */
  angle = angle + vitesse;
  if (angle > angleMax) {
    angle = angleMax;
    vitesse = 0;
    monServo.detach();
    etatServo = SERVO_A_ANGLE_MAX;
  }
  else if (angle < angleMin) {
    angle = angleMin;
    vitesse = 0;
    monServo.detach();
    etatServo = SERVO_A_ANGLE_MIN;
  }

  byte evenement = lireInter();
  if (evenement == DROIT)  {
    digitalWrite(Led,1);
    monServo.attach(1);
    switch (etatServo)
    {
      case SERVO_A_ANGLE_MIN:
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
        vitesse =  1;
        etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
        break;
    }
  }
  if (evenement == DEVIE) {
    digitalWrite(Led,0);
    monServo.attach(1);
    switch (etatServo)
    {
      case SERVO_A_ANGLE_MAX:
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
        vitesse = -1;
        etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
        break;
    }
  }
  delay(2);
}
Mon objectif est d’installer ce programme sur carte nano , mais avec 4 commandes
En reprenant le skecth de jlb et les remarques de DDEF  et après avoir réalisé la manip d’essai des 8 inters sur une entrée , je suis arrivé à ce début( semblant) de programme :

// A PRIORI PAS DE MODIFICATION
#include <Servo.h>
 
const byte SERVO_A_ANGLE_MIN = 0;
const byte SERVO_A_ANGLE_MAX = 1;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3;

const boolean DROIT = true;     // MODIFICATION PROG     
const boolean DEVIE = false;    // MODIFICATION PROG
 
const int angleMin = 1250;
const int angleMax = 1750;
 
struct DescripteurServo {
  Servo objetServo;
  int vitesse;
  int angle;
  int pin;
  byte etatServo;
};

struct DescripteurServo servoMoteur[4];
 
const byte NON_PRESSE = 0;
const byte ENFONCE = 1;
const byte PRESSE = 2;
 
byte etatAutomate = NON_PRESSE;
int etatPoussoir = -1;
 
const byte AUCUN_EVENEMENT = 0;
const byte EVENEMENT_PRESSE = 1;
const byte EVENEMENT_RELACHE = 2;

//variable pour les inters

boolean ancienA0  = HIGH;
boolean nouveauA0 = HIGH;
boolean ancienA1  = HIGH;
boolean nouveauA1 = HIGH;
boolean ancienA2  = HIGH;
boolean nouveauA2 = HIGH;
boolean ancienA3  = HIGH;
boolean nouveauA3 = HIGH;

                        //const int pinPoussoirs = 0; // A SUPPRIMER

// MODIFICATION DE LirePoussoirs et Lire Evenement AFIN D’AVOIR LE NUMERO
// ET L’ETAT DE L’INTER

   int lirePoussoirs()
  {
    int resultat;
 //  int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;  //  A SUPPRIMER

    numPoussoir = 4;                     // Ou faut il déclarer numPoussoir ?

    nouveauA0 = digitalRead(A0);   
    if (ancienA0 != nouveauA0)
    {
        ancienA0 = nouveauA0;
        numPoussoir = 0;
    }
    else
    {
        nouveauA1 = digitalRead(A1);
        if  (ancienA1 != nouveauA1)
        {
            ancienA1 = nouveauA1;
            numPoussoir = 1;
        }
        else
        {
            nouveauA2 = digitalRead(A2);
            if  (ancienA2 != nouveauA2)
            {
                ancienA2 = nouveauA2;
                numPoussoir = 2;
            }
            else
            {
                nouveauA3 = digitalRead(A3);
                if  (ancienA3 != nouveauA3)
                {
                    ancienA3 = nouveauA3;
                    numPoussoir = 3;
                }                                 
            }
        }
    }

    int nouvelEtatPoussoir = etatPoussoir; /* à priori rien ne change */
 
    switch (etatAutomate) {
        case NON_PRESSE:
            if (numPoussoir < 4)
                etatAutomate = ENFONCE;
            break;
        case ENFONCE:
            if (numPoussoir < 4) {
                etatAutomate = PRESSE;
                nouvelEtatPoussoir = numPoussoir;
            }
            else {
                etatAutomate = NON_PRESSE;
            }
            break;
        case PRESSE:
            if (numPoussoir == 4) {
                etatAutomate = NON_PRESSE;
                nouvelEtatPoussoir = -1;
            }
            break;
    }
   
    return nouvelEtatPoussoir;
}

byte lireEvenement(int *numPoussoir)
{
    byte evenement;
    int nouvelEtatPoussoir = lirePoussoirs();
   
    if (nouvelEtatPoussoir == etatPoussoir)
        evenement = AUCUN_EVENEMENT;
    if (nouvelEtatPoussoir >= 0 && etatPoussoir == -1)
        evenement = EVENEMENT_PRESSE;
    if (nouvelEtatPoussoir == -1 && etatPoussoir >= 0)
        evenement = EVENEMENT_RELACHE;
 
    etatPoussoir = nouvelEtatPoussoir;
    *numPoussoir = etatPoussoir;
   
    return evenement;
}

// A PRIORI PAS DE MODIFICATION
void setup()
{
    /* Initialisation des servos */
    int numServo;
 
    for (numServo = 0; numServo < 4; numServo++) {
        servoMoteur[numServo].angle = angleMin;
        servoMoteur[numServo].vitesse = 0;
        servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
        servoMoteur[numServo].pin = numServo + 2;
        servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
                                                 }                                       
       /* Initialisation des inters */ 
    pinMode(A0, INPUT_PULLUP);    //  BP 0
    pinMode(A1, INPUT_PULLUP);    //  BP 1
    pinMode(A2, INPUT_PULLUP);    //  BP 2
    pinMode(A3, INPUT_PULLUP);    //  BP 3     
}
// A PRIORI PAS DE MODIFICATION

void gereServo(int numServo)
{
    servoMoteur[numServo].objetServo.writeMicroseconds(servoMoteur[numServo].angle);
 
    servoMoteur[numServo].angle += servoMoteur[numServo].vitesse;
 
    if (servoMoteur[numServo].angle > angleMax) {
      servoMoteur[numServo].angle = angleMax;
      servoMoteur[numServo].vitesse = 0;
      servoMoteur[numServo].objetServo.detach();
      servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX;
    }
    else if (servoMoteur[numServo].angle < angleMin) {
      servoMoteur[numServo].angle = angleMin;
      servoMoteur[numServo].vitesse = 0;
      servoMoteur[numServo].objetServo.detach();
      servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
    }
}
//MODIFICATION J’AI PRIS DROIT = VERS ANGLE MAX ( A VERIFIER)

void evenementServo DROIT (int numServo)
{
    switch (servoMoteur[numServo].etatServo) {
        servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
        servoMoteur[numServo].vitesse =  1;
        servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
        break;
                                              } 
}

//MODIFICATION J’AI PRIS DEVIE = VERS ANGLE MIN ( A VERIFIER)

void evenementServo DEVIE (int numServo)
{
    switch (servoMoteur[numServo].etatServo) {
        servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
      case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
        servoMoteur[numServo].vitesse = -1;
        servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
        break;
                                              }
}

//MODIFICATION
void loop()
{
    int numServo;
 
    for (numServo = 0; numServo < 4; numServo++) gereServo(numServo);
 
    //  byte evenement = lireEvenement(&numServo);
 
      if (evenement == EVENEMENT_DROIT) {
        evenementServo DROIT(numServo);

     if (evenement == EVENEMENT_DEVIE) {
        evenementServo DEVIE(numServo);
   }
 
    delay(3);
}

Je pense être arrivé au max de mes compétences .
Sans aide , je ne pourrai avancer
Merci d'avance à DDEF

Bonnes fêtes à tous
Philippe

Thierry

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 744
    • Voir le profil
Re : commande servo par inter
« Réponse #10 le: décembre 31, 2015, 02:16:43 pm »
Salut, merci pour tes vœux, et recevez tous aussi mes meilleurs vœux pour cette nouvelle année en espérant qu'elle soit meilleure à tous points de vue que 2015. Ça ne devrait pas  être difficile !

J'ai jeté un coup d’œil à ton code et tenté de le compiler avec l'IDE 1.6.7 .
Il y a effectivement quelques erreurs de syntaxe, mais rien de bien compliqué !

1 : les espaces ne sont pas permis dans les identifiants : nom de fonction, de variable, de structure, etc... C'est la première correction : changer 'evenementServo DEVIE' en 'evenementServo_DEVIE'. Idem pour le DROIT bien sûr.

2 : la déclaration d'une variable consiste à donner un type et un nom. C'était le rôle de la ligne

 int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;

qui faisait à la fois la déclaration  'int numPoussoir' et l'affectation 'numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;'. Le langage C/C++ permet de faire les deux en même temps... Dans ton cas, cela signifie simplement que tu dois écrire

 int numPoussoir = 4;

ou

 int numPoussoir;
 numPoussoir = 4;

pour déclarer la variable numPoussoir en tant que entier, et y affecter 4 comme valeur.

3 : Attention aux accolades et autres parenthèses ou point-virgules ! Le langage est complètement intolérants aux fautes de syntaxe ! Dans loop(), il manquait l'accolade fermante du test sur EVENEMENT_DROIT.

4 : Pour une raison que j'ignore, la ligne

byte evenement = lireEvenement(&numServo);

était en remarque. Comme la variable 'evenement' n'était plus déclarée, les tests qui suivaient sur sa valeur ne pouvaient fonctionner ! Encore une fois, le langage ne permet pas d'approximation et ne peux pas travailler sur quelque chose qui n'est pas déclaré.

5 : Les variables EVENEMENT_DROIT et EVENEMENT_DEVIE n'existent pas !

6 : La ligne

servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);

était dans un 'switch', mais en dehors de tout 'case', ce qui est interdit ! Je l'ai donc sortie du 'switch' sans vraiment savoir quel comportement tu voulais... Parce que le attach ne devrait être fait QUE dans le setup !

7 : Je me suis permis de reformatter ton code avant de le poster ici. Comme l'a dit Denis, un formattage correct ne donne pas un code qui marche, mais un formattage incorrect donne du code difficile à mettre au point, puis à maintenir ! A ce sujet, il y a plusieurs écoles quant au placement des accolades. Certains, comme Jean-Luc, sont partisans du format avec l'accolade ouvrante à la fin de la ligne

if () {
  ...
}

que j'ai longtemps pratiqué et qui permet de gagner une ligne sur celui que je préconise maintenant avec l'accolade ouvrante toute seule sur sa ligne et au niveau du premier caractère de l'instruction associée (if, for, switch...), et avec l'accolade fermante encore seule et sur la même colonne :

if ()
{
  ...
}

il est à mon avis plus simple à lire, mais ce n'est que mon avis. Une fois ton choix fait, tu dois te l'imposer, et toujours formatter ton code en le respectant. La pire des situations étant bien entendu le mélange des deux !

// A PRIORI PAS DE MODIFICATION
#include <Servo.h>
 
const byte SERVO_A_ANGLE_MIN = 0;
const byte SERVO_A_ANGLE_MAX = 1;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3;

const boolean DROIT = true;     // MODIFICATION PROG     
const boolean DEVIE = false;    // MODIFICATION PROG
 
const int angleMin = 1250;
const int angleMax = 1750;
 
struct DescripteurServo {
  Servo objetServo;
  int vitesse;
  int angle;
  int pin;
  byte etatServo;
};

struct DescripteurServo servoMoteur[4];
 
const byte NON_PRESSE = 0;
const byte ENFONCE = 1;
const byte PRESSE = 2;
 
byte etatAutomate = NON_PRESSE;
int etatPoussoir = -1;
 
const byte AUCUN_EVENEMENT = 0;
const byte EVENEMENT_PRESSE = 1;
const byte EVENEMENT_RELACHE = 2;

//variable pour les inters

boolean ancienA0  = HIGH;
boolean nouveauA0 = HIGH;
boolean ancienA1  = HIGH;
boolean nouveauA1 = HIGH;
boolean ancienA2  = HIGH;
boolean nouveauA2 = HIGH;
boolean ancienA3  = HIGH;
boolean nouveauA3 = HIGH;

                        //const int pinPoussoirs = 0; // A SUPPRIMER

// MODIFICATION DE LirePoussoirs et Lire Evenement AFIN D’AVOIR LE NUMERO
// ET L’ETAT DE L’INTER

int lirePoussoirs()
{
  int resultat;
//  int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;  //  A SUPPRIMER

  int numPoussoir = 4;                     // Ou faut il déclarer numPoussoir ?

  nouveauA0 = digitalRead(A0);   
  if (ancienA0 != nouveauA0)
  {
    ancienA0 = nouveauA0;
    numPoussoir = 0;
  }
  else
  {
    nouveauA1 = digitalRead(A1);
    if (ancienA1 != nouveauA1)
    {
      ancienA1 = nouveauA1;
      numPoussoir = 1;
    }
    else
    {
      nouveauA2 = digitalRead(A2);
      if (ancienA2 != nouveauA2)
      {
        ancienA2 = nouveauA2;
        numPoussoir = 2;
      }
      else
      {
        nouveauA3 = digitalRead(A3);
        if  (ancienA3 != nouveauA3)
        {
          ancienA3 = nouveauA3;
          numPoussoir = 3;
        }                                 
      }
    }
  }

  int nouvelEtatPoussoir = etatPoussoir; /* à priori rien ne change */
 
  switch (etatAutomate)
  {
    case NON_PRESSE:
      if (numPoussoir < 4)
        etatAutomate = ENFONCE;
      break;
     
    case ENFONCE:
      if (numPoussoir < 4)
      {
        etatAutomate = PRESSE;
        nouvelEtatPoussoir = numPoussoir;
      }
      else
        etatAutomate = NON_PRESSE;
       
      break;
     
    case PRESSE:
      if (numPoussoir == 4)
      {
        etatAutomate = NON_PRESSE;
        nouvelEtatPoussoir = -1;
      }
      break;
  }
   
  return nouvelEtatPoussoir;
}

byte lireEvenement(int *inpNumPoussoir)
{
  byte evenement;
  int nouvelEtatPoussoir = lirePoussoirs();
   
  if (nouvelEtatPoussoir == etatPoussoir)
    evenement = AUCUN_EVENEMENT;
  if (nouvelEtatPoussoir >= 0 && etatPoussoir == -1)
    evenement = EVENEMENT_PRESSE;
  if (nouvelEtatPoussoir == -1 && etatPoussoir >= 0)
    evenement = EVENEMENT_RELACHE;
 
  etatPoussoir = nouvelEtatPoussoir;
  *inpNumPoussoir = etatPoussoir;
   
  return evenement;
}

// A PRIORI PAS DE MODIFICATION
void setup()
{
  /* Initialisation des servos */
  int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
  {
    servoMoteur[numServo].angle = angleMin;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
    servoMoteur[numServo].pin = numServo + 2;
    servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  }
 
  /* Initialisation des inters */ 
  pinMode(A0, INPUT_PULLUP);    //  BP 0
  pinMode(A1, INPUT_PULLUP);    //  BP 1
  pinMode(A2, INPUT_PULLUP);    //  BP 2
  pinMode(A3, INPUT_PULLUP);    //  BP 3     
}

// A PRIORI PAS DE MODIFICATION
void gereServo(int numServo)
{
  servoMoteur[numServo].objetServo.writeMicroseconds(servoMoteur[numServo].angle);
 
  servoMoteur[numServo].angle += servoMoteur[numServo].vitesse;
 
  if (servoMoteur[numServo].angle > angleMax)
  {
    servoMoteur[numServo].angle = angleMax;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].objetServo.detach();
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX;
  }
  else
    if (servoMoteur[numServo].angle < angleMin)
    {
    servoMoteur[numServo].angle = angleMin;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].objetServo.detach();
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
    }
}

//MODIFICATION J’AI PRIS DROIT = VERS ANGLE MAX ( A VERIFIER)
void evenementServo_DROIT (int numServo)
{
  servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  switch (servoMoteur[numServo].etatServo)
  {
    case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
      servoMoteur[numServo].vitesse =  1;
      servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
      break;
  } 
}

//MODIFICATION J’AI PRIS DEVIE = VERS ANGLE MIN ( A VERIFIER)
void evenementServo_DEVIE (int numServo)
{
  servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  switch (servoMoteur[numServo].etatServo)
  {
    case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
      servoMoteur[numServo].vitesse = -1;
      servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
      break;
  }
}

//MODIFICATION
void loop()
{
  int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
    gereServo(numServo);
 
  byte evenement = lireEvenement(&numServo);
 
  if (evenement == EVENEMENT_PRESSE)
    evenementServo_DROIT(numServo);

  if (evenement == EVENEMENT_RELACHE)
    evenementServo_DEVIE(numServo);
 
  delay(3);
}

DDEFF

  • Hero Member
  • *****
  • Messages: 738
    • Voir le profil
Re : commande servo par inter
« Réponse #11 le: décembre 31, 2015, 03:28:50 pm »
Merci Thierry !
Bons vœux aussi, bien sûr !

Le problème que j'avais (volontairement) laissé est toujours d'actualité ... ;D

En fait, j'avais remplacé l'unique ligne de Jean-Luc par 33 (!) lignes pour lire tes 4 poussoirs.

Et la détection se fait en regardant les changements d'état et on voit qu'on a appuyé sur un BP parce qu'avant il était à HIGH et que, maintenant qu'on a appuyé, il est à LOW.
Et ça fonctionne, ... et même trop bien !
Parce que quand on relâche le BP, il change aussi d'état en passant cette fois de LOW à HIGH !

Donc, on le détecte un changement une deuxième fois et, là, à tort.

L'idée est donc de compléter, par exemple :

if (ancienA0 != nouveauA0)
{
    ancienA0 = nouveauA0;
    numPoussoir = 0;
}

par :

if (ancienA0 != nouveauA0)

    ancienA0 = nouveauA0;
    if (nouveauA0 == LOW)
    {
        numPoussoir = 0;
    }
}

On garde bien le changement d'état, parce que le deuxième test n'a lieu qu'après.
C'est normal, il faut bien suivre les changements d'état.

Mais on ne change le numPoussoir que si on a appuyé sur le BP, et pas quand on le relâche.

Il faut donc faire les modifications pour les autres BP, comme A0 que je viens de donner. Je te laisse les faire, c'est en forgeant, etc...

Concernant les accolades, une bonne partie des programmes fait comme Jean-Luc, avec l'accolade juste derrière le if.
Moi, je préfère mettre l'accolade juste en dessous, ça me parait plus clair et plus aéré.

Donc, actuellement, tu as un programme mixte avec les deux façons.
Je rejoins Thierry et j'abonde dans sa remarque : on choisit une méthode et on s'y tient.

Bon courage !
Tu y es presque.  ;D
"Ce n'est pas le puits qui est trop profond, c'est ta corde qui est trop courte" (proverbe chinois)

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
Re : commande servo par inter
« Réponse #12 le: janvier 02, 2016, 10:12:15 am »
Meilleurs vœux à tous les membres pour cette année 2016 et longue vie à ce forum

J'ai modifié le code suivant vos remarques .
// Déclaration des variables pour les servomoteurs
#include <Servo.h>
 
const byte SERVO_A_ANGLE_MIN = 0;
const byte SERVO_A_ANGLE_MAX = 1;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3;

const boolean DROIT = true;   
const boolean DEVIE = false;   
 
const int angleMin = 1250;
const int angleMax = 1750;
 
struct DescripteurServo {
  Servo objetServo;
  int vitesse;
  int angle;
  int pin;
  byte etatServo;
                       };

struct DescripteurServo servoMoteur[4];
 
const byte NON_PRESSE = 0;
const byte ENFONCE = 1;
const byte PRESSE = 2;
 
byte etatAutomate = NON_PRESSE;
int etatPoussoir = -1;
 
const byte AUCUN_EVENEMENT = 0;
const byte EVENEMENT_PRESSE = 1;
const byte EVENEMENT_RELACHE = 2;

// Déclaration des variables pour les bistables

boolean ancienA0  = HIGH;
boolean nouveauA0 = HIGH;
boolean ancienA1  = HIGH;
boolean nouveauA1 = HIGH;
boolean ancienA2  = HIGH;
boolean nouveauA2 = HIGH;
boolean ancienA3  = HIGH;
boolean nouveauA3 = HIGH;

// Lecture du numéro de bistable
int lirePoussoirs()
{
  int resultat;

  int numPoussoir = 4;                   

  nouveauA0 = digitalRead(A0);   
  if (ancienA0 != nouveauA0)
  {
    ancienA0 = nouveauA0;
    if (nouveauA0==LOW);
    {
     numPoussoir = 0;
    }
  }
  else
  {
    nouveauA1 = digitalRead(A1);
    if (ancienA1 != nouveauA1)
    {
      ancienA1 = nouveauA1;
      if (nouveauA1==LOW);
      {
       numPoussoir = 1;
      }   
    }
    else
    {
       nouveauA2 = digitalRead(A2);
    if (ancienA2 != nouveauA2)
    {
      ancienA2= nouveauA2;
      if (nouveauA2==LOW);
      {
       numPoussoir = 2;
      }   
    }
    else
      {
        nouveauA3 = digitalRead(A3);
    if (ancienA3 != nouveauA3)
    {
      ancienA3 = nouveauA3;
      if (nouveauA3==LOW);
      {
       numPoussoir = 3;
      }   
    }                                   
      }
    }
  }

  int nouvelEtatPoussoir = etatPoussoir;
 
  switch (etatAutomate)
  {
    case NON_PRESSE:
      if (numPoussoir < 4)
        etatAutomate = ENFONCE;
      break;
     
    case ENFONCE:
      if (numPoussoir < 4)
      {
        etatAutomate = PRESSE;
        nouvelEtatPoussoir = numPoussoir;
      }
      else
        etatAutomate = NON_PRESSE;
       
      break;
     
    case PRESSE:
      if (numPoussoir == 4)
      {
        etatAutomate = NON_PRESSE;
        nouvelEtatPoussoir = -1;
      }
      break;
  }
   
  return nouvelEtatPoussoir;
}

byte lireEvenement(int *inpNumPoussoir)
{
  byte evenement;
  int nouvelEtatPoussoir = lirePoussoirs();
   
  if (nouvelEtatPoussoir == etatPoussoir)
    evenement = AUCUN_EVENEMENT;
  if (nouvelEtatPoussoir >= 0 && etatPoussoir == -1)
    evenement = EVENEMENT_PRESSE;
  if (nouvelEtatPoussoir == -1 && etatPoussoir >= 0)
    evenement = EVENEMENT_RELACHE;
 
  etatPoussoir = nouvelEtatPoussoir;
  *inpNumPoussoir = etatPoussoir;
   
  return evenement;
}

void setup()
{
   /* Initialisation des servos */
   int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
  {
    servoMoteur[numServo].angle = angleMin;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
    servoMoteur[numServo].pin = numServo + 2;
    servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  }
 
  /* Initialisation des bistables */
  pinMode(A0, INPUT_PULLUP);    //  BP 0
  pinMode(A1, INPUT_PULLUP);    //  BP 1
  pinMode(A2, INPUT_PULLUP);    //  BP 2
  pinMode(A3, INPUT_PULLUP);    //  BP 3     
}

void gereServo(int numServo)
{
  servoMoteur[numServo].objetServo.writeMicroseconds(servoMoteur[numServo].angle);
 
  servoMoteur[numServo].angle += servoMoteur[numServo].vitesse;
 
  if (servoMoteur[numServo].angle > angleMax)
  {
    servoMoteur[numServo].angle = angleMax;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].objetServo.detach();
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX;
  }
  else
    if (servoMoteur[numServo].angle < angleMin)
    {
    servoMoteur[numServo].angle = angleMin;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].objetServo.detach();
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
    }
}

void evenementServo_DROIT (int numServo)
{
  servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  switch (servoMoteur[numServo].etatServo)
  {
    case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
      servoMoteur[numServo].vitesse =  1;
      servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
      break;
  }
}

void evenementServo_DEVIE (int numServo)
{
  servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  switch (servoMoteur[numServo].etatServo)
  {
    case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
      servoMoteur[numServo].vitesse = -1;
      servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
      break;
  }
}

void loop()
{
  int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
    gereServo(numServo);
 
  byte evenement = lireEvenement(&numServo);
 
  if (evenement == EVENEMENT_PRESSE)
    evenementServo_DROIT(numServo);

  if (evenement == EVENEMENT_RELACHE)
    evenementServo_DEVIE(numServo);
   
  delay(3);
}
Bien sûr , j'arrive a le compiler mais il ne marche toujours pas .
Comme je vous l'ai dit précédemment , je ne sais pas programmer . Je n'ai donc pas trouver la solution , d'ailleurs , je ne sais quoi chercher.
Désolé DDEF , mais comme tu le précisais dans ton message du 18 décembre , je t'appelle à l'aide.
Cordialement

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1691
    • Voir le profil
Re : commande servo par inter
« Réponse #13 le: janvier 02, 2016, 11:13:18 am »
Bonjour et meilleurs vœux pour 2016.

Bon, si j'ai bien compris tu souhaites remplacer les 8 poussoirs par 4 interrupteurs deux positions. Il faut donc 4 broches : A0 à A3 (qui peuvent être utilisées en numérique).

En fait c'est beaucoup plus simple que ce que j'ai écrit, tu n'as pas à gérer un événement (la pression sur le poussoir). Il suffit de lire l'état de l'interrupteur et d'en déduire la vitesse pour chaque servo. Le corollaire est que la fonction lirePoussoirs() ne convient pas dans sa philosophie puisqu'elle est conçue pour ne rendre compte d'un événement sur un seul bouton.

Donc : suppression pure et simple de lireEvenement() et de lirePoussoirs(). Suppression des variables ancienAx et nouveauAx. Déclaration d'un tableau reliant un servo et son numéro à la broche où est connecté l'interrupteur qui le commande :

const byte brocheInterrupteurPourServo[4] = {
  A0,
  A1,
  A2,
  A3
};

Dans setup initialisation de ceci en INPUT_PULLUP

for (byte i = 0; i < 4; i++) {
  pinMode(brocheInterrupteurPourServo[i], INPUT_PULLUP);
}

Dans loop au lieu d'avoir :

void loop()
{
  int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
    gereServo(numServo);
 
  byte evenement = lireEvenement(&numServo);
 
  if (evenement == EVENEMENT_PRESSE)
    evenementServo_DROIT(numServo);

  if (evenement == EVENEMENT_RELACHE)
    evenementServo_DEVIE(numServo);
   
  delay(3);
}

on a :

void loop()
{
  int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
    gereServo(numServo);
 
  for (numServo = 0; numServo < 4; numServo++) {
    byte positionInterrupteur = digitalRead(brocheInterrupteurPourServo[i]);
    if (positionInterrupteur == LOW) {
      evenementServo_DROIT(numServo);
    }
    else {
      evenementServo_DEVIE(numServo);
    }
  }
  delay(3);
}

les fonctions evenementServo_DROIT et evenementServo_DEVIE sont fausses. Lorsque le servo n'est pas en mouvement, le système est bloqué, plus rien ne réagit. Je te laisse corriger ça.
Cordialement

philippe 31

  • Newbie
  • *
  • Messages: 14
    • Voir le profil
Re : commande servo par inter
« Réponse #14 le: janvier 02, 2016, 04:47:56 pm »
Jean Luc , merci  pour ton aide. Beau cadeau d'anniversaire , Eh oui 59 ans!!!!

J'ai repris le code en intégrant tes remarques

// Déclaration des variables pour les servomoteurs
#include <Servo.h>
 
const byte SERVO_A_ANGLE_MIN = 0;
const byte SERVO_A_ANGLE_MAX = 1;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2;
const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3;

const boolean DROIT = true;   
const boolean DEVIE = false;   
 
const int angleMin = 1250;
const int angleMax = 1750;
 
struct DescripteurServo {
  Servo objetServo;
  int vitesse;
  int angle;
  int pin;
  byte etatServo;
                       };

struct DescripteurServo servoMoteur[4];
 
const byte NON_PRESSE = 0;
const byte ENFONCE = 1;
const byte PRESSE = 2;
 
byte etatAutomate = NON_PRESSE;
int etatPoussoir = -1;
 
const byte AUCUN_EVENEMENT = 0;
const byte EVENEMENT_PRESSE = 1;
const byte EVENEMENT_RELACHE = 2;

// Déclaration des variables pour les bistables
 int i;
 const byte brocheInterrupteurPourServo[4] =
 {
  A0,
  A1,
  A2,
  A3
  };

// Lecture du numéro de bistable


void setup()
{
   /* Initialisation des servos */
   int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
  {
    servoMoteur[numServo].angle = angleMin;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
    servoMoteur[numServo].pin = numServo + 2;
    servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  }
 
  /* Initialisation des bistables */
 
for (byte i = 0; i < 4; i++)
  {
   pinMode(brocheInterrupteurPourServo[i], INPUT_PULLUP);
  }   
}

void gereServo(int numServo)
{
  servoMoteur[numServo].objetServo.writeMicroseconds(servoMoteur[numServo].angle);
 
  servoMoteur[numServo].angle += servoMoteur[numServo].vitesse;
 
  if (servoMoteur[numServo].angle > angleMax)
  {
    servoMoteur[numServo].angle = angleMax;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].objetServo.detach();
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX;
  }
  else
    if (servoMoteur[numServo].angle < angleMin)
    {
    servoMoteur[numServo].angle = angleMin;
    servoMoteur[numServo].vitesse = 0;
    servoMoteur[numServo].objetServo.detach();
    servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN;
    }
}

void evenementServo_DROIT (int numServo)
{
  servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  switch (servoMoteur[numServo].etatServo)
  {
    case SERVO_A_ANGLE_MIN:
    case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN:
      servoMoteur[numServo].vitesse =  1;
      servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX;
      break;
  }
}

void evenementServo_DEVIE (int numServo)
{
  servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin);
  switch (servoMoteur[numServo].etatServo)
  {
    case SERVO_A_ANGLE_MAX:
    case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX:
      servoMoteur[numServo].vitesse = -1;
      servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN;
      break;
  }
}

void loop()
{
  int numServo;
 
  for (numServo = 0; numServo < 4; numServo++)
    gereServo(numServo);
   
    for (numServo = 0; numServo < 4; numServo++)
    {
    byte positionInterrupteur = digitalRead(brocheInterrupteurPourServo[i]);
   
    if (positionInterrupteur == LOW) {
      evenementServo_DROIT(numServo);
                                      }
    else                              {
      evenementServo_DEVIE(numServo);
                                      }
     }
 
  delay(3);
}
J'ai modifié les fonctions   evenementServo_DROIT et evenementServo_GAUCHE
J'ai réalisé le montage avec 3 inters et 3 servos. Les servos fonctionnent bien , vont de droite à gauche et vis versa .
Le seul problème est que les servos sont commandés par l'inter A0 , les autres inters A1 et A2 sont à priori inertes.
Je ne pens pas avoir fait un mauvais montage !!
Salutations