moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
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
45{
46namespace displays
47{
48bool 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,
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
156void 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
165void InteractiveMarkerDisplay::publishFeedback(visualization_msgs::msg::InteractiveMarkerFeedback& feedback)
166{
167 interactive_marker_client_->publishFeedback(feedback);
168}
169
170void 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
176void InteractiveMarkerDisplay::unsubscribe()
177{
178 if (interactive_marker_client_)
179 {
180 interactive_marker_client_->disconnect();
181 }
182 Display::reset();
183}
184
185void 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
198void 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
240void InteractiveMarkerDisplay::eraseAllMarkers()
241{
242 interactive_markers_map_.clear();
243 deleteStatusStd("Interactive Marker Client");
244}
245
246void 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
255void 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
283void InteractiveMarkerDisplay::initializeCallback(
284 const visualization_msgs::srv::GetInteractiveMarkers::Response::SharedPtr& msg)
285{
286 eraseAllMarkers();
287 updateMarkers(msg->markers);
288}
289
290void InteractiveMarkerDisplay::updateCallback(const visualization_msgs::msg::InteractiveMarkerUpdate::ConstSharedPtr& msg)
291{
292 updateMarkers(msg->markers);
293 updatePoses(msg->poses);
294 eraseMarkers(msg->erases);
295}
296
297void InteractiveMarkerDisplay::resetCallback()
298{
299 eraseAllMarkers();
300 deleteStatusStd("Interactive Marker Client");
301}
302
303void 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)