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 <assisted_teleop/anti_collision_base_controller.h>
00039
00040 using namespace std;
00041 using namespace costmap_2d;
00042 using namespace base_local_planner;
00043
00044 namespace anti_collision_base_controller
00045 {
00046 AntiCollisionBaseController::AntiCollisionBaseController()
00047 {
00048
00049 costmap_ros_ = new costmap_2d::Costmap2DROS("", tf_);
00050
00051
00052 inscribed_radius_ = costmap_ros_->getInscribedRadius();
00053 circumscribed_radius_ = costmap_ros_->getCircumscribedRadius();
00054 inflation_radius_ = costmap_ros_->getInflationRadius();
00055 global_frame_ = costmap_ros_->getGlobalFrameID();
00056 robot_base_frame_ = costmap_ros_->getBaseFrameID();
00057 footprint_spec_ = costmap_ros_->getRobotFootprint();
00058
00059 ros::NodeHandle private_nh("~");
00060
00061 private_nh.param("controller_frequency", controller_frequency_, 10.0);
00062
00063 private_nh.param("acc_lim_x", acc_lim_x_, 2.5);
00064 private_nh.param("acc_lim_y", acc_lim_y_, 2.5);
00065 private_nh.param("acc_lim_th", acc_lim_theta_, 3.2);
00066 private_nh.param("sim_time", sim_time_, 1.0);
00067 private_nh.param("sim_granularity", sim_granularity_, 0.025);
00068 private_nh.param("vx_samples", vx_samples_, 3);
00069 private_nh.param("vtheta_samples", vtheta_samples_, 20);
00070
00071 private_nh.param("max_vel_x", max_vel_x_, 0.5);
00072 private_nh.param("min_vel_x", min_vel_x_, 0.1);
00073 private_nh.param("max_vel_th", max_vel_th_, 1.0);
00074 private_nh.param("min_vel_th", min_vel_th_, -1.0);
00075 private_nh.param("min_in_place_vel_th", min_in_place_vel_th_, 0.4);
00076
00077 private_nh.param("min_vel_cmd_x", min_vel_cmd_x_, 0.0);
00078 private_nh.param("min_vel_cmd_y", min_vel_cmd_y_, 0.0);
00079 private_nh.param("min_vel_cmd_theta", min_vel_cmd_theta_, 0.0);
00080
00081
00082
00083 costmap_ros_->clearNonLethalWindow(circumscribed_radius_ * 4, circumscribed_radius_ * 4);
00084 costmap_ros_->getCostmapCopy(costmap_);
00085
00086 string odom_topic, base_cmd_topic, joy_listen_topic, world_model_type;
00087 private_nh.param("odom_topic", odom_topic, string("odom"));
00088 private_nh.param("joy_listen_topic", joy_listen_topic, string("joy_cmd_vel"));
00089 private_nh.param("base_cmd_topic", base_cmd_topic, string("cmd_vel"));
00090 private_nh.param("world_model", world_model_type, string("costmap"));
00091 private_nh.param("timeout", timeout_, 0.2);
00092
00093 ROS_ASSERT_MSG(world_model_type == "costmap", "At this time, only costmap world models are supported by this controller");
00094 world_model_ = new CostmapModel(costmap_);
00095
00096 joy_sub_ = ros_node_.subscribe(joy_listen_topic, 1, &AntiCollisionBaseController::joyCallBack, this);
00097 odom_sub_ = ros_node_.subscribe(odom_topic, 1, &AntiCollisionBaseController::odomCallback, this);
00098 base_cmd_pub_ = ros_node_.advertise<geometry_msgs::Twist>(base_cmd_topic,1);
00099
00100 last_cmd_received_ = ros::Time();
00101
00102 std::vector<double> max_accns;
00103 max_accns.push_back(acc_lim_x_);
00104 max_accns.push_back(acc_lim_y_);
00105 max_accns.push_back(acc_lim_theta_);
00106
00107 sim_trajectory_ = new trajectory::Trajectory(3);
00108 sim_trajectory_->setMaxRates(max_accns);
00109 sim_trajectory_->setInterpolationMethod("linear");
00110 sim_trajectory_->autocalc_timing_ = true;
00111 }
00112
00113 AntiCollisionBaseController::~AntiCollisionBaseController()
00114 {
00115 delete costmap_ros_;
00116 }
00117
00118
00119 bool AntiCollisionBaseController::generateTrajectory(double x, double y, double theta,
00120 double vx, double vy, double vtheta,
00121 double vx_samp, double vy_samp, double vtheta_samp,
00122 double acc_x, double acc_y, double acc_theta,
00123 base_local_planner::Trajectory& traj, double sim_time_local)
00124 {
00125 double x_i = x;
00126 double y_i = y;
00127 double theta_i = theta;
00128
00129 double vx_i, vy_i, vtheta_i;
00130
00131 vx_i = vx;
00132 vy_i = vy;
00133 vtheta_i = vtheta;
00134
00135
00136 double vmag = sqrt(vx_samp * vx_samp + vy_samp * vy_samp);
00137
00138
00139 int num_steps = int(max((vmag * sim_time_local) / sim_granularity_, abs(vtheta_samp) / sim_granularity_) + 0.5);
00140
00141 double dt = sim_time_local / num_steps;
00142 double time = 0.0;
00143
00144
00145 traj.resetPoints();
00146 traj.xv_ = vx_samp;
00147 traj.yv_ = vy_samp;
00148 traj.thetav_ = vtheta_samp;
00149 traj.cost_ = -1.0;
00150
00151 if(num_steps == 0)
00152 return false;
00153
00154 std::vector<trajectory::Trajectory::TPoint> sim_point;
00155 sim_point.resize(4);
00156 for(int i=0; i < 4; i++)
00157 {
00158 sim_point[i].setDimension(3);
00159 }
00160 sim_point[0].q_[0] = vx;
00161 sim_point[0].q_[1] = vy;
00162 sim_point[0].q_[2] = vtheta;
00163 sim_point[0].time_ = 0.0;
00164
00165 sim_point[1].q_[0] = vx_samp;
00166 sim_point[1].q_[1] = vy_samp;
00167 sim_point[1].q_[2] = vtheta_samp;
00168 sim_point[1].time_ = 0.01;
00169
00170 sim_point[2].q_[0] = vx_samp;
00171 sim_point[2].q_[1] = vy_samp;
00172 sim_point[2].q_[2] = vtheta_samp;
00173 sim_point[2].time_ = 0.5;
00174
00175 sim_point[3].q_[0] = 0.0;
00176 sim_point[3].q_[1] = 0.0;
00177 sim_point[3].q_[2] = 0.0;
00178 sim_point[3].time_ = 0.51;
00179 sim_trajectory_->setTrajectory(sim_point);
00180
00181 trajectory::Trajectory::TPoint sim_current_vel;
00182 sim_current_vel.setDimension(3);
00183
00184 double total_time = sim_trajectory_->getTotalTime();
00185 ROS_DEBUG("Total time for velocity transition: %f",total_time);
00186 for(int i = 0; i < num_steps; ++i)
00187 {
00188
00189 unsigned int cell_x, cell_y;
00190
00191
00192 if(!costmap_.worldToMap(x_i, y_i, cell_x, cell_y)){
00193 traj.cost_ = -1.0;
00194 return false;
00195 }
00196
00197
00198 double footprint_cost = footprintCost(x_i, y_i, theta_i);
00199
00200
00201 if(footprint_cost < 0){
00202 traj.cost_ = -1.0;
00203 return false;
00204 }
00205
00206 time += dt;
00207
00208
00209 traj.addPoint(x_i, y_i, theta_i);
00210
00211
00212 sim_trajectory_->sample(sim_current_vel,time);
00213 vx_i = sim_current_vel.q_[0];
00214 vy_i = sim_current_vel.q_[1];
00215 vtheta_i = sim_current_vel.q_[2];
00216
00217
00218
00219
00220
00221
00222
00223 x_i = computeNewXPosition(x_i, vx_i, vy_i, theta_i, dt);
00224 y_i = computeNewYPosition(y_i, vx_i, vy_i, theta_i, dt);
00225 theta_i = computeNewThetaPosition(theta_i, vtheta_i, dt);
00226
00227 if(time > std::max(0.2,total_time))
00228 break;
00229 }
00230 double cost = -1.0;
00231 traj.cost_ = cost;
00232 return true;
00233 }
00234
00235
00236
00237 double AntiCollisionBaseController::footprintCost(double x_i, double y_i, double theta_i){
00238
00239 if(footprint_spec_.size() < 3)
00240 return -1.0;
00241
00242
00243 double cos_th = cos(theta_i);
00244 double sin_th = sin(theta_i);
00245 vector<geometry_msgs::Point> oriented_footprint;
00246 for(unsigned int i = 0; i < footprint_spec_.size(); ++i){
00247 geometry_msgs::Point new_pt;
00248 new_pt.x = x_i + (footprint_spec_[i].x * cos_th - footprint_spec_[i].y * sin_th);
00249 new_pt.y = y_i + (footprint_spec_[i].x * sin_th + footprint_spec_[i].y * cos_th);
00250 oriented_footprint.push_back(new_pt);
00251 }
00252
00253 geometry_msgs::Point robot_position;
00254 robot_position.x = x_i;
00255 robot_position.y = y_i;
00256
00257
00258 double footprint_cost = world_model_->footprintCost(robot_position, oriented_footprint, inscribed_radius_, circumscribed_radius_);
00259 return footprint_cost;
00260 }
00261
00262
00263
00264 void AntiCollisionBaseController::computeSafeVelocity(double x, double y, double theta, double vx_current, double vy_current, double vtheta_current, double vx_desired, double vy_desired, double vtheta_desired, double &vx_result, double &vy_result, double &vtheta_result)
00265 {
00266 bool not_done = true;
00267 double scale = 1.0;
00268 double dScale = 0.1;
00269 double vx_tmp, vy_tmp, vtheta_tmp;
00270
00271 base_local_planner::Trajectory traj;
00272 double sim_time_local = sim_time_;
00273 while(not_done)
00274 {
00275 vx_tmp = vx_desired * scale;
00276 vy_tmp = vy_desired * scale;
00277 vtheta_tmp = vtheta_desired * scale;
00278 if(generateTrajectory(x,y,theta,vx_current,vy_current,vtheta_current,vx_tmp,vy_tmp,vtheta_tmp,acc_lim_x_,acc_lim_y_,acc_lim_theta_,traj,sim_time_local))
00279 {
00280 not_done = false;
00281 }
00282
00283 else if(vx_tmp <= min_vel_cmd_x_ && vy_tmp <= min_vel_cmd_y_ && vtheta_tmp <= min_vel_cmd_theta_
00284 && fabs(vx_desired) > 1e-6 && fabs(vy_desired) > 1e-6 && fabs(vtheta_desired) > 1e-6){
00285 not_done = false;
00286 }
00287 scale -= dScale;
00288 if(scale < 0)
00289 {
00290 vx_tmp = 0.0;
00291 vy_tmp = 0.0;
00292 vtheta_tmp = 0.0;
00293 not_done = false;
00294 }
00295 }
00296 vx_result = vx_tmp;
00297 vy_result = vy_tmp;
00298 vtheta_result = vtheta_tmp;
00299 }
00300
00301 void AntiCollisionBaseController::joyCallBack(const geometry_msgs::Twist::ConstPtr& msg)
00302 {
00303 last_cmd_received_ = ros::Time::now();
00304 vel_desired_mutex_.lock();
00305 vel_desired_ = *msg;
00306 vel_desired_mutex_.unlock();
00307 }
00308
00309 void AntiCollisionBaseController::odomCallback(const nav_msgs::OdometryConstPtr& msg){
00310 base_odom_mutex_.lock();
00311 try
00312 {
00313 tf::Stamped<btVector3> v_in(btVector3(msg->twist.twist.linear.x, msg->twist.twist.linear.y, 0), ros::Time(), msg->header.frame_id), v_out;
00314 tf_.transformVector(robot_base_frame_, ros::Time(), v_in, msg->header.frame_id, v_out);
00315 base_odom_.linear.x = v_in.x();
00316 base_odom_.linear.y = v_in.y();
00317 base_odom_.angular.z = msg->twist.twist.angular.z;
00318 }
00319 catch(tf::LookupException& ex)
00320 {
00321 ROS_DEBUG("No odom->base Tx yet: %s", ex.what());
00322 }
00323 catch(tf::ConnectivityException& ex)
00324 {
00325 ROS_DEBUG("No odom->base Tx yet: %s\n", ex.what());
00326 }
00327 catch(tf::ExtrapolationException& ex)
00328 {
00329 ROS_DEBUG("Extrapolation exception");
00330 }
00331 base_odom_mutex_.unlock();
00332 }
00333
00334
00335 bool AntiCollisionBaseController::getRobotPose(double &x, double &y, double &theta)
00336 {
00337 tf::Stamped<tf::Pose> global_pose;
00338 if(!costmap_ros_->getRobotPose(global_pose))
00339 return false;
00340
00341 double uselessPitch, uselessRoll, yaw;
00342 global_pose.getBasis().getEulerYPR(yaw, uselessPitch, uselessRoll);
00343
00344 x = global_pose.getOrigin().x();
00345 y = global_pose.getOrigin().y();
00346 theta = yaw;
00347 return true;
00348 }
00349
00350 void AntiCollisionBaseController::spin()
00351 {
00352 ros::Rate r(controller_frequency_);
00353 while(ros_node_.ok())
00354 {
00355 ros::spinOnce();
00356 double vx_desired, vy_desired, vt_desired;
00357 vel_desired_mutex_.lock();
00358 vx_desired = vel_desired_.linear.x;
00359 vy_desired = vel_desired_.linear.y;
00360 vt_desired = vel_desired_.angular.z;
00361 vel_desired_mutex_.unlock();
00362
00363 double x,y,theta;
00364 if(!getRobotPose(x,y,theta))
00365 {
00366 ROS_ERROR("Robot pose not returned by tf");
00367 continue;
00368 }
00369
00370 double vx_current,vy_current,vt_current;
00371 base_odom_mutex_.lock();
00372 vx_current = base_odom_.linear.x;
00373 vy_current = base_odom_.linear.y;
00374 vt_current = base_odom_.angular.z;
00375 base_odom_mutex_.unlock();
00376
00377
00378 costmap_ros_->clearRobotFootprint();
00379
00380 costmap_ros_->getCostmapCopy(costmap_);
00381
00382 double vx_result, vy_result, vt_result;
00383 computeSafeVelocity(x,y,theta,vx_current,vy_current,vt_current,vx_desired,vy_desired,vt_desired,vx_result,vy_result,vt_result);
00384
00385 if(ros::Time::now() - last_cmd_received_ > ros::Duration(timeout_))
00386 {
00387 ROS_DEBUG("Last command was received too far back, setting current velocity to 0 for safety");
00388 vx_result = 0.0;
00389 vy_result = 0.0;
00390 vt_result = 0.0;
00391 }
00392
00393 geometry_msgs::Twist cmd;
00394 cmd.linear.x = vx_result;
00395 cmd.linear.y = vy_result;
00396 cmd.angular.z = vt_result;
00397 base_cmd_pub_.publish(cmd);
00398
00399 r.sleep();
00400 }
00401 return;
00402 }
00403 }
00404
00405 using namespace anti_collision_base_controller;
00406
00407 int main(int argc, char** argv)
00408 {
00409 ros::init(argc, argv, "anti_collision_base_controller");
00410 ros::spinOnce();
00411 AntiCollisionBaseController anti_collision;
00412 anti_collision.spin();
00413 return(0);
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424