34 #include <geometry_msgs/TwistStamped.h>    35 #include <geometry_msgs/WrenchStamped.h>    36 #include <std_srvs/Empty.h>    41 #include <boost/thread.hpp>    66     node_handle_ = root_nh;
    73     engage_service_server_ = node_handle_.advertiseService<std_srvs::Empty::Request, std_srvs::Empty::Response>(
"engage", boost::bind(&
TwistController::engageCallback, 
this, _1, _2));
    74     shutdown_service_server_ = node_handle_.advertiseService<std_srvs::Empty::Request, std_srvs::Empty::Response>(
"shutdown", boost::bind(&
TwistController::shutdownCallback, 
this, _1, _2));
    85     controller_nh.
getParam(
"auto_engage", auto_engage_ = 
true);
    86     controller_nh.
getParam(
"limits/load_factor", load_factor_limit = 1.5);
    87     controller_nh.
getParam(
"limits/force/z", limits_.force.z);
    88     controller_nh.
getParam(
"limits/torque/xy", limits_.torque.x);
    89     controller_nh.
getParam(
"limits/torque/xy", limits_.torque.y);
    90     controller_nh.
getParam(
"limits/torque/z", limits_.torque.z);
    91     root_nh.
param<std::string>(
"base_link_frame", base_link_frame_, 
"base_link");
    96     command_given_in_stabilized_frame_ = 
false;
   103     pid_.linear.x.reset();
   104     pid_.linear.y.reset();
   105     pid_.linear.z.reset();
   106     pid_.angular.x.reset();
   107     pid_.angular.y.reset();
   108     pid_.angular.z.reset();
   110     wrench_.wrench.force.x  = 0.0;
   111     wrench_.wrench.force.y  = 0.0;
   112     wrench_.wrench.force.z  = 0.0;
   113     wrench_.wrench.torque.x = 0.0;
   114     wrench_.wrench.torque.y = 0.0;
   115     wrench_.wrench.torque.z = 0.0;
   117     linear_z_control_error_ = 0.0;
   118     motors_running_ = 
false;
   123     boost::mutex::scoped_lock lock(command_mutex_);
   126     if (command_.header.stamp.isZero()) command_.header.stamp = 
ros::Time::now();
   127     command_given_in_stabilized_frame_ = 
false;
   130     if (!isRunning()) this->startRequest(command_.header.stamp);
   135     boost::mutex::scoped_lock lock(command_mutex_);
   137     command_.twist = *command;
   139     command_given_in_stabilized_frame_ = 
true;
   142     if (!isRunning()) this->startRequest(command_.header.stamp);
   147     boost::mutex::scoped_lock lock(command_mutex_);
   150     motors_running_ = 
true;
   156     boost::mutex::scoped_lock lock(command_mutex_);
   159     motors_running_ = 
false;
   166     wrench_output_->start();
   171     wrench_output_->stop();
   176     boost::mutex::scoped_lock lock(command_mutex_);
   179     if (twist_input_->connected() && twist_input_->enabled()) {
   180       command_.twist = twist_input_->getCommand();
   181       command_given_in_stabilized_frame_ = 
false;
   185     Twist 
command = command_.twist;
   186     Twist twist = twist_->twist();
   188     twist_body.linear =  pose_->toBody(twist.linear);
   189     twist_body.angular = pose_->toBody(twist.angular);
   192     if (command_given_in_stabilized_frame_) {
   193       double yaw = pose_->getYaw();
   194       Twist transformed = command;
   195       transformed.linear.x  = cos(yaw) * command.linear.x  - sin(yaw) * command.linear.y;
   196       transformed.linear.y  = sin(yaw) * command.linear.x  + cos(yaw) * command.linear.y;
   197       transformed.angular.x = cos(yaw) * command.angular.x - sin(yaw) * command.angular.y;
   198       transformed.angular.y = sin(yaw) * command.angular.x + cos(yaw) * command.angular.y;
   199       command = transformed;
   203     const double gravity = 9.8065;
   204     double load_factor = 1. / (  pose_->pose().orientation.w * pose_->pose().orientation.w
   205                                  - pose_->pose().orientation.x * pose_->pose().orientation.x
   206                                  - pose_->pose().orientation.y * pose_->pose().orientation.y
   207                                  + pose_->pose().orientation.z * pose_->pose().orientation.z );
   209     if (load_factor_limit > 0.0 && !(load_factor < load_factor_limit)) load_factor = load_factor_limit;
   213       if (!motors_running_ && command.linear.z > 0.1 && load_factor > 0.0) {
   214         motors_running_ = 
true;
   216       } 
else if (motors_running_ && command.linear.z < -0.1 ) {
   217         double shutdown_limit = 0.25 * std::min(command.linear.z, -0.5);
   218         if (linear_z_control_error_ > 0.0) linear_z_control_error_ = 0.0; 
   219         if (pid_.linear.z.getFilteredControlError(linear_z_control_error_, 5.0, period) < shutdown_limit) {
   220           motors_running_ = 
false;
   223           ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"z control error = " << linear_z_control_error_ << 
" >= " << shutdown_limit);
   226         linear_z_control_error_ = 0.0;
   230       if (motors_running_ && load_factor < 0.0) {
   231         motors_running_ = 
false;
   232         ROS_WARN_NAMED(
"twist_controller", 
"Shutting down motors due to flip over!");
   237     if (motors_running_) {
   238       Vector3 acceleration_command;
   239       acceleration_command.x = pid_.linear.x.update(command.linear.x, twist.linear.x, acceleration_->acceleration().x, period);
   240       acceleration_command.y = pid_.linear.y.update(command.linear.y, twist.linear.y, acceleration_->acceleration().y, period);
   241       acceleration_command.z = pid_.linear.z.update(command.linear.z, twist.linear.z, acceleration_->acceleration().z, period) + gravity;
   242       Vector3 acceleration_command_body = pose_->toBody(acceleration_command);
   244       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"twist.linear:               [" << twist.linear.x << 
" " << twist.linear.y << 
" " << twist.linear.z << 
"]");
   245       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"twist_body.angular:         [" << twist_body.angular.x << 
" " << twist_body.angular.y << 
" " << twist_body.angular.z << 
"]");
   246       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"twist_command.linear:       [" << command.linear.x << 
" " << command.linear.y << 
" " << command.linear.z << 
"]");
   247       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"twist_command.angular:      [" << command.angular.x << 
" " << command.angular.y << 
" " << command.angular.z << 
"]");
   248       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"acceleration:               [" << acceleration_->acceleration().x << 
" " << acceleration_->acceleration().y << 
" " << acceleration_->acceleration().z << 
"]");
   249       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"acceleration_command_world: [" << acceleration_command.x << 
