IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Commander un servomoteur à partir du moniteur série. Ca marche, mais pourquoi ?


Sujet :

Arduino

  1. #1
    Membre à l'essai
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2023
    Messages : 4
    Par défaut Commander un servomoteur à partir du moniteur série. Ca marche, mais pourquoi ?
    Bonjour,
    Je débute sur Arduino.

    Pour mes élèves, j'ai branché un mini servomoteur (9g) sur une carte Arduino et je peux le commander en position avec un potentiomètre. Tout fonctionne !!!

    Ensuite, je voulais tout simplement commander un servomoteur en position à partir du moniteur série.
    Malheureusement, le servomoteur revient systématiquement à 0 après s'être déplacé. Grrrrr

    Par erreur, je rajoute une ligne (ligne 26) et là ça marche.
    Est-ce que l'un d'entre vous pourrait d'expliquer pourquoi et comment je pourrai supprimer cette instruction qui me parait inutile ?

    Merci de votre aide,
    Philippe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    #include <Servo.h>
     
    Servo monservo;  // create servo object to control a servo
     
    int servopin = 9;  // analog pin used to connect the servo
    int angle;  
     
    void setup() {
      Serial.begin(9600);
      monservo.attach(servopin);  // attaches the servo  to the servo object
    }
     
    void loop() {
     
      Serial.println("Entrez un angle entre 0 et 180 :");
      while (Serial.available() == 0) {}
     
      if (Serial.available() != 0) {
        angle = Serial.parseInt();
        monservo.write(angle);
        delay(500);
        Serial.print("valeur de l'angle après l'envoi de l'angles au servo : ");
        Serial.println(angle);
     
        angle = Serial.parseInt();  // A quoi sert cette ligne ? Comment la supprimer ?
      }
    }

  2. #2
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 019
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 019
    Par défaut
    Bonjour Phil2p

    Dans les paramètres du moniteur, il faut mettre pas de fin de ligne.
    En effet, Serial.parseInt() extrait le chiffre trouvé dans le buffer et, donc, s'arrête dèsd qu'il trouve un octet "non digita2. Après ça, il reste, dans le buffer que le ou les caractères de fin de ligne.
    Au prochain tour du fait de ces "restes",
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (Serial.available()
    est encore vrai, sans que Serial.parseInt() trouve de chiffre(s) dans le buffer donc angle = 0.

    Cordialement
    jpbbricole

  3. #3
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 935
    Par défaut
    C’est le souci avec les fonctions de parseXXX fournies par Arduino. Quand elles ne trouvent pas ce qu’on attend, il y a un timeout et ça retourne quand même une valeur et on ne sait pas si ça a planté ou si l’utilisateur a vraiment rentré 0 par exemple dans votre cas

    Pour un usage simple c’est OK mais elles ne sont pas à recommander pour des usages plus avancés (aussi parce que ce sont des appels bloquants).

  4. #4
    Membre à l'essai
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2023
    Messages : 4
    Par défaut
    Merci beaucoup pour vos explications. Je crois avoir compris.

    Je comptais donner à mes élèves ce bout de code pour tester le montage d'un servomoteur sur une pince de robot.
    Auriez-vous une solution simple à ce problème car j'aurai du mal à justifier cette ligne de code supplémentaire à mes élèves.
    On ne sait jamais, si l'un d'entre eux s'y intéresse...

    Philippe

  5. #5
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 935
    Par défaut
    Faites comme @jpbricole a dit, vous réglez le moniteur série pour ne pas envoyer de caractères supplémentaires lorsque vous validez votre entrée
    Ainsi vous n’aurez que le nombre dans le buffer d’entrée série.

    Mais si un élève tape hello123coucou bien sûr ça va pas faire ce que vous voulez

  6. #6
    Membre à l'essai
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2023
    Messages : 4
    Par défaut
    Encore merci Jay M et Jpdbricole,

    Auriez-vous une solution directement dans le code qui permette une fonctionnement "normal" du code sans demander aux élèves de modifier les paramètres du moniteur "pas de fin de ligne".
    J'ai peur qu'ils oublient et que je sois obligé de passer parmi les 18 groupes après un "M'sieur, ça marche pas !!!!". ;-)

    Je vous souhaite une bonne journée,
    Philippe

  7. #7
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 019
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 019
    Par défaut
    Bonjour Phil2p
    Citation Envoyé par Phil2p Voir le message
    Auriez-vous une solution directement dans le code qui permette une fonctionnement "normal" du code ...
    Oui, en faisant appel au timout du port série:
    Serial.setTimeout(50);,
    ainsi cela fonctionne qu'il y aie ou pas des caractères de fin.

    ä Serial.readString(), pour lire ce qui a été introduit dans la ligne de commande
    et à .trim() pour enlever tout caractère(s) indésirable(s) tels que cr, lf, espace(s) en début ou en fin etc.

    Cette façon de faire permet de faire évoluer, rapidement, un système de commandes, comme commander des servo en spécifiant quel servo par SBD55 pour servo bras droite à 55°.

    Le programme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #include <Servo.h>
     
    Servo monservo;  // create servo object to control a servo
     
    const int servopin = 9;  // digital pin used to connect the servo
    int angle;
     
    void setup() {
    	Serial.begin(9600);
    	Serial.setTimeout(50);     // Pour fin des commandes depuis le moniteur
    	monservo.attach(servopin);  // attaches the servo  to the servo object
    }
     
    void loop() {
     
    	Serial.println("Entrez un angle entre 0 et 180 :");
    	while (Serial.available() == 0) {};     // Attente de l'introduction de l'angle
     
    	if (Serial.available())
    	{
    		String cmdRecue = Serial.readString();
    		cmdRecue.trim();     // Pour nettoyer la commande reçue
     
    		angle = cmdRecue.toInt();     // Convertir la commande reçue en int
    		monservo.write(angle);     // Envoyer l'angle au servo
    		delay(500);
    		Serial.print("valeur de l'angle apres l'envoi de l'angles au servo : ");
    		Serial.println(angle);
    	}
    }
    Cordialement
    jpbbricole

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 935
    Par défaut
    Bonjour

    le if qui suit le whiled and ce code

    Citation Envoyé par jpbbricole Voir le message

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	while (Serial.available() == 0) {};     // Attente de l'introduction de l'angle
     
    	if (Serial.available())
    	{
    	...
    	}
    }
    est inutile puisque l'on sort du while si et seulement si Serial.available() est non nul, donc le test suivant est toujours vrai. (et le ; fait double emploi avec les {} dans le while)


    sur les arduino ou le chien de garde est activé par défaut, la boucle while (Serial.available() == 0) {} peut faire planter l'arduino. Mettre un delay(1); par exemple dans le while règlera le problème.

    on aura toujours le souci que toInt() répond 0 si on n'arrive pas à lire un entier dans la chaîne et donc on ne sait pas si l'utilsateur a vraiment voulu dire 0 ou si c'est une erreur de saisie. on peut si on veut se prémunir contre cela utiliser strtol() éventuellement (ou tester si le premier caractère de la chaîne est un chiffre ou le + ou le - suivi d'un chiffre)

  9. #9
    Membre Expert
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    Février 2013
    Messages
    1 019
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2013
    Messages : 1 019
    Par défaut
    Binjour Jay M
    Citation Envoyé par Jay M Voir le message
    Bonjour

    le if qui suit le whiled and ce code
    ...
    est inutile puisque l'on sort du while si et seulement si Serial.available() est non nul, donc le test suivant est toujours vrai. (et le ; fait double emploi avec les {} dans le while)
    Oui et non, surtout non, dans ce code, il y a 2 parties bien distinctes, l'invite à entrer un angle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    	Serial.println("Entrez un angle entre 0 et 180 :");
    	while (Serial.available() == 0) {};     // Attente de l'introduction de l'angle
    et la lecture de l'angle introduit par l'opérateur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	if (Serial.available())
    	{
    		......
    	}
    supprimer ce if reviendrai à faire un amalgame des 2 parties ce qui est, à mon avis, une mauvaise option.

    Citation Envoyé par Jay M Voir le message
    on aura toujours le souci que toInt() répond 0 si on n'arrive pas à lire un entier ...
    Quoi que l'on fasse on aura toujours un souci, alors autant faire simple, j'utilise cette méthode quasiment tout le temps, et strtol() ne renvoie que des valeurs numériques, ce qui empêche de faire évoluer les commandes vers du plus complexe mélangeant chiffres et lettres.

    Cordialement
    jpbbricole

  10. #10
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 935
    Par défaut
    bonjour @jpbricole

    c'est votre code, vous l'interprétez comme vous voulez.

    Mon point est simplement de dire
    - le if ne sert à rien. On sait que la condition testée sera toujours vraie à cause du while précédent.
    - le toInt() peut conduire à une erreur d'interprétation. Si on veut gérer le cas où l'utilisateur n'a pas entré un nombre il existe d'autres techniques (strtol, sscanf) qui permettent de le faire.

    concernant votre code, pour moi il y a cinq parties qui sont:

    1/ invitation à entrer un angle
    Serial.println("Entrez un angle entre 0 et 180 :");

    2/ attente bloquante de l'arrivée du premier caractère de la réponse (pour ne pas dépendre du timeout. cela introduit une hypothèse plausible sur le terminal série)
    while (Serial.available() == 0) {}

    3/lecture de la réponse
    String cmdRecue = Serial.readString();

    4/ analyse de la réponse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    cmdRecue.trim();     // Pour nettoyer la commande reçue
    angle = cmdRecue.toInt();     // Convertir la commande reçue en int


    5/ actions en fonction de l'analyse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    monservo.write(angle);     // Envoyer l'angle au servo
    Serial.print("valeur de l'angle : ");
    Serial.println(angle);
    delay(500);



    c'est bien un processus séquentiel que l'on a mis en place, qui dépend du fait que l'on sait que le terminal série arduino envoie le texte tapé d'un seul coup et non pas à chaque touche appuyée par l'utilisateur (d'autres terminaux ont d'autres types de comportement).

    le if après le while fait double emploi, on sait qu'on est sorti de l'attente active parce que un caractère était présent donc ce n'est pas la peine de tester à nouveau.

    Quoi que l'on fasse on aura toujours un souci, alors autant faire simple, j'utilise cette méthode quasiment tout le temps, et strtol() ne renvoie que des valeurs numériques, ce qui empêche de faire évoluer les commandes vers du plus complexe mélangeant chiffres et lettres.
    Non strtol() renvoie à la fois une valeur numérique mais aussi dans endptr (si on l'a fourni) une information capitale sur l'analyse de la chaine qui permet de décider si oui ou non la lecture s'est bien passée. On pourrait aussi utiliser sscanf() si on ne lit qu'un entier, là encore on aura une info sur le succès de la lecture.

    ce qui empêche de faire évoluer les commandes vers du plus complexe mélangeant chiffres et lettres.
    Hum... non, pas plus qu'avec votre code. On a dans le buffer de lecture le texte à analyser. Si vous faites cmdRecue.toInt() vous faites de toutes façons l'hypothèse qu'il y a un entier à lire. Si vous avez autre chose dans le buffer vous pouvez faire d'autres analyses de la même manière.





    personnellement je n'aime pas les fonctions de lecture avec timeout, je préfère la lecture asynchrone qui ne fait pas d'hypothèse pour avoir un code générique, mais je comprends que si l'on vise la simplicité ce soit une option.

  11. #11
    Membre Expert

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 697
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 697
    Par défaut
    Bonjour jpbbricole,

    Citation Envoyé par jpbbricole Voir le message
    ...supprimer ce if reviendrait à faire un amalgame des 2 parties ce qui est, à mon avis, une mauvaise option...
    Je pense que Jay M. a raison, le if vérifie une condition dont on est sûr qu'elle est vrai. Il ne sert donc à rien. Quant à le mettre pour justifier l'identification d'un bloc fonctionnel inévitable, cela ne paraît guère légitime. Une petite ligne en commentaire ferait tout au si bien l'affaire.

    Ceci étant, cela n'empêche pas le bon fonctionnement, d'autant que les optimisations du compilateur peuvent avoir le bon goût de retirer le code inutile.

    Salut

  12. #12
    Membre à l'essai
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2023
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2023
    Messages : 4
    Par défaut
    Merci beaucoup Jpbbricole, Jay M et Guesset pour avoir trouvé une solution à mon problème et avoir pris le temps de m'expliquer.

    Bien cordialement,
    Philippe

Discussions similaires

  1. Réponses: 4
    Dernier message: 28/02/2023, 19h18
  2. Méthode d'interpolation a partir d"une série de valeurs
    Par User dans le forum Algorithmes et structures de données
    Réponses: 55
    Dernier message: 18/03/2008, 10h00
  3. Lancer une commande DOS a partir d'un poste UNIX
    Par sam.fet dans le forum Linux
    Réponses: 7
    Dernier message: 19/05/2006, 15h06
  4. executer une commande dos a partir d'une page WEB
    Par wagga84 dans le forum Langage
    Réponses: 1
    Dernier message: 15/03/2006, 12h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo