-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtracking_force.m
145 lines (127 loc) · 5.29 KB
/
tracking_force.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
% 环境力 f_env = k_env * (x_act - x_init)
%% Parameters
% Initial parameters of controlled system.
m = 1;
c = 0;
k = 0;
maxM = 200; % Maximum gain allowed by slider.
maxC = 200;
maxK = 100;
initialPos = 5;
initialVel = 0;
% Initial controller parameters.
% p = 0; % Proportional gain (spring).
% i = 0; % Integral gain.
% d = 0; % Derivative gain (damper).
% maxP = 200; % Maximum gain allowed by slider.
% maxI = 200;
% maxD = 100;
tend = 5; % Window of simulation time being shown.
% Target of controller.
targetPos = 0;
targetVel = 0; % Not changed (so far anyway).
%% GUI setup:
fig = figure(1);
fig.Name = 'PID Example';
fig.MenuBar = 'none';
fig.Position(3:4) = [800, 600];
plotAx = subplot(4, 4, [1, 2, 3, 5, 6, 7, 9, 10, 11]); % For a time history plot of the result.
plotAx.ButtonDownFcn = @setpointClickFcn;
plotAx.Box = 'on';
hold on;
positionTrace = plot(0, 0, 'LineWidth', 2);
currentPositionPt = plot(0, 0, '.r', 'MarkerSize', 30);
% setpointLine = plot([0, tend], [targetPos, targetPos], ':k', 'LineWidth', 2); % Show the target of the controller.
hold off;
axis([0, tend, -10, 10]);
% Bottom 1/4 is left open for slider bars (P, I, & D gains).
mSlider = uicontrol(fig, 'Style', 'slider');
mSlider.Units = 'normalized';
mSlider.Position(3) = 0.8; % Make it nearly the width of the figure.
mSlider.Position(2) = 0.2; % Vertically space out sliders.
mSlider.Callback = @pCallback;
mSliderLabel = uicontrol(fig, 'Style', 'text', 'String', 'Mass: 0', 'Units', 'normalized');
mSliderLabel.Position = [0.85, 0.145, 0.1, 0.08];
cSlider = uicontrol(fig, 'Style', 'slider');
cSlider.Units = 'normalized';
cSlider.Position(3) = 0.8; % Make it nearly the width of the figure.
cSlider.Position(2) = 0.12;
cSlider.Callback = @iCallback;
cSliderLabel = uicontrol(fig, 'Style', 'text', 'String', 'Damp: 0', 'Units', 'normalized');
cSliderLabel.Position = [0.85, 0.065, 0.1, 0.08];
kSlider = uicontrol(fig, 'Style', 'slider');
kSlider.Units = 'normalized';
kSlider.Position(3) = 0.8; % Make it nearly the width of the figure.
kSlider.Position(2) = 0.05;
kSlider.Callback = @dCallback;
kSliderLabel = uicontrol(fig, 'Style', 'text', 'String', 'Spring: 0', 'Units', 'normalized');
kSliderLabel.Position = [0.85, -0.005, 0.1, 0.08];
% Select which dynamics should be simulated currently.
dynamicsSelector = uicontrol(fig, 'Style', 'popupmenu');
dynamicsSelector.Units = 'normalized';
dynamicsSelector.Position = [0.72 0.8 0.25 0.1];
dynamicsSelector.String = {'Constant force & Fixed point', 'Dynamic force & Fixed point', 'Constant force & Trajectory', 'Dynamic force & Tracjectory'};
dynamicsSelector.Callback = @dynamicsSelectorFcn;
currentDynamics = 1; % 1,2,3 corresponding to the selector values.
dynamicsLabel = uicontrol(fig, 'Style', 'text', 'String', 'Dynamics (w/o controller)', 'Units', 'normalized');
dynamicsLabel.Position = [0.72, 0.9, 0.25, 0.03];
% Select the sort of setpoint being tracked. Defaults to click the plot to
% select.
setpointSelector = uicontrol(fig, 'Style', 'popupmenu');
setpointSelector.Units = 'normalized';
setpointSelector.Position = [0.72 0.65 0.25 0.1];
setpointSelector.String = {'Click plot', 'Square wave', 'Triangle wave', 'Sawtooth wave', 'Sine wave'};
setpointSelector.Callback = @setpointSelectorCallback;
currentSetpointMode = 1; % 1,2,3,4,5 corresponding to the selector values.
setpointLabel = uicontrol(fig, 'Style', 'text', 'String', 'Controller setpoint', 'Units', 'normalized');
setpointLabel.Position = [0.72, 0.75, 0.25, 0.03];
%% Realtime integration and plotting loop.
currentState = [initialPos, initialVel, 0];
bufferSize = 200;
timeBuffer = zeros(bufferSize, 1);
positionBuffer = ones(bufferSize, 1) * initialPos(1);
tic;
currTime = toc;
prevTime = currTime;
while (ishandle(fig)) % Dies when window is closed.
currTime = toc;
% What signal are we tracking?
switch currentSetpointMode
case 1
% No need to change here.
case 2
targetPos = 5 * square(currTime);
case 3
targetPos = 5 * sawtooth(currTime, 0.5);
case 4
targetPos = 5 * sawtooth(currTime);
case 5
targetPos = 5 * sin(currTime);
end
% RK4 integration, as fast as computer is able to run this loop.
dt = currTime - prevTime;
k_1 = dt * springMassDamper(0, currentState);
k_2 = dt * springMassDamper(0, currentState + k_1 / 2);
k_3 = dt * springMassDamper(0, currentState + k_2 / 2);
k_4 = dt * springMassDamper(0, currentState + k_3);
currentState = currentState + (k_1 + 2 * k_2 + 2 * k_3 + k_4) / 6;
prevTime = currTime;
% Only update the plot buffer if there's been enough change in time for
% it to matter.
if (currTime - timeBuffer(end) > tend / bufferSize)
% Shift and update buffers.
timeBuffer = circshift(timeBuffer, -1);
timeBuffer(end) = currTime;
positionBuffer = circshift(positionBuffer, -1);
positionBuffer(end) = currentState(1);
positionTrace.XData = timeBuffer;
% Update plot data and re-draw.
positionTrace.YData = positionBuffer;
currentPositionPt.XData = timeBuffer(end);
currentPositionPt.YData = positionBuffer(end);
plotAx.XLim = [timeBuffer(1), timeBuffer(end)];
setpointLine.XData = [timeBuffer(1), timeBuffer(end)];
setpointLine.YData = [targetPos, targetPos];
drawnow;
end
end