BruControl: Brewery control & automation software

Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum

Help Support Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
I just clicked to give @BrunDog that 1000th like ;-)


In v1.1RC (1.0.1 build 10) How do we use(view) a Global variable inside a script, the 'new' command makes a new variable, the 'global' command is not recognized...
 
Last edited:
Thank you!!

Since it is an element, not a variable, you do not need to declare it inside a script. Just access it via

Code:
"Global Name" value

thank you both, it was the 'value' I was missing...

Having a blast with it, I really, really, really like the keypad that pops up when you click a PID or variable... that is a HUGE help on a tablet...

question, is Tilt in this release?
 
thank you both, it was the 'value' I was missing...

Having a blast with it, I really, really, really like the keypad that pops up when you click a PID or variable... that is a HUGE help on a tablet...

question, is Tilt in this release?

Yes
SdJ3D0j.png
 
what interface model and firmware are you using for Tilt? I plan on trying to use Feather M0, and v44J.

The release notes say: TILT sensor Device Element (ESP32 only, on virtual ports 220 - 224) - does that mean a vanilla ESP32 or something based on that like the Feather?

Either way, my vanilla ESP32's will be here Saturday to play with.
 
Does changing a BruControl PID Target to 0.5 degrees above or below the input(via script if that matters) cause the PID algorithm to act the same way as if the input were to move 0.5 degrees below or above the Target? Or does it 'reset' things in the PID algorithm that would make it act differently than the input just changing on it's own?
 
Does changing a BruControl PID Target to 0.5 degrees above or below the input(via script if that matters) cause the PID algorithm to act the same way as if the input were to move 0.5 degrees below or above the Target? Or does it 'reset' things in the PID algorithm that would make it act differently than the input just changing on it's own?

I suppose either scenario would give similar results. Technically a lowered temp target would be arrived at via no heating and a higher target would be arrived to via heating, so the times would be different, but probably not much difference to notice.

The real crux of your question however is the "reset" question. And thats a really good one. So, when a PID is running, re-establishing it (which occurs during a settings change) does not erase the steady-state parameters such as cycle time points and the integral. If you disable it and then re-enable it, those are indeed erased and started over. Make sense?
 
Doh! OK, I bought one of the HiLetGo units above along with a https://www.amazon.com/gp/product/B01N0SB08Q last september... will dig them up and program...

for a second I was going to ask this to integrate with the TiltPi, but then I realized BC can probably end up being better. Particularly I don't like how the TiltPi just takes a random value every 15 minutes to chart to the cloud instead of an average or mean of the 450 values in that same 15 minute period.
 
I suppose either scenario would give similar results. Technically a lowered temp target would be arrived at via no heating and a higher target would be arrived to via heating, so the times would be different, but probably not much difference to notice.

The real crux of your question however is the "reset" question. And thats a really good one. So, when a PID is running, re-establishing it (which occurs during a settings change) does not erase the steady-state parameters such as cycle time points and the integral. If you disable it and then re-enable it, those are indeed erased and started over. Make sense?

yep... to test, I just set the target a tenth of a degree above the input (at 2:49 in the chart), have a small Kp(1.0), a really small Ki(0.1), and a large Kd (100) and a MaxIntegral of 20%... it took nearly a full minute to move from 0, then climbed to 24, I assume 20 is the MaxIntegral contribution and 4 is related to the .1 degree offset and Kp.. Then when the temp starts to nudge up to the next level of the 1-wire sensor, we see the spikes happen, going to max and then zero, which seems to be ignoring the Kd that is supposed to steady the output trajectory...

any suggestions on making thee spikes be little 1-2% changes???
upload_2019-3-7_14-59-54.png
 

Attachments

  • upload_2019-3-7_14-49-25.png
    upload_2019-3-7_14-49-25.png
    158.4 KB · Views: 41
and this is what I get when going into the debug:
Code:
BruControl v44J.E Debug:1
%1&14;Rsp:%1
End:86290
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
Beg:140424
Msg:%2&17;
Debug:0
%2&17;
 
