Système d'ouverture de porte cochère sécurisé avec verrouillage.

Bonjour,
J'ai du d'abord faire quelques modifications pour adapter cette vieille porte de bois qui a connu la guerre.

La fermeture se faisait par emboîtement, une barre de métal qui s'enfonçait dans un trou du sol et une autre barre de bois sur toute la hauteur servant à verrouiller le haut.

La modification a consisté à supprimer l’emboîtement, ajouter une butée au sol pour la porte gauche, des butées sur la porte droite en superposition. Elle doit donc se fermer en dernier.
Le verrouillage du haut se fait par un loquet avec ressort de rappel que j'ai fabriqué, manipulé par un servo-moteur.
Le sol n'étant pas égalisé, j'ai du ajouter un pontet au sol pour que le servo du bas n'ai pas une grande course à effectuer.

La porte gauche doit se fermer en premier. Pour éviter que le vent fasse trop de pression, la porte droite démarre 5 secondes plus tard.

Le matériel:

  • arduino nano
    -boitier de télécommande 12 V de ce genre
  • module 4 relais
  • 2 modules alimentation LM2596
  • 1 module MP1584
  • 1 mosfet N pour commander les leds de signalisation
  • 1 batterie 24 V 2 Ah ( récupe aspirateurs sans fil HS)
  • 1 chargeur 29 V 0,2 A
  • 2 servo-moteur https://www.electronicoscaldas.com/datasheet/MG996R_Tower-Pro.pdf
  • 1 système d'ouverture de porte récupéré suite carte électronique HS.

le schéma

Le programme

/*
Automatisme de porte cochère sécurisée avec vérouillage.

Sécurité : Arrêt sur seuil de courant moteur.
consommation secteur : 6.3 W avec transfo d'origine à vide.
remplacé par un chargeur 29 V 0.2 A et batterie NIMH 24 V 2 Ah.
consommation secteur : 2.2 W, batterie en charge, 1W batterie chargée.
Consommation du cuircuit au repos : 24 V 27 mA.

Voir sur youtube https://youtu.be/mJgig6ms-fo
*/

#include <Servo.h>
#include "OneButton.h" // librairie de gestion des boutons
#include <ScheduleTable.h>// librairie séquenceur

SchedTable<6> ouvrePorte(2800);
SchedTable<4> fermePorte(5000);
SchedTable<2> signalisation(24, 50);//2 actions dans table de 24 unités de 50 ms

// pins
const int pinSV = 2; // alim servo, actif à 0
const int pinFD = 3; // fermeture moteur droit
const int pinD = 4; // ouverture moteur droit
const int pinFG = 5; // fermeture moteurG
const int pinG = 6; // ouverture moteurG
OneButton pinFermer(7, true);
OneButton pinOuvrir(8, true);
const int pinPF = 9 ;//contact fin de course porte fermée
Servo verrouB;  // pin 10
Servo verrouH;  // pin 11
const int pinPO = 12; // contact fdc porte ouverte
const int pinLamp = 13; // signalisation
const int pinPFG = A2; //fdc porte gauche fermée
const int pinIG = A5 ; // mesure du courant moteur droit
const int pinID = A6 ; // courant moteur gauche
const int pinbat = A7 ; // contrôle batterie


// états
bool ouverture;
bool fermeture;
bool moteurD = 0; // rotation moteur droit
bool moteurG = 0; // rotation moteur gauche
bool actif = 0; //détermine l'action des boutons
bool pasClos; // état contact porte fermée, 0 si fermé
bool pasOuvert;// état contact porte ouverte, 0 si ouvert

// variables
int ID; //courant moteur droit (résistance 0.1 ohm)
int IG;
int Imax = 70;// X 0,049 = 3.43 A; maxi 150  7,35 A;normal 20 = 1 A;
int Vbat;// non utilisé, la surveillance des moteurs suffit
unsigned long chrono; // duree d'ouverture, fermeture
unsigned long chronoD; // duree de blocage moteur droit
unsigned long chronoG; // idem gauche
int cycleD = 0;// chaque fois qu'un dépassement de Imax est détecté
int cycleG = 0;// idem moteur gauche
int nbCycle = 20;

