Jump to content
  • This is not a forum but a community!

    20100521_GTX_0003.JPGWe all love this mythical and popular car, because we sailed in one being childrens, because someone in the family had one or just because it always made us want it... because it's endearing, whatever we say.
    Its great success is certainly due to the fact that with a simple mechanics, with little or no electronics, it is easy to maintain by yourself without expensive tools, without forgetting that the parts are not expensive and always easy to find. Even today, for some homes, students and people with "little budget", it is a source of great comfort at a lower price: far from car loans and garage mechanics, which are becoming more and more inaccessible. The small engines models (the most common) are very robust and still consume very little, sometimes less than recent "equivalent" cars, which makes it by definition just as ecological, if not even more by the simple fact that we we always use it instead of buying new ones ... At the level of the official technical control, benefiting from its "seniority", it does not undergo the modern standards much too restrictive, the tranquility is assured.
    Today it is still an interesting car for everyday use, especially and clearly from an economic point of view.
    Collectors are also beginning to take an interest in this 30-year-old "granny": restoration, maintenance or refurbishment, repairs, etc ... make it possible to find "newer than new" models for the pleasure of the eyes and to see this French heritage thus safeguarded.
    We have created this community to bring together all those who are interested and who wish to take part in this adventure to preserve their Renault Super 5, whether by maintenance, repair or restoration: you will find in this community all useful information and tips on these topics.

    The forum is freely accessible in its entirety: there is no need to contribute, buy, neither pay anything to integrate the community and participate.
    To be able to ask questions and share your interest, all you have to do is register and present yourself properly!
    You do not have to have a Super 5: an interest in auto mechanics is enough

    Welcome !

    (This message disappears if you register into the forum)

    [Translated from french using GoogleTranslation tool]

     

totojest

Commandes de chauffage contrôlées par Arduino

33 posts in this topic

Recommended Posts

Mesdames Messieurs, bonsoir!

 

La commande de chauffage électronique pour Super 5 est terminée :hiha: Les tests sur mon bureau sont très prometteurs, il ne restera plus que l'épreuve finale avec tout ça sur place dans la voiture. La console conserve son apparence d'origine, comme je voulais, on ne touche pas à l'esthétique pour contenter les puristes :top: (Bon de mon coté, je ne vais pas garder cet aspect là, mais je parlerai de l'évolution dans le topic de l'Automatic)

 

Voici la console modifiée. Le panneau n'est pas très propre car j'y avais précédemment décollé le film sur lequel on a les inscriptions, mais on n'y touche pas, je vous expliquerai ça dans le futur tutoriel:

DSCF7836.JPG.ea23f785c123bb9be1004e85bdf00a48.JPG

 

Mais derrière le panneau, c'est une autre histoire :D

DSCF7833.JPG.d9016e202b7e686f91ec5ca6b23256fb.JPG

 

Voici 3 vidéos tests:

Test de la commande de chauffage

 

Test de la commande de mixage d'air

 

Test final avec temporisation de mouvement

 

Et le code de cette version, dans lequel je temporise le mouvement des servomoteurs pour éviter les mouvements brusques:

#include <Servo.h>

// Différents modes
enum VALMIX_MODE
{
  PLEINE_FACE,
  PLEIN_PIEDS,
  PAREBRISE_PIEDS_FACE,
  PLEIN_PAREBRISE,
  
  MIX_NB,                          // Nombre de modes disponibles
  MIX_DEFAULT = PLEIN_PAREBRISE,   // Mode par défaut  
};

// Structure d'une entrée de configuration
struct  ENTRY_CONFIG
{
  int haut;
  int bas;  
};

Servo servomixh;        // création de l'objet servomixh (servo mixage haut)
Servo servomixb;        // création de l'objet servomixb (servo mixage bas)
Servo servochau;        // création de l'objet servochau (servo chauffage)

// Déclaration des raccordements sur la carte
int cmdchau = 0;        // Pin A0: entrée analogique sur laquelle est connectée le potentiomètre de commande de chauffage
int pin_servomixh = 6;  // Pin 6 sur lequel est branché le servo de mixage haut sur l'Arduino
int pin_servomixb = 5;  // Pin 5 sur lequel est branché le servo de mixage bas sur l'Arduino
int pin_servochau = 3;  // Pin 3 sur lequel est branché le servo de chauffage sur l'Arduino
int pin_pleinface = 8;  // Pin 8 sur lequel est branché la commande de mixage pleine face
int pin_pleinpied = 9;  // Pin 9 sur lequel est branché la commande de mixage plein pieds
int pin_parebpied = 10; // Pin 10 sur lequel est branché la commande de mixage parebrise, pieds et face
int pin_parebrise = 11; // Pin 11 sur lequel est branché la commande de mixage plein parebrise

