HumanMemory.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package RobotAPI::ArmarXObjects::ExampleMemory
17 * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu )
18 * @date 2020
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "HumanMemory.h"
24
25#include <algorithm>
26#include <iterator>
27#include <string>
28#include <vector>
29
30#include <Ice/Current.h>
31
32#include <SimoxUtility/algorithm/apply.hpp>
33#include <VirtualRobot/VirtualRobot.h>
34
41#include <ArmarXCore/interface/core/time.h>
42
47#include <RobotAPI/interface/aron/Aron.h>
51
54#include <VisionX/libraries/armem_human/aron/FaceRecognition.aron.generated.h>
55#include <VisionX/libraries/armem_human/aron/HumanPose.aron.generated.h>
56#include <VisionX/libraries/armem_human/aron/Person.aron.generated.h>
58
60{
61
64 {
67
68 setMemoryName("Human");
69
70 profileSegment.defineProperties(defs, "profile.");
71 personInstanceSegment.defineProperties(defs, "instance");
72 poseSegment.defineProperties(defs, "pose.");
73 faceRecognitionSegment.defineProperties(defs, "face.");
74 identificationSegment.defineProperties(defs, "ident.");
75 humanActivitySegment.defineProperties(defs, "activity.");
76 humanRobotInteractionSegment.defineProperties(defs, "interaction.");
77
78 return defs;
79 }
80
82 profileSegment(iceAdapter()),
83 personInstanceSegment(iceAdapter()),
84 poseSegment(iceAdapter()),
85 faceRecognitionSegment(iceAdapter()),
86 identificationSegment(iceAdapter()),
87 humanActivitySegment(iceAdapter()),
88 humanRobotInteractionSegment(iceAdapter()),
89 visu(poseSegment, faceRecognitionSegment, personInstanceSegment)
90 {
91 addPlugin(virtualRobotReaderPlugin);
92 }
93
94 std::string
96 {
97 return "HumanMemory";
98 }
99
100 void
102 {
103 profileSegment.init();
104 personInstanceSegment.init();
105 poseSegment.init();
106 faceRecognitionSegment.init();
107 identificationSegment.init();
108 humanActivitySegment.init();
109 humanRobotInteractionSegment.init();
110 visu.init();
111
112 workingMemory().addCoreSegment("RecognizedAction");
113 }
114
115 void
117 {
118 visu.connect(arviz, getDebugObserver());
119 }
120
121 void
125
126 void
130
132 HumanMemory::getSynchronizedRobot(const std::string& robotName,
134 {
135 // seach and retrieve robot
136 auto& robot = [&]() -> VirtualRobot::RobotPtr&
137 {
138 // retrieve robot from memory if it is not in cache
139 if (robots.count(robotName) == 0)
140 {
141 auto newRobot = virtualRobotReaderPlugin->get().getRobot(robotName);
142 ARMARX_CHECK_NOT_NULL(newRobot)
143 << "Failed to obtain robot with name `" << robotName << "`.";
144
145 robots[robotName] = newRobot;
146 }
147
148 return robots.at(robotName);
149 }();
150
151 // synchronize robot
152 bool const success = virtualRobotReaderPlugin->get().synchronizeRobot(*robot, timestamp);
153
154 if (not success)
155 {
156 // throw armarx::LocalException(
157 // "Failed synchronizing the robot to calculate the global human pose from a reported "
158 // "human pose in camera coordinate system. Query timestamp is '")
159 // << timestamp << "'.";
160 return nullptr;
161 }
162
163 return robot;
164 }
165
166 void
168 const ::armarx::aron::data::dto::AronDictSeq& dictSeq,
169 const ::std::string& providerName,
170 const ::armarx::core::time::dto::DateTime& iceTimestamp,
171 const ::Ice::Current& /*c*/)
172 {
173 if (dictSeq.empty())
174 {
175 return;
176 }
177
178 // convert from ice
180 fromIce(iceTimestamp, timestamp);
181
182 // convert to our aron type
183 const auto toHumanPose = [](const ::armarx::aron::data::dto::DictPtr& dict)
184 { return armarx::human::arondto::HumanPose::FromAron(dict); };
185
186 std::vector<armarx::human::arondto::HumanPose> humanPoses =
187 simox::alg::apply(dictSeq, toHumanPose);
188
189 // synchronize robot
190 const std::string robotName =
191 humanPoses.front().keypoints.begin()->second.positionCamera.header.agent;
192
193 const auto robot = getSynchronizedRobot(robotName, timestamp);
194
195 if (not robot)
196 {
197 ARMARX_INFO << deactivateSpam(1) << "Failed to obtain robot `" << robotName
198 << "`. Won't commit poses";
199 return;
200 }
201
202 ARMARX_CHECK_NOT_NULL(robot) << "Failed to obtain robot with name `" << robotName << "`.";
203
204 // fill global pose info
205 {
206 for (armarx::human::arondto::HumanPose& humanPose : humanPoses)
207 {
208 for (auto& [_, keyPoint] : humanPose.keypoints)
209 {
210 const auto& cameraFrame = keyPoint.positionCamera.header.frame;
211 const auto& agent = keyPoint.positionCamera.header.agent;
212
213 const FramedPosition keypoint(
214 keyPoint.positionCamera.position, cameraFrame, agent);
215 // ARMARX_IMPORTANT << VAROUT(keyPoint.positionCamera.position.transpose());
216
217 // global pose
218 {
219 keyPoint.positionGlobal = armarx::arondto::FramedPosition();
220 armarx::toAron(keyPoint.positionGlobal.value(),
223 agent));
224 }
225
226 // pose in root frame
227 {
228 keyPoint.positionRobot = armarx::arondto::FramedPosition();
229 armarx::toAron(keyPoint.positionRobot.value(),
230 armarx::FramedPosition(keypoint.toRootEigen(robot),
231 robot->getRootNode()->getName(),
232 agent));
233 }
234
235 // Orientation information available.
236 if (keyPoint.orientationCamera.has_value())
237 {
238 ARMARX_CHECK_EQUAL(keyPoint.orientationCamera->header.frame,
239 keyPoint.positionCamera.header.frame);
240
241 const FramedPose keypointPose(
242 keyPoint.orientationCamera->orientation.toRotationMatrix(),
243 keyPoint.positionCamera.position,
244 cameraFrame,
245 agent);
246
247 // global pose
248 {
249 const Eigen::Isometry3f global_T_human(
250 keypointPose.toGlobalEigen(robot));
251
252 keyPoint.orientationGlobal = armarx::arondto::FramedOrientation();
253
255 keyPoint.orientationGlobal.value(),
256 armarx::FramedOrientation(Eigen::Matrix3f{global_T_human.linear()},
258 agent));
259 }
260
261 // pose in root frame
262 {
263 const Eigen::Isometry3f robot_root_T_human(
264 keypointPose.toRootEigen(robot));
265
266
267 keyPoint.orientationRobot = armarx::arondto::FramedOrientation();
268
269 armarx::toAron(keyPoint.orientationRobot.value(),
271 Eigen::Matrix3f{robot_root_T_human.linear()},
272 robot->getRootNode()->getName(),
273 agent));
274 }
275 }
276 }
277 }
278 }
279
280 // commit human poses
281 commitHumanPoses(humanPoses, providerName, timestamp);
282 }
283
284 void
286 const ::armarx::aron::data::dto::AronDictSeq& dictSeq,
287 const ::std::string& providerName,
288 const ::armarx::core::time::dto::DateTime& iceTimestamp,
289 const ::Ice::Current& /*c*/)
290 {
291 if (dictSeq.empty())
292 {
293 return;
294 }
295
296 // convert from ice
298 fromIce(iceTimestamp, timestamp);
299
300 // convert to our aron type
301 const auto toPersonFace = [](const ::armarx::aron::data::dto::DictPtr& dict)
302 { return armarx::human::arondto::FaceRecognition::FromAron(dict); };
303
304 std::vector<armarx::human::arondto::FaceRecognition> personFaces =
305 simox::alg::apply(dictSeq, toPersonFace);
306
307 // synchronize robot
308 const std::string robotName = "Armar7"; // TODO: Get robot name
309
310 const auto robot = getSynchronizedRobot(robotName, timestamp);
311
312 if (not robot)
313 {
314 ARMARX_INFO << deactivateSpam(1) << "Failed to obtain robot `" << robotName
315 << "`. Won't commit poses";
316 return;
317 }
318
319 ARMARX_CHECK_NOT_NULL(robot) << "Failed to obtain robot with name `" << robotName << "`.";
320
321 // fill global pose info
322 {
323 for (armarx::human::arondto::FaceRecognition& personFace : personFaces)
324 {
326 fromAron(personFace.framedPosition3D, fp);
327 personFace.position3DGlobal = fp.toGlobalEigen(robot);
328 }
329 }
330
331 // commit human poses
332 commitPersonFaces(personFaces, providerName, timestamp);
333 }
334
335 void
337 const std::vector<::armarx::human::arondto::HumanPose>& humanPoses,
338 const std::string& providerName,
340 {
342
343 const auto providerId = armem::MemoryID(
345 const auto entityID = providerId.withEntityName("human_poses").withTimestamp(timestamp);
346
347 armem::EntityUpdate update;
348 update.entityID = entityID;
349 update.sentTime = timestamp; // TODO this is not fully correct
350 update.referencedTime = timestamp;
351
352 std::transform(
353 humanPoses.begin(),
354 humanPoses.end(),
355 std::back_inserter(update.instancesData),
356 [](const ::armarx::human::arondto::HumanPose& humanPose) -> armarx::aron::data::DictPtr
357 { return humanPose.toAron(); });
358
359 commit.add(update);
360
361 ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
362
364 }
365
366 void
368 const std::vector<::armarx::human::arondto::FaceRecognition>& personFaces,
369 const std::string& providerName,
371 {
373
374 const auto providerId = armem::MemoryID(
376 const auto entityID = providerId.withEntityName("human_poses").withTimestamp(timestamp);
377
378 armem::EntityUpdate update;
379 update.entityID = entityID;
380 update.sentTime = timestamp; // TODO this is not fully correct
381 update.referencedTime = timestamp;
382
383 std::transform(personFaces.begin(),
384 personFaces.end(),
385 std::back_inserter(update.instancesData),
386 [](const ::armarx::human::arondto::FaceRecognition& personFace)
387 -> armarx::aron::data::DictPtr { return personFace.toAron(); });
388
389 commit.add(update);
390
391 ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
392
394 }
395
396 void
397 HumanMemory::commitHumanProfiles(const ::armarx::aron::data::dto::AronDictSeq& dictSeq,
398 const ::std::string& providerName,
399 const ::armarx::core::time::dto::DateTime& iceTimestamp,
400 const ::std::string& entityName,
401 const ::Ice::Current& /*unused*/)
402 {
403 if (dictSeq.empty())
404 {
405 return;
406 }
407
408 // convert from ice
410 fromIce(iceTimestamp, timestamp);
411
412 // convert to our aron type
413 const auto toHumanProfile = [](const ::armarx::aron::data::dto::DictPtr& dict)
414 { return armarx::human::arondto::Person::FromAron(dict); };
415
416 std::vector<armarx::human::arondto::Person> humanProfiles =
417 simox::alg::apply(dictSeq, toHumanProfile);
418
419 ARMARX_DEBUG << "Collected all information on human profile from ice call"
420 << "\n"
421 << "entityName: " << entityName;
422
423 //call actual commit method
424 this->commitHumanProfilesA(humanProfiles, providerName, timestamp, entityName);
425 }
426
427 void
429 const std::vector<armarx::human::arondto::Person>& humanProfiles,
430 const ::std::string& providerName,
432 const ::std::string& entityName)
433 {
435 const auto providerId = armem::MemoryID(
437 const auto entityID = providerId.withEntityName(entityName).withTimestamp(timestamp);
438
439 armem::EntityUpdate update;
440 update.entityID = entityID;
441 update.sentTime = timestamp; // TODO this is not fully correct
442 update.referencedTime = timestamp;
443
444 for (const auto& humanProfile : humanProfiles)
445 {
446 update.instancesData.push_back(humanProfile.toAron());
447 }
448
449 commit.add(update);
450
451 ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
452
454 }
455} // namespace armarx::armem::server::human_memory
std::string timestamp()
Default component property definition container.
Definition Component.h:70
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
const DebugObserverInterfacePrx & getDebugObserver() const
The FramedOrientation class.
Definition FramedPose.h:216
The FramedPose class.
Definition FramedPose.h:281
Eigen::Matrix4f toGlobalEigen(const SharedRobotInterfacePrx &referenceRobot) const
Eigen::Matrix4f toRootEigen(const SharedRobotInterfacePrx &referenceRobot) const
The FramedPosition class.
Definition FramedPose.h:158
Eigen::Vector3f toGlobalEigen(const SharedRobotInterfacePrx &referenceRobot) const
Eigen::Vector3f toRootEigen(const SharedRobotInterfacePrx &referenceRobot) const
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
data::CommitResult commitLocking(const data::Commit &commitIce, Time timeArrived)
static const std::string CORE_SEGMENT_NAME
Definition PoseSegment.h:50
static const std::string CORE_SEGMENT_NAME
Definition Segment.h:38
static const std::string CORE_SEGMENT_NAME
Definition Segment.h:35
void commitHumanProfiles(const ::armarx::aron::data::dto::AronDictSeq &dictSeq, const ::std::string &providerName, const ::armarx::core::time::dto::DateTime &timestamp, const std::string &entityName, const ::Ice::Current &=::Ice::emptyCurrent) override
void onInitComponent() override
Pure virtual hook for the subclass.
void onDisconnectComponent() override
Hook for subclass.
void commitPersonFaces(const std::vector<::armarx::human::arondto::FaceRecognition > &personFaces, const std::string &providerName, const armarx::DateTime &timestamp)
void commitHumanPosesInCameraFrame(const ::armarx::aron::data::dto::AronDictSeq &dictSeq, const ::std::string &providerName, const ::armarx::core::time::dto::DateTime &timestamp, const ::Ice::Current &=::Ice::emptyCurrent) override
VirtualRobot::RobotPtr getSynchronizedRobot(const std::string &robotName, const armarx::DateTime &timestamp)
void commitHumanProfilesA(const std::vector< armarx::human::arondto::Person > &humanProfiles, const ::std::string &providerName, const armarx::DateTime &timestamp, const ::std::string &entityName)
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Creates the property definition container.
void commitPersonFacesInCameraFrame(const ::armarx::aron::data::dto::AronDictSeq &dictSeq, const ::std::string &providerName, const ::armarx::core::time::dto::DateTime &timestamp, const ::Ice::Current &=::Ice::emptyCurrent) override
void onConnectComponent() override
Pure virtual hook for the subclass.
void commitHumanPoses(const std::vector<::armarx::human::arondto::HumanPose > &humanPoses, const std::string &providerName, const armarx::DateTime &timestamp)
void onExitComponent() override
Hook for subclass.
std::string getDefaultName() const override
Retrieve default name of component.
virtual data::CommitResult commit(const data::Commit &commit, const Ice::Current &=Ice::emptyCurrent) override
CoreSegment & addCoreSegment(const std::string &name, Args... args)
Represents a point in time.
Definition DateTime.h:25
#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_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
void fromIce(const data::MemoryID &ice, MemoryID &id)
void fromAron(const arondto::MemoryID &dto, MemoryID &bo)
std::shared_ptr< Dict > DictPtr
Definition Dict.h:42
void toAron(arondto::PackagePath &dto, const PackageFileLocation &bo)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
A bundle of updates to be sent to the memory.
Definition Commit.h:90
An update of an entity for a specific point in time.
Definition Commit.h:26