Controlling servo for long periods of time

I have a setup to control the defrosting of a heat pump, the principle is a servo blocks the airflow of a sensor when the appropriate time has been reached.

This works great for 2-4 days with approximately 20 servo movements per day, then all of a sudden the servo stops working. Everything else continues working (monitoring of defrost time, temperatures, runtime and humidity).

I use servo.h and have tried implementing attached() to figure out if the servo is not connected (without success).

The servo is a cheap 9g and it is powered by a separate 6v power source with common ground.

Is there a time limit for the servo timers? Or something else I have missed/should try?

Welcome to the forum.

ontop:
Or something else I have missed/should try?

Yes there are several things you missed. They are listed here, #7 onwards and #11 in particular. I'm not trying to be condescending, but you must provide at least the basics in order for anyone here or elsewhere to be able to help you.

Paul

And you need to say whether the servo is still o.k. or has it died. Does the servo still work with a simple sweep program?

If there is any continuous load on the servo it won't last long, particularly when run on 6V.

Steve

Figured asking for the code would be the first answer :slight_smile: but debugging of code was not the question and my code is in the need of cleaning before posting...

The servo is working fine for the first couple of days then something happens, erratic servo might be the problem but the question still remains:

Is there a time limit for the servo timers?

To futher define my setup:

  • lcd display
  • servo
  • one wire temeprature probe
  • dht22
  • sd card
  • 6 v power supply
  • unsigned long arrays used for storing of runtime/defrost time

There is no load on the servo and it is attached at all times, tried dettach() after each movement as they are quite infrequnet but that did not solve the problem.

When the problem appears pulling the plug solves the problem.

There's no time limit for servos - you should be able to run them effectively forever with an appropriate power supply.

I assume that there's a problem in your code. Guessing, I expect you're using Strings and fragmenting your heap leading to an eventual crash.

I am for sure no code expert and the code is probably very far from optimal! Cleaned some testing and the brand of the pump. There might be some swedish words in there and strange usage of UL as part of trying to solve previous errors:

Please provide some pointers, part 1 of the code:

#include <Servo.h>
#include <LiquidCrystal.h>
#include <SD.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <DHT.h>
#include <DHT_U.h>
LiquidCrystal lcd(10, 9, 8, 7, 6, 5);

// Temperature
#define ONE_WIRE_BUS 14
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// SD card
#define CS_PIN 19
// SCK 13
// MISO 12
// MOSI 11
File file;

//Humidity
#define DHTPIN 3     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);

unsigned long pMs = 0UL; // last time update 
unsigned long cM = 0UL;
unsigned long oi = 0UL; //oldinterval interval at which to do something (milliseconds)
long ni = 10000; //newinterv

int count = 0;
unsigned long nii[20]={3780000UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL};
unsigned long dfr[20]={0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL,0UL};
float humsum = 0;
float hummax = 0;
float hummin = 99;
float tempsum = 0;
float average = 0;
float drifttemp = 0;
float drifttemp2 = -15;
float drifttemp3 = 0;
float average2 = 0;
unsigned long sensor1 = 0UL;
int dtt[20]={-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17};
unsigned long dtime[20];
unsigned long dint = 0;
int eff = 0;

unsigned long dfrsum = 2UL;

unsigned long niisum = 10UL;
unsigned long uo = 0UL;
unsigned long un = 0UL;
float temp; //temp evaporator
float temp2; //temp humidity sensor
float hum; //humidity
int df; //defrostfinished temp
int ndf = -30; //newdefrostfinished temp
unsigned long dfe = 1000UL; //dfe
unsigned long dfs = 1000UL; //dfs
int servoPin = 2;
Servo servo;  
boolean defrost = false;
boolean startdefrost = false;
boolean standby = false;
boolean mem = 0;
boolean dusch = false;
void setup() 
{
//Pull up
pinMode(4,INPUT_PULLUP);
pinMode(1,INPUT_PULLUP);
pinMode(0,INPUT_PULLUP);
pinMode(A1,INPUT_PULLUP);
pinMode(A2,INPUT_PULLUP);
pinMode(A3,INPUT_PULLUP);
pinMode(A4,INPUT_PULLUP);
   

  lcd.begin(16,2);
  lcd.print("Brand");
  lcd.setCursor(0,1);
  lcd.print("Defrost timer");
  delay(1000);
  lcd.clear();
  lcd.setCursor(0,0);
  pinMode(CS_PIN, OUTPUT);
  if (!SD.begin(CS_PIN)) {
     lcd.print("SD Card failed"); // don't do anything more:
     return;
     }
     lcd.print("SD card OK      ");
  servo.attach(servoPin);
  servo.write(40);
  delay(2000);
  //servo.detach();
  lcd.clear();     
  dht.begin();
  sensors.begin(); //temp sensor start
  pMs = millis();
}

void servorestart(){
  #include <Servo.h>
  int servoPin = 2;
  Servo servo;  
  servo.attach(servoPin);
  servo.write(50);
  delay(2000);
}

