Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
smooth_control_law.cpp
1 // Copyright (c) 2023 Alberto J. Tudela Roldán
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "geometry_msgs/msg/pose_stamped.hpp"
16 #include "nav2_util/geometry_utils.hpp"
17 #include "nav2_graceful_controller/ego_polar_coords.hpp"
18 #include "nav2_graceful_controller/smooth_control_law.hpp"
19 
20 namespace nav2_graceful_controller
21 {
22 
24  double k_phi, double k_delta, double beta, double lambda,
25  double slowdown_radius, double deceleration_max,
26  double v_linear_min, double v_linear_max, double v_angular_max)
27 : k_phi_(k_phi), k_delta_(k_delta), beta_(beta), lambda_(lambda),
28  slowdown_radius_(slowdown_radius), deceleration_max_(deceleration_max),
29  v_linear_min_(v_linear_min), v_linear_max_(v_linear_max), v_angular_max_(v_angular_max)
30 {
31 }
32 
34  double k_phi, double k_delta, double beta, double lambda)
35 {
36  k_phi_ = k_phi;
37  k_delta_ = k_delta;
38  beta_ = beta;
39  lambda_ = lambda;
40 }
41 
42 void SmoothControlLaw::setSlowdownRadius(double slowdown_radius)
43 {
44  slowdown_radius_ = slowdown_radius;
45 }
46 
47 void SmoothControlLaw::setMaxDeceleration(double deceleration_max)
48 {
49  deceleration_max_ = deceleration_max;
50 }
51 
53  const double v_linear_min, const double v_linear_max, const double v_angular_max)
54 {
55  v_linear_min_ = v_linear_min;
56  v_linear_max_ = v_linear_max;
57  v_angular_max_ = v_angular_max;
58 }
59 
61  const geometry_msgs::msg::Pose & target, const geometry_msgs::msg::Pose & current,
62  const bool & backward)
63 {
64  // Convert the target to polar coordinates
65  auto ego_coords = EgocentricPolarCoordinates(target, current, backward);
66  // Calculate the curvature
67  double curvature = calculateCurvature(ego_coords.r, ego_coords.phi, ego_coords.delta);
68  // Invert the curvature if the robot is moving backwards
69  curvature = backward ? -curvature : curvature;
70 
71  // Adjust the linear velocity as a function of the path curvature to
72  // slowdown the controller as it approaches its target
73  double v = v_linear_max_ / (1.0 + beta_ * std::pow(fabs(curvature), lambda_));
74 
75  // Slowdown when the robot is near the target to remove singularity
76  v = std::min(v_linear_max_ * (ego_coords.r / slowdown_radius_), v);
77 
78  // Constraint robot velocity within deceleration limits
79  v = std::min(sqrt(2 * ego_coords.r * deceleration_max_), v);
80 
81  // Set some small v_min when far away from origin to promote faster
82  // turning motion when the curvature is very high
83  v = std::clamp(v, v_linear_min_, v_linear_max_);
84 
85  // Set the velocity to negative if the robot is moving backwards
86  v = backward ? -v : v;
87 
88  // Compute the angular velocity
89  double w = curvature * v;
90  // Bound angular velocity between [-max_angular_vel, max_angular_vel]
91  double w_bound = std::clamp(w, -v_angular_max_, v_angular_max_);
92  // And linear velocity to follow the curvature
93  v = (curvature != 0.0) ? (w_bound / curvature) : v;
94 
95  // Return the velocity command
96  geometry_msgs::msg::Twist cmd_vel;
97  cmd_vel.linear.x = v;
98  cmd_vel.angular.z = w_bound;
99  return cmd_vel;
100 }
101 
103  const geometry_msgs::msg::Pose & target, const bool & backward)
104 {
105  return calculateRegularVelocity(target, geometry_msgs::msg::Pose(), backward);
106 }
107 
108 geometry_msgs::msg::Pose SmoothControlLaw::calculateNextPose(
109  const double dt,
110  const geometry_msgs::msg::Pose & target,
111  const geometry_msgs::msg::Pose & current,
112  const bool & backward)
113 {
114  geometry_msgs::msg::Twist vel = calculateRegularVelocity(target, current, backward);
115  geometry_msgs::msg::Pose next;
116  double yaw = tf2::getYaw(current.orientation);
117  next.position.x = current.position.x + vel.linear.x * dt * cos(yaw);
118  next.position.y = current.position.y + vel.linear.x * dt * sin(yaw);
119  yaw += vel.angular.z * dt;
120  next.orientation = nav2_util::geometry_utils::orientationAroundZAxis(yaw);
121  return next;
122 }
123 
124 double SmoothControlLaw::calculateCurvature(double r, double phi, double delta)
125 {
126  // Calculate the proportional term of the control law as the product of the gain and the error:
127  // difference between the actual steering angle and the virtual control for the slow subsystem
128  double prop_term = k_delta_ * (delta - std::atan(-k_phi_ * phi));
129  // Calculate the feedback control law for the steering
130  double feedback_term = (1.0 + (k_phi_ / (1.0 + std::pow(k_phi_ * phi, 2)))) * sin(delta);
131  // Calculate the path curvature
132  return -1.0 / r * (prop_term + feedback_term);
133 }
134 
135 } // namespace nav2_graceful_controller
void setCurvatureConstants(const double k_phi, const double k_delta, const double beta, const double lambda)
Set the values that define the curvature.
double calculateCurvature(double r, double phi, double delta)
Calculate the path curvature using a Lyapunov-based feedback control law from "A smooth control law f...
geometry_msgs::msg::Twist calculateRegularVelocity(const geometry_msgs::msg::Pose &target, const geometry_msgs::msg::Pose &current, const bool &backward=false)
Compute linear and angular velocities command using the curvature.
double k_phi_
Ratio of the rate of change in phi to the rate of change in r. Controls the convergence of the slow s...
void setMaxDeceleration(const double deceleration_max)
Set the maximum deceleration.
void setSpeedLimit(const double v_linear_min, const double v_linear_max, const double v_angular_max)
Update the velocity limits.
double v_linear_min_
Minimum linear velocity.
geometry_msgs::msg::Pose calculateNextPose(const double dt, const geometry_msgs::msg::Pose &target, const geometry_msgs::msg::Pose &current, const bool &backward=false)
Calculate the next pose of the robot by generating a velocity command using the curvature and the cur...
double v_linear_max_
Maximum linear velocity.
void setSlowdownRadius(const double slowdown_radius)
Set the slowdown radius.
double beta_
Constant factor applied to the path curvature. This value must be positive. Determines how fast the v...
double k_delta_
Constant factor applied to the heading error feedback. Controls the convergence of the fast subsystem...
double slowdown_radius_
Radial threshold applied to the slowdown rule.
double lambda_
Constant factor applied to the path curvature. This value must be greater or equal to 1....
double v_angular_max_
Maximum angular velocity.
SmoothControlLaw(double k_phi, double k_delta, double beta, double lambda, double slowdown_radius, double deceleration_max, double v_linear_min, double v_linear_max, double v_angular_max)
Constructor for nav2_graceful_controller::SmoothControlLaw.
Egocentric polar coordinates defined as the difference between the robot pose and the target pose rel...