Controlling electrical heating element with PWM and relay -

Hi,

Question:

If I try to regulate the output of an electrical heating element (say from a stove or something) by connecting it to a relay and then to an arduino, can I use PWM to regulate the general output of the heater?

The reason I'm wondering is because the frequency of the PWM (around 500Hz?) is about 10 times higher than that of the electrical grid (50Hz) so I don't know if this is "bad for the grid".

I recall reading somewhere (it might've been here for all I remember) that connecting dimmers (from light bulbs etc) to heaters messes with the frequency of the grid, so I was wondering if (a) this is true and (b) this would happen with my setup.

Thanks!

Make your own pwm with looong intervals.

I assume you mean the relay will turn on the power to the heater but where does the PWM come in?
How many watts is the heater?

I have done this with a chicken incubator using a SSR but I did slow down the frequency though. I changed over to PID direct to relay as the ssslllooowww response from the heating element didn't require PWM.

Try PID_RelayOutput in the PID examples.

You cannot use "standard" PWM with a relay to run a heating element since the relay cannot respond to high frequency signals. It's normal to run heaters in "burst" mode whereby you turn the heater on for several seconds/minutes, then turn it off for several seconds/minutes. By this means you average out amount of heat produced to maintain a 'constant' temperature.

Also, if you are using a PID type algorithm you will require some degree of "D" or derivative control which looks at the 'rate-of-rise' and 'rate-of-fall' of the measured variable so's your controller can begin taking the necessary corrective action before the set-point is actually reached.

Edit: Brain was out of gear. D is Derivative not Differential since it is dV/dt ie rate of change of the variable V

1 Like

Thanks for al the answers so far!

So even solid state relays can't handle that speed?

I would use a 500W and a 1000W element (so i might have to incorporate some coding for that too).

My idea was indeed to use a PID to regulate the heating. (I'm still reading up on it more cause I'm not a 100% up to speed with it yet, so forgive any mistakes regarding PID).

So if I get it the consensus would be to use PID with a Kd that is not zero, and write my own PWM-code to create a 1 second interval or something? (Or would say, 10Hz be too much still?)

Is there any other way you can control the output of a 500W heating element?

(another idea I had was to use a gas heater for my purpose and install a stepper motor and a Hall-effect sensor to control the gasflow... but that's a whole other story)

Thank you!

Nelson_Pelson:
So even solid state relays can't handle that speed?

No. SSRs use a TRIAC as the control element. TRAICs (and the related SCR element used for DC control) can only be turned on, you cannot manually turn them off. They only turn off when the current through them falls below a certain turn-off value.

The fastest type of control you can use with a TRIAC is phase control. This requires monitoring the zero-crossing of the AC power and firing the TRIAC at a specified time after each zero-crossing. I think this is called phase control, or something similar.

You likely don't need to bother with the complexity of phase like that. A large thermal system like a stove is likely to have extremely slow response times. Other people are suggesting using a very slow PWM frequency (more like 0.5 HZ instead of 0.5 kHz), and I agree. It will be much easier to do, and the performance loss compared to phase control will be completely minuscule.

Nelson_Pelson:
Thanks for al the answers so far!

So even solid state relays can't handle that speed?

I would use a 500W and a 1000W element (so i might have to incorporate some coding for that too).

My idea was indeed to use a PID to regulate the heating. (I'm still reading up on it more cause I'm not a 100% up to speed with it yet, so forgive any mistakes regarding PID).

So if I get it the consensus would be to use PID with a Kd that is not zero, and write my own PWM-code to create a 1 second interval or something? (Or would say, 10Hz be too much still?)

Is there any other way you can control the output of a 500W heating element?

(another idea I had was to use a gas heater for my purpose and install a stepper motor and a Hall-effect sensor to control the gasflow... but that's a whole other story)

Thanks you!

As I said before, the PID_RelayOutput example seems to suit your project exactly.

/********************************************************
 * PID RelayOutput Example
 * Same as basic example, except that this time, the output
 * is going to a digital pin which (we presume) is controlling
 * a relay.  the pid is designed to Output an analog value,
 * but the relay can only be On/Off.
 *
 *   to connect them together we use "time proportioning
 * control"  it's essentially a really slow version of PWM.
 * first we decide on a window size (5000mS say.) we then 
 * set the pid to adjust its output between 0 and that window
 * size.  lastly, we add some logic that translates the PID
 * output into "Relay On Time" with the remainder of the 
 * window being "Relay Off Time"
 ********************************************************/

#include <PID_v1.h>
#define RelayPin 6

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;
void setup()
{
  windowStartTime = millis();
  
  //initialize the variables we're linked to
  Setpoint = 100;

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(0);
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
  else digitalWrite(RelayPin,LOW);

}

And something like one of these relays for the element. This one is way over rated for your proposed 1500w but you get the idea.

Okay cool, that all makes a lot more sense now!

moose4621:
As I said before, the PID_RelayOutput example seems to suit your project exactly.

I had looked into that code before but wasn't up to speed with how the PID library worked exactly. A little more reading helped a lot!

One more question about that code tho:

void loop()
{
  Input = analogRead(0);
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
  else digitalWrite(RelayPin,LOW);

}

Why is the output here in seconds? (or why is the output compared to how much time has elapsed within the Windowsize?
If the input is an Analogueread (so in my case probably a thermocouple) then how is the output a time? Maybe I'm still confused about the PID... I'm still reading up on it (sorry 'bout that!)

Quick edit: I understand that the output isn't necessarily the same unit as the input, but I'm confused at how the PID knows 'what to output'....

Nelson

Not sure if I can explain this but here goes. :slight_smile:

The PID tries to achieve setpoint. (100deg).
From a cold start the PID Output will be 5000, (windowSize), and so the relay will be on for the whole 5 sec window.
As the Input, (thermistor)?, gets closer to Setpoint the PID reduces the Output which is then compared to the windowSize and the relay is turned on for a proportional portion of the 5 sec window.
When the Input equals or exceeds the Setpoint, the Output will reduce to low numbers or 0, (depending on the speed of response of the Input and the PID tuning), and the relay will be off for the major portion of the 5 second window accordingly.
You have the PID to tune the response between the Input and Output and you also have the window size to play with.
A very slow responding system means you can increase the windowSize while a fast responding system would require a small windowSize.

I hope that makes sense. It makes sense in my mind while I am typing but so often, it doesn't make sense to the reader. :confused:
There are many people on here who are far more knowledgeable than I to help you with the tuning.

1 Like

Simple translation of the three terms of PID. The output signal is a combination of three factors

P Proportional Output component is proportional to the difference (the error) between the set-point (the desired variable) and the input (the measured variable) So the greater the error, the greater the P term

I Integral Output component is a function of how long the error has existed (it is therefore time dependant) ie the longer the error exists the greater is the I component

D Derivative Output component is a function of how fast the error is deviating from the set-point. So, the faster it deviates, the greater is the derivative component

In general most simple control systems will only require P and I functions. Systems with long time responses, such as large volume vessels or large thermal masses will require all three functions. In particular the D term is there to minimise overshoot due to the system inertia.

Here's a simple duty cycle sketch, set cycle time in "cycleTime" variable (in milliseconds, default set to 30000, 30 seconds), type desired duty cycle percent (0 to 100) in top of serial monitor and hit [ENTER].

unsigned long cycleStart, onTime, cycleTime = 30000;
bool power = false, oldPower = false;
const byte powerPin = 13;
byte percent;

void setup()
{
  Serial.begin(9600);
  pinMode(powerPin, OUTPUT);
}

void loop()
{
  if(millis() - cycleStart < onTime)
    power = true;
  else
    power = false;
  if(millis() - cycleStart > cycleTime)
    cycleStart += cycleTime;
    
  if(power != oldPower)
  {  
    Serial.print("Power ");
    Serial.println(power ? "ON" : "OFF");
    oldPower = power;
    digitalWrite(powerPin,power);
  }   
  // if there's any serial available, read it:
  if (Serial.available() > 0)
  {
    // look for the next valid integer in the incoming serial stream:
    percent = Serial.parseInt();
    // look for the newline. That's the end of your
    // sentence:
    if (Serial.read() == '\n') {
    }
    percent = constrain(percent, 0, 100);
    onTime = cycleTime * 0.01 * percent;
    cycleStart = millis();
    Serial.println(percent);
  }
}