// Déclaration des variables dans le programme
int valchau = 30;                  // Variable contenant la valeur de position du potentiomètre de chauffage (et qui sera convertie en position du servo chauffage)
int prev_valchau = 1024;           // Valeur précédente pour détecter les changements : mis à une valeur invalide pour forcer l'init au 1er cycle
int poschau;                       // Variable utilisée pour temporiser le déplacement du servomoteur de chauffage
int posmixh;                       // Variable utilisée pour temporiser le déplacement du servomoteur de mixage haut
int posmixb;                       // Variable utilisée pour temporiser le déplacement du servomoteur de mixage bas
int anglefroid = 90;               // Valeur d'angle pour la position froid du servo de chauffage
int anglechaud = 175;              // Valeur d'angle pour la position chaud du servo de chauffage
int increment = 1;                 // Valeur d'incrément d'angle pour la temporisation des mouvements
int attente = 30;                  // Temps de temporisation de mouvement du servomoteur en milliseconde
int relance = 1000;                // Temps de temporisation avant le rafraichissement du programme en milliseconde
VALMIX_MODE valmix=MIX_DEFAULT;    // Variable contenant la valeur de commande de mixage d'air (utilisée uniquement pour le débug)
VALMIX_MODE prev_valmix=MIX_NB;    // Valeur précédente pour détecter les changements : mis à une valeur invalide pour forcer l'init au 1er cycle
int entredeux = 0;                 // Compteur pour savoir si le bouton est bloqué entre deux positions (quand il atteind une certaine valeur on considère que le bouton n'est pas correctement en place et on adoptera une position de sécurité)

// Tableau des configurations possibles
ENTRY_CONFIG configuration[MIX_NB] =
{
//    haut  bas   
  {   10,   10  },    // PLEINE_FACE 
  {   55,   55  },    // PLEIN_PIEDS
  {   100,  55  },    // PAREBRISE_PIEDS_FACE
  {   145,  10  },    // PLEIN_PAREBRISE
};

// Initialisation
void setup() {
  Serial.begin(9600);                    // Ouvre le port série                   
  while(!Serial){;}     
  servomixh.attach(pin_servomixh);       // attache le servo mixage haut à son pin spécifié
  servomixb.attach(pin_servomixb);       // attache le servo mixage bas à son pin spécifié
  servochau.attach(pin_servochau);       // attache le servo chauffage à son pin spécifié
  pinMode(pin_pleinface,INPUT_PULLUP);   // on déclare le pin "pleine face" comme un pin d'entrée "pullup"
  pinMode(pin_pleinpied,INPUT_PULLUP);   // on déclare le pin "plein pieds" comme un pin d'entrée "pullup"
  pinMode(pin_parebpied,INPUT_PULLUP);   // on déclare le pin "parebrise, pieds et face" comme un pin d'entrée "pullup"
  pinMode(pin_parebrise,INPUT_PULLUP);   // on déclare le pin "plein parebrise" comme un pin d'entrée "pullup"  
}

