Moving away from arduino- best uProcessor for making PID device?

Thread Starter

camjerlams

Joined Dec 23, 2012
56
Hi,
I'm an amateur teaching myself some electronics. Ive recently made a plant waterer with an arduino using a closed loop control, now I'd like to try and make a PID controller for a small ceramic heating element but I'd like to move away from the arduino to reduce size and teach myself a few things.

I have an ATMega 328 with a crystal oscillator that I thought I could program, then I could design my own PCB and case for this device and have them printed which would be more pro than just slapping an arduino inside a waetherproof box as I have done with the plant thing.

I have never programmed a uProcessor from scratch so before jummping in i thought I'd ask what is the best/most popular for something like this?
Or to put it another way- if I wanted to easily make a prototype device for mass production what uProcessor would be best?

Any links to tutorials and whatnot are very welcome.

Cheers!
 

Thread Starter

camjerlams

Joined Dec 23, 2012
56
An Arduino Nano/uno/Pro Mini is really nothing more than a ATMega 328 so you could just develop your project using an Arduino board and IDE and then load the program into an ATMega 328 fitted to your own PCB.
Could one sell a device running on Arduino IDE? It's not that I intend to, I just want to know that I can make something that is entirely mine.
 

Thread Starter

camjerlams

Joined Dec 23, 2012
56
An Arduino Nano/uno/Pro Mini is really nothing more than a ATMega 328 so you could just develop your project using an Arduino board and IDE and then load the program into an ATMega 328 fitted to your own PCB.
Nevermind I just looked it up and that is totally fine if someone wants to do that, hence all the arduino compatible stuff on the market.
Thanks for the reply :).
https://www.arduino.cc/en/Main/FAQ
 

jayanthd

Joined Jul 4, 2015
945
If you can use PIC, AVR, dsPIC, PIC24, PIC32 then I can provide you a PIC library. it will solve 95% of your problem. All you have to do is calculate Kp, Ki and Kd values and use it to control your Heater. Heater will be AC and you need a TRIAC to control the power to it. You need a ZCD circuit also. You need to detect the ZC and then after the required delay you have to fire the TRIAC.
 

Thread Starter

camjerlams

Joined Dec 23, 2012
56
If you can use PIC, AVR, dsPIC, PIC24, PIC32 then I can provide you a PIC library. it will solve 95% of your problem. All you have to do is calculate Kp, Ki and Kd values and use it to control your Heater. Heater will be AC and you need a TRIAC to control the power to it. You need a ZCD circuit also. You need to detect the ZC and then after the required delay you have to fire the TRIAC.
OK sure I'd like to have a look at that. So the TRIAC provides square wave AC for the element? I want to make it battery powered.
 

tranzz4md

Joined Apr 10, 2015
315
Battery powered? So, that'd be isolated from the power circuit for the heater? Heaters need POWER.

The triac won't be making any square waves, not by itself at least. You may of course be thinking of a very, very small heater and the whole thing being battery powered, for a short period of time.
 

R!f@@

Joined Apr 2, 2009
10,004
OK sure I'd like to have a look at that. So the TRIAC provides square wave AC for the element? I want to make it battery powered.
Battery powered PID controlled heater does not require zero crossing and a triac. One properly rated MOSFET will do.
If jayanthd provides you with a PID library than you can by all means make it quite easily.
 

jayanthd

Joined Jul 4, 2015
945
The original library was written by DanyR at mikroe forum. It was in mikroPascal. I had converted it to mikroC. I am attaching the file which I made looking at the mikroPascal code.

Here is the link for DanyR's libraries. I just check it now and he also has made a mikroC version.

You can use the library with any C Compiler.

http://libstock.mikroe.com/projects/view/161/pid-library

For .mpkg files you need mikroE's free Package Manager tool to extract and install.

If your code is small ( < 4 KB ) then you can use demo version of mikroElektronika's mikroC PRO PIC or any mikroE Compiler.


Here is the code which I ported from mikroPascal.

C:
// ---------------------------------------------------------- //
// ---- PID library with fixed calculation time interval ---- //
// ---------------------------------------------------------- //

// D. Rosseel
// Original: 27-09-2011
// Latest update: 31-10-2011

/* History:
  27-09-2011: Original Version.
  04-10-2011: Added the "Integration Improvement" mechanism. This mechanism prevents overshoot/ringing/oscillation due to integration.
  05-10-2011: Reduced code size a little, made "Integration Improvement" easier to read.
  12-10-2011: More than one PID controller can operate now in one program with the usage of "PIDController" variables.
  31-10-2011: Added the "Differentiation Improvement" mechanism. This mechanism prevents unnecessary delays due to differentiation.
*/

// Documentation: http://en.wikipedia.org/wiki/PID_controller/ and http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/


#define BOOL unsigned char
#define TRUE 1
#define FALSE 0

struct PID {
       double PID_Kp, PID_Ki, PID_Kd;
       double PID_Integrated;
       double PID_Prev_Input;
       double PID_MinOutput, PID_MaxOutput;
       BOOL PID_First_Time, PID_Int_Improvement, PID_Diff_Improvement;
       double PID_Prev_AbsError;
} Controller;

void Init_PID(double Kp, double Ki, double Kd, double MinOutput, double MaxOutput);
// Initialises the PID engine of "Controller"
// Kp = the "proportional" error multiplier
// Ki = the "integrated value" error multiplier
// Kd = the "derivative" error multiplier
// MinOutput = the minimal value the output value can have (should be < 0)
// MaxOutput = the maximal value the output can have (should be > 0)

