teleop_safety.cpp
Go to the documentation of this file.
00001 #include <carl_safety/teleop_safety.h>
00002 
00003 using namespace std;
00004 
00005 teleop_safety::teleop_safety()
00006 {
00007   // a private handle for this ROS node (allows retrieval of relative parameters)
00008   ros::NodeHandle private_nh("~");
00009 
00010   // create the ROS topics
00011   cmd_vel_pub = node.advertise<geometry_msgs::Twist>("cmd_vel", 10);
00012   cmd_vel_safety_check = node.subscribe<geometry_msgs::Twist>("/cmd_vel_safety_check", 10, &teleop_safety::cmd_vel_safety_check_cback, this);
00013   scan_sub = node.subscribe<sensor_msgs::LaserScan>("/scan", 10, &teleop_safety::scan_cback, this);
00014   map_sub = node.subscribe<nav_msgs::OccupancyGrid>("/map", 10, &teleop_safety::map_cback, this);
00015   amcl_pose_sub = node.subscribe<geometry_msgs::PoseWithCovarianceStamped>("/amcl_pose", 10, &teleop_safety::amcl_pose_cback, this);
00016 
00017   // initialize everything
00018   pListener = new (tf::TransformListener);
00019 
00020   forward_throttle_safety_factor_base = 0.0;
00021   reverse_throttle_safety_factor_base = 0.0;
00022 }
00023 
00024 teleop_safety::~teleop_safety()
00025 {
00026   delete pListener;
00027 }
00028 
00029 void teleop_safety::cmd_vel_safety_check_cback(const geometry_msgs::Twist::ConstPtr& cmd)
00030 {
00031   twist = *cmd;
00032   if(twist.linear.x > 0){
00033     twist.linear.x *= forward_throttle_safety_factor_base;
00034   }
00035   else if(twist.linear.x < 0){
00036     twist.linear.x *= reverse_throttle_safety_factor_base;
00037   }
00038   cmd_vel_pub.publish(twist);
00039 }
00040 
00041 void teleop_safety::scan_cback(const sensor_msgs::LaserScan::ConstPtr& ptr)
00042 {
00043   static int index = 0;
00044   static double closestDists[2];
00045   geometry_msgs::PointStamped laser_point;
00046   geometry_msgs::PointStamped base_point;
00047 
00048   sensor_msgs::LaserScan scan = *ptr;
00049 
00050   laser_point.header.frame_id = "hokuyo_link";
00051   laser_point.header.stamp = scan.header.stamp;
00052   laser_point.point.z = 0.0;
00053 
00054   int i = 0;
00055   double currentAngle;
00056   double closestDist = scan.range_max;
00057 
00058   for(currentAngle = scan.angle_min; currentAngle < scan.angle_max; currentAngle+=scan.angle_increment){
00059     //if the point is not within range
00060     if(scan.ranges[i] < scan.range_min || scan.ranges[i] > scan.range_max || isnan(scan.ranges[i])){
00061        i++;
00062        continue;
00063     }
00064 
00065     //get the x and y components of the vector to the point
00066     laser_point.point.x = cos(currentAngle) * scan.ranges[i];
00067     laser_point.point.y = sin(currentAngle) * scan.ranges[i];
00068     try{
00069       //transform that point to the base_link frame
00070       pListener->transformPoint("base_link", laser_point, base_point);
00071     }
00072     catch(tf::TransformException& ex){
00073       i++;
00074       continue;
00075     }
00076     
00077     //calculate the distance to point
00078     double dist = sqrt(pow(base_point.point.x,2.0)+pow(base_point.point.y,2.0));
00079     //if it is the closest point in the scan record it
00080     if(dist < closestDist){
00081       closestDist = dist;
00082     }
00083     i++;
00084   }
00085   
00086   //record the new closest point in the buffer of last 3 closest distances
00087   closestDists[index] = closestDist;
00088   if(index+1==2) index=0;
00089   else index++;
00090 
00091   //take the closest distance of the last 3 scans to determine speed with
00092   closestDist = scan.range_max;
00093   for(i = 0; i < 2; i++)
00094     if(closestDists[i] < closestDist)
00095       closestDist = closestDists[i];
00096 
00097   //set the throttle value based on the distance
00098   if(closestDist < MIN_FORWARD_SAFE_DIST)
00099     forward_throttle_safety_factor_base = 0.0;
00100   else if(closestDist > START_FORWARD_SAFETY_THROTTLE_DIST)
00101     forward_throttle_safety_factor_base = 1.0;
00102   else{
00103     forward_throttle_safety_factor_base = (closestDist-MIN_FORWARD_SAFE_DIST)/(START_FORWARD_SAFETY_THROTTLE_DIST-MIN_FORWARD_SAFE_DIST);
00104     if(forward_throttle_safety_factor_base < 0.1) forward_throttle_safety_factor_base = 0.1;
00105   }
00106   
00107 }
00108 
00109 void teleop_safety::map_cback(const nav_msgs::OccupancyGrid::ConstPtr& map){
00110   //captures the map for later use
00111   savedMap = *map;
00112 }
00113 
00114 void teleop_safety::amcl_pose_cback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& pose){
00115   //get distances in occupancy grid units 
00116   static double startTrottleDistMap = START_REVERSE_SAFETY_THROTTLE_DIST/savedMap.info.resolution;
00117   static double minSafeDistMap = MIN_REVERSE_SAFE_DIST/savedMap.info.resolution;
00118 
00119   //get the yaw angle of robot in radians 
00120   double angle = tf::getYaw(pose->pose.pose.orientation);
00121   double closestDist;
00122 
00123   //round estimated position to nearest occupancy grid cell
00124   int i = round(pose->pose.pose.position.y/savedMap.info.resolution);
00125   int j = round(pose->pose.pose.position.x/savedMap.info.resolution);
00126 
00127   closestDist = startTrottleDistMap;
00128   reverse_throttle_safety_factor_base = 0.8;
00129   //for each grid cell that is within startTrottleDistMap of (x,y)
00130   for(int x = i - (int)round(startTrottleDistMap); x < i + (int)round(startTrottleDistMap); x++){
00131     for(int y = j - (int)round(startTrottleDistMap); y < j + (int)round(startTrottleDistMap); y++){
00132 
00133       //if current point is within the map and is an obstical 
00134       if(x >= 0 && x < savedMap.info.height && y >= 0 && y < savedMap.info.width 
00135          && savedMap.data[(x*savedMap.info.width) + y] != 0){
00136 
00137         //get the angle and distance of the point in relation to the robot in the grid
00138         double ptAngle = atan2(x-i,y-j);
00139         double dist = sqrt(pow(x-i,2)+pow(y-j,2));
00140 
00141         double angleDiff = angle-ptAngle;
00142         while (angleDiff < -M_PI) angleDiff += (2*M_PI);
00143         while (angleDiff > M_PI) angleDiff -= (2*M_PI);
00144 
00145         //if the point is the clostes point thus far and it is behind the robot
00146         if(dist<=closestDist && angleDiff>(3*M_PI/4)){//(ptAngle<angle-(3*M_PI/4) || ptAngle>angle+(3*M_PI/4))){
00147           //set new closest distance
00148           closestDist = dist;
00149           //if the distance is below the min allowed stop the robot
00150           if(closestDist < minSafeDistMap)
00151             reverse_throttle_safety_factor_base = 0.0; 
00152           //else if it is in the trottle zone, linearly decearse the allowed speed 
00153           //in relation to the distance of the point
00154           else if(closestDist <= startTrottleDistMap){
00155             reverse_throttle_safety_factor_base = (closestDist-minSafeDistMap)/(startTrottleDistMap-minSafeDistMap);
00156             if(reverse_throttle_safety_factor_base < 0.1) reverse_throttle_safety_factor_base = 0.1;
00157           }
00158         } 
00159 
00160       }
00161     }
00162   }
00163   
00164   if(reverse_throttle_safety_factor_base > 0.8) reverse_throttle_safety_factor_base = 0.8;
00165 }
00166 
00167 int main(int argc, char **argv)
00168 {
00169   // initialize ROS and the node
00170   ros::init(argc, argv, "teleop_safety");
00171   teleop_safety t;
00172   ros::Rate loop_rate(60);
00173   while (ros::ok())
00174   {
00175     ros::spinOnce();
00176     loop_rate.sleep();
00177   }
00178 
00179   return EXIT_SUCCESS;
00180 }


carl_safety
Author(s): David Kent , Brian Hetherman
autogenerated on Thu Jun 6 2019 19:03:13