MultiViewPointCloudProcessor.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::MultiViewPointCloudProcessor
17 * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18 * @date 2020
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
24
26
27#include <pcl/common/transforms.h>
28#include <pcl/filters/approximate_voxel_grid.h>
29
31
33
34#include <VisionX/interface/components/Calibration.h>
35#include <VisionX/interface/core/PointCloudProcessorInterface.h>
36
37#define call_template_function(F) \
38 switch (_pointCloudProviderInfo.pointCloudFormat->type) \
39 { \
40 case visionx::PointContentType::ePoints: \
41 F<pcl::PointXYZ>(); \
42 break; \
43 case visionx::PointContentType::eColoredPoints: \
44 F<pcl::PointXYZRGBA>(); \
45 break; \
46 case visionx::PointContentType::eColoredOrientedPoints: \
47 F<pcl::PointXYZRGBNormal>(); \
48 break; \
49 case visionx::PointContentType::eLabeledPoints: \
50 F<pcl::PointXYZL>(); \
51 break; \
52 case visionx::PointContentType::eColoredLabeledPoints: \
53 F<pcl::PointXYZRGBL>(); \
54 break; \
55 case visionx::PointContentType::eIntensity: \
56 F<pcl::PointXYZI>(); \
57 break; \
58 case visionx::PointContentType::eOrientedPoints: \
59 ARMARX_ERROR << "eOrientedPoints NOT HANDLED IN VISIONX"; \
60 [[fallthrough]]; \
61 default: \
62 ARMARX_ERROR << "Could not call " #F ", because format '" \
63 << _pointCloudProviderInfo.pointCloudFormat->type << "' is unknown"; \
64 } \
65 do \
66 { \
67 } while (false)
68
69//common
70namespace armarx
71{
72 std::string
74 {
75 return "MultiViewPointCloudProcessor";
76 }
77
78 std::string
83
86 {
89 prop->defineOptionalProperty<std::string>(
90 "ProviderReferenceFrame",
91 "",
92 "Name of the point cloud refence frame (empty = autodetect)");
93 std::lock_guard guard{_cfgBufWriteMutex};
94 prop->optional(_cfgBuf.getWriteBuffer(), "", "");
95 return prop;
96 }
97
99} // namespace armarx
100
101//gui
102namespace armarx
103{
104 RemoteGui::WidgetPtr
106 {
107 std::lock_guard guard{_cfgBufWriteMutex};
109 .addChild(RemoteGui::MakeGuiConfig("cfg", _cfgBuf.getWriteBuffer()))
111 .addChild(RemoteGui::makeButton("start"))
112 .addChild(RemoteGui::makeButton("stop"))
113 .addChild(RemoteGui::makeButton("clear"))
114 .addHSpacer());
115 }
116
117 void
119 {
120 prx.receiveUpdates();
121 std::lock_guard guard{_cfgBufWriteMutex};
122
123 prx.getValue(_cfgBuf.getWriteBuffer(), "cfg");
124 if (prx.getButtonClicked("start"))
125 {
127 }
128 if (prx.getButtonClicked("stop"))
129 {
131 }
132 if (prx.getButtonClicked("clear"))
133 {
135 }
136 prx.sendUpdates();
137 _cfgBuf.commitWrite();
138 }
139} // namespace armarx
140
141//hooks
142namespace armarx
143{
144 void
146 {
147 _pointCloudProviderName = getProperty<std::string>("ProviderName");
148 usingPointCloudProvider(_pointCloudProviderName);
149 }
150
151 void
153 {
154 //provider
155 {
156 _pointCloudProviderInfo = getPointCloudProvider(_pointCloudProviderName, true);
157 _pointCloudProvider = _pointCloudProviderInfo.proxy;
158 _pointCloudProviderRefFrame = getProperty<std::string>("ProviderReferenceFrame");
159 if (_pointCloudProviderRefFrame.empty())
160 {
161 _pointCloudProviderRefFrame = "root";
162 auto frameprov =
163 visionx::ReferenceFrameInterfacePrx::checkedCast(_pointCloudProvider);
164 if (frameprov)
165 {
166 _pointCloudProviderRefFrame = frameprov->getReferenceFrame();
167 }
168 }
169 ARMARX_INFO << VAROUT(_pointCloudProviderRefFrame);
170
171 if (!_providerThread.joinable())
172 {
173 //result cloud of point type
175 _providerThread = std::thread{[&] { call_template_function(doProvide); }};
176 }
177 }
178 //robot
179 {
180 _robot = addRobot("_robot", VirtualRobot::RobotIO::eStructure);
181 }
182 //gui
184 [this](RemoteGui::TabProxy& prx) { processGui(prx); });
185 }
186
187 void
189 {
190 _stopProviding = true;
191 _providerThread.join();
192 }
193} // namespace armarx
194
195//Ice methods
196namespace armarx
197{
198 void
200 {
201 ++_currentViewpoint;
202 _doRecord = true;
203 }
204
205 void
207 {
208 _doRecord = false;
209 }
210
211 void
213 {
214 _doClear = true;
215 }
216
217 void
219 {
220 std::lock_guard guard{_cfgBufWriteMutex};
221 _cfgBuf.getWriteBuffer().maxNumberOfFramesPerViewPoint = n;
222 _cfgBuf.commitWrite();
223 }
224
225 void
227 {
228 std::lock_guard guard{_cfgBufWriteMutex};
229 _cfgBuf.getWriteBuffer().gridSize = s;
230 _cfgBuf.commitWrite();
231 }
232
233 void
234 MultiViewPointCloudProcessor::setFrameRate(Ice::Float r, const Ice::Current&)
235 {
236 std::lock_guard guard{_cfgBufWriteMutex};
237 _cfgBuf.getWriteBuffer().frameRate = r;
238 _cfgBuf.commitWrite();
239 }
240} // namespace armarx
241
242//process
243namespace armarx
244{
245 void
250
251 template <class PointType>
252 void
254 {
256 {
258 };
259 const auto doRecord = _doRecord.load();
260 if (_doClear)
261 {
262 std::lock_guard guard{_viewPointsMutex};
263 _viewPoints.clear();
264 _currentViewpoint = doRecord ? 0 : -1;
265 _doClear = false;
266 }
267 if (!doRecord)
268 {
269 return;
270 }
271 const auto currentViewpoint = _currentViewpoint.load();
272 ARMARX_CHECK_GREATER_EQUAL(currentViewpoint, 0);
273 using cloud_t = pcl::PointCloud<PointType>;
274 using cloud_ptr_t = typename cloud_t::Ptr;
275
276 std::unique_lock lock{_cfgBufReadMutex};
277 const auto buf = _cfgBuf.getUpToDateReadBuffer();
278 lock.unlock();
279 setDebugObserverDatafield("cfg", buf);
280 setDebugObserverDatafield("currentViewpoint", currentViewpoint);
281 setDebugObserverDatafield("doRecord", doRecord);
282
283 //get cloud + transform to global
284 cloud_ptr_t transformedCloud;
285 {
286 if (!waitForPointClouds(_pointCloudProviderName, 100))
287 {
288 ARMARX_INFO << deactivateSpam(10, _pointCloudProviderName)
289 << "Timeout or error while waiting for point cloud data of provider "
290 << _pointCloudProviderName;
291 return;
292 }
293 cloud_ptr_t inputCloud(new cloud_t);
294 getPointClouds(_pointCloudProviderName, inputCloud);
295 synchronizeLocalClone(_robot);
296
297 const Eigen::Matrix4f providerInRootFrame = [&]() -> Eigen::Matrix4f
298 {
299 FramedPose fp{
300 Eigen::Matrix4f::Identity(), _pointCloudProviderRefFrame, _robot->getName()};
301 fp.changeFrame(_robot, "Global");
302 return fp.toEigen();
303 }();
304
305 transformedCloud = cloud_ptr_t(new cloud_t);
306 pcl::transformPointCloud(*inputCloud, *transformedCloud, providerInRootFrame);
307 }
308 setDebugObserverDatafield("cloud_size_in", transformedCloud->size());
309 std::lock_guard guard{_viewPointsMutex};
310 const auto p = static_cast<std::size_t>(currentViewpoint);
311 if (p + 1 > _viewPoints.size())
312 {
313 _viewPoints.resize(p + 1);
314 }
315 _viewPoints.at(p).clouds.emplace_back(transformedCloud);
316 if (buf.maxNumberOfFramesPerViewPoint > 0)
317 {
318 while (_viewPoints.at(p).clouds.size() >
319 static_cast<std::size_t>(buf.maxNumberOfFramesPerViewPoint))
320 {
321 _viewPoints.at(p).clouds.pop_front();
322 }
323 }
324 setDebugObserverDatafield("current_view_num_clouds", _viewPoints.at(p).clouds.size());
325 }
326
327 template <class PointType>
328 void
330 {
331 using cloud_t = pcl::PointCloud<PointType>;
332 using cloud_ptr_t = typename cloud_t::Ptr;
333 std::deque<std::uint64_t> idxVec;
334 while (!_stopProviding)
335 {
336 const auto timeBeg = std::chrono::high_resolution_clock::now();
337
338 std::unique_lock lock{_cfgBufReadMutex};
339 const auto buf = _cfgBuf.getUpToDateReadBuffer();
340 lock.unlock();
341
342 cloud_ptr_t cloud(new cloud_t);
343 {
344 std::lock_guard guard{_viewPointsMutex};
345 if (idxVec.size() < _viewPoints.size())
346 {
347 idxVec.resize(_viewPoints.size());
348 }
349 for (std::size_t i = 0; i < idxVec.size(); ++i)
350 {
351 const auto& inVec = _viewPoints.at(i).clouds;
352 const auto idx = (idxVec.at(i)++) % inVec.size();
353 const auto& in = *std::any_cast<cloud_ptr_t>(inVec.at(idx));
354 auto& out = cloud->points;
355 out.insert(out.end(), in.begin(), in.end());
356 }
357 }
358 //downsample
359 if (buf.gridSize > 0)
360 {
361 pcl::ApproximateVoxelGrid<PointType> grid;
362 grid.setLeafSize(Eigen::Vector3f::Constant(buf.gridSize));
363 grid.setInputCloud(cloud);
364 cloud_ptr_t tempCloud(new cloud_t);
365 grid.filter(*tempCloud);
366 tempCloud.swap(cloud);
367 }
368 //provide
370
371 //sleep for frame rate
372 if (frameRate > 0)
373 {
374 const long dtms = 1 / frameRate * 1000;
375 std::this_thread::sleep_until(timeBeg + std::chrono::milliseconds{dtms});
376 }
377 }
378 }
379} // namespace armarx
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
#define call_template_function(F)
#define VAROUT(x)
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 FramedPose class.
Definition FramedPose.h:281
void changeFrame(const SharedRobotInterfacePrx &referenceRobot, const std::string &newFrame)
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
Brief description of class MultiViewPointCloudProcessor.
void stopRecordingViewPoint(const Ice::Current &=Ice::emptyCurrent) override
void clearViewPoints(const Ice::Current &=Ice::emptyCurrent) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void process() override
Process the vision component.
void onExitPointCloudProcessor() override
Exit the ImapeProcessor component.
void startRecordingNextViewPoint(const Ice::Current &=Ice::emptyCurrent) override
void onConnectPointCloudProcessor() override
Implement this method in the PointCloudProcessor in order execute parts when the component is fully i...
void setFrameRate(Ice::Float r, const Ice::Current &=Ice::emptyCurrent) override
void setDownsamplingGridSize(Ice::Float s, const Ice::Current &=Ice::emptyCurrent) override
void onInitPointCloudProcessor() override
Setup the vision component.
void setMaxNumberOfFramesPerViewPoint(Ice::Int n, const Ice::Current &=Ice::emptyCurrent) override
std::string getDefaultName() const override
Retrieve default name of component.
bool getButtonClicked(std::string const &name)
ValueProxy< T > getValue(std::string const &name)
bool synchronizeLocalClone(const VirtualRobot::RobotPtr &robot) const
VirtualRobot::RobotPtr addRobot(const std::string &id, const VirtualRobot::RobotPtr &robot, const VirtualRobot::RobotNodeSetPtr &rns={}, const VirtualRobot::RobotNodePtr &node={})
void enableResultPointClouds(std::string resultProviderName="")
Enables visualization.
int getPointClouds(const PointCloudPtrT &pointCloudPtr)
Poll PointClouds from provider.
void usingPointCloudProvider(std::string providerName)
Registers a delayed topic subscription and a delayed provider proxy retrieval which will be available...
PointCloudProviderInfo getPointCloudProvider(std::string name, bool waitForProxy=false)
Select an PointCloudProvider.
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
void provideResultPointClouds(const PointCloudPtrT &pointClouds, std::string providerName="")
sends result PointClouds for visualization
#define ARMARX_CHECK_GREATER_EQUAL(lhs, rhs)
This macro evaluates whether lhs is greater or equal (>=) rhs and if it turns out to be false it will...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ON_SCOPE_EXIT
Executes given code when the enclosing scope is left.
detail::VBoxLayoutBuilder makeVBoxLayout(std::string const &name="")
detail::HBoxLayoutBuilder makeHBoxLayout(std::string const &name="")
detail::ButtonBuilder makeButton(std::string const &name)
RemoteGui::WidgetPtr MakeGuiConfig(const std::string &name, const T &val)
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Derived & addChild(WidgetPtr const &child)