// Boucle d'analyse
void loop() {
  // SERVO CHAUFFAGE
  valchau = analogRead(cmdchau);                           // Lit la valeur actuelle du potentiomètre (valeur comprise entre 0 et 1023)
  valchau = map(valchau, 0, 1023, anglefroid, anglechaud); // Mise à l'échelle pour renvoyer la position entre la position froid et la position chaud
  if (valchau != prev_valchau)                             // On ne déplace le servo que si nécessaire
  {
    // Temporisation de mouvement
    poschau = prev_valchau;
    if (valchau < prev_valchau)                                              // Si la valeur demandée est inférieure à la valeur précédente
    {
      for (poschau = prev_valchau; poschau >= valchau; poschau -= increment) // On décroit l'angle selon la valeur d'incrément
      {
        servochau.write(poschau);                                            // Déplace le servo chauffage à la position spécifiée
        delay(attente);                                                      // Attente selon la valeur spécifiée
      }
    }
    else if (valchau > prev_valchau)
    {
      for (poschau = prev_valchau; poschau <= valchau; poschau += increment) // On accroit l'angle selon la valeur d'incrément
      {
        servochau.write(poschau);                                            // Déplace le servo chauffage à la position spécifiée
        delay(attente);                                                      // Attente selon la valeur spécifiée
      }
    }
    prev_valchau = valchau;                // Mise à jour de la valeur précédente
  }
  
  // SERVO MIXAGE
  boolean pleinface = digitalRead(pin_pleinface); // On définit sur quelle position la commande de mixage est placée (attention, le booleen est à 0 quand on est sur la position)
  boolean pleinpied = digitalRead(pin_pleinpied);
  boolean parebpied = digitalRead(pin_parebpied);
  boolean parebrise = digitalRead(pin_parebrise);

  // Définition des angles à adopter pour chacun des servos en fonction de la commande demandée
  if (!pleinface)         // Mode plein face
  {
    entredeux = 0;
    valmix = PLEINE_FACE;
  }
  else if (!pleinpied)   // Mode plein pieds
  {
    entredeux = 0;
    valmix = PLEIN_PIEDS;
  }
  else if (!parebpied)   // Mode parebrise, pieds et face
  {
    entredeux = 0;
    valmix = PAREBRISE_PIEDS_FACE;
  }
  else if (!parebrise)   // Mode plein parebrise
  {
    entredeux = 0;
    valmix = PLEIN_PAREBRISE;
  }
  else                   // Sécurité: Si on laisse le bouton coincé entre deux positions, on adoptera le mode "parebrise" par défaut après un temps d'attente
  {
    entredeux++;
  }

  // Sécurité:
  if (entredeux>=15)     // Quand on a atteint un certain quota (et donc après un certain temps, 15 secondes ici), on passe en mode "parebrise" par sécurité
  {
    valmix=MIX_DEFAULT;
  }

  if ( valmix != prev_valmix )                                  // Si changement de position détecté, on applique les nouvelles valeurs aux servomoteurs
  {
    // Temporisation de mouvement. On initialise les valeurs de position qui assureront le mouvement des servomoteurs de mixage
    posmixh = configuration[prev_valmix].haut;
    posmixb = configuration[prev_valmix].bas;

    // Déplacement du servo de mixage bas (si nécéssaire) (lui d'abord car c'est celui qui a le moins de mouvement à effectuer: seulement 45° si besoin)
    if (configuration[valmix].bas < configuration[prev_valmix].bas)                                                // Si la valeur demandée est inférieure à la valeur précédente pour le servo de mixage bas
    {
      for (posmixb = configuration[prev_valmix].bas; posmixb >= configuration[valmix].bas; posmixb -= increment)   // On décroit l'angle selon la valeur d'incrément
      {
        servomixb.write(posmixb);                                                                                  // Déplace le servo mixage bas à la position spécifiée
        delay(attente);                                                                                            // Attente selon la valeur spécifiée
      }
    }
    else if (configuration[valmix].bas > configuration[prev_valmix].bas)                                           // Si la valeur demandée est supérieure à la valeur précédente pour le servo de mixage bas
    {
      for (posmixb = configuration[prev_valmix].bas; posmixb <= configuration[valmix].bas; posmixb += increment)   // On accroit l'angle selon la valeur d'incrément
      {
        servomixb.write(posmixb);                                                                                  // Déplace le servo mixage bas à la position spécifiée
        delay(attente);                                                                                            // Attente selon la valeur spécifiée
      }
    }

    // Déplacement du servo de mixage haut (si nécéssaire)
    if (configuration[valmix].haut < configuration[prev_valmix].haut)                                              // Si la valeur demandée est inférieure à la valeur précédente pour le servo de mixage haut
    {
      for (posmixh = configuration[prev_valmix].haut; posmixh >= configuration[valmix].haut; posmixh -= increment) // On décroit l'angle selon la valeur d'incrément
      {
        servomixh.write(posmixh);                                                                                  // Déplace le servo mixage haut à la position spécifiée
        delay(attente);                                                                                            // Attente selon la valeur spécifiée
      }
    }
    else if (configuration[valmix].haut > configuration[prev_valmix].haut)                                         // Si la valeur demandée est supérieure à la valeur précédente pour le servo de mixage haut
    {
      for (posmixh = configuration[prev_valmix].haut; posmixh <= configuration[valmix].haut; posmixh += increment) // On accroit l'angle selon la valeur d'incrément
      {
        servomixh.write(posmixh);                                                                                  // Déplace le servo mixage haut à la position spécifiée
        delay(attente);                                                                                            // Attente selon la valeur spécifiée
      }
    }

    prev_valmix = valmix;                                                                                          // Mise à jour de la valeur précédente
  }

  delay(relance);                         // Attente avant de relancer la boucle définie selon la variable relance
  
  // Débug
  Serial.print(" // CHAUFFAGE : ");
  Serial.print(valchau);               // Valeur de commande choisie pour le chauffage (sur l'échelle de 10 à 95°)
  Serial.print(" | Position reelle chauffage : ");
  Serial.println(servochau.read());    // Position du servomoteur chauffage
  Serial.print(" | MIXAGE : ");
  Serial.print(valmix);                // Valeur de commande choisie pour le mixage
  Serial.print(" | Position reelle mixage haut : ");
  Serial.println(servomixh.read());    // Position du servomoteur mixage haut
  Serial.print(" | Position reelle mixage bas : ");
  Serial.println(servomixb.read());    // Position du servomoteur mixage bas
  Serial.print(" | ENTRE DEUX : ");
  Serial.print(entredeux);             // Valeur du compteur d'entre deux
}

Une évolution possible de cette version pour moi seraient une coupure de la ventilation dès qu'un servo entre en mouvement. On en a parlé au tout début de topic, mais je n'ai pas le matériel pour mettre ça en oeuvre tout de suite...

 

Et il faudra aussi que je surveille les positions initiales des servomoteurs quand on alimente l'Arduino (ce qui correspondra à la mise au contact dans la voiture), pour les faire forcer le moins possible.

Share this post


Link to post
Share on other sites

BRAVO 🙌🙌🙌

C'est juste impressionnant 😄

  • Thanks 1

Share this post


Link to post
Share on other sites

Sympa ! :)

Je serais curieux de savoir comment t'as fait le bouton à 4 positions. Je suppose que t'as procédé ainsi en prévision de ton prochain montage moins "look super5" (je parie sur un control-panel style avion, avec plein de boutons et de LEDs :ph34r:), car sinon, un autre potentiomètre aurait été suffisant, en gardant le côté cranté de la mécanique d'avant : t'aurais pas eu le problème "entre-deux" et t'aurais pu aussi faire un mouvement graduel (comme le réel) en interpolant selon la position du bouton.

 

