moveit2
The MoveIt Motion Planning Framework for ROS 2.
interactive_marker_display.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * Copyright (c) 2019, Open Source Robotics Foundation, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 #include <map>
31 #include <memory>
32 #include <string>
33 #include <utility>
34 #include <vector>
35 
36 #include <rviz_common/properties/bool_property.hpp>
37 #include <rviz_common/validate_floats.hpp>
38 #include <rviz_common/display_context.hpp>
39 
40 #include <rviz_default_plugins/displays/interactive_markers/interactive_marker_namespace_property.hpp>
41 
43 
44 namespace rviz_default_plugins
45 {
46 namespace displays
47 {
48 bool validateFloats(const visualization_msgs::msg::InteractiveMarker& msg)
49 {
50  bool valid = true;
51  valid = valid && rviz_common::validateFloats(msg.pose);
52  valid = valid && rviz_common::validateFloats(msg.scale);
53  for (const auto& control : msg.controls)
54  {
55  valid = valid && rviz_common::validateFloats(control.orientation);
56  for (const auto& marker : control.markers)
57  {
58  valid = valid && rviz_common::validateFloats(marker.pose);
59  valid = valid && rviz_common::validateFloats(marker.scale);
60  valid = valid && rviz_common::validateFloats(marker.color);
61  valid = valid && rviz_common::validateFloats(marker.points);
62  }
63  }
64  return valid;
65 }
66 
68 {
69  interactive_marker_namespace_property_ =
70  new InteractiveMarkerNamespaceProperty("Interactive Markers Namespace", "",
71  "Namespace of the interactive marker server to connect to.", this,
72  SLOT(namespaceChanged()));
73 
74  show_descriptions_property_ =
75  new rviz_common::properties::BoolProperty("Show Descriptions", true,
76  "Whether or not to show the descriptions of each Interactive Marker.",
77  this, SLOT(updateShowDescriptions()));
78 
79  show_axes_property_ = new rviz_common::properties::BoolProperty(
80  "Show Axes", false, "Whether or not to show the axes of each Interactive Marker.", this, SLOT(updateShowAxes()));
81 
82  show_visual_aids_property_ = new rviz_common::properties::BoolProperty(
83  "Show Visual Aids", false, "Whether or not to show visual helpers while moving/rotating Interactive Markers.",
84  this, SLOT(updateShowVisualAids()));
85 
86  enable_transparency_property_ = new rviz_common::properties::BoolProperty(
87  "Enable Transparency", true,
88  "Whether or not to allow transparency for auto-completed markers (e.g. rings and arrows).", this,
89  SLOT(updateEnableTransparency()));
90 }
91 
93 {
94  // auto ros_node_abstraction = context_->getRosNodeAbstraction().lock();
95  // if (!ros_node_abstraction) {
96  // return;
97  // }
98  //
99  // interactive_marker_namespace_property_->initialize(ros_node_abstraction);
100  //
101  rclcpp::NodeOptions options;
102  options.arguments({ "--ros-args", "-r",
103  "__node:=" + std::string("interactive_marker_display_") +
104  std::to_string(reinterpret_cast<std::size_t>(this)) });
105  pnode_ = rclcpp::Node::make_shared("_", "", options);
106  private_executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
107  private_executor_->add_node(pnode_);
108  // start executor on a different thread now
109  private_executor_thread_ = std::thread([this]() { private_executor_->spin(); });
110  auto frame_transformer = context_->getFrameManager()->getTransformer();
111  // rclcpp::Node::SharedPtr node = ros_node_abstraction->get_raw_node();
112  interactive_marker_client_ = std::make_unique<interactive_markers::InteractiveMarkerClient>(
113  pnode_, frame_transformer, fixed_frame_.toStdString());
114 
115  interactive_marker_client_->setInitializeCallback(
116  [this](const visualization_msgs::srv::GetInteractiveMarkers::Response::SharedPtr& msg) {
117  return initializeCallback(msg);
118  });
119  interactive_marker_client_->setUpdateCallback(
120  [this](const visualization_msgs::msg::InteractiveMarkerUpdate::ConstSharedPtr& msg) {
121  return updateCallback(msg);
122  });
123  interactive_marker_client_->setResetCallback([this]() { return resetCallback(); });
124  interactive_marker_client_->setStatusCallback(
125  [this](interactive_markers::InteractiveMarkerClient::Status status, const std::string& message) {
126  return statusCallback(status, message);
127  });
128 
129  subscribe();
130 }
131 
133 {
134  subscribe();
135 }
136 
138 {
139  unsubscribe();
140 }
141 
143 {
144  unsubscribe();
145 
146  if (interactive_marker_namespace_property_->isEmpty())
147  {
148  setStatus(rviz_common::properties::StatusProperty::Error, "Interactive Marker Client",
149  QString("Error connecting: empty namespace"));
150  return;
151  }
152 
153  subscribe();
154 }
155 
156 void InteractiveMarkerDisplay::subscribe()
157 {
158  const std::string topic_namespace = interactive_marker_namespace_property_->getNamespaceStd();
159  if (isEnabled() && !topic_namespace.empty())
160  {
161  interactive_marker_client_->connect(topic_namespace);
162  }
163 }
164 
165 void InteractiveMarkerDisplay::publishFeedback(visualization_msgs::msg::InteractiveMarkerFeedback& feedback)
166 {
167  interactive_marker_client_->publishFeedback(feedback);
168 }
169 
170 void InteractiveMarkerDisplay::onStatusUpdate(rviz_common::properties::StatusProperty::Level level,
171  const std::string& name, const std::string& text)
172 {
173  setStatusStd(level, name, text);
174 }
175 
176 void InteractiveMarkerDisplay::unsubscribe()
177 {
178  if (interactive_marker_client_)
179  {
180  interactive_marker_client_->disconnect();
181  }
182  Display::reset();
183 }
184 
185 void InteractiveMarkerDisplay::update(float wall_dt, float ros_dt)
186 {
187  (void)wall_dt;
188  (void)ros_dt;
189 
190  interactive_marker_client_->update();
191 
192  for (const auto& name_marker_pair : interactive_markers_map_)
193  {
194  name_marker_pair.second->update();
195  }
196 }
197 
198 void InteractiveMarkerDisplay::updateMarkers(const std::vector<visualization_msgs::msg::InteractiveMarker>& markers)
199 {
200  for (const visualization_msgs::msg::InteractiveMarker& marker : markers)
201  {
202  if (!validateFloats(marker))
203  {
204  setStatusStd(rviz_common::properties::StatusProperty::Error, marker.name, "Marker contains invalid floats!");
205  continue;
206  }
207  RVIZ_COMMON_LOG_DEBUG_STREAM("Processing interactive marker '" << marker.name << "'. " << marker.controls.size());
208 
209  auto int_marker_entry = interactive_markers_map_.find(marker.name);
210 
211  if (int_marker_entry == interactive_markers_map_.end())
212  {
213  int_marker_entry =
214  interactive_markers_map_
215  .insert(std::make_pair(marker.name, std::make_shared<InteractiveMarker>(getSceneNode(), context_)))
216  .first;
217  connect(int_marker_entry->second.get(), SIGNAL(userFeedback(visualization_msgs::msg::InteractiveMarkerFeedback&)),
218  this, SLOT(publishFeedback(visualization_msgs::msg::InteractiveMarkerFeedback&)));
219  connect(
220  int_marker_entry->second.get(),
221  SIGNAL(statusUpdate(rviz_common::properties::StatusProperty::Level, const std::string&, const std::string&)),
222  this,
223  SLOT(onStatusUpdate(rviz_common::properties::StatusProperty::Level, const std::string&, const std::string&)));
224  }
225 
226  if (int_marker_entry->second->processMessage(marker))
227  {
228  int_marker_entry->second->setShowAxes(show_axes_property_->getBool());
229  int_marker_entry->second->setShowVisualAids(show_visual_aids_property_->getBool());
230  int_marker_entry->second->setShowDescription(show_descriptions_property_->getBool());
231  }
232  else
233  {
234  unsubscribe();
235  return;
236  }
237  }
238 }
239 
240 void InteractiveMarkerDisplay::eraseAllMarkers()
241 {
242  interactive_markers_map_.clear();
243  deleteStatusStd("Interactive Marker Client");
244 }
245 
246 void InteractiveMarkerDisplay::eraseMarkers(const std::vector<std::string>& erases)
247 {
248  for (const std::string& marker_name : erases)
249  {
250  interactive_markers_map_.erase(marker_name);
251  deleteStatusStd(marker_name);
252  }
253 }
254 
255 void InteractiveMarkerDisplay::updatePoses(
256  const std::vector<visualization_msgs::msg::InteractiveMarkerPose>& marker_poses)
257 {
258  for (const visualization_msgs::msg::InteractiveMarkerPose& marker_pose : marker_poses)
259  {
260  if (!rviz_common::validateFloats(marker_pose.pose))
261  {
262  setStatusStd(rviz_common::properties::StatusProperty::Error, marker_pose.name,
263  "Pose message contains invalid floats!");
264  return;
265  }
266 
267  auto int_marker_entry = interactive_markers_map_.find(marker_pose.name);
268 
269  if (int_marker_entry != interactive_markers_map_.end())
270  {
271  int_marker_entry->second->processMessage(marker_pose);
272  }
273  else
274  {
275  setStatusStd(rviz_common::properties::StatusProperty::Error, marker_pose.name,
276  "Pose received for non-existing marker '" + marker_pose.name);
277  unsubscribe();
278  return;
279  }
280  }
281 }
282 
283 void InteractiveMarkerDisplay::initializeCallback(
284  const visualization_msgs::srv::GetInteractiveMarkers::Response::SharedPtr& msg)
285 {
286  eraseAllMarkers();
287  updateMarkers(msg->markers);
288 }
289 
290 void InteractiveMarkerDisplay::updateCallback(const visualization_msgs::msg::InteractiveMarkerUpdate::ConstSharedPtr& msg)
291 {
292  updateMarkers(msg->markers);
293  updatePoses(msg->poses);
294  eraseMarkers(msg->erases);
295 }
296 
297 void InteractiveMarkerDisplay::resetCallback()
298 {
299  eraseAllMarkers();
300  deleteStatusStd("Interactive Marker Client");
301 }
302 
303 void InteractiveMarkerDisplay::statusCallback(interactive_markers::InteractiveMarkerClient::Status status,
304  const std::string& message)
305 {
306  rviz_common::properties::StatusProperty::Level rviz_level;
307  switch (status)
308  {
309  case interactive_markers::InteractiveMarkerClient::STATUS_DEBUG:
310  rviz_level = rviz_common::properties::StatusProperty::Ok;
311  break;
312  case interactive_markers::InteractiveMarkerClient::STATUS_INFO:
313  rviz_level = rviz_common::properties::StatusProperty::Ok;
314  break;
315  case interactive_markers::InteractiveMarkerClient::STATUS_WARN:
316  rviz_level = rviz_common::properties::StatusProperty::Warn;
317  break;
318  case interactive_markers::InteractiveMarkerClient::STATUS_ERROR:
319  rviz_level = rviz_common::properties::StatusProperty::Error;
320  break;
321  default:
322  RVIZ_COMMON_LOG_WARNING("Unexpected status level from interactive marker client received");
323  rviz_level = rviz_common::properties::StatusProperty::Error;
324  }
325  setStatusStd(rviz_level, "Interactive Marker Client", message);
326 }
327 
329 {
330  if (interactive_marker_client_)
331  {
332  interactive_marker_client_->setTargetFrame(fixed_frame_.toStdString());
333  }
334  Display::reset();
335 }
336 
338 {
339  Display::reset();
340  unsubscribe();
341  subscribe();
342 }
343 
345 {
346  bool show = show_descriptions_property_->getBool();
347 
348  for (const auto& name_marker_pair : interactive_markers_map_)
349  {
350  name_marker_pair.second->setShowDescription(show);
351  }
352 }
353 
355 {
356  bool show = show_axes_property_->getBool();
357 
358  for (const auto& name_marker_pair : interactive_markers_map_)
359  {
360  name_marker_pair.second->setShowAxes(show);
361  }
362 }
363 
365 {
366  bool show = show_visual_aids_property_->getBool();
367 
368  for (const auto& name_marker_pair : interactive_markers_map_)
369  {
370  name_marker_pair.second->setShowVisualAids(show);
371  }
372 }
373 
375 {
376  // This is not very efficient, but works
377  unsubscribe();
378  interactive_marker_client_->setEnableAutocompleteTransparency(enable_transparency_property_->getBool());
379  subscribe();
380 }
381 
382 } // namespace displays
383 } // namespace rviz_default_plugins
384 
385 #include <pluginlib/class_list_macros.hpp> // NOLINT(build/include_order)
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
void publishFeedback(visualization_msgs::msg::InteractiveMarkerFeedback &feedback)
void onStatusUpdate(rviz_common::properties::StatusProperty::Level level, const std::string &name, const std::string &text)
bool validateFloats(const visualization_msgs::msg::InteractiveMarker &msg)
name
Definition: setup.py:7