Multiple PIDs

I'm write a program with multiple PID's and I was just wondering what variables if any can be shared between them?
PID PIDname(&Input, &Output, &Setpoint, consKp1, consKi1, consKd1 ,DIRECT). Can any of the 6 variables (not DIRECT)
be shared. I ask because my program will be running 6 PID's and can get quite large quickly. Thanks in advance!!!

It depends. If you’re controlling six identical systems, you might share the tuning parameters. For example if you were controlling six egg incubators using the same hardware, they might be expected to behave the same. It’s quite likely in such a scenario that they would vary a bit; might matter to you, might not.

If you had six incubators that were started at the same time, you might even share the setpoint.

Input & output though should be separate. If you had a lab environment where things are guaranteed the same - say at a NASA facility, you might, in some bizarre set of circumstances, share them, but in the kind of situation where you’re using an Arduino to control things, just give each PID its own set.

Thanks for the reply. I'm eventually going to try to control 6 linear actuators as part of a Stewart platform. I have build 1 test actuator as a proof of concept and I have it tracking 1 of 6 outputs from BFF motion software very smoothly but when I add another PID code block with shared variables it still works sort of, but it becomes VERY rough. As a follow up question can the PID name be an array variable? PID PIDnumber(&Input, &Output, &Setpoint, consKp1, consKi1, consKd1 ,DIRECT). Thanks.

Sorry previous post didn't work right PIDname was supposed to be followed by square brackets. Weird.

The variables you supply to a PID don't take up much space and you'd have to be desperately short of memory before it was worth bothering to save those few bytes.

You can create an array of PID objects, too, as long as you declare and initialize the array in one step. Doing so means that you do NOT use array notation for the elements, so the forum software won't mangle anything.

Thanks for the reply PaulS. Can you provide an example on how to create an array of PID objects? Here’s the code I have so far.

/*BFF motion software reader and driver for Arduino v1.0 by Richard Cummins.
 Even pins are for actuator 'extend' and odd pins are for actuator 'retract'.
 Credit to Brett Beauregard for his excellent PID library. Some code also by
 Brett Beauregard from his PID adaptive tuning example. Code is free to use.
 Remember code must be tuned to whatever device(s) you're attempting to control.
 Enjoy!
 */






#include <PID_v1.h>

int cr, count=1, pin, c, time=5;
int sread[9];
//Define Variables we'll be connecting to
double Input, Output1, Output2, Output3, Output4, Output5, Output6, Setpoint, gap;
//Define the aggressive and conservative Tuning Parameters
double aggKp=1.0, aggKi=0.042, aggKd=0.22;
double consKp=0.2, consKi=0.01, consKd=0.07;

//Specify the links and initial tuning parameters
PID act1PID(&Input, &Output1, &Setpoint, consKp, consKi, consKd ,DIRECT);
PID act2PID(&Input, &Output2, &Setpoint, consKp, consKi, consKd ,DIRECT);
PID act3PID(&Input, &Output3, &Setpoint, consKp, consKi, consKd ,DIRECT);
PID act4PID(&Input, &Output4, &Setpoint, consKp, consKi, consKd ,DIRECT);
PID act5PID(&Input, &Output5, &Setpoint, consKp, consKi, consKd ,DIRECT);
PID act6PID(&Input, &Output6, &Setpoint, consKp, consKi, consKd ,DIRECT);

void setup()
{
  Serial.begin(9600);
  for (c=2; c<14; c++)
  {
    pinMode(c, OUTPUT);
  }
  act1PID.SetMode(AUTOMATIC);
  act1PID.SetSampleTime(time);
  act2PID.SetMode(AUTOMATIC);
  act2PID.SetSampleTime(time);
  act3PID.SetMode(AUTOMATIC);
  act3PID.SetSampleTime(time);
  act4PID.SetMode(AUTOMATIC);
  act4PID.SetSampleTime(time);
  act5PID.SetMode(AUTOMATIC);
  act5PID.SetSampleTime(time);
  act6PID.SetMode(AUTOMATIC);
  act6PID.SetSampleTime(time); 

}

