Porte poulailler économique autonome

Détail et code

/* porte automatique poulailler avec Arduino Pro Mini

  - pv 6 v 1 W, mesure la luminosité et charge les 3 piles alcalines R6.
  - moteur d'imprimante et sa courroie (récup)
  - Consommation 6 µA en veille, led "power" et régulateur enlevés.
  - Ouverture au seuil "jour" après plusieurs confirmations, cycles
  de 8 secondes de période de veille, évitant les détections intempestives.
  - Se ferme au seuil "nuit", environ 1/2 heure après que
  les poules soient rentrées.
  - Une touche en interruption mémorise le seuil "nuit", à faire plutôt
  l'hiver quand les poules rentrent par luminosité plus faible.
  - Arret sur blocage moteur 20 mS ou délai dépassé.
  - Si le fin de course(ILS) n'est pas détecté, la fermeture est relancée
  8 secondes plus tard.
  - découpe de l'ouverture H = 30 cm L = 32.5 cm
  - poids de la trappe 300 gr
  - contre-poids 200 gr
  - piles usées, la porte plus difficile à ouvrir reste fermée.
*/

#include <LowPower.h> //6 µA en veille
#include <EEPROM.h>

/* declaration des constantes pour les noms des broches */
const byte pinBouton = 2;// sauve le seuil nuit
const byte pinILS = A0; // ILS fin de course
const byte pinpv = A3; // résistane 47k vers A3; 100k au moins
const byte pinmoteur = A2; // mesure courant moteur sur 1 Ohm
const byte fermer = 4; // commande de fermeture
const byte ouvrir = 3; // commande d'ouverture

/* declaration des variables */
int nuit = 70; // 0.3 v; presque nuit
int jour = 250;  //  1 v; jour bien entammé
int UPV; // mesure de luminosité
int courant_moteur;// max au blocage 0.6 A
byte ILS; // fin de course trappe fermée
byte cycle = 6;// X 8 seconde de durée de veille
byte retard = 0; // compte le nombre de cycles effectués
byte ouvert; // 1 si trappe ouverte
byte rotation = 0; // état moteur arrêté
unsigned long debut_blocage; // chrono du temps de blocage
unsigned long duree_rotation; // chrono de rotation
int mem_courant; // courant moteur au début du blocage
int delai_blocage = 20;// durée de blocage avant arrêt
int addr = 0;// première adresse de l'EEPROM
byte lecture; // de l'EEPROM
volatile bool appuiBref = false;


void setup() {
  // initialisation des broches entree/sortie
  pinMode(pinBouton,  INPUT_PULLUP);
  pinMode(pinILS,  INPUT);
  pinMode(pinpv, INPUT);
  pinMode(pinmoteur, INPUT);
  pinMode(fermer, OUTPUT);
  pinMode(ouvrir, OUTPUT);

  //module relais, commandes inverssées :
  digitalWrite(ouvrir, 1); digitalWrite(fermer, 1);

  //interruption par bouton poussoir
  attachInterrupt(digitalPinToInterrupt(pinBouton), bouton, FALLING);
  // enregistre la valeur "nuit" par défaut si case vierge
  lecture = EEPROM.read(addr);
  if (lecture == 255) { // vierge
    EEPROM.write(addr, (nuit));
  }
  else {//sinon récupère la valeur en EEPROM
    nuit = lecture;
  }
  UPV = analogRead(pinpv);// mesure la luminosité
  Serial.begin(115200);// affiche sur moniteur série
  Serial.print (" seuil nuit = ") ; Serial.print (nuit) ;
  Serial.print (" UPV = ") ; Serial.println (UPV) ;
  //initialisation trappe
  retard = cycle;//pour que l'ouverture ou la fermeture soit sans délais
  if (UPV <= jour)fermeture(); // la nuit
  else ouverture(); // le jour
} // fin setup

