MemoryGroupBoxController.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2012-2025, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package RobotStateComponent::
19 * @author Samet Soenmez (uewtt at student dot kit dot edu)
20 * @date 2025t
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
26
27#include <QLayout>
28#include <QGroupBox>
29#include <QLabel>
30
35
40
42{
44 MemoryViewerUIContext& uiContext,
45 std::shared_ptr<armem::gui::model::MemoryViewerModel> model)
46 {
47 _model = std::move(model);
48 _statusLabel = uiContext.statusLabel;
49 _instanceGroupBoxController = std::make_unique<InstanceGroupBoxController>(
50 uiContext,
51 _model);
52
53 // for prediction widget
54 auto entityInfoRetriever = [this](const MemoryID& entityID) -> PredictionWidget::EntityInfo
55 {
56 client::Reader reader = _model->memoryReaders().at(entityID.memoryName);
57 if (!reader.predictionPrx)
58 {
59 std::stringstream sstream;
60 sstream << "Predictions are not available for memory '" << entityID.memoryName
61 << "'.";
62 _statusLabel->setText(QString::fromStdString(sstream.str()));
63 return {};
64 }
65
66 std::map<MemoryID, std::vector<PredictionEngine>> predictionEngines;
67 client::QueryResult queryResult;
68 try
69 {
70 predictionEngines = reader.getAvailablePredictionEngines();
71 queryResult = reader.queryMemoryIDs({entityID}, armem::query::DataMode::NoData);
72 }
73 catch (const Ice::LocalException& e)
74 {
75 std::stringstream sstream;
76 sstream << "Could not get prediction engines and type from memory: " << e.what();
77 _statusLabel->setText(QString::fromStdString(sstream.str()));
78 return {nullptr, {}};
79 }
80
81 aron::type::ObjectPtr entityType;
82 if (queryResult.success)
83 {
84 auto* providerSegment = queryResult.memory.findProviderSegment(entityID);
85 if (providerSegment != nullptr)
86 {
87 entityType = providerSegment->aronType();
88 }
89 }
91 .type = entityType,
92 .engines = armem::accumulateEntriesContainingID(predictionEngines, entityID)};
93 };
94
95 _memoryGroupBoxView = new armem::gui::view::MemoryGroupBoxView(std::move(entityInfoRetriever));
96 armarx::gui::replaceWidget(uiContext.memoryGroupBox, _memoryGroupBoxView, uiContext.memoryGroupBoxParentLayout);
98
99 connect(_memoryGroupBoxView->tree(),
101 _instanceGroupBoxController.get(),
103
104 connect(_memoryGroupBoxView->predictionWidget(),
106 this,
108
109 connect(_memoryGroupBoxView->commitWidget(),
111 this,
113
114 connect(_memoryGroupBoxView->ltmWidget(),
116 this,
118
119 connect(_memoryGroupBoxView->ltmWidget(),
121 this,
123
124 connect(_memoryGroupBoxView->ltmWidget(),
126 this,
128
129 connect(_memoryGroupBoxView->queryWidget(),
131 this,
132 &This::updateActiveMemories);
133
134 connect(_memoryGroupBoxView->queryWidget(),
136 this,
137 &This::updateRecursionDepth);
138
139 connect(_memoryGroupBoxView->queryWidget(),
141 this,
142 &This::updateDataMode);
143
144 connect(_memoryGroupBoxView->queryWidget(),
146 this,
147 &This::updateDropRemovedMemories);
148
149 connect(_memoryGroupBoxView->queryWidget(),
151 this,
152 &This::updateDropDisabledMemories);
153
154 connect(_memoryGroupBoxView->snapshotSelectorWidget(),
156 this,
157 &This::updateSelector);
158
159 updateActiveMemories();
160 updateRecursionDepth(_memoryGroupBoxView->queryWidget()->queryLinkRecursionDepth());
161 updateDataMode();
162 updateDropRemovedMemories();
163 updateDropDisabledMemories();
164 updateSelector();
165 }
166
167 void
169 const aron::type::ObjectPtr& entityType,
171 const std::string& engineID)
172 {
173
174 std::stringstream errorStream;
175 auto showError = [this, &errorStream]()
176 { _statusLabel->setText(QString::fromStdString(errorStream.str())); };
177
178 if (!entityID.hasEntityName() || entityID.hasGap())
179 {
180 errorStream << "Could not convert " << entityID << " to valid entity ID.";
181 showError();
182 return;
183 }
184 auto readers = _model->memoryReadersCopy();
185 if (readers.find(entityID.memoryName) == readers.end())
186 {
187 errorStream << "Not connected to memory '" << entityID.memoryName
188 << "', cannot make prediction.";
189 showError();
190 return;
191 }
192 client::Reader reader = readers.at(entityID.memoryName);
193 if (!reader.predictionPrx)
194 {
195 errorStream << "Predictions are not available for memory '" << entityID.memoryName
196 << "'.";
197 showError();
198 return;
199 }
200 PredictionRequest request;
201 request.snapshotID = entityID.withTimestamp(timestamp);
202 request.predictionSettings.predictionEngineID = engineID;
203 PredictionResult result;
204 try
205 {
206 result = reader.predict({request}).at(0);
207 }
208 catch (const Ice::LocalException& e)
209 {
210 errorStream << "Could not make prediction request: " << e.what();
211 showError();
212 return;
213 }
214
215 if (!result.success)
216 {
217 errorStream << "Prediction failed: " << result.errorMessage;
218 showError();
219 return;
220 }
221
222 auto* view = new AronDataView();
223 _instanceGroupBoxController->instanceGroupBoxView()->instanceView()->addDataView(view);
224 view->update(result.prediction, entityType);
225 }
226
227 void
229 {
231 auto now = armem::Time::Now();
232
233 const std::string memoryIDStr = _memoryGroupBoxView->commitWidget()->getMemoryID();
234 const std::string aronJSONStr = _memoryGroupBoxView->commitWidget()->getAronJSON();
235
236 ARMARX_INFO << "Committing to " << memoryIDStr << " the data: " << aronJSONStr;
237
238 MemoryID memId(memoryIDStr);
239
240 if (!memId.hasEntityName())
241 {
242 ARMARX_WARNING << "The entered MemoryID '" << memoryIDStr
243 << "' does not contain an entity.";
244 }
245 else
246 {
247
248 nlohmann::json json = nlohmann::json::parse(aronJSONStr);
249
250 // ToDo: multiple objects
251 auto aron =
253 json);
254
255 auto writers = _model->memoryWritersCopy();
256 if (const auto& it = writers.find(memId.memoryName); it == writers.end())
257 {
258 ARMARX_WARNING << "No memory with name '" << memId.memoryName
259 << "' available for commit.";
260 }
261 else
262 {
263 armem::Commit comm;
264 auto& entityUpdate = comm.add();
265 entityUpdate.entityID = memId;
266 entityUpdate.confidence = 1.0;
267 entityUpdate.instancesData = {aron};
268 entityUpdate.referencedTime = now;
269 it->second.commit(comm);
270 }
271 }
272
274 }
275
276 void
278 {
279 TIMING_START(MemoryStore);
280
281 auto enabledMemories = _memoryGroupBoxView->ltmWidget()->getEnabledLTMMemories();
282 auto memoryReaders = _model->memoryReadersCopy();
283 for (auto& [name, reader] : memoryReaders)
284 {
285 // skip if memory should not be queried
286 if (std::find(enabledMemories.begin(), enabledMemories.end(), name) ==
287 enabledMemories.end())
288 {
289 continue;
290 }
291
292 // Query memory
293 auto q_res = reader.query(_model->queryInput());
294 if (q_res.success)
295 {
296 server::dto::DirectlyStoreInput input;
297 input.memory = q_res.toIce().memory;
298 reader.directlyStore(input);
299 }
300 else
301 {
302 std::string status = "Query of memory " + name + " was unsuccessful.";
303 _statusLabel->setText(QString::fromStdString(status));
304 }
305 }
306
307 TIMING_END_STREAM(MemoryStore, ARMARX_VERBOSE);
308 }
309
310 void
312 {
313 TIMING_START(MemoryStartRecording);
314
315 auto enabledMemories = _memoryGroupBoxView->ltmWidget()->getEnabledLTMMemories();
316 auto memoryReaders = _model->memoryReadersCopy();
317 for (auto& [name, reader] : memoryReaders)
318 {
319 // skip if memory should not be queried
320 if (std::find(enabledMemories.begin(), enabledMemories.end(), name) ==
321 enabledMemories.end())
322 {
323 continue;
324 }
325 reader.startRecording();
326 }
327
328 TIMING_END_STREAM(MemoryStartRecording, ARMARX_VERBOSE);
329 }
330
331 void
333 {
334 TIMING_START(MemoryStopRecording);
335
336 auto enabledMemories = _memoryGroupBoxView->ltmWidget()->getEnabledLTMMemories();
337 auto memoryReaders = _model->memoryReadersCopy();
338 for (auto& [name, reader] : memoryReaders)
339 {
340 // skip if memory should not be queried
341 if (std::find(enabledMemories.begin(), enabledMemories.end(), name) ==
342 enabledMemories.end())
343 {
344 continue;
345 }
346 reader.stopRecording();
347 }
348
349 TIMING_END_STREAM(MemoryStopRecording, ARMARX_VERBOSE);
350 }
351
352 void
354 {
355 // TODO: atm after deselecting every memory, memory tree isnt updating
356 std::map<std::string, const armem::wm::Memory*> memoriesToUpdate;
357
358 auto checkboxStates = _model->activeMemoryStates();
359 auto memoryData = _model->memoryDataCopy();
360 for (auto& [name, data] : memoryData)
361 {
362 if (checkboxStates[name] == armem::gui::ActiveMemoryState::FoundAndChecked)
363 {
364 ARMARX_DEBUG << deactivateSpam(10) << "updating memory tree for " << name;
365 memoriesToUpdate[name] = &data;
366 }
367 }
368
369 TIMING_START(GuiUpdateMemoryTree)
370
371 _memoryGroupBoxView->tree()->update(memoriesToUpdate);
372
373 TIMING_END_STREAM(GuiUpdateMemoryTree, ARMARX_VERBOSE)
374
375 if (_model->debugObserver())
376 {
377 try
378 {
379 _model->debugObserver()->setDebugDatafield(
380 Logging::tag.tagName,
381 "GUI Update [ms]",
382 new Variant(GuiUpdateMemoryTree.toMilliSecondsDouble()));
383 }
384 catch (const Ice::Exception&)
385 {
386 // Ignore ...
387 }
388 }
389 }
390
391 void
392 MemoryGroupBoxController::updateActiveMemories()
393 {
394 _model->setActiveMemoryStates(_memoryGroupBoxView->queryWidget()->getAvailableMemoryStates());
395 }
396
397 void
398 MemoryGroupBoxController::updateRecursionDepth(int value)
399 {
400 _model->setRecursionDepth(value);
401 }
402
403 void
404 MemoryGroupBoxController::updateDataMode()
405 {
406 _model->setDataMode(_memoryGroupBoxView->queryWidget()->dataMode());
407 }
408
409 void
410 MemoryGroupBoxController::updateDropRemovedMemories()
411 {
412 _model->setDropRemovedMemories(_memoryGroupBoxView->queryWidget()->dropRemovedMemories());
413 }
414
415 void
416 MemoryGroupBoxController::updateDropDisabledMemories()
417 {
418 _model->setDropDisabledMemories(_memoryGroupBoxView->queryWidget()->dropDisabledMemories());
419 }
420
421 void
422 MemoryGroupBoxController::updateSelector()
423 {
424 _model->setSelector(_memoryGroupBoxView->snapshotSelectorWidget()->selector());
425 }
426
427 armem::gui::view::MemoryGroupBoxView*
429 {
430 return _memoryGroupBoxView;
431 }
432
435 {
436 return _instanceGroupBoxController.get();
437 }
438
439}
std::string timestamp()
#define ARMARX_CHECK_NULL(ptr)
SpamFilterDataPtr deactivateSpam(float deactivationDurationSec=10.0f, const std::string &identifier="", bool deactivate=true) const
disables the logging for the current line for the given amount of seconds.
Definition Logging.cpp:99
The Variant class is described here: Variants.
Definition Variant.h:224
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
MemoryID withTimestamp(Time time) const
Definition MemoryID.cpp:433
std::string memoryName
Definition MemoryID.h:50
Reads data from a memory server.
Definition Reader.h:25
std::map< MemoryID, std::vector< PredictionEngine > > getAvailablePredictionEngines() const
Get the list of prediction engines supported by the memory.
Definition Reader.cpp:621
QueryResult queryMemoryIDs(const std::vector< MemoryID > &ids, armem::query::DataMode dataMode=armem::query::DataMode::WithData) const
Query a specific set of memory IDs.
Definition Reader.cpp:374
std::vector< PredictionResult > predict(const std::vector< PredictionRequest > &requests) const
Get a prediction for the state of multiple entity instances in the future.
Definition Reader.cpp:577
server::PredictingMemoryInterfacePrx predictionPrx
Definition Reader.h:228
void makePrediction(const MemoryID &entityID, const aron::type::ObjectPtr &entityType, const armarx::DateTime &timestamp, const std::string &engineID)
void recursionDepthChanged(int value)
armem::query::DataMode dataMode() const
std::map< std::string, armem::gui::ActiveMemoryState > getAvailableMemoryStates() const
void selectedItemChanged(const MemoryID &id)
The selected item or its contents have changed.
armem::gui::view::MemoryGroupBoxView * memoryGroupBoxView() const
void onMakePrediction(const MemoryID &entityID, const aron::type::ObjectPtr &entityType, const armarx::DateTime &timestamp, const std::string &engineID)
MemoryGroupBoxController(MemoryViewerUIContext &uiContext, std::shared_ptr< armem::gui::model::MemoryViewerModel > model)
static data::DictPtr ConvertFromNlohmannJSONObject(const nlohmann::json &, const armarx::aron::Path &p={})
Represents a point in time.
Definition DateTime.h:25
static DateTime Now()
Definition DateTime.cpp:51
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
#define TIMING_START(name)
Helper macro to do timing tests.
Definition TimeUtil.h:289
#define TIMING_END_STREAM(name, os)
Prints duration.
Definition TimeUtil.h:310
instance::AronDataView AronDataView
@ NoData
Just get the structure, but no ARON data.
Definition DataMode.h:8
std::vector< ValueT > accumulateEntriesContainingID(const std::map< MemoryID, ValueT > &idMap, const MemoryID &id)
Return all values of keys containing the given ID.
std::shared_ptr< Object > ObjectPtr
Definition Object.h:36
void replaceWidget(WidgetT *&old, QWidget *neu, QLayout *parentLayout)
Definition gui_utils.h:34
A bundle of updates to be sent to the memory.
Definition Commit.h:90
EntityUpdate & add()
Definition Commit.cpp:80
MemoryID entityID
The entity's ID.
Definition Commit.h:28
PredictionSettings predictionSettings
Definition Prediction.h:51
aron::data::DictPtr prediction
Definition Prediction.h:63
auto * findProviderSegment(const MemoryID &providerSegmentID)
Retrieve a provider segment.
Result of a QueryInput.
Definition Query.h:51
wm::Memory memory
The slice of the memory that matched the query.
Definition Query.h:58