forked from petercorke/robotics-toolbox-matlab
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mstraj.m
231 lines (200 loc) · 7.55 KB
/
mstraj.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
%MSTRAJ Multi-segment multi-axis trajectory
%
% TRAJ = MSTRAJ(WP, QDMAX, TSEG, Q0, DT, TACC, OPTIONS) is a trajectory
% (KxN) for N axes moving simultaneously through M segment. Each segment
% is linear motion and polynomial blends connect the segments. The axes
% start at Q0 (1xN) and pass through M-1 via points defined by the rows of
% the matrix WP (MxN), and finish at the point defined by the last row of WP.
% The trajectory matrix has one row per time step, and one column per
% axis. The number of steps in the trajectory K is a function of the
% number of via points and the time or velocity limits that apply.
%
% - WP (MxN) is a matrix of via points, 1 row per via point, one column
% per axis. The last via point is the destination.
% - QDMAX (1xN) are axis speed limits which cannot be exceeded,
% - TSEG (1xM) are the durations for each of the K segments
% - Q0 (1xN) are the initial axis coordinates
% - DT is the time step
% - TACC (1x1) is the acceleration time used for all segment transitions
% - TACC (1xM) is the acceleration time per segment, TACC(i) is the acceleration
% time for the transition from segment i to segment i+1. TACC(1) is also
% the acceleration time at the start of segment 1.
%
% TRAJ = MSTRAJ(WP, QDMAX, TSEG, [], DT, TACC, OPTIONS) as above but the
% initial coordinates are taken from the first row of WP.
%
% TRAJ = MSTRAJ(WP, QDMAX, Q0, DT, TACC, QD0, QDF, OPTIONS) as above
% but additionally specifies the initial and final axis velocities (1xN).
%
% Options::
% 'verbose' Show details.
%
% Notes::
% - Only one of QDMAX or TSEG can be specified, the other is set to [].
% - If no output arguments are specified the trajectory is plotted.
% - The path length K is a function of the number of via points, Q0, DT
% and TACC.
% - The final via point P(end,:) is the destination.
% - The motion has M segments from Q0 to P(1,:) to P(2,:) ... to P(end,:).
% - All axes reach their via points at the same time.
% - Can be used to create joint space trajectories where each axis is a joint
% coordinate.
% - Can be used to create Cartesian trajectories where the "axes"
% correspond to translation and orientation in RPY or Euler angle form.
%
% See also MTRAJ, LSPB, CTRAJ.
% Copyright (C) 1993-2017, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB. If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com
function [TG, t, info] = mstraj(segments, qdmax, tsegment, q0, dt, Tacc, varargin)
if isempty(q0)
q0 = segments(1,:);
segments = segments(2:end,:);
end
assert(size(segments,2) == size(q0,2), 'RTB:mstraj:badarg', 'WP and Q0 must have same number of columns');
assert(xor(~isempty(qdmax), ~isempty(tsegment)), 'RTB:mstraj:badarg', 'Must specify either qdmax or tsegment, but not both');
if isempty(qdmax)
assert(length(tsegment) == size(segments,1), 'RTB:mstraj:badarg', 'Length of TSEG does not match number of segments');
else
assert(length(qdmax) == size(segments,2), 'RTB:mstraj:badarg', 'Length of QDMAX does not match number of axes');
end
ns = numrows(segments);
nj = numcols(segments);
[opt,args] = tb_optparse([], varargin);
if length(args) > 0
qd0 = args{1};
else
qd0 = zeros(1, nj);
end
if length(args) > 1
qdf = args{2};
else
qdf = zeros(1, nj);
end
% set the initial conditions
q_prev = q0;
qd_prev = qd0;
clock = 0; % keep track of time
arrive = []; % record planned time of arrival at via points
tg = [];
taxis = [];
for seg=1:ns
if opt.verbose
fprintf('------------------- segment %d\n', seg);
end
% set the blend time, just half an interval for the first segment
if length(Tacc) > 1
tacc = Tacc(seg);
else
tacc = Tacc;
end
tacc = ceil(tacc/dt)*dt;
tacc2 = ceil(tacc/2/dt) * dt;
if seg == 1
taccx = tacc2;
else
taccx = tacc;
end
% estimate travel time
% could better estimate distance travelled during the blend
q_next = segments(seg,:); % current target
dq = q_next - q_prev; % total distance to move this segment
%% probably should iterate over the next section to get qb right...
% while 1
% qd_next = (qnextnext - qnext)
% tb = abs(qd_next - qd) ./ qddmax;
% qb = f(tb, max acceleration)
% dq = q_next - q_prev - qb
% tl = abs(dq) ./ qdmax;
if ~isempty(qdmax)
% qdmax is specified, compute slowest axis
qb = taccx * qdmax / 2; % distance moved during blend
tb = taccx;
% convert to time
tl = abs(dq) ./ qdmax;
%tl = abs(dq - qb) ./ qdmax;
tl = ceil(tl/dt) * dt;
% find the total time and slowest axis
tt = tb + tl;
[tseg,slowest] = max(tt);
info(seg).slowest = slowest;
info(seg).segtime = tseg;
info(seg).axtime = tt;
info(seg).clock = clock;
% best if there is some linear motion component
if tseg <= 2*tacc
tseg = 2 * tacc;
end
elseif ~isempty(tsegment)
% segment time specified, use that
tseg = tsegment(seg);
slowest = NaN;
end
% log the planned arrival time
arrive(seg) = clock + tseg;
if seg > 1
arrive(seg) = arrive(seg) + tacc2;
end
if opt.verbose
fprintf('seg %d, slowest axis %d, time required %.4g\n', ...
seg, slowest, tseg);
end
%% create the trajectories for this segment
% linear velocity from qprev to qnext
qd = dq / tseg;
% add the blend polynomial
qb = jtraj(q0, q_prev+tacc2*qd, 0:dt:taccx, qd_prev, qd);
tg = [tg; qb(2:end,:)];
clock = clock + taccx; % update the clock
% add the linear part, from tacc/2+dt to tseg-tacc/2
for t=tacc2+dt:dt:tseg-tacc2
s = t/tseg;
q0 = (1-s) * q_prev + s * q_next; % linear step
tg = [tg; q0];
clock = clock + dt;
end
q_prev = q_next; % next target becomes previous target
qd_prev = qd;
end
% add the final blend
qb = jtraj(q0, q_next, 0:dt:tacc2, qd_prev, qdf);
tg = [tg; qb(2:end,:)];
info(seg+1).segtime = tacc2;
info(seg+1).clock = clock;
% plot a graph if no output argument
if nargout == 0
t = (0:numrows(tg)-1)'*dt;
clf
plot(t, tg, '-o');
hold on
plot(arrive, segments, 'bo', 'MarkerFaceColor', 'k');
hold off
grid
xlabel('time');
xaxis(t(1), t(end))
return
end
if nargout > 0
TG = tg;
end
if nargout > 1
t = (0:numrows(tg)-1)'*dt;
end
if nargout > 2
infout = info;
end