28#include <opencv2/opencv.hpp>
34 const std::string SimpleEpisodicMemory::NO_EPISODE =
"NO_EPISODE";
37 {EpisodeStatus::EPISODE_STARTED,
"started"},
38 {EpisodeStatus::EPISODE_COMPLETED_SUCCESS,
"success"},
39 {EpisodeStatus::EPISODE_COMPLETED_FAILURE,
"failure"},
40 {EpisodeStatus::EPISODE_COMPLETED_ABORT,
"abort"},
44 {ActionStatus::ACTION_STARTED,
"started"},
45 {ActionStatus::ACTION_RUNNING,
"running"},
46 {ActionStatus::ACTION_REPEATED,
"repeated"},
47 {ActionStatus::ACTION_COMPLETED_SUCCESS,
"success"},
48 {ActionStatus::ACTION_COMPLETED_FAILURE,
"failure"},
53 {ObjectPoseEventType::NEW_OBJECT_RECOGNIZED,
"newly detected"},
54 {ObjectPoseEventType::OBJECT_POSE_UPDATE,
"updated"},
60 return "SimpleEpisodicMemory";
66 m_enable_export =
true;
67 m_export_folder =
"/tmp/EMExport";
87 SimpleEpisodicMemory::export_episode()
const
90 if (m_current_episode.episodeName == NO_EPISODE)
94 if (m_current_episode.imageEvents.size() + m_current_episode.actionEvents.size() +
95 m_current_episode.humanPoseEvents.size() + m_current_episode.speechEvents.size() +
96 m_current_episode.objectPoseEvents.size() +
97 m_current_episode.kinematicUnitEvents.size() +
98 m_current_episode.platformUnitEvents.size() +
99 m_current_episode.platformUnitTargetEvents.size() ==
106 if (std::filesystem::exists(m_export_folder))
108 const std::string episode_output =
109 m_export_folder +
"/episode_" + std::to_string(m_current_episode.startedInMs) +
"/";
110 if (!std::filesystem::create_directory(episode_output))
112 ARMARX_ERROR <<
"Couldn't create episode folder: " << episode_output;
116 const std::string camera_output = episode_output +
"camera/";
117 if (!std::filesystem::create_directory(camera_output))
123 const std::string object_output = episode_output +
"objects/";
124 if (!std::filesystem::create_directory(object_output))
130 const std::string action_output = episode_output +
"actions/";
131 if (!std::filesystem::create_directory(action_output))
137 const std::string human_poses_output = episode_output +
"poses/";
138 if (!std::filesystem::create_directory(human_poses_output))
144 const std::string speech_output = episode_output +
"speech/";
145 if (!std::filesystem::create_directory(speech_output))
151 const std::string platformUnit_output = episode_output +
"platformUnit/";
152 if (!std::filesystem::create_directory(platformUnit_output))
158 const std::string platformUnitTarget_output = episode_output +
"platformUnitTarget/";
159 if (!std::filesystem::create_directory(platformUnitTarget_output))
161 ARMARX_ERROR <<
"Couldn't create platformUnitTarget folder";
165 const std::string kinematicUnit_output = episode_output +
"kinematicUnit/";
166 if (!std::filesystem::create_directory(kinematicUnit_output))
178 std::filesystem::path path{episode_output +
"episode.json"};
180 std::ofstream e_ofs(path);
182 e_ofs <<
"\t\"name\": \"" + m_current_episode.episodeName +
"\",\n";
183 e_ofs <<
"\t\"status\": \"" +
185 m_current_episode.status) +
187 e_ofs <<
"\t\"started\": \"" + std::to_string(m_current_episode.startedInMs) +
189 e_ofs <<
"\t\"ended\": \"" + std::to_string(m_current_episode.endedInMs) +
"\"\n";
197 for (
const auto& objectEvent : m_current_episode.objectPoseEvents)
199 const double timestamp = objectEvent.receivedInMs;
201 std::ofstream o_ofs(object_output +
"obj_" + std::to_string(
timestamp) +
204 o_ofs <<
"\t\"name\": \"" + objectEvent.objectName +
"\",\n";
205 o_ofs <<
"\t\"position\": [" + std::to_string(objectEvent.x) +
", " +
206 std::to_string(objectEvent.y) +
", " +
207 std::to_string(objectEvent.z) +
"],\n";
208 o_ofs <<
"\t\"started\": \"" + std::to_string(
timestamp) +
"\",\n";
209 o_ofs <<
"\t\"frame\": \"" + objectEvent.frame +
"\",\n";
210 o_ofs <<
"\t\"type\": \"" +
221 for (
const auto& actionEvent : m_current_episode.actionEvents)
223 const double timestamp = actionEvent.receivedInMs;
225 std::ofstream a_ofs(action_output +
"act_" + std::to_string(
timestamp) +
228 a_ofs <<
"\t\"name\": \"" + actionEvent.actionName +
"\",\n";
229 a_ofs <<
"\t\"status\": \"" +
231 actionEvent.status) +
233 a_ofs <<
"\t\"started\": \"" + std::to_string(
timestamp) +
"\"\n";
242 for (
const auto& humanPose : m_current_episode.humanPoseEvents)
244 const double timestamp = humanPose.receivedInMs;
246 std::ofstream p_ofs(human_poses_output +
"pose_" + std::to_string(
timestamp) +
250 for (
const auto& [label, keypoint] : humanPose.keypoints)
252 p_ofs <<
"\t\"" + label +
"\":\n";
254 p_ofs <<
"\t\t \"confidence\": " + std::to_string(keypoint.confidence) +
256 p_ofs <<
"\t\t \"local\": [" + std::to_string(keypoint.x) +
", " +
257 std::to_string(keypoint.y) +
", " +
258 std::to_string(keypoint.z) +
" ],\n";
259 p_ofs <<
"\t\t \"global\": [" + std::to_string(keypoint.globalX) +
", " +
260 std::to_string(keypoint.globalY) +
", " +
261 std::to_string(keypoint.globalZ) +
" ]\n";
272 for (
const auto& speech : m_current_episode.speechEvents)
274 const double timestamp = speech.receivedInMs;
276 std::ofstream s_ofs(speech_output +
"speech_" + std::to_string(
timestamp) +
279 s_ofs <<
"\t \"text\": " << speech.text <<
"\n";
288 for (
const auto& kinematicUnit : m_current_episode.kinematicUnitEvents)
290 const double timestamp = kinematicUnit.receivedInMs;
292 std::ofstream k_ofs(kinematicUnit_output +
"kinematicUnit_" +
295 for (
const auto& [key, value] : kinematicUnit.data)
297 k_ofs <<
"\t \"" + key +
"\": {\n";
298 k_ofs <<
"\t\t \"jointAngle\": \"" <<
value.jointAngle <<
"\",\n";
299 k_ofs <<
"\t\t \"jointVelocity\": \"" <<
value.jointVelocity <<
"\",\n";
300 k_ofs <<
"\t\t \"jointTorque\": \"" <<
value.jointTorque <<
"\",\n";
301 k_ofs <<
"\t\t \"jointAcceleration\": \"" <<
value.jointAcceleration
303 k_ofs <<
"\t\t \"current\": \"" <<
value.current <<
"\",\n";
304 k_ofs <<
"\t\t \"temperature\": \"" <<
value.temperature <<
"\",\n";
305 k_ofs <<
"\t\t \"enabled\": \"" <<
value.enabled <<
"\"\n";
316 for (
const auto& platformUnit : m_current_episode.platformUnitEvents)
318 const double timestamp = platformUnit.receivedInMs;
320 std::ofstream p_ofs(platformUnit_output +
"platformUnit_" +
323 p_ofs <<
"\t \"x\": \"" << platformUnit.x <<
"\",\n";
324 p_ofs <<
"\t \"y\": \"" << platformUnit.y <<
"\",\n";
325 p_ofs <<
"\t \"rot\": \"" << platformUnit.rot <<
"\",\n";
326 p_ofs <<
"\t \"acc_x\": \"" << platformUnit.acc_x <<
"\",\n";
327 p_ofs <<
"\t \"acc_y\": \"" << platformUnit.acc_y <<
"\",\n";
328 p_ofs <<
"\t \"acc_rot\": \"" << platformUnit.acc_rot <<
"\"\n";
337 for (
const auto& platformUnitTarget : m_current_episode.platformUnitTargetEvents)
339 const double timestamp = platformUnitTarget.receivedInMs;
341 std::ofstream t_ofs(platformUnitTarget_output +
"platformUnitTarget_" +
344 t_ofs <<
"\t \"x\": \"" << platformUnitTarget.target_x <<
"\",\n";
345 t_ofs <<
"\t \"y\": \"" << platformUnitTarget.target_y <<
"\",\n";
346 t_ofs <<
"\t \"rot\": \"" << platformUnitTarget.target_rot <<
"\"\n";
356 for (
const auto& [imageProvider, imageEventList] : m_current_episode.imageEvents)
358 if (imageEventList.size() == 0)
362 const std::string image_provider_output = camera_output + imageProvider +
"/";
363 if (!std::filesystem::create_directory(image_provider_output))
365 ARMARX_ERROR <<
"Couldn't create image provider folder: " + imageProvider;
369 for (
const auto& imageEvent : imageEventList)
371 const double timestamp = imageEvent.receivedInMs;
374 if (imageEvent.colourType == memoryx::ColourSpace::GRAYSCALE)
378 std::vector<uchar>
data(imageEvent.data);
379 ARMARX_DEBUG <<
"Image size is " << imageEvent.width <<
", "
380 << imageEvent.height <<
", " << imageEvent.colourType <<
" => "
381 << imageEvent.data.size();
383 cv::Mat(imageEvent.height, imageEvent.width, mode,
data.data());
385 cv::cvtColor(cv_image, cv_image, cv::COLOR_RGB2BGR);
386 cv::imwrite(image_provider_output +
"img_" + std::to_string(
timestamp) +
390 <<
"Exporting image to: img_" + std::to_string(
timestamp) +
".jpg";
397 ARMARX_ERROR <<
"Cannot export files because folder does not exist: "
403 SimpleEpisodicMemory::clearAll()
406 m_current_episode.episodeName = NO_EPISODE;
407 m_current_episode.startedInMs = IceUtil::Time::now().toMilliSecondsDouble();
408 m_current_episode.status = EpisodeStatus::EPISODE_STARTED;
414 std::lock_guard<std::mutex> l(episodeEventMutex);
415 if (m_current_episode.episodeName != e.episodeName && e.status != EPISODE_STARTED)
417 ARMARX_ERROR <<
"Received an episode unequal to current one with non-starting status: "
420 if (m_current_episode.episodeName != e.episodeName && m_current_episode.endedInMs != 0 &&
421 e.status == EPISODE_STARTED)
423 ARMARX_WARNING <<
"Received a new starting episode without ending the last one. Last "
425 << m_current_episode.episodeName <<
". Finishing it now.";
427 abort.episodeName = m_current_episode.episodeName;
428 abort.status = EpisodeStatus::EPISODE_COMPLETED_ABORT;
429 abort.receivedInMs = IceUtil::Time::now().toMilliSecondsDouble();
433 if (e.status == EPISODE_COMPLETED_SUCCESS || e.status == EPISODE_COMPLETED_FAILURE ||
434 e.status == EPISODE_COMPLETED_ABORT)
436 ARMARX_DEBUG <<
"Received a terminating episode (" << e.episodeName <<
")";
437 m_current_episode.status = e.status;
438 m_current_episode.endedInMs = e.receivedInMs;
442 ARMARX_DEBUG <<
"Received a starting episode (" << e.episodeName <<
")";
443 m_current_episode.episodeName = e.episodeName;
444 m_current_episode.status = e.status;
445 m_current_episode.startedInMs = e.receivedInMs;
448 std::lock_guard<std::mutex> l2(imageEventMutex);
449 std::lock_guard<std::mutex> l3(humanPoseEventMutex);
450 std::lock_guard<std::mutex> l4(speechEventMutex);
451 std::lock_guard<std::mutex> l5(objectPoseEventMutex);
452 std::lock_guard<std::mutex> l6(kinematicUnitEventMutex);
453 std::lock_guard<std::mutex> l7(platformUnitEventMutex);
454 std::lock_guard<std::mutex> l8(platformUnitTargetEventMutex);
455 std::lock_guard<std::mutex> l9(actionEventMutex);
456 if (m_enable_export && m_current_episode.endedInMs != 0)
467 std::lock_guard<std::mutex> l(imageEventMutex);
468 ARMARX_DEBUG <<
"Received an image. Current number of images of provider " << i.providerName
470 << this->m_current_episode.imageEvents[i.providerName].size();
471 this->m_current_episode.imageEvents[i.providerName].push_back(i);
477 std::lock_guard<std::mutex> l(objectPoseEventMutex);
478 ARMARX_DEBUG <<
"Received an objectPose (" << o.objectName
479 <<
"). Current number of objectPoses in episode: "
480 << this->m_current_episode.objectPoseEvents.size();
481 this->m_current_episode.objectPoseEvents.push_back(o);
487 std::lock_guard<std::mutex> l(actionEventMutex);
488 ARMARX_DEBUG <<
"Received an action (" << a.actionName <<
" with status "
490 <<
")Current number of actions in episode: "
491 << this->m_current_episode.actionEvents.size();
492 this->m_current_episode.actionEvents.push_back(a);
498 std::lock_guard<std::mutex> l(humanPoseEventMutex);
499 ARMARX_DEBUG <<
"Received a human pose. Current number of poses in episode: "
500 << this->m_current_episode.humanPoseEvents.size();
501 this->m_current_episode.humanPoseEvents.push_back(p);
507 if (s.text.find(
"export now") != std::string::npos)
509 ARMARX_IMPORTANT <<
"Received export token!. Terminating current episode and create an "
512 terminate.episodeName = m_current_episode.episodeName;
513 terminate.status = EpisodeStatus::EPISODE_COMPLETED_ABORT;
514 terminate.receivedInMs = IceUtil::Time::now().toMilliSecondsDouble();
519 std::lock_guard<std::mutex> l(speechEventMutex);
521 <<
"). Current number of speeches in episode: "
522 << this->m_current_episode.speechEvents.size();
523 this->m_current_episode.speechEvents.push_back(s);
530 std::lock_guard<std::mutex> l(kinematicUnitEventMutex);
531 ARMARX_DEBUG <<
"Received a kinematicUnitEvent. Current number of events in episode: "
532 << this->m_current_episode.kinematicUnitEvents.size();
533 this->m_current_episode.kinematicUnitEvents.push_back(k);
539 std::lock_guard<std::mutex> l(platformUnitEventMutex);
540 ARMARX_DEBUG <<
"Received a platformUnitEvent. Current number of events in episode: "
541 << this->m_current_episode.platformUnitEvents.size();
542 this->m_current_episode.platformUnitEvents.push_back(p);
549 std::lock_guard<std::mutex> l(platformUnitTargetEventMutex);
550 ARMARX_DEBUG <<
"Received a platformUnitTarget. Current number of events in episode: "
551 << this->m_current_episode.platformUnitTargetEvents.size();
552 this->m_current_episode.platformUnitTargetEvents.push_back(t);
Default component property definition container.
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
void terminate()
Initiates termination of this IceManagedObject.
void onInitComponent() override
Pure virtual hook for the subclass.
void onDisconnectComponent() override
Hook for subclass.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void registerHumanPoseEvent(const Body25HumanPoseEvent &, const Ice::Current &=Ice::emptyCurrent) override
static const std::map< ActionStatus, std::string > action_status_descriptor
void registerObjectPoseEvent(const ObjectPoseEvent &, const Ice::Current &=Ice::emptyCurrent) override
void registerKinematicUnitEvent(const KinematicUnitEvent &, const Ice::Current &=Ice::emptyCurrent) override
void registerActionEvent(const ActionEvent &, const Ice::Current &=Ice::emptyCurrent) override
void registerSpeechEvent(const SpeechEvent &, const Ice::Current &=Ice::emptyCurrent) override
void onConnectComponent() override
Pure virtual hook for the subclass.
void registerImageEvent(const ImageEvent &, const Ice::Current &=Ice::emptyCurrent) override
void notifyKeyframe(const Ice::Current &=Ice::emptyCurrent) override
void onExitComponent() override
Hook for subclass.
void registerPlatformUnitEvent(const PlatformUnitEvent &, const Ice::Current &=Ice::emptyCurrent) override
void registerPlatformUnitTargetEvent(const PlatformUnitTargetEvent &, const Ice::Current &=Ice::emptyCurrent) override
std::string getDefaultName() const override
Retrieve default name of component.
static const std::map< EpisodeStatus, std::string > episode_status_descriptor
void registerEpisodeEvent(const EpisodeEvent &, const Ice::Current &=Ice::emptyCurrent) override
static const std::map< ObjectPoseEventType, std::string > object_type_descriptor
#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_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::shared_ptr< Value > value()