unittest_speed_observer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Pilz GmbH & Co. KG
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13 
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <thread>
19 
20 #include <gmock/gmock.h>
21 
22 #include <ros/ros.h>
23 #include <std_srvs/SetBool.h>
25 
27 #include <pilz_testutils/async_test.h>
28 #include <prbt_hardware_support/FrameSpeeds.h>
29 #include <prbt_hardware_support/SetSpeedLimit.h>
32 
33 namespace speed_observer_test
34 {
35 using ::testing::_;
36 using ::testing::AllOf;
37 using ::testing::AtLeast;
38 using ::testing::AtMost;
39 using ::testing::DoAll;
40 using ::testing::Return;
41 using ::testing::SetArgReferee;
42 
43 using namespace prbt_hardware_support;
44 
45 static const std::string BARRIER_SLOW{ "BARRIER_SLOW" };
46 static const std::string BARRIER_FAST{ "BARRIER_FAST" };
47 static const std::string BARRIER_LIMIT{ "BARRIER_LIMIT" };
48 static const std::string BARRIER_LIMIT_LOW{ "BARRIER_LIMIT_LOW" };
49 
50 static const std::string FRAME_SPEEDS_TOPIC_NAME{ "/frame_speeds" };
51 static const std::string RUN_PERMITTED_SERVICE_NAME{ "/run_permitted" };
52 static const std::string TEST_BASE_FRAME{ "test_base" };
53 static const std::string TEST_FRAME_A{ "a" };
54 static const std::string TEST_FRAME_B{ "b" };
55 static constexpr double TEST_FREQUENCY{ 20 };
56 // Publishing definitely faster then observing
57 static constexpr double OBSERVER_FREQUENCY {3.0 * TEST_FREQUENCY};
58 static const double SQRT_2_HALF{ 1 / sqrt(2) };
59 
60 using ::testing::AllOf;
61 using ::testing::AtLeast;
62 using ::testing::AtMost;
63 
64 class SpeedObserverUnitTest : public testing::Test, public testing::AsyncTest
65 {
66 public:
67  void SetUp() override;
68 
69  MOCK_METHOD1(frame_speeds_cb_mock, void(const FrameSpeeds::ConstPtr& msg));
70  MOCK_METHOD2(stop_cb_mock, bool(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res));
71  void publishTfAtSpeed(const double v, const double observer_frequency = OBSERVER_FREQUENCY);
72  void stopTfPublisher();
73 
74 protected:
78  ros::NodeHandle pnh_{ "~" };
79  std::vector<std::string> additional_frames_;
80  bool tf_publisher_running_{ false };
81 };
82 
84 {
85  speed_subscriber_ =
86  nh_.subscribe<FrameSpeeds>(FRAME_SPEEDS_TOPIC_NAME, 1, &SpeedObserverUnitTest::frame_speeds_cb_mock, this);
87  stop_subscriber_ = nh_.advertiseService(RUN_PERMITTED_SERVICE_NAME, &SpeedObserverUnitTest::stop_cb_mock, this);
88 
90 }
91 
92 void SpeedObserverUnitTest::publishTfAtSpeed(const double speed, const double publish_frequency)
93 {
95  ros::Rate r = ros::Rate(publish_frequency);
96  ros::Time start = ros::Time::now();
97  double t = 0;
98  tf_publisher_running_ = true;
99  while (tf_publisher_running_)
100  {
101  ros::Time current = ros::Time::now();
102  t = (current - start).toSec();
103  // a has no speed
104  geometry_msgs::TransformStamped transform_stamped_a;
105  transform_stamped_a.header.stamp = current;
106  transform_stamped_a.header.frame_id = TEST_BASE_FRAME;
107  transform_stamped_a.child_frame_id = TEST_FRAME_A;
108  transform_stamped_a.transform.translation.x = 99.0;
109  transform_stamped_a.transform.translation.y = 99.0;
110  transform_stamped_a.transform.translation.z = 99.0;
111  transform_stamped_a.transform.rotation.w = 1;
112  // b has speed v
113  geometry_msgs::TransformStamped transform_stamped_b;
114  transform_stamped_b.header.stamp = current;
115  transform_stamped_b.header.frame_id = TEST_BASE_FRAME;
116  transform_stamped_b.child_frame_id = TEST_FRAME_B;
117  // rotation in a tilted circle to cover all axis
118  transform_stamped_b.transform.translation.x = speed * cos(t);
119  transform_stamped_b.transform.translation.y = speed * SQRT_2_HALF * -sin(t);
120  transform_stamped_b.transform.translation.z = speed * SQRT_2_HALF * sin(t);
121  transform_stamped_b.transform.rotation.w = 1;
122  br.sendTransform(transform_stamped_a);
123  br.sendTransform(transform_stamped_b);
124 
125  if (tf_publisher_running_) // ending faster
126  r.sleep();
127  }
128 }
129 
131 {
132  tf_publisher_running_ = false;
133 }
134 
135 using ::testing::PrintToString;
136 MATCHER_P(RunPermittedState, x, "RunPermitted state " + std::string(negation ? "is not" : "is") + ": " + PrintToString(x) + ".")
137 {
138  return arg.data == x;
139 }
140 
141 MATCHER_P2(NameAtI, i, name,
142  "Name at index " + PrintToString(i) + std::string(negation ? "is not" : "is") + ": " + name + ".")
143 {
144  return static_cast<size_t>(i) < arg->name.size() && arg->name.at(static_cast<size_t>(i)).compare(name) == 0;
145 }
146 
147 MATCHER_P2(SpeedAtIGe, i, x,
148  "Speed at index " + PrintToString(i) + std::string(negation ? "is not" : "is") + " greater or equal to" +
149  PrintToString(x) + ".")
150 {
151  return static_cast<size_t>(i) < arg->name.size() && arg->speed.at(static_cast<size_t>(i)) >= x;
152 }
153 
154 MATCHER_P2(SpeedAtILe, i, x,
155  "Speed at index " + PrintToString(i) + std::string(negation ? "is not" : "is") + " less or equal to" +
156  PrintToString(x) + ".")
157 {
158  return static_cast<size_t>(i) < arg->name.size() && arg->speed.at(static_cast<size_t>(i)) <= x;
159 }
160 
175 TEST_F(SpeedObserverUnitTest, testStartupAndTopic)
176 {
177  /**********
178  * Step 1 *
179  **********/
180  ROS_DEBUG_STREAM("Step 1");
181  std::thread pubisher_thread_slow = std::thread(&SpeedObserverUnitTest::publishTfAtSpeed, this, 0.24, OBSERVER_FREQUENCY);
182 
183  /**********
184  * Step 2 *
185  **********/
186  ROS_DEBUG_STREAM("Step 2");
187  EXPECT_CALL(*this, frame_speeds_cb_mock(AllOf(NameAtI(0, TEST_FRAME_A), NameAtI(1, TEST_FRAME_B),
188  SpeedAtILe(0, .1), SpeedAtILe(1, .26),
189  SpeedAtIGe(0, 0), SpeedAtIGe(1, 0))))
190  .WillOnce(Return())
191  .WillOnce(Return())
192  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_SLOW))
193  .WillRepeatedly(Return());
194 
195  EXPECT_CALL(*this, stop_cb_mock(_, _)).Times(0);
196 
197  std::string reference_frame{ TEST_BASE_FRAME };
198  std::vector<std::string> frames_to_observe{ TEST_FRAME_A, TEST_FRAME_B };
199  prbt_hardware_support::SpeedObserver observer(nh_, reference_frame, frames_to_observe);
200  std::thread observer_thread = std::thread(&SpeedObserver::startObserving,
201  &observer,
204  ROS_DEBUG_STREAM("thread started");
205 
206  BARRIER({ BARRIER_SLOW });
207  stopTfPublisher();
208  pubisher_thread_slow.join();
209 
210  /*************
211  * Tear Down *
212  *************/
213  ROS_DEBUG_STREAM("Tear Down");
214  observer.terminateNow();
215  observer_thread.join();
216 }
217 
235 TEST_F(SpeedObserverUnitTest, testTooHighSpeed)
236 {
237  /**********
238  * Step 1 *
239  **********/
240  ROS_DEBUG_STREAM("Step 1");
241  std::thread pubisher_thread_fast = std::thread(&SpeedObserverUnitTest::publishTfAtSpeed, this, 0.3, OBSERVER_FREQUENCY);
242 
243  /**********
244  * Step 2 *
245  **********/
246  ROS_DEBUG_STREAM("Step 2");
247  // we can once have a slow speed, when the observer starts:
248  EXPECT_CALL(*this, frame_speeds_cb_mock(AllOf(NameAtI(0, TEST_FRAME_A), NameAtI(1, TEST_FRAME_B),
249  SpeedAtILe(0, .1), SpeedAtILe(1, .32),
250  SpeedAtIGe(0, 0), SpeedAtIGe(1, 0))))
251  .Times(AtMost(1));
252  EXPECT_CALL(*this, frame_speeds_cb_mock(AllOf(NameAtI(0, TEST_FRAME_A), NameAtI(1, TEST_FRAME_B),
253  SpeedAtILe(0, .1), SpeedAtILe(1, .32),
254  SpeedAtIGe(0, 0), SpeedAtIGe(1, .28))));
255 
256  std_srvs::SetBool::Response run_permitted_srv_resp;
257  run_permitted_srv_resp.success = true;
258 
259  EXPECT_CALL(*this, stop_cb_mock(RunPermittedState(false), _))
260  .WillRepeatedly(DoAll(SetArgReferee<1>(run_permitted_srv_resp), ACTION_OPEN_BARRIER(BARRIER_FAST)));
261 
262  std::string reference_frame{ TEST_BASE_FRAME };
263  std::vector<std::string> frames_to_observe{ TEST_FRAME_A, TEST_FRAME_B };
264  prbt_hardware_support::SpeedObserver observer(nh_, reference_frame, frames_to_observe);
265  std::thread observer_thread = std::thread(&SpeedObserver::startObserving,
266  &observer,
269  ROS_DEBUG_STREAM("thread started");
270 
271  BARRIER({ BARRIER_FAST });
272  stopTfPublisher();
273  pubisher_thread_fast.join();
274 
275  /*************
276  * Tear Down *
277  *************/
278  ROS_DEBUG_STREAM("Tear Down");
279  observer.terminateNow();
280  observer_thread.join();
281 }
282 
305 TEST_F(SpeedObserverUnitTest, testSetSpeedLimit)
306 {
307  /**********
308  * Step 1 *
309  **********/
310  ROS_DEBUG_STREAM("Step 1");
311  std::thread pubisher_thread_fast = std::thread(&SpeedObserverUnitTest::publishTfAtSpeed, this, 0.3, OBSERVER_FREQUENCY);
312 
313  /**********
314  * Step 2 *
315  **********/
316  ROS_DEBUG_STREAM("Step 2");
317 
318  // we can once have a slow speed, when the observer starts:
319  EXPECT_CALL(*this, frame_speeds_cb_mock(AllOf(NameAtI(0, TEST_FRAME_A), NameAtI(1, TEST_FRAME_B),
320  SpeedAtILe(0, .1), SpeedAtILe(1, .32),
321  SpeedAtIGe(0, 0), SpeedAtIGe(1, 0))))
322  .Times(AtMost(1));
323  EXPECT_CALL(*this, frame_speeds_cb_mock(AllOf(NameAtI(0, TEST_FRAME_A), NameAtI(1, TEST_FRAME_B),
324  SpeedAtILe(0, .1), SpeedAtILe(1, .32),
325  SpeedAtIGe(0, 0), SpeedAtIGe(1, .28))))
326  .WillOnce(Return())
327  .WillOnce(Return())
328  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_LIMIT))
329  .WillRepeatedly(Return());
330  EXPECT_CALL(*this, stop_cb_mock(_, _)).Times(0);
331 
332  std::string reference_frame{ TEST_BASE_FRAME };
333  std::vector<std::string> frames_to_observe{ TEST_FRAME_A, TEST_FRAME_B };
334  prbt_hardware_support::SpeedObserver observer(nh_, reference_frame, frames_to_observe);
335  SetSpeedLimitRequest req = SetSpeedLimitRequest();
336  SetSpeedLimitResponse res = SetSpeedLimitResponse();
337  req.speed_limit = .4;
338  observer.setSpeedLimitCb(req, res);
339  std::thread observer_thread = std::thread(&SpeedObserver::startObserving,
340  &observer,
343  ROS_DEBUG_STREAM("thread started");
344 
345  BARRIER({ BARRIER_LIMIT });
346 
347  /**********
348  * Step 3 *
349  **********/
350  ROS_DEBUG_STREAM("Step 3");
351  std_srvs::SetBool::Response run_permitted_srv_resp;
352  run_permitted_srv_resp.success = true;
353  EXPECT_CALL(*this, stop_cb_mock(RunPermittedState(false), _))
354  .WillRepeatedly(DoAll(SetArgReferee<1>(run_permitted_srv_resp), ACTION_OPEN_BARRIER(BARRIER_LIMIT_LOW)));
355 
356  req.speed_limit = .2;
357  observer.setSpeedLimitCb(req, res);
358 
359  BARRIER({ BARRIER_LIMIT_LOW });
360 
361  /*************
362  * Tear Down *
363  *************/
364  ROS_DEBUG_STREAM("Tear Down");
365  stopTfPublisher();
366  pubisher_thread_fast.join();
367  observer.terminateNow();
368  observer_thread.join();
369 }
370 
386 {
387  /**********
388  * Step 1 *
389  **********/
390  ROS_DEBUG_STREAM("Step 1");
391  std::string reference_frame{ TEST_BASE_FRAME };
392  std::vector<std::string> frames_to_observe{ TEST_FRAME_A };
393  prbt_hardware_support::SpeedObserver observer(nh_, reference_frame, frames_to_observe);
394 
395  EXPECT_THROW(observer.startObserving(TEST_FREQUENCY), std::runtime_error);
396 }
397 
409 TEST_F(SpeedObserverUnitTest, testFailingRunPermittedServiceCase)
410 {
411  // ++++++++++++++++++++++++
412  ROS_DEBUG_STREAM("Step 1");
413  // ++++++++++++++++++++++++
414  std::thread pubisher_thread_fast = std::thread(&SpeedObserverUnitTest::publishTfAtSpeed, this, 0.3, OBSERVER_FREQUENCY);
415 
416  // ++++++++++++++++++++++++
417  ROS_DEBUG_STREAM("Step 2");
418  // ++++++++++++++++++++++++
419  EXPECT_CALL(*this, stop_cb_mock(RunPermittedState(false), _))
420  .Times(1)
421  .WillOnce(DoAll(ACTION_OPEN_BARRIER_VOID(BARRIER_FAST), Return(false)));
422 
423  std::string reference_frame{ TEST_BASE_FRAME };
424  std::vector<std::string> frames_to_observe{ TEST_FRAME_A, TEST_FRAME_B };
425  prbt_hardware_support::SpeedObserver observer(nh_, reference_frame, frames_to_observe);
426  std::thread observer_thread = std::thread(&SpeedObserver::startObserving,
427  &observer,
430  ROS_DEBUG_STREAM("thread started");
431 
432  BARRIER({ BARRIER_FAST });
433 
434  // ++++++++++++++++++++++++
435  ROS_DEBUG_STREAM("Tear Down");
436  // ++++++++++++++++++++++++
437  stopTfPublisher();
438  pubisher_thread_fast.join();
439  observer.terminateNow();
440  observer_thread.join();
441 }
442 
455 TEST_F(SpeedObserverUnitTest, testSlowTfPublishing)
456 {
457  // ++++++++++++++++++++++++
458  ROS_DEBUG_STREAM("Step 1");
459  // ++++++++++++++++++++++++
460  std::thread pubisher_thread_fast = std::thread(&SpeedObserverUnitTest::publishTfAtSpeed, this, 0.24, 0.1*TEST_FREQUENCY);
461 
462  // ++++++++++++++++++++++++
463  ROS_DEBUG_STREAM("Step 2");
464  // ++++++++++++++++++++++++
465  EXPECT_CALL(*this, stop_cb_mock(RunPermittedState(false), _))
466  .Times(AtLeast(1))
467  .WillRepeatedly(DoAll(ACTION_OPEN_BARRIER_VOID(BARRIER_FAST), Return(true)));
468 
469  std::string reference_frame{ TEST_BASE_FRAME };
470  std::vector<std::string> frames_to_observe{ TEST_FRAME_A, TEST_FRAME_B };
471  prbt_hardware_support::SpeedObserver observer(nh_, reference_frame, frames_to_observe);
472  std::thread observer_thread = std::thread(&SpeedObserver::startObserving,
473  &observer,
476  ROS_DEBUG_STREAM("thread started");
477 
478  BARRIER({ BARRIER_FAST });
479 
480  // ++++++++++++++++++++++++
481  ROS_DEBUG_STREAM("Tear Down");
482  // ++++++++++++++++++++++++
483  stopTfPublisher();
484  pubisher_thread_fast.join();
485  observer.terminateNow();
486  observer_thread.join();
487 }
488 
489 } // namespace speed_observer_test
490 
491 int main(int argc, char* argv[])
492 {
493  ros::init(argc, argv, "unittest_speed_observer");
494  ros::NodeHandle nh;
495 
497  spinner.start();
498 
499  testing::InitGoogleTest(&argc, argv);
500  return RUN_ALL_TESTS();
501 }
void publishTfAtSpeed(const double v, const double observer_frequency=OBSERVER_FREQUENCY)
msg
void terminateNow()
This method will terminate the observation cycle started by startObserving().
static const std::string TEST_BASE_FRAME
static const std::string BARRIER_LIMIT
static const std::string BARRIER_LIMIT_LOW
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
TEST_F(SpeedObserverIntegrationTest, testOperationModeT1)
Tests speed observer with operation mode T1.
int main(int argc, char *argv[])
geometry_msgs::TransformStamped t
void spinner()
static constexpr double OBSERVER_FREQUENCY
static const std::string RUN_PERMITTED_SERVICE_NAME
static void waitForService(const std::string service_name, const double retry_timeout=DEFAULT_RETRY_TIMEOUT, const double msg_output_period=DEFAULT_MSG_OUTPUT_PERIOD)
static const std::string BARRIER_SLOW
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
bool setSpeedLimitCb(SetSpeedLimit::Request &req, SetSpeedLimit::Response &res)
Callback for service to set the currently active speed limit.
static const std::string BARRIER_FAST
static const std::string TEST_FRAME_A
void sendTransform(const geometry_msgs::TransformStamped &transform)
#define ROS_DEBUG_STREAM(args)
bool sleep()
static constexpr unsigned int DEFAULT_ALLOWED_MISSED_CALCULATIONS
Allowed number of missed calculations. If it is exceeded a Stop1 is triggered.
static const std::string TEST_FRAME_B
MATCHER_P(RunPermittedState, x,"RunPermitted state "+std::string(negation?"is not":"is")+": "+PrintToString(x)+".")
static Time now()
MATCHER_P2(NameAtI, i, name,"Name at index "+PrintToString(i)+std::string(negation?"is not":"is")+": "+name+".")
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
void startObserving(const double frequency, const unsigned int allowed_missed_calculations=DEFAULT_ALLOWED_MISSED_CALCULATIONS)
Starts the observation cycle. The function blocks until ros shuts down.
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)


prbt_hardware_support
Author(s):
autogenerated on Tue Feb 2 2021 03:50:17