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