Skip to content

File tree

17 files changed

+624
-75
lines changed

17 files changed

+624
-75
lines changed
 

‎.github/CODEOWNERS

+3-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ control/autoware_trajectory_follower_base/** takamasa.horibe@tier4.jp takayuki.m
6262
control/pure_pursuit/** takamasa.horibe@tier4.jp takayuki.murooka@tier4.jp
6363
control/shift_decider/** takamasa.horibe@tier4.jp takayuki.murooka@tier4.jp
6464
control/autoware_trajectory_follower_node/** takamasa.horibe@tier4.jp takayuki.murooka@tier4.jp
65-
evaluator/autoware_control_evaluator/** daniel.sanchez@tier4.jp takayuki.murooka@tier4.jp
65+
evaluator/autoware_control_evaluator/** daniel.sanchez@tier4.jp takayuki.murooka@tier4.jp kosuke.takeuchi@tier4.jp
66+
evaluator/autoware_evaluator_utils/** daniel.sanchez@tier4.jp takayuki.murooka@tier4.jp
67+
evaluator/autoware_planning_evaluator/** kyoichi.sugahara@tier4.jp maxime.clement@tier4.jp
6668
evaluator/diagnostic_converter/** kyoichi.sugahara@tier4.jp maxime.clement@tier4.jp takamasa.horibe@tier4.jp
6769
evaluator/kinematic_evaluator/** dominik.jargot@robotec.ai fumiya.watanabe@tier4.jp satoshi.ota@tier4.jp shumpei.wakabayashi@tier4.jp takamasa.horibe@tier4.jp takayuki.murooka@tier4.jp tomoya.kimura@tier4.jp
6870
evaluator/localization_evaluator/** dominik.jargot@robotec.ai koji.minoda@tier4.jp

‎evaluator/autoware_control_evaluator/CMakeLists.txt

+10-1
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,19 @@ ament_auto_add_library(control_evaluator_node SHARED
1212
)
1313

1414
rclcpp_components_register_node(control_evaluator_node
15-
PLUGIN "control_diagnostics::controlEvaluatorNode"
15+
PLUGIN "control_diagnostics::ControlEvaluatorNode"
1616
EXECUTABLE control_evaluator
1717
)
1818

19+
if(BUILD_TESTING)
20+
ament_add_ros_isolated_gtest(test_control_evaluator
21+
test/test_control_evaluator_node.cpp
22+
)
23+
target_link_libraries(test_control_evaluator
24+
control_evaluator_node
25+
)
26+
endif()
27+
1928

2029
ament_auto_package(
2130
INSTALL_TO_SHARE
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
# Planning Evaluator
1+
# Control Evaluator
22

33
## Purpose
44

55
This package provides nodes that generate metrics to evaluate the quality of control.
6+
7+
It publishes diagnostic information about control modules' outputs as well as the ego vehicle's current kinematics and position.
8+
9+
## Evaluated metrics
10+
11+
The control evaluator uses the metrics defined in `include/autoware/control_evaluator/metrics/deviation_metrics.hpp`to calculate deviations in yaw and lateral distance from the ego's set-point. The control_evaluator can also be customized to offer metrics/evaluation about other control modules. Currently, the control_evaluator offers a simple diagnostic output based on the autonomous_emergency_braking node's output, but this functionality can be extended to evaluate other control modules' performance.
12+
13+
## Kinematics output
14+
15+
The control evaluator module also constantly publishes information regarding the ego vehicle's kinematics and position. It publishes the current ego lane id with the longitudinal `s` and lateral `t` arc coordinates. It also publishes the current ego speed, acceleration and jerk in its diagnostic messages.
16+
17+
This information can be used by other nodes to establish automated evaluation using rosbags: by crosschecking the ego position and kinematics with the evaluated control module's output, it is possible to judge if the evaluated control modules reacted in a satisfactory way at certain interesting points of the rosbag reproduction.

‎evaluator/autoware_control_evaluator/include/autoware/control_evaluator/control_evaluator_node.hpp

+26-13
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@
1717

1818
#include "autoware/control_evaluator/metrics/deviation_metrics.hpp"
1919

20+
#include <autoware/route_handler/route_handler.hpp>
2021
#include <autoware/universe_utils/ros/polling_subscriber.hpp>
2122
#include <rclcpp/rclcpp.hpp>
2223

24+
#include "geometry_msgs/msg/accel_with_covariance_stamped.hpp"
25+
#include <autoware_planning_msgs/msg/lanelet_route.hpp>
2326
#include <diagnostic_msgs/msg/diagnostic_array.hpp>
2427
#include <nav_msgs/msg/odometry.hpp>
2528

26-
#include <array>
2729
#include <deque>
28-
#include <memory>
30+
#include <optional>
2931
#include <string>
3032
#include <utility>
3133
#include <vector>
@@ -39,29 +41,29 @@ using diagnostic_msgs::msg::DiagnosticStatus;
3941
using geometry_msgs::msg::Point;
4042
using geometry_msgs::msg::Pose;
4143
using nav_msgs::msg::Odometry;
44+
using LaneletMapBin = autoware_map_msgs::msg::LaneletMapBin;
45+
using autoware_planning_msgs::msg::LaneletRoute;
46+
using geometry_msgs::msg::AccelWithCovarianceStamped;
4247

4348
/**
4449
* @brief Node for control evaluation
4550
*/
46-
class controlEvaluatorNode : public rclcpp::Node
51+
class ControlEvaluatorNode : public rclcpp::Node
4752
{
4853
public:
49-
explicit controlEvaluatorNode(const rclcpp::NodeOptions & node_options);
50-
void removeOldDiagnostics(const rclcpp::Time & stamp);
51-
void removeDiagnosticsByName(const std::string & name);
52-
void addDiagnostic(const DiagnosticStatus & diag, const rclcpp::Time & stamp);
53-
void updateDiagnosticQueue(
54-
const DiagnosticArray & input_diagnostics, const std::string & function,
55-
const rclcpp::Time & stamp);
56-
54+
explicit ControlEvaluatorNode(const rclcpp::NodeOptions & node_options);
5755
DiagnosticStatus generateLateralDeviationDiagnosticStatus(
5856
const Trajectory & traj, const Point & ego_point);
5957
DiagnosticStatus generateYawDeviationDiagnosticStatus(
6058
const Trajectory & traj, const Pose & ego_pose);
61-
std::optional<DiagnosticStatus> generateStopDiagnosticStatus(
62-
const DiagnosticArray & diag, const std::string & function_name);
59+
DiagnosticStatus generateGoalLongitudinalDeviationDiagnosticStatus(const Pose & ego_pose);
60+
DiagnosticStatus generateGoalLateralDeviationDiagnosticStatus(const Pose & ego_pose);
61+
DiagnosticStatus generateGoalYawDeviationDiagnosticStatus(const Pose & ego_pose);
6362

6463
DiagnosticStatus generateAEBDiagnosticStatus(const DiagnosticStatus & diag);
64+
DiagnosticStatus generateLaneletDiagnosticStatus(const Pose & ego_pose) const;
65+
DiagnosticStatus generateKinematicStateDiagnosticStatus(
66+
const Odometry & odom, const AccelWithCovarianceStamped & accel_stamped);
6567

6668
void onDiagnostics(const DiagnosticArray::ConstSharedPtr diag_msg);
6769
void onTimer();
@@ -74,11 +76,20 @@ class controlEvaluatorNode : public rclcpp::Node
7476

7577
autoware::universe_utils::InterProcessPollingSubscriber<Odometry> odometry_sub_{
7678
this, "~/input/odometry"};
79+
autoware::universe_utils::InterProcessPollingSubscriber<AccelWithCovarianceStamped> accel_sub_{
80+
this, "~/input/acceleration"};
7781
autoware::universe_utils::InterProcessPollingSubscriber<Trajectory> traj_sub_{
7882
this, "~/input/trajectory"};
83+
autoware::universe_utils::InterProcessPollingSubscriber<LaneletRoute> route_subscriber_{
84+
this, "~/input/route", rclcpp::QoS{1}.transient_local()};
85+
autoware::universe_utils::InterProcessPollingSubscriber<LaneletMapBin> vector_map_subscriber_{
86+
this, "~/input/vector_map", rclcpp::QoS{1}.transient_local()};
7987

8088
rclcpp::Publisher<DiagnosticArray>::SharedPtr metrics_pub_;
8189

90+
// update Route Handler
91+
void getRouteData();
92+
8293
// Calculator
8394
// Metrics
8495
std::deque<rclcpp::Time> stamps_;
@@ -87,7 +98,9 @@ class controlEvaluatorNode : public rclcpp::Node
8798
std::deque<std::pair<DiagnosticStatus, rclcpp::Time>> diag_queue_;
8899
const std::vector<std::string> target_functions_ = {"autonomous_emergency_braking"};
89100

101+
autoware::route_handler::RouteHandler route_handler_;
90102
rclcpp::TimerBase::SharedPtr timer_;
103+
std::optional<AccelWithCovarianceStamped> prev_acc_stamped_{std::nullopt};
91104
};
92105
} // namespace control_diagnostics
93106