Il y a 9 heures, totojest a dit :

Et il faudra aussi que je surveille les positions initiales des servomoteurs quand on alimente l'Arduino (ce qui correspondra à la mise au contact dans la voiture), pour les faire forcer le moins possible.

T'as une flash dans l'arduino dans laquelle tu peux écrire, comme ça tu peux retrouver la dernière position à l'init... ;) 

 

Du côté du code, je pensais que t'utilisais delay() pour débuguer car c'est sa seule utilité. En pratique on évite vraiment de stopper le code pendant son exécution : si tu reprends ton code initial et que tu enlèves delay(1000) (ainsi que le code de debug/console/série) tu verras que le mouvement de ton servo suit le mouvement du bouton donc t'as pas besoin de "smoother" (lisser) comme tu fais, car tu le fais uniquement parce que ca fait des "sauts" à cause de ton cycle/retard de 1s.

Il est vivement conseillé de gérer le temps par "date" plutôt que par "attentes" (comme tu fais), tu trouveras ici : https://www.diegoyourself.com/index.php?article=arduino_bouton&page=0#time une explication de comment procéder pour faire ça. Si tu le souhaites, je peux modifier ton code pour l'adapter afin que tu comprennes le principe en le voyant sur ton propre code (seulement si tu le souhaites).

 

Enfin, tu parles à un moment d'une "zone morte" dans ton potentiomètre, comment l'as-tu branché à ton arduino ? en cas de besoin, il s'agit de mesurer une résistance, tu trouveras ici comment faire les calculs afin de bien couvrir toute la plage nécessaire et comment le calibrer : https://www.diegoyourself.com/index.php?article=arduino_resistance

  • Thanks 1

Share this post


Link to post
Share on other sites

Merci pour tes explications Zorro, je vais me pencher dessus, et oui je vais sûrement avoir besoin d'un coup de main.

 

