Controlling Multiple PID Loops with One Arduino

My blog post that gets the most attention is by far the Arduino PID Temperature Controller, and I got a great suggestion from a reader about modifying that code to accommodate more than one PID loop in a single Arduino sketch.  While this is slightly more difficult than simply adding a second PID instance, it’s not too hard.  Let me explain.

I’ve started a new file on Github for this here.  It is still a work in progress, but I hope to finish it soon.

If you notice in the previous post, the run_PID function uses while loops to kill time in between switching the SSR_PIN (which is the Solid State Relay digital control switch, in case you’ve forgotten).  I’ve copied the relevant section of the original code below.

void run_PID(double Kp, double Ki, double Kd, uint16_t WindowSize, uint32_t time_interval)

   digitalWrite(SSR_PIN, 1);
   while(millis() - windowStartTime < time_interval * ratio);

   digitalWrite(SSR_PIN, 0);
   while(millis() - windowStartTime < time_interval);

This is fine for a single loop, but multiple loops couldn’t work this way.  If you had 2 copies of this running, the first instance would execute and then the second instance would execute, causing one instance to be asleep half the time.  This serial implementation would certainly mess up your loop timing.

The fix is to move the loop outside of this function and use if statements instead.  In this way, this run_PID function simply checks if the time is right to toggle SSR_PIN and doesn’t “block” other instances.  The proposed revision is below.

void run_PID(double Kp, double Ki, double Kd, uint16_t WindowSize, uint32_t time_interval)

   if(millis() - windowStartTime < time_interval * ratio)
       digitalWrite(SSR_PIN, 1);

   if(millis() - windowStartTime < time_interval)
       digitalWrite(SSR_PIN, 0);

The run_PID function could also be further split, because now that this function will be called many times, the PID equation does not need to be computed each time.


This is just the introduction to the revisions that need to be made to handle multiple loops.  I will add to this post as I update the PID controller in github and actually test out the code.  Thanks for reading!



8 thoughts on “Controlling Multiple PID Loops with One Arduino

  1. Pingback: Arduino PID Temperature Controller | Joe's Electronics Adventures

  2. Hi Joe,

    I am going to try out your code as soon as I can on a part! I had a similar idea of using ‘if statements’ but was confused what to put as the actual condition of the statement and where to place the statements, but you seemed to have found the solution. What you are proposing is to make the conditions for the ‘if statements’ what was inside of the while loop conditions and then place them somewhere outside of run_PID? Sort of like this:

    if(millis() – windowStartTime < time_interval * ratio){
    digitalWrite(SSR_HOT, 1);
    digitalWrite(SSR_HOT, 0);
    if(millis() – windowStartTime < time_interval * ratio2){
    digitalWrite(SSR_HOT2, 1);
    digitalWrite(SSR_HOT2, 0);
    while(millis() – windowStartTime < time_interval);

    Where SSR_HOT1 is the first relay controlling temperature at location1 and SSR_HOT2 is the second relay controlling temperature at location2.

    Thanks so much for the time you put into this.



      • Great code, Joe! I have a multi-zone kiln controller that died on me.

        Had you had a chance to test your multiple PID loop code?
        Would you mind posting it to Github? Would love to take a look at it/test it out.

        I have a great test bed for this: a multi-zone (3 thermocouples, 3 PID loops) kiln controller that’s died 🙂

      • Thanks! I’m posting my multi-zone PID code to Github now. I don’t have a setup to test it, but I’d be happy to fix it if you give me feedback about it.

      • Nice!
        I’ve gotten it to compile without errors. I’m developing on a Particle Photon (their online IDE is I did have to modify the MAX31855.cpp file to get it to compile. I believe the code for the pinMode() and digitalWrite() functions was not inline with the reference documentation. I’ve pasted below the section I had to alter. I’ve commented out your code and added mine above it inline.

        Links for the reference documentation for the two functions and their appropriate modes are also below.

        void MAX31855::setup(uint8_t latch)
        _latch = latch;

        pinMode(_latch, INPUT); //should this be INPUT
        // pinMode(_latch,1);

        digitalWrite(_latch, HIGH);
        // digitalWrite(_latch,1);

        The reference documentation for the two functions is here:
        value: INPUT, OUTPUT, or INPUT_PULLUP
        value: HIGH or LOW

        Bonus questions:
        1) Ramp/soak times are usually in per hour, could this be changed easily?
        2) If you have a kiln with 3 zones with 3 thermocouples (each TC is tied to it’s own zone), how would you implement this?
        3) I see the //Temperature Cycle Settings. If you had multiple steps (example: two sequential ramps before the soak), can you simply add additional variables here and then add cases in the void loop() section?

      • To quickly answer your questions:
        1) Yes, the rate times could easily be changed. Just a little conversion math.
        2) That is the goal of the multi-PID code. It’s not quite complete, but I hope to get there this weekend.
        3) I had thought about this as well. I will make it easier to add additional steps to a cycle. I think your approach makes sense and that is likely what I will do.
        I’ll also take a look at the MAX31855 functions.
        Thanks for these great comments! I really appreciate you looking at this.

      • Hey Joe! Had you had a chance to take a look at this again?

        I’m preparing some small objects I could fire the kiln with the code if we want to run a test…

        Also, I tried PM’ing you on Twitter but I can’t message you since you don’t follow back (@worldburger)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s