文章目录

  • 1 目录概述
  • 2 算法介绍
    • 2.1 Astart改进
    • 2.2 ROS(Gazebo仿真)
      • 2.2.1 使用Gazebo仿真需要安装的功能包
      • 2.2.2 创建工作空间 catkin_ws
      • 2.2.3 Pure_pursuit算法
      • 2.2.4 LQR横向控制算法

​ 最近在学习自动驾驶规划控制相关内容,并着手用c++和ros编写相关算法,代码部分见https://github.com/NeXTzhao/planning.git,下面是对github内容的一些说明。

1 目录概述

routing_planning/Astart改进

针对A*算法做出优化:加入靠近路沿的启发函数,并对生成的轨迹点做了均值滤波处理,使轨迹更加平滑。

routing_planning/ros/src

ros工作空间中,purepursuit功能包使用purepursuit算法对spline生成的样条曲线进行了路径跟踪。lqr_steering功能包使用lqr算法对生成的五次多项式轨迹进行横向路径跟踪。

purepursuit算法:原理很简单,网上很多资料也比较多

LQR控制算法主要参考b站up主

2 算法介绍

2.1 Astart改进

 编译:g++ -std=c++11  xxx.cpp -o xx $(pkg-config --cflags --libs opencv) (需要安装opencv)

实现思路:

先用opencv将图片做灰度处理,再做二值化,将像素保存到vector二维数组作为地图,设置起点和终点,调用AStart算法(改进版:加入路沿代价函数)找到一条路径,由于算法会导致路径出现锯齿状,故用均值滤波对路径点做平滑处理。

算法流程:

见github

2.2 ROS(Gazebo仿真)

系统要求:ubuntu + ros +gazebo

2.2.1 使用Gazebo仿真需要安装的功能包

sudo apt-get install -y ros-(对应的ros版本,例如kinetic,下面两个同理)-gazebo-ros-control
sudo apt-get install -y ros-kinetic-ros-control ros-kinetic-ros-controllers
sudo apt-get install -y ros-kinetic-gazebo-ros-control

2.2.2 创建工作空间 catkin_ws

1.创建src文件,放置功能包源码:mkdir -p ~/catkin_ws/src2.进入src文件夹cd ~/catkin_ws/src3.将路径ros/src下的功能包复制粘贴到创建的src目录下4.初始化文件夹catkin_init_workspace5.编译工作空间catkin_makecd ~/catkin_ws/catkin_make

2.2.3 Pure_pursuit算法

实现思路

  1. 运用spline插值进行简单轨迹生成
  2. 编写pure_pursuit纯路径跟踪算法,对生成的轨迹进行跟踪

代码部分

