Redstone Pen

Redstone Pen

6M Downloads

Question about the Ramp Tune-In example, suitable for simple PID control?

toastonrye opened this issue Β· 10 comments

commented

I'm referencing the example from the docs;

The value of R is slowly ramped up or down until it matches the input value Y.
TICKRATE = IF(R!=Y, 1, 4)
T = CLOCK() % 2
R = IF(R<Y AND T.RE, R+1, R)
R = IF(R>Y AND T.RE, R-1, R)

By default the RLC runs every 4 ticks, but if R doesn't equal Y then the controller is sped up for faster calculation updates?
And the whole point of T is just a rising edge, but there is only a rising edge if the tickrate is an odd number?

I'm trying to figure out a simple PID control, and above looks to be exactly that.
My question, what is the best way I can try to slow it down. My loop is reacting too fast, and overshooting.
Also, it doesn't seem possible to write my own simple functions? Thanks,

commented

Hi, you make a good point there, I actually should sweep-and-update the documentation.

Before answering your questions: In the timing and quantization range that the game allows, PID might not behave ideal as expected from RW applications. The controller will likely also jitter when tuned in (between error==1 or 0).

I quickly made a quick setup for checking this. It consists of 2 RLCs. The one is a PID filter, and the other a simple low pass, and added tracks and levers for set-point and noise. Principally a PID is a nice tool - it depends that your plant at the output looks like ;)

image

image

PID

# PID config, values scaled
Kp = 20      # Proportional coeff
Ki = 2       # Integral coeff
Kd = 0       # Differential coeff
Isat = 200   # Integrator saturation
Ts = 4       # Sample period

e = Y-G       # error (setpoint-feedback)
s = TIV1(Ts)  # sample trigger
o = (e < 0) & (R==0) # overrun

# Calculate PID at sample points
yp = IF(s, e*Kp           , yp)  # P output
yi = IF(s & !o, yi + e*Ki , yi ) # I output
yi = LIM(yi, -Isat, Isat)        # I saturated
yd = IF(s, (e-e1)*Kd      , yd)  # D output
e1 = IF(s, e              , e1)  # Save e(k-1)
YY = yp + yi + yd                # Summary output

# Output to R, scale down
R = YY/10

Low pass

#
# s-T1  ( 1 / 1+Z ) filter
#
# The higher Tc, the higher the filter
# time constant.
# s-T1 filter config, Tc = 1 to 99
Tc = 75
T2 = 100-Tc
Ts = 4 # Sample time

s = TIV1(Ts)

# G is input, scale up, Yellow only
# as direct noise test
x = (G+Y) * 100

yk = IF(!s, yk, (yk*Tc + x*T2) / 100)

# Output is red, scale down, round up
# at 0.1
R = (yk+10) / 100

Answers

  1. Yes, the RLC has 4 ticks, but re-schedules if an input changes (OFF->ON or vice versa), so that it
    reacts fast to logic whilst keeping the CPU consumption low. T is really just an edge generator,
    as you already presumed. clock()%2 yields 0 or 1, where a transition from 0 to >0 is detected
    as a rising edge. Since a few Mod versions, I added the TIVx() timers, which are more accurate
    for triggering.

  2. As a PID example, the code above could be used.

  3. Slowing down your controller can be now done with increasing the sample period, e.g. s = TIVx(10)
    instead of s = TIVx(4) as in the code above.

  4. Yes, the code window is kept tight and limited to one screen, so that not too much code is entered -
    sounds strange I know, but this is to restrict the performance that the RLCs need. In Single-Player
    we normally do not care, but the mod is also used on servers (mostly not ultra high spec machines),
    and mods should take these use cases into account.

Do you make something like a temperature control? I mean where you put energy into the system, but not
take it out? (like a heater control?).

commented

This is really cool, thanks for the detailed reply! Gives me some homework to try and understand both code snippets.
Yea, I'm definitely interested in any documentation updates/examples to try.

  1. I'm going to have to experiment more with ticks, vanilla Redstone I think is 2 ticks, the RLC is 4 ticks.. I haven't played with TIVx() yet. I wish that carpet mod for Fabric was on Forge, so I could freeze/ step through ticks for learning/debugging.
  2. I copy and pasted your example, but I think I am misunderstanding how to interface with it. I made a short 4 minute video to try and concisely explain my setup and what I am trying to do.
    https://www.youtube.com/watch?v=egkZK_4Pmf4
  3. I'll need to test this tomorrow, to see how it works.
  4. Yes that makes sense, I'm just use to ComputerCraft, writing functions for when I need to call code. I'm trying to wrap my mind around how to do that with RLCs. It seems from your examples, using the AND (&) with an enable bit in a IF(X & ENABLE, true, false) is what I need to be using.

Yes, temperature control! I think it would be really cool to demonstrate your RLC PID with PneumaticCraft's heat system.

commented

Ok, reading through your PID code more carefully, I definitely interfaced incorrectly to it.
My thermostat feedback should be on the PID controller's green, and my output to the regulator should have been on the PID controller's red.

