How to instantiate multiple PIDs?

Hi all. I am working on a project where I'm using thermoelectric heaters and one wire sensors to set up a PID temperature control. I'm using the PID library and everything works fine but I have lots of redundancy in my code that I'd like to get rid of. Right now I'm running 8 PID loops so the inits look like this:

PID pid1(&Input1, &Output1, &SetPoint,S1,S2,S3, DIRECT);
PID pid2(&Input2, &Output2, &SetPoint,S1,S2,S3, DIRECT);
PID pid3(&Input3, &Output3, &SetPoint,S1,S2,S3, DIRECT);
PID pid4(&Input4, &Output4, &SetPoint,S1,S2,S3, DIRECT);
PID pid5(&Input5, &Output5, &SetPoint,S1,S2,S3, DIRECT);
PID pid6(&Input6, &Output6, &SetPoint,S1,S2,S3, DIRECT);
PID pid7(&Input7, &Output7, &SetPoint,S1,S2,S3, DIRECT);
PID pid8(&Input8, &Output8, &SetPoint,S1,S2,S3, DIRECT);



int WindowSize = 2000;
unsigned long windowStartTime1;
unsigned long windowStartTime2;
unsigned long windowStartTime3;
unsigned long windowStartTime4;
unsigned long windowStartTime5;
unsigned long windowStartTime6;
unsigned long windowStartTime7;
unsigned long windowStartTime8;

etc.. and my void loop is calling this monster on every iteration:

 if (sensNum==0){
  Input1 = tempC;
  pid1.Compute();
  unsigned long now1 = millis();
  if(now1 - windowStartTime1>WindowSize)
  { 
    windowStartTime1 += WindowSize;
  }
  if(Output1 > now1 - windowStartTime1) digitalWrite(heaterPins[7],HIGH);
  else digitalWrite(heaterPins[7],LOW);
  }
  
  if (sensNum==1){
  Input2 = tempC;
  pid2.Compute();
  //currentPID.Compute();
  unsigned long now2 = millis();
  if(now2 - windowStartTime2>WindowSize)
  { 
    windowStartTime2 += WindowSize;
  }
  if(Output2 > now2 - windowStartTime2) digitalWrite(heaterPins[4],HIGH);
  else digitalWrite(heaterPins[4],LOW);
  }
  
  if (sensNum==2){
  Input3 = tempC;
  pid3.Compute();
  unsigned long now3 = millis();
  if(now3 - windowStartTime3>WindowSize)
  { 
    windowStartTime3 += WindowSize;
  }
  if(Output3 > now3 - windowStartTime3) digitalWrite(heaterPins[5],HIGH);
  else digitalWrite(heaterPins[5],LOW);
  }

  if (sensNum==3){
  Input4 = tempC;
  pid4.Compute();
  unsigned long now4 = millis();
  if(now4 - windowStartTime4>WindowSize)
  { 
    windowStartTime4 += WindowSize;
  }
  if(Output4 > now4 - windowStartTime4) digitalWrite(heaterPins[3],HIGH);
  else digitalWrite(heaterPins[3],LOW);
  }

  if (sensNum==4){
  Input5 = tempC;
  pid5.Compute();
  unsigned long now5 = millis();
  if(now5 - windowStartTime5>WindowSize)
  { 
    windowStartTime5 += WindowSize;
  }
  if(Output5 > now5 - windowStartTime5) digitalWrite(heaterPins[0],HIGH);
  else digitalWrite(heaterPins[0],LOW);
  }

  if (sensNum==5){
  Input6 = tempC;
  pid6.Compute();
  //currentPID.Compute();
  unsigned long now6 = millis();
  if(now6 - windowStartTime6>WindowSize)
  { 
    windowStartTime6 += WindowSize;
  }
  if(Output6 > now6 - windowStartTime6) digitalWrite(heaterPins[1],HIGH);
  else digitalWrite(heaterPins[1],LOW);
  }

  if (sensNum==6){
  Input7 = tempC;
  pid7.Compute();
  unsigned long now7 = millis();
  if(now7 - windowStartTime7>WindowSize)
  { 
    windowStartTime7 += WindowSize;
  }
  if(Output7 > now7 - windowStartTime7) digitalWrite(heaterPins[2],HIGH);
  else digitalWrite(heaterPins[2],LOW);
  }

  if (sensNum==7){
  Input8 = tempC;
  pid8.Compute();
  unsigned long now8 = millis();
  if(now8 - windowStartTime8>WindowSize)
  { 
    windowStartTime8 += WindowSize;
  }
  if(Output8 > now8 - windowStartTime8) digitalWrite(heaterPins[6],HIGH);
  else digitalWrite(heaterPins[6],LOW);
  }

