36 #include <condition_variable>
37 #include <gmock/gmock.h>
38 #include <gtest/gtest.h>
45 #include <actionlib/client/simple_action_client.h>
50 #include <moveit_msgs/Constraints.h>
51 #include <moveit_msgs/GetMotionPlan.h>
52 #include <moveit_msgs/JointConstraint.h>
61 #include <moveit_msgs/MoveGroupSequenceAction.h>
63 static constexpr
int WAIT_FOR_ACTION_SERVER_TIME_OUT{ 10 };
82 void SetUp()
override;
86 MOCK_METHOD1(feedback_callback,
void(
const moveit_msgs::msg::MoveGroupSequenceFeedbackConstPtr& feedback));
87 MOCK_METHOD2(done_callback,
void(
const actionlib::SimpleClientGoalState& state,
88 const moveit_msgs::msg::MoveGroupSequenceResultConstPtr& result));
91 ros::NodeHandle ph_{
"~" };
92 actionlib::SimpleActionClient<moveit_msgs::msg::MoveGroupSequenceAction> ac_{ ph_,
SEQUENCE_ACTION_NAME,
true };
93 std::shared_ptr<moveit::planning_interface::MoveGroupInterface>
move_group_;
112 ph_.param<std::string>(
GROUP_NAME, group_name_,
"manipulator");
114 robot_model_ = model_loader_.getModel();
116 data_loader_ = std::make_unique<XmlTestdataLoader>(test_data_file_name_, robot_model_);
117 ASSERT_NE(
nullptr, data_loader_) <<
"Failed to load test data by provider.";
120 ASSERT_TRUE(ac_.waitForServer(ros::Duration(WAIT_FOR_ACTION_SERVER_TIME_OUT))) <<
"Action server is not active.";
123 start_config = data_loader_->getJoints(
"ZeroPose", group_name_);
124 robot_state::RobotState robot_state{ start_config.toRobotState() };
126 move_group_ = std::make_shared<moveit::planning_interface::MoveGroupInterface>(start_config.getGroupName());
127 move_group_->setPlannerId(
"PTP");
128 move_group_->setGoalTolerance(joint_position_tolerance_);
129 move_group_->setJointValueTarget(robot_state);
133 isAtExpectedPosition(robot_state, *(move_group_->getCurrentState()), joint_position_tolerance_, group_name_));
149 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
151 ac_.sendGoalAndWait(seq_goal);
152 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
153 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
154 <<
"Execution of sequence failed.";
155 EXPECT_TRUE(res->response.planned_trajectories.empty());
172 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
176 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
177 seq_goal.request = seq.toRequest();
179 ac_.sendGoalAndWait(seq_goal);
180 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
181 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::INVALID_GROUP_NAME)
182 <<
"Incorrect error code.";
183 EXPECT_TRUE(res->response.planned_trajectories.empty());
200 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
203 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
204 seq_goal.request = seq.toRequest();
206 ac_.sendGoalAndWait(seq_goal);
208 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
209 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN)
210 <<
"Incorrect error code.";
211 EXPECT_TRUE(res->response.planned_trajectories.empty());
229 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
232 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
233 seq_goal.request = seq.toRequest();
235 ac_.sendGoalAndWait(seq_goal);
237 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
238 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN)
239 <<
"Incorrect error code";
240 EXPECT_TRUE(res->response.planned_trajectories.empty());
258 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
259 seq.
erase(2, seq.size());
260 seq.setBlendRadius(0, 10 * seq.getBlendRadius(seq.size() - 2));
262 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
263 seq_goal.request = seq.toRequest();
265 ac_.sendGoalAndWait(seq_goal);
267 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
268 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::FAILURE) <<
"Incorrect error code";
269 EXPECT_TRUE(res->response.planned_trajectories.empty());
288 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
292 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
293 seq_goal.request = seq.toRequest();
295 ac_.sendGoalAndWait(seq_goal);
296 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
297 EXPECT_NE(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS) <<
"Incorrect error code.";
298 EXPECT_TRUE(res->response.planned_trajectories.empty());
314 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
321 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
322 seq_goal.request = seq.toRequest();
324 ac_.sendGoalAndWait(seq_goal);
325 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
326 EXPECT_NE(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS) <<
"Incorrect error code.";
327 EXPECT_TRUE(res->response.planned_trajectories.empty());
335 return arg->state == state;
339 return arg->response.error_code.val == moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
343 return !arg->response.planned_trajectories.empty();
361 using ::testing::AllOf;
362 using ::testing::AtLeast;
363 using ::testing::InSequence;
365 namespace ph = std::placeholders;
367 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
369 seq.
erase(2, seq.size());
371 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
372 seq_goal.request = seq.toRequest();
376 EXPECT_CALL(*
this, active_callback()).Times(1).RetiresOnSaturation();
378 EXPECT_CALL(*
this, done_callback(_, AllOf(IsResultSuccess(), IsResultNotEmpty())))
381 .RetiresOnSaturation();
387 EXPECT_CALL(*
this, feedback_callback(FeedbackStateEq(
"PLANNING"))).Times(AtLeast(1));
388 EXPECT_CALL(*
this, feedback_callback(FeedbackStateEq(
"MONITOR"))).Times(AtLeast(1));
389 EXPECT_CALL(*
this, feedback_callback(FeedbackStateEq(
"IDLE")))
392 .RetiresOnSaturation();
397 seq_goal, [
this](
const auto& state,
const auto& result) { done_callback(state, result); },
398 [
this] { active_callback(); }, [
this](
const auto& feedback) { feedback_callback(feedback); });
417 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
419 seq.
erase(2, seq.size());
421 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
422 seq_goal.planning_options.plan_only =
true;
423 seq_goal.request = seq.toRequest();
425 ac_.sendGoalAndWait(seq_goal);
426 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
427 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS) <<
"Sequence execution failed.";
428 EXPECT_FALSE(res->response.planned_trajectories.empty()) <<
"Planned trajectory is empty";
430 ASSERT_TRUE(
isAtExpectedPosition(*(move_group_->getCurrentState()), start_config.toRobotState(),
431 joint_position_tolerance_, group_name_))
432 <<
"Robot did move although \"PlanOnly\" flag set.";
449 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
451 seq.
erase(2, seq.size());
454 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
455 seq_goal.planning_options.plan_only =
true;
456 seq_goal.request = seq.toRequest();
458 seq_goal.planning_options.planning_scene_diff.robot_state.is_diff =
true;
460 ac_.sendGoalAndWait(seq_goal);
461 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
462 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
463 <<
"Execution of sequence failed.";
464 EXPECT_FALSE(res->response.planned_trajectories.empty()) <<
"Planned trajectory is empty";
466 ASSERT_TRUE(
isAtExpectedPosition(*(move_group_->getCurrentState()), start_config.toRobotState(),
467 joint_position_tolerance_, group_name_))
468 <<
"Robot did move although \"PlanOnly\" flag set.";
486 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
489 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
490 seq_goal.request = seq.toRequest();
491 seq_goal.planning_options.plan_only =
true;
493 ac_.sendGoalAndWait(seq_goal);
495 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
496 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::INVALID_MOTION_PLAN)
497 <<
"Incorrect error code.";
498 EXPECT_TRUE(res->response.planned_trajectories.empty());
515 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
517 seq.
erase(2, seq.size());
520 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
521 seq_goal.request = seq.toRequest();
523 seq_goal.planning_options.planning_scene_diff.robot_state.is_diff =
true;
525 ac_.sendGoalAndWait(seq_goal);
526 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
527 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
528 <<
"Execution of sequence failed.";
529 EXPECT_FALSE(res->response.planned_trajectories.empty()) <<
"Planned trajectory is empty";
545 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
546 moveit_msgs::msg::MotionSequenceRequest req{ seq.
toRequest() };
549 size_t n{ req.items.size() };
550 for (
size_t i = 0; i < n; ++i)
552 moveit_msgs::msg::MotionSequenceItem item{ req.items.at(i) };
557 item.req.start_state = moveit_msgs::msg::RobotState();
559 req.items.push_back(item);
562 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
563 seq_goal.request = req;
565 ac_.sendGoalAndWait(seq_goal);
566 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
567 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS) <<
"Incorrect error code.";
568 EXPECT_FALSE(res->response.planned_trajectories.empty()) <<
"Planned trajectory is empty";
585 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
589 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
590 seq_goal.request = seq.toRequest();
592 ac_.sendGoalAndWait(seq_goal);
593 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
594 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS);
595 EXPECT_FALSE(res->response.planned_trajectories.empty()) <<
"Planned trajectory is empty";
612 Sequence seq{ data_loader_->getSequence(
"ComplexSequence") };
614 moveit_msgs::msg::MoveGroupSequenceGoal seq_goal;
617 ac_.sendGoalAndWait(seq_goal);
618 moveit_msgs::msg::MoveGroupSequenceResultConstPtr res = ac_.getResult();
619 EXPECT_EQ(res->response.error_code.val, moveit_msgs::msg::MoveItErrorCodes::SUCCESS);
620 EXPECT_FALSE(res->response.planned_trajectories.empty()) <<
"Planned trajectory is empty";
623 int main(
int argc,
char** argv)
625 ros::init(argc, argv,
"integrationtest_sequence_action_capability");
628 ros::AsyncSpinner spinner{ 1 };
631 testing::InitGoogleTest(&argc, argv);
632 return RUN_ALL_TESTS();
#define ACTION_OPEN_BARRIER_VOID(str)
robot_model_loader::RobotModelLoader model_loader_
MOCK_METHOD1(feedback_callback, void(const moveit_msgs::msg::MoveGroupSequenceFeedbackConstPtr &feedback))
robot_model::RobotModelPtr robot_model_
JointConfiguration start_config
The configuration at which the robot stays at the beginning of each test.
MOCK_METHOD0(active_callback, void())
std::shared_ptr< moveit::planning_interface::MoveGroupInterface > move_group_
double joint_position_tolerance_
std::string test_data_file_name_
TestdataLoaderUPtr data_loader_
MOCK_METHOD2(done_callback, void(const actionlib::SimpleClientGoalState &state, const moveit_msgs::msg::MoveGroupSequenceResultConstPtr &result))
GoalType & getGoalConfiguration()
Data class storing all information regarding a Circ command.
Class to define a robot configuration in space with the help of joint values.
Base class for commands storing all general information of a command.
void setPlanningGroup(const std::string &planning_group)
Data class storing all information regarding a Sequence command.
void setAllBlendRadiiToZero()
void setBlendRadius(const size_t index_cmd, const double blend_radius)
void erase(const size_t start, const size_t end)
Deletes all commands from index 'start' to index 'end'.
moveit_msgs::msg::MotionSequenceRequest toRequest() const
Test class that allows the handling of asynchronous test objects.
MATCHER_P(FeedbackStateEq, state, "")
const std::string JOINT_POSITION_TOLERANCE("joint_position_tolerance")
int main(int argc, char **argv)
TEST_F(IntegrationTestSequenceAction, TestSendingOfEmptySequence)
Test behavior of sequence action server when empty sequence is sent.
const std::string GROUP_NAME("group_name")
MATCHER(IsResultSuccess, "")
const std::string SERVER_IDLE_EVENT
const std::string GOAL_SUCCEEDED_EVENT
const std::string TEST_DATA_FILE_NAME("testdata_file_name")
const std::string SEQUENCE_ACTION_NAME("/sequence_move_group")
::testing::AssertionResult isAtExpectedPosition(const moveit::core::RobotState &expected, const moveit::core::RobotState &actual, const double epsilon, const std::string &group_name="")
std::unique_ptr< TestdataLoader > TestdataLoaderUPtr