25#include <VirtualRobot/MathTools.h>
34#include <Ice/Current.h>
42#include <VirtualRobot/Nodes/RobotNode.h>
43#include <VirtualRobot/XML/RobotIO.h>
49#include <RobotAPI/interface/core/PoseBase.h>
65 m_decay_after_ms(5000),
66 m_periodic_task_interval(500),
67 m_min_value_for_accepting(1000),
68 m_min_coverage_of_obstacles(0.7f),
69 m_min_coverage_of_line_samples_in_obstacle(0.9f),
70 m_min_size_of_obstacles(100),
71 m_min_length_of_lines(50),
72 m_max_size_of_obstacles(600),
73 m_max_length_of_lines(10000),
74 m_thickness_of_lines(200),
75 m_security_margin_for_obstacles(500),
76 m_security_margin_for_lines(400),
77 m_remove_enabled(false),
78 m_only_visualize(false),
79 m_allow_spwan_inside(false)
97 m_decay_factor = m_periodic_task_interval;
98 m_access_bonus = m_periodic_task_interval;
101 this, &DynamicObstacleManager::update_decayable_obstacles, m_periodic_task_interval);
102 m_update_obstacles->start();
108 m_update_obstacles->stop();
128 const Eigen::Vector2f& line_end,
132 const Eigen::Vector2f difference_vec = line_end - line_start;
133 const float length = difference_vec.norm();
134 const Eigen::Vector2f center_vec = line_start + 0.5 * difference_vec;
135 const Eigen::Vector2f difference_vec_normed = difference_vec.normalized();
136 const float dot_product = difference_vec_normed(0);
137 const float cross_product = difference_vec_normed(1);
138 float yaw = acos(dot_product);
140 if (cross_product < 0)
142 yaw = 2 *
M_PI - yaw;
145 if (length < m_min_length_of_lines)
151 std::shared_lock<std::shared_mutex> l(m_managed_obstacles_mutex);
158 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
160 {managed_obstacle->m_obstacle.posX, managed_obstacle->m_obstacle.posY},
161 managed_obstacle->m_obstacle.axisLengthX,
162 managed_obstacle->m_obstacle.axisLengthY,
163 managed_obstacle->m_obstacle.yaw,
167 if (coverage >= m_min_coverage_of_line_samples_in_obstacle)
170 managed_obstacle->line_matches.push_back(line_start);
171 managed_obstacle->line_matches.push_back(line_end);
172 managed_obstacle->m_last_matched = IceUtil::Time::now();
194 ARMARX_DEBUG <<
" No matching obstacle found. Create new obstacle and add to list";
196 new_managed_obstacle->m_obstacle.name =
197 "managed_obstacle_" + std::to_string(m_obstacle_index++);
198 new_managed_obstacle->m_obstacle.posX = center_vec(0);
199 new_managed_obstacle->m_obstacle.posY = center_vec(1);
200 new_managed_obstacle->m_obstacle.refPosX = center_vec(0);
201 new_managed_obstacle->m_obstacle.refPosY = center_vec(1);
202 new_managed_obstacle->m_obstacle.yaw = yaw;
203 new_managed_obstacle->m_obstacle.axisLengthX =
204 std::clamp(length * 0.5f,
205 static_cast<float>(m_min_length_of_lines),
206 static_cast<float>(m_max_length_of_lines));
207 new_managed_obstacle->m_obstacle.axisLengthY = m_thickness_of_lines;
208 new_managed_obstacle->m_obstacle.safetyMarginX = m_security_margin_for_lines;
209 new_managed_obstacle->m_obstacle.safetyMarginY = m_security_margin_for_lines;
210 new_managed_obstacle->m_last_matched = IceUtil::Time::now();
211 new_managed_obstacle->m_published =
false;
212 new_managed_obstacle->m_value = m_min_value_for_accepting * 0.5;
213 new_managed_obstacle->position_buffer_index = 0;
214 new_managed_obstacle->position_buffer_fillctr = 0;
215 new_managed_obstacle->line_matches.push_back(line_start);
216 new_managed_obstacle->line_matches.push_back(line_end);
219 std::lock_guard<std::shared_mutex> l(m_managed_obstacles_mutex);
220 m_managed_obstacles.push_back(new_managed_obstacle);
227 const dynamicobstaclemanager::LineSegments& lines,
228 const Ice::Current&
c)
230 for (
const auto& line : lines)
239 std::lock_guard l(m_managed_obstacles_mutex);
241 ARMARX_DEBUG <<
"Remove all obstacles from obstacle map by setting their value to -inf";
244 managed_obstacle->m_value = std::numeric_limits<double>::min();
245 managed_obstacle->m_updated =
true;
252 std::lock_guard l(m_managed_obstacles_mutex);
255 <<
" from obstacle map and from obstacledetection";
258 if (managed_obstacle->m_obstacle.name == name)
260 managed_obstacle->m_value = std::numeric_limits<double>::min();
261 managed_obstacle->m_updated =
true;
262 managed_obstacle->m_published =
false;
266 m_obstacle_detection->removeObstacle(name);
267 m_obstacle_detection->updateEnvironment();
273 ARMARX_INFO <<
"Waiting for obstacles to get ready";
274 usleep(2.0 * m_min_value_for_accepting);
281 const Eigen::Vector2f& goal,
284 std::shared_lock<std::shared_mutex> l{m_managed_obstacles_mutex};
286 const Eigen::Vector2f diff = goal - agentPosition;
287 const Eigen::Vector2f orthogonal_normalized =
288 Eigen::Vector2f(Eigen::Rotation2Df(M_PI_2) * diff).normalized();
290 const float sample_step = 5;
291 const float distance_to_goal = diff.norm() + safetyRadius;
293 float current_distance = safetyRadius;
295 while (current_distance < distance_to_goal)
297 for (
const auto& man_obstacle : m_managed_obstacles)
299 Eigen::Vector2f sample =
300 agentPosition + ((goal - agentPosition).normalized() * current_distance);
301 Eigen::Vector2f sample_left = sample + (orthogonal_normalized * 250);
302 Eigen::Vector2f sample_right = sample - (orthogonal_normalized * 250);
304 obstacledetection::Obstacle obstacle = man_obstacle->m_obstacle;
305 Eigen::Vector2f obstacle_origin{obstacle.posX, obstacle.posY};
308 obstacle.axisLengthX,
309 obstacle.axisLengthY,
313 return current_distance - safetyRadius;
317 obstacle.axisLengthX,
318 obstacle.axisLengthY,
322 return current_distance - safetyRadius;
326 obstacle.axisLengthX,
327 obstacle.axisLengthY,
331 return current_distance - safetyRadius;
335 current_distance += sample_step;
338 return std::numeric_limits<float>::infinity();
343 const Eigen::Vector2f& obs_pos,
349 obstacledetection::Obstacle new_unmanaged_obstacle;
350 new_unmanaged_obstacle.name = name;
351 new_unmanaged_obstacle.posX = obs_pos(0);
352 new_unmanaged_obstacle.posY = obs_pos(1);
353 new_unmanaged_obstacle.refPosX = obs_pos(0);
354 new_unmanaged_obstacle.refPosY = obs_pos(1);
355 new_unmanaged_obstacle.yaw = e_yaw;
356 new_unmanaged_obstacle.axisLengthX =
358 static_cast<float>(m_min_size_of_obstacles),
359 static_cast<float>(m_max_size_of_obstacles));
360 new_unmanaged_obstacle.axisLengthY =
362 static_cast<float>(m_min_size_of_obstacles),
363 static_cast<float>(m_max_size_of_obstacles));
364 new_unmanaged_obstacle.safetyMarginX = m_security_margin_for_obstacles;
365 new_unmanaged_obstacle.safetyMarginY = m_security_margin_for_obstacles;
366 m_obstacle_detection->updateObstacle(new_unmanaged_obstacle);
367 m_obstacle_detection->updateEnvironment();
371 DynamicObstacleManager::update_decayable_obstacles()
374 IceUtil::Time started = IceUtil::Time::now();
375 std::vector<std::string> remove_obstacles;
383 std::shared_lock<std::shared_mutex> l(m_managed_obstacles_mutex);
384 if (!m_managed_obstacles.size())
391 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
392 managed_obstacle->update_position(m_thickness_of_lines);
397 int checked_obstacles = 0;
398 bool updated =
false;
399 int published_obstacles = 0;
400 int updated_obstacles = 0;
403 std::lock_guard l(m_managed_obstacles_mutex);
404 std::sort(m_managed_obstacles.begin(),
405 m_managed_obstacles.end(),
408 checked_obstacles = m_managed_obstacles.size();
412 std::lock_guard<std::shared_mutex> l(managed_obstacle->m_mutex);
413 if (!managed_obstacle->m_updated)
415 managed_obstacle->m_value =
416 std::max(-1.0f, managed_obstacle->m_value - m_decay_factor);
420 managed_obstacle->m_value = std::min(
421 1.0f * m_decay_after_ms, managed_obstacle->m_value + m_access_bonus);
424 if (managed_obstacle->m_published)
426 if (managed_obstacle->m_value < m_min_value_for_accepting)
429 managed_obstacle->m_published =
false;
430 if (!m_only_visualize)
432 m_obstacle_detection->removeObstacle(managed_obstacle->m_obstacle.name);
438 published_obstacles++;
439 if (managed_obstacle->m_updated)
442 if (!m_only_visualize)
444 m_obstacle_detection->updateObstacle(managed_obstacle->m_obstacle);
457 if (managed_obstacle->m_value >= m_min_value_for_accepting)
459 published_obstacles++;
461 managed_obstacle->m_published =
true;
462 if (!m_only_visualize)
464 m_obstacle_detection->updateObstacle(managed_obstacle->m_obstacle);
469 else if (managed_obstacle->m_value < 0 &&
472 remove_obstacles.push_back(managed_obstacle->m_obstacle.name);
474 else if (managed_obstacle->m_updated)
484 managed_obstacle->m_value / m_min_value_for_accepting)},
498 managed_obstacle->m_value / m_min_value_for_accepting)},
503 managed_obstacle->m_updated =
false;
510 m_obstacle_detection->updateEnvironment();
512 arviz.commit({obstacleLayer});
514 if (!remove_obstacles.empty())
516 std::lock_guard<std::shared_mutex> l(m_managed_obstacles_mutex);
517 for (
const auto& name : remove_obstacles)
520 m_managed_obstacles.erase(std::remove_if(m_managed_obstacles.begin(),
521 m_managed_obstacles.end(),
523 { return oc->m_obstacle.name == name; }),
524 m_managed_obstacles.end());
528 ARMARX_DEBUG <<
"Finished updating the " << checked_obstacles
529 <<
" managed obstacles (removed: " << remove_obstacles.size()
530 <<
", updated: " << updated_obstacles <<
"). " << published_obstacles
531 <<
" of them should be published. The whole operation took "
532 << (IceUtil::Time::now() - started).toMilliSeconds() <<
"ms";
536 DynamicObstacleManager::visualize_obstacle(
viz::Layer& layer,
538 const armarx::DrawColor& color,
543 Eigen::Vector3f dim(o->m_obstacle.axisLengthX * 2,
544 o->m_obstacle.axisLengthY * 2,
545 o->m_obstacle.axisLengthZ * 2);
547 const std::string name = o->m_obstacle.name;
549 layer.
add(viz::Box(name)
550 .position(Eigen::Vector3f(o->m_obstacle.posX, o->m_obstacle.posY, pos_z))
551 .orientation(Eigen::AngleAxisf(o->m_obstacle.yaw, Eigen::Vector3f::UnitZ())
554 .color(color.r, color.g, color.b, color.a));
562 defs->component(m_obstacle_detection,
563 "PlatformObstacleAvoidance",
564 "ObstacleAvoidanceName",
565 "The name of the used obstacle avoidance interface");
567 defs->optional(m_min_coverage_of_obstacles,
568 "MinSampleRatioPerEllipsis",
569 "Minimum percentage of samples which have to be in an elllipsis to be "
570 "considered as known obsacle");
571 defs->optional(m_min_coverage_of_line_samples_in_obstacle,
572 "MinSampleRatioPerLineSegment",
573 "Minimum percentage of samples which have to be in an elllipsis to be "
574 "considered as known obsacle");
576 m_min_size_of_obstacles,
"MinObstacleSize",
"The minimal obstacle size in mm.");
578 m_max_size_of_obstacles,
"MaxObstacleSize",
"The maximal obstacle size in mm.");
579 defs->optional(m_min_length_of_lines,
"MinLengthOfLines",
"Minimum length of lines in mm");
580 defs->optional(m_max_length_of_lines,
"MaxLengthOfLines",
"Maximum length of lines in mm");
581 defs->optional(m_decay_after_ms,
"MaxObstacleValue",
"Maximum value for the obstacles");
582 defs->optional(m_min_value_for_accepting,
583 "MinObstacleValueForAccepting",
584 "Minimum value for the obstacles to get accepted");
586 m_periodic_task_interval,
"UpdateInterval",
"The interval to check the obstacles");
587 defs->optional(m_thickness_of_lines,
"LineThickness",
"The thickness of line obstacles");
588 defs->optional(m_security_margin_for_obstacles,
589 "ObstacleSecurityMargin",
590 "Security margin of ellipsis obstacles");
592 m_security_margin_for_lines,
"LineSecurityMargin",
"Security margin of line obstacles");
593 defs->optional(m_remove_enabled,
"EnableRemove",
"Delete Obstacles when value < 0");
595 m_only_visualize,
"OnlyVisualizeObstacles",
"Connection to obstacle avoidance");
596 defs->optional(m_allow_spwan_inside,
597 "AllowInRobotSpawning",
598 "Allow obstacles to spawn inside the robot");
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
armarx::viz::Client arviz
Default component property definition container.
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
void remove_all_decayable_obstacles(const Ice::Current &=Ice::Current()) override
void onInitComponent() override
Pure virtual hook for the subclass.
static const std::string default_name
void add_decayable_line_segment(const Eigen::Vector2f &, const Eigen::Vector2f &, const Ice::Current &=Ice::Current()) override
void remove_obstacle(const std::string &name, const Ice::Current &=Ice::Current()) override
void add_decayable_obstacle(const Eigen::Vector2f &, float, float, float, const Ice::Current &=Ice::Current()) override
float distanceToObstacle(const Eigen::Vector2f &agentPosition, float safetyRadius, const Eigen::Vector2f &goal, const Ice::Current &=Ice::Current()) override
void onDisconnectComponent() override
Hook for subclass.
void wait_unitl_obstacles_are_ready(const Ice::Current &=Ice::Current()) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
DynamicObstacleManager() noexcept
void add_decayable_line_segments(const dynamicobstaclemanager::LineSegments &lines, const Ice::Current &=Ice::Current()) override
void onConnectComponent() override
Pure virtual hook for the subclass.
void directly_update_obstacle(const std::string &name, const Eigen::Vector2f &, float, float, float, const Ice::Current &=Ice::Current()) override
void onExitComponent() override
Hook for subclass.
std::string getDefaultName() const override
Retrieve default name of component.
static float line_segment_ellipsis_coverage(const Eigen::Vector2f e_origin, const float e_rx, const float e_ry, const float e_yaw, const Eigen::Vector2f line_seg_start, const Eigen::Vector2f line_seg_end)
static bool point_ellipsis_coverage(const Eigen::Vector2f e_origin, const float e_rx, const float e_ry, const float e_yaw, const Eigen::Vector2f point)
static bool ComparatorDESCPrt(ManagedObstaclePtr &i, ManagedObstaclePtr &j)
The periodic task executes one thread method repeatedly using the time period specified in the constr...
virtual Layer layer(std::string const &name) const
#define ARMARX_INFO
The normal logging level.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define TIMING_START(name)
Helper macro to do timing tests.
#define TIMING_END(name)
Prints duration.
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::shared_ptr< ManagedObstacle > ManagedObstaclePtr
void add(ElementT const &element)