Je suis vraiment un néophyte de l'Arduino, tout ce que j'ai lu jusque là sur les modèles de programmation utilisent un "delay()". Je pensais que c'était donc la manière de fonctionner de l'Arduino, et que donc une actualisation permanente de la boucle était limite obligatoire (en plus quand on appelle un élément de code "loop", c'est pour que ça tourne en boucle :laugh:).

 

Le lissage de la rotation est pour moi nécessaire, pour éviter que le servo ne se prenne des "chocs" au démarrage et à l'arrêt dès qu'on demande son mouvement. Il y a quand même des volets assez grands à manœuvrer, avec donc une certaine inertie.

 

Concernant la zone morte du potard, c'est une caractéristique du composant j'ai l'impression. Je vais refaire une mesure au multimètre pour en être sur, mais il y a bien une plage de rotation (entre 0 et 70° environ sur les 340° de rotation exploitables) où la résistance ne bouge pas du tout. Mais bon, c'est un potard de récup, je ne vais pas lui en demander de trop... Et il est branché avec ses 3 bornes sur l'Arduino comme ceci: une sur le +5V, une sur le pin analogique, et une sur le GND.

 

Enfin, pourquoi pas de potard sur le bouton de mixage? Simplement par souci d'économie. Je voulais faire une console que tout le monde puisse fabriquer soi même, et comme les servo coutent déjà un peu d'argent, je ne voulais pas augmenter inutilement le prix de la facture. En plus il aurait fallu prendre en compte une marge dans les valeurs de résistance, évaluer les valeurs en fonction de la position... Et enfin, j'ai bien moins galéré à faire le bouton 4 positions qu'à monter le potentiomètre :laugh:

 

Pour ma future commande, pas d'écran malheureusement (et à la grande déception de beaucoup de gens...), mais juste quelques LEDs de contrôle. Elle gardera le bouton rotatif de gestion de la température, aura 2 autres boutons rotatifs pour gérer la ventilation et (nouveauté) la clim/recyclage d'air, et deux boutons poussoirs de sélection du mode de mixage d'air, qui sera contrôlé par 3 LEDs :)

Share this post


Link to post
Share on other sites

Ton problème avec le potentiomètre c'est que tu l'as mal branché... Essaie le montage que je propose dans mon tuto, tu seras moins embêté et tu peux calibrer plus finement. Après c'est sur que si même à l'ohmmètre ca ne bouge pas sur une certaine plage, t'auras du mal à faire mieux...

 

Sinon, concernant le code, je reprends le code initial (sans lissage) pour démontrer l'utilisation de la temporisation "par date" plutôt que par arrêts (delay) :

#include <Servo.h>

// Différents modes
enum VALMIX_MODE
{
  MIX_PLEINE_FACE,
  MIX_PLEIN_PIEDS,
  MIX_PAREBRISE_PIEDS_FACE,
  MIX_PLEIN_PAREBRISE,
  
  MIX_NB,                          // Nombre de modes disponibles
  MIX_DEFAULT = MIX_PLEINE_FACE,   // Mode par défaut  
};

// Structure d'une entrée de configuration
struct  ENTRY_CONFIG
{
  int haut;
  int bas;  
};

Servo servomixh;        // création de l'objet servomixh (servo mixage haut)
Servo servomixb;        // création de l'objet servomixb (servo mixage bas)
Servo servochau;        // création de l'objet servochau (servo chauffage)

int cmdchau = 0;        // Entrée analogique sur laquelle est connectée le potentiomètre de commande de chauffage
int cmdmix = 1;         // Entrée analogique sur laquelle est connectée la valeur d'entrée de la résistance pour le mixage d'air
int valchau;            // Variable contenant la valeur de position du potentiomètre de chauffage (et qui sera convertie en position du servo chauffage)
int prev_valchau;       // Variable contenant la valeur précédente du potentiomètre pour détecter les changements
int marge_valchau = 2;  // Marge de changement minimale pour que la valeur soit considérée comme changée
VALMIX_MODE valmix=MIX_DEFAULT;    // Variable contenant la valeur de commande de mixage d'air (utilisée uniquement pour le débug)
VALMIX_MODE prev_valmix=MIX_NB;    // Valeur précédente pour détecter les changements : mis à une valeur invalide pour forcer l'init au 1er cycle
int entredeux;          // Compteur pour savoir si le bouton est bloqué entre deux positions (quand il atteind une certaine valeur on considère que le bouton n'est pas correctement en place et on adoptera une position de sécurité)
unsigned long date_debug=0UL; // Date du uC arduino pour affichage périodique de la trace debug
unsigned long temps_trace=1000UL; // Temps entre deux traces de debug


// tableau des configurations possibles
ENTRY_CONFIG configuration[MIX_NB] =
{
//    haut  bas   
  {   10,   10  },    // MIX_PLEINE_FACE 
  {   55,   55  },    // MIX_PLEIN_PIEDS
  {   100,  55  },    // MIX_PAREBRISE_PIEDS_FACE
  {   145,  10  },    // MIX_PLEIN_PAREBRISE
};

int pin_servomixh = 6;  // Pin 6 sur lequel est branché le servo de mixage haut sur l'Arduino
int pin_servomixb = 5;  // Pin 5 sur lequel est branché le servo de mixage bas sur l'Arduino
int pin_servochau = 3;  // Pin 3 sur lequel est branché le servo de chauffage sur l'Arduino
int pin_pleinface = 8;  // Pin 8 sur lequel est branché la commande de mixage pleine face
int pin_pleinpied = 9;  // Pin 9 sur lequel est branché la commande de mixage plein pieds
int pin_parebpied = 10; // Pin 10 sur lequel est branché la commande de mixage parebrise, pieds et face
int pin_parebrise = 11; // Pin 11 sur lequel est branché la commande de mixage plein parebrise


// Trace console pour le debug
void trace_debug()
{
  Serial.print(" // CHAUFFAGE : ");
  Serial.print(valchau);               // Valeur de commande choisie pour le chauffage (sur l'échelle de 10 à 95°)
  Serial.print(" | Position reelle chauffage : ");
  Serial.println(servochau.read());    // Position du servomoteur chauffage
  Serial.print(" | MIXAGE : ");
  Serial.print(valmix);                // Valeur de commande choisie pour le mixage
  Serial.print(" | Position reelle mixage haut : ");
  Serial.println(servomixh.read());    // Position du servomoteur mixage haut
  Serial.print(" | Position reelle mixage bas : ");
  Serial.println(servomixb.read());    // Position du servomoteur mixage bas
  Serial.print(" | ENTRE DEUX : ");
  Serial.print(entredeux);             // Valeur du compteur d'entre deux
}

// Initialisation
void setup() {
  Serial.begin(9600);                    // Ouvre le port série                   
  while(!Serial){;}     
  servomixh.attach(pin_servomixh);       // attache le servo mixage haut à son pin spécifié
  servomixb.attach(pin_servomixb);       // attache le servo mixage bas à son pin spécifié
  servochau.attach(pin_servochau);       // attache le servo chauffage à son pin spécifié
  pinMode(pin_pleinface,INPUT_PULLUP);   // on déclare le pin "pleine face" comme un pin d'entrée "pullup"
  pinMode(pin_pleinpied,INPUT_PULLUP);   // on déclare le pin "plein pieds" comme un pin d'entrée "pullup"
  pinMode(pin_parebpied,INPUT_PULLUP);   // on déclare le pin "parebrise, pieds et face" comme un pin d'entrée "pullup"
  pinMode(pin_parebrise,INPUT_PULLUP);   // on déclare le pin "plein parebrise" comme un pin d'entrée "pullup"
  valchau = 30;
  prev_valchau = valchau;
  entredeux = 0;                         // on considère que la position entre deux n'est pas par défaut
}

// Boucle d'analyse
void loop() {
  // SERVO CHAUFFAGE
  valchau = analogRead(cmdchau);           // Lit la valeur actuelle du potentiomètre (valeur comprise entre 0 et 1023)
  valchau = map(valchau, 0, 1023, 95, 10); // Mise à l'échelle pour renvoyer la position entre 10 et 95°

  // si la position a changé d'une manière notable
  if ( abs(valchau - prev_valchau) <= marge_valchau )
  {
    servochau.write(valchau);                // Déplace le servo chauffage à la position spécifiée

    //mise à jour de la dernière valeur
    prev_valchau = valchau;
  }

  
  // SERVO MIXAGE
  boolean pleinface = digitalRead(pin_pleinface); // On définit sur quelle position la commande de mixage est placée (attention, le booleen est à 0 quand on est sur la position)
  boolean pleinpied = digitalRead(pin_pleinpied);
  boolean parebpied = digitalRead(pin_parebpied);
  boolean parebrise = digitalRead(pin_parebrise);


  // Définition des angles à adopter pour chacun des servos en fonction de la commande demandée
  if (!pleinface)         // Mode plein face
  {
    entredeux = 0;
    valmix = MIX_PLEINE_FACE;
  }
  else if (!pleinpied)   // Mode plein pieds
  {
    entredeux = 0;
    valmix = MIX_PLEIN_PIEDS;
  }
  else if (!parebpied)   // Mode parebrise, pieds et face
  {
    entredeux = 0;
    valmix = MIX_PAREBRISE_PIEDS_FACE;
  }
  else if (!parebrise)   // Mode plein parebrise
  {
    entredeux = 0;
    valmix = MIX_PLEIN_PAREBRISE;
  }
  else                   // Sécurité: Si on laisse le bouton coincé entre deux positions, on adoptera le mode "parebrise" par défaut après un temps d'attente
  {
    entredeux++;
  }

  // Sécurité:
  if (entredeux>=15) // Quand on a atteint un certain quota (et donc après un certain temps, 15 secondes ici), on passe en mode "parebrise" par sécurité
  {
    valmix=MIX_DEFAULT;
  }

  // si changement de position détecté
  if ( valmix != prev_valmix )
  {
    // Application des nouvelles valeurs aux servomoteurs
    servomixh.write(configuration[valmix].haut);                // Application de la position au servo mixage haut
    servomixb.write(configuration[valmix].bas);                // Application de la position au servo mixage bas 
  
      // mise à jour de la valeur précédente
    prev_valmix = valmix;
  }

  // Débug
  // si le temps entre deux traces de débug s'est écoulé
  if ( abs(millis() - date_debug) >= temps_trace )
  {
    // afficher la trace de debug
    trace_debug();

    // mettre à jour la date pour attendre le prochain moment d'affichage
    date_debug = millis();
  }
}

 

Dans le code j'ai ajouté la modification de la commande uniquement si changement moyennant une marge d'erreur (à tester/modifier/valider) pour la commande de chaud.

A vrai dire, pour le moment dans ton code t'as pas vraiment besoin d'attendre (sauf pour faire tes tempos), mais j'illustre le principe en faisant une trace toutes les secondes.

Si tu testes ce code tel quel, tu verras que ton servo bouge à la vitesse à laquelle tu fais tourner le bouton/potard.

 

Enfin, pour le lissage du mouvement d'un servomoteur, je vais essayer de te faire une petite fonction plus tard qui devrait te simplifier la chose...

Share this post


Link to post
Share on other sites

Je viens de faire un essai en virant le "delay(relance)" de ma dernière version, et en effet, je me rends compte qu'on n'en a pas besoin.

 

Resterait à changer les delay(attente) dans les fonctions de temporisation de mouvement du servomoteur éventuellement?

Share this post


Link to post
Share on other sites
il y a une heure, totojest a dit :

Resterait à changer les delay(attente) dans les fonctions de temporisation de mouvement du servomoteur éventuellement?

oui, exactement ! :) 

