Arduino Uno Project for Curtains fails from time to time

I made a project with Arduino Uno to open and close the blinds based on the light outside. When the sun rises in the morning, the blinds go up so natural light will enter the room, when it's dark they close. An LDR is used as a sensor. Two stepper motors are rising the blinds using two separate H bridge drivers. Supply is 12vDC connected directly to the Arduino power plug.
The project also uses an ENC28J60 Ethernet adapter so one can do the following via a rudimentary html webpage:

  • See the light intensity read by the sensor,

  • Manual and Auto control, when in manual mode, the user can lift or descend the blinds manually (fully or with 10% increments)

  • See the room temperature and humidity as a bonus.

  • See how many times the blinds were risen or descended since the beginning of time (the information is recorded in the arduino eeprom, also the last settings are stored to eeprom each time an action is taken so it is read back in case of a power failure)

  • See the uptime of the system

The problem I have is the following:

After I power-cycle the Arduino everything works great. Blinds are going up/down, parameter values show correctly etc. After around two days, the web service doesn't work but the automatic function works correctly. After 3 or so days, the Arduino just hangs in a for loop it seems because it managed to run one of the stepper motor continuously for many minutes until the motor overheated, melted the PLA gear connected to the blind and stopped.
I also have a FAN (to cool down the drivers) and a relay that sends 12V to the motor drivers and is switched whenever a command is sent to the motors. The fan was on and continuously running for some time when I observed the issue.
If I power-cycle the Arduino, everything works fine again.

  1. What can I do to protect everything for (burning down a motor or even the house down)? What kind of fuse/resistor etc. can I use or what other solution can work?
  2. What can I do to make the Arduino show the webpage for more than one-two days in a row? Any idea why this is happening? Why is it the controller random/inconsistent?
  3. As a simple solution, should I just automatically reset the Arduino every 24h in the software with the reset pin connected to a DO? :slight_smile:

This is my first thread here. Hope it's the right place. Thank you for any responses.

What made you think that your question has anything to do with the Website and Forum section which is clearly stated to be for "Improvements for the web system, applications to moderator, spam, etc."? I have suggested to the Moderator to move it to the Project Guidance section.

This sort of carelessness makes unnecessary work for the Moderators.

Please read How to get the best out of the Forum

...R

There are devices called thermal fuses that I have seen with a open point under 75C, once it overheats you need to replace the fuse. You can mount the fuse to the motor and have it open the main power source. They are less then $0.08 each, you may have to buy a few spares, like 99 of them. Check your router settings, your lease might be expiring causing the disconnect. Just a guess but it happened to me a few years back with an older router. This is a starting point SWAG as I do not know your systems.

If you post your code, you will have a better chance of someone helping you. It sounds like it may be a memory issue that slowly builds up until something breaks

To prevent steppers from overheating, lower the drive current. Them overheating to the extent you describe makes me think that you have set that current too high to begin with.

Finally, the code, 1st part:

#include <EtherCard.h>
#include <EEPROM.h>
#include "DHT.h"
#define DHTPIN 3  
#define DHTTYPE DHT11   // DHT 11
#define WINDOW_SIZE 35 //array for filtering values of the light sensor
int INDEX = 0; // index for the light filter
int SUM = 0; // sum for the light filter
int READINGS[WINDOW_SIZE];
int AVERAGED_SENSOR = 0; // average value of the sensor
DHT dht(DHTPIN, DHTTYPE);
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
static byte myip[] = { 192, 168, 1, 147 }; // CS=10,  SI=11, SO = 12, SCK=13
#define BUFFER_SIZE 930 //900
byte Ethernet::buffer[BUFFER_SIZE];
BufferFiller bfill;


//------------VARIABILE DRAPERII------------//


