35 #include <VirtualRobot/Nodes/RobotNode.h>
36 #include <VirtualRobot/XML/RobotIO.h>
39 #include <Ice/Current.h>
55 m_onlyUseFirstNResults(-1),
57 m_human_confidence_filter_value(0.3),
58 m_min_velocity_treshold(15),
76 const unsigned int periodic_task_interval = 100;
79 m_check_human_task->start();
89 m_check_human_task->stop();
108 if (m_onlyUseFirstNResults == 0)
113 if (m_onlyUseFirstNResults > 0)
115 m_onlyUseFirstNResults--;
121 std::lock_guard l{m_enabled_mutex};
122 if (not m_enabled or kpml.empty())
130 std::lock_guard l{m_human_mutex};
135 std::vector<Keypoint3DMap> legacy_kpml;
136 for (
const auto& [name, entity] : kpml)
138 legacy_kpml.push_back(entity.keypointMap);
141 const OpenPoseResult closestHuman = find_closest_human(legacy_kpml, time);
144 if (not closestHuman.valid)
149 if (closestHuman.distance < m_warn_distance)
155 HumanApproximation human = approximate_human(closestHuman);
160 m_obstacle_manager->directly_update_obstacle(
"human",
161 Eigen::Vector2f(human.posX, human.posY),
167 ARMARX_DEBUG <<
"Drawing Human Obsacle at position (" << human.posX <<
", " << human.posY
168 <<
"). Needed time: " << IceUtil::Time::now() - start;
171 HumanObstacleDetection::OpenPoseResult
172 HumanObstacleDetection::find_closest_human(
const std::vector<Keypoint3DMap>& kpml,
176 OpenPoseResult closest_human;
177 closest_human.mean_position = Eigen::Vector3f(0, 0, 0);
180 closest_human.confidence = 0.0;
181 closest_human.index = -1;
182 closest_human.valid =
false;
184 for (
unsigned int i = 0; i < kpml.size(); ++i)
188 Eigen::Vector3f sum_positions(0, 0, 0);
189 float sum_distance = 0;
190 float sum_confidence = 0;
193 for (
const auto& [key,
value] : kpm)
198 sum_confidence +=
value.confidence;
199 sum_positions += Eigen::Vector3f(
value.globalX,
value.globalY,
value.globalZ);
200 sum_distance +=
value.z;
210 const Eigen::Vector3f mean_position = sum_positions * (1.0 / amount);
211 const float mean_confidence = sum_confidence / amount;
212 const float mean_distance = sum_distance / amount;
213 ARMARX_DEBUG <<
"Found a human at a distance of " << sum_distance <<
"mm with confidence "
214 << mean_confidence <<
".";
216 if (sum_distance < closest_human.distance and
217 mean_confidence >= m_human_confidence_filter_value)
219 closest_human.mean_position = mean_position;
220 closest_human.distance = mean_distance;
221 closest_human.index = i;
222 closest_human.keypoints = kpml[i];
223 closest_human.confidence = mean_confidence;
224 closest_human.valid =
true;
228 return closest_human;
231 HumanObstacleDetection::HumanApproximation
232 HumanObstacleDetection::approximate_human(
const OpenPoseResult& closest_human)
236 std::map<std::string, std::pair<IceUtil::Time, Eigen::Vector2f>>
237 transformed_points_with_timestamp;
240 if (m_pose_buffer_fillctr > 0)
242 auto& pose_buf = m_pose_buffer.getUpToDateReadBuffer();
243 for (
unsigned int i = 0; i < m_pose_buffer_fillctr; ++i)
245 for (
const auto& [key, timestamped_keypoint] : pose_buf[i].transformed_keypoints)
247 IceUtil::Time keypoint_timestamp = timestamped_keypoint.first;
248 if (closest_human.timestamp - keypoint_timestamp > m_keypoint_after)
250 transformed_points_with_timestamp[key] = timestamped_keypoint;
257 for (
const auto& [key,
value] : closest_human.keypoints)
266 transformed_points_with_timestamp[key] =
267 std::make_pair(closest_human.timestamp, Eigen::Vector2f{pos(0), pos(1)});
274 unsigned int amount = 0;
275 for (
const auto& [key, timestamped_keypoint] : transformed_points_with_timestamp)
277 Eigen::Vector2f keypoint = timestamped_keypoint.second;
279 sum_x += keypoint(0);
280 sum_y += keypoint(1);
285 Eigen::Vector2f
mean = Eigen::Vector2f::Zero();
288 mean = Eigen::Vector2f{sum_x / amount, sum_y / amount};
292 float max_distance = 0;
293 for (
const auto& [key, timestamped_keypoint] : transformed_points_with_timestamp)
295 Eigen::Vector2f keypoint = timestamped_keypoint.second;
299 ARMARX_DEBUG <<
"Found positions in current frame [X,Y,Distance]: (" <<
mean(0) <<
", "
300 <<
mean(1) <<
", " << max_distance <<
").";
301 if ((last_human_approximation.valid and
mean.isZero()) or max_distance == 0.0)
304 return last_human_approximation;
308 Eigen::Vector2f velocity;
309 float velocity_length = 0.0;
311 if (m_pose_buffer_fillctr > 0)
313 Eigen::Vector2f sum{0, 0};
314 auto& pose_buf = m_pose_buffer.getUpToDateReadBuffer();
315 for (
unsigned int i = 0; i < m_pose_buffer_fillctr; ++i)
317 sum += Eigen::Vector2f{pose_buf[i].posX, pose_buf[i].posY};
319 Eigen::Vector2f temp_mean = sum / m_pose_buffer_fillctr;
320 velocity =
mean - temp_mean;
321 velocity_length = velocity.norm();
322 Eigen::Vector2f velocity_normalized = velocity.normalized();
324 const float cross_product = velocity_normalized(1);
325 const float dot_product = velocity_normalized(0);
326 yaw = acos(dot_product);
328 if (cross_product < 0)
330 yaw = 2 *
M_PI - yaw;
334 ARMARX_DEBUG <<
"Got yaw: " << yaw <<
" and velocity vector " << velocity <<
" and length "
335 << velocity_length <<
".";
336 float velocity_multiplier = velocity_length / 15.0;
338 HumanApproximation current_frame_human;
339 current_frame_human.valid =
true;
340 current_frame_human.transformed_keypoints = transformed_points_with_timestamp;
341 current_frame_human.posX =
mean(0);
342 current_frame_human.posY =
mean(1);
343 current_frame_human.axisLengthX = max_distance * velocity_multiplier;
344 current_frame_human.axisLengthY = max_distance;
345 current_frame_human.yaw = yaw;
346 current_frame_human.timestamp = closest_human.timestamp;
349 auto& buf = m_pose_buffer.getWriteBuffer();
350 buf.at(m_pose_buffer_index++) = current_frame_human;
351 m_pose_buffer_index %= buf.size();
352 m_pose_buffer.commitWrite();
353 ++m_pose_buffer_fillctr;
354 m_pose_buffer_fillctr =
std::min(m_pose_buffer_fillctr,
static_cast<unsigned int>(buf.size()));
357 HumanApproximation mean_frame_human = current_frame_human;
358 if (m_pose_buffer_fillctr > 0)
360 Eigen::Vector2f pose_sum{0, 0};
361 Eigen::Vector2f axis_length_sum{0, 0};
362 double sum_cos_yaw = 0;
363 double sum_sin_yaw = 0;
364 auto& pose_buf = m_pose_buffer.getUpToDateReadBuffer();
365 for (
unsigned int i = 0; i < m_pose_buffer_fillctr; ++i)
367 pose_sum += Eigen::Vector2f{pose_buf[i].posX, pose_buf[i].posY};
368 axis_length_sum += Eigen::Vector2f{pose_buf[i].axisLengthX, pose_buf[i].axisLengthY};
369 sum_sin_yaw += std::sin(pose_buf[i].yaw);
370 sum_cos_yaw += std::cos(pose_buf[i].yaw);
372 mean_frame_human.posX = pose_sum(0) / m_pose_buffer_fillctr;
373 mean_frame_human.posY = pose_sum(1) / m_pose_buffer_fillctr;
378 if (velocity_length > m_min_velocity_treshold)
380 double mean_yaw = std::atan2((1.0 / m_pose_buffer_fillctr) * sum_sin_yaw,
381 (1.0 / m_pose_buffer_fillctr) * sum_cos_yaw);
384 mean_yaw += 2.0 *
M_PI;
387 mean_frame_human.yaw = mean_yaw;
391 mean_frame_human.yaw = last_human_approximation.yaw;
395 last_human_approximation = mean_frame_human;
396 return mean_frame_human;
402 std::lock_guard l{m_human_mutex};
403 const bool is_data_outdated =
404 (IceUtil::Time::now() - last_human_approximation.timestamp) > m_keypoint_after;
405 if (last_human_approximation.valid and is_data_outdated)
407 ARMARX_IMPORTANT <<
"Have not seen a human for " << m_keypoint_after <<
". "
408 <<
"Deleting obstacle.";
409 HumanApproximation human;
410 last_human_approximation = human;
412 m_obstacle_manager->remove_obstacle(
"human");
419 std::lock_guard l{m_enabled_mutex};
426 std::lock_guard l{m_enabled_mutex};
433 std::lock_guard l{m_enabled_mutex};
448 def->
topic<armarx::OpenPose3DListener>(
"OpenPoseEstimation3D");
450 def->component(m_obstacle_manager,
451 "DynamicObstacleManager",
453 "The name of the obstacle manager proxy");
455 def->optional(m_enabled,
"ActivateOnStartup",
"Activate the component on startup.");
456 def->optional(m_onlyUseFirstNResults,
457 "OnlyUseFirstNResults",
458 "Only use the first n results of OpenPose.");
459 def->optional(m_keypoint_after,
460 "ForgetOpenPoseKeypointAfter",
461 "Forget the OpenPose keypoints after X ms if not visible anymore.");
462 def->optional(m_min_velocity_treshold,
463 "MinVelocityThreshold",
464 "Velocities below this value will be considered zero.");
465 def->optional(m_human_confidence_filter_value,
466 "HumanConfidenceFilterValue",
467 "Poses with a mean confidence below this value will be discarded.");
469 m_warn_distance,
"WarnDistance",
"Distance in [mm] at which a warning should be issued.")