Carma-platform v4.11.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
trajectory_follower_wrapper_node.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024 LEIDOS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
18
20{
21 namespace std_ph = std::placeholders;
22
24 : carma_guidance_plugins::ControlPlugin(options)
25 {
26 basic_autonomy::set_logger(get_logger().get_child("basic_autonomy"));
27 // Create initial config
29 config_.vehicle_response_lag = declare_parameter<double>("vehicle_response_lag", config_.vehicle_response_lag);
30 config_.vehicle_wheel_base = declare_parameter<double>("vehicle_wheel_base", config_.vehicle_wheel_base);
31 config_.incoming_cmd_time_threshold = declare_parameter<double>("incoming_cmd_time_threshold", config_.incoming_cmd_time_threshold);
32
33 }
34
35 rcl_interfaces::msg::SetParametersResult TrajectoryFollowerWrapperNode::parameter_update_callback(const std::vector<rclcpp::Parameter> &parameters)
36 {
37 auto error_double = update_params<double>({
38 {"vehicle_response_lag", config_.vehicle_response_lag},
39 {"vehicle_wheel_base", config_.vehicle_wheel_base},
40 {"incoming_cmd_time_threshold", config_.incoming_cmd_time_threshold}
41 }, parameters);
42
43 rcl_interfaces::msg::SetParametersResult result;
44
45 result.successful = !error_double;
46
47 return result;
48 }
49
50 carma_ros2_utils::CallbackReturn TrajectoryFollowerWrapperNode::on_configure_plugin()
51 {
52 // Reset config
54
55 // Load parameters
56 get_parameter<double>("vehicle_response_lag", config_.vehicle_response_lag);
57 get_parameter<double>("vehicle_wheel_base", config_.vehicle_wheel_base);
58 get_parameter<double>("incoming_cmd_time_threshold", config_.incoming_cmd_time_threshold);
59
60 RCLCPP_INFO_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "Loaded Params: " << config_);
61 // Register runtime parameter update callback
62 add_on_set_parameters_callback(std::bind(&TrajectoryFollowerWrapperNode::parameter_update_callback, this, std_ph::_1));
63
64 // NOTE: Currently, intra-process comms must be disabled for the following subscriber that is transient_local: https://github.com/ros2/rclcpp/issues/1753
65
66 rclcpp::SubscriptionOptions intra_proc_disabled;
67 intra_proc_disabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
68
69 auto sub_qos_transient_local = rclcpp::QoS(rclcpp::KeepAll()); // A subscriber with this QoS will store all messages that it has sent on the topic
70 sub_qos_transient_local.transient_local();
71 // Setup subscriber
72 control_cmd_sub_ = create_subscription<autoware_auto_msgs::msg::AckermannControlCommand>("trajectory_follower/control_cmd", sub_qos_transient_local,
73 std::bind(&TrajectoryFollowerWrapperNode::ackermann_control_cb, this, std::placeholders::_1),intra_proc_disabled);
74
75 // Setup publishers
76 autoware_traj_pub_ = create_publisher<autoware_auto_msgs::msg::Trajectory>("trajectory_follower/reference_trajectory", 10);
77 autoware_state_pub_ = create_publisher<autoware_auto_msgs::msg::VehicleKinematicState>("trajectory_follower/current_kinematic_state", 10);
78
79 // Setup timers to publish autoware compatible info (trajectory and state)
80 autoware_info_timer_ = create_timer(
81 get_clock(),
82 std::chrono::milliseconds(33), // Spin at 30 Hz per plugin API
84
85 // Return success if everthing initialized successfully
86 return CallbackReturn::SUCCESS;
87 }
88
89
91 {
92 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "In autoware info timer callback");
93
95 {
96 // generate and publish autoware kinematic state
97 auto autoware_state = convert_state(current_pose_.get(), current_twist_.get());
98 autoware_state_pub_->publish(autoware_state);
99
100 // generate and publish autoware trajectory
101 current_trajectory_.get().header.frame_id = autoware_state.header.frame_id;
103
104 autoware_traj_pub_->publish(autoware_traj_plan);
105
106 }
107 }
108
109 double TrajectoryFollowerWrapperNode::get_wheel_angle_rad_from_twist(const geometry_msgs::msg::TwistStamped& twist) const
110 {
111
112 if (std::abs(twist.twist.linear.x) < EPSILON )
113 {
114 return 0.0;
115 }
116
117 double steering_angle = std::atan2(twist.twist.angular.z * config_.vehicle_wheel_base, twist.twist.linear.x);
118 return steering_angle;
119 }
120
121 void TrajectoryFollowerWrapperNode::ackermann_control_cb(const autoware_auto_msgs::msg::AckermannControlCommand::SharedPtr msg)
122 {
123 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "In ackermann control callback");
125 }
126
127
128 autoware_auto_msgs::msg::VehicleKinematicState TrajectoryFollowerWrapperNode::convert_state(const geometry_msgs::msg::PoseStamped& pose, const geometry_msgs::msg::TwistStamped& twist) const
129 {
130 autoware_auto_msgs::msg::VehicleKinematicState state;
131 state.header = pose.header;
132 state.header.frame_id = "map";
133 state.state.x = pose.pose.position.x;
134 state.state.y = pose.pose.position.y;
135 state.state.z = pose.pose.position.z;
136 state.state.heading.real = pose.pose.orientation.w;
137 state.state.heading.imag = pose.pose.orientation.z;
138
139 state.state.front_wheel_angle_rad = get_wheel_angle_rad_from_twist(twist);
140 state.state.longitudinal_velocity_mps = twist.twist.linear.x;
141 state.state.lateral_velocity_mps = twist.twist.linear.y;
142 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "front_wheel_angle_rad: " << state.state.front_wheel_angle_rad);
143
144
145
146 return state;
147 }
148
149 autoware_msgs::msg::ControlCommandStamped TrajectoryFollowerWrapperNode::convert_cmd(const autoware_auto_msgs::msg::AckermannControlCommand& cmd) const
150 {
151 autoware_msgs::msg::ControlCommandStamped return_cmd;
152 return_cmd.header.stamp = cmd.stamp;
153
154 return_cmd.cmd.linear_acceleration = cmd.longitudinal.acceleration;
155 return_cmd.cmd.linear_velocity = cmd.longitudinal.speed;
156 return_cmd.cmd.steering_angle = cmd.lateral.steering_tire_angle;
157
158 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "generated command cmd.stamp: " << std::to_string(rclcpp::Time(cmd.stamp).seconds()));
159 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "generated command cmd.longitudinal.acceleration: " << cmd.longitudinal.acceleration);
160 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "generated command cmd.longitudinal.speed: " << cmd.longitudinal.speed);
161 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "generated command cmd.lateral.steering_tire_angle: " << cmd.lateral.steering_tire_angle);
162 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "generated command cmd.lateral.steering_tire_rotation_rate: " << cmd.lateral.steering_tire_rotation_rate);
163
164 return return_cmd;
165 }
166
167 autoware_msgs::msg::ControlCommandStamped TrajectoryFollowerWrapperNode::generate_command()
168 {
169 // process and save the trajectory
170 autoware_msgs::msg::ControlCommandStamped converted_cmd;
171
173 {
174 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "Insufficient data, empty control command generated");
175 return converted_cmd;
176 }
177
178
180 {
181 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("trajectory_follower_wrapper"), "Control Command is old, empty control command generated");
182 return converted_cmd;
183 }
184
185 converted_cmd = convert_cmd(received_ctrl_command_.value());
186
187 return converted_cmd;
188 }
189
190 bool TrajectoryFollowerWrapperNode::isControlCommandOld(const autoware_auto_msgs::msg::AckermannControlCommand& cmd) const
191 {
192 double difference = std::abs(this->now().seconds() - rclcpp::Time(cmd.stamp).seconds());
193
194 if (difference >= config_.incoming_cmd_time_threshold)
195 {
196 return true;
197 }
198
199 return false;
200 }
201
203 {
204 return true;
205 }
206
208 {
209 return "1.0";
210 }
211
212
213} // trajectory_follower_wrapper
214
215#include "rclcpp_components/register_node_macro.hpp"
216
217// Register the component with class_loader
boost::optional< geometry_msgs::msg::TwistStamped > current_twist_
The most recent velocity message received by this node.
boost::optional< carma_planning_msgs::msg::TrajectoryPlan > current_trajectory_
The most recent trajectory received by this plugin.
boost::optional< geometry_msgs::msg::PoseStamped > current_pose_
The most recent pose message received by this node.
bool isControlCommandOld(const autoware_auto_msgs::msg::AckermannControlCommand &cmd) const
Check to see if the received control command recent or old.
autoware_msgs::msg::ControlCommandStamped convert_cmd(const autoware_auto_msgs::msg::AckermannControlCommand &cmd) const
convert autoware Ackermann control command to autoware stamped control command
carma_ros2_utils::PubPtr< autoware_auto_msgs::msg::Trajectory > autoware_traj_pub_
carma_ros2_utils::PubPtr< autoware_auto_msgs::msg::VehicleKinematicState > autoware_state_pub_
double get_wheel_angle_rad_from_twist(const geometry_msgs::msg::TwistStamped &twist) const
calculate wheel angle in rad from angular velocity in twist message
carma_ros2_utils::SubPtr< autoware_auto_msgs::msg::AckermannControlCommand > control_cmd_sub_
void ackermann_control_cb(const autoware_auto_msgs::msg::AckermannControlCommand::SharedPtr msg)
autoware's control subscription callback
void autoware_info_timer_callback()
Timer callback to spin at 30 hz and frequently publish autoware kinematic state and trajectory.
TrajectoryFollowerWrapperNode(const rclcpp::NodeOptions &options)
Node constructor.
rcl_interfaces::msg::SetParametersResult parameter_update_callback(const std::vector< rclcpp::Parameter > &parameters)
Callback for dynamic parameter updates.
autoware_auto_msgs::msg::VehicleKinematicState convert_state(const geometry_msgs::msg::PoseStamped &pose, const geometry_msgs::msg::TwistStamped &twist) const
convert vehicle's pose and twist messages to autoware kinematic state
bool get_availability() override
Get the availability status of this plugin based on the current operating environment....
std::optional< autoware_auto_msgs::msg::AckermannControlCommand > received_ctrl_command_
autoware_msgs::msg::ControlCommandStamped generate_command() override
Extending class provided method which should generate a command message which will be published to th...
std::string get_version_id() override
Returns the version id of this plugin.
carma_ros2_utils::CallbackReturn on_configure_plugin() override
This method should be used to load parameters and will be called on the configure state transition.
#define EPSILON
autoware_auto_msgs::msg::Trajectory process_trajectory_plan(const carma_planning_msgs::msg::TrajectoryPlan &tp, double vehicle_response_lag)
Given a carma type of trajectory_plan, generate autoware type of trajectory accounting for speed_lag ...
void set_logger(rclcpp::Logger logger)
Replace the module-level logger used by all basic_autonomy functions.
Definition: log.cpp:33
rclcpp::Logger get_logger()
Return the module-level logger used by all basic_autonomy functions.
Definition: log.cpp:32
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21
Stuct containing the algorithm configuration values for trajectory_follower_wrapper.