Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
kinematic_parameters.cpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2017, Locus Robotics
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "dwb_plugins/kinematic_parameters.hpp"
36 #include <atomic>
37 #include <memory>
38 #include <string>
39 #include <vector>
40 
41 #include "nav2_costmap_2d/costmap_filters/filter_values.hpp"
42 
43 using rcl_interfaces::msg::ParameterType;
44 using std::placeholders::_1;
45 
46 namespace dwb_plugins
47 {
48 
49 KinematicsHandler::KinematicsHandler()
50 {
51  kinematics_.store(new KinematicParameters);
52 }
53 
54 KinematicsHandler::~KinematicsHandler()
55 {
56  KinematicParameters * ptr = kinematics_.load();
57  if (ptr != nullptr) {
58  delete ptr;
59  }
60 }
61 
62 void KinematicsHandler::initialize(
63  const nav2::LifecycleNode::SharedPtr & nh,
64  const std::string & plugin_name)
65 {
66  node_ = nh;
67  plugin_name_ = plugin_name;
68  logger_ = nh->get_logger();
69 
70  KinematicParameters kinematics;
71 
72  kinematics.min_vel_x_ = nh->declare_or_get_parameter(
73  plugin_name + ".min_vel_x", 0.0);
74  kinematics.min_vel_y_ = nh->declare_or_get_parameter(
75  plugin_name + ".min_vel_y", 0.0);
76  kinematics.max_vel_x_ = nh->declare_or_get_parameter(
77  plugin_name + ".max_vel_x", 0.0);
78  kinematics.max_vel_y_ = nh->declare_or_get_parameter(
79  plugin_name + ".max_vel_y", 0.0);
80  kinematics.max_vel_theta_ = nh->declare_or_get_parameter(
81  plugin_name + ".max_vel_theta", 0.0);
82  kinematics.min_speed_xy_ = nh->declare_or_get_parameter(
83  plugin_name + ".min_speed_xy", 0.0);
84  kinematics.max_speed_xy_ = nh->declare_or_get_parameter(
85  plugin_name + ".max_speed_xy", 0.0);
86  kinematics.min_speed_theta_ = nh->declare_or_get_parameter(
87  plugin_name + ".min_speed_theta", 0.0);
88  kinematics.acc_lim_x_ = nh->declare_or_get_parameter(
89  plugin_name + ".acc_lim_x", 0.0);
90  kinematics.acc_lim_y_ = nh->declare_or_get_parameter(
91  plugin_name + ".acc_lim_y", 0.0);
92  kinematics.acc_lim_theta_ = nh->declare_or_get_parameter(
93  plugin_name + ".acc_lim_theta", 0.0);
94  kinematics.decel_lim_x_ = nh->declare_or_get_parameter(
95  plugin_name + ".decel_lim_x", 0.0);
96  kinematics.decel_lim_y_ = nh->declare_or_get_parameter(
97  plugin_name + ".decel_lim_y", 0.0);
98  kinematics.decel_lim_theta_ = nh->declare_or_get_parameter(
99  plugin_name + ".decel_lim_theta", 0.0);
100 
101  kinematics.base_max_vel_x_ = kinematics.max_vel_x_;
102  kinematics.base_max_vel_y_ = kinematics.max_vel_y_;
103  kinematics.base_max_speed_xy_ = kinematics.max_speed_xy_;
104  kinematics.base_max_vel_theta_ = kinematics.max_vel_theta_;
105 
106  kinematics.min_speed_xy_sq_ = kinematics.min_speed_xy_ * kinematics.min_speed_xy_;
107  kinematics.max_speed_xy_sq_ = kinematics.max_speed_xy_ * kinematics.max_speed_xy_;
108 
109  update_kinematics(kinematics);
110 }
111 
112 void KinematicsHandler::activate()
113 {
114  auto node = node_.lock();
115  // Add callback for dynamic parameters
116  post_set_params_handler_ = node->add_post_set_parameters_callback(
117  std::bind(
119  this, std::placeholders::_1));
120  on_set_params_handler_ = node->add_on_set_parameters_callback(
121  std::bind(
123  this, std::placeholders::_1));
124 }
125 
126 void KinematicsHandler::deactivate()
127 {
128  auto node = node_.lock();
129  if (post_set_params_handler_ && node) {
130  node->remove_post_set_parameters_callback(post_set_params_handler_.get());
131  }
132  post_set_params_handler_.reset();
133  if (on_set_params_handler_ && node) {
134  node->remove_on_set_parameters_callback(on_set_params_handler_.get());
135  }
136  on_set_params_handler_.reset();
137 }
138 
139 void KinematicsHandler::setSpeedLimit(
140  const double & speed_limit, const bool & percentage)
141 {
142  KinematicParameters * ptr = kinematics_.load();
143  if (ptr == nullptr) {
144  return; // Nothing to update
145  }
146  KinematicParameters kinematics(*ptr);
147 
148  if (speed_limit == nav2_costmap_2d::NO_SPEED_LIMIT) {
149  // Restore default value
150  kinematics.max_speed_xy_ = kinematics.base_max_speed_xy_;
151  kinematics.max_vel_x_ = kinematics.base_max_vel_x_;
152  kinematics.max_vel_y_ = kinematics.base_max_vel_y_;
153  kinematics.max_vel_theta_ = kinematics.base_max_vel_theta_;
154  } else {
155  if (percentage) {
156  // Speed limit is expressed in % from maximum speed of robot
157  kinematics.max_speed_xy_ = kinematics.base_max_speed_xy_ * speed_limit / 100.0;
158  kinematics.max_vel_x_ = kinematics.base_max_vel_x_ * speed_limit / 100.0;
159  kinematics.max_vel_y_ = kinematics.base_max_vel_y_ * speed_limit / 100.0;
160  kinematics.max_vel_theta_ = kinematics.base_max_vel_theta_ * speed_limit / 100.0;
161  } else {
162  // Speed limit is expressed in absolute value
163  if (speed_limit < kinematics.base_max_speed_xy_) {
164  kinematics.max_speed_xy_ = speed_limit;
165  // Handling components and angular velocity changes:
166  // Max velocities are being changed in the same proportion
167  // as absolute linear speed changed in order to preserve
168  // robot moving trajectories to be the same after speed change.
169  const double ratio = speed_limit / kinematics.base_max_speed_xy_;
170  kinematics.max_vel_x_ = kinematics.base_max_vel_x_ * ratio;
171  kinematics.max_vel_y_ = kinematics.base_max_vel_y_ * ratio;
172  kinematics.max_vel_theta_ = kinematics.base_max_vel_theta_ * ratio;
173  }
174  }
175  }
176 
177  // Do not forget to update max_speed_xy_sq_ as well
178  kinematics.max_speed_xy_sq_ = kinematics.max_speed_xy_ * kinematics.max_speed_xy_;
179 
180  update_kinematics(kinematics);
181 }
182 
183 rcl_interfaces::msg::SetParametersResult KinematicsHandler::validateParameterUpdatesCallback(
184  const std::vector<rclcpp::Parameter> & parameters)
185 {
186  rcl_interfaces::msg::SetParametersResult result;
187  result.successful = true;
188  for (const auto & parameter : parameters) {
189  const auto & param_type = parameter.get_type();
190  const auto & param_name = parameter.get_name();
191  if (param_name.find(plugin_name_ + ".") != 0) {
192  continue;
193  }
194  if (param_type == ParameterType::PARAMETER_DOUBLE) {
195  if (parameter.as_double() < 0.0 &&
196  (param_name == plugin_name_ + ".max_vel_x" || param_name == plugin_name_ + ".max_vel_y" ||
197  param_name == plugin_name_ + ".max_vel_theta" ||
198  param_name == plugin_name_ + ".max_speed_xy" ||
199  param_name == plugin_name_ + ".acc_lim_x" || param_name == plugin_name_ + ".acc_lim_y" ||
200  param_name == plugin_name_ + ".acc_lim_theta"))
201  {
202  RCLCPP_WARN(
203  logger_, "The value of parameter '%s' is incorrectly set to %f, "
204  "it should be >= 0. Ignoring parameter update.",
205  param_name.c_str(), parameter.as_double());
206  result.successful = false;
207  } else if (parameter.as_double() > 0.0 && // NOLINT
208  (param_name == plugin_name_ + ".decel_lim_x" ||
209  param_name == plugin_name_ + ".decel_lim_y" ||
210  param_name == plugin_name_ + ".decel_lim_theta"))
211  {
212  RCLCPP_WARN(
213  logger_, "The value of parameter '%s' is incorrectly set to %f, "
214  "it should be <= 0. Ignoring parameter update.",
215  param_name.c_str(), parameter.as_double());
216  result.successful = false;
217  }
218  }
219  }
220  return result;
221 }
222 
223 void
224 KinematicsHandler::updateParametersCallback(const std::vector<rclcpp::Parameter> & parameters)
225 {
226  rcl_interfaces::msg::SetParametersResult result;
227  KinematicParameters * ptr = kinematics_.load();
228  if (ptr == nullptr) {
229  return; // Nothing to update
230  }
231  KinematicParameters kinematics(*ptr);
232 
233  for (const auto & parameter : parameters) {
234  const auto & param_type = parameter.get_type();
235  const auto & param_name = parameter.get_name();
236  if (param_name.find(plugin_name_ + ".") != 0) {
237  continue;
238  }
239 
240  if (param_type == ParameterType::PARAMETER_DOUBLE) {
241  if (param_name == plugin_name_ + ".min_vel_x") {
242  kinematics.min_vel_x_ = parameter.as_double();
243  } else if (param_name == plugin_name_ + ".min_vel_y") {
244  kinematics.min_vel_y_ = parameter.as_double();
245  } else if (param_name == plugin_name_ + ".max_vel_x") {
246  kinematics.max_vel_x_ = parameter.as_double();
247  kinematics.base_max_vel_x_ = kinematics.max_vel_x_;
248  } else if (param_name == plugin_name_ + ".max_vel_y") {
249  kinematics.max_vel_y_ = parameter.as_double();
250  kinematics.base_max_vel_y_ = kinematics.max_vel_y_;
251  } else if (param_name == plugin_name_ + ".max_vel_theta") {
252  kinematics.max_vel_theta_ = parameter.as_double();
253  kinematics.base_max_vel_theta_ = kinematics.max_vel_theta_;
254  } else if (param_name == plugin_name_ + ".min_speed_xy") {
255  kinematics.min_speed_xy_ = parameter.as_double();
256  kinematics.min_speed_xy_sq_ = kinematics.min_speed_xy_ * kinematics.min_speed_xy_;
257  } else if (param_name == plugin_name_ + ".max_speed_xy") {
258  kinematics.max_speed_xy_ = parameter.as_double();
259  kinematics.base_max_speed_xy_ = kinematics.max_speed_xy_;
260  } else if (param_name == plugin_name_ + ".min_speed_theta") {
261  kinematics.min_speed_theta_ = parameter.as_double();
262  kinematics.max_speed_xy_sq_ = kinematics.max_speed_xy_ * kinematics.max_speed_xy_;
263  } else if (param_name == plugin_name_ + ".acc_lim_x") {
264  kinematics.acc_lim_x_ = parameter.as_double();
265  } else if (param_name == plugin_name_ + ".acc_lim_y") {
266  kinematics.acc_lim_y_ = parameter.as_double();
267  } else if (param_name == plugin_name_ + ".acc_lim_theta") {
268  kinematics.acc_lim_theta_ = parameter.as_double();
269  } else if (param_name == plugin_name_ + ".decel_lim_x") {
270  kinematics.decel_lim_x_ = parameter.as_double();
271  } else if (param_name == plugin_name_ + ".decel_lim_y") {
272  kinematics.decel_lim_y_ = parameter.as_double();
273  } else if (param_name == plugin_name_ + ".decel_lim_theta") {
274  kinematics.decel_lim_theta_ = parameter.as_double();
275  }
276  }
277  }
278  update_kinematics(kinematics);
279 }
280 
281 void KinematicsHandler::update_kinematics(KinematicParameters kinematics)
282 {
283  KinematicParameters * new_kinematics = new KinematicParameters(kinematics);
284  KinematicParameters * old_kinematics = kinematics_.exchange(new_kinematics);
285  if (old_kinematics != nullptr) {
286  delete old_kinematics;
287  }
288 }
289 
290 } // namespace dwb_plugins
void updateParametersCallback(const std::vector< rclcpp::Parameter > &parameters)
Apply parameter updates after validation This callback is executed when parameters have been successf...
rcl_interfaces::msg::SetParametersResult validateParameterUpdatesCallback(const std::vector< rclcpp::Parameter > &parameters)
Validate incoming parameter updates before applying them. This callback is triggered when one or more...
A struct containing one representation of the robot's kinematics.