integrationtest_speed_observer_and_operation_mode.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 <sensor_msgs/JointState.h>
24 #include <std_srvs/SetBool.h>
26 
27 #include <pilz_testutils/async_test.h>
30 #include <prbt_hardware_support/FrameSpeeds.h>
31 #include <prbt_hardware_support/OperationModes.h>
32 
34 {
35 using ::testing::_;
36 using ::testing::AtLeast;
37 using ::testing::InSequence;
38 using ::testing::PrintToString;
39 using ::testing::Return;
40 using ::testing::SetArgReferee;
41 using namespace prbt_hardware_support;
42 
43 static const std::string FRAME_SPEEDS_TOPIC_NAME{ "/frame_speeds" };
44 static const std::string FAKE_CONTROLLER_JOINT_STATES_TOPIC_NAME{ "/fake_controller_joint_states" };
45 static const std::string OPERATION_MODE_TOPIC{ "operation_mode" };
46 static const std::string RUN_PERMITTED_SERVICE{ "run_permitted" };
47 static const std::string ADDITIONAL_FRAMES_PARAM_NAME{ "additional_frames" };
48 static const std::string SPEED_LIMIT_T1_PARAM_NAME{ "speed_limit_t1" };
49 static const std::string SPEED_LIMIT_AUTOMATIC_PARAM_NAME{ "speed_limit_automatic" };
50 
51 static const std::string BARRIER_STOP_HAPPENED{ "BARRIER_STOP_HAPPENED" };
52 static const std::string BARRIER_NO_STOP_HAPPENED{ "BARRIER_NO_STOP_HAPPENED" };
53 static const std::string BARRIER_NO_SVC_SUCESS{ "BARRIER_NO_SVC_SUCESS" };
54 static const std::string BARRIER_WAIT_OUT_STOP{ "BARRIER_WAIT_OUT_STOP" };
55 
56 static const double SQRT_2_HALF{ 1 / sqrt(2) };
57 static const double TEST_FREQUENCY{ 10 };
58 static const std::string TEST_WORLD_FRAME{ "world" };
59 
60 MATCHER_P(RunPermittedState, x, "RunPermitted state " + std::string(negation ? "is not" : "is") + ": " + PrintToString(x) + ".")
61 {
62  return arg.data == x;
63 }
64 
65 MATCHER_P(ContainsAllNames, names,
66  "Names" + PrintToString(names) + std::string(negation ? "are not" : "are") + " in message.")
67 {
68  for (auto& name : names)
69  {
70  bool found{ false };
71  for (auto& argn : arg->name)
72  {
73  if (argn.compare(name) == 0)
74  {
75  found = true;
76  }
77  }
78  if (!found)
79  {
80  return false;
81  }
82  }
83 
84  return true;
85 }
86 
87 class SpeedObserverIntegrationTest : public testing::Test, public testing::AsyncTest
88 {
89 public:
90  void SetUp() override;
91  void TearDown() override;
92 
93  MOCK_METHOD2(run_permitted_cb, bool(std_srvs::SetBool::Request& req, std_srvs::SetBool::Response& res));
94  MOCK_METHOD1(frame_speeds_cb, void(const FrameSpeeds::ConstPtr& msg));
95 
96  void publishTfAtSpeed(double speed, const std::string& frame);
97  void publishJointStatesAtSpeed(double v);
98  void stopJointStatePublisher();
99  void stopTfPublisher();
100  void publishOperationMode(OperationModes::_value_type omv);
101 
102 protected:
104  ros::NodeHandle pnh_{ "~" };
105  ros::AsyncSpinner spinner_{2};
110  std::vector<std::string> additional_frames_;
111  bool joint_publisher_running_{ false };
112  bool tf_publisher_running_{ false };
113  std_srvs::SetBool::Response run_permitted_res;
116 };
117 
119 {
120  spinner_.start();
121 
122  subscriber_ =
123  nh_.subscribe<FrameSpeeds>(FRAME_SPEEDS_TOPIC_NAME, 1, &SpeedObserverIntegrationTest::frame_speeds_cb, this);
124  fake_controller_joint_states_pub_ =
125  nh_.advertise<sensor_msgs::JointState>(FAKE_CONTROLLER_JOINT_STATES_TOPIC_NAME, 1);
126  operation_mode_pub_ = nh_.advertise<OperationModes>(OPERATION_MODE_TOPIC, 10, true);
127 
128  ASSERT_TRUE(pnh_.getParam(SPEED_LIMIT_T1_PARAM_NAME, speed_limit_t1_));
129  ASSERT_TRUE(pnh_.getParam(SPEED_LIMIT_AUTOMATIC_PARAM_NAME, speed_limit_automatic_));
130  ASSERT_TRUE(pnh_.getParam(ADDITIONAL_FRAMES_PARAM_NAME, additional_frames_));
131  ROS_DEBUG_STREAM("SetUp pnh:" << pnh_.getNamespace() << " nh:" << nh_.getNamespace());
132  for (auto& frame : additional_frames_)
133  {
134  ROS_DEBUG_STREAM("- " << frame);
135  }
136 
137  run_permitted_srv_ = nh_.advertiseService(RUN_PERMITTED_SERVICE, &SpeedObserverIntegrationTest::run_permitted_cb, this);
138 
139  run_permitted_res.success = true;
140  run_permitted_res.message = "testing ...";
141 
142  waitForNode("/speed_observer_node");
143  waitForNode("/operation_mode_setup_executor_node");
144 }
145 
147 {
148  joint_publisher_running_ = false;
149  spinner_.stop();
150  nh_.shutdown();
151 }
152 
153 void SpeedObserverIntegrationTest::publishTfAtSpeed(double speed, const std::string& frame)
154 {
156  ros::Rate r = ros::Rate(TEST_FREQUENCY * 3); // publishing definitely faster then observing
157  ros::Time start = ros::Time::now();
158  double t = 0;
159  tf_publisher_running_ = true;
160  while (tf_publisher_running_)
161  {
162  ros::Time current = ros::Time::now();
163  t = (current - start).toSec();
164  geometry_msgs::TransformStamped tranform_stamped_b;
165  tranform_stamped_b.header.stamp = current + ros::Duration(0.1); // avoid override by static_transform_publisher
166  tranform_stamped_b.header.frame_id = TEST_WORLD_FRAME;
167  tranform_stamped_b.child_frame_id = frame;
168  // rotation in a tilted circle to cover all axes
169  tranform_stamped_b.transform.translation.x = speed * cos(t);
170  tranform_stamped_b.transform.translation.y = speed * SQRT_2_HALF * -sin(t);
171  tranform_stamped_b.transform.translation.z = speed * SQRT_2_HALF * sin(t);
172  tranform_stamped_b.transform.rotation.w = 1;
173  br.sendTransform(tranform_stamped_b);
174 
175  if (tf_publisher_running_) // ending faster
176  r.sleep();
177  }
178 }
179 
180 void SpeedObserverIntegrationTest::publishOperationMode(OperationModes::_value_type omv)
181 {
182  OperationModes om;
183  om.value = omv;
184  om.time_stamp = ros::Time::now();
185  operation_mode_pub_.publish(om);
186 }
187 
189 {
190  sensor_msgs::JointState js;
191  js.name = { "testing_world-a" };
192  ros::Rate r = ros::Rate(TEST_FREQUENCY * 3); // publishing definitely faster
193  // then observing
194  ros::Time start = ros::Time::now();
195  double t = 0;
196  double t_zero = 0;
197  joint_publisher_running_ = true;
198  bool first_round{true};
199  while (joint_publisher_running_ & nh_.ok())
200  {
201  ros::Time current = ros::Time::now();
202  t = (current - start).toSec();
203  if (first_round)
204  {
205  t_zero = t;
206  first_round = false;
207  }
208  // Starting with max speed abruptly is not a relevant scenario and makes the test instable
209  // The following realizes half the speed in the first round and later constant full speed
210  js.position = { (t - 0.5*t_zero) * speed };
211 
212  fake_controller_joint_states_pub_.publish(js);
213  if (joint_publisher_running_ & nh_.ok()) // ending faster
214  r.sleep();
215  }
216 }
217 
219 {
220  joint_publisher_running_ = false;
221 }
222 
224 {
225  tf_publisher_running_ = false;
226 }
227 
254 {
255  /**********
256  * Step 1 *
257  **********/
258  ROS_DEBUG("Step 1");
259 
260  EXPECT_CALL(*this, run_permitted_cb(_, _)).Times(0);
261 
262  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
263  .WillOnce(Return())
264  .WillOnce(Return())
265  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_NO_STOP_HAPPENED))
266  .WillRepeatedly(Return());
267 
268  // Set OM to T1
269  publishOperationMode(OperationModes::T1);
270 
271  BARRIER({ BARRIER_NO_STOP_HAPPENED });
272 
273  /**********
274  * Step 2 *
275  **********/
276  ROS_DEBUG("Step 2");
277 
278  EXPECT_CALL(*this, run_permitted_cb(RunPermittedState(false), _))
279  .WillOnce(DoAll(SetArgReferee<1>(run_permitted_res), ACTION_OPEN_BARRIER(BARRIER_STOP_HAPPENED)))
280  .WillRepeatedly(DoAll(SetArgReferee<1>(run_permitted_res), Return(true)));
281 
282  std::thread pubisher_thread = std::thread(&SpeedObserverIntegrationTest::publishJointStatesAtSpeed, this,
283  speed_limit_t1_ + 0.01);
284  BARRIER({ BARRIER_STOP_HAPPENED });
285  stopJointStatePublisher();
286  pubisher_thread.join();
287 
288  // Wait for more iterations of the speed observer, enabling it to process the present change of tfs
289  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
290  .WillOnce(Return())
291  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_WAIT_OUT_STOP))
292  .WillRepeatedly(Return());
293 
294  BARRIER({ BARRIER_WAIT_OUT_STOP });
295 }
296 
324 TEST_F(SpeedObserverIntegrationTest, testOperationModeAuto)
325 {
326  /**********
327  * Step 1 *
328  **********/
329  ROS_DEBUG("Step 1");
330 
331  EXPECT_CALL(*this, run_permitted_cb(_, _)).Times(0);
332 
333  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
334  .WillOnce(Return())
335  .WillOnce(Return())
336  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_NO_STOP_HAPPENED))
337  .WillRepeatedly(Return());
338 
339  // Set OM to Auto
340  publishOperationMode(OperationModes::AUTO);
341  BARRIER({ BARRIER_NO_STOP_HAPPENED });
342 
343  /**********
344  * Step 2 *
345  **********/
346  ROS_DEBUG("Step 2");
347 
348  EXPECT_CALL(*this, run_permitted_cb(_, _)).Times(0);
349 
350  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
351  .WillOnce(Return())
352  .WillOnce(Return())
353  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_NO_STOP_HAPPENED))
354  .WillRepeatedly(Return());
355 
356  std::thread pubisher_thread = std::thread(&SpeedObserverIntegrationTest::publishJointStatesAtSpeed, this,
357  speed_limit_automatic_ - 0.01);
358  BARRIER({ BARRIER_NO_STOP_HAPPENED });
359 
360  /**********
361  * Step 3 *
362  **********/
363  ROS_DEBUG("Step 3");
364 
365  EXPECT_CALL(*this, run_permitted_cb(RunPermittedState(false), _))
366  .WillOnce(DoAll(SetArgReferee<1>(run_permitted_res), ACTION_OPEN_BARRIER(BARRIER_STOP_HAPPENED)))
367  .WillRepeatedly(DoAll(SetArgReferee<1>(run_permitted_res), Return(true)));
368 
369  publishOperationMode(OperationModes::T1);
370  BARRIER({ BARRIER_STOP_HAPPENED });
371  stopJointStatePublisher();
372  pubisher_thread.join();
373 
374  // Wait for more iterations of the speed observer, enabling it to process the present change of tfs
375  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
376  .WillOnce(Return())
377  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_WAIT_OUT_STOP))
378  .WillRepeatedly(Return());
379 
380  BARRIER({ BARRIER_WAIT_OUT_STOP });
381 }
382 
407 TEST_F(SpeedObserverIntegrationTest, testAdditionalTFTree)
408 {
409  ROS_DEBUG("Step 1");
410 
411  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
412  .WillRepeatedly(Return());
413 
414  EXPECT_CALL(*this, run_permitted_cb(RunPermittedState(false), _))
415  .WillOnce(DoAll(SetArgReferee<1>(run_permitted_res), ACTION_OPEN_BARRIER(BARRIER_STOP_HAPPENED)))
416  .WillRepeatedly(DoAll(SetArgReferee<1>(run_permitted_res), Return(true)));
417 
418  publishOperationMode(OperationModes::T1);
419 
420  std::thread pubisher_thread = std::thread(&SpeedObserverIntegrationTest::publishTfAtSpeed,
421  this,
422  speed_limit_t1_ + 0.01,
423  additional_frames_[0]);
424  BARRIER({ BARRIER_STOP_HAPPENED });
425  stopTfPublisher();
426  pubisher_thread.join();
427 
428  // Wait for more iterations of the speed observer, enabling it to process the present change of tfs
429  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
430  .WillOnce(Return())
431  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_WAIT_OUT_STOP))
432  .WillRepeatedly(Return());
433 
434  BARRIER({ BARRIER_WAIT_OUT_STOP });
435 }
436 
461 TEST_F(SpeedObserverIntegrationTest, testRunPermittedServiceNoSuccess)
462 {
463  /**********
464  * Step 1 *
465  **********/
466  ROS_DEBUG("Step 1");
467 
468  run_permitted_res.success = false;
469  EXPECT_CALL(*this, run_permitted_cb(RunPermittedState(false), _))
470  .WillOnce(DoAll(SetArgReferee<1>(run_permitted_res), ACTION_OPEN_BARRIER(BARRIER_NO_SVC_SUCESS)))
471  .WillRepeatedly(DoAll(SetArgReferee<1>(run_permitted_res), Return(true)));
472 
473  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
474  .WillOnce(Return())
475  .WillOnce(Return())
476  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_NO_STOP_HAPPENED))
477  .WillRepeatedly(Return());
478 
479  // Set OM to T1
480  publishOperationMode(OperationModes::T1);
481 
482  std::thread pubisher_thread = std::thread(&SpeedObserverIntegrationTest::publishJointStatesAtSpeed, this,
483  speed_limit_t1_ + 0.01);
484  BARRIER({ BARRIER_NO_SVC_SUCESS });
485  stopJointStatePublisher();
486  pubisher_thread.join();
487 
488  // Wait for more iterations of the speed observer, enabling it to process the present change of tfs
489  EXPECT_CALL(*this, frame_speeds_cb(ContainsAllNames(additional_frames_)))
490  .WillOnce(Return())
491  .WillOnce(ACTION_OPEN_BARRIER_VOID(BARRIER_WAIT_OUT_STOP))
492  .WillRepeatedly(Return());
493 
494  BARRIER({ BARRIER_WAIT_OUT_STOP });
495 }
496 
497 } // namespace speed_observer_test
498 
499 int main(int argc, char* argv[])
500 {
501  ros::init(argc, argv, "unittest_speed_observer");
502  ros::NodeHandle nh;
503 
504  testing::InitGoogleTest(&argc, argv);
505  return RUN_ALL_TESTS();
506 }
msg
void waitForNode(std::string node_name, double loop_frequency=10.0)
Blocks until a node defined by node_name comes up.
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.
geometry_msgs::TransformStamped t
int main(int argc, char *argv[])
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
void sendTransform(const geometry_msgs::TransformStamped &transform)
#define ROS_DEBUG_STREAM(args)
bool sleep()
MATCHER_P(RunPermittedState, x,"RunPermitted state "+std::string(negation?"is not":"is")+": "+PrintToString(x)+".")
static Time now()
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
#define ROS_DEBUG(...)


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