运动控制入门到入土:pure persuit纯追踪算法gazebo仿真

本代码根据【从零开始自动驾驶】01 - 05_哔哩哔哩_bilibili 的逻辑和代码。写了一套C++代码

感谢B站up Imjusty的教学

cmdvel2gazebo.cpp

#include "cmdvel2gazebo.h"

int main(int argc, char** argv){
  ros::init(argc, argv, "cmdvel2gazebo");
  cmdvel2gazebo cmdvel2gazebo;
  cmdvel2gazebo.control();
  return 0;
}

void cmdvel2gazebo::Cmd_Vel_Callback(const geometry_msgs::Twist &twist){
  velocity = twist.linear.x / 0.3;
  // cout << "velocity:" << velocity <<endl;
  angle = max(-maxsteer, min(maxsteer, twist.angular.z));
  // cout << "angle:" << angle <<endl;
  last_Time = ros::Time::now();
  publish();
}

void cmdvel2gazebo::control(){
  ros::spin();
}

void cmdvel2gazebo::publish(){
  std_msgs::Float64 msg_vel_L, msg_vel_R, msg_ang_L, msg_ang_R;
  delta_Time = (ros::Time::now()- last_Time).toSec();
  msgs_too_old = delta_Time > timeout ? 1: 0;
  if(msgs_too_old){
    velocity = 0;
    angle= 0;
    msg_vel_L.data = velocity;
    msg_vel_R.data = velocity;
    msg_ang_L.data = angle;
    msg_ang_R.data = angle;

    pub_rearL.publish(msg_vel_L);
    pub_rearR.publish(msg_vel_R);
    pub_steerL.publish(msg_ang_L);
    pub_steerR.publish(msg_ang_R);
  }

  // cout << "velocity1:" << velocity <<endl;
  // cout << "angle1:" << angle <<endl;

  if(angle!= 0){
    radius = wheelbase/fabs(tan(angle));
    radius_rearL = radius- (copysign(1, angle)* (Tread/ 2.0));
    radius_rearR = radius+ (copysign(1, angle)* (Tread/ 2.0));
    radius_frontL = radius- (copysign(1, angle)* (Tread/ 2.0));
    radius_frontR = radius+ (copysign(1, angle)* (Tread/ 2.0));

    velocity_rearL = velocity* radius_rearL/ radius;
    velocity_rearR = velocity* radius_rearR/ radius;

    msg_vel_L.data = velocity_rearL;
    msg_vel_R.data = velocity_rearR;


    pub_rearL.publish(msg_vel_L);
    pub_rearR.publish(msg_vel_R);

    angle_frontL = atan2(wheelbase, radius_frontL)* copysign(1, angle);
    angle_frontR = atan2(wheelbase, radius_frontR)* copysign(1, angle);

    // cout << "angle_L:" << angle_frontL <<endl;
    // cout << "angle_R:" << angle_frontR <<endl;

    msg_ang_L.data = angle_frontL;
    msg_ang_R.data = angle_frontR;

    pub_steerL.publish(msg_ang_L);
    pub_steerR.publish(msg_ang_R);
  }
  else{
    msg_vel_L.data = velocity;
    msg_vel_R.data = velocity;
    msg_ang_L.data = angle;
    msg_ang_R.data = angle;

    pub_rearL.publish(msg_vel_L);
    pub_rearR.publish(msg_vel_R);
    pub_steerL.publish(msg_ang_L);
    pub_steerR.publish(msg_ang_R);
  }

}

cmdvel2gazebo::cmdvel2gazebo()
{
  pub_steerL = n.advertise <std_msgs::Float64>("/smart/front_left_steering_position_controller/command", 10);
  pub_steerR = n.advertise <std_msgs::Float64>("/smart/front_right_steering_position_controller/command", 10);
  pub_rearL = n.advertise <std_msgs::Float64>("/smart/rear_left_velocity_controller/command",10);
  pub_rearR = n.advertise <std_msgs::Float64>("/smart/rear_right_velocity_controller/command",10);
  cmd_vel_sub = n.subscribe("/smart/cmd_vel", 100, &cmdvel2gazebo::Cmd_Vel_Callback, this);


  last_Time= ros::Time::now();


  rMax = wheelbase/ tan(maxsteerInside);
  rIdeal = rMax+ (Tread/ 2.0);
  maxsteer = atan2(wheelbase, rIdeal);
}