void loop()
{
  if ((millis() - uo) > 4000){
  uo = millis();
  sensors.requestTemperatures();
  hum = dht.readHumidity();
  temp2 = dht.readTemperature();
  lcd.setCursor(0,0);
  if (mem == 1){
    lcd.setCursor(0,0);
    lcd.print("  :  :  :  :    ");
    lcd.setCursor(0,0);
    lcd.print(dfr[0]/60000);
    lcd.setCursor(3,0);
    lcd.print(dfr[1]/60000);
    lcd.setCursor(6,0);
    lcd.print(dfr[2]/60000);
    lcd.setCursor(9,0);
    lcd.print(dfr[3]/60000);
    lcd.setCursor(12,0);
    lcd.print(dfr[4]/60000);
    mem=0;
  }
  else{
  lcd.setCursor(0,0);  
  lcd.print("T      C RH    ");
  lcd.setCursor(6,0);
  lcd.print(char(223));
  lcd.setCursor(14,0);
  lcd.print(char(37));    
  lcd.setCursor(1,0);
  temp = sensors.getTempCByIndex(0);
  lcd.print(temp,1);
  lcd.setCursor(12,0);
  lcd.print(hum, 0);
  mem=1;
  }
  }
  if ((millis()-sensor1) > 4000){
    humsum += hum;
    tempsum += temp2;
    ++average;
    if ( hum > hummax){
      hummax = hum;
    }
    if ( hum < hummin){
      hummin = hum;
    }
    sensor1 = millis();
  }
  
  if ((millis()-dint) > 10000){
       dint = millis();
       dtt[0] = (int)temp*10;
       dtime[0] = millis();
       count = 19;
        for(count = 19 ; count > 0 ; count--){
            dtt[count]=dtt[count-1];
            dtime[count] = dtime[count-1];          
        }
  } 

   
 if (((int)temp > -2) && (defrost == false) && ((millis()-pMs) > 1200000) && ((dtt[14] + 20) < dtt[2])){
      lcd.begin(16,2);
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("Defrosting      ");
      defrost = true;
      if (servo.attached() == false){
        servorestart();
      }
      else{
      servo.write(40);
      }
      delay(1000);
      //servo.detach();
        count = 0;
        for(count = 0 ; count < 19 ; count++){
            if(((dtt[count]-dtt[count+1]) >= 5)){
             //&& (dtt[count] < -50)
             dfs = dtime[count+1];
             oi = dtime[count+1] - dfe;
            }
        }
      lcd.setCursor(11,1);
      lcd.print((millis()-(unsigned long)dfs)/1000);
      lcd.setCursor(15,1);
      lcd.print("s");
      nii[0] = oi;
      ndf=-30; 
      return;
 }
   if (defrost == false){
      if ((millis()-pMs) > 600000){
        drifttemp += temp;
        ++average2;
      }
    if ((int)temp > -2 && ((millis()-pMs) > 600000)){
      nii[0] += millis()- cM;  
      cM = millis();
    }
    if ((hummax - 6.0) > hummin && dusch == false){
      nii[0] += 3600000UL;
      dusch = true;
    }
    if((millis() - pMs) > nii[0] && startdefrost == false) {
      oi = nii[0]; 
      //servo.attach(servoPin);
      if (servo.attached() == false){
        servorestart();
      }
      else{
      servo.write(155);
      }
      ndf=temp;
      startdefrost = true;
      return;
     }

I wonder if there's a memory implication to the continual re-#include-ing of servo.h?

Does it ignore subsequent includes, or over write the old one in the same place, or use new memory?

Part2:

    if ((ndf + 1) <= temp && startdefrost == true){
      servo.write(40);
      delay(1000);
      //servo.detach();
      lcd.begin(16,2);
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("Defrosting      ");
      defrost = true;
      startdefrost = false;
      dfs = millis();
      ndf=-30; 
      return;
        }
    
   
  
    lcd.setCursor(1,1);
    lcd.print("  :  :  :  :    ");
    lcd.setCursor(0,1);
    lcd.print((millis()-pMs)/60000);
    lcd.setCursor(4,1);
    if(nii[0]/60000>99){
      lcd.print(99);
      }
      else {
      lcd.print(nii[0]/60000);
      }
    lcd.setCursor(7,1);
    if(nii[1]/60000>99){
      lcd.print(99);
      }
      else {
      lcd.print(nii[1]/60000);
      }
    lcd.setCursor(10,1);
        if(nii[2]/60000>99){
      lcd.print(99);
      }
      else {
      lcd.print(nii[2]/60000);
      }
    lcd.setCursor(13,1);
    eff=100*(float)niisum/((float)niisum+(float)dfrsum);
    lcd.print(eff);
    lcd.print(char(37));// print %
   }
  if(defrost == true){
    df = (int)temp;
    lcd.setCursor(11,1);
      if(((millis() - (unsigned long)dfs)/1000)>3500){
        lcd.setCursor(0,1);
        lcd.print("Standby         ");
        dfe = millis();
        standby = true;
      }
      else{
    lcd.print((millis() - (unsigned long)dfs)/1000);
    lcd.setCursor(15,1);
    lcd.print("s");        
      }
      if((df+1) < ndf){
        defrost = false;
        pMs = millis();
        if (standby == false){
          dfe = millis();
        }
        standby =  false;
        
        if ((drifttemp2 < (drifttemp/average2)) && (drifttemp2 > -2)) {
          drifttemp3 = (0.25*drifttemp2) + 5.25;
        }
        else if ((drifttemp/average2) > -2){
          drifttemp3 = (0.25*drifttemp/average2) + 5.25;
        }
        else{
          drifttemp3 = 1;
        }
        dfr[0]=(dfe-dfs);
        count = 19;
        for(count = 19 ; count > 0 ; count--){
            dfr[count]=dfr[count-1];
            nii[count]=nii[count-1];          
        }
        
        count = 1;
        dfrsum = 0;
        niisum = 0;
        for(count = 1 ; count < 20 ; count++){
            dfrsum += dfr[count];
            niisum += nii[count];  
        }
        File dataFile = SD.open("Defrost.txt", FILE_WRITE);
        if (dataFile) {
        dataFile.print(millis()/1000);
        dataFile.print(",");
        float averagetemp = (tempsum/average);
        dataFile.print(averagetemp);
        dataFile.print(",");
        float averagehum = (humsum/average);
        dataFile.print(averagehum);
        dataFile.print(",");
        dataFile.print(oi/1000); 
        dataFile.print(",");
        dataFile.println(dfr[0]/1000);
        dataFile.close();
        average = 0;
        humsum = 0;
        hummax = 0;
        tempsum = 0;
        hummin = 99;
        dusch = false;
        }
        // if the file isn't open, pop up an error:
        else{
        lcd.setCursor(0,1);
        lcd.print("SD Error        ");
        }
        if(dfr[0] < 650000UL){
           nii[0] = oi + 300000UL;
        }   
        else if((dfr[0] >= 650000UL) && (dfr[0] < 750000UL)){
           nii[0] = oi + (((-1.8*dfr[0])+1350000UL));
        }        
        else if((dfr[0] >= 750000UL) && (dfr[0] < 850000UL)){
           nii[0] = oi - (((2.4*dfr[0])-1800000UL));
        }
        else if(dfr[0] >= 850000UL){
           nii[0] = oi - 300000UL;
        }
        if(nii[0] <= 2100000UL){
           nii[0] = 2100000UL;
        }
        if(nii[0] >= 4800000UL){
           nii[0] = 4800000UL;
        }
        if((nii[2] - nii[0]) > 300000UL){
           nii[0] = nii[2];
        }
        drifttemp2 = drifttemp/average2;
        average2 = 0;
        drifttemp = 0;
        
      }
    else{
      if( df > ndf){
        ndf = df;
      }
      delay(2000);
    }
  } 
}