/*** @file purepursuit.cpp*/
#include <ros/ros.h>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>#include <geometry_msgs/Twist.h>
#include <nav_msgs/Path.h>
#include <tf/tf.h>
#include <tf/transform_broadcaster.h>
#include "geometry_msgs/PoseStamped.h"#include "cpprobotics_types.h"
#include "cubic_spline.h"#define PREVIEW_DIS 3  //预瞄距离#define Ld 1.868  //轴距using namespace std;
using namespace cpprobotics;ros::Publisher purepersuit_;
ros::Publisher path_pub_;
nav_msgs::Path path;float carVelocity = 0;
float preview_dis = 0;
float k = 0.1;// 计算四元数转换到欧拉角
std::array<float, 3> calQuaternionToEuler(const float x, const float y,const float z, const float w) {std::array<float, 3> calRPY = {(0, 0, 0)};// roll = atan2(2(wx+yz),1-2(x*x+y*y))calRPY[0] = atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y));// pitch = arcsin(2(wy-zx))calRPY[1] = asin(2 * (w * y - z * x));// yaw = atan2(2(wx+yz),1-2(y*y+z*z))calRPY[2] = atan2(2 * (w * z + x * y), 1 - 2 * (y * y + z * z));return calRPY;
}cpprobotics::Vec_f r_x_;
cpprobotics::Vec_f r_y_;int pointNum = 0;  //保存路径点的个数
int targetIndex = pointNum - 1;
/*方案一*/
// vector<int> bestPoints_ = {pointNum - 1};
/*方案二*/
vector<float> bestPoints_ = {0.0};//计算发送给模型车的转角
void poseCallback(const geometry_msgs::PoseStamped &currentWaypoint) {auto currentPositionX = currentWaypoint.pose.position.x;auto currentPositionY = currentWaypoint.pose.position.y;auto currentPositionZ = 0.0;auto currentQuaternionX = currentWaypoint.pose.orientation.x;auto currentQuaternionY = currentWaypoint.pose.orientation.y;auto currentQuaternionZ = currentWaypoint.pose.orientation.z;auto currentQuaternionW = currentWaypoint.pose.orientation.w;std::array<float, 3> calRPY =calQuaternionToEuler(currentQuaternionX, currentQuaternionY,currentQuaternionZ, currentQuaternionW);/*************************************************************************************************//  方案一:通过累加路径距离,和预瞄距离进行比较以及夹角方向// 寻找匹配目标点for (int i = 0; i < pointNum; i++) {float lad = 0.0;  //累加前视距离float next_x = r_x_[i + 1];float next_y = r_y_[i + 1];lad += sqrt(pow(next_x - currentPositionX, 2) +pow(next_y - currentPositionY, 2));// cos(aAngle)判断方向float aAngle =atan2(next_y - currentPositionY, next_x - currentPositionX) -calRPY[2];if (lad > preview_dis && cos(aAngle) >= 0) {targetIndex = i + 1;bestPoints_.push_back(targetIndex);break;}}// 取容器中的最大值int index = *max_element(bestPoints_.begin(), bestPoints_.end());***************************************************************************************************//**************************************************************************************************/// 方案二:通过计算当前坐标和目标轨迹距离,找到一个最小距离的索引号int index;vector<float> bestPoints_;for (int i = 0; i < pointNum; i++) {// float lad = 0.0;float path_x = r_x_[i];float path_y = r_y_[i];// 遍历所有路径点和当前位置的距离,保存到数组中float lad = sqrt(pow(path_x - currentPositionX, 2) +pow(path_y - currentPositionY, 2));bestPoints_.push_back(lad);}// 找到数组中最小横向距离auto smallest = min_element(bestPoints_.begin(), bestPoints_.end());// 找到最小横向距离的索引位置index = distance(bestPoints_.begin(), smallest);int temp_index;for (int i = index; i < pointNum; i++) {//遍历路径点和预瞄点的距离,从最小横向位置的索引开始float dis =sqrt(pow(r_y_[index] - r_y_[i], 2) + pow(r_x_[index] - r_x_[i], 2));//判断跟预瞄点的距离if (dis < preview_dis) {temp_index = i;} else {break;}}index = temp_index;/**************************************************************************************************/float alpha =atan2(r_y_[index] - currentPositionY, r_x_[index] - currentPositionX) -calRPY[2];// 当前点和目标点的距离Idfloat dl = sqrt(pow(r_y_[index] - currentPositionY, 2) +pow(r_x_[index] - currentPositionX, 2));// 发布小车运动指令及运动轨迹if (dl > 0.2) {float theta = atan(2 * Ld * sin(alpha) / dl);geometry_msgs::Twist vel_msg;vel_msg.linear.x = 3;vel_msg.angular.z = theta;purepersuit_.publish(vel_msg);// 发布小车运动轨迹geometry_msgs::PoseStamped this_pose_stamped;this_pose_stamped.pose.position.x = currentPositionX;this_pose_stamped.pose.position.y = currentPositionY;geometry_msgs::Quaternion goal_quat = tf::createQuaternionMsgFromYaw(theta);this_pose_stamped.pose.orientation.x = currentQuaternionX;this_pose_stamped.pose.orientation.y = currentQuaternionY;this_pose_stamped.pose.orientation.z = currentQuaternionZ;this_pose_stamped.pose.orientation.w = currentQuaternionW;this_pose_stamped.header.stamp = ros::Time::now();this_pose_stamped.header.frame_id = "world";path.poses.push_back(this_pose_stamped);} else {geometry_msgs::Twist vel_msg;vel_msg.linear.x = 0;vel_msg.angular.z = 0;purepersuit_.publish(vel_msg);}path_pub_.publish(path);
}void velocityCall(const geometry_msgs::TwistStamped &carWaypoint) {// carVelocity = carWaypoint.linear.x;carVelocity = carWaypoint.twist.linear.x;preview_dis = k * carVelocity + PREVIEW_DIS;
}void pointCallback(const nav_msgs::Path &msg) {// geometry_msgs/PoseStamped[] posespointNum = msg.poses.size();// auto a = msg.poses[0].pose.position.x;for (int i = 0; i < pointNum; i++) {r_x_.push_back(msg.poses[i].pose.position.x);r_y_.push_back(msg.poses[i].pose.position.y);}int main(int argc, char **argv) {//创建节点ros::init(argc, argv, "pure_pursuit");//创建节点句柄ros::NodeHandle n;//创建Publisher,发送经过pure_pursuit计算后的转角及速度purepersuit_ = n.advertise<geometry_msgs::Twist>("/smart/cmd_vel", 20);path_pub_ = n.advertise<nav_msgs::Path>("rvizpath", 100, true);// ros::Rate loop_rate(10);path.header.frame_id = "world";// 设置时间戳path.header.stamp = ros::Time::now();geometry_msgs::PoseStamped pose;pose.header.stamp = ros::Time::now();// 设置参考系pose.header.frame_id = "world";ros::Subscriber splinePath = n.subscribe("/splinepoints", 20, pointCallback);ros::Subscriber carVel = n.subscribe("/smart/velocity", 20, velocityCall);ros::Subscriber carPose = n.subscribe("/smart/rear_pose", 20, poseCallback);ros::spin();return 0;
}