void setup() {
  Serial.begin(115200);
  pinMode(pinFG, OUTPUT);// fermeture gauche
  pinMode(pinG, OUTPUT);//ouverture gauche
  pinMode(pinFD, OUTPUT);//fermeture droite
  pinMode(pinD, OUTPUT);//ouverture droite
  pinMode(pinLamp, OUTPUT);// signalisation
  pinMode(pinPF, INPUT_PULLUP);// contact porte fermée
  pinMode(pinPFG, INPUT_PULLUP);// contact porte gauche fermée
  pinMode(pinPO, INPUT_PULLUP);// contact porte ouverte
  pinMode(pinSV, OUTPUT);//alim servos

  digitalWrite(pinSV, 1); //alim servos et relais coupée au repos
  digitalWrite(pinD, 1);// ouverture droit
  digitalWrite(pinFD, 1);// fermeture droit
  digitalWrite(pinG, 1);// ouverture gauche
  digitalWrite(pinFG, 1);// fermeture gauche

  pinOuvrir.attachClick(simpleClic);
  pinOuvrir.attachDoubleClick(doubleClic);
  pinFermer.attachClick(unClic);

  ouvrePorte.at(1,    [] { chrono = millis(); digitalWrite (pinSV, 0); verrouB.attach(10); verrouH.attach(11);} );
  ouvrePorte.at(10,   [] { signalisation.start(); verrouB.write(0); verrouH.write(20); } );
  ouvrePorte.at(400,  [] { ouverture = 1; digitalWrite(pinD, 0); moteurG = 1; moteurD = 1;} );
  ouvrePorte.at(600,  [] { actif = 1; } ); 
  ouvrePorte.at(1200, [] { verrouB.detach(); verrouH.write(180);} );
  ouvrePorte.at(2800, [] { digitalWrite(pinG, 0); verrouH.detach(); } );

  fermePorte.at(1,    [] { chrono = millis(); digitalWrite (pinSV, 0);  moteurG = 1; moteurD = 1;});
  fermePorte.at(100,  [] { signalisation.start(); digitalWrite (pinFG, 0); actif = 1;});
  fermePorte.at(300,  [] { fermeture = 1;});
  fermePorte.at(5000, [] { digitalWrite (pinFD, 0);});
  signalisation.at(5, [] { digitalWrite(pinLamp, HIGH); });// pinLamp
  signalisation.at(6, [] { digitalWrite(pinLamp, LOW); });
}

void unClic()//telecommande seule
{
  if (!actif)fermePorte.start(1); // au repos
  else arret();
}

void simpleClic()//bouton de porte + telecommande
{
  if (!actif)ouvrePorte.start(1);
  else arret();
}

void doubleClic()//bouton de porte
{
  if (!actif)fermePorte.start(1);
}

void arret() {
  ouvrePorte.stop(); fermePorte.stop();
  digitalWrite (pinD, 1);// arret moteur droit
  digitalWrite (pinFD, 1);// arret moteur droit
  moteurD = 0;
  digitalWrite (pinFG, 1);// arret moteur droit
  digitalWrite (pinG, 1);// arret moteur gauche
  moteurG = 0;
  signalisation.stop();
  digitalWrite(pinLamp, LOW);
  fermeture = 0;  ouverture = 0;
  actif = 0; //retour repos
  digitalWrite (pinSV, 1);
  cycleD = cycleG = 0;
}// fin arret()


void loop() {
  ScheduleTable::update();
  pinOuvrir.tick();
  pinFermer.tick();

  pasClos = digitalRead(pinPF);
  pasOuvert = digitalRead(pinPO);

  //surveillance du courant des moteurs
  if (moteurG)// tourne
  {
    IG = analogRead(pinIG);
    if (IG > Imax)
    {
      Serial.print(IG); Serial.print("G");
      if (!cycleG) {// débute le comptage
        chronoG = millis();
        Serial.println(" RAZ...");
      }
      cycleG++;
      if (cycleG > nbCycle)// nombre de dépassements
      { // stop la porte gauche
        digitalWrite (pinG, 1);// arret moteur gauche
        digitalWrite (pinFG, 1);
        moteurG = 0; actif = 0; cycleG = 0;
        Serial.print(" le blocage a duré : ");
        Serial.println(millis() - chronoG);// environ 50 à 200 ms
      }
    }
    if ((millis() - chronoG) > 400) {//remets à zéro le comptage
      cycleG = 0;
    }
  }

  if (moteurD)// tourne
  {
    ID = analogRead(pinID);

    if (ID > Imax)
    {
      Serial.print(ID); Serial.print("D");
      if (!cycleD) {
        chronoD = millis();
        Serial.println(" RAZ...");
      }
      cycleD++;
      if (cycleD > nbCycle) {// arret moteur droit
        digitalWrite (pinD, 1);
        digitalWrite (pinFD, 1);
        moteurD = 0;
        actif = 0; cycleD = 0;
        Serial.print(" le blocage a duré : ");
        Serial.println(millis() - chronoD);//durée du blocage
      }
    }
    if ((millis() - chronoD) > 400) {
      cycleD = 0;
    }
  }

  // La porte droite ne doit pas être fermé en premier
  if (!moteurG && fermeture && moteurD)
  {
    if (digitalRead(pinPFG)) {//si ouvert, on stoppe la porte droite
      digitalWrite (pinFD, 1);// arret moteur droit
      moteurD = 0;
    }
  }

  // fin de course porte gauche ouverte
  if (!moteurG && ouverture && !pasOuvert) // ouvert
  {// la porte droite s'ouvre 2.4 s avant
    arret();
    Serial.print(" ouvert durée : "); Serial.println(millis() - chrono);
  }

  if (fermeture && !pasClos && !moteurD)//portes fermées
  {
    // verrouillage après détection fin de course porte droite fermée
    verrouH.attach(11);
    verrouH.write(180);//relache le haut si arrêt trop rapide
    delay(100); verrouH.detach();
    verrouB.attach(10);  verrouB.write(180); // vérouille le bas
    delay(600);// suffit comme délai
    verrouB.detach();
    arret();
    Serial.print(" fermé durée : "); Serial.println(millis() - chrono);
  }

} // end of loop