int inA1 = A1; // input 1 of stepper 1
int inA2 = A2; // input 2 of stepper 1
int inB1 = A3; // input 3 of stepper 1
int inB2 = A4; // input 4 of stepper 1
int inA3 = 6; // input 1 of stepper 2
int inA4 = 7; // input 2 of stepper 2
int inB3 = 8; // input 3 of stepper 2
int inB4 = 9; // input 4 of stepper 2
//Variabile globale
int stepDelay = 28; // Delay between steps in milliseconds for stepper 1 up
int LogPOS = 0;
int lightSensorPin = A0;
int temp=0; //temperature
int hum=0; //humidity
int hif=0; // heat index
int x = 0; //verificare pozitie motor 1 in functii
int y = 0; //verificare pozitie motor 2 in functii
int z = 0; //variabila numar de pasi executie functii motor
int Sensor;
int LogUP = 0; //nr. de ridicari
int LogDown = 0; //nr. de coborari
int address1 = 0;
int address2 = 1;
int address3 = 2;
int address4 = 3;
int address5 = 4;
byte RecPosST;
byte RecPosDR;
byte RecNrUrcari;
byte RecNrCoborari;
byte RecCtrl; //store Control State to EEPROM
byte RecState; //store last state to EEPROM
//bool MagSensST;
//bool MagSensDR = false;
unsigned long time_now = 0;
int period=2000;
//---------VARIABILE PAGINA WEB----------


bool CTRLST = false; //variabila control automat/manual
bool ST10M = false; //variabila control stanga 10% -
bool ST10P = false; //variabila control stanga 10% +
bool STST = false; // variabila control draperie stanga
bool DRST = false; // variabila control draperie dreapta
bool DR10M = false; //variabila control dreapta 10% +
bool DR10P = false; //variabila control dreapta 10% -
const char http_OK[] PROGMEM =
  "HTTP/1.0 200 OK\r\n"
  "Content-Type: text/html\r\n"
  "Pragma: no-cache\r\n\r\n";


const char http_Found[] PROGMEM =
  "HTTP/1.0 302 Found\r\n"
  "Location: /\r\n\r\n";


const char http_Unauthorized[] PROGMEM =
  "HTTP/1.0 401 Unauthorized\r\n"
  "Content-Type: text/html\r\n\r\n"
  "<h1>401 Unauthorized</h1>";


void homePage()
{
  // long d = millis()/86400000; // 86400000 milliseconds in a day
  long t = millis() / 1000;
  word h = t / 3600;
  byte m = (t / 60) % 60;
  byte s = t % 60;
  bfill.emit_p(PSTR("$F"
                    "<meta http-equiv='refresh' content='5'/>"
                    "<body bgcolor=""#99CCFF"">"
                    "<div style = 'display:flex; position:absolute; top:0; bottom:0; right:0; left:0; '>"
                    "<div id = 'divC' style = 'margin:auto;'> "
                    "<h2>"
                    "
"
                    "Lumina: $D ☀"
                    "

"
                    "Control:&nbsp;<a href=\"?CONTROL=$F\">$F</a>"
                    "

"
                    "ST:&nbsp;"
                    "<a href=\"?STANGA10M=$F\">$F</a>&nbsp;&nbsp;&nbsp;&nbsp;"
                    "<a href=\"?STANGA=$F\">$F</a>&nbsp;&nbsp;&nbsp;&nbsp;"
                    "<a href=\"?STANGA10P=$F\">$F</a>"
                    "

"
                    "DR:&nbsp;"
                    "<a href=\"?DREAPTA10M=$F\">$F</a>&nbsp;&nbsp;&nbsp;&nbsp;"
                    "<a href=\"?DREAPTA=$F\">$F</a>&nbsp;&nbsp;&nbsp;&nbsp;"
                    "<a href=\"?DREAPTA10P=$F\">$F</a>"
                    "

"
                    "Urcari: $D  &nbsp;&nbsp;&nbsp;&nbsp; Coborari: $D"
                    "

"
                    "Temp: $D ℃, Umid: $D %, Hindex: $D"
                    "

"
                    "Timp: $D$D:$D$D:$D$D</h2>"
                    "</div>"
                    "</div>"


                   ),
                   
               http_OK,
               AVERAGED_SENSOR,
              // Sensor,
               CTRLST ? PSTR("off") : PSTR("on"), CTRLST ? PSTR("AUTO") : PSTR("MANUAL"),
               ST10M ? PSTR("off") : PSTR("on"), ST10M ? PSTR("10% ▽") : PSTR("10% ▽"),
               STST ? PSTR("off") : PSTR("on"), STST ? PSTR("  SUS  ") : PSTR("  JOS  "),
               ST10P ? PSTR("off") : PSTR("on"), ST10P ? PSTR("10% △") : PSTR("10% △"),
               DR10M ? PSTR("off") : PSTR("on"), DR10M ? PSTR("10% ▽") : PSTR("10% ▽"),
               DRST ? PSTR("off") : PSTR("on"), DRST ? PSTR(" SUS ") : PSTR("  JOS  "),
               DR10P ? PSTR("off") : PSTR("on"), DR10P ? PSTR("10% △") : PSTR("10% △"),
               LogUP,
               LogDown,
               temp,
               hum,
               hif,
               h / 10, h % 10, m / 10, m % 10, s / 10, s % 10);
}


