Temperature controlled Linear Actuator issue with Relay Timer

Hello. I need some assistance with my temperature controlled linear actuator. I'm using it to open and close a cupboard door for better airflow and cooling of my server cabinet.

The actuator is 30mm and extends at 0.7mm/s. I want the relay to activate at 29.5c extend the actuator which takes 4.3sec, then turn off the relay. Wait until the temp is 27.5c and retract the actuator in a similar way.

An example of a similar relay and temp sensor design is here:

I'm using a SHT31 temp sensor instead because it was all i had. The code has changed a fair bit and ive added 'blink without delay' type code to still monitor the temperature.

My Code

The problem i have is that the timing of my delays seems off. I think the issues are all in my 'void loop' section but i cant think what it would be.

Any ideas would be appreciated.

Hi, @mschipper
Please post your code using code tags so it can be viewed.
To add code please click this link;

Thanks... Tom.. :grinning: :+1: :coffee: :australia:

Looks quite complicated for your goal.
You want it to read the temperature how often?
You want it to open at a certain temperature and close at another?
Those are the only real requirements?

Yes open and close at certain temperature set points but the 4.3sec off delay is to save the motor of the actuator.

If i was to check the temp every 30 seconds that would be fine.

Currently its checking nonstop. The relay turns on and off after the delay but then turns straight back on again even if the temp is the same.

#include <Wire.h>
#include <SHT31.h> // https://github.com/RobTillaart/SHT31
#include <timeObj.h> // https://github.com/leftCoast/LC_baseTools

#define RELAY1_PIN 6  //relay 1 pin to activate coil
#define RELAY2_PIN 7  //relay 2 pin to activate coil
#define SHT31_ADDRESS   0x44

uint32_t start;
uint32_t stop;

SHT31 sht;

int open_door_temp = 29.5;
int close_door_temp = 27.5;
bool        relay1State;
bool        relay2State;
timeObj     relayTimer(4300);  // Its in miliseconds. 1000 ms = a second, 60 seconds = minute 5 minutes..
timeObj     loopTimer(1000);        // I guess you want the loop slowed down?

void setup(void) {
   
   Serial.begin(115200);
   Serial.println(__FILE__);
   Serial.print("SHT31_LIB_VERSION: \t");
   Serial.println(SHT31_LIB_VERSION);

   Wire.begin();
   sht.begin(SHT31_ADDRESS);
   Wire.setClock(100000);

   uint16_t stat = sht.readStatus();
   Serial.print(stat, HEX);
   Serial.println();

   // Relay setup and shut off..
   pinMode(RELAY1_PIN, OUTPUT);
   pinMode(RELAY2_PIN, OUTPUT);   
   digitalWrite(RELAY1_PIN, HIGH);
   digitalWrite(RELAY2_PIN, HIGH);  
   relay1State = false;              // Relay is off.
   relay2State = false;              // Relay is off.

   // Fire up your loop slowing timer.
   loopTimer.start();
}


// A function that turns the fan on and off.
bool switchRelay(bool onOff, char relay_pin) {
         
   if (onOff) {                        // If we want the relay on..
      digitalWrite(relay_pin, LOW);    // Fire it up.
      relayTimer.start();              // Start the timer.
   } else {                            // Else, we want it off..
      digitalWrite(relay_pin, HIGH);   // shut it down.
   }
   
   bool relayState = onOff;                 // The relay state is now what they asked for.
   return relayState;
}


void loop(void) {
   sht.read();
   float temp = sht.getTemperature(); // Values for heat and tempature.
  
   // Serial.print is useful if you are using serial monitor on PC and is not required for this code to work 
   // Serial.print("\t");
   // Serial.print(temp, 1);
   // Serial.print("\t");
   // Serial.println(temp, 1);
   // delay(100);

   if (loopTimer.ding()) {                                 // If the loop timer has expired..
      if (!relay1State && !relay2State) {                  // If the fan's off..
         if (temp > open_door_temp) {                      // And we are past our temp..
            relay1State = switchRelay(true, RELAY1_PIN);   // Open the actuator!
			      relay2State = switchRelay(false, RELAY2_PIN);
         } else if (temp <= open_door_temp) {
            relay1State = switchRelay(false, RELAY1_PIN);			 
            relay2State = switchRelay(true, RELAY2_PIN);   // Close the actuator!
         }
      } else if (relayTimer.ding()) {                      // Else, if the fan IS running, and the timer has expired..
         if (temp > open_door_temp) {                      // And the room has reached ambiant..
            relay1State = switchRelay(false, RELAY1_PIN);  // Off with the relay!
         } else if (temp <= open_door_temp) {
            relay2State = switchRelay(false, RELAY2_PIN);  // Off with the relay!
         }
      }
      
      loopTimer.start();                                 // Reset your loop timer.
   }
}

Timing is not the way to control actuator positioning, sooner or later, the actuator will be run to it's end of stroke and it, or it's driver, will burn up. You need limit switches or position feedback if the actuators don't have one or the other. Post a link to the actuator or brand name and exact part number.

