Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comment manipuler des objets/class

Sujet résolu
    18 septembre 2017 à 12:08:17

    Bonjour,

    Je suis actuellement le MOOC Arduino ou l'on doit faire un Tp feux rouge (orange 1s, rouge 3s, vert 3s).

    Je suis débutant et j'ai essayé d'abord un code simple puis un tableaux à 2 entrées et dans mes recherches je suis tombé sur la class, donc voici ma première class !

    Par contre j'ai un soucis pour manipuler les objets crées, par exemple comment fait t'on une boucle ?

    c.a.d 

    Pour chaque objet de la class -> faire ceci

    Après moult recherches (je connait trop peu l'anglais) je m'adresse à vous pour m'aider à progresser.

    d'avance merci et bonne journée

    class lampe {
      public:
        lampe(int p,int t);
        void initPin();
        void allumEtteint();
      private:
        int port, temps;
    };
    //fonction pour class lampe
    //constructeur
      lampe::lampe(int p,int t){
         this->port=p;
         this->temps=t;
      };
          void lampe::initPin(){
             pinMode(port, OUTPUT);
          }    
          void lampe::allumEtteint (){
            digitalWrite(port,HIGH);
            delay(temps);
            digitalWrite(port,LOW);
           }       
    lampe ledOrange(7,1000), ledRouge(6,3000), ledVerte(8,3000);

     //ICI je cherche une méthode pour lister les objets crées et pour chaque objet ->faire ceci

     void setup() {  
      ledOrange.initPin();
      ledRouge.initPin();
      ledVerte.initPin();  
    }
    void loop() {
      ledOrange.allumEtteint();
      ledRouge.allumEtteint();
      ledVerte.allumEtteint();
    }



    -
    Edité par SelfFish 18 septembre 2017 à 12:09:10

    • Partager sur Facebook
    • Partager sur Twitter
      18 septembre 2017 à 14:04:41

      Salut,

      Je te déconseillerais déjà de t'attaquer à un projet "adurino" comme premier projet, pour la simple et bonne raison que la programmation embarquée est un domaine tout à fait à part.  J'aurais presque tendance à dire : garde bien ton adurino de coté pendant quelques mois, le temps de t'habituer au principes de programmation, tu auras bien plus de plaisir de ton adurino par la suite.

      Ensuite, la programmation orientée objet implique d'avoir une philosophie toute particulière.  Par exemple, on va partir du principe que ta lampe doit être prête à fonctionner dés le moment où elle est créée.

      Tu ne devrais donc pas avoir cette fonction "initPin" dans ton code, car elle implique que l'utilisateur de la lampe (en fait, toi) doit penser à appeler cette fonction sur chaque lampe qu'il va créer avant de pouvoir l'utiliser.  La loi de finagle aidant, tu peux partir du principe que ce n'est qu'une question de temps avant que tu n'oublies de le faire ;)

      Or, il se fait que cette fonction ne doit être exécutée qu'une seule fois, au moment de la création de ta lampe, et que l'on dispose justement de la fonctionnalité idéale pour "faire quelque chose" au moment de la création d'un objet : c'est son constructeur.

      Place donc ta commande pinMode(port, OUTPU) directement dans ton constructeur.

      De cette manière, tu pourras te contenter de créer tes leds en ayant la certitude qu'elles seront correctement initialisées.

      Ensuite, tu dois te mettre en tête que "nommer, c'est créer" ou, comme disait l'autre

      --Eragon 2006

      Brisingr signifie le feu.  C'est le feu.  Le mot, c'est la chose.  Connait le mot, tu maitrisera la chose

      Or, allumer et éteindre une lampe, ce sont deux faces d'une même pièce, mais il y a une astuce:

      Tu ne peux pas d'avantage allumer une lampe qui est déjà allumée qu'il ne te serait possible d'éteindre une lampe... éteinte. 

      Il serait donc utile de séparer l'allumage et l'extinction, en faisant en sorte que ta lampe sache "dans quel état elle est", de manière à éviter d'essayer d'allumer (respectivement d'éteindre) une lampe qui ... est allumée (respectivement éteinte).

      Tu pourrais donc créer une énumération proche de

      enum LedState{
          OFF,
          ON
      };

      pour désigner cet état et modifier ta classe Led pour quelle prenne la forme (je garde ton code d'origine autant que faire se peut)

      class lampe {
        public:
          lampe(int p,int t);
          void allumer();
          void eteindre()
        private:
          int port;
          LedState state
      };
      //fonction pour class lampe
      //constructeur
      lampe::lampe(int p,int t){
          this->port=p;
          state = OFF;
          pinMode(port, OUTPUT);
      };
      void lampe::allumer(){
          // il n'y a rien à faire si la lampe est allumée
          if(state == OFF){ 
             digitalWrite(port,HIGH);
             state = ON;
          }
      }
      void lampe::eteindre(){
          // il n'y a rien à faire si la lampe est éteinte
          if(state == ON){ 
             digitalWrite(port,LOW);
             state = OFF;
          }
      }

      Quant au clignotement (qui correspond à ce que fait ta fonction allumEteint), poses toi la question de savoir qui doit décider le temps que ta led doit rester allumée?  Est-ce ta led elle-même? ou est il plus sensé de croire que tu voudras qu'elle reste parfois allumée 1 secondes et que tu voudras parfois qu'elle reste allumée 4 secondes (valeurs prises totalement au hasard)?

      Pour faire clignoter ta lampe, tu devrais donc rajouter une fonction "clignoter" à ta classe.  Comme c'est à l'utilisateur de décider de la durée d'allumage lors du clignotement, cette fonction devrait prendre la durée en paramètre.

      Au final, ta classe prendrait la forme de

      class lampe {
        public:
          lampe(int p);
          void allumer();
          void eteindre()
          void clignoter(int duree);
        private:
          int port;
          LedState state
      };
      //fonction pour class lampe
      //constructeur
      lampe::lampe(int p){
          this->port=p;
          state = OFF;
          pinMode(port, OUTPUT);
      };
      void lampe::allumer(){
          // il n'y a rien à faire si la lampe est allumée
          if(state == OFF){ 
             digitalWrite(port,HIGH);
             state = ON;
          }
      }
      void lampe::eteindre(){
          // il n'y a rien à faire si la lampe est éteinte
          if(state == ON){ 
             digitalWrite(port,LOW);
             state = OFF;
          }
      }
      void lampe::clignoter(int duree){
          allumer();
          delay(duree);
          eteindre();
      }

      De cette manière, ta fonction loop (que l'on va renommer "clignoter", car, oui, on peut le faire)pourrait ressembler à quelque chose comme

      void clignoter(lampe & l1, lampe& l2, lampe & l3){
          l1.clignoter(1000);
          l2.clignoter(3000);
          l3.clignoter(4000);
      }

      et le tout serait "chapeauté" par une fonction main qui ressemblerait à

      int main(){
          lampe orange(7);
          lampe rouge(6);
          lampe verte(8);
          while(condition){
              clignoter(orange, rouge, verte);
          }
          return 0;
      }

      Ensuite, parce que je n'en ai pas encore parlé, il faut savoir qu'il y a tout intérêt à utiliser ce que l'on appelle la liste d'initialisation au lieu d'initialiser les membres dans le constructeur ==>un peu de lecture<==.  Si bien que nous allons modifier un tout petit peu le code du constructeur pour lui donner la forme de

      lampe::lampe(int p): port(p), state(OFF){
          pinMode(port, OUTPUT);
      }

      Enfin, il faut savoir que la syntaxe que je viens de donnée est la syntaxe "à l'ancienne", qui a été dépréciée en 2011 avec l'arrivée de C++11 (on en est à C++14 arrivé en 2014, voire C++17 dont l'arrivée est prévue cette année mais qui est déjà implémenté par de nombreux compilateurs).

      La syntaxe recommandée, si ton compilateur supporte au minimum C++11 (sinon, je ne peux que te conseiller de mettre le compilateur à jour, bien que je saches la difficulté que cela représente sous adurino) nécessiterait quelques modifications supplémentaires, dans le constructeur et dans la fonction main pour leur donner une forme finale proche de

      lampe::lampe(int p):port{p}, state{OFF}{
          pinMode(port, OUTPUT);
      }
      int main(){
          lampe orange{7};
          lampe rouge{6};
          lampe verte{8};
          while(condition){
              clignoter(orange, rouge, verte);
          }
          return 0;
      }
      • Partager sur Facebook
      • Partager sur Twitter
      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
        18 septembre 2017 à 18:25:03

        Question bête:

        Le DP singleton ne serait-il pas adapté pour la programmation arduino ?
        Histoire de faire (en apparence), un peut moins "variables global".

        • Partager sur Facebook
        • Partager sur Twitter
          18 septembre 2017 à 22:06:21

          Beurk... Quelle horreur!!!

          Si tu tiens à faire quelque chose qui ait moins l'apparence d'une variable globale, aies au moins la décence de choisir le DP service locator, s'il te plait ;)

          • Partager sur Facebook
          • Partager sur Twitter
          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
            19 septembre 2017 à 6:54:36

            Bonjour Koala01,

            Tout d'abord merci pour ta réponse magistrale ! Premièrement, je veux continuer ma formation sur l’Arduino et en parallèle me perfectionner en programmation. C'est mon premier cours et tout ce que je fais n’était pas nécessaire un code simple suffisait. Mais ce faisant, j'ai pris gout à la programmation du coup beaucoup de temps passés (notamment sur le site de ton lien mais bien d'autres) pour écrire ce code mais que du plaisir. J'ai un métier (viticulteur) et je cours pas après quoi que ce soit c'est juste un jeu.

            Pour ce qui de la fonction init en fait j'y avais pensé je me disais bien que la moindre des choses pour une class est d'initialiser son objet mais ça ne résolvait pas la deuxième boucle du programme dans loop() de plus tous les exemples d’Arduino les ports s'initialisent dans set up alors j'ai pas été plus loin merci en tous les cas car j'ai bien compris que les deux fonctions mise d'origine sont juste la pour aider l'utilisateur.

            Pour la fonction allume éteint j'avais crée une fonction qui inversait son etat comme ça j'avais qu'une seule fonction que ce soit pour allum ou eteint pour le code avec tableaux 2 entrées mais travaillant sur les class je suis parti sur un code plus "simple"

            //fonction inverse l'etat broche digital
            void digitalChangeEtat (int p){
               byte etatBrocheDigit = digitalRead (p);
               // Inverse l'état de la LED
              digitalWrite(p,!etatBrocheDigit);
             }


            Désormais j'utiliserai le boolean comme dans ton exemple (c'est d'une efficacité à toute épreuve, les booleen!). ca evite beaucoup de lignes de code.

            voila ton code n'a pas fini de m'inspirer car j'ai compris que chaque chose à une portée reste à bien comprendre laquelle.

            Pour ce qui est de la version de c, c++ j'en ai aucune  idée d'ailleurs j'avais posté ma question dans le forum C au départ et on m'a dit de plutôt poster ici.

            D'ailleurs pour ceux qui veulent connaitre la réponse à ma question c'est ici:

            https://openclassrooms.com/forum/sujet/manipuler-class-et-objet-arduino

            encore merci et bonne journée.



            • Partager sur Facebook
            • Partager sur Twitter
              19 septembre 2017 à 9:02:37

              Pour la version de C++, il me semble que le compilateur adurino est Gcc, non ?

              Si oui, essaye simplement de compiler un code proche de

              #include <array>
              #include <iostream>
              int main(){
                  std::array<int, 4> tab{1,2,3,4};
                  for(auto it : tab){
                      std::cout<<it<<" ";
                  }
                  return 0;
              }

              qui ne fonctionnera qu'en C++11 et ultérieur.  Si bien que, si tu le compile sous la forme de g++ main.cpp, il y aura deux solutions:

              • Soit adurino utilise une version 6.x ou une version 7.x de Gcc, et cela compilera tout seul
              • Soit adurino utilise une version 4.x de Gcc, et tu obtiendras une erreur.

              La première solution serait l'idéale, bien sur, mais j'ai quelques doutes sur le sujet.

              Par contre, j'ai le pressentiment que tu seras dans la deuxième solution.  Il faudra donc faire des essais en rajoutant l'option -std= <VERSION> (ou <VERSION> serait soit c++14 soit c++11, en préférant la première si possible) ce qui donnerait une commande proche de g++ -std=c++14 main.cpp.

              Si le code compile avec cette option, tu es sauvé.  Sinon, ben, faudra rester en C++98 :p

              EDIT: je viens de tomber sur =>ce lien<= qui semble proposer une Gcc-7.0.2 pour adurino.  Je ne l'ai pas testé, mais il serait sans doute intéressant pour toi de faire la transition ;)

              -
              Edité par koala01 19 septembre 2017 à 9:09:49

              • Partager sur Facebook
              • Partager sur Twitter
              Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                20 septembre 2017 à 6:22:55

                Je vais installer Gcc-7.0.2 plus tard mais c'est une source précieuse, merci. D'abord disséquer mon cours du jour et je ferais la transition d'ici 3/4 jours et je te dirais.
                • Partager sur Facebook
                • Partager sur Twitter

                Comment manipuler des objets/class

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown