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;
204 o_ofs <<
"\t\"name\": \"" + objectEvent.objectName +
"\",\n";
205 o_ofs <<
"\t\"position\": [" +
std::to_string(objectEvent.x) +
", " +
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;
228 a_ofs <<
"\t\"name\": \"" + actionEvent.actionName +
"\",\n";
229 a_ofs <<
"\t\"status\": \"" +
231 actionEvent.status) +
242 for (
const auto& humanPose : m_current_episode.humanPoseEvents)
244 const double timestamp = humanPose.receivedInMs;
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) +
", " +
259 p_ofs <<
"\t\t \"global\": [" +
std::to_string(keypoint.globalX) +
", " +
272 for (
const auto& speech : m_current_episode.speechEvents)
274 const double timestamp = speech.receivedInMs;
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);
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);