br3ttb / Arduino-PID-Library

1.93k stars 1.11k forks source link

Use arrays with PID library #113

Open simeon9696 opened 3 years ago

simeon9696 commented 3 years ago

Would it be possible to use arrays with the constructors? I have six valves with different input, output and setpoints so I wanted to know if could do something like below:

//Specify the links and initial tuning parameters
double Kp=10, Ki=2, Kd=5;

double temperatures[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
double setPoints[] = {25.0, 25.0, 25.0, 25.0, 25.0, 25.0};
double valveDutyCycle[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};

//Define Variables we'll be connecting to

PID aNeckPID(&temperatures[0] + 0, &valveDutyCycle[0] + 0, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE);
PID aBodyPID(&temperatures[0] + 1, &valveDutyCycle[0] + 1, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE);
PID aBasePID(&temperatures[0] + 2, &valveDutyCycle[0] + 2, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE);
PID bNeckPID(&temperatures[0] + 3, &valveDutyCycle[0] + 3, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE);
PID bBodyPID(&temperatures[0] + 4, &valveDutyCycle[0] + 4, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE);
PID bBasePID(&temperatures[0] + 5, &valveDutyCycle[0] + 5, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE);

PID valves[] = {aNeckPID, aBodyPID, aBasePID, bNeckPID, bBodyPID, bBasePID};

Then in loop() do:

 for (int i = 0; i < NUM_THERMOCOUPLES; i++)
  {
    valves[i].Compute();
   //pwm1.setPWM(i, 0, valveDutyCycle[i]); 
    Serial.print("VALVE: ");
    Serial.print(i);
    Serial.print(" IN: ");
    Serial.print(temperatures[i]);
    Serial.print(" SET: ");
    Serial.print(setPoints[i]);
    Serial.print(" C ");
    Serial.print(" OUT: ");
    Serial.print(valveDutyCycle[i]);
    Serial.println(" ");
  }; 

The valves are controlled via a PWM signal and I have 6 valves

br3ttb commented 3 years ago

You would need to have an array of pid objects, as each input/output/setpoint would lead to different internal values at runtime within the pid class. Each pid would only see one member of each array, but you could achieve what you want

On Tue, Jun 29, 2021, 3:47 PM simeon9696 @.***> wrote:

Would it be possible to use arrays with the constructors? I have six valves with different input, output and setpoints so I wanted to know if could do something like below:

//Specify the links and initial tuning parameters double Kp=10, Ki=2, Kd=5;

double temperatures[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; double setPoints[] = {25.0, 25.0, 25.0, 25.0, 25.0, 25.0}; double valveDutyCycle[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};

//Define Variables we'll be connecting to

PID aNeckPID(&temperatures[0] + 0, &valveDutyCycle[0] + 0, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE); PID aBodyPID(&temperatures[0] + 1, &valveDutyCycle[0] + 1, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE); PID aBasePID(&temperatures[0] + 2, &valveDutyCycle[0] + 2, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE); PID bNeckPID(&temperatures[0] + 3, &valveDutyCycle[0] + 3, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE); PID bBodyPID(&temperatures[0] + 4, &valveDutyCycle[0] + 4, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE); PID bBasePID(&temperatures[0] + 5, &valveDutyCycle[0] + 5, &setPoints[0] + 5, Kp, Ki, Kd, REVERSE);

PID valves[] = {aNeckPID, aBodyPID, aBasePID, bNeckPID, bBodyPID, bBasePID};

Then in loop() do:

for (int i = 0; i < NUM_THERMOCOUPLES; i++) { valves[i].Compute(); //pwm1.setPWM(i, 0, valveDutyCycle[i]); Serial.print("VALVE: "); Serial.print(i); Serial.print(" IN: "); Serial.print(temperatures[i]); Serial.print(" SET: "); Serial.print(setPoints[i]); Serial.print(" C "); Serial.print(" OUT: "); Serial.print(valveDutyCycle[i]); Serial.println(" "); };

The valves are controlled via a PWM signal and I have 6 valves

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/br3ttb/Arduino-PID-Library/issues/113, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACYX4TKJC4VXWLNT47C3HDTVIPNPANCNFSM47Q4YHOQ .

simeon9696 commented 3 years ago

@br3ttb wouldn't that array of pid objects be my valves array?

br3ttb commented 3 years ago

Yup! I read too fast on my phone.

I've never seen this done, but I don't know why it wouldn't work. question: why are all your & setpoint references +5, while input and output are incremented?

Also, I'm rusty on pointers, but wouldn't you need to add the size of the data type to get to the next element? (+4,8,12 instead of 1,2,3)

Lastly, and again, rusty on pointers: Can you not do &output[2] to get a reference to that array element?

On Tue, Jun 29, 2021, 5:50 PM simeon9696 @.***> wrote:

@br3ttb https://github.com/br3ttb wouldn't that array of pid objects be my valves array?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/br3ttb/Arduino-PID-Library/issues/113#issuecomment-870942197, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACYX4WQU7U6DCXYGSB3WMDTVI5ZFANCNFSM47Q4YHOQ .

simeon9696 commented 3 years ago

@br3ttb your first question, that's a typo and I believe that's what led me to believe that it wasn't working because I was changing the first set point in the array and nothing changed so I thought I was passing it wrong in the first place.

Yes, I'd need to add the size of the actual data type, I think I'll determine that at using sizeof rather than hardcoding it

&output[2] I myself don't know if this will decay into a pointer to the first element in the array or the 3rd element in the array

Though, according to this link under the section 'Passing array to function using call by reference' it should work.

If you have any ideas please let me know! I'll comment here with the working code

joba-1 commented 3 years ago

see inline comments below

simeon9696 @.***> schrieb am Mi. 30. Juni 2021 um 12:46:

Yes, I'd need to add the size of the actual data type, I think I'll determine that at using sizeof rather than hardcoding it

no. As long as the compiler knows the type, it will do the pointer arithmetic for you.

&output[2] I myself don't know if this will decay into a pointer to the

first element in the array or the 3rd element in the array

you get the address of the 3rd element.

To clarify (I hope :) ) this is all synonym

given some_element_type output[3] and sizeof(char) == 1 and char my_ptr_to_char = (char )output;

these are the same (pointer to first element) output == &output[0] == (some_element_type *)my_ptr_to_char

and this to the second element output + 1 == &output[1] == (some_element_type *) my_ptr_to_char + sizeof(some_element_type)

and this to the last element output + 2 == &output[2] == (some_element_type ) my_ptr_to_char + 2 sizeof(some_element_type)

-- iphone so i typo

simeon9696 commented 3 years ago

Much thanks to @br3ttb and @joba-1. For some reason, I had to create an array of references to the PID objects.

//Specify the links and initial tuning parameters, these are global variables
double Kp=10, Ki=3, Kd=7;

double temperatures[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
double setPoints[] = {25.0, 25.0, 25.0, 25.0, 25.0, 25.0};
double valveDutyCycle[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};

//Define Variables we'll be connecting to
PID aNeckPID(&temperatures[0], &valveDutyCycle[0], &setPoints[0], Kp, Ki, Kd, DIRECT);
PID aBodyPID(&temperatures[1], &valveDutyCycle[1], &setPoints[1], Kp, Ki, Kd, DIRECT);
PID aBasePID(&temperatures[2], &valveDutyCycle[2], &setPoints[2], Kp, Ki, Kd, DIRECT);
PID bNeckPID(&temperatures[3], &valveDutyCycle[3], &setPoints[3], Kp, Ki, Kd, DIRECT);
PID bBodyPID(&temperatures[4], &valveDutyCycle[4], &setPoints[4], Kp, Ki, Kd, DIRECT);
PID bBasePID(&temperatures[5], &valveDutyCycle[5], &setPoints[5], Kp, Ki, Kd, DIRECT);

PID *valves[] = {&aNeckPID, &aBodyPID, &aBasePID, &bNeckPID, &bBodyPID, &bBasePID};

loop()

// NUM_THERMOCOUPLES is 6
 for (int i = 0; i < NUM_THERMOCOUPLES; i++)
  {
    valves[i] -> Compute();
    pwm1.setPWM(i, 0, valveDutyCycle[i]); 
    Serial.print("VALVE: ");
    Serial.print(i);
    Serial.print(" IN: ");
    Serial.print(temperatures[i]);
    Serial.print(" SET: ");
    Serial.print(setPoints[i]);
    Serial.print(" C ");
    Serial.print(" OUT: ");
    Serial.print(valveDutyCycle[i]);
    Serial.println(" ");
  };