Feedback control · University · about 30 min
Finding the gain where it oscillates, and working back from there to something usable.
[1 mark]The Ziegler-Nichols PID row from the lesson, for a measured Ku and Tu. What does it print?
KU, TU = 10.0, 1.6 kp = 0.6 * KU ki = 1.2 * KU / TU kd = 0.075 * KU * TU print(round(kp, 2), round(ki, 2), round(kd, 2))
6.0 7.5 1.2
Kp = 0.6 x 10 = 6, Ki = 1.2 x 10 / 1.6 = 7.5, Kd = 0.075 x 10 x 1.6 = 1.2.
[1 mark]Ku = 8 and Tu = 2 s. What Ki does the Ziegler-Nichols PI row give? Give two decimal places.
[1 mark]Ku = 9. What Kp does the Ziegler-Nichols P-only row give?
[1 mark]Ziegler-Nichols gains make the robot swing lively, each swing a quarter of the last. What is a common and sensible next move?
[1 mark]The response arrives, settles short of the target, and stays short. What should change?
[1 mark]The response shows a slow, wallowing oscillation. What should change?
[1 mark]In what order does the lesson say to bring in the three terms?
Run the heading loop at several gains, print the swing at each, and print ku: and tu:.
from bugbot import * connect() DT = 0.25
The hint students can ask for: Run the same loop several times, each at a higher gain, and watch the error. Steady oscillation that neither grows nor dies is the ultimate gain. The period is the time between two peaks.
from bugbot import *
connect()
DT = 0.25
def swing(kp, ticks=32):
"""Turn a quarter turn at this gain; report how much the error swings, and how fast, in the second half."""
target = heading() + 90
errors = []
for tick in range(ticks):
error = (target - heading() + 180) % 360 - 180
errors.append(error)
plot("kp %s" % kp, error)
drive(0, 0, max(-100.0, min(100.0, kp * error)))
wait(DT)
stop()
wait(0.5)
late = errors[ticks // 2:]
mean = sum(late) / len(late)
crossings = 0
for a, b in zip(late, late[1:]):
if (a - mean) * (b - mean) < 0:
crossings += 1
span = max(late) - min(late)
period = len(late) * DT * 2.0 / crossings if crossings else 0.0
return span, period
ku, tu = 0.0, 0.0
for kp in (2.0, 4.0, 6.0, 8.0, 10.0):
span, period = swing(kp)
print("kp", kp, "swing", round(span, 1), "period", round(period, 2))
if span > 10.0 and ku == 0.0:
ku, tu = kp, period
print("ku:", ku)
print("tu:", round(tu, 2))
Any program that meets the task's checks is marked correct in the simulator; this is one way, not the only way.