test_navigate_remember.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024, the neonavigation authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <cmath>
31 #include <cstddef>
32 #include <string>
33 #include <unistd.h>
34 #include <vector>
35 
36 #include <ros/ros.h>
37 
38 #include <costmap_cspace_msgs/CSpace3D.h>
39 #include <nav_msgs/GetPlan.h>
40 #include <nav_msgs/OccupancyGrid.h>
41 #include <nav_msgs/Path.h>
42 #include <planner_cspace_msgs/PlannerStatus.h>
43 #include <std_srvs/Empty.h>
44 #include <tf2/utils.h>
47 
49 
50 #include <gtest/gtest.h>
51 
52 class NavigateWithRememberUpdates : public ::testing::Test
53 {
54 protected:
58  planner_cspace_msgs::PlannerStatus::ConstPtr planner_status_;
59  costmap_cspace_msgs::CSpace3D::ConstPtr costmap_;
60  nav_msgs::Path::ConstPtr path_;
67  std::vector<tf2::Stamped<tf2::Transform>> traj_;
68  std::string test_scope_;
69 
71  : tfl_(tfbuf_)
72  {
75  "/planner_3d/status", 10, &NavigateWithRememberUpdates::cbStatus, this);
77  srv_forget_ =
78  nh_.serviceClient<std_srvs::EmptyRequest, std_srvs::EmptyResponse>(
79  "forget_planning_cost");
81  nh_.advertise<geometry_msgs::PoseWithCovarianceStamped>("initialpose", 1, true);
82  pub_patrol_nodes_ = nh_.advertise<nav_msgs::Path>("patrol_nodes", 1, true);
83  }
84 
85  virtual void SetUp()
86  {
87  test_scope_ = "[" + std::to_string(getpid()) + "] ";
88 
90  ros::Rate rate(10.0);
91 
92  geometry_msgs::PoseWithCovarianceStamped pose;
93  pose.header.frame_id = "map";
94  pose.pose.pose.position.x = 2.1;
95  pose.pose.pose.position.y = 3.0;
96  pose.pose.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), 1.57));
98 
99  const ros::Time deadline = ros::Time::now() + ros::Duration(15);
100 
101  while (ros::ok())
102  {
103  ros::spinOnce();
104  rate.sleep();
105  const ros::Time now = ros::Time::now();
106  if (now > deadline)
107  {
108  FAIL() << test_scope_ << now << " SetUp: transform timeout" << std::endl;
109  }
110  if (tfbuf_.canTransform("map", "base_link", now, ros::Duration(0.5)))
111  {
112  break;
113  }
114  }
115 
116  while (ros::ok() && !costmap_)
117  {
118  ros::spinOnce();
119  rate.sleep();
120  const ros::Time now = ros::Time::now();
121  if (now > deadline)
122  {
123  FAIL() << test_scope_ << now << " SetUp: costmap timeout" << std::endl;
124  }
125  }
126 
127  std_srvs::EmptyRequest req;
128  std_srvs::EmptyResponse res;
129  srv_forget_.call(req, res);
130 
131  ros::Duration(1.0).sleep();
132  }
133  void cbCostmap(const costmap_cspace_msgs::CSpace3D::ConstPtr& msg)
134  {
135  costmap_ = msg;
136  std::cerr << test_scope_ << msg->header.stamp << " Costmap received." << std::endl;
137  }
138  void cbStatus(const planner_cspace_msgs::PlannerStatus::ConstPtr& msg)
139  {
140  if (!planner_status_ || planner_status_->status != msg->status || planner_status_->error != msg->error)
141  {
142  std::cerr << test_scope_ << msg->header.stamp << " Status updated." << msg << std::endl;
143  }
145  }
146  void cbPath(const nav_msgs::Path::ConstPtr& msg)
147  {
148  if (!path_ || path_->poses.size() != msg->poses.size())
149  {
150  if (msg->poses.size() == 0)
151  {
152  std::cerr << test_scope_ << msg->header.stamp << " Path updated. (empty)" << std::endl;
153  }
154  else
155  {
156  std::cerr
157  << test_scope_ << msg->header.stamp << " Path updated." << std::endl
158  << msg->poses.front().pose.position.x << ", " << msg->poses.front().pose.position.y << std::endl
159  << msg->poses.back().pose.position.x << ", " << msg->poses.back().pose.position.y << std::endl;
160  }
161  path_ = msg;
162  }
163  }
165  {
166  geometry_msgs::TransformStamped trans_tmp =
167  tfbuf_.lookupTransform("map", "base_link", now, ros::Duration(0.5));
169  tf2::fromMsg(trans_tmp, trans);
170  traj_.push_back(trans);
171  return trans;
172  }
174  {
175  double x_prev(0), y_prev(0);
176  tf2::Quaternion rot_prev(0, 0, 0, 1);
177 
178  std::cerr << test_scope_ << traj_.size() << " points recorded" << std::endl;
179 
180  for (const auto& t : traj_)
181  {
182  const double x = t.getOrigin().getX();
183  const double y = t.getOrigin().getY();
184  const tf2::Quaternion rot = t.getRotation();
185  const double yaw_diff = rot.angleShortestPath(rot_prev);
186  if (std::abs(x - x_prev) > 0.1 || std::abs(y - y_prev) > 0.1 || std::abs(yaw_diff) > 0.2)
187  {
188  x_prev = x;
189  y_prev = y;
190  rot_prev = rot;
191  std::cerr << t.stamp_ << " " << x << " " << y << " " << tf2::getYaw(rot) << std::endl;
192  }
193  }
194  }
195 
196  void waitForPlannerStatus(const std::string& name, const int expected_error)
197  {
198  ros::spinOnce();
199  ros::Duration(0.2).sleep();
200 
201  ros::Rate wait(10);
202  ros::Time deadline = ros::Time::now() + ros::Duration(10);
203  while (ros::ok())
204  {
205  ros::spinOnce();
206  wait.sleep();
207 
208  const ros::Time now = ros::Time::now();
209 
210  if (now > deadline)
211  {
213  FAIL()
214  << test_scope_ << "/" << name << ": Navigation timeout." << std::endl
215  << "now: " << now << std::endl
216  << "status: " << planner_status_ << " (expected: " << expected_error << ")";
217  }
218 
219  if (planner_status_->error == expected_error)
220  {
221  return;
222  }
223  }
224  }
225 };
226 
228 {
229  ros::spinOnce();
230  ros::Duration(0.2).sleep();
231 
232  nav_msgs::Path path;
233  path.poses.resize(1);
234  path.header.frame_id = "map";
235  path.poses[0].header.frame_id = path.header.frame_id;
236  path.poses[0].pose.position.x = 1.5;
237  path.poses[0].pose.position.y = 5.6;
238  path.poses[0].pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), 1.57));
239  pub_patrol_nodes_.publish(path);
240 
241  tf2::Transform goal;
242  tf2::fromMsg(path.poses.back().pose, goal);
243 
244  ros::Rate wait(10);
245  const ros::Time deadline = ros::Time::now() + ros::Duration(120);
246  while (ros::ok())
247  {
248  ros::spinOnce();
249  wait.sleep();
250 
251  const ros::Time now = ros::Time::now();
252 
253  if (now > deadline)
254  {
255  dumpRobotTrajectory();
256  FAIL()
257  << test_scope_ << "Navigation timeout." << std::endl
258  << "now: " << now << std::endl
259  << "status: " << planner_status_;
260  break;
261  }
262 
264  try
265  {
266  trans = lookupRobotTrans(now);
267  }
268  catch (tf2::TransformException& e)
269  {
270  std::cerr << test_scope_ << e.what() << std::endl;
271  continue;
272  }
273 
274  auto goal_rel = trans.inverse() * goal;
275  if (goal_rel.getOrigin().length() < 0.2 &&
276  std::abs(tf2::getYaw(goal_rel.getRotation())) < 0.2)
277  {
278  std::cerr << test_scope_ << "Navagation success." << std::endl;
279  ros::Duration(2.0).sleep();
280  return;
281  }
282  }
283  ASSERT_TRUE(false);
284 }
285 
286 int main(int argc, char** argv)
287 {
288  testing::InitGoogleTest(&argc, argv);
289  ros::init(argc, argv, "test_navigate_remember");
290 
291  return RUN_ALL_TESTS();
292 }
NavigateWithRememberUpdates::srv_forget_
ros::ServiceClient srv_forget_
Definition: test_navigate_remember.cpp:64
ros::ServiceClient::waitForExistence
bool waitForExistence(ros::Duration timeout=ros::Duration(-1))
NavigateWithRememberUpdates::sub_status_
ros::Subscriber sub_status_
Definition: test_navigate_remember.cpp:62
NavigateWithRememberUpdates::nh_
ros::NodeHandle nh_
Definition: test_navigate_remember.cpp:55
msg
msg
ros::Publisher
planner_status.h
ros::init
ROSCPP_DECL void init(const M_string &remappings, const std::string &name, uint32_t options=0)
NavigateWithRememberUpdates::SetUp
virtual void SetUp()
Definition: test_navigate_remember.cpp:85
tf2::getYaw
double getYaw(const A &a)
tf2::fromMsg
void fromMsg(const A &, B &b)
utils.h
NavigateWithRememberUpdates::pub_patrol_nodes_
ros::Publisher pub_patrol_nodes_
Definition: test_navigate_remember.cpp:66
ros.h
NavigateWithRememberUpdates::planner_status_
planner_cspace_msgs::PlannerStatus::ConstPtr planner_status_
Definition: test_navigate_remember.cpp:58
ros::NodeHandle::serviceClient
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
ros::spinOnce
ROSCPP_DECL void spinOnce()
tf2::Stamped
NavigateWithRememberUpdates::costmap_
costmap_cspace_msgs::CSpace3D::ConstPtr costmap_
Definition: test_navigate_remember.cpp:59
wait
void wait(int seconds)
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
ros::NodeHandle::advertise
Publisher advertise(AdvertiseOptions &ops)
NavigateWithRememberUpdates::NavigateWithRememberUpdates
NavigateWithRememberUpdates()
Definition: test_navigate_remember.cpp:70
ros::ok
ROSCPP_DECL bool ok()
tf2_ros::TransformListener
NavigateWithRememberUpdates::pub_initial_pose_
ros::Publisher pub_initial_pose_
Definition: test_navigate_remember.cpp:65
tf2_ros::Buffer::canTransform
virtual bool canTransform(const std::string &target_frame, const ros::Time &target_time, const std::string &source_frame, const ros::Time &source_time, const std::string &fixed_frame, const ros::Duration timeout, std::string *errstr=NULL) const
main
int main(int argc, char **argv)
Definition: test_navigate_remember.cpp:286
TEST_F
TEST_F(NavigateWithRememberUpdates, Navigate)
Definition: test_navigate_remember.cpp:227
NavigateWithRememberUpdates::dumpRobotTrajectory
void dumpRobotTrajectory()
Definition: test_navigate_remember.cpp:173
tf2::Transform
NavigateWithRememberUpdates::cbPath
void cbPath(const nav_msgs::Path::ConstPtr &msg)
Definition: test_navigate_remember.cpp:146
ros::ServiceClient
NavigateWithRememberUpdates::sub_costmap_
ros::Subscriber sub_costmap_
Definition: test_navigate_remember.cpp:61
tf2_ros::Buffer
NavigateWithRememberUpdates::cbCostmap
void cbCostmap(const costmap_cspace_msgs::CSpace3D::ConstPtr &msg)
Definition: test_navigate_remember.cpp:133
ros::NodeHandle::subscribe
Subscriber subscribe(const std::string &topic, uint32_t queue_size, const boost::function< void(C)> &callback, const VoidConstPtr &tracked_object=VoidConstPtr(), const TransportHints &transport_hints=TransportHints())
NavigateWithRememberUpdates::traj_
std::vector< tf2::Stamped< tf2::Transform > > traj_
Definition: test_navigate_remember.cpp:67
ros::Rate::sleep
bool sleep()
Navigate
Definition: test_navigate.cpp:55
transform_listener.h
NavigateWithRememberUpdates::path_
nav_msgs::Path::ConstPtr path_
Definition: test_navigate_remember.cpp:60
ros::Time
NavigateWithRememberUpdates::test_scope_
std::string test_scope_
Definition: test_navigate_remember.cpp:68
ros::ServiceClient::call
bool call(const MReq &req, MRes &resp, const std::string &service_md5sum)
NavigateWithRememberUpdates::lookupRobotTrans
tf2::Stamped< tf2::Transform > lookupRobotTrans(const ros::Time &now)
Definition: test_navigate_remember.cpp:164
NavigateWithRememberUpdates::tfl_
tf2_ros::TransformListener tfl_
Definition: test_navigate_remember.cpp:57
tf2::Quaternion
tf2_geometry_msgs.h
tf2::toMsg
B toMsg(const A &a)
ros::Rate
NavigateWithRememberUpdates::waitForPlannerStatus
void waitForPlannerStatus(const std::string &name, const int expected_error)
Definition: test_navigate_remember.cpp:196
ros::Duration::sleep
bool sleep() const
NavigateWithRememberUpdates::tfbuf_
tf2_ros::Buffer tfbuf_
Definition: test_navigate_remember.cpp:56
tf2::TransformException
NavigateWithRememberUpdates
Definition: test_navigate_remember.cpp:52
ros::Duration
tf2::Quaternion::angleShortestPath
tf2Scalar angleShortestPath(const Quaternion &q) const
t
geometry_msgs::TransformStamped t
tf2_ros::Buffer::lookupTransform
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const ros::Time &target_time, const std::string &source_frame, const ros::Time &source_time, const std::string &fixed_frame, const ros::Duration timeout) const
ros::NodeHandle
ros::Subscriber
NavigateWithRememberUpdates::sub_path_
ros::Subscriber sub_path_
Definition: test_navigate_remember.cpp:63
ros::Time::now
static Time now()
NavigateWithRememberUpdates::cbStatus
void cbStatus(const planner_cspace_msgs::PlannerStatus::ConstPtr &msg)
Definition: test_navigate_remember.cpp:138


planner_cspace
Author(s): Atsushi Watanabe
autogenerated on Fri May 16 2025 02:15:23