PointCloudToArViz.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::PointCloudToArViz
17 * @author Rainer Kartmann ( rainer dot kartmann 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
23#include "PointCloudToArViz.h"
24
25#include <pcl/common/transforms.h>
26#include <pcl/impl/point_types.hpp>
27#include <pcl/point_types.h>
28
29#include <SimoxUtility/math/convert/mat4f_to_pos.h>
30#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
31#include <SimoxUtility/math/convert/pos_rpy_to_mat4f.h>
32
36
40
41namespace visionx
42{
43
46 {
48 "ProviderWaitMs", 100, "Time to wait for each point cloud provider [ms].");
49 }
50
53 {
56
57 defs->optional(
58 params.pointSizeInPixels, "viz.pointSizeInPixels", "The point size in pixels.");
59 defs->optional(params.checkFinite,
60 "viz.checkFinite",
61 "Enable to check points for being finite. "
62 "\nEnable this option if the drawn point cloud causes the screen to become "
63 "purely white.");
64 defs->optional(params.labeled,
65 "viz.labeled",
66 "If true and point cloud is labeled, draw colors according to labels.");
67 defs->optional(params.alsoVisualizeNode,
68 "viz.showNode",
69 "If true also the node's coordinate systems is shown.");
70
71 defs->optional(params.robotName, "robotName", "");
72 defs->optional(
73 params.pointCloudNodeName,
74 "pointCloudNodeName",
75 " If the point cloud header does not provide a frame id, this info is used.");
76
77 return defs;
78 }
79
81 {
82 addPlugin(virtualRobotReaderPlugin);
83 }
84
85 std::string
87 {
88 return "PointCloudToArViz";
89 }
90
91 void
93 {
94 params.providerWaitTime =
95 IceUtil::Time::milliSeconds(getProperty<int>("ProviderWaitMs").getValue());
96 }
97
98 void
100 {
101 if (virtualRobotReaderPlugin->isAvailable())
102 {
103 robot = virtualRobotReaderPlugin->get().getRobot(params.robotName);
104 // No need to synchronize the robot here. We synchronize it later anyway.
105 }
106
109 }
110
111 void
115
116 void
120
121 void
123 {
124 // Fetch input clouds.
125 for (const std::string& providerName : getPointCloudProviderNames())
126 {
127 if (waitForPointClouds(providerName,
128 static_cast<int>(params.providerWaitTime.toMilliSeconds())))
129 {
130 auto it = cache.find(providerName);
131 if (it == cache.end())
132 {
133 it = cache.emplace(providerName, armarx::viz::PointCloud(providerName)).first;
134 }
135 armarx::viz::PointCloud& vizCloud = it->second;
136
137 Parameters params;
138 {
139 std::scoped_lock lock(paramMutex);
140 params = this->params;
141 }
142
143 vizCloud.checkFinite(params.checkFinite);
144 vizCloud.pointSizeInPixels(params.pointSizeInPixels);
145
146 const PointContentType type = getPointCloudFormat(providerName)->type;
147 std::optional<PointCloudToArViz::OriginInfo> originInfo;
148
150 {
151 pcl::PointCloud<pcl::PointXYZRGBL>::Ptr inputCloud(
152 new pcl::PointCloud<pcl::PointXYZRGBL>);
153 getPointClouds(providerName, inputCloud);
154 originInfo = applyCustomTransform(*inputCloud);
155 vizCloud.pointCloud(*inputCloud, params.labeled);
156 }
157 else
158 {
159 pcl::PointCloud<pcl::PointXYZRGBA>::Ptr inputCloud(
160 new pcl::PointCloud<pcl::PointXYZRGBA>);
161 getPointClouds(providerName, inputCloud);
162 originInfo = applyCustomTransform(*inputCloud);
163 vizCloud.pointCloud(*inputCloud);
164 }
165
166 armarx::viz::Layer layer = arviz.layer(providerName);
167 if (params.alsoVisualizeNode && originInfo.has_value())
168 {
169 auto originPose = armarx::viz::Pose(originInfo->name);
170 originPose.pose(originInfo->pose);
171 originPose.scale(3);
172 layer.add(originPose);
173 }
174
175 layer.add(vizCloud);
176 arviz.commit({layer});
177 }
178 else
179 {
180 ARMARX_VERBOSE << "Timeout waiting for point cloud provider " << providerName
181 << ".";
182 }
183 }
184 }
185
186 void
187 PointCloudToArViz::setPointSizeInPixels(float pointSizeInPixels, const Ice::Current&)
188 {
189 std::scoped_lock lock(paramMutex);
190 params.pointSizeInPixels = pointSizeInPixels;
191 }
192
193 void
194 PointCloudToArViz::setCustomTransform(const armarx::PoseBasePtr& transformPtr,
195 const Ice::Current&)
196 {
197 return;
198
199 // std::scoped_lock lock(paramMutex);
200 // params.customTransform = armarx::PosePtr::dynamicCast(transformPtr)->toEigen();
201 // if (params.customTransform->isIdentity())
202 // {
203 // params.customTransform = std::nullopt;
204 // }
205 }
206
207 template <class PointT>
208 std::optional<PointCloudToArViz::OriginInfo>
209 PointCloudToArViz::applyCustomTransform(pcl::PointCloud<PointT>& pointCloud)
210 {
211 ARMARX_CHECK_NOT_NULL(virtualRobotReaderPlugin);
212 if (not virtualRobotReaderPlugin->isAvailable())
213 {
215 << "The robot reader plugin is deactivated. Won't transform point cloud";
216 return std::nullopt;
217 }
218
220 {
221 std::scoped_lock lock(robotMutex);
222 ARMARX_CHECK(virtualRobotReaderPlugin->get().synchronizeRobot(
223 *robot, armarx::core::time::Duration::MicroSeconds(pointCloud.header.stamp)));
224 }
225
226 const auto pointCloudNodeName = [&]() -> std::string
227 {
228 // highest prio: use frame id of point cloud.
229 if (not pointCloud.header.frame_id.empty())
230 {
231 return pointCloud.header.frame_id;
232 }
233
234 // check if fallback solution is available
236 << deactivateSpam(100)
237 << "The point cloud header does not provide a frame_id. Using property instead";
238
239 ARMARX_CHECK_NOT_EMPTY(params.pointCloudNodeName)
240 << "The `pointCloudNodeName` property must be provided as the point cloud "
241 "header "
242 "frame id is not set!";
243
244 return params.pointCloudNodeName;
245 }();
246
247 if (not robot)
248 {
250 << "The robot is not available. Won't transform point cloud";
251 return std::nullopt;
252 }
253
254 Eigen::Matrix4f globalSensorPose = Eigen::Matrix4f::Identity();
255 if (pointCloudNodeName != armarx::GlobalFrame)
256 {
257 {
258 std::scoped_lock lock(robotMutex);
260 const auto node = robot->getRobotNode(pointCloudNodeName);
262 << "No robot node with name `" << pointCloudNodeName << "`";
263 globalSensorPose = node->getGlobalPose();
264 }
265
266 pcl::transformPointCloud(pointCloud, pointCloud, globalSensorPose);
267 }
268 else if (not localTransformationNodeName.empty())
269 {
271 << "Local transformation node cannot be set as point cloud is in global "
272 "frame already";
273 }
274
275 pointCloud.header.frame_id = armarx::GlobalFrame;
276
277 return OriginInfo{.name = pointCloudNodeName, .pose = globalSensorPose};
278 }
279
280 void
282 {
283 using namespace armarx::RemoteGui::Client;
284
285 GridLayout grid;
286 int row = 0;
287
288 tab.checkFinite.setName("Check Finite");
289 tab.checkFinite.setValue(params.checkFinite);
290
291 tab.pointSizeInPixels.setName("Point Size [pixels]");
292 tab.pointSizeInPixels.setDecimals(2);
293 tab.pointSizeInPixels.setRange(0, 100);
294 tab.pointSizeInPixels.setSteps(100);
295 tab.pointSizeInPixels.setValue(params.pointSizeInPixels);
296
297 tab.labeled.setName("Color by Labels");
298 tab.labeled.setValue(params.labeled);
299
300 grid.add(Label(tab.checkFinite.getName()), {row, 0}).add(tab.checkFinite, {row, 1});
301 row++;
302 grid.add(Label(tab.pointSizeInPixels.getName()), {row, 0})
303 .add(tab.pointSizeInPixels, {row, 1});
304 row++;
305 grid.add(Label(tab.labeled.getName()), {row, 0}).add(tab.labeled, {row, 1});
306 row++;
307
308 tab.localTransformationNode = ComboBox();
309 tab.localTransformationNode.addOption("");
310 for (const std::string& nodeName : robot->getRobotNodeNames())
311 {
312 tab.localTransformationNode.addOption(nodeName);
313 }
314 grid.add(Label("Local node: "), {row, 0}).add(tab.localTransformationNode, {row, 1});
315 row++;
316
317 auto createFloatSpinBox = [&](float min, float max, float value)
318 {
319 auto spinBox = FloatSpinBox();
320 spinBox.setRange(min, max);
321 spinBox.setValue(value);
322 tab.transfSpinBoxes.push_back(spinBox);
323 return spinBox;
324 };
325
326 int col = 0;
327 grid.add(Label("Transformation: "), {row, col++})
328 .add(Label("x"), {row, col++})
329 .add(createFloatSpinBox(-5000, 5000, 0), {row, col++})
330 .add(Label("y"), {row, col++})
331 .add(createFloatSpinBox(-5000, 5000, 0), {row, col++})
332 .add(Label("z"), {row, col++})
333 .add(createFloatSpinBox(-5000, 5000, 0), {row, col++})
334 .add(Label("roll"), {row, col++})
335 .add(createFloatSpinBox(-M_PI, M_PI, 0), {row, col++})
336 .add(Label("pitch"), {row, col++})
337 .add(createFloatSpinBox(-M_PI, M_PI, 0), {row, col++})
338 .add(Label("yaw"), {row, col++})
339 .add(createFloatSpinBox(-M_PI, M_PI, 0), {row, col++});
340 row++;
341
342 VBoxLayout root = {grid, VSpacer()};
343 RemoteGui_createTab(getName(), root, &tab);
344 }
345
346 void
348 {
349 std::scoped_lock lock(paramMutex);
350 if (tab.checkFinite.hasValueChanged())
351 {
352 params.checkFinite = tab.checkFinite.getValue();
353 }
354 if (tab.pointSizeInPixels.hasValueChanged())
355 {
356 params.pointSizeInPixels = tab.pointSizeInPixels.getValue();
357 }
358 if (tab.labeled.hasValueChanged())
359 {
360 params.labeled = tab.labeled.getValue();
361 }
362
363 if (tab.localTransformationNode.hasValueChanged())
364 {
365 localTransformationNodeName = tab.localTransformationNode.getValue();
366
367 if (not localTransformationNodeName.empty())
368 {
369 const auto localTransf =
370 robot->getRobotNode(localTransformationNodeName)->getLocalTransformation();
371 const Eigen::Vector3f pos = simox::math::mat4f_to_pos(localTransf);
372 const Eigen::Vector3f rpy = simox::math::mat4f_to_rpy(localTransf);
373
374 for (unsigned int i = 0; i < 3; i++)
375 {
376 tab.transfSpinBoxes.at(i).setValue(pos[i]);
377 }
378 for (unsigned int i = 0; i < 3; i++)
379 {
380 tab.transfSpinBoxes.at(i + 3).setValue(rpy[i]);
381 }
382 }
383 }
384
385 bool update = false;
386 for (auto& spinBox : tab.transfSpinBoxes)
387 {
388 if (spinBox.hasValueChanged())
389 {
390 update = true;
391 }
392 }
393 if (update)
394 {
395 {
396 std::scoped_lock lock(robotMutex);
397
398 auto localTransformation =
399 simox::math::pos_rpy_to_mat4f(tab.transfSpinBoxes.at(0).getValue(),
400 tab.transfSpinBoxes.at(1).getValue(),
401 tab.transfSpinBoxes.at(2).getValue(),
402 tab.transfSpinBoxes.at(3).getValue(),
403 tab.transfSpinBoxes.at(4).getValue(),
404 tab.transfSpinBoxes.at(5).getValue());
405
406 robot->getRobotNode(localTransformationNodeName)
407 ->setLocalTransformation(localTransformation);
408 robot->updatePose();
409
410 ARMARX_INFO << "Updating localTransformation of " +
411 tab.localTransformationNode.getName() + " to "
412 << localTransformation.matrix();
413 }
414 }
415 }
416
417
418} // namespace visionx
int Label(int n[], int size, int *curLabel, MiscLib::Vector< std::pair< int, size_t > > *labels)
Definition Bitmap.cpp:801
#define ARMARX_CHECK_NOT_EMPTY(c)
#define M_PI
Definition MathTools.h:17
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
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
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
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 synchronizeRobot(VirtualRobot::Robot &robot, const armem::Time &timestamp) const
Synchronize both the platform pose and the joint values of a virtual robot, according to the robot st...
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
Definition Duration.cpp:24
PointCloud & pointSizeInPixels(float s)
Definition PointCloud.h:53
PointCloud & pointCloud(const PointCloudT &cloud)
Draw a point cloud.
Definition PointCloud.h:206
PointCloud & checkFinite(bool enabled=true)
Enable or disable checking whether points are finite when adding them (disabled by default).
Definition PointCloud.h:38
int getPointClouds(const PointCloudPtrT &pointCloudPtr)
Poll PointClouds from provider.
MetaPointCloudFormatPtr getPointCloudFormat(std::string providerName)
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
std::vector< std::string > getPointCloudProviderNames() const
Get the names of providers for which usingPointCloudProvider() has been called.
Property definitions of PointCloudToArViz.
virtual void setPointSizeInPixels(float pointSizeInPixels, const Ice::Current &=Ice::emptyCurrent) override
virtual void setCustomTransform(const armarx::PoseBasePtr &transform, const Ice::Current &=Ice::emptyCurrent) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void onExitPointCloudProcessor() override
void onConnectPointCloudProcessor() override
void onDisconnectPointCloudProcessor() override
void onInitPointCloudProcessor() override
std::string getDefaultName() const override
T min(T t1, T t2)
Definition gdiam.h:44
T max(T t1, T t2)
Definition gdiam.h:51
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#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
std::string const GlobalFrame
Variable of the global coordinate system.
Definition FramedPose.h:65
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
bool isLabeled(PointContentType type)
ArmarX headers.
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
GridLayout & add(Widget const &child, Pos pos, Span span=Span{1, 1})
Definition Widgets.cpp:438
void setName(std::string const &name)
Definition Widgets.cpp:19
void add(ElementT const &element)
Definition Layer.h:31