Writer.cpp
Go to the documentation of this file.
1 #include "Writer.h"
2 
3 #include <SimoxUtility/algorithm/get_map_keys_values.h>
4 
7 
10 #include <RobotAPI/libraries/ArmarXObjects/aron/ObjectID.aron.generated.h>
16 #include <RobotAPI/libraries/armem_objects/aron/ObjectClass.aron.generated.h>
17 #include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h>
18 #include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h>
19 #include <RobotAPI/libraries/armem_robot/aron/RobotDescription.aron.generated.h>
22 
23 #include "utils.h"
24 
26 {
27  void
29  {
30  ARMARX_DEBUG << "Writer: registerPropertyDefinitions";
31 
32  const std::string prefix = propertyPrefix;
33 
34  def->optional(properties.memoryName, prefix + "MemoryName");
35 
36  def->optional(properties.coreInstanceSegmentName,
37  prefix + "CoreSegment",
38  "Name of the memory core segment to use for object instances.");
39  def->optional(properties.coreClassSegmentName,
40  prefix + "CoreSegment",
41  "Name of the memory core segment to use for object classes.");
42 
43  ARMARX_IMPORTANT << "Writer: add property '" << prefix << "ProviderName'";
44  def->required(
45  properties.providerName, prefix + "write.ProviderName", "Name of this provider");
46  }
47 
48  void
50  {
51  // Wait for the memory to become available and add it as dependency.
52  ARMARX_IMPORTANT << "Writer: Waiting for memory '" << properties.memoryName << "' ...";
53  try
54  {
55  memoryWriter = memoryNameSystem.useWriter(properties.memoryName);
56  memoryReader = memoryNameSystem.useReader(properties.memoryName);
57  ARMARX_IMPORTANT << "Writer: Connected to memory '" << properties.memoryName << "'";
58  }
60  {
61  ARMARX_ERROR << e.what();
62  return;
63  }
64 
65  const auto resultCoreClassSegment =
66  memoryWriter.addSegment(properties.coreClassSegmentName, properties.providerName);
67 
68  const auto resultCoreInstanceSegmentName =
69  memoryWriter.addSegment(properties.coreInstanceSegmentName, properties.providerName);
70 
71  armem::MemoryID refId = armem::MemoryID(resultCoreClassSegment.segmentID);
72 
73  armem::MemoryID id;
74  id.setCoreSegmentID(refId); // listen to all provider segments!
75 
76  updateKnownObjects();
77  memoryNameSystem.subscribe(id, this, &Writer::updateKnownObjects);
78  }
79 
80  void
81  Writer::updateKnownObject(const armem::MemoryID& snapshotId)
82  {
83  arondto::RobotDescription aronArticulatedObjectDescription;
84  // aronArticulatedObjectDescription.fromAron(snapshotId.ent);
85 
86  // TODO(fabian.reister): implement
87  }
88 
89  void
90  Writer::updateKnownObjects(const armem::MemoryID& subscriptionID,
91  const std::vector<armem::MemoryID>& snapshotIDs)
92  {
93  ARMARX_INFO << "New objects available!";
94  updateKnownObjects();
95  }
96 
97  void
98  Writer::updateKnownObjects()
99  {
100  knownObjects = queryDescriptions(Time::Now());
101 
102  ARMARX_INFO << "Known articulated objects " << simox::alg::get_keys(knownObjects);
103  }
104 
105  std::optional<armem::MemoryID>
106  Writer::storeOrGetClass(const ArticulatedObject& obj)
107  {
108  ARMARX_TRACE;
109 
110  const auto objectId = knownObjects.find(obj.description.name);
111 
112  // check if exists
113  if (objectId != knownObjects.end())
114  {
115  return objectId->second;
116  }
117 
118  ARMARX_INFO << simox::alg::get_keys(knownObjects);
119 
120  throw LocalException("articulated object class " + obj.description.name + " not found");
121 
122  // otherwise create
123  if (properties.allowClassCreation)
124  {
125  return storeClass(obj);
126  }
127 
128  return std::nullopt;
129  }
130 
131  std::optional<armem::MemoryID>
133  {
134  std::lock_guard g{memoryWriterMutex};
135 
136  ARMARX_DEBUG << "Trying to create core segment + provider segment";
137 
138  // TODO(fabian.reister): variable provider segment
139  const auto result =
140  memoryWriter.addSegment(properties.coreClassSegmentName, properties.providerName);
141 
142  if (not result.success)
143  {
144  ARMARX_ERROR << "Creating core segment failed. Reason: " << result.errorMessage;
145  return std::nullopt;
146  }
147 
148  const auto& timestamp = obj.timestamp;
149 
150  const auto providerId = armem::MemoryID(result.segmentID);
151  const auto entityID =
152  providerId.withEntityName(obj.description.name).withTimestamp(timestamp);
153 
155  update.entityID = entityID;
156 
157  arondto::RobotDescription aronArticulatedObjectDescription;
158  toAron(aronArticulatedObjectDescription, obj.description);
159 
160  update.instancesData = {aronArticulatedObjectDescription.toAron()};
161  update.referencedTime = timestamp;
162 
163  ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
164  armem::EntityUpdateResult updateResult = memoryWriter.commit(update);
165 
166  ARMARX_DEBUG << updateResult;
167 
168  if (not updateResult.success)
169  {
170  ARMARX_ERROR << updateResult.errorMessage;
171  return std::nullopt;
172  }
173 
174  // update cache (TODO: likely remove this)
175  knownObjects[obj.description.name] = updateResult.snapshotID;
176 
177  return updateResult.snapshotID;
178  }
179 
180  std::string
182  {
183  return properties.providerName;
184  }
185 
186  void
187  Writer::setProviderName(const std::string& providerName)
188  {
189  this->properties.providerName = providerName;
190  }
191 
192  bool
194  {
195  std::lock_guard g{memoryWriterMutex};
196 
197  const auto& timestamp = obj.timestamp;
198 
199  ARMARX_CHECK(not obj.instance.empty()) << "An object instance name must be provided!";
200  const std::string entityName = obj.description.name + "/" + obj.instance;
201 
202  ARMARX_DEBUG << "Storing articulated object instance '" << entityName << "' (provider '"
203  << properties.providerName << "')";
204 
205  const auto providerId = armem::MemoryID()
206  .withMemoryName(properties.memoryName)
207  .withCoreSegmentName(properties.coreInstanceSegmentName)
208  .withProviderSegmentName(properties.providerName);
209 
211  update.entityID = providerId.withEntityName(entityName);
212  // .withTimestamp(timestamp); // You only need to specify the entity ID, not the snapshot ID
213 
214  // arondto::Robot aronArticulatedObject;
215  // robot::toAron(aronArticulatedObject, obj);
216 
217  arondto::ObjectInstance objectInstance;
218  toAron(objectInstance, obj.config);
219 
220  const auto classId = storeOrGetClass(obj);
221 
222  if (not classId)
223  {
224  ARMARX_WARNING << "Could not get class for object " << obj.description.name;
225  return false;
226  }
227 
228  // install memory link
229  toAron(objectInstance.classID, *classId);
230 
231  armem::MemoryID id;
232  id.setEntityID(classId->getEntityID());
233 
234  armarx::ObjectID objectId(id.entityName);
235 
237  cs.className = objectId.className();
238  cs.instanceName = objectId.instanceName();
239  cs.dataset = objectId.dataset();
240 
241  objectInstance.pose.objectID = cs;
242  objectInstance.pose.providerName = properties.providerName;
243  objectInstance.pose.attachmentValid = false;
244 
245  update.instancesData = {objectInstance.toAron()};
246  update.referencedTime = timestamp;
247 
248  ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
249  armem::EntityUpdateResult updateResult = memoryWriter.commit(update);
250 
251  ARMARX_DEBUG << updateResult;
252 
253  if (not updateResult.success)
254  {
255  ARMARX_WARNING << updateResult.errorMessage;
256  }
257 
258  return updateResult.success;
259  }
260 
261  bool
263  {
264  const std::optional<armem::MemoryID> classId = storeOrGetClass(obj);
265 
266  if (not classId)
267  {
268  ARMARX_WARNING << "Could not get class id for object " << obj.description.name << "! "
269  << "Known classes are " << simox::alg::get_keys(knownObjects);
270  return false;
271  }
272 
273  return storeInstance(obj);
274  }
275 
276  // TODO this is a duplicate
277  std::optional<robot::RobotDescription>
278  Writer::getRobotDescription(const armarx::armem::wm::Memory& memory) const
279  {
280  // clang-format off
281  const armem::wm::ProviderSegment& providerSegment = memory
282  .getCoreSegment(properties.coreClassSegmentName)
283  .getProviderSegment(properties.providerName); // TODO(fabian.reister): all
284  // clang-format on
285 
286  if (const armem::wm::EntityInstance* instance = findFirstInstance(providerSegment))
287  {
288  return convertRobotDescription(*instance);
289  }
290  else
291  {
292  ARMARX_WARNING << "No entity snapshots found";
293  return std::nullopt;
294  }
295  }
296 
297  std::unordered_map<std::string, armem::MemoryID>
298  Writer::getRobotDescriptions(const armarx::armem::wm::Memory& memory) const
299  {
300  const armem::wm::CoreSegment& coreSegment =
301  memory.getCoreSegment(properties.coreClassSegmentName);
302 
303  std::unordered_map<std::string, armem::MemoryID> descriptions;
304  coreSegment.forEachEntity(
305  [&descriptions](const wm::Entity& entity)
306  {
307  if (entity.empty())
308  {
309  ARMARX_WARNING << "No entity found";
310  return true;
311  }
312 
313  const armem::wm::EntitySnapshot& sn = entity.getFirstSnapshot();
314  if (const auto robotDescription = convertRobotDescription(sn.getInstance(0)))
315  {
316  const armem::MemoryID snapshotID(sn.id());
317  descriptions.insert({robotDescription->name, snapshotID});
318  }
319  return true;
320  });
321 
322  return descriptions;
323  }
324 
325  std::unordered_map<std::string, armem::MemoryID>
326  Writer::queryDescriptions(const armem::Time& timestamp)
327  {
328  // Query all entities from provider.
329  armem::client::query::Builder qb;
330 
331  // clang-format off
332  qb
333  .coreSegments().withName(properties.coreClassSegmentName)
334  .providerSegments().all()
335  .entities().all()
336  .snapshots().latest(); // TODO beforeTime(timestamp);
337  // clang-format on
338 
339  const armem::client::QueryResult qResult = memoryReader.query(qb.buildQueryInput());
340 
341  ARMARX_DEBUG << "Lookup result in reader: " << qResult;
342 
343  if (not qResult.success) /* c++20 [[unlikely]] */
344  {
345  return {};
346  }
347 
348  return getRobotDescriptions(qResult.memory);
349  }
350 
351 } // namespace armarx::armem::articulated_object
armarx::armem::MemoryID::setCoreSegmentID
void setCoreSegmentID(const MemoryID &id)
Definition: MemoryID.cpp:361
armarx::ObjectID
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
Definition: ObjectID.h:11
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:183
armarx::armem::wm::ProviderSegment
Client-side working memory provider segment.
Definition: memory_definitions.h:105
query.h
armarx::armem::MemoryID::withMemoryName
MemoryID withMemoryName(const std::string &name) const
Definition: MemoryID.cpp:396
armarx::armem::wm::EntityInstance
Client-side working entity instance.
Definition: memory_definitions.h:32
armarx::armem::robot::Robot
Definition: types.h:68
armarx::armem::attachment::ObjectID
armem::MemoryID ObjectID
Definition: types.h:79
armarx::armem::articulated_object::Writer::setProviderName
void setProviderName(const std::string &providerName)
Definition: Writer.cpp:187
armarx::core::time::DateTime::Now
static DateTime Now()
Definition: DateTime.cpp:55
armarx::armem::EntityUpdateResult
Result of an EntityUpdate.
Definition: Commit.h:72
armarx::ObjectID::dataset
std::string dataset() const
Definition: ObjectID.h:24
MemoryID.h
armarx::armem::base::MemoryBase::getCoreSegment
CoreSegmentT & getCoreSegment(const std::string &name)
Definition: MemoryBase.h:132
armarx::armem::articulated_object::Writer::getProviderName
std::string getProviderName() const
Definition: Writer.cpp:181
armarx::armem::client::Writer::addSegment
data::AddSegmentResult addSegment(const std::string &coreSegmentName, const std::string &providerSegmentName, bool clearWhenExists=false)
Definition: Writer.cpp:16
armarx::armem::toAron
void toAron(arondto::MemoryID &dto, const MemoryID &bo)
Definition: aron_conversions.cpp:19
armarx::armem::client::MemoryNameSystem::useWriter
Writer useWriter(const MemoryID &memoryID)
Use a memory server and get a writer for it.
Definition: MemoryNameSystem.cpp:276
armarx::armem::articulated_object::Writer::connect
void connect(armem::client::MemoryNameSystem &memoryNameSystem)
Definition: Writer.cpp:49
armarx::memory
Brief description of class memory.
Definition: memory.h:39
armarx::armem::findFirstInstance
const ContainerT::EntityInstanceT * findFirstInstance(const ContainerT &container)
Definition: operations.h:41
armarx::armem::articulated_object::convertRobotDescription
std::optional< robot::RobotDescription > convertRobotDescription(const armem::wm::EntityInstance &instance)
Definition: utils.cpp:10
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::armem::client::Writer::commit
CommitResult commit(const Commit &commit)
Writes a Commit to the memory.
Definition: Writer.cpp:51
ARMARX_TRACE
#define ARMARX_TRACE
Definition: trace.h:69
armarx::armem::articulated_object::ArticulatedObject
armarx::armem::robot::Robot ArticulatedObject
Definition: types.h:140
armarx::armem::MemoryID::withProviderSegmentName
MemoryID withProviderSegmentName(const std::string &name) const
Definition: MemoryID.cpp:412
armarx::armem::MemoryID
A memory ID.
Definition: MemoryID.h:47
armarx::ObjectID::className
std::string className() const
Definition: ObjectID.h:28
if
if(!yyvaluep)
Definition: Grammar.cpp:724
armarx::armem::MemoryID::withCoreSegmentName
MemoryID withCoreSegmentName(const std::string &name) const
Definition: MemoryID.cpp:404
armarx::armem::robot::Robot::description
RobotDescription description
Definition: types.h:70
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:177
ObjectID.h
error.h
armarx::armem::wm::Memory
Client-side working memory.
Definition: memory_definitions.h:133
armarx::armem::client::MemoryNameSystem::useReader
Reader useReader(const MemoryID &memoryID)
Use a memory server and get a reader for it.
Definition: MemoryNameSystem.cpp:184
armarx::armem::robot::Robot::instance
std::string instance
Definition: types.h:71
armarx::armem::EntityUpdate
An update of an entity for a specific point in time.
Definition: Commit.h:27
armarx::armem::client::util::MemoryListener::subscribe
SubscriptionHandle subscribe(const MemoryID &subscriptionID, Callback Callback)
Definition: MemoryListener.cpp:116
ObjectInfo.h
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:189
armarx::armem::articulated_object::Writer::store
bool store(const ArticulatedObject &obj) override
Definition: Writer.cpp:262
operations.h
aron_conversions.h
utils.h
armarx::armem::server::ltm::util::mongodb::detail::update
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition: mongodb.cpp:67
aron_conversions.h
armarx::ObjectID::instanceName
std::string instanceName() const
Definition: ObjectID.h:32
armarx::armem::robot::Robot::timestamp
DateTime timestamp
Definition: types.h:75
armarx::core::time::DateTime
Represents a point in time.
Definition: DateTime.h:24
armarx::armem::robot::RobotDescription::name
std::string name
Definition: types.h:21
armarx::armem::server::wm::EntitySnapshot
armem::wm::EntitySnapshot EntitySnapshot
Definition: forward_declarations.h:65
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
PropertyDefinitionContainer.h
Writer.h
armarx::armem::articulated_object::Writer::storeClass
std::optional< armem::MemoryID > storeClass(const ArticulatedObject &obj)
Definition: Writer.cpp:132
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::armem::articulated_object
Definition: ArticulatedObjectReader.cpp:24
armarx::armem::client::MemoryNameSystem
The memory name system (MNS) client.
Definition: MemoryNameSystem.h:69
armarx::armem::error::CouldNotResolveMemoryServer
Indicates that a query to the Memory Name System failed.
Definition: mns.h:26
armarx::armem::articulated_object::Writer::storeInstance
bool storeInstance(const ArticulatedObject &obj)
Definition: Writer.cpp:193
armarx::armem::articulated_object::Writer::registerPropertyDefinitions
void registerPropertyDefinitions(armarx::PropertyDefinitionsPtr &def)
Definition: Writer.cpp:28
Logging.h
robot_conversions.h
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::armem::MemoryID::setEntityID
void setEntityID(const MemoryID &id)
Definition: MemoryID.cpp:375
armarx::armem::robot::Robot::config
RobotState config
Definition: types.h:73
armarx::human::MemoryID
const armem::MemoryID MemoryID
Definition: memory_ids.cpp:29