Petite vidéo de démonstration Automatisme de porte cochère sécurisé avec verrouillage piloté par arduino - YouTube

Mise à jour du 04/04/2020 200404.ino (7.16 KB)
Mise à jour du 23/09/2020 202309MAJ.ino (9.15 KB)

Extrait du moniteur série représentant une ouverture et une fermeture.
Les lignes finissants par RAZ correspondent à des surintensités momentanées, dues aux démarrages de moteur ou des à coups du au vent, sans occasionner de blocage.
Une lettre indique G pour moteur gauche, D pour le droit, le nombre en 2 chiffres, la valeur brute du courant mesuré...
A 9:03:13 blocage volontaire avec la main, puis relancé.

Copies du moniteur série

test 10 cycles, Imax 70 :

09:01:36.966 -> 71G RAZ...
09:01:36.966 -> 75G78G80G79G77G76G73G72D RAZ...
09:01:41.875 -> 75D75D75D75D73D72D71G RAZ...
09:02:01.845 -> 71G71G71G71G72G71G72G71G71G74G le blocage a duré : 40
09:02:04.924 -> 72D RAZ...
09:02:04.924 -> 71D72D73D75D75D74D76D75D77D76D le blocage a duré : 3
09:02:05.638 ->  fermé durée : 28785
09:02:23.341 -> 71G RAZ...
09:02:23.341 -> 72G72G71G71D RAZ...
09:02:43.383 -> 73D71D71D71D72D72D71D71D72D72D le blocage a duré : 90
09:02:48.352 -> 71G RAZ...
09:02:48.404 -> 71G71G71G71G72G71G72G72G72G71G le blocage a duré : 35
09:02:48.404 ->  ouvert durée : 27892
09:03:02.675 -> 72G RAZ...
09:03:02.675 -> 75G74G74G72G71G RAZ...
09:03:13.250 -> 71G71G71G72G71G71G71G72G71G71G le blocage a duré : 78
09:03:36.370 -> 71G RAZ...
09:03:36.370 -> 71G71G71G72G73G72G71G73G72G72G le blocage a duré : 40
09:03:43.752 -> 71D RAZ...
09:03:43.752 -> 72D71D71D71D71D73D71D71D72D71D le blocage a duré : 21
09:03:44.500 ->  fermé durée : 23599

test 20 cycles Imax 75 :

09:20:53.367 -> 76G RAZ...
09:21:13.492 -> 76D RAZ...
09:21:13.492 -> 76D77D76D76D76D77D76D77D79D76D76D76D76D76D77D76D76D76D76D76D le blocage a duré : 133
09:21:18.642 -> 76G RAZ...
09:21:18.642 -> 76G76G76G76G76G76G76G76G77G76G77G78G76G77G77G78G78G79G77G77G le blocage a duré : 31
09:21:18.676 ->  ouvert durée : 28131
09:21:52.361 -> 76G RAZ...
09:21:52.361 -> 76G77G76G77G78G76G76G76G76G76G77G76G76G76G78G76G76G76G77G77G le blocage a duré : 50
09:21:55.435 -> 76D RAZ...
09:21:55.435 -> 76D76D76D76D77D77D76D76D78D76D77D78D78D76D78D76D78D76D76D77D le blocage a duré : 6
09:21:56.153 ->  fermé durée : 30567

J'avais commencé par un pont H avec des Mosfets, mais ma détection n'étant pas au point, après avoir cramé plusieurs IRF9540, je suis passé au module relais.
Je pense que des mosfets avec Rds de valeur plus faible ça aurait tenu.
Les diodes en série sur les entrées A5 et A6 sont pour les protéger des transitoires venant des moteurs... Depuis je n'ai plus d'entrée qui crame.

Suggestions et critiques sont les bienvenues :wink:

Super projet ! T'est un spécialiste de la porte motorisée !

