moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
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
55namespace moveit_setup
56{
57namespace 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 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// ******************************************************************************************
194void 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
210void 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// ******************************************************************************************
218void 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
bool isValidXML(const std::string &new_urdf_contents, int &error_row, std::string &error_description) const
Check if the given xml is valid.
bool outputGazeboURDFFile(const std::filesystem::path &file_path)
std::string getGazeboCompatibleURDF()
Parses the existing urdf and constructs a string from it with the elements required by gazebo simulat...