cmdvel2gazebo::~cmdvel2gazebo()
{
}

transform_publisher.cpp

#include "transform_publisher.h"

int main(int argc, char** argv){
  ros::init(argc, argv, "transform_publisher");
  transform_publisher transform_publisher;
  transform_publisher.control();
}

void transform_publisher::pose_callback(const geometry_msgs::PoseStamped &pose_msgs){
  auto pose = pose_msgs.pose.position;
  cout << pose << endl;
  auto orientation = pose_msgs.pose.orientation;
  static tf::TransformBroadcaster br;
  tf::Transform transform;
  transform.setOrigin(tf::Vector3(pose.x, pose.y, pose.z));
  transform.setRotation(tf::Quaternion(orientation.x, orientation.y, orientation.z, orientation.w));

  br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", "base_link"));
}

void transform_publisher::control(){
  ros::spin();
}

transform_publisher::transform_publisher(){
  center_pose_sub = n.subscribe("/smart/center_pose", 10, &transform_publisher::pose_callback, this);
}

transform_publisher::~transform_publisher(){

}

vehicle_pose_and_velocity_updater.cpp

#include "vehicle_pose_and_velocity_updater.h"

int main(int argc, char** argv){
  ros::init(argc, argv, "vehicle_pose_and_velocity_updater");
  vehicle_pose_and_velocity_updater vehicle_pose_and_velocity_updater;
  vehicle_pose_and_velocity_updater.control();
  return 0;
}

void vehicle_pose_and_velocity_updater::model_states_callback(const gazebo_msgs::ModelStatesConstPtr &states){
  int modelCount = states->name.size();
  for(int modelInd = 0; modelInd < modelCount; ++modelInd)
  {
    if(states->name[modelInd] == "smart")
    {
      vehicle_position = states->pose[modelInd];
      vehicle_velocity = states->twist[modelInd];
      orientation = vehicle_position.orientation;

      tf::Quaternion quaternion1(
        orientation.x,
        orientation.y,
        orientation.z,
        orientation.w
      );
      double roll, pitch, yaw;//定义存储r\p\y的容器
      tf::Matrix3x3(quaternion1).getRPY(roll, pitch, yaw);//进行转换
      time_stamp = ros::Time::now();

      geometry_msgs::PoseStamped center_pose;
      center_pose.header.frame_id = "/world";
      center_pose.header.stamp = time_stamp;
      center_pose.pose.position = vehicle_position.position;
		  center_pose.pose.orientation = vehicle_position.orientation;
		  center_pose_pub.publish(center_pose);

      geometry_msgs::PoseStamped rear_pose;
      rear_pose.header.frame_id = "/world";
      rear_pose.header.stamp = time_stamp;
      double center_x = vehicle_position.position.x;
      double center_y = vehicle_position.position.y;
      double rear_x = center_x - cos(yaw) * 0.945;
      double rear_y = center_y - sin(yaw) * 0.945;
      rear_pose.pose.position.x = rear_x;
      rear_pose.pose.position.y = rear_y;
      rear_pose.pose.orientation = vehicle_position.orientation;
      rear_pose_pub.publish(rear_pose);

      geometry_msgs::TwistStamped velocity;
      velocity.header.frame_id ="world";
      velocity.header.stamp = time_stamp;
      velocity.twist.linear = vehicle_velocity.linear;
      velocity.twist.angular = vehicle_velocity.angular;
      vel_pub.publish(velocity);
    }
  }
}

void vehicle_pose_and_velocity_updater::control(){
  ros::spin();
}


vehicle_pose_and_velocity_updater::vehicle_pose_and_velocity_updater(){
  rear_pose_pub = n.advertise<geometry_msgs::PoseStamped>("/smart/rear_pose", 10);
  center_pose_pub = n.advertise<geometry_msgs::PoseStamped>("/smart/center_pose", 10);
  vel_pub = n.advertise<geometry_msgs::TwistStamped>("/smart/velocity",10);

  model_states_sub = n.subscribe("/gazebo/model_states", 10, &vehicle_pose_and_velocity_updater::model_states_callback,this);
}

vehicle_pose_and_velocity_updater::~vehicle_pose_and_velocity_updater(){

}

waypoint_loader.cpp