‎evaluator/autoware_control_evaluator/include/autoware/control_evaluator/metrics/deviation_metrics.hpp

+24
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,30 @@ double calcLateralDeviation(const Trajectory & traj, const Point & point);
4242
*/
4343
double calcYawDeviation(const Trajectory & traj, const Pose & pose);
4444

45+
/**
46+
* @brief calculate longitudinal deviation from target_point to base_pose
47+
* @param [in] pose input base_pose
48+
* @param [in] point input target_point
49+
* @return longitudinal deviation from base_pose to target_point
50+
*/
51+
double calcLongitudinalDeviation(const Pose & base_pose, const Point & target_point);
52+
53+
/**
54+
* @brief calculate lateral deviation from target_point to base_pose
55+
* @param [in] pose input base_pose
56+
* @param [in] point input target_point
57+
* @return lateral deviation from base_pose to target_point
58+
*/
59+
double calcLateralDeviation(const Pose & base_pose, const Point & target_point);
60+
61+
/**
62+
* @brief calculate yaw deviation from base_pose to target_pose
63+
* @param [in] pose input base_pose
64+
* @param [in] pose input target_pose
65+
* @return yaw deviation from base_pose to target_pose
66+
*/
67+
double calcYawDeviation(const Pose & base_pose, const Pose & target_pose);
68+
4569
} // namespace metrics
4670
} // namespace control_diagnostics
4771

Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
<launch>
22
<arg name="input/diagnostics" default="/diagnostics"/>
33
<arg name="input/odometry" default="/localization/kinematic_state"/>
4+
<arg name="input/acceleration" default="/localization/acceleration"/>
45
<arg name="input/trajectory" default="/planning/scenario_planning/trajectory"/>
6+
<arg name="map_topic_name" default="/map/vector_map"/>
7+
<arg name="route_topic_name" default="/planning/mission_planning/route"/>
58
<!-- control evaluator -->
69
<group>
710
<node name="control_evaluator" exec="control_evaluator" pkg="autoware_control_evaluator">
811
<param from="$(find-pkg-share autoware_control_evaluator)/param/control_evaluator.defaults.yaml"/>
912
<remap from="~/input/diagnostics" to="$(var input/diagnostics)"/>
1013
<remap from="~/input/odometry" to="$(var input/odometry)"/>
14+
<remap from="~/input/acceleration" to="$(var input/acceleration)"/>
1115
<remap from="~/input/trajectory" to="$(var input/trajectory)"/>
1216
<remap from="~/metrics" to="/control/control_evaluator/metrics"/>
17+
<remap from="~/input/vector_map" to="$(var map_topic_name)"/>
18+
<remap from="~/input/route" to="$(var route_topic_name)"/>
1319
</node>
1420
</group>
1521
</launch>

