27 #include <opencv2/opencv.hpp>
35 const std::string SimpleEpisodicMemory::NO_EPISODE =
"NO_EPISODE";
39 {EpisodeStatus::EPISODE_STARTED,
"started"},
40 {EpisodeStatus::EPISODE_COMPLETED_SUCCESS,
"success"},
41 {EpisodeStatus::EPISODE_COMPLETED_FAILURE,
"failure"},
42 {EpisodeStatus::EPISODE_COMPLETED_ABORT,
"abort"},
47 {ActionStatus::ACTION_STARTED,
"started"},
48 {ActionStatus::ACTION_RUNNING,
"running"},
49 {ActionStatus::ACTION_REPEATED,
"repeated"},
50 {ActionStatus::ACTION_COMPLETED_SUCCESS,
"success"},
51 {ActionStatus::ACTION_COMPLETED_FAILURE,
"failure"},
56 {ObjectPoseEventType::NEW_OBJECT_RECOGNIZED,
"newly detected"},
57 {ObjectPoseEventType::OBJECT_POSE_UPDATE,
"updated"},
62 return "SimpleEpisodicMemory";
67 m_enable_export =
true;
68 m_export_folder =
"/tmp/EMExport";
84 void SimpleEpisodicMemory::export_episode()
const
87 if (m_current_episode.episodeName == NO_EPISODE)
91 if (m_current_episode.imageEvents.size() + m_current_episode.actionEvents.size() + m_current_episode.humanPoseEvents.size() +
92 m_current_episode.speechEvents.size() + m_current_episode.objectPoseEvents.size() + m_current_episode.kinematicUnitEvents.size() +
93 m_current_episode.platformUnitEvents.size() + m_current_episode.platformUnitTargetEvents.size() == 0)
99 if (std::filesystem::exists(m_export_folder))
101 const std::string episode_output = m_export_folder +
"/episode_" +
std::to_string(m_current_episode.startedInMs) +
"/";
102 if (!std::filesystem::create_directory(episode_output))
104 ARMARX_ERROR <<
"Couldn't create episode folder: " << episode_output;
108 const std::string camera_output = episode_output +
"camera/";
109 if (!std::filesystem::create_directory(camera_output))
115 const std::string object_output = episode_output +
"objects/";
116 if (!std::filesystem::create_directory(object_output))
122 const std::string action_output = episode_output +
"actions/";
123 if (!std::filesystem::create_directory(action_output))
129 const std::string human_poses_output = episode_output +
"poses/";
130 if (!std::filesystem::create_directory(human_poses_output))
136 const std::string speech_output = episode_output +
"speech/";
137 if (!std::filesystem::create_directory(speech_output))
143 const std::string platformUnit_output = episode_output +
"platformUnit/";
144 if (!std::filesystem::create_directory(platformUnit_output))
150 const std::string platformUnitTarget_output = episode_output +
"platformUnitTarget/";
151 if (!std::filesystem::create_directory(platformUnitTarget_output))
153 ARMARX_ERROR <<
"Couldn't create platformUnitTarget folder";
157 const std::string kinematicUnit_output = episode_output +
"kinematicUnit/";
158 if (!std::filesystem::create_directory(kinematicUnit_output))
170 std::filesystem::path path{ episode_output +
"episode.json" };
172 std::ofstream e_ofs(path);
174 e_ofs <<
"\t\"name\": \"" + m_current_episode.episodeName +
"\",\n";
176 e_ofs <<
"\t\"started\": \"" +
std::to_string(m_current_episode.startedInMs) +
"\",\n";
177 e_ofs <<
"\t\"ended\": \"" +
std::to_string(m_current_episode.endedInMs) +
"\"\n";
185 for (
const auto& objectEvent : m_current_episode.objectPoseEvents)
187 const double timestamp = objectEvent.receivedInMs;
189 std::ofstream o_ofs(object_output +
"obj_" +
std::to_string(timestamp) +
".json");
191 o_ofs <<
"\t\"name\": \"" + objectEvent.objectName +
"\",\n";
193 o_ofs <<
"\t\"started\": \"" +
std::to_string(timestamp) +
"\",\n";
194 o_ofs <<
"\t\"frame\": \"" + objectEvent.frame +
"\",\n";
204 for (
const auto& actionEvent : m_current_episode.actionEvents)
206 const double timestamp = actionEvent.receivedInMs;
208 std::ofstream a_ofs(action_output +
"act_" +
std::to_string(timestamp) +
".json");
210 a_ofs <<
"\t\"name\": \"" + actionEvent.actionName +
"\",\n";
212 a_ofs <<
"\t\"started\": \"" +
std::to_string(timestamp) +
"\"\n";
221 for (
const auto& humanPose : m_current_episode.humanPoseEvents)
223 const double timestamp = humanPose.receivedInMs;
225 std::ofstream p_ofs(human_poses_output +
"pose_" +
std::to_string(timestamp) +
".json");
228 for (
const auto& [label, keypoint] : humanPose.keypoints)
230 p_ofs <<
"\t\"" + label +
"\":\n";
232 p_ofs <<
"\t\t \"confidence\": " +
std::to_string(keypoint.confidence) +
",\n";
245 for (
const auto& speech : m_current_episode.speechEvents)
247 const double timestamp = speech.receivedInMs;
249 std::ofstream s_ofs(speech_output +
"speech_" +
std::to_string(timestamp) +
".json");
251 s_ofs <<
"\t \"text\": " << speech.text <<
"\n";
260 for (
const auto& kinematicUnit : m_current_episode.kinematicUnitEvents)
262 const double timestamp = kinematicUnit.receivedInMs;
264 std::ofstream k_ofs(kinematicUnit_output +
"kinematicUnit_" +
std::to_string(timestamp) +
".json");
266 for (
const auto& [key,
value] : kinematicUnit.data)
268 k_ofs <<
"\t \"" + key +
"\": {\n";
269 k_ofs <<
"\t\t \"jointAngle\": \"" <<
value.jointAngle <<
"\",\n";
270 k_ofs <<
"\t\t \"jointVelocity\": \"" <<
value.jointVelocity <<
"\",\n";
271 k_ofs <<
"\t\t \"jointTorque\": \"" <<
value.jointTorque <<
"\",\n";
272 k_ofs <<
"\t\t \"jointAcceleration\": \"" <<
value.jointAcceleration <<
"\",\n";
273 k_ofs <<
"\t\t \"current\": \"" <<
value.current <<
"\",\n";
274 k_ofs <<
"\t\t \"temperature\": \"" <<
value.temperature <<
"\",\n";
275 k_ofs <<
"\t\t \"enabled\": \"" <<
value.enabled <<
"\"\n";
286 for (
const auto& platformUnit : m_current_episode.platformUnitEvents)
288 const double timestamp = platformUnit.receivedInMs;
290 std::ofstream p_ofs(platformUnit_output +
"platformUnit_" +
std::to_string(timestamp) +
".json");
292 p_ofs <<
"\t \"x\": \"" << platformUnit.x <<
"\",\n";
293 p_ofs <<
"\t \"y\": \"" << platformUnit.y <<
"\",\n";
294 p_ofs <<
"\t \"rot\": \"" << platformUnit.rot <<
"\",\n";
295 p_ofs <<
"\t \"acc_x\": \"" << platformUnit.acc_x <<
"\",\n";
296 p_ofs <<
"\t \"acc_y\": \"" << platformUnit.acc_y <<
"\",\n";
297 p_ofs <<
"\t \"acc_rot\": \"" << platformUnit.acc_rot <<
"\"\n";
306 for (
const auto& platformUnitTarget : m_current_episode.platformUnitTargetEvents)
308 const double timestamp = platformUnitTarget.receivedInMs;
310 std::ofstream t_ofs(platformUnitTarget_output +
"platformUnitTarget_" +
std::to_string(timestamp) +
".json");
312 t_ofs <<
"\t \"x\": \"" << platformUnitTarget.target_x <<
"\",\n";
313 t_ofs <<
"\t \"y\": \"" << platformUnitTarget.target_y <<
"\",\n";
314 t_ofs <<
"\t \"rot\": \"" << platformUnitTarget.target_rot <<
"\"\n";
324 for (
const auto& [imageProvider, imageEventList] : m_current_episode.imageEvents)
326 if (imageEventList.size() == 0)
330 const std::string image_provider_output = camera_output + imageProvider +
"/";
331 if (!std::filesystem::create_directory(image_provider_output))
333 ARMARX_ERROR <<
"Couldn't create image provider folder: " + imageProvider;
337 for (
const auto& imageEvent : imageEventList)
339 const double timestamp = imageEvent.receivedInMs;
342 if (imageEvent.colourType == memoryx::ColourSpace::GRAYSCALE)
346 std::vector<uchar>
data(imageEvent.data);
347 ARMARX_DEBUG <<
"Image size is " << imageEvent.width <<
", " << imageEvent.height <<
", " << imageEvent.colourType <<
" => " << imageEvent.data.size();
348 cv::Mat cv_image = cv::Mat(imageEvent.height, imageEvent.width, mode,
data.data());
350 cv::cvtColor(cv_image, cv_image, cv::COLOR_RGB2BGR);
351 cv::imwrite(image_provider_output +
"img_" +
std::to_string(timestamp) +
".jpg", cv_image);
359 ARMARX_ERROR <<
"Cannot export files because folder does not exist: " << m_export_folder;
363 void SimpleEpisodicMemory::clearAll()
366 m_current_episode.episodeName = NO_EPISODE;
367 m_current_episode.startedInMs = IceUtil::Time::now().toMilliSecondsDouble();
368 m_current_episode.status = EpisodeStatus::EPISODE_STARTED;
373 std::lock_guard<std::mutex> l(episodeEventMutex);
374 if (m_current_episode.episodeName != e.episodeName && e.status != EPISODE_STARTED)
376 ARMARX_ERROR <<
"Received an episode unequal to current one with non-starting status: " << e.episodeName;
378 if (m_current_episode.episodeName != e.episodeName && m_current_episode.endedInMs != 0 && e.status == EPISODE_STARTED)
380 ARMARX_WARNING <<
"Received a new starting episode without ending the last one. Last episodes name is " << m_current_episode.episodeName <<
". Finishing it now.";
382 abort.episodeName = m_current_episode.episodeName;
383 abort.status = EpisodeStatus::EPISODE_COMPLETED_ABORT;
384 abort.receivedInMs = IceUtil::Time::now().toMilliSecondsDouble();
388 if (e.status == EPISODE_COMPLETED_SUCCESS || e.status == EPISODE_COMPLETED_FAILURE || e.status == EPISODE_COMPLETED_ABORT)
390 ARMARX_DEBUG <<
"Received a terminating episode (" << e.episodeName <<
")";
391 m_current_episode.status = e.status;
392 m_current_episode.endedInMs = e.receivedInMs;
396 ARMARX_DEBUG <<
"Received a starting episode (" << e.episodeName <<
")";
397 m_current_episode.episodeName = e.episodeName;
398 m_current_episode.status = e.status;
399 m_current_episode.startedInMs = e.receivedInMs;
402 std::lock_guard<std::mutex> l2(imageEventMutex);
403 std::lock_guard<std::mutex> l3(humanPoseEventMutex);
404 std::lock_guard<std::mutex> l4(speechEventMutex);
405 std::lock_guard<std::mutex> l5(objectPoseEventMutex);
406 std::lock_guard<std::mutex> l6(kinematicUnitEventMutex);
407 std::lock_guard<std::mutex> l7(platformUnitEventMutex);
408 std::lock_guard<std::mutex> l8(platformUnitTargetEventMutex);
409 std::lock_guard<std::mutex> l9(actionEventMutex);
410 if (m_enable_export && m_current_episode.endedInMs != 0)
420 std::lock_guard<std::mutex> l(imageEventMutex);
421 ARMARX_DEBUG <<
"Received an image. Current number of images of provider " << i.providerName <<
" in episode: " << this->m_current_episode.imageEvents[i.providerName].size();
422 this->m_current_episode.imageEvents[i.providerName].push_back(i);
427 std::lock_guard<std::mutex> l(objectPoseEventMutex);
428 ARMARX_DEBUG <<
"Received an objectPose (" << o.objectName <<
"). Current number of objectPoses in episode: " << this->m_current_episode.objectPoseEvents.size();
429 this->m_current_episode.objectPoseEvents.push_back(o);
434 std::lock_guard<std::mutex> l(actionEventMutex);
436 this->m_current_episode.actionEvents.push_back(
a);
441 std::lock_guard<std::mutex> l(humanPoseEventMutex);
442 ARMARX_DEBUG <<
"Received a human pose. Current number of poses in episode: " << this->m_current_episode.humanPoseEvents.size();
443 this->m_current_episode.humanPoseEvents.push_back(p);
448 if (
s.text.find(
"export now") != std::string::npos)
450 ARMARX_IMPORTANT <<
"Received export token!. Terminating current episode and create an empty new one.";
452 terminate.episodeName = m_current_episode.episodeName;
453 terminate.status = EpisodeStatus::EPISODE_COMPLETED_ABORT;
454 terminate.receivedInMs = IceUtil::Time::now().toMilliSecondsDouble();
459 std::lock_guard<std::mutex> l(speechEventMutex);
460 ARMARX_DEBUG <<
"Received spoken text (" <<
s.text <<
"). Current number of speeches in episode: " << this->m_current_episode.speechEvents.size();
461 this->m_current_episode.speechEvents.push_back(
s);
466 std::lock_guard<std::mutex> l(kinematicUnitEventMutex);
467 ARMARX_DEBUG <<
"Received a kinematicUnitEvent. Current number of events in episode: " << this->m_current_episode.kinematicUnitEvents.size();
468 this->m_current_episode.kinematicUnitEvents.push_back(k);
473 std::lock_guard<std::mutex> l(platformUnitEventMutex);
474 ARMARX_DEBUG <<
"Received a platformUnitEvent. Current number of events in episode: " << this->m_current_episode.platformUnitEvents.size();
475 this->m_current_episode.platformUnitEvents.push_back(p);
480 std::lock_guard<std::mutex> l(platformUnitTargetEventMutex);
481 ARMARX_DEBUG <<
"Received a platformUnitTarget. Current number of events in episode: " << this->m_current_episode.platformUnitTargetEvents.size();
482 this->m_current_episode.platformUnitTargetEvents.push_back(t);