void loop() {
  UPV = analogRead(pinpv);
  ILS = digitalRead(pinILS);
  if (!digitalRead(pinBouton)) {
    sauvseuilNuit();
  }
  else if (rotation) { // le moteur tourne
    courant_moteur = analogRead(pinmoteur);// sur résistance de 0.5 Ohm
    Serial.print (millis() - duree_rotation) ; Serial.print ("ms ") ;
    Serial.print (courant_moteur * 4.7 * 2 / 1024) ; Serial.print ("A ") ;

    if (courant_moteur != mem_courant) { // variable normalement
      mem_courant = courant_moteur;// sauve la valeur
      debut_blocage = millis();// debute le comptage
    }
    else if (courant_moteur == mem_courant ) { // pas de changement
      if ((millis() - debut_blocage) > delai_blocage)stop();
    }

    if (  millis() - duree_rotation > 3500)stop(); // sécurité
  }// fin rotation

  else if (UPV <= nuit && ouvert)fermeture(); // au crépuscule
  else if (UPV >= jour && !ouvert)ouverture(); // à l'aube
  else if (!ouvert && !ILS) { // mal fermée
    retard = cycle;// annule le retard
    fermeture();// relancée après une période de veille
  }
  else  { // pas de changement
    retard = 0;
    veille();
  }
}// fin de loop()

void bouton() {
  appuiBref = true; // autorisé si appui bref
  // appui bouton déclenché par interruption
}

// active la mise en veille pour 8 secondes
void veille(void) {
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); // mise en veille
  // Le programme reprends ici après 8 secondes
}

void ouverture() {
  retard++;
  if (retard > cycle) { // 56 secondes
    digitalWrite(ouvrir, 0);
    rotation = 1; retard = 0; ouvert = 1;
    duree_rotation = millis();
  }
  else veille();
};

void fermeture() {
  retard++;
  if (retard > cycle) { // 56  secondes
    digitalWrite(fermer, 0);
    rotation = 1; retard = 0; ouvert = 0;
    duree_rotation = millis();
  }
  else veille();
};

void stop() {
  digitalWrite(ouvrir, 1); digitalWrite(fermer, 1);
  rotation = 0;
  Serial.print (" ouvert = ") ; Serial.print (ouvert) ;
  Serial.print (" courant moteur = ") ; Serial.print (courant_moteur) ;
  Serial.print (" UPV = ") ; Serial.print (UPV) ;
  Serial.print (" durée ") ; Serial.print (millis() - duree_rotation) ;
  Serial.println ("ms ") ;
  delay(100);
  veille();
};// stop

void sauvseuilNuit() { // enregistre le seuil crépuscule
  EEPROM.write(addr, (UPV)); // 0 à 254 0 à 1.35 V
  nuit = UPV;
}

Vidéo prochainement.

Merci du partage - un peu d’explications sur le contexte serait pas mal aussi.

Une petite remarque au passage :

Quand vous avez 2 conditions mutuellement exclusives il vaut mieux utiliser if/else (si le courant n’est pas différent de mem_courant c’est qu’il est égal forcément) et dans ce cas comme on dirait que vous utilisez aussi un seuil, votre code serait plus sécurisé avec un test d’inégalité sur le courant max car la lecture est imprécise et pourrait fluctuer autour de mem_courant.

Bonjour JLM, le but est de détecter le blocage du moteur pendant lequel, le courant ne varie plus, au moins pendant les 20 mS déterminées par delai_blocage .

Par exemple, un extrait du relevé du moniteur série pendant l'ouverture

0.38A 50ms 0.39A 51ms 0.39A 51ms 0.41A 52ms 0.43A 53ms 0.45A 54ms 0.47A 55ms 0.47A 56ms 0.46A 57ms 0.45A 58ms 0.47A 59ms 0.46A 60ms 0.45A 61ms 0.44A 62ms 0.44A 62ms 0.43A 63ms 0.43A 64ms 0.44A 65ms 0.42A 66ms 0.42A 67ms 0.44A 68ms 0.45A 69ms 0.46A 70ms

Il ne se passe pas 4 mS sans variation du courant moteur

Je n'ai qu'une connaissance assez limitée du code, je l'ai appris en m'intéressant au javascript, vous auriez formulé ça comment ?


le souci potentiel c'est que la lecture de la valeur du courant par

n'est pas forcement exactement stable même si le courant n'évolue pas ou peu.

Dans votre exemple on voit bien que ça oscille avec des lectures consécutives peuvent donner entre 0.42A et 0.47A ➜ ce qui fait que votre algo de détection n'est jamais déclenché et vous êtes sauvé par votre

