diff --git a/CMakeLists.txt b/CMakeLists.txt index 2689d8b4b3e7101ce3c15321c1c4fc30c73e4ea5..f12c25078f5a0d12f815e031cb82fd225e70ea0b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ find_package(catkin REQUIRED) # ******************************************************************** # Add catkin additional components here # ******************************************************************** -find_package(catkin REQUIRED COMPONENTS std_msgs nav_msgs visualization_msgs geometry_msgs nav_core pluginlib tf costmap_2d voxel_grid angles base_local_planner cmake_modules) +find_package(catkin REQUIRED COMPONENTS std_msgs nav_msgs ackermann_msgs visualization_msgs geometry_msgs nav_core pluginlib tf costmap_2d voxel_grid angles base_local_planner cmake_modules) ## System dependencies are found with CMake's conventions find_package(Boost REQUIRED COMPONENTS thread) @@ -62,7 +62,7 @@ catkin_package( # ******************************************************************** # Add ROS and IRI ROS run time dependencies # ******************************************************************** - CATKIN_DEPENDS std_msgs nav_msgs visualization_msgs geometry_msgs nav_core pluginlib tf costmap_2d voxel_grid angles base_local_planner + CATKIN_DEPENDS std_msgs nav_msgs ackermann_msgs visualization_msgs geometry_msgs nav_core pluginlib tf costmap_2d voxel_grid angles base_local_planner # ******************************************************************** # Add system and labrobotica run time dependencies here # ******************************************************************** diff --git a/include/ackermann_odom_helper.h b/include/ackermann_odom_helper.h index ec1fb9c53a3707c1109353031fe04d8ec18f0470..8f09f7c3ff4b3a172b7879fe0345b073087be594 100644 --- a/include/ackermann_odom_helper.h +++ b/include/ackermann_odom_helper.h @@ -40,16 +40,11 @@ #include <tf/transform_datatypes.h> #include <nav_msgs/Odometry.h> +#include <ackermann_msgs/AckermannDriveStamped.h> +#include <ackermann_msgs/AckermannDrive.h> #include <ros/ros.h> #include <boost/thread.hpp> -typedef struct -{ - double trans_speed; - double steer_angle; - double steer_speed; -}TAckermannState; - class AckermannOdomHelper { public: @@ -58,22 +53,24 @@ class AckermannOdomHelper * @param odom_topic The topic on which to subscribe to Odometry * messages. If the empty string is given (the default), no * subscription is done. */ - AckermannOdomHelper(std::string odom_topic = "",int num_avg_samples=10); + AckermannOdomHelper(const std::string &odom_topic ="",const std::string &ackermann_topic="",int num_avg_samples=10); - void get_odom(nav_msgs::Odometry& base_odom); - void get_robot_vel(tf::Stamped<tf::Pose>& robot_vel); - void get_ackermann_state(TAckermannState &state); + void get_odom(nav_msgs::Odometry &base_odom); + void get_robot_vel(tf::Stamped<tf::Pose> &robot_vel); + void get_ackermann_state(ackermann_msgs::AckermannDrive &state); /** @brief Set the odometry topic. This overrides what was set in the constructor, if anything. * * This unsubscribes from the old topic (if any) and subscribes to the new one (if any). * * If odom_topic is the empty string, this just unsubscribes from the previous topic. */ - void set_odom_topic(std::string odom_topic); + void set_odom_topic(const std::string &odom_topic); + void set_ackermann_topic(const std::string &ackermann_topic); void set_average_samples(int num_average_samples); /** @brief Return the current odometry topic. */ std::string get_odom_topic(void) const; + std::string get_ackermann_topic(void) const; int get_average_samples(void); ~AckermannOdomHelper(); @@ -83,17 +80,26 @@ class AckermannOdomHelper * @param msg An Odometry message */ void odom_callback(const nav_msgs::Odometry::ConstPtr& msg); + /** + * @brief Callback for receiving ackermann data + * @param msg An AckermannDriveStamped message + */ + void ackermann_callback(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg); private: //odom topic std::string odom_topic_; - std::vector<TAckermannState> last_states; + + // ackermann topic + std::string ackermann_topic_; // we listen on odometry on the odom topic ros::Subscriber odom_sub_; nav_msgs::Odometry base_odom_; boost::mutex odom_mutex_; + + ros::Subscriber ackermann_sub_; + std::vector<ackermann_msgs::AckermannDrive> ackermann_data_; // global tf frame id - std::string frame_id_; ///< The frame_id associated this data }; #endif /* ODOMETRY_HELPER_ROS2_H_ */ diff --git a/include/ackermann_planner.h b/include/ackermann_planner.h index bc10f22966c7f517b305ecc6843da8116df10ee3..ba93e7247fd3de29f4e28551f19b0cf25a8b0b41 100644 --- a/include/ackermann_planner.h +++ b/include/ackermann_planner.h @@ -104,7 +104,7 @@ class AckermannPlanner * @param drive_velocities The velocities to send to the robot base * @return The highest scoring trajectory. A cost >= 0 means the trajectory is legal to execute. */ - base_local_planner::Trajectory find_best_path(geometry_msgs::PoseStamped &global_pose,TAckermannState ackermann,geometry_msgs::PoseStamped& drive_velocities,std::vector<geometry_msgs::Point> footprint_spec); + base_local_planner::Trajectory find_best_path(geometry_msgs::PoseStamped &global_pose,ackermann_msgs::AckermannDrive &ackermann,geometry_msgs::PoseStamped& drive_velocities,std::vector<geometry_msgs::Point> footprint_spec); /** * @brief Take in a new global plan for the local planner to follow, and adjust local costmaps diff --git a/include/ackermann_planner_ros.h b/include/ackermann_planner_ros.h index 19a72bcd6a809cb9279752fb06fabd82792fe96d..33f48c061fb25ef8387c81cd53d00cb06b8b4f41 100644 --- a/include/ackermann_planner_ros.h +++ b/include/ackermann_planner_ros.h @@ -143,6 +143,7 @@ class AckermannPlannerROS : public nav_core::BaseLocalPlanner AckermannOdomHelper odom_helper_; std::string odom_topic_; + std::string ackermann_topic_; bool stucked; bool first; diff --git a/package.xml b/package.xml index 412ede92c1a661f1700437337205091fa2177ce1..d7b89a91e3b44c4358fcb5ac92c4d76a5b2f2410 100755 --- a/package.xml +++ b/package.xml @@ -31,6 +31,7 @@ <!-- <build_depend>message_generation</build_depend> --> <build_depend>std_msgs</build_depend> <build_depend>nav_msgs</build_depend> + <build_depend>ackermann_msgs</build_depend> <build_depend>visualization_msgs</build_depend> <build_depend>geometry_msgs</build_depend> <build_depend>base_local_planner</build_depend> @@ -49,6 +50,7 @@ <!-- <run_depend>message_runtime</run_depend> --> <run_depend>std_msgs</run_depend> <run_depend>nav_msgs</run_depend> + <run_depend>ackermann_msgs</run_depend> <run_depend>visualization_msgs</run_depend> <run_depend>geometry_msgs</run_depend> <run_depend>base_local_planner</run_depend> diff --git a/src/ackermann_odom_helper.cpp b/src/ackermann_odom_helper.cpp index 525643e72ae792200a6cfe1fffbf055f3ce36480..5056a825c74f61c9f8fb6a0e6d8eb781e51add5e 100644 --- a/src/ackermann_odom_helper.cpp +++ b/src/ackermann_odom_helper.cpp @@ -36,38 +36,41 @@ *********************************************************************/ #include <ackermann_odom_helper.h> -AckermannOdomHelper::AckermannOdomHelper(std::string odom_topic,int num_avg_samples) +AckermannOdomHelper::AckermannOdomHelper(const std::string &odom_topic,const std::string &ackermann_topic,int num_avg_samples) { - set_odom_topic( odom_topic ); - last_states.resize(num_avg_samples); + set_odom_topic(odom_topic); + set_ackermann_topic(ackermann_topic); + ackermann_data_.resize(num_avg_samples); } void AckermannOdomHelper::odom_callback(const nav_msgs::Odometry::ConstPtr& msg) { - static int current_index=0; - ROS_INFO_ONCE("odom received!"); + ROS_INFO_ONCE("Odom received!"); //we assume that the odometry is published in the frame of the base boost::mutex::scoped_lock lock(odom_mutex_); - this->last_states[current_index].trans_speed=msg->twist.twist.linear.z; - this->last_states[current_index].steer_angle=msg->twist.twist.angular.x; - this->last_states[current_index].steer_speed=msg->twist.twist.angular.y; - current_index=(current_index+1)%this->last_states.size(); - base_odom_.twist.twist.linear.x = msg->twist.twist.linear.x; - base_odom_.twist.twist.linear.y = msg->twist.twist.linear.y; - base_odom_.twist.twist.linear.z = msg->twist.twist.linear.z;// ackermann forward speed - base_odom_.twist.twist.angular.x = msg->twist.twist.angular.x;//ackermann steer angle - base_odom_.twist.twist.angular.y = msg->twist.twist.angular.y;//ackermann steer speed - base_odom_.twist.twist.angular.z = msg->twist.twist.angular.z; + base_odom_=*msg; +} + +void AckermannOdomHelper::ackermann_callback(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg) +{ + static int current_index=0; + ROS_INFO_ONCE("Ackermann received!"); + + boost::mutex::scoped_lock lock(odom_mutex_); + ackermann_data_[current_index]=msg->drive; + current_index=(current_index+1)%this->ackermann_data_.size(); } //copy over the odometry information -void AckermannOdomHelper::get_odom(nav_msgs::Odometry& base_odom) { +void AckermannOdomHelper::get_odom(nav_msgs::Odometry& base_odom) +{ boost::mutex::scoped_lock lock(odom_mutex_); base_odom = base_odom_; } -void AckermannOdomHelper::get_robot_vel(tf::Stamped<tf::Pose>& robot_vel) { +void AckermannOdomHelper::get_robot_vel(tf::Stamped<tf::Pose>& robot_vel) +{ // Set current velocities from odometry geometry_msgs::Twist global_vel; { @@ -82,26 +85,26 @@ void AckermannOdomHelper::get_robot_vel(tf::Stamped<tf::Pose>& robot_vel) { robot_vel.stamp_ = ros::Time(); } -void AckermannOdomHelper::get_ackermann_state(TAckermannState &state) +void AckermannOdomHelper::get_ackermann_state(ackermann_msgs::AckermannDrive &state) { unsigned int i=0; boost::mutex::scoped_lock lock(odom_mutex_); - state.trans_speed=0; - state.steer_angle=0; - state.steer_speed=0; - for(i=0;i<this->last_states.size();i++) + state.speed=0; + state.steering_angle=0; + state.steering_angle_velocity=0; + for(i=0;i<this->ackermann_data_.size();i++) { - state.trans_speed+=this->last_states[i].trans_speed; - state.steer_angle+=this->last_states[i].steer_angle; - state.steer_speed+=this->last_states[i].steer_speed; + state.speed+=this->ackermann_data_[i].speed; + state.steering_angle+=this->ackermann_data_[i].steering_angle; + state.steering_angle_velocity+=this->ackermann_data_[i].steering_angle_velocity; } - state.trans_speed/=this->last_states.size(); - state.steer_angle/=this->last_states.size(); - state.steer_speed/=this->last_states.size(); + state.speed/=this->ackermann_data_.size(); + state.steering_angle/=this->ackermann_data_.size(); + state.steering_angle_velocity/=this->ackermann_data_.size(); } -void AckermannOdomHelper::set_odom_topic(std::string odom_topic) +void AckermannOdomHelper::set_odom_topic(const std::string &odom_topic) { if( odom_topic != odom_topic_ ) { @@ -119,11 +122,29 @@ void AckermannOdomHelper::set_odom_topic(std::string odom_topic) } } +void AckermannOdomHelper::set_ackermann_topic(const std::string &ackermann_topic) +{ + if(ackermann_topic != ackermann_topic_ ) + { + ackermann_topic_ = ackermann_topic; + + if( ackermann_topic_ != "" ) + { + ros::NodeHandle gn; + ackermann_sub_ = gn.subscribe<ackermann_msgs::AckermannDriveStamped>( ackermann_topic_, 1, boost::bind( &AckermannOdomHelper::ackermann_callback, this, _1 )); + } + else + { + ackermann_sub_.shutdown(); + } + } +} + void AckermannOdomHelper::set_average_samples(int num_average_samples) { boost::mutex::scoped_lock lock(odom_mutex_); - if(num_average_samples!=this->last_states.size()) - this->last_states.resize(num_average_samples); + if(num_average_samples!=this->ackermann_data_.size()) + this->ackermann_data_.resize(num_average_samples); } std::string AckermannOdomHelper::get_odom_topic(void) const @@ -131,9 +152,14 @@ std::string AckermannOdomHelper::get_odom_topic(void) const return this->odom_topic_; } +std::string AckermannOdomHelper::get_ackermann_topic(void) const +{ + return this->ackermann_topic_; +} + int AckermannOdomHelper::get_average_samples(void) { - return this->last_states.size(); + return this->ackermann_data_.size(); } AckermannOdomHelper::~AckermannOdomHelper() diff --git a/src/ackermann_planner.cpp b/src/ackermann_planner.cpp index cf8f4a3e5b68ec470b9b39f0fb844e0bfc7b86e0..969dcd2b6323032e21f145e6e96457dc687dba4b 100644 --- a/src/ackermann_planner.cpp +++ b/src/ackermann_planner.cpp @@ -239,7 +239,7 @@ void AckermannPlanner::update_plan_and_local_costs(geometry_msgs::PoseStamped &g /* * given the current state of the robot, find a good trajectory */ -base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::PoseStamped &global_pose,TAckermannState ack_state,geometry_msgs::PoseStamped& drive_velocities,std::vector<geometry_msgs::Point> footprint_spec) +base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::PoseStamped &global_pose,ackermann_msgs::AckermannDrive &ackermann,geometry_msgs::PoseStamped& drive_velocities,std::vector<geometry_msgs::Point> footprint_spec) { obstacle_costs_.setFootprint(footprint_spec); @@ -247,14 +247,14 @@ base_local_planner::Trajectory AckermannPlanner::find_best_path(geometry_msgs::P boost::mutex::scoped_lock l(configuration_mutex_); Eigen::Vector3f pos(global_pose.pose.position.x, global_pose.pose.position.y, tf::getYaw(global_pose.pose.orientation)); - Eigen::Vector3f ackermann(ack_state.trans_speed,ack_state.steer_angle,ack_state.steer_speed); + Eigen::Vector3f ack_state(ackermann.speed,ackermann.steering_angle,ackermann.steering_angle_velocity); geometry_msgs::PoseStamped goal_pose = global_plan_.back(); Eigen::Vector3f goal(goal_pose.pose.position.x, goal_pose.pose.position.y, tf::getYaw(goal_pose.pose.orientation)); AckermannPlannerLimits limits = planner_util_->get_current_limits(); // prepare cost functions and generators for this run generator_.initialise(pos, - ackermann, + ack_state, goal, &limits, vsamples_); diff --git a/src/ackermann_planner_ros.cpp b/src/ackermann_planner_ros.cpp index e293aea0dbe39ac7adf91a2f19bc2d9c382610b1..18a29fed0162e5d124114872b71de0db07e17142 100644 --- a/src/ackermann_planner_ros.cpp +++ b/src/ackermann_planner_ros.cpp @@ -52,7 +52,7 @@ PLUGINLIB_EXPORT_CLASS(AckermannPlannerROS, nav_core::BaseLocalPlanner) AckermannPlannerROS::AckermannPlannerROS() : initialized_(false), - odom_helper_("odom",10), setup_(false) + odom_helper_("odom","ackermann_feedback",10), setup_(false) { patience_=1; this->stucked=false; @@ -125,6 +125,10 @@ void AckermannPlannerROS::initialize(std::string name,tf2_ros::Buffer* tf,costma { odom_helper_.set_odom_topic( odom_topic_ ); } + if( private_nh.getParam( "ackermann_topic", ackermann_topic_ )) + { + odom_helper_.set_ackermann_topic( ackermann_topic_ ); + } initialized_ = true; @@ -160,7 +164,6 @@ void AckermannPlannerROS::publish_local_plan(std::vector<geometry_msgs::PoseStam base_local_planner::publishPlan(path, l_plan_pub_); } - void AckermannPlannerROS::publish_global_plan(std::vector<geometry_msgs::PoseStamped>& path) { base_local_planner::publishPlan(path, g_plan_pub_); @@ -177,24 +180,24 @@ bool AckermannPlannerROS::ackermann_compute_velocity_commands(geometry_msgs::Pos return false; } - TAckermannState ackermann; + ackermann_msgs::AckermannDrive ackermann; AckermannPlannerLimits limits; odom_helper_.get_ackermann_state(ackermann); limits=planner_util_.get_current_limits(); // saturate speeds and angles - if(ackermann.trans_speed>limits.max_trans_vel) - ackermann.trans_speed=limits.max_trans_vel; - else if(ackermann.trans_speed<limits.min_trans_vel) - ackermann.trans_speed=limits.min_trans_vel; - if(ackermann.steer_angle>limits.max_steer_angle) - ackermann.steer_angle=limits.max_steer_angle; - else if(ackermann.steer_angle<limits.min_steer_angle) - ackermann.steer_angle=limits.min_steer_angle; - if(ackermann.steer_speed>limits.max_steer_vel) - ackermann.steer_speed=limits.max_steer_vel; - else if(ackermann.steer_speed<limits.min_steer_vel) - ackermann.steer_speed=limits.min_steer_vel; + if(ackermann.speed>limits.max_trans_vel) + ackermann.speed=limits.max_trans_vel; + else if(ackermann.speed<limits.min_trans_vel) + ackermann.speed=limits.min_trans_vel; + if(ackermann.steering_angle>limits.max_steer_angle) + ackermann.steering_angle=limits.max_steer_angle; + else if(ackermann.steering_angle<limits.min_steer_angle) + ackermann.steering_angle=limits.min_steer_angle; + if(ackermann.steering_angle_velocity>limits.max_steer_vel) + ackermann.steering_angle_velocity=limits.max_steer_vel; + else if(ackermann.steering_angle_velocity<limits.min_steer_vel) + ackermann.steering_angle_velocity=limits.min_steer_vel; //compute what trajectory to drive along geometry_msgs::PoseStamped drive_cmds; @@ -430,7 +433,7 @@ bool AckermannPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel) // check wether the robot get stucked or not if(new_segment || this->first) { - TAckermannState ackermann; + ackermann_msgs::AckermannDrive ackermann; odom_helper_.get_ackermann_state(ackermann); // steer the car without moving if the steering angle is big