-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmain_laserodo_sim_video.cpp
401 lines (309 loc) · 14.6 KB
/
main_laserodo_sim_video.cpp
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
/* Project: Laser odometry
Author: Mariano Jaimez Tarifa
Date: January 2015 */
#include <iostream>
#include <mrpt/system/threads.h> // sleep()
#include <mrpt/utils/CConfigFile.h>
#include <mrpt/utils/CConfigFileMemory.h>
#include "laserodo_sim_video.h"
const char *default_cfg_txt =
"; ---------------------------------------------------------------\n"
"; FILE: Reactive Parameters.txt\n"
";\n"
"; MJT @ JUIN-2013\n"
"; ---------------------------------------------------------------\n\n\n"
"[ROBOT_CONFIG]\n"
"Name = MyRobot\n\n"
"HEIGHT_LEVELS = 1 \n\n" //Only one level works with this simulator + odometry!!!!!
";Indicate the geometry of each level \n\n"
";Type: Polyhedric (LEVELX_HEIGHT, LEVELX_VECTORX, LEVELX_VECTORY) \n\n"
"LEVEL1_HEIGHT = 0.6 \n"
"LEVEL1_VECTORX = -0.2 0.4 -0.2 \n"
"LEVEL1_VECTORY = -0.3 0 0.3 \n\n"
"[LASER_CONFIG] \n\n"
";Indicate the laser parameters. This information must be consistent with that included before \n"
";Laser pose is relative to the robot coordinate system. \n"
";Information required: LASERX_POSE, LASERY_POSE, LASERX_MAX_RANGE, LASERX_APERTURE \n"
"; LASERX_STD_ERROR, LASERX_LEVEL, LASERX_SEGMENTS \n\n"
"LASER_POSE = 0 0 0.1 0 0 0 \n"
"LASER_MAX_RANGE = 30 \n"
"LASER_APERTURE = 270 \n"
"LASER_STD_ERROR = 0.05 \n" //0.01
"LASER_LEVEL = 1 \n"
"LASER_SEGMENTS = 1080 \n\n"
"[NAVIGATION_CONFIG] \n\n"
"; 0: VFF, 1: ND \n"
"HOLONOMIC_METHOD = 1 \n\n"
"; Parameters for the navigation \n"
"; ---------------------------------------------------- \n\n"
"weights = 0.5 0.05 0.5 2.0 0.5 0.3 \n\n"
"; 1: Free space \n"
"; 2: Dist. in sectors \n"
"; 3: Heading toward target \n"
"; 4: Closer to target (euclidean) \n"
"; 5: Hysteresis \n"
"; 6: Security Distance \n\n"
"DIST_TO_TARGET_FOR_SENDING_EVENT = 0.5 ; Minimum distance to target for sending the end event. Set to 0 to send it just on navigation end \n\n"
"X0 = -4 ; Initial location (meters) \n" //x = -7, y = -4
"Y0 = 3 \n"
"PHI0 = 0 ; In degrees \n"
"VMAX_MPS = 0.70 ; Speed limits - mps \n"
"WMAX_DEGPS = 60 ; dps \n"
"SPEEDFILTER_TAU = 0 ; The 'TAU' time constant of a first order lowpass filter for speed commands (s) \n"
"ROBOTMODEL_DELAY = 0 ; The delay until motor reaction (s) \n"
"ROBOTMODEL_TAU = 0 ; The 'TAU' time constant of a first order robot model (s) \n"
"MAX_DISTANCE_PTG = 2 ; Marks the maximum distance regarded by the reactive navigator (m) \n"
"GRID_RESOLUTION = 0.02 ; Resolutions used to build the collision_grid \n\n\n"
"; PTGs .All of them has the same fields to fill, but they don't use all of them. \n"
";----------------------------------------------------------------------------------- \n"
"; Types: 1 - Circular arcs \n"
"; 2 - alpha - A, Trajectories with asymptotical heading \n"
"; 3 - C|C,S, R = vmax/wmax, Trajectories to move backward and then forward \n"
"; 4 - C|C,s, like PTG 3, but if t > threshold -> v = w = 0 \n"
"; 5 - CS, Trajectories with a minimum turning radius \n"
"; 6 - alpha - SP, Trajectories built upon a spiral segment \n"
"; 7 - \n\n"
"PTG_COUNT = 3 ;Number of path models used \n\n"
"PTG1_TYPE = 1 \n"
"PTG1_NALFAS = 121 \n"
"PTG1_VMAX = 0.5 \n"
"PTG1_WMAX = 45 \n"
"PTG1_K = 1 \n"
"PTG1_AV = 57.3 \n"
"PTG1_AW = 57.3 \n\n"
"PTG2_TYPE = 2 \n"
"PTG2_NALFAS = 121 \n"
"PTG2_VMAX = 0.5 \n"
"PTG2_WMAX = 45 \n"
"PTG2_K = 1.0 \n"
"PTG2_AV = 57.3 \n"
"PTG2_AW = 57.3 \n\n"
"PTG3_TYPE = 5 \n"
"PTG3_NALFAS = 121 \n"
"PTG3_VMAX = 0.5 \n"
"PTG3_WMAX = 45 \n"
"PTG3_K = 1.0 \n"
"PTG3_AV = 57.3 \n"
"PTG3_AW = 57.3 \n\n"
"; Parameters for the 'Nearness diagram' Holonomic method \n"
"; ------------------------------------------------------------ \n\n"
"[ND_CONFIG] \n"
"factorWeights = 1.0 2.0 0.5 1.0 \n"
"; 1: Free space \n"
"; 2: Dist. in sectors \n"
"; 3: Closer to target (euclidean) \n"
"; 4: Hysteresis \n"
"WIDE_GAP_SIZE_PERCENT = 0.25 ; The robot travels nearer to obstacles if this parameter is small. \n"
" ; The smaller it is, the closer the selected direction is respect to \n"
" ; the Target direction in TP-Space (under some conditions) \n"
"MAX_SECTOR_DIST_FOR_D2_PERCENT = 0.25 ; \n"
"RISK_EVALUATION_SECTORS_PERCENT = 0.25 ; \n"
"RISK_EVALUATION_DISTANCE = 0.7 ; Parameter used to decrease speed if obstacles are closer than this threshold \n"
" ; in normalized ps-meters [0,1] \n"
"TARGET_SLOW_APPROACHING_DISTANCE = 0.8 ; Used to decrease speed gradually when the target is going to be reached \n"
"TOO_CLOSE_OBSTACLE = 0.03 ; In normalized ps-meters [0,1] \n\n\n"
"; Parameters for the VFF Holonomic method \n"
"; ------------------------------------------------------------ \n\n"
"[VFF_CONFIG] \n\n"
"TARGET_SLOW_APPROACHING_DISTANCE = 0.8 ; Used to decrease speed gradually when the target is going to be reached \n"
"TARGET_ATTRACTIVE_FORCE = 7.5 ; Use it to control the relative weight of the target respect to the obstacles \n\n\n";
// ------------------------------------------------------
// MAIN
// ------------------------------------------------------
int main()
{
//Initial steps. Load configuration from file or default
//------------------------------------------------------
CMyReactInterface ReactInterface;
CReactiveNavigationSystem3D rn3d(ReactInterface, false, false);
utils::CConfigFileMemory configNavigation(default_cfg_txt);
rn3d.loadConfigFile( configNavigation );
ReactInterface.loadMaps( configNavigation );
ReactInterface.loadConfiguration( configNavigation );
//Initialize all methods
ReactInterface.initializeEverything();
rn3d.initialize();
//Main loop
//------------------------------------------
bool stop = 0;
bool working = false;
bool one_step = false;
bool moving_target = 0;
int pushed_key = 0;
int iter_count = 0;
TPoint3D last_Target_Pos(0,0,0);
unsigned int odo_freq = 4;
unsigned int react_sim_per_est = 1;
float sim_period = 1.f/float(odo_freq*react_sim_per_est);
CTicTac target_clock;
target_clock.Tic();
const float dt = 0.025;
utils::CTicTac clock;
clock.Tic();
MyObserver observer;
observer.observeBegin(ReactInterface.window);
observer.mouse_click = 0;
while (!stop)
{
if (ReactInterface.window.keyHit())
pushed_key = ReactInterface.window.getPushedKey();
else
pushed_key = 0;
switch (pushed_key) {
case 'm':
//Move the target
moving_target = 1;
break;
case 's':
//Start/stop continuous estimation
working = !working;
break;
case 'n':
//Estimate next step
one_step = true;
break;
case 'e':
//Exit program
stop = 1;
rn3d.cancel();
break;
case 'r':
//Compute statistics (deviations of the odometry from ground truth)
ReactInterface.computeErrors(odo_freq);
break;
case 'f':
//Save results in file
ReactInterface.saveResults(odo_freq);
break;
case 'c':
//Reset pose estimation
ReactInterface.resetScene();
ReactInterface.real_poses.clear();
ReactInterface.est_poses.clear(); ReactInterface.est_time = 0.f;
ReactInterface.test_poses.clear(); ReactInterface.test_time = 0.f;
ReactInterface.psm_poses.clear(); ReactInterface.psm_time = 0.f;
ReactInterface.csm_poses.clear(); ReactInterface.csm_time = 0.f;
break;
case 'x':
//Save scans
ReactInterface.saveScans();
break;
}
//Set the target when the user clicks the mouse
if (observer.mouse_click == 1)
{
observer.mouse_click = 0;
if (moving_target == 1)
{
moving_target = 0;
const CAbstractReactiveNavigationSystem::TNavigationParams nav_params = ReactInterface.createNewTarget(last_Target_Pos.x, last_Target_Pos.y, 0.3, 0);
rn3d.navigate(&nav_params);
}
}
// Run reactive + odometry
//==============================================================================
if ((working)||(one_step))
{
//Controlling the runtime
while (clock.Tac() < dt);
clock.Tic();
//Execute navigation
ReactInterface.robotSim.simulateInterval( sim_period );
rn3d.navigationStep();
//---------------------------------------------------------------------------------------------
//Modify the speed manually for the experiments
// ReactInterface.robotSim.simulateInterval( 0.000001f ); //To update internal v,w and retrieve their last value according to the reactive command
////const float rand_scale = 0.75f*(1.f + sin(0.015f*iter_count));
// const float vel_scaling = 3.f;
// const float rand_scale = (odo_freq/vel_scaling)*0.75f*(1.f + sin(0.015f*iter_count));
// const float new_v = rand_scale*ReactInterface.robotSim.getV();
// const float new_w = rand_scale*ReactInterface.robotSim.getW();
// ReactInterface.changeSpeeds(new_v, new_w);
//New terminate condition for the freq data adquisition
// if (ReactInterface.real_poses.size() >= 3000)
// {
// ReactInterface.saveResults(odo_freq);
// stop = true;
// }
//---------------------------------------------------------------------------------------------
iter_count++;
if (iter_count % react_sim_per_est == 0)
{
//Execute odometry
ReactInterface.runRF2O();
//Execute PSM
if (ReactInterface.draw_psm) ReactInterface.runPolarScanMatching();
//Execute CSM
if (ReactInterface.draw_csm) ReactInterface.runCanonicalScanMatching();
//Add the new poses
ReactInterface.real_poses.push_back(CPose3D(ReactInterface.new_pose));
ReactInterface.est_poses.push_back(CPose3D(ReactInterface.odo.laser_pose));
ReactInterface.test_poses.push_back(CPose3D(ReactInterface.odo_test.laser_pose));
ReactInterface.psm_poses.push_back((CPose3D(ReactInterface.new_psm_pose)));
ReactInterface.csm_poses.push_back((CPose3D(ReactInterface.new_csm_pose)));
}
//Create new target if we have reached the previous one or we cannot reach it
if ((rn3d.IDLE == rn3d.getCurrentState())||(target_clock.Tac() > 10.f))
{
target_clock.Tic();
CSimplePointsMap auxpoints;
ReactInterface.senseObstacles( auxpoints );
//Create new random target within the map bounds:
bool valid_target = false;
const float maxdist_next_target = 10.f;
while (!valid_target)
{
const float rand_num_x = float(std::rand()%1000)/1000.f;
const float rand_num_y = float(std::rand()%1000)/1000.f;
// last_Target_Pos.x = ReactInterface.map.getXMin() + rand_num_x*(ReactInterface.map.getXMax() - ReactInterface.map.getXMin());
// last_Target_Pos.y = ReactInterface.map.getYMin() + rand_num_y*(ReactInterface.map.getYMax() - ReactInterface.map.getYMin());
last_Target_Pos.x = maxdist_next_target*(0.5f - rand_num_x) + ReactInterface.new_pose[0];
last_Target_Pos.y = maxdist_next_target*(0.5f - rand_num_y) + ReactInterface.new_pose[1];
//Check whether the new target is valid
const float range = 0.8f;
valid_target = true;
for (float u=-0.5f; u<=0.5f; u+= 0.1f)
for (float v=-0.5f; v<=0.5f; v+= 0.1f)
if (ReactInterface.map.getPos(last_Target_Pos.x + u*range, last_Target_Pos.y + v*range) < 0.7f)
valid_target = false;
}
const CAbstractReactiveNavigationSystem::TNavigationParams nav_params = ReactInterface.createNewTarget(last_Target_Pos.x, last_Target_Pos.y, 0.3, 0);
rn3d.navigate(&nav_params);
//ReactInterface.scene->getByClass<CDisk>(0)->setLocation(last_Target_Pos.x, last_Target_Pos.y, last_Target_Pos.z);
}
//Sense new obstacles and update scene
if ((rn3d.IDLE == rn3d.getCurrentState())||(rn3d.SUSPENDED == rn3d.getCurrentState()))
{
CSimplePointsMap auxpoints;
ReactInterface.senseObstacles( auxpoints );
}
ReactInterface.updateScene();
//mrpt::system::sleep(10); //To slow it down
if (one_step)
one_step = false;
}
//Move target with the mouse
if (moving_target == 1)
{
int mouse_x,mouse_y;
if (ReactInterface.window.getLastMousePosition(mouse_x,mouse_y))
{
// Get the ray in 3D for the latest mouse (X,Y):
math::TLine3D ray;
ReactInterface.scene->getViewport("main")->get3DRayForPixelCoord(mouse_x,mouse_y,ray);
// Create a 3D plane, e.g. Z = 0
const math::TPlane ground_plane(TPoint3D(0,0,0),TPoint3D(1,0,0),TPoint3D(0,1,0));
// Intersection of the line with the plane:
math::TObject3D inters;
math::intersect(ray,ground_plane, inters);
// Interpret the intersection as a point, if there is an intersection:
// if (inters.getPoint(last_Target_Pos))
// {
// // Move an object to the position picked by the user:
// ReactInterface.scene->getByClass<CDisk>(0)->setLocation(last_Target_Pos.x, last_Target_Pos.y, last_Target_Pos.z);
// }
}
}
}
return 0;
}