attitude_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 
29 #include <ros/ros.h>
30 
32 #include <control_toolbox/pid.h>
33 
34 #include <geometry_msgs/WrenchStamped.h>
35 
39 
40 #include <tf/transform_listener.h> // for tf::getPrefixParam()
41 
42 #include <boost/thread/mutex.hpp>
43 #include <std_msgs/Bool.h>
44 #include <limits>
45 
47 {
48 
49 using namespace hector_quadrotor_interface;
50 
51 class AttitudeController : public controller_interface::Controller<hector_quadrotor_interface::QuadrotorInterface>
52 {
53 public:
55  {
56  }
57 
59  {
60  attitude_subscriber_helper_.reset();
61  estop_sub_.shutdown();
62  }
63 
65  ros::NodeHandle &controller_nh)
66  {
67  pose_ = interface->getPose();
68  twist_ = interface->getTwist();
69  accel_ = interface->getAccel();
70  motor_status_ = interface->getMotorStatus();
71 
72  root_nh.param<std::string>("base_link_frame", base_link_frame_, "base_link");
73  root_nh.param<std::string>("base_stabilized_frame", base_stabilized_frame_, "base_stabilized");
74  root_nh.param<double>("estop_deceleration", estop_deceleration_, 1.0);
75  double command_timeout_sec = 0.0;
76  root_nh.param<double>("command_timeout", command_timeout_sec, 0.0);
77  command_timeout_ = ros::Duration(command_timeout_sec);
78 
79  // resolve frames
80  tf_prefix_ = tf::getPrefixParam(root_nh);
81  base_link_frame_ = tf::resolve(tf_prefix_, base_link_frame_);
82  base_stabilized_frame_ = tf::resolve(tf_prefix_, base_stabilized_frame_);
83 
84  getMassAndInertia(root_nh, mass_, inertia_);
85 
86  attitude_input_ = interface->addInput<AttitudeCommandHandle>("attitude");
87  yawrate_input_ = interface->addInput<YawrateCommandHandle>("yawrate");
88  thrust_input_ = interface->addInput<ThrustCommandHandle>("thrust");
89  wrench_output_ = interface->addOutput<WrenchCommandHandle>("wrench");
90 
91  // subscribe to attitude, yawrate, and thrust
92  attitude_subscriber_helper_ = boost::make_shared<AttitudeSubscriberHelper>(ros::NodeHandle(root_nh, "command"),
93  boost::ref(command_mutex_),
94  boost::ref(attitude_command_),
95  boost::ref(yawrate_command_),
96  boost::ref(thrust_command_));
97 
98  // initialize PID controllers
99  pid_.roll.init(ros::NodeHandle(controller_nh, "roll"));
100  pid_.pitch.init(ros::NodeHandle(controller_nh, "pitch"));
101  pid_.yawrate.init(ros::NodeHandle(controller_nh, "yawrate"));
102 
103  attitude_limiter_.init(controller_nh);
104  yawrate_limiter_.init(controller_nh, "yawrate");
105 
106  estop_ = false;
107  estop_sub_ = root_nh.subscribe("estop", 1, &AttitudeController::estopCb, this);
108 
109  return true;
110  }
111 
112  void reset()
113  {
114  pid_.roll.reset();
115  pid_.pitch.reset();
116  pid_.yawrate.reset();
117  wrench_control_ = geometry_msgs::WrenchStamped();
118  }
119 
120  virtual void starting(const ros::Time &time)
121  {
122  reset();
123  wrench_output_->start();
124  }
125 
126  virtual void stopping(const ros::Time &time)
127  {
128  wrench_output_->stop();
129  }
130 
131  virtual void update(const ros::Time &time, const ros::Duration &period)
132  {
133  boost::mutex::scoped_lock lock(command_mutex_);
134 
135  if (attitude_input_->connected() && attitude_input_->enabled())
136  {
137  attitude_command_ = attitude_input_->getCommand();
138  }
139  if (yawrate_input_->connected() && yawrate_input_->enabled())
140  {
141  yawrate_command_ = yawrate_input_->getCommand();
142  }
143  if (thrust_input_->connected() && thrust_input_->enabled())
144  {
145  thrust_command_ = thrust_input_->getCommand();
146  }
147 
148  attitude_command_ = attitude_limiter_(attitude_command_);
149  yawrate_command_ = yawrate_limiter_(yawrate_command_);
150  thrust_command_ = thrust_limiter_(thrust_command_);
151 
152  // TODO move estop to gazebo plugin
153  if ((motor_status_->motorStatus().running == true) &&
154  !command_timeout_.isZero() && (
155  time > attitude_command_.header.stamp + command_timeout_ ||
156  time > yawrate_command_.header.stamp + command_timeout_ ||
157  time > thrust_command_.header.stamp + command_timeout_ ) )
158  {
159  if (!command_estop_) {
160  estop_thrust_command_ = thrust_command_;
161  }
162  ROS_WARN_STREAM_THROTTLE_NAMED(1.0, "attitude_controller", "No command received for "
163  << (time - std::min(std::min(attitude_command_.header.stamp, yawrate_command_.header.stamp), thrust_command_.header.stamp)).toSec() <<
164  "s, triggering estop");
165  command_estop_ = true;
166  } else if (command_estop_) {
167  command_estop_ = false;
168  }
169 
170  double roll, pitch, yaw;
171  pose_->getEulerRPY(roll, pitch, yaw);
172 
173  Twist twist = twist_->twist(), twist_body;
174  twist_body.linear = pose_->toBody(twist.linear);
175  twist_body.angular = pose_->toBody(twist.angular);
176 
177  Accel accel = accel_->acceleration(), accel_body;
178  accel_body.linear = pose_->toBody(accel.linear);
179  accel_body.angular = pose_->toBody(accel.angular);
180 
181  if (estop_ || command_estop_)
182  {
183  attitude_command_.roll = attitude_command_.pitch = yawrate_command_.turnrate = 0;
184  estop_thrust_command_.thrust -= estop_deceleration_ * mass_ * period.toSec();
185  if (estop_thrust_command_.thrust < 0) estop_thrust_command_.thrust = 0;
186  thrust_command_ = estop_thrust_command_;
187  }
188 
189  // Control approach:
190  // 1. We consider the roll and pitch commands as desired accelerations in the base_stabilized frame,
191  // not considering wind (inverse of the calculation in velocity_controller.cpp).
192  Vector3 acceleration_command_base_stabilized;
193  acceleration_command_base_stabilized.x = sin(attitude_command_.pitch);
194  acceleration_command_base_stabilized.y = -sin(attitude_command_.roll);
195  acceleration_command_base_stabilized.z = 1.0;
196 
197  // 2. Transform desired acceleration to the body frame (via the world frame).
198  // The result is independent of the yaw angle because the yaw rotation will be undone in the toBody() step.
199  double sin_yaw, cos_yaw;
200  sincos(yaw, &sin_yaw, &cos_yaw);
201  Vector3 acceleration_command_world, acceleration_command_body;
202  acceleration_command_world.x = cos_yaw * acceleration_command_base_stabilized.x - sin_yaw * acceleration_command_base_stabilized.y;
203  acceleration_command_world.y = sin_yaw * acceleration_command_base_stabilized.x + cos_yaw * acceleration_command_base_stabilized.y;
204  acceleration_command_world.z = acceleration_command_base_stabilized.z;
205  acceleration_command_body = pose_->toBody(acceleration_command_world);
206 
207  // 3. Control error is proportional to the desired acceleration in the body frame!
208  wrench_control_.wrench.torque.x = inertia_[0] * pid_.roll.computeCommand(-acceleration_command_body.y, period);
209  wrench_control_.wrench.torque.y = inertia_[1] * pid_.pitch.computeCommand(acceleration_command_body.x, period);
210  wrench_control_.wrench.torque.z = inertia_[2] * pid_.yawrate.computeCommand((yawrate_command_.turnrate - twist_body.angular.z), period);
211  wrench_control_.wrench.force.x = 0.0;
212  wrench_control_.wrench.force.y = 0.0;
213  wrench_control_.wrench.force.z = thrust_command_.thrust;
214 
215  // set wrench output
216  wrench_control_.header.stamp = time;
217  wrench_control_.header.frame_id = base_link_frame_;
218  wrench_output_->setCommand(wrench_control_.wrench);
219  }
220 
221  void estopCb(const std_msgs::BoolConstPtr &estop_msg)
222  {
223  boost::mutex::scoped_lock lock(command_mutex_);
224 
225  bool estop = static_cast<bool>(estop_msg->data);
226  if (estop_ == false && estop == true)
227  {
228  estop_thrust_command_ = thrust_command_;
229  }
230  estop_ = estop;
231  }
232 
233 private:
234 
239 
244 
246 
247  hector_uav_msgs::AttitudeCommand attitude_command_;
248  hector_uav_msgs::YawrateCommand yawrate_command_;
249  hector_uav_msgs::ThrustCommand thrust_command_;
250  geometry_msgs::WrenchStamped wrench_control_;
251 
255  std::string base_link_frame_, base_stabilized_frame_;
256  std::string tf_prefix_;
257 
259  bool estop_, command_estop_;
260  hector_uav_msgs::ThrustCommand estop_thrust_command_;
263 
264  struct
265  {
267  } pid_;
268 
269  double mass_;
270  double inertia_[3];
271 
272  boost::mutex command_mutex_;
273 };
274 
275 } // namespace hector_quadrotor_controllers
276 
278 
280 )
std::string getPrefixParam(ros::NodeHandle &nh)
hector_quadrotor_interface::YawrateCommandLimiter yawrate_limiter_
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
boost::shared_ptr< HandleType > addInput(const std::string &name)
hector_quadrotor_interface::ThrustCommandLimiter thrust_limiter_
std::string resolve(const std::string &prefix, const std::string &frame_name)
void estopCb(const std_msgs::BoolConstPtr &estop_msg)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
TFSIMD_FORCE_INLINE Vector3()
#define ROS_WARN_STREAM_THROTTLE_NAMED(rate, name, args)
boost::shared_ptr< hector_quadrotor_interface::AttitudeSubscriberHelper > attitude_subscriber_helper_
boost::shared_ptr< HandleType > addOutput(const std::string &name)
virtual void update(const ros::Time &time, const ros::Duration &period)
bool getMassAndInertia(const ros::NodeHandle &nh, double &mass, double inertia[3])
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
virtual bool init(hector_quadrotor_interface::QuadrotorInterface *interface, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
hector_quadrotor_interface::AttitudeCommandLimiter attitude_limiter_


hector_quadrotor_controllers
Author(s): Johannes Meyer , Paul Bovbel
autogenerated on Mon Jun 10 2019 13:36:53