First, I'm not sure what the graph is showing. I assume temps from 1-wire sensors. While those spikes look really big, you have a span of only 2 degrees on the graph, so I wouldn't call them spikes. The 1-wire resolution is about 0.225 degrees F, so one step would look big on a temp graph like that. The blue spike is about that amount. The orange looks like 2 or 4 times that amount, but again, not sure what these are displaying.
 
and this is what I get when going into the debug:
Code:
BruControl v44J.E Debug:1
%1&14;Rsp:%1
End:86290
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
Beg:140424
Msg:%2&17;
Debug:0
%2&17;

Assuming you want the PID values... you need to go to the second level of debug, so send %1&14; twice.
 
First, I'm not sure what the graph is showing. I assume temps from 1-wire sensors. While those spikes look really big, you have a span of only 2 degrees on the graph, so I wouldn't call them spikes. The 1-wire resolution is about 0.225 degrees F, so one step would look big on a temp graph like that. The blue spike is about that amount. The orange looks like 2 or 4 times that amount, but again, not sure what these are displaying.

The spikes are using the right scale, temp is on the left, a .1 degree F temp change is causing a full-scale output change (80% ismy max output, I set it to 100% MaxOutput and Kd to 300 and it acted the same)
 
Assuming you want the PID values... you need to go to the second level of debug, so send %1&14; twice.

ahhhhh... I was wondering how to get that... well, I seemed to have locked up something, I shut down BC with things left running to do the debug, and when I started back up, I think I hit the shortcut to run 1.0, and now I get a blank workspace when I start 1.01... I have configs backed up several places and rebooted... is there somewhere I can delete the temp files that may be causing it the not see my config files? rebooting machine now
 
Dunno... everything is in the BruControl folder... nowhere else.

Also, little trick... you can actually connect your terminal (termite) then send the control code from the communications dialog of the interface. Just send %1 - no &14 or semicolon. The debug data will come out of the serial pipe.
 
OK, here is a small snippet(I cannot get out of it, so I am making the best of it)
the ambient temp in my office is causing the temp to slowly rise, so I set the target .10 degrees above the input and wait(67.42 target, input is 67.32)

the first section shows an error of 10, then the temp bumps up and we have an error of -13, then the temp goes back down, the error is 10, but the output is 255... how do I get that output to not go full scale?

Code:
Port:3 PWM out:0
1W on:200
-Port:3-
In:6732
Err:10
Prop:1
TInt:-4863
Int:-48
Der:0
Out:0
--
Port:3 PWM out:0
1W on:200
-Port:3-
In:6755
Err:-13
Prop:-1
TInt:-4876
Int:-48
Der:6900
Out:0
--
Port:3 PWM out:0
1W on:200
-Port:3-
In:6732
Err:10
Prop:1
TInt:-4866
Int:-48
Der:-6900
Out:255
--

edit: and disconnecting termite and going back in stopped the debug, so I am good there...
 
Shouldn't the Derivative in the 2nd message be added to, not subtracted from the other components, giving 49 instead of 5 as the output value?

Code:
Port:3 PWM out:61
1W on:200
-Port:3-
In:6822
Err:10
Prop:10
TInt:5100
Int:51
Der:0
Out:61
--
Port:3 PWM out:61
1W on:200
1W on:200
-Port:3-
In:6844
Err:-12
Prop:-12
TInt:3900
Int:39
Der:22
Out:5
--
Port:3 PWM out:5
1W on:200
-Port:3-
In:6844
Err:-12
Prop:-12
TInt:2700
Int:27
Der:0
Out:15
--
 
how do I get that output to not go full scale?

Your Kd is extremly high you want to dramatically reduce it or the best is to set it to zero. Derivative is as a rule of thumb best used in processes with large time constant or "lag". Otherwise there's mostly drawbacks using it especially if the input got noise of any kind.
 