操作步骤:(新开终端窗口)

source devel/setup.sh
roslaunch car_model spawn_car.launch
roslaunch purepursuit splinepath.launch
roslaunch purepursuit purepursuit.launch
rviz 中add /splinepoints /rvizpath  /smart(在rviz显示中,红色为小车运动轨迹,绿色为规划模块给出的轨迹)

Pure_pursuit仿真结果:

2.2.4 LQR横向控制算法

实现思路

  1. 运用五次多项式生成控制算法所需要的轨迹
  2. 编写lqr路径跟踪算法,对轨迹进行跟踪控制

代码部分

/*** @file frenetlqr.cpp*/#include <stdio.h>
#include <Eigen/Eigen>
#include <array>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Path.h>
#include <tf/tf.h>
#include <tf/transform_broadcaster.h>#include "cpprobotics_types_double.h"
#include "frenet_path_double.h"
#include "quintic_polynomial_double.h"#define DT 0.1  // time tick [s]using namespace cpprobotics;ros::Publisher frenet_lqr_;
ros::Publisher path_pub_;
ros::Publisher trajectory_path;nav_msgs::Path path;
nav_msgs::Path trajectorypath;/**************************************************************************/// t-t0经历的时间
double T = 50;double xend = 80.0;
double yend = 30.0;// 起始状态
std::array<double, 3> x_start{0.0, 0.0, 0.0};
std::array<double, 3> x_end{xend, 0.0, 0.0};
// 终点状态
std::array<double, 3> y_start{0.0, 0.0, 0.0};
std::array<double, 3> y_end{yend, 0.0, 0.0};/**************************************************************************/
/*** 整车参数及状态
*/
// 纵向速度
double vx = 0.01;
// 横向速度
double vy = 0;  //质心侧偏角视为不变
// 轮胎侧偏刚度
double cf = -65494.663, cr = -115494.663;// 前后悬架载荷
double mass_fl = 500, mass_fr = 500, mass_rl = 520, mass_rr = 520;
double mass_front = mass_fl + mass_fr;
double mass_rear = mass_rl + mass_rr;
double m = mass_front + mass_rear;// 最大纵向加速度
double max_lateral_acceleration = 5.0;
// 最大制动减速度
double standstill_acceleration = -3.0;
// 轴距
double wheel_base = 3.8;
// 前轴中心到质心的距离
double a = wheel_base * (1.0 - mass_front / m);
// 后轴中心到质心的距离
double b = wheel_base * (1.0 - mass_rear / m);// 车辆绕z轴转动的转动惯量
double Iz = std::pow(a, 2) * mass_front + std::pow(b, 2) * mass_rear;// 轮胎最大转角(rad)
double wheel_max_degree = 0.6;/**************************************************************************//*** @brief 计算四元数转换到欧拉角* @return std::array<double, 3>*/
std::array<double, 3> calQuaternionToEuler(const double x, const double y,const double z, const double w) {std::array<double, 3> calRPY = {(0, 0, 0)};// roll = atan2(2(wx+yz),1-2(x*x+y*y))calRPY[0] = atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y));// pitch = arcsin(2(wy-zx))calRPY[1] = asin(2 * (w * y - z * x));// yaw = atan2(2(wx+yz),1-2(y*y+z*z))calRPY[2] = atan2(2 * (w * z + x * y), 1 - 2 * (y * y + z * z));return calRPY;
}
/**************************************************************************//*** @brief 规划路径**/
FrenetPath fp;
void calc_frenet_paths() {// 纵向QuinticPolynomial lon_qp(x_start[0], x_start[1], x_start[2], x_end[0],x_end[1], x_end[2], T);// 横向QuinticPolynomial lat_qp(y_start[0], y_start[1], y_start[2], y_end[0],y_end[1], y_end[2], T, xend);for (double t = 0; t < T; t += DT) {double x = lon_qp.calc_point_x(t);double xd = lon_qp.calc_point_xd(t);double xdd = lon_qp.calc_point_xdd(t);fp.t.push_back(t);fp.x.push_back(x);fp.x_d.push_back(xd);fp.x_dd.push_back(xdd);double y_x_t = lat_qp.calc_point_y_x(x);double y_x_d = lat_qp.calc_point_y_x_d(x);double y_x_t_d = lat_qp.calc_point_y_t_d(y_x_d, xd);double y_x_dd = lat_qp.calc_point_y_x_dd(x);double y_x_t_dd = lat_qp.calc_point_y_t_dd(y_x_dd, xd, y_x_d, xdd);fp.y.push_back(y_x_t);fp.y_d.push_back(y_x_t_d);fp.y_dd.push_back(y_x_t_dd);// 压入航向角// fp.threat.push_back(lat_qp.calc_point_thetar(y_x_t_d, xd));// 压入曲率fp.k.push_back(lat_qp.calc_point_k(y_x_dd, y_x_d));// fp.k.push_back(lat_qp.calc_point_k(y_x_t_dd, y_x_t_d, xdd, xd));}int num = fp.x.size();for (int i = 0; i < num; i++) {double dy = fp.y[i + 1] - fp.y[i];double dx = fp.x[i + 1] - fp.x[i];fp.threat.push_back(lat_qp.calc_point_thetar(dy, dx));}// 最后一个道路航向角和前一个相同// fp.threat.push_back(fp.threat.back());
}
/**************************************************************************//*** @brief 寻找匹配点及距离最短的点* @return int*/
int index_ = 0;
int findTrajref(double current_post_x, double current_post_y) {int numPoints = fp.x.size();// double dis_min = std::pow(fp.x[0] - current_post_x, 2) +//                  std::pow(fp.y[0] - current_post_y, 2);double dis_min = std::numeric_limits<double>::max();int index = 0;for (int i = index; i < numPoints; i++) {double temp_dis = std::pow(fp.x[i] - current_post_x, 2) +std::pow(fp.y[i] - current_post_y, 2);// printf("dis_min,temp_dis=%f,%f \n", dis_min, temp_dis);if (temp_dis < dis_min) {dis_min = temp_dis;index = i;}}index_ = index;// printf("index,numPoints=%d,%d \n", index, numPoints);return index;
}/*** @brief 计算误差err和投影点的曲率*  1.先遍历找到匹配点*  2.通过匹配点近似求解投影点*    2.1 由投影点得到对应的航向角和曲率* @return std::array<double, 5>*/
std::array<double, 5> cal_err_k(double current_post_x, double current_post_y,std::array<double, 3> calRPY) {std::array<double, 5> err_k;int index = findTrajref(current_post_x, current_post_y);// 找到index后,开始求解投影点// Eigen::Vector2f tor;Eigen::Matrix<double, 2, 1> tor;tor << cos(fp.threat[index]), sin(fp.threat[index]);// Eigen::Vector2f nor;Eigen::Matrix<double, 2, 1> nor;nor << -sin(fp.threat[index]), cos(fp.threat[index]);// Eigen::Vector2f d_err;Eigen::Matrix<double, 2, 1> d_err;d_err << current_post_x - fp.x[index], current_post_y - fp.y[index];double phi = calRPY[2];// nor.transpose()对nor转置double ed = nor.transpose() * d_err;// double ed = -vx*sin();double es = tor.transpose() * d_err;// 投影点的threat角度double projection_point_threat = fp.threat[index] + fp.k[index] * es;// double phi = fp.threat[index];double ed_d = vy * cos(phi - projection_point_threat) +vx * sin(phi - projection_point_threat);// 计算ephi// double ephi = sin(phi - projection_point_threat);double ephi = phi - projection_point_threat;// 计算s_ddouble s_d = (vx * cos(phi - projection_point_threat) -vy * sin(phi - projection_point_threat)) /(1 - fp.k[index] * ed);double phi_d = vx * fp.k[index];double ephi_d = phi_d - fp.k[index] * s_d;// 计算投影点曲率kdouble projection_point_curvature = fp.k[index];err_k[0] = ed;err_k[1] = ed_d;err_k[2] = ephi;err_k[3] = ephi_d;err_k[4] = projection_point_curvature;return err_k;
}/*** @brief 求解k系数*   1.首先用迭代法解黎卡提方程得到参数得到p矩阵*   2.将p带入k得到k值*   2.将得到的k带入u(n)=-kx(n)得到u也就是转角的控制量* @return Eigen::RowVector4cf*/
Eigen::Matrix<double, 1, 4> cal_dlqr(Eigen::Matrix4d A,Eigen::Matrix<double, 4, 1> B,Eigen::Matrix4d Q,Eigen::Matrix<double, 1, 1> R) {// 设置最大循环迭代次数int numLoop = 200;// 设置目标极小值double minValue = 10e-10;Eigen::Matrix4d p_old;p_old = Q;/*************************************//*** 离散化状态方程**/double ts = 0.001;Eigen::Matrix4d eye;eye.setIdentity(4, 4);Eigen::Matrix4d Ad;Ad = (eye - ts * 0.5 * A).inverse() * (eye + ts * 0.5 * A);Eigen::Matrix<double, 4, 1> Bd;Bd = B * ts;/*************************************/for (int i = 0; i < numLoop; i++) {// B.inverse()求逆Eigen::Matrix4d p_new = Ad.transpose() * p_old * Ad -Ad.transpose() * p_old * Bd *(R + Bd.transpose() * p_old * Bd).inverse() *Bd.transpose() * p_old * Ad +Q;// p.determinant()求行列式// if (std::abs((p_old - p_new).determinant()) <= minValue) {// cwiseAbs()求绝对值、maxCoeff()求最大系数if (fabs((p_new - p_old).maxCoeff()) < minValue) {p_old = p_new;break;}p_old = p_new;}Eigen::Matrix<double, 1, 4> k;// Eigen::RowVector4f;// 当两个超出范围的浮点数(即INF)进行运算时,运算结果会成为NaN。k = (R + Bd.transpose() * p_old * Bd).inverse() * Bd.transpose() * p_old * Ad;return k;
}/*** @brief 计算k值** @param err_k* @return Eigen::Matrix<double, 1, 4>*/
Eigen::Matrix<double, 1, 4> cal_k(std::array<double, 5> err_k) {Eigen::Matrix4d A;A << 0, 1, 0, 0, 0, (cf + cr) / (m * vx), -(cf + cr) / m,(a * cf - b * cr) / (m * vx), 0, 0, 0, 1, 0,(a * cf - b * cr) / (Iz * vx), -(a * cf - b * cr) / Iz,(a * a * cf + b * b * cr) / (Iz * vx);// Eigen::Vector4f B;Eigen::Matrix<double, 4, 1> B;B << 0, -cf / m, 0, -a * cf / Iz;// Eigen::Matrix4f Q;// // 设置成单位矩阵Eigen::Matrix4d Q;// Q.setIdentity(4, 4);Q(0, 0) = 60;Q(1, 1) = 1;Q(2, 2) = 1;Q(3, 3) = 1;Eigen::Matrix<double, 1, 1> R;R(0, 0) = 35.0;// MatrixXd矩阵只能用(),VectorXd不仅能用()还能用[]Eigen::Matrix<double, 1, 4> k = cal_dlqr(A, B, Q, R);return k;
}/*** @brief 计算前馈环节* @return double*/
double cal_forword_angle(Eigen::Matrix<double, 1, 4> k,std::array<double, 5> err_k) {double k3 = k[2];// 不足转向系数double kv = b * m / (cf * wheel_base) - a * m / (cr * wheel_base);//投影点的曲率final_path.k[index]double point_curvature = err_k[4];double forword_angle =wheel_base * point_curvature + kv * vx * vx * point_curvature -k3 * (b * point_curvature - a * m * vx * vx * point_curvature / cr / b);return forword_angle;
}/*** @brief 计算前轮转角u*/
double cal_angle(Eigen::Matrix<double, 1, 4> k, double forword_angle,std::array<double, 5> err_k) {Eigen::Matrix<double, 4, 1> err;err << err_k[0], err_k[1], err_k[2], err_k[3];double angle = -k * err + forword_angle;return angle;
}/*** @brief 限制前轮最大转角*/
double limitSterringAngle(double value, double bound1, double bound2) {if (bound1 > bound2) {std::swap(bound1, bound2);}if (value < bound1) {return bound1;} else if (value > bound2) {return bound2;}return value;
}/*** @brief 统一调用各个子函数* @return double*/
double theta_angle(double currentPositionX, double currentPositionY,std::array<double, 3> cal_RPY) {std::array<double, 5> err_k =cal_err_k(currentPositionX, currentPositionY, cal_RPY);Eigen::Matrix<double, 1, 4> k = cal_k(err_k);double forword_angle = cal_forword_angle(k, err_k);double tempangle = cal_angle(k, forword_angle, err_k);double angle =limitSterringAngle(tempangle, -wheel_max_degree, wheel_max_degree);printf("angle,forword_angle=%.3f,%.3f\n", angle, forword_angle);return angle;
}void velocityCall(const geometry_msgs::TwistStamped &carWaypoint) {//错误写法 carVelocity = carWaypoint.linear.x;vx = carWaypoint.twist.linear.x;
}void poseCallback(const geometry_msgs::PoseStamped &currentWaypoint) {double currentPositionX = currentWaypoint.pose.position.x;double currentPositionY = currentWaypoint.pose.position.y;double currentPositionZ = 0.0;double currentQuaternionX = currentWaypoint.pose.orientation.x;double currentQuaternionY = currentWaypoint.pose.orientation.y;double currentQuaternionZ = currentWaypoint.pose.orientation.z;double currentQuaternionW = currentWaypoint.pose.orientation.w;std::array<double, 3> cal_RPY =calQuaternionToEuler(currentQuaternionX, currentQuaternionY,currentQuaternionZ, currentQuaternionW);double theta = theta_angle(currentPositionX, currentPositionY, cal_RPY);int numpoints = fp.x.size();if (index_ < numpoints - 2) {geometry_msgs::Twist vel_msg;vel_msg.linear.x = 8;vel_msg.angular.z = theta;frenet_lqr_.publish(vel_msg);geometry_msgs::PoseStamped this_pose_stamped;this_pose_stamped.pose.position.x = currentPositionX;this_pose_stamped.pose.position.y = currentPositionY;geometry_msgs::Quaternion goal_quat = tf::createQuaternionMsgFromYaw(theta);this_pose_stamped.pose.orientation.x = currentQuaternionX;this_pose_stamped.pose.orientation.y = currentQuaternionY;this_pose_stamped.pose.orientation.z = currentQuaternionZ;this_pose_stamped.pose.orientation.w = currentQuaternionW;this_pose_stamped.header.stamp = ros::Time::now();this_pose_stamped.header.frame_id = "world";trajectorypath.poses.push_back(this_pose_stamped);trajectory_path.publish(trajectorypath);} else {geometry_msgs::Twist vel_msg;vel_msg.linear.x = 0;vel_msg.angular.z = 0;frenet_lqr_.publish(vel_msg);}
}int main(int argc, char **argv) {//创建节点ros::init(argc, argv, "lqr");//创建节点句柄ros::NodeHandle a;//创建Publisher,发送经过lqr计算后的转角及速度frenet_lqr_ = a.advertise<geometry_msgs::Twist>("/smart/cmd_vel", 20);//初始化五次多项式轨迹calc_frenet_paths();int Num = fp.x.size();for (int i = 0; i < Num; i++) {printf("x,y,th,k,i=%.3f,%.3f,%.3f,%f,%d \n", fp.x[i], fp.y[i],fp.threat[i],fp.k[i], i);}/**************************************************************/// 发布规划轨迹path_pub_ = a.advertise<nav_msgs::Path>("rviz_path", 20, true);path.header.frame_id = "world";path.header.stamp = ros::Time::now();geometry_msgs::PoseStamped pose;pose.header.stamp = ros::Time::now();pose.header.frame_id = "world";int sNum = fp.x.size();for (int i = 0; i < sNum; i++) {pose.pose.position.x = fp.x[i];pose.pose.position.y = fp.y[i];path.poses.push_back(pose);}path_pub_.publish(path);/**************************************************************///发布小车运动轨迹trajectory_path = a.advertise<nav_msgs::Path>("trajector_ypath", 20, true);trajectorypath.header.frame_id = "world";trajectorypath.header.stamp = ros::Time::now();/**************************************************************/ros::Subscriber carVel = a.subscribe("/smart/velocity", 20, velocityCall);ros::Subscriber carPose = a.subscribe("/smart/rear_pose", 20, poseCallback);ros::spin();return 0;
};

