Skip to content

Commit 16b3494

Browse files
committed
Revise L07
1 parent 973658d commit 16b3494

16 files changed

+912
-0
lines changed

07_Regelungstechnik/07_Regelungstechnik.md

Lines changed: 565 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# https://www.csestack.org/control-systems-simulation-python-example/
2+
import math
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
6+
steps = 1000
7+
8+
class SecondOrderSystem:
9+
def __init__(self, d1, d2):
10+
if d1 > 0:
11+
e1 = -1.0 / d1
12+
x1 = math.exp(e1)
13+
else: x1 = 0
14+
if d2 > 0:
15+
e2 = -1.0 / d2
16+
x2 = math.exp(e2)
17+
else: x2 = 0
18+
a = 1.0 - x1 # b = x1
19+
c = 1.0 - x2 # d = x2
20+
self.ac = a * c
21+
self.bpd = x1 + x2
22+
self.bd = x1 * x2
23+
self.init_system()
24+
25+
def init_system(self):
26+
self.Yppr = 0
27+
self.Ypr = 0
28+
29+
def __call__(self, X):
30+
Y = self.ac * X + self.bpd * self.Ypr - self.bd * self.Yppr
31+
self.Yppr = self.Ypr
32+
self.Ypr = Y
33+
return Y
34+
35+
class PIDControlBlock:
36+
def __init__(self, Kp, Ki, Kd):
37+
self.Kp = Kp
38+
self.Ki = Ki
39+
self.Kd = Kd
40+
self.Epr = 0
41+
self.Eppr = 0
42+
self.Epppr = 0
43+
self.Sum = 0
44+
45+
def __call__(self, E):
46+
self.Sum += 0.5 * self.Ki * (E + self.Epr) # where T ~1
47+
U = self.Kp * E + self.Sum + 0.1667 * self.Kd * (E - self.Epppr + 3.0 * (self.Epr - self.Eppr))
48+
self.Epppr = self.Eppr
49+
self.Eppr = self.Epr
50+
self.Epr = E
51+
return U
52+
53+
class ClosedLoopSystem:
54+
def __init__(self, controller, plant) :
55+
self.P = plant
56+
self.C = controller
57+
self.Ypr = 0
58+
59+
def __call__(self, X):
60+
E = X - self.Ypr
61+
U = self.C(E)
62+
Y = self.P(U)
63+
self.Ypr = Y
64+
return Y
65+
66+
Plant = SecondOrderSystem(250, 100)
67+
#Pid = PIDControlBlock(5, 0.0143, 356.25)
68+
Pid = PIDControlBlock(2, 0, 0)
69+
Ctrl = ClosedLoopSystem(Pid, Plant)
70+
t = np.arange(0, 1001)
71+
setpoints = np.zeros(len(t))
72+
setpoints[np.where(t > 50)]= 100
73+
y = np.arange(0, 1001, dtype = float)
74+
for index, value in enumerate(setpoints):
75+
y[index]=Ctrl(value)
76+
fig, ax = plt.subplots()
77+
ax.plot(t, setpoints, label = "Setpoint")
78+
ax.plot(t, y, label = "Controled speed level")
79+
plt.xlabel("Time")
80+
plt.ylabel("Speed")
81+
plt.legend()
82+
plt.grid()
83+
plt.show()
84+
#plt.savefig('foo.png')

