Skip to content

Commit 07e6f41

Browse files
authored
feat: add autoware_simple_pure_pursuit package (#140)
Signed-off-by: Takayuki Murooka <takayuki5168@gmail.com> Signed-off-by: mitukou1109 <mitukou1109@gmail.com>
1 parent e6fef7b commit 07e6f41

9 files changed

+523
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
project(autoware_simple_pure_pursuit)
3+
4+
find_package(autoware_cmake REQUIRED)
5+
autoware_package()
6+
7+
ament_auto_add_library(${PROJECT_NAME}_lib SHARED
8+
DIRECTORY src
9+
)
10+
11+
rclcpp_components_register_node(${PROJECT_NAME}_lib
12+
PLUGIN "autoware::control::simple_pure_pursuit::SimplePurePursuitNode"
13+
EXECUTABLE ${PROJECT_NAME}_exe
14+
)
15+
16+
if(BUILD_TESTING)
17+
ament_add_ros_isolated_gtest(${PROJECT_NAME}_test
18+
test/test_simple_pure_pursuit.cpp
19+
)
20+
target_link_libraries(${PROJECT_NAME}_test
21+
${PROJECT_NAME}_lib
22+
)
23+
endif()
24+
25+
ament_auto_package(
26+
INSTALL_TO_SHARE
27+
launch
28+
config
29+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Simple Pure Pursuit
2+
3+
The `simple_pure_pursuit` node receives a reference trajectory from `motion_velocity_smoother` and calculates the control command using the pure pursuit algorithm.
4+
5+
## Flowchart
6+
7+
![Flowchart](https://www.plantuml.com/plantuml/png/LOuxSWCn28PxJa5fNy5Rn4NkiKCaB3D1Q4T2XMyVeZZEH8q6_iV7TJXrdrN1nPMnsUvIkSFQ0roSFlcTd3QG6vvaO8u1ErD-l9tHxsnuUl0u0-jWG1pU3c3BSWCelSq3KvYTzzJCUzFuQoNBOVqk32tTEMDffF_xCDxbc1yguxvQyPdSbhGuY3-aS2RIj6kp8Zwp6EalS7kfmvcxMDd9Yl86aSLr8i0Bz0pziM21hk6TLRy0)
8+
9+
## Input topics
10+
11+
| Name | Type | Description |
12+
| :------------------- | :---------------------------------------- | :------------------- |
13+
| `~/input/odometry` | `nav_msgs::msg::Odometry` | ego odometry |
14+
| `~/input/trajectory` | `autoware_planning_msgs::msg::Trajectory` | reference trajectory |
15+
16+
## Output topics
17+
18+
| Name | Type | Description | QoS Durability |
19+
| :------------------------- | :------------------------------------ | :-------------- | :------------- |
20+
| `~/output/control_command` | `autoware_control_msgs::msg::Control` | control command | `volatile` |
21+
22+
## Parameters
23+
24+
{{ json_to_markdown("control/autoware_simple_pure_pursuit/schema/simple_pure_pursuit.schema.json") }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**:
2+
ros__parameters:
3+
lookahead_gain: 1.0
4+
lookahead_min_distance: 1.0
5+
speed_proportional_gain: 1.0
6+
use_external_target_vel: false
7+
external_target_vel: 1.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<launch>
2+
<arg name="vehicle_info_param_file" default="$(find-pkg-share autoware_vehicle_info_utils)/config/vehicle_info.param.yaml"/>
3+
4+
<node pkg="autoware_simple_pure_pursuit" exec="autoware_simple_pure_pursuit_exe" name="simple_pure_pursuit" output="screen">
5+
<param from="$(find-pkg-share autoware_simple_pure_pursuit)/config/simple_pure_pursuit.param.yaml"/>
6+
<param from="$(var vehicle_info_param_file)"/>
7+
8+
<remap from="~/input/odometry" to="/localization/kinematic_state"/>
9+
<remap from="~/input/trajectory" to="/planning/scenario_planning/trajectory"/>
10+
<remap from="~/output/control_command" to="/control/trajectory_follower/control_cmd"/>
11+
</node>
12+
</launch>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0"?>
2+
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
3+
<package format="3">
4+
<name>autoware_simple_pure_pursuit</name>
5+
<version>0.0.0</version>
6+
<description>The autoware_simple_pure_pursuit package</description>
7+
<maintainer email="yuki.takagi@tier4.jp">Yuki Takagi</maintainer>
8+
<maintainer email="kosuke.takeuchi@tier4.jp">Kosuke Takeuchi</maintainer>
9+
<maintainer email="takayuki.murooka@tier4.jp">Takayuki Murooka</maintainer>
10+
11+
<license>Apache License 2.0</license>
12+
13+
<buildtool_depend>ament_cmake_auto</buildtool_depend>
14+
<buildtool_depend>autoware_cmake</buildtool_depend>
15+
16+
<depend>autoware_control_msgs</depend>
17+
<depend>autoware_motion_utils</depend>
18+
<depend>autoware_planning_msgs</depend>
19+
<depend>autoware_test_utils</depend>
20+
<depend>autoware_utils</depend>
21+
<depend>autoware_vehicle_info_utils</depend>
22+
<depend>rclcpp</depend>
23+
<depend>rclcpp_components</depend>
24+
25+
<test_depend>ament_cmake_ros</test_depend>
26+
<test_depend>ament_lint_auto</test_depend>
27+
<test_depend>autoware_lint_common</test_depend>
28+
29+
<export>
30+
<build_type>ament_cmake</build_type>
31+
</export>
32+
</package>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "Parameters for Simple Pure Pursuit Node",
4+
"type": "object",
5+
"definitions": {
6+
"autoware_simple_pure_pursuit": {
7+
"type": "object",
8+
"properties": {
9+
"lookahead_gain": {
10+
"type": "number",
11+
"description": "Gain for lookahead distance calculation: {lookahead distance} = lookahead_gain * {target velocity} + lookahead_min_distance",
12+
"minimum": 0.0
13+
},
14+
"lookahead_min_distance": {
15+
"type": "number",
16+
"description": "Minimum lookahead distance [m]",
17+
"minimum": 0.0
18+
},
19+
"speed_proportional_gain": {
20+
"type": "number",
21+
"description": "Gain for longitudinal acceleration calculation: {longitudinal acceleration} = speed_proportional_gain * ({target velocity} - {current velocity})",
22+
"minimum": 0.0
23+
},
24+
"use_external_target_vel": {
25+
"type": "boolean",
26+
"description": "Whether to use external target velocity"
27+
},
28+
"external_target_vel": {
29+
"type": "number",
30+
"description": "External target velocity [m/s]",
31+
"minimum": 0.0
32+
}
33+
},
34+
"required": [
35+
"lookahead_gain",
36+
"lookahead_min_distance",
37+
"speed_proportional_gain",
38+
"use_external_target_vel",
39+
"external_target_vel"
40+
],
41+
"additionalProperties": false
42+
}
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright 2024 TIER IV, Inc.
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 "simple_pure_pursuit.hpp"
16+
17+
#include <autoware/motion_utils/trajectory/trajectory.hpp>
18+
#include <autoware_utils/geometry/pose_deviation.hpp>
19+
20+
#include <tf2/utils.h>
21+
22+
#include <algorithm>
23+
24+
namespace autoware::control::simple_pure_pursuit
25+
{
26+
using autoware::motion_utils::findNearestIndex;
27+
28+
SimplePurePursuitNode::SimplePurePursuitNode(const rclcpp::NodeOptions & node_options)
29+
: Node("simple_pure_pursuit", node_options),
30+
pub_control_command_(
31+
create_publisher<autoware_control_msgs::msg::Control>("~/output/control_command", 1)),
32+
vehicle_info_(autoware::vehicle_info_utils::VehicleInfoUtils(*this).getVehicleInfo()),
33+
lookahead_gain_(declare_parameter<float>("lookahead_gain")),
34+
lookahead_min_distance_(declare_parameter<float>("lookahead_min_distance")),
35+
speed_proportional_gain_(declare_parameter<float>("speed_proportional_gain")),
36+
use_external_target_vel_(declare_parameter<bool>("use_external_target_vel")),
37+
external_target_vel_(declare_parameter<float>("external_target_vel"))
38+
{
39+
using namespace std::literals::chrono_literals;
40+
timer_ = rclcpp::create_timer(
41+
this, get_clock(), 30ms, std::bind(&SimplePurePursuitNode::on_timer, this));
42+
}
43+
44+
void SimplePurePursuitNode::on_timer()
45+
{
46+
// 1. subscribe data
47+
const auto odom_ptr = odom_sub_.take_data();
48+
const auto traj_ptr = traj_sub_.take_data();
49+
if (!odom_ptr || !traj_ptr) {
50+
return;
51+
}
52+
53+
// 2. extract subscribed data
54+
const auto odom = *odom_ptr;
55+
const auto traj = *traj_ptr;
56+
57+
// 3. create control command
58+
const auto control_command = create_control_command(odom, traj);
59+
60+
// 4. publish control command
61+
pub_control_command_->publish(control_command);
62+
}
63+
64+
autoware_control_msgs::msg::Control SimplePurePursuitNode::create_control_command(
65+
const Odometry & odom, const Trajectory & traj)
66+
{
67+
const size_t closest_traj_point_idx = findNearestIndex(traj.points, odom.pose.pose.position);
68+
69+
// when the ego reaches the goal
70+
if (closest_traj_point_idx == traj.points.size() - 1 || traj.points.size() <= 5) {
71+
autoware_control_msgs::msg::Control control_command;
72+
control_command.stamp = get_clock()->now();
73+
control_command.longitudinal.velocity = 0.0;
74+
control_command.longitudinal.acceleration = -10.0;
75+
RCLCPP_DEBUG_THROTTLE(get_logger(), *get_clock(), 5000, "reached to the goal");
76+
return control_command;
77+
}
78+
79+
// calculate target longitudinal velocity
80+
const double target_longitudinal_vel =
81+
use_external_target_vel_ ? external_target_vel_
82+
: traj.points.at(closest_traj_point_idx).longitudinal_velocity_mps;
83+
84+
// calculate control command
85+
autoware_control_msgs::msg::Control control_command;
86+
control_command.longitudinal = calc_longitudinal_control(odom, target_longitudinal_vel);
87+
control_command.lateral =
88+
calc_lateral_control(odom, traj, target_longitudinal_vel, closest_traj_point_idx);
89+
90+
return control_command;
91+
}
92+
93+
autoware_control_msgs::msg::Longitudinal SimplePurePursuitNode::calc_longitudinal_control(
94+
const Odometry & odom, const double target_longitudinal_vel) const
95+
{
96+
const double current_longitudinal_vel = odom.twist.twist.linear.x;
97+
98+
autoware_control_msgs::msg::Longitudinal longitudinal_control_command;
99+
longitudinal_control_command.velocity = target_longitudinal_vel;
100+
longitudinal_control_command.acceleration =
101+
speed_proportional_gain_ * (target_longitudinal_vel - current_longitudinal_vel);
102+
103+
return longitudinal_control_command;
104+
}
105+
106+
autoware_control_msgs::msg::Lateral SimplePurePursuitNode::calc_lateral_control(
107+
const Odometry & odom, const Trajectory & traj, const double target_longitudinal_vel,
108+
const size_t closest_traj_point_idx) const
109+
{
110+
// calculate lookahead distance
111+
const double lookahead_distance =
112+
lookahead_gain_ * target_longitudinal_vel + lookahead_min_distance_;
113+
114+
// calculate center coordinate of rear wheel
115+
const double rear_x = odom.pose.pose.position.x -
116+
vehicle_info_.wheel_base_m / 2.0 * std::cos(odom.pose.pose.orientation.z);
117+
const double rear_y = odom.pose.pose.position.y -
118+
vehicle_info_.wheel_base_m / 2.0 * std::sin(odom.pose.pose.orientation.z);
119+
120+
// search lookahead point
121+
auto lookahead_point_itr = std::find_if(
122+
traj.points.begin() + closest_traj_point_idx, traj.points.end(),
123+
[&](const TrajectoryPoint & point) {
124+
return std::hypot(point.pose.position.x - rear_x, point.pose.position.y - rear_y) >=
125+
lookahead_distance;
126+
});
127+
if (lookahead_point_itr == traj.points.end()) {
128+
lookahead_point_itr = traj.points.end() - 1;
129+
}
130+
const double lookahead_point_x = lookahead_point_itr->pose.position.x;
131+
const double lookahead_point_y = lookahead_point_itr->pose.position.y;
132+
133+
// calculate steering angle
134+
autoware_control_msgs::msg::Lateral lateral_control_command;
135+
const double alpha = std::atan2(lookahead_point_y - rear_y, lookahead_point_x - rear_x) -
136+
tf2::getYaw(odom.pose.pose.orientation);
137+
lateral_control_command.steering_tire_angle =
138+
std::atan2(2.0 * vehicle_info_.wheel_base_m * std::sin(alpha), lookahead_distance);
139+
140+
return lateral_control_command;
141+
}
142+
} // namespace autoware::control::simple_pure_pursuit
143+
144+
#include <rclcpp_components/register_node_macro.hpp>
145+
RCLCPP_COMPONENTS_REGISTER_NODE(autoware::control::simple_pure_pursuit::SimplePurePursuitNode)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2024 TIER IV, Inc.
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+
#ifndef SIMPLE_PURE_PURSUIT_HPP_
16+
#define SIMPLE_PURE_PURSUIT_HPP_
17+
18+
#include <autoware_utils/ros/polling_subscriber.hpp>
19+
#include <autoware_vehicle_info_utils/vehicle_info_utils.hpp>
20+
#include <rclcpp/rclcpp.hpp>
21+
22+
#include <autoware_control_msgs/msg/control.hpp>
23+
#include <autoware_planning_msgs/msg/trajectory.hpp>
24+
#include <autoware_planning_msgs/msg/trajectory_point.hpp>
25+
#include <nav_msgs/msg/odometry.hpp>
26+
27+
namespace autoware::control::simple_pure_pursuit
28+
{
29+
using autoware_planning_msgs::msg::Trajectory;
30+
using autoware_planning_msgs::msg::TrajectoryPoint;
31+
using nav_msgs::msg::Odometry;
32+
33+
class SimplePurePursuitNode : public rclcpp::Node
34+
{
35+
public:
36+
explicit SimplePurePursuitNode(const rclcpp::NodeOptions & node_options);
37+
38+
private:
39+
// subscribers
40+
autoware_utils::InterProcessPollingSubscriber<Odometry> odom_sub_{this, "~/input/odometry"};
41+
autoware_utils::InterProcessPollingSubscriber<Trajectory> traj_sub_{this, "~/input/trajectory"};
42+
43+
// publishers
44+
rclcpp::Publisher<autoware_control_msgs::msg::Control>::SharedPtr pub_control_command_;
45+
46+
// timer
47+
rclcpp::TimerBase::SharedPtr timer_;
48+
49+
// vehicle info
50+
const autoware::vehicle_info_utils::VehicleInfo vehicle_info_;
51+
52+
// pure pursuit parameters
53+
const double lookahead_gain_;
54+
const double lookahead_min_distance_;
55+
const double speed_proportional_gain_;
56+
const bool use_external_target_vel_;
57+
const double external_target_vel_;
58+
59+
// functions
60+
void on_timer();
61+
autoware_control_msgs::msg::Control create_control_command(
62+
const Odometry & odom, const Trajectory & traj);
63+
autoware_control_msgs::msg::Longitudinal calc_longitudinal_control(
64+
const Odometry & odom, const double target_longitudinal_vel) const;
65+
autoware_control_msgs::msg::Lateral calc_lateral_control(
66+
const Odometry & odom, const Trajectory & traj, const double target_longitudinal_vel,
67+
const size_t closest_traj_point_idx) const;
68+
69+
public:
70+
friend class SimplePurePursuitNodeTest;
71+
};
72+
73+
} // namespace autoware::control::simple_pure_pursuit
74+
75+
#endif // SIMPLE_PURE_PURSUIT_HPP_

0 commit comments

Comments
 (0)