#include "frenet_planner.h" #include #include #include //#include #include #include using namespace std; using namespace Eigen; iv::decition::FrenetPlanner::FrenetPlanner(){ this->planner_id = 1; this->planner_name = "Frenet"; this->lidarGridPtr = NULL; } iv::decition::FrenetPlanner::~FrenetPlanner(){ free(this->lidarGridPtr); } /** * @brief iv::decition::FrenetPlanner::getPath * 采用的基于frenet坐标系的最优局部路径生成方法,可实现从当前车道变换到另一车道之间的路径生成。还可实现车辆在路线旁起步的“有迹可循”。 * 计算的是,在车辆到达 原始地图路径偏移offset距离的车道 之前,frenet下规划的路径。 * * @param now_gps_ins 实时gps信息 * @param gpsMapLine 地图数据点 * @param PathPoint 地图路线中距离车辆位置最近的一个点的序号 * @param offset 在车辆避障中,地图源路线所在车道 与 即将去往的车道 之间的距离差值。可以为负值。offset = -(roadNow - roadOri)*roadWidth * @param lidarGridPtr 激光雷达信息网格 * @return 返回一条车辆坐标系下的路径 */ std::vector iv::decition::FrenetPlanner::getPath(GPS_INS now_gps_ins, const std::vector& gpsMapLine, int PathPoint, double offset, iv::LidarGridPtr lidarGridPtr){ this->roadNow = -1; this->now_gps_ins = now_gps_ins; this->gpsMapLine = gpsMapLine; this->PathPoint = PathPoint; this->lidarGridPtr = lidarGridPtr; LaneChangePlanner *lcp = new LaneChangePlanner(); std::vector gpsTrace = lcp->getPath(now_gps_ins,gpsMapLine,PathPoint,0,lidarGridPtr); delete lcp; double realSecSpeed = now_gps_ins.speed / 3.6; leftWidth = offset; rightWidth = offset; std::vector trace = getGpsTrace_AfterCalcFrenetTrace(gpsTrace,realSecSpeed); return trace; } /** * @brief iv::decition::FrenetPlanner::chooseRoadByFrenet * 用frenet的方法对每条道路考察,选择一个最优的道路 * @param now_gps_ins 实时gps信息 * @param gpsMapLine 地图数据点 * @param PathPoint 地图路线中距离车辆位置最近的一个点的序号 * @param offsetL 在选择道路中,地图源路线左边的最大宽度。可以为负值。offsetL = -(roadSum - 1)*roadWidth * @param offsetR 在选择道路中,地图源路线右边的最大宽度。可以为非负值。offsetR = (roadOri - 0)*roadWidth * @param lidarGridPtr 激光雷达信息网格 * @return */ int iv::decition::FrenetPlanner::chooseRoadByFrenet(GPS_INS now_gps_ins, const std::vector& gpsMapLine, int PathPoint, double offsetL, double offsetR, iv::LidarGridPtr lidarGridPtr,int roadNow){ this->roadNow = roadNow; this->aimRoadByFrenet = -1; this->now_gps_ins = now_gps_ins; this->gpsMapLine = gpsMapLine; this->PathPoint = PathPoint; this->lidarGridPtr = lidarGridPtr; LaneChangePlanner *lcp = new LaneChangePlanner(); std::vector gpsTrace = lcp->getPath(now_gps_ins,gpsMapLine,PathPoint,0,lidarGridPtr); delete lcp; double realSecSpeed = now_gps_ins.speed / 3.6; leftWidth = offsetL; rightWidth = offsetR; std::vector trace = getGpsTrace_AfterCalcFrenetTrace(gpsTrace,realSecSpeed); return aimRoadByFrenet; } /** * @brief iv::decition::FrenetPlanner::getGpsTrace_AfterCalcFrenetTrace * 进行frenet规划的总函数,还包括了规划前的一些准备工作,比如frenet坐标系建立、车辆起始状态等。 * @param gpsTrace 地图路线上从PathPoint开始的600个点 * @param realsecSpeed 实时车速 [m/s] * @return 返回一条frenet规划后并转换到车辆坐标系下的路径 */ std::vector iv::decition::FrenetPlanner::getGpsTrace_AfterCalcFrenetTrace(const std::vector& gpsTrace,double realsecSpeed){ vector trace; vector frenet_s; double stp=0.0; //把gpsTrace里的点全部转为frenet坐标系下的点,存储在frenet_s中。相当于frenet坐标系的S轴。 FrenetPoint tmp={.x=gpsTrace[0].x,.y=gpsTrace[0].y,.s=0.0,.d=0.0}; frenet_s.push_back(tmp); for(int i=1; igpsMapLine,this->PathPoint,this->now_gps_ins); double c_s_speed = realsecSpeed * cos(car_now_at_frenet.tangent_Ang-M_PI/2); double c_d_speed = realsecSpeed * sin(car_now_at_frenet.tangent_Ang-M_PI/2); double realAcc = ServiceCarStatus.mfCalAcc; double c_s_dd = realAcc * cos(car_now_at_frenet.tangent_Ang-M_PI/2); double c_d_dd = realAcc * sin(car_now_at_frenet.tangent_Ang-M_PI/2); vector path=frenet_optimal_planning(car_now_at_frenet,frenet_s,c_s_speed,c_d_speed,c_d_dd); return path; } /** * @brief iv::decition::FrenetPlanner::frenet_optimal_planning * 对frenet规划出的路径进行后续操作,并选出损失最小的一条路径作为最优路径 * @param car_now_frenet_point 车辆当前位置在frenet坐标系下的坐标 * @param frenet_s frenet坐标系的s轴 * @param c_speed 车辆的纵向速度。沿s轴方向的速度。 * @param c_d_d 车辆沿d方向的速度。 * @param c_d_dd 车辆沿d方向的加速度。 * @return 返回一条frenet规划的最优路径 */ vector iv::decition::FrenetPlanner::frenet_optimal_planning(iv::decition::FrenetPoint car_now_frenet_point, const std::vector& frenet_s, double c_speed, double c_d_d, double c_d_dd){ double s0 = car_now_frenet_point.s; double c_d = car_now_frenet_point.d; vector gpsTrace; vector fplist=calc_frenet_paths(c_speed, c_d, c_d_d, c_d_dd, s0); //frenet规划 sort(fplist.begin(),fplist.end(),comp); //按损失度由小到大进行排序 for(int i=0; i::max)(); // Frenet_path bestpath; // for(int i=0; i fplist[i].cf){ // min_cost = fplist[i].cf; // bestpath = fplist[i]; // } // } // gpsTrace = frenet_path_to_gpsTrace(bestpath); // aimRoadByFrenet = bestpath.roadflag; // return gpsTrace; */ } /** * @brief iv::decition::FrenetPlanner::calc_frenet_paths * 正式规划出不同的frenet路径,并统计相应的损失度。单从车辆行驶的平滑性计算而得,后续需检测是否有障碍物。 * @param c_speed 车辆的纵向速度。沿s轴方向的速度 * @param c_d 车辆的横向(d方向)偏移距离 * @param c_d_d 车辆沿d方向的速度 * @param c_d_dd 车辆沿d方向的加速度 * @param s0 车辆沿s方向的坐标 * @return 返回多条frenet路径 */ vector iv::decition::FrenetPlanner::calc_frenet_paths(double c_speed, double c_d, double c_d_d, double c_d_dd, double s0){ vector frenet_paths; int roadNum = round(abs((leftWidth-rightWidth)/ServiceParameterStatus.D_ROAD_W)); //roadNum为frenet算法的起始道路序号 //采样,并对每一个目标配置生成轨迹 for(double di=leftWidth; di<=rightWidth; di+=ServiceParameterStatus.D_ROAD_W,roadNum--){ if(roadNum == this->roadNow) continue; //横向动作规划 for(double Ti=ServiceParameterStatus.MINT; Ti& fplist,const std::vector& frenet_s){ for(auto& fp:fplist){ for(int i=0; igpsMapLine,this->PathPoint,this->now_gps_ins); //第二种方法 fp.x.push_back(ix); fp.y.push_back(iy); } for(int i=0; i<(fp.x.size()-1); ++i){ double dx = fp.x[i+1] - fp.x[i]; double dy = fp.y[i+1] - fp.y[i]; fp.yaw.push_back(atan2(dy,dx)); fp.ds.push_back(sqrt(dx*dx + dy*dy)); } fp.ds.push_back(fp.ds.back()); fp.yaw.push_back(fp.yaw.back()); for(int i = 0; i < (fp.yaw.size() - 1); ++i){ fp.c.push_back((fp.yaw[i + 1] - fp.yaw[i]) / fp.ds[i]); } } } void iv::decition::FrenetPlanner::calc_global_single_path(Frenet_path &fp, const std::vector &frenet_s){ for(int i=0; igpsMapLine,this->PathPoint,this->now_gps_ins); //第二种方法 fp.x.push_back(ix); fp.y.push_back(iy); } for(int i=0; i<(fp.x.size()-1); ++i){ double dx = fp.x[i+1] - fp.x[i]; double dy = fp.y[i+1] - fp.y[i]; fp.yaw.push_back(atan2(dy,dx)); fp.ds.push_back(sqrt(dx*dx + dy*dy)); } fp.ds.push_back(fp.ds.back()); fp.yaw.push_back(fp.yaw.back()); for(int i = 0; i < (fp.yaw.size() - 1); ++i){ fp.c.push_back((fp.yaw[i + 1] - fp.yaw[i]) / fp.ds[i]); } } /** * @brief iv::decition::FrenetPlanner::check_paths * 对多条frenet路径进行检验,排除不符合要求的路径。 * @param fplist 多条frenet路径 * @return 排除部分路径后的多条frenet路径 */ vector iv::decition::FrenetPlanner::check_paths(const vector& fplist){ vector okind; int i=0; int j=0; for(i=0; iServiceParameterStatus.MAX_SPEED) //最大速度检查 goto ContinueFlag; } for(j=0; jServiceParameterStatus.MAX_ACCEL) //最大加速度检查 goto ContinueFlag; } for(j=30; jServiceParameterStatus.MAX_CURVATURE)//最大曲率检查 goto ContinueFlag; } if(!check_collision(fplist[i])) continue; okind.push_back(fplist[i]); ContinueFlag:continue; } return okind; } bool iv::decition::FrenetPlanner::check_single_path(const iv::decition::Frenet_path &fp){ int j=0; cout<<"&&&&&&&&&&fp.roadflag: "<ServiceParameterStatus.MAX_SPEED) //最大速度检查 return false; } for(j=0; jServiceParameterStatus.MAX_ACCEL) //最大加速度检查 return false; } for(j=30; jServiceParameterStatus.MAX_CURVATURE)//最大曲率检查 return false; } if(!check_collision(fp)) return false; return true; } /** * @brief iv::decition::FrenetPlanner::check_collision * 检验frenet路径上是否有障碍物,调用的是改进的函数computeObsOnRoadByFrenet。 * @param frenet_path 一条frenet路径 * @param car_now_frenet_point 车辆当前位置在frenet坐标系下的坐标 * @return 在路径上有障碍物返回false,否则返回true。 */ bool iv::decition::FrenetPlanner::check_collision(const iv::decition::Frenet_path &frenet_path){ std::vector gpsTrace = frenet_path_to_gpsTrace(frenet_path); double obs=-1; // iv::decition::DecideGps00().computeObsOnRoadByFrenet(this->lidarGridPtr,gpsTrace,obs,this->gpsMapLine,this->PathPoint,this->now_gps_ins); if(obs > 0 && obs < 30) return false; else return true; } /** * @brief iv::decition::FrenetPlanner::frenet_path_to_gpsTrace * 将frenet路径转换到车辆坐标系下。 * @param frenet_path 一条frenet路径 * @return 一条车辆坐标系下的路径 */ vector iv::decition::FrenetPlanner::frenet_path_to_gpsTrace(const Frenet_path& frenet_path){ vector gpsTrace; for (int i=0; i& gpsTrace) { double closestLen = 100000; //large number int closestWaypoint = 0; for(int i = 1; i < gpsTrace.size(); i++) { double map_x = gpsTrace[i].x; double map_y = gpsTrace[i].y; double dist = distance(x,y,map_x,map_y); if(dist < closestLen) { closestLen = dist; closestWaypoint = i; } } return closestWaypoint; } /* |==========================================================| * | 车辆坐标系与 frenet 坐标系互转的第一种方法。 | * |==========================================================| */ // 车体坐标转frenet坐标。frenet坐标原点是 gpsTrace 中序号为0的点。 // Transform from Cartesian x,y coordinates to Frenet s,d coordinates iv::decition::FrenetPoint iv::decition::FrenetPlanner::XY2Frenet(double x, double y, const std::vector& gpsTrace){ int next_wp=ClosestWaypoint( x, y, gpsTrace); int prev_wp = next_wp-1; //prev_wp代表在next_wp的前一个点计算坐标,能够保证frenet_s都是依次相加的。避免在next_wp计算frenet_s的话,可能出现减的情况。 // if(next_wp == 0){ // prev_wp = gpsTrace.size()-1; // } double n_x = gpsTrace[next_wp].x-gpsTrace[prev_wp].x; double n_y = gpsTrace[next_wp].y-gpsTrace[prev_wp].y; double x_x = x - gpsTrace[prev_wp].x; double x_y = y - gpsTrace[prev_wp].y; // find the projection of x onto n double proj_norm = (x_x*n_x+x_y*n_y)/(n_x*n_x+n_y*n_y); double proj_x = proj_norm*n_x; double proj_y = proj_norm*n_y; //proj_x、proj_y应该为垂足的坐标 double frenet_d = sqrt((x_x - proj_x) * (x_x - proj_x) + (x_y - proj_y) * (x_y - proj_y)); //经手动推算frenet_d = abs(n_x * x_y - n_y * x_x) / sqrt(n_x * n_x + n_y * n_y)。 //即frenet_d,等于点(x,y)到 过prev_wp、next_wp两点的直线 的垂直距离。 //see if d value is positive or negative by comparing it to a center point double center_x = 1000-gpsTrace[prev_wp].x; double center_y = 2000-gpsTrace[prev_wp].y; double centerToPos = distance(center_x,center_y,x_x,x_y); double centerToRef = distance(center_x,center_y,proj_x,proj_y); if(centerToPos <= centerToRef){ frenet_d *= -1; } // calculate s value double frenet_s = 0; for(int i = 0; i < prev_wp; i++){ frenet_s += distance(gpsTrace[i].x,gpsTrace[i].y,gpsTrace[i+1].x,gpsTrace[i+1].y); } if(prev_wp<=0){ frenet_s -= distance(0,0,proj_x,proj_y); }else{ frenet_s += distance(0,0,proj_x,proj_y); } double tmp_Angle = atan2(n_y,n_x); return {x:x,y:y,s:frenet_s,d:frenet_d,tangent_Ang:tmp_Angle}; } // frenet坐标转车体坐标。 // Transform from Frenet s,d coordinates to Cartesian x,y void iv::decition::FrenetPlanner::Frenet2XY(double *res_x, double *res_y, double s, double d, const vector& frenetTrace){ int prev_wp = 0; //退出循环时,prev_wp 最大是等于 frenetTrace.size()-2。 while(s > frenetTrace[prev_wp+1].s && (prev_wp < (int)(frenetTrace.size()-2) )){ prev_wp++; } int wp2 = prev_wp+1; double heading = atan2((frenetTrace[wp2].y-frenetTrace[prev_wp].y),(frenetTrace[wp2].x-frenetTrace[prev_wp].x)); double seg_s = (s-frenetTrace[prev_wp].s); double seg_x = frenetTrace[prev_wp].x+seg_s*cos(heading); double seg_y = frenetTrace[prev_wp].y+seg_s*sin(heading); double perp_heading = heading-M_PI*0.5; *res_x = seg_x + d*cos(perp_heading); *res_y = seg_y + d*sin(perp_heading); } /* |==========================================================| * | 车辆坐标系与 frenet 坐标系互转的第二种方法。 | * |==========================================================| */ // 车体坐标转frenet坐标。frenet坐标原点是 gpsTrace 中序号为0的点。 iv::decition::FrenetPoint iv::decition::FrenetPlanner::getFrenetfromXY(double x, double y, const std::vector& gpsTrace,const std::vector& gpsMap,int pathpoint,GPS_INS nowGps){ int next_wp=ClosestWaypoint( x, y, gpsTrace); int prev_wp = next_wp-1; //prev_wp代表在next_wp的前一个点计算坐标,能够保证frenet_s都是依次相加的。避免在next_wp计算frenet_s的话,可能出现减的情况。 // if(next_wp == 0){ // prev_wp = gpsTrace.size()-1; // } GPS_INS gps = Coordinate_UnTransfer(x,y,nowGps); Point2D pt = Coordinate_Transfer(gps.gps_x,gps.gps_y, *gpsMap[(pathpoint+prev_wp)%gpsMap.size()]); // calculate s value double frenet_s = 0; for(int i = 0; i < prev_wp; i++){ frenet_s += distance(gpsTrace[i].x,gpsTrace[i].y,gpsTrace[i+1].x,gpsTrace[i+1].y); } frenet_s += pt.y; //theta为prev_wp处车的航向角 与 nowGps处的车辆坐标系下x轴之间的夹角,逆时针为正。 double theta = (nowGps.ins_heading_angle - gpsMap[(pathpoint+prev_wp)%gpsMap.size()]->ins_heading_angle+90); double tmp_Angle = theta * M_PI / 180; return {x:x,y:y,s:frenet_s,d:pt.x,tangent_Ang:tmp_Angle}; } void iv::decition::FrenetPlanner::getXYfromFrenet(double *res_x, double *res_y, double s, double d, const vector& frenetTrace,const std::vector& gpsMap,int pathpoint,GPS_INS nowGps) { int prev_wp = -1; while((prev_wp < (int)(frenetTrace.size()-1) ) && s > frenetTrace[prev_wp+1].s) { prev_wp++; } if(prev_wp < 0){ prev_wp = 0; } // int wp2 =prev_wp+1; GPS_INS gps= Coordinate_UnTransfer( d, s-frenetTrace[prev_wp].s , *gpsMap[(pathpoint+prev_wp)%gpsMap.size()]); Point2D pt = Coordinate_Transfer( gps.gps_x, gps.gps_y, nowGps); *res_x = pt.x; *res_y = pt.y; } iv::decition::Quintic_polynomial::Quintic_polynomial(double xs, double vxs, double axs, double xe, double vxe, double axe, double T){ //计算五次多项式系数 this->xs = xs; this->vxs = vxs; this->axs = axs; this->xe = xe; this->vxe = vxe; this->axe = axe; this->a0 = xs; this->a1 = vxs; this->a2 = axs/ 2.0; MatrixXd A(3, 3); MatrixXd b(3, 1); MatrixXd x(3, 1); A << pow(T, 3), pow(T, 4), pow(T, 5), 3*pow(T, 2), 4*pow(T, 3), 5*pow(T, 4), 6*T, 12*T*T, 20*pow(T, 3); b << xe - a0 - a1*T - a2*T*T, vxe - a1 - 2*a2*T, axe - 2*a2; x=A.colPivHouseholderQr().solve(b); this->a3 = x(0,0); this->a4 = x(1,0); this->a5 = x(2,0); } iv::decition::Quintic_polynomial::~Quintic_polynomial(){ } double iv::decition::Quintic_polynomial::calc_point(double t){ double xt = this->a0 + this->a1 * t + this->a2 * t*t + this->a3 * t*t*t + this->a4 * t*t*t*t + this->a5 * t*t*t*t*t; return xt; } double iv::decition::Quintic_polynomial::calc_first_derivative(double t){ double xt = this->a1 + 2*this->a2 * t + 3*this->a3 * t*t + 4*this->a4 * t*t*t + 5*this->a5 * t*t*t*t; return xt; } double iv::decition::Quintic_polynomial::calc_second_derivative(double t){ double xt = 2*this->a2 + 6*this->a3 * t + 12*this->a4 * t*t + 20*this->a5 * t*t*t; return xt; } double iv::decition::Quintic_polynomial::calc_third_derivative(double t){ double xt = 6*this->a3 + 24*this->a4 * t + 60*this->a5 * t*t; return xt; } iv::decition::Quartic_polynomial::Quartic_polynomial(double xs, double vxs, double axs, double vxe, double axe, double T){ //计算四次多项式系数 this->xs = xs; this->vxs = vxs; this->axs = axs; this->vxe = vxe; this->axe = axe; this->a0 = xs; this->a1 = vxs; this->a2 = axs / 2.0; MatrixXd A(2, 2); MatrixXd b(2, 1); MatrixXd x(2, 1); A << 3*pow(T, 2), 4*pow(T, 3), 6*T, 12*T*T ; b << vxe - a1 - 2*a2*T, axe - 2*a2; x=A.colPivHouseholderQr().solve(b); this->a3 = x(0,0); this->a4 = x(1,0); } iv::decition::Quartic_polynomial::~Quartic_polynomial(){ } double iv::decition::Quartic_polynomial::calc_point(double t){ double xt = this->a0 + this->a1*t + this->a2*t*t + this->a3*t*t*t + this->a4*t*t*t*t; return xt; } double iv::decition::Quartic_polynomial::calc_first_derivative(double t){ double xt = this->a1 + 2*this->a2*t + 3*this->a3*t*t + 4*this->a4*t*t*t; return xt; } double iv::decition::Quartic_polynomial::calc_second_derivative(double t){ double xt = 2*this->a2 + 6*this->a3*t + 12*this->a4*t*t; return xt; } double iv::decition::Quartic_polynomial::calc_third_derivative(double t){ double xt = 6*this->a3 + 24*this->a4*t; return xt; } bool iv::decition::FrenetPlanner::comp(const iv::decition::Frenet_path &a, const iv::decition::Frenet_path &b){ return a.cf < b.cf; }