/* 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;
}
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
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
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.
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.
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.