Hello, I am currently carrying out a 8 week internship assignment where I have to automate a door for a solar-powered chicken coop, and I'm already in my 7th week.
I am currently using an Arduino UNO board, a 2 channel relay module, a solar cell, a 3.7V lipo battery and a LCD display with buttons.
The door is opened and closed using a motor that turns in either direction and rolls or unwinds a wire that opens or closes the door.
I first managed to carry out a loop test program where by pressing the RIGHT button on the LCD screen: the door closes up to the DOWN sensor, stops for 3 seconds when the motor is paused, then goes up until it reaches the UP sensor, where the motor pauses again before closing the loop. Just press the RIGHT button again to restart the loop.
Here is the assembly I made:
The program I created before also makes it possible to display on the LCD screen the voltage consumed by the motor and the voltage at the terminals of the solar cell.
Now I want to create a new program based on the manual version, and where the door will open and close according to the brightness threshold measured by the solar cell. Morning and evening time delays will also be integrated, where the door will open in the morning, and close in the evening. The manual door operation program with the test loop will still be present in the program since it is an improvement of the old program.
In theory, once the assembly is powered by the lipo battery, the program will have 3 alternatives:
-If the voltage across the solar cell is below 0 for at least 10 seconds, and as long as the RIGHT button is not pressed, the automatic closing program will be triggered and the door will close.
-If the voltage across the solar cell is greater than or equal to 0 for at least 10 seconds, and as long as the RIGHT button is not pressed, the automatic opening program will be triggered and the door will open.
-If the RIGHT button is triggered within 10 seconds after the battery has supplied power to the fixture, the manual closing and opening program will be triggered and the door will close and then open.
Here is the program that I realized so far:
//moteur + relais + LCD + cellule + capteurs
// LCD Keypad Shield
#include <LiquidCrystal.h>
// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
//variables
int lcd_key = 0;
int adc_key_in = 0;
int TensionBAS = 0;
int TensionHAUT = 0;
//constantes
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
#define CapteurBAS 11
#define CapteurHAUT 12
#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2
int state_relais_manuel = 0;
int state_fermeture_auto = 0;
int state_ouverture_auto = 0;
int state_seuil_ensoleillement;
unsigned long temps_mesures = 0;
unsigned long temps_relais_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;
void setup()
{
// On met les pin de chaque relais en sortie
pinMode(RelayPin1, OUTPUT);
pinMode(RelayPin2, OUTPUT);
pinMode(CapteurBAS, INPUT);
pinMode(CapteurHAUT, INPUT);
lcd.begin(16, 2); // Démarrage de l'écran
lcd.setCursor(0,0); // Positionnement du curseur au début
lcd.print("Mesure tension"); // Message
}
void loop()
{
lcd_key = read_LCD_buttons(); // Lecture des touches
// Sous traite les différentes tâches
task_mesure_tensions();
task_relais_manuel();
switch (lcd_key) // Action en cas de touche pressée
{
case btnRIGHT: //en appuyant sur le bouton RIGHT
{
if (state_relais_manuel == 0){
state_relais_manuel = 1; //on incrémente la variable state de 1
}
break;
}
}
if (state_seuil_ensoleillement = 0){
task_fermeture_auto(); //lance le programme de fermeture dans la nuit
state_fermeture_auto++; //incrémente de 1a la valeur de la variable
}
else if (state_seuil_ensoleillement = 1){
task_ouverture_auto(); //lance le programme d'ouverture dans la journée
state_ouverture_auto++; //incrémente de 1a la valeur de la variable
}
}//boucle
void task_mesure_tensions()
{
unsigned long temps_actuel = millis();
if( (temps_actuel - temps_mesures) >= 250ul )
{
temps_mesures = temps_actuel;
// Transforme la mesure (nombre entier) en tension via un produit en croix
int valeur1 = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
int valeur2 = analogRead(A2); // Mesure la tension consommée par le moteur
float tension1 = (float)valeur1 * (5.0 / 1023.0);
float tension2 = (float)valeur2 * (5.0 / 1023.0);
// Affiche la mesure de la tension sur l'écran LCD et attends 250 ms
lcd.setCursor(0,1); // Positionnement du curseur début de ligne
if (tension1 < 1){
state_seuil_ensoleillement = 0;//la variable passe à 0 lorsqu'il fait nuit
}
else if (tension1 >= 1){
state_seuil_ensoleillement = 1;//la variable passe à 1 lorsqu'il fait jour
}
lcd.print("L");
lcd.print(state_seuil_ensoleillement); //affiche la valeur de l'état de la cellule solaire
lcd.print(" O");
lcd.print(state_ouverture_auto); //affiche la valeur de l'état de l'ouverture automatique
lcd.print(" F");
lcd.print(state_fermeture_auto); //affiche la valeur de l'état de la fermeture automatique
lcd.print(" M");
lcd.print(state_relais_manuel); //affiche la valeur de l'état du mode manuel de la porte
}//if
}//task_mesure_tensions
void task_relais_manuel()
{
unsigned long temps_actuel = millis();
switch( state_relais_manuel )
{
case 1:
// On allume l'un des relais alors que l'autre est éteint...
digitalWrite(RelayPin1, LOW);
digitalWrite(RelayPin2, HIGH);
//delay(10000);
temps_relais_manuel = temps_actuel;
state_relais_manuel++;
break;
case 2:
if( digitalRead(CapteurBAS) == LOW ) //lorsque le contact du capteur BAS est fermé...
{
// On éteint ensuite le ler relais: le moteur est en pause pendant 3 secondes...
digitalWrite(RelayPin1, HIGH);
digitalWrite(RelayPin2, HIGH);
//delay(5000);
temps_relais_manuel = temps_actuel;
state_relais_manuel++;
}//if
break;
case 3:
if( (temps_actuel - temps_relais_manuel) >= 3000ul )
{
// Puis on allume l'autre...
digitalWrite(RelayPin1, HIGH);
digitalWrite(RelayPin2, LOW);
//delay(10000);
temps_relais_manuel = temps_actuel;
state_relais_manuel++;
}//if
break;
case 4:
if( digitalRead(CapteurHAUT) == LOW ) //lorsque le contact du capteur HAUT est fermé...
{
// Enfin, on éteins le 2ème relais: le moteur est encore en pause pendant 3 secondes...
digitalWrite(RelayPin1, HIGH);
digitalWrite(RelayPin2, HIGH);
//delay(5000);
temps_relais_manuel = temps_actuel;
state_relais_manuel++;
}//if
break;
case 5:
if( (temps_actuel - temps_relais_manuel) >= 3000ul )
{
//reviens à l'état initial après 3 secondes de pause
state_relais_manuel = 0;
}//if
break;
}//switch
}//task_relais_manuel
void task_fermeture_auto ()
{
unsigned long temps_actuel = millis();
switch( state_fermeture_auto )
{
case 1:
if( (temps_actuel - temps_fermeture_auto) >= 10000ul && state_relais_manuel == 0 && state_ouverture_auto == 0 )
{
// Une fois la tempo écoulée, on active l'un des relais alors que l'autre reste inactif...
digitalWrite(RelayPin1, LOW);
digitalWrite(RelayPin2, HIGH);
//delay(10000);
temps_fermeture_auto = temps_actuel;
state_fermeture_auto++;
}//if
break;
case 2:
if( digitalRead(CapteurBAS) == LOW ) //lorsque le contact du capteur BAS est fermé...
{
// On éteint ensuite le ler relais: la porte est complétement fermée
digitalWrite(RelayPin1, HIGH);
digitalWrite(RelayPin2, HIGH);
//delay(5000);
temps_fermeture_auto = temps_actuel;
state_fermeture_auto++;
}//if
break;
case 3:
if( (temps_actuel - temps_fermeture_auto) >= 3000ul )
{
//laisse la porte fermée et remet la variable à l'état initial.
state_fermeture_auto = 0;
}//if
break;
}//switch
}//task_fermeture_auto
void task_ouverture_auto ()
{
unsigned long temps_actuel = millis();
switch( state_ouverture_auto )
{
case 1:
if( (temps_actuel - temps_ouverture_auto) >= 10000ul && state_relais_manuel == 0 && state_fermeture_auto == 0)
{
// Une fois la tempo écoulée, on active le 2ème relais alors que le 1er reste inactif...
digitalWrite(RelayPin1, HIGH);
digitalWrite(RelayPin2, LOW);
//delay(10000);
temps_ouverture_auto = temps_actuel;
state_ouverture_auto++;
}//if
break;
case 2:
if( digitalRead(CapteurHAUT) == LOW ) //lorsque le contact du capteur HAUT est fermé...
{
// On éteint ensuite le ler relais: le moteur est en pause pendant 3 secondes...
digitalWrite(RelayPin1, HIGH);
digitalWrite(RelayPin2, HIGH);
//delay(5000);
temps_ouverture_auto = temps_actuel;
state_ouverture_auto++;
}//if
break;
case 3:
if( (temps_actuel - temps_ouverture_auto) >= 3000ul )
{
//laisse la porte ouverte et remet la variable à l'état initial.
state_ouverture_auto = 0;
}//if
break;
}//switch
}//task_ouverture_auto
// Fonction de lecture des touches
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // Lecture du port analogique
// Les valeurs qui suivent doivent être adaptées au shield
if (adc_key_in > 1000) return btnNONE; // En principe 1023 quand aucune touche n'est pressée
if (adc_key_in < 50) return btnRIGHT; // 0
if (adc_key_in < 195) return btnUP; // 99
if (adc_key_in < 380) return btnDOWN; // 255
if (adc_key_in < 555) return btnLEFT; // 409
if (adc_key_in < 790) return btnSELECT; // 640
return btnNONE;
}
To perform tests, I set the door halfway up, then started a self-closing test by plunging my workroom into darkness.
Result: Strangely, after 10 seconds the door opens instead of closing, and stops at the UP sensor.
This time I repeat the experiment, now illuminating the solar cell in daylight.
Result: This time the door still opens, but without stopping at the UP sensor.
To find my error, I decide to modify my program so that the LCD screen displays, instead of the voltages at the terminals of the solar cell and the motor, the values of the variables "state_fermeture_auto" for F, "state_ouverture_auto" for O, and “state_relais_manuel” for M. L makes it possible to designate the value of “state_seuil_ensolenement”.
I then reproduce the automatic closing test.
Result: First, for some reason, the screen displays anything for "auto_opening_state", with fluctuating multi-digit numbers that change each time instead of just showing a single digit like L, F, and M.
In addition, after 10 seconds spent in the dark, the door opens while the value of "auto_fermeture_state" remains at 0, and does not even stop when it comes near the sensor.
Another remark: by varying the value of "state_seuil_ensolenement", called L, during the 10 seconds, alternately from 0 to 1 before returning to 0, the door opens once the 10-second period has passed.
Indeed, the extinguished program supposed to close while L was assigned to 0 DURING these entire 10 seconds.
Out of curiosity, I decided to try the manual mode of the program by pressing the RIGHT button.
Result: The loop operates without interruption, and the value M varies well according to the states of the relays.
So only the manual mode function of the door works, but I don't understand the mistakes I made for the automatic opening and closing functions.
Have I made a programming error?
Thank you in advance if someone could answer me quickly and suggest a correction to my program.