CmdVelSafety.cpp
Go to the documentation of this file.
00001 
00002 
00003 #include "ros/ros.h"
00004 #include "geometry_msgs/Twist.h"
00005 #include "nav_msgs/GridCells.h"
00006 #include "tf/transform_listener.h"
00007 #include "tf/transform_datatypes.h"
00008 
00009 #include <math.h>
00010 #include <unistd.h>
00011 
00012 #include <boost/shared_ptr.hpp>
00013 
00014 using namespace std;
00015 
00016 double min_spd = 0.075; //any speed lower than this is allowed
00017 double max_spd = 1.5; //maximum speed to be sent as a command vel
00018 
00019 double timestep = 0.2; //how many seconds to estimate into the future
00020 
00021 double stop_radius = 0.5;
00022 double inflation_radius=1.5;
00023 
00024 bool has_grid=false;
00025 nav_msgs::GridCells obstacles;
00026 
00027 ros::Publisher cmd_vel_pub;
00028 
00029 boost::shared_ptr<tf::TransformListener> tf_listener;
00030 
00031 double getMinimumDistance(tf::Vector3 position, nav_msgs::GridCells grid) {
00032 
00033   double distance_sq=-1;
00034   int size = grid.cells.size();
00035   double my_x=position.getX(), my_y=position.getY();
00036   double stop_radius_sq = stop_radius*stop_radius;
00037   for (int i=0; i<size; i++) {
00038     double d_sq = pow(grid.cells[i].x-my_x,2)+pow(grid.cells[i].y-my_y,2);
00039     if (distance_sq==-1 || d_sq<distance_sq) distance_sq=d_sq;
00040     if (d_sq<=stop_radius_sq) return 0;
00041   }
00042 
00043   return sqrt(distance_sq);
00044 }
00045 
00046 double getSafeVelocityLimit(tf::Vector3 vel) {
00047   //get current position + orientation
00048   //   by listening to the transform from obstacles->header->frame_id to /base_link
00049   tf::StampedTransform transform;
00050   try {
00051     tf_listener->lookupTransform(
00052         obstacles.header.frame_id,
00053         "/base_link",
00054         ros::Time(0),
00055         transform);
00056   }
00057   catch (tf::TransformException ex) {
00058     ROS_ERROR("Couldn't get current position: %s",ex.what());
00059     return min_spd;
00060   }
00061   //estimate future position, current_position+cmd_vel*sometimeconst*orientation
00062   tf::Vector3 future_pos = transform.getOrigin();
00063   tf::Vector3 v = vel.rotate(tf::Vector3(0,0,1),tf::getYaw(transform.getRotation()));
00064   future_pos=future_pos+timestep*v;
00065   //get minimum distance of future position
00066   if (!has_grid) {
00067     ROS_ERROR("Haven't received a grid yet so speed will be fully limited");
00068     return min_spd;
00069   }
00070   double mindist = getMinimumDistance(future_pos,obstacles);
00071   ROS_DEBUG("got minimum distance %f",mindist);
00072   //calculate velocity scale based on mindist of futurepos 
00073   //   (minspd@<=minrad --lerp--> 1@>=maxrad)
00074   double speed_limit;
00075   if (mindist>inflation_radius) speed_limit=max_spd;
00076   else if (mindist<=stop_radius) speed_limit=min_spd;
00077   else speed_limit = min(min_spd+(max_spd-min_spd)*(mindist-stop_radius)/(inflation_radius-stop_radius),max_spd);
00078   //return it
00079   ROS_DEBUG_STREAM("  computed velocity scale: "<<speed_limit);
00080   return speed_limit;
00081 }
00082 
00083 void obstaclesCallback(const nav_msgs::GridCells::ConstPtr& msg)
00084 {
00085   if (!has_grid) ROS_INFO("Got first grid");
00086   else ROS_DEBUG("Got a grid");
00087   obstacles = *msg;
00088   has_grid=true;
00089 }
00090 
00091 void cmdVelCallback(const geometry_msgs::Twist::ConstPtr& msg)
00092 {
00093   geometry_msgs::Twist vel = *msg;
00094   ROS_DEBUG_STREAM("Got unsafe command vel (" 
00095       << vel.linear.x << ", "
00096       << vel.linear.y << ", " 
00097       << vel.angular.z << ")" );
00098   //put it in a tf vector for convenience
00099   tf::Vector3 v;
00100   v.setX(vel.linear.x);
00101   v.setY(vel.linear.y);
00102   //find the speed
00103   double speed = v.length();
00104   //find the speed limit
00105   double speed_limit = getSafeVelocityLimit(v);
00106   //limit the speed if needed
00107   if (speed_limit<speed) {
00108     v=v.normalized()*speed_limit;
00109     vel.linear.x=v.getX();
00110     vel.linear.y=v.getY();
00111   }
00112   //publish the limited speed
00113   cmd_vel_pub.publish(vel);
00114   ROS_DEBUG_STREAM("Sent safe command vel (" 
00115       << vel.linear.x << ", "
00116       << vel.linear.y << ", " 
00117       << vel.angular.z << ")" );
00118 }
00119 
00120 int main(int argc, char **argv)
00121 {
00122   ros::init(argc, argv, "cmd_vel_safety");
00123 
00124   ros::NodeHandle n;
00125 
00126   n.getParam("/move_base_node/local_costmap/inflation_radius",stop_radius);
00127   ROS_INFO("Using obstacle radius of %lf",stop_radius);
00128   inflation_radius=max(stop_radius*1.5,stop_radius+0.2);
00129 
00130   tf_listener.reset(new tf::TransformListener());
00131 
00132   ros::Subscriber cmd_vel_sub;
00133   ROS_INFO("Subscribing to cmd_vel_unsafe");
00134   cmd_vel_sub = n.subscribe("cmd_vel_unsafe", 1, cmdVelCallback);
00135 
00136   ros::Subscriber grid_sub;
00137   ROS_INFO("Subscribing to /move_base_node/local_costmap/obstacles");
00138   grid_sub = n.subscribe("/move_base_node/global_costmap/obstacles", 1, obstaclesCallback);
00139 
00140   ROS_INFO("Advertising safe command velocity publisher");
00141   cmd_vel_pub = n.advertise<geometry_msgs::Twist>("cmd_vel",1);
00142 
00143   ros::spin();
00144 }
00145 


youbot_oodl
Author(s): Sebastian Blumenthal
autogenerated on Mon Oct 6 2014 09:06:15