Share this post


Link to post
Share on other sites

Re,

Voici une manière de gérer la vitesse des servos en utilisant millis() :

#include <Servo.h>

// Différents modes
enum VALMIX_MODE
{
  MIX_PLEINE_FACE,
  MIX_PLEIN_PIEDS,
  MIX_PAREBRISE_PIEDS_FACE,
  MIX_PLEIN_PAREBRISE,
  
  MIX_NB,                          // Nombre de modes disponibles
  MIX_DEFAULT = MIX_PLEINE_FACE,   // Mode par défaut  
};

// Structure d'une entrée de configuration
struct  ENTRY_CONFIG
{
  int haut;
  int bas;  
};

// Différents servomoteurs disponnibles dans ce programme
enum SERVOMOTEURS
{
  SERVO_HAUT,
  SERVO_BAS,
  SERVO_CHAUD,

  SERVO_NB,   // Nombre de servomoteurs disponnibles
};

// structure d'un servomoteur pour pouvoir gérer sa vitesse de rotation
struct ENTRY_SERVO
{
  Servo *servomotor;            // Instance du servomoteur associé
  int  current_angle;           // Angle courant
  int  target_angle;            // Angle de consigne (à atteindre)
  unsigned long moving_speed;   // Vitesse de déplacement en °/s 

  unsigned long date_start;     // Date à laquelle le dernier mouvement a démarré
};



Servo servomixh;        // création de l'objet servomixh (servo mixage haut)
Servo servomixb;        // création de l'objet servomixb (servo mixage bas)
Servo servochau;        // création de l'objet servochau (servo chauffage)