I'm still unsure about that low pass filter controller, do I even need it? Or was that made for simulating?

commented
commented

Hey man, alright, I could take a look at the video, so let's quickly walk through ;)

As you deduced already correctly you only need the RLC with the PID code:

2024-04-05_20 10 41

  • Your feedback input is the thermostat at G, and it should rise from 0 to 15 like the temperature rises.
  • Your target temperature is set on Y with the analog lever, and the 0-to-15 scaled signal represents the same temperature values as the thermostat curve.
  • Your controller output is R to the Regulator Tube Module.

Digital filters like PID normally run with a constant sampling rate. To do this with the RLC, we need make the sample trigger s=TIV1(Ts) - if the sampling period Ts is 20tck, then s will be ON for one tick every second. It's a bit "meh" that we need to use the signal = IF(s, ...., signal) thing to skip calculating if we are not in that sample tick, but well;

What the PID does is trying to bring G to the same value as Y by changing R as needed.

  • First we calculate how far we are away, that's called the error e: e = Y-G.

  • The proportional part directly reacts with a scaling to that error yp = Kp * e

  • The integral part reacts over time by adding Ki * e every sample tick to its output.

  • The differential part reacts to how fast G vs Y changes with the scaling Kd * de/dt, where the delta de is simply calculated by subtracting the last error value from the current one. And the the time change is Ts because this is the difference between the last and the current sampling point.

  • The saturation is only a fence guard that is often built into PI controllers, so that the integrator does not run away and needs ages to get down again.

  • I additionally added the overrun o to my setup, this can help avoiding that the integrator runs away downward, because redstone does not have negative values, so we can only push energy into the system, but cannot actively take it out. If our output R is already zero, the integrator can be set on hold, so that it does not fall far below zero while the boiler slowly cools down itself.

  • To increase the resolution of the coefficients, they are scaled x10 Kp=2.0 -> 20, and we finally divide the output by 10 again.

That's basically it. The rest should be tuning. Likely, do will not need the differential part, with that resolution and noise it normally causes more trouble than help. The resulting PI controller code is then:

# PI config, values scaled x10
Ts = 4       # Sample period
Kp = 20      # Proportional coeff
Ki = 2       # Integral coeff
Isat = 200   # I saturation

e = Y-G      # error
s = TIV1(Ts) # sample trigger
o = (e < 0) & (R==0) # overrun

# Calculate PI at sample points
yp = if(s, e*Kp      , yp) # P output 
yi = if(s & !o, yi + e*Ki  , yi )  # I output
yi = LIM(yi, -Isat, Isat) # I saturated

# Output to R, scale down
R = (yp + yi + yd) / 10
  • If you get overshoots, play with the sampling time first, the time quantization is likely better than the redstone value resolution.

Alternatively, the hysteresis controller in the docs may also be a simple alternative in case the tuning does not work out. Cheer's;;

commented

Oky, small update, to ease the pain with the sampling rate, I modified TICKRATE=... to ignore signal interrupts, so the whole TIV1 and IF... will be obsolete then. What MC version/loader are you on, so that I update this earlier?

commented

I am currently playing a modpack E9E (v1.20.1) for Minecraft 1.19.2.
But I'll update myself.

Redstone Pen 1.2.20
Forge 1.19.2-43.2.14

I had another question I was meaning to ask, I haven't been in game yet to check.
Is it possible to do something like a tickrate = 0, so it stops? Like a debugging where you could step through each calculation?

commented

Uh, ok. mc1.19 is a while ago. I'll need to port back stepwise, but should be feasible.

I have no debug stepping implemented - the whole code is executed every tick top-down, and the world around cannot be stopped normally. What I have is a display of the current values of variables by hovering the RLC symbol in the UI:
image

Hmm, something like a oscilloscope like tracking could help, but this may be a mayor pain to implement with the means that MC provides. I'll give it another thought some day ;)

commented

What you have shown me is working great so far, I wouldn't bother back-porting it to 1.19 if you are already onto the next version. I'm actually not sure what you mean by modifying the tickrate to ignore interrupts, I don't see tickrate in your example code?

I am not sure how that carpet mod freezes the tickrate, I guess he is doing it to the whole world which can be weird.

It's actually really interesting you mention the oscilloscope, I was thinking that would be really cool to have a historian like MineFactory Reloaded did. I've been playing that old version recently, it would be cool to have some sort of trend of your 6 possible colours.

If you don't remember it, I have a short 10 second example of that MFR historian here https://youtu.be/pUNqm1xlFQM?t=900 (link should take you to the 15:00 mark where it is).

Anyways, you more than answered my original question. Your PID script/ explanation is great, thanks so much!

commented

Hi, aye something similar crossed my mind. It would have to support multi-channel somehow, and still fit into a vanillarish look & feel, or be an item with a monitor. Let's see, I have already a connector for Arduino and other stuff in the mod, so a scope UI should be a feasible challenge ;) Cheer's;-