#include "waypoint_loader.h"

double waypoint_loader::two_points_distance(const geometry_msgs::Point &current_position, const geometry_msgs::Point &last_position){
  double x,y,z;
  x = current_position.x - last_position.x;
  y = current_position.y - last_position.y;
  z = current_position.z - last_position.z;
  return sqrt(x*x+y*y+z*z);
}

vector<styx_msgs::Waypoint> waypoint_loader::decelerate(const vector<styx_msgs::Waypoint> &data){
  vector<styx_msgs::Waypoint> Return_data = data;
  styx_msgs::Waypoint last;
  double dist, vel;
  last = data[waypoint_count -1];
  last.twist.twist.linear.x = 0;
  for (int i = 0; i < data.size(); i++)
  {
    dist = two_points_distance(data[i].pose.pose.position, last.pose.pose.position);
    vel = sqrt(2* MAX_DECEL* dist);
    if(vel<1){
      vel=0;
    }
    Return_data[i].twist.twist.linear.x = min(vel, data[i].twist.twist.linear.x);
  }
  return Return_data;
}


void waypoint_loader::getPose(std::string s, double *v)
{
  int p = 0;
  int q = 0;
  for (int i = 0; i < s.size(); i++)
  {
    if (s[i] == ',' || i == s.size() - 1)
    {
      char tab2[16];
      strcpy(tab2, s.substr(p, i - p).c_str());
      v[q] = std::strtod(tab2, NULL);
      p = i + 1;
      q++;
    }
  }
}

int waypoint_loader::process(){
  std::ifstream f(ros::package::getPath("waypoint_loader") + "/waypoints/" + "waypoints.csv");
  //f.open(ros::package::find(plan_pkg)+"/paths/path.csv"); //ros::package::find(plan_pkg)
  if (!f.is_open())
  {
    ROS_ERROR("failed to open file");
    return 0;
  }
  std::string line;
  std::vector<styx_msgs::Waypoint> waypoints;
  styx_msgs::Lane lane;
  double scale = 100;
  int count = -1;
  nav_msgs::Path ros_path_;

  geometry_msgs::PoseArray track;
  track.header.stamp = ros::Time::now();
  track.header.frame_id = "/world";
  while (std::getline(f, line))
  {
    count++;
    double pose[3];
    getPose(line, pose);
    tf::Quaternion q = tf::createQuaternionFromRPY(0, 0, pose[2]);
    geometry_msgs::Pose pose1;

    geometry_msgs::PoseStamped pose2;
    styx_msgs::Waypoint pose3;
    ros_path_.header.frame_id = "/world";
    ros_path_.header.stamp = ros::Time::now();  
    pose2.header = ros_path_.header;

    pose2.pose.position.x = pose[0];
    pose2.pose.position.y = pose[1];
    pose2.pose.position.z = 0;

    pose1.orientation.x = q.x();
    pose1.orientation.y = q.y();
    pose1.orientation.z = q.z();
    pose1.orientation.w = q.w();
    pose1.position.x = pose[0];
    pose1.position.y = pose[1];
    pose1.position.z = 0;

    pose3.pose.pose.position.x = pose[0];
    pose3.pose.pose.position.y = pose[1];
    pose3.pose.pose.position.z = 0;
    pose3.pose.pose.orientation.x = q.x();
    pose3.pose.pose.orientation.y = q.y();
    pose3.pose.pose.orientation.z = q.z();
    pose3.pose.pose.orientation.w = q.w();
    pose3.twist.twist.linear.x = 2.78;
    pose3.forward = true;

    waypoints.push_back(pose3);
    track.poses.push_back(pose1);
    ros_path_.poses.push_back(pose2);
  }

  waypoint_count = waypoints.size();
  waypoints = decelerate(waypoints);

  lane.header.frame_id = "world";
  lane.header.stamp = ros::Time::now();
  lane.waypoints = waypoints;

  while (ros::ok())
  {
    path_pub.publish(track);
    state_pub_.publish(ros_path_);
    path.publish(lane);
  }
  return 0;
}

int main(int argc, char **argv)
{
  setlocale(LC_ALL, "");
  ros::init(argc, argv, "waypoint_loader");
  waypoint_loader waypoint_loader;
  ros::AsyncSpinner spinner(1);
  spinner.start();
  sleep(1);
  waypoint_loader.process();
}