Pourquoi tu a besoin d'une alim en 5.2V et une en 5 V ?

Super projet ! T'est un spécialiste de la porte motorisée !

Merci, mais pas vraiment, j'ai passé beaucoup de temps à chercher les meilleurs "algorithmes".

Pourquoi tu a besoin d'une alim en 5.2V et une en 5 V ?

L'appel de courant au démarrage des servos-moteur faisait rebouter l'arduino nano.

J'en ai profité aussi pour alimenter les bobines de la carte relais par l'intermédiaire de la broche JD-VCC, en enlevant le cavalier JD-VSS. ILs peuvent aussi générer des transitoires néfastes.

J'ai aussi levé la patte 5 du LM2596 pour le désactiver au repos. Ça a permis de consommer moins et de terminer la charge de la batterie à 28 V avec un courant d'entretien très faible.

J'ai passé beaucoup de temps à peaufiner le code de surveillance moteur

  //surveillance du courant des moteurs
  if (moteurG)// tourne
  {
    IG = analogRead(pinIG);
    if (IG > Imax)
    {
      Serial.print(IG); Serial.print("G");
      if (!cycleG) {// débute le comptage
        chronoG = millis();
        Serial.println(" RAZ...");
      }
      cycleG++;
      if (cycleG > nbCycle)// nombre de dépassements
      { // stop la porte gauche
        digitalWrite (pinG, 1);// arret ouverture gauche
        digitalWrite (pinFG, 1);// arret fermeture gauche
        moteurG = 0; actif = 0; cycleG = 0;
        Serial.print(" le blocage a duré : ");
        Serial.println(millis() - chronoG);// environ 50 à 200 ms
      }
    }
    if ((millis() - chronoG) > 400) {//remets à zéro le comptage
      cycleG = 0;
    }
  }

Il faut jongler entre 3 paramètres pour ne blesser personne, garder une puissance suffisante pour lutter contre les rafales de vent sans s'arrêter trop facilement, passer le pic de démarrage :
Imax : sensibilité au déclenchement
nbCycle : nombre de dépassements
400 : durée avant remise à zéro.

Jusqu'alors, pas de soucis. Juste une fois ou le vent fort a empêché les verrous de s'ouvrir . Dans ce cas, les moteurs s’arrêtent en moins de 10 ms. suffit soit d'aider la porte, soit passer en mode manuel, prévu aussi.
Les servos sont des 10 kgf.cm, mais quand ça coince ... https://www.electronicoscaldas.com/datasheet/MG996R_Tower-Pro.pdf

Mise à jour du 23/09/2020 sans le préambule (trop de caractères).

#include <Servo.h>
#include "OneButton.h" // librairie de gestion des boutons
#include <ScheduleTable.h>// librairie séquenceur

SchedTable<6> ouvrePorte(3000);
SchedTable<6> fermePorte(6300);
SchedTable<2> cycleFlash(1000);//

// pins
const byte pinSV = 2; // alim servo, actif à 0
const byte pinFD = 3; // fermeture moteur droit
const byte pinD = 4; // ouverture moteur droit
const byte pinFG = 5; // fermeture moteurG
const byte pinG = 6; // ouverture moteurG
OneButton pinFermer(7, true);
OneButton pinOuvrir(8, true);
const byte pinPF = 9 ;//contact fin de course porte fermée
Servo verrouB;  // pin 10
Servo verrouH;  // pin 11
const byte pinPO = 12; // contact fdc porte ouverte
const byte pinLamp = 13; // signalisation
const byte pinPFG = A2; //fdc porte gauche fermée
const byte pinIG = A5 ; // mesure du courant moteur droit
const byte pinID = A6 ; // courant moteur gauche
const byte pinbat = A7 ; // contrôle batterie


// états
bool ouverture;
bool fermeture;
bool moteurD = 0; // rotation moteur droit
bool moteurG = 0; // rotation moteur gauche
bool actif = 0; //détermine l'action des boutons
bool D_clos; // état contact NO porte fermée, 0 si fermé
bool G_ouvert;// état contact NO porte ouverte, 0 si ouvert
bool G_clos;// état contact NO porte gauche fermée

// variables
int ID; //courant moteur droit (résistance 0.1 ohm)
int IG;// idem gauche
int Imax = 62;// X 0,049 = 3 A; maxi 150 = 7,35 A; normal 20 = 1 A;
byte dureeBlocage = 50;
unsigned long chrono = 0; // duree d'ouverture, fermeture
unsigned long chronoD = 0; // duree de blocage moteur droit
unsigned long chronoG = 0; // idem gauche
unsigned long Tencours; // durée de l'action en cours

