gazebo_quadrotor_simple_controller.cpp
Go to the documentation of this file.
1 //=================================================================================================
2 // Copyright (c) 2012-2016, Institute of Flight Systems and Automatic Control,
3 // Technische Universität Darmstadt.
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 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of hector_quadrotor nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //=================================================================================================
28 
30 #include <gazebo/common/Events.hh>
31 #include <gazebo/physics/physics.hh>
32 
33 #include <cmath>
34 
35 #include <geometry_msgs/Wrench.h>
36 
37 namespace gazebo {
38 
40 {
41 }
42 
44 // Destructor
46 {
47 #if (GAZEBO_MAJOR_VERSION < 8)
48  event::Events::DisconnectWorldUpdateBegin(updateConnection);
49 #endif
50  updateConnection.reset();
51 
53  delete node_handle_;
54 }
55 
57 // Load the controller
58 void GazeboQuadrotorSimpleController::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
59 {
60  gzwarn << "The GazeboQuadrotorSimpleController plugin is DEPRECATED in ROS hydro. Please use the twist_controller in package hector_quadrotor_controller instead." << std::endl;
61 
62  world = _model->GetWorld();
63  link = _model->GetLink();
64  link_name_ = link->GetName();
65 
66  // default parameters
67  namespace_.clear();
68  velocity_topic_ = "cmd_vel";
69  imu_topic_.clear();
70  state_topic_.clear();
71  wrench_topic_ = "wrench_out";
72  max_force_ = -1;
73  auto_engage_ = true;
74 
75  // load parameters from sdf
76  if (_sdf->HasElement("robotNamespace")) namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>();
77  if (_sdf->HasElement("topicName")) velocity_topic_ = _sdf->GetElement("topicName")->Get<std::string>();
78  if (_sdf->HasElement("imuTopic")) imu_topic_ = _sdf->GetElement("imuTopic")->Get<std::string>();
79  if (_sdf->HasElement("stateTopic")) state_topic_ = _sdf->GetElement("stateTopic")->Get<std::string>();
80  if (_sdf->HasElement("wrenchTopic")) wrench_topic_ = _sdf->GetElement("wrenchTopic")->Get<std::string>();
81  if (_sdf->HasElement("maxForce")) max_force_ = _sdf->GetElement("maxForce")->Get<double>();
82  if (_sdf->HasElement("autoEngage")) auto_engage_ = _sdf->GetElement("autoEngage")->Get<bool>();
83 
84  if (_sdf->HasElement("bodyName") && _sdf->GetElement("bodyName")->GetValue()) {
85  link_name_ = _sdf->GetElement("bodyName")->Get<std::string>();
86  link = _model->GetLink(link_name_);
87  }
88 
89  if (!link)
90  {
91  ROS_FATAL("gazebo_ros_baro plugin error: bodyName: %s does not exist\n", link_name_.c_str());
92  return;
93  }
94 
95  // configure controllers
96  controllers_.roll.Load(_sdf, "rollpitch");
97  controllers_.pitch.Load(_sdf, "rollpitch");
98  controllers_.yaw.Load(_sdf, "yaw");
99  controllers_.velocity_x.Load(_sdf, "velocityXY");
100  controllers_.velocity_y.Load(_sdf, "velocityXY");
101  controllers_.velocity_z.Load(_sdf, "velocityZ");
102 
103  // Get inertia and mass of quadrotor body
104 #if (GAZEBO_MAJOR_VERSION >= 8)
105  inertia = link->GetInertial()->PrincipalMoments();
106  mass = link->GetInertial()->Mass();
107 #else
108  inertia = link->GetInertial()->GetPrincipalMoments();
109  mass = link->GetInertial()->GetMass();
110 #endif
111 
112  // Make sure the ROS node for Gazebo has already been initialized
113  if (!ros::isInitialized())
114  {
115  ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
116  << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
117  return;
118  }
119 
121  ros::NodeHandle param_handle(*node_handle_, "controller");
122 
123  // subscribe command
124  param_handle.getParam("velocity_topic", velocity_topic_);
125  if (!velocity_topic_.empty())
126  {
127  ros::SubscribeOptions ops = ros::SubscribeOptions::create<geometry_msgs::Twist>(
128  velocity_topic_, 1,
132  }
133 
134  // subscribe imu
135  param_handle.getParam("imu_topic", imu_topic_);
136  if (!imu_topic_.empty())
137  {
138  ros::SubscribeOptions ops = ros::SubscribeOptions::create<sensor_msgs::Imu>(
139  imu_topic_, 1,
140  boost::bind(&GazeboQuadrotorSimpleController::ImuCallback, this, _1),
143 
144  ROS_INFO_NAMED("quadrotor_simple_controller", "Using imu information on topic %s as source of orientation and angular velocity.", imu_topic_.c_str());
145  }
146 
147  // subscribe state
148  param_handle.getParam("state_topic", state_topic_);
149  if (!state_topic_.empty())
150  {
151  ros::SubscribeOptions ops = ros::SubscribeOptions::create<nav_msgs::Odometry>(
152  state_topic_, 1,
153  boost::bind(&GazeboQuadrotorSimpleController::StateCallback, this, _1),
156 
157  ROS_INFO_NAMED("quadrotor_simple_controller", "Using state information on topic %s as source of state information.", state_topic_.c_str());
158  }
159 
160  // advertise wrench
161  param_handle.getParam("wrench_topic", wrench_topic_);
162  if (!wrench_topic_.empty())
163  {
164  ros::AdvertiseOptions ops = ros::AdvertiseOptions::create<geometry_msgs::Wrench>(
165  wrench_topic_, 10,
167  );
169  }
170 
171  // engage/shutdown service servers
172  {
173  ros::AdvertiseServiceOptions ops = ros::AdvertiseServiceOptions::create<std_srvs::Empty>(
174  "engage", boost::bind(&GazeboQuadrotorSimpleController::EngageCallback, this, _1, _2),
176  );
178 
179  ops = ros::AdvertiseServiceOptions::create<std_srvs::Empty>(
180  "shutdown", boost::bind(&GazeboQuadrotorSimpleController::ShutdownCallback, this, _1, _2),
182  );
184  }
185 
186  // callback_queue_thread_ = boost::thread( boost::bind( &GazeboQuadrotorSimpleController::CallbackQueueThread,this ) );
187 
188 
189  Reset();
190 
191  // New Mechanism for Updating every World Cycle
192  // Listen to the update event. This event is broadcast every
193  // simulation iteration.
194  controlTimer.Load(world, _sdf);
195  updateConnection = event::Events::ConnectWorldUpdateBegin(
196  boost::bind(&GazeboQuadrotorSimpleController::Update, this));
197 }
198 
200 // Callbacks
201 void GazeboQuadrotorSimpleController::VelocityCallback(const geometry_msgs::TwistConstPtr& velocity)
202 {
204 }
205 
206 void GazeboQuadrotorSimpleController::ImuCallback(const sensor_msgs::ImuConstPtr& imu)
207 {
208 #if (GAZEBO_MAJOR_VERSION >= 8)
209  pose.Rot().Set(imu->orientation.w, imu->orientation.x, imu->orientation.y, imu->orientation.z);
210  euler = pose.Rot().Euler();
211  angular_velocity = pose.Rot().RotateVector(ignition::math::Vector3d(imu->angular_velocity.x, imu->angular_velocity.y, imu->angular_velocity.z));
212 #else
213  pose.rot.Set(imu->orientation.w, imu->orientation.x, imu->orientation.y, imu->orientation.z);
214  euler = pose.rot.GetAsEuler();
215  angular_velocity = pose.rot.RotateVector(math::Vector3(imu->angular_velocity.x, imu->angular_velocity.y, imu->angular_velocity.z));
216 #endif
217 }
218 
219 void GazeboQuadrotorSimpleController::StateCallback(const nav_msgs::OdometryConstPtr& state)
220 {
221 #if (GAZEBO_MAJOR_VERSION >= 8)
222  ignition::math::Vector3d velocity1(velocity);
223 #else
224  math::Vector3 velocity1(velocity);
225 #endif
226 
227  if (imu_topic_.empty()) {
228 #if (GAZEBO_MAJOR_VERSION >= 8)
229  pose.Pos().Set(state->pose.pose.position.x, state->pose.pose.position.y, state->pose.pose.position.z);
230  pose.Rot().Set(state->pose.pose.orientation.w, state->pose.pose.orientation.x, state->pose.pose.orientation.y, state->pose.pose.orientation.z);
231  euler = pose.Rot().Euler();
232 #else
233  pose.pos.Set(state->pose.pose.position.x, state->pose.pose.position.y, state->pose.pose.position.z);
234  pose.rot.Set(state->pose.pose.orientation.w, state->pose.pose.orientation.x, state->pose.pose.orientation.y, state->pose.pose.orientation.z);
235  euler = pose.rot.GetAsEuler();
236 #endif
237  angular_velocity.Set(state->twist.twist.angular.x, state->twist.twist.angular.y, state->twist.twist.angular.z);
238  }
239 
240  velocity.Set(state->twist.twist.linear.x, state->twist.twist.linear.y, state->twist.twist.linear.z);
241 
242  // calculate acceleration
243  double dt = !state_stamp.isZero() ? (state->header.stamp - state_stamp).toSec() : 0.0;
244  state_stamp = state->header.stamp;
245  if (dt > 0.0) {
246  acceleration = (velocity - velocity1) / dt;
247  } else {
248  acceleration.Set();
249  }
250 }
251 
252 bool GazeboQuadrotorSimpleController::EngageCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
253 {
254  ROS_INFO_NAMED("quadrotor_simple_controller", "Engaging motors!");
255  running_ = true;
256  return true;
257 }
258 
259 bool GazeboQuadrotorSimpleController::ShutdownCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
260 {
261  ROS_INFO_NAMED("quadrotor_simple_controller", "Shutting down motors!");
262  running_ = false;
263  return true;
264 }
265 
267 // Update the controller
269 {
270  // Get new commands/state
272 
273  double dt;
274  if (controlTimer.update(dt) && dt > 0.0) {
275  // Get Pose/Orientation from Gazebo (if no state subscriber is active)
276 #if (GAZEBO_MAJOR_VERSION >= 8)
277  if (imu_topic_.empty()) {
278  pose = link->WorldPose();
279  angular_velocity = link->WorldAngularVel();
280  euler = pose.Rot().Euler();
281  }
282  if (state_topic_.empty()) {
283  acceleration = (link->WorldLinearVel() - velocity) / dt;
284  velocity = link->WorldLinearVel();
285  }
286 #else
287  if (imu_topic_.empty()) {
288  pose = link->GetWorldPose();
289  angular_velocity = link->GetWorldAngularVel();
290  euler = pose.rot.GetAsEuler();
291  }
292  if (state_topic_.empty()) {
293  acceleration = (link->GetWorldLinearVel() - velocity) / dt;
294  velocity = link->GetWorldLinearVel();
295  }
296 #endif
297 
298  // Auto engage/shutdown
299  if (auto_engage_) {
300  if (!running_ && velocity_command_.linear.z > 0.1) {
301  running_ = true;
302  ROS_INFO_NAMED("quadrotor_simple_controller", "Engaging motors!");
303 #if (GAZEBO_MAJOR_VERSION >= 8)
304  } else if (running_ && controllers_.velocity_z.i < -1.0 && velocity_command_.linear.z < -0.1 && (velocity.Z() > -0.1 && velocity.Z() < 0.1)) {
305 #else
306  } else if (running_ && controllers_.velocity_z.i < -1.0 && velocity_command_.linear.z < -0.1 && (velocity.z > -0.1 && velocity.z < 0.1)) {
307 #endif
308  running_ = false;
309  ROS_INFO_NAMED("quadrotor_simple_controller", "Shutting down motors!");
310  }
311  }
312 
313  // static Time lastDebug;
314  // if ((world->GetSimTime() - lastDebug).Double() > 0.5) {
315  // ROS_DEBUG_STREAM_NAMED("quadrotor_simple_controller", "Velocity: gazebo = [" << link->GetWorldLinearVel() << "], state = [" << velocity << "]");
316  // ROS_DEBUG_STREAM_NAMED("quadrotor_simple_controller", "Acceleration: gazebo = [" << link->GetWorldLinearAccel() << "], state = [" << acceleration << "]");
317  // ROS_DEBUG_STREAM_NAMED("quadrotor_simple_controller", "Angular Velocity: gazebo = [" << link->GetWorldAngularVel() << "], state = [" << angular_velocity << "]");
318  // lastDebug = world->GetSimTime();
319  // }
320 
321  // Get gravity
322 #if (GAZEBO_MAJOR_VERSION >= 8)
323  ignition::math::Vector3d gravity_body = pose.Rot().RotateVector(world->Gravity());
324  double gravity = gravity_body.Length();
325  double load_factor = gravity * gravity / world->Gravity().Dot(gravity_body); // Get gravity
326 #else
327  math::Vector3 gravity_body = pose.rot.RotateVector(world->GetPhysicsEngine()->GetGravity());
328  double gravity = gravity_body.GetLength();
329  double load_factor = gravity * gravity / world->GetPhysicsEngine()->GetGravity().Dot(gravity_body); // Get gravity
330 #endif
331 
332  // Rotate vectors to coordinate frames relevant for control
333 #if (GAZEBO_MAJOR_VERSION >= 8)
334  ignition::math::Quaterniond heading_quaternion(cos(euler.Z()/2),0,0,sin(euler.Z()/2));
335  ignition::math::Vector3d velocity_xy = heading_quaternion.RotateVectorReverse(velocity);
336  ignition::math::Vector3d acceleration_xy = heading_quaternion.RotateVectorReverse(acceleration);
337  ignition::math::Vector3d angular_velocity_body = pose.Rot().RotateVectorReverse(angular_velocity);
338 #else
339  math::Quaternion heading_quaternion(cos(euler.z/2),0,0,sin(euler.z/2));
340  math::Vector3 velocity_xy = heading_quaternion.RotateVectorReverse(velocity);
341  math::Vector3 acceleration_xy = heading_quaternion.RotateVectorReverse(acceleration);
342  math::Vector3 angular_velocity_body = pose.rot.RotateVectorReverse(angular_velocity);
343 #endif
344 
345  // update controllers
346  force.Set(0.0, 0.0, 0.0);
347  torque.Set(0.0, 0.0, 0.0);
348  if (running_) {
349 #if (GAZEBO_MAJOR_VERSION >= 8)
350  double pitch_command = controllers_.velocity_x.update(velocity_command_.linear.x, velocity_xy.X(), acceleration_xy.X(), dt) / gravity;
351  double roll_command = -controllers_.velocity_y.update(velocity_command_.linear.y, velocity_xy.Y(), acceleration_xy.Y(), dt) / gravity;
352  torque.X() = inertia.X() * controllers_.roll.update(roll_command, euler.X(), angular_velocity_body.X(), dt);
353  torque.Y() = inertia.Y() * controllers_.pitch.update(pitch_command, euler.Y(), angular_velocity_body.Y(), dt);
354  // torque.X() = inertia.X() * controllers_.roll.update(-velocity_command_.linear.y/gravity, euler.X(), angular_velocity_body.X(), dt);
355  // torque.Y() = inertia.Y() * controllers_.pitch.update(velocity_command_.linear.x/gravity, euler.Y(), angular_velocity_body.Y(), dt);
356  torque.Z() = inertia.Z() * controllers_.yaw.update(velocity_command_.angular.z, angular_velocity.Z(), 0, dt);
357  force.Z() = mass * (controllers_.velocity_z.update(velocity_command_.linear.z, velocity.Z(), acceleration.Z(), dt) + load_factor * gravity);
358  if (max_force_ > 0.0 && force.Z() > max_force_) force.Z() = max_force_;
359  if (force.Z() < 0.0) force.Z() = 0.0;
360 #else
361  double pitch_command = controllers_.velocity_x.update(velocity_command_.linear.x, velocity_xy.x, acceleration_xy.x, dt) / gravity;
362  double roll_command = -controllers_.velocity_y.update(velocity_command_.linear.y, velocity_xy.y, acceleration_xy.y, dt) / gravity;
363  torque.x = inertia.x * controllers_.roll.update(roll_command, euler.x, angular_velocity_body.x, dt);
364  torque.y = inertia.y * controllers_.pitch.update(pitch_command, euler.y, angular_velocity_body.y, dt);
365  // torque.x = inertia.x * controllers_.roll.update(-velocity_command_.linear.y/gravity, euler.x, angular_velocity_body.x, dt);
366  // torque.y = inertia.y * controllers_.pitch.update(velocity_command_.linear.x/gravity, euler.y, angular_velocity_body.y, dt);
368  force.z = mass * (controllers_.velocity_z.update(velocity_command_.linear.z, velocity.z, acceleration.z, dt) + load_factor * gravity);
369  if (max_force_ > 0.0 && force.z > max_force_) force.z = max_force_;
370  if (force.z < 0.0) force.z = 0.0;
371 #endif
372  } else {
379  }
380 
381  // static double lastDebugOutput = 0.0;
382  // if (last_time.Double() - lastDebugOutput > 0.1) {
383  // ROS_DEBUG_NAMED("quadrotor_simple_controller", "Velocity = [%g %g %g], Acceleration = [%g %g %g]", velocity.x, velocity.y, velocity.z, acceleration.x, acceleration.y, acceleration.z);
384  // ROS_DEBUG_NAMED("quadrotor_simple_controller", "Command: linear = [%g %g %g], angular = [%g %g %g], roll/pitch = [%g %g]", velocity_command_.linear.x, velocity_command_.linear.y, velocity_command_.linear.z, velocity_command_.angular.x*180/M_PI, velocity_command_.angular.y*180/M_PI, velocity_command_.angular.z*180/M_PI, roll_command*180/M_PI, pitch_command*180/M_PI);
385  // ROS_DEBUG_NAMED("quadrotor_simple_controller", "Mass: %g kg, Inertia: [%g %g %g], Load: %g g", mass, inertia.x, inertia.y, inertia.z, load_factor);
386  // ROS_DEBUG_NAMED("quadrotor_simple_controller", "Force: [%g %g %g], Torque: [%g %g %g]", force.x, force.y, force.z, torque.x, torque.y, torque.z);
387  // lastDebugOutput = last_time.Double();
388  // }
389 
390  // Publish wrench
391  if (wrench_publisher_) {
392  geometry_msgs::Wrench wrench;
393 #if (GAZEBO_MAJOR_VERSION >= 8)
394  wrench.force.x = force.X();
395  wrench.force.y = force.Y();
396  wrench.force.z = force.Z();
397  wrench.torque.x = torque.X();
398  wrench.torque.y = torque.Y();
399  wrench.torque.z = torque.Z();
400 #else
401  wrench.force.x = force.x;
402  wrench.force.y = force.y;
403  wrench.force.z = force.z;
404  wrench.torque.x = torque.x;
405  wrench.torque.y = torque.y;
406  wrench.torque.z = torque.z;
407 #endif
408  wrench_publisher_.publish(wrench);
409  }
410  }
411 
412  // set force and torque in gazebo
413  link->AddRelativeForce(force);
414 #if (GAZEBO_MAJOR_VERSION >= 8)
415  link->AddRelativeTorque(torque - link->GetInertial()->CoG().Cross(force));
416 #else
417  link->AddRelativeTorque(torque - link->GetInertial()->GetCoG().Cross(force));
418 #endif
419 }
420 
422 // Reset the controller
424 {
431 
432  force.Set();
433  torque.Set();
434 
435  // reset state
436  pose.Reset();
437  velocity.Set();
438  angular_velocity.Set();
439  acceleration.Set();
440  euler.Set();
442 
443  running_ = false;
444 }
445 
447 // PID controller implementation
449 {
450 }
451 
453 {
454 }
455 
456 void GazeboQuadrotorSimpleController::PIDController::Load(sdf::ElementPtr _sdf, const std::string& prefix)
457 {
458  gain_p = 0.0;
459  gain_d = 0.0;
460  gain_i = 0.0;
461  time_constant = 0.0;
462  limit = -1.0;
463 
464  if (!_sdf) return;
465  // _sdf->PrintDescription(_sdf->GetName());
466  if (_sdf->HasElement(prefix + "ProportionalGain")) gain_p = _sdf->GetElement(prefix + "ProportionalGain")->Get<double>();
467  if (_sdf->HasElement(prefix + "DifferentialGain")) gain_d = _sdf->GetElement(prefix + "DifferentialGain")->Get<double>();
468  if (_sdf->HasElement(prefix + "IntegralGain")) gain_i = _sdf->GetElement(prefix + "IntegralGain")->Get<double>();
469  if (_sdf->HasElement(prefix + "TimeConstant")) time_constant = _sdf->GetElement(prefix + "TimeConstant")->Get<double>();
470  if (_sdf->HasElement(prefix + "Limit")) limit = _sdf->GetElement(prefix + "Limit")->Get<double>();
471 }
472 
473 double GazeboQuadrotorSimpleController::PIDController::update(double new_input, double x, double dx, double dt)
474 {
475  // limit command
476  if (limit > 0.0 && fabs(new_input) > limit) new_input = (new_input < 0 ? -1.0 : 1.0) * limit;
477 
478  // filter command
479  if (dt + time_constant > 0.0) {
480  dinput = (new_input - input) / (dt + time_constant);
481  input = (dt * new_input + time_constant * input) / (dt + time_constant);
482  }
483 
484  // update proportional, differential and integral errors
485  p = input - x;
486  d = dinput - dx;
487  i = i + dt * p;
488 
489  // update control output
490  output = gain_p * p + gain_d * d + gain_i * i;
491  return output;
492 }
493 
495 {
496  input = dinput = 0;
497  p = i = d = output = 0;
498 }
499 
500 // Register this plugin with the simulator
501 GZ_REGISTER_MODEL_PLUGIN(GazeboQuadrotorSimpleController)
502 
503 } // namespace gazebo
d
physics::LinkPtr link
The link referred to by this plugin.
#define ROS_FATAL(...)
boost::shared_ptr< void const > VoidConstPtr
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
#define ROS_INFO_NAMED(name,...)
virtual void Load(physics::WorldPtr _world, sdf::ElementPtr _sdf, const std::string &_prefix="update")
double update(double input, double x, double dx, double dt)
void publish(const boost::shared_ptr< M > &message) const
struct gazebo::GazeboQuadrotorSimpleController::Controllers controllers_
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()
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
virtual void Load(sdf::ElementPtr _sdf, const std::string &prefix="")
virtual bool update()
void VelocityCallback(const geometry_msgs::TwistConstPtr &)
bool EngageCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
#define ROS_FATAL_STREAM(args)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void limit(T &value, const T &min, const T &max)
virtual void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
bool getParam(const std::string &key, std::string &s) const
bool ShutdownCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
void StateCallback(const nav_msgs::OdometryConstPtr &)
boost::shared_ptr< void > VoidPtr


hector_quadrotor_gazebo_plugins
Author(s): Johannes Meyer
autogenerated on Mon Jun 10 2019 13:36:58