HumanRobotInteractionReader.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 * @author Joana Plewnia ( joana dot plewnia at kit dot edu )
17 * @date 2025
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
23
24#include <iterator>
25
28
30
31#include <VisionX/libraries/armem_human/aron/HumanRobotInteraction.aron.generated.h>
33
35{
37
38 armarx::armem::client::query::Builder
40 {
42
44 qb.coreSegments().withName(properties().coreSegmentName);
45
48 {
49 if (not query.providerName.empty())
50 {
51 return coreSegmentQuery.providerSegments().withName(query.providerName);
52 }
53 return coreSegmentQuery.providerSegments().all();
54 }();
55
56 providerQuery.entities().all().snapshots().beforeOrAtTime(query.timestamp);
57
58 return qb;
59 }
60
63 {
65
67 qb.coreSegments().withName(properties().coreSegmentName);
68
71 {
72 if (not query.providerName.empty())
73 {
74 return coreSegmentQuery.providerSegments().withName(query.providerName);
75 }
76 return coreSegmentQuery.providerSegments().all();
77 }();
78
79 providerQuery.entities().all().snapshots().latest();
80
81 return qb;
82 }
83
84 std::vector<HumanRobotInteraction>
86 const DateTime& timestamp,
87 const Duration& maxAge) const
88 {
90 std::vector<HumanRobotInteraction> interactions;
91
92 providerSegment.forEachEntity(
93 [&](const wm::Entity& entity)
94 {
96
97 const auto& entitySnapshot = entity.getLatestSnapshot();
98
99 entitySnapshot.forEachInstance(
100 [&interactions, &timestamp, &maxAge](const auto& entityInstance)
101 {
103
104 const core::time::Duration dtToNow =
105 timestamp - entityInstance.metadata().referencedTime;
106
107 if (dtToNow < maxAge and dtToNow.isPositive())
108 {
109 const auto aronDto =
111 entityInstance);
112 ARMARX_CHECK(aronDto) << "Failed casting to HumanRobotInteraction";
113
114 HumanRobotInteraction interaction;
115 fromAron(*aronDto, interaction);
116
117 interactions.push_back(interaction);
118 };
119 });
120 });
121
122 return interactions;
123 }
124
125 std::string
127 {
128 return "mem.human.interaction.";
129 }
130
133 {
134 return {.memoryName = "Human", .coreSegmentName = "HumanRobotInteraction"};
135 }
136
138 InteractionReader::query(const Query& query, bool latest) const
139 {
141
143 if (latest)
144 {
146 }
147 else
148 {
149 qb = buildQuery(query);
150 }
151
152 ARMARX_INFO << "[InteractionReader] Querying memory...";
153 ARMARX_INFO << "[InteractionReader] Memory name: " << properties().memoryName;
154 ARMARX_INFO << "[InteractionReader] Core segment: " << properties().coreSegmentName;
155 ARMARX_INFO << "[InteractionReader] Provider: " << query.providerName;
156
158
159 ARMARX_INFO << "[InteractionReader] Query result: success=" << qResult.success;
160 if (!qResult.success)
161 {
162 ARMARX_INFO << "[InteractionReader] Error: " << qResult.errorMessage;
163 }
164
165 if (not qResult.success)
166 {
167 ARMARX_WARNING << "Failed to query data from memory: " << qResult.errorMessage;
168 return {.interactions = {},
169 .status = Result::Status::Error,
170 .errorMessage = qResult.errorMessage};
171 }
172
174
175 // Check if core segment exists
176 if (!qResult.memory.hasCoreSegment(properties().coreSegmentName))
177 {
178 ARMARX_WARNING << "[InteractionReader] Core segment '" << properties().coreSegmentName
179 << "' does not exist in memory!";
180 ARMARX_INFO << "[InteractionReader] Available core segments:";
181 qResult.memory.forEachCoreSegment([](const auto& segment)
182 { ARMARX_INFO << " - " << segment.name(); });
183 return {.interactions = {},
184 .status = Result::Status::NoData,
185 .errorMessage = "Core segment not found"};
186 }
187
188 const auto coreSegment = qResult.memory.getCoreSegment(properties().coreSegmentName);
189
190 if (query.providerName.empty())
191 {
193
194 std::vector<HumanRobotInteraction> allInteractions;
195
196 coreSegment.forEachProviderSegment(
197 [this, &allInteractions, &query](const auto& providerSegment)
198 {
199 const std::vector<HumanRobotInteraction> interactions =
200 asHumanRobotInteractions(providerSegment, query.timestamp, query.maxAge);
201 std::copy(interactions.begin(),
202 interactions.end(),
203 std::back_inserter(allInteractions));
204 });
205
206 if (allInteractions.empty())
207 {
208 return {.interactions = {},
209 .status = Result::Status::NoData,
210 .errorMessage = "No entities"};
211 }
212
213 return Result{.interactions = allInteractions, .status = Result::Status::Success};
214 }
215
217
218 // -> provider segment name is set
219 if (not coreSegment.hasProviderSegment(query.providerName))
220 {
221 ARMARX_INFO << deactivateSpam(5) << "Provider segment `" << query.providerName
222 << "` does not exist (yet).";
223 return {.interactions = {}, .status = Result::Status::NoData};
224 }
225
227
228 const wm::ProviderSegment& providerSegment =
229 coreSegment.getProviderSegment(query.providerName);
230
231 if (providerSegment.empty())
232 {
233 ARMARX_WARNING << "No entities.";
234 return {.interactions = {},
235 .status = Result::Status::NoData,
236 .errorMessage = "No entities"};
237 }
238
239 try
240 {
242
243 const auto interactions =
244 asHumanRobotInteractions(providerSegment, query.timestamp, query.maxAge);
245 return Result{.interactions = interactions, .status = Result::Status::Success};
246 }
247 catch (...)
248 {
249 return Result{.status = Result::Status::Error,
250 .errorMessage = GetHandledExceptionString()};
251 }
252 }
253
254 std::vector<HumanRobotInteraction>
256 const std::string& lastName,
257 const Duration& maxAge,
258 const std::string& providerName)
259 {
260 Query queryDefinition = Query{.providerName = providerName,
261 .timestamp = armem::Time::Now(),
262 .maxAge = maxAge};
263
264 auto queryResult = query(queryDefinition, true);
265
266 std::vector<HumanRobotInteraction> matchingInteractions;
267
268 if (queryResult.status == Result::Status::Success)
269 {
270 for (const auto& interaction : queryResult.interactions)
271 {
272 if (interaction.personID.has_value() &&
273 interaction.personID.value().firstName == firstName &&
274 interaction.personID.value().lastName == lastName)
275 {
276 matchingInteractions.push_back(interaction);
277 }
278 }
279
280 if (matchingInteractions.empty())
281 {
282 ARMARX_INFO << "No interactions found for person " << firstName << " "
283 << lastName;
284 }
285 }
286 else
287 {
288 ARMARX_WARNING << "Failed to query interactions from memory";
289 }
290
291 return matchingInteractions;
292 }
293
294 std::optional<HumanRobotInteraction>
296 const std::string& lastName,
297 const std::string& providerName)
298 {
299 Query queryDefinition = Query{.providerName = providerName,
300 .timestamp = armem::Time::Now(),
301 .maxAge = armarx::Duration::Minutes(1000)};
302
303 auto queryResult = query(queryDefinition, true);
304
305 if (queryResult.status == Result::Status::Success)
306 {
307 // Find the latest interaction for the given person
308 std::optional<HumanRobotInteraction> latestInteraction;
309 DateTime latestTime;
310
311 for (const auto& interaction : queryResult.interactions)
312 {
313 if (interaction.personID.has_value() &&
314 interaction.personID.value().firstName == firstName &&
315 interaction.personID.value().lastName == lastName)
316 {
317 if (!latestInteraction.has_value() || interaction.startTime > latestTime)
318 {
319 latestInteraction = interaction;
320 latestTime = interaction.startTime;
321 }
322 }
323 }
324
325 if (latestInteraction.has_value())
326 {
327 return latestInteraction;
328 }
329 else
330 {
331 ARMARX_INFO << "No interactions found for person " << firstName << " "
332 << lastName;
333 }
334 }
335 else
336 {
337 ARMARX_WARNING << "Failed to query interactions from memory";
338 }
339
340 return std::nullopt;
341 }
342
343} // namespace armarx::armem::human::client
std::string timestamp()
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
static Duration Minutes(std::int64_t minutes)
Constructs a duration in minutes.
Definition Duration.cpp:96
bool forEachCoreSegment(CoreSegmentFunctionT &&func)
Definition MemoryBase.h:188
bool hasCoreSegment(const std::string &name) const
Definition MemoryBase.h:107
CoreSegmentT & getCoreSegment(const std::string &name)
Definition MemoryBase.h:134
QueryResult query(const QueryInput &input) const
Perform a query on the WM.
Definition Reader.cpp:119
The query::Builder class provides a fluent-style specification of hierarchical queries.
Definition Builder.h:22
CoreSegmentSelector & coreSegments()
Start specifying core segments.
Definition Builder.cpp:42
CoreSegmentSelector & withName(const std::string &name) override
ProviderSegmentSelector & providerSegments()
Start specifying provider segments.
SnapshotSelector & snapshots()
Start specifying entity snapshots.
Definition selectors.cpp:92
ProviderSegmentSelector & withName(const std::string &name) override
EntitySelector & entities()
Start specifying entities.
ProviderSegmentSelector & all() override
SnapshotSelector & beforeOrAtTime(Time timestamp)
Definition selectors.cpp:73
const armem::client::Reader & memoryReader() const
std::vector< HumanRobotInteraction > queryInteractionsForPerson(const std::string &firstName, const std::string &lastName, const Duration &maxAge, const std::string &providerName="")
::armarx::armem::client::query::Builder buildQuery(const Query &query) const
::armarx::armem::client::query::Builder buildLatestQuery(const Query &query) const
Result query(const Query &query, bool latest) const
std::optional< HumanRobotInteraction > queryLatestInteractionForPerson(const std::string &firstName, const std::string &lastName, const std::string &providerName="")
std::vector< HumanRobotInteraction > asHumanRobotInteractions(const wm::ProviderSegment &providerSegment, const DateTime &timestamp, const Duration &maxAge) const
Represents a point in time.
Definition DateTime.h:25
static DateTime Now()
Definition DateTime.cpp:51
Represents a duration.
Definition Duration.h:17
bool isPositive() const
Tests whether the duration is positive (value in µs > 0).
Definition Duration.cpp:168
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
void fromAron(const armarx::human::arondto::HumanPose &dto, HumanPose &bo)
armarx::core::time::Duration Duration
std::optional< AronClass > tryCast(const wm::EntityInstance &item)
Tries to cast a armem::EntityInstance to AronClass.
Definition util.h:45
std::string GetHandledExceptionString()
auto & getLatestSnapshot(int snapshotIndex=0)
Retrieve the latest entity snapshot.
Result of a QueryInput.
Definition Query.h:51
wm::Memory memory
The slice of the memory that matched the query.
Definition Query.h:58
#define ARMARX_TRACE
Definition trace.h:77