Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
standard_traj_generator.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/standard_traj_generator.hpp"
36 #include <string>
37 #include <vector>
38 #include <algorithm>
39 #include <memory>
40 #include "dwb_plugins/xy_theta_iterator.hpp"
41 #include "pluginlib/class_list_macros.hpp"
42 #include "dwb_core/exceptions.hpp"
43 #include "nav2_ros_common/node_utils.hpp"
44 #include "tf2/utils.hpp"
45 #include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
46 
47 namespace dwb_plugins
48 {
49 
51  const nav2::LifecycleNode::SharedPtr & nh,
52  const std::string & plugin_name)
53 {
54  plugin_name_ = plugin_name;
55  kinematics_handler_ = std::make_shared<KinematicsHandler>();
56  kinematics_handler_->initialize(nh, plugin_name_);
58 
59  nav2::declare_parameter_if_not_declared(
60  nh,
61  plugin_name + ".sim_time", rclcpp::ParameterValue(1.7));
62  nav2::declare_parameter_if_not_declared(
63  nh,
64  plugin_name + ".discretize_by_time", rclcpp::ParameterValue(false));
65 
66  nav2::declare_parameter_if_not_declared(
67  nh,
68  plugin_name + ".time_granularity", rclcpp::ParameterValue(0.5));
69  nav2::declare_parameter_if_not_declared(
70  nh,
71  plugin_name + ".linear_granularity", rclcpp::ParameterValue(0.5));
72  nav2::declare_parameter_if_not_declared(
73  nh,
74  plugin_name + ".angular_granularity", rclcpp::ParameterValue(0.025));
75  nav2::declare_parameter_if_not_declared(
76  nh,
77  plugin_name + ".include_last_point", rclcpp::ParameterValue(true));
78 
79  nav2::declare_parameter_if_not_declared(
80  nh,
81  plugin_name + ".limit_vel_cmd_in_traj", rclcpp::ParameterValue(false));
82 
83  /*
84  * If discretize_by_time, then sim_granularity represents the amount of time that should be between
85  * two successive points on the trajectory.
86  *
87  * If discretize_by_time is false, then sim_granularity is the maximum amount of distance between
88  * two successive points on the trajectory, and angular_sim_granularity is the maximum amount of
89  * angular distance between two successive points.
90  */
91  nh->get_parameter(plugin_name + ".sim_time", sim_time_);
92  nh->get_parameter(plugin_name + ".discretize_by_time", discretize_by_time_);
93  nh->get_parameter(plugin_name + ".time_granularity", time_granularity_);
94  nh->get_parameter(plugin_name + ".linear_granularity", linear_granularity_);
95  nh->get_parameter(plugin_name + ".angular_granularity", angular_granularity_);
96  nh->get_parameter(plugin_name + ".include_last_point", include_last_point_);
97  nh->get_parameter(plugin_name + ".limit_vel_cmd_in_traj", limit_vel_cmd_in_traj_);
98 }
99 
101 {
102  kinematics_handler_->activate();
103 }
104 
106 {
107  kinematics_handler_->deactivate();
108 }
109 
111  const nav2::LifecycleNode::SharedPtr & nh)
112 {
113  velocity_iterator_ = std::make_shared<XYThetaIterator>();
114  velocity_iterator_->initialize(nh, kinematics_handler_, plugin_name_);
115 }
116 
118  const nav_2d_msgs::msg::Twist2D & current_velocity)
119 {
120  velocity_iterator_->startNewIteration(current_velocity, sim_time_);
121 }
122 
124 {
125  return velocity_iterator_->hasMoreTwists();
126 }
127 
128 nav_2d_msgs::msg::Twist2D StandardTrajectoryGenerator::nextTwist()
129 {
130  return velocity_iterator_->nextTwist();
131 }
132 
134  const nav_2d_msgs::msg::Twist2D & cmd_vel)
135 {
136  std::vector<double> steps;
137  if (discretize_by_time_) {
138  steps.resize(ceil(sim_time_ / time_granularity_));
139  } else { // discretize by distance
140  double vmag = hypot(cmd_vel.x, cmd_vel.y);
141 
142  // the distance the robot would travel in sim_time if it did not change velocity
143  double projected_linear_distance = vmag * sim_time_;
144 
145  // the angle the robot would rotate in sim_time
146  double projected_angular_distance = fabs(cmd_vel.theta) * sim_time_;
147 
148  // Pick the maximum of the two
149  int num_steps = ceil(
150  std::max(
151  projected_linear_distance / linear_granularity_,
152  projected_angular_distance / angular_granularity_));
153  steps.resize(num_steps);
154  }
155  if (steps.size() == 0) {
156  steps.resize(1);
157  }
158  std::fill(steps.begin(), steps.end(), sim_time_ / steps.size());
159  return steps;
160 }
161 
163  const geometry_msgs::msg::Pose & start_pose,
164  const nav_2d_msgs::msg::Twist2D & start_vel,
165  const nav_2d_msgs::msg::Twist2D & cmd_vel)
166 {
167  dwb_msgs::msg::Trajectory2D traj;
168  traj.velocity = cmd_vel;
169  // simulate the trajectory
170  geometry_msgs::msg::Pose pose = start_pose;
171  nav_2d_msgs::msg::Twist2D vel = start_vel;
172  double running_time = 0.0;
173  std::vector<double> steps = getTimeSteps(cmd_vel);
174  traj.poses.push_back(start_pose);
175  bool first_vel = false;
176  for (double dt : steps) {
177  // calculate velocities
178  vel = computeNewVelocity(cmd_vel, vel, dt);
179  if (!first_vel && limit_vel_cmd_in_traj_) {
180  traj.velocity = vel;
181  first_vel = true;
182  }
183 
184  // update the position of the robot using the velocities passed in
185  pose = computeNewPosition(pose, vel, dt);
186 
187  traj.poses.push_back(pose);
188  traj.time_offsets.push_back(rclcpp::Duration::from_seconds(running_time));
189  running_time += dt;
190  } // end for simulation steps
191 
192  if (include_last_point_) {
193  traj.poses.push_back(pose);
194  traj.time_offsets.push_back(rclcpp::Duration::from_seconds(running_time));
195  }
196 
197  return traj;
198 }
199 
204  const nav_2d_msgs::msg::Twist2D & cmd_vel,
205  const nav_2d_msgs::msg::Twist2D & start_vel, const double dt)
206 {
207  KinematicParameters kinematics = kinematics_handler_->getKinematics();
208  nav_2d_msgs::msg::Twist2D new_vel;
209  new_vel.x = projectVelocity(
210  start_vel.x, kinematics.getAccX(),
211  kinematics.getDecelX(), dt, cmd_vel.x);
212  new_vel.y = projectVelocity(
213  start_vel.y, kinematics.getAccY(),
214  kinematics.getDecelY(), dt, cmd_vel.y);
215  new_vel.theta = projectVelocity(
216  start_vel.theta,
217  kinematics.getAccTheta(), kinematics.getDecelTheta(),
218  dt, cmd_vel.theta);
219  return new_vel;
220 }
221 
223  const geometry_msgs::msg::Pose start_pose,
224  const nav_2d_msgs::msg::Twist2D & vel, const double dt)
225 {
226  geometry_msgs::msg::Pose new_pose;
227 
228  double theta = tf2::getYaw(start_pose.orientation);
229  new_pose.position.x = start_pose.position.x +
230  (vel.x * cos(theta) + vel.y * cos(M_PI_2 + theta)) * dt;
231  new_pose.position.y = start_pose.position.y +
232  (vel.x * sin(theta) + vel.y * sin(M_PI_2 + theta)) * dt;
233 
234  double new_theta = theta + vel.theta * dt;
235  tf2::Quaternion q;
236  q.setRPY(0.0, 0.0, new_theta);
237  new_pose.orientation = tf2::toMsg(q);
238 
239  return new_pose;
240 }
241 
242 } // namespace dwb_plugins
243 
244 PLUGINLIB_EXPORT_CLASS(
Interface for iterating through possible velocities and creating trajectories.
Standard DWA-like trajectory generator.
void startNewIteration(const nav_2d_msgs::msg::Twist2D &current_velocity) override
Start a new iteration based on the current velocity.
double angular_granularity_
If not discretizing by time, the amount of angular space between points.
virtual nav_2d_msgs::msg::Twist2D computeNewVelocity(const nav_2d_msgs::msg::Twist2D &cmd_vel, const nav_2d_msgs::msg::Twist2D &start_vel, const double dt)
Calculate the velocity after a set period of time, given the desired velocity and acceleration limits...
std::string plugin_name_
the name of the overlying plugin ID
void deactivate()
Resets callbacks for dynamic parameter handling.
void activate()
Registers callbacks for dynamic parameter handling.
bool hasMoreTwists() override
Test to see whether there are more twists to test.
virtual std::vector< double > getTimeSteps(const nav_2d_msgs::msg::Twist2D &cmd_vel)
Compute an array of time deltas between the points in the generated trajectory.
bool limit_vel_cmd_in_traj_
Option to limit velocity in the trajectory generator by using current velocity.
double linear_granularity_
If not discretizing by time, the amount of linear space between points.
virtual geometry_msgs::msg::Pose computeNewPosition(const geometry_msgs::msg::Pose start_pose, const nav_2d_msgs::msg::Twist2D &vel, const double dt)
Use the robot's kinematic model to predict new positions for the robot.
double time_granularity_
If discretizing by time, the amount of time between each point in the traj.
void initialize(const nav2::LifecycleNode::SharedPtr &nh, const std::string &plugin_name) override
Initialize parameters as needed.
virtual void initializeIterator(const nav2::LifecycleNode::SharedPtr &nh)
Initialize the VelocityIterator pointer. Put in its own function for easy overriding.
dwb_msgs::msg::Trajectory2D generateTrajectory(const geometry_msgs::msg::Pose &start_pose, const nav_2d_msgs::msg::Twist2D &start_vel, const nav_2d_msgs::msg::Twist2D &cmd_vel) override
Given a cmd_vel in the robot's frame and initial conditions, generate a Trajectory2D.
nav_2d_msgs::msg::Twist2D nextTwist() override
Return the next twist and advance the iteration.
A struct containing one representation of the robot's kinematics.