39 #include <costmap_cspace_msgs/CSpace3D.h>
40 #include <nav_msgs/GetPlan.h>
41 #include <nav_msgs/OccupancyGrid.h>
42 #include <nav_msgs/Path.h>
43 #include <planner_cspace_msgs/PlannerStatus.h>
44 #include <std_msgs/Empty.h>
45 #include <std_srvs/Empty.h>
49 #include <trajectory_tracker_msgs/PathWithVelocity.h>
53 #include <gtest/gtest.h>
62 nav_msgs::OccupancyGrid::ConstPtr
map_;
65 costmap_cspace_msgs::CSpace3D::ConstPtr
costmap_;
67 trajectory_tracker_msgs::PathWithVelocity::ConstPtr
path_vel_;
80 std::vector<tf2::Stamped<tf2::Transform>>
traj_;
97 "forget_planning_cost");
101 nh_.
advertise<geometry_msgs::PoseWithCovarianceStamped>(
"initialpose", 1,
true);
108 "[" + std::to_string(getpid()) +
"/" +
109 ::testing::UnitTest::GetInstance()->current_test_info()->name() +
"] ";
141 geometry_msgs::PoseWithCovarianceStamped pose;
142 pose.header.frame_id =
"map";
143 pose.pose.pose.position.x = 2.5;
144 pose.pose.pose.position.y = 0.45;
145 pose.pose.pose.orientation.z = 1.0;
153 ASSERT_LT(now, deadline) <<
test_scope_ <<
"Initial transform timeout";
183 std_srvs::EmptyRequest req;
184 std_srvs::EmptyResponse res;
189 void cbCostmap(
const costmap_cspace_msgs::CSpace3D::ConstPtr& msg)
192 std::cerr <<
test_scope_ <<
msg->header.stamp <<
" Costmap received." << std::endl;
194 void cbMap(
const nav_msgs::OccupancyGrid::ConstPtr& msg)
197 std::cerr <<
test_scope_ <<
msg->header.stamp <<
" Map received." << std::endl;
199 void cbMapLocal(
const nav_msgs::OccupancyGrid::ConstPtr& msg)
206 std::cerr <<
test_scope_ <<
msg->header.stamp <<
" Local map received." << std::endl;
208 void cbStatus(
const planner_cspace_msgs::PlannerStatus::ConstPtr& msg)
212 std::cerr <<
test_scope_ <<
msg->header.stamp <<
" Status updated." <<
msg << std::endl;
216 void cbPath(
const nav_msgs::Path::ConstPtr& msg)
220 if (
msg->poses.size() == 0)
222 std::cerr <<
test_scope_ <<
msg->header.stamp <<
" Path updated. (empty)" << std::endl;
227 <<
test_scope_ <<
msg->header.stamp <<
" Path updated." << std::endl
228 <<
msg->poses.front().pose.position.x <<
", " <<
msg->poses.front().pose.position.y << std::endl
229 <<
msg->poses.back().pose.position.x <<
", " <<
msg->poses.back().pose.position.y << std::endl;
234 void cbPathVel(
const trajectory_tracker_msgs::PathWithVelocity::ConstPtr& msg)
238 if (
msg->poses.size() == 0)
240 std::cerr <<
test_scope_ <<
msg->header.stamp <<
" PathWithVelocity updated. (empty)" << std::endl;
245 <<
test_scope_ <<
msg->header.stamp <<
" PathWithVelocity updated." << std::endl
246 <<
msg->poses.front().pose.position.x <<
", " <<
msg->poses.front().pose.position.y << std::endl
247 <<
msg->poses.back().pose.position.x <<
", " <<
msg->poses.back().pose.position.y << std::endl;
261 int num_occupied = 0;
269 std::cerr <<
test_scope_ <<
" Local map applied. occupied grids:" << num_occupied << std::endl;
274 geometry_msgs::TransformStamped trans_tmp =
278 traj_.push_back(trans);
283 double x_prev(0), y_prev(0);
286 std::cerr <<
test_scope_ <<
traj_.size() <<
" points recorded" << std::endl;
288 for (
const auto&
t :
traj_)
290 const double x =
t.getOrigin().getX();
291 const double y =
t.getOrigin().getY();
294 if (std::abs(x - x_prev) >= 0 || std::abs(y - y_prev) >= 0 || std::abs(yaw_diff) >= 0)
299 std::cerr <<
t.stamp_ <<
" " << x <<
" " << y <<
" " <<
tf2::getYaw(rot) << std::endl;
307 ASSERT_TRUE(
static_cast<bool>(
map_));
326 <<
test_scope_ <<
"/" << name <<
": Navigation timeout." << std::endl
327 <<
"now: " << now << std::endl
328 <<
"status: " <<
planner_status_ <<
" (expected: " << expected_error <<
")";
342 ASSERT_TRUE(
static_cast<bool>(map_));
345 path.poses.resize(2);
346 path.header.frame_id =
"map";
347 path.poses[0].header.frame_id = path.header.frame_id;
348 path.poses[0].pose.position.x = 1.7;
349 path.poses[0].pose.position.y = 2.8;
351 path.poses[1].header.frame_id = path.header.frame_id;
352 path.poses[1].pose.position.x = 1.9;
353 path.poses[1].pose.position.y = 2.8;
355 pub_patrol_nodes_.publish(path);
371 dumpRobotTrajectory();
373 << test_scope_ <<
"Navigation timeout." << std::endl
374 <<
"now: " << now << std::endl
375 <<
"status: " << planner_status_;
382 trans = lookupRobotTrans(now);
386 std::cerr << test_scope_ << e.what() << std::endl;
390 auto goal_rel = trans.inverse() * goal;
391 if (goal_rel.getOrigin().length() < 0.2 &&
392 std::abs(
tf2::getYaw(goal_rel.getRotation())) < 0.2)
394 std::cerr << test_scope_ <<
"Navigation success." << std::endl;
399 for (
int x = -2; x <= 2; ++x)
401 for (
int y = -1; y <= 1; ++y)
403 const tf2::Vector3 pos =
404 trans * tf2::Vector3(x * map_->info.resolution, y * map_->info.resolution, 0);
405 const int map_x = pos.x() / map_->info.resolution;
406 const int map_y = pos.y() / map_->info.resolution;
407 const size_t addr = map_x + map_y * map_->info.width;
408 ASSERT_LT(addr, map_->data.size());
409 ASSERT_LT(map_x,
static_cast<int>(map_->info.width));
410 ASSERT_LT(map_y,
static_cast<int>(map_->info.height));
413 ASSERT_NE(map_->data[addr], 100);
423 ASSERT_TRUE(
static_cast<bool>(map_));
424 ASSERT_TRUE(
static_cast<bool>(map_local_));
429 path.poses.resize(1);
430 path.header.frame_id =
"map";
431 path.poses[0].header.frame_id = path.header.frame_id;
432 path.poses[0].pose.position.x = 1.7;
433 path.poses[0].pose.position.y = 2.8;
435 pub_patrol_nodes_.publish(path);
452 dumpRobotTrajectory();
454 << test_scope_ <<
"Navigation timeout." << std::endl
455 <<
"now: " << now << std::endl
456 <<
"status: " << planner_status_;
463 trans = lookupRobotTrans(now);
467 std::cerr << test_scope_ << e.what() << std::endl;
471 auto goal_rel = trans.inverse() * goal;
472 if (goal_rel.getOrigin().length() < 0.2 &&
473 std::abs(
tf2::getYaw(goal_rel.getRotation())) < 0.2)
475 std::cerr << test_scope_ <<
"Navagation success." << std::endl;
480 for (
int x = -2; x <= 2; ++x)
482 for (
int y = -1; y <= 1; ++y)
484 const tf2::Vector3 pos =
485 trans * tf2::Vector3(x * map_->info.resolution, y * map_->info.resolution, 0);
486 const int map_x = pos.x() / map_->info.resolution;
487 const int map_y = pos.y() / map_->info.resolution;
488 const size_t addr = map_x + map_y * map_->info.width;
489 ASSERT_LT(addr, map_->data.size());
490 ASSERT_LT(map_x,
static_cast<int>(map_->info.width));
491 ASSERT_LT(map_y,
static_cast<int>(map_->info.height));
494 ASSERT_NE(map_->data[addr], 100);
495 ASSERT_NE(map_local_->data[addr], 100);
505 nh_.serviceClient<nav_msgs::GetPlanRequest, nav_msgs::GetPlanResponse>(
506 "/planner_3d/make_plan");
509 ASSERT_TRUE(
static_cast<bool>(map_));
511 nav_msgs::GetPlanRequest req;
512 nav_msgs::GetPlanResponse res;
515 req.start.header.frame_id =
"map";
516 req.start.pose.position.x = 1.95;
517 req.start.pose.position.y = 0.45;
518 req.start.pose.orientation =
521 req.goal.header.frame_id =
"map";
522 req.goal.pose.position.x = 1.25;
523 req.goal.pose.position.y = 2.15;
524 req.goal.pose.orientation =
527 ASSERT_FALSE(srv_plan.
call(req, res));
531 ASSERT_TRUE(srv_plan.
call(req, res));
532 EXPECT_NEAR(1.25, res.plan.poses.back().pose.position.x, 1.0e-5);
533 EXPECT_NEAR(2.25, res.plan.poses.back().pose.position.y, 1.0e-5);
536 req.tolerance = 0.2f;
537 ASSERT_TRUE(srv_plan.
call(req, res));
538 EXPECT_NEAR(1.25, res.plan.poses.back().pose.position.x, 1.0e-5);
539 EXPECT_NEAR(2.35, res.plan.poses.back().pose.position.y, 1.0e-5);
542 req.goal.header.frame_id =
"map";
543 req.goal.pose.position.x = 1.85;
544 req.goal.pose.position.y = 2.75;
545 req.goal.pose.orientation =
547 ASSERT_TRUE(srv_plan.
call(req, res));
549 EXPECT_NEAR(req.start.pose.position.x, res.plan.poses.front().pose.position.x, 1.0e-5);
550 EXPECT_NEAR(req.start.pose.position.y, res.plan.poses.front().pose.position.y, 1.0e-5);
551 EXPECT_NEAR(req.goal.pose.position.x, res.plan.poses.back().pose.position.x, 1.0e-5);
552 EXPECT_NEAR(req.goal.pose.position.y, res.plan.poses.back().pose.position.y, 1.0e-5);
554 for (
const geometry_msgs::PoseStamped& p : res.plan.poses)
556 const int map_x = p.pose.position.x / map_->info.resolution;
557 const int map_y = p.pose.position.y / map_->info.resolution;
558 const size_t addr = map_x + map_y * map_->info.width;
559 ASSERT_LT(addr, map_->data.size());
560 ASSERT_LT(map_x,
static_cast<int>(map_->info.width));
561 ASSERT_LT(map_y,
static_cast<int>(map_->info.height));
564 ASSERT_NE(map_->data[addr], 100);
570 ros::Publisher pub_path = nh_.advertise<nav_msgs::Path>(
"patrol_nodes", 1,
true);
573 ASSERT_TRUE(
static_cast<bool>(map_));
574 ASSERT_TRUE(
static_cast<bool>(map_local_));
579 path.poses.resize(1);
580 path.header.frame_id =
"map";
581 path.poses[0].header.frame_id = path.header.frame_id;
582 path.poses[0].pose.position.x = 1.19;
583 path.poses[0].pose.position.y = 1.90;
584 path.poses[0].pose.orientation.w = 1.0;
602 dumpRobotTrajectory();
604 << test_scope_ <<
"Navigation timeout." << std::endl
605 <<
"now: " << now << std::endl
606 <<
"status: " << planner_status_;
610 if (planner_status_->error == planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND)
620 if (pnh_.param(
"enable_crowd_mode",
false))
622 GTEST_SKIP() <<
"enable_crowd_mode is set";
626 ASSERT_TRUE(
static_cast<bool>(map_));
627 ASSERT_TRUE(
static_cast<bool>(map_local_));
629 for (
int x = 10; x <= 16; ++x)
631 for (
int y = 22; y <= 26; ++y)
633 const int pos = x + y * map_local_->info.width;
634 map_local_->data[pos] = 100;
640 path.poses.resize(1);
641 path.header.frame_id =
"map";
642 path.poses[0].header.frame_id = path.header.frame_id;
643 path.poses[0].pose.position.x = 1.25;
644 path.poses[0].pose.position.y = 2.55;
645 path.poses[0].pose.orientation.w = 1.0;
646 pub_patrol_nodes_.publish(path);
648 waitForPlannerStatus(
"Got stuck", planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND);
649 ASSERT_FALSE(::testing::Test::HasFailure());
651 for (
int x = 10; x <= 16; ++x)
653 for (
int y = 22; y <= 26; ++y)
655 const int pos = x + y * map_local_->info.width;
656 map_local_->data[pos] = 0;
659 waitForPlannerStatus(
"Stuck recovered", planner_cspace_msgs::PlannerStatus::GOING_WELL);
665 ASSERT_TRUE(
static_cast<bool>(map_));
666 ASSERT_TRUE(
static_cast<bool>(map_local_));
668 for (
int x = 21; x <= 28; ++x)
670 for (
int y = 2; y <= 8; ++y)
672 const int pos = x + y * map_local_->info.width;
673 map_local_->data[pos] = 100;
679 path.poses.resize(1);
680 path.header.frame_id =
"map";
681 path.poses[0].header.frame_id = path.header.frame_id;
682 path.poses[0].pose.position.x = 1.25;
683 path.poses[0].pose.position.y = 2.55;
684 path.poses[0].pose.orientation.w = 1.0;
685 pub_patrol_nodes_.publish(path);
687 waitForPlannerStatus(
"Got stuck", planner_cspace_msgs::PlannerStatus::IN_ROCK);
688 ASSERT_FALSE(::testing::Test::HasFailure());
690 for (
int x = 21; x <= 28; ++x)
692 for (
int y = 2; y <= 8; ++y)
694 const int pos = x + y * map_local_->info.width;
695 map_local_->data[pos] = 0;
698 waitForPlannerStatus(
"Stuck recovered", planner_cspace_msgs::PlannerStatus::GOING_WELL);
703 if (!pnh_.param(
"enable_crowd_mode",
false))
705 GTEST_SKIP() <<
"enable_crowd_mode is not set";
709 ASSERT_TRUE(
static_cast<bool>(map_));
710 ASSERT_TRUE(
static_cast<bool>(map_local_));
713 path.poses.resize(1);
714 path.header.frame_id =
"map";
715 path.poses[0].header.frame_id = path.header.frame_id;
716 path.poses[0].pose.position.x = 1.6;
717 path.poses[0].pose.position.y = 2.2;
719 pub_patrol_nodes_.publish(path);
736 dumpRobotTrajectory();
738 << test_scope_ <<
"Navigation timeout." << std::endl
739 <<
"now: " << now << std::endl
740 <<
"status: " << planner_status_;
747 trans = lookupRobotTrans(now);
751 std::cerr << test_scope_ << e.what() << std::endl;
755 const auto goal_rel = trans.inverse() * goal;
756 if (goal_rel.getOrigin().length() < 0.2 &&
757 std::abs(
tf2::getYaw(goal_rel.getRotation())) < 0.2 &&
758 planner_status_->status == planner_cspace_msgs::PlannerStatus::DONE)
760 std::cerr << test_scope_ <<
"Navigation success." << std::endl;
765 const size_t rx = trans.getOrigin().x() / map_->info.resolution;
766 const size_t ry = trans.getOrigin().y() / map_->info.resolution;
767 const size_t data_size = map_local_->data.size();
768 map_local_->data.clear();
769 map_local_->data.resize(data_size, 0);
771 for (
int i = -bs; i <= bs; ++i)
773 map_local_->data[std::min((rx + i) + (ry - bs) * map_local_->info.width, data_size - 1)] = 100;
774 map_local_->data[std::min((rx + i) + (ry + bs) * map_local_->info.width, data_size - 1)] = 100;
775 map_local_->data[std::min((rx - bs) + (ry + i) * map_local_->info.width, data_size - 1)] = 100;
776 map_local_->data[std::min((rx + bs) + (ry + i) * map_local_->info.width, data_size - 1)] = 100;
783 if (!pnh_.param(
"enable_crowd_mode",
false))
785 GTEST_SKIP() <<
"enable_crowd_mode is not set";
788 ros::Publisher pub_trigger = nh_.advertise<std_msgs::Empty>(
"/planner_3d/temporary_escape", 1);
791 ASSERT_TRUE(
static_cast<bool>(map_));
792 ASSERT_TRUE(
static_cast<bool>(map_local_));
795 path.poses.resize(1);
796 path.header.frame_id =
"map";
797 path.poses[0].header.frame_id = path.header.frame_id;
798 path.poses[0].pose.position.x = 1.6;
799 path.poses[0].pose.position.y = 2.2;
801 pub_patrol_nodes_.publish(path);
810 const size_t data_size = map_local_->data.size();
811 map_local_->data.clear();
812 map_local_->data.resize(data_size, 0);
825 dumpRobotTrajectory();
827 << test_scope_ <<
"Navigation timeout." << std::endl
828 <<
"now: " << now << std::endl
829 <<
"status: " << planner_status_;
836 trans = lookupRobotTrans(now);
840 std::cerr << test_scope_ << e.what() << std::endl;
844 const auto goal_rel = trans.inverse() * goal;
845 if (goal_rel.getOrigin().length() < 0.2 &&
846 std::abs(
tf2::getYaw(goal_rel.getRotation())) < 0.2 &&
847 planner_status_->status == planner_cspace_msgs::PlannerStatus::DONE)
849 std::cerr << test_scope_ <<
"Navigation success." << std::endl;
856 int main(
int argc,
char** argv)
858 testing::InitGoogleTest(&argc, argv);
861 return RUN_ALL_TESTS();