PersonMemoryDebugger.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 VisionX::ArmarXObjects::person_memory_debugger
17 * @author Peter Albrecht ( usnlf at student dot kit dot edu )
18 * @date 2024
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23
25
26#include <optional>
27#include <utility>
28
29#include <Eigen/Core>
30#include <Eigen/Geometry>
31
32#include <SimoxUtility/algorithm/get_map_keys_values.h>
33#include <SimoxUtility/algorithm/string/string_tools.h>
34
36
46
48#include <VisionX/libraries/armem_human/aron/FaceRecognition.aron.generated.h>
49#include <VisionX/libraries/armem_human/aron/HumanPose.aron.generated.h>
50#include <VisionX/libraries/armem_human/aron/Person.aron.generated.h>
51#include <VisionX/libraries/armem_human/aron/PersonInstance.aron.generated.h>
58
60{
61
62 const std::string PersonMemoryDebugger::pose_provider_name = "person_memory_debugger";
63 const std::string PersonMemoryDebugger::profile_provider_name = "person_memory_debugger";
64 const std::string PersonMemoryDebugger::recognition_provider_name = "person_memory_debugger";
65
68 {
71 def->defineRequiredProperty<std::string>("robotName");
72 return def;
73 }
74
75 void
79
80 void
82 {
83 idCounter = 0;
84 running = true;
85 properties.robotName = this->getProperty<std::string>("robotName");
86 while (running)
87 {
88 this->run();
89 }
90 }
91
92 void
96
97 void
101
102 void
103 PersonMemoryDebugger::run()
104 {
105 ARMARX_INFO << "Use 'pose [id] [x] [y] [z]' to commit a pose at location";
106 ARMARX_INFO << "Use 'face [profile entityName] [x] [y] [z]' to commit a face at location";
107 ARMARX_INFO << "Use 'profile [firstName lastName]' to commit a profile";
108 ARMARX_INFO << "Use 'read [firstName lastName]' to read a profile";
109 ARMARX_INFO << "Use 'readPreferences [firstName lastName]' to read a profiles preferences";
110 ARMARX_INFO << "Use 'writePreferences [firstName lastName]' to write debug values to a "
111 "profiles preferences";
112 ARMARX_INFO << "Use 'setCustomAttribute [firstName lastName]' to write a debug attribute "
113 "to a profile";
114 ARMARX_INFO << "Use 'readDrinkPreference [firstName lastName]' to read the drink "
115 "preferences from a profile";
116 ARMARX_INFO << "Use 'setDrinkPreference [firstName lastName drink]' to set a drink as "
117 "someones favorite drink";
118 ARMARX_INFO << "Use 'createPersonInstance [firstName lastName]' to create a new "
119 "PersonInstance and commit it to memory";
120 ARMARX_INFO << "Use 'exit' to exit";
121 std::string command;
122 //std::getline(std::cin, command);
123 std::cin >> command;
124 if (command == "pose")
125 {
126 poseCommand();
127 }
128 else if (command == "face")
129 {
130 faceRecognitionCommand();
131 }
132 else if (command == "profile")
133 {
134 profileCommand();
135 }
136 else if (command == "exit")
137 {
138 running = false;
139 }
140 else if (command == "read")
141 {
142 readProfileCommand();
143 }
144 else if (command == "readPreferences")
145 {
146 readPreferencesCommand();
147 }
148 else if (command == "writePreferences")
149 {
150 writeNewPreferencesCommand();
151 }
152 else if (command == "setCustomAttribute")
153 {
154 setCustomAttributeCommand();
155 }
156 else if (command == "readDrinkPreference")
157 {
158 readDrinkPreferenceCommand();
159 }
160 else if (command == "setDrinkPreference")
161 {
162 setDrinkPreferenceCommand();
163 }
164 else if (command == "createPersonInstance")
165 {
166 createPersonInstanceCommand();
167 }
168 else
169 {
170 ARMARX_WARNING << "Unrecognized command. Ignoring... "
171 << "\n"
172 << command;
173 }
174
175 std::cin.clear();
176 }
177
178 void
179 PersonMemoryDebugger::poseCommand()
180 {
181 std::string id, x_s, y_s, z_s;
182 std::cin >> id >> x_s >> y_s >> z_s;
183 float x = std::stof(x_s);
184 float y = std::stof(y_s);
185 float z = std::stof(z_s);
186 Eigen::Vector3f pos(x, y, z);
187 commitPose(pos, id);
188 }
189
190 void
191 PersonMemoryDebugger::faceRecognitionCommand()
192 {
193 std::string id, x_s, y_s, z_s;
194 std::cin >> id >> x_s >> y_s >> z_s;
195
196 auto profileId = findProfileId(id);
197 if (not profileId.has_value())
198 {
199 ARMARX_WARNING << "Could not find profile. Continuing..";
200 }
201
202 float x = std::stof(x_s);
203 float y = std::stof(y_s);
204 float z = std::stof(z_s);
205
206 Eigen::Vector3f pos(x, y, z);
207 commitFaceRecognition(pos, profileId);
208 }
209
210 void
211 PersonMemoryDebugger::profileCommand()
212 {
213 std::string firstName;
214 std::cin >> firstName;
215 std::string lastName;
216 std::cin >> lastName;
217 armarx::armem::human::PersonID id = armarx::armem::human::PersonID();
218 id.firstName = firstName;
219 id.lastName = lastName;
220 commitProfile(id);
221 }
222
223 void
224 PersonMemoryDebugger::readProfileCommand()
225 {
226 std::string firstName;
227 std::cin >> firstName;
228 std::string lastName;
229 std::cin >> lastName;
230 this->readProfile(firstName, lastName);
231 }
232
233 void
234 PersonMemoryDebugger::readPreferencesCommand()
235 {
236 std::string firstName;
237 std::cin >> firstName;
238 std::string lastName;
239 std::cin >> lastName;
240 this->readPreferences(firstName, lastName);
241 }
242
243 void
244 PersonMemoryDebugger::readDrinkPreferenceCommand()
245 {
246 std::string firstName;
247 std::cin >> firstName;
248 std::string lastName;
249 std::cin >> lastName;
250 this->readDrinkPreference(firstName, lastName);
251 }
252
253 void
254 PersonMemoryDebugger::setDrinkPreferenceCommand()
255 {
256 std::string firstName;
257 std::cin >> firstName;
258 std::string lastName;
259 std::cin >> lastName;
260 std::string drink;
261 std::cin >> drink;
262 this->setDrinkPreference(firstName, lastName, drink);
263 }
264
265 void
266 PersonMemoryDebugger::writeNewPreferencesCommand()
267 {
268 std::string firstName;
269 std::cin >> firstName;
270 std::string lastName;
271 std::cin >> lastName;
272 this->writeNewPreferences(firstName, lastName);
273 }
274
275 void
276 PersonMemoryDebugger::setCustomAttributeCommand()
277 {
278 std::string firstName;
279 std::cin >> firstName;
280 std::string lastName;
281 std::cin >> lastName;
282 this->setCustomAttribute(firstName, lastName);
283 }
284
285 void
286 PersonMemoryDebugger::createPersonInstanceCommand()
287 {
288 std::string firstName;
289 std::cin >> firstName;
290 std::string lastName;
291 std::cin >> lastName;
292 this->createPersonInstance(firstName, lastName);
293 }
294
295 void
296 PersonMemoryDebugger::commitProfile(armarx::armem::human::PersonID& personID)
297 {
298 armarx::armem::human::Person debugProfile;
299 debugProfile.id = personID;
302 debugProfile.physiologicalBiometrics.heightInMillimeters = 160000;
303
304 this->profileWriter.connect(memoryNameSystem());
305
306 ARMARX_INFO << "Committing profile with name: " << debugProfile.id.firstName << " "
307 << debugProfile.id.lastName;
308
309 profileWriter.commitHumanProfile(
310 debugProfile, "person_memory_debugger", armarx::armem::Time::Now());
311 }
312
313 std::optional<armarx::armem::MemoryID>
314 PersonMemoryDebugger::findProfileId(std::string& entityId)
315 {
316 armarx::armem::client::Reader profileReader =
318
319 armarx::armem::client::QueryResult queryResult =
321 std::optional<armarx::armem::MemoryID> foundProfileId = std::nullopt;
322
323 // memory fetch failed
324 if (not queryResult.success)
325 {
326 return std::nullopt;
327 }
328
329 // find the first matching profile
330 queryResult.memory.forEachInstance(
331 [&entityId, &foundProfileId](armarx::armem::wm::EntityInstance& instance)
332 {
333 if (foundProfileId.has_value())
334 {
335 // we want the first match, and ignore all further matches here.
336 return;
337 }
338
339 if (instance.id().entityName == entityId)
340 {
341 // match found
342 foundProfileId = instance.id();
343 }
344 });
345
346 return foundProfileId;
347 }
348
349 void
350 PersonMemoryDebugger::commitFaceRecognition(Eigen::Vector3f& facePosition,
351 std::optional<armarx::armem::MemoryID> profileId)
352 {
353 armarx::armem::client::Writer poseWriter =
355
356 // get the id counter
357 std::stringstream ss;
358 ss << idCounter++;
359
360 armarx::armem::human::FaceRecognition bo;
362 armarx::FramedPosition(facePosition, armarx::GlobalFrame, properties.robotName);
363 // doesnt make sense, but this isn't set in prod anyways
364 bo.position2D = Eigen::Vector2i::Identity();
365 bo.position3DGlobal = facePosition;
366 // profile id may be nullopt, but this case is communicated to the user
367 bo.profileID = std::move(profileId);
368 bo.extents2D = Eigen::Vector2i::Zero();
369
370 armarx::human::arondto::FaceRecognition dto;
372
373 armarx::armem::MemoryID entityId =
375 .withEntityName(ss.str());
376
377 armarx::armem::EntityUpdate update = {
378 .entityID = entityId,
379 .instancesData = {dto.toAron()},
380 .referencedTime = armarx::armem::Time::Now(),
381 .confidence = 1.0F,
382 .sentTime = armarx::armem::Time::Now(),
383 .arrivedTime = armarx::armem::Time::Now(),
384 };
385
386 // hack
388 << "Committing face recognition for profile: "
389 << profileId.value_or(armarx::armem::MemoryID().withEntityName("INVALID")).entityName;
390 poseWriter.commit(update);
391 }
392
393 void
394 PersonMemoryDebugger::commitPose(Eigen::Vector3f& facePosition, std::string& humanId)
395 {
396 armarx::armem::client::Writer poseWriter = memoryNameSystem().getWriter(armarx::human::PoseCoreSegmentID);
397
398 armarx::armem::human::HumanPose pose;
399 pose.humanTrackingId = humanId;
403 armarx::FramedOrientation defaultOrientation(
404 Eigen::Quaternionf::UnitRandom(), armarx::GlobalFrame, properties.robotName);
405
406 using namespace armarx::human::pose::model::k4a_bt_body_32;
407
408 // iterate over all joints, and set their global positions to the face pos.
409 // this is the only value required to be valid by the PersonInstanceUpdater
410 for (auto& joint : JointNames.names())
411 {
412 armarx::armem::human::PoseKeypoint key = {
413 .label = joint,
414 .confidence = 1.0F,
415 .positionCamera =
416 armarx::FramedPosition(facePosition, "camera", properties.robotName),
417 .orientationCamera = armarx::FramedOrientation(
418 Eigen::Quaternionf::UnitRandom(), "camera", properties.robotName),
419 .positionRobot =
420 armarx::FramedPosition(facePosition, "robot", properties.robotName),
421 .orientationRobot = armarx::FramedOrientation(
422 Eigen::Quaternionf::UnitRandom(), "robot", properties.robotName),
423 .positionGlobal =
424 armarx::FramedPosition(facePosition, armarx::GlobalFrame, properties.robotName),
425 .orientationGlobal = defaultOrientation,
426 };
427 // set every joint to face position
428 pose.keypoints[joint] = key;
429 }
430
431 armarx::armem::MemoryID entityId =
433 .withEntityName(humanId);
434
435 armarx::human::arondto::HumanPose dto;
437
438 armarx::armem::EntityUpdate update = {
439 .entityID = entityId,
440 .instancesData = {dto.toAron()},
441 .referencedTime = armarx::armem::Time::Now(),
442 .confidence = 1.0F,
443 .sentTime = armarx::armem::Time::Now(),
444 .arrivedTime = armarx::armem::Time::Now(),
445 };
446
447 ARMARX_INFO << "Committing pose with PersonID '" << humanId << "'.";
448 poseWriter.commit(update);
449 }
450
451 void
452 PersonMemoryDebugger::readProfile(const std::string& firstName, const std::string& lastName)
453 {
454 ARMARX_INFO << "Reading profile for " << firstName << " " << lastName;
455 this->profileReader.connect(memoryNameSystem());
456 armarx::armem::human::Person profile = profileReader.queryLatestProfileByName(
458 ARMARX_INFO << profile.id.firstName << " " << profile.id.lastName;
461 {
462 ARMARX_INFO << "Gender: diverse";
463 }
465 {
466 ARMARX_INFO << "Gender: female";
467 }
468 else
469 {
470 ARMARX_INFO << "Other gender";
471 }
472 }
473
474 void
475 PersonMemoryDebugger::readPreferences(const std::string& firstName, const std::string& lastName)
476 {
477 ARMARX_INFO << "Reading preferences for " << firstName << " " << lastName;
478 this->profileReader.connect(memoryNameSystem());
479 const armarx::core::time::Duration maxAge =
481 const armarx::armem::human::Preferences preferences = profileReader.queryPreferences(
482 firstName, lastName, maxAge, PersonMemoryDebugger::profile_provider_name);
483
484 if (!preferences.food.has_value())
485 {
486 ARMARX_INFO << "No preferences for food set";
487 }
488 ARMARX_INFO << "Food preferences (preferred): " << preferences.food.value().preferred;
489 ARMARX_INFO << "Food preferences (disliked): " << preferences.food.value().disliked;
490 }
491
492 void
493 PersonMemoryDebugger::readDrinkPreference(const std::string& firstName,
494 const std::string& lastName)
495 {
496 ARMARX_INFO << "Reading preferred drinks for " << firstName << " " << lastName;
497 this->profileReader.connect(memoryNameSystem());
498 const std::vector<std::string> drinks = profileReader.getPreferredDrinks(
500
501 if (drinks.empty())
502 {
503 ARMARX_INFO << "No drinks set";
504 return;
505 }
506 ARMARX_INFO << "Preferred drinks: " << drinks;
507 }
508
509 void
510 PersonMemoryDebugger::setDrinkPreference(const std::string& firstName,
511 const std::string& lastName,
512 const std::string& drink)
513 {
514 this->profileWriter.connect(memoryNameSystem());
515
516 armarx::armem::human::PersonID personID;
517 personID.firstName = firstName;
518 personID.lastName = lastName;
519
520 profileWriter.setPreferredDrink(personID,
523 drink);
524
525 ARMARX_INFO << "Set drink '" << drink << "' as favorite drink for " << personID.firstName << " " << personID.lastName;
526 }
527
528 void
529 PersonMemoryDebugger::writeNewPreferences(const std::string& firstName,
530 const std::string& lastName)
531 {
532 this->profileWriter.connect(memoryNameSystem());
533
534 armarx::armem::human::Preferences preferences;
535 preferences.food = std::optional<armarx::armem::human::Preference>(
536 {.preferred = {"pizza", "chocolate"}, .disliked = {"vegetables"}});
537
538 armarx::armem::human::PersonID personID;
539 personID.firstName = firstName;
540 personID.lastName = lastName;
541 profileWriter.commitPreferencesToProfile(personID,
544 preferences);
545 ARMARX_INFO << "Committed preferences to " << personID.firstName << " " << personID.lastName;
546 }
547
548 void
549 PersonMemoryDebugger::setCustomAttribute(const std::string& firstName,
550 const std::string& lastName)
551 {
552 this->profileWriter.connect(memoryNameSystem());
553 std::vector<armarx::armem::human::Preference> preferences;
554
555 armarx::armem::human::PersonID personID;
556 personID.firstName = firstName;
557 personID.lastName = lastName;
558
559 profileWriter.setCustomAttributeInProfile(personID,
562 "favouriteNumber",
563 "42");
564
565 ARMARX_INFO << "Set custom attribute for " << personID.firstName << " " << personID.lastName;
566 }
567
568 void
569 PersonMemoryDebugger::createPersonInstance(const std::string& firstName,
570 const std::string& lastName)
571 {
572 ARMARX_INFO << "Creating PersonInstance for " << firstName << " " << lastName;
573
574 // First, find or create the profile
575 std::string profileEntityName = firstName + "-" + lastName;
576 auto profileId = findProfileId(profileEntityName);
577
578 if (!profileId.has_value())
579 {
580 ARMARX_INFO << "Profile not found. Creating profile first...";
581 armarx::armem::human::PersonID personID;
582 personID.firstName = firstName;
583 personID.lastName = lastName;
584 commitProfile(personID);
585
586 // After committing, find the profile ID again
587 profileId = findProfileId(profileEntityName);
588 if (!profileId.has_value())
589 {
590 ARMARX_WARNING << "Failed to create or find profile. Cannot create PersonInstance.";
591 return;
592 }
593 }
594
595 // Create dummy pose and face recognition if needed
596 // For debugging, we'll use default/empty memory IDs or create minimal data
597 Eigen::Vector3f defaultPosition(0.0f, 0.0f, 1.5f); // 1.5m height as default
598
599 // Create the PersonInstance
600 armarx::armem::human::PersonInstance personInstance;
601 personInstance.profileID = profileId.value();
602
603 // Set empty/invalid IDs for face and pose (they can be updated later)
604 personInstance.faceRecognitionID = armarx::armem::MemoryID();
605 personInstance.poseID = armarx::armem::MemoryID();
606
607 // Set the global pose (identity pose at default position)
608 personInstance.globalPose = Eigen::Isometry3f::Identity();
609 personInstance.globalPose.translation() = defaultPosition;
610
611 // Convert to DTO for serialization
612 armarx::human::arondto::PersonInstance dto;
613 armarx::armem::human::toAron(dto, personInstance);
614
615 // Create the entity update
616 armarx::armem::MemoryID entityId =
618 .withProviderSegmentName("person_memory_debugger")
619 .withEntityName(profileEntityName);
620
621 armarx::armem::EntityUpdate update = {
622 .entityID = entityId,
623 .instancesData = {dto.toAron()},
624 .referencedTime = armarx::armem::Time::Now(),
625 .confidence = 1.0F,
626 .sentTime = armarx::armem::Time::Now(),
627 .arrivedTime = armarx::armem::Time::Now(),
628 };
629
630 // Get writer for PersonInstance segment
631 armarx::armem::client::Writer personInstanceWriter =
633
634 // Commit the PersonInstance
635 personInstanceWriter.commit(update);
636
637 ARMARX_INFO << "Successfully created PersonInstance for " << firstName << " " << lastName
638 << " with entity name '" << profileEntityName << "'";
639 }
640
641 std::string
643 {
644 return "PersonMemoryDebugger";
645 }
646
647 // ARMARX_REGISTER_COMPONENT_EXECUTABLE(PersonMemoryDebugger,
648 // PersonMemoryDebugger::GetDefaultName());
649
650} // namespace visionx::components::person_memory_debugger
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
Property< PropertyType > getProperty(const std::string &name)
static DateTime Now()
Definition DateTime.cpp:51
MemoryID withProviderSegmentName(const std::string &name) const
Definition MemoryID.cpp:417
MemoryID withEntityName(const std::string &name) const
Definition MemoryID.cpp:425
std::string entityName
Definition MemoryID.h:53
Reader getReader(const MemoryID &memoryID)
Get a reader to the given memory name.
Writer getWriter(const MemoryID &memoryID)
Get a writer to the given memory name.
QueryResult getLatestSnapshotsIn(const MemoryID &id, armem::query::DataMode dataMode=armem::query::DataMode::WithData) const
Get the latest snapshots under the given memory ID.
Definition Reader.cpp:427
CommitResult commit(const Commit &commit) const
Writes a Commit to the memory.
Definition Writer.cpp:68
static DateTime Now()
Definition DateTime.cpp:51
static Duration Minutes(std::int64_t minutes)
Constructs a duration in minutes.
Definition Duration.cpp:96
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
void toAron(armarx::human::arondto::HumanPose &dto, const HumanPose &bo)
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition mongodb.cpp:68
const simox::meta::EnumNames< Joints > JointNames
Names of the joints as defined in the body model.
const armem::MemoryID ProfileCoreSegmentID
const armem::MemoryID FaceRecognitionCoreSegmentID
const armem::MemoryID PersonInstanceCoreSegmentID
const armem::MemoryID PoseCoreSegmentID
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
wm::Memory memory
The slice of the memory that matched the query.
Definition Query.h:58
std::optional< armarx::armem::MemoryID > profileID
Definition types.h:80
std::optional< std::string > humanTrackingId
Definition types.h:47
armarx::armem::MemoryID profileID
Definition types.h:85
Eigen::Isometry3f globalPose
Definition types.h:90
armarx::armem::MemoryID faceRecognitionID
Definition types.h:86
armarx::armem::MemoryID poseID
Definition types.h:87
PhysicalData physiologicalBiometrics
Definition types.h:213
std::optional< double > heightInMillimeters
Definition types.h:169
std::optional< Preference > food
Definition types.h:183