ObstacleAvoidingPlatformUnit.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * @package RobotAPI::ArmarXObjects::ObstacleAvoidingPlatformUnit
17  * @author Christian R. G. Dreher <c.dreher@kit.edu>
18  * @date 2020
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 
25 
26 
27 // STD/STL
28 #include <algorithm>
29 #include <cmath>
30 #include <limits>
31 #include <numeric>
32 
33 // Eigen
34 #include <Eigen/Core>
35 #include <Eigen/Geometry>
36 
37 // Simox
38 #include <SimoxUtility/math.h>
39 
40 // ArmarX
42 
43 namespace
44 {
45 
46  void
47  invalidate(float& v)
48  {
49  v = std::numeric_limits<float>::infinity();
50  }
51 
52  void
53  invalidate(Eigen::Vector2f& v)
54  {
55  v.x() = std::numeric_limits<float>::infinity();
56  v.y() = std::numeric_limits<float>::infinity();
57  }
58 
59  void
60  invalidate(Eigen::Vector3f& v)
61  {
62  v.x() = std::numeric_limits<float>::infinity();
63  v.y() = std::numeric_limits<float>::infinity();
64  v.z() = std::numeric_limits<float>::infinity();
65  }
66 
67  template <typename T>
68  void
69  invalidate(std::deque<T>& d)
70  {
71  d.clear();
72  }
73 
74  std::string
76  {
77  switch (mode)
78  {
80  return "position";
82  return "velocity";
84  default:
85  return "unset";
86  }
87  }
88 
89 } // namespace
90 
92  "ObstacleAvoidingPlatformUnit";
93 
94 
96 
97 
99 
100 void
102 {
103  ARMARX_DEBUG << "Initializing " << getName() << ".";
104 
105  ARMARX_DEBUG << "Initialized " << getName() << ".";
106 }
107 
108 void
110 {
111  ARMARX_DEBUG << "Starting " << getName() << ".";
112 
113  if (!hasRobot("robot"))
114  {
115  m_robot = addRobot("robot", VirtualRobot::RobotIO::eStructure);
116  }
117 
118  invalidate(m_control_data.target_vel);
119  invalidate(m_control_data.target_rot_vel);
120  invalidate(m_control_data.target_pos);
121  invalidate(m_control_data.target_ori);
122  invalidate(m_viz.start);
123  invalidate(m_control_data.vel_history);
124 
125  ARMARX_DEBUG << "Started " << getName() << ".";
126 }
127 
128 void
130 {
131  ARMARX_DEBUG << "Exiting " << getName() << ".";
132 
133  schedule_high_level_control_loop(control_mode::none);
134 
135  ARMARX_DEBUG << "Exited " << getName() << ".";
136 }
137 
138 std::string
140 {
141  return default_name;
142 }
143 
144 void
146  const float target_pos_y,
147  const float target_ori,
148  const float pos_reached_threshold,
149  const float ori_reached_threshold,
150  const Ice::Current&)
151 {
152  using namespace simox::math;
153 
154  std::scoped_lock l{m_control_data.mutex};
155 
156  m_control_data.target_pos = Eigen::Vector2f{target_pos_x, target_pos_y};
157  m_control_data.target_ori = periodic_clamp<float>(target_ori, -M_PI, M_PI);
158  m_control_data.pos_reached_threshold = pos_reached_threshold;
159  m_control_data.ori_reached_threshold = ori_reached_threshold;
160 
161  // clear the buffer to prevent any movement into arbitrary directions
162  invalidate(m_control_data.vel_history);
163 
164  invalidate(m_control_data.target_vel);
165  invalidate(m_control_data.target_rot_vel);
166 
167  schedule_high_level_control_loop(control_mode::position);
168 }
169 
170 void
172  const float target_vel_y,
173  const float target_rot_vel,
174  const Ice::Current&)
175 {
176  using namespace simox::math;
177 
178  std::scoped_lock l{m_control_data.mutex};
179 
180  m_control_data.target_vel = Eigen::Vector2f{target_vel_x, target_vel_y};
181  m_control_data.target_rot_vel = periodic_clamp<float>(target_rot_vel, -M_PI, M_PI);
182 
183  invalidate(m_control_data.target_pos);
184  invalidate(m_control_data.target_ori);
185 
186  ARMARX_CHECK(m_control_data.target_vel.allFinite());
187  ARMARX_CHECK(std::isfinite(m_control_data.target_rot_vel));
188 
189  schedule_high_level_control_loop(control_mode::velocity);
190 }
191 
192 void
194  const float target_pos_delta_y,
195  const float target_delta_ori,
196  const float pos_reached_threshold,
197  const float ori_reached_threshold,
198  const Ice::Current& current)
199 {
200  using namespace simox::math;
201 
202  // Transform relative to global.
203  std::unique_lock lock{m_control_data.mutex};
204  synchronizeLocalClone(m_robot);
205  const Eigen::Vector2f agent_pos = m_robot->getGlobalPosition().head<2>();
206  const float agent_ori = mat4f_to_rpy(m_robot->getGlobalPose()).z();
207  lock.unlock();
208 
209  // Use moveTo.
210  moveTo(agent_pos.x() + target_pos_delta_x,
211  agent_pos.y() + target_pos_delta_y,
212  agent_ori + target_delta_ori,
213  pos_reached_threshold,
214  ori_reached_threshold,
215  current);
216 }
217 
218 void
220  const float max_rot_vel,
221  const Ice::Current&)
222 {
223  std::scoped_lock l{m_control_data.mutex};
224  m_control_data.max_vel = max_pos_vel;
225  m_control_data.max_rot_vel = max_rot_vel;
226  m_platform->setMaxVelocities(max_pos_vel, max_rot_vel);
227 }
228 
229 void
231 {
232  schedule_high_level_control_loop(control_mode::none);
233  m_platform->stopPlatform();
234 }
235 
236 void
237 armarx::ObstacleAvoidingPlatformUnit::schedule_high_level_control_loop(control_mode mode)
238 {
239  std::scoped_lock l{m_control_loop.mutex};
240 
241  // If the control mode didn't change, there's nothing to do.
242  if (m_control_loop.mode == mode)
243  {
244  return;
245  }
246 
247  // If a control loop is runnung, stop it and wait for termination.
248  if (m_control_loop.mode != mode and m_control_loop.task)
249  {
250  ARMARX_VERBOSE << "Stopping " << ::to_string(m_control_loop.mode) << " control.";
251  const bool join = true;
252  m_control_loop.task->stop(join);
253  }
254 
255  // If the new control mode is none, no new control loop needs to be created.
256  if (mode == control_mode::none)
257  {
258  ARMARX_VERBOSE << "Going into stand-by.";
259  return;
260  }
261 
262  // Start next control loop.
263  ARMARX_VERBOSE << "Starting " << ::to_string(mode) << " control.";
264  m_control_loop.mode = mode;
265  m_control_loop.task = new RunningTask<ObstacleAvoidingPlatformUnit>(
266  this, &ObstacleAvoidingPlatformUnit::high_level_control_loop);
267  m_control_loop.task->start();
268 }
269 
270 void
271 armarx::ObstacleAvoidingPlatformUnit::high_level_control_loop()
272 {
273  const control_mode mode = m_control_loop.mode;
274  ARMARX_VERBOSE << "Started " << ::to_string(mode) << " control.";
275 
276  try
277  {
278  CycleUtil cu{m_control_loop.cycle_time};
279  while (not m_control_loop.task->isStopped())
280  {
281  const velocities vels = get_velocities();
282 
283  // Debug.
285  m["err_dist"] = new Variant{vels.err_dist};
286  m["err_angular_dist"] = new Variant{vels.err_angular_dist};
287 
288  m["target_global_x"] = new Variant{vels.target_global.x()};
289  m["target_global_y"] = new Variant{vels.target_global.y()};
290  m["target_global_abs"] = new Variant{vels.target_global.norm()};
291 
292  m["target_local_x"] = new Variant{vels.target_local.x()};
293  m["target_local_y"] = new Variant{vels.target_local.y()};
294  m["target_local_abs"] = new Variant(vels.target_local.norm());
295  m["target_rot"] = new Variant{vels.target_rot};
296 
297  m["modulated_global_x"] = new Variant{vels.modulated_global.x()};
298  m["modulated_global_y"] = new Variant{vels.modulated_global.y()};
299  m["modulated_global_abs"] = new Variant{vels.modulated_global.norm()};
300 
301  m["modulated_local_x"] = new Variant{vels.modulated_local.x()};
302  m["modulated_local_y"] = new Variant{vels.modulated_local.y()};
303  m["modulated_local_abs"] = new Variant{vels.modulated_local.norm()};
304 
305  setDebugObserverChannel("ObstacleAvoidingPlatformCtrl", m);
306 
307  m_platform->move(vels.modulated_local.x(), vels.modulated_local.y(), vels.target_rot);
308  visualize(vels);
309  cu.waitForCycleDuration();
310  }
311  }
312  catch (const std::exception& e)
313  {
314  ARMARX_ERROR << "Error occured while running control loop.\n" << e.what();
315  }
316  catch (...)
317  {
318  ARMARX_ERROR << "Unknown error occured while running control loop.";
319  }
320 
321  // clear the buffer such that zero-velocity is set without delay
322  invalidate(m_control_data.vel_history);
323 
324  m_platform->move(0, 0, 0);
325  m_platform->stopPlatform();
326  m_control_loop.mode = control_mode::none;
327 
328  visualize();
329 
330  ARMARX_VERBOSE << "Stopped " << ::to_string(mode) << " control.";
331 }
332 
333 armarx::ObstacleAvoidingPlatformUnit::velocities
334 armarx::ObstacleAvoidingPlatformUnit::get_velocities()
335 {
336  using namespace simox::math;
337 
338  // Acquire control_data mutex to ensure data remains consistent.
339  std::scoped_lock l{m_control_data.mutex};
340 
341  // Update agent and get target velocities.
342  update_agent_dependent_values();
343  const Eigen::Vector2f target_vel = get_target_velocity();
344  const float target_rot_vel = get_target_rotational_velocity();
345 
346  // Apply obstacle avoidance and apply post processing to get the modulated velocity.
347  const Eigen::Vector2f modulated_vel = [this, &target_vel]
348  {
349  obstacleavoidance::Agent agent;
350  agent.safety_margin = m_control_data.agent_safety_margin;
351  agent.pos = Eigen::Vector3f{m_control_data.agent_pos.x(), m_control_data.agent_pos.y(), 0};
352  agent.desired_vel = Eigen::Vector3f{target_vel.x(), target_vel.y(), 0};
353 
354  const Eigen::Vector2f raw = m_obstacle_avoidance->modulateVelocity(agent).head<2>();
355  return post_process_vel(target_vel, norm_max(raw, m_control_data.max_vel));
356  }();
357 
358  ARMARX_CHECK(modulated_vel.allFinite()) << "Velocity contains non-finite values.";
359  ARMARX_CHECK(std::isfinite(target_rot_vel)) << "Rotation velocity is non-finite.";
360 
361  ARMARX_DEBUG << "Target velocity: " << target_vel.transpose()
362  << "; norm: " << target_vel.norm() << "; " << target_rot_vel;
363  ARMARX_DEBUG << "Modulated velocity: " << modulated_vel.transpose() << modulated_vel.norm();
364 
365  const auto r = Eigen::Rotation2D(m_control_data.agent_ori).toRotationMatrix().inverse();
366 
367  velocities vels;
368  vels.target_local = r * target_vel;
369  vels.target_global = target_vel;
370  vels.modulated_local = r * modulated_vel;
371  vels.modulated_global = modulated_vel;
372  vels.target_rot = target_rot_vel;
373  vels.err_dist = m_control_data.target_dist;
374  vels.err_angular_dist = m_control_data.target_angular_dist;
375 
376  return vels;
377 }
378 
379 Eigen::Vector2f
380 armarx::ObstacleAvoidingPlatformUnit::get_target_velocity() const
381 {
382  using namespace simox::math;
383 
384  Eigen::Vector2f uncapped_target_vel = Eigen::Vector2f::Zero();
385 
386  if (m_control_loop.mode == control_mode::position /*and not target_position_reached()*/)
387  {
388  uncapped_target_vel =
389  (m_control_data.target_pos - m_control_data.agent_pos) * m_control_data.kp;
390  }
391  else if (m_control_loop.mode == control_mode::velocity)
392  {
393  uncapped_target_vel = m_control_data.target_vel;
394  }
395 
396  ARMARX_CHECK(uncapped_target_vel.allFinite());
397 
398  return norm_max(uncapped_target_vel, m_control_data.max_vel);
399 }
400 
401 float
402 armarx::ObstacleAvoidingPlatformUnit::get_target_rotational_velocity() const
403 {
404  using namespace simox::math;
405 
406  float uncapped_target_rot_vel = 0;
407 
408  if (m_control_loop.mode == control_mode::position /*and not target_orientation_reached()*/)
409  {
410  m_rot_pid_controller.update(m_control_data.target_angular_dist, 0);
411  uncapped_target_rot_vel = -m_rot_pid_controller.getControlValue();
412  }
413  else if (m_control_loop.mode == control_mode::velocity)
414  {
415  uncapped_target_rot_vel = m_control_data.target_rot_vel;
416  }
417 
418  ARMARX_CHECK(std::isfinite(uncapped_target_rot_vel));
419 
420  return std::copysign(std::min(std::fabs(uncapped_target_rot_vel), m_control_data.max_rot_vel),
421  uncapped_target_rot_vel);
422 }
423 
424 void
425 armarx::ObstacleAvoidingPlatformUnit::update_agent_dependent_values()
426 {
427  using namespace simox::math;
428 
429  synchronizeLocalClone(m_robot);
430  m_control_data.agent_pos = m_robot->getGlobalPosition().head<2>();
431  m_control_data.agent_ori =
432  periodic_clamp<float>(mat4f_to_rpy(m_robot->getGlobalPose()).z(), -M_PI, M_PI);
433 
434  ARMARX_CHECK_GREATER(m_control_data.agent_ori, -M_PI);
435  ARMARX_CHECK_LESS(m_control_data.agent_ori, M_PI);
436 
437  // Update distances in position mode.
438  if (m_control_loop.mode == control_mode::position)
439  {
440  ARMARX_CHECK_GREATER(m_control_data.target_ori, -M_PI);
441  ARMARX_CHECK_LESS(m_control_data.target_ori, M_PI);
442  ARMARX_CHECK(m_control_data.target_pos.allFinite());
443  ARMARX_CHECK(std::isfinite(m_control_data.target_ori));
444 
445  m_control_data.target_dist = (m_control_data.target_pos - m_control_data.agent_pos).norm();
446  m_control_data.target_angular_dist = periodic_clamp<float>(
447  m_control_data.target_ori - m_control_data.agent_ori, -M_PI, M_PI);
448 
449  ARMARX_CHECK_GREATER(m_control_data.target_angular_dist, -M_PI);
450  ARMARX_CHECK_LESS(m_control_data.target_angular_dist, M_PI);
451 
452  ARMARX_DEBUG << "Distance to target: " << m_control_data.target_dist << " mm and "
453  << m_control_data.target_angular_dist << " rad.";
454  }
455  // Otherwise invalidate them.
456  else
457  {
458  invalidate(m_control_data.target_dist);
459  invalidate(m_control_data.target_angular_dist);
460  }
461 }
462 
463 bool
464 armarx::ObstacleAvoidingPlatformUnit::target_position_reached() const
465 {
466  if (m_control_loop.mode == control_mode::position)
467  {
468  return m_control_data.target_dist < m_control_data.pos_reached_threshold;
469  }
470 
471  // Cannot reach any target in non-position mode.
472  return false;
473 }
474 
475 bool
476 armarx::ObstacleAvoidingPlatformUnit::target_orientation_reached() const
477 {
478  if (m_control_loop.mode == control_mode::position)
479  {
480  return std::fabs(m_control_data.target_angular_dist) < m_control_data.ori_reached_threshold;
481  }
482 
483  // Cannot reach any target in non-position mode.
484  return false;
485 }
486 
487 bool
488 armarx::ObstacleAvoidingPlatformUnit::target_reached() const
489 {
490  if (m_control_loop.mode == control_mode::position)
491  {
492  return target_position_reached() and target_orientation_reached();
493  }
494 
495  return false;
496 }
497 
498 Eigen::Vector2f
499 armarx::ObstacleAvoidingPlatformUnit::post_process_vel(const Eigen::Vector2f& target_vel,
500  const Eigen::Vector2f& modulated_vel)
501 {
502  ARMARX_CHECK(target_vel.allFinite());
503  ARMARX_CHECK(modulated_vel.allFinite());
504 
505  // Update buffer.
506  m_control_data.vel_history.push_front(std::make_tuple(target_vel, modulated_vel));
507  const unsigned max_real_buffer_size =
508  std::max(m_control_data.amount_smoothing, m_control_data.amount_max_vel);
509  if (m_control_data.vel_history.size() > max_real_buffer_size)
510  {
511  m_control_data.vel_history.resize(max_real_buffer_size);
512  }
513 
514  // Smooth by calculating mean over the last `m_control_data.amount_smoothing` elements.
515  const Eigen::Vector2f mean_modulated_vel = calculate_mean_modulated_vel();
516 
517  const bool is_near_target = this->is_near_target(mean_modulated_vel);
518 
519  // Min velocity is determined through distance to target.
520  float min_vel =
521  is_near_target ? m_control_data.min_vel_near_target : m_control_data.min_vel_general;
522  if (target_vel.norm() < min_vel)
523  {
524  min_vel = target_vel.norm();
525  }
526 
527  // Determine max velocity by considering the coherency between the last
528  // `m_control_data.amount_max_vel` pairs of desired and modulated velocities.
529  // If the robot is almost at the goal position and no collision needs to be avoided
530  // (aka moving into the direction of the target position), we can prevent overshooting by
531  // clipping the velocity. The reference velocity is computed by a standard P-controller.
532  const float max_vel = is_near_target ? target_vel.norm() : calculate_adaptive_max_vel();
533 
534  ARMARX_CHECK(mean_modulated_vel.allFinite());
535  ARMARX_CHECK(std::isfinite(min_vel));
536  ARMARX_CHECK(std::isfinite(max_vel));
537 
538  return simox::math::norm_clamp(mean_modulated_vel, min_vel, max_vel);
539 }
540 
541 bool
542 armarx::ObstacleAvoidingPlatformUnit::is_near_target(
543  const Eigen::Vector2f& control_velocity) const noexcept
544 {
545  if (m_control_data.target_dist < m_control_data.pos_near_threshold)
546  {
547  const Eigen::Vector2f target_direction =
548  m_control_data.target_pos - m_control_data.agent_pos;
549  const Eigen::Vector2f control_direction = control_velocity / control_velocity.norm();
550 
551  const float sim = simox::math::cosine_similarity(target_direction, control_direction);
552 
553  // if almost pointing into same direction
554  if (sim > cos(M_PI_4))
555  {
556  return true;
557  }
558  }
559 
560  return false;
561 }
562 
563 Eigen::Vector2f
564 armarx::ObstacleAvoidingPlatformUnit::calculate_mean_modulated_vel() const
565 {
566  const unsigned adaptive_buffer_size = calculate_adaptive_smoothing_buffer_size();
567  const unsigned elements =
568  std::min<unsigned>(m_control_data.vel_history.size(), adaptive_buffer_size);
569  auto end = m_control_data.vel_history.begin();
570  std::advance(end, elements);
571 
572  const auto transform =
573  [elements](const Eigen::Vector2f& vel,
574  const std::tuple<Eigen::Vector2f, Eigen::Vector2f>& vels) -> Eigen::Vector2f
575  { return vel + std::get<1>(vels) * (1. / elements); };
576 
577  return std::accumulate(
578  m_control_data.vel_history.begin(), end, Eigen::Vector2f{0, 0}, transform);
579 }
580 
581 unsigned
582 armarx::ObstacleAvoidingPlatformUnit::calculate_adaptive_smoothing_buffer_size() const
583 {
584  // buffer_size(min_buffer_size_dist) = min_buffer_size
585  const float min_buffer_size_dist = 200;
586  const float min_buffer_size = 3;
587  // buffer_size(max_buffer_size_dist) = max_buffer_size
588  const float max_buffer_size_dist = 1500;
589  const float max_buffer_size = m_control_data.amount_smoothing;
590 
591  ARMARX_CHECK_LESS(min_buffer_size, max_buffer_size);
592 
593  if (m_control_loop.mode == control_mode::position)
594  {
595  // Given the two points, calculate m and b in: f(x) = m * x + b
596  const float m =
597  (max_buffer_size - min_buffer_size) / (max_buffer_size_dist - min_buffer_size_dist);
598  const float b = min_buffer_size - (m * min_buffer_size_dist);
599 
600 
601  // Calculate buffer size and clamp value if need be.
602  return static_cast<unsigned>(
603  std::clamp(m * m_control_data.target_dist + b, min_buffer_size, max_buffer_size));
604  }
605  else
606  {
607  // In velocity control mode, don't smooth that much.
608  return min_buffer_size;
609  }
610 }
611 
612 float
613 armarx::ObstacleAvoidingPlatformUnit::calculate_adaptive_max_vel() const
614 {
615  using namespace simox::math;
616 
617  if (m_control_loop.mode == control_mode::position and m_control_data.adaptive_max_vel_exp > 0)
618  {
619  std::vector<float> angular_similarities;
620 
621  const unsigned elements =
622  std::min<unsigned>(m_control_data.vel_history.size(), m_control_data.amount_max_vel);
623  auto end = m_control_data.vel_history.begin();
624  std::advance(end, elements);
625 
626  const auto transform =
627  [elements](const std::tuple<Eigen::Vector2f, Eigen::Vector2f>& vels) -> float
628  {
629  const auto& [desired_vel, modulated_vel] = vels;
630 
631  if (desired_vel.isZero() and modulated_vel.isZero())
632  {
633  return 1;
634  }
635  else if (desired_vel.isZero() xor modulated_vel.isZero())
636  {
637  return -1;
638  }
639 
640  return angular_similarity(desired_vel, modulated_vel) / elements;
641  };
642 
643  // TODO: GCC 9+: Use transform_reduce instead of transform + accumulate.
644  // const float mean_angular_similarity = std::transform_reduce(
645  // m_control_data.vel_history.begin(), end,
646  // 0,
647  // std::plus<float>(),
648  // transform);
649 
650  std::transform(m_control_data.vel_history.begin(),
651  end,
652  std::back_inserter(angular_similarities),
653  transform);
654 
655  const float mean_angular_similarity = std::accumulate(
656  angular_similarities.begin(), angular_similarities.end(), 0.f, std::plus<float>());
657  const float max_vel_factor =
658  std::pow(mean_angular_similarity, m_control_data.adaptive_max_vel_exp);
659 
660  return max_vel_factor * m_control_data.max_vel;
661  }
662  else
663  {
664  return m_control_data.max_vel;
665  }
666 }
667 
668 void
669 armarx::ObstacleAvoidingPlatformUnit::visualize()
670 {
671  const Eigen::Vector2f zero = Eigen::Vector2f::Zero();
672  velocities vels;
673  vels.target_local = zero;
674  vels.target_global = zero;
675  vels.modulated_local = zero;
676  vels.modulated_global = zero;
677  vels.target_rot = 0;
678 
679  visualize(vels);
680 }
681 
682 void
683 armarx::ObstacleAvoidingPlatformUnit::visualize(const velocities& vels)
684 {
685  using namespace armarx::viz;
686 
687  if (not m_viz.enabled)
688  {
689  return;
690  }
691 
692  Eigen::Vector3f agent_pos{m_control_data.agent_pos.x(), m_control_data.agent_pos.y(), 0};
693 
694  // Progress. Only draw in position control mode.
695  Layer l_prog = arviz.layer("progress");
696  if (m_control_loop.mode == control_mode::position)
697  {
698  const float min_keypoint_dist = 50;
699 
700  // If no start is set, use current agent pos.
701  if (not m_viz.start.allFinite())
702  {
703  m_viz.start = agent_pos;
704  }
705 
706  const Eigen::Vector3f& last_keypoint_pos =
707  m_viz.path.size() >= 1 ? m_viz.path.back() : m_viz.start;
708 
709  // Keep a certain distance between path keypoints.
710  if ((last_keypoint_pos - agent_pos).norm() > min_keypoint_dist)
711  {
712  m_viz.path.push_back(agent_pos);
713  }
714 
715  // Draw path.
716  if (not target_reached())
717  {
718  // Start.
719  l_prog.add(
720  Sphere{"start"}.position(m_viz.start).color(Color::cyan(255, 64)).radius(40));
721 
722  // Path.
723  for (unsigned i = 0; i < m_viz.path.size(); ++i)
724  {
725  l_prog.add(Sphere{"path_" + std::to_string(i + 1)}
726  .position(m_viz.path[i])
727  .color(Color::magenta(255, 128))
728  .radius(20));
729  }
730 
731  // Goal.
732  const Eigen::Vector3f target{
733  m_control_data.target_pos.x(), m_control_data.target_pos.y(), 0};
734  l_prog.add(
735  Arrow{"goal"}
736  .fromTo(target + Eigen::Vector3f{0, 0, 220}, target + Eigen::Vector3f{0, 0, 40})
737  .color(Color::red(255, 128))
738  .width(20));
739  }
740  else
741  {
742  m_viz.path.clear();
743  invalidate(m_viz.start);
744  }
745  }
746 
747  // Velocities.
748  Layer l_vels = arviz.layer("velocities");
749  if (m_control_loop.mode != control_mode::none)
750  {
751  const float min_velocity = 15;
752  const Eigen::Vector3f from1{agent_pos + Eigen::Vector3f{0, 0, 2000}};
753  const Eigen::Vector3f from2 = from1 + Eigen::Vector3f{0, 0, 200};
754  const Eigen::Vector3f original{vels.target_global.x(), vels.target_global.y(), 0};
755  const Eigen::Vector3f modulated{vels.modulated_global.x(), vels.modulated_global.y(), 0};
756 
757  if (original.norm() > min_velocity)
758  {
759  l_vels.add(Arrow{"original"}
760  .fromTo(from1, from1 + original * 5)
761  .color(Color::green(255, 128))
762  .width(25));
763  }
764 
765  if (modulated.norm() > min_velocity)
766  {
767  l_vels.add(Arrow{"modulated"}
768  .fromTo(from2, from2 + modulated * 5)
769  .color(Color::cyan(255, 128))
770  .width(25));
771  }
772  }
773 
774  // Agent.
775  Layer l_agnt = arviz.layer("agent");
776  if (m_control_loop.mode != control_mode::none)
777  {
778  l_agnt.add(Sphere{"agent"}.position(agent_pos).color(Color::red(255, 128)).radius(50));
779 
780  // Agent safety margin.
781  if (m_control_data.agent_safety_margin > 0)
782  {
783  l_agnt.add(Cylinder{"agent_safety_margin"}
784  .pose(simox::math::pos_rpy_to_mat4f(agent_pos, -M_PI_2, 0, 0))
785  .color(Color::red(255, 64))
786  .radius(m_control_data.agent_safety_margin)
787  .height(2));
788  }
789  }
790 
791  arviz.commit({l_prog, l_vels, l_agnt});
792 }
793 
796 {
798 
799  def->component(m_platform, "Platform");
800  def->component(m_obstacle_avoidance, "PlatformObstacleAvoidance");
801 
802  // Settings.
803  def->optional(m_control_data.adaptive_max_vel_exp,
804  "adaptive_max_vel_exponent",
805  "Adaptive max vel exponent. This throttles the max_vel adaptively "
806  "depending on the angle between target velocity and modulated velocity. "
807  "0 = disable.");
808  def->optional(m_control_data.min_vel_near_target,
809  "min_vel_near_target",
810  "Velocity in [mm/s] "
811  "the robot should at least set when near the target");
812  def->optional(m_control_data.min_vel_general,
813  "min_vel_general",
814  "Velocity in [mm/s] the robot "
815  "should at least set on general");
816  def->optional(m_control_data.pos_near_threshold,
817  "pos_near_threshold",
818  "Distance in [mm] after "
819  "which the robot is considered to be near the target for min velocity, "
820  "smoothing, etc.");
821 
822  // Control parameters.
823  def->optional(m_control_data.kp, "control.pos.kp");
824  def->optional(m_rot_pid_controller.Kp, "control.rot.kp");
825  def->optional(m_rot_pid_controller.Ki, "control.rot.ki");
826  def->optional(m_rot_pid_controller.Kd, "control.rot.kd");
827  def->optional(m_control_loop.cycle_time, "control.pose.cycle_time", "Control loop cycle time.");
828 
829  // Obstacle avoidance parameter.
830  def->optional(m_control_data.agent_safety_margin, "doa.agent_safety_margin");
831 
832  return def;
833 }
armarx::ObstacleAvoidingPlatformUnit::control_mode
control_mode
Definition: ObstacleAvoidingPlatformUnit.h:66
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
Eigen
Definition: Elements.h:32
armarx::StringVariantBaseMap
std::map< std::string, VariantBasePtr > StringVariantBaseMap
Definition: ManagedIceObject.h:110
armarx::ObstacleAvoidingPlatformUnit::onInitPlatformUnit
virtual void onInitPlatformUnit() override
Definition: ObstacleAvoidingPlatformUnit.cpp:101
armarx::ObstacleAvoidingPlatformUnit::getDefaultName
virtual std::string getDefaultName() const override
Retrieve default name of component.
Definition: ObstacleAvoidingPlatformUnit.cpp:139
armarx::ObstacleAvoidingPlatformUnit::moveRelative
virtual void moveRelative(float target_pos_delta_x, float target_pos_delta_y, float target_delta_ori, float pos_reached_threshold, float ori_reached_threshold, const Ice::Current &=Ice::Current{}) override
Definition: ObstacleAvoidingPlatformUnit.cpp:193
armarx::ObstacleAvoidingPlatformUnit::move
virtual void move(float target_vel_x, float target_vel_y, float target_rot_vel, const Ice::Current &=Ice::Current{}) override
Definition: ObstacleAvoidingPlatformUnit.cpp:171
armarx::ObstacleAvoidingPlatformUnit::control_mode::none
@ none
boost::target
Vertex target(const detail::edge_base< Directed, Vertex > &e, const PCG &)
Definition: point_cloud_graph.h:668
ARMARX_CHECK_GREATER
#define ARMARX_CHECK_GREATER(lhs, rhs)
This macro evaluates whether lhs is greater (>) than rhs and if it turns out to be false it will thro...
Definition: ExpressionException.h:116
ObstacleAvoidingPlatformUnit.h
armarx::viz::Arrow
Definition: Elements.h:196
ARMARX_CHECK_LESS
#define ARMARX_CHECK_LESS(lhs, rhs)
This macro evaluates whether lhs is less (<) than rhs and if it turns out to be false it will throw a...
Definition: ExpressionException.h:102
armarx::viz::Cylinder::height
Cylinder & height(float h)
Definition: Elements.h:84
armarx::viz::Layer::add
void add(ElementT const &element)
Definition: Layer.h:31
return
return() armarx_set_target("PointCloudViewerGuiPlugin") find_package(MPI REQUIRED) find_package(VTK REQUIRED) find_package(Coin QUIET) armarx_build_if(Coin_FOUND "Coin 3D not found") set(COMPONENT_LIBS VisionXInterfaces VisionXCore VisionXPointCloud VTK
Definition: CMakeLists.txt:1
armarx::viz::Sphere
Definition: Elements.h:133
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
clamp
double clamp(double x, double a, double b)
Definition: point.hpp:136
armarx::ObstacleAvoidingPlatformUnit::onExitPlatformUnit
virtual void onExitPlatformUnit() override
Definition: ObstacleAvoidingPlatformUnit.cpp:129
armarx::viz::ElementOps::position
DerivedT & position(float x, float y, float z)
Definition: ElementOps.h:136
std::isfinite
bool isfinite(const std::vector< T, Ts... > &v)
Definition: algorithm.h:366
armarx::ObstacleAvoidingPlatformUnit::onStartPlatformUnit
virtual void onStartPlatformUnit() override
Definition: ObstacleAvoidingPlatformUnit.cpp:109
M_PI
#define M_PI
Definition: MathTools.h:17
armarx::ObstacleAvoidingPlatformUnit::control_mode::position
@ position
armarx::viz::Arrow::width
Arrow & width(float w)
Definition: Elements.h:211
armarx::ObstacleAvoidingPlatformUnit::setMaxVelocities
virtual void setMaxVelocities(float max_pos_vel, float max_rot_vel, const Ice::Current &=Ice::Current{}) override
Definition: ObstacleAvoidingPlatformUnit.cpp:219
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::viz::Cylinder
Definition: Elements.h:71
armarx::viz::Sphere::radius
Sphere & radius(float r)
Definition: Elements.h:138
armarx::ObstacleAvoidingPlatformUnit::default_name
static const std::string default_name
Definition: ObstacleAvoidingPlatformUnit.h:202
max
T max(T t1, T t2)
Definition: gdiam.h:51
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
armarx::ObstacleAvoidingPlatformUnit::~ObstacleAvoidingPlatformUnit
virtual ~ObstacleAvoidingPlatformUnit() override
armarx::viz::Color::red
static Color red(int r=255, int a=255)
Definition: Color.h:88
armarx::viz::Color::cyan
static Color cyan(int c=255, int a=255)
Green + Blue.
Definition: Color.h:109
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::transform
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT >>
Convenience function (with less typing) to transform a container of type InputT into the same contain...
Definition: algorithm.h:351
armarx::viz::Arrow::fromTo
Arrow & fromTo(const Eigen::Vector3f &from, const Eigen::Vector3f &to)
Definition: Elements.h:219
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
armarx::navigation::algorithms::visualize
void visualize(const algorithms::Costmap &costmap, viz::Layer &layer, const std::string &name, const float zOffset)
Definition: visualization.cpp:25
armarx::ObstacleAvoidingPlatformUnit::ObstacleAvoidingPlatformUnit
ObstacleAvoidingPlatformUnit()
armarx::viz::Color::magenta
static Color magenta(int m=255, int a=255)
Red + Blue.
Definition: Color.h:123
armarx::viz::ElementOps::pose
DerivedT & pose(Eigen::Matrix4f const &pose)
Definition: ElementOps.h:176
armarx::ObstacleAvoidingPlatformUnit::moveTo
virtual void moveTo(float target_pos_x, float target_pos_y, float target_ori, float pos_reached_threshold, float ori_reached_threshold, const Ice::Current &=Ice::Current{}) override
Definition: ObstacleAvoidingPlatformUnit.cpp:145
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::viz::ElementOps::color
DerivedT & color(Color color)
Definition: ElementOps.h:218
armarx::ObstacleAvoidingPlatformUnit::createPropertyDefinitions
virtual PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: ObstacleAvoidingPlatformUnit.cpp:795
armarx::ManagedIceObject::getName
std::string getName() const
Retrieve name of object.
Definition: ManagedIceObject.cpp:108
armarx::viz::Layer::size
std::size_t size() const noexcept
Definition: Layer.h:52
armarx::ObstacleAvoidingPlatformUnit::control_mode::velocity
@ velocity
armarx::viz::Color::green
static Color green(int g=255, int a=255)
Definition: Color.h:94
min
T min(T t1, T t2)
Definition: gdiam.h:44
armarx::ObstacleAvoidingPlatformUnit::stopPlatform
virtual void stopPlatform(const Ice::Current &=Ice::Current{}) override
Definition: ObstacleAvoidingPlatformUnit.cpp:230
armarx::viz::Layer
Definition: Layer.h:12
Variant.h
armarx::PlatformUnit::createPropertyDefinitions
PropertyDefinitionsPtr createPropertyDefinitions() override
Definition: PlatformUnit.cpp:35
armarx::viz
This file is part of ArmarX.
Definition: ArVizStorage.cpp:418
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
norm
double norm(const Point &a)
Definition: point.hpp:102