moveit2
The MoveIt Motion Planning Framework for ROS 2.
simulation_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
40 
41 // Qt
42 #include <QColor>
43 #include <QLabel>
44 #include <QMessageBox>
45 #include <QPushButton>
46 #include <QTextEdit>
47 #include <QVBoxLayout>
48 #include <QProcess>
49 
51 #include <moveit_msgs/msg/display_robot_state.hpp>
52 
53 #include <regex>
54 
55 namespace moveit_setup
56 {
57 namespace simulation
58 {
59 // ******************************************************************************************
60 // Constructor
61 // ******************************************************************************************
63 {
64  // Basic widget container
65  QVBoxLayout* layout = new QVBoxLayout();
66  layout->setAlignment(Qt::AlignTop);
67 
68  // Top Header Area ------------------------------------------------
69 
70  auto header = new HeaderWidget("Simulate With Gazebo",
71  "The following tool will auto-generate the URDF changes needed for Gazebo "
72  "compatibility with ROSControl and MoveIt. The needed changes are shown in green.",
73  this);
74  layout->addWidget(header);
75  layout->addSpacerItem(new QSpacerItem(1, 8, QSizePolicy::Fixed, QSizePolicy::Fixed));
76 
77  // Top Buttons --------------------------------------------------
78  QHBoxLayout* controls_layout = new QHBoxLayout();
79 
80  // Used to overwrite the original URDF
81  btn_overwrite_ = new QPushButton("Over&write original URDF", this);
82  btn_overwrite_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
83  connect(btn_overwrite_, SIGNAL(clicked()), this, SLOT(overwriteURDF()));
84  controls_layout->addWidget(btn_overwrite_);
85 
86  btn_open_ = new QPushButton("&Open original URDF", this);
87  btn_open_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
88  btn_open_->setToolTip("Open original URDF file in editor");
89  connect(btn_open_, SIGNAL(clicked()), this, SLOT(openURDF()));
90  controls_layout->addWidget(btn_open_);
91 
92  // Align buttons to the left
93  controls_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Fixed));
94 
95  // Add layout
96  layout->addLayout(controls_layout);
97 
98  // When there are no changes to be made
99  no_changes_label_ = new QLabel(this);
100  no_changes_label_->setText("URDF is ready for Gazebo. No changes required.");
101  no_changes_label_->setFont(QFont(QFont().defaultFamily(), 18));
102  no_changes_label_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
103  no_changes_label_->setAlignment(Qt::AlignTop);
104  layout->addWidget(no_changes_label_);
105 
106  // URDF text
107  simulation_text_ = new QTextEdit(this);
108  simulation_text_->setLineWrapMode(QTextEdit::NoWrap);
109  layout->addWidget(simulation_text_);
110  // Configure highlighter
111  auto highlighter = new XmlSyntaxHighlighter(simulation_text_->document());
112  QTextCharFormat format;
113  format.setForeground(Qt::darkGreen);
114  highlighter->addTag("inertial", format);
115  highlighter->addTag("transmission", format);
116  highlighter->addTag("gazebo", format);
117 
118  // Copy URDF link, hidden initially
119  copy_urdf_ = new QLabel(this);
120  copy_urdf_->setText("<a href='contract'>Copy to Clipboard</a>");
121  connect(copy_urdf_, &QLabel::linkActivated, this, &SimulationWidget::copyURDF);
122  layout->addWidget(copy_urdf_);
123 
124  // Finish Layout --------------------------------------------------
125  this->setLayout(layout);
126 }
127 
129 {
130  if (!simulation_text_->document()->isEmpty())
131  return; // nothing to do
132 
133  simulation_text_->setVisible(true);
134  std::string text = setup_step_.getGazeboCompatibleURDF();
135 
136  simulation_text_->document()->setPlainText(QString::fromStdString(text));
137 
138  // Add generated Gazebo URDF to config file if not empty
139  bool have_changes = !text.empty();
140  config_data_->save_gazebo_urdf_ = have_changes;
141 
142  // GUI elements are visible only if there are URDF changes to display/edit
143  simulation_text_->setVisible(have_changes);
144  btn_overwrite_->setVisible(have_changes);
145  btn_open_->setVisible(have_changes && !qgetenv("EDITOR").isEmpty());
146  copy_urdf_->setVisible(have_changes);
147  no_changes_label_->setVisible(!have_changes);
148 
149  // Disable overwrite button if URDF originates from xacro
150  btn_overwrite_->setDisabled(config_data_->urdf_from_xacro_);
151  QString tooltip;
152  if (btn_overwrite_->isEnabled())
153  tooltip = tr("Overwrite URDF in original location:\n").append(setup_step_.getURDFPath().c_str());
154  else
155  tooltip = tr("Cannot overwrite original, <i>xacro-based</i> URDF");
156  btn_overwrite_->setToolTip(tooltip);
157 
158  if (have_changes)
159  config_data_->changes |= MoveItConfigData::SIMULATION;
160  else
161  config_data_->changes &= ~MoveItConfigData::SIMULATION;
162 }
163 
165 {
166  if (!config_data_->save_gazebo_urdf_)
167  return true; // saving is disabled anyway
168 
169  // validate XML
170  std::string urdf = simulation_text_->document()->toPlainText().toStdString();
171  int error_row;
172  std::string error_description;
173 
174  if (setup_step_.isValidXML(urdf, error_row, error_description))
175  {
176  config_data_->gazebo_urdf_string_ = std::move(urdf);
177  return true;
178  }
179  else
180  {
181  QTextCursor cursor = simulation_text_->textCursor();
182  cursor.movePosition(QTextCursor::Start);
183  cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, error_row);
184  simulation_text_->setTextCursor(cursor);
185  QMessageBox::warning(this, tr("Gazebo URDF"), tr("Error parsing XML:\n").append(error_description.c_str()));
186  simulation_text_->setFocus(Qt::OtherFocusReason);
187  return false; // reject switching
188  }
189 }
190 
191 // ******************************************************************************************
192 // Called when save URDF button is clicked
193 // ******************************************************************************************
194 void SimulationWidget::overwriteURDF()
195 {
196  if (!focusLost()) // validate XML
197  return;
198 
199  if (!setup_step_.outputGazeboURDFFile(config_data_->urdf_path_))
200  QMessageBox::warning(this, "Gazebo URDF", tr("Failed to save to ").append(config_data_->urdf_path_.c_str()));
201  else // Display success message
202  QMessageBox::information(this, "Overwriting Successful",
203  "Original robot description URDF was successfully overwritten.");
204 
205  // Remove Gazebo URDF file from list of to-be-written config files
206  config_data_->save_gazebo_urdf_ = false;
207  config_data_->changes &= ~MoveItConfigData::SIMULATION;
208 }
209 
210 void SimulationWidget::openURDF()
211 {
212  QProcess::startDetached(qgetenv("EDITOR"), { setup_step_.getURDFPath().c_str() });
213 }
214 
215 // ******************************************************************************************
216 // Called the copy to clipboard button is clicked
217 // ******************************************************************************************
218 void SimulationWidget::copyURDF()
219 {
220  simulation_text_->selectAll();
221  simulation_text_->copy();
222 }
223 } // namespace simulation
224 } // namespace moveit_setup
225 
226 #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 focusGiven() override
function called when widget is activated, allows to update/initialize GUI
bool focusLost() override
function called when widget loses focus, although switching away can be rejected
std::filesystem::path getURDFPath() const
Definition: simulation.hpp:60
bool isValidXML(const std::string &new_urdf_contents, int &error_row, std::string &error_description) const
Check if the given xml is valid.
Definition: simulation.cpp:188
bool outputGazeboURDFFile(const std::filesystem::path &file_path)
Definition: simulation.cpp:173
std::string getGazeboCompatibleURDF()
Parses the existing urdf and constructs a string from it with the elements required by gazebo simulat...
Definition: simulation.cpp:85
bool isEmpty(const moveit_msgs::msg::Constraints &constr)
Check if any constraints were specified.
Definition: utils.cpp:127
std::string append(const std::string &left, const std::string &right)