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
43namespace
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
100void
102{
103 ARMARX_DEBUG << "Initializing " << getName() << ".";
104
105 ARMARX_DEBUG << "Initialized " << getName() << ".";
106}
107
108void
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
128void
130{
131 ARMARX_DEBUG << "Exiting " << getName() << ".";
132
133 schedule_high_level_control_loop(control_mode::none);
134
135 ARMARX_DEBUG << "Exited " << getName() << ".";
136}
137
138std::string
143
144void
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
170void
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
192void
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
218void
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
229void
231{
232 schedule_high_level_control_loop(control_mode::none);
233 m_platform->stopPlatform();
234}
235
236void
237armarx::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
270void
271armarx::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
333armarx::ObstacleAvoidingPlatformUnit::velocities
334armarx::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
379Eigen::Vector2f
380armarx::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
401float
402armarx::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
424void
425armarx::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
463bool
464armarx::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
475bool
476armarx::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
487bool
488armarx::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
498Eigen::Vector2f
499armarx::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
541bool
542armarx::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
563Eigen::Vector2f
564armarx::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
581unsigned
582armarx::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
612float
613armarx::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
668void
669armarx::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
682void
683armarx::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}
std::string to_string(BLEProthesisInterface::State s)
#define M_PI
Definition MathTools.h:17
This util class helps with keeping a cycle time during a control cycle.
Definition CycleUtil.h:41
std::string getName() const
Retrieve name of object.
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
virtual ~ObstacleAvoidingPlatformUnit() override
virtual PropertyDefinitionsPtr createPropertyDefinitions() override
virtual void stopPlatform(const Ice::Current &=Ice::Current{}) override
virtual void move(float target_vel_x, float target_vel_y, float target_rot_vel, const Ice::Current &=Ice::Current{}) override
virtual void setMaxVelocities(float max_pos_vel, float max_rot_vel, const Ice::Current &=Ice::Current{}) override
virtual std::string getDefaultName() const override
Retrieve default name of component.
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
PropertyDefinitionsPtr createPropertyDefinitions() override
bool synchronizeLocalClone(const VirtualRobot::RobotPtr &robot) const
VirtualRobot::RobotPtr addRobot(const std::string &id, const VirtualRobot::RobotPtr &robot, const VirtualRobot::RobotNodeSetPtr &rns={}, const VirtualRobot::RobotNodePtr &node={})
The Variant class is described here: Variants.
Definition Variant.h:224
#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...
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#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...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
double v(double t, double v0, double a0, double j)
Definition CtrlUtil.h:39
void visualize(const algorithms::Costmap &costmap, viz::Layer &layer, const std::string &name, const float zOffset)
std::map< std::string, VariantBasePtr > StringVariantBaseMap
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
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
const std::string & to_string(const std::string &s)
Vertex target(const detail::edge_base< Directed, Vertex > &e, const PCG &)
bool isfinite(const std::vector< T, Ts... > &v)
Definition algorithm.h:366
double norm(const Point &a)
Definition point.hpp:102
void add(ElementT const &element)
Definition Layer.h:31