35 #include <Eigen/Geometry>
38 #include <SimoxUtility/math.h>
50 v = std::numeric_limits<float>::infinity();
55 invalidate(Eigen::Vector2f&
v)
57 v.x() = std::numeric_limits<float>::infinity();
58 v.y() = std::numeric_limits<float>::infinity();
63 invalidate(Eigen::Vector3f&
v)
65 v.x() = std::numeric_limits<float>::infinity();
66 v.y() = std::numeric_limits<float>::infinity();
67 v.z() = std::numeric_limits<float>::infinity();
71 void invalidate(std::deque<T>& d)
119 if (!hasRobot(
"robot"))
121 m_robot = addRobot(
"robot", VirtualRobot::RobotIO::eStructure);
124 invalidate(m_control_data.target_vel);
125 invalidate(m_control_data.target_rot_vel);
126 invalidate(m_control_data.target_pos);
127 invalidate(m_control_data.target_ori);
128 invalidate(m_viz.start);
139 schedule_high_level_control_loop(control_mode::none);
155 const float target_pos_x,
156 const float target_pos_y,
157 const float target_ori,
158 const float pos_reached_threshold,
159 const float ori_reached_threshold,
162 using namespace simox::math;
164 std::scoped_lock l{m_control_data.mutex};
166 m_control_data.target_pos = Eigen::Vector2f{target_pos_x, target_pos_y};
167 m_control_data.target_ori = periodic_clamp<float>(target_ori, -
M_PI,
M_PI);
168 m_control_data.pos_reached_threshold = pos_reached_threshold;
169 m_control_data.ori_reached_threshold = ori_reached_threshold;
171 invalidate(m_control_data.target_vel);
172 invalidate(m_control_data.target_rot_vel);
174 m_rot_pid_controller.reset();
176 schedule_high_level_control_loop(control_mode::position);
182 const float target_vel_x,
183 const float target_vel_y,
184 const float target_rot_vel,
187 using namespace simox::math;
189 std::scoped_lock l{m_control_data.mutex};
191 m_control_data.target_vel = Eigen::Vector2f{target_vel_x, target_vel_y};
192 m_control_data.target_rot_vel = periodic_clamp<float>(target_rot_vel, -
M_PI,
M_PI);
194 invalidate(m_control_data.target_pos);
195 invalidate(m_control_data.target_ori);
200 schedule_high_level_control_loop(control_mode::velocity);
206 const float target_pos_delta_x,
207 const float target_pos_delta_y,
208 const float target_delta_ori,
209 const float pos_reached_threshold,
210 const float ori_reached_threshold,
211 const Ice::Current& current)
213 using namespace simox::math;
216 std::unique_lock lock{m_control_data.mutex};
217 synchronizeLocalClone(m_robot);
218 const Eigen::Vector2f agent_pos = m_robot->getGlobalPosition().head<2>();
219 const float agent_ori = mat4f_to_rpy(m_robot->getGlobalPose()).z();
224 agent_pos.x() + target_pos_delta_x,
225 agent_pos.y() + target_pos_delta_y,
226 agent_ori + target_delta_ori,
227 pos_reached_threshold,
228 ori_reached_threshold,
240 max_pos_vel =
std::max(max_pos_vel, 0.
F);
241 max_rot_vel =
std::max(max_rot_vel, 0.
F);
243 std::scoped_lock l{m_control_data.mutex};
244 m_control_data.max_vel = max_pos_vel;
245 m_control_data.max_rot_vel = max_rot_vel;
246 m_platform->setMaxVelocities(max_pos_vel, max_rot_vel);
253 schedule_high_level_control_loop(control_mode::none);
254 m_platform->stopPlatform();
259 armarx::ObstacleAwarePlatformUnit::schedule_high_level_control_loop(control_mode mode)
261 std::scoped_lock l{m_control_loop.mutex};
264 if (m_control_loop.mode == mode)
270 if (m_control_loop.mode != mode and m_control_loop.task)
273 const bool join =
true;
274 m_control_loop.task->stop(join);
278 if (mode == control_mode::none)
286 m_control_loop.mode = mode;
287 m_control_loop.task =
new RunningTask<ObstacleAwarePlatformUnit>(
289 &ObstacleAwarePlatformUnit::high_level_control_loop);
290 m_control_loop.task->start();
295 armarx::ObstacleAwarePlatformUnit::high_level_control_loop()
297 const control_mode mode = m_control_loop.mode;
302 CycleUtil cu{m_control_loop.cycle_time};
303 while (not m_control_loop.task->isStopped())
305 const velocities vels = get_velocities();
309 m[
"err_dist"] =
new Variant{vels.err_dist};
310 m[
"err_angular_dist"] =
new Variant{vels.err_angular_dist};
312 m[
"target_global_x"] =
new Variant{vels.target_global.x()};
313 m[
"target_global_y"] =
new Variant{vels.target_global.y()};
314 m[
"target_global_abs"] =
new Variant{vels.target_global.norm()};
316 m[
"target_local_x"] =
new Variant{vels.target_local.x()};
317 m[
"target_local_y"] =
new Variant{vels.target_local.y()};
318 m[
"target_local_abs"] =
new Variant(vels.target_local.norm());
319 m[
"target_rot"] =
new Variant{vels.target_rot};
321 m[
"modulated_global_x"] =
new Variant{vels.modulated_global.x()};
322 m[
"modulated_global_y"] =
new Variant{vels.modulated_global.y()};
323 m[
"modulated_global_abs"] =
new Variant{vels.modulated_global.norm()};
325 m[
"modulated_local_x"] =
new Variant{vels.modulated_local.x()};
326 m[
"modulated_local_y"] =
new Variant{vels.modulated_local.y()};
327 m[
"modulated_local_abs"] =
new Variant{vels.modulated_local.norm()};
341 setDebugObserverChannel(
"ObstacleAwarePlatformCtrl", m);
343 m_platform->move(vels.modulated_local.x(), vels.modulated_local.y(), vels.target_rot);
345 cu.waitForCycleDuration();
348 catch (
const std::exception& e)
350 ARMARX_ERROR <<
"Error occured while running control loop.\n"
355 ARMARX_ERROR <<
"Unknown error occured while running control loop.";
358 m_platform->move(0, 0, 0);
359 m_platform->stopPlatform();
360 m_control_loop.mode = control_mode::none;
368 armarx::ObstacleAwarePlatformUnit::velocities
369 armarx::ObstacleAwarePlatformUnit::get_velocities()
371 using namespace simox::math;
374 std::scoped_lock l{m_control_data.mutex};
376 update_agent_dependent_values();
377 const Eigen::Vector2f target_vel = get_target_velocity();
378 const float target_rot_vel = get_target_rotational_velocity();
380 const Eigen::Vector2f extents = Eigen::Affine3f(m_robot->getRobotNode(
"PlatformCornerFrontLeft")->getPoseInRootFrame()).translation().head<2>();
383 const Eigen::Vector2f modulated_vel = [
this, &target_vel, &extents]
386 ARMARX_DEBUG <<
"Circle approximation: " << circle.radius;
387 m_viz.boundingCircle = circle;
388 const float distance = m_obsman->distanceToObstacle(m_control_data.agent_pos , circle.radius, m_control_data.target_pos);
395 const Eigen::Vector2f vel = modifier * target_vel;
396 return vel.norm() > 20 ? vel : Eigen::Vector2f{0, 0};
399 ARMARX_CHECK(modulated_vel.allFinite()) <<
"Velocity contains non-finite values.";
402 ARMARX_DEBUG <<
"Target velocity: " << target_vel.transpose()
403 <<
"; norm: " << target_vel.norm() <<
"; " << target_rot_vel;
404 ARMARX_DEBUG <<
"Modulated velocity: " << modulated_vel.transpose() << modulated_vel.norm();
406 const auto r = Eigen::Rotation2D(m_control_data.agent_ori).toRotationMatrix().inverse();
409 vels.target_local = r * target_vel;
410 vels.target_global = target_vel;
411 vels.modulated_local = r * modulated_vel;
412 vels.modulated_global = modulated_vel;
413 vels.target_rot = target_rot_vel;
414 vels.err_dist = m_control_data.target_dist;
415 vels.err_angular_dist = m_control_data.target_angular_dist;
422 armarx::ObstacleAwarePlatformUnit::get_target_velocity()
425 using namespace simox::math;
427 Eigen::Vector2f uncapped_target_vel = Eigen::Vector2f::Zero();
429 if (m_control_loop.mode == control_mode::position )
431 uncapped_target_vel =
432 (m_control_data.target_pos - m_control_data.agent_pos) * m_control_data.kp;
434 else if (m_control_loop.mode == control_mode::velocity)
436 uncapped_target_vel = m_control_data.target_vel;
441 return norm_max(uncapped_target_vel, m_control_data.max_vel);
446 armarx::ObstacleAwarePlatformUnit::get_target_rotational_velocity()
449 using namespace simox::math;
451 float uncapped_target_rot_vel = 0;
453 if (m_control_loop.mode == control_mode::position )
455 m_rot_pid_controller.update(m_control_data.agent_ori, m_control_data.target_ori);
456 uncapped_target_rot_vel = m_rot_pid_controller.getControlValue();
458 else if (m_control_loop.mode == control_mode::velocity)
460 uncapped_target_rot_vel = m_control_data.target_rot_vel;
465 return std::clamp(uncapped_target_rot_vel, -m_control_data.max_rot_vel, m_control_data.max_rot_vel);
473 armarx::ObstacleAwarePlatformUnit::update_agent_dependent_values()
475 using namespace simox::math;
477 synchronizeLocalClone(m_robot);
478 m_control_data.agent_pos = m_robot->getGlobalPosition().head<2>();
479 m_control_data.agent_ori =
480 periodic_clamp<float>(mat4f_to_rpy(m_robot->getGlobalPose()).z(), -
M_PI,
M_PI);
486 if (m_control_loop.mode == control_mode::position)
493 m_control_data.target_dist =
494 (m_control_data.target_pos - m_control_data.agent_pos).
norm();
495 m_control_data.target_angular_dist =
496 periodic_clamp<float>(m_control_data.target_ori - m_control_data.agent_ori,
502 ARMARX_DEBUG <<
"Distance to target: " << m_control_data.target_dist <<
" mm and "
503 << m_control_data.target_angular_dist <<
" rad.";
508 invalidate(m_control_data.target_dist);
509 invalidate(m_control_data.target_angular_dist);
515 armarx::ObstacleAwarePlatformUnit::target_position_reached()
518 if (m_control_loop.mode == control_mode::position)
520 return m_control_data.target_dist < m_control_data.pos_reached_threshold;
529 armarx::ObstacleAwarePlatformUnit::target_orientation_reached()
532 if (m_control_loop.mode == control_mode::position)
534 return std::fabs(m_control_data.target_angular_dist) < m_control_data.ori_reached_threshold;
543 armarx::ObstacleAwarePlatformUnit::target_reached()
546 if (m_control_loop.mode == control_mode::position)
548 return target_position_reached() and target_orientation_reached();
556 armarx::ObstacleAwarePlatformUnit::is_near_target(const
Eigen::Vector2f& control_velocity)
559 if (m_control_data.target_dist < m_control_data.pos_near_threshold)
561 const Eigen::Vector2f target_direction = m_control_data.target_pos - m_control_data.agent_pos;
562 const Eigen::Vector2f control_direction = control_velocity / control_velocity.norm();
564 const float sim = simox::math::cosine_similarity(target_direction, control_direction);
567 if (sim > cos(M_PI_4))
578 armarx::ObstacleAwarePlatformUnit::visualize()
580 const Eigen::Vector2f zero = Eigen::Vector2f::Zero();
582 vels.target_local = zero;
583 vels.target_global = zero;
584 vels.modulated_local = zero;
585 vels.modulated_global = zero;
593 armarx::ObstacleAwarePlatformUnit::visualize(
const velocities& vels)
597 if (not m_viz.enabled)
602 Eigen::Vector3f agent_pos{m_control_data.agent_pos.x(), m_control_data.agent_pos.y(), 0};
605 Layer l_prog = arviz.layer(
"progress");
606 if (m_control_loop.mode == control_mode::position)
608 const float min_keypoint_dist = 50;
614 .pose(simox::math::pos_rpy_to_mat4f(agent_pos, -M_PI_2, 0, 0) * Eigen::Isometry3f(Eigen::Translation3f(0, -1000, 0)).matrix())
615 .radius(m_viz.boundingCircle.radius)
620 if (not m_viz.start.allFinite())
622 m_viz.start = agent_pos;
625 const Eigen::Vector3f& last_keypoint_pos =
626 m_viz.path.size() >= 1 ? m_viz.path.back() : m_viz.start;
629 if ((last_keypoint_pos - agent_pos).
norm() > min_keypoint_dist)
631 m_viz.path.push_back(agent_pos);
635 if (not target_reached())
644 for (
unsigned i = 0; i < m_viz.path.size(); ++i)
647 .position(m_viz.path[i])
653 const Eigen::Vector3f
target{m_control_data.target_pos.x(),
654 m_control_data.target_pos.y(),
658 target + Eigen::Vector3f{0, 0, 40})
665 invalidate(m_viz.start);
670 Layer l_vels = arviz.layer(
"velocities");
671 if (m_control_loop.mode != control_mode::none)
673 const float min_velocity = 15;
674 const Eigen::Vector3f from1{agent_pos + Eigen::Vector3f{0, 0, 2000}};
675 const Eigen::Vector3f from2 = from1 + Eigen::Vector3f{0, 0, 200};
676 const Eigen::Vector3f original{vels.target_global.x(), vels.target_global.y(), 0};
677 const Eigen::Vector3f modulated{vels.modulated_global.x(), vels.modulated_global.y(), 0};
679 if (original.norm() > min_velocity)
682 .
fromTo(from1, from1 + original * 5)
687 if (modulated.norm() > min_velocity)
690 .
fromTo(from2, from2 + modulated * 5)
699 Layer l_agnt = arviz.layer(
"agent");
700 if (m_control_loop.mode != control_mode::none)
708 if (m_control_data.agent_safety_margin > 0)
711 .
pose(simox::math::pos_rpy_to_mat4f(agent_pos, -M_PI_2, 0, 0))
713 .radius(m_control_data.agent_safety_margin)
718 arviz.commit({l_prog, l_vels, l_agnt});
727 def->component(m_platform,
"Platform");
728 def->component(m_obsman,
"ObstacleAvoidingPlatformUnit");
731 def->optional(m_control_data.min_vel_near_target,
"min_vel_near_target",
"Velocity in [mm/s] "
732 "the robot should at least set when near the target");
733 def->optional(m_control_data.min_vel_general,
"min_vel_general",
"Velocity in [mm/s] the robot "
734 "should at least set on general");
735 def->optional(m_control_data.pos_near_threshold,
"pos_near_threshold",
"Distance in [mm] after "
736 "which the robot is considered to be near the target for min velocity, "
740 def->optional(m_control_data.kp,
"control.pos.kp");
741 def->optional(m_rot_pid_controller.Kp,
"control.rot.kp");
742 def->optional(m_rot_pid_controller.Ki,
"control.rot.ki");
743 def->optional(m_rot_pid_controller.Kd,
"control.rot.kd");
744 def->optional(m_control_loop.cycle_time,
"control.pose.cycle_time",
"Control loop cycle time.");
747 def->optional(m_control_data.agent_safety_margin,
"doa.agent_safety_margin");