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