twist_handler.cpp
Go to the documentation of this file.
00001 #include <nj_oa_laser/twist_handler.h>
00002 
00003 #include <ros/ros.h>
00004 
00005 namespace nj_oa_laser
00006 {
00007 
00008 TwistHandler::TwistHandler(const double robot_radius) :
00009   robot_radius(robot_radius),
00010   min_distance(1.5 * robot_radius),
00011   long_distance(5 * robot_radius),
00012   short_lateral_distance(2 * robot_radius),
00013   long_lateral_distance(1.5 * short_lateral_distance),
00014   force_turn_left_factor(3),
00015   turnrate_collide(0.4),
00016   vel_close_obstacle(0.5),
00017   turnrate_factor(0.9),
00018   max_linear_velocity(1),
00019   max_angular_velocity(1)
00020 {
00021 }
00022 
00034 geometry_msgs::Twist TwistHandler::getTwist(const sensor_msgs::LaserScan& scan)
00035 {
00036    bool collide = false;
00037    bool go_straight = true;
00038    double sum_distance_front = 0;
00039    unsigned int count_distance_front = 0;
00040    double sum_y = 0;
00041    unsigned int count_y = 0;
00042    double integral_collide = 0;
00043 
00044    double x;
00045    double y;
00046    // Start and end values for the integral in collide rectangle.
00047    double previous_x_yplus = min_distance;
00048    double previous_x_yminus = 0;
00049 
00050    for (unsigned int i = 0; i < scan.ranges.size(); ++i)
00051    {
00052      const double angle = angles::normalize_angle(scan.angle_min + i * scan.angle_increment);
00053      if ((angle < -M_PI_2) || (angle > M_PI_2))
00054      {
00055        // Do no consider a beam directed backwards.
00056        continue;
00057      }
00058 
00059      if ((-M_PI_4 < angle) && (angle < M_PI_4))
00060      {
00061        sum_distance_front += scan.ranges[i];
00062        count_distance_front++;
00063      }
00064 
00065      x = scan.ranges[i] * std::cos(angle);
00066      y = scan.ranges[i] * std::sin(angle);
00067 
00068      if (x < min_distance)
00069      {
00070        if ((-short_lateral_distance < y) && (y < short_lateral_distance))
00071        {
00072          if (y > 0)
00073          {
00074            integral_collide += y * (previous_x_yplus - x); 
00075            previous_x_yplus = x;
00076          }
00077          else
00078          {
00079            integral_collide += y * (x - previous_x_yminus); 
00080            previous_x_yminus = x;
00081          }
00082          collide = true;
00083        }
00084        else
00085        {
00086          // Front distance is short, lateral distance is large.
00087          // Add the cut distance to the integral.
00088          if (y > 0)
00089          {
00090            integral_collide += short_lateral_distance * (previous_x_yplus - x);
00091            previous_x_yplus = x;
00092          }
00093          else
00094          {
00095            integral_collide -= short_lateral_distance * (x - previous_x_yminus);
00096            previous_x_yminus = x;
00097          }
00098        }
00099      } 
00100 
00101      if ((x < long_distance) && (-long_lateral_distance < y) && (y < long_lateral_distance))
00102      {
00103        go_straight = false;
00104      }
00105      sum_y += y;
00106      count_y++;
00107    }
00108 
00109    // Complete the integral.
00110    integral_collide += short_lateral_distance * previous_x_yplus;
00111    integral_collide -= short_lateral_distance * (min_distance - previous_x_yminus);
00112 
00113    // Corner detection.
00114    const bool force_turn_left = (count_distance_front > 0) &&
00115      (sum_distance_front / count_distance_front < force_turn_left_factor * min_distance);
00116 
00117    geometry_msgs::Twist twist;
00118    if (force_turn_left)
00119    {
00120      twist.angular.z = turnrate_collide;
00121      ROS_DEBUG("Mean dist to obstacle within %.3f, force left turn",
00122          force_turn_left_factor * min_distance);
00123    }
00124    else if (collide)
00125    { 
00126      twist.linear.x = 0;
00127      if (integral_collide > 0)
00128      { 
00129        // Obstacle distance is larger, i.e. space is more free, go there.
00130        twist.angular.z = turnrate_collide;
00131        ROS_DEBUG("Obstacle on the right, turn left");
00132      }
00133      else
00134      {
00135        twist.angular.z = -turnrate_collide;
00136        ROS_DEBUG("Obstacle on the left, turn right");
00137      }      
00138    }
00139    else if (go_straight)
00140    {
00141      twist.linear.x = max_linear_velocity;
00142      twist.angular.z = 0;
00143      ROS_DEBUG("No obstacle");
00144    }
00145    else
00146    {
00147      twist.linear.x = vel_close_obstacle;
00148      twist.angular.z = turnrate_factor * sum_y / ((double) count_y);
00149      ROS_DEBUG("Obstacle seen within %.3f, %.3f",  long_distance, long_lateral_distance);
00150    }
00151 
00152    if (twist.linear.x < -max_linear_velocity)
00153    {
00154      twist.linear.x = -max_linear_velocity;
00155    }
00156    else if (twist.linear.x > max_linear_velocity)
00157    {
00158      twist.linear.x = max_linear_velocity;
00159    }
00160 
00161    if (twist.angular.z < -max_angular_velocity)
00162    {
00163      twist.angular.z = -max_angular_velocity;
00164    }
00165    else if (twist.angular.z > max_angular_velocity)
00166    {
00167      twist.angular.z = max_angular_velocity;
00168    }
00169 
00170    return twist;
00171 }
00172 
00173 } // namespace nj_laser
00174 


nj_oa_laser
Author(s): Gaël Ecorchard , Karel Košnar
autogenerated on Thu Jun 6 2019 17:50:51