controller.hpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Marcus Liebhardt, Yujin Robot.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of Yujin Robot nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 /*****************************************************************************
00031 ** Ifdefs
00032 *****************************************************************************/
00033 
00034 #ifndef YOCS_CONTROLLER_HPP_
00035 #define YOCS_CONTROLLER_HPP_
00036 
00037 /*****************************************************************************
00038 ** Includes
00039 *****************************************************************************/
00040 #include <cmath>
00041 #include <string>
00042 #include <geometry_msgs/Twist.h>
00043 #include <ros/ros.h>
00044 #include <std_msgs/Bool.h>
00045 #include <std_msgs/Empty.h>
00046 #include <std_msgs/Float32.h>
00047 #include <std_msgs/String.h>
00048 #include <tf/transform_listener.h>
00049 #include <yocs_controllers/default_controller.hpp>
00050 #include <yocs_math_toolkit/geometry.hpp>
00051 
00052 namespace yocs
00053 {
00054 
00080 class DiffDrivePoseController : public Controller
00081 {
00082 public:
00083   DiffDrivePoseController(ros::NodeHandle& nh, std::string& name) : Controller(),
00084                                                                        nh_(nh),
00085                                                                        name_(name){};
00086   virtual ~DiffDrivePoseController(){};
00087 
00092   bool init();
00093 
00097   void spinOnce();
00098 
00099 private:
00103   bool getPoseDiff();
00107   void getControlOutput();
00111   void setControlOutput();
00112 
00117   void controlMaxVelCB(const std_msgs::Float32ConstPtr msg);
00118 
00123   void enableCB(const std_msgs::StringConstPtr msg);
00124 
00129   void disableCB(const std_msgs::EmptyConstPtr msg);
00130 
00138   double boundRange(double v, double min, double max);
00139 
00140   // basics
00141   ros::NodeHandle nh_;
00142   std::string name_;
00143 
00144   // interfaces
00146   ros::Subscriber enable_controller_subscriber_;
00148   ros::Subscriber disable_controller_subscriber_;
00150   ros::Subscriber control_velocity_subscriber_;
00152   ros::Publisher command_velocity_publisher_;
00154   ros::Publisher pose_reached_publisher_;
00155 
00156   // variables and constants for the control law
00158   double r_;
00160   double theta_;
00162   double delta_;
00164   double v_;
00166   double v_min_;
00168   double v_max_;
00170   double w_;
00172   double w_min_;
00174   double w_max_;
00176   double cur_;
00178   double k_1_;
00180   double k_2_;
00185   double beta_;
00190   double lambda_;
00192   double dist_thres_;
00194   double orient_thres_;
00196   bool pose_reached_;
00198   double dist_eps_;
00200   double orient_eps_;
00201 
00203   tf::TransformListener tf_listener_;
00205   tf::StampedTransform tf_goal_pose_rel_;
00207   std::string base_frame_name_;
00209   std::string goal_frame_name_;
00210 };
00211 
00212 bool DiffDrivePoseController::init()
00213 {
00214   enable_controller_subscriber_ = nh_.subscribe("enable", 10, &DiffDrivePoseController::enableCB, this);
00215   disable_controller_subscriber_ = nh_.subscribe("disable", 10, &DiffDrivePoseController::disableCB, this);
00216   control_velocity_subscriber_ = nh_.subscribe("control_max_vel", 10, &DiffDrivePoseController::controlMaxVelCB, this);
00217   command_velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>("command_velocity", 10);
00218   pose_reached_publisher_ = nh_.advertise<std_msgs::Bool>("pose_reached", 10);
00219 
00220   // retrieve configuration parameters
00221   base_frame_name_ = "base_footprint";
00222   if(!nh_.getParam("base_frame_name", base_frame_name_))
00223   {
00224     ROS_WARN_STREAM("Couldn't retrieve parameter 'base_frame_name' from parameter server! Using default '"
00225                     << base_frame_name_ << "'. [" << name_ <<"]");
00226   }
00227   goal_frame_name_ = "base_goal_pose";
00228   if(!nh_.getParam("goal_frame_name", goal_frame_name_))
00229   {
00230     ROS_WARN_STREAM("Couldn't retrieve parameter 'goal_frame_name' from parameter server! Using default '"
00231                     << goal_frame_name_ << "'. [" << name_ <<"]");
00232   }
00233   v_ = 0.0;
00234   v_min_ = 0.01;
00235   if(!nh_.getParam("v_min", v_min_))
00236   {
00237     ROS_WARN_STREAM("Couldn't retrieve parameter 'v_min' from parameter server! Using default '"
00238                     << v_min_ << "'. [" << name_ <<"]");
00239   }
00240   v_max_ = 0.5;
00241   if(!nh_.getParam("v_max", v_max_))
00242   {
00243     ROS_WARN_STREAM("Couldn't retrieve parameter 'v_max' from parameter server! Using default '"
00244                     << v_max_ << "'. [" << name_ <<"]");
00245   }
00246   w_min_ = 0.01;
00247   if(!nh_.getParam("w_min", w_min_))
00248   {
00249     ROS_WARN_STREAM("Couldn't retrieve parameter 'w_min' from parameter server! Using default '"
00250                     << w_min_ << "'. [" << name_ <<"]");
00251   }
00252   w_max_ = M_PI / 4 * v_max_;
00253   if(!nh_.getParam("w_max", w_max_))
00254   {
00255     ROS_WARN_STREAM("Couldn't retrieve parameter 'w_max' from parameter server! Using default '"
00256                     << w_max_ << "'. [" << name_ <<"]");
00257   }
00258   k_1_ = 1.0;
00259   if(!nh_.getParam("k_1", k_1_))
00260   {
00261     ROS_WARN_STREAM("Couldn't retrieve parameter 'k_1' from parameter server! Using default '"
00262                     << k_1_ << "'. [" << name_ <<"]");
00263   }
00264   k_2_ = 3.0;
00265   if(!nh_.getParam("k_2", k_2_))
00266   {
00267     ROS_WARN_STREAM("Couldn't retrieve parameter 'k_2' from parameter server! Using default '"
00268                     << k_2_ << "'. [" << name_ <<"]");
00269   }
00270   beta_ = 0.4;
00271   if(!nh_.getParam("beta", beta_))
00272   {
00273     ROS_WARN_STREAM("Couldn't retrieve parameter 'beta' from parameter server! Using default '"
00274                     << beta_ << "'. [" << name_ <<"]");
00275   }
00276   lambda_ = 2.0;
00277   if(!nh_.getParam("lambda", lambda_))
00278   {
00279     ROS_WARN_STREAM("Couldn't retrieve parameter 'lambda' from parameter server! Using default '"
00280                     << lambda_ << "'. [" << name_ <<"]");
00281   }
00282   dist_thres_ = 0.01;
00283   if(!nh_.getParam("dist_thres", dist_thres_))
00284   {
00285     ROS_WARN_STREAM("Couldn't retrieve parameter 'dist_thres' from parameter server! Using default '"
00286                     << dist_thres_ << "'. [" << name_ <<"]");
00287   }
00288   orient_thres_ = 0.02;
00289   if(!nh_.getParam("orient_thres", orient_thres_))
00290   {
00291     ROS_WARN_STREAM("Couldn't retrieve parameter 'orient_thres' from parameter server! Using default '"
00292                     << orient_thres_ << "'. [" << name_ <<"]");
00293   }
00294   dist_eps_ = dist_eps_ * 0.2;
00295   if(!nh_.getParam("dist_eps", dist_eps_))
00296   {
00297     ROS_WARN_STREAM("Couldn't retrieve parameter 'dist_eps' from parameter server! Using default '"
00298                     << dist_eps_ << "'. [" << name_ <<"]");
00299   }
00300   orient_eps_ = orient_thres_ * 0.2;
00301   if(!nh_.getParam("orient_eps", orient_eps_))
00302   {
00303     ROS_WARN_STREAM("Couldn't retrieve parameter 'orient_eps' from parameter server! Using default '"
00304                     << orient_eps_ << "'. [" << name_ <<"]");
00305   }
00306   pose_reached_ = false;
00307   ROS_DEBUG_STREAM("Controller initialised with the following parameters: [" << name_ <<"]");
00308   ROS_DEBUG_STREAM("base_frame_name = " << base_frame_name_ <<", goal_frame_name = "
00309                    << goal_frame_name_ << " [" << name_ <<"]");
00310   ROS_DEBUG_STREAM("v_max = " << v_max_ <<", k_1 = " << k_1_ << ", k_2 = " << k_2_ << ", beta = " << beta_
00311                    << ", lambda = " << lambda_ << ", dist_thres = " << dist_thres_
00312                    << ", orient_thres = " << orient_thres_ <<" [" << name_ <<"]");
00313   return true;
00314 };
00315 
00316 void DiffDrivePoseController::spinOnce()
00317 {
00318   if (this->getState())
00319   {
00320     ROS_DEBUG_STREAM_THROTTLE(1.0, "Controller spinning. [" << name_ <<"]");
00321     // determine pose difference in polar coordinates
00322     if (!getPoseDiff())
00323     {
00324       ROS_WARN_STREAM_THROTTLE(1.0, "Getting pose difference failed. Skipping control loop. [" << name_ <<"]");
00325       return;
00326     }
00327     // determine controller output (v, w)
00328     getControlOutput();
00329     // set control output (v, w)
00330     setControlOutput();
00331     // Logging
00332     ROS_DEBUG_STREAM_THROTTLE(1.0, "Current state: [" << name_ <<"]");
00333     ROS_DEBUG_STREAM_THROTTLE(1.0, "r = " << r_ << ", theta = " << theta_ << ", delta = " << delta_
00334                                    << " [" << name_ <<"]");
00335     ROS_DEBUG_STREAM_THROTTLE(1.0, "cur = " << cur_ << ", v = " << v_ << ", w = " << w_ << " [" << name_ <<"]");
00336   }
00337   else
00338   {
00339     ROS_DEBUG_STREAM_THROTTLE(3.0, "Controller is disabled. Idling ... [" << name_ <<"]");
00340   }
00341 };
00342 
00343 bool DiffDrivePoseController::getPoseDiff()
00344 {
00345   // use tf to get information about the goal pose relative to the base
00346   try
00347   {
00348     tf_listener_.lookupTransform(base_frame_name_, goal_frame_name_, ros::Time(0), tf_goal_pose_rel_);
00349   }
00350   catch (tf::TransformException const &ex)
00351   {
00352     ROS_WARN_STREAM_THROTTLE(1.0, "Couldn't get transform from base to goal pose! [" << name_ <<"]");
00353     ROS_DEBUG_STREAM_THROTTLE(1.0, "tf error: " << ex.what());
00354     return false;
00355   }
00356 
00357   // determine distance to goal
00358   r_ = std::sqrt(std::pow(tf_goal_pose_rel_.getOrigin().getX(), 2)
00359                  + std::pow(tf_goal_pose_rel_.getOrigin().getY(), 2));
00360   // determine orientation of r relative to the base frame
00361   delta_ = std::atan2(-tf_goal_pose_rel_.getOrigin().getY(), tf_goal_pose_rel_.getOrigin().getX());
00362   
00363   // determine orientation of r relative to the goal frame
00364   // helper: theta = tf's orientation + delta
00365   double heading =  mtk::wrapAngle(tf::getYaw(tf_goal_pose_rel_.getRotation()));
00366   theta_ = heading + delta_;
00367 
00368   return true;
00369 };
00370 
00371 void DiffDrivePoseController::getControlOutput()
00372 {
00373   double atan2_k1_tehta = std::atan2(-theta_, k_1_);
00374 
00375   cur_ = (-1 / r_) * (k_2_ * (delta_ - atan2_k1_tehta)
00376          + (1 + (k_1_ / (1 + std::pow((k_1_ * theta_), 2)))) * sin(delta_));
00377   v_ = v_max_ / (1 + beta_ * std::pow(std::abs(cur_), lambda_));
00378 
00379   v_ = boundRange(v_, v_min_, v_max_);
00380 
00381   w_ = cur_ * v_; // unbounded for now
00382   w_ = boundRange(w_, w_min_, w_max_);
00383 
00384   // pose reached thresholds
00385   if (r_ <= dist_thres_)
00386   {
00387     v_ = 0;
00388     if (std::abs(delta_ - theta_) <= orient_thres_)
00389     {
00390       w_ = 0;
00391     }
00392   }
00393 
00394   // check, if pose has been reached
00395   if ((r_ <= dist_thres_) && (std::abs(delta_ - theta_) <= orient_thres_))
00396   {
00397     if (!pose_reached_)
00398     {
00399       pose_reached_ = true;
00400       ROS_INFO_STREAM("Pose reached. [" << name_ <<"]");
00401       std_msgs::Bool bool_msg;
00402       bool_msg.data = true;
00403       pose_reached_publisher_.publish(bool_msg);
00404     }
00405   }
00406   else if ((r_ > (dist_thres_ + dist_eps_)) || (std::abs(delta_ - theta_) > (orient_thres_ + orient_eps_)))
00407   {
00408     if (pose_reached_)
00409     {
00410       pose_reached_ = false;
00411       ROS_INFO_STREAM("Tracking new goal pose. [" << name_ <<"]");
00412     }
00413   }
00414 };
00415 
00416 double DiffDrivePoseController::boundRange(double v, double min, double max)
00417 {
00418   // bounds for v
00419   if (v < 0.0)
00420   {
00421     if (v > -min)
00422     {
00423       v = -min;
00424     }
00425     else if (v < -max)
00426     {
00427       v = -max;
00428     }
00429   }
00430   else
00431   {
00432     if (v < min)
00433     {
00434       v = min;
00435     }
00436     else if (v > max)
00437     {
00438       v = max;
00439     }
00440   }
00441 
00442   return v;
00443 }
00444 
00445 void DiffDrivePoseController::setControlOutput()
00446 {
00447   geometry_msgs::TwistPtr cmd_vel(new geometry_msgs::Twist());
00448   if (!pose_reached_)
00449   {
00450     cmd_vel->linear.x = v_;
00451     cmd_vel->angular.z = w_;
00452   }
00453   command_velocity_publisher_.publish(cmd_vel);
00454 };
00455 
00456 void DiffDrivePoseController::controlMaxVelCB(const std_msgs::Float32ConstPtr msg)
00457 {
00458   v_max_ = msg->data;
00459   ROS_INFO_STREAM("Maximum linear control velocity has been set to " << v_max_ << ". [" << name_ << "]");
00460 };
00461 
00462 void DiffDrivePoseController::enableCB(const std_msgs::StringConstPtr msg)
00463 {
00464   if (this->enable())
00465   {
00466     goal_frame_name_ = msg->data;
00467     ROS_INFO_STREAM("Controller has been enabled. [" << name_ << "] with goal frame [" << goal_frame_name_ << "]");
00468   }
00469   else
00470   {
00471     ROS_INFO_STREAM("Controller was already enabled. [" << name_ <<"] with Goal frame [" << goal_frame_name_ << "]");
00472   }
00473 };
00474 
00475 void DiffDrivePoseController::disableCB(const std_msgs::EmptyConstPtr msg)
00476 {
00477   if (this->disable())
00478   {
00479     ROS_INFO_STREAM("Controller has been disabled. [" << name_ <<"]");
00480   }
00481   else
00482   {
00483     ROS_INFO_STREAM("Controller was already disabled. [" << name_ <<"]");
00484   }
00485 };
00486 
00487 } // namespace yocs
00488 
00489 #endif /* YOCS_CONTROLLER_HPP_ */


yocs_diff_drive_pose_controller
Author(s): Marcus Liebhardt
autogenerated on Thu Jun 6 2019 21:47:33