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;
00017 double max_spd = 1.5;
00018
00019 double timestep = 0.2;
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
00048
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
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
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
00073
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
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
00099 tf::Vector3 v;
00100 v.setX(vel.linear.x);
00101 v.setY(vel.linear.y);
00102
00103 double speed = v.length();
00104
00105 double speed_limit = getSafeVelocityLimit(v);
00106
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
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