void setup()
{
 
  //  //---------Initializare IO Draperii----------//
  pinMode(inA1, OUTPUT);
  pinMode(inA2, OUTPUT);
  pinMode(inB1, OUTPUT);
  pinMode(inB2, OUTPUT);
  pinMode(inA3, OUTPUT);
  pinMode(inA4, OUTPUT);
  pinMode(inB3, OUTPUT);
  pinMode(inB4, OUTPUT);
  pinMode(4, OUTPUT);
  //END ---------Initializare IO Draperii----------//
  if (ether.begin(BUFFER_SIZE, mymac) == 0)
    Serial.println("Cannot initialise ethernet.");
  else
    Serial.println("Ethernet initialised.");
  ether.staticSetup(myip);
  if (EEPROM.read(address5)==1) {CTRLST=true;} else {CTRLST=false;}
  if (EEPROM.read(address1)==98) {DRST=true;} else {DRST=false;}
  if (EEPROM.read(address2)==98) {STST=true;} else {STST=false;}
}

2nd part of the code, functions that command the motors to go forward/backwards/stop and then other functions that call them in order to execute the fwd and backwards for a certain amount of steps (z).

//motor 1 going fwd
void step1u2() {
  digitalWrite(inA1, LOW);
  digitalWrite(inA2, HIGH);
  digitalWrite(inB1, HIGH);
  digitalWrite(inB2, LOW);
  delay(stepDelay);


}
2nd part, some functions to control the motors:
//motor 1 going fwd
void step2u2() {
  digitalWrite(inA1, LOW);
  digitalWrite(inA2, HIGH);
  digitalWrite(inB1, LOW);
  digitalWrite(inB2, HIGH);
  delay(stepDelay);
}


//blabla functions for sending pulses to the steper 1 and stepper 2 to go forward and backwards


//---------STOP MOTORS-----------------------


void stopMotor1() {
  digitalWrite(inA3, LOW);
  digitalWrite(inA4, LOW);
  digitalWrite(inB3, LOW);
  digitalWrite(inB4, LOW);
}


void stopMotor2() {
  digitalWrite(inA1, LOW);
  digitalWrite(inA2, LOW);
  digitalWrite(inB1, LOW);
  digitalWrite(inB2, LOW);
}


//----------END STOP MOTORS-------------//


//UP function for drapes right automatic
void drapesUP1() {
//  int i=0;


  for (int i = 0; i <= z; i++) {
    step1u1();
    step2u1();
    step3u1();
    step4u1();
  }
  
  x = 98;
  EEPROM.write(address1, x); // write the latest value to EEPROM
}


//DOWN function for drapes right
void drapesDOWN1() {
 for (int i = 0; i <= z; i++) {
    step3d1();
    step2d1();
    step1d1();
    step4d1();
  }
  x = 99;
  EEPROM.write(address1, x); // write the latest value to EEPROM
}


//UP function for drapes left
void drapesUP2() {
 for (int i = 0; i <= z; i++) {
    step1u2();
    step2u2();
    step3u2();
    step4u2();
  }
  y = 98;
  EEPROM.write(address2, y); // write the latest value to EEPROM
}


//Down function for drapes left
void drapesDOWN2() {
  for (int i = 0; i <= z; i++) {
    step3d2();
    step2d2();
    step1d2();
    step4d2();
  }
  y = 99;
  EEPROM.write(address2, y); // write the latest value to EEPROM
}


//-----------------MANUAL CTRL 10% ---------------------------


