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(),
300 .humanPose2DOverride = std::nullopt,
301 .robotPosition = std::nullopt,
305 const auto handoverCostmap = builder.create(sceneInfo);
308 const auto global_T_robot_opt = builder.getOptimalHandoverPose(sceneInfo);
313 const auto costmapDuration = ts2 - ts1;
314 const auto optimalPoseDuration = ts3 - ts2;
316 ARMARX_INFO <<
"Handover costmap computed in " << costmapDuration.toMilliSeconds()
318 ARMARX_INFO <<
"Optimal pose computed in " << optimalPoseDuration.toMilliSeconds()
322 if (!global_T_robot_opt.has_value())
330 const auto robotDescription = services.virtualRobotReaderPlugin->get().queryDescription(
334 services.virtualRobotReaderPlugin->get().getRobot(properties.robot.name);
336 <<
"Robot '" << properties.robot.name <<
"' not found in RobotStateMemory.";
338 ARMARX_CHECK(services.virtualRobotReaderPlugin->get().synchronizeRobot(
340 <<
"Failed to synchronize robot '" << properties.robot.name <<
"'.";
342 viz::Layer layer =
arviz.layer(
"optimal_handover_pose");
344 viz::Robot vizRobot(
"optimal_handover_robot");
345 vizRobot.useCollisionModel();
346 vizRobot.file(robotDescription->xml);
347 vizRobot.joints(robot->getJointValues());
348 vizRobot.pose(
conv::to3D(global_T_robot_opt.value()));
357 Component::readObstacleDistanceMap()
359 const memory::client::costmap::Reader::Query query{
360 .providerName = properties.obstacleDistanceMap.providerName,
361 .name = properties.obstacleDistanceMap.name,
364 const auto result = services.costmapReaderPlugin->get().query(query);
366 if (result.costmap.has_value())
368 obstacleDistanceMap.emplace(result.costmap.value());
377 Component::queryHumans()
379 detectedHumans.clear();
382 armem::human::client::PersonInstanceReader::QueryResolved query;
387 query.
providerName = properties.personInstanceProviderName;
391 const auto result = services.personInstanceReaderPlugin->get().queryResolved(query);
395 ARMARX_WARNING <<
"Failed to query person instances: " << result.errorMessage;
399 ARMARX_VERBOSE <<
"Queried " << result.personInstances.size() <<
" person instances";
400 detectedHumans = result.personInstances;