int cmdchau = 0;        // Entrée analogique sur laquelle est connectée le potentiomètre de commande de chauffage
int cmdmix = 1;         // Entrée analogique sur laquelle est connectée la valeur d'entrée de la résistance pour le mixage d'air
int valchau;            // Variable contenant la valeur de position du potentiomètre de chauffage (et qui sera convertie en position du servo chauffage)
int prev_valchau;       // Variable contenant la valeur précédente du potentiomètre pour détecter les changements
int marge_valchau = 2;  // Marge de changement minimale pour que la valeur soit considérée comme changée
VALMIX_MODE valmix=MIX_DEFAULT;    // Variable contenant la valeur de commande de mixage d'air (utilisée uniquement pour le débug)
int entredeux;          // Compteur pour savoir si le bouton est bloqué entre deux positions (quand il atteind une certaine valeur on considère que le bouton n'est pas correctement en place et on adoptera une position de sécurité)
unsigned long date_debug=0UL; // Date du uC arduino pour affichage périodique de la trace debug
unsigned long temps_trace=1000UL; // Temps entre deux traces de debug


// tableau des configurations possibles
ENTRY_CONFIG configuration[MIX_NB] =
{
//    haut  bas   
  {   10,   10  },    // MIX_PLEINE_FACE 
  {   55,   55  },    // MIX_PLEIN_PIEDS
  {   100,  55  },    // MIX_PAREBRISE_PIEDS_FACE
  {   145,  10  },    // MIX_PLEIN_PAREBRISE
};

// Table des servomoteurs utilisés dans le programe
ENTRY_SERVO servomoteur[SERVO_NB] =
{
//  servomotor  current_angle                    target_angle                     moving_speed(°/s)  date_start (0=stop)
  { &servomixh, configuration[MIX_DEFAULT].haut, configuration[MIX_DEFAULT].haut, 5,                 0 },
  { &servomixb, configuration[MIX_DEFAULT].bas,  configuration[MIX_DEFAULT].bas,  5,                 0 },
  { &servochau, 0,                               0,                               5,                 0 },
};

int pin_servomixh = 6;  // Pin 6 sur lequel est branché le servo de mixage haut sur l'Arduino
int pin_servomixb = 5;  // Pin 5 sur lequel est branché le servo de mixage bas sur l'Arduino
int pin_servochau = 3;  // Pin 3 sur lequel est branché le servo de chauffage sur l'Arduino
int pin_pleinface = 8;  // Pin 8 sur lequel est branché la commande de mixage pleine face
int pin_pleinpied = 9;  // Pin 9 sur lequel est branché la commande de mixage plein pieds
int pin_parebpied = 10; // Pin 10 sur lequel est branché la commande de mixage parebrise, pieds et face
int pin_parebrise = 11; // Pin 11 sur lequel est branché la commande de mixage plein parebrise

// Gestion d'un servomoteur
void manage_servomotor(ENTRY_SERVO *servomoteur)
{
  // si l'angle de consigne est différent de l'angle actuel
  if ( servomoteur->target_angle != servomoteur->current_angle )
  {
    // calculer la durée d'un pas (1°)
    unsigned long step_length_ms = 1000UL / servomoteur->moving_speed;

    // s'assurer d'au moins 1ms/pas (pour éviter les bloquages)
    if (step_length_ms <= 0UL)
    {
      step_length_ms = 1UL;
    }

    // capturer la date courante (pour éviter d'appeller millis plusieurs fois)
    unsigned long current_date = (unsigned long)millis();
    
    // si le chrono n'a pas encore été démarré 
    if ( servomoteur->date_start == 0UL )
    {
      // démarrer le chrono pour le prochain pas
      servomoteur->date_start = current_date;
    }
    // sinon, le chrono tourne, si la durée d'un pas a été atteinte ou dépassée
    else if ( (current_date - servomoteur->date_start) >= step_length_ms )
    {
      // s'il faut incrémenter
      if ( servomoteur->current_angle < servomoteur->target_angle )
      {
        servomoteur->current_angle++;
      }
      // sinon, il faut aller dans l'autre sens
      else
      {
        servomoteur->current_angle--;
      }

      // envoyer la nouvelle consigne au servomoteur
      servomoteur->servomotor->write(servomoteur->current_angle);

      // mettre à jour le chrono pour le prochain pas
      servomoteur->date_start = current_date;
    }
    // sinon : le chrono tourne, il faut attendre encore...
    else
    {
      ; // rien à faire
    }
  }
  // sinon : angle cible/consigne déjà atteint
  else
  {
    // stopper le chrono au cas où il tournait
    servomoteur->date_start = 0;
  }
}

// Trace console pour le debug
void trace_debug()
{
  Serial.print(" // CHAUFFAGE : ");
  Serial.print(valchau);               // Valeur de commande choisie pour le chauffage (sur l'échelle de 10 à 95°)
  Serial.print(" | Position reelle chauffage : ");
  Serial.println(servochau.read());    // Position du servomoteur chauffage
  Serial.print(" | MIXAGE : ");
  Serial.print(valmix);                // Valeur de commande choisie pour le mixage
  Serial.print(" | Position reelle mixage haut : ");
  Serial.println(servomixh.read());    // Position du servomoteur mixage haut
  Serial.print(" | Position reelle mixage bas : ");
  Serial.println(servomixb.read());    // Position du servomoteur mixage bas
  Serial.print(" | ENTRE DEUX : ");
  Serial.print(entredeux);             // Valeur du compteur d'entre deux
}