void loop()
{
  if (Serial.available()>0)
  {
    cr=Serial.read();
    if (cr==65)
    {
      do
      {
        if (Serial.available()>0)
        {
          sread[count]=(Serial.read());
          count++;
        }
      }
      while(count<9);
    }
  }
  if (sread[1]==66)
  {    
    //--------------------------------------------------actuator 1 
    Setpoint=sread[3]; 
    Setpoint=Setpoint*4;
    Input = analogRead(0);
    if (Setpoint > Input)
    {
      act1PID.SetControllerDirection(DIRECT);
      analogWrite(3, LOW);
      pin=2;
    }
    else
    {
      act1PID.SetControllerDirection(REVERSE);
      analogWrite(2, LOW);
      pin=3;
    }
    gap = abs(Setpoint-Input); //distance away from setpoint
    if(gap<10)
    {  //we're close to setpoint, use conservative tuning parameters
      act1PID.SetTunings(consKp, consKi, consKd);
    }
    else
    {
      //we're far from setpoint, use aggressive tuning parameters
      act1PID.SetTunings(aggKp, aggKi, aggKd);
    }

    act1PID.Compute();
    analogWrite(pin, Output1); 
    //--------------------------------------------------actuator 2
    Setpoint=sread[4]; 
    Setpoint=Setpoint*4;
    Input = analogRead(1);
    if (Setpoint > Input)
    {
      act2PID.SetControllerDirection(DIRECT);
      analogWrite(5, LOW);
      pin=4;
    }
    else
    {
      act2PID.SetControllerDirection(REVERSE);
      analogWrite(4, LOW);
      pin=5;
    }
    gap = abs(Setpoint-Input); //distance away from setpoint
    if(gap<10)
    {  //we're close to setpoint, use conservative tuning parameters
      act2PID.SetTunings(consKp, consKi, consKd);
    }
    else
    {
      //we're far from setpoint, use aggressive tuning parameters
      act2PID.SetTunings(aggKp, aggKi, aggKd);
    }

    act2PID.Compute();
    analogWrite(pin, Output2);
    //--------------------------------------------------actuator 3
    Setpoint=sread[5]; 
    Setpoint=Setpoint*4;
    Input = analogRead(2);
    if (Setpoint > Input)
    {
      act3PID.SetControllerDirection(DIRECT);
      analogWrite(7, LOW);
      pin=6;
    }
    else
    {
      act3PID.SetControllerDirection(REVERSE);
      analogWrite(6, LOW);
      pin=7;
    }
    gap = abs(Setpoint-Input); //distance away from setpoint
    if(gap<10)
    {  //we're close to setpoint, use conservative tuning parameters
      act3PID.SetTunings(consKp, consKi, consKd);
    }
    else
    {
      //we're far from setpoint, use aggressive tuning parameters
      act3PID.SetTunings(aggKp, aggKi, aggKd);
    }

    act3PID.Compute();
    analogWrite(pin, Output3);
    //--------------------------------------------------actuator 4
    Setpoint=sread[6]; 
    Setpoint=Setpoint*4;
    Input = analogRead(3);
    if (Setpoint > Input)
    {
      act4PID.SetControllerDirection(DIRECT);
      analogWrite(9, LOW);
      pin=8;
    }
    else
    {
      act4PID.SetControllerDirection(REVERSE);
      analogWrite(8, LOW);
      pin=9;
    }
    gap = abs(Setpoint-Input); //distance away from setpoint
    if(gap<10)
    {  //we're close to setpoint, use conservative tuning parameters
      act4PID.SetTunings(consKp, consKi, consKd);
    }
    else
    {
      //we're far from setpoint, use aggressive tuning parameters
      act4PID.SetTunings(aggKp, aggKi, aggKd);
    }

    act4PID.Compute();
    analogWrite(pin, Output4); 
    //--------------------------------------------------actuator 5 
    Setpoint=sread[7]; 
    Setpoint=Setpoint*4;
    Input = analogRead(4);
    if (Setpoint > Input)
    {
      act5PID.SetControllerDirection(DIRECT);
      analogWrite(11, LOW);
      pin=10;
    }
    else
    {
      act5PID.SetControllerDirection(REVERSE);
      analogWrite(10, LOW);
      pin=11;
    }
    gap = abs(Setpoint-Input); //distance away from setpoint
    if(gap<10)
    {  //we're close to setpoint, use conservative tuning parameters
      act5PID.SetTunings(consKp, consKi, consKd);
    }
    else
    {
      //we're far from setpoint, use aggressive tuning parameters
      act5PID.SetTunings(aggKp, aggKi, aggKd);
    }

    act5PID.Compute();
    analogWrite(pin, Output5);
    //--------------------------------------------------actuator 6
    Setpoint=sread[8]; 
    Setpoint=Setpoint*4;
    Input = analogRead(5);
    if (Setpoint > Input)
    {
      act6PID.SetControllerDirection(DIRECT);
      analogWrite(13, LOW);
      pin=12;
    }
    else
    {
      act6PID.SetControllerDirection(REVERSE);
      analogWrite(12, LOW);
      pin=13;
    }
    gap = abs(Setpoint-Input); //distance away from setpoint
    if(gap<10)
    {  //we're close to setpoint, use conservative tuning parameters
      act6PID.SetTunings(consKp, consKi, consKd);
    }
    else
    {
      //we're far from setpoint, use aggressive tuning parameters
      act6PID.SetTunings(aggKp, aggKi, aggKd);
    }

    act6PID.Compute();
    analogWrite(pin, Output6);                              
  }
  count=1;
}

