moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
setup_assistant_widget.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2012, Willow Garage, Inc.
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 * * Neither the name of Willow Garage nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34
35/* Author: Dave Coleman */
36
37// SA
39
40// Qt
41#include <QApplication>
42#include <QCloseEvent>
43#include <QHBoxLayout>
44#include <QMessageBox>
45#include <QPushButton>
46#include <QSplitter>
47#include <QStackedWidget>
48#include <QString>
49#include <pluginlib/class_loader.hpp> // for loading all avail kinematic planners
50
51namespace moveit_setup
52{
53namespace assistant
54{
55// ******************************************************************************************
56// Outer User Interface for MoveIt Configuration Assistant
57// ******************************************************************************************
58SetupAssistantWidget::SetupAssistantWidget(const rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr& node,
59 QWidget* parent, const boost::program_options::variables_map& args)
60 : QWidget(parent)
61 , node_abstraction_(node)
62 , node_(node_abstraction_.lock()->get_raw_node())
63 , widget_loader_("moveit_setup_framework", "moveit_setup::SetupStepWidget")
64{
65 // Create object to hold all MoveIt configuration data
66 config_data_ = std::make_shared<DataWarehouse>(node_);
67
68 // Set debug mode flag if necessary
69 if (args.count("debug"))
70 config_data_->debug = true;
71
72 // Setting the window icon
73 auto icon_path = getSharePath("moveit_ros_visualization") / "icons/classes/MotionPlanning.png";
74 setWindowIcon(QIcon(icon_path.c_str()));
75
76 // Basic widget container -----------------------------------------
77 QHBoxLayout* layout = new QHBoxLayout();
78 layout->setAlignment(Qt::AlignTop);
79
80 // Create main content stack for various screens
81 main_content_ = new QStackedWidget();
82 current_index_ = -1;
83
84 // Setup Steps --------------------------------------------------------
85 std::vector<std::string> setup_steps;
86 // TODO: The list of setup steps should be read from a parameter with some as the default
87 // TODO: (or be configured dynamically in some other step)
88 setup_steps.push_back("moveit_setup::core::StartScreenWidget");
89 setup_steps.push_back("moveit_setup::srdf_setup::DefaultCollisionsWidget");
90 setup_steps.push_back("moveit_setup::srdf_setup::VirtualJointsWidget");
91 setup_steps.push_back("moveit_setup::srdf_setup::PlanningGroupsWidget");
92 setup_steps.push_back("moveit_setup::srdf_setup::RobotPosesWidget");
93 setup_steps.push_back("moveit_setup::srdf_setup::EndEffectorsWidget");
94 setup_steps.push_back("moveit_setup::srdf_setup::PassiveJointsWidget");
95 setup_steps.push_back("moveit_setup::controllers::UrdfModificationsWidget");
96 setup_steps.push_back("moveit_setup::controllers::ROS2ControllersWidget");
97 setup_steps.push_back("moveit_setup::controllers::MoveItControllersWidget");
98 // setup_steps.push_back("moveit_setup::simulation::SimulationWidget");
99 setup_steps.push_back("moveit_setup::app::PerceptionWidget");
100 setup_steps.push_back("moveit_setup::app::LaunchesWidget");
101 setup_steps.push_back("moveit_setup::core::AuthorInformationWidget");
102 setup_steps.push_back("moveit_setup::core::ConfigurationFilesWidget");
103 node_->declare_parameter("setup_steps", setup_steps);
104 setup_steps = node_->get_parameter("setup_steps").as_string_array();
105
106 // Rviz View Right Pane ---------------------------------------------------
107 rviz_panel_ = new RVizPanel(this, node_abstraction_, config_data_);
108 rviz_panel_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
109 rviz_panel_->hide(); // do not show until after the start screen
110
111 for (const std::string& step_class : setup_steps)
112 {
113 auto widget = widget_loader_.createSharedInstance(step_class);
114 widget->initialize(node_, this, rviz_panel_, config_data_);
115
116 connect(widget.get(), SIGNAL(dataUpdated()), this, SLOT(onDataUpdate()));
117 connect(widget.get(), SIGNAL(advanceRequest()), this, SLOT(onAdvanceRequest()));
118 connect(widget.get(), SIGNAL(setModalMode(bool)), this, SLOT(onModalModeUpdate(bool)));
119 const std::string name = widget->getSetupStep().getName();
120 steps_.push_back(widget);
121
122 main_content_->addWidget(widget.get());
123
124 nav_name_list_ << name.c_str();
125 }
126
127 // Pass command arg values to start screen and show appropriate part of screen
128 if (args.count("urdf_path"))
129 {
130 config_data_->preloadWithURDFPath(args["urdf_path"].as<std::filesystem::path>());
131 }
132 if (args.count("config_pkg"))
133 {
134 config_data_->preloadWithFullConfig(args["config_pkg"].as<std::string>());
135 }
136
137 // Navigation Left Pane --------------------------------------------------
138 navs_view_ = new NavigationWidget(this);
139 navs_view_->setNavs(nav_name_list_);
140 if (!steps_.empty())
141 {
142 navs_view_->setEnabled(0, true);
143 moveToScreen(0);
144 }
145
146 // Split screen -----------------------------------------------------
147 splitter_ = new QSplitter(Qt::Horizontal, this);
148 splitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
149 splitter_->addWidget(navs_view_);
150 splitter_->addWidget(main_content_);
151 splitter_->addWidget(rviz_panel_);
152 splitter_->setHandleWidth(6);
153 // splitter_->setCollapsible( 0, false ); // don't let navigation collapse
154 layout->addWidget(splitter_);
155
156 // Add event for switching between screens -------------------------
157 connect(navs_view_, SIGNAL(clicked(const QModelIndex&)), this, SLOT(navigationClicked(const QModelIndex&)));
158
159 // Final Layout Setup ---------------------------------------------
160 setLayout(layout);
161
162 // Title
163 setWindowTitle("MoveIt Setup Assistant"); // title of window
164
165 // Show screen before message
166 QApplication::processEvents();
167}
168
169// ******************************************************************************************
170// Change screens of Setup Assistant
171// ******************************************************************************************
172void SetupAssistantWidget::navigationClicked(const QModelIndex& index)
173{
174 // Convert QModelIndex to int
175 moveToScreen(index.row());
176}
177
178void SetupAssistantWidget::onDataUpdate()
179{
180 for (size_t index = 0; index < steps_.size(); index++)
181 {
182 bool ready = steps_[index]->isReady();
183 navs_view_->setEnabled(index, ready);
184 }
185
186 if (rviz_panel_->isReadyForInitialization())
187 {
188 rviz_panel_->initialize();
189 // Replace logo with Rviz screen
190 rviz_panel_->show();
191 }
192}
193
194void SetupAssistantWidget::onAdvanceRequest()
195{
196 if (static_cast<unsigned int>(current_index_ + 1) < steps_.size())
197 {
198 moveToScreen(current_index_ + 1);
199 }
200}
201
202// ******************************************************************************************
203// Change screens
204// ******************************************************************************************
206{
207 std::scoped_lock slock(change_screen_lock_);
208 if (!navs_view_->isEnabled(index))
209 {
210 return;
211 }
212
213 if (current_index_ != index)
214 {
215 // Send the focus lost command to the screen widget
216 if (current_index_ >= 0)
217 {
218 auto ssw = steps_[current_index_];
219 if (!ssw->focusLost())
220 {
221 navs_view_->setSelected(current_index_);
222 return; // switching not accepted
223 }
224 }
225
226 current_index_ = index;
227
228 // Unhighlight anything on robot
229 rviz_panel_->unhighlightAll();
230
231 // Change screens
232 main_content_->setCurrentIndex(index);
233
234 // Send the focus given command to the screen widget
235 steps_[current_index_]->focusGiven();
236
237 // Change navigation selected option
238 navs_view_->setSelected(index);
239 }
240}
241
242// ******************************************************************************************
243// Ping ROS on interval
244// ******************************************************************************************
245void SetupAssistantWidget::updateTimer()
246{
247 // TODO: Figure out if there's a ROS 2 equivalent of this that needs to be run
248 // ros::spinOnce(); // keep ROS node alive
249}
250
251// ******************************************************************************************
252// Qt close event function for reminding user to save
253// ******************************************************************************************
254void SetupAssistantWidget::closeEvent(QCloseEvent* event)
255{
256 // Only prompt to close if not in debug mode
257 if (!config_data_->debug)
258 {
259 if (QMessageBox::question(this, "Exit Setup Assistant",
260 QString("Are you sure you want to exit the MoveIt Setup Assistant?"),
261 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
262 {
263 event->ignore();
264 return;
265 }
266 }
267
268 // Shutdown app
269 event->accept();
270}
271
272// ******************************************************************************************
273// Qt Error Handling - TODO
274// ******************************************************************************************
275bool SetupAssistantWidget::notify(QObject* /*receiver*/, QEvent* /*event*/)
276{
277 QMessageBox::critical(this, "Error", "An error occurred and was caught by Qt notify event handler.", QMessageBox::Ok);
278
279 return false;
280}
281
282// ******************************************************************************************
283// Change the widget modal state based on subwidgets state
284// ******************************************************************************************
285void SetupAssistantWidget::onModalModeUpdate(bool isModal)
286{
287 navs_view_->setDisabled(isModal);
288
289 for (int i = 0; i < nav_name_list_.count(); ++i)
290 {
291 navs_view_->setEnabled(i, !isModal && steps_[i]->isReady());
292 }
293}
294
295} // namespace assistant
296} // namespace moveit_setup
bool isReadyForInitialization() const
void setNavs(const QList< QString > &navs)
SetupAssistantWidget(const rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr &node, QWidget *parent, const boost::program_options::variables_map &args)
virtual bool notify(QObject *rec, QEvent *ev)
std::filesystem::path getSharePath(const std::string &package_name)
Return a path for the given package's share folder.
Definition utilities.hpp:51