void setup() {
  Serial.begin(115200);
  pinMode(pinFG, OUTPUT);// fermeture gauche
  pinMode(pinG, OUTPUT);//ouverture gauche
  pinMode(pinFD, OUTPUT);//fermeture droite
  pinMode(pinD, OUTPUT);//ouverture droite
  pinMode(pinLamp, OUTPUT);// signalisation
  pinMode(pinPF, INPUT_PULLUP);// contact porte fermée droite
  pinMode(pinPFG, INPUT_PULLUP);// contact porte gauche fermée
  pinMode(pinPO, INPUT_PULLUP);// contact porte ouverte
  pinMode(pinSV, OUTPUT);//alim servos

  // RAZ des sorties alim servos et relais coupée au repos
  digitalWrite(pinSV, 1);// alim servos
  digitalWrite(pinD, 1); // ouverture droit
  digitalWrite(pinG, 1); // ouverture gauche
  digitalWrite(pinFD, 1);// fermeture droit
  digitalWrite(pinFG, 1);// fermeture gauche

  pinOuvrir.attachClick(simpleClic);
  pinOuvrir.attachDoubleClick(doubleClic);
  pinFermer.attachClick(unClic);

  ouvrePorte.at(1,    [] { chrono = millis(); digitalWrite (pinSV, 0);// alim servos
                           verrouB.attach(10); verrouH.attach(11); cycleFlash.start();
                           verrouB.write(10);//ouvre et maintien le verrou bas
                           if (D_clos)verrouH.write(20);//ouvre le verrou haut au départ
                         } );
  ouvrePorte.at(400,  [] { digitalWrite(pinD, 0); actif = 1;} );
  ouvrePorte.at(600,  [] { moteurD = 1; ouverture = 1; } );
  ouvrePorte.at(1200, [] { verrouB.detach(); verrouH.write(180);} );// relache le verrou haut
  ouvrePorte.at(2800, [] { digitalWrite(pinG, 0); verrouH.detach(); } );
  ouvrePorte.at(3000, [] { moteurG = 1; } );

  fermePorte.at(1,    [] { chrono = millis(); verrouB.attach(10) ; cycleFlash.start();
                           digitalWrite (pinSV, 0);
                         });
  fermePorte.at(100,  [] { verrouB.write(10); digitalWrite (pinFG, 0);});
  fermePorte.at(300,  [] { fermeture = 1;  moteurG = 1; actif = 1;});
  fermePorte.at(6000, [] { digitalWrite (pinFD, 0);});
  fermePorte.at(6200, [] { moteurD = 1;});

  cycleFlash.at(1,    [] { digitalWrite(pinLamp, HIGH); });
  cycleFlash.at(30,   [] { digitalWrite(pinLamp, LOW); });
}

void unClic()// telecommande seule
{
  if (!actif)fermePorte.start(1); // au repos
  else arret();
}

void simpleClic()// bouton de porte + telecommande
{
  if (!actif)ouvrePorte.start(1);
  else arret();
}

void doubleClic()//bouton de porte
{
  if (!actif)fermePorte.start(1);
}

// surveillance du courant des moteurs
void surveilleG()
{
  if (moteurG)// tourne
  {
    IG = analogRead(pinIG);
    if (IG > Imax)
    {
      Serial.print(" IG"); Serial.print(IG);
      if ((millis() - chronoG) > dureeBlocage)// durée blocage dépassée
      { // stop le moteur gauche
        digitalWrite (pinG, 1);
        digitalWrite (pinFG, 1);
        moteurG = 0; chronoG = 0;
        Serial.println(" moteurG bloqué ");
      }
      else if (!chronoG)chronoG = millis();// démarre le comptage
    }
    else chronoG = 0; // RAZ compteur
  }
}

void surveilleD()
{
  if (moteurD)// tourne
  {
    ID = analogRead(pinID);
    if (ID > Imax)
    {
      Serial.print(" ID"); Serial.print(ID);
      if ((millis() - chronoD) > dureeBlocage)// durée blocage dépassée
      { // stop le moteur droit
        digitalWrite (pinD, 1);
        digitalWrite (pinFD, 1);
        moteurD = 0; chronoD = 0;
        Serial.println(" moteurD bloqué ");
      }
      else if (!chronoD)chronoD = millis();// démarre le comptage
    }
    else chronoD = 0;
  }
}

void arret() {
  ouvrePorte.stop(); fermePorte.stop();
  digitalWrite (pinD, 1);// arret moteur droit
  digitalWrite (pinFD, 1);// arret moteur droit
  moteurD = 0;
  digitalWrite (pinFG, 1);// arret moteur droit
  digitalWrite (pinG, 1);// arret moteur gauche
  moteurG = 0;
  cycleFlash.stop();
  digitalWrite(pinLamp, LOW);
  fermeture = 0;  ouverture = 0;
  actif = 0; //retour repos
  digitalWrite (pinSV, 1);
  cycleFlash.setPeriod(1000);
  Serial.print(" durée : "); Serial.println(millis() - chrono);
}// fin arret()