" " << acceleration_command.y << 
" " << acceleration_command.z << 
"]");
   250       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"acceleration_command_body:  [" << acceleration_command_body.x << 
" " << acceleration_command_body.y << 
" " << acceleration_command_body.z << 
"]");
   252       wrench_.wrench.torque.x = inertia_[0] * pid_.angular.x.update(-acceleration_command_body.y / gravity, 0.0, twist_body.angular.x, period);
   253       wrench_.wrench.torque.y = inertia_[1] * pid_.angular.y.update( acceleration_command_body.x / gravity, 0.0, twist_body.angular.y, period);
   254       wrench_.wrench.torque.z = inertia_[2] * pid_.angular.z.update( command.angular.z, twist.angular.z, 0.0, period);
   255       wrench_.wrench.force.x  = 0.0;
   256       wrench_.wrench.force.y  = 0.0;
   257       wrench_.wrench.force.z  = mass_ * ((acceleration_command.z - gravity) * load_factor + gravity);
   259       if (limits_.force.z > 0.0 && wrench_.wrench.force.z > limits_.force.z) wrench_.wrench.force.z = limits_.force.z;
   260       if (wrench_.wrench.force.z <= std::numeric_limits<double>::min()) wrench_.wrench.force.z = std::numeric_limits<double>::min();
   261       if (limits_.torque.x > 0.0) {
   262         if (wrench_.wrench.torque.x >  limits_.torque.x) wrench_.wrench.torque.x =  limits_.torque.x;
   263         if (wrench_.wrench.torque.x < -limits_.torque.x) wrench_.wrench.torque.x = -limits_.torque.x;
   265       if (limits_.torque.y > 0.0) {
   266         if (wrench_.wrench.torque.y >  limits_.torque.y) wrench_.wrench.torque.y =  limits_.torque.y;
   267         if (wrench_.wrench.torque.y < -limits_.torque.y) wrench_.wrench.torque.y = -limits_.torque.y;
   269       if (limits_.torque.z > 0.0) {
   270         if (wrench_.wrench.torque.z >  limits_.torque.z) wrench_.wrench.torque.z =  limits_.torque.z;
   271         if (wrench_.wrench.torque.z < -limits_.torque.z) wrench_.wrench.torque.z = -limits_.torque.z;
   274       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"wrench_command.force:       [" << wrench_.wrench.force.x << 
" " << wrench_.wrench.force.y << 
" " << wrench_.wrench.force.z << 
"]");
   275       ROS_DEBUG_STREAM_NAMED(
"twist_controller", 
"wrench_command.torque:      [" << wrench_.wrench.torque.x << 
" " << wrench_.wrench.torque.y << 
" " << wrench_.wrench.torque.z << 
"]");
   282     wrench_.header.stamp = time;
   283     wrench_.header.frame_id = base_link_frame_;
   284     wrench_output_->setCommand(wrench_.wrench);
 void stopping(const ros::Time &time)
AccelerationHandlePtr acceleration_
virtual bool getMassAndInertia(double &mass, double inertia[3])
boost::shared_ptr< HandleType > addOutput(const std::string &name)
geometry_msgs::TwistStamped command_
#define ROS_INFO_NAMED(name,...)
#define ROS_DEBUG_STREAM_NAMED(name, args)
#define ROS_WARN_NAMED(name,...)
double linear_z_control_error_
std::string base_link_frame_
void update(const ros::Time &time, const ros::Duration &period)
TwistCommandHandlePtr twist_input_
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
ros::NodeHandle node_handle_
boost::shared_ptr< HandleType > addInput(const std::string &name)
void starting(const ros::Time &time)
virtual AccelerationHandlePtr getAcceleration()
bool engageCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
ROSLIB_DECL std::string command(const std::string &cmd)
void twistCommandCallback(const geometry_msgs::TwistStampedConstPtr &command)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const 
ros::ServiceServer engage_service_server_
ros::Subscriber cmd_vel_subscriber_
ros::ServiceServer shutdown_service_server_
ros::Subscriber twist_subscriber_
geometry_msgs::Wrench limits_
bool getParam(const std::string &key, std::string &s) const 
virtual PoseHandlePtr getPose()
void cmd_velCommandCallback(const geometry_msgs::TwistConstPtr &command)
boost::mutex command_mutex_
WrenchCommandHandlePtr wrench_output_
bool command_given_in_stabilized_frame_
geometry_msgs::WrenchStamped wrench_
virtual TwistHandlePtr getTwist()
bool shutdownCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
bool init(QuadrotorInterface *interface, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)