58 const std::string Component::defaultName =
"handover_costmap_provider";
130 if (not costmapUpdateTask->isRunning())
132 ARMARX_INFO <<
"Starting handover costmap update task.";
133 costmapUpdateTask->start();
140 if (costmapUpdateTask->isRunning())
142 ARMARX_INFO <<
"Stopping handover costmap update task.";
143 costmapUpdateTask->stop();
155 return Component::defaultName;
161 return Component::defaultName;
249 while (costmapUpdateTask->isRunning())
252 readObstacleDistanceMap();
256 computeHandoverCostmap();
258 metronome.waitForNextTick();
263 Component::computeHandoverCostmap()
265 if (!obstacleDistanceMap.has_value())
268 <<
"Cannot compute handover costmap: no obstacle distance map available";
272 if (detectedHumans.empty())
275 <<
"No humans detected, skipping handover costmap computation";
279 algorithms::costmap::HandoverCostmapBuilder builder{obstacleDistanceMap->params(),
280 properties.handoverCostmapParams};
282 std::vector<armem::human::HumanPose> otherHumans;
283 if (detectedHumans.size() > 1)
286 detectedHumans | ranges::views::drop(1) |
287 ranges::views::filter(
288 [](
const armem::human::MemoryResolvedPersonInstance& personInstance)
noexcept
289 {
return personInstance.
humanPose.has_value(); }) |
290 ranges::views::transform(
291 [](
const armem::human::MemoryResolvedPersonInstance& personInstance)
noexcept
292 {
return personInstance.
humanPose.value(); }) |
296 algorithms::costmap::HandoverCostmapBuilder::SceneInformation sceneInfo{
297 .humanPose = detectedHumans.front().humanPose.value(),
298 .otherHumans = otherHumans,
299 .distanceMap = obstacleDistanceMap.value(),
303 const auto handoverCostmap = builder.create(sceneInfo);
306 const auto global_T_robot_opt = builder.getOptimalHandoverPose(sceneInfo);
311 const auto costmapDuration = ts2 - ts1;
312 const auto optimalPoseDuration = ts3 - ts2;
314 ARMARX_INFO <<
"Handover costmap computed in " << costmapDuration.toMilliSeconds()
316 ARMARX_INFO <<
"Optimal pose computed in " << optimalPoseDuration.toMilliSeconds()
320 if (!global_T_robot_opt.has_value())
328 const auto robotDescription = services.virtualRobotReaderPlugin->get().queryDescription(
332 services.virtualRobotReaderPlugin->get().getRobot(properties.robot.name);
334 <<
"Robot '" << properties.robot.name <<
"' not found in RobotStateMemory.";
336 ARMARX_CHECK(services.virtualRobotReaderPlugin->get().synchronizeRobot(
338 <<
"Failed to synchronize robot '" << properties.robot.name <<
"'.";
340 viz::Layer layer =
arviz.layer(
"optimal_handover_pose");
342 viz::Robot vizRobot(
"optimal_handover_robot");
343 vizRobot.useCollisionModel();
344 vizRobot.file(robotDescription->xml);
345 vizRobot.joints(robot->getJointValues());
346 vizRobot.pose(
conv::to3D(global_T_robot_opt.value()));
355 Component::readObstacleDistanceMap()
357 const memory::client::costmap::Reader::Query query{
358 .providerName = properties.obstacleDistanceMap.providerName,
359 .name = properties.obstacleDistanceMap.name,
362 const auto result = services.costmapReaderPlugin->get().query(query);
364 if (result.costmap.has_value())
366 obstacleDistanceMap.emplace(result.costmap.value());
375 Component::queryHumans()
377 detectedHumans.clear();
380 armem::human::client::PersonInstanceReader::QueryResolved query;
385 query.
providerName = properties.personInstanceProviderName;
389 const auto result = services.personInstanceReaderPlugin->get().queryResolved(query);
393 ARMARX_WARNING <<
"Failed to query person instances: " << result.errorMessage;
397 ARMARX_VERBOSE <<
"Queried " << result.personInstances.size() <<
" person instances";
398 detectedHumans = result.personInstances;