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
25#include <pcl/common/transforms.h>
26#include <pcl/filters/approximate_voxel_grid.h>
27
29
31
32#include <VisionX/interface/components/Calibration.h>
33#include <VisionX/interface/core/PointCloudProcessorInterface.h>
34
35#define call_template_function(F) \
36 switch (_pointCloudProviderInfo.pointCloudFormat->type) \
37 { \
38 case visionx::PointContentType::ePoints: \
39 F<pcl::PointXYZ>(); \
40 break; \
41 case visionx::PointContentType::eColoredPoints: \
42 F<pcl::PointXYZRGBA>(); \
43 break; \
44 case visionx::PointContentType::eColoredOrientedPoints: \
45 F<pcl::PointXYZRGBNormal>(); \
46 break; \
47 case visionx::PointContentType::eLabeledPoints: \
48 F<pcl::PointXYZL>(); \
49 break; \
50 case visionx::PointContentType::eColoredLabeledPoints: \
51 F<pcl::PointXYZRGBL>(); \
52 break; \
53 case visionx::PointContentType::eIntensity: \
54 F<pcl::PointXYZI>(); \
55 break; \
56 case visionx::PointContentType::eOrientedPoints: \
57 ARMARX_ERROR << "eOrientedPoints NOT HANDLED IN VISIONX"; \
58 [[fallthrough]]; \
59 default: \
60 ARMARX_ERROR << "Could not call " #F ", because format '" \
61 << _pointCloudProviderInfo.pointCloudFormat->type << "' is unknown"; \
62 } \
63 do \
64 { \
65 } while (false)
66
67//common
68namespace armarx
69{
70 std::string
72 {
73 return "MultiViewPointCloudProcessor";
74 }
75
78 {
81 prop->defineOptionalProperty<std::string>(
82 "ProviderReferenceFrame",
83 "",
84 "Name of the point cloud refence frame (empty = autodetect)");
85 std::lock_guard guard{_cfgBufWriteMutex};
86 prop->optional(_cfgBuf.getWriteBuffer(), "", "");
87 return prop;
88 }
89} // namespace armarx
90
91//gui
92namespace armarx
93{
94 RemoteGui::WidgetPtr
96 {
97 std::lock_guard guard{_cfgBufWriteMutex};
99 .addChild(RemoteGui::MakeGuiConfig("cfg", _cfgBuf.getWriteBuffer()))
101 .addChild(RemoteGui::makeButton("start"))
102 .addChild(RemoteGui::makeButton("stop"))
103 .addChild(RemoteGui::makeButton("clear"))
104 .addHSpacer());
105 }
106
107 void
109 {
110 prx.receiveUpdates();
111 std::lock_guard guard{_cfgBufWriteMutex};
112
113 prx.getValue(_cfgBuf.getWriteBuffer(), "cfg");
114 if (prx.getButtonClicked("start"))
115 {
117 }
118 if (prx.getButtonClicked("stop"))
119 {
121 }
122 if (prx.getButtonClicked("clear"))
123 {
125 }
126 prx.sendUpdates();
127 _cfgBuf.commitWrite();
128 }
129} // namespace armarx
130
131//hooks
132namespace armarx
133{
134 void
136 {
137 _pointCloudProviderName = getProperty<std::string>("ProviderName");
138 usingPointCloudProvider(_pointCloudProviderName);
139 }
140
141 void
143 {
144 //provider
145 {
146 _pointCloudProviderInfo = getPointCloudProvider(_pointCloudProviderName, true);
147 _pointCloudProvider = _pointCloudProviderInfo.proxy;
148 _pointCloudProviderRefFrame = getProperty<std::string>("ProviderReferenceFrame");
149 if (_pointCloudProviderRefFrame.empty())
150 {
151 _pointCloudProviderRefFrame = "root";
152 auto frameprov =
153 visionx::ReferenceFrameInterfacePrx::checkedCast(_pointCloudProvider);
154 if (frameprov)
155 {
156 _pointCloudProviderRefFrame = frameprov->getReferenceFrame();
157 }
158 }
159 ARMARX_INFO << VAROUT(_pointCloudProviderRefFrame);
160
161 if (!_providerThread.joinable())
162 {
163 //result cloud of point type
165 _providerThread = std::thread{[&] { call_template_function(doProvide); }};
166 }
167 }
168 //robot
169 {
170 _robot = addRobot("_robot", VirtualRobot::RobotIO::eStructure);
171 }
172 //gui
174 [this](RemoteGui::TabProxy& prx) { processGui(prx); });
175 }
176
177 void
179 {
180 _stopProviding = true;
181 _providerThread.join();
182 }
183} // namespace armarx
184
185//Ice methods
186namespace armarx
187{
188 void
190 {
191 ++_currentViewpoint;
192 _doRecord = true;
193 }
194
195 void
197 {
198 _doRecord = false;
199 }
200
201 void
203 {
204 _doClear = true;
205 }
206
207 void
209 {
210 std::lock_guard guard{_cfgBufWriteMutex};
211 _cfgBuf.getWriteBuffer().maxNumberOfFramesPerViewPoint = n;
212 _cfgBuf.commitWrite();
213 }
214
215 void
217 {
218 std::lock_guard guard{_cfgBufWriteMutex};
219 _cfgBuf.getWriteBuffer().gridSize = s;
220 _cfgBuf.commitWrite();
221 }
222
223 void
224 MultiViewPointCloudProcessor::setFrameRate(Ice::Float r, const Ice::Current&)
225 {
226 std::lock_guard guard{_cfgBufWriteMutex};
227 _cfgBuf.getWriteBuffer().frameRate = r;
228 _cfgBuf.commitWrite();
229 }
230} // namespace armarx
231
232//process
233namespace armarx
234{
235 void
240
241 template <class PointType>
242 void
244 {
246 {
248 };
249 const auto doRecord = _doRecord.load();
250 if (_doClear)
251 {
252 std::lock_guard guard{_viewPointsMutex};
253 _viewPoints.clear();
254 _currentViewpoint = doRecord ? 0 : -1;
255 _doClear = false;
256 }
257 if (!doRecord)
258 {
259 return;
260 }
261 const auto currentViewpoint = _currentViewpoint.load();
262 ARMARX_CHECK_GREATER_EQUAL(currentViewpoint, 0);
263 using cloud_t = pcl::PointCloud<PointType>;
264 using cloud_ptr_t = typename cloud_t::Ptr;
265
266 std::unique_lock lock{_cfgBufReadMutex};
267 const auto buf = _cfgBuf.getUpToDateReadBuffer();
268 lock.unlock();
269 setDebugObserverDatafield("cfg", buf);
270 setDebugObserverDatafield("currentViewpoint", currentViewpoint);
271 setDebugObserverDatafield("doRecord", doRecord);
272
273 //get cloud + transform to global
274 cloud_ptr_t transformedCloud;
275 {
276 if (!waitForPointClouds(_pointCloudProviderName, 100))
277 {
278 ARMARX_INFO << deactivateSpam(10, _pointCloudProviderName)
279 << "Timeout or error while waiting for point cloud data of provider "
280 << _pointCloudProviderName;
281 return;
282 }
283 cloud_ptr_t inputCloud(new cloud_t);
284 getPointClouds(_pointCloudProviderName, inputCloud);
285 synchronizeLocalClone(_robot);
286
287 const Eigen::Matrix4f providerInRootFrame = [&]() -> Eigen::Matrix4f
288 {
289 FramedPose fp{
290 Eigen::Matrix4f::Identity(), _pointCloudProviderRefFrame, _robot->getName()};
291 fp.changeFrame(_robot, "Global");
292 return fp.toEigen();
293 }();
294
295 transformedCloud = cloud_ptr_t(new cloud_t);
296 pcl::transformPointCloud(*inputCloud, *transformedCloud, providerInRootFrame);
297 }
298 setDebugObserverDatafield("cloud_size_in", transformedCloud->size());
299 std::lock_guard guard{_viewPointsMutex};
300 const auto p = static_cast<std::size_t>(currentViewpoint);
301 if (p + 1 > _viewPoints.size())
302 {
303 _viewPoints.resize(p + 1);
304 }
305 _viewPoints.at(p).clouds.emplace_back(transformedCloud);
306 if (buf.maxNumberOfFramesPerViewPoint > 0)
307 {
308 while (_viewPoints.at(p).clouds.size() >
309 static_cast<std::size_t>(buf.maxNumberOfFramesPerViewPoint))
310 {
311 _viewPoints.at(p).clouds.pop_front();
312 }
313 }
314 setDebugObserverDatafield("current_view_num_clouds", _viewPoints.at(p).clouds.size());
315 }
316
317 template <class PointType>
318 void
320 {
321 using cloud_t = pcl::PointCloud<PointType>;
322 using cloud_ptr_t = typename cloud_t::Ptr;
323 std::deque<std::uint64_t> idxVec;
324 while (!_stopProviding)
325 {
326 const auto timeBeg = std::chrono::high_resolution_clock::now();
327
328 std::unique_lock lock{_cfgBufReadMutex};
329 const auto buf = _cfgBuf.getUpToDateReadBuffer();
330 lock.unlock();
331
332 cloud_ptr_t cloud(new cloud_t);
333 {
334 std::lock_guard guard{_viewPointsMutex};
335 if (idxVec.size() < _viewPoints.size())
336 {
337 idxVec.resize(_viewPoints.size());
338 }
339 for (std::size_t i = 0; i < idxVec.size(); ++i)
340 {
341 const auto& inVec = _viewPoints.at(i).clouds;
342 const auto idx = (idxVec.at(i)++) % inVec.size();
343 const auto& in = *std::any_cast<cloud_ptr_t>(inVec.at(idx));
344 auto& out = cloud->points;
345 out.insert(out.end(), in.begin(), in.end());
346 }
347 }
348 //downsample
349 if (buf.gridSize > 0)
350 {
351 pcl::ApproximateVoxelGrid<PointType> grid;
352 grid.setLeafSize(Eigen::Vector3f::Constant(buf.gridSize));
353 grid.setInputCloud(cloud);
354 cloud_ptr_t tempCloud(new cloud_t);
355 grid.filter(*tempCloud);
356 tempCloud.swap(cloud);
357 }
358 //provide
360
361 //sleep for frame rate
362 if (frameRate > 0)
363 {
364 const long dtms = 1 / frameRate * 1000;
365 std::this_thread::sleep_until(timeBeg + std::chrono::milliseconds{dtms});
366 }
367 }
368 }
369} // namespace armarx
#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
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
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)