-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathPolyTrajGen.m
338 lines (305 loc) · 14.6 KB
/
PolyTrajGen.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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
classdef PolyTrajGen < TrajGen
properties (SetAccess = private)
% Basic params
algorithm; % poly-coeff /end-derivative
% Polynomial
polyCoeffSet; % set of P = [p1 p2 ... pM] where pm = (N+1) x 1 vector
N; % polynomial order
M; % number of segment of polynomial
maxContiOrder; % maximum degree of continuity when joining two segments
% Optimization
nVar; % total number of variables
segState; % segState(:,m) = [Nf ; Nc]
end
%% 1. Public method
methods % public methods
function obj = PolyTrajGen(knots,order,algo,dim,maxContiOrder)
% PolyTrajGen(knots,order,algo,dim)
% Intialize the functor to generate trajectory
obj = obj@TrajGen(knots,dim);
obj.N = order;
if strcmp(algo,'poly-coeff')
fprintf('Optimization will be performed on the coefficients.\n'); obj.algorithm = algo;
elseif strcmp(algo,'end-derivative')
fprintf('Optimization will be performed on end derivatives. This will improve optimization performance.\n'); obj.algorithm = algo;
else
error('algorithm is invalid. enter either : poly-coeff or end-derivative\n');
return;
end
obj.M = length(knots)-1;
obj.maxContiOrder = maxContiOrder;
obj.nVar = (obj.N+1) * (obj.M);
% Optimization
obj.isSolved = false;
obj.fixPinSet = cell(obj.M,1);
obj.loosePinSet = cell(obj.M,1);
% State
obj.segState = zeros(2,obj.M);
obj.fixPinOrder = cell(obj.M,1);
end
function setDerivativeObj(obj,weight_mask)
% setDerivativeObj(obj,weight_mask)
% Set the derivative objective functions. weight_mask ith element = penalty weight for intgeral of i th-derivative squared
if length(weight_mask) > obj.N
warning('Order of derivative objective > order of poly. Higher terms will be ignored. ');
weight_mask = weight_mask(1:obj.N);
end
obj.weight_mask = weight_mask;
end
function addPin(obj,pin)
% addPin(obj,pin)
% Impose a constraint to the dth derivative at time t to X as
% an equality (fix pin) or inequality (loose pin). In case of
% fix pin, imposing time should be knots of this polynomial.
% pin = struct('t',,'d',,'X',)
% X = Xval or X = [Xl Xu] where Xl or Xu is D x 1 vector
t = pin.t; X = pin.X; % the t is global time
addPin@TrajGen(obj,pin); % call the common function of addPin
[m,~] = obj.findSegInteval(t);
if size(X,2) == 2 % inequality (loose pin)
obj.loosePinSet{m} = [obj.loosePinSet{m} pin];
elseif size(X,2) == 1 % equality (fixed pin)
assert (t == obj.Ts(m) || t == obj.Ts(m+1),'Fix pin should be imposed only knots\n');
if obj.segState(1,m) <= obj.N+1
obj.fixPinSet{m} = [obj.fixPinSet{m} pin];
obj.segState(1,m) = obj.segState(1,m) + 1;
obj.fixPinOrder{m} = [obj.fixPinOrder{m} pin.d];
else
warning('FixPin exceed the dof of this segment. Pin ignored\n');
end
else
warning('Dim of pin value is invalid\;');
end
end
function solve(obj)
obj.isSolved = true;
% Prepare QP
[QSet,ASet,BSet,AeqSet,BeqSet] = obj.getQPSet;
if strcmp(obj.algorithm,'end-derivative')
mapMat = obj.coeff2endDerivatives(AeqSet{1});
[QSet,HSet,ASet,BSet] = obj.mapQP(QSet,ASet,BSet,AeqSet,BeqSet);
end
for dd = 1:obj.dim % per element
% Then, solve the optimization
fprintf('solving %d th dimension..\n', dd)
if strcmp(obj.algorithm,'poly-coeff')
[Phat,~,flag] = quadprog(QSet{dd},[],ASet{dd},BSet{dd},AeqSet{dd},BeqSet{dd});
else
[dP,~,flag] = quadprog(QSet{dd},HSet{dd},ASet{dd},BSet{dd}); dF = BeqSet{dd};
if flag == 1
Phat = mapMat\[dF;dP];
end
end
obj.isSolved = obj.isSolved && (flag == 1);
if (flag == 1)
fprintf('success! \n')
P = obj.scaleMatBigInv*Phat;
obj.polyCoeffSet{dd} = reshape(P,obj.N+1,[]);
else
fprintf('Failure..\n');
end
end
fprintf('Done!\n');
end
function val = eval(obj,t,d)
% val = eval(obj,t,d)
% Evaluate d th order derivative of the piecewise polynomial at time t or at time sequence t. Extrapolation is turned on.
val = zeros(obj.dim,length(t));
for dd = 1:obj.dim
for idx = 1:length(t)
ti = t(idx);
if ti < obj.Ts(1) || ti > obj.Ts(end)
warning('Eval of t: out of bound. Extrapolation\n');
end
[m,~]=obj.findSegInteval(ti);
dTm = obj.Ts(m+1) - obj.Ts(m);
val(dd,idx) = obj.tVec((ti - obj.Ts(m)),d)'*obj.polyCoeffSet{dd}(:,m);
end
end
end
end % public method
%% 2. Priavte method
methods (Access = private) % to be private
function val = B(obj,n,d)
% Returns the nth order ceoffs (n=0...N) of time vector of dth
% derivative.
if d == 0
val = 1;
else
accumProd = cumprod(n:-1:n-(d-1));
val = (n>=d) * accumProd(end);
end
end
function vec = tVec(obj,t,d)
% time vector evaluated at time t with d th order derivative.
vec = zeros(obj.N+1,1);
for i = d+1:obj.N+1
vec(i) = obj.B(i-1,d)*t^(i-1-d);
end
end
function mat = scaleMat(obj,delT)
mat = zeros(obj.N+1);
for i = 1:obj.N+1
mat(i,i) = delT^(i-1);
end
end
function mat = scaleMatBig(obj)
% scaling matrix with all knots. Used to remap phat to p
matSet = {};
for m = 1:obj.M
matSet{m} = obj.scaleMat(obj.Ts(m+1)-obj.Ts(m));
end
mat = blkdiag(matSet{:});
end
function mat = scaleMatBigInv(obj)
% scaling matrix with all knots. Used to remap phat to p
matSet = {};
for m = 1:obj.M
matSet{m} = obj.scaleMat(1/(obj.Ts(m+1)-obj.Ts(m)));
end
mat = blkdiag(matSet{:});
end
function mat = IntDerSquard(obj,d)
% integral (0 to 1) of squard d th derivative
if d > obj.N
warning('Order of derivative > poly order \n')
end
mat = zeros(obj.N+1);
for i = 1:obj.N+1
for j = 1:obj.N+1
if (i+j-2*d -1) > 0
mat(i,j) = obj.B(i-1,d) *obj.B(j-1,d) / (i+j-2*d-1);
end
end
end
end
function [m,tau] = findSegInteval(obj,t)
% [m,tau] = findSegInteval(obj,t)
% returns the segment index + nomalized time, which contains time t
m = max(find(t >= obj.Ts));
if isempty(m)
warning('Eval of t : leq T0. eval target = 1st segment')
m = 1;
elseif m >= obj.M+1
if t ~= obj.Ts(end)
warning('Eval of t : geq TM. eval target = last segment')
end
m = obj.M;
else
end
tau = (t - obj.Ts(m)) / (obj.Ts(m+1) - obj.Ts(m));
end
function [aeqSet,beqSet]=fixPinMatSet(obj,pin)
aeqSet = cell(obj.dim,1); beqSet = cell(obj.dim,1);
t = pin.t; X = pin.X; d = pin.d;
[m,tau] = obj.findSegInteval(t);
idxStart = (m-1)*(obj.N+1) + 1; idxEnd = m*(obj.N+1);
dTm = obj.Ts(m+1) - obj.Ts(m);
for dd = 1:obj.dim
aeq = zeros(1,obj.nVar);
aeq(:,idxStart:idxEnd) = obj.tVec(tau,d)'/dTm^d;
aeqSet{dd} = aeq;
beq = X(dd);
beqSet{dd} = beq;
end
end
function [aSet,bSet] = loosePinMatSet(obj,pin)
aSet = cell(obj.dim,1); bSet = cell(obj.dim,1);
t = pin.t; X = pin.X; d=pin.d;
[m,tau] = obj.findSegInteval(t);
idxStart = (m-1)*(obj.N+1) + 1; idxEnd = m*(obj.N+1);
dTm = obj.Ts(m+1) - obj.Ts(m);
for dd = 1:obj.dim
a = zeros(2,obj.nVar); b = zeros(2,1);
a(:,idxStart:idxEnd) = [obj.tVec(tau,d)'/dTm^d; -obj.tVec(tau,d)'/dTm^d;]; b(:) = [X(dd,2) -X(dd,1)];
aSet{dd} = a; bSet{dd} = b;
end
end
function [aeq, beq] = contiMat(obj,m,dmax)
idxStart = (m-1)*(obj.N+1) + 1; idxEnd = (m+1)*(obj.N+1);
dTm1 = obj.Ts(m+1) - obj.Ts(m);
dTm2 = obj.Ts(m+2) - obj.Ts(m+1);
aeq = zeros(dmax+1,obj.nVar); beq = zeros(dmax+1,1);
for d = 0:dmax
aeq(d+1,idxStart : idxEnd) = [obj.tVec(1,d)'/dTm1^(d) -obj.tVec(0,d)'/dTm2^(d)];
end
end
function [QSet,ASet,BSet,AeqSet,BeqSet] = getQPSet(obj)
QSet = cell(obj.dim,1); ASet = cell(obj.dim,1); BSet = cell(obj.dim,1); AeqSet = cell(obj.dim,1); BeqSet = cell(obj.dim,1);
% 1. Objective
for dd = 1:obj.dim
Q = zeros(obj.nVar);
for d = 1:length(obj.weight_mask)
for m = 1:obj.M
dT = obj.Ts(m+1) - obj.Ts(m);
Qm{m} = obj.IntDerSquard(d)/dT^(2*d-1);
end
Qd = blkdiag(Qm{:}); Q = Q + obj.weight_mask(d)*Qd;
end
QSet{dd} = Q;
end
% 2. Constraint
for m = 1:obj.M
% Fix pin
for pin = obj.fixPinSet{m}
[aeqSet,beqSet]=obj.fixPinMatSet(pin);
for dd = 1:obj.dim
AeqSet{dd} = [AeqSet{dd} ; aeqSet{dd}]; BeqSet{dd} = [BeqSet{dd} ; beqSet{dd}];
end
end
% Continuity
if m < obj.M
contiDof = min(obj.maxContiOrder+1,obj.N+1 - obj.segState(1,m)); obj.segState(2,m) = contiDof; % including 0th order
if contiDof ~= obj.maxContiOrder+1
warnStr = sprintf('Connecting segment (%d,%d) : lacks %d dof for imposed %d th continuity',...
m,m+1,obj.maxContiOrder+1 - contiDof,obj.maxContiOrder);
warning(warnStr);
end
if contiDof > 0
[aeq,beq]=obj.contiMat(m,contiDof-1);
for dd = 1:obj.dim
AeqSet{dd} = [AeqSet{dd} ; aeq]; BeqSet{dd} = [BeqSet{dd} ; beq];
end
end
end
% Loose pin
for pin = obj.loosePinSet{m}
[aSet,bSet]=obj.loosePinMatSet(pin);
for dd = 1:obj.dim
ASet{dd} = [ASet{dd} ; aSet{dd}]; BSet{dd} = [BSet{dd} ; bSet{dd}];
end
end
end
end
function mapMat = coeff2endDerivatives(obj,Aeq)
% mapMat = coeff2endDerivatives(obj,Aeq)
assert (size(Aeq,2) <= obj.nVar, 'Pin + continuity constraints are already full. No dof for optim.\n');
mapMat = Aeq;
for m = 1:obj.M
freePinOrder = setdiff(0:obj.N,obj.fixPinOrder{m}); dof = obj.N+1 - (sum(obj.segState(:,m)));
freeOrder = freePinOrder(1:dof);
for order = freeOrder
virtualPin.t = obj.Ts(m); virtualPin.X = zeros(obj.dim,1); virtualPin.d = order;
aeqSet = obj.fixPinMatSet(virtualPin); aeq = aeqSet{1};
mapMat = [mapMat ; aeq];
end
end
end
function [QSet,HSet,ASet,BSet]=mapQP(obj,QSet,ASet,BSet,AeqSet,BeqSet)
% [QSet,HSet,ASet,BSet]=mapQP(obj,QSet,ASet,BSet,AeqSet,BeqSet)
% Map optim problem w.r.t poly coeff to w.r.t end derivative
Afp = obj.coeff2endDerivatives(AeqSet{1}); AfpInv = inv(Afp);
Nf = size(AeqSet{1},1);
Qtmp = AfpInv'*QSet{1}*AfpInv;
Qff = Qtmp(1:Nf,1:Nf); Qfp = Qtmp(1:Nf,Nf+1:end); Qpf = Qtmp(Nf+1:end,1:Nf); Qpp = Qtmp(Nf+1:end,Nf+1:end);
for dd = 1:obj.dim
df = BeqSet{dd};
QSet{dd} = 2*Qpp; HSet{dd} = df'*(Qfp+Qpf');
if ~isempty(ASet{dd})
A = ASet{dd}*AfpInv;
ASet{dd} = A(:,Nf+1:end); BSet{dd} = BSet{dd} - A(:,1:Nf)*df;
end
end
end
end
end