Nav2 Navigation Stack - rolling  main
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, double slowdown_radius,
25  double v_linear_min, double v_linear_max, double v_angular_max)
26 : k_phi_(k_phi), k_delta_(k_delta), beta_(beta), lambda_(lambda), slowdown_radius_(slowdown_radius),
27  v_linear_min_(v_linear_min), v_linear_max_(v_linear_max), v_angular_max_(v_angular_max)
28 {
29 }
30 
32  double k_phi, double k_delta, double beta, double lambda)
33 {
34  k_phi_ = k_phi;
35  k_delta_ = k_delta;
36  beta_ = beta;
37  lambda_ = lambda;
38 }
39 
40 void SmoothControlLaw::setSlowdownRadius(double slowdown_radius)
41 {
42  slowdown_radius_ = slowdown_radius;
43 }
44 
46  const double v_linear_min, const double v_linear_max, const double v_angular_max)
47 {
48  v_linear_min_ = v_linear_min;
49  v_linear_max_ = v_linear_max;
50  v_angular_max_ = v_angular_max;
51 }
52 
54  const geometry_msgs::msg::Pose & target, const geometry_msgs::msg::Pose & current,
55  const bool & backward)
56 {
57  // Convert the target to polar coordinates
58  auto ego_coords = EgocentricPolarCoordinates(target, current, backward);
59  // Calculate the curvature
60  double curvature = calculateCurvature(ego_coords.r, ego_coords.phi, ego_coords.delta);
61  // Invert the curvature if the robot is moving backwards
62  curvature = backward ? -curvature : curvature;
63 
64  // Adjust the linear velocity as a function of the path curvature to
65  // slowdown the controller as it approaches its target
66  double v = v_linear_max_ / (1.0 + beta_ * std::pow(fabs(curvature), lambda_));
67 
68  // Slowdown when the robot is near the target to remove singularity
69  v = std::min(v_linear_max_ * (ego_coords.r / slowdown_radius_), v);
70 
71  // Set some small v_min when far away from origin to promote faster
72  // turning motion when the curvature is very high
73  v = std::clamp(v, v_linear_min_, v_linear_max_);
74 
75  // Set the velocity to negative if the robot is moving backwards
76  v = backward ? -v : v;
77 
78  // Compute the angular velocity
79  double w = curvature * v;
80  // Bound angular velocity between [-max_angular_vel, max_angular_vel]
81  double w_bound = std::clamp(w, -v_angular_max_, v_angular_max_);
82  // And linear velocity to follow the curvature
83  v = (curvature != 0.0) ? (w_bound / curvature) : v;
84 
85  // Return the velocity command
86  geometry_msgs::msg::Twist cmd_vel;
87  cmd_vel.linear.x = v;
88  cmd_vel.angular.z = w_bound;
89  return cmd_vel;
90 }
91 
93  const geometry_msgs::msg::Pose & target, const bool & backward)
94 {
95  return calculateRegularVelocity(target, geometry_msgs::msg::Pose(), backward);
96 }
97 
98 geometry_msgs::msg::Pose SmoothControlLaw::calculateNextPose(
99  const double dt,
100  const geometry_msgs::msg::Pose & target,
101  const geometry_msgs::msg::Pose & current,
102  const bool & backward)
103 {
104  geometry_msgs::msg::Twist vel = calculateRegularVelocity(target, current, backward);
105  geometry_msgs::msg::Pose next;
106  double yaw = tf2::getYaw(current.orientation);
107  next.position.x = current.position.x + vel.linear.x * dt * cos(yaw);
108  next.position.y = current.position.y + vel.linear.x * dt * sin(yaw);
109  yaw += vel.angular.z * dt;
110  next.orientation = nav2_util::geometry_utils::orientationAroundZAxis(yaw);
111  return next;
112 }
113 
114 double SmoothControlLaw::calculateCurvature(double r, double phi, double delta)
115 {
116  // Calculate the proportional term of the control law as the product of the gain and the error:
117  // difference between the actual steering angle and the virtual control for the slow subsystem
118  double prop_term = k_delta_ * (delta - std::atan(-k_phi_ * phi));
119  // Calculate the feedback control law for the steering
120  double feedback_term = (1.0 + (k_phi_ / (1.0 + std::pow(k_phi_ * phi, 2)))) * sin(delta);
121  // Calculate the path curvature
122  return -1.0 / r * (prop_term + feedback_term);
123 }
124 
125 } // 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 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.
SmoothControlLaw(double k_phi, double k_delta, double beta, double lambda, double slowdown_radius, double v_linear_min, double v_linear_max, double v_angular_max)
Constructor for nav2_graceful_controller::SmoothControlLaw.
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.
Egocentric polar coordinates defined as the difference between the robot pose and the target pose rel...