07_Regelungstechnik/code/main.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# https://www.csestack.org/control-systems-simulation-python-example/
2+
import math
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
6+
steps = 2000
7+
8+
class SecondOrderSystem:
9+
def __init__(self, d1, d2):
10+
if d1 > 0:
11+
e1 = -1.0 / d1
12+
x1 = math.exp(e1)
13+
else: x1 = 0
14+
if d2 > 0:
15+
e2 = -1.0 / d2
16+
x2 = math.exp(e2)
17+
else: x2 = 0
18+
a = 1.0 - x1 # b = x1
19+
c = 1.0 - x2 # d = x2
20+
self.ac = a * c
21+
self.bpd = x1 + x2
22+
self.bd = x1 * x2
23+
self.init_system()
24+
25+
def init_system(self):
26+
self.Yppr = 0
27+
self.Ypr = 0
28+
29+
def __call__(self, X):
30+
Y = self.ac * X + self.bpd * self.Ypr - self.bd * self.Yppr
31+
self.Yppr = self.Ypr
32+
self.Ypr = Y
33+
return Y
34+
35+
fig, ax = plt.subplots()
36+
37+
Plant = SecondOrderSystem(250, 100)
38+
t = np.arange(0, steps)
39+
y = np.arange(0, steps, dtype = float)
40+
for speed in [10, 100, 150, 200]:
41+
for index, value in enumerate(t):
42+
y[index]=Plant(speed)
43+
ax.plot(t, y, label = f"Voltage level '{speed}'")
44+
Plant.init_system()
45+
46+
plt.xlabel("Time")
47+
plt.ylabel("Speed")
48+
plt.legend()
49+
plt.grid()
50+
#plt.show()
51+
plt.savefig('foo.png')
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
"""
2+
Move to specified pose
3+
Author: Daniel Ingram (daniel-s-ingram)
4+
Atsushi Sakai (@Atsushi_twi)
5+
Seied Muhammad Yazdian (@Muhammad-Yazdian)
6+
P. I. Corke, "Robotics, Vision & Control", Springer 2017, ISBN 978-3-319-54413-7
7+
"""
8+
9+
import matplotlib.pyplot as plt
10+
import numpy as np
11+
from random import random
12+
13+
14+
class PathFinderController:
15+
"""
16+
Constructs an instantiate of the PathFinderController for navigating a
17+
3-DOF wheeled robot on a 2D plane
18+
Parameters
19+
----------
20+
Kp_rho : The linear velocity gain to translate the robot along a line
21+
towards the goal
22+
Kp_alpha : The angular velocity gain to rotate the robot towards the goal
23+
Kp_beta : The offset angular velocity gain accounting for smooth merging to
24+
the goal angle (i.e., it helps the robot heading to be parallel
25+
to the target angle.)
26+
"""
27+
28+
def __init__(self, Kp_rho, Kp_alpha, Kp_beta):
29+
self.Kp_rho = Kp_rho
30+
self.Kp_alpha = Kp_alpha
31+
self.Kp_beta = Kp_beta
32+
33+
def calc_control_command(self, x_diff, y_diff, theta, theta_goal):
34+
"""
35+
Returns the control command for the linear and angular velocities as
36+
well as the distance to goal
37+
Parameters
38+
----------
39+
x_diff : The position of target with respect to current robot position
40+
in x direction
41+
y_diff : The position of target with respect to current robot position
42+
in y direction
43+
theta : The current heading angle of robot with respect to x axis
44+
theta_goal: The target angle of robot with respect to x axis
45+
Returns
46+
-------
47+
rho : The distance between the robot and the goal position
48+
v : Command linear velocity
49+
w : Command angular velocity
50+
"""
51+
52+
# Description of local variables:
53+
# - alpha is the angle to the goal relative to the heading of the robot
54+
# - beta is the angle between the robot's position and the goal
55+
# position plus the goal angle
56+
# - Kp_rho*rho and Kp_alpha*alpha drive the robot along a line towards
57+
# the goal
58+
# - Kp_beta*beta rotates the line so that it is parallel to the goal
59+
# angle
60+
#
61+
# Note:
62+
# we restrict alpha and beta (angle differences) to the range
63+
# [-pi, pi] to prevent unstable behavior e.g. difference going
64+
# from 0 rad to 2*pi rad with slight turn
65+
66+
rho = np.hypot(x_diff, y_diff)
67+
alpha = (np.arctan2(y_diff, x_diff)
68+
- theta + np.pi) % (2 * np.pi) - np.pi
69+
beta = (theta_goal - theta - alpha + np.pi) % (2 * np.pi) - np.pi
70+
v = self.Kp_rho * rho
71+
w = self.Kp_alpha * alpha - self.Kp_beta * beta
72+
73+
if alpha > np.pi / 2 or alpha < -np.pi / 2:
74+
v = -v
75+
76+
return rho, v, w
77+
78+
79+
def move_to_pose(controller, x_start, y_start, theta_start, x_goal, y_goal, theta_goal, trajectory_color):
80+
x = x_start
81+
y = y_start
82+
theta = theta_start
83+
84+
x_diff = x_goal - x
85+
y_diff = y_goal - y
86+
87+
x_traj, y_traj = [], []
88+
89+
rho = np.hypot(x_diff, y_diff)
90+
while rho > 0.003 or (abs(theta - theta_goal) > 0.01):
91+
x_traj.append(x)
92+
y_traj.append(y)
93+
94+
x_diff = x_goal - x
95+
y_diff = y_goal - y
96+
97+
rho, v, w = controller.calc_control_command(
98+
x_diff, y_diff, theta, theta_goal)
99+
100+
if abs(v) > MAX_LINEAR_SPEED:
101+
v = np.sign(v) * MAX_LINEAR_SPEED
102+
103+
if abs(w) > MAX_ANGULAR_SPEED:
104+
w = np.sign(w) * MAX_ANGULAR_SPEED
105+
106+
theta = theta + w * dt
107+
x = x + v * np.cos(theta) * dt
108+
y = y + v * np.sin(theta) * dt
109+
110+
if show_animation: # pragma: no cover
111+
plt.cla()
112+
plot_scene(x_start, y_start, theta_start,
113+
x_goal, y_goal, theta_goal,
114+
x, y, theta,
115+
x_traj, y_traj,
116+
trajectory_color)
117+
118+
plot_scene(x_start, y_start, theta_start,
119+
x_goal, y_goal, theta_goal,
120+
x, y, theta,
121+
x_traj, y_traj,
122+
trajectory_color)
123+
124+
def plot_scene(x_start, y_start, theta_start,
125+
x_goal, y_goal, theta_goal,
126+
x, y, theta,
127+
x_traj, y_traj,
128+
trajectory_color):
129+
plt.text(10, 10, "diff_x = {:>2.2f}\ndiff_y = {:>2.2f}\ndiff_t = {:>2.2f}".
130+
format(abs(x_goal - x),
131+
abs(y_goal - y),
132+
abs(theta_goal- theta)
133+
))
134+
plt.arrow(x_start, y_start, np.cos(theta_start),
135+
np.sin(theta_start), color='r', width=0.1)
136+
plt.arrow(x_goal, y_goal, np.cos(theta_goal),
137+
np.sin(theta_goal), color='g', width=0.1)
138+
plot_vehicle(x, y, theta, x_traj, y_traj, trajectory_color)
139+
140+
141+
def plot_vehicle(x, y, theta, x_traj, y_traj, trajectory_color): # pragma: no cover
142+
# Corners of triangular vehicle when pointing to the right (0 radians)
143+
p1_i = np.array([0.5, 0, 1]).T
144+
p2_i = np.array([-0.5, 0.25, 1]).T
145+
p3_i = np.array([-0.5, -0.25, 1]).T
146+
147+
T = transformation_matrix(x, y, theta)
148+
p1 = np.matmul(T, p1_i)
149+
p2 = np.matmul(T, p2_i)
150+
p3 = np.matmul(T, p3_i)
151+
152+
plt.plot([p1[0], p2[0]], [p1[1], p2[1]], 'k-')
153+
plt.plot([p2[0], p3[0]], [p2[1], p3[1]], 'k-')
154+
plt.plot([p3[0], p1[0]], [p3[1], p1[1]], 'k-')
155+
156+
plt.plot(x_traj, y_traj, trajectory_color)
157+
158+
# for stopping simulation with the esc key.
159+
plt.gcf().canvas.mpl_connect(
160+
'key_release_event',
161+
lambda event: [exit(0) if event.key == 'escape' else None])
162+
163+
plt.xlim(0, 20)
164+
plt.ylim(0, 20)
165+
166+
plt.pause(dt)
167+
168+
169+
def transformation_matrix(x, y, theta):
170+
return np.array([
171+
[np.cos(theta), -np.sin(theta), x],
172+
[np.sin(theta), np.cos(theta), y],
173+
[0, 0, 1]
174+
])
175+
176+
# Robot specifications
177+
MAX_LINEAR_SPEED = 15
178+
MAX_ANGULAR_SPEED = 8
179+
180+
# Animated or static visualisation
181+
show_animation = False
182+
dt = 0.005
183+
184+
def main():
185+
x_start = 3.25
186+
y_start = 16.0
187+
theta_start = 0.38
188+
x_goal = 15
189+
y_goal = 2.5
190+
theta_goal = -1.2
191+
192+
print("Initial x: %.2f m\nInitial y: %.2f m\nInitial theta: %.2f rad\n" %
193+
(x_start, y_start, theta_start))
194+
print("Goal x: %.2f m\nGoal y: %.2f m\nGoal theta: %.2f rad\n" %
195+
(x_goal, y_goal, theta_goal))
196+
197+
print("Press Esc to stop.")
198+
199+
controller_A = PathFinderController(5, 15, 3)
200+
move_to_pose(controller_A, x_start, y_start, theta_start, x_goal, y_goal, theta_goal, '--b')
201+
202+
controller_B = PathFinderController(5, 3, 3)
203+
move_to_pose(controller_B, x_start, y_start, theta_start, x_goal, y_goal, theta_goal, '--r')
204+
205+
#plt.savefig('move_to_pose.png')
206+
plt.show()
207+
print("Aus die Maus")
208+
209+
if __name__ == '__main__':
210+
main()
75.7 KB
Loading
401 KB
Loading
6.78 KB
Loading
5.56 KB
Loading
6.36 KB
Loading
21.2 KB
Loading

0 commit comments

Comments
 (0)