-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feature] Added service based waypoint planner with continuous odomet…
…ry integration
- Loading branch information
Showing
11 changed files
with
376 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#ifndef CARROT_BASE_H | ||
#define CARROT_BASE_H | ||
|
||
#include <vector> | ||
|
||
#include "eigen3/Eigen/Dense" | ||
#include "navigation_types.h" | ||
|
||
using navigation::CarrotPlan; | ||
using navigation::Odom; | ||
|
||
class CarrotBase { | ||
public: | ||
// Virtual destructor for proper cleanup of derived classes | ||
virtual ~CarrotBase() {} | ||
|
||
/** | ||
* Pure virtual function to be implemented by derived classes. | ||
* @param local_carrot: The target waypoint in local coordinates. | ||
* @return A struct containing the computed carrot plan. | ||
*/ | ||
virtual struct CarrotPlan GetCarrot(const Eigen::Vector2f& local_carrot, | ||
const Odom& odom) = 0; | ||
|
||
protected: | ||
Eigen::Vector2f current_carrot_; // Current carrot location | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
//======================================================================== | ||
// This software is free: you can redistribute it and/or modify | ||
// it under the terms of the GNU Lesser General Public License Version 3, | ||
// as published by the Free Software Foundation. | ||
// | ||
// This software is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Lesser General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Lesser General Public License | ||
// Version 3 in the file COPYING that came with this distribution. | ||
// If not, see <http://www.gnu.org/licenses/>. | ||
//======================================================================== | ||
/*! | ||
\file carrot_service.h | ||
\brief Carrot server client interface for local navigation. | ||
\author Arthur Zhang (C) 2024 | ||
*/ | ||
//======================================================================== | ||
#ifndef API_CARROT_H | ||
#define API_CARROT_H | ||
|
||
#include <geometry_msgs/PoseStamped.h> | ||
#include <nav_msgs/Path.h> | ||
#include <ros/ros.h> | ||
#include <std_msgs/Bool.h> | ||
|
||
#include <condition_variable> | ||
#include <mutex> | ||
#include <vector> | ||
|
||
#include "amrl_msgs/CarrotPlannerSrv.h" | ||
#include "carrot_base.h" // Include the parent class header | ||
|
||
using navigation::CarrotPlan; | ||
using navigation::Odom; | ||
|
||
class CarrotService : public CarrotBase { | ||
public: | ||
// Constructor | ||
explicit CarrotService(const std::string& service_name); | ||
|
||
// Overridden plan function | ||
CarrotPlan GetCarrot(const Eigen::Vector2f& local_carrot, | ||
const Odom& odom) override; | ||
|
||
private: | ||
ros::NodeHandle nh_; // ROS node handle | ||
ros::ServiceClient service_client_; // ROS service client | ||
|
||
// Thread-safe shared state | ||
CarrotPlan latest_carrot_plan_; // Latest carrot plan | ||
Odom latest_odom_; // Latest odometry message | ||
bool has_carrot_ = false; // Indicates if a carrot exists | ||
bool service_request_ongoing_ = | ||
false; // Indicates if a service request is ongoing | ||
std::mutex mutex_; // Mutex for thread-safe access | ||
std::condition_variable cv_; // Condition variable for blocking | ||
|
||
// Helper functions | ||
void TransformCarrot(const Odom& odom, CarrotPlan& carrot_plan); | ||
void RequestCarrotUpdate(const Eigen::Vector2f& local_waypoint, | ||
const Odom& odom); | ||
}; | ||
|
||
#endif // API_CARROT_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#include "carrot_service.h" | ||
|
||
#include <stdexcept> | ||
#include <thread> | ||
|
||
using amrl_msgs::CarrotPlannerSrv; | ||
using Eigen::Affine2f; | ||
using Eigen::Vector2f; | ||
using navigation::CarrotPlan; | ||
using navigation::Odom; | ||
using std::vector; | ||
|
||
// Constructor | ||
CarrotService::CarrotService(const std::string& service_name) { | ||
// Initialize the ROS service client | ||
service_client_ = nh_.serviceClient<CarrotPlannerSrv>(service_name); | ||
} | ||
|
||
CarrotPlan CarrotService::GetCarrot(const Vector2f& local_waypoint, | ||
const Odom& odom) { | ||
// Initiate a service request if no request is ongoing | ||
{ | ||
std::lock_guard<std::mutex> lock(mutex_); | ||
if (!service_request_ongoing_) { | ||
service_request_ongoing_ = true; | ||
std::thread(&CarrotService::RequestCarrotUpdate, this, local_waypoint, | ||
odom) | ||
.detach(); | ||
} | ||
} | ||
|
||
// Transform the current path to the current odom frame | ||
TransformCarrot(odom, latest_carrot_plan_); | ||
|
||
return latest_carrot_plan_; | ||
} | ||
|
||
void CarrotService::TransformCarrot(const Odom& odom, CarrotPlan& carrot_plan) { | ||
// Block until a carrot exists | ||
std::unique_lock<std::mutex> lock(mutex_); | ||
cv_.wait(lock, [this] { return has_carrot_; }); | ||
|
||
// Transformations at time t0 and t1 | ||
Eigen::Affine2f T_baset0_odom = | ||
latest_odom_.toAffine2f(); // Transformation from local @ t' to odom | ||
Eigen::Affine2f T_baset1_odom = | ||
odom.toAffine2f(); // Transformation from local @ t'' to odom | ||
|
||
// Compute the relative transformation: local @ t' -> odom -> local @ t'' | ||
Eigen::Affine2f T_baset0_baset1 = T_baset1_odom.inverse() * T_baset0_odom; | ||
|
||
// Transform the path to the local frame at t'' | ||
for (const auto& point : latest_carrot_plan_.path) { | ||
// Transform local frame @ t' to odom frame, then to local frame @ t'' | ||
carrot_plan.path.emplace_back(T_baset0_baset1 * point); | ||
} | ||
carrot_plan.path_idx = carrot_plan.path.size() - 1; | ||
} | ||
|
||
void CarrotService::RequestCarrotUpdate(const Vector2f& local_waypoint, | ||
const Odom& odom) { | ||
try { | ||
CarrotPlannerSrv srv; | ||
|
||
// Prepare service request | ||
srv.request.carrot.header.stamp = ros::Time::now(); | ||
srv.request.carrot.header.frame_id = "map"; | ||
srv.request.carrot.pose.position.x = local_waypoint.x(); | ||
srv.request.carrot.pose.position.y = local_waypoint.y(); | ||
srv.request.carrot.pose.position.z = 0.0; | ||
srv.request.carrot.pose.orientation.x = 0.0; | ||
srv.request.carrot.pose.orientation.y = 0.0; | ||
srv.request.carrot.pose.orientation.z = 0.0; | ||
srv.request.carrot.pose.orientation.w = 1.0; | ||
|
||
// Call the service | ||
if (service_client_.call(srv)) { | ||
if (!srv.response.path.poses.empty()) { | ||
CarrotPlan new_plan; | ||
|
||
// Extract path | ||
for (const auto& pose : srv.response.path.poses) { | ||
new_plan.path.emplace_back( | ||
Eigen::Vector2f(pose.pose.position.x, pose.pose.position.y)); | ||
} | ||
|
||
// Update shared carrot plan | ||
{ | ||
std::lock_guard<std::mutex> lock(mutex_); | ||
latest_carrot_plan_ = new_plan; | ||
latest_odom_ = odom; | ||
has_carrot_ = true; | ||
} | ||
// printf("Service call successful\n"); | ||
cv_.notify_all(); | ||
} else { | ||
ROS_ERROR("Carrot planner service failed to compute a valid plan"); | ||
} | ||
} else { | ||
ROS_ERROR("Failed to call carrot planner service"); | ||
} | ||
} catch (const std::exception& e) { | ||
ROS_ERROR("Exception in carrot planner service: %s", e.what()); | ||
} | ||
|
||
// Mark service request as completed | ||
{ | ||
std::lock_guard<std::mutex> lock(mutex_); | ||
service_request_ongoing_ = false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
//======================================================================== | ||
// This software is free: you can redistribute it and/or modify | ||
// it under the terms of the GNU Lesser General Public License Version 3, | ||
// as published by the Free Software Foundation. | ||
// | ||
// This software is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Lesser General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Lesser General Public License | ||
// Version 3 in the file COPYING that came with this distribution. | ||
// If not, see <http://www.gnu.org/licenses/>. | ||
//======================================================================== | ||
/*! | ||
\file carrot_service.h | ||
\brief Carrot server client interface for local navigation. | ||
\author Arthur Zhang (C) 2024 | ||
*/ | ||
//======================================================================== | ||
#ifndef API_CARROT_H | ||
#define API_CARROT_H | ||
|
||
#include <geometry_msgs/PoseStamped.h> | ||
#include <nav_msgs/Path.h> | ||
#include <ros/ros.h> | ||
#include <std_msgs/Bool.h> | ||
|
||
#include <condition_variable> | ||
#include <mutex> | ||
#include <vector> | ||
|
||
#include "amrl_msgs/CarrotPlannerSrv.h" | ||
#include "carrot_base.h" // Include the parent class header | ||
|
||
using navigation::CarrotPlan; | ||
using navigation::Odom; | ||
|
||
class CarrotService : public CarrotBase { | ||
public: | ||
// Constructor | ||
explicit CarrotService(const std::string& service_name); | ||
|
||
// Overridden plan function | ||
CarrotPlan GetCarrot(const Eigen::Vector2f& local_carrot, | ||
const Odom& odom) override; | ||
|
||
private: | ||
ros::NodeHandle nh_; // ROS node handle | ||
ros::ServiceClient service_client_; // ROS service client | ||
|
||
// Thread-safe shared state | ||
CarrotPlan latest_carrot_plan_; // Latest carrot plan | ||
Odom latest_odom_; // Latest odometry message | ||
bool has_carrot_ = false; // Indicates if a carrot exists | ||
bool service_request_ongoing_ = | ||
false; // Indicates if a service request is ongoing | ||
std::mutex mutex_; // Mutex for thread-safe access | ||
std::condition_variable cv_; // Condition variable for blocking | ||
|
||
// Helper functions | ||
void TransformCarrot(const Odom& odom, CarrotPlan& carrot_plan); | ||
void RequestCarrotUpdate(const Eigen::Vector2f& local_waypoint, | ||
const Odom& odom); | ||
}; | ||
|
||
#endif // API_CARROT_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.