jockey.cpp
Go to the documentation of this file.
00001 #include <nj_costmap/jockey.h>
00002 
00003 namespace nj_costmap
00004 {
00005 
00006 Jockey::Jockey(const std::string& name, const double frontier_width) :
00007   lama_jockeys::NavigatingJockey(name),
00008   odom_frame_("odom"),
00009   range_cutoff_(0),
00010   has_crossing_(false),
00011   last_map_orientation_(0),
00012   crossing_detector_(frontier_width),
00013   obstacle_avoider_(frontier_width / 2, "base_laser_link")
00014 {
00015   private_nh_.getParam("odom_frame", odom_frame_);
00016   range_cutoff_set_ = private_nh_.getParam("range_cutoff", range_cutoff_);
00017 
00018   pub_twist_ = private_nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00019   pub_crossing_marker_ = private_nh_.advertise<visualization_msgs::Marker>("crossing_marker", 50, true);
00020   pub_exits_marker_ = private_nh_.advertise<visualization_msgs::Marker>("exits_marker", 50, true);
00021   pub_place_profile_ = private_nh_.advertise<sensor_msgs::PointCloud>("place_profile_cloud", 50, true);
00022   pub_crossing_ = private_nh_.advertise<lama_msgs::Crossing>("abs_crossing", 50, true);
00023 
00024   initTwistHandlerParam();
00025 }
00026 
00027 void Jockey::initTwistHandlerParam()
00028 {
00029   // Parameters from nj_oa_laser::TwistHandler.
00030   private_nh_.getParam("robot_radius", obstacle_avoider_.robot_radius);
00031   private_nh_.getParam("min_distance", obstacle_avoider_.min_distance);
00032   private_nh_.getParam("long_distance", obstacle_avoider_.long_distance);
00033   private_nh_.getParam("turnrate_collide", obstacle_avoider_.turnrate_collide);
00034   private_nh_.getParam("vel_close_obstacle", obstacle_avoider_.vel_close_obstacle);
00035   private_nh_.getParam("turnrate_factor", obstacle_avoider_.turnrate_factor);
00036   private_nh_.getParam("max_linear_velocity", obstacle_avoider_.max_linear_velocity);
00037   private_nh_.getParam("max_angular_velocity", obstacle_avoider_.max_angular_velocity);
00038 
00039   // Parameters from nj_oa_costmap::TwistHandler.
00040   private_nh_.getParam("laser_frame", obstacle_avoider_.laser_frame);
00041 
00042   int fake_laser_beam_count;
00043   if (private_nh_.getParam("fake_laser_beam_count", fake_laser_beam_count))
00044   {
00045     if (fake_laser_beam_count > 1)
00046     {
00047       obstacle_avoider_.fake_laser_beam_count = fake_laser_beam_count;
00048     }
00049     else
00050     {
00051       ROS_ERROR_STREAM("Parameter " << private_nh_.getNamespace() << "/fake_laser_beam_count must be at least 2, setting to default");
00052     }
00053   }
00054 
00055   private_nh_.getParam("range_max", obstacle_avoider_.range_max);
00056 }
00057 
00058 void Jockey::onTraverse()
00059 {
00060   ROS_INFO("Received action TRAVERSE or CONTINUE");
00061   crossing_goer_.resetIntegrals();
00062   costmap_handler_ = private_nh_.subscribe("local_costmap", 1, &Jockey::handleCostmap, this);
00063   ROS_DEBUG("Costmap handler started");
00064   
00065   ros::Rate r(100);
00066   while (ros::ok())
00067   {
00068     if (server_.isPreemptRequested() && !ros::ok())
00069     {
00070       ROS_INFO("%s: Preempted", jockey_name_.c_str());
00071       // set the action state to preempted
00072       server_.setPreempted();
00073       break;
00074     }
00075 
00076     if (has_crossing_)
00077     {
00078       geometry_msgs::Twist twist;
00079       // Use crossing_goer_ if true else obstacle_avoider_
00080       bool goto_crossing = true;
00081       if (rel_crossing_.frontiers.empty())
00082       {
00083         goto_crossing = false;
00084       }
00085       if (rel_crossing_.frontiers.size() == 1)
00086       {
00087         if ((std::abs(rel_crossing_.frontiers[0].angle) > M_PI_2))
00088         {
00089           goto_crossing = false;
00090         }
00091       }
00092       if (rel_crossing_.frontiers.size() == 2)
00093       {
00094         if ((std::abs(rel_crossing_.frontiers[0].angle) > M_PI_2) &&
00095               (std::abs(rel_crossing_.frontiers[1].angle) > M_PI_2))
00096         {
00097           goto_crossing = false;
00098         }
00099       }
00100       if (goto_crossing)
00101       {
00102         // Go to the crossing center if the number of exits is at least 3
00103         // or if one exit is in front of the robot.
00104         bool goal_reached = crossing_goer_.goto_crossing(rel_crossing_, twist);
00105         pub_twist_.publish(twist);
00106         ROS_DEBUG("Go to crossing");
00107 
00108         if (goal_reached)
00109         {
00110           result_.final_state = result_.DONE;
00111           result_.completion_time = getCompletionDuration();
00112           server_.setSucceeded(result_);
00113           break;
00114         }
00115       }
00116       else
00117       {
00118         // Go forward while avoiding obstacles.
00119         twist = obstacle_avoider_.getTwist(map_);
00120         pub_twist_.publish(twist);
00121         ROS_DEBUG("Avoid obstacles");
00122       }
00123       ROS_DEBUG("twist (%.3f, %.3f)", twist.linear.x, twist.angular.z);
00124       has_crossing_ = false;
00125     }
00126     ros::spinOnce();
00127     r.sleep();
00128   }
00129   ROS_DEBUG("Exiting onTraverse");
00130 }
00131 
00132 void Jockey::onStop()
00133 {
00134   ROS_DEBUG("Received action STOP or INTERRUPT");
00135   costmap_handler_.shutdown();
00136   result_.final_state = result_.DONE;
00137   result_.completion_time = ros::Duration(0.0);
00138   server_.setSucceeded(result_);
00139 }
00140 
00141 void Jockey::onInterrupt()
00142 {
00143   ROS_DEBUG("Received action INTERRUPT");
00144   onStop();
00145 }
00146 
00147 void Jockey::onContinue()
00148 {
00149   ROS_DEBUG("Received action CONTINUE");
00150   onTraverse();
00151 }
00152 
00155 void Jockey::handleCostmap(const nav_msgs::OccupancyGridConstPtr& msg)
00156 {
00157   map_ = *msg;
00158   if (range_cutoff_set_)
00159   {
00160     if (std::abs(range_cutoff_ - (-1)) < 1e-10)
00161     {
00162       // Adapt the range cut-off by first computing the radius.
00163       abs_crossing_ = crossing_detector_.crossingDescriptor(map_);
00164       ROS_DEBUG("Raw Crossing (%.3f, %.3f, %.3f), number of exits: %zu",
00165           abs_crossing_.center.x, abs_crossing_.center.y, abs_crossing_.radius,
00166           abs_crossing_.frontiers.size());
00167 
00168       abs_crossing_ = crossing_detector_.crossingDescriptor(map_, 1.8 * abs_crossing_.radius);
00169       ROS_DEBUG("Adapative range cut-off: %.3f", 1.8 * abs_crossing_.radius);
00170       ROS_DEBUG("Crossing with adapted range (%.3f, %.3f, %.3f), number of exits: %zu",
00171           abs_crossing_.center.x, abs_crossing_.center.y, abs_crossing_.radius,
00172           abs_crossing_.frontiers.size());
00173     }
00174     else
00175     {
00176       abs_crossing_ = crossing_detector_.crossingDescriptor(map_, range_cutoff_);
00177       ROS_DEBUG("Crossing: (%.3f, %.3f, %.3f), range cut-off: %.3f, number of exits: %zu",
00178           abs_crossing_.center.x, abs_crossing_.center.y, abs_crossing_.radius,
00179           range_cutoff_, abs_crossing_.frontiers.size());
00180     }
00181   }
00182   else
00183   {
00184     abs_crossing_ = crossing_detector_.crossingDescriptor(map_);
00185     ROS_DEBUG("Crossing (%.3f, %.3f, %.3f), number of exits: %zu",
00186         abs_crossing_.center.x, abs_crossing_.center.y, abs_crossing_.radius, abs_crossing_.frontiers.size());
00187   }
00188  
00189   ROS_DEBUG("Crossing (%.3f, %.3f, %.3f), number of exits: %zu",
00190       abs_crossing_.center.x, abs_crossing_.center.y, abs_crossing_.radius, abs_crossing_.frontiers.size());
00191 
00192   // Get the rotation between odom_frame_ and the map frame.
00193   tf::StampedTransform tr;
00194   bool lookup_successfull = false;
00195   try
00196   {
00197     tf_listener_.waitForTransform(odom_frame_, map_.header.frame_id,
00198         map_.header.stamp, ros::Duration(0.2));
00199     tf_listener_.lookupTransform(odom_frame_, map_.header.frame_id, 
00200         map_.header.stamp, tr);
00201     lookup_successfull = true;
00202   }
00203   catch (tf::TransformException ex)
00204   {
00205     ROS_ERROR("%s", ex.what());
00206   }
00207 
00208   // Angle from LaserScan (on which the map is based) to the map.
00209   double map_relative_orientation = last_map_orientation_;
00210   if (lookup_successfull)
00211   {
00212     map_relative_orientation = tf::getYaw(tr.getRotation());
00213     last_map_orientation_ = map_relative_orientation;
00214   }
00215 
00216   // Transform the crossing with absolute angles to relative angles.
00217   rel_crossing_ = abs_crossing_;
00218   lama_common::rotateCrossing(rel_crossing_, map_relative_orientation);
00219   has_crossing_ = true;
00220 
00221   for (size_t i = 0; i < rel_crossing_.frontiers.size(); ++i)
00222   {
00223     ROS_DEBUG("Relative frontier angle = %.3f", rel_crossing_.frontiers[i].angle);
00224   }
00225 
00226   // Visualization: a sphere at detected crossing center.
00227   if (pub_crossing_marker_.getNumSubscribers())
00228   {
00229     visualization_msgs::Marker m = lama_common::getCrossingCenterMarker(map_.header.frame_id, abs_crossing_);
00230     pub_crossing_marker_.publish(m);
00231   }
00232 
00233   // Visualization: a line at each detected road.
00234   if (pub_exits_marker_.getNumSubscribers())
00235   {
00236     visualization_msgs::Marker m = lama_common::getFrontiersMarker(map_.header.frame_id, abs_crossing_);
00237     pub_exits_marker_.publish(m);
00238   }
00239 
00240   // PlaceProfile visualization message.
00241   if (pub_place_profile_.getNumSubscribers())
00242   {
00243     sensor_msgs::PointCloud cloud = lama_common::placeProfileToPointCloud(crossing_detector_.getPlaceProfile());
00244     pub_place_profile_.publish(cloud);
00245   }
00246 
00247   pub_crossing_.publish(rel_crossing_);
00248 }
00249 
00250 } // namespace nj_costmap
00251 


nj_costmap
Author(s): Gaƫl Ecorchard
autogenerated on Sat Jun 8 2019 20:58:46