25 #include <VirtualRobot/MathTools.h>
34 #include <Ice/Current.h>
39 using namespace Eigen;
42 #include <VirtualRobot/Nodes/RobotNode.h>
43 #include <VirtualRobot/XML/RobotIO.h>
49 #include <RobotAPI/interface/core/PoseBase.h>
61 DynamicObstacleManager::DynamicObstacleManager() noexcept :
63 m_decay_after_ms(5000),
64 m_periodic_task_interval(500),
65 m_min_value_for_accepting(1000),
66 m_min_coverage_of_obstacles(0.7f),
67 m_min_coverage_of_line_samples_in_obstacle(0.9f),
68 m_min_size_of_obstacles(100),
69 m_min_length_of_lines(50),
70 m_max_size_of_obstacles(600),
71 m_max_length_of_lines(10000),
72 m_thickness_of_lines(200),
73 m_security_margin_for_obstacles(500),
74 m_security_margin_for_lines(400),
75 m_remove_enabled(false),
76 m_only_visualize(false),
77 m_allow_spwan_inside(false)
82 DynamicObstacleManager::getDefaultName()
const
84 return DynamicObstacleManager::default_name;
88 DynamicObstacleManager::onInitComponent()
93 DynamicObstacleManager::onConnectComponent()
95 m_decay_factor = m_periodic_task_interval;
96 m_access_bonus = m_periodic_task_interval;
99 this, &DynamicObstacleManager::update_decayable_obstacles, m_periodic_task_interval);
100 m_update_obstacles->start();
104 DynamicObstacleManager::onDisconnectComponent()
106 m_update_obstacles->stop();
110 DynamicObstacleManager::onExitComponent()
115 DynamicObstacleManager::add_decayable_obstacle(
const Eigen::Vector2f& e_origin,
125 DynamicObstacleManager::add_decayable_line_segment(
const Eigen::Vector2f& line_start,
126 const Eigen::Vector2f& line_end,
130 const Eigen::Vector2f difference_vec = line_end - line_start;
131 const float length = difference_vec.norm();
132 const Eigen::Vector2f center_vec = line_start + 0.5 * difference_vec;
133 const Eigen::Vector2f difference_vec_normed = difference_vec.normalized();
134 const float dot_product = difference_vec_normed(0);
135 const float cross_product = difference_vec_normed(1);
136 float yaw = acos(dot_product);
138 if (cross_product < 0)
140 yaw = 2 *
M_PI - yaw;
143 if (length < m_min_length_of_lines)
149 std::shared_lock<std::shared_mutex> l(m_managed_obstacles_mutex);
156 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
157 float coverage = ManagedObstacle::line_segment_ellipsis_coverage(
158 {managed_obstacle->m_obstacle.posX, managed_obstacle->m_obstacle.posY},
159 managed_obstacle->m_obstacle.axisLengthX,
160 managed_obstacle->m_obstacle.axisLengthY,
161 managed_obstacle->m_obstacle.yaw,
165 if (coverage >= m_min_coverage_of_line_samples_in_obstacle)
168 managed_obstacle->line_matches.push_back(line_start);
169 managed_obstacle->line_matches.push_back(line_end);
170 managed_obstacle->m_last_matched = IceUtil::Time::now();
192 ARMARX_DEBUG <<
" No matching obstacle found. Create new obstacle and add to list";
194 new_managed_obstacle->m_obstacle.name =
196 new_managed_obstacle->m_obstacle.posX = center_vec(0);
197 new_managed_obstacle->m_obstacle.posY = center_vec(1);
198 new_managed_obstacle->m_obstacle.refPosX = center_vec(0);
199 new_managed_obstacle->m_obstacle.refPosY = center_vec(1);
200 new_managed_obstacle->m_obstacle.yaw = yaw;
201 new_managed_obstacle->m_obstacle.axisLengthX =
203 static_cast<float>(m_min_length_of_lines),
204 static_cast<float>(m_max_length_of_lines));
205 new_managed_obstacle->m_obstacle.axisLengthY = m_thickness_of_lines;
206 new_managed_obstacle->m_obstacle.safetyMarginX = m_security_margin_for_lines;
207 new_managed_obstacle->m_obstacle.safetyMarginY = m_security_margin_for_lines;
208 new_managed_obstacle->m_last_matched = IceUtil::Time::now();
209 new_managed_obstacle->m_published =
false;
210 new_managed_obstacle->m_value = m_min_value_for_accepting * 0.5;
211 new_managed_obstacle->position_buffer_index = 0;
212 new_managed_obstacle->position_buffer_fillctr = 0;
213 new_managed_obstacle->line_matches.push_back(line_start);
214 new_managed_obstacle->line_matches.push_back(line_end);
217 std::lock_guard<std::shared_mutex> l(m_managed_obstacles_mutex);
218 m_managed_obstacles.push_back(new_managed_obstacle);
224 DynamicObstacleManager::add_decayable_line_segments(
225 const dynamicobstaclemanager::LineSegments& lines,
226 const Ice::Current&
c)
228 for (
const auto& line : lines)
230 add_decayable_line_segment(line.lineStart, line.lineEnd,
c);
235 DynamicObstacleManager::remove_all_decayable_obstacles(
const Ice::Current&)
237 std::lock_guard l(m_managed_obstacles_mutex);
239 ARMARX_DEBUG <<
"Remove all obstacles from obstacle map by setting their value to -inf";
243 managed_obstacle->m_updated =
true;
248 DynamicObstacleManager::remove_obstacle(
const std::string& name,
const Ice::Current&)
250 std::lock_guard l(m_managed_obstacles_mutex);
253 <<
" from obstacle map and from obstacledetection";
256 if (managed_obstacle->m_obstacle.name == name)
259 managed_obstacle->m_updated =
true;
260 managed_obstacle->m_published =
false;
264 m_obstacle_detection->removeObstacle(name);
265 m_obstacle_detection->updateEnvironment();
269 DynamicObstacleManager::wait_unitl_obstacles_are_ready(
const Ice::Current&)
271 ARMARX_INFO <<
"Waiting for obstacles to get ready";
272 usleep(2.0 * m_min_value_for_accepting);
277 DynamicObstacleManager::distanceToObstacle(
const Eigen::Vector2f& agentPosition,
279 const Eigen::Vector2f& goal,
282 std::shared_lock<std::shared_mutex> l{m_managed_obstacles_mutex};
284 const Eigen::Vector2f diff = goal - agentPosition;
285 const Eigen::Vector2f orthogonal_normalized =
286 Eigen::Vector2f(Eigen::Rotation2Df(M_PI_2) * diff).normalized();
288 const float sample_step = 5;
289 const float distance_to_goal = diff.norm() + safetyRadius;
291 float current_distance = safetyRadius;
293 while (current_distance < distance_to_goal)
295 for (
const auto& man_obstacle : m_managed_obstacles)
297 Eigen::Vector2f sample =
298 agentPosition + ((goal - agentPosition).normalized() * current_distance);
299 Eigen::Vector2f sample_left = sample + (orthogonal_normalized * 250);
300 Eigen::Vector2f sample_right = sample - (orthogonal_normalized * 250);
302 obstacledetection::Obstacle obstacle = man_obstacle->m_obstacle;
303 Eigen::Vector2f obstacle_origin{obstacle.posX, obstacle.posY};
305 if (ManagedObstacle::point_ellipsis_coverage(obstacle_origin,
306 obstacle.axisLengthX,
307 obstacle.axisLengthY,
311 return current_distance - safetyRadius;
314 if (ManagedObstacle::point_ellipsis_coverage(obstacle_origin,
315 obstacle.axisLengthX,
316 obstacle.axisLengthY,
320 return current_distance - safetyRadius;
323 if (ManagedObstacle::point_ellipsis_coverage(obstacle_origin,
324 obstacle.axisLengthX,
325 obstacle.axisLengthY,
329 return current_distance - safetyRadius;
333 current_distance += sample_step;
336 return std::numeric_limits<float>::infinity();
340 DynamicObstacleManager::directly_update_obstacle(
const std::string& name,
341 const Eigen::Vector2f& obs_pos,
347 obstacledetection::Obstacle new_unmanaged_obstacle;
348 new_unmanaged_obstacle.name = name;
349 new_unmanaged_obstacle.posX = obs_pos(0);
350 new_unmanaged_obstacle.posY = obs_pos(1);
351 new_unmanaged_obstacle.refPosX = obs_pos(0);
352 new_unmanaged_obstacle.refPosY = obs_pos(1);
353 new_unmanaged_obstacle.yaw = e_yaw;
354 new_unmanaged_obstacle.axisLengthX =
356 static_cast<float>(m_min_size_of_obstacles),
357 static_cast<float>(m_max_size_of_obstacles));
358 new_unmanaged_obstacle.axisLengthY =
360 static_cast<float>(m_min_size_of_obstacles),
361 static_cast<float>(m_max_size_of_obstacles));
362 new_unmanaged_obstacle.safetyMarginX = m_security_margin_for_obstacles;
363 new_unmanaged_obstacle.safetyMarginY = m_security_margin_for_obstacles;
364 m_obstacle_detection->updateObstacle(new_unmanaged_obstacle);
365 m_obstacle_detection->updateEnvironment();
369 DynamicObstacleManager::update_decayable_obstacles()
373 std::vector<std::string> remove_obstacles;
376 viz::Layer obstacleLayer = arviz.layer(m_obstacle_manager_layer_name);
381 std::shared_lock<std::shared_mutex> l(m_managed_obstacles_mutex);
382 if (!m_managed_obstacles.size())
389 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
390 managed_obstacle->update_position(m_thickness_of_lines);
395 int checked_obstacles = 0;
396 bool updated =
false;
397 int published_obstacles = 0;
398 int updated_obstacles = 0;
401 std::lock_guard l(m_managed_obstacles_mutex);
402 std::sort(m_managed_obstacles.begin(),
403 m_managed_obstacles.end(),
404 ManagedObstacle::ComparatorDESCPrt);
406 checked_obstacles = m_managed_obstacles.size();
410 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
411 if (!managed_obstacle->m_updated)
413 managed_obstacle->m_value =
414 std::max(-1.0f, managed_obstacle->m_value - m_decay_factor);
418 managed_obstacle->m_value =
std::min(
419 1.0f * m_decay_after_ms, managed_obstacle->m_value + m_access_bonus);
422 if (managed_obstacle->m_published)
424 if (managed_obstacle->m_value < m_min_value_for_accepting)
427 managed_obstacle->m_published =
false;
428 if (!m_only_visualize)
430 m_obstacle_detection->removeObstacle(managed_obstacle->m_obstacle.name);
436 published_obstacles++;
437 if (managed_obstacle->m_updated)
440 if (!m_only_visualize)
442 m_obstacle_detection->updateObstacle(managed_obstacle->m_obstacle);
455 if (managed_obstacle->m_value >= m_min_value_for_accepting)
457 published_obstacles++;
459 managed_obstacle->m_published =
true;
460 if (!m_only_visualize)
462 m_obstacle_detection->updateObstacle(managed_obstacle->m_obstacle);
467 else if (managed_obstacle->m_value < 0 &&
470 remove_obstacles.push_back(managed_obstacle->m_obstacle.name);
472 else if (managed_obstacle->m_updated)
482 managed_obstacle->m_value / m_min_value_for_accepting)},
496 managed_obstacle->m_value / m_min_value_for_accepting)},
501 managed_obstacle->m_updated =
false;
508 m_obstacle_detection->updateEnvironment();
510 arviz.commit({obstacleLayer});
512 if (!remove_obstacles.empty())
514 std::lock_guard<std::shared_mutex> l(m_managed_obstacles_mutex);
515 for (
const auto& name : remove_obstacles)
518 m_managed_obstacles.erase(std::remove_if(m_managed_obstacles.begin(),
519 m_managed_obstacles.end(),
521 { return oc->m_obstacle.name == name; }),
522 m_managed_obstacles.end());
526 ARMARX_DEBUG <<
"Finished updating the " << checked_obstacles
527 <<
" managed obstacles (removed: " << remove_obstacles.size()
528 <<
", updated: " << updated_obstacles <<
"). " << published_obstacles
529 <<
" of them should be published. The whole operation took "
530 << (IceUtil::Time::now() - started).toMilliSeconds() <<
"ms";
534 DynamicObstacleManager::visualize_obstacle(
viz::Layer& layer,
536 const armarx::DrawColor& color,
541 Eigen::Vector3f dim(o->m_obstacle.axisLengthX * 2,
542 o->m_obstacle.axisLengthY * 2,
543 o->m_obstacle.axisLengthZ * 2);
545 const std::string name = o->m_obstacle.name;
548 .position(Eigen::Vector3f(o->m_obstacle.posX, o->m_obstacle.posY, pos_z))
549 .
orientation(Eigen::AngleAxisf(o->m_obstacle.yaw, Eigen::Vector3f::UnitZ())
552 .
color(color.r, color.g, color.b, color.a));
556 DynamicObstacleManager::createPropertyDefinitions()
561 "PlatformObstacleAvoidance",
562 "ObstacleAvoidanceName",
563 "The name of the used obstacle avoidance interface");
565 defs->optional(m_min_coverage_of_obstacles,
566 "MinSampleRatioPerEllipsis",
567 "Minimum percentage of samples which have to be in an elllipsis to be "
568 "considered as known obsacle");
569 defs->optional(m_min_coverage_of_line_samples_in_obstacle,
570 "MinSampleRatioPerLineSegment",
571 "Minimum percentage of samples which have to be in an elllipsis to be "
572 "considered as known obsacle");
574 m_min_size_of_obstacles,
"MinObstacleSize",
"The minimal obstacle size in mm.");
576 m_max_size_of_obstacles,
"MaxObstacleSize",
"The maximal obstacle size in mm.");
577 defs->optional(m_min_length_of_lines,
"MinLengthOfLines",
"Minimum length of lines in mm");
578 defs->optional(m_max_length_of_lines,
"MaxLengthOfLines",
"Maximum length of lines in mm");
579 defs->optional(m_decay_after_ms,
"MaxObstacleValue",
"Maximum value for the obstacles");
580 defs->optional(m_min_value_for_accepting,
581 "MinObstacleValueForAccepting",
582 "Minimum value for the obstacles to get accepted");
584 m_periodic_task_interval,
"UpdateInterval",
"The interval to check the obstacles");
585 defs->optional(m_thickness_of_lines,
"LineThickness",
"The thickness of line obstacles");
586 defs->optional(m_security_margin_for_obstacles,
587 "ObstacleSecurityMargin",
588 "Security margin of ellipsis obstacles");
590 m_security_margin_for_lines,
"LineSecurityMargin",
"Security margin of line obstacles");
591 defs->optional(m_remove_enabled,
"EnableRemove",
"Delete Obstacles when value < 0");
593 m_only_visualize,
"OnlyVisualizeObstacles",
"Connection to obstacle avoidance");
594 defs->optional(m_allow_spwan_inside,
595 "AllowInRobotSpawning",
596 "Allow obstacles to spawn inside the robot");