void Set_PID_Int_Improvement(BOOL On_);
// Switches on or off the "Integration Improvement" mechanism of "Controller". This mechanism prevents overshoot/ringing/oscillation
// due to integration. To be used after "Init_PID", which switches off the mechanism for compatibility reasons.

void Set_PID_Diff_Improvement(BOOL On_);
// Switches on or off the "Differentiation Improvement" mechanism of "Controller". This mechanism prevents unneccessary correction
// delay when the actual value is changing towards the setpoint.
// To be used after "Init_PID", which switches off the mechanism for compatibility reasons.

void Reset_PID();
// Re-initialises the PID engine of "Controller" without change of settings

double PID_Calculate(double Setpoint, double InputValue);
// To be called at a regular time interval (e.g. every 100 msec)
// Setpoint: the target value for "InputValue" to be reached
// InputValue: the actual value measured in the system
// Functionresult: PID function of (SetPoint - InputValue) of "Controller",
//   a positive value means "InputValue" is too low (< SetPoint), the process should take action to increase it
//   a negative value means "InputValue" is too high (> SetPoint), the process should take action to decrease it
// Timing: A call to this routine costs 140 uS time (P18F2550 running at 48 Mhz)


void Reset_PID() {
    Controller.PID_Integrated    = 0.0;
    Controller.PID_Prev_Input    = 0.0;
    Controller.PID_Prev_AbsError = 0.0;
    Controller.PID_First_Time    = TRUE;
}

void Set_PID_Int_Improvement(BOOL On_) {
  Controller.PID_Int_Improvement = On_;
}

void Set_PID_Diff_Improvement(BOOL On_) {
  Controller.PID_Diff_Improvement = On_;
}

void Init_PID(double Kp, double Ki, double Kd, double MinOutput, double MaxOutput) {
    Controller.PID_Kp               = Kp;
    Controller.PID_Ki               = Ki;
    Controller.PID_Kd               = Kd;
    Controller.PID_MinOutput        = MinOutput;
    Controller.PID_MaxOutput        = MaxOutput;
    Controller.PID_Integrated       = 0.0;
    Controller.PID_Prev_Input       = 0.0;
    Controller.PID_Prev_AbsError    = 0.0;
    Controller.PID_Int_Improvement  = FALSE;
    Controller.PID_Diff_Improvement = FALSE;
    Controller.PID_First_Time       = TRUE;
}

char Sign(double Value) {
  if(Value >= 0)return 1;  // positive
  else return 0;           // negative
}

double AbsReal(double val1) {
  if(Val1 < 0)return -Val1;
  else return Val1;
}

double Limit(double *Value, double MinOutput, double MaxOutput) {
  if(*Value < MinOutput)*Value = MinOutput;
  else if(*Value > MaxOutput)*Value = MaxOutput;
}

double PID_Calculate(double Setpoint, double InputValue) {
    double Err, ErrValue, DiffValue, ErrAbs, RetVal;

    Err = SetPoint - InputValue;
    if(Controller.PID_Diff_Improvement)ErrAbs = AbsReal(Err);

    // --- calculate proportional value ---
    ErrValue  = Err * Controller.PID_Kp;

    // --- PID Int Improvement ---
    if(Controller.PID_Int_Improvement)
          if(Sign(Err) != Sign(Controller.PID_Integrated)) {
                 Controller.PID_Integrated = 0.0;
          }

    // --- Calculate integrated value ---
    Controller.PID_Integrated = Controller.PID_Integrated + (Err * Controller.PID_Ki);
    // limit it to output minimum and maximum
    Limit(&Controller.PID_Integrated, Controller.PID_MinOutput, Controller.PID_MaxOutput);

    // --- calculate derivative value ---
    if(Controller.PID_First_Time) {
      // to avoid a huge DiffValue the first time (PID_Prev_Input = 0)
      Controller.PID_First_Time    = FALSE;
      Controller.PID_Prev_Input    = InputValue;
      Controller.PID_Prev_AbsError = 0.0;
    }

    DiffValue = (InputValue - Controller.PID_Prev_Input) * Controller.PID_Kd;
    Controller.PID_Prev_Input = InputValue;

    // --- PID Diff Improvement ---
    if(Controller.PID_Diff_Improvement) {
      if(ErrAbs < Controller.PID_Prev_AbsError)DiffValue = 0.0; // error becomes smaller, stop differentiation action
      Controller.PID_Prev_AbsError = ErrAbs;
    }

    // --- calculate total ---
    RetVal = ErrValue + Controller.PID_Integrated - DiffValue; // mind the minus sign!!!
    // limit it to output minimum and maximum
    Limit(&RetVal, Controller.PID_MinOutput, Controller.PID_MaxOutput);

    return RetVal;
}

double output;

void main() {   
        
     while(1) {   
        
          Init_PID(2,0,0, -100, 100);  // Init_PID(double Kp, double Ki, double Kd, double MinOutput, double MaxOutput)

          output = PID_Calculate(20, 20);  // double PID_Calculate(double Setpoint, double InputValue)
     }
}
 

Attachments

Last edited:

jayanthd

Joined Jul 4, 2015
945
For battery powered Heater you have to use PWM with PID and ofcourse a Power Mosfet is needed. Choose a Logic gate Power Mosfet with very low Rds(on).
 
Top