stfwi / redstonepen

Minecraft mod adding a pen to draw Redstone tracks in all directions, a PLC for Redstone, and relays.
MIT License
14 stars 2 forks source link

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

Closed toastonrye closed 2 months ago

toastonrye commented 3 months ago

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,

stfwi commented 3 months ago

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?).

toastonrye commented 3 months ago

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.

toastonrye commented 3 months ago

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?

stfwi commented 3 months ago

Hi, cool, ;). Ya the filter is not needed, I just needed in the test world some plant to control, something reacting slowly and where noise/load can be added. Cheers,-On 5 Apr 2024, at 05:34, toastonrye @.***> wrote: 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?

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.***>

stfwi commented 3 months ago

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

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.

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

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

stfwi commented 3 months ago

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?

toastonrye commented 3 months ago

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?

stfwi commented 2 months ago

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 ;)

toastonrye commented 2 months ago

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!

stfwi commented 2 months ago

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;-