waypoint_updater.cpp

#include "waypoint_updater.h"

void waypoint_updater::publish_waypoints(const int &idx, const ros::Publisher &final_waypoints_pub, const ros::Publisher &final_path_pub){
  styx_msgs::Lane Lane_pub;
  Lane_pub.header = base_waypoints.header;
  if(idx + LOOKAHEAD_WPS < waypoint_count){
    for (int i = 0; i < LOOKAHEAD_WPS; i++)
    {
    Lane_pub.waypoints.push_back(base_waypoints.waypoints[idx+i]);
    }
  }
  else
  {
    for (int i = 0; i < waypoint_count - idx; i++)
    {
    Lane_pub.waypoints.push_back(base_waypoints.waypoints[idx+i]);
    }
  }

  nav_msgs::Path path;
  path.header.frame_id = "/world";
  for(int i = 0; i < Lane_pub.waypoints.size();i++){
    geometry_msgs::PoseStamped path_element;
    path_element.pose.position.x = Lane_pub.waypoints[i].pose.pose.position.x;
    path_element.pose.position.y = Lane_pub.waypoints[i].pose.pose.position.y;
    path_element.pose.position.z = Lane_pub.waypoints[i].pose.pose.position.z;
    path.poses.push_back(path_element);
  }
  final_waypoints_pub.publish(Lane_pub);
  final_path_pub.publish(path);
}

int waypoint_updater::get_closest_waypoint_idx(){
  pcl::PointXYZ searchPoint;
  searchPoint.x = pose.pose.position.x;
  searchPoint.y = pose.pose.position.y;
  searchPoint.z = pose.pose.position.z;

  vector<int> pointIdxNKNSearch(K);
  vector<float> pointNKNSquaredDistance(K);
  if(kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0){
    for (size_t i=0; i<pointIdxNKNSearch.size (); ++i){
      // cout << "    点" << (*cloud)[pointIdxNKNSearch[i]].x
      //   << " " << (*cloud)[pointIdxNKNSearch[i]].y
      //   << " " << (*cloud)[pointIdxNKNSearch[i]].z
      //   << " (平方距离: " << pointNKNSquaredDistance[i] << ")" << endl;
      // cout << "Index :" << pointIdxNKNSearch[i] << endl;
    }
    return pointIdxNKNSearch[0];
  }
}

void waypoint_updater::pose_cb(const geometry_msgs::PoseStamped &msg)
{
  pose = msg;
  // cout << pose << endl;
}

void waypoint_updater::waypoint_cb(const styx_msgs::Lane &waypoints)
{
  waypoint_count = waypoints.waypoints.size();
  base_waypoints = waypoints;
  if((*cloud).size() == 0 ){
    cloud->width = 56;
    cloud->height = 1; 
    cloud->points.resize(cloud->width * cloud->height); 
    for (int i = 0; i < waypoints.waypoints.size(); i++){
      (*cloud)[i].x = waypoints.waypoints[i].pose.pose.position.x;
      (*cloud)[i].y = waypoints.waypoints[i].pose.pose.position.y;
      (*cloud)[i].z = waypoints.waypoints[i].pose.pose.position.z;
    }
    kdtree.setInputCloud(cloud);
  }
}

void waypoint_updater::process(){
  while(ros::ok())
  {
    ros::spinOnce();
    if(base_waypoints.waypoints.size()!=0){
      int closest_waypoint_idx = get_closest_waypoint_idx();
      publish_waypoints(closest_waypoint_idx, final_waypoints_pub, final_path_pub);
    }
  }
}

int main(int argc, char** argv){
  ros::init(argc, argv, "waypoint_updater");
  waypoint_updater waypoint_updater;
  waypoint_updater.process();
  return 0;
}

pure_persuit.cpp

#include "pure_persuit.h"

