moveit2
The MoveIt Motion Planning Framework for ROS 2.
perception_widget.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2018, Mohamad Ayman.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * The name of Mohamad Ayman may not be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *********************************************************************/
33 
34 /* Author: Mohamad Ayman */
35 
36 // SA
39 
40 // Qt
41 #include <QApplication>
42 #include <QComboBox>
43 #include <QFormLayout>
44 #include <QGroupBox>
45 #include <QLabel>
46 #include <QLineEdit>
47 #include <QVBoxLayout>
48 
49 namespace moveit_setup
50 {
51 namespace app
52 {
54 {
55  // Basic widget container
56  QVBoxLayout* layout = new QVBoxLayout();
57  layout->setAlignment(Qt::AlignTop);
58 
59  // Top Header Area ------------------------------------------------
60 
61  auto header = new HeaderWidget(
62  "Setup 3D Perception Sensors",
63  "Configure your 3D sensors to work with MoveIt. Please see <a "
64  "href='https://moveit.picknik.ai/galactic/doc/examples/perception_pipeline/perception_pipeline_tutorial.html"
65  "'>Perception Documentation</a> for more details.",
66  this);
67  layout->addWidget(header);
68 
69  // Add spacing
70  QSpacerItem* blank_space = new QSpacerItem(1, 8);
71  layout->addSpacerItem(blank_space);
72 
73  // Plugin type combo box
74  QLabel* plugin_field_title = new QLabel(this);
75  plugin_field_title->setText("Optionally choose a type of 3D sensor plugin to configure:");
76  layout->addWidget(plugin_field_title);
77 
78  sensor_plugin_field_ = new QComboBox(this);
79  sensor_plugin_field_->setEditable(false);
80  sensor_plugin_field_->setMaximumWidth(600);
81  connect(sensor_plugin_field_, SIGNAL(currentIndexChanged(int)), this, SLOT(sensorPluginChanged(int)));
82  layout->addWidget(sensor_plugin_field_);
83 
84  // Point Cloud group -------------------------------------------
85  point_cloud_group_ = new QGroupBox("Point Cloud");
86 
87  QFormLayout* point_cloud_form_layout = new QFormLayout();
88  point_cloud_form_layout->setContentsMargins(0, 15, 0, 15);
89 
90  // Point Cloud Topic
91  point_cloud_topic_field_ = new QLineEdit(this);
92  point_cloud_topic_field_->setMaximumWidth(400);
93  point_cloud_form_layout->addRow("Point Cloud Topic:", point_cloud_topic_field_);
94 
95  // Max Range
96  max_range_field_ = new QLineEdit(this);
97  max_range_field_->setMaximumWidth(400);
98  max_range_field_->setValidator(new QDoubleValidator(this));
99  point_cloud_form_layout->addRow("Max Range:", max_range_field_);
100 
101  // Point Subsample
102  point_subsample_field_ = new QLineEdit(this);
103  point_subsample_field_->setMaximumWidth(400);
104  point_subsample_field_->setValidator(new QIntValidator(this));
105  point_cloud_form_layout->addRow("Point Subsample:", point_subsample_field_);
106 
107  // Padding Offset
108  padding_offset_field_ = new QLineEdit(this);
109  padding_offset_field_->setMaximumWidth(400);
110  padding_offset_field_->setValidator(new QDoubleValidator(this));
111  point_cloud_form_layout->addRow("Padding Offset:", padding_offset_field_);
112 
113  // Padding Scale
114  padding_scale_field_ = new QLineEdit(this);
115  padding_scale_field_->setMaximumWidth(400);
116  padding_scale_field_->setValidator(new QDoubleValidator(this));
117  point_cloud_form_layout->addRow("Padding Scale:", padding_scale_field_);
118 
119  // Filtered Cloud Topic
120  filtered_cloud_topic_field_ = new QLineEdit(this);
121  filtered_cloud_topic_field_->setMaximumWidth(400);
122  point_cloud_form_layout->addRow("Filtered Cloud Topic:", filtered_cloud_topic_field_);
123 
124  // Max Update Rate
125  max_update_rate_field_ = new QLineEdit(this);
126  max_update_rate_field_->setMaximumWidth(400);
127  max_update_rate_field_->setValidator(new QDoubleValidator(this));
128  point_cloud_form_layout->addRow("Max Update Rate:", max_update_rate_field_);
129 
130  // Point Cloud form layout
131  point_cloud_group_->setLayout(point_cloud_form_layout);
132  layout->addWidget(point_cloud_group_);
133 
134  // Depth map group --------------------------------------------
135  depth_map_group_ = new QGroupBox("Depth Map");
136 
137  // Depth Map form layout
138  QFormLayout* depth_map_form_layout = new QFormLayout();
139  depth_map_form_layout->setContentsMargins(0, 15, 0, 15);
140 
141  // Image Topic
142  image_topic_field_ = new QLineEdit(this);
143  image_topic_field_->setMaximumWidth(400);
144  depth_map_form_layout->addRow("Image Topic:", image_topic_field_);
145 
146  // Queue Size
147  queue_size_field_ = new QLineEdit(this);
148  queue_size_field_->setMaximumWidth(400);
149  queue_size_field_->setValidator(new QIntValidator(this));
150  depth_map_form_layout->addRow("Queue Size:", queue_size_field_);
151 
152  // Near Clipping Plane Distance
153  near_clipping_field_ = new QLineEdit(this);
154  near_clipping_field_->setMaximumWidth(400);
155  near_clipping_field_->setValidator(new QDoubleValidator(this));
156  depth_map_form_layout->addRow("Near Clipping Plane Distance:", near_clipping_field_);
157 
158  // Far Clipping Plane Distance
159  far_clipping_field_ = new QLineEdit(this);
160  far_clipping_field_->setMaximumWidth(400);
161  far_clipping_field_->setValidator(new QDoubleValidator(this));
162  depth_map_form_layout->addRow("Far Clipping Plane Distance:", far_clipping_field_);
163 
164  // Shadow Threshold
165  shadow_threshold_field_ = new QLineEdit(this);
166  shadow_threshold_field_->setMaximumWidth(400);
167  shadow_threshold_field_->setValidator(new QDoubleValidator(this));
168  depth_map_form_layout->addRow("Shadow Threshold:", shadow_threshold_field_);
169 
170  // Padding Offset
171  depth_padding_offset_field_ = new QLineEdit(this);
172  depth_padding_offset_field_->setMaximumWidth(400);
173  depth_padding_offset_field_->setValidator(new QDoubleValidator(this));
174  depth_map_form_layout->addRow("Padding Offset:", depth_padding_offset_field_);
175 
176  // Padding Scale
177  depth_padding_scale_field_ = new QLineEdit(this);
178  depth_padding_scale_field_->setMaximumWidth(400);
179  depth_padding_scale_field_->setValidator(new QDoubleValidator(this));
180  depth_map_form_layout->addRow("Padding Scale:", depth_padding_scale_field_);
181 
182  // Filtered Cloud Topic
183  depth_filtered_cloud_topic_field_ = new QLineEdit(this);
184  depth_filtered_cloud_topic_field_->setMaximumWidth(400);
185  depth_map_form_layout->addRow("Filtered Cloud Topic:", depth_filtered_cloud_topic_field_);
186 
187  // Filtered Cloud Topic
188  depth_max_update_rate_field_ = new QLineEdit(this);
189  depth_max_update_rate_field_->setMaximumWidth(400);
190  depth_max_update_rate_field_->setValidator(new QDoubleValidator(this));
191  depth_map_form_layout->addRow("Max Update Rate:", depth_max_update_rate_field_);
192 
193  depth_map_group_->setLayout(depth_map_form_layout);
194  layout->addWidget(depth_map_group_);
195 
196  layout->setAlignment(Qt::AlignTop);
197 
198  // Finish Layout --------------------------------------------------
199  this->setLayout(layout);
200 }
201 
202 // ******************************************************************************************
203 // Received when this widget is chosen from the navigation menu
204 // ******************************************************************************************
206 {
208 }
209 
210 // ******************************************************************************************
211 // Received when another widget is chosen from the navigation menu
212 // ******************************************************************************************
214 {
215  // Save the sensor plugin configuration to sensors_plugin_config data structure
216  if (sensor_plugin_field_->currentIndex() == 1)
217  {
218  // Point Cloud plugin fields
219  SensorParameters params;
220  params["sensor_plugin"] = "occupancy_map_monitor/PointCloudOctomapUpdater";
221  params["point_cloud_topic"] = point_cloud_topic_field_->text().trimmed().toStdString();
222  params["max_range"] = max_range_field_->text().trimmed().toStdString();
223  params["point_subsample"] = point_subsample_field_->text().trimmed().toStdString();
224  params["padding_offset"] = padding_offset_field_->text().trimmed().toStdString();
225  params["padding_scale"] = padding_scale_field_->text().trimmed().toStdString();
226  params["max_update_rate"] = max_update_rate_field_->text().trimmed().toStdString();
227  params["filtered_cloud_topic"] = filtered_cloud_topic_field_->text().trimmed().toStdString();
228 
229  setup_step_.setConfig(params);
230  }
231  else if (sensor_plugin_field_->currentIndex() == 2)
232  {
233  // Depth Map plugin fields
234  SensorParameters params;
235  params["sensor_plugin"] = "occupancy_map_monitor/DepthImageOctomapUpdater";
236  params["image_topic"] = image_topic_field_->text().trimmed().toStdString();
237  params["queue_size"] = queue_size_field_->text().trimmed().toStdString();
238  params["near_clipping_plane_distance"] = near_clipping_field_->text().trimmed().toStdString();
239  params["far_clipping_plane_distance"] = far_clipping_field_->text().trimmed().toStdString();
240  params["shadow_threshold"] = shadow_threshold_field_->text().trimmed().toStdString();
241  params["padding_scale"] = depth_padding_scale_field_->text().trimmed().toStdString();
242  params["padding_offset"] = depth_padding_offset_field_->text().trimmed().toStdString();
243  params["filtered_cloud_topic"] = depth_filtered_cloud_topic_field_->text().trimmed().toStdString();
244  params["max_update_rate"] = depth_max_update_rate_field_->text().trimmed().toStdString();
245 
246  setup_step_.setConfig(params);
247  }
248  else
249  {
250  // Clear the sensors_plugin_config data structure
251  setup_step_.clearSensorPluginConfig();
252  }
253  return true;
254 }
255 
256 void PerceptionWidget::sensorPluginChanged(int index)
257 {
258  if (index == 1)
259  {
260  // Point cloud form visible, depth map form invisible
261  point_cloud_group_->setVisible(true);
262  depth_map_group_->setVisible(false);
263  }
264  else if (index == 2)
265  {
266  // Depth map form visible, point cloud form invisible
267  point_cloud_group_->setVisible(false);
268  depth_map_group_->setVisible(true);
269  }
270  else
271  {
272  // All forms invisible
273  point_cloud_group_->setVisible(false);
274  depth_map_group_->setVisible(false);
275  }
276 }
277 
279 {
280  // Only load this combo box once
281  static bool has_loaded = false;
282  if (has_loaded)
283  return;
284  has_loaded = true;
285 
286  // Add None option, the default
287  sensor_plugin_field_->addItem("None");
288  sensor_plugin_field_->setCurrentIndex(0);
289 
290  // Add the two available plugins to combo box
291  sensor_plugin_field_->addItem("Point Cloud");
292  sensor_plugin_field_->addItem("Depth Map");
293 
294  const auto& sensors_vec_map = setup_step_.getSensorPluginConfig();
295  for (auto& sensor_plugin_config : sensors_vec_map)
296  {
297  if (sensor_plugin_config.at("sensor_plugin") == std::string("occupancy_map_monitor/PointCloudOctomapUpdater"))
298  {
299  sensor_plugin_field_->setCurrentIndex(1);
300  point_cloud_topic_field_->setText(QString(sensor_plugin_config.at("point_cloud_topic").c_str()));
301  max_range_field_->setText(QString(sensor_plugin_config.at("max_range").c_str()));
302  point_subsample_field_->setText(QString(sensor_plugin_config.at("point_subsample").c_str()));
303  padding_offset_field_->setText(QString(sensor_plugin_config.at("padding_offset").c_str()));
304  padding_scale_field_->setText(QString(sensor_plugin_config.at("padding_scale").c_str()));
305  max_update_rate_field_->setText(QString(sensor_plugin_config.at("max_update_rate").c_str()));
306  filtered_cloud_topic_field_->setText(QString(sensor_plugin_config.at("filtered_cloud_topic").c_str()));
307  }
308  else if (sensor_plugin_config.at("sensor_plugin") == std::string("occupancy_map_monitor/DepthImageOctomapUpdater"))
309  {
310  sensor_plugin_field_->setCurrentIndex(2);
311  image_topic_field_->setText(QString(sensor_plugin_config.at("image_topic").c_str()));
312  queue_size_field_->setText(QString(sensor_plugin_config.at("queue_size").c_str()));
313  near_clipping_field_->setText(QString(sensor_plugin_config.at("near_clipping_plane_distance").c_str()));
314  far_clipping_field_->setText(QString(sensor_plugin_config.at("far_clipping_plane_distance").c_str()));
315  shadow_threshold_field_->setText(QString(sensor_plugin_config.at("shadow_threshold").c_str()));
316  depth_padding_scale_field_->setText(QString(sensor_plugin_config.at("padding_scale").c_str()));
317  depth_padding_offset_field_->setText(QString(sensor_plugin_config.at("padding_offset").c_str()));
318  depth_filtered_cloud_topic_field_->setText(QString(sensor_plugin_config.at("filtered_cloud_topic").c_str()));
319  depth_max_update_rate_field_->setText(QString(sensor_plugin_config.at("max_update_rate").c_str()));
320  }
321  }
322 }
323 
324 } // namespace app
325 } // namespace moveit_setup
326 
327 #include <pluginlib/class_list_macros.hpp> // NOLINT
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
The GUI code for one SetupStep.
void loadSensorPluginsComboBox()
Populate the combo dropdown box with sensor plugins.
void focusGiven() override
Received when this widget is chosen from the navigation menu.
bool focusLost() override
Received when another widget is chosen from the navigation menu.
void clearSensorPluginConfig()
Clear the sensor plugin configuration parameter list.
Definition: perception.hpp:68
void setConfig(const SensorParameters &parameters)
Definition: perception.hpp:73
const std::vector< SensorParameters > & getSensorPluginConfig()
Definition: perception.hpp:60
std::map< std::string, std::string > SensorParameters