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
26
27#include <pcl/common/transforms.h>
28#include <pcl/impl/point_types.hpp>
29#include <pcl/point_types.h>
30
31#include <SimoxUtility/math/convert/mat4f_to_pos.h>
32#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
33#include <SimoxUtility/math/convert/pos_rpy_to_mat4f.h>
34
38
42
43namespace visionx
44{
45
48 {
50 "ProviderWaitMs", 100, "Time to wait for each point cloud provider [ms].");
51 }
52
55 {
58
59 defs->optional(
60 params.pointSizeInPixels, "viz.pointSizeInPixels", "The point size in pixels.");
61 defs->optional(params.checkFinite,
62 "viz.checkFinite",
63 "Enable to check points for being finite. "
64 "\nEnable this option if the drawn point cloud causes the screen to become "
65 "purely white.");
66 defs->optional(params.labeled,
67 "viz.labeled",
68 "If true and point cloud is labeled, draw colors according to labels.");
69 defs->optional(params.alsoVisualizeNode,
70 "viz.showNode",
71 "If true also the node's coordinate systems is shown.");
72
73 defs->optional(params.robotName, "robotName", "");
74 defs->optional(
75 params.pointCloudNodeName,
76 "pointCloudNodeName",
77 " If the point cloud header does not provide a frame id, this info is used.");
78
79 return defs;
80 }
81
83 {
84 addPlugin(virtualRobotReaderPlugin);
85 }
86
87 std::string
89 {
90 return "PointCloudToArViz";
91 }
92
93 std::string
95 {
96 return GetDefaultName();
97 }
98
99 void
101 {
102 params.providerWaitTime =
103 IceUtil::Time::milliSeconds(getProperty<int>("ProviderWaitMs").getValue());
104 }
105
106 void
108 {
109 if (virtualRobotReaderPlugin->isAvailable())
110 {
111 robot = virtualRobotReaderPlugin->get().getRobot(params.robotName);
112 // No need to synchronize the robot here. We synchronize it later anyway.
113 }
114
117 }
118
119 void
123
124 void
128
129 void
131 {
132 // Fetch input clouds.
133 for (const std::string& providerName : getPointCloudProviderNames())
134 {
135 if (waitForPointClouds(providerName,
136 static_cast<int>(params.providerWaitTime.toMilliSeconds())))
137 {
138 auto it = cache.find(providerName);
139 if (it == cache.end())
140 {
141 it = cache.emplace(providerName, armarx::viz::PointCloud(providerName)).first;
142 }
143 armarx::viz::PointCloud& vizCloud = it->second;
144
145 Parameters params;
146 {
147 std::scoped_lock lock(paramMutex);
148 params = this->params;
149 }
150
151 vizCloud.checkFinite(params.checkFinite);
152 vizCloud.pointSizeInPixels(params.pointSizeInPixels);
153
154 const PointContentType type = getPointCloudFormat(providerName)->type;
155 std::optional<PointCloudToArViz::OriginInfo> originInfo;
156
158 {
159 pcl::PointCloud<pcl::PointXYZRGBL>::Ptr inputCloud(
160 new pcl::PointCloud<pcl::PointXYZRGBL>);
161 getPointClouds(providerName, inputCloud);
162 originInfo = applyCustomTransform(*inputCloud);
163 vizCloud.pointCloud(*inputCloud, params.labeled);
164 }
165 else
166 {
167 pcl::PointCloud<pcl::PointXYZRGBA>::Ptr inputCloud(
168 new pcl::PointCloud<pcl::PointXYZRGBA>);
169 getPointClouds(providerName, inputCloud);
170 originInfo = applyCustomTransform(*inputCloud);
171 vizCloud.pointCloud(*inputCloud);
172 }
173
174 armarx::viz::Layer layer = arviz.layer(providerName);
175 if (params.alsoVisualizeNode && originInfo.has_value())
176 {
177 auto originPose = armarx::viz::Pose(originInfo->name);
178 originPose.pose(originInfo->pose);
179 originPose.scale(3);
180 layer.add(originPose);
181 }
182
183 layer.add(vizCloud);
184 arviz.commit({layer});
185 }
186 else
187 {
188 ARMARX_VERBOSE << "Timeout waiting for point cloud provider " << providerName
189 << ".";
190 }
191 }
192 }
193
194 void
195 PointCloudToArViz::setPointSizeInPixels(float pointSizeInPixels, const Ice::Current&)
196 {
197 std::scoped_lock lock(paramMutex);
198 params.pointSizeInPixels = pointSizeInPixels;
199 }
200
201 void
202 PointCloudToArViz::setCustomTransform(const armarx::PoseBasePtr& transformPtr,
203 const Ice::Current&)
204 {
205 return;
206
207 // std::scoped_lock lock(paramMutex);
208 // params.customTransform = armarx::PosePtr::dynamicCast(transformPtr)->toEigen();
209 // if (params.customTransform->isIdentity())
210 // {
211 // params.customTransform = std::nullopt;
212 // }
213 }
214
215 template <class PointT>
216 std::optional<PointCloudToArViz::OriginInfo>
217 PointCloudToArViz::applyCustomTransform(pcl::PointCloud<PointT>& pointCloud)
218 {
219 ARMARX_CHECK_NOT_NULL(virtualRobotReaderPlugin);
220 if (not virtualRobotReaderPlugin->isAvailable())
221 {
223 << "The robot reader plugin is deactivated. Won't transform point cloud";
224 return std::nullopt;
225 }
226
228 {
229 std::scoped_lock lock(robotMutex);
230 ARMARX_CHECK(virtualRobotReaderPlugin->get().synchronizeRobot(
231 *robot, armarx::core::time::Duration::MicroSeconds(pointCloud.header.stamp)));
232 }
233
234 const auto pointCloudNodeName = [&]() -> std::string
235 {
236 // highest prio: use frame id of point cloud.
237 if (not pointCloud.header.frame_id.empty())
238 {
239 return pointCloud.header.frame_id;
240 }
241
242 // check if fallback solution is available
244 << deactivateSpam(100)
245 << "The point cloud header does not provide a frame_id. Using property instead";
246
247 ARMARX_CHECK_NOT_EMPTY(params.pointCloudNodeName)
248 << "The `pointCloudNodeName` property must be provided as the point cloud "
249 "header "
250 "frame id is not set!";
251
252 return params.pointCloudNodeName;
253 }();
254
255 if (not robot)
256 {
258 << "The robot is not available. Won't transform point cloud";
259 return std::nullopt;
260 }
261
262 Eigen::Matrix4f globalSensorPose = Eigen::Matrix4f::Identity();
263 if (pointCloudNodeName != armarx::GlobalFrame)
264 {
265 {
266 std::scoped_lock lock(robotMutex);
268 const auto node = robot->getRobotNode(pointCloudNodeName);
270 << "No robot node with name `" << pointCloudNodeName << "`";
271 globalSensorPose = node->getGlobalPose();
272 }
273
274 pcl::transformPointCloud(pointCloud, pointCloud, globalSensorPose);
275 }
276 else if (not localTransformationNodeName.empty())
277 {
279 << "Local transformation node cannot be set as point cloud is in global "
280 "frame already";
281 }
282
283 pointCloud.header.frame_id = armarx::GlobalFrame;
284
285 return OriginInfo{.name = pointCloudNodeName, .pose = globalSensorPose};
286 }
287
288 void
290 {
291 using namespace armarx::RemoteGui::Client;
292
293 GridLayout grid;
294 int row = 0;
295
296 tab.checkFinite.setName("Check Finite");
297 tab.checkFinite.setValue(params.checkFinite);
298
299 tab.pointSizeInPixels.setName("Point Size [pixels]");
300 tab.pointSizeInPixels.setDecimals(2);
301 tab.pointSizeInPixels.setRange(0, 100);
302 tab.pointSizeInPixels.setSteps(100);
303 tab.pointSizeInPixels.setValue(params.pointSizeInPixels);
304
305 tab.labeled.setName("Color by Labels");
306 tab.labeled.setValue(params.labeled);
307
308 grid.add(Label(tab.checkFinite.getName()), {row, 0}).add(tab.checkFinite, {row, 1});
309 row++;
310 grid.add(Label(tab.pointSizeInPixels.getName()), {row, 0})
311 .add(tab.pointSizeInPixels, {row, 1});
312 row++;
313 grid.add(Label(tab.labeled.getName()), {row, 0}).add(tab.labeled, {row, 1});
314 row++;
315
316 tab.localTransformationNode = ComboBox();
317 tab.localTransformationNode.addOption("");
318 for (const std::string& nodeName : robot->getRobotNodeNames())
319 {
320 tab.localTransformationNode.addOption(nodeName);
321 }
322 grid.add(Label("Local node: "), {row, 0}).add(tab.localTransformationNode, {row, 1});
323 row++;
324
325 auto createFloatSpinBox = [&](float min, float max, float value)
326 {
327 auto spinBox = FloatSpinBox();
328 spinBox.setRange(min, max);
329 spinBox.setValue(value);
330 if (max > 100)
331 {
332 spinBox.setSteps(max - min);
333 spinBox.setDecimals(1);
334 }
335 else
336 {
337 spinBox.setSteps((max - min) * 1000);
338 spinBox.setDecimals(4);
339 }
340 tab.transfSpinBoxes.push_back(spinBox);
341 return spinBox;
342 };
343
344 int col = 0;
345 grid.add(Label("Transformation: "), {row, col++})
346 .add(Label("x"), {row, col++})
347 .add(createFloatSpinBox(-5000, 5000, 0), {row, col++})
348 .add(Label("y"), {row, col++})
349 .add(createFloatSpinBox(-5000, 5000, 0), {row, col++})
350 .add(Label("z"), {row, col++})
351 .add(createFloatSpinBox(-5000, 5000, 0), {row, col++})
352 .add(Label("roll"), {row, col++})
353 .add(createFloatSpinBox(-M_PI, M_PI, 0), {row, col++})
354 .add(Label("pitch"), {row, col++})
355 .add(createFloatSpinBox(-M_PI, M_PI, 0), {row, col++})
356 .add(Label("yaw"), {row, col++})
357 .add(createFloatSpinBox(-M_PI, M_PI, 0), {row, col++});
358 row++;
359
360 VBoxLayout root = {grid, VSpacer()};
361 RemoteGui_createTab(getName(), root, &tab);
362 }
363
364 void
366 {
367 std::scoped_lock lock(paramMutex);
368 if (tab.checkFinite.hasValueChanged())
369 {
370 params.checkFinite = tab.checkFinite.getValue();
371 }
372 if (tab.pointSizeInPixels.hasValueChanged())
373 {
374 params.pointSizeInPixels = tab.pointSizeInPixels.getValue();
375 }
376 if (tab.labeled.hasValueChanged())
377 {
378 params.labeled = tab.labeled.getValue();
379 }
380
381 if (tab.localTransformationNode.hasValueChanged())
382 {
383 localTransformationNodeName = tab.localTransformationNode.getValue();
384
385 if (not localTransformationNodeName.empty())
386 {
387 const auto localTransf =
388 robot->getRobotNode(localTransformationNodeName)->getLocalTransformation();
389 const Eigen::Vector3f pos = simox::math::mat4f_to_pos(localTransf);
390 const Eigen::Vector3f rpy = simox::math::mat4f_to_rpy(localTransf);
391
392 for (unsigned int i = 0; i < 3; i++)
393 {
394 tab.transfSpinBoxes.at(i).setValue(pos[i]);
395 }
396 for (unsigned int i = 0; i < 3; i++)
397 {
398 tab.transfSpinBoxes.at(i + 3).setValue(rpy[i]);
399 }
400 }
401 }
402
403 bool update = false;
404 for (auto& spinBox : tab.transfSpinBoxes)
405 {
406 if (spinBox.hasValueChanged())
407 {
408 update = true;
409 }
410 }
411 if (update)
412 {
413 {
414 std::scoped_lock lock(robotMutex);
415
416 auto localTransformation =
417 simox::math::pos_rpy_to_mat4f(tab.transfSpinBoxes.at(0).getValue(),
418 tab.transfSpinBoxes.at(1).getValue(),
419 tab.transfSpinBoxes.at(2).getValue(),
420 tab.transfSpinBoxes.at(3).getValue(),
421 tab.transfSpinBoxes.at(4).getValue(),
422 tab.transfSpinBoxes.at(5).getValue());
423
424 robot->getRobotNode(localTransformationNodeName)
425 ->setLocalTransformation(localTransformation);
426 robot->updatePose();
427
428 ARMARX_INFO << "Updating localTransformation of " +
429 tab.localTransformationNode.getName() + " to "
430 << localTransformation.matrix();
431 }
432 }
433 }
434
435
436
438} // namespace visionx
int Label(int n[], int size, int *curLabel, MiscLib::Vector< std::pair< int, size_t > > *labels)
Definition Bitmap.cpp:801
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
#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.
Brief description of class 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
static std::string GetDefaultName()
void onInitPointCloudProcessor() override
std::string getDefaultName() const override
Retrieve default name of component.
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