ObjectMemory.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package RobotAPI::ArmarXObjects::ObjectMemory
17 * @author Rainer Kartmann ( rainer dot kartmann at kit dot edu )
18 * @date 2021
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#include "ObjectMemory.h"
24
25#include <VirtualRobot/VirtualRobot.h>
26
32
38#include <RobotAPI/libraries/armem_objects/aron/Marker.aron.generated.h>
39#include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h>
41
43
45
47{
48
51 {
54
55 const std::string prefix = "mem.";
56 workingMemory().name() = objects::memoryID.memoryName;
57
58 classSegment.defineProperties(defs, prefix + "cls.");
59 instance::SegmentAdapter::defineProperties(defs, prefix + "inst.");
61
62 attachmentSegment.defineProperties(defs, prefix + "attachments.");
63
64
65 // Publish
66 defs->topic(debugObserver);
67
68 // Subscribe
69 defs->topic<
70 objpose::
71 ObjectPoseTopic>(); // "ObjectPoseTopic", "ObjectPoseTopicName", "Name of the Object Pose Topic.");
72
73 // Use
74 // defs->component(kinematicUnitObserver); // Optional dependency.
75 defs->defineOptionalProperty<std::string>("cmp.KinematicUnitObserverName",
76 "KinematicUnitObserver",
77 "Name of the kinematic unit observer.");
78 defs->optional(predictionTimeWindow,
79 "prediction.TimeWindow",
80 "Duration of time window into the past to use for predictions"
81 " when requested via the PredictingMemoryInterface (in seconds).");
82
83 defs->optional(p.markerMemoryName, prefix + ".marker.Name", "Marker Memory Name");
84 defs->optional(p.maxMarkerHistorySize,
85 prefix + ".marker.maxHistorySize",
86 "Maximum marker memory history size");
87
88 return defs;
89 }
90
94 classSegment(iceAdapter()),
95 attachmentSegment(iceAdapter()),
96 virtualRobotReaderPlugin(nullptr)
97 {
98 addPlugin(virtualRobotReaderPlugin);
99 }
100
104
105 std::string
107 {
108 return "ObjectMemory";
109 }
110
111 void
113 {
114 const auto initSegmentWithCatch = [&](const std::string& segmentName, const auto&& fn)
115 {
116 try
117 {
118 fn();
119 }
120 catch (const LocalException& e)
121 {
122 ARMARX_ERROR << "Failed to init `" << segmentName << "` segment. Reason: \n"
123 << e.what();
124 }
125 catch (const std::exception& e)
126 {
127 ARMARX_ERROR << "Failed to init `" << segmentName << "` segment. Reason: \n"
128 << e.what();
129 }
130 catch (...)
131 {
132 ARMARX_ERROR << "Failed to init `" << segmentName
133 << "` segment for unknown reason.";
134 }
135 };
136
137 // Class segment needs to be initialized before instance segment,
138 // as the instance segment may refer to and search through the class segment.
139 initSegmentWithCatch("class", [&]() { classSegment.init(); });
140
143
144 initSegmentWithCatch("attachment", [&]() { attachmentSegment.init(); });
145
146 initSegmentWithCatch(p.markerMemoryName,
147 [&]()
148 {
149 workingMemory()
150 .addCoreSegment(p.markerMemoryName,
151 arondto::Marker::ToAronType())
152 .setMaxHistorySize(p.maxMarkerHistorySize);
153 });
154 }
155
156 void
158 {
159 ARMARX_CHECK_NOT_NULL(virtualRobotReaderPlugin);
160
162 kinematicUnitObserver, "cmp.KinematicUnitObserverName", false, "", false);
163
164 // Pass the debug observer to the long-term memory for timing measurements
165 if (debugObserver)
166 {
167 longtermMemory().setDebugObserver(debugObserver);
168 ARMARX_INFO << "Debug observer set for LTM timing measurements";
169 }
170
171 // Create first to use the original values.
173
174 // ARMARX_CHECK(virtualRobotReaderPlugin->isAvailable());
175
176 instance::SegmentAdapter::connect(&virtualRobotReaderPlugin->get(),
177 kinematicUnitObserver,
179 debugObserver);
180
182 std::experimental::make_observer(&virtualRobotReaderPlugin->get()),
184 debugObserver);
185
186 classSegment.connect(ArVizComponentPluginUser::getArvizClient());
187
188 attachmentSegment.connect();
189
191 }
192
193 void
195 {
197 // FIXME
198 // familiar_object_instance::SegmentAdapter::disconnect();
199 // classSegment.disconnect();
200 // attachmentSegment.disconnect();
201 }
202
203 void
207
208 armem::actions::GetActionsOutputSeq
209 ObjectMemory::getActions(const armem::actions::GetActionsInputSeq& inputs)
210 {
211 using namespace armem::actions;
212 GetActionsOutputSeq outputs;
213 for (const auto& input : inputs)
214 {
215 auto memoryID = armarx::fromIce<armem::MemoryID>(input.id);
216 if (armem::contains(armem::MemoryID("Object", "Class"), memoryID) and
217 memoryID.hasEntityName() and not memoryID.hasGap())
218 {
219 Menu menu{
220 Action{"vis", "Visualize object"},
221 };
222 // For strange C++ reasons, this works, but emplace_back doesn't.
223 outputs.push_back({menu.toIce()});
224 }
225 }
226
227 return outputs;
228 }
229
230 armem::actions::ExecuteActionOutputSeq
231 ObjectMemory::executeActions(const armem::actions::ExecuteActionInputSeq& inputs)
232 {
233 using namespace armem::actions;
234 ExecuteActionOutputSeq outputs;
235
236 for (const auto& input : inputs)
237 {
238 auto memoryID = armarx::fromIce<armem::MemoryID>(input.id);
239 if (input.actionPath == ActionPath{"vis"})
240 {
241 if (armem::contains(armem::MemoryID("Object", "Class"), memoryID) and
242 memoryID.hasEntityName() and not memoryID.hasGap())
243 {
244 classSegment.visualizeClass(memoryID);
245 outputs.emplace_back(true, "");
246 }
247 else
248 {
249 std::stringstream sstream;
250 sstream << "MemoryID " << memoryID
251 << " does not refer to a valid object class.";
252 outputs.emplace_back(false, sstream.str());
253 }
254 }
255 else
256 {
257 std::stringstream sstream;
258 sstream << "Action path " << input.actionPath << " is not defined.";
259 outputs.emplace_back(false, sstream.str());
260 }
261 }
262 return outputs;
263 }
264
265 armem::prediction::data::PredictionResultSeq
266 ObjectMemory::predict(const armem::prediction::data::PredictionRequestSeq& requests)
267 {
268 std::vector<armem::prediction::data::PredictionResult> results;
269 for (const auto& request : requests)
270 {
271 auto boRequest = armarx::fromIce<armem::PredictionRequest>(request);
273 result.snapshotID = boRequest.snapshotID;
274 if (armem::contains(workingMemory().id().withCoreSegmentName("Instance"),
275 boRequest.snapshotID) and
276 not boRequest.snapshotID.hasGap() and boRequest.snapshotID.hasTimestamp())
277 {
278 objpose::ObjectPosePredictionRequest objPoseRequest;
279 toIce(objPoseRequest.timeWindow, Duration::SecondsDouble(predictionTimeWindow));
280 objPoseRequest.objectID = toIce(ObjectID(request.snapshotID.entityName));
281 objPoseRequest.settings = request.settings;
282 toIce(objPoseRequest.timestamp, boRequest.snapshotID.timestamp);
283
284 objpose::ObjectPosePredictionResult objPoseResult =
285 predictObjectPoses({objPoseRequest}).at(0);
286 result.success = objPoseResult.success;
287 result.errorMessage = objPoseResult.errorMessage;
288
289 if (objPoseResult.success)
290 {
292 builder.latestEntitySnapshot(boRequest.snapshotID);
294 query(builder.buildQueryInputIce()));
295 std::string instanceError =
296 "Could not find instance '" + boRequest.snapshotID.str() + "' in memory";
297 if (!queryResult.success)
298 {
299 result.success = false;
300 result.errorMessage << instanceError << ":\n" << queryResult.errorMessage;
301 }
302 else
303 {
304 if (not boRequest.snapshotID.hasInstanceIndex())
305 {
306 boRequest.snapshotID.instanceIndex = 0;
307 }
308 auto* aronInstance = queryResult.memory.findLatestInstance(
309 boRequest.snapshotID, boRequest.snapshotID.instanceIndex);
310 if (aronInstance == nullptr)
311 {
312 result.success = false;
313 result.errorMessage << instanceError << ": No latest instance found.";
314 }
315 else
316 {
317 auto instance =
318 armem::arondto::ObjectInstance::FromAron(aronInstance->data());
320 instance.pose,
321 armarx::fromIce<objpose::ObjectPose>(objPoseResult.prediction));
322 result.prediction = instance.toAron();
323 }
324 }
325 }
326 }
327 else
328 {
329 result.success = false;
330 result.errorMessage << "No predictions are supported for MemoryID "
331 << boRequest.snapshotID;
332 }
333 results.push_back(result.toIce());
334 }
335
336 return results;
337 }
338
339 void
341 {
342 using namespace armarx::RemoteGui::Client;
343
344 tab.reset(new RemoteGuiTab);
345
346 tab->instance.setup(*this);
347 tab->clazz.setup(classSegment);
348
349 HBoxLayout segments = {tab->instance.group, tab->clazz.group};
350 VBoxLayout root = {segments, VSpacer()};
351 RemoteGui_createTab(Component::getName(), root, tab.get());
352 }
353
354 void
356 {
357 tab->instance.update(*this);
358 tab->clazz.update(classSegment);
359
360 if (tab->clazz.data.rebuild)
361 {
363 }
364 }
365
366 void
367 ObjectMemory::reloadKnownObjectClasses(const Ice::Current& current)
368 {
369 ARMARX_INFO << "Reloading object classes ...";
370 classSegment.reloadObjectClassesByObjectFinder();
371 ARMARX_INFO << "Reloaded object classes.";
372 }
373
374
375} // namespace armarx::armem::server::obj
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
armarx::viz::Client & getArvizClient()
Default component property definition container.
Definition Component.h:70
ProxyType getProxyFromProperty(const std::string &propertyName, bool addToDependencies=false, const std::string &endpoints="", bool throwOnProxyError=true)
Get a proxy whose name is specified by the given property.
Definition Component.h:242
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
Definition ObjectID.h:11
bool hasGap() const
Indicate whether this ID has a gap such as in 'Memory//MyProvider' (no core segment name).
Definition MemoryID.cpp:163
bool hasEntityName() const
Definition MemoryID.h:121
void latestEntitySnapshot(const MemoryID &entityID)
Definition Builder.cpp:131
armem::query::data::Input buildQueryInputIce() const
Definition Builder.cpp:21
void setDebugObserver(DebugObserverInterfacePrx observer)
Set an optional debug observer for timing measurements.
Definition MemoryBase.h:517
Brief description of class ObjectMemory.
armem::actions::ExecuteActionOutputSeq executeActions(const armem::actions::ExecuteActionInputSeq &inputs) override
void onInitComponent() override
Pure virtual hook for the subclass.
void onDisconnectComponent() override
Hook for subclass.
armem::actions::GetActionsOutputSeq getActions(const armem::actions::GetActionsInputSeq &inputs) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
Creates the property definition container.
void onConnectComponent() override
Pure virtual hook for the subclass.
void reloadKnownObjectClasses(const Ice::Current &current) override
void onExitComponent() override
Hook for subclass.
armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq &requests) override
std::string getDefaultName() const override
void connect(std::experimental::observer_ptr< robot_state::VirtualRobotReader > virtualRobotReader, viz::Client arviz, DebugObserverInterfacePrx debugObserver)
void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string &prefix="")
void connect(robot_state::VirtualRobotReader *virtualRobotReader, KinematicUnitObserverInterfacePrx kinematicUnitObserver, viz::Client arviz, DebugObserverInterfacePrx debugObserver)
virtual objpose::ObjectPosePredictionResultSeq predictObjectPoses(const objpose::ObjectPosePredictionRequestSeq &requests, ICE_CURRENT_ARG) override
void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string &prefix="")
virtual armem::query::data::Result query(const armem::query::data::Input &input, const Ice::Current &=Ice::emptyCurrent) override
static Duration SecondsDouble(double seconds)
Constructs a duration in seconds.
Definition Duration.cpp:78
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
const MemoryID memoryID
bool contains(const MemoryID &general, const MemoryID &specific)
Indicates whether general is "less specific" than, or equal to, specific, i.e.
Definition MemoryID.cpp:563
void toIce(data::MemoryID &ice, const MemoryID &id)
void toAron(arondto::ObjectAttachmentInfo &dto, const ObjectAttachmentInfo &bo)
Definition objpose.cpp:21
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
void fromIce(const std::map< IceKeyT, IceValueT > &iceMap, boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
observer_ptr< _Tp > make_observer(_Tp *__p) noexcept
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
aron::data::DictPtr prediction
Definition Prediction.h:63
armem::prediction::data::PredictionResult toIce() const