‎evaluator/autoware_control_evaluator/package.xml

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
<description>ROS 2 node for evaluating control</description>
77
<maintainer email="daniel.sanchez@tier4.jp">Daniel SANCHEZ</maintainer>
88
<maintainer email="takayuki.murooka@tier4.jp">takayuki MUROOKA</maintainer>
9+
<maintainer email="kosuke.takeuchi@tier4.jp">kosuke TAKEUCHI</maintainer>
10+
<maintainer email="temkei.kem@tier4.jp">Temkei Kem</maintainer>
911
<license>Apache License 2.0</license>
1012

1113
<author email="daniel.sanchez@tier4.jp">Daniel SANCHEZ</author>
@@ -14,14 +16,19 @@
1416
<buildtool_depend>ament_cmake_auto</buildtool_depend>
1517
<buildtool_depend>autoware_cmake</buildtool_depend>
1618

19+
<depend>autoware_evaluator_utils</depend>
1720
<depend>autoware_motion_utils</depend>
1821
<depend>autoware_planning_msgs</depend>
22+
<depend>autoware_route_handler</depend>
23+
<depend>autoware_test_utils</depend>
1924
<depend>autoware_universe_utils</depend>
2025
<depend>diagnostic_msgs</depend>
26+
<depend>nav_msgs</depend>
2127
<depend>pluginlib</depend>
2228
<depend>rclcpp</depend>
2329
<depend>rclcpp_components</depend>
24-
<!-- <depend>nav_msgs</depend> -->
30+
<depend>tf2</depend>
31+
<depend>tf2_ros</depend>
2532

2633
<test_depend>ament_cmake_ros</test_depend>
2734
<test_depend>ament_lint_auto</test_depend>

‎evaluator/autoware_control_evaluator/src/control_evaluator_node.cpp

+164-56
Original file line numberDiff line numberDiff line change
@@ -14,101 +14,147 @@
1414

1515
#include "autoware/control_evaluator/control_evaluator_node.hpp"
1616

17-
#include <fstream>
18-
#include <iostream>
19-
#include <map>
20-
#include <memory>
17+
#include "autoware/evaluator_utils/evaluator_utils.hpp"
18+
19+
#include <lanelet2_extension/utility/query.hpp>
20+
#include <lanelet2_extension/utility/utilities.hpp>
21+
22+
#include <algorithm>
23+
#include <limits>
2124
#include <string>
2225
#include <utility>
2326
#include <vector>
2427

2528
namespace control_diagnostics
2629
{
27-
controlEvaluatorNode::controlEvaluatorNode(const rclcpp::NodeOptions & node_options)
30+
ControlEvaluatorNode::ControlEvaluatorNode(const rclcpp::NodeOptions & node_options)
2831
: Node("control_evaluator", node_options)
2932
{
3033
using std::placeholders::_1;
3134
control_diag_sub_ = create_subscription<DiagnosticArray>(
32-
"~/input/diagnostics", 1, std::bind(&controlEvaluatorNode::onDiagnostics, this, _1));
35+
"~/input/diagnostics", 1, std::bind(&ControlEvaluatorNode::onDiagnostics, this, _1));
3336

3437
// Publisher
3538
metrics_pub_ = create_publisher<DiagnosticArray>("~/metrics", 1);
3639

3740
// Timer callback to publish evaluator diagnostics
3841
using namespace std::literals::chrono_literals;
3942
timer_ =
40-
rclcpp::create_timer(this, get_clock(), 100ms, std::bind(&controlEvaluatorNode::onTimer, this));
41-
}
42-
43-
void controlEvaluatorNode::removeOldDiagnostics(const rclcpp::Time & stamp)
44-
{
45-
constexpr double KEEP_TIME = 1.0;
46-
diag_queue_.erase(
47-
std::remove_if(
48-
diag_queue_.begin(), diag_queue_.end(),
49-
[stamp](const std::pair<diagnostic_msgs::msg::DiagnosticStatus, rclcpp::Time> & p) {
50-
return (stamp - p.second).seconds() > KEEP_TIME;
51-
}),
52-
diag_queue_.end());
53-
}
54-
55-
void controlEvaluatorNode::removeDiagnosticsByName(const std::string & name)
56-
{
57-
diag_queue_.erase(
58-
std::remove_if(
59-
diag_queue_.begin(), diag_queue_.end(),
60-
[&name](const std::pair<diagnostic_msgs::msg::DiagnosticStatus, rclcpp::Time> & p) {
61-
return p.first.name.find(name) != std::string::npos;
62-
}),
63-
diag_queue_.end());
43+
rclcpp::create_timer(this, get_clock(), 100ms, std::bind(&ControlEvaluatorNode::onTimer, this));
6444
}
6545