il faudrait définir un intervalle plutôt qu'une valeur absolue et si vous restez dans cet intervalle pendant vos 20ms alors c'est que votre condition est réalisée.

c'est typiquement une définition de programme qui se prête bien à la programmation par machine à états (cf mon tuto éventuellement)

(sinon d'autres solutions utilisent des capteurs de fin de course pour définir la position haute ou basse - mais attention où vous les placez à cause des déjections et diverses "pollutions" possible dans le poulailler).

Non ça marche bien comme ça.
L'exemple donné est en court d'ouverture. le courant est normalement instable.

Le stop à 3.5 S n'est qu'une sécurité ultime, l'ouverture se faisant en 2.8 S, c'est juste en cas ou les piles commenceraient à être défaillantes, mais depuis plusieurs mois d'essais, elles pètent la forme avec 5. 5 V, 4.8 V à l'origine

Extrait du moniteur juste avant le stop

0.56A 2676ms 0.56A 2677ms 0.56A 2678ms 0.56A 2679ms 0.56A 2680ms 0.56A 2681ms 0.56A 2682ms 0.56A 2683ms 0.56A 2684ms 0.56A 2685ms 0.56A 2686ms 0.56A 2688ms 0.56A 2689ms 0.56A 2691ms 0.56A 2692ms 0.56A 2693ms 0.56A 2694ms 0.56A ouvert = 1 courant moteur = 123 UPV = 802 durée 2699ms

ok si c'est stabilisé à 0.56A pourquoi pas - vous avez de la chance avec votre alim/moteur/driver mais comme vous avez le stop à 3.5s le risque reste limité

Pas toujours 0.56A, le principal étant la stabilisation. Il y a aussi le fait que la mesure sur une résistance de 1 Ohm offre une tolérance importante.

J'ai une porte cochère qui fonctionne ainsi depuis des années ( le projet est sur le forum Système d'ouverture de porte cochère sécurisé avec verrouillage. )
Exemple en fermeture (moteur bloqué)

0.66A 1411ms 0.66A 1412ms 0.65A 1413ms 0.66A 1414ms 0.66A 1415ms 0.66A 1416ms 0.66A 1417ms 0.66A 1418ms 0.66A 1419ms 0.66A 1420ms 0.66A 1422ms 0.66A 1423ms 0.66A 1424ms 0.66A 1425ms 0.66A 1426ms 0.66A 1427ms 0.66A 1428ms 0.66A 1429ms 0.66A 1430ms 0.66A 1431ms 0.66A 1432ms 0.66A 1433ms 0.66A 1435ms 0.66A 1436ms 0.66A 1437ms 0.66A 1438ms 0.66A 1439ms 0.66A ouvert = 0 courant moteur = 143 UPV = 32 durée 1444ms

La vidéo rapide.
Je fait un reset pour accélérer, le panneau est caché de la lumière à la fermeture.

1 Like

très bien et bonne idée le contre-poids !

Merci, sans contre-poids, le moteur n'est pas assez puissant pour ouvrir et la trappe ne peu pas blesser un animal, car son poids relatif est très faible.

Justement avec la détection de fin de course par le courant moteur, je n'en ai mis qu'un, un interrupteur à lame souple dans le bas de la boite, pour détecter la fermeture effective, vérifiée seulement après la première période de veille.
Il est activé par un petit aimant fixé sur la tige acier à sa jonction avec la courroie.

Un couvercle est prévu pour la protection des salissures.

Bonjour JML,
Il m'a fallu une nuit de sommeil pour comprendre, désolé.
J'ai corrigé le code( dans mon premier post aussi) et ça fonctionne.
Même si les 2 conditions s'enchainent, la deuxième ne peut se réaliser, mais vous avez raison, c'est perdre du temps de processeur de la poser.

En même temps, le moteur manquant un peu de puissance en cas de point dur au démarrage, j'ai diminué la résistance de mesure à 0.5 Ohm

Le moteur réducteur fait environ 200 RPM, un moteur de 100 aurait eu plus de puissance, par rapport au diamètre de poulie de 1,36 cm.

Bonsoir,

J'ai bien aimé cette astuce

Et j'aurais bien voulu en savoir plus.

Comme par exemple
Quel courant a travers R3 = 22R?

Combien de temps tiennent les piles grâce à cette astuce?

...