AffordanceExtraction.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 Lesser General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * ArmarX is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * @package VisionX
18 * @author Peter Kaiser (peter dot kaiser at kit dot edu)
19 * @date 2014
20 * @copyright http://www.gnu.org/licenses/gpl.txt
21 * GNU General Public License
22 */
23
25
28
31
32#include <AffordanceKit/embodiments/Armar3Embodiment.h>
33#include <AffordanceKit/embodiments/Armar4Embodiment.h>
34#include <AffordanceKit/embodiments/WalkManEmbodiment.h>
39
40using namespace armarx;
41
46
47void
49{
50 std::unique_lock lock(primitivesMutex);
51
53 {
56 hasNewPrimitives = true;
57
58 ARMARX_INFO << "New segmentation available: " << primitiveSegmentation->size()
59 << " Primitives";
60 }
61 else
62 {
64 << "New segmentation available, but failed to access environmental primitives segment";
65 }
66}
67
68void
70{
71 std::string embodimentName = getProperty<std::string>("EmbodimentName").getValue();
72
73 ARMARX_INFO << "Using embodiment '" << embodimentName << "'";
74 if (embodimentName == "Armar3")
75 {
76 embodiment.reset(new AffordanceKit::Armar3Embodiment());
77 }
78 else if (embodimentName == "Armar4")
79 {
80 embodiment.reset(new AffordanceKit::Armar4Embodiment());
81 }
82 else if (embodimentName == "WalkMan")
83 {
84 embodiment.reset(new AffordanceKit::WalkManEmbodiment());
85 }
86 else
87 {
88 ARMARX_ERROR << "Unknown embodiment '" << embodimentName
89 << "' specified. Affordance extraction will not work properly.";
90 embodiment.reset(new AffordanceKit::Embodiment());
91 }
92
93 affordanceExtractionCertainty = getProperty<float>("AffordanceExtractionCertainty").getValue();
94 ARMARX_INFO << "Affordance extraction certainty: " << affordanceExtractionCertainty;
95
97 new AffordanceKit::PlatformGraspAffordance(embodiment, affordanceExtractionCertainty));
99 new AffordanceKit::PrismaticGraspAffordance(embodiment, affordanceExtractionCertainty));
100 graspAffordance.reset(new AffordanceKit::GraspAffordance(
102
103 supportAffordance.reset(
104 new AffordanceKit::SupportAffordance(embodiment, platformGraspAffordance));
105 leanAffordance.reset(new AffordanceKit::LeanAffordance(embodiment, platformGraspAffordance));
106 liftAffordance.reset(new AffordanceKit::LiftAffordance(embodiment, prismaticGraspAffordance));
107 holdAffordance.reset(new AffordanceKit::HoldAffordance(embodiment, prismaticGraspAffordance));
108 turnAffordance.reset(new AffordanceKit::TurnAffordance(embodiment, prismaticGraspAffordance));
109 pushAffordance.reset(new AffordanceKit::PushAffordance(embodiment, graspAffordance));
110 pullAffordance.reset(new AffordanceKit::PullAffordance(embodiment, prismaticGraspAffordance));
111
113 new AffordanceKit::BimanualPlatformGraspAffordance(embodiment, platformGraspAffordance));
115 new AffordanceKit::BimanualPrismaticGraspAffordance(embodiment, prismaticGraspAffordance));
116 bimanualGraspAffordance.reset(new AffordanceKit::BimanualGraspAffordance(
119 new AffordanceKit::BimanualOpposedGraspAffordance(embodiment, bimanualGraspAffordance));
121 new AffordanceKit::BimanualAlignedGraspAffordance(embodiment, bimanualGraspAffordance));
123 new AffordanceKit::BimanualOpposedPlatformGraspAffordance(
126 new AffordanceKit::BimanualOpposedPrismaticGraspAffordance(
129 new AffordanceKit::BimanualAlignedPlatformGraspAffordance(
132 new AffordanceKit::BimanualAlignedPrismaticGraspAffordance(
134 bimanualTurnAffordance.reset(new AffordanceKit::BimanualTurnAffordance(
137 new AffordanceKit::BimanualLiftAffordance(embodiment,
141
142 affordanceTypes[graspAffordance->getName()] = memoryx::eAffordanceTypeGrasp;
143 affordanceTypes[platformGraspAffordance->getName()] = memoryx::eAffordanceTypeGraspPlatform;
144 affordanceTypes[prismaticGraspAffordance->getName()] = memoryx::eAffordanceTypeGraspPrismatic;
145 affordanceTypes[supportAffordance->getName()] = memoryx::eAffordanceTypeSupport;
146 affordanceTypes[leanAffordance->getName()] = memoryx::eAffordanceTypeLean;
147 affordanceTypes[holdAffordance->getName()] = memoryx::eAffordanceTypeHold;
148 affordanceTypes[pushAffordance->getName()] = memoryx::eAffordanceTypePush;
149 affordanceTypes[pullAffordance->getName()] = memoryx::eAffordanceTypePull;
150 affordanceTypes[liftAffordance->getName()] = memoryx::eAffordanceTypeLift;
151 affordanceTypes[turnAffordance->getName()] = memoryx::eAffordanceTypeTurn;
152 affordanceTypes[pushAffordance->getName()] = memoryx::eAffordanceTypePush;
154 memoryx::eAffordanceTypeBimanualGraspPlatform;
156 memoryx::eAffordanceTypeBimanualGraspPrismatic;
157 affordanceTypes[bimanualGraspAffordance->getName()] = memoryx::eAffordanceTypeBimanualGrasp;
159 memoryx::eAffordanceTypeBimanualGraspOpposed;
161 memoryx::eAffordanceTypeBimanualGraspAligned;
163 memoryx::eAffordanceTypeBimanualOpposedGraspPlatform;
165 memoryx::eAffordanceTypeBimanualOpposedGraspPrismatic;
167 memoryx::eAffordanceTypeBimanualAlignedGraspPlatform;
169 memoryx::eAffordanceTypeBimanualAlignedGraspPrismatic;
170 affordanceTypes[bimanualTurnAffordance->getName()] = memoryx::eAffordanceTypeBimanualTurn;
171 affordanceTypes[bimanualLiftAffordance->getName()] = memoryx::eAffordanceTypeBimanualLift;
172
183
195
196 maxPrimitiveSamplingSize = getProperty<int>("MaxPrimitiveSamplingSize").getValue();
197 ARMARX_INFO << "Ignoring primitives with samplings larger than " << maxPrimitiveSamplingSize
198 << " entries";
199
200 std::string affordanceRestrictionString =
201 getProperty<std::string>("RestrictToAffordanceList").getValue();
202 if (affordanceRestrictionString != "")
203 {
204 auto affordanceRestrictionList = Split(affordanceRestrictionString, ",");
205 affordanceRestriction.insert(affordanceRestrictionList.begin(),
206 affordanceRestrictionList.end());
207 }
208
209 std::vector<std::string> affordances;
210 for (auto& a : unimanualAffordances)
211 {
212 if (affordanceRestriction.size() == 0 ||
213 affordanceRestriction.find(a->getName()) != affordanceRestriction.end())
214 {
215 affordances.push_back(a->getName());
216 }
217 }
218
219 for (auto& a : bimanualAffordances)
220 {
221 if (affordanceRestriction.size() == 0 ||
222 affordanceRestriction.find(a->getName()) != affordanceRestriction.end())
223 {
224 affordances.push_back(a->getName());
225 }
226 }
227
228 ARMARX_INFO << "Configured affordances: " << affordances;
229
230 offeringTopic(getProperty<std::string>("AffordanceExtractionTopicName").getValue());
231 usingTopic(getProperty<std::string>("PrimitiveExtractionTopicName").getValue());
232
233 usingProxy(getProperty<std::string>("WorkingMemoryName").getValue());
234
235 offeringTopic(getProperty<std::string>("DebugObserverName").getValue());
236
239}
240
241void
243{
244 const Ice::CommunicatorPtr ic = getIceManager()->getCommunicator();
245
247 getProperty<std::string>("WorkingMemoryName").getValue());
248 if (!workingMemoryPrx)
249 {
250 ARMARX_ERROR << "Failed to obtain working memory proxy";
251 return;
252 }
253
254 affordanceSegment = workingMemoryPrx->getAffordanceSegment();
256 {
257 ARMARX_ERROR << "Failed to obtain affordance segment pointer";
258 return;
259 }
260
261 environmentalPrimitiveSegment = workingMemoryPrx->getEnvironmentalPrimitiveSegment();
263 {
264 ARMARX_ERROR << "Failed to obtain environmental primitive segment pointer";
265 return;
266 }
267
269 getProperty<std::string>("DebugObserverName").getValue());
270
272 getProperty<std::string>("AffordanceExtractionTopicName").getValue());
274
275 hasNewPrimitives = false;
276}
277
278void
283
284void
288
289void
290AffordanceExtraction::addObservation(const PoseBasePtr& endEffectorPose,
291 const std::string& affordance,
292 const std::string& primitiveId,
293 float result,
294 float certainty,
295 float sigma_pos,
296 float sigma_rot,
297 const Ice::Current& c)
298{
299 std::unique_lock lock1(primitivesMutex);
300 std::unique_lock lock2(affordancesMutex);
301
302 Eigen::Matrix4f pose = PosePtr::dynamicCast(endEffectorPose)->toEigen();
303
305 {
306 // This might happen if primitives have already been present in the memory on startup
309 }
310
311 ARMARX_INFO << "Adding Experiment(primitive=" << primitiveId << ", affordance=" << affordance
312 << ", result=" << result << ", certainty=" << certainty
313 << ", sigma_pos=" << sigma_pos << ", sigma_rot=" << sigma_rot << ")";
314
315 AffordanceKit::PrimitivePtr primitive = primitiveSegmentation->getPrimitiveById(primitiveId);
316
317 bool found = false;
318 for (auto& a : unimanualAffordances)
319 {
320 if (a->getName() == affordance && a->existsForPrimitive(primitive))
321 {
322 a->addObservation(AffordanceKit::ObservationPtr(new AffordanceKit::Observation(
323 primitive, pose, result, certainty, sigma_pos, sigma_rot)));
324 found = true;
325 }
326 }
327
328 for (auto& a : bimanualAffordances)
329 {
330 if (a->getName() == affordance && a->existsForPrimitive(primitive))
331 {
332 a->addObservation(AffordanceKit::ObservationPtr(new AffordanceKit::Observation(
333 primitive, pose, result, certainty, sigma_pos, sigma_rot)));
334 found = true;
335 }
336 }
337
338 if (!found)
339 {
340 ARMARX_WARNING << "Discarding experiment, because affordance or primitive were not found.";
341 }
342
343 // Export updated primitives to memory
348 << " affordances updated and reported";
349
350 listenerPrx->reportNewAffordances();
351}
352
353void
354AffordanceExtraction::exportScene(const std::string& filename, const Ice::Current& c)
355{
356 ARMARX_INFO << "Exporting current scene to '" << filename << "'";
357
359 s.save(filename);
360}
361
362void
363AffordanceExtraction::importScene(const std::string& filename, const Ice::Current& c)
364{
365 ARMARX_INFO << "Importing scene from '" << filename << "'";
366
368 s.load(filename);
370
371 listenerPrx->reportNewAffordances();
372}
373
374void
376{
377 AffordanceKit::PrimitiveSetPtr primitives;
378
379 {
380 std::unique_lock lock(primitivesMutex);
381
382 if (!hasNewPrimitives)
383 {
384 return;
385 }
386 hasNewPrimitives = false;
387
388 primitives = primitiveSegmentation;
389 }
390
391 {
392 std::unique_lock lock(enableMutex);
393
394 if (!enabled)
395 {
396 return;
397 }
398 }
399
400 long originalTimestamp = 0;
401 if (primitives->size() > 0)
402 {
403 originalTimestamp = (*primitives->begin())->getTimestamp();
404
405 IceUtil::Time ts = IceUtil::Time::microSeconds(originalTimestamp);
406 std::string timestampString = ts.toDateTime().substr(ts.toDateTime().find(' ') + 1);
407
408 ARMARX_INFO << "Processing new set of primitives (timestamp: " << timestampString << ")";
409
410 environmentalPrimitiveSegment->removeOlderPrimitives(
411 new armarx::TimestampVariant(originalTimestamp));
412
413 ARMARX_INFO << "Primitives older than " << timestampString << " removed";
414 }
415
416 int spatialStepSize = getProperty<float>("SpatialSamplingDistance").getValue();
417 int numOrientationalSteps = getProperty<int>("NumOrientationalSamplings").getValue();
418
419 {
420 std::unique_lock lock(affordancesMutex);
421
422 for (auto& a : unimanualAffordances)
423 {
424 if (affordanceRestriction.size() == 0 ||
425 affordanceRestriction.find(a->getName()) != affordanceRestriction.end())
426 {
427 a->reset();
428 }
429 }
430 for (auto& a : bimanualAffordances)
431 {
432 if (affordanceRestriction.size() == 0 ||
433 affordanceRestriction.find(a->getName()) != affordanceRestriction.end())
434 {
435 a->reset();
436 }
437 }
438
439 bool samplingNeeded = true;
440 for (auto& primitive : *primitives)
441 {
442 if (primitive->getSamplingSize() > 0)
443 {
444 samplingNeeded = false;
445 }
446
447 if (maxPrimitiveSamplingSize > 0 &&
448 primitive->getSamplingSize() > maxPrimitiveSamplingSize)
449 {
450 // Sampling was read from memory, so we need to apply the max sampling size policy again
451 ARMARX_INFO << "Ignoring primitive " << primitive->getId() << ", sampling size "
452 << primitive->getSamplingSize() << " is too large";
453 primitive->resetSampling();
454 }
455 }
456
457 IceUtil::Time t = IceUtil::Time::now();
458 if (samplingNeeded)
459 {
460 primitives->sample(spatialStepSize, numOrientationalSteps, maxPrimitiveSamplingSize);
461 ARMARX_INFO << "Sampling of primitives took "
462 << (IceUtil::Time::now() - t).toMilliSeconds() << " ms";
463 }
464 else
465 {
466 ARMARX_INFO << "Sampling not necessary";
467 }
468
469 for (auto& a : unimanualAffordances)
470 {
471 if (affordanceRestriction.size() == 0 ||
472 affordanceRestriction.find(a->getName()) != affordanceRestriction.end())
473 {
474 IceUtil::Time t = IceUtil::Time::now();
475 a->evaluatePrimitiveSet(primitives);
476 ARMARX_INFO << "Evaluation of affordance '" << a->getName() << "' took "
477 << (IceUtil::Time::now() - t).toMilliSeconds() << " ms";
478 }
479 }
480
481 for (auto& a : bimanualAffordances)
482 {
483 if (affordanceRestriction.size() == 0 ||
484 affordanceRestriction.find(a->getName()) != affordanceRestriction.end())
485 {
486 IceUtil::Time t = IceUtil::Time::now();
487 a->evaluatePrimitiveSet(primitives);
488 ARMARX_INFO << "Evaluation of affordance '" << a->getName() << "' took "
489 << (IceUtil::Time::now() - t).toMilliSeconds() << " ms";
490 }
491 }
492
493 ARMARX_INFO << "Total time for affordance extraction: "
494 << (IceUtil::Time::now() - t).toMilliSeconds() << " ms";
495
496 {
497 std::unique_lock lock(enableMutex);
498
499 if (!enabled)
500 {
501 ARMARX_INFO << "Affordance extraction interrupted (pipeline step disabled)";
502 return;
503 }
504 }
505
506 t = IceUtil::Time::now();
509
510 std::string affordanceName = "";
511 float uncertainty = s.getTotalUncertainty(affordanceName);
512 float positiveDecisionRate = s.getPositiveDecisionRate(affordanceName);
513 float negativeDecisionRate = s.getNegativeDecisionRate(affordanceName);
514 float conflict = s.getTotalConflict(affordanceName);
515
517 valueMap["uncertainty"] = new Variant(uncertainty);
518 valueMap["positiveDecisionRate"] = new Variant(positiveDecisionRate);
519 valueMap["negativeDecisionRate"] = new Variant(negativeDecisionRate);
520 valueMap["conflict"] = new Variant(conflict);
521 debugObserver->setDebugChannel(getName(), valueMap);
522
523
525 << " new affordances written to memory: "
526 << (IceUtil::Time::now() - t).toMilliSeconds() << " ms";
527
528 {
529 std::unique_lock lock(timestampMutex);
530 lastProcessedTimestamp = originalTimestamp;
531 }
532
533 listenerPrx->reportNewAffordances();
535 << " affordances extracted and reported";
536 }
537}
538
545
546void
548{
549 std::unique_lock lock(enableMutex);
550
551 ARMARX_INFO << "Pipeline step enabled";
552 enabled = true;
553}
554
555void
557{
558 std::unique_lock lock(enableMutex);
559
560 ARMARX_INFO << "Pipeline step disabled";
561 enabled = false;
562}
563
564bool
566{
567 std::unique_lock lock(enableMutex);
568 return enabled;
569}
570
571armarx::TimestampBasePtr
573{
574 std::unique_lock lock(timestampMutex);
576}
constexpr T c
AffordanceKit::BimanualPrismaticGraspAffordancePtr bimanualPrismaticGraspAffordance
AffordanceKit::BimanualTurnAffordancePtr bimanualTurnAffordance
AffordanceKit::BimanualOpposedGraspAffordancePtr bimanualOpposedGraspAffordance
AffordanceKit::HoldAffordancePtr holdAffordance
AffordanceKit::PlatformGraspAffordancePtr platformGraspAffordance
memoryx::AffordanceSegmentBasePrx affordanceSegment
AffordanceKit::BimanualGraspAffordancePtr bimanualGraspAffordance
memoryx::WorkingMemoryInterfacePrx workingMemoryPrx
void reportNewPointCloudSegmentation(const Ice::Current &c=Ice::emptyCurrent) override
AffordanceKit::PrismaticGraspAffordancePtr prismaticGraspAffordance
std::vector< AffordanceKit::UnimanualAffordancePtr > unimanualAffordances
std::map< std::string, memoryx::AffordanceType > affordanceTypes
void addObservation(const PoseBasePtr &endEffectorPose, const std::string &affordance, const std::string &primitiveId, float result, float certainty, float sigma_pos, float sigma_rot, const Ice::Current &c=Ice::emptyCurrent) override
AffordanceKit::BimanualAlignedGraspAffordancePtr bimanualAlignedGraspAffordance
AffordanceKit::BimanualPlatformGraspAffordancePtr bimanualPlatformGraspAffordance
AffordanceKit::LiftAffordancePtr liftAffordance
AffordanceKit::PushAffordancePtr pushAffordance
AffordanceKit::PullAffordancePtr pullAffordance
void enablePipelineStep(const Ice::Current &c=Ice::emptyCurrent) override
DebugObserverInterfacePrx debugObserver
AffordanceKit::BimanualLiftAffordancePtr bimanualLiftAffordance
AffordanceKit::BimanualAlignedPrismaticGraspAffordancePtr bimanualAlignedPrismaticGraspAffordance
std::set< std::string > affordanceRestriction
void disablePipelineStep(const Ice::Current &c=Ice::emptyCurrent) override
PropertyDefinitionsPtr createPropertyDefinitions() override
std::vector< AffordanceKit::BimanualAffordancePtr > bimanualAffordances
AffordanceKit::EmbodimentPtr embodiment
AffordanceExtractionListenerPrx listenerPrx
AffordanceKit::SupportAffordancePtr supportAffordance
AffordanceKit::PrimitiveSetPtr primitiveSegmentation
AffordanceKit::GraspAffordancePtr graspAffordance
AffordanceKit::BimanualAlignedPlatformGraspAffordancePtr bimanualAlignedPlatformGraspAffordance
AffordanceKit::TurnAffordancePtr turnAffordance
void exportScene(const std::string &filename, const Ice::Current &c=Ice::emptyCurrent) override
memoryx::EnvironmentalPrimitiveSegmentBasePrx environmentalPrimitiveSegment
AffordanceKit::BimanualOpposedPrismaticGraspAffordancePtr bimanualOpposedPrismaticGraspAffordance
AffordanceKit::BimanualOpposedPlatformGraspAffordancePtr bimanualOpposedPlatformGraspAffordance
PeriodicTask< AffordanceExtraction >::pointer_type affordanceExtractionTask
armarx::TimestampBasePtr getLastProcessedTimestamp(const Ice::Current &c=Ice::emptyCurrent) override
bool isPipelineStepEnabled(const Ice::Current &c=Ice::emptyCurrent) override
void importScene(const std::string &filename, const Ice::Current &c=Ice::emptyCurrent) override
AffordanceKit::LeanAffordancePtr leanAffordance
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
std::string getName() const
Retrieve name of object.
IceManagerPtr getIceManager() const
Returns the IceManager.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
The periodic task executes one thread method repeatedly using the time period specified in the constr...
Implements a Variant type for timestamps.
The Variant class is described here: Variants.
Definition Variant.h:224
#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
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Definition IceManager.h:49
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::map< std::string, VariantBasePtr > StringVariantBaseMap
std::vector< std::string > Split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.