gazebo_ros_control_plugin.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Open Source Robotics Foundation
5  * Copyright (c) 2013, The Johns Hopkins University
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the Open Source Robotics Foundation
19  * nor the names of its contributors may be
20  * used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *********************************************************************/
36 
37 /* Author: Dave Coleman, Jonathan Bohren
38  Desc: Gazebo plugin for ros_control that allows 'hardware_interfaces' to be plugged in
39  using pluginlib
40 */
41 
42 // Boost
43 #include <boost/bind.hpp>
44 
46 #include <urdf/model.h>
47 #include <chrono>
48 #include <thread>
49 
50 namespace gazebo_ros_control
51 {
52 
54 {
55  // Disconnect from gazebo events
56  update_connection_.reset();
57 }
58 
59 // Overloaded Gazebo entry point
60 void GazeboRosControlPlugin::Load(gazebo::physics::ModelPtr parent, sdf::ElementPtr sdf)
61 {
62  ROS_INFO_STREAM_NAMED("gazebo_ros_control","Loading gazebo_ros_control plugin");
63 
64 
65  // Save pointers to the model
66  parent_model_ = parent;
67  sdf_ = sdf;
68 
69  // Error message if the model couldn't be found
70  if (!parent_model_)
71  {
72  ROS_ERROR_STREAM_NAMED("loadThread","parent model is NULL");
73  return;
74  }
75 
76  // Check that ROS has been initialized
77  if(!ros::isInitialized())
78  {
79  ROS_FATAL_STREAM_NAMED("gazebo_ros_control","A ROS node for Gazebo has not been initialized, unable to load plugin. "
80  << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
81  return;
82  }
83 
84  // Get namespace for nodehandle
85  if(sdf_->HasElement("robotNamespace"))
86  {
87  robot_namespace_ = sdf_->GetElement("robotNamespace")->Get<std::string>();
88  }
89  else
90  {
91  robot_namespace_ = parent_model_->GetName(); // default
92  }
93 
94  // Get robot_description ROS param name
95  if (sdf_->HasElement("robotParam"))
96  {
97  robot_description_ = sdf_->GetElement("robotParam")->Get<std::string>();
98  }
99  else
100  {
101  robot_description_ = "robot_description"; // default
102  }
103 
104  // Get the robot simulation interface type
105  if(sdf_->HasElement("robotSimType"))
106  {
107  robot_hw_sim_type_str_ = sdf_->Get<std::string>("robotSimType");
108  }
109  else
110  {
111  robot_hw_sim_type_str_ = "gazebo_ros_control/DefaultRobotHWSim";
112  ROS_DEBUG_STREAM_NAMED("loadThread","Using default plugin for RobotHWSim (none specified in URDF/SDF)\""<<robot_hw_sim_type_str_<<"\"");
113  }
114 
115  // temporary fix to bug regarding the robotNamespace in default_robot_hw_sim.cpp (see #637)
116  std::string robot_ns = robot_namespace_;
117 
118  // Get the Gazebo simulation period
119 #if GAZEBO_MAJOR_VERSION >= 8
120  ros::Duration gazebo_period(parent_model_->GetWorld()->Physics()->GetMaxStepSize());
121 #else
122  ros::Duration gazebo_period(parent_model_->GetWorld()->GetPhysicsEngine()->GetMaxStepSize());
123 #endif
124 
125  // Decide the plugin control period
126  if(sdf_->HasElement("controlPeriod"))
127  {
128  control_period_ = ros::Duration(sdf_->Get<double>("controlPeriod"));
129 
130  // Check the period against the simulation period
131  if( control_period_ < gazebo_period )
132  {
133  ROS_ERROR_STREAM_NAMED("gazebo_ros_control","Desired controller update period ("<<control_period_
134  <<" s) is faster than the gazebo simulation period ("<<gazebo_period<<" s).");
135  }
136  else if( control_period_ > gazebo_period )
137  {
138  ROS_WARN_STREAM_NAMED("gazebo_ros_control","Desired controller update period ("<<control_period_
139  <<" s) is slower than the gazebo simulation period ("<<gazebo_period<<" s).");
140  }
141  }
142  else
143  {
144  control_period_ = gazebo_period;
145  ROS_DEBUG_STREAM_NAMED("gazebo_ros_control","Control period not found in URDF/SDF, defaulting to Gazebo period of "
146  << control_period_);
147  }
148 
149  // Get parameters/settings for controllers from ROS param server
151 
152  // Initialize the emergency stop code.
153  e_stop_active_ = false;
154  last_e_stop_active_ = false;
155  if (sdf_->HasElement("eStopTopic"))
156  {
157  const std::string e_stop_topic = sdf_->GetElement("eStopTopic")->Get<std::string>();
159  }
160 
161  ROS_INFO_NAMED("gazebo_ros_control", "Starting gazebo_ros_control plugin in namespace: %s", robot_namespace_.c_str());
162 
163  // Read urdf from ros parameter server then
164  // setup actuators and mechanism control node.
165  // This call will block if ROS is not properly initialized.
166  const std::string urdf_string = getURDF(robot_description_);
167  if (!parseTransmissionsFromURDF(urdf_string))
168  {
169  ROS_ERROR_NAMED("gazebo_ros_control", "Error parsing URDF in gazebo_ros_control plugin, plugin not active.\n");
170  return;
171  }
172 
173  // Load the RobotHWSim abstraction to interface the controllers with the gazebo model
174  try
175  {
178  ("gazebo_ros_control",
179  "gazebo_ros_control::RobotHWSim"));
180 
182  urdf::Model urdf_model;
183  const urdf::Model *const urdf_model_ptr = urdf_model.initString(urdf_string) ? &urdf_model : NULL;
184 
185  if(!robot_hw_sim_->initSim(robot_ns, model_nh_, parent_model_, urdf_model_ptr, transmissions_))
186  {
187  ROS_FATAL_NAMED("gazebo_ros_control","Could not initialize robot simulation interface");
188  return;
189  }
190 
191  // Create the controller manager
192  ROS_DEBUG_STREAM_NAMED("ros_control_plugin","Loading controller_manager");
193  controller_manager_.reset
195 
196  // Listen to the update event. This event is broadcast every simulation iteration.
198  gazebo::event::Events::ConnectWorldUpdateBegin
199  (boost::bind(&GazeboRosControlPlugin::Update, this));
200 
201  }
203  {
204  ROS_FATAL_STREAM_NAMED("gazebo_ros_control","Failed to create robot simulation interface loader: "<<ex.what());
205  }
206 
207  ROS_INFO_NAMED("gazebo_ros_control", "Loaded gazebo_ros_control.");
208 }
209 
210 // Called by the world update start event
212 {
213  // Get the simulation time and period
214 #if GAZEBO_MAJOR_VERSION >= 8
215  gazebo::common::Time gz_time_now = parent_model_->GetWorld()->SimTime();
216 #else
217  gazebo::common::Time gz_time_now = parent_model_->GetWorld()->GetSimTime();
218 #endif
219  ros::Time sim_time_ros(gz_time_now.sec, gz_time_now.nsec);
220  ros::Duration sim_period = sim_time_ros - last_update_sim_time_ros_;
221 
222  robot_hw_sim_->eStopActive(e_stop_active_);
223 
224  // Check if we should update the controllers
225  if(sim_period >= control_period_) {
226  // Store this simulation time
227  last_update_sim_time_ros_ = sim_time_ros;
228 
229  // Update the robot simulation with the state of the gazebo model
230  robot_hw_sim_->readSim(sim_time_ros, sim_period);
231 
232  // Compute the controller commands
233  bool reset_ctrlrs;
234  if (e_stop_active_)
235  {
236  reset_ctrlrs = false;
237  last_e_stop_active_ = true;
238  }
239  else
240  {
242  {
243  reset_ctrlrs = true;
244  last_e_stop_active_ = false;
245  }
246  else
247  {
248  reset_ctrlrs = false;
249  }
250  }
251  controller_manager_->update(sim_time_ros, sim_period, reset_ctrlrs);
252  }
253 
254  // Update the gazebo model with the result of the controller
255  // computation
256  robot_hw_sim_->writeSim(sim_time_ros, sim_time_ros - last_write_sim_time_ros_);
257  last_write_sim_time_ros_ = sim_time_ros;
258 }
259 
260 // Called on world reset
262 {
263  // Reset timing variables to not pass negative update periods to controllers on world reset
266 }
267 
268 // Get the URDF XML from the parameter server
269 std::string GazeboRosControlPlugin::getURDF(std::string param_name) const
270 {
271  std::string urdf_string;
272 
273  // search and wait for robot_description on param server
274  while (urdf_string.empty())
275  {
276  std::string search_param_name;
277  if (model_nh_.searchParam(param_name, search_param_name))
278  {
279  ROS_INFO_ONCE_NAMED("gazebo_ros_control", "gazebo_ros_control plugin is waiting for model"
280  " URDF in parameter [%s] on the ROS param server.", search_param_name.c_str());
281 
282  model_nh_.getParam(search_param_name, urdf_string);
283  }
284  else
285  {
286  ROS_INFO_ONCE_NAMED("gazebo_ros_control", "gazebo_ros_control plugin is waiting for model"
287  " URDF in parameter [%s] on the ROS param server.", robot_description_.c_str());
288 
289  model_nh_.getParam(param_name, urdf_string);
290  }
291 
292  std::this_thread::sleep_for(std::chrono::microseconds(100000));
293  }
294  ROS_DEBUG_STREAM_NAMED("gazebo_ros_control", "Recieved urdf from param server, parsing...");
295 
296  return urdf_string;
297 }
298 
299 // Get Transmissions from the URDF
300 bool GazeboRosControlPlugin::parseTransmissionsFromURDF(const std::string& urdf_string)
301 {
303  return true;
304 }
305 
306 // Emergency stop callback
307 void GazeboRosControlPlugin::eStopCB(const std_msgs::BoolConstPtr& e_stop_active)
308 {
309  e_stop_active_ = e_stop_active->data;
310 }
311 
312 
313 // Register this plugin with the simulator
315 } // namespace
static bool parse(const std::string &urdf_string, std::vector< TransmissionInfo > &transmissions)
#define ROS_INFO_NAMED(name,...)
#define ROS_DEBUG_STREAM_NAMED(name, args)
#define ROS_ERROR_STREAM_NAMED(name, args)
boost::shared_ptr< controller_manager::ControllerManager > controller_manager_
URDF_EXPORT bool initString(const std::string &xmlstring)
std::string getURDF(std::string param_name) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ROSCPP_DECL bool isInitialized()
#define ROS_INFO_STREAM_NAMED(name, args)
boost::shared_ptr< gazebo_ros_control::RobotHWSim > robot_hw_sim_
bool parseTransmissionsFromURDF(const std::string &urdf_string)
#define ROS_FATAL_STREAM_NAMED(name, args)
bool getParam(const std::string &key, std::string &s) const
std::vector< transmission_interface::TransmissionInfo > transmissions_
GZ_REGISTER_MODEL_PLUGIN(GazeboRosControlPlugin)
#define ROS_INFO_ONCE_NAMED(name,...)
void eStopCB(const std_msgs::BoolConstPtr &e_stop_active)
bool searchParam(const std::string &key, std::string &result) const
boost::shared_ptr< pluginlib::ClassLoader< gazebo_ros_control::RobotHWSim > > robot_hw_sim_loader_
#define ROS_FATAL_NAMED(name,...)
#define ROS_ERROR_NAMED(name,...)
Plugin template for hardware interfaces for ros_control and Gazebo.
virtual void Load(gazebo::physics::ModelPtr parent, sdf::ElementPtr sdf)
#define ROS_WARN_STREAM_NAMED(name, args)


gazebo_ros_control
Author(s): Jonathan Bohren, Dave Coleman
autogenerated on Wed Aug 24 2022 02:48:00