-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[RotationShimController] Rotate to goal heading
When arriving in the goal xy tolerance, the rotation shim controller takes back the control and perform the necessary rotation to be in the correct goal orientation. This can be useful when the final orientaion of the robot matters. It can also simplify the configuration of the primary controller since it would not have to be configured to be able to reach the target orientation.
- Loading branch information
Showing
3 changed files
with
147 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,8 @@ void RotationShimController::configure( | |
node, plugin_name_ + ".simulate_ahead_time", rclcpp::ParameterValue(1.0)); | ||
nav2_util::declare_parameter_if_not_declared( | ||
node, plugin_name_ + ".primary_controller", rclcpp::PARAMETER_STRING); | ||
nav2_util::declare_parameter_if_not_declared( | ||
node, plugin_name_ + ".rotate_to_goal_heading", rclcpp::ParameterValue(false)); | ||
|
||
node->get_parameter(plugin_name_ + ".angular_dist_threshold", angular_dist_threshold_); | ||
node->get_parameter(plugin_name_ + ".forward_sampling_distance", forward_sampling_distance_); | ||
|
@@ -73,6 +75,8 @@ void RotationShimController::configure( | |
node->get_parameter("controller_frequency", control_frequency); | ||
control_duration_ = 1.0 / control_frequency; | ||
|
||
node->get_parameter("rotate_to_goal_heading", rotate_to_goal_heading_); | ||
|
||
try { | ||
primary_controller_ = lp_loader_.createUniqueInstance(primary_controller); | ||
RCLCPP_INFO( | ||
|
@@ -134,11 +138,71 @@ void RotationShimController::cleanup() | |
primary_controller_.reset(); | ||
} | ||
|
||
/** | ||
* @brief Check if the robot pose is within the Goal Checker's tolerances to goal | ||
* @param global_checker Pointer to the goal checker | ||
* @param robot Pose of robot | ||
* @param path Path to retreive goal pose from | ||
* @return bool If robot is within goal checker tolerances to the goal | ||
*/ | ||
static bool withinPositionGoalTolerance( | ||
nav2_core::GoalChecker * goal_checker, | ||
const geometry_msgs::msg::Pose & robot, | ||
const geometry_msgs::msg::Pose & goal) | ||
{ | ||
if (goal_checker) { | ||
geometry_msgs::msg::Pose pose_tolerance; | ||
geometry_msgs::msg::Twist velocity_tolerance; | ||
goal_checker->getTolerances(pose_tolerance, velocity_tolerance); | ||
|
||
const auto pose_tolerance_sq = pose_tolerance.position.x * pose_tolerance.position.x; | ||
|
||
auto dx = robot.position.x - goal.position.x; | ||
auto dy = robot.position.y - goal.position.y; | ||
|
||
auto dist_sq = dx * dx + dy * dy; | ||
|
||
if (dist_sq < pose_tolerance_sq) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
geometry_msgs::msg::TwistStamped RotationShimController::computeVelocityCommands( | ||
const geometry_msgs::msg::PoseStamped & pose, | ||
const geometry_msgs::msg::Twist & velocity, | ||
nav2_core::GoalChecker * goal_checker) | ||
{ | ||
// Rotate to goal heading when in goal xy tolerance | ||
if (rotate_to_goal_heading_) { | ||
std::lock_guard<std::mutex> lock_reinit(mutex_); | ||
|
||
try { | ||
geometry_msgs::msg::Pose sampled_pt_goal = transformPoseToBaseFrame(getSampledPathGoal()); | ||
if (withinPositionGoalTolerance(goal_checker, pose.pose, sampled_pt_goal)) { | ||
double pose_yaw, pose_pitch, pose_roll; | ||
double goal_yaw, goal_pitch, goal_roll; | ||
tf2::getEulerYPR(pose.pose.orientation, pose_yaw, pose_pitch, pose_roll); | ||
tf2::getEulerYPR(sampled_pt_goal.orientation, goal_yaw, goal_pitch, goal_roll); | ||
|
||
double angular_distance_to_heading = std::abs(goal_yaw - pose_yaw); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
SteveMacenski
Member
|
||
if (angular_distance_to_heading > M_PI) { | ||
angular_distance_to_heading -= M_PI; | ||
} | ||
|
||
return computeRotateToHeadingCommand(angular_distance_to_heading, pose, velocity); | ||
} | ||
} catch (const std::runtime_error & e) { | ||
RCLCPP_INFO( | ||
logger_, | ||
"Rotation Shim Controller was unable to find a goal point," | ||
" a rotational collision was detected, or TF failed to transform" | ||
" into base frame! what(): %s", e.what()); | ||
} | ||
} | ||
|
||
if (path_updated_) { | ||
nav2_costmap_2d::Costmap2D * costmap = costmap_ros_->getCostmap(); | ||
std::unique_lock<nav2_costmap_2d::Costmap2D::mutex_t> lock(*(costmap->getMutex())); | ||
|
@@ -201,6 +265,16 @@ geometry_msgs::msg::PoseStamped RotationShimController::getSampledPathPt() | |
"passing off to primary controller plugin.", forward_sampling_distance_)); | ||
} | ||
|
||
geometry_msgs::msg::PoseStamped RotationShimController::getSampledPathGoal() | ||
{ | ||
if (current_path_.poses.size() == 0) { | ||
throw nav2_core::ControllerException( | ||
"Path is empty - cannot find a goal point"); | ||
} | ||
|
||
return current_path_.poses[current_path_.poses.size() - 1]; | ||
} | ||
|
||
geometry_msgs::msg::Pose | ||
RotationShimController::transformPoseToBaseFrame(const geometry_msgs::msg::PoseStamped & pt) | ||
{ | ||
|
@@ -306,6 +380,9 @@ RotationShimController::dynamicParametersCallback(std::vector<rclcpp::Parameter> | |
simulate_ahead_time_ = parameter.as_double(); | ||
} | ||
} | ||
if (name == plugin_name_ + ".rotate_to_goal_heading") { | ||
rotate_to_goal_heading_ = parameter.as_bool(); | ||
} | ||
} | ||
|
||
result.successful = true; | ||
|
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
I think this will fail if goal_yaw is -pi and pose_yaw pi. Robot is already aligned, but I assume this could trigger a full rotation on the spot.
This could help:
https://github.com/ros/angles/blob/54ad72b0ce473a2e1d98da447898bf2fcd36519f/angles/include/angles/angles.h#L104C72-L104C73