I have lag so I want the control to be very, very slow, and small steps.. if it moves 10% of the scale for a 1 degree change in a minute, it is far, far too much, it should move 1%

For comparison, My Sestos has a P of 30, i of 1000 (but it is 1/i, so .001 I guess?) and a D of 120, (but that was seconds, not sure if the BC PID has a 'time' correlation to the units or what...)


Now my mega stopped outputting on the debug level 2... is there a way to reset it, I am not physically in front of it...
Code:
BruControl v44J.E Debug:1
%1&14;Rsp:%1
End:991
Beg:2589
Msg:%1&14;

BruControl v44J.E Debug:2
%1&14;Rsp:%1
End:2590
IP:192.168.1.202
CL:0
IP:192.168.1.202
CL:0
 
Your Kd is extremly high you want to dramatically reduce it or the best is to set it to zero. Derivative is as a rule of thumb best used in processes with large time constant or "lag". Otherwise there's mostly drawbacks using it especially if the input got noise of any kind.

This is correct. We are tuning heated fluid systems, not high speed motors... derivative can be safely set to 0 and use a PI controller only.
 
Last edited:
Hi Greg,

No worries. We have already integrated the Atlas Scientific pH and DO sensors to BC via the I2C. We are working on including it in v1.1.

So did this Atlas Scientific pH sensor make it into RC v1.0.1.10 because I haven't found it mentioned yet. If not, when might it be? I've had a shiny new Atlas pH setup for a while and I would very much like to use it :).
 
No, otherwise it would accelerate!

Derivative is a damper. This might help: https://www.controleng.com/articles/understanding-derivative-in-pid-control/

OK, how do I keep the output from changing so rapidly with a tiny error of a tenth of a degree? it went from 61 to 5 in a single sample... normally, I would use derivative.. I was thinking if it added it, it would have gone from 61 to 49, which is big, but not as big as 61 to 5..

Are you using something like this I found on arduino.cc? I am thinking if I do the math I will get a better picture
Code:
// Derivative term using error change
  //  derivative = (error - pre_error)  / (double)(timeChange * .000001); // uses real delta T not a fixed delta T
  //  DTerm = kd * derivative;
  // Derivative term using angle change
  if (kd) {
    derivative = (input - lastInput)  / (double)(timeChange * .000001); // uses real delta T not a fixed delta T
    DTerm =  (-kd * derivative);
  }
 
So did this Atlas Scientific pH sensor make it into RC v1.0.1.10 because I haven't found it mentioned yet. If not, when might it be? I've had a shiny new Atlas pH setup for a while and I would very much like to use it :).

Ouch! Called to the carpet. Truth be told... we deferred it! It's taken us long enough to get this version out. But I will make sure we get it added for incremental updates.
 
OK, how do I keep the output from changing so rapidly with a tiny error of a tenth of a degree? it went from 61 to 5 in a single sample... normally, I would use derivative.. I was thinking if it added it, it would have gone from 61 to 49, which is big, but not as big as 61 to 5..

Are you using something like this I found on arduino.cc? I am thinking if I do the math I will get a better picture
Code:
// Derivative term using error change
  //  derivative = (error - pre_error)  / (double)(timeChange * .000001); // uses real delta T not a fixed delta T
  //  DTerm = kd * derivative;
  // Derivative term using angle change
  if (kd) {
    derivative = (input - lastInput)  / (double)(timeChange * .000001); // uses real delta T not a fixed delta T
    DTerm =  (-kd * derivative);
  }

You do not want to use derivative. Any singular change, multiplied by a big coefficient, will create a massive variation. Eliminate it completely IMO. If you want slow adjustments... use a moderate P and a moderate I. Limit the integral as needed to perform but prevent overwhelming windup.
 
You do not want to use derivative. Any singular change, multiplied by a big coefficient, will create a massive variation. Eliminate it completely IMO. If you want slow adjustments... use a moderate P and a moderate I. Limit the integral as needed to perform but prevent overwhelming windup.