操作步骤:(新开终端窗口)

source devel/setup.sh
roslaunch car_model spawn_car.launch
roslaunch lqr_steering frenet_lqr.launch
rviz 中add /trajector_ypath /rviz_path  /smart (在rviz显示中,红色为小车运动轨迹,绿色为规划模块给出的轨迹)

LQR仿真结果:

自动驾驶规划控制(A*、pure pursuit、LQR算法,使用c++在ubuntu和ros环境下实现)相关推荐

  1. 自动驾驶规划控制系列文章(一)——车辆数学模型

    目录 一.车辆自行车运动学模型(kinematic bicycle model) 1.基于车辆重心的运动学模型 2. 以后轴中心为原点的运动学模型 二.车辆自行车动力学模型(kinematic bic ...

  2. 自动驾驶规划控制软硬一体化控制器解决方案(一)

    随着社会的进步,汽车工业和电子科技发展迅速,车载电子器件的数量越来越多,汽车 电子的平台集成度越来越高,两者的融合正在革新着人们的驾乘体验.本文基于 x86 SoC 进 行系统设计,实现高效的汽车智能 ...

  3. 自动驾驶规划术语与搜索空间的几种方法

    1. 导读 目前,自动驾驶或自动驾驶汽车是学术界和汽车界研究的核心,因为它具有多方面的优势,包括提高安全性.减少拥堵.降低排放和提高机动性.其实软件是支持自动驾驶的关键驱动因素,在将乘客或货物从指定的 ...

  4. 自动驾驶规划方法综述

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:本文来源: ...

  5. 自动驾驶车辆控制测评标准

    自动驾驶中,车辆控制是基础,以什么指标来测评就显的很关键,以下是Apollo 车辆控制评测分析指标,可以在此基础上做裁剪,来满足自己自动驾驶车辆控制的需求. 序号 参数 名称 说明 平均控制性能相关参 ...

  6. Arduino毕业设计——基于Arduino+PID+AI的自动驾驶小车控制系统设计与实现(毕业论文+程序源码)——自动驾驶小车控制系统

    基于Arduino+PID+AI的自动驾驶小车控制系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Arduino+PID+AI的自动驾驶小车控制系统设计与实现,文章末尾附有本毕业设计的 ...

  7. 自动驾驶笔记-轨迹跟踪之①纯跟踪算法(Pure Pursuit)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.阿克曼转向模型 1.1 模型理解 1.2 模型表达 二.纯跟踪算法(Pure Pursuit) 2.1 算法理解 ...

  8. 关于自动驾驶车辆控制

    目录 1. 本文目的 2. 自动驾驶中控制原理 2.1 控制在自动驾驶中的位置 2.2 控制的数据流 3. 汽车控制模型 3.1 汽车运动学模型 3.2 汽车动力学模型 3.3 运动学模型和动力学模型 ...

  9. 自动驾驶车辆控制(坐标转换与横向积分误差)

    文章目录 前言 一. Frenet坐标变换与横向误差微分方程 1.1问题描述 1.2 公式推导 前言 本文应配合b站up主"忠厚老实的老王"的自动驾驶控制算法系列视频食用.. 一. ...

最新文章

  1. 列子御风 大道至简 心诚天人合一
  2. 技术新进展!谷歌AI部门宣布发现新技术以加速AI神经网络训练
  3. 《新一代人工智能伦理规范》发布
  4. 分享Kali Linux 2017年第23周镜像文件
  5. DropDownList中显示无限级树形结构
  6. python3项目源代码下载_2019年最值得关注的34个Python开源项目——Let's go!
  7. POJ 1276 ATM凑钱(动态规划)(未解答)
  8. 热式气体质量流量计检定规程_宁夏热式气体质量流量计价位,玻璃管液位计怎么样...
  9. Docker方式安装SonarQube
  10. 清理Visual Studio最近打开的项目、文件、查找内容和最近引用组件
  11. 什么是“好的”测试用例?
  12. 如何从命令行删除MongoDB数据库?
  13. C++ 领域:游戏、HPC、编译器、金融、财务
  14. 虚拟服务器ftp文件权限修改,虚拟主机用户ftp和apache用户文件互操作权限解决方法...
  15. python中tab的用法_详解Python中expandtabs()方法的使用
  16. Java面试准备(一)
  17. 打开计算机页面闪,电脑打开网页闪烁几大原因及解决
  18. 小小一方士 C# Async\Await 之 上传/下载文件进度条实现原理
  19. vue设置必填项和判断必填项是否填入的弹窗提示
  20. C#中的get和set用法

热门文章

  1. 求一个N阶方阵右下三角元素的和
  2. use notification
  3. 怎么核对姓名、银行卡、身份证是不是同一个人?
  4. GAN相关:PAN(Perceptual Adversarial Network)/ 感知对抗网络
  5. 如何用javascript api for arcgis调用有参数的GP服务
  6. JavaScript - 专题 - 彻底搞懂parseInt
  7. 计算机毕业设计ssm基于HTML5的流浪动物领养平台yww0b系统+程序+源码+lw+远程部署
  8. 懒加载vue jQuery
  9. 网管工具——网络人(netman)
  10. php实现打字效果,JS实现的打字机效果示例代码