PointCloudProcessor.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, 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 VisionX::Core
19 * @author David Gonzalez Aguirre (david dot gonzalez at kit dot edu)
20 * @date 2014
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25#include "PointCloudProcessor.h"
26
27#include <chrono>
28#include <thread>
29
30#include <pcl/console/print.h>
31
37
38#include <VisionX/interface/components/Calibration.h> // For ReferenceFrameInterface
39
40
41using namespace armarx;
42
43namespace visionx
44{
45
51
53 resultPointCloudProviderName("ResultPointCloudProvider"),
54 pointContentType(PointContentType::eColoredPoints)
55 {
56 }
57
58 void
60 {
61 resultPointCloudProviderName = name;
62 }
63
64 std::string
66 {
67 return resultPointCloudProviderName;
68 }
69
70 void
72 {
73 this->shmCapacity = shmCapacity;
74 }
75
76 size_t
78 {
79 return shmCapacity;
80 }
81
82 void
84 {
85 pointContentType = type;
86 }
87
88 PointContentType
90 {
91 return pointContentType;
92 }
93
94 void
98
99 void
103
104 MetaPointCloudFormatPtr
106 {
107 MetaPointCloudFormatPtr info = new MetaPointCloudFormat();
108 info->capacity = static_cast<Ice::Int>(shmCapacity);
109 info->size = static_cast<Ice::Int>(shmCapacity);
110 info->type = pointContentType;
111 return info;
112 }
113
120
122 std::string prefix) :
124 {
126 "FrameRate",
127 0.0,
128 "Number of frames per second. If zero then this property is ignored.");
130 "AutomaticTypeConversion", false, "Automatically convert different point cloud types.");
132 "ProviderName", "", "Name(s) of the point cloud provider(s).");
133 }
134
135 void
137 {
138
139 switch (getProperty<armarx::MessageTypeT>("MinimumLoggingLevel"))
140 {
142 pcl::console::setVerbosityLevel(pcl::console::L_VERBOSE);
143 break;
145 pcl::console::setVerbosityLevel(pcl::console::L_DEBUG);
146 break;
149 pcl::console::setVerbosityLevel(pcl::console::L_INFO);
150 break;
152 pcl::console::setVerbosityLevel(pcl::console::L_WARN);
153 break;
156 pcl::console::setVerbosityLevel(pcl::console::L_ERROR);
157 break;
158 default:
159 pcl::console::setVerbosityLevel(pcl::console::L_ALWAYS);
160 break;
161 }
162
163
164 if (hasProperty("FrameRate"))
165 {
166 getProperty(frameRate, "FrameRate");
167 }
168 else
169 {
170 frameRate = 0.0;
171 }
172
173 if (hasProperty("AutomaticTypeConversion"))
174 {
175 getProperty(automaticConversion, "AutomaticTypeConversion");
176 }
177 else
178 {
179 automaticConversion = false;
180 }
181
182 if (hasProperty("ProviderName") &&
183 !getProperty<std::string>("ProviderName").getValue().empty())
184 {
185 std::vector<std::string> providerNames =
186 armarx::Split(getProperty<std::string>("ProviderName"), ",", true);
187
188 for (const std::string& providerName : providerNames)
189 {
190 if (providerName.empty())
191 {
192 ARMARX_ERROR << "Property " << VAROUT(providerNames)
193 << " contains an invalid value";
194 }
195 else
196 {
197 usingPointCloudProvider(providerName);
198 }
199 }
200 }
201 else
202 {
203 ARMARX_INFO << "The PointCloudProcessor " << getDefaultName() << "'s properties seem to"
204 << "\nnot derive from PointCloudProcessorPropertyDefinitions. Consider"
205 << "\nderiving " << getDefaultName()
206 << "'s properties from this class to get"
207 << "\ndefault point cloud processor properties, such as 'ProviderName', and"
208 << "\nthe respective features.";
209 }
210
211
213 }
214
215 void
217 {
220
221 for (const auto& [providerName, _] : usedPointCloudProviders)
222 {
223 if (pointCloudProviderInfoMap.count(providerName) == 0)
224 {
225 getPointCloudProvider(providerName);
226 }
227 }
228
230 processorTask->start();
231 }
232
233 void
239
240 void
242 {
243 ARMARX_VERBOSE << "PointCloudProcessor::onExitComponent()";
245
246 std::shared_lock lock(pointCloudProviderInfoMutex);
247
248 for (auto& resultProvider : resultPointCloudProviders)
249 {
250 getArmarXManager()->removeObjectBlocking(resultProvider.first);
251 }
252 }
253
254 void
256 {
257 ARMARX_INFO << "Starting PointCloud Processor";
258
259 // main loop of component
260 while (!processorTask->isStopped())
261 {
262 // call process method of sub class
263 process();
264
265 if (frameRate > 0)
266 {
267 fpsCounter.assureFPS(frameRate);
268 }
269 else
270 {
271 std::this_thread::sleep_for(std::chrono::milliseconds(1));
272 }
273 }
274
275 ARMARX_INFO << "Stopping PointCloud Processor";
276 }
277
278 void
280 {
281 std::unique_lock lock(pointCloudProviderInfoMutex);
282
283 // use PointCloud event topic
284 usingTopic(providerName + ".PointCloudListener");
285
286 // create shared memory consumer
289 this, providerName, "PointCloudProvider");
290
291 usedPointCloudProviders.emplace(providerName, consumer);
292 }
293
294 void
296 {
297 std::unique_lock lock(pointCloudProviderInfoMutex);
298
299 if (usedPointCloudProviders.count(providerName))
300 {
301 usedPointCloudProviders.erase(providerName);
302 }
303
304 {
305 if (pointCloudProviderInfoMap.count(providerName))
306 {
307 pointCloudProviderInfoMap.erase(providerName);
308 }
309 }
310
311 // Following calls take care of existence of argument themself, no need to check.
312 // If they return false, we can still be sure the dependency is removed and the
313 // topic unsubscribed.
314
315 // Unsubscribe topic
316 this->unsubscribeFromTopic(providerName + ".PointCloudListener");
317
318 // Remove proxy dependencies
319 this->removeProxyDependency(providerName);
320 std::string memoryName = providerName + "Memory" + "PointCloudProvider";
321 this->removeProxyDependency(memoryName);
322 }
323
326 {
327 std::unique_lock lock(pointCloudProviderInfoMutex);
328
329 if (pointCloudProviderInfoMap.count(providerName))
330 {
331 // return pointCloudProviderInfoMap[providerName];
332 ARMARX_INFO << "Point cloud provider already started: " << providerName;
333 }
334
335 PointCloudProviderInfo providerInfo;
336
337 // get proxy for PointCloud polling
338 ARMARX_DEBUG << "getProxy '" << providerName << "' waitForProxy = " << waitForProxy
339 << "\nproviders: " << getMapKeys(pointCloudProviderInfoMap);
340 providerInfo.proxy = getProxy<PointCloudProviderInterfacePrx>(providerName, waitForProxy);
341 ARMARX_DEBUG << "getProxy '" << providerName << "'...done!";
342 providerInfo.pointCloudFormat = providerInfo.proxy->getPointCloudFormat();
343
344 providerInfo.pointCloudAvailableEvent.reset(new std::condition_variable);
345 providerInfo.pointCloudAvailable = false;
346
347 size_t pointCloudBufferSize = static_cast<size_t>(providerInfo.pointCloudFormat->size);
348 providerInfo.buffer.resize(pointCloudBufferSize);
349
350
351 {
352 pointCloudProviderInfoMap.emplace(providerName, providerInfo);
353 }
354
355
356 std::unique_lock lock2(statisticsMutex);
357
358 statistics[providerName].pollingFPS.reset();
359 statistics[providerName].pointCloudProviderFPS.reset();
360
361 if (!providerInfo.proxy->hasSharedMemorySupport())
362 {
363 ARMARX_IMPORTANT << "shared memory not available for provider " << providerName;
364 usedPointCloudProviders[providerName]->setTransferMode(eIce);
365 pointCloudProviderInfoMap[providerName].pointCloudTransferMode = eIceTransfer;
366 // pointCloudProviderInfoMap[providerName].info = new MetaInfoSizeBase(0, 0, TimeUtil::GetTime().toMicroSeconds());
367 removeProxyDependency(usedPointCloudProviders[providerName]->getMemoryName());
368 }
369 else
370 {
371 //////////////////////////
372 // start communication
373 //////////////////////////
374 usedPointCloudProviders[providerName]->start();
375 }
376
377
378 // usedPointCloudProviders[providerName]->start();
379
380 return providerInfo;
381 }
382
385 {
386 std::string providerName;
387 {
388 std::shared_lock lock(pointCloudProviderInfoMutex);
391 if (pointCloudProviderInfoMap.size() > 1)
392 {
393 ARMARX_ERROR << "Calling getPointCloudProvider without "
394 << "PointCloudProvider name but using multiple "
395 << "PointCloudProviders";
396 }
398 providerName = pointCloudProviderInfoMap.begin()->first;
399 }
400 return getPointCloudProvider(providerName, waitForProxy);
401 }
402
403 std::vector<std::string>
405 {
406 std::vector<std::string> names;
407 names.reserve(usedPointCloudProviders.size());
408 for (const auto& [name, _] : usedPointCloudProviders)
409 {
410 names.push_back(name);
411 }
412 return names;
413 }
414
415 bool
416 PointCloudProcessor::isPointCloudProviderKnown(const std::string& providerName) const
417 {
418 return usedPointCloudProviders.count(providerName) > 0;
419 }
420
421 void
422 PointCloudProcessor::enableResultPointClouds(std::string resultProviderName,
423 size_t shmCapacity,
424 PointContentType pointContentType)
425 {
426 if (resultProviderName == "")
427 {
428 resultProviderName = getName() + "Result";
429 }
430
431 std::unique_lock lock(resultProviderMutex);
432
433 if (resultPointCloudProviders.count(resultProviderName))
434 {
435 ARMARX_WARNING << "result point cloud provider already exists: " << resultProviderName;
436 }
437 else
438 {
441 resultProvider->setName(resultProviderName);
442 resultProvider->setShmCapacity(shmCapacity);
443 resultProvider->setPointContentType(pointContentType);
444
445 getArmarXManager()->addObject(resultProvider);
446
447 {
448 resultPointCloudProviders.emplace(resultProvider->getName(), resultProvider);
449 }
450
451 lock.unlock();
452
453 resultProvider->getObjectScheduler()->waitForObjectState(eManagedIceObjectStarted);
454 }
455 }
456
457 bool
459 {
460 std::shared_lock lock(pointCloudProviderInfoMutex);
461
463 if (pointCloudProviderInfoMap.size() > 1)
464 {
465 ARMARX_ERROR << "Calling waitForPointClouds without PointCloudProvider name but using "
466 "multiple PointCloudProviders";
467 return false;
468 }
469
471 const std::string& providerName = pointCloudProviderInfoMap.begin()->first;
472
474 return waitForPointClouds(providerName, milliseconds);
475 }
476
477 bool
478 PointCloudProcessor::waitForPointClouds(const std::string& providerName, int milliseconds)
479 {
480 std::shared_lock lock(pointCloudProviderInfoMutex);
481
483 // find PointCloud provider by name
484 auto iter = pointCloudProviderInfoMap.find(providerName);
485 if (iter == pointCloudProviderInfoMap.end())
486 {
488 << "Trying to wait for PointClouds from unknown PointCloud provider '"
489 << providerName << "'. Call usingPointCloudProvider before."
490 << "\nKnown providers: " << getPointCloudProviderNames();
491 return false;
492 }
493
494 if (iter->second.pointCloudAvailable)
495 {
496 return true;
497 }
499
500 auto cond = iter->second.pointCloudAvailableEvent;
501
502 lock.unlock();
503
504 // wait for conditionale
505 std::mutex mut;
506 std::unique_lock lock2(mut);
507 auto td = std::chrono::milliseconds(milliseconds);
508
509
510 return cond->wait_for(lock2, td) != std::cv_status::timeout;
511 }
512
513 bool
515 {
516 std::shared_lock lock(pointCloudProviderInfoMutex);
517
518 // find PointCloud provider by name
519 auto iter = pointCloudProviderInfoMap.find(providerName);
520 if (iter == pointCloudProviderInfoMap.end())
521 {
523 << "Asked for new point cloud data for unknown PointCloud provider '"
524 << providerName << "'. Call usingPointCloudProvider() beforehand."
525 << "\nKnown providers: " << getPointCloudProviderNames();
526
527 return false;
528 }
529
530 return iter->second.pointCloudAvailable;
531 }
532
533 MetaPointCloudFormatPtr
535 {
536 std::shared_lock lock(pointCloudProviderInfoMutex);
537
538 MetaPointCloudFormatPtr format;
539
540 // find PointCloud provider
541 auto iter = pointCloudProviderInfoMap.find(providerName);
542 if (iter == pointCloudProviderInfoMap.end())
543 {
545 << "Trying to wait for PointClouds from unknown PointCloud provider '"
546 << providerName << "'. Call usingPointCloudProvider before."
547 << "\nKnown providers: " << getPointCloudProviderNames();
548 }
549 else
550 {
551 format = iter->second.proxy->getPointCloudFormat();
552 }
553
554 return format;
555 }
556
558 PointCloudProcessor::getPointCloudTransferStats(std::string providerName, bool resetStats)
559 {
560 std::unique_lock lock(statisticsMutex);
561
562 auto iter = statistics.find(providerName);
563 if (iter == statistics.end())
564 {
565 ARMARX_ERROR << "Requesting statistics for unknown PointCloud provider '"
566 << providerName << "'"
567 << "\nKnown providers: " << getPointCloudProviderNames();
569 }
570
571 PointCloudTransferStats stats = iter->second;
572
573 if (resetStats)
574 {
575 iter->second.pointCloudProviderFPS.reset();
576 iter->second.pollingFPS.reset();
577 }
578 else
579 {
580 iter->second.pointCloudProviderFPS.recalculate();
581 iter->second.pollingFPS.recalculate();
582 }
583
584 return stats;
585 }
586
587 std::string
588 PointCloudProcessor::getPointCloudFrame(const std::string& providerName,
589 const std::string& defaultFrame)
590 {
591 std::shared_lock lock(pointCloudProviderInfoMutex);
592
593 auto find = pointCloudProviderInfoMap.find(providerName);
595 << "Requesting information about unknown point cloud provider ''" << providerName
596 << "'."
597 << "\nKnown providers: " << getPointCloudProviderNames();
598
599 const PointCloudProviderInfo& providerInfo = find->second;
600 auto frameProv = ReferenceFrameInterfacePrx::checkedCast(providerInfo.proxy);
601
602 return frameProv ? frameProv->getReferenceFrame() : defaultFrame;
603 }
604
605 void
606 PointCloudProcessor::reportPointCloudAvailable(const std::string& providerName,
607 const Ice::Current&)
608 {
609 std::shared_lock lock(pointCloudProviderInfoMutex);
610
611 // find provider
612 std::map<std::string, PointCloudProviderInfo>::iterator iter =
613 pointCloudProviderInfoMap.find(providerName);
614
615 if (iter == pointCloudProviderInfoMap.end())
616 {
617 ARMARX_ERROR << "Received notification from unknown point cloud provider '"
618 << providerName << "'."
619 << "\nKnown providers: " << getPointCloudProviderNames();
620 return;
621 }
622
623 iter->second.pointCloudAvailable = true;
624 iter->second.pointCloudAvailableEvent->notify_all();
625
626 // update statistics
627 std::unique_lock lock2(statisticsMutex);
628 statistics[providerName].pointCloudProviderFPS.update();
629 }
630
631} // namespace visionx
#define VAROUT(x)
ComponentPropertyDefinitions(std::string prefix, bool hasObjectNameParameter=true)
Definition Component.cpp:46
static TPtr create(Ice::PropertiesPtr properties=Ice::createProperties(), const std::string &configName="", const std::string &configDomain="ArmarX")
Factory method for a component.
Definition Component.h:116
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
The IceSharedMemoryConsumer reads data via Ice or shared memory.
IceUtil::Handle< IceSharedMemoryConsumer< MemoryObject, MemoryObjectMetaInfo > > pointer_type
pointer type for convenience.
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
bool unsubscribeFromTopic(const std::string &name)
Unsubscribe from a topic.
virtual std::string getDefaultName() const =0
Retrieve default name of component.
void usingTopic(const std::string &name, bool orderedPublishing=false)
Registers a proxy for subscription after initialization.
void waitForProxy(std::string const &name, bool addToDependencies)
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)
bool removeProxyDependency(const std::string &name)
This function removes the dependency of this object on the in parameter name specified object.
ArmarXManagerPtr getArmarXManager() const
Returns the ArmarX manager used to add and remove components.
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)
bool hasProperty(const std::string &name)
virtual void onInitComponent() override
void releasePointCloudProvider(std::string providerName)
Removes topic subscription and provider proxy dependency to release a point cloud provider.
std::string getPointCloudFrame(const std::string &providerName, const std::string &defaultFrame="")
Get the reference frame of the point cloud by given provider.
virtual void process()=0
Process the vision component.
virtual void onInitPointCloudProcessor()=0
Setup the vision component.
std::map< std::string, IceInternal::Handle< ResultPointCloudProvider > > resultPointCloudProviders
std::map< std::string, PointCloudTransferStats > statistics
bool isPointCloudProviderKnown(const std::string &providerName) const
Indicate whether the given name identifies a known point cloud provider.
void enableResultPointClouds(std::string resultProviderName="")
Enables visualization.
virtual void onDisconnectComponent() override
virtual void onConnectPointCloudProcessor()=0
Implement this method in the PointCloudProcessor in order execute parts when the component is fully i...
MetaPointCloudFormatPtr getPointCloudFormat(std::string providerName)
std::shared_mutex pointCloudProviderInfoMutex
PointCloudProviderMap usedPointCloudProviders
void usingPointCloudProvider(std::string providerName)
Registers a delayed topic subscription and a delayed provider proxy retrieval which will be available...
virtual void onDisconnectPointCloudProcessor()
Implement this method in the PointCloudProcessor in order execute parts when the component looses net...
virtual void onConnectComponent() override
PointCloudProviderInfo getPointCloudProvider(std::string name, bool waitForProxy=false)
Select an PointCloudProvider.
bool pointCloudHasNewData(std::string providerName)
Returns current status for the given point cloud.
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
armarx::RunningTask< PointCloudProcessor >::pointer_type processorTask
PointCloudTransferStats getPointCloudTransferStats(std::string providerName, bool resetStats=false)
Retrieve statistics for a connection to an PointCloudProvider.
virtual void onExitComponent() override
std::vector< std::string > getPointCloudProviderNames() const
Get the names of providers for which usingPointCloudProvider() has been called.
virtual void onExitPointCloudProcessor()=0
Exit the ImapeProcessor component.
void reportPointCloudAvailable(const std::string &providerName, const Ice::Current &c=Ice::emptyCurrent) override
Listener callback function.
std::map< std::string, PointCloudProviderInfo > pointCloudProviderInfoMap
PointCloudProviderInterfacePrx proxy
Proxy to PointCloud provider.
MetaPointCloudFormatPtr pointCloudFormat
PointCloud format struct that contains all necessary PointCloud information.
std::vector< unsigned char > buffer
Memory block.
std::shared_ptr< std::condition_variable > pointCloudAvailableEvent
Conditional variable used internally for synchronization purposes.
bool pointCloudAvailable
Indicates whether an PointCloud is available.
The PointCloudTransferStats class provides information on the connection between PointCloudProvider a...
PointContentType getPointContentType() const
void setShmCapacity(size_t shmCapacity)
void setPointContentType(PointContentType type)
virtual void onInitPointCloudProvider() override
This is called when the Component::onInitComponent() is called.
virtual MetaPointCloudFormatPtr getDefaultPointCloudFormat() override
default point cloud format used to initialize shared memory
virtual armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
virtual void onExitPointCloudProvider() override
This is called when the Component::onExitComponent() setup is called.
virtual std::string getDefaultName() const override
Retrieve default name of component.
void setResultPointCloudProviderName(const std::string &name)
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK_NOT_EQUAL(lhs, rhs)
This macro evaluates whether lhs is inequal (!=) rhs and if it turns out to be false it will throw an...
#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
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#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
This file offers overloads of toIce() and fromIce() functions for STL container types.
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.
void getMapKeys(const MapType &map, OutputIteratorType it)
Definition algorithm.h:173
ArmarX headers.
#define ARMARX_TRACE
Definition trace.h:77