moveit2
The MoveIt Motion Planning Framework for ROS 2.
unittest_trajectory_blender_transition_window.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2018 Pilz GmbH & Co. KG
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Pilz GmbH & Co. KG nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include <memory>
36 
37 #include <gtest/gtest.h>
38 
43 #include <tf2_eigen/tf2_eigen.hpp>
44 #include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
45 
49 
55 #include "test_utils.h"
56 
57 #include <rclcpp/rclcpp.hpp>
58 
59 using namespace pilz_industrial_motion_planner;
61 
62 static const std::string PARAM_NAMESPACE_LIMITS = "robot_description_planning";
63 class TrajectoryBlenderTransitionWindowTest : public testing::Test
64 {
65 protected:
70  void SetUp() override
71  {
72  rclcpp::NodeOptions node_options;
73  node_options.automatically_declare_parameters_from_overrides(true);
74  node_ = rclcpp::Node::make_shared("unittest_trajectory_blender_transition_window", node_options);
75 
76  // load robot model
77  rm_loader_ = std::make_unique<robot_model_loader::RobotModelLoader>(node_);
78  robot_model_ = rm_loader_->getModel();
79  ASSERT_TRUE(bool(robot_model_)) << "Failed to load robot model";
80  planning_scene_ = std::make_shared<planning_scene::PlanningScene>(robot_model_);
81 
82  // get parameters
83  ASSERT_TRUE(node_->has_parameter("planning_group"));
84  node_->get_parameter<std::string>("planning_group", planning_group_);
85  ASSERT_TRUE(node_->has_parameter("target_link"));
86  node_->get_parameter<std::string>("target_link", target_link_);
87  ASSERT_TRUE(node_->has_parameter("cartesian_velocity_tolerance"));
88  node_->get_parameter<double>("cartesian_velocity_tolerance", cartesian_velocity_tolerance_);
89  ASSERT_TRUE(node_->has_parameter("cartesian_angular_velocity_tolerance"));
90  node_->get_parameter<double>("cartesian_angular_velocity_tolerance", cartesian_angular_velocity_tolerance_);
91  ASSERT_TRUE(node_->has_parameter("joint_velocity_tolerance"));
92  node_->get_parameter<double>("joint_velocity_tolerance", joint_velocity_tolerance_);
93  ASSERT_TRUE(node_->has_parameter("joint_acceleration_tolerance"));
94  node_->get_parameter<double>("joint_acceleration_tolerance", joint_acceleration_tolerance_);
95  ASSERT_TRUE(node_->has_parameter("sampling_time"));
96  node_->get_parameter<double>("sampling_time", sampling_time_);
97  ASSERT_TRUE(node_->has_parameter("testdata_file_name"));
98  node_->get_parameter<std::string>("testdata_file_name", test_data_file_name_);
99 
100  // load the test data provider
101  data_loader_ = std::make_unique<XmlTestdataLoader>(test_data_file_name_, robot_model_);
102  ASSERT_NE(nullptr, data_loader_) << "Failed to load test data by provider.";
103 
104  // check robot model
105  testutils::checkRobotModel(robot_model_, planning_group_, target_link_);
106 
107  // create the limits container
110  node_, PARAM_NAMESPACE_LIMITS, robot_model_->getActiveJointModels());
111 
112  cartesian_limits::Params cart_limits;
113  cart_limits.max_trans_vel = 1 * M_PI;
114  cart_limits.max_trans_acc = 2;
115  cart_limits.max_trans_dec = 2;
116  cart_limits.max_rot_vel = 1;
117 
118  planner_limits_.setJointLimits(joint_limits);
119  planner_limits_.setCartesianLimits(cart_limits);
120 
121  // initialize trajectory generators and blender
122  lin_generator_ = std::make_unique<TrajectoryGeneratorLIN>(robot_model_, planner_limits_, planning_group_);
123  ASSERT_NE(nullptr, lin_generator_) << "failed to create LIN trajectory generator";
124  blender_ = std::make_unique<TrajectoryBlenderTransitionWindow>(planner_limits_);
125  ASSERT_NE(nullptr, blender_) << "failed to create trajectory blender";
126  }
127 
128  void TearDown() override
129  {
130  robot_model_.reset();
131  }
132 
136  std::vector<planning_interface::MotionPlanResponse> generateLinTrajs(const Sequence& seq, size_t num_cmds)
137  {
138  std::vector<planning_interface::MotionPlanResponse> responses(num_cmds);
139  for (size_t index = 0; index < num_cmds; ++index)
140  {
141  planning_interface::MotionPlanRequest req{ seq.getCmd<LinCart>(index).toRequest() };
142  // Set start state of request to end state of previous trajectory (except
143  // for first)
144  if (index > 0)
145  {
146  moveit::core::robotStateToRobotStateMsg(responses[index - 1].trajectory->getLastWayPoint(), req.start_state);
147  }
148  // generate trajectory
150  lin_generator_->generate(planning_scene_, req, resp, sampling_time_);
151  if (resp.error_code.val != moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
152  {
153  std::runtime_error("Failed to generate trajectory.");
154  }
155  responses.at(index) = resp;
156  }
157  return responses;
158  }
159 
160 protected:
161  // ros stuff
162  rclcpp::Node::SharedPtr node_;
163  moveit::core::RobotModelConstPtr robot_model_;
164  std::unique_ptr<robot_model_loader::RobotModelLoader> rm_loader_;
165  planning_scene::PlanningSceneConstPtr planning_scene_;
166 
167  std::unique_ptr<TrajectoryGenerator> lin_generator_;
168  std::unique_ptr<TrajectoryBlenderTransitionWindow> blender_;
169 
170  // test parameters from parameter server
171  std::string planning_group_, target_link_;
172  double cartesian_velocity_tolerance_, cartesian_angular_velocity_tolerance_, joint_velocity_tolerance_,
175 
176  std::string test_data_file_name_;
178 };
179 
192 {
193  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
194 
195  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
196 
199 
200  blend_req.group_name = "invalid_group_name";
201  blend_req.link_name = target_link_;
202  blend_req.first_trajectory = res.at(0).trajectory;
203  blend_req.second_trajectory = res.at(1).trajectory;
204 
205  blend_req.blend_radius = seq.getBlendRadius(0);
206  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
207 }
208 
221 {
222  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
223 
224  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
225 
228 
229  blend_req.group_name = planning_group_;
230  blend_req.link_name = "invalid_target_link";
231  blend_req.first_trajectory = res.at(0).trajectory;
232  blend_req.second_trajectory = res.at(1).trajectory;
233 
234  blend_req.blend_radius = seq.getBlendRadius(0);
235  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
236 }
237 
251 {
252  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
253 
254  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
255 
258 
259  blend_req.group_name = planning_group_;
260  blend_req.link_name = target_link_;
261  blend_req.first_trajectory = res.at(0).trajectory;
262  blend_req.second_trajectory = res.at(1).trajectory;
263 
264  blend_req.blend_radius = -0.1;
265  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
266 }
267 
280 {
281  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
282 
283  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
284 
287 
288  blend_req.group_name = planning_group_;
289  blend_req.link_name = target_link_;
290  blend_req.first_trajectory = res.at(0).trajectory;
291  blend_req.second_trajectory = res.at(1).trajectory;
292 
293  blend_req.blend_radius = 0.;
294  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
295 }
296 
309 TEST_F(TrajectoryBlenderTransitionWindowTest, testDifferentSamplingTimes)
310 {
311  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
312 
313  // perform lin trajectory generation and modify sampling time
314  std::size_t num_cmds{ 2 };
315  std::vector<planning_interface::MotionPlanResponse> responses(num_cmds);
316 
317  for (size_t index = 0; index < num_cmds; ++index)
318  {
319  planning_interface::MotionPlanRequest req{ seq.getCmd<LinCart>(index).toRequest() };
320  // Set start state of request to end state of previous trajectory (except
321  // for first)
322  if (index > 0)
323  {
324  moveit::core::robotStateToRobotStateMsg(responses[index - 1].trajectory->getLastWayPoint(), req.start_state);
325  sampling_time_ *= 2;
326  }
327  // generate trajectory
329  lin_generator_->generate(planning_scene_, req, resp, sampling_time_);
330  if (resp.error_code.val != moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
331  {
332  std::runtime_error("Failed to generate trajectory.");
333  }
334  responses.at(index) = resp;
335  }
336 
339 
340  blend_req.group_name = planning_group_;
341  blend_req.link_name = target_link_;
342  blend_req.first_trajectory = responses[0].trajectory;
343  blend_req.second_trajectory = responses[1].trajectory;
344  blend_req.blend_radius = seq.getBlendRadius(0);
345  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
346 }
347 
362 TEST_F(TrajectoryBlenderTransitionWindowTest, testNonUniformSamplingTime)
363 {
364  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
365 
366  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
367 
368  // Modify first time interval
369  EXPECT_GT(res[0].trajectory->getWayPointCount(), 2u);
370  res[0].trajectory->setWayPointDurationFromPrevious(1, 2 * sampling_time_);
371 
374 
375  blend_req.group_name = planning_group_;
376  blend_req.link_name = target_link_;
377  blend_req.first_trajectory = res.at(0).trajectory;
378  blend_req.second_trajectory = res.at(1).trajectory;
379  blend_req.blend_radius = seq.getBlendRadius(0);
380  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
381 }
382 
396 TEST_F(TrajectoryBlenderTransitionWindowTest, testNotIntersectingTrajectories)
397 {
398  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
399 
400  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 1) };
401 
404 
405  blend_req.group_name = planning_group_;
406  blend_req.link_name = target_link_;
407  blend_req.first_trajectory = res.at(0).trajectory;
408  // replace the second trajectory to make the two trajectories timely not
409  // intersect
410  blend_req.second_trajectory = res.at(0).trajectory;
411  blend_req.blend_radius = seq.getBlendRadius(0);
412  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
413 }
414 
428 {
429  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
430 
431  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
432 
435 
436  blend_req.group_name = planning_group_;
437  blend_req.link_name = target_link_;
438  blend_req.blend_radius = seq.getBlendRadius(0);
439 
440  blend_req.first_trajectory = res.at(0).trajectory;
441  blend_req.second_trajectory = res.at(1).trajectory;
442 
443  // Modify last waypoint of first trajectory and first point of second
444  // trajectory
445  blend_req.first_trajectory->getLastWayPointPtr()->setVariableVelocity(0, 1.0);
446  blend_req.second_trajectory->getFirstWayPointPtr()->setVariableVelocity(0, 1.0);
447 
448  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
449 }
450 
464 TEST_F(TrajectoryBlenderTransitionWindowTest, testTraj1InsideBlendRadius)
465 {
466  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
467 
468  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
469 
470  double lin1_distance;
471  lin1_distance = (res[0].trajectory->getFirstWayPoint().getFrameTransform(target_link_).translation() -
472  res[0].trajectory->getLastWayPoint().getFrameTransform(target_link_).translation())
473  .norm();
474 
477 
478  blend_req.group_name = planning_group_;
479  blend_req.link_name = target_link_;
480  blend_req.blend_radius = 1.1 * lin1_distance;
481 
482  blend_req.first_trajectory = res.at(0).trajectory;
483  blend_req.second_trajectory = res.at(1).trajectory;
484 
485  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
486 }
487 
501 TEST_F(TrajectoryBlenderTransitionWindowTest, testTraj2InsideBlendRadius)
502 {
503  Sequence seq{ data_loader_->getSequence("NoIntersectionTraj2") };
504 
505  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
506 
509 
510  blend_req.group_name = planning_group_;
511  blend_req.link_name = target_link_;
512  blend_req.blend_radius = seq.getBlendRadius(0);
513 
514  blend_req.first_trajectory = res.at(0).trajectory;
515  blend_req.second_trajectory = res.at(1).trajectory;
516 
517  EXPECT_FALSE(blender_->blend(planning_scene_, blend_req, blend_res));
518 }
519 
539 {
540  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
541 
542  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
543 
546 
547  blend_req.group_name = planning_group_;
548  blend_req.link_name = target_link_;
549  blend_req.blend_radius = seq.getBlendRadius(0);
550 
551  blend_req.first_trajectory = res.at(0).trajectory;
552  blend_req.second_trajectory = res.at(1).trajectory;
553 
554  EXPECT_TRUE(blender_->blend(planning_scene_, blend_req, blend_res));
555 
556  EXPECT_TRUE(testutils::checkBlendResult(blend_req, blend_res, planner_limits_, joint_velocity_tolerance_,
557  joint_acceleration_tolerance_, cartesian_velocity_tolerance_,
558  cartesian_angular_velocity_tolerance_));
559 }
560 
581 TEST_F(TrajectoryBlenderTransitionWindowTest, testOverlappingBlendTrajectories)
582 {
583  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
584  // Set goal of second traj to start of first traj.
585  seq.getCmd<LinCart>(1).setGoalConfiguration(seq.getCmd<LinCart>(0).getStartConfiguration());
586 
587  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
588 
591 
592  blend_req.group_name = planning_group_;
593  blend_req.link_name = target_link_;
594  blend_req.first_trajectory = res.at(0).trajectory;
595  blend_req.second_trajectory = res.at(1).trajectory;
596  blend_req.blend_radius = seq.getBlendRadius(0);
597  EXPECT_TRUE(blender_->blend(planning_scene_, blend_req, blend_res));
598 
599  EXPECT_TRUE(testutils::checkBlendResult(blend_req, blend_res, planner_limits_, joint_velocity_tolerance_,
600  joint_acceleration_tolerance_, cartesian_velocity_tolerance_,
601  cartesian_angular_velocity_tolerance_));
602 }
603 
628 {
629  const double sine_scaling_factor{ 0.01 };
630  const double time_scaling_factor{ 10 };
631 
632  Sequence seq{ data_loader_->getSequence("SimpleSequence") };
633 
634  std::vector<planning_interface::MotionPlanResponse> res{ generateLinTrajs(seq, 2) };
635 
636  // prepare looping over trajectories
637  std::vector<robot_trajectory::RobotTrajectoryPtr> sine_trajs(2);
638 
639  for (size_t traj_index = 0; traj_index < 2; ++traj_index)
640  {
641  auto lin_traj{ res.at(traj_index).trajectory };
642 
643  CartesianTrajectory cart_traj;
644  trajectory_msgs::msg::JointTrajectory joint_traj;
645  const double duration{ lin_traj->getWayPointDurationFromStart(lin_traj->getWayPointCount()) };
646  // time from start zero does not work
647  const double time_from_start_offset{ time_scaling_factor * lin_traj->getWayPointDurations().back() };
648 
649  // generate modified cartesian trajectory
650  for (size_t i = 0; i < lin_traj->getWayPointCount(); ++i)
651  {
652  // transform time to interval [0, 4*pi]
653  const double sine_arg{ 4 * M_PI * lin_traj->getWayPointDurationFromStart(i) / duration };
654 
655  // get pose
656  CartesianTrajectoryPoint waypoint;
657  const Eigen::Isometry3d eigen_pose{ lin_traj->getWayPointPtr(i)->getFrameTransform(target_link_) };
658  geometry_msgs::msg::Pose waypoint_pose = tf2::toMsg(eigen_pose);
659 
660  // add scaled sine function
661  waypoint_pose.position.x += sine_scaling_factor * sin(sine_arg);
662  waypoint_pose.position.y += sine_scaling_factor * sin(sine_arg);
663  waypoint_pose.position.z += sine_scaling_factor * sin(sine_arg);
664 
665  // add to trajectory
666  waypoint.pose = waypoint_pose;
667  waypoint.time_from_start = rclcpp::Duration::from_seconds(
668  time_from_start_offset + time_scaling_factor * lin_traj->getWayPointDurationFromStart(i));
669  cart_traj.points.push_back(waypoint);
670  }
671 
672  // prepare ik
673  std::map<std::string, double> initial_joint_position, initial_joint_velocity;
674  for (const std::string& joint_name :
675  lin_traj->getFirstWayPointPtr()->getJointModelGroup(planning_group_)->getActiveJointModelNames())
676  {
677  if (traj_index == 0)
678  {
679  initial_joint_position[joint_name] = lin_traj->getFirstWayPoint().getVariablePosition(joint_name);
680  initial_joint_velocity[joint_name] = lin_traj->getFirstWayPoint().getVariableVelocity(joint_name);
681  }
682  else
683  {
684  initial_joint_position[joint_name] =
685  sine_trajs[traj_index - 1]->getLastWayPoint().getVariablePosition(joint_name);
686  initial_joint_velocity[joint_name] =
687  sine_trajs[traj_index - 1]->getLastWayPoint().getVariableVelocity(joint_name);
688  }
689  }
690 
691  moveit_msgs::msg::MoveItErrorCodes error_code;
692  if (!generateJointTrajectory(planning_scene_, planner_limits_.getJointLimitContainer(), cart_traj, planning_group_,
693  target_link_, initial_joint_position, initial_joint_velocity, joint_traj, error_code,
694  true))
695  {
696  std::runtime_error("Failed to generate trajectory.");
697  }
698 
699  joint_traj.points.back().velocities.assign(joint_traj.points.back().velocities.size(), 0.0);
700  joint_traj.points.back().accelerations.assign(joint_traj.points.back().accelerations.size(), 0.0);
701 
702  // convert trajectory_msgs::JointTrajectory to robot_trajectory::RobotTrajectory
703  sine_trajs[traj_index] = std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, planning_group_);
704  sine_trajs.at(traj_index)->setRobotTrajectoryMsg(lin_traj->getFirstWayPoint(), joint_traj);
705  }
706 
707  TrajectoryBlendRequest blend_req;
708  TrajectoryBlendResponse blend_res;
709 
710  blend_req.group_name = planning_group_;
711  blend_req.link_name = target_link_;
712  blend_req.blend_radius = seq.getBlendRadius(0);
713 
714  blend_req.first_trajectory = sine_trajs.at(0);
715  blend_req.second_trajectory = sine_trajs.at(1);
716 
717  EXPECT_TRUE(blender_->blend(planning_scene_, blend_req, blend_res));
718 
719  EXPECT_TRUE(testutils::checkBlendResult(blend_req, blend_res, planner_limits_, joint_velocity_tolerance_,
720  joint_acceleration_tolerance_, cartesian_velocity_tolerance_,
721  cartesian_angular_velocity_tolerance_));
722 }
723 
724 int main(int argc, char** argv)
725 {
726  rclcpp::init(argc, argv);
727  testing::InitGoogleTest(&argc, argv);
728  return RUN_ALL_TESTS();
729 }
void SetUp() override
Create test scenario for trajectory blender.
std::unique_ptr< TrajectoryBlenderTransitionWindow > blender_
std::unique_ptr< robot_model_loader::RobotModelLoader > rm_loader_
std::vector< planning_interface::MotionPlanResponse > generateLinTrajs(const Sequence &seq, size_t num_cmds)
Generate lin trajectories for blend sequences.
static JointLimitsContainer getAggregatedLimits(const rclcpp::Node::SharedPtr &node, const std::string &param_namespace, const std::vector< const moveit::core::JointModel * > &joint_models)
Aggregates(combines) the joint limits from joint model and node parameters. The rules for the combina...
Container for JointLimits, essentially a map with convenience functions. Adds the ability to as for l...
This class combines CartesianLimit and JointLimits into on single class.
Data class storing all information regarding a linear command.
Definition: lin.h:48
Data class storing all information regarding a Sequence command.
Definition: sequence.h:54
void robotStateToRobotStateMsg(const RobotState &state, moveit_msgs::msg::RobotState &robot_state, bool copy_attached_bodies=true)
Convert a MoveIt robot state to a robot state message.
std::unique_ptr< TestdataLoader > XmlTestDataLoaderUPtr
bool generateJointTrajectory(const planning_scene::PlanningSceneConstPtr &scene, const JointLimitsContainer &joint_limits, const KDL::Trajectory &trajectory, const std::string &group_name, const std::string &link_name, const std::map< std::string, double > &initial_joint_position, double sampling_time, trajectory_msgs::msg::JointTrajectory &joint_trajectory, moveit_msgs::msg::MoveItErrorCodes &error_code, bool check_self_collision=false)
Generate joint trajectory from a KDL Cartesian trajectory.
TEST_F(GetSolverTipFrameIntegrationTest, TestHasSolverManipulator)
Check if hasSolver() can be called successfully for the manipulator group.
moveit_msgs::msg::MotionPlanRequest MotionPlanRequest
bool checkBlendResult(const pilz_industrial_motion_planner::TrajectoryBlendRequest &blend_req, const pilz_industrial_motion_planner::TrajectoryBlendResponse &blend_res, const pilz_industrial_motion_planner::LimitsContainer &limits, double joint_velocity_tolerance, double joint_acceleration_tolerance, double cartesian_velocity_tolerance, double cartesian_angular_velocity_tolerance)
check the blending result of lin-lin
void checkRobotModel(const moveit::core::RobotModelConstPtr &robot_model, const std::string &group_name, const std::string &link_name)
std::vector< CartesianTrajectoryPoint > points
Response to a planning query.
moveit::core::MoveItErrorCode error_code
int main(int argc, char **argv)
const std::string PARAM_NAMESPACE_LIMITS