// Initialisation
void setup() {
  Serial.begin(9600);                    // Ouvre le port série                   
  while(!Serial){;}     
  servomixh.attach(pin_servomixh);       // attache le servo mixage haut à son pin spécifié
  servomixb.attach(pin_servomixb);       // attache le servo mixage bas à son pin spécifié
  servochau.attach(pin_servochau);       // attache le servo chauffage à son pin spécifié
  pinMode(pin_pleinface,INPUT_PULLUP);   // on déclare le pin "pleine face" comme un pin d'entrée "pullup"
  pinMode(pin_pleinpied,INPUT_PULLUP);   // on déclare le pin "plein pieds" comme un pin d'entrée "pullup"
  pinMode(pin_parebpied,INPUT_PULLUP);   // on déclare le pin "parebrise, pieds et face" comme un pin d'entrée "pullup"
  pinMode(pin_parebrise,INPUT_PULLUP);   // on déclare le pin "plein parebrise" comme un pin d'entrée "pullup"
  valchau = 30;
  entredeux = 0;                         // on considère que la position entre deux n'est pas par défaut
}

// Boucle d'analyse
void loop() {
  // SERVO CHAUFFAGE
  valchau = analogRead(cmdchau);           // Lit la valeur actuelle du potentiomètre (valeur comprise entre 0 et 1023)
  valchau = map(valchau, 0, 1023, 95, 10); // Mise à l'échelle pour renvoyer la position entre 10 et 95°

  // Déplace le servo chauffage à la position spécifiée
  servomoteur[SERVO_CHAUD].target_angle = valchau;

  
  // SERVO MIXAGE
  boolean pleinface = digitalRead(pin_pleinface); // On définit sur quelle position la commande de mixage est placée (attention, le booleen est à 0 quand on est sur la position)
  boolean pleinpied = digitalRead(pin_pleinpied);
  boolean parebpied = digitalRead(pin_parebpied);
  boolean parebrise = digitalRead(pin_parebrise);


  // Définition des angles à adopter pour chacun des servos en fonction de la commande demandée
  if (!pleinface)         // Mode plein face
  {
    entredeux = 0;
    valmix = MIX_PLEINE_FACE;
  }
  else if (!pleinpied)   // Mode plein pieds
  {
    entredeux = 0;
    valmix = MIX_PLEIN_PIEDS;
  }
  else if (!parebpied)   // Mode parebrise, pieds et face
  {
    entredeux = 0;
    valmix = MIX_PAREBRISE_PIEDS_FACE;
  }
  else if (!parebrise)   // Mode plein parebrise
  {
    entredeux = 0;
    valmix = MIX_PLEIN_PAREBRISE;
  }
  else                   // Sécurité: Si on laisse le bouton coincé entre deux positions, on adoptera le mode "parebrise" par défaut après un temps d'attente
  {
    entredeux++;
  }

  // Sécurité:
  if (entredeux>=15) // Quand on a atteint un certain quota (et donc après un certain temps, 15 secondes ici), on passe en mode "parebrise" par sécurité
  {
    valmix=MIX_DEFAULT;
  }

  // Application des nouvelles valeurs aux servomoteurs
  servomoteur[SERVO_HAUT].target_angle = configuration[valmix].haut;                // Application de la position au servo mixage haut
  servomoteur[SERVO_BAS].target_angle = configuration[valmix].bas;                  // Application de la position au servo mixage bas 
  

  // Pour tous les servomoteurs à gérer
  for(int i=0; i<SERVO_NB; i++)
  {
    // gérer le servomoteur courant
    manage_servomotor( &(servomoteur[i]) );
  }

  // Débug
  // si le temps entre deux traces de débug s'est écoulé
  if ( abs(millis() - date_debug) >= temps_trace )
  {
    // afficher la trace de debug
    trace_debug();

    // mettre à jour la date pour attendre le prochain moment d'affichage
    date_debug = millis();
  }
}

 

Ca compile, mais je n'ai pas testé.

En gros, tu définis la consigne et le programme se débrouille pour l'y emmener à la vitesse que t'as choisi (en °/s). Ca t'affranchit de tester si ça a changé car il ne fait plus rien une fois que la consigne est atteinte.

Reste le problème de l'init, mais en y réfléchissant bien, c'est un problème plus embêtant qu'il ne paraît l'être... L'utilisation de la flash pourrait te permettre de retrouver la dernière config au rallumage, ca reste à mon sens le meilleur moyen de démarrer "pas trop loin" de comment c'était...

 

En espérant que ça puisse t'aider, n'hésite pas à poser des questions si quelque chose ne te semble pas clair (ou si ca ne marche pas, vu que je n'ai pas testé... :nosweat:)

Enfin, c'est un peu brouillon parce que c'est du C, moi je préfère faire en C++ (mes librairies arduino "pro" sont en C++), mais là pour dépanner et faire un truc simple c'est certainement déjà suffisant.

Share this post


Link to post
Share on other sites

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...

Important Information

By using this site, you agree to our terms Terms of Use of use and privacy policy Privacy Policy.