Problem with debugging a chicken door project

Hello !
First post here, so don't hesitate to tell me if it's the wrong section or anything.

I'm working on yet another automated chicken door.
I was happy of the first breadboard test phase, and soldered it into a protoboard for testing.

The project is powered by a small solar panel + controller.
It use a RTC3231 to setup the opening and closing time, a L298N for the motor, and a relay to switch off the L298N when not in use. There is a switch for auto/manual mode, with button to control the door in manual mode.

I installed the circuit in test mode, and it works as it should, for a few hours, or even a few days, but then it start to behave erratically:

  • In manual mode, when i pressed a button, there is a short action but then the relay and L298N switch off directly.
  • The end of course switch are not reconnected anymore
  • The time of the RTC3231 gets off
  • I feel that without the L298N plugged the circuit works fine but i should test it for an extended period of time to be sure of that

All these erratic behaviour are fixed if i reboot the arduino by switching off/on the power.

Another suspicious thing, at some point i disconnected the 12v power and plugged the USB to the arduino, the arduino USB port smoked directly. But it is still working. (i changed it still in case, to be sure it is not the problem).
Note: This was before adding the Schottky diode after the stepdown +5 DC output, i did not retry it, didnt want to fry another arduino

What i suspect could be to investigate:

  • The 5v regulator of the L298N is overheating
  • Needs some decoupling caps or other electronic components i missed (I'm a beginner)
  • Some bad soldering, but i find it weird that it works fine for hours first.
  • Instability in the voltage or ground loop

Ideas i had for now:

  • Replace the relay by Mosfet/transistor system to cut more properly the L298N 12v and 5v, this time not using its internal voltage regulator for its logic part.

I would be very interested to have troubleshooting ideas from more experienced people around here to put me back on track !

Here is a KiCad schematic

I can upload the code, but the fact that the project works for hours and even days sometime before the problems gives me the impression that the problem is more at the electronic side.

(Edited for clarity)

That would be a good idea.

What is the temperature range that everything is subjected to?

What is the current used by the motor?

The circuit is inside the chicken coop, the temperature in France can be from ~ -10°C to 35°C outside, the coop is a bit isolated so should be a bit less in the extreme range.

The motor is a JGA25-370
+12VDC 60 RPM
Current without load: 50mA
Current while blocked: 1.2A

Also the power side is a 7Ah Lead battery, with a 20W solar panel with a small solar charge controller (typical cheap model)

and here is my code:
(sorry for the french comments and variable names, do not hesitate to ask if you have any question about it)

#include <Wire.h>
#include "RTClib.h"
#include <Dusk2Dawn.h>
#include <LowPower.h>

RTC_DS3231 rtc;
Dusk2Dawn soleil(46.6717, 5.3468, 1);  // le Fay, UTC+1

const int openButtonPin = 2;         // ouverture manuelle
const int closeButtonPin = 3;        // fermeture manuelle
const int modeSwitchPin = 4;         // Switch controle manuel ou horraire
const int relayPin = 5;              // Pin connectée à IN du relais
const int finDeCourseFermePin = 7;   // detecteur de fin de course Porte fermée
const int finDeCourseOuvertPin = 8;  // detecteur de fin de course Porte ouverte
const int motorPinA = 9;             // driver moteur L298 PinA
const int motorPinB = 10;            // driver moteur L298 PinB
const int enaPin = 11;               // driveur moteur L298 Pin ENA


int offsetSunriseMinutes = 0;  // Ouvre X minutes AVANT le lever du soleil
int offsetSunsetMinutes = 30;  // Ferme X minutes APRÈS le coucher du soleil

int sunriseTime = -1;  // en minutes depuis minuit
int sunsetTime = -1;

// ------------- Mode entrée horaire manuelle pour tests ------------------
bool modeManuelHoraire = false;              // false = auto lever/coucher, true = horaires manuels
int heureManuelleOuverture = (7 * 60) + 0;   // 07:00 en minutes aprĂšs minuit
int heureManuelleFermeture = (20 * 60) + 0;  // 21:00

enum PorteEtat { OUVERTE,
                 FERMEE,
                 EN_MOUVEMENT_OUVERTURE,
                 EN_MOUVEMENT_FERMETURE };
PorteEtat etatPorte = FERMEE;

bool dernierEtatMotorButton = HIGH;
bool dernierEtatSleepButton = HIGH;
bool porteAutoOuverte = false;
bool porteAutoFermee = false;
bool dernierEtatModeManuel = false;

volatile bool demandeOuverture = false;
volatile bool demandeFermeture = false;
volatile bool modeManuel = false;

//-----------SETUP-----------------
void setup() {
  Wire.begin();

  pinMode(openButtonPin, INPUT_PULLUP);
  pinMode(closeButtonPin, INPUT_PULLUP);
  pinMode(modeSwitchPin, INPUT_PULLUP);
  pinMode(finDeCourseFermePin, INPUT_PULLUP);
  pinMode(finDeCourseOuvertPin, INPUT_PULLUP);
  pinMode(motorPinA, OUTPUT);
  pinMode(motorPinB, OUTPUT);
  pinMode(enaPin, OUTPUT);
  pinMode(relayPin, OUTPUT);

  attachInterrupt(digitalPinToInterrupt(openButtonPin), ouvrirPorteInterrupt, FALLING);
  attachInterrupt(digitalPinToInterrupt(closeButtonPin), fermerPorteInterrupt, FALLING);

  digitalWrite(enaPin, LOW);    // ENA éteint au départ
  digitalWrite(relayPin, LOW);  // relais désactivé si actif à LOW
  arreterMoteur();

  Serial.begin(9600);
  delay(500);
  Serial.println("Début setup");
  if (!rtc.begin()) {
    Serial.println("RTC non détecté !");
    while (1)
      ;
  }

  // Décommente une seule fois pour régler l'heure :
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  DateTime now = rtc.now();

  Serial.print("Heure RTC actuelle : ");
  if (now.hour() < 10) Serial.print("0");
  Serial.print(now.hour());
  Serial.print(":");
  if (now.minute() < 10) Serial.print("0");
  Serial.print(now.minute());
  Serial.print(":");
  if (now.second() < 10) Serial.print("0");
  Serial.println(now.second());
  mettreAJourHeuresSoleil(now);

  afficherHorairesProgrammes();

  // DĂ©termination de l’état initial
  bool finDeCourseFerme = digitalRead(finDeCourseFermePin);
  bool finDeCourseOuvert = digitalRead(finDeCourseOuvertPin);

  if (finDeCourseFerme == LOW) {
    etatPorte = FERMEE;
    Serial.println("État initial : PORTE FERMÉE");
  } else if (finDeCourseOuvert == LOW) {
    etatPorte = OUVERTE;
    Serial.println("État initial : PORTE OUVERTE");
  } else {
    // Ni ouvert ni fermé
    etatPorte = EN_MOUVEMENT_OUVERTURE;  // ou un nouvel état INCONNU
    Serial.println("État initial : INCONNU (porte entre les deux)");
  }

  // Réduction de fréquence pour économie d'énergie
  //CLKPR = 0x80;
  //CLKPR = 0x01;
}

void loop() {
  DateTime now = rtc.now();
  int minutesNow = now.hour() * 60 + now.minute();

  bool finDeCourseFerme = digitalRead(finDeCourseFermePin);    // LOW = activé
  bool finDeCourseOuvert = digitalRead(finDeCourseOuvertPin);  // LOW = activé

  modeManuelHoraire = (digitalRead(modeSwitchPin) == LOW);

  // --- LIRE SI MANUEL OU AUTO ---
  modeManuelHoraire = (digitalRead(modeSwitchPin) == LOW);
  // Pour affichage :
  if (modeManuel != dernierEtatModeManuel) {
    Serial.print("Mode actuel : ");
    Serial.println(modeManuel ? "MANUEL (boutons)" : "AUTOMATIQUE (horaires)");
    dernierEtatModeManuel = modeManuel;
  }

  // --- CONTROLES MANUELS ---
  if (demandeOuverture) {
    demandeOuverture = false;
    if (etatPorte == FERMEE) ouvrirPorte();
  }
  if (demandeFermeture) {
    demandeFermeture = false;
    if (etatPorte == OUVERTE) fermerPorte();
  }

  // --- FINS DE COURSE ---
  if (etatPorte == EN_MOUVEMENT_FERMETURE && finDeCourseFerme == LOW) {
    arreterMoteur();
    etatPorte = FERMEE;
    Serial.println("Porte fermée");
  }
  if (etatPorte == EN_MOUVEMENT_OUVERTURE && finDeCourseOuvert == LOW) {
    arreterMoteur();
    etatPorte = OUVERTE;
    Serial.println("Porte ouverte");
  }

  // --- OUVERTURE ET FERMETURE AUTO ---
  if (!modeManuelHoraire) {  // Mode Auto si switch sur position Auto sinon bypass
    int heureOuverture = modeManuelHoraire ? heureManuelleOuverture : sunriseTime;
    int heureFermeture = modeManuelHoraire ? heureManuelleFermeture : sunsetTime;

    PorteEtat etatVoulue;
    if (minutesNow < heureOuverture) {
      etatVoulue = FERMEE;
    } else if (minutesNow < heureFermeture) {
      etatVoulue = OUVERTE;
    } else {
      etatVoulue = FERMEE;
    }

    if ((etatPorte == FERMEE || etatPorte == OUVERTE) && etatPorte != etatVoulue) {
      if (etatVoulue == OUVERTE) {
        Serial.println("Ouverture auto");
        ouvrirPorte();
      } else {
        Serial.println("Fermeture auto");
        fermerPorte();
      }
    }
  }

  // --- MISE EN VEILLE ---
  if (etatPorte == OUVERTE || etatPorte == FERMEE) {  // Mise en veille si la porte n'est pas en mouvement
    arreterMoteur();
    desactiverRelais();
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }

  // Sinon, on reste actif pour suivre le mouvement

  delay(50);  // Anti-rebond simple
}

void fermerPorte() {
  activerRelais();
  Serial.println("L289 alimenté");
  digitalWrite(motorPinA, HIGH);
  digitalWrite(motorPinB, LOW);
  digitalWrite(enaPin, HIGH);
  etatPorte = EN_MOUVEMENT_FERMETURE;
  mettreAJourHeuresSoleil(rtc.now());
}

void ouvrirPorte() {
  activerRelais();
  Serial.println("L289 alimenté");
  digitalWrite(motorPinA, LOW);
  digitalWrite(motorPinB, HIGH);
  digitalWrite(enaPin, HIGH);
  etatPorte = EN_MOUVEMENT_OUVERTURE;
  mettreAJourHeuresSoleil(rtc.now());
}

void arreterMoteur() {
  digitalWrite(motorPinA, LOW);
  digitalWrite(motorPinB, LOW);
  digitalWrite(enaPin, LOW);
  desactiverRelais();
  Serial.println("L289 en veille");
}

void afficherHeureReadable(int totalMinutes) {
  int h = totalMinutes / 60;
  int m = totalMinutes % 60;
  if (h < 10) Serial.print("0");
  Serial.print(h);
  Serial.print(":");
  if (m < 10) Serial.print("0");
  Serial.println(m);
}

void mettreAJourHeuresSoleil(DateTime now) {
  int rise = soleil.sunrise(now.year(), now.month(), now.day(), true);
  int set = soleil.sunset(now.year(), now.month(), now.day(), true);
  sunriseTime = rise + offsetSunriseMinutes;
  sunsetTime = set + offsetSunsetMinutes;
  Serial.print("Lever du soleil a: ");
  afficherHeureReadable(sunriseTime);
  Serial.print("Coucher du soleil a: ");
  afficherHeureReadable(sunsetTime);
}

void afficherHorairesProgrammes() {
  Serial.print("Mode horaire : ");
  Serial.println(modeManuelHoraire ? "MANUEL" : "AUTOMATIQUE");
  Serial.print("Ouverture programmée à : ");
  if (modeManuelHoraire) {
    afficherHeureReadable(heureManuelleOuverture);
  } else {
    afficherHeureReadable(sunriseTime);
  }
  Serial.print("Fermeture programmée à : ");
  if (modeManuelHoraire) {
    afficherHeureReadable(heureManuelleFermeture);
  } else {
    afficherHeureReadable(sunsetTime);
  }
}

void activerRelais() {
  digitalWrite(relayPin, HIGH);  // active relais (ou HIGH selon ton module)
  delay(100);                    // petite temporisation pour que le relais se ferme bien
}

void desactiverRelais() {
  digitalWrite(relayPin, LOW);  // désactive le relais
  delay(50);
}

void ouvrirPorteInterrupt() {
  if (digitalRead(modeSwitchPin) == LOW) {  // mode manuel
    demandeOuverture = true;
  }
}

void fermerPorteInterrupt() {
  if (digitalRead(modeSwitchPin) == LOW) {  // mode manuel
    demandeFermeture = true;
  }
}

void wakeUp() {
  // Juste pour sortir de la veille, rien Ă  faire ici
}

You should investigate this first.
I wonder if your board is correctly protected.
Maybe you want to post some good photos of your circuits.

Not answering your questions, but if you intend to make updates to your circuit, instead of playing with mosfets, why don't you relace the L298N with something more efficient and skip the power cut completely.

It could miss some protection yes.

I added a diode at the output of the +5V from the stepdown module now, I still didnt test if arduino will still fried if usb powered while in the circuit.

Maybe a diode between the motor and the circuit to avoid current getting backward could be a good idea ?
Some decoupling 100nF caps for some of the UC could maybe help to stabilise a bit as well ?
I was thinking to add a 220uF cap just before the L298N +12V input too.

As it is a protoboard it will be hard to guess from pictures, but here are some:
The soldering is "a bit" sloppy, but if it was a short i suspect it will not work for hours/days before problems happening.

The idea was to test it on the protoboard and etch a little PCB afterward to have something cleaner.

I'm totally open to ideas to replace the l298N by something else. Ideally i want to keep the power use below 4mA when the motor is not in use. I am around 3mA now with the arduino sleeping and the L298N cut.



TB6612FNG for example has standby current <1uA and motor driving efficiency double compared to L298N.

1 Like

Not really since you drive the motor on both directions.

Hardware, things I would suspect:
L298 overheating and shutting down
MP1584-adjustable: Those tiny little pots can be very unreliable.
35C is very hot for an Arduino

Software:
Dusk2Dawn: website says "Use at own risk"

35C is very hot for an Arduino and most hobby type electronics.

1 Like

Noted! if it can enter sleep mode and use <1uA while still powered, it is very tempting to switch to one of those, so i can remove all the relay/mosfets parts.

I could maybe try to use one of these USB output from the solar controller for the +5v instead of the MP1584 to reduce the main +12v ?

From the Arduino official specs i see: Recommended temperature range: -25°C to +70°C.

If you are really interested in low power, use a Pro Mini instead of the UNO.

If it's stable, well regulated and free of voltage transients.

Recommended temperature range: -25°C to +70°C.

Take with a grain of salt.

And you save some significant power while driving the motor.
But you need to be sure you don't give it more than 13.5V.

1 Like

I had this in mind too yes.
But for now, without the hungry L298N, while its shut down by the relay, the total ~3mA use is fine with me like this. It should last around 3 months without any solar recharge.

Its a very cheap solar controller, so i would probably not bet on this.

Looks like you are using a Nano, if it is a clone version then all bets are off on the temperature rating.

1 Like

I personally don't like those adjustable buck regulators with the tiny pots.

Also have not ruled ot a software problem.

I still have some LM7805 in TO-220 around, would you think it is a better option?

Not for saving power.
If you are going to use a linear regulator, then you might as well connect the 12V to the Nano Vin and use it's regulator but again heat may be an issue.

1 Like

I see.
Yes +12v for the VIN input is maybe a bit much.

Would you have a recommandation of a better way to get a proper 5V line from my +12v input while keeping the power usage on the low side?

Reducing it to around ~7-8v and then use the VIN could be an option as well maybe.