moveit2
The MoveIt Motion Planning Framework for ROS 2.
robot_state_display.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2008, 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: Ioan Sucan */
36 
40 
41 #include <rclcpp/qos.hpp>
42 
43 // #include <rviz/visualization_manager.h>
44 #include <rviz_default_plugins/robot/robot.hpp>
45 #include <rviz_default_plugins/robot/robot_link.hpp>
46 
47 #include <rviz_common/properties/property.hpp>
48 #include <rviz_common/properties/string_property.hpp>
49 #include <rviz_common/properties/bool_property.hpp>
50 #include <rviz_common/properties/float_property.hpp>
51 #include <rviz_common/properties/ros_topic_property.hpp>
52 #include <rviz_common/properties/color_property.hpp>
53 #include <rviz_common/display_context.hpp>
54 #include <rviz_common/frame_manager_iface.hpp>
55 
56 #include <OgreSceneManager.h>
57 #include <OgreSceneNode.h>
58 
59 #include <memory>
60 
61 namespace moveit_rviz_plugin
62 {
63 // ******************************************************************************************
64 // Base class constructor
65 // ******************************************************************************************
66 RobotStateDisplay::RobotStateDisplay() : Display(), update_state_(false)
67 {
68  robot_description_property_ = new rviz_common::properties::StringProperty(
69  "Robot Description", "robot_description", "The name of the ROS parameter where the URDF for the robot is loaded",
70  this, SLOT(changedRobotDescription()), this);
71 
72  robot_state_topic_property_ = new rviz_common::properties::RosTopicProperty(
73  "Robot State Topic", "display_robot_state",
74  rosidl_generator_traits::data_type<moveit_msgs::msg::DisplayRobotState>(),
75  "The topic on which the moveit_msgs::msg::DisplayRobotState messages are received", this,
76  SLOT(changedRobotStateTopic()), this);
77 
78  // Planning scene category -------------------------------------------------------------------------------------------
80  new rviz_common::properties::StringProperty("Robot Root Link", "",
81  "Shows the name of the root link for the robot model", this,
82  SLOT(changedRootLinkName()), this);
83  root_link_name_property_->setReadOnly(true);
84 
85  robot_alpha_property_ = new rviz_common::properties::FloatProperty(
86  "Robot Alpha", 1.0f, "Specifies the alpha for the robot links", this, SLOT(changedRobotSceneAlpha()), this);
87  robot_alpha_property_->setMin(0.0);
88  robot_alpha_property_->setMax(1.0);
89 
91  new rviz_common::properties::ColorProperty("Attached Body Color", QColor(150, 50, 150),
92  "The color for the attached bodies", this,
93  SLOT(changedAttachedBodyColor()), this);
94 
95  enable_link_highlight_ = new rviz_common::properties::BoolProperty("Show Highlights", true,
96  "Specifies whether link highlighting is enabled",
97  this, SLOT(changedEnableLinkHighlight()), this);
99  new rviz_common::properties::BoolProperty("Visual Enabled", true,
100  "Whether to display the visual representation of the robot.", this,
101  SLOT(changedEnableVisualVisible()), this);
103  new rviz_common::properties::BoolProperty("Collision Enabled", false,
104  "Whether to display the collision representation of the robot.", this,
105  SLOT(changedEnableCollisionVisible()), this);
106 
107  show_all_links_ = new rviz_common::properties::BoolProperty(
108  "Show All Links", true, "Toggle all links visibility on or off.", this, SLOT(changedAllLinks()), this);
109 }
110 
111 // ******************************************************************************************
112 // Deconstructor
113 // ******************************************************************************************
115 
117 {
118  Display::onInitialize();
119  auto ros_node_abstraction = context_->getRosNodeAbstraction().lock();
120  if (!ros_node_abstraction)
121  {
122  RVIZ_COMMON_LOG_WARNING("Unable to lock weak_ptr from DisplayContext in RobotStateDisplay constructor");
123  return;
124  }
125  robot_state_topic_property_->initialize(ros_node_abstraction);
126  node_ = ros_node_abstraction->get_raw_node();
127  robot_ = std::make_shared<RobotStateVisualization>(scene_node_, context_, "Robot State", this);
128  changedEnableVisualVisible();
129  changedEnableCollisionVisible();
130  robot_->setVisible(false);
131 }
132 
134 {
135  robot_->clear();
136  rdf_loader_.reset();
137  Display::reset();
138  if (isEnabled())
139  onEnable();
140 }
141 
142 void RobotStateDisplay::changedAllLinks()
143 {
144  Property* links_prop = subProp("Links");
145  QVariant value(show_all_links_->getBool());
146 
147  for (int i = 0; i < links_prop->numChildren(); ++i)
148  {
149  Property* link_prop = links_prop->childAt(i);
150  link_prop->setValue(value);
151  }
152 }
153 
154 void RobotStateDisplay::setHighlight(const std::string& link_name, const std_msgs::msg::ColorRGBA& color)
155 {
156  rviz_default_plugins::robot::RobotLink* link = robot_->getRobot().getLink(link_name);
157  if (link)
158  {
159  link->setColor(color.r, color.g, color.b);
160  link->setRobotAlpha(color.a * robot_alpha_property_->getFloat());
161  }
162 }
163 
164 void RobotStateDisplay::unsetHighlight(const std::string& link_name)
165 {
166  rviz_default_plugins::robot::RobotLink* link = robot_->getRobot().getLink(link_name);
167  if (link)
168  {
169  link->unsetColor();
170  link->setRobotAlpha(robot_alpha_property_->getFloat());
171  }
172 }
173 
174 void RobotStateDisplay::changedEnableLinkHighlight()
175 {
176  if (enable_link_highlight_->getBool())
177  {
178  for (std::pair<const std::string, std_msgs::msg::ColorRGBA>& highlight : highlights_)
179  {
180  setHighlight(highlight.first, highlight.second);
181  }
182  }
183  else
184  {
185  for (std::pair<const std::string, std_msgs::msg::ColorRGBA>& highlight : highlights_)
186  {
187  unsetHighlight(highlight.first);
188  }
189  }
190 }
191 
192 void RobotStateDisplay::changedEnableVisualVisible()
193 {
194  robot_->setVisualVisible(enable_visual_visible_->getBool());
195 }
196 
197 void RobotStateDisplay::changedEnableCollisionVisible()
198 {
199  robot_->setCollisionVisible(enable_collision_visible_->getBool());
200 }
201 
203  const moveit_msgs::msg::DisplayRobotState::_highlight_links_type& highlight_links)
204 {
205  if (highlight_links.empty() && highlights_.empty())
206  return;
207 
208  std::map<std::string, std_msgs::msg::ColorRGBA> highlights;
209  for (const moveit_msgs::msg::ObjectColor& highlight_link : highlight_links)
210  {
211  highlights[highlight_link.id] = highlight_link.color;
212  }
213 
214  if (enable_link_highlight_->getBool())
215  {
216  std::map<std::string, std_msgs::msg::ColorRGBA>::iterator ho = highlights_.begin();
217  std::map<std::string, std_msgs::msg::ColorRGBA>::iterator hn = highlights.begin();
218  while (ho != highlights_.end() || hn != highlights.end())
219  {
220  if (ho == highlights_.end())
221  {
222  setHighlight(hn->first, hn->second);
223  ++hn;
224  }
225  else if (hn == highlights.end())
226  {
227  unsetHighlight(ho->first);
228  ++ho;
229  }
230  else if (hn->first < ho->first)
231  {
232  setHighlight(hn->first, hn->second);
233  ++hn;
234  }
235  else if (hn->first > ho->first)
236  {
237  unsetHighlight(ho->first);
238  ++ho;
239  }
240  else if (hn->second != ho->second)
241  {
242  setHighlight(hn->first, hn->second);
243  ++ho;
244  ++hn;
245  }
246  else
247  {
248  ++ho;
249  ++hn;
250  }
251  }
252  }
253 
254  swap(highlights, highlights_);
255 }
256 
257 void RobotStateDisplay::changedAttachedBodyColor()
258 {
259  if (robot_)
260  {
261  QColor color = attached_body_color_property_->getColor();
262  std_msgs::msg::ColorRGBA color_msg;
263  color_msg.r = color.redF();
264  color_msg.g = color.greenF();
265  color_msg.b = color.blueF();
266  color_msg.a = robot_alpha_property_->getFloat();
267  robot_->setDefaultAttachedObjectColor(color_msg);
268  update_state_ = true;
269  }
270 }
271 
272 void RobotStateDisplay::changedRobotDescription()
273 {
274  if (isEnabled())
275  reset();
276 }
277 
278 void RobotStateDisplay::changedRootLinkName()
279 {
280 }
281 
282 void RobotStateDisplay::changedRobotSceneAlpha()
283 {
284  if (robot_)
285  {
286  robot_->setAlpha(robot_alpha_property_->getFloat());
287  QColor color = attached_body_color_property_->getColor();
288  std_msgs::msg::ColorRGBA color_msg;
289  color_msg.r = color.redF();
290  color_msg.g = color.greenF();
291  color_msg.b = color.blueF();
292  color_msg.a = robot_alpha_property_->getFloat();
293  robot_->setDefaultAttachedObjectColor(color_msg);
294  update_state_ = true;
295  }
296 }
297 
298 void RobotStateDisplay::changedRobotStateTopic()
299 {
300  using namespace std::placeholders;
301  // reset model to default state, we don't want to show previous messages
302  if (static_cast<bool>(robot_state_))
303  robot_state_->setToDefaultValues();
304  update_state_ = true;
305  robot_->setVisible(false);
306  setStatus(rviz_common::properties::StatusProperty::Warn, "RobotState", "No msg received");
307 
308  robot_state_subscriber_ = node_->create_subscription<moveit_msgs::msg::DisplayRobotState>(
309  robot_state_topic_property_->getStdString(), rclcpp::ServicesQoS(),
310  [this](const moveit_msgs::msg::DisplayRobotState::ConstSharedPtr& state) { return newRobotStateCallback(state); });
311 }
312 
313 void RobotStateDisplay::newRobotStateCallback(const moveit_msgs::msg::DisplayRobotState::ConstSharedPtr& state_msg)
314 {
315  if (!robot_model_)
316  return;
317  if (!robot_state_)
318  robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
319  // possibly use TF to construct a moveit::core::Transforms object to pass in to the conversion function?
320  try
321  {
322  if (!moveit::core::isEmpty(state_msg->state))
324  setRobotHighlights(state_msg->highlight_links);
325  }
326  catch (const moveit::Exception& e)
327  {
328  robot_state_->setToDefaultValues();
329  setRobotHighlights(moveit_msgs::msg::DisplayRobotState::_highlight_links_type());
330  setStatus(rviz_common::properties::StatusProperty::Error, "RobotState", e.what());
331  robot_->setVisible(false);
332  return;
333  }
334 
335  if (robot_->isVisible() != !state_msg->hide)
336  {
337  robot_->setVisible(!state_msg->hide);
338  if (robot_->isVisible())
339  setStatus(rviz_common::properties::StatusProperty::Ok, "RobotState", "");
340  else
341  setStatus(rviz_common::properties::StatusProperty::Warn, "RobotState", "Hidden");
342  }
343 
344  update_state_ = true;
345 }
346 
347 void RobotStateDisplay::setLinkColor(const std::string& link_name, const QColor& color)
348 {
349  setLinkColor(&robot_->getRobot(), link_name, color);
350 }
351 
352 void RobotStateDisplay::unsetLinkColor(const std::string& link_name)
353 {
354  unsetLinkColor(&robot_->getRobot(), link_name);
355 }
356 
358 {
359  robot_->setVisible(visible);
360 }
361 
362 void RobotStateDisplay::setLinkColor(rviz_default_plugins::robot::Robot* robot, const std::string& link_name,
363  const QColor& color)
364 {
365  rviz_default_plugins::robot::RobotLink* link = robot->getLink(link_name);
366 
367  // Check if link exists
368  if (link)
369  link->setColor(color.redF(), color.greenF(), color.blueF());
370 }
371 
372 void RobotStateDisplay::unsetLinkColor(rviz_default_plugins::robot::Robot* robot, const std::string& link_name)
373 {
374  rviz_default_plugins::robot::RobotLink* link = robot->getLink(link_name);
375 
376  // Check if link exists
377  if (link)
378  link->unsetColor();
379 }
380 
381 // ******************************************************************************************
382 // Load
383 // ******************************************************************************************
385 {
386  if (robot_description_property_->getStdString().empty())
387  {
388  setStatus(rviz_common::properties::StatusProperty::Error, "RobotModel", "`Robot Description` field can't be empty");
389  return;
390  }
391 
392  rdf_loader_ = std::make_shared<rdf_loader::RDFLoader>(node_, robot_description_property_->getStdString(), true);
393  loadRobotModel();
394  rdf_loader_->setNewModelCallback([this]() { return loadRobotModel(); });
395 }
396 
398 {
399  if (rdf_loader_->getURDF())
400  {
401  try
402  {
403  const srdf::ModelSharedPtr& srdf =
404  rdf_loader_->getSRDF() ? rdf_loader_->getSRDF() : std::make_shared<srdf::Model>();
405  robot_model_ = std::make_shared<moveit::core::RobotModel>(rdf_loader_->getURDF(), srdf);
406  robot_->load(*robot_model_->getURDF());
407  robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
408  robot_state_->setToDefaultValues();
409  bool old_state = root_link_name_property_->blockSignals(true);
410  root_link_name_property_->setStdString(getRobotModel()->getRootLinkName());
411  root_link_name_property_->blockSignals(old_state);
412  update_state_ = true;
413  setStatus(rviz_common::properties::StatusProperty::Ok, "RobotModel", "Loaded successfully");
414 
415  changedEnableVisualVisible();
416  changedEnableCollisionVisible();
417  }
418  catch (std::exception& e)
419  {
420  setStatus(rviz_common::properties::StatusProperty::Error, "RobotModel",
421  QString("Loading failed: %1").arg(e.what()));
422  }
423  }
424  else
425  setStatus(rviz_common::properties::StatusProperty::Error, "RobotModel", "Loading failed");
426 
427  highlights_.clear();
428 }
429 
430 void RobotStateDisplay::load(const rviz_common::Config& config)
431 {
432  // This property needs to be loaded in onEnable() below, which is triggered
433  // in the beginning of Display::load() before the other property would be available
434  robot_description_property_->load(config.mapGetChild("Robot Description"));
435  Display::load(config);
436 }
437 
439 {
440  Display::onEnable();
441  if (!rdf_loader_)
443  changedRobotStateTopic();
445 }
446 
447 // ******************************************************************************************
448 // Disable
449 // ******************************************************************************************
451 {
452  robot_state_subscriber_.reset();
453  if (robot_)
454  robot_->setVisible(false);
455  Display::onDisable();
456 }
457 
458 void RobotStateDisplay::update(float wall_dt, float ros_dt)
459 {
460  Display::update(wall_dt, ros_dt);
463  {
464  update_state_ = false;
465  robot_state_->update();
466  robot_->update(robot_state_);
467  }
468 }
469 
470 // ******************************************************************************************
471 // Calculate Offset Position
472 // ******************************************************************************************
474 {
475  if (!getRobotModel())
476  return;
477 
478  Ogre::Vector3 position;
479  Ogre::Quaternion orientation;
480 
481  context_->getFrameManager()->getTransform(getRobotModel()->getModelFrame(), rclcpp::Time(0, 0, RCL_ROS_TIME),
482  position, orientation);
483 
484  scene_node_->setPosition(position);
485  scene_node_->setOrientation(orientation);
486 }
487 
489 {
490  Display::fixedFrameChanged();
492 }
493 
494 } // namespace moveit_rviz_plugin
This may be thrown if unrecoverable errors occur.
Definition: exceptions.h:53
rviz_common::properties::RosTopicProperty * robot_state_topic_property_
void load(const rviz_common::Config &config) override
moveit::core::RobotModelConstPtr robot_model_
void setHighlight(const std::string &link_name, const std_msgs::msg::ColorRGBA &color)
void update(float wall_dt, float ros_dt) override
void setRobotHighlights(const moveit_msgs::msg::DisplayRobotState::_highlight_links_type &highlight_links)
rviz_common::properties::FloatProperty * robot_alpha_property_
rviz_common::properties::ColorProperty * attached_body_color_property_
rviz_common::properties::StringProperty * root_link_name_property_
rclcpp::Subscription< moveit_msgs::msg::DisplayRobotState >::SharedPtr robot_state_subscriber_
void unsetHighlight(const std::string &link_name)
rviz_common::properties::BoolProperty * enable_visual_visible_
void calculateOffsetPosition()
Set the scene node's position, given the target frame and the planning frame.
void unsetLinkColor(const std::string &link_name)
void newRobotStateCallback(const moveit_msgs::msg::DisplayRobotState::ConstSharedPtr &state)
rviz_common::properties::BoolProperty * enable_link_highlight_
rviz_common::properties::BoolProperty * enable_collision_visible_
rviz_common::properties::BoolProperty * show_all_links_
rviz_common::properties::StringProperty * robot_description_property_
void setLinkColor(const std::string &link_name, const QColor &color)
std::map< std::string, std_msgs::msg::ColorRGBA > highlights_
moveit::core::RobotStatePtr robot_state_
const moveit::core::RobotModelConstPtr & getRobotModel() const
bool isEmpty(const moveit_msgs::msg::PlanningScene &msg)
Check if a message includes any information about a planning scene, or whether it is empty.
bool robotStateMsgToRobotState(const Transforms &tf, const moveit_msgs::msg::RobotState &robot_state, RobotState &state, bool copy_attached_bodies=true)
Convert a robot state msg (with accompanying extra transforms) to a MoveIt robot state.
robot
Definition: pick.py:53