//UP function for drapes right automatic
void drapesUP110() {
  int i = 0;
  do {
    i = i + 1;
    step1u1();
    step2u1();
    step3u1();
    step4u1();
  }
  while (i < z);
}


//DOWN function for drapes right
void drapesDOWN110() {
  int i = 0;
  do {
    i = i + 1;
    step3d1();
    step2d1();
    step1d1();
    step4d1();
  }
  while (i < z);
}


void drapesUP210() {
  int i = 0;
  do {
    i = i + 1;
    step1u2();
    step2u2();
    step3u2();
    step4u2();
  }
  while (i < z);
}


//Down function for drapes left
void drapesDOWN210() {
  int i = 0;
  do {
    i = i + 1;
    step3d2();
    step2d2();
    step1d2();
    step4d2();
  }
  while (i < z);
}

And finally, the loop part, without the manual control that’s not relevant. It’s a lot of code, but many things are repeating themselves…
Sketch uses 15,498 bytes (48%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,669 bytes (81%) of dynamic memory, leaving 379 bytes for local variables. Maximum is 2,048 bytes.

//-------------------------------PROGRAM GENERAL-----------------------------------------PROGRAM GENERAL---------------------------------------PROGRAM GENERAL------------------
void loop()
{






  //------------------------------VERIFICARE BUTOANE WEBPAGE--------------------------------VERIFICARE BUTOANE WEBPAGE -----------------------------VERIFICARE BUTOANE WEBPAGE-----




  Sensor = analogRead(lightSensorPin);
  SUM=SUM-READINGS[INDEX]; // Remove the oldest entry from the sum
  READINGS[INDEX]=Sensor;  // Add the newest reading to the window
  SUM=SUM+Sensor; // Add the newest reading to the sum
  INDEX=(INDEX+1)%WINDOW_SIZE; // Increment the index, and wrap to 0 if it exceeds the window size
  AVERAGED_SENSOR=SUM/WINDOW_SIZE; // Divide the sum of the window by the window size for the result
  delay(50);
  // lux=(250.000000/(ADC_val*Sensor))-50.000000;
  RecPosDR = EEPROM.read(address1);
  RecPosST = EEPROM.read(address2);
  RecNrUrcari = EEPROM.read(address3);
  RecNrCoborari = EEPROM.read(address4);
  RecState=EEPROM.read(address5);
  LogUP = RecNrUrcari;
  LogDown = RecNrCoborari;
  x = RecPosDR;
  y = RecPosST;
  word len = ether.packetReceive();   // check for ethernet packet
  word pos = ether.packetLoop(len);   // check for tcp packet
  if (pos) {
    bfill = ether.tcpOffset();
    char *data = (char *) Ethernet::buffer + pos;
    if (strncmp("GET /", data, 5) != 0) {
      // Unsupported HTTP request
      // 304 or 501 response would be more appropriate
      bfill.emit_p(http_Unauthorized);
    }
    else
    {
      data += 5;
      if (data[0] == ' ')
      {
        // Return home page
      homePage();
      }
      else if (strncmp("?CONTROL=on ", data, 12) == 0 )  {
        // Control status AUTOMAT
        CTRLST = true;
        EEPROM.write(address5, 1); //log last state as being AUTO
        bfill.emit_p(http_Found);
      }
      else if (strncmp("?CONTROL=off ", data, 13) == 0) {
        // Control status MANUAL
        CTRLST = false;
        EEPROM.write(address5, 0); //log last state as being MAN
        bfill.emit_p(http_Found);
      }
      //Dreapta status sus
      else if (strncmp("?DREAPTA=on ", data, 12) == 0) {
        DRST = true;
        bfill.emit_p(http_Found);
      }
      //Dreapta status jos
      else if (strncmp("?DREAPTA=off ", data, 13) == 0) {
        DRST = false;


        bfill.emit_p(http_Found);
      }
      //Stanga status sus
      else if (strncmp("?STANGA=on ", data, 11) == 0) {
        STST = true;
        bfill.emit_p(http_Found);
      }
      //stanga status jos
      else if (strncmp("?STANGA=off ", data, 12) == 0) {
        STST = false;
        bfill.emit_p(http_Found);
      }
      //Stanga 10% pozitiv
      else if ((strncmp("?STANGA10P=on ", data, 14) == 0) || (strncmp("?STANGA10P=off ", data, 15) == 0)) {
        ST10P = true;
        bfill.emit_p(http_Found);
      }
      //Stanga 10% negativ
      else if ((strncmp("?STANGA10M=on ", data, 14) == 0) || (strncmp("?STANGA10M=off ", data, 15) == 0)) {
        ST10M = true;
        bfill.emit_p(http_Found);
      }
      //Dreapta 10% pozitiv
      else if ((strncmp("?DREAPTA10P=on ", data, 15) == 0) || (strncmp("?DREAPTA10P=off ", data, 16) == 0)) {
        DR10P = true;
        bfill.emit_p(http_Found);
      }
      //Dreapta 10% negativ
      else if ((strncmp("?DREAPTA10M=on ", data, 15) == 0) || (strncmp("?DREAPTA10M=off ", data, 16) == 0)) {
        DR10M = true;
        bfill.emit_p(http_Found);
      }
      else {
        // Page not found
        bfill.emit_p(http_Unauthorized);
      }
    }
    ether.httpServerReply(bfill.position());    // send http response
  }


  //------------------------------CONTROL AUTOMAT----------------------------------CONTROL AUTOMAT ----------------------------------CONTROL AUTOMAT--------------------------


  if (CTRLST == true)
    
  {
    if (AVERAGED_SENSOR > 6 && x == 99 && AVERAGED_SENSOR <50) //Light diode high, control to auto, drapes are not up
    {
      if (RecState==0)
      {
        EEPROM.write(address5, 1); //log last state as being AUTO
      }
      digitalWrite(4, HIGH); //RELAY ON
      z = 216; // cursa maxima motor stanga
      drapesUP1();
      stopMotor1();
      digitalWrite(4, LOW); //RELAY OFF
      LogUP = LogUP + 1;
      EEPROM.write(address3, LogUP); //write no of descends to EEPROM
      DRST=true;
      delay(500);


    }
    if (AVERAGED_SENSOR > 6 && y == 99 && AVERAGED_SENSOR <50) //Light diode high, control to auto, drapes are not up
    {
      if (RecState==0)
      {
        EEPROM.write(address5, 1); //log last state as being AUTO
      }
      digitalWrite(4, HIGH); //RELAY ON
      z = 232; // cursa maxima motor dreapta
      drapesUP2();
      stopMotor2();
      // delay(200);
      digitalWrite(4, LOW); //RELAY OFF
      LogUP = LogUP + 1;
      EEPROM.write(address3, LogUP); //write no of descends to EEPROM
      STST=true;
      delay(500);
    }


    if (AVERAGED_SENSOR < 1 && x == 98 ) //Light diode low, control to auto, drapes are up
    {
       if (RecState==0)
      {
        EEPROM.write(address5, 1); //log last state as being AUTO
      }
      EEPROM.write(address5, 1); //log last state
      digitalWrite(4, HIGH); //RELAY ON
      z = 216; //z maxim motor stanga
      drapesDOWN1();
      stopMotor1();
      digitalWrite(4, LOW); //RELAY OFF
      LogDown = LogDown + 1;
      EEPROM.write(address4, LogDown); //write no of descends to EEPROM
      DRST=false;
      delay(500);
    }
    if (AVERAGED_SENSOR < 1 && y == 98 ) //Light diode low, control to auto, drapes are up
    {
       if (RecState==0)
      {
        EEPROM.write(address5, 1); //log last state as being AUTO
      }
      digitalWrite(4, HIGH); //RELAY ON
      z = 232; //z maxim motor dreapta
      drapesDOWN2();
      stopMotor2();
      LogDown = LogDown + 1;
      digitalWrite(4, LOW); //RELAY OFF
      EEPROM.write(address4, LogDown); //write no of descends to EEPROM
      STST=false;
      delay(500);
    }
    
  }


  
if (millis() >= time_now+period) {
time_now += period;
hum = dht.readHumidity(); //humidity
temp = dht.readTemperature(); //temperature
hif = dht.computeHeatIndex(temp, hum, false); // heat index


} 
}

For long programs please just add the .ino file as an attachment. Joining bits together introduces the risk of creating additional errors.

Better still, create a short program that illustrates the problem.

…R

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.