SemanticRelationAnalyzer.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 VisionX::ArmarXObjects::SemanticRelationAnalyzer
17 * @author Fabian Paus ( fabian dot paus at kit dot edu )
18 * @date 2019
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
26
27#include <VirtualRobot/CollisionDetection/CollisionChecker.h>
28#include <VirtualRobot/CollisionDetection/CollisionCheckerImplementation.h>
29#include <VirtualRobot/CollisionDetection/CollisionModel.h>
30#include <VirtualRobot/ManipulationObject.h>
31#include <VirtualRobot/Visualization/TriMeshModel.h>
32
34
39
40#include <SemanticObjectRelations/Shapes/json/ShapeSerializers.h>
41#include <SemanticObjectRelations/SupportAnalysis/json.h>
42#include <SemanticObjectRelations/Visualization/ContactDetectionVisualizer.h>
43#include <SemanticObjectRelations/Visualization/SupportAnalysisVisualizer.h>
44
45namespace armarx
46{
48 std::string prefix) :
50 {
52 "WorkingMemoryName", "WorkingMemory", "Name of WorkingMemory component");
54 "PriorKnowledgeName", "PriorKnowledge", "Name of PriorKnowledge component");
55 defineOptionalProperty<std::string>("RobotStateComponentName",
56 "RobotStateComponent",
57 "Name of RobotStateComponent component");
59 "DebugDrawerTopicName", "DebugDrawerUpdates", "The name of the debug drawer topic");
60 defineOptionalProperty<int>("UpdatePeriodInMS", 10, "Update period in ms");
61
63 "VisuLevel",
64 semrel::VisuLevel::RESULT,
65 "Visualization level: Determines what is shown in the debug drawer\n"
66 "Possible values: live, verbose, result, user, disabled")
67 .map("live", semrel::VisuLevel::LIVE_VISU)
68 .map("verbose", semrel::VisuLevel::VERBOSE)
69 .map("result", semrel::VisuLevel::RESULT)
70 .map("user", semrel::VisuLevel::USER)
71 .map("disabled", semrel::VisuLevel::DISABLED);
72
74 "ContactMarginInMM", 5.0f, "Margin (mm) used during contact detection between objects");
75 }
76
77 static semrel::ContactPointList
78 calculateContactPoints(semrel::ShapeList const& objects)
79 {
80 semrel::ContactPointList result;
81
82 VirtualRobot::CollisionCheckerPtr collisionChecker =
83 VirtualRobot::CollisionChecker::getGlobalCollisionChecker();
84 for (std::size_t i = 0; i < objects.size(); ++i)
85 {
87 dynamic_cast<armarx::semantic::SimoxObjectShape const&>(*objects[i]);
88 for (std::size_t j = i + 1; j < objects.size(); ++j)
89 {
91 dynamic_cast<armarx::semantic::SimoxObjectShape const&>(*objects[j]);
92 Eigen::Affine3f poseB(shapeB.object->getGlobalPose());
93
94 VirtualRobot::CollisionModelPtr collModelA = shapeA.object->getCollisionModel();
95 VirtualRobot::CollisionModelPtr collModelB = shapeB.object->getCollisionModel();
96 VirtualRobot::MultiCollisionResult collisions =
97 collisionChecker->checkMultipleCollisions(collModelA, collModelB);
98
99 //auto& facesA = collModelA->getTriMeshModel()->faces;
100 auto& facesB = collModelB->getTriMeshModel()->faces;
101 auto& normalsB = collModelB->getTriMeshModel()->normals;
102 for (VirtualRobot::SingleCollisionPair const& collision : collisions.pairs)
103 {
104 //VirtualRobot::MathTools::TriangleFace const& faceOnA = facesA.at(collision.id1);
105 VirtualRobot::MathTools::TriangleFace const& faceOnB = facesB.at(collision.id2);
106
107 Eigen::Vector3f globalPointOnB = collision.contact2;
108
109 Eigen::Vector3f localNormalOnB;
110 if (faceOnB.idNormal1 == UINT_MAX)
111 {
112 localNormalOnB = poseB.linear() * faceOnB.normal;
113 }
114 else
115 {
116 Eigen::Vector3f n1B = normalsB[faceOnB.idNormal1];
117 Eigen::Vector3f n2B = normalsB[faceOnB.idNormal2];
118 Eigen::Vector3f n3B = normalsB[faceOnB.idNormal3];
119
120 localNormalOnB = (n1B + n2B + n3B).normalized();
121 }
122 Eigen::Vector3f globalNormalOnB = poseB.linear() * localNormalOnB;
123
124 result.emplace_back(&shapeA, &shapeB, globalPointOnB, globalNormalOnB);
125 }
126 }
127 }
128
129 return result;
130 }
131
132 static void
133 filterObjectsWithoutCollisionModel(std::vector<memoryx::ObjectInstanceWrapper>& objects)
134 {
135 // Filter out object without collision model
136 auto removeIter = std::remove_if(
137 objects.begin(),
138 objects.end(),
139 [](memoryx::ObjectInstanceWrapper const& object)
140 {
141 // Check whether this thing has a collision model
142 if (object.manipulationObject->getCollisionModel())
143 {
144 if (object.manipulationObject->getCollisionModel()->getTriMeshModel())
145 {
146 return false;
147 }
148 else
149 {
150 ARMARX_WARNING_S << "No tri-mesh model in '"
151 << object.instanceInMemory->getMostProbableClass() << "'";
152 }
153 }
154 else
155 {
156 ARMARX_WARNING_S << "No collision model in '"
157 << object.instanceInMemory->getMostProbableClass() << "'";
158 }
159 return true;
160 });
161 objects.erase(removeIter, objects.end());
162 }
163
164 semantic::data::Graph
166 {
167 std::lock_guard<std::mutex> lock(componentMutex);
168
169 std::vector<memoryx::ObjectInstanceWrapper> objectInstances =
170 objectInstancesSegment_.queryObjects();
171 filterObjectsWithoutCollisionModel(objectInstances);
172
173 semrel::ShapeList shapes;
174 std::set<semrel::ShapeID> safeShapes;
175 std::set<std::string> safeObjectClassNames = {"workbench", "booth"};
176
177 std::vector<std::string> names;
178 int uniqueID = 0;
179 for (auto& object : objectInstances)
180 {
181 std::string objectClass = object.instanceInMemory->getMostProbableClass();
182 // Here we have the manipulation object, i.e. mesh of the object
183 if (safeObjectClassNames.count(objectClass) > 0)
184 {
185 ARMARX_IMPORTANT << "Adding safe object: " << object.instanceInMemory->getName();
186 safeShapes.insert(semrel::ShapeID{uniqueID});
187 }
188 object.manipulationObject->getCollisionModel()->inflateModel(prop_ContactMarginInMM);
189 std::unique_ptr<semantic::SimoxObjectShape> shape =
190 std::make_unique<semantic::SimoxObjectShape>(object.manipulationObject,
191 objectClass);
192 shape->entityId = object.instanceInMemory->getId();
193
194 shape->setID(semrel::ShapeID{uniqueID});
195 uniqueID += 1;
196 shapes.push_back(std::move(shape));
197 }
198
199 ARMARX_INFO << deactivateSpam(1) << "Object instances (" << shapes.size() << "): " << names;
200
201 // Do the contact detection our own way (for now)
202 semrel::ContactPointList contactPoints = calculateContactPoints(shapes);
203 semrel::ContactGraph contactGraph = semrel::buildContactGraph(contactPoints, shapes);
204 //semrel::SupportAnalysisVisualizer& visu = semrel::SupportAnalysisVisualizer::get();
205 semrel::ContactDetectionVisualizer& visu = semrel::ContactDetectionVisualizer::get();
206 visu.drawContactPoints(contactPoints);
207
208 semrel::SupportGraph supportGraph =
209 supportAnalysis.performSupportAnalysis(shapes, safeShapes, &contactGraph);
210 ARMARX_IMPORTANT << "Supprt graph:\n" << supportGraph;
211
212 // , semantic::JsonSimoxShapeSerializer()
213 semrel::AttributedGraph attributedGraph = semrel::toAttributedGraph(supportGraph);
214 attributedGraph.serializeObjects(semrel::toShapeMap(shapes));
215 semantic::data::Graph iceGraph = armarx::semantic::toIce(attributedGraph);
216 getGraphStorageTopic()->begin_reportGraph("Support", iceGraph);
217
218 memoryx::RelationList relations = semantic::toMemory(attributedGraph);
219 relationSegment->replaceRelations(relations);
220
221 return iceGraph;
222 }
223
224#define GET_PROP(name) prop_##name = getProperty<decltype(prop_##name)>(#name).getValue()
225
226 void
228 {
229 // Register shape serializer for
230
231 GET_PROP(WorkingMemoryName);
232 GET_PROP(PriorKnowledgeName);
233 GET_PROP(RobotStateComponentName);
234 GET_PROP(DebugDrawerTopicName);
235 GET_PROP(UpdatePeriodInMS);
236 GET_PROP(ContactMarginInMM);
237
238 offeringTopic(prop_DebugDrawerTopicName);
239
241 }
242
243 void
245 {
246 workingMemory = getProxy<memoryx::WorkingMemoryInterfacePrx>(prop_WorkingMemoryName);
247 priorKnowledge = getProxy<memoryx::PriorKnowledgeInterfacePrx>(prop_PriorKnowledgeName);
248 robotStateComponent =
249 getProxy<RobotStateComponentInterfacePrx>(prop_RobotStateComponentName);
250 debugDrawer = getTopic<DebugDrawerInterfacePrx>(prop_DebugDrawerTopicName);
251
253 semrel::VisuLevel visuLevel = getProperty<semrel::VisuLevel>("VisuLevel").getValue();
254 semrel::VisualizerInterface::get().setMinimumVisuLevel(visuLevel);
255
256 relationSegment = workingMemory->getRelationsSegment();
257 objectInstancesSegment_.initFromProxies(priorKnowledge, workingMemory, robotStateComponent);
258
259 jsonSerializer.reset(
260 new semantic::JsonSimoxShapeSerializer(&objectInstancesSegment_.objectClassSegment));
261 semantic::JsonSimoxShapeSerializer::registerSerializer(jsonSerializer, true);
262
263 // We call the method once for test purposes
265
267 this, &SemanticRelationAnalyzer::update, prop_UpdatePeriodInMS);
268 updateTask->start();
269 }
270
271 void
273 {
274 updateTask->stop();
275 updateTask = nullptr;
276 }
277
278 void
282
289
290 static std::string const LAYER_NAME = "SemanticRelationAnalyzer";
291
292 void
293 SemanticRelationAnalyzer::update()
294 {
295 // extractSupportGraphFromWorkingMemory(Ice::Current());
296 }
297
298} // namespace armarx
299
300std::string
302{
303 return "SemanticRelationAnalyzer";
304}
305
306std::string
311
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define GET_PROP(name)
ComponentPropertyDefinitions(std::string prefix, bool hasObjectNameParameter=true)
Definition Component.cpp:46
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.
std::string getName() const
Retrieve name of object.
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...
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
armarx::semantic::GraphStorageTopicPrx const & getGraphStorageTopic()
Brief description of class SemanticRelationAnalyzer.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
semantic::data::Graph extractSupportGraphFromWorkingMemory(const Ice::Current &) override
std::string getDefaultName() const override
Retrieve default name of component.
static void setAsImplementation(const std::string &tag)
Definition ArmarXLog.cpp:9
static void setAsImplementation(const armarx::DebugDrawerInterfacePrx &debugDrawer)
VirtualRobot::ManipulationObjectPtr object
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
data::Graph toIce(const semrel::AttributedGraph &input)
Definition graph.cpp:15
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.