void loop() {
  ScheduleTable::update();
  pinOuvrir.tick();
  pinFermer.tick();

  D_clos = !digitalRead(pinPF);
  G_ouvert = !digitalRead(pinPO);
  G_clos = !digitalRead(pinPFG);

  Tencours = millis() - chrono;
  if (actif && (Tencours > 40000))  //arret forcé en cas d'avarie
  {
    arret();
    Serial.println(" délai dépassé ");
  }

  //surveillance du courant des moteurs
  surveilleD();
  surveilleG();

  // fin de course porte gauche ouverte
  if (ouverture && (Tencours > 3000))
  {
    if ( G_ouvert && !moteurD && !moteurG) arret(); // ouvert      
    // moteurG arrêté et porte non ouverte : signal d'alerte
    if (!moteurG && !G_ouvert)cycleFlash.setPeriod(300);
  }

  if (fermeture && (Tencours > 6300))// normal 23 secondes, max 36 seconde par vent continu
  {
    if (D_clos && !moteurD && !moteurG) // portes fermées
    {
      // verrouillage après détection fin de course porte droite fermée
      verrouH.attach(11);
      verrouH.write(180);//relache le haut si arrêt trop rapide
      delay(100); verrouH.detach();
      verrouB.attach(10);  verrouB.write(180); // vérouille le bas
      delay(600);// suffit comme délai
      verrouB.detach();
      Serial.print(" fermé ");
      arret();
    }
    //si la gauche s'arrête avant fin de course, la droite doit aussi s'arrêter
    if (!moteurG && !G_clos)//G arrêté et porte non fermée
    {
      digitalWrite (pinFD, 1); moteurD = 0; // arret moteur droit
      cycleFlash.setPeriod(300);
    }
    //moteurD arrêté et porte non fermée
    if (!moteurD && !D_clos)cycleFlash.setPeriod(300);
  }
} // end of loop

Mise à jour, préambule et fichier

Maj du 23/09/2019

modifications effectuées :

  • Suite à parfois arrêt d'une porte avant démarrage :
    validation des moteurs (moteurD et moteurG) 0.2 secondes après leur démarrage

  • Par vent fort et constant, la porte peut rattraper la gauche :
    6 secondes de retard pour la fermeture porte droite

  • En cas d'avarie ne permettant pas de détecter la fin de course :
    arret forcé à 40 secondes en sécurité.

  • si arrêt d'une porte avant arrêt normal, clignotement plus rapide : signal erreur

  • La porte droite devant chevaucher la gauche si arrêt porte gauche
    avant fin de course : arrêt moteur droit et signal erreur

  • Signalisation période normale: 1 seconde, erreur : 0.3 secondes.

  • Porte droite force trop en ouverture et délai avant blocage trop long en ouverture :
    Nouveau code de détection plus précis et rapide: arrêt dépassement de Imax durant dureeBlocage de 50 mS.

// surveillance du courant des moteurs
void surveilleG()
{
  if (moteurG)// tourne
  {
    IG = analogRead(pinIG);//lecture aux bornes de la résistance 0.1 ohm
    if (IG > Imax)
    {
      Serial.print(" IG"); Serial.print(IG);
      if ((millis() - chronoG) > dureeBlocage)// durée blocage dépassée
      { // stop le moteur gauche
        digitalWrite (pinG, 1);
        digitalWrite (pinFG, 1);
        moteurG = 0; chronoG = 0;
        Serial.println(" moteurG bloqué ");
      }
      else if (!chronoG)chronoG = millis();// démarre le comptage
    }
    else chronoG = 0; // RAZ compteur
  }
}

Idem pour le moteur droit.

202309MAJ.ino (9.15 KB)

Bonjour,

MAJ du 02/12/2020

  • Cause température basse et déformation de la porte droite, le contact de fermeture
    ne s'était pas fermé, conséquence :
    pas de verouillage bas et la porte droite ne pouvait pas s'ouvrir.

  • ajouté la fonction verrouillage().

  • modifié les fonctions ouverture et fermeture sans tenir compte des contact fin de course :

  • fin de course validé quand les 2 moteurs sont arrêtés, après un temps minimun
    de fermeture ou d'ouverture.

  • signal d'erreur si un moteur s'arrête hors délai.

  • L'arrêt du moteur gauche en fermeture stoppe aussi la droite (chevauchement).

  • arrêt forcé sur délai normal dépassé

#include <Servo.h>
#include "OneButton.h" // librairie de gestion des boutons
#include <ScheduleTable.h>// librairie séquenceur

SchedTable<6> ouvrePorte(3000);
SchedTable<6> fermePorte(6300);
SchedTable<2> cycleFlash(1000);//

