Go Down

Topic: Système d'ouverture de porte cochère sécurisé avec verrouillage. (Read 217 times) previous topic - next topic

achess

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
Code: [Select]
/*
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 https://youtu.be/mJgig6ms-fo

achess

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é.

Code: [Select]
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 ;)

nimaj

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 ?

achess

Quote
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".
Quote
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
Code: [Select]
  //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
 

Go Up