Main MRPT website > C++ reference for MRPT 1.9.9
CPTG_Holo_Blend.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "nav-precomp.h" // Precomp header
12 #include <mrpt/utils/types_math.h>
13 #include <mrpt/utils/CStream.h>
14 #include <mrpt/utils/round.h>
15 #include <mrpt/utils/CTimeLogger.h>
16 #include <mrpt/math/poly_roots.h>
18 
19 using namespace mrpt::nav;
20 using namespace mrpt::utils;
21 using namespace mrpt::system;
22 
25 
26 /*
27 Closed-form PTG. Parameters:
28 - Initial velocity vector (xip, yip)
29 - Target velocity vector depends on \alpha: xfp = V_MAX*cos(alpha), yfp =
30 V_MAX*sin(alpha)
31 - T_ramp_max max time for velocity interpolation (xip,yip) -> (xfp, yfp)
32 - W_MAX: Rotational velocity for robot heading forwards.
33 
34 Number of steps "d" for each PTG path "k":
35 - Step = time increment PATH_TIME_STEP
36 
37 */
38 
39 // Uncomment only for benchmarking during development
40 //#define DO_PERFORMANCE_BENCHMARK
41 
42 #ifdef DO_PERFORMANCE_BENCHMARK
43 mrpt::utils::CTimeLogger tl_holo("CPTG_Holo_Blend");
44 #define PERFORMANCE_BENCHMARK \
45  CTimeLoggerEntry tle(tl_holo, __CURRENT_FUNCTION_NAME__);
46 #else
47 #define PERFORMANCE_BENCHMARK
48 #endif
49 
50 double CPTG_Holo_Blend::PATH_TIME_STEP = 10e-3; // 10 ms
51 double CPTG_Holo_Blend::eps = 1e-4; // epsilon for detecting 1/0 situation
52 
53 // As a macro instead of a function (uglier) to allow for const variables
54 // (safer)
55 #define COMMON_PTG_DESIGN_PARAMS \
56  const double vxi = m_nav_dyn_state.curVelLocal.vx, \
57  vyi = m_nav_dyn_state.curVelLocal.vy; \
58  const double vf_mod = internal_get_v(dir); \
59  const double vxf = vf_mod * cos(dir), vyf = vf_mod * sin(dir); \
60  const double T_ramp = internal_get_T_ramp(dir);
61 
62 #if 0
63 static double calc_trans_distance_t_below_Tramp_abc_analytic(double t, double a, double b, double c)
64 {
66 
67  ASSERT_(t >= 0);
68  if (t == 0.0) return .0;
69 
70  double dist;
71  // Handle special case: degenerate sqrt(a*t^2+b*t+c) = sqrt((t-r)^2) = |t-r|
72  const double discr = b*b - 4 * a*c;
73  if (std::abs(discr)<1e-6)
74  {
75  const double r = -b / (2 * a);
76  // dist= definite integral [0,t] of: |t-r| dt
77  dist = r*std::abs(r)*0.5 - (r - t)*std::abs(r - t)*0.5;
78  }
79  else
80  {
81  // General case:
82  // Indefinite integral of sqrt(a*t^2+b*t+c):
83  const double int_t = (t*(1.0 / 2.0) + (b*(1.0 / 4.0)) / a)*sqrt(c + b*t + a*(t*t)) + 1.0 / pow(a, 3.0 / 2.0)*log(1.0 / sqrt(a)*(b*(1.0 / 2.0) + a*t) + sqrt(c + b*t + a*(t*t)))*(a*c - (b*b)*(1.0 / 4.0))*(1.0 / 2.0);
84  // Limit when t->0:
85  const double int_t0 = (b*sqrt(c)*(1.0 / 4.0)) / a + 1.0 / pow(a, 3.0 / 2.0)*log(1.0 / sqrt(a)*(b + sqrt(a)*sqrt(c)*2.0)*(1.0 / 2.0))*(a*c - (b*b)*(1.0 / 4.0))*(1.0 / 2.0);
86  dist = int_t - int_t0;// Definite integral [0,t]
87  }
88 #ifdef _DEBUG
89  using namespace mrpt;
91  ASSERT_(dist >= .0);
92 #endif
93  return dist;
94 }
95 #endif
96 
97 // Numeric integration of: sqrt(a*t^2+b*t+c) for t=[0,T]
99  double T, double a, double b, double c)
100 {
102 
103  double d = .0;
104  const unsigned int NUM_STEPS = 15;
105 
106  ASSERT_(a >= .0);
107  ASSERT_(c >= .0);
108  double feval_t = std::sqrt(c); // t (initial: t=0)
109  double feval_tp1; // t+1
110 
111  const double At = T / (NUM_STEPS);
112  double t = .0;
113  for (unsigned int i = 0; i < NUM_STEPS; i++)
114  {
115  // Eval function at t+1:
116  t += At;
117  double dd = a * t * t + b * t + c;
118 
119  // handle numerical innacuracies near t=T_ramp:
120  ASSERT_(dd > -1e-5);
121  if (dd < 0) dd = .0;
122 
123  feval_tp1 = sqrt(dd);
124 
125  // Trapezoidal rule:
126  d += At * (feval_t + feval_tp1) * 0.5;
127 
128  // for next step:
129  feval_t = feval_tp1;
130  }
131 
132  return d;
133 }
134 
135 // Axiliary function for calc_trans_distance_t_below_Tramp() and others:
137  double t, double a, double b, double c)
138 {
139 // JLB (29 Jan 2017): it turns out that numeric integration is *faster* and more
140 // accurate (does not have "special cases")...
141 #if 0
142  double ret = calc_trans_distance_t_below_Tramp_abc_analytic(t, a, b, c);
143 #else
145 #endif
146 
147  return ret;
148 }
149 
150 // Axiliary function for computing the line-integral distance along the
151 // trajectory, handling special cases of 1/0:
153  double k2, double k4, double vxi, double vyi, double t)
154 {
155  /*
156  dd = sqrt( (4*k2^2 + 4*k4^2)*t^2 + (4*k2*vxi + 4*k4*vyi)*t + vxi^2 + vyi^2 )
157  dt
158  a t^2 + b t + c
159  */
160  const double c = (vxi * vxi + vyi * vyi);
161  if (std::abs(k2) > eps || std::abs(k4) > eps)
162  {
163  const double a = ((k2 * k2) * 4.0 + (k4 * k4) * 4.0);
164  const double b = (k2 * vxi * 4.0 + k4 * vyi * 4.0);
165 
166  // Numerically-ill case: b=c=0 (initial vel=0)
167  if (std::abs(b) < eps && std::abs(c) < eps)
168  {
169  // Indefinite integral of simplified case: sqrt(a)*t
170  const double int_t = sqrt(a) * (t * t) * 0.5;
171  return int_t; // Definite integral [0,t]
172  }
173  else
174  {
175  return calc_trans_distance_t_below_Tramp_abc(t, a, b, c);
176  }
177  }
178  else
179  {
180  return std::sqrt(c) * t;
181  }
182 }
183 
185 {
186  m_pathStepCountCache.assign(m_alphaValuesCount, -1); // mark as invalid
187 }
188 
190 {
193 
194  m_alphaValuesCount = 31;
195  T_ramp_max = 0.9;
196  V_MAX = 1.0;
197  W_MAX = mrpt::utils::DEG2RAD(40);
198 }
199 
201  const mrpt::utils::CConfigFileBase& cfg, const std::string& sSection)
202 {
205 
207  T_ramp_max, double, T_ramp_max, cfg, sSection);
209  v_max_mps, double, V_MAX, cfg, sSection);
211  w_max_dps, double, W_MAX, cfg, sSection);
212  MRPT_LOAD_CONFIG_VAR(turningRadiusReference, double, cfg, sSection);
213 
214  MRPT_LOAD_HERE_CONFIG_VAR(expr_V, string, expr_V, cfg, sSection);
215  MRPT_LOAD_HERE_CONFIG_VAR(expr_W, string, expr_W, cfg, sSection);
216  MRPT_LOAD_HERE_CONFIG_VAR(expr_T_ramp, string, expr_T_ramp, cfg, sSection);
217 }
219  mrpt::utils::CConfigFileBase& cfg, const std::string& sSection) const
220 {
221  MRPT_START
222  const int WN = 25, WV = 30;
223 
225 
226  cfg.write(
227  sSection, "T_ramp_max", T_ramp_max, WN, WV,
228  "Max duration of the velocity interpolation since a vel_cmd is issued "
229  "[s].");
230  cfg.write(
231  sSection, "v_max_mps", V_MAX, WN, WV,
232  "Maximum linear velocity for trajectories [m/s].");
233  cfg.write(
234  sSection, "w_max_dps", mrpt::utils::RAD2DEG(W_MAX), WN, WV,
235  "Maximum angular velocity for trajectories [deg/s].");
236  cfg.write(
237  sSection, "turningRadiusReference", turningRadiusReference, WN, WV,
238  "An approximate dimension of the robot (not a critical parameter) "
239  "[m].");
240 
241  cfg.write(
242  sSection, "expr_V", expr_V, WN, WV,
243  "Math expr for |V| as a function of "
244  "`dir`,`V_MAX`,`W_MAX`,`T_ramp_max`.");
245  cfg.write(
246  sSection, "expr_W", expr_W, WN, WV,
247  "Math expr for |omega| (disregarding the sign, only the module) as a "
248  "function of `dir`,`V_MAX`,`W_MAX`,`T_ramp_max`.");
249  cfg.write(
250  sSection, "expr_T_ramp", expr_T_ramp, WN, WV,
251  "Math expr for `T_ramp` as a function of "
252  "`dir`,`V_MAX`,`W_MAX`,`T_ramp_max`.");
253 
255 
256  MRPT_END
257 }
258 
260 {
261  return mrpt::format(
262  "PTG_Holo_Blend_Tramp=%.03f_Vmax=%.03f_Wmax=%.03f", T_ramp_max, V_MAX,
263  W_MAX);
264 }
265 
267 {
269 
270  switch (version)
271  {
272  case 0:
273  case 1:
274  case 2:
275  case 3:
276  case 4:
277  if (version >= 1)
278  {
280  }
281 
282  in >> T_ramp_max >> V_MAX >> W_MAX >> turningRadiusReference;
283  if (version == 2)
284  {
285  double dummy_maxAllowedDirAngle; // removed in v3
286  in >> dummy_maxAllowedDirAngle;
287  }
288  if (version >= 4)
289  {
290  in >> expr_V >> expr_W >> expr_T_ramp;
291  }
292  break;
293  default:
295  };
296 }
297 
299  mrpt::utils::CStream& out, int* version) const
300 {
301  if (version)
302  {
303  *version = 4;
304  return;
305  }
306 
309 
310  out << T_ramp_max << V_MAX << W_MAX << turningRadiusReference;
311  out << expr_V << expr_W << expr_T_ramp;
312 }
313 
315  double x, double y, int& out_k, double& out_d, double tolerance_dist) const
316 {
318 
319  MRPT_UNUSED_PARAM(tolerance_dist);
320  ASSERT_(x != 0 || y != 0);
321 
322  const double err_threshold = 1e-3;
323  const double T_ramp = T_ramp_max;
324  const double vxi = m_nav_dyn_state.curVelLocal.vx,
325  vyi = m_nav_dyn_state.curVelLocal.vy;
326 
327  // Use a Newton iterative non-linear optimizer to find the "exact" solution
328  // for (t,alpha)
329  // in each case: (1) t<T_ramp and (2) t>T_ramp
330 
331  // Initial value:
332  Eigen::Vector3d q; // [t vxf vyf]
333  q[0] = T_ramp_max * 1.1;
334  q[1] = V_MAX * x / sqrt(x * x + y * y);
335  q[2] = V_MAX * y / sqrt(x * x + y * y);
336 
337  // Iterate: case (2) t > T_ramp
338  double err_mod = 1e7;
339  bool sol_found = false;
340  for (int iters = 0; !sol_found && iters < 25; iters++)
341  {
342  const double TR_ = 1.0 / (T_ramp);
343  const double TR2_ = 1.0 / (2 * T_ramp);
344 
345  // Eval residual:
346  Eigen::Vector3d r;
347  if (q[0] >= T_ramp)
348  {
349  r[0] = 0.5 * T_ramp * (vxi + q[1]) + (q[0] - T_ramp) * q[1] - x;
350  r[1] = 0.5 * T_ramp * (vyi + q[2]) + (q[0] - T_ramp) * q[2] - y;
351  }
352  else
353  {
354  r[0] = vxi * q[0] + q[0] * q[0] * TR2_ * (q[1] - vxi) - x;
355  r[1] = vyi * q[0] + q[0] * q[0] * TR2_ * (q[2] - vyi) - y;
356  }
357  const double alpha = atan2(q[2], q[1]);
358  const double V_MAXsq = mrpt::math::square(this->internal_get_v(alpha));
359  r[2] = q[1] * q[1] + q[2] * q[2] - V_MAXsq;
360 
361  // Jacobian: q=[t vxf vyf] q0=t q1=vxf q2=vyf
362  // dx/dt dx/dvxf dx/dvyf
363  // dy/dt dy/dvxf dy/dvyf
364  // dVF/dt dVF/dvxf dVF/dvyf
365  Eigen::Matrix3d J;
366  if (q[0] >= T_ramp)
367  {
368  J(0, 0) = q[1];
369  J(0, 1) = 0.5 * T_ramp + q[0];
370  J(0, 2) = 0.0;
371  J(1, 0) = q[2];
372  J(1, 1) = 0.0;
373  J(1, 2) = 0.5 * T_ramp + q[0];
374  }
375  else
376  {
377  J(0, 0) = vxi + q[0] * TR_ * (q[1] - vxi);
378  J(0, 1) = TR2_ * q[0] * q[0];
379  J(0, 2) = 0.0;
380  J(1, 0) = vyi + q[0] * TR_ * (q[2] - vyi);
381  J(1, 1) = 0.0;
382  J(1, 2) = TR2_ * q[0] * q[0];
383  }
384  J(2, 0) = 0.0;
385  J(2, 1) = 2 * q[1];
386  J(2, 2) = 2 * q[2];
387 
388  Eigen::Vector3d q_incr = J.householderQr().solve(r);
389  q -= q_incr;
390 
391  err_mod = r.norm();
392  sol_found = (err_mod < err_threshold);
393  }
394 
395  if (sol_found && q[0] >= .0)
396  {
397  const double alpha = atan2(q[2], q[1]);
399 
400  const double solved_t = q[0];
401  const unsigned int solved_step = solved_t / PATH_TIME_STEP;
402  const double found_dist = this->getPathDist(out_k, solved_step);
403 
404  out_d = found_dist / this->refDistance;
405  return true;
406  }
407  else
408  {
409  return false;
410  }
411 }
412 
413 bool CPTG_Holo_Blend::PTG_IsIntoDomain(double x, double y) const
414 {
415  int k;
416  double d;
417  return inverseMap_WS2TP(x, y, k, d);
418 }
419 
421 {
422  // Nothing to do in a closed-form PTG.
423 }
424 
426  uint16_t k) const
427 {
428  const double dir_local = CParameterizedTrajectoryGenerator::index2alpha(k);
429 
432  cmd->vel = internal_get_v(dir_local);
433  cmd->dir_local = dir_local;
434  cmd->ramp_time = internal_get_T_ramp(dir_local);
435  cmd->rot_speed =
436  mrpt::utils::signWithZero(dir_local) * internal_get_w(dir_local);
437 
439 }
440 
442 {
443  if (m_pathStepCountCache.size() > k && m_pathStepCountCache[k] > 0)
444  return m_pathStepCountCache[k];
445 
446  uint32_t step;
447  if (!getPathStepForDist(k, this->refDistance, step))
448  {
450  "Could not solve closed-form distance for k=%u",
451  static_cast<unsigned>(k));
452  }
453  ASSERT_(step > 0);
454  if (m_pathStepCountCache.size() != m_alphaValuesCount)
455  {
456  m_pathStepCountCache.assign(m_alphaValuesCount, -1);
457  }
458  m_pathStepCountCache[k] = step;
459  return step;
460 }
461 
463  uint16_t k, uint32_t step, mrpt::math::TPose2D& p) const
464 {
465  const double t = PATH_TIME_STEP * step;
468  const double wf =
469  mrpt::utils::signWithZero(dir) * this->internal_get_w(dir);
470  const double TR2_ = 1.0 / (2 * T_ramp);
471 
472  // Translational part:
473  if (t < T_ramp)
474  {
475  p.x = vxi * t + t * t * TR2_ * (vxf - vxi);
476  p.y = vyi * t + t * t * TR2_ * (vyf - vyi);
477  }
478  else
479  {
480  p.x = T_ramp * 0.5 * (vxi + vxf) + (t - T_ramp) * vxf;
481  p.y = T_ramp * 0.5 * (vyi + vyf) + (t - T_ramp) * vyf;
482  }
483 
484  // Rotational part:
485  const double wi = m_nav_dyn_state.curVelLocal.omega;
486 
487  if (t < T_ramp)
488  {
489  // Time required to align completed?
490  const double a = TR2_ * (wf - wi), b = (wi), c = -dir;
491 
492  // Solves equation `a*x^2 + b*x + c = 0`.
493  double r1, r2;
494  int nroots = mrpt::math::solve_poly2(a, b, c, r1, r2);
495  if (nroots != 2)
496  {
497  p.phi = .0; // typical case: wi=wf=0
498  }
499  else
500  {
501  const double t_solve = std::max(r1, r2);
502  if (t > t_solve)
503  p.phi = dir;
504  else
505  p.phi = wi * t + t * t * TR2_ * (wf - wi);
506  }
507  }
508  else
509  {
510  // Time required to align completed?
511  const double t_solve = (dir - T_ramp * 0.5 * (wi + wf)) / wf + T_ramp;
512  if (t > t_solve)
513  p.phi = dir;
514  else
515  p.phi = T_ramp * 0.5 * (wi + wf) + (t - T_ramp) * wf;
516  }
517 }
518 
520 {
521  const double t = PATH_TIME_STEP * step;
523 
525  const double TR2_ = 1.0 / (2 * T_ramp);
526 
527  const double k2 = (vxf - vxi) * TR2_;
528  const double k4 = (vyf - vyi) * TR2_;
529 
530  if (t < T_ramp)
531  {
532  return calc_trans_distance_t_below_Tramp(k2, k4, vxi, vyi, t);
533  }
534  else
535  {
536  const double dist_trans =
537  (t - T_ramp) * V_MAX +
538  calc_trans_distance_t_below_Tramp(k2, k4, vxi, vyi, T_ramp);
539  return dist_trans;
540  }
541 }
542 
544  uint16_t k, double dist, uint32_t& out_step) const
545 {
547 
550 
551  const double TR2_ = 1.0 / (2 * T_ramp);
552 
553  const double k2 = (vxf - vxi) * TR2_;
554  const double k4 = (vyf - vyi) * TR2_;
555 
556  // --------------------------------------
557  // Solution within t >= T_ramp ??
558  // --------------------------------------
559  const double dist_trans_T_ramp =
560  calc_trans_distance_t_below_Tramp(k2, k4, vxi, vyi, T_ramp);
561  double t_solved = -1;
562 
563  if (dist >= dist_trans_T_ramp)
564  {
565  // Good solution:
566  t_solved = T_ramp + (dist - dist_trans_T_ramp) / V_MAX;
567  }
568  else
569  {
570  // ------------------------------------
571  // Solutions within t < T_ramp
572  //
573  // Cases:
574  // 1) k2=k4=0 --> vi=vf. Path is straight line
575  // 2) b=c=0 -> vi=0
576  // 3) Otherwise, general case
577  // ------------------------------------
578  if (std::abs(k2) < eps && std::abs(k4) < eps)
579  {
580  // Case 1
581  t_solved = (dist) / V_MAX;
582  }
583  else
584  {
585  const double a = ((k2 * k2) * 4.0 + (k4 * k4) * 4.0);
586  const double b = (k2 * vxi * 4.0 + k4 * vyi * 4.0);
587  const double c = (vxi * vxi + vyi * vyi);
588 
589  // Numerically-ill case: b=c=0 (initial vel=0)
590  if (std::abs(b) < eps && std::abs(c) < eps)
591  {
592  // Case 2:
593  t_solved = sqrt(2.0) * 1.0 / pow(a, 1.0 / 4.0) * sqrt(dist);
594  }
595  else
596  {
597  // Case 3: general case with non-linear equation:
598  // dist = (t/2 + b/(4*a))*(a*t^2 + b*t + c)^(1/2) -
599  // (b*c^(1/2))/(4*a) + (log((b/2 + a*t)/a^(1/2) + (a*t^2 + b*t +
600  // c)^(1/2))*(- b^2/4 + a*c))/(2*a^(3/2)) - (log((b +
601  // 2*a^(1/2)*c^(1/2))/(2*a^(1/2)))*(- b^2/4 + a*c))/(2*a^(3/2))
602  // dist =
603  // (t*(1.0/2.0)+(b*(1.0/4.0))/a)*sqrt(c+b*t+a*(t*t))-(b*sqrt(c)*(1.0/4.0))/a+1.0/pow(a,3.0/2.0)*log(1.0/sqrt(a)*(b*(1.0/2.0)+a*t)+sqrt(c+b*t+a*(t*t)))*(a*c-(b*b)*(1.0/4.0))*(1.0/2.0)-1.0/pow(a,3.0/2.0)*log(1.0/sqrt(a)*(b+sqrt(a)*sqrt(c)*2.0)*(1.0/2.0))*(a*c-(b*b)*(1.0/4.0))*(1.0/2.0);
604 
605  // We must solve this by iterating:
606  // Newton method:
607  // Minimize f(t)-dist = 0
608  // with: f(t)=calc_trans_distance_t_below_Tramp_abc(t)
609  // and: f'(t) = sqrt(a*t^2+b*t+c)
610 
611  t_solved = T_ramp * 0.6; // Initial value for starting
612  // interation inside the valid domain
613  // of the function t=[0,T_ramp]
614  for (int iters = 0; iters < 10; iters++)
615  {
616  double err = calc_trans_distance_t_below_Tramp_abc(
617  t_solved, a, b, c) -
618  dist;
619  const double diff =
620  std::sqrt(a * t_solved * t_solved + b * t_solved + c);
621  ASSERT_(std::abs(diff) > 1e-40);
622  t_solved -= (err) / diff;
623  if (t_solved < 0) t_solved = .0;
624  if (std::abs(err) < 1e-3) break; // Good enough!
625  }
626  }
627  }
628  }
629  if (t_solved >= 0)
630  {
631  out_step = mrpt::utils::round(t_solved / PATH_TIME_STEP);
632  return true;
633  }
634  else
635  return false;
636 }
637 
639  double ox, double oy, uint16_t k, double& tp_obstacle_k) const
640 {
641  const double R = m_robotRadius;
644 
645  const double TR2_ = 1.0 / (2 * T_ramp);
646  const double TR_2 = T_ramp * 0.5;
647  const double T_ramp_thres099 = T_ramp * 0.99;
648  const double T_ramp_thres101 = T_ramp * 1.01;
649 
650  double sol_t = -1.0; // candidate solution for shortest time to collision
651 
652  // Note: It's tempting to try to solve first for t>T_ramp because it has
653  // simpler (faster) equations,
654  // but there are cases in which we will have valid collisions for t>T_ramp
655  // but other valid ones
656  // for t<T_ramp as well, so the only SAFE way to detect shortest distances
657  // is to check over increasing values of "t".
658 
659  // Try to solve first for t<T_ramp:
660  const double k2 = (vxf - vxi) * TR2_;
661  const double k4 = (vyf - vyi) * TR2_;
662 
663  // equation: a*t^4 + b*t^3 + c*t^2 + d*t + e = 0
664  const double a = (k2 * k2 + k4 * k4);
665  const double b = (k2 * vxi * 2.0 + k4 * vyi * 2.0);
666  const double c = -(k2 * ox * 2.0 + k4 * oy * 2.0 - vxi * vxi - vyi * vyi);
667  const double d = -(ox * vxi * 2.0 + oy * vyi * 2.0);
668  const double e = -R * R + ox * ox + oy * oy;
669 
670  double roots[4];
671  int num_real_sols = 0;
672  if (std::abs(a) > eps)
673  {
674  // General case: 4th order equation
675  // a * x^4 + b * x^3 + c * x^2 + d * x + e
676  num_real_sols =
677  mrpt::math::solve_poly4(roots, b / a, c / a, d / a, e / a);
678  }
679  else if (std::abs(b) > eps)
680  {
681  // Special case: k2=k4=0 (straight line path, no blend)
682  // 3rd order equation:
683  // b * x^3 + c * x^2 + d * x + e
684  num_real_sols = mrpt::math::solve_poly3(roots, c / b, d / b, e / b);
685  }
686  else
687  {
688  // Special case: 2nd order equation (a=b=0)
689  const double discr = d * d - 4 * c * e; // c*t^2 + d*t + e = 0
690  if (discr >= 0)
691  {
692  num_real_sols = 2;
693  roots[0] = (-d + sqrt(discr)) / (2 * c);
694  roots[1] = (-d - sqrt(discr)) / (2 * c);
695  }
696  else
697  {
698  num_real_sols = 0;
699  }
700  }
701 
702  for (int i = 0; i < num_real_sols; i++)
703  {
704  if (roots[i] == roots[i] && // not NaN
705  std::isfinite(roots[i]) && roots[i] >= .0 &&
706  roots[i] <= T_ramp * 1.01)
707  {
708  if (sol_t < 0)
709  sol_t = roots[i];
710  else
711  mrpt::utils::keep_min(sol_t, roots[i]);
712  }
713  }
714 
715  // Invalid with these equations?
716  if (sol_t < 0 || sol_t > T_ramp_thres101)
717  {
718  // Now, attempt to solve with the equations for t>T_ramp:
719  sol_t = -1.0;
720 
721  const double c1 = TR_2 * (vxi - vxf) - ox;
722  const double c2 = TR_2 * (vyi - vyf) - oy;
723 
724  const double a = vf_mod * vf_mod;
725  const double b = 2 * (c1 * vxf + c2 * vyf);
726  const double c = c1 * c1 + c2 * c2 - R * R;
727 
728  const double discr = b * b - 4 * a * c;
729  if (discr >= 0)
730  {
731  const double sol_t0 = (-b + sqrt(discr)) / (2 * a);
732  const double sol_t1 = (-b - sqrt(discr)) / (2 * a);
733 
734  // Identify the shortest valid collision time:
735  if (sol_t0 < T_ramp && sol_t1 < T_ramp)
736  sol_t = -1.0;
737  else if (sol_t0 < T_ramp && sol_t1 >= T_ramp_thres099)
738  sol_t = sol_t1;
739  else if (sol_t1 < T_ramp && sol_t0 >= T_ramp_thres099)
740  sol_t = sol_t0;
741  else if (sol_t1 >= T_ramp_thres099 && sol_t0 >= T_ramp_thres099)
742  sol_t = std::min(sol_t0, sol_t1);
743  }
744  }
745 
746  // Valid solution?
747  if (sol_t < 0) return;
748  // Compute the transversed distance:
749  double dist;
750 
751  if (sol_t < T_ramp)
752  dist = calc_trans_distance_t_below_Tramp(k2, k4, vxi, vyi, sol_t);
753  else
754  dist = (sol_t - T_ramp) * V_MAX +
755  calc_trans_distance_t_below_Tramp(k2, k4, vxi, vyi, T_ramp);
756 
757  // Store in the output variable:
758  internal_TPObsDistancePostprocess(ox, oy, dist, tp_obstacle_k);
759 }
760 
762  double ox, double oy, std::vector<double>& tp_obstacles) const
763 {
765 
766  for (unsigned int k = 0; k < m_alphaValuesCount; k++)
767  {
768  updateTPObstacleSingle(ox, oy, k, tp_obstacles[k]);
769  } // end for each "k" alpha
770 }
771 
773 {
774  // Nothing to do in a closed-form PTG.
775 }
776 
779 {
782 }
783 
784 bool CPTG_Holo_Blend::supportVelCmdNOP() const { return true; }
785 double CPTG_Holo_Blend::maxTimeInVelCmdNOP(int path_k) const
786 {
787  // const double dir_local =
788  // CParameterizedTrajectoryGenerator::index2alpha(path_k);
789 
790  const size_t nSteps = getPathStepCount(path_k);
791  const double max_t =
792  PATH_TIME_STEP *
793  (nSteps *
794  0.7 /* leave room for obstacle detection ahead when we are far down the predicted PTG path */);
795  return max_t;
796 }
797 
798 double CPTG_Holo_Blend::getPathStepDuration() const { return PATH_TIME_STEP; }
800  : T_ramp_max(-1.0), V_MAX(-1.0), W_MAX(-1.0), turningRadiusReference(0.30)
801 {
803 }
804 
806  const mrpt::utils::CConfigFileBase& cfg, const std::string& sSection)
807  : turningRadiusReference(0.30)
808 {
810  this->loadFromConfigFile(cfg, sSection);
811 }
812 
815 {
816  std::map<std::string, double*> symbols;
817  symbols["dir"] = &m_expr_dir;
818  symbols["V_MAX"] = &V_MAX;
819  symbols["W_MAX"] = &W_MAX;
820  symbols["T_ramp_max"] = &T_ramp_max;
821  symbols["T_ramp_max"] = &T_ramp_max;
822 
823  m_expr_v.register_symbol_table(symbols);
824  m_expr_w.register_symbol_table(symbols);
825  m_expr_T_ramp.register_symbol_table(symbols);
826 
827  // Default expressions (can be overloaded by values in a config file)
828  expr_V = "V_MAX";
829  expr_W = "W_MAX";
830  expr_T_ramp = "T_ramp_max";
831 }
832 
833 double CPTG_Holo_Blend::internal_get_v(const double dir) const
834 {
835  const_cast<double&>(m_expr_dir) = dir;
836  return std::abs(m_expr_v.eval());
837 }
838 double CPTG_Holo_Blend::internal_get_w(const double dir) const
839 {
840  const_cast<double&>(m_expr_dir) = dir;
841  return std::abs(m_expr_w.eval());
842 }
843 double CPTG_Holo_Blend::internal_get_T_ramp(const double dir) const
844 {
845  const_cast<double&>(m_expr_dir) = dir;
846  return m_expr_T_ramp.eval();
847 }
848 
850  const std::string& cacheFilename, const bool verbose)
851 {
852  // No need to initialize anything, just do some params sanity checks:
853  ASSERT_(T_ramp_max > 0);
854  ASSERT_(V_MAX > 0);
855  ASSERT_(W_MAX > 0);
857  ASSERT_(m_robotRadius > 0);
858 
859  // Compile user-given expressions:
860  m_expr_v.compile(expr_V, std::map<std::string, double>(), "expr_V");
861  m_expr_w.compile(expr_W, std::map<std::string, double>(), "expr_w");
862  m_expr_T_ramp.compile(
863  expr_T_ramp, std::map<std::string, double>(), "expr_T_ramp");
864 
865 #ifdef DO_PERFORMANCE_BENCHMARK
866  tl.dumpAllStats();
867 #endif
868 
869  m_pathStepCountCache.clear();
870 }
double index2alpha(uint16_t k) const
Alpha value for the discrete corresponding value.
int signWithZero(T x)
Returns the sign of X as "0", "1" or "-1".
void internal_initialize(const std::string &cacheFilename=std::string(), const bool verbose=true) override
Must be called after setting all PTG parameters and before requesting converting obstacles to TP-Spac...
GLclampf GLclampf GLclampf alpha
Definition: glext.h:3525
void loadDefaultParams() override
Loads a set of default parameters; provided exclusively for the PTG-configurator tool.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
GLdouble GLdouble t
Definition: glext.h:3689
#define min(a, b)
unsigned __int16 uint16_t
Definition: rptypes.h:44
#define MRPT_LOAD_HERE_CONFIG_VAR( variableName, variableType, targetVariable, configFileObject, sectionNameStr)
void loadShapeFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string &section)
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
double DEG2RAD(const double x)
Degrees to radians.
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
std::string getDescription() const override
Gets a short textual description of the PTG and its parameters.
double getPathDist(uint16_t k, uint32_t step) const override
Access path k ([0,N-1]=>[-pi,pi] in alpha): traversed distance at discrete step step.
virtual void saveToConfigFile(mrpt::utils::CConfigFileBase &cfg, const std::string &sSection) const override
This method saves the options to a ".ini"-like file or memory-stored string list. ...
mrpt::math::CRuntimeCompiledExpression m_expr_w
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
#define MRPT_LOAD_HERE_CONFIG_VAR_DEGREES_NO_DEFAULT( variableName, variableType, targetVariable, configFileObject, sectionNameStr)
#define MRPT_CHECK_NORMAL_NUMBER(val)
bool getPathStepForDist(uint16_t k, double dist, uint32_t &out_step) const override
Access path k ([0,N-1]=>[-pi,pi] in alpha): largest step count for which the traversed distance is < ...
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:3721
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
bool PTG_IsIntoDomain(double x, double y) const override
Returns the same than inverseMap_WS2TP() but without any additional cost.
mrpt::math::CRuntimeCompiledExpression m_expr_T_ramp
void internal_deinitialize() override
This must be called to de-initialize the PTG if some parameter is to be changed.
virtual void loadFromConfigFile(const mrpt::utils::CConfigFileBase &cfg, const std::string &sSection) override
Parameters accepted by this base class:
static double calc_trans_distance_t_below_Tramp(double k2, double k4, double vxi, double vyi, double t)
Axiliary function for computing the line-integral distance along the trajectory, handling special cas...
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value...
virtual double maxTimeInVelCmdNOP(int path_k) const override
Only for PTGs supporting supportVelCmdNOP(): this is the maximum time (in seconds) for which the path...
virtual void internal_writeToStream(mrpt::utils::CStream &out) const
This class allows loading and storing values and vectors of different types from a configuration text...
virtual void loadFromConfigFile(const mrpt::utils::CConfigFileBase &cfg, const std::string &sSection) override
Parameters accepted by this base class:
double internal_get_v(const double dir) const
Evals expr_v.
void getPathPose(uint16_t k, uint32_t step, mrpt::math::TPose2D &p) const override
Access path k ([0,N-1]=>[-pi,pi] in alpha): pose of the vehicle at discrete step step.
virtual void loadDefaultParams()
Loads a set of default parameters into the PTG.
double ramp_time
: Blending time between current and target time.
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
This is the base class for any user-defined PTG.
A PTG for circular-shaped robots with holonomic kinematics.
double RAD2DEG(const double x)
Radians to degrees.
virtual void internal_readFromStream(mrpt::utils::CStream &in)
#define MRPT_END
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
double dir_local
: direction, relative to the current robot heading (radians).
double getPathStepDuration() const override
Returns the duration (in seconds) of each "step".
void internal_shape_saveToStream(mrpt::utils::CStream &out) const
const GLubyte * c
Definition: glext.h:6313
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
std::vector< int > m_pathStepCountCache
double internal_get_w(const double dir) const
Evals expr_w.
virtual void loadDefaultParams() override
Loads a set of default parameters; provided exclusively for the PTG-configurator tool.
int solve_poly4(double *x, double a, double b, double c, double d) noexcept
Solves quartic equation x^4 + a*x^3 + b*x^2 + c*x + d = 0 by Dekart-Euler method. ...
Definition: poly_roots.cpp:254
GLubyte GLubyte b
Definition: glext.h:6279
const double eps
void onNewNavDynamicState() override
Invoked when m_nav_dyn_state has changed; gives the PTG the opportunity to react and parameterize pat...
void updateTPObstacle(double ox, double oy, std::vector< double > &tp_obstacles) const override
Updates the radial map of closest TP-Obstacles given a single obstacle point at (ox,oy)
void internal_shape_loadFromStream(mrpt::utils::CStream &in)
virtual bool supportVelCmdNOP() const override
Returns true if it is possible to stop sending velocity commands to the robot and, still, the robot controller will be able to keep following the last sent trajectory ("NOP" velocity commands).
GLsizei const GLchar ** string
Definition: glext.h:4101
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
bool inverseMap_WS2TP(double x, double y, int &out_k, double &out_d, double tolerance_dist=0.10) const override
Computes the closest (alpha,d) TP coordinates of the trajectory point closest to the Workspace (WS) C...
void updateTPObstacleSingle(double ox, double oy, uint16_t k, double &tp_obstacle_k) const override
Like updateTPObstacle() but for one direction only (k) in TP-Space.
#define MRPT_START
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
static double calc_trans_distance_t_below_Tramp_abc(double t, double a, double b, double c)
Axiliary function for calc_trans_distance_t_below_Tramp() and others.
#define MRPT_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( variableName, variableType, targetVariable, configFileObject, sectionNameStr)
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void write(const std::string &section, const std::string &name, enum_t value, const int name_padding_width=-1, const int value_padding_width=-1, const std::string &comment=std::string())
static double calc_trans_distance_t_below_Tramp_abc_numeric(double T, double a, double b, double c)
GLdouble GLdouble GLdouble r
Definition: glext.h:3705
const float R
static double PATH_TIME_STEP
Duration of each PTG "step" (default: 10e-3=10 ms)
T square(const T x)
Inline function for the square of a number.
double internal_get_T_ramp(const double dir) const
Evals expr_T_ramp.
GLuint in
Definition: glext.h:7274
Lightweight 2D pose.
#define ASSERT_(f)
A versatile "profiler" that logs the time spent within each pair of calls to enter(X)-leave(X), among other stats.
Definition: CTimeLogger.h:45
void internal_processNewRobotShape() override
Will be called whenever the robot shape is set / updated.
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:25
#define PERFORMANCE_BENCHMARK
GLenum GLint GLint y
Definition: glext.h:3538
size_t getPathStepCount(uint16_t k) const override
Access path k ([0,N-1]=>[-pi,pi] in alpha): number of discrete "steps" along the trajectory.
static double eps
Mathematical "epsilon", to detect ill-conditioned situations (e.g.
#define MRPT_LOAD_CONFIG_VAR( variableName, variableType, configFileObject, sectionNameStr)
An useful macro for loading variables stored in a INI-like file under a key with the same name that t...
GLenum GLint x
Definition: glext.h:3538
std::shared_ptr< CVehicleVelCmd > Ptr
unsigned __int32 uint32_t
Definition: rptypes.h:47
GLubyte GLubyte GLubyte a
Definition: glext.h:6279
GLfloat GLfloat p
Definition: glext.h:6305
mrpt::math::CRuntimeCompiledExpression m_expr_v
void saveToConfigFile(mrpt::utils::CConfigFileBase &cfg, const std::string &sSection) const override
This method saves the options to a ".ini"-like file or memory-stored string list. ...
double rot_speed
: (rad/s) rotational speed for rotating such as the robot slowly faces forward.
int solve_poly3(double *x, double a, double b, double c) noexcept
Solves cubic equation x^3 + a*x^2 + b*x + c = 0.
Definition: poly_roots.cpp:29
virtual mrpt::kinematics::CVehicleVelCmd::Ptr directionToMotionCommand(uint16_t k) const override
Converts a discretized "alpha" value into a feasible motion command or action.
virtual mrpt::kinematics::CVehicleVelCmd::Ptr getSupportedKinematicVelocityCommand() const override
Returns an empty kinematic velocity command object of the type supported by this PTG.
#define COMMON_PTG_DESIGN_PARAMS
uint16_t m_alphaValuesCount
The number of discrete values for "alpha" between -PI and +PI.
uint16_t alpha2index(double alpha) const
Discrete index value for the corresponding alpha value.
int solve_poly2(double a, double b, double c, double &r1, double &r2) noexcept
Solves equation a*x^2 + b*x + c = 0.
Definition: poly_roots.cpp:401
virtual void saveToConfigFile(mrpt::utils::CConfigFileBase &cfg, const std::string &sSection) const override
This method saves the options to a ".ini"-like file or memory-stored string list. ...



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019