66-
void controlEvaluatorNode::addDiagnostic(
67-
const diagnostic_msgs::msg::DiagnosticStatus & diag, const rclcpp::Time & stamp)
46+
void ControlEvaluatorNode::getRouteData()
6847
{
69-
diag_queue_.push_back(std::make_pair(diag, stamp));
70-
}
71-
72-
void controlEvaluatorNode::updateDiagnosticQueue(
73-
const DiagnosticArray & input_diagnostics, const std::string & function,
74-
const rclcpp::Time & stamp)
75-
{
76-
const auto it = std::find_if(
77-
input_diagnostics.status.begin(), input_diagnostics.status.end(),
78-
[&function](const diagnostic_msgs::msg::DiagnosticStatus & diag) {
79-
return diag.name.find(function) != std::string::npos;
80-
});
81-
if (it != input_diagnostics.status.end()) {
82-
removeDiagnosticsByName(it->name);
83-
addDiagnostic(*it, input_diagnostics.header.stamp);
48+
// route
49+
{
50+
const auto msg = route_subscriber_.takeNewData();
51+
if (msg) {
52+
if (msg->segments.empty()) {
53+
RCLCPP_ERROR(get_logger(), "input route is empty. ignored");
54+
} else {
55+
route_handler_.setRoute(*msg);
56+
}
57+
}
8458
}
8559

86-
removeOldDiagnostics(stamp);
60+
// map
61+
{
62+
const auto msg = vector_map_subscriber_.takeNewData();
63+
if (msg) {
64+
route_handler_.setMap(*msg);
65+
}
66+
}
8767
}
8868

89-
void controlEvaluatorNode::onDiagnostics(const DiagnosticArray::ConstSharedPtr diag_msg)
69+
void ControlEvaluatorNode::onDiagnostics(const DiagnosticArray::ConstSharedPtr diag_msg)
9070
{
9171
// add target diagnostics to the queue and remove old ones
9272
for (const auto & function : target_functions_) {
93-
updateDiagnosticQueue(*diag_msg, function, now());
73+
autoware::evaluator_utils::updateDiagnosticQueue(*diag_msg, function, now(), diag_queue_);
9474
}
9575
}
9676

97-
DiagnosticStatus controlEvaluatorNode::generateAEBDiagnosticStatus(const DiagnosticStatus & diag)
77+
DiagnosticStatus ControlEvaluatorNode::generateAEBDiagnosticStatus(const DiagnosticStatus & diag)
9878
{
9979
DiagnosticStatus status;
10080
status.level = status.OK;
10181
status.name = diag.name;
10282
diagnostic_msgs::msg::KeyValue key_value;
10383
key_value.key = "decision";
10484
const bool is_emergency_brake = (diag.level == DiagnosticStatus::ERROR);
105-
key_value.value = (is_emergency_brake) ? "stop" : "none";
85+
key_value.value = (is_emergency_brake) ? "deceleration" : "none";
10686
status.values.push_back(key_value);
87+
return status;
88+
}
10789

90+
DiagnosticStatus ControlEvaluatorNode::generateLaneletDiagnosticStatus(const Pose & ego_pose) const
91+
{
92+
const auto current_lanelets = [&]() {
93+
lanelet::ConstLanelet closest_route_lanelet;
94+
route_handler_.getClosestLaneletWithinRoute(ego_pose, &closest_route_lanelet);
95+
const auto shoulder_lanelets = route_handler_.getShoulderLaneletsAtPose(ego_pose);
96+
lanelet::ConstLanelets closest_lanelets{closest_route_lanelet};
97+
closest_lanelets.insert(
98+
closest_lanelets.end(), shoulder_lanelets.begin(), shoulder_lanelets.end());
99+
return closest_lanelets;
100+
}();
101+
const auto arc_coordinates = lanelet::utils::getArcCoordinates(current_lanelets, ego_pose);
102+
lanelet::ConstLanelet current_lane;
103+
lanelet::utils::query::getClosestLanelet(current_lanelets, ego_pose, &current_lane);
104+
105+
DiagnosticStatus status;
106+
status.name = "ego_lane_info";
107+
status.level = status.OK;
108+
diagnostic_msgs::msg::KeyValue key_value;
109+
key_value.key = "lane_id";
110+
key_value.value = std::to_string(current_lane.id());
111+
status.values.push_back(key_value);
112+
key_value.key = "s";
113+
key_value.value = std::to_string(arc_coordinates.length);
114+
status.values.push_back(key_value);
115+
key_value.key = "t";
116+
key_value.value = std::to_string(arc_coordinates.distance);
117+
status.values.push_back(key_value);
108118
return status;
109119
}
110120

111-
DiagnosticStatus controlEvaluatorNode::generateLateralDeviationDiagnosticStatus(
121+
DiagnosticStatus ControlEvaluatorNode::generateKinematicStateDiagnosticStatus(
122+
const Odometry & odom, const AccelWithCovarianceStamped & accel_stamped)
123+
{
124+
DiagnosticStatus status;
125+
status.name = "kinematic_state";
126+
status.level = status.OK;
127+
diagnostic_msgs::msg::KeyValue key_value;
128+
key_value.key = "vel";
129+
key_value.value = std::to_string(odom.twist.twist.linear.x);
130+
status.values.push_back(key_value);
131+
key_value.key = "acc";
132+
const auto & acc = accel_stamped.accel.accel.linear.x;
133+
key_value.value = std::to_string(acc);
134+
status.values.push_back(key_value);
135+
key_value.key = "jerk";
136+
const auto jerk = [&]() {
137+
if (!prev_acc_stamped_.has_value()) {
138+
prev_acc_stamped_ = accel_stamped;
139+
return 0.0;
140+
}
141+
const auto t = static_cast<double>(accel_stamped.header.stamp.sec) +
142+
static_cast<double>(accel_stamped.header.stamp.nanosec) * 1e-9;
143+
const auto prev_t = static_cast<double>(prev_acc_stamped_.value().header.stamp.sec) +
144+
static_cast<double>(prev_acc_stamped_.value().header.stamp.nanosec) * 1e-9;
145+
const auto dt = t - prev_t;
146+
if (dt < std::numeric_limits<double>::epsilon()) return 0.0;
147+
148+
const auto prev_acc = prev_acc_stamped_.value().accel.accel.linear.x;
149+
prev_acc_stamped_ = accel_stamped;
150+
return (acc - prev_acc) / dt;
151+
}();
152+
key_value.value = std::to_string(jerk);
153+
status.values.push_back(key_value);
154+
return status;
155+
}
156+
157+
DiagnosticStatus ControlEvaluatorNode::generateLateralDeviationDiagnosticStatus(
112158
const Trajectory & traj, const Point & ego_point)
113159
{
114160
const double lateral_deviation = metrics::calcLateralDeviation(traj, ego_point);
@@ -124,7 +170,7 @@ DiagnosticStatus controlEvaluatorNode::generateLateralDeviationDiagnosticStatus(
124170
return status;
125171
}
126172

127-
DiagnosticStatus controlEvaluatorNode::generateYawDeviationDiagnosticStatus(
173+
DiagnosticStatus ControlEvaluatorNode::generateYawDeviationDiagnosticStatus(
128174
const Trajectory & traj, const Pose & ego_pose)
129175
{
130176
const double yaw_deviation = metrics::calcYawDeviation(traj, ego_pose);
@@ -140,11 +186,59 @@ DiagnosticStatus controlEvaluatorNode::generateYawDeviationDiagnosticStatus(
140186
return status;
141187
}
142188

143-
void controlEvaluatorNode::onTimer()
189+
DiagnosticStatus ControlEvaluatorNode::generateGoalLongitudinalDeviationDiagnosticStatus(
190+
const Pose & ego_pose)
191+
{
192+
DiagnosticStatus status;
193+
const double longitudinal_deviation =
194+
metrics::calcLongitudinalDeviation(route_handler_.getGoalPose(), ego_pose.position);
195+
196+
status.level = status.OK;
197+
status.name = "goal_longitudinal_deviation";
198+
diagnostic_msgs::msg::KeyValue key_value;
199+
key_value.key = "metrics_value";
200+
key_value.value = std::to_string(longitudinal_deviation);
201+
status.values.push_back(key_value);
202+
return status;
203+
}
204+
205+
DiagnosticStatus ControlEvaluatorNode::generateGoalLateralDeviationDiagnosticStatus(
206+
const Pose & ego_pose)
207+
{
208+
DiagnosticStatus status;
209+
const double lateral_deviation =
210+
metrics::calcLateralDeviation(route_handler_.getGoalPose(), ego_pose.position);
211+
212+
status.level = status.OK;
213+
status.name = "goal_lateral_deviation";
214+
diagnostic_msgs::msg::KeyValue key_value;
215+
key_value.key = "metrics_value";
216+
key_value.value = std::to_string(lateral_deviation);
217+
status.values.push_back(key_value);
218+
return status;
219+
}
220+
221+
DiagnosticStatus ControlEvaluatorNode::generateGoalYawDeviationDiagnosticStatus(
222+
const Pose & ego_pose)
223+
{
224+
DiagnosticStatus status;
225+
const double yaw_deviation = metrics::calcYawDeviation(route_handler_.getGoalPose(), ego_pose);
226+
227+
status.level = status.OK;
228+
status.name = "goal_yaw_deviation";
229+
diagnostic_msgs::msg::KeyValue key_value;
230+
key_value.key = "metrics_value";
231+
key_value.value = std::to_string(yaw_deviation);
232+
status.values.push_back(key_value);
233+
return status;
234+
}
235+
236+
void ControlEvaluatorNode::onTimer()
144237
{
145238
DiagnosticArray metrics_msg;
146239
const auto traj = traj_sub_.takeData();
147240
const auto odom = odometry_sub_.takeData();
241+
const auto acc = accel_sub_.takeData();
148242

149243
// generate decision diagnostics from input diagnostics
150244
for (const auto & function : target_functions_) {
@@ -171,10 +265,24 @@ void controlEvaluatorNode::onTimer()
171265
metrics_msg.status.push_back(generateYawDeviationDiagnosticStatus(*traj, ego_pose));
172266
}
173267

268+
getRouteData();
269+
if (odom && route_handler_.isHandlerReady()) {
270+
const Pose ego_pose = odom->pose.pose;
271+
metrics_msg.status.push_back(generateLaneletDiagnosticStatus(ego_pose));
272+
273+
metrics_msg.status.push_back(generateGoalLongitudinalDeviationDiagnosticStatus(ego_pose));
274+
metrics_msg.status.push_back(generateGoalLateralDeviationDiagnosticStatus(ego_pose));
275+
metrics_msg.status.push_back(generateGoalYawDeviationDiagnosticStatus(ego_pose));
276+
}
277+
278+
if (odom && acc) {
279+
metrics_msg.status.push_back(generateKinematicStateDiagnosticStatus(*odom, *acc));
280+
}
281+
174282
metrics_msg.header.stamp = now();
175283
metrics_pub_->publish(metrics_msg);
176284
}
177285
} // namespace control_diagnostics
178286

179287
#include "rclcpp_components/register_node_macro.hpp"
180-
RCLCPP_COMPONENTS_REGISTER_NODE(control_diagnostics::controlEvaluatorNode)
288+
RCLCPP_COMPONENTS_REGISTER_NODE(control_diagnostics::ControlEvaluatorNode)

‎evaluator/autoware_control_evaluator/src/metrics/deviation_metrics.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,20 @@ double calcYawDeviation(const Trajectory & traj, const Pose & pose)
3838
autoware::universe_utils::calcYawDeviation(traj.points[nearest_index].pose, pose));
3939
}
4040

41+
double calcLongitudinalDeviation(const Pose & base_pose, const Point & target_point)
42+
{
43+
return std::abs(autoware::universe_utils::calcLongitudinalDeviation(base_pose, target_point));
44+
}
45+
46+
double calcLateralDeviation(const Pose & base_pose, const Point & target_point)
47+
{
48+
return std::abs(autoware::universe_utils::calcLateralDeviation(base_pose, target_point));
49+
}
50+
51+
double calcYawDeviation(const Pose & base_pose, const Pose & target_pose)
52+
{
53+
return std::abs(autoware::universe_utils::calcYawDeviation(base_pose, target_pose));
54+
}
55+
4156
} // namespace metrics
4257
} // namespace control_diagnostics
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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 "ament_index_cpp/get_package_share_directory.hpp"
16+
#include "gtest/gtest.h"
17+
#include "rclcpp/rclcpp.hpp"
18+
#include "rclcpp/time.hpp"
19+
#include "tf2_ros/transform_broadcaster.h"
20+
21+
#include <autoware/control_evaluator/control_evaluator_node.hpp>
22+
23+
#include "autoware_planning_msgs/msg/trajectory.hpp"
24+
#include "diagnostic_msgs/msg/diagnostic_array.hpp"
25+
#include "geometry_msgs/msg/transform_stamped.hpp"
26+
27+
#include "boost/lexical_cast.hpp"
28+
29+
#include <tf2/LinearMath/Quaternion.h>
30+
31+
#include <memory>
32+
#include <string>
33+
#include <utility>
34+
#include <vector>
35+
36+
using EvalNode = control_diagnostics::ControlEvaluatorNode;
37+
using Trajectory = autoware_planning_msgs::msg::Trajectory;
38+
using TrajectoryPoint = autoware_planning_msgs::msg::TrajectoryPoint;
39+
using diagnostic_msgs::msg::DiagnosticArray;
40+
using nav_msgs::msg::Odometry;
41+
42+
constexpr double epsilon = 1e-6;
43+
44+
class EvalTest : public ::testing::Test
45+
{
46+
protected:
47+
void SetUp() override
48+
{
49+
rclcpp::init(0, nullptr);
50+
51+
rclcpp::NodeOptions options;
52+
const auto share_dir =
53+
ament_index_cpp::get_package_share_directory("autoware_control_evaluator");
54+
55+
dummy_node = std::make_shared<rclcpp::Node>("control_evaluator_test_node");
56+
eval_node = std::make_shared<EvalNode>(options);
57+
// Enable all logging in the node
58+
auto ret = rcutils_logging_set_logger_level(
59+
dummy_node->get_logger().get_name(), RCUTILS_LOG_SEVERITY_DEBUG);
60+
if (ret != RCUTILS_RET_OK) {
61+
std::cerr << "Failed to set logging severity to DEBUG\n";
62+
}
63+
ret = rcutils_logging_set_logger_level(
64+
eval_node->get_logger().get_name(), RCUTILS_LOG_SEVERITY_DEBUG);
65+
if (ret != RCUTILS_RET_OK) {
66+
std::cerr << "Failed to set logging severity to DEBUG\n";
67+
}
68+
traj_pub_ =
69+
rclcpp::create_publisher<Trajectory>(dummy_node, "/control_evaluator/input/trajectory", 1);
70+
odom_pub_ =
71+
rclcpp::create_publisher<Odometry>(dummy_node, "/control_evaluator/input/odometry", 1);
72+
tf_broadcaster_ = std::make_unique<tf2_ros::TransformBroadcaster>(dummy_node);
73+
publishEgoPose(0.0, 0.0, 0.0);
74+
}
75+
76+
~EvalTest() override { rclcpp::shutdown(); }
77+
78+
void setTargetMetric(const std::string & metric_str)
79+
{
80+
const auto is_target_metric = [metric_str](const auto & status) {
81+
return status.name == metric_str;
82+
};
83+
metric_sub_ = rclcpp::create_subscription<DiagnosticArray>(
84+
dummy_node, "/control_evaluator/metrics", 1, [=](const DiagnosticArray::ConstSharedPtr msg) {
85+
const auto it = std::find_if(msg->status.begin(), msg->status.end(), is_target_metric);
86+
if (it != msg->status.end()) {
87+
metric_value_ = boost::lexical_cast<double>(it->values[0].value);
88+
metric_updated_ = true;
89+
}
90+
});
91+
}
92+
93+
Trajectory makeTrajectory(const std::vector<std::pair<double, double>> & traj)
94+
{
95+
Trajectory t;
96+
t.header.frame_id = "map";
97+
TrajectoryPoint p;
98+
for (const std::pair<double, double> & point : traj) {
99+
p.pose.position.x = point.first;
100+
p.pose.position.y = point.second;
101+
t.points.push_back(p);
102+
}
103+
return t;
104+
}
105+
106+
void publishTrajectory(const Trajectory & traj)
107+
{
108+
traj_pub_->publish(traj);
109+
rclcpp::spin_some(eval_node);
110+
rclcpp::spin_some(dummy_node);
111+
rclcpp::sleep_for(std::chrono::milliseconds(100));
112+
}
113+
114+
double publishTrajectoryAndGetMetric(const Trajectory & traj)
115+
{
116+
metric_updated_ = false;
117+
traj_pub_->publish(traj);
118+
while (!metric_updated_) {
119+
rclcpp::spin_some(eval_node);
120+
rclcpp::spin_some(dummy_node);
121+
rclcpp::sleep_for(std::chrono::milliseconds(100));
122+
}
123+
return metric_value_;
124+
}
125+
126+
void publishEgoPose(const double x, const double y, const double yaw)
127+
{
128+
Odometry odom;
129+
odom.header.frame_id = "map";
130+
odom.header.stamp = dummy_node->now();
131+
odom.pose.pose.position.x = x;
132+
odom.pose.pose.position.y = y;
133+
odom.pose.pose.position.z = 0.0;
134+
tf2::Quaternion q;
135+
q.setRPY(0.0, 0.0, yaw);
136+
odom.pose.pose.orientation.x = q.x();
137+
odom.pose.pose.orientation.y = q.y();
138+
odom.pose.pose.orientation.z = q.z();
139+
odom.pose.pose.orientation.w = q.w();
140+
141+
odom_pub_->publish(odom);
142+
rclcpp::spin_some(eval_node);
143+
rclcpp::spin_some(dummy_node);
144+
rclcpp::sleep_for(std::chrono::milliseconds(100));
145+
}
146+
147+
// Latest metric value
148+
bool metric_updated_ = false;
149+
double metric_value_;
150+
// Node
151+
rclcpp::Node::SharedPtr dummy_node;
152+
EvalNode::SharedPtr eval_node;
153+
// Trajectory publishers
154+
rclcpp::Publisher<Trajectory>::SharedPtr traj_pub_;
155+
rclcpp::Publisher<Odometry>::SharedPtr odom_pub_;
156+
rclcpp::Subscription<DiagnosticArray>::SharedPtr metric_sub_;
157+
// TF broadcaster
158+
std::unique_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
159+
};
160+
161+
TEST_F(EvalTest, TestYawDeviation)
162+
{
163+
auto setYaw = [](geometry_msgs::msg::Quaternion & msg, const double yaw_rad) {
164+
tf2::Quaternion q;
165+
q.setRPY(0.0, 0.0, yaw_rad);
166+
msg.x = q.x();
167+
msg.y = q.y();
168+
msg.z = q.z();
169+
msg.w = q.w();
170+
};
171+
setTargetMetric("yaw_deviation");
172+
Trajectory t = makeTrajectory({{0.0, 0.0}, {1.0, 0.0}});
173+
for (auto & p : t.points) {
174+
setYaw(p.pose.orientation, M_PI);
175+
}
176+
177+
publishEgoPose(0.0, 0.0, M_PI);
178+
EXPECT_NEAR(publishTrajectoryAndGetMetric(t), 0.0, epsilon);
179+
180+
publishEgoPose(0.0, 0.0, 0.0);
181+
EXPECT_NEAR(publishTrajectoryAndGetMetric(t), M_PI, epsilon);
182+
183+
publishEgoPose(0.0, 0.0, -M_PI);
184+
EXPECT_NEAR(publishTrajectoryAndGetMetric(t), 0.0, epsilon);
185+
}
186+
187+
TEST_F(EvalTest, TestLateralDeviation)
188+
{
189+
setTargetMetric("lateral_deviation");
190+
Trajectory t = makeTrajectory({{0.0, 0.0}, {1.0, 0.0}});
191+
192+
publishEgoPose(0.0, 0.0, 0.0);
193+
EXPECT_NEAR(publishTrajectoryAndGetMetric(t), 0.0, epsilon);
194+
195+
publishEgoPose(1.0, 1.0, 0.0);
196+
EXPECT_NEAR(publishTrajectoryAndGetMetric(t), 1.0, epsilon);
197+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
cmake_minimum_required(VERSION 3.14)
2+
project(autoware_evaluator_utils)
3+
4+
find_package(autoware_cmake REQUIRED)
5+
autoware_package()
6+
7+
ament_auto_add_library(evaluator_utils SHARED
8+
src/evaluator_utils.cpp
9+
)
10+
11+
ament_auto_package(
12+
INSTALL_TO_SHARE
13+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Evaluator Utils
2+
3+
## Purpose
4+
5+
This package provides utils functions for other evaluator packages
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 AUTOWARE__EVALUATOR_UTILS__EVALUATOR_UTILS_HPP_
16+
#define AUTOWARE__EVALUATOR_UTILS__EVALUATOR_UTILS_HPP_
17+
18+
#include <rclcpp/rclcpp.hpp>
19+
20+
#include <diagnostic_msgs/msg/diagnostic_array.hpp>
21+
22+
#include <deque>
23+
#include <optional>
24+
#include <string>
25+
#include <utility>
26+
#include <vector>
27+
28+
namespace autoware::evaluator_utils
29+
{
30+
31+
using diagnostic_msgs::msg::DiagnosticArray;
32+
using diagnostic_msgs::msg::DiagnosticStatus;
33+
using DiagnosticQueue = std::deque<std::pair<DiagnosticStatus, rclcpp::Time>>;
34+
35+
void removeOldDiagnostics(const rclcpp::Time & stamp, DiagnosticQueue & diag_queue);
36+
void removeDiagnosticsByName(const std::string & name, DiagnosticQueue & diag_queue);
37+
void addDiagnostic(
38+
const DiagnosticStatus & diag, const rclcpp::Time & stamp, DiagnosticQueue & diag_queue);
39+
void updateDiagnosticQueue(
40+
const DiagnosticArray & input_diagnostics, const std::string & function,
41+
const rclcpp::Time & stamp, DiagnosticQueue & diag_queue);
42+
43+
} // namespace autoware::evaluator_utils
44+
45+
#endif // AUTOWARE__EVALUATOR_UTILS__EVALUATOR_UTILS_HPP_
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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_evaluator_utils</name>
5+
<version>0.1.0</version>
6+
<description>ROS 2 node for evaluating control</description>
7+
<maintainer email="daniel.sanchez@tier4.jp">Daniel SANCHEZ</maintainer>
8+
<maintainer email="takayuki.murooka@tier4.jp">Takayuki MUROOKA</maintainer>
9+
<license>Apache License 2.0</license>
10+
11+
<author email="daniel.sanchez@tier4.jp">Daniel SANCHEZ</author>
12+
<author email="takayuki.murooka@tier4.jp">Takayuki MUROOKA</author>
13+
14+
<buildtool_depend>ament_cmake_auto</buildtool_depend>
15+
<buildtool_depend>autoware_cmake</buildtool_depend>
16+
17+
<depend>diagnostic_msgs</depend>
18+
<depend>rclcpp</depend>
19+
<depend>rclcpp_components</depend>
20+
21+
<export>
22+
<build_type>ament_cmake</build_type>
23+
</export>
24+
</package>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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 "autoware/evaluator_utils/evaluator_utils.hpp"
16+
17+
#include <algorithm>
18+
19+
namespace autoware::evaluator_utils
20+
{
21+
void removeOldDiagnostics(const rclcpp::Time & stamp, DiagnosticQueue & diag_queue)
22+
{
23+
constexpr double KEEP_TIME = 1.0;
24+
diag_queue.erase(
25+
std::remove_if(
26+
diag_queue.begin(), diag_queue.end(),
27+
[stamp](const std::pair<DiagnosticStatus, rclcpp::Time> & p) {
28+
return (stamp - p.second).seconds() > KEEP_TIME;
29+
}),
30+
diag_queue.end());
31+
}
32+
33+
void removeDiagnosticsByName(const std::string & name, DiagnosticQueue & diag_queue)
34+
{
35+
diag_queue.erase(
36+
std::remove_if(
37+
diag_queue.begin(), diag_queue.end(),
38+
[&name](const std::pair<DiagnosticStatus, rclcpp::Time> & p) {
39+
return p.first.name.find(name) != std::string::npos;
40+
}),
41+
diag_queue.end());
42+
}
43+
44+
void addDiagnostic(
45+
const DiagnosticStatus & diag, const rclcpp::Time & stamp, DiagnosticQueue & diag_queue)
46+
{
47+
diag_queue.push_back(std::make_pair(diag, stamp));
48+
}
49+
50+
void updateDiagnosticQueue(
51+
const DiagnosticArray & input_diagnostics, const std::string & function,
52+
const rclcpp::Time & stamp, DiagnosticQueue & diag_queue)
53+
{
54+
const auto it = std::find_if(
55+
input_diagnostics.status.begin(), input_diagnostics.status.end(),
56+
[&function](const DiagnosticStatus & diag) {
57+
return diag.name.find(function) != std::string::npos;
58+
});
59+
if (it != input_diagnostics.status.end()) {
60+
removeDiagnosticsByName(it->name, diag_queue);
61+
addDiagnostic(*it, input_diagnostics.header.stamp, diag_queue);
62+
}
63+
64+
removeOldDiagnostics(stamp, diag_queue);
65+
}
66+
} // namespace autoware::evaluator_utils

‎launch/tier4_control_launch/launch/control.launch.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -376,13 +376,16 @@ def launch_setup(context, *args, **kwargs):
376376
# control evaluator
377377
control_evaluator_component = ComposableNode(
378378
package="autoware_control_evaluator",
379-
plugin="control_diagnostics::controlEvaluatorNode",
379+
plugin="control_diagnostics::ControlEvaluatorNode",
380380
name="control_evaluator",
381381
remappings=[
382382
("~/input/diagnostics", "/diagnostics"),
383383
("~/input/odometry", "/localization/kinematic_state"),
384+
("~/input/acceleration", "/localization/acceleration"),
384385
("~/input/trajectory", "/planning/scenario_planning/trajectory"),
385386
("~/metrics", "/control/control_evaluator/metrics"),
387+
("~/input/vector_map", "/map/vector_map"),
388+
("~/input/route", "/planning/mission_planning/route"),
386389
],
387390
)
388391

‎launch/tier4_simulator_launch/launch/simulator.launch.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@
147147
<!-- Diagnostic Converter -->
148148
<group if="$(var launch_diagnostic_converter)">
149149
<node name="diagnostic_converter" exec="diagnostic_converter" pkg="diagnostic_converter" output="screen">
150-
<param name="diagnostic_topics" value="[/planning/planning_evaluator/metrics, /control/control_evaluator/metrics, /diagnostics_err]"/>
150+
<param name="diagnostic_topics" value="[/planning/planning_evaluator/metrics, /control/control_evaluator/metrics, /diagnostics_err, /system/processing_time_checker/metrics]"/>
151151
</node>
152152
</group>
153153

0 commit comments

Comments
 (0)
Please sign in to comment.