// pins
const byte pinSV = 2; // alim servo, actif à 0
const byte pinFD = 3; // fermeture moteur droit
const byte pinD = 4; // ouverture moteur droit
const byte pinFG = 5; // fermeture moteurG
const byte pinG = 6; // ouverture moteurG
OneButton pinFermer(7, true);
OneButton pinOuvrir(8, true);
const byte pinPF = 9 ;//contact fin de course porte fermée
Servo verrouB;  // pin 10
Servo verrouH;  // pin 11
const byte pinPO = 12; // contact fdc porte ouverte
const byte pinLamp = 13; // signalisation
const byte pinPFG = A2; //fdc porte gauche fermée
const byte pinIG = A5 ; // mesure du courant moteur droit
const byte pinID = A6 ; // courant moteur gauche
const byte pinbat = A7 ; // contrôle batterie

// états
bool ouverture;
bool fermeture;
bool moteurD = 0; // rotation moteur droit
bool moteurG = 0; // rotation moteur gauche
bool actif = 0; //détermine l'action des boutons
bool D_clos; // état contact NO porte fermée, 0 si fermé
bool G_ouvert;// état contact NO porte ouverte, 0 si ouvert
bool G_clos;// état contact NO porte gauche fermée
bool normal = 1; // déroulement normal. anormal si arrêt avant fin de course
// variables
int ID; //courant moteur droit (résistance 0.1 ohm)
int IG;// idem gauche
int Imax = 70;// X 0,049 = 3.43 A; maxi 150 = 7,35 A; normal 20 = 1 A;
byte dureeBlocage = 50;
unsigned long chrono = 0; // duree d'ouverture, fermeture
unsigned long chronoD = 0; // duree de blocage moteur droit
unsigned long chronoG = 0; // idem gauche
unsigned long Tencours; // durée de l'action en cours

void setup() {
  Serial.begin(115200);
  pinMode(pinFG, OUTPUT);// fermeture gauche
  pinMode(pinG, OUTPUT);//ouverture gauche
  pinMode(pinFD, OUTPUT);//fermeture droite
  pinMode(pinD, OUTPUT);//ouverture droite
  pinMode(pinLamp, OUTPUT);// signalisation
  pinMode(pinPF, INPUT_PULLUP);// contact porte fermée droite
  pinMode(pinPFG, INPUT_PULLUP);// contact porte gauche fermée
  pinMode(pinPO, INPUT_PULLUP);// contact porte ouverte
  pinMode(pinSV, OUTPUT);//alim servos

  // RAZ des sorties alim servos et relais coupée au repos
  digitalWrite(pinSV, 1);// alim servos
  digitalWrite(pinD, 1); // ouverture droit
  digitalWrite(pinG, 1); // ouverture gauche
  digitalWrite(pinFD, 1);// fermeture droit
  digitalWrite(pinFG, 1);// fermeture gauche

  pinOuvrir.attachClick(simpleClic);
  pinOuvrir.attachDoubleClick(doubleClic);
  pinFermer.attachClick(unClic);

  ouvrePorte.at(1,    [] { chrono = millis(); digitalWrite (pinSV, 0);// alim servos
                           verrouB.attach(10); verrouH.attach(11); cycleFlash.start();
                           verrouB.write(10);//ouvre et maintien le verrou bas
                           verrouH.write(20);//ouvre le verrou haut au départ
                         } );
  ouvrePorte.at(400,  [] { digitalWrite(pinD, 0); actif = 1;} );
  ouvrePorte.at(600,  [] { moteurD = 1; ouverture = 1;} );
  ouvrePorte.at(1200, [] { verrouB.detach(); verrouH.write(180);} );// relache le verrou haut
  ouvrePorte.at(2800, [] { digitalWrite(pinG, 0); verrouH.detach(); } );
  ouvrePorte.at(3000, [] { moteurG = 1; } );

  fermePorte.at(1,    [] { chrono = millis(); verrouB.attach(10) ; cycleFlash.start();
                           digitalWrite (pinSV, 0);//active les servos
                         });
  fermePorte.at(100,  [] { verrouB.write(10); digitalWrite (pinFG, 0);});
  fermePorte.at(300,  [] { fermeture = 1;  moteurG = 1; actif = 1;});
  fermePorte.at(6000, [] { digitalWrite (pinFD, 0);});
  fermePorte.at(6200, [] { moteurD = 1;});

  cycleFlash.at(1,    [] { digitalWrite(pinLamp, HIGH); });
  cycleFlash.at(30,   [] { digitalWrite(pinLamp, LOW); });
}

void unClic()// telecommande seule
{
  if (!actif)fermePorte.start(1); // au repos
  else {
    normal = 0;
    arret();
  }
}

