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>
19 #include <RobotAPI/libraries/armem_robot_state/aron/Robot.aron.generated.h>
20 #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 
73 
74  std::optional<armem::MemoryID>
75  Writer::storeOrGetClass(const ArticulatedObject& obj) const
76  {
78 
79  // key: name of object: RobotDescription::name
80  const std::unordered_map<std::string, MemoryID> knownObjects = queryDescriptions(Time::Now());
81  ARMARX_VERBOSE << "Known articulated objects " << simox::alg::get_keys(knownObjects);
82 
83  const auto objectId = knownObjects.find(obj.description.name);
84 
85  // check if exists
86  if (objectId != knownObjects.end())
87  {
88  return objectId->second;
89  }
90 
91  ARMARX_INFO << simox::alg::get_keys(knownObjects);
92 
93  throw LocalException("articulated object class " + obj.description.name + " not found");
94 
95  // otherwise create
96  if (properties.allowClassCreation)
97  {
98  return storeClass(obj);
99  }
100 
101  return std::nullopt;
102  }
103 
104  std::optional<armem::MemoryID>
106  {
107  std::lock_guard g{memoryWriterMutex};
108 
109  ARMARX_DEBUG << "Trying to create core segment + provider segment";
110 
111  // TODO(fabian.reister): variable provider segment
112  const auto result =
113  memoryWriter.addSegment(properties.coreClassSegmentName, properties.providerName);
114 
115  if (not result.success)
116  {
117  ARMARX_ERROR << "Creating core segment failed. Reason: " << result.errorMessage;
118  return std::nullopt;
119  }
120 
121  const auto& timestamp = obj.timestamp;
122 
123  const auto providerId = armem::MemoryID(result.segmentID);
124  const auto entityID =
125  providerId.withEntityName(obj.description.name).withTimestamp(timestamp);
126 
128  update.entityID = entityID;
129 
130  arondto::RobotDescription aronArticulatedObjectDescription;
131  toAron(aronArticulatedObjectDescription, obj.description);
132 
133  update.instancesData = {aronArticulatedObjectDescription.toAron()};
134  update.referencedTime = timestamp;
135 
136  ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
137  armem::EntityUpdateResult updateResult = memoryWriter.commit(update);
138 
139  ARMARX_DEBUG << updateResult;
140 
141  if (not updateResult.success)
142  {
143  ARMARX_ERROR << updateResult.errorMessage;
144  return std::nullopt;
145  }
146 
147  return updateResult.snapshotID;
148  }
149 
150  std::string
152  {
153  return properties.providerName;
154  }
155 
156  void
157  Writer::setProviderName(const std::string& providerName)
158  {
159  this->properties.providerName = providerName;
160  }
161 
162  bool
163  Writer::storeInstance(const ArticulatedObject& obj, const bool isStatic) const
164  {
165  std::lock_guard g{memoryWriterMutex};
166 
167  const auto& timestamp = obj.timestamp;
168 
169  ARMARX_CHECK(not obj.instance.empty()) << "An object instance name must be provided!";
170  const std::string entityName = obj.description.name + "/" + obj.instance;
171 
172  ARMARX_DEBUG << "Storing articulated object instance '" << entityName << "' (provider '"
173  << properties.providerName << "')";
174 
175  const auto providerId = armem::MemoryID()
176  .withMemoryName(properties.memoryName)
177  .withCoreSegmentName(properties.coreInstanceSegmentName)
178  .withProviderSegmentName(properties.providerName);
179 
181  update.entityID = providerId.withEntityName(entityName);
182  // .withTimestamp(timestamp); // You only need to specify the entity ID, not the snapshot ID
183 
184  // arondto::Robot aronArticulatedObject;
185  // robot::toAron(aronArticulatedObject, obj);
186 
187  arondto::ObjectInstance objectInstance;
188  toAron(objectInstance, obj.config);
189 
190  const std::optional<armem::MemoryID> classId = storeOrGetClass(obj);
191 
192  if (not classId)
193  {
194  ARMARX_WARNING << "Could not get class for object " << obj.description.name;
195  return false;
196  }
197 
198  // install memory link
199  toAron(objectInstance.classID, *classId);
200 
201  // set object instance id
202  const MemoryID memoryInstanceId = classId->withEntityName(entityName);
203 
204  armem::MemoryID id;
205  id.setEntityID(memoryInstanceId.getEntityID());
206 
207  armarx::ObjectID objectId(id.entityName);
208  ARMARX_DEBUG << "Object ID: " << objectId;
209 
210  ARMARX_CHECK_NOT_EMPTY(objectId.instanceName())
211  << "An object instance name must be provided!";
212 
214  cs.className = objectId.className();
215  cs.instanceName = objectId.instanceName();
216  cs.dataset = objectId.dataset();
217 
218  objectInstance.pose.objectID = cs;
219  objectInstance.pose.providerName = properties.providerName;
220  objectInstance.pose.attachmentValid = false;
221 
222  objectInstance.pose.isStatic = isStatic;
223 
224  update.instancesData = {objectInstance.toAron()};
225  update.referencedTime = timestamp;
226 
227  ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
228  armem::EntityUpdateResult updateResult = memoryWriter.commit(update);
229 
230  ARMARX_DEBUG << updateResult;
231 
232  if (not updateResult.success)
233  {
234  ARMARX_WARNING << updateResult.errorMessage;
235  }
236 
237  return updateResult.success;
238  }
239 
240  bool
241  Writer::store(const ArticulatedObject& obj, const bool isStatic) const
242  {
243  const std::optional<armem::MemoryID> classId = storeOrGetClass(obj);
244 
245  if (not classId)
246  {
247  ARMARX_WARNING << "Could not get class id for object " << obj.description.name << "! "
248  << "Known classes are " << simox::alg::get_keys(queryDescriptions(Time::Now()));
249  return false;
250  }
251 
252  return storeInstance(obj, isStatic);
253  }
254 
255  // TODO this is a duplicate
256  std::optional<robot_state::description::RobotDescription>
257  Writer::getRobotDescription(const armarx::armem::wm::Memory& memory) const
258  {
259  // clang-format off
260  const armem::wm::ProviderSegment& providerSegment = memory
261  .getCoreSegment(properties.coreClassSegmentName)
262  .getProviderSegment(properties.providerName); // TODO(fabian.reister): all
263  // clang-format on
264 
265  if (const armem::wm::EntityInstance* instance = findFirstInstance(providerSegment))
266  {
267  return convertRobotDescription(*instance);
268  }
269  else
270  {
271  ARMARX_WARNING << "No entity snapshots found";
272  return std::nullopt;
273  }
274  }
275 
276  std::unordered_map<std::string, armem::MemoryID>
277  Writer::getRobotDescriptions(const armarx::armem::wm::Memory& memory) const
278  {
279  const armem::wm::CoreSegment& coreSegment =
280  memory.getCoreSegment(properties.coreClassSegmentName);
281 
282  std::unordered_map<std::string, armem::MemoryID> descriptions;
283  coreSegment.forEachEntity(
284  [&descriptions](const wm::Entity& entity)
285  {
286  if (entity.empty())
287  {
288  ARMARX_WARNING << "No entity found";
289  return true;
290  }
291 
292  const armem::wm::EntitySnapshot& sn = entity.getFirstSnapshot();
293  if (const auto robotDescription = convertRobotDescription(sn.getInstance(0)))
294  {
295  const armem::MemoryID snapshotID(sn.id());
296  descriptions.insert({robotDescription->name, snapshotID});
297  }
298  return true;
299  });
300 
301  return descriptions;
302  }
303 
304  std::unordered_map<std::string, armem::MemoryID>
305  Writer::queryDescriptions(const armem::Time& timestamp) const
306  {
307  // Query all entities from provider.
308  armem::client::query::Builder qb;
309 
310  // clang-format off
311  qb
312  .coreSegments().withName(properties.coreClassSegmentName)
313  .providerSegments().all()
314  .entities().all()
315  .snapshots().beforeTime(timestamp);
316  // clang-format on
317 
318  const armem::client::QueryResult qResult = memoryReader.query(qb.buildQueryInput());
319 
320  ARMARX_DEBUG << "Lookup result in reader: " << qResult;
321 
322  if (not qResult.success) /* c++20 [[unlikely]] */
323  {
324  return {};
325  }
326 
327  return getRobotDescriptions(qResult.memory);
328  }
329 
330 } // namespace armarx::armem::articulated_object
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::ObjectID
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
Definition: ObjectID.h:10
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:190
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:401
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:157
armarx::core::time::DateTime::Now
static DateTime Now()
Definition: DateTime.cpp:51
armarx::armem::EntityUpdateResult
Result of an EntityUpdate.
Definition: Commit.h:69
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:151
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:289
armarx::armem::articulated_object::Writer::connect
void connect(armem::client::MemoryNameSystem &memoryNameSystem)
Definition: Writer.cpp:50
ARMARX_CHECK_NOT_EMPTY
#define ARMARX_CHECK_NOT_EMPTY(c)
Definition: ExpressionException.h:224
armarx::memory
Brief description of class memory.
Definition: memory.h:38
armarx::armem::findFirstInstance
const ContainerT::EntityInstanceT * findFirstInstance(const ContainerT &container)
Definition: operations.h:37
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:77
armarx::armem::articulated_object::Writer::storeInstance
bool storeInstance(const ArticulatedObject &obj, bool isStatic) const
Definition: Writer.cpp:163
armarx::armem::MemoryID::withProviderSegmentName
MemoryID withProviderSegmentName(const std::string &name) const
Definition: MemoryID.cpp:417
armarx::armem::MemoryID
A memory ID.
Definition: MemoryID.h:47
armarx::armem::articulated_object::Writer::store
bool store(const ArticulatedObject &obj, bool isStatic) const override
Definition: Writer.cpp:241
if
if(!yyvaluep)
Definition: Grammar.cpp:645
armarx::armem::MemoryID::withCoreSegmentName
MemoryID withCoreSegmentName(const std::string &name) const
Definition: MemoryID.cpp:409
armarx::armem::robot_state::Robot::config
RobotState config
Definition: types.h:131
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
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:198
armarx::armem::EntityUpdate
An update of an entity for a specific point in time.
Definition: Commit.h:25
aron_conversions.h
armarx::armem::client::Writer::commit
CommitResult commit(const Commit &commit) const
Writes a Commit to the memory.
Definition: Writer.cpp:59
ObjectInfo.h
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
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:68
aron_conversions.h
armarx::core::time::DateTime
Represents a point in time.
Definition: DateTime.h:24
aron_conversions.h
armarx::armem::MemoryID::getEntityID
MemoryID getEntityID() const
Definition: MemoryID.cpp:310
armarx::armem::server::wm::EntitySnapshot
armem::wm::EntitySnapshot EntitySnapshot
Definition: forward_declarations.h:66
armarx::armem::MemoryID::withEntityName
MemoryID withEntityName(const std::string &name) const
Definition: MemoryID.cpp:425
armarx::armem::robot_state::description::RobotDescription::name
std::string name
Definition: types.h:48
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
PropertyDefinitionContainer.h
Writer.h
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::armem::articulated_object
Definition: ArticulatedObjectReader.cpp:26
armarx::armem::client::MemoryNameSystem
The memory name system (MNS) client.
Definition: MemoryNameSystem.h:68
armarx::armem::error::CouldNotResolveMemoryServer
Indicates that a query to the Memory Name System failed.
Definition: mns.h:24
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:105
Logging.h
robot_conversions.h
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::armem::MemoryID::setEntityID
void setEntityID(const MemoryID &id)
Definition: MemoryID.cpp:380
armarx::armem::robot_state::Robot::description
description::RobotDescription description
Definition: types.h:128
armarx::human::MemoryID
const armem::MemoryID MemoryID
Definition: memory_ids.cpp:28