1
+ classdef RBT
2
+ properties
3
+ eps = 0.1 ; % Step in C-space used by RRT-based algorithms
4
+ N_max = 10000 ; % Max. number of considered nodes
5
+ N_spines = 7 ; % Number of bur spines
6
+ d_crit = 0.03 ; % Critical distance in W-space when RBT becomes RRT
7
+ delta = pi ; % Radius of hypersphere from q to q_e
8
+ path = []; % Traversed path (sequence of nodes from q_init to q_goal)
9
+ N_iter = 0 ; % Iteration counter
10
+ T_alg = 0 ; % Total algorithm runtime
11
+ T_max = 1 ; % Maximal algorithm runtime in [s]
12
+ end
13
+
14
+ methods
15
+ function this = RBT(eps , N_max , N_spines , d_crit , delta )
16
+ if nargin > 0
17
+ this.eps = eps ;
18
+ this.N_max = N_max ;
19
+ this.N_spines = N_spines ;
20
+ this.d_crit = d_crit ;
21
+ this.delta = delta ;
22
+ end
23
+ end
24
+
25
+
26
+ function this = Run(this )
27
+ global robot tree ;
28
+ TN = 2 ; % Determines which trees is chosen, 1: from q_init; 2: from q_goal
29
+ tree.nodes = {robot .q_init , robot .q_goal }; % Consisting of two parts, one from q_init and another from q_goal
30
+ tree.pointers = {{0 }, {0 }}; % Pointing to location of parent/children in trees
31
+ tree.distances = {NaN , NaN }; % Distance to each obstacle for each node
32
+ this.T_alg = tic ;
33
+
34
+ if CheckCollision(robot .q_init )
35
+ disp(' Initial robot configuration is in the collision!' );
36
+ return ;
37
+ end
38
+ if CheckCollision(robot .q_goal )
39
+ disp(' Goal robot configuration is in the collision!' );
40
+ return ;
41
+ end
42
+
43
+ while true
44
+ %% Generating bur
45
+ TN = 3 - TN ;
46
+ q_e = this .GetRandomNode();
47
+ [q_near , q_near_p ] = GetNearestNode(tree.nodes{TN }, q_e );
48
+ d_c = this .Get_dc(TN , q_near_p );
49
+ if d_c > this .d_crit
50
+ for i = 1 : this .N_spines
51
+ q_e = q_near + this .GetRandomNode();
52
+ q_e = this .SaturateSpine(q_near , q_e , this .delta );
53
+ q_e = this .PruneSpine(q_near , q_e );
54
+ [q_new , ~ ] = this .GenerateSpine(q_near , q_e , d_c );
55
+ q_new_p = UpgradeTree(TN , q_near_p , q_new , NaN );
56
+ end
57
+ else % Distance to obstacle is less than d_crit
58
+ [q_new , ~ , collision ] = this .GenerateEdge(q_near , q_e ); % Spine is generated using RRT
59
+ if ~collision
60
+ q_new_p = UpgradeTree(TN , q_near_p , q_new , NaN );
61
+ else
62
+ q_new_p = q_near_p ;
63
+ end
64
+ end
65
+
66
+ %% Bur-Connect
67
+ TN = 3 - TN ;
68
+ [q_near , q_near_p ] = GetNearestNode(tree.nodes{TN }, q_new );
69
+ collision = false ; % Is collision occured
70
+ reached = false ; % If trees are connected
71
+ while ~collision && ~reached
72
+ d_c = this .Get_dc(TN , q_near_p );
73
+ if d_c > this .d_crit
74
+ [q_near , reached ] = this .GenerateSpine(q_near , q_new , d_c ); % Spine is generated using RBT
75
+ else
76
+ [q_near , reached , collision ] = this .GenerateEdge(q_near , q_new ); % Spine is generated using RRT
77
+ end
78
+ if ~collision
79
+ q_near_p = UpgradeTree(TN , q_near_p , q_near , NaN );
80
+ end
81
+ end
82
+
83
+ this.N_iter = this .N_iter + 1 ;
84
+ if reached
85
+ this.path = GetPath(q_near_p , q_new_p , TN );
86
+ this.T_alg = toc(this .T_alg );
87
+ disp([' The path is found in ' , num2str(this .T_alg * 1000 ), ' [ms].' ]);
88
+ return ;
89
+ elseif size(tree.nodes{1 },2 )+size(tree.nodes{2 },2 ) >= this .N_max
90
+ this.T_alg = toc(this .T_alg );
91
+ disp(' The path is not found.' );
92
+ return ;
93
+ end
94
+ TN = 3 - TN ;
95
+ end
96
+ end
97
+
98
+
99
+ function q_e = GetRandomNode(~)
100
+ % Adding a random node with uniform distribution in C-space
101
+ global robot ;
102
+
103
+ q_e = (robot .range(: ,2 )-robot .range(: ,1 )).*rand(robot .N_DOF ,1 ) + robot .range(: ,1 );
104
+ end
105
+
106
+
107
+ function [q_new , reached , collision ] = GenerateEdge(this , q , q_e )
108
+ % Edge is generated from q towards q_e for eps
109
+ % q_new is new reached node
110
+ % collision means whether collision occured when moving from q towards q_e
111
+ % reached means whether q_e is reached
112
+
113
+ D = norm(q_e - q );
114
+ if D < this .eps
115
+ reached = true ;
116
+ if D == 0
117
+ collision = false ;
118
+ q_new = q ;
119
+ return ;
120
+ end
121
+ step = D ;
122
+ else
123
+ reached = false ;
124
+ step = this .eps ;
125
+ end
126
+
127
+ eps0 = this .eps / 10 ;
128
+ K = ceil(step / eps0 );
129
+ Step = step /(K * D );
130
+ for k = K : -1 : 1
131
+ q_new = q + k * Step *(q_e - q );
132
+ collision = CheckCollision(q_new );
133
+ if collision
134
+ q_new = q ;
135
+ reached = false ;
136
+ return ;
137
+ end
138
+ end
139
+ q_new = q + K * Step *(q_e - q );
140
+
141
+ end
142
+
143
+
144
+ function [q_new , reached ] = GenerateSpine(~, q , q_e , d_c )
145
+ global robot ;
146
+ % Spine is generated from q towards q_e
147
+ % q_new represents new reached node
148
+ % reached means whether q_e is reached
149
+
150
+ q_new = q ;
151
+ if q_e == q
152
+ reached = true ;
153
+ return ;
154
+ end
155
+
156
+ reached = false ;
157
+ [xyz_q , ~ ] = DirectKinematics(robot , q );
158
+ xyz_q_new = xyz_q ;
159
+ rho = 0 ; % Path length in W-space
160
+ K_max = 5 ; % Number of iterations for computing q*
161
+ k = 1 ;
162
+ while true
163
+ step = ComputeStep(q_new , q_e , d_c - rho , xyz_q_new ); % 'd_c-rho' is the remaining path length in W-space
164
+ if step > 1
165
+ q_new = q_e ;
166
+ reached = true ;
167
+ else
168
+ q_new = q_new + step *(q_e - q_new );
169
+ end
170
+ if k == K_max || reached
171
+ break ;
172
+ end
173
+ [xyz_q_new , ~ ] = DirectKinematics(robot , q_new );
174
+ Rho = zeros(robot .N_links ,1 );
175
+ for i = 2 : robot .N_links + 1
176
+ Rho(i - 1 ) = norm(xyz_q_new(: ,i )-xyz_q(: ,i ));
177
+ end
178
+ rho = max(Rho );
179
+ k = k + 1 ;
180
+ end
181
+
182
+ function step = ComputeStep(q , q_e , fi , xyz )
183
+ if robot .dim == 2 % assumes that N_links = N_DOF
184
+ d = 0 ;
185
+ for ii = 1 : robot .N_links
186
+ r = [robot .DH_table(ii ,2 ), zeros(1 ,robot .N_links - ii )];
187
+ for kk = ii + 1 : robot .N_links
188
+ r(kk ) = norm(xyz(: ,kk + 1 )-xyz(: ,ii ));
189
+ end
190
+ d = d + max(r )*abs(q_e(ii )-q(ii ));
191
+ end
192
+ else
193
+ if robot .model == 1
194
+ L = [robot .DH_table(1 ,1 ), robot .DH_table(2 ,2 ), robot .DH_table(4 ,1 ), robot .DH_table(6 ,1 )];
195
+ r(1 ) = max([norm(xyz(1 : 2 ,3 )), norm(xyz(1 : 2 ,4 )), norm(xyz(1 : 2 ,5 ))]);
196
+ r(2 ) = max([L(2 ), norm(xyz(: ,4 )-xyz(: ,2 )), norm(xyz(: ,5 )-xyz(: ,2 ))]);
197
+ r(3 ) = max([L(3 ), norm(xyz(: ,5 )-xyz(: ,3 ))]);
198
+ C_proj = Get_C_proj(xyz(: ,3 ), xyz(: ,4 ), xyz(: ,5 ));
199
+ r(4 ) = norm(xyz(: ,5 )-C_proj );
200
+ r(5 ) = L(4 );
201
+ elseif robot .model == 2
202
+ L = [robot .DH_table(1 ,1 ), robot .DH_table(2 ,2 ), robot .DH_table(3 ,2 ), ...
203
+ robot .DH_table(4 ,1 ), robot .DH_table(5 ,2 ), robot .DH_table(6 ,1 )];
204
+ r(1 ) = max([norm(xyz(1 : 2 ,3 )), norm(xyz(1 : 2 ,4 )), norm(xyz(1 : 2 ,5 )), norm(xyz(1 : 2 ,6 )), norm(xyz(1 : 2 ,7 ))]' +robot .radii(2 : end ));
205
+ r(2 ) = max([L(2 ), norm(xyz(: ,4 )-xyz(: ,2 )), norm(xyz(: ,5 )-xyz(: ,2 )), norm(xyz(: ,6 )-xyz(: ,2 )), norm(xyz(: ,7 )-xyz(: ,2 ))]' +robot .radii(2 : end ));
206
+ r(3 ) = max([L(3 ), norm(xyz(: ,5 )-xyz(: ,3 )), norm(xyz(: ,6 )-xyz(: ,3 )), norm(xyz(: ,7 )-xyz(: ,3 ))]' +robot .radii(3 : end ));
207
+ C_proj1 = Get_C_proj(xyz(: ,4 ), xyz(: ,5 ), xyz(: ,6 ));
208
+ C_proj2 = Get_C_proj(xyz(: ,4 ), xyz(: ,5 ), xyz(: ,7 ));
209
+ r(4 ) = max([norm(xyz(: ,6 )-C_proj1 ), norm(xyz(: ,7 )-C_proj2 )]' +robot .radii(5 : end ));
210
+ r(5 ) = max([L(5 ), norm(xyz(: ,7 )-xyz(: ,5 ))]' +robot .radii(5 : end ));
211
+ end
212
+ d = r * abs(q(1 : end - 1 )-q_e(1 : end - 1 ));
213
+ end
214
+ step = fi / d ;
215
+
216
+ function C_proj = Get_C_proj(A , B , C )
217
+ % C_proj is projection of C on line determined with A and B
218
+ AB = B - A ;
219
+ t_opt = (C - A )' *AB /(AB ' *AB );
220
+ C_proj = A + t_opt * AB ;
221
+ end
222
+ end
223
+ end
224
+
225
+
226
+ function q_e = SaturateSpine(~, q , q_e , length )
227
+ Norm = norm(q_e - q );
228
+ if Norm > 0
229
+ q_e = q + length *(q_e - q )/Norm ;
230
+ end
231
+ end
232
+
233
+
234
+ function q_e = PruneSpine(~, q , q_e )
235
+ % Prune spine from q to q_e, if it comes out C-space domain
236
+ global robot ;
237
+
238
+ bounds = zeros(robot .N_DOF ,1 );
239
+ indices = [];
240
+ for k = 1 : robot .N_DOF
241
+ if q_e(k ) > pi
242
+ bounds(k ) = pi ;
243
+ indices = [indices , k ];
244
+ elseif q_e(k ) < - pi
245
+ bounds(k ) = - pi ;
246
+ indices = [indices , k ];
247
+ end
248
+ end
249
+ if length(indices ) == 1
250
+ t = (bounds(indices )-q(indices ))/(q_e(indices )-q(indices ));
251
+ q_e = q + t *(q_e - q );
252
+ elseif length(indices ) > 1
253
+ for k = indices
254
+ t = (bounds(k )-q(k ))/(q_e(k )-q(k ));
255
+ q_temp = q + t *(q_e - q );
256
+ if q_temp >= - pi * ones(robot .N_DOF ,1 ) & q_temp <= pi * ones(robot .N_DOF ,1 )
257
+ q_e = q_temp ;
258
+ break ;
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+
265
+ function d_c = Get_dc(~, TN , q_p )
266
+ % Get minimal distance from q (determined with q_p) to obstacles
267
+ % TN - tree number
268
+ % q_p - pointer at node q
269
+ global tree ;
270
+
271
+ if isnan(tree.distances{TN }(q_p ))
272
+ q = tree.nodes{TN }(: ,q_p );
273
+ [d_c , ~ ] = GetDistance(q );
274
+ tree.distances{TN }(q_p ) = d_c ;
275
+ else
276
+ d_c = tree.distances{TN }(q_p );
277
+ end
278
+ end
279
+
280
+ end
281
+ end
0 commit comments