Posts Tagged PID controller

A Time Out for Documentation

I coming back from 2 weeks of vacation and trying to get back into the swing of things. I decided now would be a good time to post some documentation of where thing are on the reflow oven. I have decided to use a joystick and an RGB LCD for the menu system. Right now the goal is to be able to select from different reflow profiles stored in EEPROM and run them. Here is a flow diagram of the menus system as of today:

While I am at it, I decided to document the schematic. Here it is as of today:I may still add in an air stirring fan, and a servo and fan that opens the door and blows air  to help cool the PCBs. I’ll be trying these things out once I have all these parts integrated into one sketch. I know these are a bit rough but I thought I share some things now and clean them up later as thing progress.


, , ,

Leave a comment

Reflow Oven PID

Wow, it has been a busy week but not without something to show for it. I have working on the reflow oven project on two major fronts. The first was to create a python plotting interface such that I could plot out the PID varibles over time. The second was tuning the PID for the reflow oven. I had pretty good success on both accounts. This post will just be talking about the success of the PID and some of the non conventional stuff put in place to make it that way.

The PID algorithm didn’t depart too much from the classic model.The PID now is in the main loop() of the Arduino code. It will be in it’s own subroutine later. Here is the heart of the code:

int error, pid, diff, ingr, prop;
	//calculate PID
	time = millis();
	reference = SnPbProfilePoint(time);
    //reference =500;

    for (i=0;i<4;i++){
        temperature += thermocouple.readQtrCelsius();
        temperature /= 2;

In order to keep the calculations for SnPbProfilePoint(time) and the PID variables in integer math (avoiding floating point math) temperature is left in its native scale of 1/4 degC per count. I added a method called readQtrCelsius() to the MAX6675 class to read back this raw data. Time is left in milliseconds to keep as much accurracy as possible. I averaged the temperature with four readings to help with noise. I tried up to eight but anything over four didn’t seem to make a difference.

	error = reference-temperature;
	prop = 32*error;
	diff = 128*(temperature-temp_last)-256*(reference - ref_last);

	ingr = error/24+ingr_last;
	if (error>0){ingr+=1;}
	if (error<0) {ingr-=10;	}

	ingr = constrain(ingr,0,1000);

	pid = prop + ingr - diff;

The prop was scaled to a non oscillation value once I thought the diff scalers were good.
The differential variable is generated with a couple of twists. Instead of basing it off of the difference in error it is calculated with a change in temperature reading and the change in reference. Doing it this way helped it keep up with the changing reference. It is also weighted heavily when compared to the P and the I variables.

The ingr was the wimp of the three. I found that turning the scaler down so low most of the time resulted in a 0 contribution. So to keep some in there I added or subtracted some based on the sign of the error. For a constant reference, this will still zero out error over time. Since the oven is quick on the rise in temperature but slow on the fall (no active cooling) it was give a faster integration in the negative direction. Finally it was constrained between 0 and 100% duty cycle because beyond these extremes would add response delay.

    pid = constrain(pid,1,1000);
	// turn on pwm
	digitalWrite(pwmOut, HIGH);
    if (pid<1000) {digitalWrite(pwmOut, LOW);}
    ingr_last = ingr;
    temp_last = temperature;
    ref_last = reference;

    //update Plot then loop again

The duty cycle is proportional to pid. pid =1000 is 100% pwm. pid was constrained between 1 and 1000. The minimum of 1 was because delay(0) turns out to be a very looooong delay.


I am quite pleased with the results! Next I will tackle the LCD and the menu system and then start putting all these pieces together into a complete system.

, ,

Leave a comment

Reflow Plot Profile

Lately I have been working on the reflow plot profile and how it could be implemented within the arduino controller.

I have consolidated the reflow profile information so I could wrap my head around what the oven needs to do. My plan right now is to have the Arduino hold a number of different profiles in EEPROM. These stored profiles will be user selectable and adjustable using the LCD screen and user input.

I have made a function that outputs a waveform of this shape.  All of the twists and turns are built with adjustable parameters.

int SnPbProfilePoint(unsigned long theTime) {
// each count is 1/4 degC, time count are milliSeconds
// pre-heat, flux activation, reflow, cooling
// profile for SnPb (Tin-Led)
// wetting time is duration spent above 183degC

// Pre-Heat: 0-110sec
// raise the temperature up from 25degC to 110degC over 100sec
// preheat = Time*(110-25)degC/100+25 =
// Time*(phMaxT-ambT)/phTime+ambT
unsigned long  phMaxT = 440; //4 * 110
unsigned long  ambT = 100; // = 4 * 25
unsigned long phTime = 100000; //=100*1000

// Flux Activation: 100-160sec
// raise the temperature up from 110degC to 125degC over 60sec
// =110+(125-110)*(Time-100)/60 =
// phMaxT+(faMaxT-phMaxT)*(Time-phTime)/faTime
unsigned long  faMaxT = 500; //(4*125)
unsigned long faTime = 60000;//(1000*60)

// <a class="zem_slink" title="Reflow soldering" href="" rel="wikipedia">Reflow</a>: 160-250sec
// raise the temperature up from 125degC to 240degC over 90sec
// = 125 + (250 -125)* (Time -100-60)/90
// faMaxT + (rfMaxT-faMaxT)*(Time-phTime-faTime)/rfTime
unsigned long  rfMaxT = 960;//(4*240)
unsigned long  rfTime = 90000;//(1000*90)

// Cool Down: 250sec+ 6deg/sec max rampdown
// 240-5deg/sec*(time-90-100-60)
// rfMaxT - cdSlope*(Time-rfTime-phTime-faTime)
unsigned long  cdSlope =16;//(4*4)
unsigned long sp;

 sp = 0;
  if (theTime < phTime){
    sp = ambT + (theTime*(phMaxT - ambT))/phTime;
  else if (theTime < (phTime+faTime)){
      sp = phMaxT + ((faMaxT-phMaxT)*(theTime-phTime))/faTime;
  else if  (theTime < (phTime+faTime+rfTime)){
      sp = faMaxT + ((rfMaxT-faMaxT)*(theTime-phTime-faTime))/rfTime;
  else if (theTime < phTime+faTime+rfTime+1000*(rfMaxT-ambT)/cdSlope){
    sp = rfMaxT - (cdSlope*(theTime-rfTime-phTime-faTime))/1000;
  else {
    sp=ambT ;
return int(sp);

With a lot of head scratching and some luck I was able to alter the python code to accept both  X and  Y values (instead of just Y). This allowed me to output a plot from the arduino through the serial port.

There are some issues with the plotting code that I need to address before I get into trying to tune a PID for the oven. The software is very heavy on my laptop. I don’t think it should be but it is. I think it might have something to do with the threading going on involving the serial port. Also, sometimes I can’t get the plotting software to stop and close. It just likes to take over all of the CPU cycles. That’s not very efficient considering that I am sending one point a second. I would like to configure it to detect and accept multiple traces based on what the Arduino sends it. I have some ideas on how to do this but will take some additional python research as I am not a programmer by trade.

, , ,

Leave a comment