test_debug_outputs.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019, 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 <ros/ros.h>
31 
32 #include <nav_msgs/OccupancyGrid.h>
33 #include <nav_msgs/Path.h>
34 #include <neonavigation_metrics_msgs/Metrics.h>
35 #include <planner_cspace_msgs/PlannerStatus.h>
36 #include <sensor_msgs/PointCloud.h>
37 
38 #include <gtest/gtest.h>
39 
40 class DebugOutputsTest : public ::testing::Test
41 {
42 public:
45  , cnt_path_(0)
46  , cnt_hysteresis_(0)
47  , cnt_remembered_(0)
48  {
49  sub_status_ = nh_.subscribe("/planner_3d/status", 1, &DebugOutputsTest::cbStatus, this);
50  sub_metrics_ = nh_.subscribe("/planner_3d/metrics", 1, &DebugOutputsTest::cbMetrics, this);
51  sub_path_ = nh_.subscribe("path", 1, &DebugOutputsTest::cbPath, this);
52  sub_hysteresis_ = nh_.subscribe("/planner_3d/hysteresis_map", 1, &DebugOutputsTest::cbHysteresis, this);
53  sub_remembered_ = nh_.subscribe("/planner_3d/remembered_map", 1, &DebugOutputsTest::cbRemembered, this);
54  sub_distance_ = nh_.subscribe("/planner_3d/distance_map", 1, &DebugOutputsTest::cbDistance, this);
55 
56  // Wait planner
57  while (ros::ok())
58  {
59  ros::Duration(0.1).sleep();
60  ros::spinOnce();
61  if (cnt_planner_ready_ > 5 && cnt_path_ > 5)
62  break;
63  }
64  map_hysteresis_ = nullptr;
65  map_remembered_ = nullptr;
66  map_distance_ = nullptr;
67  cnt_hysteresis_ = 0;
68  cnt_remembered_ = 0;
69  cnt_distance_ = 0;
70 
71  // Wait receiving the messages
72  while (ros::ok())
73  {
74  ros::Duration(0.1).sleep();
75  ros::spinOnce();
76  // First hysteresis map doesn't have previous path information.
77  if (cnt_hysteresis_ > 2 && cnt_remembered_ > 2)
78  break;
79  }
80  }
81  void showMap(const nav_msgs::OccupancyGrid::ConstPtr& msg)
82  {
83  std::cerr << std::hex;
84  for (size_t y = 0; y < msg->info.height; ++y)
85  {
86  for (size_t x = 0; x < msg->info.width; ++x)
87  {
88  std::cerr << (msg->data[x + y * msg->info.width] / 11);
89  }
90  std::cerr << std::endl;
91  }
92  std::cerr << std::dec;
93 
94  std::streamsize ss = std::cerr.precision();
95  std::cerr << "path:" << std::endl
96  << std::setprecision(3);
97  for (const auto& p : path_->poses)
98  std::cerr << p.pose.position.x << ", " << p.pose.position.y << ", " << std::endl;
99 
100  std::cerr << std::setprecision(ss);
101  }
102 
103 protected:
104  void cbHysteresis(const nav_msgs::OccupancyGrid::ConstPtr& msg)
105  {
106  cnt_hysteresis_++;
107  map_hysteresis_ = msg;
108  }
109  void cbRemembered(const nav_msgs::OccupancyGrid::ConstPtr& msg)
110  {
111  cnt_remembered_++;
112  map_remembered_ = msg;
113  }
114  void cbDistance(const sensor_msgs::PointCloud::ConstPtr& msg)
115  {
116  cnt_distance_++;
117  map_distance_ = msg;
118  }
119  void cbStatus(const planner_cspace_msgs::PlannerStatus::ConstPtr& msg)
120  {
121  if (msg->error == planner_cspace_msgs::PlannerStatus::GOING_WELL &&
122  msg->status == planner_cspace_msgs::PlannerStatus::DOING)
124  }
125  void cbMetrics(const neonavigation_metrics_msgs::Metrics::ConstPtr& msg)
126  {
127  metrics_ = msg;
128  }
129  void cbPath(const nav_msgs::Path::ConstPtr& msg)
130  {
131  if (msg->poses.size() > 0)
132  {
133  ++cnt_path_;
134  path_ = msg;
135  }
136  }
137 
139  nav_msgs::OccupancyGrid::ConstPtr map_hysteresis_;
140  nav_msgs::OccupancyGrid::ConstPtr map_remembered_;
141  sensor_msgs::PointCloud::ConstPtr map_distance_;
142  nav_msgs::Path::ConstPtr path_;
143  neonavigation_metrics_msgs::Metrics::ConstPtr metrics_;
155 };
156 
158 {
159  int x;
160  int y;
161  char value;
162 };
163 
165 {
166  ASSERT_TRUE(static_cast<bool>(map_hysteresis_));
167 
168  // Robot is at (25, 4) and goal is at (10, 4)
169  const PositionAndValue data_set[] =
170  {
171  {25, 4, 0},
172  {20, 4, 0},
173  {15, 4, 0},
174  {10, 4, 0},
175  {25, 1, 100},
176  {20, 1, 100},
177  {15, 1, 100},
178  {10, 1, 100},
179  {25, 7, 100},
180  {20, 7, 100},
181  {15, 7, 100},
182  {10, 7, 100},
183  };
184  for (auto data : data_set)
185  {
186  const size_t addr = data.x + data.y * map_hysteresis_->info.width;
187  EXPECT_EQ(data.value, map_hysteresis_->data[addr]) << "x: " << data.x << ", y: " << data.y;
188  }
189  if (::testing::Test::HasFailure())
190  {
192  }
193 }
194 
196 {
197  ASSERT_TRUE(static_cast<bool>(map_remembered_));
198 
199  // Robot is at (25, 5) and obstacles are placed at
200  // (0, 0)-(31, 0) and (18, 10)-(31, 10).
201  // Costmap is expanded by 1 grid.
202  const PositionAndValue data_set[] =
203  {
204  {17, 0, 100}, // occupied
205  {17, 1, 100}, // expanded
206  {17, 2, 0}, // free
207  {17, 8, 0}, // free
208  {17, 9, 100}, // expanded
209  {17, 10, 100}, // occupied
210  };
211  for (auto data : data_set)
212  {
213  const size_t addr = data.x + data.y * map_remembered_->info.width;
214  EXPECT_EQ(data.value, map_remembered_->data[addr]) << "x: " << data.x << ", y: " << data.y;
215  }
216  if (::testing::Test::HasFailure())
217  {
219  }
220 }
221 
223 {
224  ASSERT_TRUE(static_cast<bool>(map_distance_));
225 
226  // Robot is at (2.5, 0.5) and goal is at (1.0, 0.5)
227  for (size_t i = 0; i < map_distance_->points.size(); ++i)
228  {
229  const float x = map_distance_->points[i].x;
230  const float y = map_distance_->points[i].y;
231  const float d = map_distance_->channels[0].values[i];
232  if (std::abs(y - 0.5) < 0.05)
233  {
234  const float dist_from_goal = std::abs(x - 1.0);
235  ASSERT_NEAR(dist_from_goal, d, 0.15);
236  }
237  }
238 }
239 
241 {
242  metrics_ = nullptr;
243  ros::Duration(0.5).sleep();
244  ros::spinOnce();
245  ASSERT_TRUE(metrics_);
246  ASSERT_NE(0u, metrics_->data.size());
247 }
248 
249 int main(int argc, char** argv)
250 {
251  testing::InitGoogleTest(&argc, argv);
252  ros::init(argc, argv, "test_debug_outputs");
253 
254  return RUN_ALL_TESTS();
255 }
d
ros::Subscriber sub_metrics_
nav_msgs::Path::ConstPtr path_
ros::Subscriber sub_remembered_
neonavigation_metrics_msgs::Metrics::ConstPtr metrics_
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void cbPath(const nav_msgs::Path::ConstPtr &msg)
nav_msgs::OccupancyGrid::ConstPtr map_remembered_
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void cbHysteresis(const nav_msgs::OccupancyGrid::ConstPtr &msg)
void cbStatus(const planner_cspace_msgs::PlannerStatus::ConstPtr &msg)
data
void cbDistance(const sensor_msgs::PointCloud::ConstPtr &msg)
TEST_F(DebugOutputsTest, Hysteresis)
ros::Subscriber sub_status_
ROSCPP_DECL bool ok()
nav_msgs::OccupancyGrid::ConstPtr map_hysteresis_
void cbMetrics(const neonavigation_metrics_msgs::Metrics::ConstPtr &msg)
sensor_msgs::PointCloud::ConstPtr map_distance_
void showMap(const nav_msgs::OccupancyGrid::ConstPtr &msg)
void cbRemembered(const nav_msgs::OccupancyGrid::ConstPtr &msg)
ros::Subscriber sub_distance_
bool sleep() const
int main(int argc, char **argv)
ROSCPP_DECL void spinOnce()
ros::Subscriber sub_path_
ros::Subscriber sub_hysteresis_


planner_cspace
Author(s): Atsushi Watanabe
autogenerated on Mon Jul 3 2023 02:39:06