-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathPlotter.m
214 lines (170 loc) · 6.12 KB
/
Plotter.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Animate the acrobot after the MAIN script has been run.
%
% Matthew Sheen, 2014
%
% Note: data is passed from this to the callback functions in the figure
% object's UserData field.
% For compatibility with 2014a and earlier, I use set/get instead of the
% object.field notation.
% Can also be done with global vars as in the backup version. I hate
% global variables so, this version is the result.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Plotter(p)
close all
%Playback speed:
% playback = p.animationSpeed;
%Name the whole window and define the mouse callback function
f = figure;
set(f,'WindowButtonMotionFcn','','WindowButtonDownFcn',@ClickDown,'WindowButtonUpFcn',@ClickUp,'KeyPressFc',@KeyPress);
figData.xtarget = [];
figData.ytarget = [];
figData.Fx = [];
figData.Fy = [];
figData.xend = [];
figData.yend = [];
figData.fig = f;
figData.tarControl = true;
%%%%%%%% 1st Subplot -- the pendulum animation %%%%%%%
figData.simArea = subplot(1,1,1); %Eliminated other subplots, but left this for syntax consistency.
axis equal
hold on
%Create pendulum link1 object:
width1 = p.l1*0.05;
xdat1 = 0.5*width1*[-1 1 1 -1];
ydat1 = p.l1*[0 0 1 1];
link1 = patch(xdat1,ydat1, [0 0 0 0],'r');
%Create pendulum link2 object:
width2 = p.l2*0.05;
xdat2 = 0.5*width2*[-1 1 1 -1];
ydat2 = p.l2*[0 0 1 1];
link2 = patch(xdat2,ydat2, [0 0 0 0],'b');
axis([-3.5 3.5 -3.6 3.6]);
%Dots for the hinges:
h1 = plot(0,0,'.k','MarkerSize',40); %First link anchor
h2 = plot(0,0,'.k','MarkerSize',40); %link1 -> link2 hinge
%Timer label:
timer = text(-3.2,-3.2,'0.00','FontSize',28);
%Torque meters on screen
tmeter1 = text(0.6,-3.2,'0.00','FontSize',22,'Color', 'r');
tmeter2 = text(2.2,-3.2,'0.00','FontSize',22,'Color', 'b');
%Target Pt.
targetPt = plot(p.xtarget,p.ytarget,'xr','MarkerSize',30);
hold off
%Make the whole window big for handy viewing:
set(f, 'units', 'inches', 'position', [5 5 10 9])
set(f,'Color',[1,1,1]);
% Turn the axis off
ax = get(f,'Children');
set(ax,'Visible','off');
%Animation plot loop -- Includes symplectic integration now.
z1 = p.init;
told = 0;
set(f,'UserData',figData);
tic %Start the clock
while (ishandle(f))
figData = get(f,'UserData');
%%%% INTEGRATION %%%%
tnew = toc;
dt = tnew - told;
%Old velocity and position
xold = [z1(1),z1(3)];
vold = [z1(2),z1(4)];
%Call RHS given old state
[zdot1, T1, T2] = FullDyn(tnew,z1,p);
vinter1 = [zdot1(1),zdot1(3)];
ainter = [zdot1(2),zdot1(4)];
vinter2 = vold + ainter*dt; %Update velocity based on old RHS call
%Update position.
xnew = xold + vinter2*dt;
vnew = (xnew-xold)/dt;
z2 = [xnew(1) vnew(1) xnew(2) vnew(2)];
z1 = z2;
told = tnew;
%%%%%%%%%%%%%%%%%%%%
%If there are new mouse click locations, then set those as the new
%target.
if ~isempty(figData.xtarget)
p.xtarget = figData.xtarget;
end
if ~isempty(figData.ytarget)
p.ytarget = figData.ytarget;
end
set(targetPt,'xData',p.xtarget); %Change the target point graphically.
set(targetPt,'yData',p.ytarget);
%When you hit a key, it changes to force mode, where the mouse will
%pull things.
ra_e = ForwardKin(p.l1,p.l2,z1(1),z1(3));
figData.xend = ra_e(1);
figData.yend = ra_e(2);
set(f,'UserData',figData);
if ~isempty(figData.Fx)
p.Fx = figData.Fx;
end
if ~isempty(figData.Fy)
p.Fy = figData.Fy;
end
tstar = told; %Get the time (used during this entire iteration)
%On screen timer.
set(timer,'string',strcat(num2str(tstar,3),'s'))
zstar = z1;%interp1(time,zarray,tstar); %Interpolate data at this instant in time.
%Rotation matrices to manipulate the vertices of the patch objects
%using theta1 and theta2 from the output state vector.
rot1 = [cos(zstar(1)), -sin(zstar(1)); sin(zstar(1)),cos(zstar(1))]*[xdat1;ydat1];
set(link1,'xData',rot1(1,:))
set(link1,'yData',rot1(2,:))
rot2 = [cos(zstar(3)+zstar(1)), -sin(zstar(3)+zstar(1)); sin(zstar(3)+zstar(1)),cos(zstar(3)+zstar(1))]*[xdat2;ydat2];
set(link2,'xData',rot2(1,:)+(rot1(1,3)+rot1(1,4))/2) %We want to add the midpoint of the far edge of the first link to all points in link 2.
set(link2,'yData',rot2(2,:)+(rot1(2,3)+rot1(2,4))/2)
%Change the hinge dot location
set(h2,'xData',(rot1(1,3)+rot1(1,4))/2)
set(h2,'yData',(rot1(2,3)+rot1(2,4))/2)
%Show torques on screen (text only atm) update for time series later.
set(tmeter1,'string',strcat(num2str(T1,2),' Nm'));
set(tmeter2,'string',strcat(num2str(T2,2),' Nm'));
drawnow;
end
end
%%%% BEGIN CALLBACKS FOR MOUSE AND KEYBOARD STUFF %%%%%
% When click-up occurs, disable the mouse motion detecting callback
function ClickUp(varargin)
figData = get(varargin{1},'UserData');
set(figData.fig,'WindowButtonMotionFcn','');
figData.Fx = 0;
figData.Fy = 0;
set(varargin{1},'UserData',figData);
end
% When click-down occurs, enable the mouse motion detecting callback
function ClickDown(varargin)
figData = get(varargin{1},'UserData');
figData.Fx = 0;
figData.Fy = 0;
set(figData.fig,'WindowButtonMotionFcn',@MousePos);
set(varargin{1},'UserData',figData);
end
% any keypress switches from dragging the setpoint to applying a
% disturbance.
function KeyPress(hObject, eventdata, handles)
figData = get(hObject,'UserData');
figData.tarControl = ~figData.tarControl;
if figData.tarControl
disp('Mouse will change the target point of the end effector.')
else
disp('Mouse will apply a force on end effector.')
end
set(hObject,'UserData',figData);
end
% Checks mouse position and sends it back up.
function MousePos(varargin)
figData = get(varargin{1},'UserData');
mousePos = get(figData.simArea,'CurrentPoint');
if figData.tarControl
figData.xtarget = mousePos(1,1);
figData.ytarget = mousePos(1,2);
else
figData.Fx = 10*(mousePos(1,1)-figData.xend);
figData.Fy = 10*(mousePos(1,2)-figData.yend);
end
set(varargin{1},'UserData',figData);
end