Is there a way to build an array of PID objects so that I can just call them in a loop? Something like:

PID *pidArr[8]'
PID *pPntr
pPntr = & pid1(arg1,arg2...);
pidArr[0] = pPntr;

No success so far. Thanks.

Suggest an Array of PID 's

Then one control .Loop Pass index of array to Loop to pick up correct data..

8) 8)

Right now I'm running 8 PID loops so the inits look like this:

Are you really using 8 heaters to achieve one temperature?

Are you really using 8 heaters to achieve one temperature?

Sorry about the confusion. I have 8 heaters and 8 sensors, one PID for each.

Suggest an Array of PID 's

Then one control .Loop Pass index of array to Loop to pick up correct data..

Hmm. Ordinarily the way I would achieve this is to instantiate the object assigned to a variable name, like.. PID pid1 = new PID(args); Then I could add pid1 to an array. PID pidArr[] = {pid1,pid2... etc}

It looks like this is achieved in the Arduino IDE with:

PID pid1(args);
PID pid2(args);
PID allPIDS[2] = {pid1,pid2};

Thanks. :blush:

I'm not familiar with the PID library, but unless there is a constructor that takes no arguments, you will not be able to directly create an array of PID objects. You might be able use an array of pointers to PID objects instead.

With this approach you will end up with 16 PID objects...

PID pid1(args);
PID pid2(args);
PID allPIDS[2] = {pid1,pid2};

With this approach you will end up with 16 PID objects..

point taken. I tried this instead:

PID pid1(&Input1, &Output1, &allSetPoints[0], S1,S2,S3, DIRECT);
PID pid2(&Input2, &Output2, &allSetPoints[1], S1,S2,S3, DIRECT);
PID pid3(&Input3, &Output3, &allSetPoints[2], S1,S2,S3, DIRECT);
PID pid4(&Input4, &Output4, &allSetPoints[3], S1,S2,S3, DIRECT);
PID pid5(&Input5, &Output5, &allSetPoints[4], S1,S2,S3, DIRECT);
PID pid6(&Input6, &Output6, &allSetPoints[5], S1,S2,S3, DIRECT);
PID pid7(&Input7, &Output7, &allSetPoints[6], S1,S2,S3, DIRECT);
PID pid8(&Input8, &Output8, &allSetPoints[7], S1,S2,S3, DIRECT);
PID *allPIDS[NumberOfDevices] = {&pid1,&pid2,&pid3,&pid4,&pid5,&pid6,&pid7,&pid8};

and then I try to dereference the PIDs..

PID pid = *allPIDS[sensNum];
  Inputs[sensNum] = tempC;
  pid.Compute();

It compiles but doesn't compute a new PID setpoint. I'll have to examine my code more to insure I didn't make a careless error somewhere.

I can't find a problem with the code aside from it not working.

I'm not familiar with the PID library, but unless there is a constructor that takes no arguments, you will not be able to directly create an array of PID objects. You might be able use an array of pointers to PID objects instead.

The PID library constructor does take arguments. That said, I've just changed it by adding a method to initialize the parameters the constructor once handled. I tried this and it compiles. I'll test it on the Arduino this evening.

PID pid = *allPIDS[sensNum];
  Inputs[sensNum] = tempC;
  pid.Compute();

With this code you make a copy of the object and then exercise the copy. Not sure if this will give you want you want. Especially if you call non-const methods. Try this instead...

allPIDS[sensNum]->Compute();
allPIDS[sensNum]->Compute();

That was the ticket! :) Thanks David