ctrl_interface.cpp
Go to the documentation of this file.
00001 /*
00002  *  MAV Ctrl Interface
00003  *  Copyright (C) 2011, CCNY Robotics Lab
00004  *  Ivan Dryanovski <ivan.dryanovski@gmail.com>
00005  *
00006  *  http://robotics.ccny.cuny.edu
00007  *
00008  *  This program is free software: you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation, either version 3 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 #include "mav_ctrl_interface/ctrl_interface.h"
00023 
00024 namespace mav
00025 {
00026 
00027 CtrlInterface::CtrlInterface(ros::NodeHandle nh, ros::NodeHandle nh_private):
00028   nh_(nh), 
00029   nh_private_(nh_private),
00030   tf_listener_(ros::Duration(10.0)),
00031   costmap_("my_costmap", tf_listener_)
00032 {
00033   ROS_INFO("Starting CtrlInterface"); 
00034 
00035   ros::NodeHandle nh_mav (nh_, "mav");
00036 
00037   // **** get parameters
00038 
00039   initializeParams();
00040 
00041   // **** initialize vaiables
00042 
00043   ctrl_type_ = mav::PositionCtrl;
00044 
00045   des_vel_.linear.x = 0.0;
00046   des_vel_.linear.y = 0.0;
00047   des_vel_.linear.z = 0.0;
00048   des_vel_.angular.x = 0.0;
00049   des_vel_.angular.y = 0.0;
00050   des_vel_.angular.z = 0.0;
00051 
00052   tf::Pose identity;
00053   identity.setIdentity();
00054   tf::poseTFToMsg(identity, cur_pose_.pose);  
00055   cur_pose_.header.frame_id = fixed_frame_;
00056 
00057   cur_goal_ = des_pose_ = cur_pose_;
00058 
00059   navfn_.initialize("my_navfn_planner", &costmap_);
00060 
00061   // *** register publishers
00062 
00063   cmd_pose_publisher_ = nh_mav.advertise<geometry_msgs::PoseStamped>(
00064     "cmd/pose", 10);
00065   cmd_vel_publisher_ = nh_mav.advertise<geometry_msgs::TwistStamped>(
00066     "cmd/vel", 10);
00067 
00068   goal_publisher_= nh_mav.advertise<geometry_msgs::PoseStamped>(
00069     "cmd/goal", 10);
00070   plan_publisher_ = nh_mav.advertise<nav_msgs::Path>(
00071     "plan", 10);
00072   array_publisher_ = nh_mav.advertise<geometry_msgs::PoseArray>(
00073     "plan_array", 10);
00074 
00075   // **** register subscribers
00076 
00077   cur_pose_subscriber_ = nh_mav.subscribe(
00078     "pose", 10, &CtrlInterface::curPoseCallback, this);
00079   goal2D_subscriber_ = nh_mav.subscribe(
00080     "goal2D_rviz", 10, &CtrlInterface::goal2Dcallback, this);
00081   cmd_joy_vel_subscriber_ = nh_mav.subscribe(
00082     "cmd_joy/vel", 10, &CtrlInterface::cmdJoyVelCallback, this);
00083   cmd_plan_vel_subscriber_ = nh_mav.subscribe(
00084     "cmd_plan/vel", 10, &CtrlInterface::cmdPlanVelCallback, this);
00085 
00086   // **** register service servers
00087 
00088   change_des_pose_srv_ = nh_mav.advertiseService(
00089     "changeDesPose", &CtrlInterface::changeDesPose, this);
00090   pos_hold_srv_ = nh_mav.advertiseService(
00091     "positionHold", &CtrlInterface::positionHold, this);
00092   vel_hold_srv_ = nh_mav.advertiseService(
00093     "velocityHold", &CtrlInterface::velocityHold, this);
00094 
00095   set_ctrl_type_client_ = nh_mav.serviceClient<mav_srvs::SetCtrlType>(
00096     "setCtrlType");
00097 
00098   // **** timers
00099 
00100   cmd_timer_ = nh_private_.createTimer(
00101     ros::Duration(0.100), &CtrlInterface::cmdTimerCallback, this);
00102   plan_timer_ = nh_private_.createTimer(
00103     ros::Duration(0.100), &CtrlInterface::planTimerCallback, this);
00104 }
00105 
00106 CtrlInterface::~CtrlInterface()
00107 {
00108   ROS_INFO("Destroying QuadSimplePlanner"); 
00109 
00110 }
00111 
00112 void CtrlInterface::initializeParams()
00113 {
00114   yaw_turn_tolerance_ = 30.0 * (M_PI / 180.0);
00115   plan_goal_tolerance_ = 0.10;
00116 
00117   goal_tf_tolerance_ = 5.0;
00118 
00119   if (!nh_private_.getParam("fixed_frame", fixed_frame_))
00120     fixed_frame_ = "/odom";
00121 
00122   if (!nh_private_.getParam("direct_pos_ctrl", direct_pos_ctrl_))
00123     direct_pos_ctrl_ = true;
00124 
00125   if (!nh_private_.getParam("allow_joy_vel_cmd", allow_joy_vel_cmd_))
00126     allow_joy_vel_cmd_ = true;
00127   if (!nh_private_.getParam("allow_plan_vel_cmd", allow_plan_vel_cmd_))
00128     allow_plan_vel_cmd_ = true;
00129 
00130   if (!nh_private_.getParam("wp_dist_max", wp_dist_max_))
00131     wp_dist_max_ = 1.50;
00132   if (!nh_private_.getParam("wp_dist_tolerance", wp_dist_tolerance_))
00133     wp_dist_tolerance_ = 0.10;
00134   if (!nh_private_.getParam("wp_angle_tolerance", wp_angle_tolerance_))
00135     wp_angle_tolerance_ = 10.0 * (M_PI / 180.0);
00136 
00137   if (allow_joy_vel_cmd_) 
00138     ROS_INFO("Joystick velocity commands are enabled.");
00139   else
00140     ROS_INFO("Joystick velocity commands are disabled.");
00141 
00142   if (allow_plan_vel_cmd_) 
00143     ROS_INFO("Planner velocity commands are enabled.");
00144   else
00145     ROS_INFO("Planner velocity commands are disabled.");
00146 
00147   fixed_frame_ = tf_listener_.resolve(fixed_frame_);
00148 }
00149 
00150 
00151 void CtrlInterface::planTimerCallback(const ros::TimerEvent& event)
00152 {
00153   boost::mutex::scoped_lock(mutex_);
00154 
00155   if (ctrl_type_ == mav::PositionCtrl && !direct_pos_ctrl_)
00156   { 
00157     computeWpFromPlan();
00158   }
00159 }
00160 
00161 void CtrlInterface::computeWpFromPlan()
00162 {
00163   // **** if the plan is mepty, don't do anything
00164   
00165   if (plan_decomposed_.empty()) return;
00166 
00167   // **** find the first waypoint which is outside of tolerance
00168 
00169   unsigned int wp_idx;
00170 
00171   for (wp_idx = 0; wp_idx < plan_decomposed_.size(); ++wp_idx)
00172   {
00173     const geometry_msgs::PoseStamped& plan_wp = plan_decomposed_[wp_idx];
00174 
00175     // calculate distance to waypoint
00176     float dx = plan_wp.pose.position.x - cur_pose_.pose.position.x;
00177     float dy = plan_wp.pose.position.y - cur_pose_.pose.position.y;
00178     float wp_dist = sqrt(dx*dx + dy*dy);
00179 
00180     // calculate angle to waypoint
00181     tf::Quaternion cur_q, wp_q;
00182     tf::quaternionMsgToTF(cur_pose_.pose.orientation, cur_q);
00183     tf::quaternionMsgToTF(plan_wp.pose.orientation, wp_q);
00184     float cur_angle = tf::getYaw(cur_q);
00185     float wp_angle = tf::getYaw(wp_q);
00186     float wp_angle_diff = wp_angle - cur_angle;
00187     if      (wp_angle_diff >= M_PI) wp_angle_diff -= 2.0 * M_PI;
00188     else if (wp_angle_diff < -M_PI) wp_angle_diff += 2.0 * M_PI; 
00189 
00190     // if waypoint isnt reached, use it as des_pose
00191     if (wp_dist > wp_dist_tolerance_ || 
00192         std::abs(wp_angle_diff) > wp_angle_tolerance_)
00193     {
00194       // TODO: some check for collision here
00195 
00196       des_pose_.pose.position.x = plan_wp.pose.position.x;
00197       des_pose_.pose.position.y = plan_wp.pose.position.y;
00198       des_pose_.pose.orientation = plan_wp.pose.orientation;
00199 
00200       break;
00201     }
00202   }
00203  
00204   // **** erase old (reached) waypoints
00205   plan_decomposed_.erase(plan_decomposed_.begin(), 
00206                          plan_decomposed_.begin() + wp_idx);
00207 
00208 }
00209 
00210 void CtrlInterface::cmdTimerCallback(const ros::TimerEvent& event)
00211 {
00212   boost::mutex::scoped_lock(mutex_);
00213 
00214   if (ctrl_type_ == mav::PositionCtrl) 
00215   {
00216     publishCmdPose();
00217   }
00218 }
00219 
00220 void CtrlInterface::cmdJoyVelCallback(const geometry_msgs::TwistStamped::ConstPtr twist_msg)
00221 {
00222   boost::mutex::scoped_lock(mutex_);
00223 
00224   if (!allow_joy_vel_cmd_)
00225   {
00226     ROS_WARN("Received joystick velocity command, but allow_joy_vel_cmd is set to false");
00227     return;
00228   }
00229 
00230   if (ctrl_type_ != mav::VelocityCtrl)
00231   {
00232     ROS_WARN("Received joystick velocity command, but ctrl_type is not VELOCITY");
00233     return;
00234   }
00235 
00236   // TODO: check for frame here
00237 
00238   ROS_INFO("Executing velocity command from joystick.");
00239 
00240   des_vel_ = twist_msg->twist;
00241 
00242   publishCmdVel();
00243 }
00244 
00245 void CtrlInterface::cmdPlanVelCallback(const geometry_msgs::Twist::ConstPtr twist_msg)
00246 {
00247   boost::mutex::scoped_lock(mutex_);
00248 
00249   if (!allow_plan_vel_cmd_)
00250   {
00251     ROS_WARN("Received planner velocity command, but allow_plan_vel_cmd is set to false");
00252     return;
00253   }
00254 
00255   if (ctrl_type_ != mav::VelocityCtrl)
00256   {
00257     ROS_WARN("Received joystick velocity command, but ctrl_type is not VELOCITY");
00258     return;
00259   }
00260 
00261   // TODO: check for frame here
00262 
00263   ROS_INFO("Executing velocity command from planner.");
00264 
00265   des_vel_ = *twist_msg;
00266 
00267   publishCmdVel();
00268 }
00269 
00270 void CtrlInterface::curPoseCallback(const geometry_msgs::PoseStamped::ConstPtr pose_msg)
00271 {
00272   boost::mutex::scoped_lock(mutex_);
00273 
00274   std::string frame = tf_listener_.resolve(pose_msg->header.frame_id);
00275 
00276   if (frame != fixed_frame_)
00277   {
00278     ROS_INFO_ONCE("Pose message does not match the fixed frame (%s, %s), transforming",
00279       frame.c_str(), fixed_frame_.c_str());
00280     
00281     try
00282     {
00283       tf_listener_.waitForTransform(
00284         fixed_frame_, pose_msg->header.frame_id, pose_msg->header.stamp, ros::Duration(1.0));
00285 
00286       tf_listener_.transformPose(fixed_frame_, *pose_msg, cur_pose_);
00287     }
00288     catch (tf::TransformException ex)
00289     {
00290       ROS_WARN("Could not transform goal pose %s", ex.what());
00291       return;
00292     }
00293   }
00294   else
00295   {
00296     cur_pose_ = *pose_msg;
00297   }
00298 }
00299 
00300 void CtrlInterface::goal2Dcallback(const geometry_msgs::PoseStamped::ConstPtr goal_msg)
00301 {
00302   if (ctrl_type_ == mav::PositionCtrl)
00303   {
00304     // **** transform the message to the correct frame
00305     std::string frame = tf_listener_.resolve(goal_msg->header.frame_id);
00306     geometry_msgs::PoseStamped goal_fixed_frame;
00307 
00308     if (frame != fixed_frame_)
00309     {
00310       ROS_INFO_ONCE("Goal messages does not match the fixed frame (%s, %s), transforming",
00311         frame.c_str(), fixed_frame_.c_str());
00312       
00313       try
00314       {
00315         tf_listener_.waitForTransform(
00316           fixed_frame_, goal_msg->header.frame_id, goal_msg->header.stamp, ros::Duration(goal_tf_tolerance_));
00317 
00318         tf_listener_.transformPose(fixed_frame_, *goal_msg, goal_fixed_frame);
00319       }
00320       catch (tf::TransformException ex)
00321       {
00322         ROS_WARN("Could not transform goal pose %s", ex.what());
00323         return;
00324       }
00325     }
00326     else
00327     {
00328       goal_fixed_frame = *goal_msg;
00329     }
00330 
00331     boost::mutex::scoped_lock(mutex_);
00332 
00333     if (direct_pos_ctrl_)
00334     {
00335       // **** direct pos. ctrl - no obstacle avoidance
00336       ROS_INFO("Goal(2d) received. Executing direct poistion control to goal.");
00337 
00338       // set 2D porion of pose to the new goal
00339       des_pose_.pose.position.x = goal_fixed_frame.pose.position.x;
00340       des_pose_.pose.position.y = goal_fixed_frame.pose.position.y;
00341 
00342       double des_yaw = tf::getYaw(goal_fixed_frame.pose.orientation);
00343       tf::Quaternion des_q = tf::createQuaternionFromYaw(des_yaw);
00344       tf::quaternionTFToMsg(des_q, des_pose_.pose.orientation);
00345 
00346       publishCmdPose();
00347     }
00348     else
00349     {
00350       // **** obstacle avoidance
00351       ROS_INFO("Goal(2d) received. Will use for path planning");
00352 
00353       // set 2D porion of pose to the new goal
00354       cur_goal_.pose.position.x = goal_fixed_frame.pose.position.x;
00355       cur_goal_.pose.position.y = goal_fixed_frame.pose.position.y;
00356 
00357       double goal_yaw = tf::getYaw(goal_fixed_frame.pose.orientation);
00358       tf::Quaternion goal_q = tf::createQuaternionFromYaw(goal_yaw);
00359       tf::quaternionTFToMsg(goal_q, cur_goal_.pose.orientation);
00360 
00361       computePlan();
00362 
00363       // for visualization
00364       publishPlans();
00365     }
00366   }
00367   else if (ctrl_type_ == mav::VelocityCtrl)
00368   {
00369     ROS_WARN("Received Goal(2d) while in velocity node, ignoring.");
00370   }
00371   else
00372   {
00373     ROS_WARN("Unknown control mode");
00374   }
00375 }
00376 
00377 bool CtrlInterface::positionHold(mav_srvs::PositionHold::Request  &req,
00378                                  mav_srvs::PositionHold::Response &res)
00379 {
00380   ROS_INFO("Position hold request received");
00381 
00382   boost::mutex::scoped_lock(mutex_);
00383 
00384   // cancel previous commands - freeze to current point
00385   des_pose_ = cur_pose_;
00386 
00387   // clear the plan
00388   cur_goal_ = cur_pose_;
00389   plan_.clear();
00390   plan_decomposed_.clear();
00391 
00392   publishPlans();
00393   publishCmdPose();
00394 
00395   // set controller to position control
00396   ROS_INFO("Setting ctrl mode to POSITION control");
00397   ctrl_type_ = mav::PositionCtrl;
00398 
00399   // call the flyer interface service
00400   mav_srvs::SetCtrlType set_ctrl_type_srv;
00401   set_ctrl_type_srv.request.ctrl_type = ctrl_type_;
00402   return set_ctrl_type_client_.call(set_ctrl_type_srv);
00403 }
00404 
00405 void CtrlInterface::publishPlans()
00406 {
00407   // **** publish the goal
00408   
00409   goal_publisher_.publish(cur_goal_);
00410 
00411   // **** publish the original plan
00412 
00413   navfn_.publishPlan(plan_, 1.0, 0.0, 1.0, 1.0);
00414 
00415   // **** publish the decomposed plan
00416 
00417   nav_msgs::Path path_msg;
00418   path_msg.header.frame_id = cur_goal_.header.frame_id;
00419   path_msg.poses = plan_decomposed_;
00420   
00421   plan_publisher_.publish(path_msg);
00422 
00423   // **** publish the plan array
00424 
00425   geometry_msgs::PoseArray array_msg;
00426   array_msg.header = path_msg.header;
00427 
00428   for (unsigned int i = 0; i < path_msg.poses.size(); ++i)
00429     array_msg.poses.push_back(path_msg.poses[i].pose);
00430 
00431   array_publisher_.publish(array_msg);
00432 
00433   // **** printf for debug
00434   /*
00435   for (unsigned int i = 0; i < plan_decomposed_.size(); ++i)
00436   {
00437     geometry_msgs::Pose& a = plan_decomposed_[i].pose;
00438 
00439     tf::Quaternion q;
00440     tf::quaternionMsgToTF(a.orientation, q);
00441 
00442     printf("[%d] %f %f %f\n", i, a.position.x, a.position.y, tf::getYaw(q));
00443   }
00444   */
00445 }
00446 
00447 bool CtrlInterface::velocityHold(mav_srvs::VelocityHold::Request  &req,
00448                                  mav_srvs::VelocityHold::Response &res)
00449 {
00450   ROS_INFO("Velocity hold request received");
00451 
00452   boost::mutex::scoped_lock(mutex_);
00453 
00454   // cancel prev. vel commands - freeze to 0 velocity
00455   des_vel_.linear.x = 0.0;
00456   des_vel_.linear.y = 0.0;
00457   des_vel_.linear.z = 0.0;
00458   des_vel_.angular.x = 0.0;
00459   des_vel_.angular.y = 0.0;
00460   des_vel_.angular.z = 0.0;
00461   publishCmdVel();
00462   
00463   // set controller to velocity control
00464   ROS_INFO("Setting ctrl type to VELOCITY control");
00465   ctrl_type_ = mav::VelocityCtrl;
00466 
00467   // call the flyer interface service
00468   mav_srvs::SetCtrlType set_ctrl_type_srv;
00469   set_ctrl_type_srv.request.ctrl_type = ctrl_type_; 
00470   return set_ctrl_type_client_.call(set_ctrl_type_srv);
00471 }
00472 
00473 bool CtrlInterface::changeDesPose(mav_srvs::ChangeDesPose::Request  &req,
00474                                   mav_srvs::ChangeDesPose::Response &res)
00475 {
00476   ROS_INFO("ChangeDesPose request received");
00477 
00478   boost::mutex::scoped_lock(mutex_);
00479 
00480   publishCmdPose();
00481  
00482   des_pose_.pose.position.x += req.delta_x;
00483   des_pose_.pose.position.y += req.delta_y;
00484   des_pose_.pose.position.z += req.delta_z;
00485 
00486   publishCmdPose();
00487 
00488   return true;
00489 }
00490 
00491 void CtrlInterface::publishCmdPose()
00492 {
00493         geometry_msgs::PoseStamped cmd_pose;
00494   
00495   cmd_pose = des_pose_;
00496   cmd_pose.header.stamp = ros::Time::now();
00497 
00498   cmd_pose_publisher_.publish(cmd_pose);
00499 }
00500 
00501 void CtrlInterface::publishCmdVel()
00502 {
00503         geometry_msgs::TwistStamped cmd_vel;
00504   
00505   cmd_vel.header.stamp = ros::Time::now();
00506   cmd_vel.header.frame_id = fixed_frame_;
00507   cmd_vel.twist = des_vel_;
00508 
00509   cmd_vel_publisher_.publish(cmd_vel);
00510 }
00511 
00512 void CtrlInterface::computePlan()
00513 {
00514   // **** clear previous plans
00515 
00516   plan_.clear();
00517   plan_decomposed_.clear();
00518 
00519   // **** create a path plan using the map
00520 
00521   ros::Time start_time_plan = ros::Time::now();
00522   bool result_plan = navfn_.makePlan(cur_pose_, cur_goal_, plan_goal_tolerance_, plan_);
00523   ros::Time end_time_plan = ros::Time::now();
00524 
00525   if (result_plan)
00526   {
00527     ROS_INFO("Plan computed in %.1f ms", (end_time_plan - start_time_plan).toSec() * 1000.0);
00528   }
00529   else
00530   {
00531     // TODO: handle this, maybe using position hold?
00532     ROS_WARN("Plan could not be computed!");
00533     return;
00534   }
00535 
00536   // **** decompose the path plan into a waypoint plan
00537 
00538   ros::Time start_time_dec = ros::Time::now();
00539   bool result_dec = decomposePlan(plan_, plan_decomposed_);
00540   ros::Time end_time_dec = ros::Time::now();
00541 
00542   if (result_dec)
00543   {
00544     ROS_INFO("Plan decomposed in %.1f ms", (end_time_dec - start_time_dec).toSec() * 1000.0);
00545   }
00546   else
00547   {
00548     // TODO: handle this, maybe using position hold?
00549     ROS_WARN("Plan could not be decomposed!");
00550     return;
00551   }
00552 }
00553 
00554 bool CtrlInterface::decomposePlan(
00555   const std::vector<geometry_msgs::PoseStamped>& plan_in, 
00556   std::vector<geometry_msgs::PoseStamped>& plan_out)
00557 {
00558   plan_out.clear();
00559 
00560   int size = plan_in.size();
00561 
00562   int start = 0;
00563   int end = size - 1;
00564 
00565   costmap_2d::Costmap2D costmap;
00566   costmap_.getCostmapCopy(costmap);
00567 
00568   bool result = decomposePlan(costmap, plan_in, plan_out, start, end);
00569 
00570   if (!result) return false;
00571 
00572   // **** compute orientation for each WP
00573 
00574   // set start point and end point orientations to cur_pose and cur_goal
00575   geometry_msgs::PoseStamped& s_p = plan_out[0];
00576   geometry_msgs::PoseStamped& e_p = plan_out[plan_out.size() - 1];  
00577 
00578   s_p.pose.orientation = cur_pose_.pose.orientation;
00579   e_p.pose.orientation = cur_goal_.pose.orientation;
00580 
00581   plan_out.push_back(plan_out[plan_out.size() - 1]);
00582 
00583   // set orientations for inside waypoints
00584   for (unsigned int i = 0; i < plan_out.size() - 2; ++i)
00585   {
00586     geometry_msgs::PoseStamped& a = plan_out[i];
00587     geometry_msgs::PoseStamped& b = plan_out[i+1];    
00588 
00589     float dx = b.pose.position.x - a.pose.position.x;
00590     float dy = b.pose.position.y - a.pose.position.y;
00591 
00592     float angle = atan2(dy, dx);
00593   
00594     tf::Quaternion b_q = tf::createQuaternionFromYaw(angle);    
00595     tf::quaternionTFToMsg(b_q, b.pose.orientation);
00596   }
00597 
00598   // **** introduce turn-on-dime waypoints
00599 
00600   std::vector<geometry_msgs::PoseStamped> plan_out_f;
00601   for (unsigned int i = 0; i < plan_out.size() - 1; ++i)
00602   {
00603     geometry_msgs::PoseStamped& a = plan_out[i];
00604     geometry_msgs::PoseStamped& b = plan_out[i+1];         
00605 
00606     tf::Quaternion q_a, q_b;
00607 
00608     tf::quaternionMsgToTF(a.pose.orientation, q_a);
00609     tf::quaternionMsgToTF(b.pose.orientation, q_b);
00610   
00611     float yaw_a = tf::getYaw(q_a);
00612     float yaw_b = tf::getYaw(q_b);
00613 
00614     float d_angle = (yaw_b - yaw_a);
00615     if      (d_angle >= M_PI) d_angle -= 2.0 * M_PI;
00616     else if (d_angle < -M_PI) d_angle += 2.0 * M_PI;
00617 
00618     plan_out_f.push_back(a);
00619 
00620     if (std::abs(d_angle) > yaw_turn_tolerance_)
00621     {
00622       geometry_msgs::PoseStamped m = a;
00623       m.pose.orientation = b.pose.orientation;
00624       plan_out_f.push_back(m);
00625     }
00626   }
00627 
00628   plan_out = plan_out_f;
00629 
00630   return true;
00631 }
00632 
00633 bool CtrlInterface::decomposePlan(
00634   const costmap_2d::Costmap2D& costmap,
00635   const std::vector<geometry_msgs::PoseStamped>& plan_in, 
00636   std::vector<geometry_msgs::PoseStamped>& plan_out,
00637   int start, int end)
00638 {
00639   // 0. params - TODO: move these out of funciton
00640 
00641   float resolution = 0.05;  // TODO: get these from map
00642   int cost_threshold = 100;
00643 
00644   // 1. check for a straight line between start and end
00645 
00646   if (end - start == 1)
00647   {
00648     plan_out.resize(2);
00649     plan_out[0] = plan_in[start];
00650     plan_out[1] = plan_in[end];
00651     return true;
00652   }
00653 
00654   if (start == end)
00655   {
00656     printf("ERROR\n");
00657     return false;
00658   }
00659 
00660   const geometry_msgs::Point& p_start = plan_in[start].pose.position;
00661   const geometry_msgs::Point& p_end   = plan_in[end].pose.position;
00662 
00663   double dx = p_end.x - p_start.x;
00664   double dy = p_end.y - p_start.y;
00665   double L = sqrt(dx*dx + dy*dy);
00666   
00667   // if length is reasonably small
00668   if (L < wp_dist_max_)
00669   {
00670     dx /= L;
00671     dy /= L;
00672     
00673     dx *= resolution;
00674     dy *= resolution;
00675 
00676     double l = 0.0;
00677     double x = p_start.x;
00678     double y = p_start.y;
00679 
00680     bool obstacle_found = false;
00681 
00682     while(l < L)
00683     {
00684       unsigned int mx, my;
00685       costmap.worldToMap(x, y, mx, my);
00686       int cost = costmap.getCost(mx, my);
00687 
00688       if (cost > cost_threshold)
00689       {
00690         obstacle_found = true;
00691         break;
00692       }  
00693       x += dx;
00694       y += dy;
00695       l += resolution;
00696     }
00697 
00698     if (!obstacle_found)
00699     {
00700       // straight line exists
00701       plan_out.resize(2);
00702       plan_out[0] = plan_in[start];
00703       plan_out[1] = plan_in[end];
00704       return true;
00705     }
00706   }
00707 
00708   // 2. if no straight line exists, or length too big,
00709   // divide and recurse
00710 
00711   int mid = (start + end) / 2;
00712 
00713   std::vector<geometry_msgs::PoseStamped> plan_l; 
00714   std::vector<geometry_msgs::PoseStamped> plan_r;
00715 
00716   bool left_result  = decomposePlan(costmap, plan_in, plan_l, start, mid);
00717   bool right_result = decomposePlan(costmap, plan_in, plan_r, mid,   end);
00718 
00719   if (!left_result || !right_result) return false;
00720 
00721   plan_out.reserve(plan_l.size() + plan_r.size() - 1);
00722   plan_out.insert(plan_out.begin(), plan_l.begin(), plan_l.end());
00723   plan_out.insert(plan_out.end(), plan_r.begin() + 1, plan_r.end());
00724 
00725   return true;
00726 }
00727 
00728 
00729 } // end namespace mav


mav_ctrl_interface
Author(s): Ivan Dryanovski
autogenerated on Thu Jan 2 2014 11:28:04