void simpleClic()// bouton de porte + telecommande
{
  if (!actif)ouvrePorte.start(1);
  else {
    normal = 0;
    arret();
  }
}

void doubleClic()//bouton de porte
{
  if (!actif)fermePorte.start(1);
}

// surveillance du courant des moteurs
void surveilleG()
{
  if (moteurG)// tourne
  {
    IG = analogRead(pinIG);
    if (IG > Imax)
    {
      Serial.print(" IG"); Serial.print(IG);
      if ((millis() - chronoG) > dureeBlocage)// durée blocage dépassée
      { // stop le moteur gauche
        digitalWrite (pinG, 1);
        digitalWrite (pinFG, 1);
        moteurG = 0; chronoG = 0;
        Serial.println(" moteurG bloqué ");
      }
      else if (!chronoG)chronoG = millis();// démarre le comptage
    }
    else chronoG = 0; // RAZ compteur
  }
}

void surveilleD()
{
  if (moteurD)// tourne
  {
    ID = analogRead(pinID);
    if (ID > Imax)
    {
      Serial.print(" ID"); Serial.print(ID);
      if ((millis() - chronoD) > dureeBlocage)// durée blocage dépassée
      { // stop le moteur droit
        digitalWrite (pinD, 1);
        digitalWrite (pinFD, 1);
        moteurD = 0; chronoD = 0;
        Serial.println(" moteurD bloqué ");
      }
      else if (!chronoD)chronoD = millis();// démarre le comptage
    }
    else chronoD = 0;
  }
}

void verrouillage() {
  verrouH.attach(11);
  delay(500); // rebond de la porte
  verrouH.write(180);//relache le haut si arrêt trop rapide
  delay(100); verrouH.detach();
  verrouB.attach(10);  verrouB.write(180); // vérouille le bas
  delay(600);// suffit comme délai
  verrouB.detach();
  Serial.print(" fermé ");
  arret();
}

void arret() {
  ouvrePorte.stop(); fermePorte.stop();
  digitalWrite (pinD, 1);// arret moteur droit
  digitalWrite (pinFD, 1);// arret moteur droit
  moteurD = 0;
  digitalWrite (pinFG, 1);// arret moteur droit
  digitalWrite (pinG, 1);// arret moteur gauche
  moteurG = 0;
  cycleFlash.stop();
  digitalWrite(pinLamp, LOW);
  fermeture = 0;  ouverture = 0;
  actif = 0; //retour repos
  digitalWrite (pinSV, 1); // coupe l'alim des servos
  cycleFlash.setPeriod(1000);
  Serial.print(" durée : "); Serial.println(millis() - chrono);
}// fin arret()

void loop() {
  ScheduleTable::update();
  pinOuvrir.tick();
  pinFermer.tick();

  D_clos = !digitalRead(pinPF);
  G_ouvert = !digitalRead(pinPO);
  G_clos = !digitalRead(pinPFG);

  Tencours = millis() - chrono;

  //surveillance du courant des moteurs
  surveilleD();
  surveilleG();

  if (ouverture) {
    if (normal) {
      if (Tencours > 22000) {// normal
        if (!moteurG && !moteurD) arret(); // ouvert
      }
      else if (!moteurD && (Tencours > 600) && (Tencours < 19600)) {// anormal
        cycleFlash.setPeriod(300);
        normal = 0;
      }
      else if (!moteurG && (Tencours > 3000) && (Tencours < 22000)) {// anormal
        cycleFlash.setPeriod(300);
        normal = 0;
      }
      else if (Tencours > 35000) {
        arret();
        Serial.println(" délai dépassé ");
      }
    }
    else {// sans limite dans le temps
      if (!moteurG && !moteurD) arret(); // ouvert
      normal = 1;
    }
  }

  if (fermeture) {
    if (normal)
    {
      if (Tencours > 25200) {// normal
        if (!moteurG && !moteurD) verrouillage(); // fermé
      }
      //si la gauche s'arrête avant fin de course, la droite doit aussi s'arrêter
      else if (!moteurG && !G_clos)//G arrêté et porte non fermée
      {
        digitalWrite (pinFD, 1); moteurD = 0; // arret moteur droit
        cycleFlash.setPeriod(300);
        normal = 0;
      }
      else if (!moteurD && (Tencours > 6200) && (Tencours < 25200)) {// anormal
        cycleFlash.setPeriod(300);
        normal = 0;
      }
      else if (Tencours > 39000) {
        verrouillage();
        Serial.println(" délai dépassé ");
      }
    }
    else { // sans limite dans le temps
      if (!moteurG && !moteurD) verrouillage(); // fermé
      normal = 1;
    }
  }

} // fin de loop

201202MAJ.ino (10.6 KB)