How do I slow down the changes from happening?


Here is the complete code snippet from http://forum.arduino.cc/index.php?topic=430374.0
(in the derivative section 2 methods are discussed, one using 'error - previous error', and the other using 'input-previous input'. Can you tell us which you use or share the code snippet so I can do the math by hand to get a grasp of what I need or what is happening?)

It has been just short of 30 years since I did the math and diff eq, but I can dig out the textbook from my engineering control theory class where we had to show out work for boat rudders and conveyor motors and such... if I can calculate how much it will change, I can come up with better coefficients manually and then watch the PID happen...


Code:
unsigned long now = micros();
unsigned long timeChange = (now - lastTime);
if (timeChange >= (SampleTime * 1000)) // Minimum Sample Time
{
  double DTerm = 0;
  double derivative = 0;
  // kp -  proportional gain
  // ki -  Integral gain
  // kd -  derivative gain
  // dt -  loop interval time
  // outMax - maximum value of manipulated variable
  // outMin - minimum value of manipulated variable

  // Calculate error
  double error = Setpoint - input;

  // Proportional term

  double PTerm = kp * error;

  // Integral term
  integral += error * (double) (timeChange * .000001); // uses real delta T not a fixed delta T
  ITerm = ki * integral;
  if ((ITerm > outMax) || (ITerm < outMin) ) integral -= error * (double) (timeChange * .000001); // Prevemts Windup
  /*
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    We were not talking about that but it's something clever:
    ....Jerky robot, that's because the Kd * de(t)/dt term goes to infinity when you change the set-point. Try instead of using the angle error, e(t), use the negative of the actual value change, dangle(t)/dt. they are equivalent but this way you avoid infinity errors.

    Kd*de(t)/dt = -Kd*dangle(t)/dt
    ///////////////////////////////////////////////////////////////////////////////////////////////////
  */
  // Derivative term using error change
  //  derivative = (error - pre_error)  / (double)(timeChange * .000001); // uses real delta T not a fixed delta T
  //  DTerm = kd * derivative;
  // Derivative term using angle change
  if (kd) {
    derivative = (input - lastInput)  / (double)(timeChange * .000001); // uses real delta T not a fixed delta T
    DTerm =  (-kd * derivative);
  }

  //Compute PID Output
  double output = PTerm + ITerm + DTerm ;
  //output = max(outMin,output);
  if (output > outMax) output = outMax;
  else if (output < outMin) output = outMin;

  //Remember some variables for next time
  pre_error = error;
  lastInput = input;
  lastTime = now;
  // Debugging
#ifdef DEBUG
  static long QTimer = millis();
  if ((long)( millis() - QTimer ) >= 100) {  // Spam Delay at 100 miliseconds
    QTimer = millis() ;
    char S[10];
    //Serial.print(F("\tSkipCtr ")); Serial.print(SkipCtr);
    Serial.print(F("\tIn ")); Serial.print(dtostrf(input, 6, 2, S));
    Serial.print(F("\tSetpt ")); Serial.print(dtostrf(Setpoint, 6, 2, S));
    Serial.print(F("\t/\\T ")); Serial.print(dtostrf(timeChange, 6, 2, S));
    Serial.print(F("\tKp ")); Serial.print(dtostrf(PTerm, 6, 2, S));
    Serial.print(F("\tKi ")); Serial.print(dtostrf(ITerm, 6, 2, S));
    //Serial.print(F("\tKd ")); Serial.print(dtostrf(kd,6,2,S));
    //Serial.print(F("\tderivative ")); Serial.print(dtostrf(derivative,6,2,S));
    Serial.print(F("\tKd ")); Serial.print(dtostrf(DTerm, 9, 0, S));
    Serial.print(F("\tOut ")); Serial.print((int)output);
    Serial.println();
  }
#endif
}
 
Does anyone have a link to a preferred DIN rail mount 30A DP 120V coil? My google-fu is not strong this morning for some reason.
 
Back
Top