bloodnok_vc:
I wonder if there's a memory implication to the continual re-#include-ing of servo.h?

Does it ignore subsequent includes, or over write the old one in the same place, or use new memory?

This was yet an attempt to solve the issue, did not work though.

I could adjust the voltage to the servo, might that work?

Scrapping the servo and adding a digital pot on the wiring of the pump sensor might be a solution but I would like to avoid fiddeling with the pump itself.

bloodnok_vc:
I wonder if there’s a memory implication to the continual re-#include-ing of servo.h?

Perhaps, depending what is in the .h file. But this code:

void servorestart(){
  #include <Servo.h>
  int servoPin = 2;
  Servo servo;  <---- this line
  servo.attach(servoPin);
  servo.write(50);
  delay(2000);
}

may well cause memory problems. @wilykat, you need to learn some basic programming concepts such as scope of variables. The line I indicated above creates a new instance of a servo object. This exists only until the function ends. It has no effect on the servo variable declared at the top of the sketch.

My advice would be to dismantle the code which is quite complex and build it from scratch to produce the minimal code at which the problem occurs. Of course, if it happens randomly and only every few days, that could take forever.

Can you isolate the circumstances in which the problem occurs, ie is it when it's doing "this" but not "that"?

@PaulRB: This was added as an attempt to re-initiate the servo as part of problem solving, the problem occurs without this part.

@bloodnok_vc: Agree, I try to fool the processor of the equipment and have been forced to add a lot of ifs depending of the circumstances in the pump. I have not tried sweep for a couple of days, that might tell if it is a general problem and not code specific.

Since your project is to do with de-frosting, and you're heading into spring, you have the summer to work on it :wink:

Hehe, you are spot on! This is actually project number three which was initiated last summer.

no 1. Defrosting with a thermostat controlled fan - only moved the ice to other places.
no 2. Melt ice with a heat cable - only helped where the cable was placed.
no 3. Arduino to limit the runtime and hence have less ice to melt, works very well for the first 2-4 days then the servo stops (display, SD, probes still works fine)