10#include <SimoxUtility/algorithm/string/string_tools.h>
32#include <armarx/navigation/skills/aron/NavigateToLocation.aron.generated.h>
35#include <range/v3/action.hpp>
36#include <range/v3/algorithm/contains.hpp>
37#include <range/v3/range/conversion.hpp>
38#include <range/v3/view/concat.hpp>
39#include <range/v3/view/filter.hpp>
40#include <range/v3/view/map.hpp>
41#include <range/v3/view/transform.hpp>
46 armarx::skills::SkillDescription
51 defaultParameters.useObjectLocations =
true;
53 defaultParameters.navigateToLocation.fromAron(
55 defaultParameters.navigateToLocation.location =
"<Resolved according to 'locationName'>";
58 description <<
"Resolve a named location and navigate to it."
59 <<
"\n\n`locationName`: The location's human-readable name."
60 <<
"\n\n`minMatchRatio`: Minimum match ratio required to accept a match "
61 "between a location's name and `locationName`."
62 <<
"\n\nThe parameters `navigateToLocation` are passed to the sub skill "
63 "`NavigateToLocation`, except for `navigateToLocation.location`, which is "
64 "set to the location that `locationName` is resolved to.";
69 .rootProfileDefaults = defaultParameters.toAron(),
71 .parametersType = Params::ToAronType(),
89 NavigateToNamedLocation::main(
const Base::SpecializedMainInput& in)
93 struct ResolvedLocation
101 const auto resolvedLocationFromObjectFn = [&]() -> std::optional<ResolvedLocation>
105 const auto objectPosesIce = objectPoseStorage->getObjectPoses();
107 const std::map<armarx::ObjectID, armem::clazz::ObjectClass> objectClasses =
117 if(not ranges::contains(ranges::views::keys(objectClasses),
118 pose.objectID.getClassID(),
120 { return oid.getClassID(); }))
122 ARMARX_VERBOSE <<
"Requested to match object but there is no match";
126 const auto& objectClass = objectClasses.at(pose.objectID.getClassID());
127 const auto& recognizedNames = objectClass.names.recognized;
130 return ranges::contains(recognizedNames,
131 simox::alg::to_lower(in.parameters.locationName),
132 simox::alg::to_lower);
136 const std::vector<objpose::ObjectPose> matchingObjects =
137 objectPoses | ranges::views::filter(isMatchingObject) | ranges::to<std::vector>();
139 ARMARX_INFO <<
"Found " << matchingObjects.size() <<
" objects matching location name '"
140 << in.parameters.locationName <<
"'.";
144 const auto getMatchingLocation = [&](
const objpose::ObjectPose& pose)
145 -> std::vector<armarx::navigation::core::Location>
147 const std::string locationName = pose.objectID.getClassID().str() +
"/inFrontOf";
148 const std::string locationNameWithInstance =
149 pose.objectID.getClassID().str() +
"/inFrontOf:" + pose.objectID.instanceName();
151 const auto matchingLocations =
153 ARMARX_INFO <<
"Found " << matchingLocations.size() <<
" locations matching name "
154 <<
QUOTED(locationName) <<
".";
156 const auto matchingLocationsWithInstance =
158 locationNameWithInstance,
160 ARMARX_INFO <<
"Found " << matchingLocationsWithInstance.size()
161 <<
" locations matching name " <<
QUOTED(locationNameWithInstance)
164 const auto appendLocationInstanceName =
165 [&pose](core::Location loc) -> core::Location
167 loc.name +=
":" + pose.objectID.instanceName();
172 const auto matchingLocationsWithAppendedInstance =
173 matchingLocations | ranges::views::transform(appendLocationInstanceName) |
174 ranges::to<std::vector>();
176 return ranges::views::concat(matchingLocationsWithAppendedInstance,
177 matchingLocationsWithInstance) |
178 ranges::to<std::vector>();
182 std::vector<armarx::navigation::core::Location> associatedLocations;
183 for (
const auto& matchingObject : matchingObjects)
185 const auto locationsForObject = getMatchingLocation(matchingObject);
186 for (
const core::Location& loc : locationsForObject)
189 <<
" for matching object " <<
QUOTED(matchingObject.objectID.str())
191 associatedLocations.push_back(loc);
195 ARMARX_INFO <<
"Found total of " << associatedLocations.size()
196 <<
" associated locations for matching objects.";
198 for (
const auto& loc : associatedLocations)
203 if (associatedLocations.empty())
208 if (associatedLocations.size() > 1)
210 ARMARX_WARNING <<
"Multiple associated locations found for matching objects. Using "
214 const auto& firstLocation = *associatedLocations.begin();
216 return ResolvedLocation{.name = firstLocation.name, .provider = firstLocation.provider};
221 const auto resolvedLocationFromKnownLocationsFn = [&]() -> std::optional<ResolvedLocation>
223 std::stringstream log;
225 services.locationReader->resolveLocationName(in.parameters.locationName,
226 in.parameters.minMatchRatio,
230 ARMARX_CHECK(matchResult.resolved.has_value() xor matchResult.errorMessage.has_value());
232 if (matchResult.errorMessage.has_value())
234 ARMARX_INFO <<
"Failed to resolve location name '" << in.parameters.locationName
235 <<
"'. Reason: " << matchResult.errorMessage.value();
240 return ResolvedLocation{.name = matchResult.resolved->locationId.entityName,
242 matchResult.resolved->locationId.providerSegmentName};
246 std::optional<ResolvedLocation> resolvedLocation;
248 if (in.parameters.useObjectLocations)
250 const auto resolvedLocationFromObject = resolvedLocationFromObjectFn();
251 if (resolvedLocationFromObject.has_value())
253 resolvedLocation = resolvedLocationFromObject;
254 ARMARX_INFO <<
"Resolved location name '" << in.parameters.locationName
255 <<
"' to location associated with matching object.";
259 if (not resolvedLocation.has_value())
261 const auto resolvedLocationFromKnownLocations = resolvedLocationFromKnownLocationsFn();
263 if (resolvedLocationFromKnownLocations.has_value())
265 resolvedLocation = resolvedLocationFromKnownLocations;
266 ARMARX_INFO <<
"Resolved location name '" << in.parameters.locationName
267 <<
"' to known location: "
268 <<
QUOTED(resolvedLocation->provider +
"::" + resolvedLocation->name)
273 if (not resolvedLocation.has_value())
275 ARMARX_ERROR <<
"Could not resolve location name '" << in.parameters.locationName
276 <<
"' to any location.";
281 <<
QUOTED(resolvedLocation->provider +
"::" + resolvedLocation->name)
288 using ParamsT = arondto::NavigateToLocationParams;
294 [&resolvedLocation, &in](ParamsT&
parameters)
noexcept
297 parameters = in.parameters.navigateToLocation;
299 parameters.location = resolvedLocation->name;
300 parameters.locationProvider =
301 resolvedLocation->provider;
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
std::map< armarx::ObjectID, armem::clazz::ObjectClass > getAllObjectClasses()
static Duration Hours(std::int64_t hours)
Constructs a duration in hours.
std::vector< core::Location > locations()
static armarx::skills::SkillDescription DefaultSkillDescription()
::armarx::skills::SkillDescription GetSkillDescription()
::armarx::skills::SimpleSpecializedSkill< Params > Base
NavigateToNamedLocation(const Properties &properties, const Services &services)
const ObjectPoseStorageInterfacePrx & getObjectPoseStorage() const
Get the object pose storage's proxy.
arondto::NavigateToNamedLocationParams ParamType
std::optional< TerminatedSkillStatusUpdate > callSubskill(const SkillID &skillId)
Call a subskill with the given ID and its default parameters.
static MainResult MakeSucceededResult(aron::data::DictPtr data=nullptr)
armarx::aron::data::DictPtr parameters
SkillDescription description
void throwIfSkillShouldTerminate(const std::string &abortedMessage="") const
static MainResult MakeFailedResult(aron::data::DictPtr data=nullptr)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
std::vector< core::Location > findMatchingLocations(const std::vector< core::Location > &locations, const std::string &locationName, const std::optional< std::string > &provider)
const armarx::skills::SkillID NavigateToNamedLocation
std::vector< ObjectPose > ObjectPoseSeq
void fromIce(const Box &box, simox::OrientedBox< float > &oobb)
bool skillExecutionFailed(const std::optional< armarx::skills::TerminatedSkillStatusUpdate > &update)
This file offers overloads of toIce() and fromIce() functions for STL container types.
This file is part of ArmarX.
This file is part of ArmarX.
armarx::skills::SkillID navigateToLocation
armarx::navigation::memory::client::graph::Reader * locationReader
objpose::ObjectPoseClient objectPoseClient
armarx::armem::obj::clazz::ClassReader * objectClassReader
An object pose as stored by the ObjectPoseStorage.
A result struct for th main method of a skill.