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>
48 #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)
83 std::string DynamicObstacleManager::getDefaultName()
const
85 return DynamicObstacleManager::default_name;
89 void DynamicObstacleManager::onInitComponent()
95 void DynamicObstacleManager::onConnectComponent()
97 m_decay_factor = m_periodic_task_interval;
98 m_access_bonus = m_periodic_task_interval;
101 &DynamicObstacleManager::update_decayable_obstacles, m_periodic_task_interval);
102 m_update_obstacles->start();
105 void DynamicObstacleManager::onDisconnectComponent()
107 m_update_obstacles->stop();
110 void DynamicObstacleManager::onExitComponent()
115 void DynamicObstacleManager::add_decayable_obstacle(
const Eigen::Vector2f& e_origin,
float e_rx,
float e_ry,
float e_yaw,
const Ice::Current&)
121 void DynamicObstacleManager::add_decayable_line_segment(
const Eigen::Vector2f& line_start,
const Eigen::Vector2f& line_end,
const Ice::Current&)
124 const Eigen::Vector2f difference_vec = line_end - line_start;
125 const float length = difference_vec.norm();
126 const Eigen::Vector2f center_vec = line_start + 0.5 * difference_vec;
127 const Eigen::Vector2f difference_vec_normed = difference_vec.normalized();
128 const float dot_product = difference_vec_normed(0);
129 const float cross_product = difference_vec_normed(1);
130 float yaw = acos(dot_product);
132 if (cross_product < 0)
134 yaw = 2 *
M_PI - yaw;
137 if (length < m_min_length_of_lines)
143 std::shared_lock<std::shared_mutex> l(m_managed_obstacles_mutex);
150 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
151 float coverage = ManagedObstacle::line_segment_ellipsis_coverage(
152 {managed_obstacle->m_obstacle.posX, managed_obstacle->m_obstacle.posY}, managed_obstacle->m_obstacle.axisLengthX, managed_obstacle->m_obstacle.axisLengthY, managed_obstacle->m_obstacle.yaw,
153 line_start, line_end);
155 if (coverage >= m_min_coverage_of_line_samples_in_obstacle)
158 managed_obstacle->line_matches.push_back(line_start);
159 managed_obstacle->line_matches.push_back(line_end);
160 managed_obstacle->m_last_matched = IceUtil::Time::now();
182 ARMARX_DEBUG <<
" No matching obstacle found. Create new obstacle and add to list";
184 new_managed_obstacle->m_obstacle.name =
"managed_obstacle_" +
std::to_string(m_obstacle_index++);
185 new_managed_obstacle->m_obstacle.posX = center_vec(0);
186 new_managed_obstacle->m_obstacle.posY = center_vec(1);
187 new_managed_obstacle->m_obstacle.refPosX = center_vec(0);
188 new_managed_obstacle->m_obstacle.refPosY = center_vec(1);
189 new_managed_obstacle->m_obstacle.yaw = yaw;
190 new_managed_obstacle->m_obstacle.axisLengthX =
std::clamp(length * 0.5f,
static_cast<float>(m_min_length_of_lines),
static_cast<float>(m_max_length_of_lines));
191 new_managed_obstacle->m_obstacle.axisLengthY = m_thickness_of_lines;
192 new_managed_obstacle->m_obstacle.safetyMarginX = m_security_margin_for_lines;
193 new_managed_obstacle->m_obstacle.safetyMarginY = m_security_margin_for_lines;
194 new_managed_obstacle->m_last_matched = IceUtil::Time::now();
195 new_managed_obstacle->m_published =
false;
196 new_managed_obstacle->m_value = m_min_value_for_accepting * 0.5;
197 new_managed_obstacle->position_buffer_index = 0;
198 new_managed_obstacle->position_buffer_fillctr = 0;
199 new_managed_obstacle->line_matches.push_back(line_start);
200 new_managed_obstacle->line_matches.push_back(line_end);
203 std::lock_guard<std::shared_mutex> l(m_managed_obstacles_mutex);
204 m_managed_obstacles.push_back(new_managed_obstacle);
209 void DynamicObstacleManager::add_decayable_line_segments(
const dynamicobstaclemanager::LineSegments& lines,
const Ice::Current&
c)
211 for (
const auto& line : lines)
213 add_decayable_line_segment(line.lineStart, line.lineEnd,
c);
218 void DynamicObstacleManager::remove_all_decayable_obstacles(
const Ice::Current&)
220 std::lock_guard l(m_managed_obstacles_mutex);
222 ARMARX_DEBUG <<
"Remove all obstacles from obstacle map by setting their value to -inf";
226 managed_obstacle->m_updated =
true;
230 void DynamicObstacleManager::remove_obstacle(
const std::string& name,
const Ice::Current&)
232 std::lock_guard l(m_managed_obstacles_mutex);
234 ARMARX_DEBUG <<
"Remove Obstacle " << name <<
" from obstacle map and from obstacledetection";
237 if (managed_obstacle->m_obstacle.name == name)
240 managed_obstacle->m_updated =
true;
241 managed_obstacle->m_published =
false;
245 m_obstacle_detection->removeObstacle(name);
246 m_obstacle_detection->updateEnvironment();
249 void DynamicObstacleManager::wait_unitl_obstacles_are_ready(
const Ice::Current&)
251 ARMARX_INFO <<
"Waiting for obstacles to get ready";
252 usleep(2.0 * m_min_value_for_accepting);
258 DynamicObstacleManager::distanceToObstacle(
const Eigen::Vector2f& agentPosition,
float safetyRadius,
const Eigen::Vector2f& goal,
const Ice::Current&)
260 std::shared_lock<std::shared_mutex> l{m_managed_obstacles_mutex};
262 const Eigen::Vector2f diff = goal - agentPosition;
263 const Eigen::Vector2f orthogonal_normalized = Eigen::Vector2f(Eigen::Rotation2Df(M_PI_2) * diff).normalized();
265 const float sample_step = 5;
266 const float distance_to_goal = diff.norm() + safetyRadius;
268 float current_distance = safetyRadius;
270 while (current_distance < distance_to_goal)
272 for (
const auto& man_obstacle : m_managed_obstacles)
274 Eigen::Vector2f sample = agentPosition + ((goal - agentPosition).normalized() * current_distance);
275 Eigen::Vector2f sample_left = sample + (orthogonal_normalized * 250);
276 Eigen::Vector2f sample_right = sample - (orthogonal_normalized * 250);
278 obstacledetection::Obstacle obstacle = man_obstacle->m_obstacle;
279 Eigen::Vector2f obstacle_origin{obstacle.posX, obstacle.posY};
281 if (ManagedObstacle::point_ellipsis_coverage(obstacle_origin, obstacle.axisLengthX, obstacle.axisLengthY, obstacle.yaw, sample))
283 return current_distance - safetyRadius;
286 if (ManagedObstacle::point_ellipsis_coverage(obstacle_origin, obstacle.axisLengthX, obstacle.axisLengthY, obstacle.yaw, sample_left))
288 return current_distance - safetyRadius;
291 if (ManagedObstacle::point_ellipsis_coverage(obstacle_origin, obstacle.axisLengthX, obstacle.axisLengthY, obstacle.yaw, sample_right))
293 return current_distance - safetyRadius;
297 current_distance += sample_step;
300 return std::numeric_limits<float>::infinity();
304 void DynamicObstacleManager::directly_update_obstacle(
const std::string& name,
const Eigen::Vector2f& obs_pos,
float e_rx,
float e_ry,
float e_yaw,
const Ice::Current&)
306 obstacledetection::Obstacle new_unmanaged_obstacle;
307 new_unmanaged_obstacle.name = name;
308 new_unmanaged_obstacle.posX = obs_pos(0);
309 new_unmanaged_obstacle.posY = obs_pos(1);
310 new_unmanaged_obstacle.refPosX = obs_pos(0);
311 new_unmanaged_obstacle.refPosY = obs_pos(1);
312 new_unmanaged_obstacle.yaw = e_yaw;
313 new_unmanaged_obstacle.axisLengthX =
std::clamp(e_rx,
static_cast<float>(m_min_size_of_obstacles),
static_cast<float>(m_max_size_of_obstacles));
314 new_unmanaged_obstacle.axisLengthY =
std::clamp(e_ry,
static_cast<float>(m_min_size_of_obstacles),
static_cast<float>(m_max_size_of_obstacles));
315 new_unmanaged_obstacle.safetyMarginX = m_security_margin_for_obstacles;
316 new_unmanaged_obstacle.safetyMarginY = m_security_margin_for_obstacles;
317 m_obstacle_detection->updateObstacle(new_unmanaged_obstacle);
318 m_obstacle_detection->updateEnvironment();
322 void DynamicObstacleManager::update_decayable_obstacles()
326 std::vector<std::string> remove_obstacles;
329 viz::Layer obstacleLayer = arviz.layer(m_obstacle_manager_layer_name);
334 std::shared_lock<std::shared_mutex> l(m_managed_obstacles_mutex);
335 if (!m_managed_obstacles.size())
342 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
343 managed_obstacle->update_position(m_thickness_of_lines);
348 int checked_obstacles = 0;
349 bool updated =
false;
350 int published_obstacles = 0;
351 int updated_obstacles = 0;
354 std::lock_guard l(m_managed_obstacles_mutex);
355 std::sort(m_managed_obstacles.begin(), m_managed_obstacles.end(), ManagedObstacle::ComparatorDESCPrt);
357 checked_obstacles = m_managed_obstacles.size();
361 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
362 if (!managed_obstacle->m_updated)
364 managed_obstacle->m_value =
std::max(-1.0f, managed_obstacle->m_value - m_decay_factor);
368 managed_obstacle->m_value =
std::min(1.0f * m_decay_after_ms, managed_obstacle->m_value + m_access_bonus);
371 if (managed_obstacle->m_published)
373 if (managed_obstacle->m_value < m_min_value_for_accepting)
376 managed_obstacle->m_published =
false;
377 if (!m_only_visualize)
379 m_obstacle_detection->removeObstacle(managed_obstacle->m_obstacle.name);
385 published_obstacles++;
386 if (managed_obstacle->m_updated)
389 if (!m_only_visualize)
391 m_obstacle_detection->updateObstacle(managed_obstacle->m_obstacle);
404 if (managed_obstacle->m_value >= m_min_value_for_accepting)
406 published_obstacles++;
408 managed_obstacle->m_published =
true;
409 if (!m_only_visualize)
411 m_obstacle_detection->updateObstacle(managed_obstacle->m_obstacle);
416 else if (managed_obstacle->m_value < 0 && m_remove_enabled)
418 remove_obstacles.push_back(managed_obstacle->m_obstacle.name);
420 else if (managed_obstacle->m_updated)
422 visualize_obstacle(obstacleLayer, managed_obstacle, armarx::DrawColor{1, 1, 1,
std::min(0.9f, managed_obstacle->m_value / m_min_value_for_accepting)}, 40,
true);
426 visualize_obstacle(obstacleLayer, managed_obstacle, armarx::DrawColor{1, 1, 1,
std::min(0.9f, managed_obstacle->m_value / m_min_value_for_accepting)}, 40,
true);
429 managed_obstacle->m_updated =
false;
436 m_obstacle_detection->updateEnvironment();
438 arviz.commit({obstacleLayer});
440 if (!remove_obstacles.empty())
442 std::lock_guard<std::shared_mutex> l(m_managed_obstacles_mutex);
443 for (
const auto& name : remove_obstacles)
446 m_managed_obstacles.erase(
448 m_managed_obstacles.begin(),
449 m_managed_obstacles.end(),
452 return oc->m_obstacle.name == name;
455 m_managed_obstacles.end()
460 ARMARX_DEBUG <<
"Finished updating the " << checked_obstacles <<
" managed obstacles (removed: " << remove_obstacles.size() <<
", updated: " << updated_obstacles <<
"). " << published_obstacles <<
" of them should be published. The whole operation took " << (IceUtil::Time::now() - started).toMilliSeconds() <<
"ms";
463 void DynamicObstacleManager::visualize_obstacle(
viz::Layer& layer,
const ManagedObstaclePtr& o,
const armarx::DrawColor& color,
double pos_z,
bool text)
466 Eigen::Vector3f dim(o->m_obstacle.axisLengthX * 2,
467 o->m_obstacle.axisLengthY * 2,
468 o->m_obstacle.axisLengthZ * 2);
470 const std::string name = o->m_obstacle.name;
472 layer.
add(
viz::Box(name).position(Eigen::Vector3f(o->m_obstacle.posX, o->m_obstacle.posY, pos_z))
473 .
orientation(Eigen::AngleAxisf(o->m_obstacle.yaw, Eigen::Vector3f::UnitZ()).toRotationMatrix())
474 .
size(dim).
color(color.r, color.g, color.b, color.a));
483 defs->
component(m_obstacle_detection,
"PlatformObstacleAvoidance",
"ObstacleAvoidanceName",
"The name of the used obstacle avoidance interface");
485 defs->optional(m_min_coverage_of_obstacles,
"MinSampleRatioPerEllipsis",
"Minimum percentage of samples which have to be in an elllipsis to be considered as known obsacle");
486 defs->optional(m_min_coverage_of_line_samples_in_obstacle,
"MinSampleRatioPerLineSegment",
"Minimum percentage of samples which have to be in an elllipsis to be considered as known obsacle");
487 defs->optional(m_min_size_of_obstacles,
"MinObstacleSize",
"The minimal obstacle size in mm.");
488 defs->optional(m_max_size_of_obstacles,
"MaxObstacleSize",
"The maximal obstacle size in mm.");
489 defs->optional(m_min_length_of_lines,
"MinLengthOfLines",
"Minimum length of lines in mm");
490 defs->optional(m_max_length_of_lines,
"MaxLengthOfLines",
"Maximum length of lines in mm");
491 defs->optional(m_decay_after_ms,
"MaxObstacleValue",
"Maximum value for the obstacles");
492 defs->optional(m_min_value_for_accepting,
"MinObstacleValueForAccepting",
"Minimum value for the obstacles to get accepted");
493 defs->optional(m_periodic_task_interval,
"UpdateInterval",
"The interval to check the obstacles");
494 defs->optional(m_thickness_of_lines,
"LineThickness",
"The thickness of line obstacles");
495 defs->optional(m_security_margin_for_obstacles,
"ObstacleSecurityMargin",
"Security margin of ellipsis obstacles");
496 defs->optional(m_security_margin_for_lines,
"LineSecurityMargin",
"Security margin of line obstacles");
497 defs->optional(m_remove_enabled,
"EnableRemove",
"Delete Obstacles when value < 0");
498 defs->optional(m_only_visualize,
"OnlyVisualizeObstacles",
"Connection to obstacle avoidance");
499 defs->optional(m_allow_spwan_inside,
"AllowInRobotSpawning",
"Allow obstacles to spawn inside the robot");