It works pretty well. I’m thinking of adding a narrow ‘dead band’ because of the PID ‘noise’ when the input comes back to steady state.

Can you provide an example on how to create an array of PID objects?

Something like this:

PID pidArray[] = {
    PID(&Input, &Output1, &Setpoint, consKp, consKi, consKd ,DIRECT),
    PID(&Input, &Output2, &Setpoint, consKp, consKi, consKd ,DIRECT),
    PID(&Input, &Output3, &Setpoint, consKp, consKi, consKd ,DIRECT),
    PID(&Input, &Output4, &Setpoint, consKp, consKi, consKd ,DIRECT),
    PID(&Input, &Output5, &Setpoint, consKp, consKi, consKd ,DIRECT),
    PID(&Input, &Output6, &Setpoint, consKp, consKi, consKd ,DIRECT),
};

Of course, Output should be any array, too.

Thanks for the example. I’m just trying to figure it out. Newbie programmer :slight_smile:

I tried this…

#include <PID_v1.h>

int cr, count=1, pin, c, time=5;
int sread[9];
double Output[6];
//Define Variables we'll be connecting to
double Input, Setpoint, gap;
//Define the aggressive and conservative Tuning Parameters
double aggKp=1.0, aggKi=0.042, aggKd=0.22;
double consKp=0.2, consKi=0.01, consKd=0.07;

//Specify the links and initial tuning parameters
PID actuator[]={
PID(&Input, &Output[1], &Setpoint, consKp, consKi, consKd ,DIRECT);
PID{&Input, &Output[2], &Setpoint, consKp, consKi, consKd ,DIRECT);
PID(&Input, &Output[3], &Setpoint, consKp, consKi, consKd ,DIRECT);
PID(&Input, &Output[4], &Setpoint, consKp, consKi, consKd ,DIRECT);
PID(&Input, &Output[5], &Setpoint, consKp, consKi, consKd ,DIRECT);
PID(&Input, &Output[6], &Setpoint, consKp, consKi, consKd ,DIRECT);
};

I got these errors.

sketch_jun01a:15: error: expected `}' before ';' token
sketch_jun01a:16: error: expected unqualified-id before '{' token

Help please!

I got these errors.

What are array elements separated by? Hint: Not semicolons.

Got the hint , not ; Tried this…

#include <PID_v1.h>

int cr, count=1, pin, c, time=5;
int sread[9];
double Output[6];
//Define Variables we'll be connecting to
double Input, Setpoint, gap;
//Define the aggressive and conservative Tuning Parameters
double aggKp=1.0, aggKi=0.042, aggKd=0.22;
double consKp=0.2, consKi=0.01, consKd=0.07;

//Specify the links and initial tuning parameters
PID actuator[]={
PID(&Input, &Output[1], &Setpoint, consKp, consKi, consKd ,DIRECT),
PID{&Input, &Output[2], &Setpoint, consKp, consKi, consKd ,DIRECT),
PID(&Input, &Output[3], &Setpoint, consKp, consKi, consKd ,DIRECT),
PID(&Input, &Output[4], &Setpoint, consKp, consKi, consKd ,DIRECT),
PID(&Input, &Output[5], &Setpoint, consKp, consKi, consKd ,DIRECT),
PID(&Input, &Output[6], &Setpoint, consKp, consKi, consKd ,DIRECT),
};

Got this…

sketch_jun01b:15: error: expected primary-expression before ‘{’ token
sketch_jun01b:15: error: expected `}’ before ‘{’ token
sketch_jun01b:15: error: expected ‘,’ or ‘;’ before ‘{’ token

PID(&Input, &Output[1], &Setpoint, consKp, consKi, consKd ,DIRECT),
PID{&Input, &Output[2], &Setpoint, consKp, consKi, consKd ,DIRECT),

Working now! Thanks for your help.