LookAtObject.cpp
Go to the documentation of this file.
1#include "LookAtObject.h"
2
3#include <vector>
4
5#include <Eigen/Core>
6#include <Eigen/Geometry>
7
8#include <range/v3/algorithm/max_element.hpp>
9#include <range/v3/range/conversion.hpp>
10#include <range/v3/view/transform.hpp>
11
12#include <SimoxUtility/shapes/AxisAlignedBoundingBox.h>
13#include <SimoxUtility/shapes/OrientedBox.h>
14
20#include <ArmarXCore/interface/core/UserException.h>
21
33
34#include <armarx/view_selection/gaze_targets/aron/AttentionType.aron.generated.h>
35#include <armarx/view_selection/gaze_targets/aron/GazeTarget.aron.generated.h>
36#include <armarx/view_selection/skills/aron/LookAt.aron.generated.h>
37#include <armarx/view_selection/skills/aron/LookAtObject.aron.generated.h>
40
42{
44 {
45 }
46
48 LookAtObject::init(const Base::SpecializedInitInput& in)
49 {
50 return ::armarx::skills::Skill::InitResult{
52 }
53
55 LookAtObject::main(const Base::SpecializedMainInput& in)
56 {
57
58 ObjectID objectID;
59 fromAron(in.parameters.object, objectID);
60
61 ARMARX_INFO << "Querying object " << QUOTED(objectID);
62
63 const auto result = srv_.objectInstanceReader->queryLatestObjectInstance(objectID);
64
65 if (not result)
66 {
67 ARMARX_INFO << "Memory query did not provide any observation for " << objectID;
68 return MakeFailedResult();
69 }
70
71 // make sure that the instance name is set.
72 objectID = result->objectID;
73
74 const simox::OrientedBoxf oobb = [&]()
75 {
76 if (result->localOOBB.has_value())
77 {
78 return result->localOOBB.value();
79 }
80
81 // fallback: load from file system
82 {
83 auto finder = ObjectFinder();
84 auto objectClassInfoOpt = finder.findObject(objectID);
85 ARMARX_CHECK_NOT_NULL(objectClassInfoOpt);
86
87 const auto& objectClassInfo = objectClassInfoOpt.value();
88
89 const auto oobbOpt = objectClassInfo.loadOOBB();
90 ARMARX_CHECK_NOT_NULL(oobbOpt);
91
92 const simox::OrientedBoxf& oobb = oobbOpt.value();
93 return oobb;
94 }
95 }();
96
97
98 const armarx::objpose::ObjectPose& objectObservation = result.value();
99
100
101 const Eigen::Vector3f global_P_obj = [&]() -> Eigen::Vector3f
102 {
103 const Eigen::Isometry3f globalObjectPose{objectObservation.objectPoseGlobal};
104
105 ARMARX_INFO << "Object global position " << globalObjectPose.translation();
106
107 using armarx::view_selection::skills::arondto::PointOnObject;
108 switch (in.parameters.pointOnObject.value)
109 {
110 case PointOnObject::Center:
111 {
112 const Eigen::Vector3f globalObjectCenter =
113 globalObjectPose * (oobb.center() + in.parameters.pointOnObjectOffset);
114
115 return globalObjectCenter;
116 break;
117 }
118 case PointOnObject::BoundingBoxTopCenter:
119 {
120 // All 8 permutations
121 const std::vector<Eigen::Vector3f> faceCenterMultipliers{
122 Eigen::Vector3f::UnitX(),
123 -Eigen::Vector3f::UnitX(),
124 Eigen::Vector3f::UnitY(),
125 -Eigen::Vector3f::UnitY(),
126 Eigen::Vector3f::UnitZ(),
127 -Eigen::Vector3f::UnitZ(),
128 };
129
130 const auto applyTransformation =
131 [&globalObjectPose,
132 &oobb,
133 pointOnObjectOffset = in.parameters.pointOnObjectOffset](
134 const Eigen::Vector3f& faceMultiplier) -> Eigen::Vector3f
135 {
136 const Eigen::Vector3f shift =
137 Eigen::Vector3f(oobb.dimensions() / 2) +
138 Eigen::Vector3f{Eigen::Vector3f(oobb.dimensions() / 2).array() *
139 faceMultiplier.array()};
140
141
142 return Eigen::Vector3f{globalObjectPose * oobb.from_box_frame(shift) +
143 pointOnObjectOffset};
144
145
146 // const Eigen::Isometry3f globalObjectBB =
147 // globalObjectPose * Eigen::Isometry3f{oobb.transformation()};
148
149
150 // return globalObjectBB * shift;
151 };
152
153 const std::vector<Eigen::Vector3f> globalObjectSurfaceCenters =
154 faceCenterMultipliers | ranges::views::transform(applyTransformation) |
155 ranges::to_vector;
156
157 const std::vector<float> height =
158 globalObjectSurfaceCenters |
159 ranges::views::transform([](const Eigen::Vector3f& v) { return v.z(); }) |
160 ranges::to_vector;
161
162 const auto it = ranges::max_element(height);
163
164 const Eigen::Vector3f& highestSurfaceCenter =
165 globalObjectSurfaceCenters.at(std::distance(height.begin(), it));
166
167 return highestSurfaceCenter;
168
169 break;
170 }
171 default:
172 throw armarx::InvalidArgumentException("should not get here");
173 }
174 }();
175
176 ARMARX_INFO << "Looking at global position " << global_P_obj;
177
178 // check whether the position is valid
179 if (in.parameters.permissibleRegionGlobalFrame.has_value())
180 {
182 << "Permissible region provided. Will check whether object position is valid.";
183
185 srv_.virtualRobotReader.synchronizeRobot(*srv_.robot, armarx::Clock::Now()));
186
187 const Eigen::Isometry3f global_T_root{srv_.robot->getGlobalPose()};
188 const Eigen::Vector3f root_P_obj = global_T_root.inverse() * global_P_obj;
189
190 ::simox::OrientedBoxf bb;
191 fromAron(in.parameters.permissibleRegionGlobalFrame.value(), bb);
192
193 ARMARX_INFO << VAROUT(root_P_obj);
194 ARMARX_INFO << VAROUT(bb.center());
195 // ARMARX_INFO << VAROUT(bb.extents());
196
197 if (bb.contains(root_P_obj))
198 {
199 ARMARX_INFO << "Object position is inside permissible region.";
200 // We are good to go. We can continue.
201 }
202 else
203 {
204 ARMARX_INFO << "Object position is outside permissible region.";
205 return MakeFailedResult();
206 }
207 }
208 // check whether the position is valid
209 else if (in.parameters.permissibleRegionRobotFrame.has_value())
210 {
212 << "Permissible region provided. Will check whether object position is valid.";
213
215 srv_.virtualRobotReader.synchronizeRobot(*srv_.robot, armarx::Clock::Now()));
216
217 const Eigen::Isometry3f global_T_root{srv_.robot->getGlobalPose()};
218 const Eigen::Vector3f root_P_obj = global_T_root.inverse() * global_P_obj;
219
220 ::simox::AxisAlignedBoundingBox bb;
221 fromAron(in.parameters.permissibleRegionRobotFrame.value(), bb);
222
223 ARMARX_INFO << VAROUT(root_P_obj);
224 ARMARX_INFO << VAROUT(bb.center());
225 ARMARX_INFO << VAROUT(bb.extents());
226
227 if (bb.is_inside(root_P_obj))
228 {
229 ARMARX_INFO << "Object position is inside permissible region.";
230 // We are good to go. We can continue.
231 }
232 else
233 {
234 ARMARX_INFO << "Object position is outside permissible region.";
235 return MakeFailedResult();
236 }
237 }
238
239 // generate view target
240 const armarx::view_selection::gaze_targets::arondto::GazeTarget gazeTarget = [&]()
241 {
242 armarx::view_selection::gaze_targets::arondto::GazeTarget gazeTarget;
243 gazeTarget.name = "LookAtObject_" + objectID.str();
244
245 gazeTarget.position.header.agent = ""; // not needed
246 gazeTarget.position.header.frame = armarx::GlobalFrame; // not needed
247
248 gazeTarget.position.position = global_P_obj;
249
250 gazeTarget.duration =
251 armarx::core::time::Duration::SecondsDouble(in.parameters.durationSeconds);
252
253 gazeTarget.priority.attentionType =
254 gaze_targets::arondto::AttentionType::ImplEnum::TaskDriven;
255 gazeTarget.priority.priority = in.parameters.priority;
256
257 gazeTarget.creationTimestamp = Clock::Now();
258 gazeTarget.keepInQueue = false;
259
260 return gazeTarget;
261 }();
262
263 // execute subskill
264 {
265 using Parameters = armarx::view_selection::skills::arondto::LookAtParams;
266
267 // prepare skill id
268 const ::armarx::skills::SkillID skillId{
269 .providerId =
270 ::armarx::skills::ProviderID{.providerName = armarx::view_selection::skills::
271 constants::ViewSelectionSkillProviderName},
273
274
275 // call subskill using skill id and a parameter-update function that returns the aron parameters
276 auto update = callSubskill<Parameters>(skillId,
277 [&gazeTarget](Parameters& subSkillParams)
278 { subSkillParams.target = gazeTarget; });
279
281 {
282 return MakeFailedResult();
283 }
284 }
285
286 return MakeSucceededResult();
287 }
288
289 void
290 LookAtObject::onStopRequested()
291 {
292 }
293
294 ::armarx::skills::SkillDescription
296 {
297 Params defaults;
298 defaults.priority = 100;
299 //defaults.maxObservationAgeSeconds = 15 * 60; // quater of an hour
300 defaults.durationSeconds = 20;
301 defaults.pointOnObject = armarx::view_selection::skills::arondto::PointOnObject::Center;
302 defaults.pointOnObjectOffset = Eigen::Vector3f::Zero();
303 defaults.permissibleRegionGlobalFrame = std::nullopt;
304 defaults.permissibleRegionRobotFrame = std::nullopt;
305
307 .skillId = skill_ids::LookAtObject,
308 .description = "Look at the location where an instance of the object class has most "
309 "recently been seen.",
310 .rootProfileDefaults = defaults.toAron(),
311 .timeout = armarx::Duration::Minutes(5),
312 .parametersType = Params::ToAronType(),
313 .resultType = Result::ToAronType(),
314 };
315 }
316
317} // namespace armarx::view_selection::skills
#define VAROUT(x)
#define QUOTED(x)
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
static Duration Minutes(std::int64_t minutes)
Constructs a duration in minutes.
Definition Duration.cpp:96
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
Definition ObjectID.h:11
std::string str() const
Return "dataset/className" or "dataset/className/instanceName".
Definition ObjectID.cpp:60
static Duration SecondsDouble(double seconds)
Constructs a duration in seconds.
Definition Duration.cpp:78
std::optional< TerminatedSkillStatusUpdate > callSubskill(const SkillID &skillId)
Call a subskill with the given ID and its default parameters.
Definition Skill.cpp:119
static MainResult MakeSucceededResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:413
static MainResult MakeFailedResult(aron::data::DictPtr data=nullptr)
Definition Skill.cpp:422
::armarx::skills::SimpleSpecializedSkill< Params > Base
static armarx::skills::SkillDescription DefaultSkillDescription()
#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.
Definition Logging.h:181
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition mongodb.cpp:68
double v(double t, double v0, double a0, double j)
Definition CtrlUtil.h:39
aron::data::DictPtr Parameters
bool skillExecutionFailed(const std::optional< armarx::skills::TerminatedSkillStatusUpdate > &update)
const armarx::skills::SkillID LookAtObject
Definition skill_ids.cpp:44
This file is part of ArmarX.
Definition constants.cpp:26
void fromAron(const arondto::PackagePath &dto, PackageFileLocation &bo)
Eigen::Matrix4f objectPoseGlobal
The object pose in the global frame.
Definition ObjectPose.h:71
A result struct for skill initialization.
Definition Skill.h:50
A result struct for th main method of a skill.
Definition Skill.h:62
std::experimental::observer_ptr<::armarx::armem::obj::instance::Reader > objectInstanceReader