geometry_msgs::Twist pure_persuit::calculateTwistCommand(){
  double lad = 0.0;
  int targetIndex = currentWaypoints.waypoints.size() -1;
  for(int i = 0; i<currentWaypoints.waypoints.size(); i++){
    if(i+1 < currentWaypoints.waypoints.size()){
      double this_x = currentWaypoints.waypoints[i].pose.pose.position.x;
			double this_y = currentWaypoints.waypoints[i].pose.pose.position.y;
			double next_x = currentWaypoints.waypoints[i+1].pose.pose.position.x;
			double next_y = currentWaypoints.waypoints[i+1].pose.pose.position.y;
      lad = lad + hypot(next_x - this_x, next_y - this_y);
      if(lad > HORIZON){
        targetIndex = i+1;
        break;
      }
    }
  }

  geometry_msgs::Twist twistCmd;
  styx_msgs::Waypoint targetWaypoint;
  double targetSpeed, targetX, targetY, currentX, currentY;
  targetWaypoint = currentWaypoints.waypoints[targetIndex];
  targetSpeed = currentWaypoints.waypoints[0].twist.twist.linear.x;
  targetX = targetWaypoint.pose.pose.position.x;
  targetY = targetWaypoint.pose.pose.position.y;
  currentX = currentPose.pose.position.x;
  currentY = currentPose.pose.position.y;
  tf::Quaternion q(currentPose.pose.orientation.x, currentPose.pose.orientation.y, currentPose.pose.orientation.z, currentPose.pose.orientation.w);
  double roll, pitch, yaw;
  tf::Matrix3x3(q).getRPY(roll, pitch, yaw);
  auto alpha = atan2(targetY - currentY, targetX - currentX) - yaw;
  auto l = sqrt(pow(currentX - targetX, 2) + pow(currentY - targetY, 2));
  if(l > 0.5){
    auto theta = atan(2 * 1.868 * sin(alpha) / l);
    twistCmd.linear.x = targetSpeed;
    twistCmd.angular.z = theta; 
  }
  else{
    twistCmd.linear.x = 0;
    twistCmd.angular.z = 0; 
  }
  return twistCmd;
}

void pure_persuit::process(){
  while (ros::ok())
  {
    ros::spinOnce();
    if(currentWaypoints.waypoints.size()!=0){
    geometry_msgs::Twist twistCommand = calculateTwistCommand();
    cmd_vel.publish(twistCommand);
    }
  }
}

void pure_persuit::pose_cb(const geometry_msgs::PoseStamped &data1){
  currentPose = data1;
}

void pure_persuit::vel_cb(const geometry_msgs::TwistStamped &data2){
  currentVelocity = data2;
}

void pure_persuit::lane_cb(const styx_msgs::Lane &data3){
  currentWaypoints = data3;
}

int main(int argc, char** argv){
  ros::init(argc, argv, "pure_persuit");
  pure_persuit pure_persuit;
  pure_persuit.process();
  return 0;
}

github:GitHub - casso1993/Pure_Persuit_Simulation

1.open gazebo

roslaunch gazebo_ros empty_world.launch

2.run the set environment

roslaunch car_model spawn_car.launch

3.run rviz

rviz

File -> open config -> "src/car_model/rviz_config/samrt.rviz"

4.run pure persuit

roslaunch pure_persuit pure_persuit.launch

偷懒,先不写原理

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MATLAB中的Pure Pursuit是一种路径规划算法,用于模拟自动驾驶车辆等应用场景中的目标跟踪。该算法通过计算车辆当前位置与目标位置之间的距离与方向差,实现车辆在给定路径上跟踪目标。 Pure Pursuit算法实现步骤如下:首先,需要确定车辆与路径的几何关系。在路径上选择一个点作为目标点,然后根据车辆当前状态计算目标点与车辆的位置、朝向之间的距离和方向差。根据这些信息,可以计算出车辆与目标点之间的前轮转角。 其次,需要根据车辆的物理约束来选择目标点。通常情况下,车辆无法瞬间转向,因此需要选择一个合理的目标点,使得车辆能够平滑地跟踪路径。在选择目标点时,可以考虑车辆的转弯半径、最大转角等因素。 最后,需要根据车辆的控制系统来执行前轮转角。根据目标点与车辆之间的距离和方向差,可以计算出车辆与目标点之间的前轮转角。通过控制系统,可以将这个转角转化为车辆的控制指令,从而实现车辆在给定路径上的跟踪。 总结来说,MATLAB中的Pure Pursuit算法通过计算车辆与目标点之间的距离和方向差,实现车辆在给定路径上的跟踪。该算法需要确定车辆与路径的几何关系、选择合适的目标点,并根据车辆的控制系统执行前轮转角。通过这些步骤,可以实现自动驾驶车辆等应用场景中的路径规划。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值