Its a fairly cheap one since i dont need anything heavy duty for a cupboard door. :wink: It's a OK03 ismini linear actuator.

Sounds like it has a limit switch "...... means the length when linear actuator 100% fully open, meanwhile,it will touch the head limited switch and stop automatically."

12V Micro Linear Actuator: 12V 7MMS 128N

Either way i couldnt see the need to have the relay on all the time if it doesnt need to be which is why i though a short relay timer would be appropriate.

Hi,


It looks as though it is fitted with internal limit switches, to protect itself.

But you need external switches to let your code know if the arm is at either end of its travel.

Tom... :grinning: :+1: :coffee: :australia:

I worked it out. They delayed switch is probably overkill but its more a safety than anything else.

Here is my finished code. If anyone can think or a tidier way to do the same thing i'd be interested. As i said it works but i dont like repeating similar code like i did in the 'void loop' section.

Temp-Controlled-Linear-Actuator

I ended up using a L9110 stepper motor controller instead of the relays as it was a better sized unit.

#include <Wire.h>
#include <SHT31.h> // https://github.com/RobTillaart/SHT31

#define a1a_PIN 6  //a1a pin to L9110
#define a1b_PIN 7  //a1b pin to L9110
#define SHT31_ADDRESS   0x44

uint32_t start;
uint32_t stop;

SHT31 sht;

int open_door_temp = 30;
int close_door_temp = 28;
bool        a1aState;
bool        a1bState;
float        tempReached;
unsigned long tempReachedMillis; // when temp was reached
unsigned long actuatorTurnedOnAt; // when actuator was turned on
unsigned long turnOffDelay = 5000; // turn off actuator after this. Based on a 30mm, 7mm/s actuator it should take 4.3secs to open/close.

void setup(void) {
   
   Serial.begin(115200);
   Serial.println(__FILE__);
   Serial.print("SHT31_LIB_VERSION: \t");
   Serial.println(SHT31_LIB_VERSION);

   Wire.begin();
   sht.begin(SHT31_ADDRESS);
   Wire.setClock(100000);

   uint16_t stat = sht.readStatus();
   Serial.print(stat, HEX);
   Serial.println();

   // L9110 setup and shut off..
   pinMode(a1a_PIN, OUTPUT);
   pinMode(a1b_PIN, OUTPUT);   
   digitalWrite(a1a_PIN, HIGH);
   digitalWrite(a1b_PIN, HIGH);  
   a1aState = true;              // L9110, actuator closed
   a1bState = false;              // L9110, actuator open
}


// A function that turns the actuator on and off.
bool switchL9110(bool onOff, char L9110_pin) {
         
   if (onOff) {                        // If we want the L9110 on..
      digitalWrite(L9110_pin, LOW);    // Fire it up.
   } else {                            // Else, we want it off..
      digitalWrite(L9110_pin, HIGH);   // shut it down.
   }
   
   bool pinState = onOff;                 // The L9110 state is now what they asked for.
   return pinState;
}

void loop(void) {
	// get the time at the start of this loop()
	unsigned long currentMillis = millis(); 
	
	sht.read();
	float temp = sht.getTemperature(); // Values for heat and tempature.
  
	// Serial.print is useful if you are using serial monitor on PC and is not required for this code to work 
	// Serial.print("\t");
	// Serial.print(temp, 1);
	// Serial.print("\t");
	// Serial.print(a1aState, 1);
	// Serial.print("\t");
	// Serial.print(tempReached, 1);
	// Serial.print("\t");
	// Serial.println(a1bState, 1);

	if (tempReached <= open_door_temp && temp > open_door_temp) {
		tempReachedMillis = currentMillis;
		a1aState = switchL9110(true, a1a_PIN);   // Open the actuator!
		a1bState = switchL9110(false, a1b_PIN);
		tempReached = temp;
		if (a1aState) {
			actuatorTurnedOnAt = currentMillis;    // start the timer.
		}
	}
	
	if (tempReached > close_door_temp && temp <= close_door_temp) {
		tempReachedMillis = currentMillis;
		a1aState = switchL9110(false, a1a_PIN);			 
		a1bState = switchL9110(true, a1b_PIN);   // Close the actuator!
		tempReached = temp;
		if (a1bState) {
			actuatorTurnedOnAt = currentMillis;    // start the timer.
		}
	}
	
	if (a1aState) {
		// okay, actuator on, check for how long
		if ((unsigned long)(currentMillis - actuatorTurnedOnAt) >= turnOffDelay) {
			a1aState = false;
			digitalWrite(a1a_PIN, HIGH);   // shut it down.
		}
	}
	
	if (a1bState) {
		// okay, actuator on, check for how long
		if ((unsigned long)(currentMillis - actuatorTurnedOnAt) >= turnOffDelay) {
			a1bState = false;
			digitalWrite(a1b_PIN, HIGH);   // shut it down.
		}
	}
}