34 #include <Eigen/Geometry>
37 #include <SimoxUtility/math.h>
38 #include <VirtualRobot/Nodes/RobotNode.h>
39 #include <VirtualRobot/Safety.h>
50 v = std::numeric_limits<float>::infinity();
54 invalidate(Eigen::Vector2f&
v)
56 v.x() = std::numeric_limits<float>::infinity();
57 v.y() = std::numeric_limits<float>::infinity();
61 invalidate(Eigen::Vector3f&
v)
63 v.x() = std::numeric_limits<float>::infinity();
64 v.y() = std::numeric_limits<float>::infinity();
65 v.z() = std::numeric_limits<float>::infinity();
70 invalidate(std::deque<T>& d)
113 if (!hasRobot(
"robot"))
115 m_robot = addRobot(
"robot", VirtualRobot::RobotIO::eStructure);
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);
132 schedule_high_level_control_loop(control_mode::none);
145 const float target_pos_y,
146 const float target_ori,
147 const float pos_reached_threshold,
148 const float ori_reached_threshold,
151 using namespace simox::math;
153 std::scoped_lock l{m_control_data.mutex};
155 m_control_data.target_pos = Eigen::Vector2f{target_pos_x, target_pos_y};
156 m_control_data.target_ori = periodic_clamp<float>(target_ori, -
M_PI,
M_PI);
157 m_control_data.pos_reached_threshold = pos_reached_threshold;
158 m_control_data.ori_reached_threshold = ori_reached_threshold;
160 invalidate(m_control_data.target_vel);
161 invalidate(m_control_data.target_rot_vel);
163 m_rot_pid_controller.reset();
165 schedule_high_level_control_loop(control_mode::position);
170 const float target_vel_y,
171 const float target_rot_vel,
174 using namespace simox::math;
176 std::scoped_lock l{m_control_data.mutex};
178 m_control_data.target_vel = Eigen::Vector2f{target_vel_x, target_vel_y};
179 m_control_data.target_rot_vel = periodic_clamp<float>(target_rot_vel, -
M_PI,
M_PI);
181 invalidate(m_control_data.target_pos);
182 invalidate(m_control_data.target_ori);
187 schedule_high_level_control_loop(control_mode::velocity);
192 const float target_pos_delta_y,
193 const float target_delta_ori,
194 const float pos_reached_threshold,
195 const float ori_reached_threshold,
196 const Ice::Current& current)
198 using namespace simox::math;
201 std::unique_lock lock{m_control_data.mutex};
202 synchronizeLocalClone(m_robot);
203 const Eigen::Vector2f agent_pos = m_robot->getGlobalPosition().head<2>();
204 const float agent_ori = mat4f_to_rpy(m_robot->getGlobalPose()).z();
208 moveTo(agent_pos.x() + target_pos_delta_x,
209 agent_pos.y() + target_pos_delta_y,
210 agent_ori + target_delta_ori,
211 pos_reached_threshold,
212 ori_reached_threshold,
222 max_pos_vel =
std::max(max_pos_vel, 0.
F);
223 max_rot_vel =
std::max(max_rot_vel, 0.
F);
225 std::scoped_lock l{m_control_data.mutex};
226 m_control_data.max_vel = max_pos_vel;
227 m_control_data.max_rot_vel = max_rot_vel;
228 m_platform->setMaxVelocities(max_pos_vel, max_rot_vel);
234 schedule_high_level_control_loop(control_mode::none);
235 m_platform->stopPlatform();
239 armarx::ObstacleAwarePlatformUnit::schedule_high_level_control_loop(control_mode mode)
241 std::scoped_lock l{m_control_loop.mutex};
244 if (m_control_loop.mode == mode)
250 if (m_control_loop.mode != mode and m_control_loop.task)
253 const bool join =
true;
254 m_control_loop.task->stop(join);
258 if (mode == control_mode::none)
266 m_control_loop.mode = mode;
267 m_control_loop.task =
new RunningTask<ObstacleAwarePlatformUnit>(
268 this, &ObstacleAwarePlatformUnit::high_level_control_loop);
269 m_control_loop.task->start();
273 armarx::ObstacleAwarePlatformUnit::high_level_control_loop()
275 const control_mode mode = m_control_loop.mode;
280 CycleUtil cu{m_control_loop.cycle_time};
281 while (not m_control_loop.task->isStopped())
283 const velocities vels = get_velocities();
287 m[
"err_dist"] =
new Variant{vels.err_dist};
288 m[
"err_angular_dist"] =
new Variant{vels.err_angular_dist};
290 m[
"target_global_x"] =
new Variant{vels.target_global.x()};
291 m[
"target_global_y"] =
new Variant{vels.target_global.y()};
292 m[
"target_global_abs"] =
new Variant{vels.target_global.norm()};
294 m[
"target_local_x"] =
new Variant{vels.target_local.x()};
295 m[
"target_local_y"] =
new Variant{vels.target_local.y()};
296 m[
"target_local_abs"] =
new Variant(vels.target_local.norm());
297 m[
"target_rot"] =
new Variant{vels.target_rot};
299 m[
"modulated_global_x"] =
new Variant{vels.modulated_global.x()};
300 m[
"modulated_global_y"] =
new Variant{vels.modulated_global.y()};
301 m[
"modulated_global_abs"] =
new Variant{vels.modulated_global.norm()};
303 m[
"modulated_local_x"] =
new Variant{vels.modulated_local.x()};
304 m[
"modulated_local_y"] =
new Variant{vels.modulated_local.y()};
305 m[
"modulated_local_abs"] =
new Variant{vels.modulated_local.norm()};
319 setDebugObserverChannel(
"ObstacleAwarePlatformCtrl", m);
321 m_platform->move(vels.modulated_local.x(), vels.modulated_local.y(), vels.target_rot);
323 cu.waitForCycleDuration();
326 catch (
const std::exception& e)
328 ARMARX_ERROR <<
"Error occured while running control loop.\n" << e.what();
332 ARMARX_ERROR <<
"Unknown error occured while running control loop.";
335 m_platform->move(0, 0, 0);
336 m_platform->stopPlatform();
337 m_control_loop.mode = control_mode::none;
344 armarx::ObstacleAwarePlatformUnit::velocities
345 armarx::ObstacleAwarePlatformUnit::get_velocities()
347 using namespace simox::math;
350 std::scoped_lock l{m_control_data.mutex};
352 update_agent_dependent_values();
353 const Eigen::Vector2f target_vel = get_target_velocity();
354 const float target_rot_vel = get_target_rotational_velocity();
356 const Eigen::Vector2f extents =
357 Eigen::Affine3f(m_robot->getRobotNode(
"PlatformCornerFrontLeft")->getPoseInRootFrame())
362 const Eigen::Vector2f modulated_vel = [
this, &target_vel, &extents]
365 ARMARX_DEBUG <<
"Circle approximation: " << circle.radius;
366 m_viz.boundingCircle = circle;
367 const float distance = m_obsman->distanceToObstacle(
368 m_control_data.agent_pos , circle.radius, m_control_data.target_pos);
375 const Eigen::Vector2f vel = modifier * target_vel;
376 return vel.norm() > 20 ? vel : Eigen::Vector2f{0, 0};
379 ARMARX_CHECK(modulated_vel.allFinite()) <<
"Velocity contains non-finite values.";
382 ARMARX_DEBUG <<
"Target velocity: " << target_vel.transpose()
383 <<
"; norm: " << target_vel.norm() <<
"; " << target_rot_vel;
384 ARMARX_DEBUG <<
"Modulated velocity: " << modulated_vel.transpose() << modulated_vel.norm();
386 const auto r = Eigen::Rotation2D(m_control_data.agent_ori).toRotationMatrix().inverse();
389 vels.target_local = r * target_vel;
390 vels.target_global = target_vel;
391 vels.modulated_local = r * modulated_vel;
392 vels.modulated_global = modulated_vel;
393 vels.target_rot = target_rot_vel;
394 vels.err_dist = m_control_data.target_dist;
395 vels.err_angular_dist = m_control_data.target_angular_dist;
401 armarx::ObstacleAwarePlatformUnit::get_target_velocity()
const
403 using namespace simox::math;
405 Eigen::Vector2f uncapped_target_vel = Eigen::Vector2f::Zero();
407 if (m_control_loop.mode == control_mode::position )
409 uncapped_target_vel =
410 (m_control_data.target_pos - m_control_data.agent_pos) * m_control_data.kp;
412 else if (m_control_loop.mode == control_mode::velocity)
414 uncapped_target_vel = m_control_data.target_vel;
419 return norm_max(uncapped_target_vel, m_control_data.max_vel);
423 armarx::ObstacleAwarePlatformUnit::get_target_rotational_velocity()
const
425 using namespace simox::math;
427 float uncapped_target_rot_vel = 0;
429 if (m_control_loop.mode == control_mode::position )
431 m_rot_pid_controller.update(m_control_data.agent_ori, m_control_data.target_ori);
432 uncapped_target_rot_vel = m_rot_pid_controller.getControlValue();
434 else if (m_control_loop.mode == control_mode::velocity)
436 uncapped_target_rot_vel = m_control_data.target_rot_vel;
442 uncapped_target_rot_vel, -m_control_data.max_rot_vel, m_control_data.max_rot_vel);
449 armarx::ObstacleAwarePlatformUnit::update_agent_dependent_values()
451 using namespace simox::math;
453 synchronizeLocalClone(m_robot);
454 m_control_data.agent_pos = m_robot->getGlobalPosition().head<2>();
455 m_control_data.agent_ori =
456 periodic_clamp<float>(mat4f_to_rpy(m_robot->getGlobalPose()).z(), -
M_PI,
M_PI);
462 if (m_control_loop.mode == control_mode::position)
469 m_control_data.target_dist = (m_control_data.target_pos - m_control_data.agent_pos).
norm();
470 m_control_data.target_angular_dist = periodic_clamp<float>(
471 m_control_data.target_ori - m_control_data.agent_ori, -
M_PI,
M_PI);
476 ARMARX_DEBUG <<
"Distance to target: " << m_control_data.target_dist <<
" mm and "
477 << m_control_data.target_angular_dist <<
" rad.";
482 invalidate(m_control_data.target_dist);
483 invalidate(m_control_data.target_angular_dist);
488 armarx::ObstacleAwarePlatformUnit::target_position_reached()
const
490 if (m_control_loop.mode == control_mode::position)
492 return m_control_data.target_dist < m_control_data.pos_reached_threshold;
500 armarx::ObstacleAwarePlatformUnit::target_orientation_reached()
const
502 if (m_control_loop.mode == control_mode::position)
504 return std::fabs(m_control_data.target_angular_dist) < m_control_data.ori_reached_threshold;
512 armarx::ObstacleAwarePlatformUnit::target_reached()
const
514 if (m_control_loop.mode == control_mode::position)
516 return target_position_reached() and target_orientation_reached();
523 armarx::ObstacleAwarePlatformUnit::is_near_target(
524 const
Eigen::Vector2f& control_velocity) const noexcept
526 if (m_control_data.target_dist < m_control_data.pos_near_threshold)
528 const Eigen::Vector2f target_direction =
529 m_control_data.target_pos - m_control_data.agent_pos;
530 const Eigen::Vector2f control_direction = control_velocity / control_velocity.norm();
532 const float sim = simox::math::cosine_similarity(target_direction, control_direction);
535 if (sim > cos(M_PI_4))
545 armarx::ObstacleAwarePlatformUnit::visualize()
547 const Eigen::Vector2f zero = Eigen::Vector2f::Zero();
549 vels.target_local = zero;
550 vels.target_global = zero;
551 vels.modulated_local = zero;
552 vels.modulated_global = zero;
559 armarx::ObstacleAwarePlatformUnit::visualize(
const velocities& vels)
563 if (not m_viz.enabled)
568 Eigen::Vector3f agent_pos{m_control_data.agent_pos.x(), m_control_data.agent_pos.y(), 0};
571 Layer l_prog = arviz.layer(
"progress");
572 if (m_control_loop.mode == control_mode::position)
574 const float min_keypoint_dist = 50;
580 .pose(simox::math::pos_rpy_to_mat4f(agent_pos, -M_PI_2, 0, 0) *
581 Eigen::Isometry3f(Eigen::Translation3f(0, -1000, 0)).matrix())
582 .radius(m_viz.boundingCircle.radius)
587 if (not m_viz.start.allFinite())
589 m_viz.start = agent_pos;
592 const Eigen::Vector3f& last_keypoint_pos =
593 m_viz.path.size() >= 1 ? m_viz.path.back() : m_viz.start;
596 if ((last_keypoint_pos - agent_pos).
norm() > min_keypoint_dist)
598 m_viz.path.push_back(agent_pos);
602 if (not target_reached())
609 for (
unsigned i = 0; i < m_viz.path.size(); ++i)
612 .position(m_viz.path[i])
618 const Eigen::Vector3f
target{
619 m_control_data.target_pos.x(), m_control_data.target_pos.y(), 0};
629 invalidate(m_viz.start);
634 Layer l_vels = arviz.layer(
"velocities");
635 if (m_control_loop.mode != control_mode::none)
637 const float min_velocity = 15;
638 const Eigen::Vector3f from1{agent_pos + Eigen::Vector3f{0, 0, 2000}};
639 const Eigen::Vector3f from2 = from1 + Eigen::Vector3f{0, 0, 200};
640 const Eigen::Vector3f original{vels.target_global.x(), vels.target_global.y(), 0};
641 const Eigen::Vector3f modulated{vels.modulated_global.x(), vels.modulated_global.y(), 0};
643 if (original.norm() > min_velocity)
646 .
fromTo(from1, from1 + original * 5)
651 if (modulated.norm() > min_velocity)
654 .
fromTo(from2, from2 + modulated * 5)
663 Layer l_agnt = arviz.layer(
"agent");
664 if (m_control_loop.mode != control_mode::none)
669 if (m_control_data.agent_safety_margin > 0)
672 .
pose(simox::math::pos_rpy_to_mat4f(agent_pos, -M_PI_2, 0, 0))
674 .radius(m_control_data.agent_safety_margin)
679 arviz.commit({l_prog, l_vels, l_agnt});
687 def->component(m_platform,
"Platform");
688 def->component(m_obsman,
"ObstacleAvoidingPlatformUnit");
691 def->optional(m_control_data.min_vel_near_target,
692 "min_vel_near_target",
693 "Velocity in [mm/s] "
694 "the robot should at least set when near the target");
695 def->optional(m_control_data.min_vel_general,
697 "Velocity in [mm/s] the robot "
698 "should at least set on general");
699 def->optional(m_control_data.pos_near_threshold,
700 "pos_near_threshold",
701 "Distance in [mm] after "
702 "which the robot is considered to be near the target for min velocity, "
706 def->optional(m_control_data.kp,
"control.pos.kp");
707 def->optional(m_rot_pid_controller.Kp,
"control.rot.kp");
708 def->optional(m_rot_pid_controller.Ki,
"control.rot.ki");
709 def->optional(m_rot_pid_controller.Kd,
"control.rot.kd");
710 def->optional(m_control_loop.cycle_time,
"control.pose.cycle_time",
"Control loop cycle time.");
713 def->optional(m_control_data.agent_safety_margin,
"doa.agent_safety_margin");