13
13
// limitations under the License.
14
14
15
15
#include < ../src/lanelet2_plugins/default_planner.hpp>
16
+ #include < ament_index_cpp/get_package_share_directory.hpp>
16
17
#include < autoware/universe_utils/geometry/boost_geometry.hpp>
18
+ #include < autoware/universe_utils/geometry/geometry.hpp>
17
19
#include < autoware_test_utils/autoware_test_utils.hpp>
18
20
19
21
#include < boost/geometry/io/wkt/write.hpp>
20
22
21
23
#include < gtest/gtest.h>
22
24
#include < lanelet2_core/Forward.h>
25
+ #include < lanelet2_core/LaneletMap.h>
23
26
#include < lanelet2_core/geometry/Polygon.h>
24
27
#include < lanelet2_core/primitives/Lanelet.h>
25
28
#include < lanelet2_core/primitives/LineString.h>
26
29
#include < lanelet2_core/primitives/Point.h>
30
+ #include < tf2/utils.h>
27
31
28
- struct DefaultPlanner : protected autoware ::mission_planner::lanelet2::DefaultPlanner
32
+ using autoware::universe_utils::calcOffsetPose;
33
+ using autoware::universe_utils::createQuaternionFromRPY;
34
+ using autoware_planning_msgs::msg::LaneletRoute;
35
+ using geometry_msgs::msg::Pose;
36
+ using RoutePoints = std::vector<geometry_msgs::msg::Pose>;
37
+
38
+ // inherit DefaultPlanner to access protected methods and make wrapper to private methods
39
+ struct DefaultPlanner : public autoware ::mission_planner::lanelet2::DefaultPlanner
29
40
{
30
- void set_front_offset ( const double offset) { vehicle_info_. max_longitudinal_offset_m = offset; }
31
- void set_dummy_map () { route_handler_.setMap (autoware::test_utils::makeMapBinMsg ()); }
41
+ // todo(someone): create tests with various kinds of maps
42
+ void set_default_test_map () { route_handler_.setMap (autoware::test_utils::makeMapBinMsg ()); }
32
43
[[nodiscard]] bool check_goal_inside_lanes (
33
44
const lanelet::ConstLanelet & closest_lanelet_to_goal,
34
45
const lanelet::ConstLanelets & path_lanelets,
@@ -37,15 +48,61 @@ struct DefaultPlanner : protected autoware::mission_planner::lanelet2::DefaultPl
37
48
return check_goal_footprint_inside_lanes (
38
49
closest_lanelet_to_goal, path_lanelets, goal_footprint);
39
50
}
51
+ bool is_goal_valid_wrapper (
52
+ const geometry_msgs::msg::Pose & goal, const lanelet::ConstLanelets & path_lanelets)
53
+ {
54
+ return is_goal_valid (goal, path_lanelets);
55
+ }
56
+
57
+ lanelet::ConstLanelets get_lanelets_from_ids (const std::vector<lanelet::Id> & ids)
58
+ {
59
+ const auto lanelet_map_ptr = route_handler_.getLaneletMapPtr ();
60
+
61
+ lanelet::ConstLanelets lanelets;
62
+
63
+ for (const auto & id : ids) {
64
+ lanelets.push_back (lanelet_map_ptr->laneletLayer .get (id));
65
+ }
66
+ return lanelets;
67
+ }
68
+ };
69
+
70
+ class DefaultPlannerTest : public ::testing::Test
71
+ {
72
+ protected:
73
+ void SetUp () override
74
+ {
75
+ rclcpp::init (0 , nullptr );
76
+
77
+ rclcpp::NodeOptions options;
78
+
79
+ const auto autoware_test_utils_dir =
80
+ ament_index_cpp::get_package_share_directory (" autoware_test_utils" );
81
+ const auto mission_planner_dir =
82
+ ament_index_cpp::get_package_share_directory (" autoware_mission_planner" );
83
+ options.arguments (
84
+ {" --ros-args" , " --params-file" ,
85
+ autoware_test_utils_dir + " /config/test_vehicle_info.param.yaml" , " --params-file" ,
86
+ mission_planner_dir + " /config/mission_planner.param.yaml" });
87
+ // NOTE: vehicle width and length set by test_vehicle_info.param.yaml are as follows
88
+ // vehicle_width: 1.83, vehicle_length: 4.77
89
+
90
+ node_ = std::make_shared<rclcpp::Node>(" test_node" , options);
91
+ planner_.initialize (node_.get ());
92
+ }
93
+
94
+ ~DefaultPlannerTest () override { rclcpp::shutdown (); }
95
+
96
+ std::shared_ptr<rclcpp::Node> node_;
97
+
98
+ DefaultPlanner planner_;
40
99
};
41
100
42
- TEST (TestLanelet2PluginsDefaultPlanner , checkGoalInsideLane)
101
+ TEST_F (DefaultPlannerTest , checkGoalInsideLane)
43
102
{
44
103
// Test with dummy map such that only the lanelets provided as inputs are used for the ego lane
45
- DefaultPlanner planner;
46
- planner.set_dummy_map ();
104
+ planner_.set_default_test_map ();
47
105
// vehicle max longitudinal offset is used to retrieve additional lanelets from the map
48
- planner.set_front_offset (0.0 );
49
106
lanelet::LineString3d left_bound;
50
107
lanelet::LineString3d right_bound;
51
108
left_bound.push_back (lanelet::Point3d{lanelet::InvalId, -1 , -1 });
@@ -63,7 +120,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
63
120
goal_footprint.outer ().emplace_back (0.5 , 0.5 );
64
121
goal_footprint.outer ().emplace_back (0.5 , 0 );
65
122
goal_footprint.outer ().emplace_back (0 , 0 );
66
- EXPECT_TRUE (planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet}, goal_footprint));
123
+ EXPECT_TRUE (planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet}, goal_footprint));
67
124
68
125
// the footprint touches the border of the lanelet
69
126
goal_footprint.clear ();
@@ -72,7 +129,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
72
129
goal_footprint.outer ().emplace_back (1 , 1 );
73
130
goal_footprint.outer ().emplace_back (1 , 0 );
74
131
goal_footprint.outer ().emplace_back (0 , 0 );
75
- EXPECT_TRUE (planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet}, goal_footprint));
132
+ EXPECT_TRUE (planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet}, goal_footprint));
76
133
77
134
// add lanelets such that the footprint touches the linestring shared by the combined lanelets
78
135
lanelet::LineString3d next_left_bound;
@@ -83,7 +140,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
83
140
next_right_bound.push_back (lanelet::Point3d{lanelet::InvalId, 2 , 1 });
84
141
lanelet::ConstLanelet next_lanelet{lanelet::InvalId, next_left_bound, next_right_bound};
85
142
EXPECT_TRUE (
86
- planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
143
+ planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
87
144
88
145
// the footprint is inside the other lanelet
89
146
goal_footprint.clear ();
@@ -93,7 +150,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
93
150
goal_footprint.outer ().emplace_back (1.6 , -0.5 );
94
151
goal_footprint.outer ().emplace_back (1.1 , -0.5 );
95
152
EXPECT_TRUE (
96
- planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
153
+ planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
97
154
98
155
// the footprint is completely outside of the lanelets
99
156
goal_footprint.clear ();
@@ -103,7 +160,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
103
160
goal_footprint.outer ().emplace_back (1.6 , 1.5 );
104
161
goal_footprint.outer ().emplace_back (1.1 , 1.5 );
105
162
EXPECT_FALSE (
106
- planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
163
+ planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
107
164
108
165
// the footprint is outside of the lanelets but touches an edge
109
166
goal_footprint.clear ();
@@ -113,7 +170,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
113
170
goal_footprint.outer ().emplace_back (1.6 , 1.0 );
114
171
goal_footprint.outer ().emplace_back (1.1 , 1.0 );
115
172
EXPECT_FALSE (
116
- planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
173
+ planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
117
174
118
175
// the footprint is outside of the lanelets but share a point
119
176
goal_footprint.clear ();
@@ -123,7 +180,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
123
180
goal_footprint.outer ().emplace_back (3.0 , 1.0 );
124
181
goal_footprint.outer ().emplace_back (2.0 , 1.0 );
125
182
EXPECT_FALSE (
126
- planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
183
+ planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
127
184
128
185
// ego footprint that overlaps both lanelets
129
186
goal_footprint.clear ();
@@ -133,7 +190,7 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
133
190
goal_footprint.outer ().emplace_back (1.5 , -0.5 );
134
191
goal_footprint.outer ().emplace_back (-0.5 , -0.5 );
135
192
EXPECT_TRUE (
136
- planner .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
193
+ planner_ .check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
137
194
138
195
// ego footprint that goes further than the next lanelet
139
196
goal_footprint.clear ();
@@ -143,5 +200,215 @@ TEST(TestLanelet2PluginsDefaultPlanner, checkGoalInsideLane)
143
200
goal_footprint.outer ().emplace_back (2.5 , -0.5 );
144
201
goal_footprint.outer ().emplace_back (-0.5 , -0.5 );
145
202
EXPECT_FALSE (
146
- planner.check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
203
+ planner_.check_goal_inside_lanes (goal_lanelet, {goal_lanelet, next_lanelet}, goal_footprint));
204
+ }
205
+
206
+ TEST_F (DefaultPlannerTest, isValidGoal)
207
+ {
208
+ planner_.set_default_test_map ();
209
+
210
+ std::vector<lanelet::Id> path_lanelet_ids = {9102 , 9540 , 9546 , 9178 , 52 , 124 };
211
+ const auto path_lanelets = planner_.get_lanelets_from_ids (path_lanelet_ids);
212
+
213
+ const double yaw_threshold = 0.872665 ; // 50 degrees
214
+
215
+ /* *
216
+ * 1) goal pose within the lanelet
217
+ */
218
+ // goal pose within the lanelet
219
+ Pose goal_pose;
220
+ goal_pose.position .x = 3810.24951171875 ;
221
+ goal_pose.position .y = 73769.2578125 ;
222
+ goal_pose.position .z = 0.0 ;
223
+ goal_pose.orientation .x = 0.0 ;
224
+ goal_pose.orientation .y = 0.0 ;
225
+ goal_pose.orientation .z = 0.23908402523702438 ;
226
+ goal_pose.orientation .w = 0.9709988820160721 ;
227
+ const double yaw = tf2::getYaw (goal_pose.orientation );
228
+ EXPECT_TRUE (planner_.is_goal_valid_wrapper (goal_pose, path_lanelets));
229
+
230
+ // move 1m to the right to make the goal outside of the lane
231
+ Pose right_offset_goal_pose = calcOffsetPose (goal_pose, 0.0 , 1.0 , 0.0 );
232
+ EXPECT_FALSE (planner_.is_goal_valid_wrapper (right_offset_goal_pose, path_lanelets));
233
+
234
+ // move 1m to the left to make the goal outside of the lane
235
+ Pose left_offset_goal_pose = calcOffsetPose (goal_pose, 0.0 , -1.0 , 0.0 );
236
+ EXPECT_FALSE (planner_.is_goal_valid_wrapper (left_offset_goal_pose, path_lanelets));
237
+
238
+ // rotate to the right
239
+ Pose right_rotated_goal_pose = goal_pose;
240
+ right_rotated_goal_pose.orientation = createQuaternionFromRPY (0.0 , 0.0 , yaw + yaw_threshold);
241
+ EXPECT_FALSE (planner_.is_goal_valid_wrapper (right_rotated_goal_pose, path_lanelets));
242
+
243
+ // rotate to the left
244
+ Pose left_rotated_goal_pose = goal_pose;
245
+ left_rotated_goal_pose.orientation = createQuaternionFromRPY (0.0 , 0.0 , yaw - yaw_threshold);
246
+ EXPECT_FALSE (planner_.is_goal_valid_wrapper (left_rotated_goal_pose, path_lanelets));
247
+
248
+ /* *
249
+ * 2) goal pose on the road shoulder
250
+ */
251
+ std::vector<lanelet::Id> path_lanelet_to_road_shoulder_ids = {9102 , 9540 , 9546 };
252
+ lanelet::Id target_road_shoulder_id = 10304 ; // left road shoulder of 9546
253
+ const auto path_lanelets_to_road_shoulder =
254
+ planner_.get_lanelets_from_ids (path_lanelet_to_road_shoulder_ids);
255
+ const auto target_road_shoulder =
256
+ planner_.get_lanelets_from_ids ({target_road_shoulder_id}).front ();
257
+
258
+ Pose goal_pose_on_road_shoulder;
259
+ goal_pose_on_road_shoulder.position .x = 3742.3825513144147 ;
260
+ goal_pose_on_road_shoulder.position .y = 73737.75783925217 ;
261
+ goal_pose_on_road_shoulder.position .z = 0.0 ;
262
+ goal_pose_on_road_shoulder.orientation .x = 0.0 ;
263
+ goal_pose_on_road_shoulder.orientation .y = 0.0 ;
264
+ goal_pose_on_road_shoulder.orientation .z = 0.23721495449671745 ;
265
+ goal_pose_on_road_shoulder.orientation .w = 0.9714571865826721 ;
266
+ EXPECT_TRUE (
267
+ planner_.is_goal_valid_wrapper (goal_pose_on_road_shoulder, path_lanelets_to_road_shoulder));
268
+
269
+ // put goal on the left bound of the road shoulder
270
+ // if the goal is on the road shoulder, the footprint can be outside of the lane, and only the
271
+ // angle is checked
272
+ const auto left_bound = target_road_shoulder.leftBound ();
273
+ Pose goal_pose_on_road_shoulder_left_bound = goal_pose_on_road_shoulder;
274
+ goal_pose_on_road_shoulder_left_bound.position .x = left_bound.front ().x ();
275
+ goal_pose_on_road_shoulder_left_bound.position .y = left_bound.front ().y ();
276
+ EXPECT_TRUE (planner_.is_goal_valid_wrapper (
277
+ goal_pose_on_road_shoulder_left_bound, path_lanelets_to_road_shoulder));
278
+
279
+ // move goal pose outside of the road shoulder
280
+ Pose goal_pose_outside_road_shoulder =
281
+ calcOffsetPose (goal_pose_on_road_shoulder_left_bound, 0.0 , 0.1 , 0.0 );
282
+ EXPECT_FALSE (planner_.is_goal_valid_wrapper (
283
+ goal_pose_outside_road_shoulder, path_lanelets_to_road_shoulder));
284
+
285
+ // rotate goal to the right
286
+ Pose right_rotated_goal_pose_on_road_shoulder = goal_pose_on_road_shoulder;
287
+ right_rotated_goal_pose_on_road_shoulder.orientation =
288
+ createQuaternionFromRPY (0.0 , 0.0 , yaw + yaw_threshold);
289
+ EXPECT_FALSE (planner_.is_goal_valid_wrapper (
290
+ right_rotated_goal_pose_on_road_shoulder, path_lanelets_to_road_shoulder));
291
+
292
+ /* *
293
+ * todo(someone): add more test for parking area
294
+ */
295
+ }
296
+
297
+ TEST_F (DefaultPlannerTest, plan)
298
+ {
299
+ planner_.set_default_test_map ();
300
+
301
+ /* *
302
+ * 1) goal pose within the lanelet
303
+ */
304
+ RoutePoints route_points;
305
+ Pose start_pose;
306
+ start_pose.position .x = 3717.239501953125 ;
307
+ start_pose.position .y = 73720.84375 ;
308
+ start_pose.position .z = 0.0 ;
309
+ start_pose.orientation .x = 0.00012620055018808463 ;
310
+ start_pose.orientation .y = -0.0005077247816171834 ;
311
+ start_pose.orientation .z = 0.2412209576008544 ;
312
+
313
+ Pose goal_pose;
314
+ goal_pose.position .x = 3810.24951171875 ;
315
+ goal_pose.position .y = 73769.2578125 ;
316
+ goal_pose.position .z = 0.0 ;
317
+ goal_pose.orientation .x = 0.0 ;
318
+ goal_pose.orientation .y = 0.0 ;
319
+ goal_pose.orientation .z = 0.23908402523702438 ;
320
+ goal_pose.orientation .w = 0.9709988820160721 ;
321
+
322
+ route_points.push_back (start_pose);
323
+ route_points.push_back (goal_pose);
324
+ const auto route = planner_.plan (route_points);
325
+
326
+ EXPECT_EQ (route.start_pose .position .x , start_pose.position .x );
327
+ EXPECT_EQ (route.start_pose .position .y , start_pose.position .y );
328
+ EXPECT_EQ (route.goal_pose .position .x , goal_pose.position .x );
329
+ EXPECT_EQ (route.goal_pose .position .y , goal_pose.position .y );
330
+ std::vector<lanelet::Id> path_lanelet_ids = {9102 , 9540 , 9546 , 9178 , 52 , 124 };
331
+ EXPECT_EQ (route.segments .size (), path_lanelet_ids.size ());
332
+ for (size_t i = 0 ; i < route.segments .size (); i++) {
333
+ EXPECT_EQ (route.segments [i].preferred_primitive .id , path_lanelet_ids[i]);
334
+ const auto & primitives = route.segments [i].primitives ;
335
+ EXPECT_TRUE (std::find_if (primitives.begin (), primitives.end (), [&](const auto & primitive) {
336
+ return primitive.id == path_lanelet_ids[i];
337
+ }) != primitives.end ());
338
+ }
339
+
340
+ /* *
341
+ * 2) goal pose on the road shoulder
342
+ */
343
+ Pose goal_pose_on_road_shoulder;
344
+ goal_pose_on_road_shoulder.position .x = 3742.3825513144147 ;
345
+ goal_pose_on_road_shoulder.position .y = 73737.75783925217 ;
346
+ goal_pose_on_road_shoulder.position .z = 0.0 ;
347
+ goal_pose_on_road_shoulder.orientation .x = 0.0 ;
348
+ goal_pose_on_road_shoulder.orientation .y = 0.0 ;
349
+ goal_pose_on_road_shoulder.orientation .z = 0.23721495449671745 ;
350
+ goal_pose_on_road_shoulder.orientation .w = 0.9714571865826721 ;
351
+
352
+ RoutePoints route_points_to_road_shoulder;
353
+ route_points_to_road_shoulder.push_back (start_pose);
354
+ route_points_to_road_shoulder.push_back (goal_pose_on_road_shoulder);
355
+ const auto route_to_road_shoulder = planner_.plan (route_points_to_road_shoulder);
356
+
357
+ EXPECT_EQ (route_to_road_shoulder.start_pose .position .x , start_pose.position .x );
358
+ EXPECT_EQ (route_to_road_shoulder.start_pose .position .y , start_pose.position .y );
359
+ EXPECT_EQ (route_to_road_shoulder.goal_pose .position .x , goal_pose_on_road_shoulder.position .x );
360
+ EXPECT_EQ (route_to_road_shoulder.goal_pose .position .y , goal_pose_on_road_shoulder.position .y );
361
+ std::vector<lanelet::Id> path_lanelet_to_road_shoulder_ids = {9102 , 9540 , 9546 };
362
+ EXPECT_EQ (route_to_road_shoulder.segments .size (), path_lanelet_to_road_shoulder_ids.size ());
363
+ for (size_t i = 0 ; i < route_to_road_shoulder.segments .size (); i++) {
364
+ EXPECT_EQ (
365
+ route_to_road_shoulder.segments [i].preferred_primitive .id ,
366
+ path_lanelet_to_road_shoulder_ids[i]);
367
+ const auto & primitives = route_to_road_shoulder.segments [i].primitives ;
368
+ EXPECT_TRUE (std::find_if (primitives.begin (), primitives.end (), [&](const auto & primitive) {
369
+ return primitive.id == path_lanelet_to_road_shoulder_ids[i];
370
+ }) != primitives.end ());
371
+ }
372
+ }
373
+
374
+ // `visualize` function is used for user too, so it is more important than debug functions
375
+ TEST_F (DefaultPlannerTest, visualize)
376
+ {
377
+ DefaultPlanner planner;
378
+ planner_.set_default_test_map ();
379
+ const LaneletRoute route = autoware::test_utils::makeBehaviorNormalRoute ();
380
+ const auto marker_array = planner_.visualize (route);
381
+ // clang-format off
382
+ const std::vector<std::string> expected_ns = {
383
+ // 1) lanelet::visualization::laneletsBoundaryAsMarkerArray
384
+ // center line is not set in the test lanelets,
385
+ // so "center_lane_line" and "center_line_arrows" are not visualized
386
+ " left_lane_bound" , " right_lane_bound" , " lane_start_bound" ,
387
+ // 2) lanelet::visualization::laneletsAsMarkerArray
388
+ " route_lanelets" ,
389
+ // 3) lanelet::visualization::laneletsAsMarkerArray
390
+ " goal_lanelets" };
391
+ // clang-format on
392
+ for (const auto & marker : marker_array.markers ) {
393
+ EXPECT_TRUE (std::find (expected_ns.begin (), expected_ns.end (), marker.ns ) != expected_ns.end ());
394
+ }
395
+ }
396
+
397
+ TEST_F (DefaultPlannerTest, visualizeDebugFootrprint)
398
+ {
399
+ DefaultPlanner planner;
400
+ planner_.set_default_test_map ();
401
+
402
+ autoware::universe_utils::LinearRing2d footprint;
403
+ footprint.push_back ({1.0 , 1.0 });
404
+ footprint.push_back ({1.0 , -1.0 });
405
+ footprint.push_back ({0.0 , -1.0 });
406
+ footprint.push_back ({-1.0 , -1.0 });
407
+ footprint.push_back ({-1.0 , 1.0 });
408
+ footprint.push_back ({0.0 , 1.0 });
409
+ footprint.push_back ({1.0 , 1.0 });
410
+
411
+ const auto marker_array = planner_.visualize_debug_footprint (footprint);
412
+ EXPECT_EQ (marker_array.markers .size (), 1 );
413
+ EXPECT_EQ (marker_array.markers [0 ].points .size (), 7 );
147
414
}
0 commit comments