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{
44
47 {
50
51 const std::string prefix = "mem.";
52 workingMemory().name() = objects::memoryID.memoryName;
53
54 classSegment.defineProperties(defs, prefix + "cls.");
55 instance::SegmentAdapter::defineProperties(defs, prefix + "inst.");
57
58 attachmentSegment.defineProperties(defs, prefix + "attachments.");
59
60
61 // Publish
62 defs->topic(debugObserver);
63
64 // Subscribe
65 defs->topic<
66 objpose::
67 ObjectPoseTopic>(); // "ObjectPoseTopic", "ObjectPoseTopicName", "Name of the Object Pose Topic.");
68
69 // Use
70 // defs->component(kinematicUnitObserver); // Optional dependency.
71 defs->defineOptionalProperty<std::string>("cmp.KinematicUnitObserverName",
72 "KinematicUnitObserver",
73 "Name of the kinematic unit observer.");
74 defs->optional(predictionTimeWindow,
75 "prediction.TimeWindow",
76 "Duration of time window into the past to use for predictions"
77 " when requested via the PredictingMemoryInterface (in seconds).");
78
79 defs->optional(p.markerMemoryName, prefix + ".marker.Name", "Marker Memory Name");
80 defs->optional(p.maxMarkerHistorySize,
81 prefix + ".marker.maxHistorySize",
82 "Maximum marker memory history size");
83
84 return defs;
85 }
86
90 classSegment(iceAdapter()),
91 attachmentSegment(iceAdapter()),
92 virtualRobotReaderPlugin(nullptr)
93 {
94 addPlugin(virtualRobotReaderPlugin);
95 }
96
100
101 std::string
103 {
104 return "ObjectMemory";
105 }
106
107 void
109 {
110 const auto initSegmentWithCatch = [&](const std::string& segmentName, const auto&& fn)
111 {
112 try
113 {
114 fn();
115 }
116 catch (const LocalException& e)
117 {
118 ARMARX_ERROR << "Failed to init `" << segmentName << "` segment. Reason: \n"
119 << e.what();
120 }
121 catch (const std::exception& e)
122 {
123 ARMARX_ERROR << "Failed to init `" << segmentName << "` segment. Reason: \n"
124 << e.what();
125 }
126 catch (...)
127 {
128 ARMARX_ERROR << "Failed to init `" << segmentName
129 << "` segment for unknown reason.";
130 }
131 };
132
133 // Class segment needs to be initialized before instance segment,
134 // as the instance segment may refer to and search through the class segment.
135 initSegmentWithCatch("class", [&]() { classSegment.init(); });
136
139
140 initSegmentWithCatch("attachment", [&]() { attachmentSegment.init(); });
141
142 initSegmentWithCatch(p.markerMemoryName,
143 [&]()
144 {
145 workingMemory()
146 .addCoreSegment(p.markerMemoryName,
147 arondto::Marker::ToAronType())
148 .setMaxHistorySize(p.maxMarkerHistorySize);
149 });
150 }
151
152 void
154 {
155 ARMARX_CHECK_NOT_NULL(virtualRobotReaderPlugin);
156
158 kinematicUnitObserver, "cmp.KinematicUnitObserverName", false, "", false);
159
160 // Pass the debug observer to the long-term memory for timing measurements
161 if (debugObserver)
162 {
163 longtermMemory().setDebugObserver(debugObserver);
164 ARMARX_INFO << "Debug observer set for LTM timing measurements";
165 }
166
167 // Create first to use the original values.
169
170 // ARMARX_CHECK(virtualRobotReaderPlugin->isAvailable());
171
172 instance::SegmentAdapter::connect(&virtualRobotReaderPlugin->get(),
173 kinematicUnitObserver,
175 debugObserver);
176
178 std::experimental::make_observer(&virtualRobotReaderPlugin->get()),
180 debugObserver);
181
182 classSegment.connect(ArVizComponentPluginUser::getArvizClient());
183
184 attachmentSegment.connect();
185
187 }
188
189 void
191 {
193 // FIXME
194 // familiar_object_instance::SegmentAdapter::disconnect();
195 // classSegment.disconnect();
196 // attachmentSegment.disconnect();
197 }
198
199 void
203
204 armem::actions::GetActionsOutputSeq
205 ObjectMemory::getActions(const armem::actions::GetActionsInputSeq& inputs)
206 {
207 using namespace armem::actions;
208 GetActionsOutputSeq outputs;
209 for (const auto& input : inputs)
210 {
211 auto memoryID = armarx::fromIce<armem::MemoryID>(input.id);
212 if (armem::contains(armem::MemoryID("Object", "Class"), memoryID) and
213 memoryID.hasEntityName() and not memoryID.hasGap())
214 {
215 Menu menu{
216 Action{"vis", "Visualize object"},
217 };
218 // For strange C++ reasons, this works, but emplace_back doesn't.
219 outputs.push_back({menu.toIce()});
220 }
221 }
222
223 return outputs;
224 }
225
226 armem::actions::ExecuteActionOutputSeq
227 ObjectMemory::executeActions(const armem::actions::ExecuteActionInputSeq& inputs)
228 {
229 using namespace armem::actions;
230 ExecuteActionOutputSeq outputs;
231
232 for (const auto& input : inputs)
233 {
234 auto memoryID = armarx::fromIce<armem::MemoryID>(input.id);
235 if (input.actionPath == ActionPath{"vis"})
236 {
237 if (armem::contains(armem::MemoryID("Object", "Class"), memoryID) and
238 memoryID.hasEntityName() and not memoryID.hasGap())
239 {
240 classSegment.visualizeClass(memoryID);
241 outputs.emplace_back(true, "");
242 }
243 else
244 {
245 std::stringstream sstream;
246 sstream << "MemoryID " << memoryID
247 << " does not refer to a valid object class.";
248 outputs.emplace_back(false, sstream.str());
249 }
250 }
251 else
252 {
253 std::stringstream sstream;
254 sstream << "Action path " << input.actionPath << " is not defined.";
255 outputs.emplace_back(false, sstream.str());
256 }
257 }
258 return outputs;
259 }
260
261 armem::prediction::data::PredictionResultSeq
262 ObjectMemory::predict(const armem::prediction::data::PredictionRequestSeq& requests)
263 {
264 std::vector<armem::prediction::data::PredictionResult> results;
265 for (const auto& request : requests)
266 {
267 auto boRequest = armarx::fromIce<armem::PredictionRequest>(request);
269 result.snapshotID = boRequest.snapshotID;
270 if (armem::contains(workingMemory().id().withCoreSegmentName("Instance"),
271 boRequest.snapshotID) and
272 not boRequest.snapshotID.hasGap() and boRequest.snapshotID.hasTimestamp())
273 {
274 objpose::ObjectPosePredictionRequest objPoseRequest;
275 toIce(objPoseRequest.timeWindow, Duration::SecondsDouble(predictionTimeWindow));
276 objPoseRequest.objectID = toIce(ObjectID(request.snapshotID.entityName));
277 objPoseRequest.settings = request.settings;
278 toIce(objPoseRequest.timestamp, boRequest.snapshotID.timestamp);
279
280 objpose::ObjectPosePredictionResult objPoseResult =
281 predictObjectPoses({objPoseRequest}).at(0);
282 result.success = objPoseResult.success;
283 result.errorMessage = objPoseResult.errorMessage;
284
285 if (objPoseResult.success)
286 {
288 builder.latestEntitySnapshot(boRequest.snapshotID);
290 query(builder.buildQueryInputIce()));
291 std::string instanceError =
292 "Could not find instance '" + boRequest.snapshotID.str() + "' in memory";
293 if (!queryResult.success)
294 {
295 result.success = false;
296 result.errorMessage << instanceError << ":\n" << queryResult.errorMessage;
297 }
298 else
299 {
300 if (not boRequest.snapshotID.hasInstanceIndex())
301 {
302 boRequest.snapshotID.instanceIndex = 0;
303 }
304 auto* aronInstance = queryResult.memory.findLatestInstance(
305 boRequest.snapshotID, boRequest.snapshotID.instanceIndex);
306 if (aronInstance == nullptr)
307 {
308 result.success = false;
309 result.errorMessage << instanceError << ": No latest instance found.";
310 }
311 else
312 {
313 auto instance =
314 armem::arondto::ObjectInstance::FromAron(aronInstance->data());
316 instance.pose,
317 armarx::fromIce<objpose::ObjectPose>(objPoseResult.prediction));
318 result.prediction = instance.toAron();
319 }
320 }
321 }
322 }
323 else
324 {
325 result.success = false;
326 result.errorMessage << "No predictions are supported for MemoryID "
327 << boRequest.snapshotID;
328 }
329 results.push_back(result.toIce());
330 }
331
332 return results;
333 }
334
335 void
337 {
338 using namespace armarx::RemoteGui::Client;
339
340 tab.reset(new RemoteGuiTab);
341
342 tab->instance.setup(*this);
343 tab->clazz.setup(classSegment);
344
345 HBoxLayout segments = {tab->instance.group, tab->clazz.group};
346 VBoxLayout root = {segments, VSpacer()};
347 RemoteGui_createTab(Component::getName(), root, tab.get());
348 }
349
350 void
352 {
353 tab->instance.update(*this);
354 tab->clazz.update(classSegment);
355
356 if (tab->clazz.data.rebuild)
357 {
359 }
360 }
361
362 void
363 ObjectMemory::reloadKnownObjectClasses(const Ice::Current& current)
364 {
365 ARMARX_INFO << "Reloading object classes ...";
366 classSegment.reloadObjectClassesByObjectFinder();
367 ARMARX_INFO << "Reloaded object classes.";
368 }
369
370
371} // namespace armarx::armem::server::obj
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:513
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