00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <eband_local_planner/eband_trajectory_controller.h>
00039 #include <tf/transform_datatypes.h>
00040
00041
00042 namespace eband_local_planner{
00043
00044 using std::min;
00045 using std::max;
00046
00047
00048 EBandTrajectoryCtrl::EBandTrajectoryCtrl() : costmap_ros_(NULL), initialized_(false), band_set_(false), visualization_(false) {}
00049
00050
00051 EBandTrajectoryCtrl::EBandTrajectoryCtrl(std::string name, costmap_2d::Costmap2DROS* costmap_ros)
00052 : costmap_ros_(NULL), initialized_(false), band_set_(false), visualization_(false)
00053 {
00054
00055 initialize(name, costmap_ros);
00056
00057
00058 pid_.initPid(1, 0, 0, 10, -10);
00059 }
00060
00061
00062 EBandTrajectoryCtrl::~EBandTrajectoryCtrl() {}
00063
00064
00065 void EBandTrajectoryCtrl::initialize(std::string name, costmap_2d::Costmap2DROS* costmap_ros)
00066 {
00067
00068
00069 if(!initialized_)
00070 {
00071
00072 ros::NodeHandle node_private("~/" + name);
00073
00074 in_final_goal_turn_ = false;
00075
00076
00077 costmap_ros_ = costmap_ros;
00078
00079
00080 last_vel_.linear.x = 0.0;
00081 last_vel_.linear.y = 0.0;
00082 last_vel_.linear.z = 0.0;
00083 last_vel_.angular.x = 0.0;
00084 last_vel_.angular.y = 0.0;
00085 last_vel_.angular.z = 0.0;
00086
00087
00088 geometry_msgs::Pose2D tmp_pose2D;
00089 tmp_pose2D.x = 0.0;
00090 tmp_pose2D.y = 0.0;
00091 tmp_pose2D.theta = 0.0;
00092 Pose2DToPose(ref_frame_band_, tmp_pose2D);
00093
00094
00095 initialized_ = true;
00096 }
00097 else
00098 {
00099 ROS_WARN("This planner has already been initialized, doing nothing.");
00100 }
00101 }
00102
00103
00104 void EBandTrajectoryCtrl::reconfigure(
00105 eband_local_planner::EBandPlannerConfig& config)
00106 {
00107 max_vel_lin_ = config.max_vel_lin;
00108 max_vel_th_ = config.max_vel_th;
00109 min_vel_lin_ = config.min_vel_lin;
00110 min_vel_th_ = config.min_vel_th;
00111 min_in_place_vel_th_ = config.min_in_place_vel_th;
00112 in_place_trans_vel_ = config.in_place_trans_vel;
00113 tolerance_trans_ = config.xy_goal_tolerance;
00114 tolerance_rot_ = config.yaw_goal_tolerance;
00115 k_p_ = config.k_prop;
00116 k_nu_ = config.k_damp;
00117 ctrl_freq_ = config.Ctrl_Rate;
00118 acc_max_ = config.max_acceleration;
00119 virt_mass_ = config.virtual_mass;
00120 acc_max_trans_ = config.max_translational_acceleration;
00121 acc_max_rot_ = config.max_rotational_acceleration;
00122 rotation_correction_threshold_ = config.rotation_correction_threshold;
00123
00124
00125 differential_drive_hack_ = config.differential_drive;
00126 bubble_velocity_multiplier_ = config.bubble_velocity_multiplier;
00127 rotation_threshold_multiplier_ = config.rotation_threshold_multiplier;
00128 disallow_hysteresis_ = config.disallow_hysteresis;
00129 }
00130
00131
00132 void EBandTrajectoryCtrl::setVisualization(boost::shared_ptr<EBandVisualization> target_visual)
00133 {
00134 target_visual_ = target_visual;
00135
00136 visualization_ = true;
00137 }
00138
00139 bool EBandTrajectoryCtrl::setBand(const std::vector<Bubble>& elastic_band)
00140 {
00141 elastic_band_ = elastic_band;
00142 band_set_ = true;
00143 return true;
00144 }
00145
00146
00147 bool EBandTrajectoryCtrl::setOdometry(const nav_msgs::Odometry& odometry)
00148 {
00149 odom_vel_.linear.x = odometry.twist.twist.linear.x;
00150 odom_vel_.linear.y = odometry.twist.twist.linear.y;
00151 odom_vel_.linear.z = 0.0;
00152 odom_vel_.angular.x = 0.0;
00153 odom_vel_.angular.y = 0.0;
00154 odom_vel_.angular.z = odometry.twist.twist.angular.z;
00155
00156 return true;
00157 }
00158
00159
00160
00161 double angularDiff (const geometry_msgs::Twist& heading,
00162 const geometry_msgs::Pose& pose)
00163 {
00164 const double pi = 3.14159265;
00165 const double t1 = atan2(heading.linear.y, heading.linear.x);
00166 const double t2 = tf::getYaw(pose.orientation);
00167 const double d = t1-t2;
00168
00169 if (fabs(d)<pi)
00170 return d;
00171 else if (d<0)
00172 return d+2*pi;
00173 else
00174 return d-2*pi;
00175 }
00176
00177 bool EBandTrajectoryCtrl::getTwistDifferentialDrive(geometry_msgs::Twist& twist_cmd, bool& goal_reached) {
00178 goal_reached = false;
00179
00180 geometry_msgs::Twist robot_cmd, bubble_diff;
00181 robot_cmd.linear.x = 0.0;
00182 robot_cmd.angular.z = 0.0;
00183
00184 bool command_provided = false;
00185
00186
00187 if(!initialized_) {
00188 ROS_ERROR("Requesting feedforward command from not initialized planner. Please call initialize() before using this planner");
00189 return false;
00190 }
00191
00192
00193 if( (!band_set_) || (elastic_band_.size() < 2) ) {
00194 ROS_WARN("Requesting feedforward command from empty band.");
00195 return false;
00196 }
00197
00198
00199 bubble_diff = getFrame1ToFrame2InRefFrameNew(
00200 elastic_band_.at(0).center.pose,
00201 elastic_band_.at(1).center.pose,
00202 elastic_band_.at(0).center.pose);
00203
00204 float distance_from_goal = -1.0f;
00205
00206
00207
00208 if (!command_provided) {
00209 int curr_target_bubble = 1;
00210
00211 while(curr_target_bubble < ((int) elastic_band_.size()) - 1) {
00212 curr_target_bubble++;
00213 bubble_diff =
00214 getFrame1ToFrame2InRefFrameNew(
00215 elastic_band_.at(0).center.pose,
00216 elastic_band_.at(curr_target_bubble).center.pose,
00217 elastic_band_.at(0).center.pose);
00218 }
00219
00220
00221 if (!disallow_hysteresis_) {
00222 if(fabs(bubble_diff.linear.x) > tolerance_trans_ ||
00223 fabs(bubble_diff.linear.y) > tolerance_trans_) {
00224 in_final_goal_turn_ = false;
00225 }
00226 }
00227
00228
00229 int goal_bubble = (((int) elastic_band_.size()) - 1);
00230 bubble_diff = getFrame1ToFrame2InRefFrameNew(
00231 elastic_band_.at(0).center.pose,
00232 elastic_band_.at(goal_bubble).center.pose,
00233 elastic_band_.at(0).center.pose);
00234
00235 distance_from_goal = sqrtf(bubble_diff.linear.x * bubble_diff.linear.x +
00236 bubble_diff.linear.y * bubble_diff.linear.y);
00237
00238
00239
00240
00241 if((fabs(bubble_diff.linear.x) <= 0.6 * tolerance_trans_ &&
00242 fabs(bubble_diff.linear.y) <= 0.6 * tolerance_trans_) ||
00243 in_final_goal_turn_) {
00244
00245 double robot_yaw = tf::getYaw(elastic_band_.at(0).center.pose.orientation);
00246 double goal_yaw = tf::getYaw(elastic_band_.at((int)elastic_band_.size() - 1).center.pose.orientation);
00247 float orientation_diff = angles::normalize_angle(goal_yaw - robot_yaw);
00248 if (fabs(orientation_diff) > tolerance_rot_) {
00249 in_final_goal_turn_ = true;
00250 ROS_DEBUG("Performing in place rotation for goal (diff): %f", orientation_diff);
00251 double rotation_sign = -2 * (orientation_diff < 0) + 1;
00252 robot_cmd.angular.z =
00253 rotation_sign * min_in_place_vel_th_ + k_p_ * orientation_diff;
00254 if (fabs(robot_cmd.angular.z) > max_vel_th_) {
00255 robot_cmd.angular.z = rotation_sign * max_vel_th_;
00256 }
00257 } else {
00258 in_final_goal_turn_ = false;
00259 ROS_INFO ("TrajectoryController: Goal reached with distance %.2f, %.2f (od = %.2f)"
00260 "; sending zero velocity",
00261 bubble_diff.linear.x, bubble_diff.linear.y, orientation_diff);
00262
00263 robot_cmd.linear.x = 0.0;
00264 robot_cmd.angular.z = 0.0;
00265 goal_reached = true;
00266 }
00267 command_provided = true;
00268 }
00269 }
00270
00271
00272 bubble_diff = getFrame1ToFrame2InRefFrameNew(
00273 elastic_band_.at(0).center.pose,
00274 elastic_band_.at(1).center.pose,
00275 elastic_band_.at(0).center.pose);
00276
00277
00278 if (!command_provided) {
00279 ROS_DEBUG("Goal has not been reached, performing checks to move towards goal");
00280
00281
00282 double distance_to_next_bubble = sqrt(
00283 bubble_diff.linear.x * bubble_diff.linear.x +
00284 bubble_diff.linear.y * bubble_diff.linear.y);
00285 double radius_of_next_bubble = 0.7 * elastic_band_.at(1).expansion;
00286 double in_place_rotation_threshold =
00287 rotation_threshold_multiplier_ *
00288 fabs(atan2(radius_of_next_bubble,distance_to_next_bubble));
00289 ROS_DEBUG("In-place rotation threshold: %f(%f,%f)",
00290 in_place_rotation_threshold, radius_of_next_bubble, distance_to_next_bubble);
00291
00292
00293 if (fabs(bubble_diff.angular.z) > in_place_rotation_threshold) {
00294 robot_cmd.angular.z = k_p_ * bubble_diff.angular.z;
00295 double rotation_sign = (bubble_diff.angular.z < 0) ? -1.0 : +1.0;
00296 if (fabs(robot_cmd.angular.z) < min_in_place_vel_th_) {
00297 robot_cmd.angular.z = rotation_sign * min_in_place_vel_th_;
00298 }
00299 if (fabs(robot_cmd.angular.z) > max_vel_th_) {
00300 robot_cmd.angular.z = rotation_sign * max_vel_th_;
00301 }
00302 ROS_DEBUG("Performing in place rotation for start (diff): %f with rot vel: %f", bubble_diff.angular.z, robot_cmd.angular.z);
00303 command_provided = true;
00304 }
00305 }
00306
00307
00308
00309 if (!command_provided) {
00310
00311
00312 double forward_sign = -2 * (bubble_diff.linear.x < 0) + 1;
00313 double bubble_radius = 0.7 * elastic_band_.at(0).expansion;
00314 double velocity_multiplier = bubble_velocity_multiplier_ * bubble_radius;
00315
00316 double max_vel_lin = max_vel_lin_;
00317 if (distance_from_goal < 0.75f) {
00318 max_vel_lin = (max_vel_lin < 0.3) ? 0.15 : max_vel_lin / 2;
00319 }
00320
00321 double linear_velocity = velocity_multiplier * max_vel_lin;
00322 linear_velocity *= cos(bubble_diff.angular.z);
00323 if (fabs(linear_velocity) > max_vel_lin_) {
00324 linear_velocity = forward_sign * max_vel_lin_;
00325 } else if (fabs(linear_velocity) < min_vel_lin_) {
00326 linear_velocity = forward_sign * min_vel_lin_;
00327 }
00328
00329
00330 double error = bubble_diff.angular.z;
00331 double rotation_sign = -2 * (bubble_diff.angular.z < 0) + 1;
00332 double angular_velocity = k_p_ * error;
00333 if (fabs(angular_velocity) > max_vel_th_) {
00334 angular_velocity = rotation_sign * max_vel_th_;
00335 } else if (fabs(angular_velocity) < min_vel_th_) {
00336 angular_velocity = rotation_sign * min_vel_th_;
00337 }
00338
00339 ROS_DEBUG("Selected velocity: lin: %f, ang: %f",
00340 linear_velocity, angular_velocity);
00341
00342 robot_cmd.linear.x = linear_velocity;
00343 robot_cmd.angular.z = angular_velocity;
00344 command_provided = true;
00345 }
00346
00347 twist_cmd = robot_cmd;
00348 ROS_DEBUG("Final command: %f, %f", twist_cmd.linear.x, twist_cmd.angular.z);
00349 return true;
00350 }
00351
00352
00353 bool EBandTrajectoryCtrl::getTwist(geometry_msgs::Twist& twist_cmd, bool& goal_reached)
00354 {
00355 goal_reached = false;
00356 if (differential_drive_hack_) {
00357 return getTwistDifferentialDrive(twist_cmd, goal_reached);
00358 }
00359
00360
00361 geometry_msgs::Twist robot_cmd, bubble_diff, control_deviation;
00362 robot_cmd.linear.x = 0.0;
00363 robot_cmd.linear.y = 0.0;
00364 robot_cmd.linear.z = 0.0;
00365 robot_cmd.angular.x = 0.0;
00366 robot_cmd.angular.y = 0.0;
00367 robot_cmd.angular.z = 0.0;
00368
00369
00370 twist_cmd = robot_cmd;
00371 control_deviation = robot_cmd;
00372
00373
00374 if(!initialized_)
00375 {
00376 ROS_ERROR("Requesting feedforward command from not initialized planner. Please call initialize() before using this planner");
00377 return false;
00378 }
00379
00380
00381 if( (!band_set_) || (elastic_band_.size() < 2) )
00382 {
00383 ROS_WARN("Requesting feedforward command from empty band.");
00384 return false;
00385 }
00386
00387
00388
00389
00390 double scaled_radius = 0.7 * elastic_band_.at(0).expansion;
00391
00392
00393 double bubble_distance, ang_pseudo_dist;
00394 bubble_diff = getFrame1ToFrame2InRefFrame(elastic_band_.at(0).center.pose,
00395 elastic_band_.at(1).center.pose,
00396 ref_frame_band_);
00397 ang_pseudo_dist = bubble_diff.angular.z * getCircumscribedRadius(*costmap_ros_);
00398 bubble_distance = sqrt( (bubble_diff.linear.x * bubble_diff.linear.x) + (bubble_diff.linear.y * bubble_diff.linear.y) +
00399 (ang_pseudo_dist * ang_pseudo_dist) );
00400
00401 if(visualization_)
00402 {
00403 target_visual_->publishBubble("ctrl_target", 1, target_visual_->blue, elastic_band_.at(0));
00404 target_visual_->publishBubble("ctrl_target", 2, target_visual_->blue, elastic_band_.at(1));
00405 }
00406
00407
00408 double abs_ctrl_dev;
00409 control_deviation = bubble_diff;
00410
00411
00412 ang_pseudo_dist = control_deviation.angular.z * getCircumscribedRadius(*costmap_ros_);
00413 abs_ctrl_dev = sqrt( (control_deviation.linear.x * control_deviation.linear.x) +
00414 (control_deviation.linear.y * control_deviation.linear.y) +
00415 (ang_pseudo_dist * ang_pseudo_dist) );
00416
00417
00418 if(scaled_radius < bubble_distance)
00419 {
00420
00421 double scale_difference = scaled_radius / bubble_distance;
00422 bubble_diff.linear.x *= scale_difference;
00423 bubble_diff.linear.y *= scale_difference;
00424 bubble_diff.angular.z *= scale_difference;
00425
00426 control_deviation = bubble_diff;
00427 }
00428
00429
00430
00431 if(scaled_radius > bubble_distance)
00432 {
00433
00434 if(elastic_band_.size() > 2)
00435 {
00436
00437 double next_bubble_distance;
00438 geometry_msgs::Twist next_bubble_diff;
00439 next_bubble_diff = getFrame1ToFrame2InRefFrame(elastic_band_.at(1).center.pose,
00440 elastic_band_.at(2).center.pose,
00441 ref_frame_band_);
00442 ang_pseudo_dist = next_bubble_diff.angular.z * getCircumscribedRadius(*costmap_ros_);
00443 next_bubble_distance = sqrt( (next_bubble_diff.linear.x * next_bubble_diff.linear.x) +
00444 (next_bubble_diff.linear.y * next_bubble_diff.linear.y) +
00445 (ang_pseudo_dist * ang_pseudo_dist) );
00446
00447 if(scaled_radius > (bubble_distance + next_bubble_distance) )
00448 {
00449
00450 control_deviation.linear.x = bubble_diff.linear.x + next_bubble_diff.linear.x;
00451 control_deviation.linear.y = bubble_diff.linear.y + next_bubble_diff.linear.y;
00452 control_deviation.angular.z = bubble_diff.angular.z + next_bubble_diff.angular.z;
00453
00454 if(visualization_)
00455 target_visual_->publishBubble("ctrl_target", 3, target_visual_->red, elastic_band_.at(2));
00456 }
00457 else
00458 {
00459 if(visualization_)
00460 target_visual_->publishBubble("ctrl_target", 3, target_visual_->red, elastic_band_.at(2));
00461
00462
00463
00464 double b_distance, cosine_at_bub;
00465 double vec_prod, norm_vec1, norm_vec2;
00466 double ang_pseudo_dist1, ang_pseudo_dist2;
00467
00468
00469 ang_pseudo_dist1 = bubble_diff.angular.z * getCircumscribedRadius(*costmap_ros_);
00470 ang_pseudo_dist2 = next_bubble_diff.angular.z * getCircumscribedRadius(*costmap_ros_);
00471
00472 vec_prod = - ( (bubble_diff.linear.x * next_bubble_diff.linear.x) +
00473 (bubble_diff.linear.y * next_bubble_diff.linear.y) +
00474 (ang_pseudo_dist1 * ang_pseudo_dist2) );
00475
00476 norm_vec1 = sqrt( (bubble_diff.linear.x * bubble_diff.linear.x) +
00477 (bubble_diff.linear.y * bubble_diff.linear.y) +
00478 (ang_pseudo_dist1 * ang_pseudo_dist1) );
00479
00480 norm_vec2 = sqrt( (next_bubble_diff.linear.x * next_bubble_diff.linear.x) +
00481 (next_bubble_diff.linear.y * next_bubble_diff.linear.y) +
00482 (ang_pseudo_dist2 * ang_pseudo_dist2) );
00483
00484
00485 cosine_at_bub = vec_prod / norm_vec1 / norm_vec2;
00486 b_distance = bubble_distance * cosine_at_bub + sqrt( scaled_radius*scaled_radius -
00487 bubble_distance*bubble_distance * (1.0 - cosine_at_bub*cosine_at_bub) );
00488
00489
00490 double scale_next_difference = b_distance / next_bubble_distance;
00491 next_bubble_diff.linear.x *= scale_next_difference;
00492 next_bubble_diff.linear.y *= scale_next_difference;
00493 next_bubble_diff.angular.z *= scale_next_difference;
00494
00495
00496 control_deviation.linear.x = bubble_diff.linear.x + next_bubble_diff.linear.x;
00497 control_deviation.linear.y = bubble_diff.linear.y + next_bubble_diff.linear.y;
00498 control_deviation.angular.z = bubble_diff.angular.z + next_bubble_diff.angular.z;
00499
00500 }
00501 }
00502 }
00503
00504
00505 ang_pseudo_dist = control_deviation.angular.z * getCircumscribedRadius(*costmap_ros_);
00506 abs_ctrl_dev = sqrt( (control_deviation.linear.x * control_deviation.linear.x) +
00507 (control_deviation.linear.y * control_deviation.linear.y) +
00508 (ang_pseudo_dist * ang_pseudo_dist) );
00509
00510
00511 if(visualization_)
00512 {
00513
00514 geometry_msgs::Pose2D tmp_bubble_2d, curr_bubble_2d;
00515 geometry_msgs::Pose tmp_pose;
00516
00517 Bubble new_bubble = elastic_band_.at(0);
00518 PoseToPose2D(elastic_band_.at(0).center.pose, curr_bubble_2d);
00519 tmp_bubble_2d.x = curr_bubble_2d.x + control_deviation.linear.x;
00520 tmp_bubble_2d.y = curr_bubble_2d.y + control_deviation.linear.y;
00521 tmp_bubble_2d.theta = curr_bubble_2d.theta + control_deviation.angular.z;
00522 Pose2DToPose(tmp_pose, tmp_bubble_2d);
00523 new_bubble.center.pose = tmp_pose;
00524 new_bubble.expansion = 0.1;
00525 target_visual_->publishBubble("ctrl_target", 0, target_visual_->red, new_bubble);
00526 }
00527
00528
00529 const geometry_msgs::Point& goal = (--elastic_band_.end())->center.pose.position;
00530 const double dx = elastic_band_.at(0).center.pose.position.x - goal.x;
00531 const double dy = elastic_band_.at(0).center.pose.position.y - goal.y;
00532 const double dist_to_goal = sqrt(dx*dx + dy*dy);
00533
00534
00535
00536 if (dist_to_goal > rotation_correction_threshold_)
00537 {
00538
00539 const double angular_diff = angularDiff(control_deviation, elastic_band_.at(0).center.pose);
00540 const double vel = pid_.computeCommand(angular_diff, ros::Duration(1/ctrl_freq_));
00541 const double mult = fabs(vel) > max_vel_th_ ? max_vel_th_/fabs(vel) : 1.0;
00542 control_deviation.angular.z = vel*mult;
00543 const double abs_vel = fabs(control_deviation.angular.z);
00544
00545 ROS_DEBUG_THROTTLE_NAMED (1.0, "angle_correction",
00546 "Angular diff is %.2f and desired angular "
00547 "vel is %.2f. Initial translation velocity "
00548 "is %.2f, %.2f", angular_diff,
00549 control_deviation.angular.z,
00550 control_deviation.linear.x,
00551 control_deviation.linear.y);
00552 const double trans_mult = max(0.01, 1.0 - abs_vel/max_vel_th_);
00553 control_deviation.linear.x *= trans_mult;
00554 control_deviation.linear.y *= trans_mult;
00555 ROS_DEBUG_THROTTLE_NAMED (1.0, "angle_correction",
00556 "Translation multiplier is %.2f and scaled "
00557 "translational velocity is %.2f, %.2f",
00558 trans_mult, control_deviation.linear.x,
00559 control_deviation.linear.y);
00560 }
00561 else
00562 ROS_DEBUG_THROTTLE_NAMED (1.0, "angle_correction",
00563 "Not applying angle correction because "
00564 "distance to goal is %.2f", dist_to_goal);
00565
00566
00567
00568
00569
00570 geometry_msgs::Twist desired_velocity, currbub_maxvel_dir;
00571 double desvel_abs, desvel_abs_trans, currbub_maxvel_abs;
00572 double scale_des_vel;
00573 desired_velocity = robot_cmd;
00574 currbub_maxvel_dir = robot_cmd;
00575
00576
00577 desired_velocity.linear.x = k_p_/k_nu_ * control_deviation.linear.x;
00578 desired_velocity.linear.y = k_p_/k_nu_ * control_deviation.linear.y;
00579 desired_velocity.angular.z = k_p_/k_nu_ * control_deviation.angular.z;
00580
00581
00582
00583
00584 int curr_bub_num = 0;
00585 currbub_maxvel_abs = getBubbleTargetVel(curr_bub_num, elastic_band_, currbub_maxvel_dir);
00586
00587
00588 ang_pseudo_dist = desired_velocity.angular.z * getCircumscribedRadius(*costmap_ros_);
00589 desvel_abs = sqrt( (desired_velocity.linear.x * desired_velocity.linear.x) +
00590 (desired_velocity.linear.y * desired_velocity.linear.y) +
00591 (ang_pseudo_dist * ang_pseudo_dist) );
00592 if(desvel_abs > currbub_maxvel_abs)
00593 {
00594 scale_des_vel = currbub_maxvel_abs / desvel_abs;
00595 desired_velocity.linear.x *= scale_des_vel;
00596 desired_velocity.linear.y *= scale_des_vel;
00597 desired_velocity.angular.z *= scale_des_vel;
00598 }
00599
00600
00601 desvel_abs_trans = sqrt( (desired_velocity.linear.x * desired_velocity.linear.x) + (desired_velocity.linear.y * desired_velocity.linear.y) );
00602
00603 if(desvel_abs_trans > max_vel_lin_)
00604 {
00605 scale_des_vel = max_vel_lin_ / desvel_abs_trans;
00606 desired_velocity.linear.x *= scale_des_vel;
00607 desired_velocity.linear.y *= scale_des_vel;
00608
00609 desired_velocity.angular.z *= scale_des_vel;
00610 }
00611
00612
00613 if(fabs(desired_velocity.angular.z) > max_vel_th_)
00614 {
00615 scale_des_vel = max_vel_th_ / fabs(desired_velocity.angular.z);
00616 desired_velocity.angular.z *= scale_des_vel;
00617
00618 desired_velocity.linear.x *= scale_des_vel;
00619 desired_velocity.linear.y *= scale_des_vel;
00620 }
00621
00622
00623 geometry_msgs::Twist acc_desired;
00624 acc_desired = robot_cmd;
00625 acc_desired.linear.x = (1.0/virt_mass_) * k_nu_ * (desired_velocity.linear.x - last_vel_.linear.x);
00626 acc_desired.linear.y = (1.0/virt_mass_) * k_nu_ * (desired_velocity.linear.y - last_vel_.linear.y);
00627 acc_desired.angular.z = (1.0/virt_mass_) * k_nu_ * (desired_velocity.angular.z - last_vel_.angular.z);
00628
00629
00630 double scale_acc;
00631 double abs_acc_trans = sqrt( (acc_desired.linear.x*acc_desired.linear.x) + (acc_desired.linear.y*acc_desired.linear.y) );
00632 if(abs_acc_trans > acc_max_trans_)
00633 {
00634 scale_acc = acc_max_trans_ / abs_acc_trans;
00635 acc_desired.linear.x *= scale_acc;
00636 acc_desired.linear.y *= scale_acc;
00637
00638 acc_desired.angular.z *= scale_acc;
00639 }
00640
00641 if(fabs(acc_desired.angular.z) > acc_max_rot_)
00642 {
00643 scale_acc = fabs(acc_desired.angular.z) / acc_max_rot_;
00644 acc_desired.angular.z *= scale_acc;
00645
00646 acc_desired.linear.x *= scale_acc;
00647 acc_desired.linear.y *= scale_acc;
00648 }
00649
00650
00651 last_vel_.linear.x = last_vel_.linear.x + acc_desired.linear.x / ctrl_freq_;
00652 last_vel_.linear.y = last_vel_.linear.y + acc_desired.linear.y / ctrl_freq_;
00653 last_vel_.angular.z = last_vel_.angular.z + acc_desired.angular.z / ctrl_freq_;
00654
00655
00656
00657
00658
00659 last_vel_ = limitTwist(last_vel_);
00660
00661
00662 robot_cmd = last_vel_;
00663
00664
00665 robot_cmd = transformTwistFromFrame1ToFrame2(robot_cmd, ref_frame_band_, elastic_band_.at(0).center.pose);
00666
00667
00668 int curr_target_bubble = 1;
00669 while(fabs(bubble_diff.linear.x) <= tolerance_trans_ &&
00670 fabs(bubble_diff.linear.y) <= tolerance_trans_ &&
00671 fabs(bubble_diff.angular.z) <= tolerance_rot_)
00672 {
00673 if(curr_target_bubble < ((int) elastic_band_.size()) - 1)
00674 {
00675 curr_target_bubble++;
00676
00677
00678 bubble_diff = getFrame1ToFrame2InRefFrame(elastic_band_.at(0).center.pose, elastic_band_.at(curr_target_bubble).center.pose,
00679 ref_frame_band_);
00680 }
00681 else
00682 {
00683 ROS_DEBUG_THROTTLE_NAMED (1.0, "controller_state",
00684 "Goal reached with distance %.2f, %.2f, %.2f"
00685 "; sending zero velocity",
00686 bubble_diff.linear.x, bubble_diff.linear.y,
00687 bubble_diff.angular.z);
00688
00689 robot_cmd.linear.x = 0.0;
00690 robot_cmd.linear.y = 0.0;
00691 robot_cmd.angular.z = 0.0;
00692
00693 last_vel_.linear.x = 0.0;
00694 last_vel_.linear.y = 0.0;
00695 last_vel_.angular.z = 0.0;
00696 goal_reached = true;
00697 break;
00698 }
00699 }
00700
00701 twist_cmd = robot_cmd;
00702
00703 return true;
00704 }
00705
00706
00707 double EBandTrajectoryCtrl::getBubbleTargetVel(const int& target_bub_num, const std::vector<Bubble>& band, geometry_msgs::Twist& VelDir)
00708 {
00709
00710 VelDir.linear.x = 0.0;
00711 VelDir.linear.y = 0.0;
00712 VelDir.linear.z = 0.0;
00713 VelDir.angular.x = 0.0;
00714 VelDir.angular.y = 0.0;
00715 VelDir.angular.z = 0.0;
00716
00717
00718 if(target_bub_num >= ((int) band.size() - 1))
00719 return 0.0;
00720
00721
00722
00723 double v_max_curr_bub, v_max_next_bub;
00724 double bubble_distance, angle_to_pseudo_vel, delta_vel_max;
00725 geometry_msgs::Twist bubble_diff;
00726
00727
00728 v_max_curr_bub = sqrt(2 * elastic_band_.at(target_bub_num).expansion * acc_max_);
00729
00730
00731 ROS_ASSERT( (target_bub_num >= 0) && ((target_bub_num +1) < (int) band.size()) );
00732 bubble_diff = getFrame1ToFrame2InRefFrame(band.at(target_bub_num).center.pose, band.at(target_bub_num + 1).center.pose,
00733 ref_frame_band_);
00734 angle_to_pseudo_vel = bubble_diff.angular.z * getCircumscribedRadius(*costmap_ros_);
00735
00736 bubble_distance = sqrt( (bubble_diff.linear.x * bubble_diff.linear.x) + (bubble_diff.linear.y * bubble_diff.linear.y) +
00737 (angle_to_pseudo_vel * angle_to_pseudo_vel) );
00738
00739
00740 VelDir.linear.x =bubble_diff.linear.x/bubble_distance;
00741 VelDir.linear.y =bubble_diff.linear.y/bubble_distance;
00742 VelDir.angular.z =bubble_diff.angular.z/bubble_distance;
00743
00744
00745 if(bubble_distance > band.at(target_bub_num).expansion )
00746 return v_max_curr_bub;
00747
00748
00749
00750 int next_bub_num = target_bub_num + 1;
00751 geometry_msgs::Twist dummy_twist;
00752 v_max_next_bub = getBubbleTargetVel(next_bub_num, band, dummy_twist);
00753
00754
00755 if(v_max_next_bub >= v_max_curr_bub)
00756 return v_max_curr_bub;
00757
00758
00759
00760 delta_vel_max = sqrt(2 * bubble_distance * acc_max_);
00761 v_max_curr_bub = v_max_next_bub + delta_vel_max;
00762
00763 return v_max_curr_bub;
00764 }
00765
00766
00767 geometry_msgs::Twist EBandTrajectoryCtrl::getFrame1ToFrame2InRefFrame(const geometry_msgs::Pose& frame1, const geometry_msgs::Pose& frame2, const geometry_msgs::Pose& ref_frame)
00768 {
00769
00770 geometry_msgs::Pose2D frame1_pose2D, frame2_pose2D, ref_frame_pose2D;
00771 geometry_msgs::Pose2D frame1_pose2D_rf, frame2_pose2D_rf;
00772 geometry_msgs::Twist frame_diff;
00773
00774
00775 PoseToPose2D(frame1, frame1_pose2D);
00776 PoseToPose2D(frame2, frame2_pose2D);
00777 PoseToPose2D(ref_frame, ref_frame_pose2D);
00778
00779
00780 frame1_pose2D_rf.x = (frame1_pose2D.x - ref_frame_pose2D.x) * cos(ref_frame_pose2D.theta) +
00781 (frame1_pose2D.y - ref_frame_pose2D.y) * sin(ref_frame_pose2D.theta);
00782 frame1_pose2D_rf.y = -(frame1_pose2D.x - ref_frame_pose2D.x) * sin(ref_frame_pose2D.theta) +
00783 (frame1_pose2D.y - ref_frame_pose2D.y) * cos(ref_frame_pose2D.theta);
00784 frame1_pose2D_rf.theta = frame1_pose2D.theta - ref_frame_pose2D.theta;
00785 frame1_pose2D_rf.theta = angles::normalize_angle(frame1_pose2D_rf.theta);
00786
00787 frame2_pose2D_rf.x = (frame2_pose2D.x - ref_frame_pose2D.x) * cos(ref_frame_pose2D.theta) +
00788 (frame2_pose2D.y - ref_frame_pose2D.y) * sin(ref_frame_pose2D.theta);
00789 frame2_pose2D_rf.y = -(frame2_pose2D.x - ref_frame_pose2D.x) * sin(ref_frame_pose2D.theta) +
00790 (frame2_pose2D.y - ref_frame_pose2D.y) * cos(ref_frame_pose2D.theta);
00791 frame2_pose2D_rf.theta = frame2_pose2D.theta - ref_frame_pose2D.theta;
00792 frame2_pose2D_rf.theta = angles::normalize_angle(frame2_pose2D_rf.theta);
00793
00794
00795 frame_diff.linear.x = frame2_pose2D_rf.x - frame1_pose2D_rf.x;
00796 frame_diff.linear.y = frame2_pose2D_rf.y - frame1_pose2D_rf.y;
00797 frame_diff.linear.z = 0.0;
00798 frame_diff.angular.x = 0.0;
00799 frame_diff.angular.y = 0.0;
00800 frame_diff.angular.z = frame2_pose2D_rf.theta - frame1_pose2D_rf.theta;
00801
00802 frame_diff.angular.z = angles::normalize_angle(frame_diff.angular.z);
00803
00804 return frame_diff;
00805 }
00806
00807 geometry_msgs::Twist EBandTrajectoryCtrl::getFrame1ToFrame2InRefFrameNew(const geometry_msgs::Pose& frame1, const geometry_msgs::Pose& frame2, const geometry_msgs::Pose& ref_frame)
00808 {
00809
00810 double x1 = frame1.position.x - ref_frame.position.x;
00811 double y1 = frame1.position.y - ref_frame.position.y;
00812 double x2 = frame2.position.x - ref_frame.position.x;
00813 double y2 = frame2.position.y - ref_frame.position.y;
00814 double yaw_ref = tf::getYaw(ref_frame.orientation);
00815
00816 double x_diff = x2 - x1;
00817 double y_diff = y2 - y1;
00818 double theta_diff = atan2(y_diff, x_diff);
00819
00820
00821 double rotation = angles::normalize_angle(yaw_ref);
00822 double x_final = x_diff * cos(rotation) + y_diff * sin(rotation);
00823 double y_final = - x_diff * sin(rotation) + y_diff * cos(rotation);
00824
00825 geometry_msgs::Twist twist_msg;
00826 twist_msg.linear.x = x_final;
00827 twist_msg.linear.y = y_final;
00828 twist_msg.angular.z = angles::normalize_angle(theta_diff - yaw_ref);
00829
00830 return twist_msg;
00831 }
00832
00833
00834 geometry_msgs::Twist EBandTrajectoryCtrl::transformTwistFromFrame1ToFrame2(const geometry_msgs::Twist& curr_twist,
00835 const geometry_msgs::Pose& frame1, const geometry_msgs::Pose& frame2)
00836 {
00837 geometry_msgs::Pose2D frame1_pose2D, frame2_pose2D;
00838 geometry_msgs::Twist tmp_transformed;
00839 double delta_ang;
00840
00841 tmp_transformed = curr_twist;
00842
00843
00844 PoseToPose2D(frame1, frame1_pose2D);
00845 PoseToPose2D(frame2, frame2_pose2D);
00846
00847
00848 delta_ang = frame2_pose2D.theta - frame1_pose2D.theta;
00849 delta_ang = angles::normalize_angle(delta_ang);
00850
00851
00852 tmp_transformed.linear.x = curr_twist.linear.x * cos(delta_ang) + curr_twist.linear.y * sin(delta_ang);
00853 tmp_transformed.linear.y = -curr_twist.linear.x * sin(delta_ang) + curr_twist.linear.y * cos(delta_ang);
00854
00855 return tmp_transformed;
00856 }
00857
00858
00859 geometry_msgs::Twist EBandTrajectoryCtrl::limitTwist(const geometry_msgs::Twist& twist)
00860 {
00861 geometry_msgs::Twist res = twist;
00862
00863
00864 double lin_overshoot = sqrt(res.linear.x * res.linear.x + res.linear.y * res.linear.y) / max_vel_lin_;
00865 double lin_undershoot = min_vel_lin_ / sqrt(res.linear.x * res.linear.x + res.linear.y * res.linear.y);
00866 if (lin_overshoot > 1.0)
00867 {
00868 res.linear.x /= lin_overshoot;
00869 res.linear.y /= lin_overshoot;
00870
00871 res.angular.z /= lin_overshoot;
00872 }
00873
00874
00875 if(lin_undershoot > 1.0)
00876 {
00877 res.linear.x *= lin_undershoot;
00878 res.linear.y *= lin_undershoot;
00879
00880 }
00881
00882 if (fabs(res.angular.z) > max_vel_th_)
00883 {
00884 double scale = max_vel_th_/fabs(res.angular.z);
00885
00886 res.angular.z *= scale;
00887
00888 res.linear.x *= scale;
00889 res.linear.y *= scale;
00890 }
00891
00892 if (fabs(res.angular.z) < min_vel_th_) res.angular.z = min_vel_th_ * sign(res.angular.z);
00893
00894
00895
00896 if(sqrt(twist.linear.x * twist.linear.x + twist.linear.y * twist.linear.y) < in_place_trans_vel_)
00897 {
00898 if (fabs(res.angular.z) < min_in_place_vel_th_)
00899 res.angular.z = min_in_place_vel_th_ * sign(res.angular.z);
00900
00901 res.linear.x = 0.0;
00902 res.linear.y = 0.0;
00903 }
00904
00905 ROS_DEBUG("Angular command %f", res.angular.z);
00906 return res;
00907 }
00908
00909
00910 }