moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
unittest_trajectory_functions.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 <gtest/gtest.h>
36
37#include <map>
38#include <math.h>
39#include <string>
40#include <vector>
41
42#include <Eigen/Geometry>
43#include <kdl/frames.hpp>
44#include <kdl/path_roundedcomposite.hpp>
45#include <kdl/rotational_interpolation_sa.hpp>
46#include <kdl/trajectory.hpp>
47#include <kdl/trajectory_segment.hpp>
48#include <kdl/velocityprofile_trap.hpp>
53#include <tf2_eigen/tf2_eigen.hpp>
54#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
55
60#include "test_utils.h"
61
62#define _USE_MATH_DEFINES
63
64static constexpr double EPSILON{ 1.0e-6 };
65static constexpr double IK_SEED_OFFSET{ 0.1 };
66static constexpr double L0{ 0.2604 }; // Height of foot
67static constexpr double L1{ 0.3500 }; // Height of first connector
68static constexpr double L2{ 0.3070 }; // Height of second connector
69static constexpr double L3{ 0.0840 }; // Distance last joint to flange
70
71// parameters from parameter server
72const std::string PARAM_PLANNING_GROUP_NAME("planning_group");
73const std::string GROUP_TIP_LINK_NAME("group_tip_link");
74const std::string ROBOT_TCP_LINK_NAME("tcp_link");
75const std::string IK_FAST_LINK_NAME("ik_fast_link");
76const std::string RANDOM_TEST_NUMBER("random_test_number");
77
81class TrajectoryFunctionsTestBase : public testing::Test
82{
83protected:
88 void SetUp() override
89 {
90 rclcpp::NodeOptions node_options;
91 node_options.automatically_declare_parameters_from_overrides(true);
92 node_ = rclcpp::Node::make_shared("unittest_trajectory_functions", node_options);
93
94 // load robot model
95 rm_loader_ = std::make_unique<robot_model_loader::RobotModelLoader>(node_);
96 robot_model_ = rm_loader_->getModel();
97 ASSERT_TRUE(bool(robot_model_)) << "Failed to load robot model";
98 planning_scene_ = std::make_shared<planning_scene::PlanningScene>(robot_model_);
99
100 // get parameters
101 ASSERT_TRUE(node_->has_parameter("planning_group"));
102 node_->get_parameter<std::string>("planning_group", planning_group_);
103 ASSERT_TRUE(node_->has_parameter("group_tip_link"));
104 node_->get_parameter<std::string>("group_tip_link", group_tip_link_);
105 ASSERT_TRUE(node_->has_parameter("tcp_link"));
106 node_->get_parameter<std::string>("tcp_link", tcp_link_);
107 ASSERT_TRUE(node_->has_parameter("ik_fast_link"));
108 node_->get_parameter<std::string>("ik_fast_link", ik_fast_link_);
109 ASSERT_TRUE(node_->has_parameter("random_test_number"));
110 node_->get_parameter<int>("random_test_number", random_test_number_);
111
112 // check robot model
114
115 // initialize the zero state configurationg and test joint state
116 joint_names_ = robot_model_->getJointModelGroup(planning_group_)->getActiveJointModelNames();
117 for (const auto& joint_name : joint_names_)
118 {
119 zero_state_[joint_name] = 0.0;
120 }
121 }
122
123 void TearDown() override
124 {
125 robot_model_.reset();
126 }
127
135 bool tfNear(const Eigen::Isometry3d& pose1, const Eigen::Isometry3d& pose2, double epsilon);
136
137protected:
138 // ros stuff
139 rclcpp::Node::SharedPtr node_;
140 moveit::core::RobotModelConstPtr robot_model_;
141 std::unique_ptr<robot_model_loader::RobotModelLoader> rm_loader_;
142 planning_scene::PlanningSceneConstPtr planning_scene_;
143
144 // test parameters from parameter server
147 std::vector<std::string> joint_names_;
148 std::map<std::string, double> zero_state_;
149
150 // random seed
151 uint32_t random_seed_{ 100 };
152 random_numbers::RandomNumberGenerator rng_{ random_seed_ };
153};
154
155bool TrajectoryFunctionsTestBase::tfNear(const Eigen::Isometry3d& pose1, const Eigen::Isometry3d& pose2, double epsilon)
156{
157 for (std::size_t i = 0; i < 3; ++i)
158 {
159 for (std::size_t j = 0; j < 4; ++j)
160 {
161 if (fabs(pose1(i, j) - pose2(i, j)) > fabs(epsilon))
162 return false;
163 }
164 }
165 return true;
166}
167
174
175// TODO(henningkayser): re-enable gripper tests
176// /**
177// * @brief Parametrized class for tests, that only run with a gripper
178// */
179// class TrajectoryFunctionsTestOnlyGripper : public TrajectoryFunctionsTestBase
180// {
181// };
182
189{
190 Eigen::Isometry3d tip_pose;
191 std::map<std::string, double> test_state = zero_state_;
192 EXPECT_TRUE(pilz_industrial_motion_planner::computeLinkFK(planning_scene_, group_tip_link_, test_state, tip_pose));
193 EXPECT_NEAR(tip_pose(0, 3), 0, EPSILON);
194 EXPECT_NEAR(tip_pose(1, 3), 0, EPSILON);
195 EXPECT_NEAR(tip_pose(2, 3), L0 + L1 + L2 + L3, EPSILON);
196
197 test_state[joint_names_.at(1)] = M_PI_2;
198 EXPECT_TRUE(pilz_industrial_motion_planner::computeLinkFK(planning_scene_, group_tip_link_, test_state, tip_pose));
199 EXPECT_NEAR(tip_pose(0, 3), L1 + L2 + L3, EPSILON);
200 EXPECT_NEAR(tip_pose(1, 3), 0, EPSILON);
201 EXPECT_NEAR(tip_pose(2, 3), L0, EPSILON);
202
203 test_state[joint_names_.at(1)] = -M_PI_2;
204 test_state[joint_names_.at(2)] = M_PI_2;
205 EXPECT_TRUE(pilz_industrial_motion_planner::computeLinkFK(planning_scene_, group_tip_link_, test_state, tip_pose));
206 EXPECT_NEAR(tip_pose(0, 3), -L1, EPSILON);
207 EXPECT_NEAR(tip_pose(1, 3), 0, EPSILON);
208 EXPECT_NEAR(tip_pose(2, 3), L0 - L2 - L3, EPSILON);
209
210 // wrong link name
211 std::string link_name = "wrong_link_name";
212 EXPECT_FALSE(pilz_industrial_motion_planner::computeLinkFK(planning_scene_, link_name, test_state, tip_pose));
213}
214
219{
220 // Load solver
221 const moveit::core::JointModelGroup* jmg = robot_model_->getJointModelGroup(planning_group_);
222 const kinematics::KinematicsBaseConstPtr& solver = jmg->getSolverInstance();
223
224 if (!solver)
225 {
226 throw("No IK solver configured for group '" + planning_group_ + "'");
227 }
228 // robot state
229 moveit::core::RobotState rstate(robot_model_);
230
231 while (random_test_number_ > 0)
232 {
233 // sample random robot state
234 rstate.setToRandomPositions(jmg, rng_);
235 rstate.update();
236 geometry_msgs::msg::Pose pose_expect = tf2::toMsg(rstate.getFrameTransform(ik_fast_link_));
237
238 // prepare inverse kinematics
239 std::vector<geometry_msgs::msg::Pose> ik_poses;
240 ik_poses.push_back(pose_expect);
241 std::vector<double> ik_seed, ik_expect, ik_actual;
242 for (const auto& joint_name : jmg->getActiveJointModelNames())
243 {
244 ik_expect.push_back(rstate.getVariablePosition(joint_name));
245 if (rstate.getVariablePosition(joint_name) > 0)
246 {
247 ik_seed.push_back(rstate.getVariablePosition(joint_name) - IK_SEED_OFFSET);
248 }
249 else
250 {
251 ik_seed.push_back(rstate.getVariablePosition(joint_name) + IK_SEED_OFFSET);
252 }
253 }
254
255 std::vector<std::vector<double>> ik_solutions;
257 moveit_msgs::msg::MoveItErrorCodes err_code;
259
260 // compute all ik solutions
261 EXPECT_TRUE(solver->getPositionIK(ik_poses, ik_seed, ik_solutions, ik_result, options));
262
263 // compute one ik solution
264 EXPECT_TRUE(solver->getPositionIK(pose_expect, ik_seed, ik_actual, err_code));
265
266 ASSERT_EQ(ik_expect.size(), ik_actual.size());
267
268 for (std::size_t i = 0; i < ik_expect.size(); ++i)
269 {
270 EXPECT_NEAR(ik_actual.at(i), ik_expect.at(i), 4 * IK_SEED_OFFSET);
271 }
272
273 --random_test_number_;
274 }
275}
276
282{
283 // robot state
284 moveit::core::RobotState rstate(robot_model_);
285 const moveit::core::JointModelGroup* jmg = robot_model_->getJointModelGroup(planning_group_);
286
287 while (random_test_number_ > 0)
288 {
289 // sample random robot state
290 rstate.setToRandomPositions(jmg, rng_);
291
292 Eigen::Isometry3d pose_expect = rstate.getFrameTransform(tcp_link_);
293
294 // copy the random state and set ik seed
295 std::map<std::string, double> ik_seed, ik_expect;
296 for (const auto& joint_name : joint_names_)
297 {
298 ik_expect[joint_name] = rstate.getVariablePosition(joint_name);
299 if (rstate.getVariablePosition(joint_name) > 0)
300 {
301 ik_seed[joint_name] = rstate.getVariablePosition(joint_name) - IK_SEED_OFFSET;
302 }
303 else
304 {
305 ik_seed[joint_name] = rstate.getVariablePosition(joint_name) + IK_SEED_OFFSET;
306 }
307 }
308
309 rstate.setVariablePositions(ik_seed);
310 rstate.update();
311
312 // compute the ik
313 std::map<std::string, double> ik_actual;
314
315 EXPECT_TRUE(rstate.setFromIK(robot_model_->getJointModelGroup(planning_group_), pose_expect, tcp_link_));
316
317 for (const auto& joint_name : joint_names_)
318 {
319 ik_actual[joint_name] = rstate.getVariablePosition(joint_name);
320 }
321
322 // compare ik solution and expected value
323 for (const auto& joint_pair : ik_actual)
324 {
325 EXPECT_NEAR(joint_pair.second, ik_expect.at(joint_pair.first), 4 * IK_SEED_OFFSET);
326 }
327
328 // compute the pose from ik_solution
329 rstate.setVariablePositions(ik_actual);
330 rstate.update();
331 Eigen::Isometry3d pose_actual = rstate.getFrameTransform(tcp_link_);
332
333 EXPECT_TRUE(tfNear(pose_expect, pose_actual, EPSILON));
334
335 --random_test_number_;
336 }
337}
338
344{
345 // robot state
346 moveit::core::RobotState rstate(robot_model_);
347
348 const std::string frame_id = robot_model_->getModelFrame();
349 const moveit::core::JointModelGroup* jmg = robot_model_->getJointModelGroup(planning_group_);
350
351 while (random_test_number_ > 0)
352 {
353 // sample random robot state
354 rstate.setToRandomPositions(jmg, rng_);
355
356 Eigen::Isometry3d pose_expect = rstate.getFrameTransform(tcp_link_);
357
358 // copy the random state and set ik seed
359 std::map<std::string, double> ik_seed, ik_expect;
360 for (const auto& joint_name : robot_model_->getJointModelGroup(planning_group_)->getActiveJointModelNames())
361 {
362 ik_expect[joint_name] = rstate.getVariablePosition(joint_name);
363 if (rstate.getVariablePosition(joint_name) > 0)
364 {
365 ik_seed[joint_name] = rstate.getVariablePosition(joint_name) - IK_SEED_OFFSET;
366 }
367 else
368 {
369 ik_seed[joint_name] = rstate.getVariablePosition(joint_name) + IK_SEED_OFFSET;
370 }
371 }
372
373 // compute the ik
374 std::map<std::string, double> ik_actual;
375 EXPECT_TRUE(pilz_industrial_motion_planner::computePoseIK(planning_scene_, planning_group_, tcp_link_, pose_expect,
376 frame_id, ik_seed, ik_actual, false));
377
378 // compare ik solution and expected value
379 for (const auto& joint_pair : ik_actual)
380 {
381 EXPECT_NEAR(joint_pair.second, ik_expect.at(joint_pair.first), 4 * IK_SEED_OFFSET);
382 }
383
384 --random_test_number_;
385 }
386}
387
391TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testComputePoseIKInvalidGroupName)
392{
393 const std::string frame_id = robot_model_->getModelFrame();
394 Eigen::Isometry3d pose_expect;
395
396 std::map<std::string, double> ik_seed;
397
398 // compute the ik
399 std::map<std::string, double> ik_actual;
400 EXPECT_FALSE(pilz_industrial_motion_planner::computePoseIK(planning_scene_, "InvalidGroupName", tcp_link_,
401 pose_expect, frame_id, ik_seed, ik_actual, false));
402}
403
407TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testComputePoseIKInvalidLinkName)
408{
409 const std::string frame_id = robot_model_->getModelFrame();
410 Eigen::Isometry3d pose_expect;
411
412 std::map<std::string, double> ik_seed;
413
414 // compute the ik
415 std::map<std::string, double> ik_actual;
416 EXPECT_FALSE(pilz_industrial_motion_planner::computePoseIK(planning_scene_, planning_group_, "WrongLink", pose_expect,
417 frame_id, ik_seed, ik_actual, false));
418}
419
425TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testComputePoseIKInvalidFrameId)
426{
427 Eigen::Isometry3d pose_expect;
428
429 std::map<std::string, double> ik_seed;
430
431 // compute the ik
432 std::map<std::string, double> ik_actual;
433 EXPECT_FALSE(pilz_industrial_motion_planner::computePoseIK(planning_scene_, planning_group_, tcp_link_, pose_expect,
434 "InvalidFrameId", ik_seed, ik_actual, false));
435}
436
437// /**
438// * @brief Test if activated self collision for a pose that would be in self
439// * collision without the check results in a
440// * valid ik solution.
441// */
442// TEST_F(TrajectoryFunctionsTestOnlyGripper, testComputePoseIKSelfCollisionForValidPosition)
443// {
444// const std::string frame_id = robot_model_->getModelFrame();
445// const moveit::core::JointModelGroup* jmg = robot_model_->getJointModelGroup(planning_group_);
446//
447// // create seed
448// std::vector<double> ik_seed_states = { -0.553, 0.956, 1.758, 0.146, -1.059, 1.247 };
449// auto joint_names = jmg->getActiveJointModelNames();
450//
451// std::map<std::string, double> ik_seed;
452// for (unsigned int i = 0; i < ik_seed_states.size(); ++i)
453// {
454// ik_seed[joint_names[i]] = ik_seed_states[i];
455// }
456//
457// // create expected pose
458// geometry_msgs::msg::Pose pose;
459// pose.position.x = -0.454;
460// pose.position.y = -0.15;
461// pose.position.z = 0.431;
462// pose.orientation.y = 0.991562;
463// pose.orientation.w = -0.1296328;
464// Eigen::Isometry3d pose_expect;
465// normalizeQuaternion(pose.orientation);
466// tf2::fromMsg(pose, pose_expect);
467//
468// // compute the ik without self collision check and expect the resulting pose
469// // to be in self collision.
470// std::map<std::string, double> ik_actual1;
471// EXPECT_TRUE(pilz_industrial_motion_planner::computePoseIK(planning_scene_, planning_group_, tcp_link_, pose_expect,
472// frame_id, ik_seed, ik_actual1, false));
473//
474// moveit::core::RobotState rstate(robot_model_);
475// planning_scene::PlanningScene rscene(robot_model_);
476//
477// std::vector<double> ik_state;
478// std::transform(ik_actual1.begin(), ik_actual1.end(), std::back_inserter(ik_state),
479// [](const auto& pair) { return pair.second; });
480//
481// rstate.setJointGroupPositions(jmg, ik_state);
482// rstate.update();
483//
484// collision_detection::CollisionRequest collision_req;
485// collision_req.group_name = jmg->getName();
486// collision_detection::CollisionResult collision_res;
487//
488// rscene.checkSelfCollision(collision_req, collision_res, rstate);
489//
490// EXPECT_TRUE(collision_res.collision);
491//
492// // compute the ik with collision detection activated and expect the resulting
493// // pose to be without self collision.
494// std::map<std::string, double> ik_actual2;
495// EXPECT_TRUE(pilz_industrial_motion_planner::computePoseIK(robot_model_, planning_group_, tcp_link_, pose_expect,
496// frame_id, ik_seed, ik_actual2, true));
497//
498// std::vector<double> ik_state2;
499// std::transform(ik_actual2.begin(), ik_actual2.end(), std::back_inserter(ik_state2),
500// [](const auto& pair) { return pair.second; });
501// rstate.setJointGroupPositions(jmg, ik_state2);
502// rstate.update();
503//
504// collision_detection::CollisionResult collision_res2;
505// rscene.checkSelfCollision(collision_req, collision_res2, rstate);
506//
507// EXPECT_FALSE(collision_res2.collision);
508// }
509
514TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testComputePoseIKSelfCollisionForInvalidPose)
515{
516 // robot state
517 moveit::core::RobotState rstate(robot_model_);
518
519 const std::string frame_id = robot_model_->getModelFrame();
520 const moveit::core::JointModelGroup* jmg = robot_model_->getJointModelGroup(planning_group_);
521
522 // create seed
523 std::map<std::string, double> ik_seed;
524 for (const auto& joint_name : jmg->getActiveJointModelNames())
525 {
526 ik_seed[joint_name] = 0;
527 }
528
529 // create goal
530 std::vector<double> ik_goal = { 0, 2.3, -2.3, 0, 0, 0 };
531
532 rstate.setJointGroupPositions(jmg, ik_goal);
533
534 Eigen::Isometry3d pose_expect = rstate.getFrameTransform(tcp_link_);
535
536 // compute the ik with disabled collision check
537 std::map<std::string, double> ik_actual;
538 EXPECT_TRUE(pilz_industrial_motion_planner::computePoseIK(planning_scene_, planning_group_, tcp_link_, pose_expect,
539 frame_id, ik_seed, ik_actual, false));
540
541 // compute the ik with enabled collision check
542 EXPECT_FALSE(pilz_industrial_motion_planner::computePoseIK(planning_scene_, planning_group_, tcp_link_, pose_expect,
543 frame_id, ik_seed, ik_actual, true));
544}
545
556TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testVerifySampleJointLimitsWithSmallDuration)
557{
558 const std::map<std::string, double> position_last, velocity_last, position_current;
559 double duration_last{ 0.0 };
561
562 double duration_current = 10e-7;
563
564 EXPECT_FALSE(pilz_industrial_motion_planner::verifySampleJointLimits(position_last, velocity_last, position_current,
565 duration_last, duration_current, joint_limits));
566}
567
578TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testVerifySampleJointLimitsVelocityViolation)
579{
580 const std::string test_joint_name{ "joint" };
581
582 std::map<std::string, double> position_last{ { test_joint_name, 2.0 } };
583 std::map<std::string, double> position_current{ { test_joint_name, 10.0 } };
584 std::map<std::string, double> velocity_last;
585 double duration_current{ 1.0 };
586 double duration_last{ 0.0 };
588
590 // Calculate the max allowed velocity in such a way that it is always smaller
591 // than the current velocity.
592 test_joint_limits.max_velocity =
593 ((position_current.at(test_joint_name) - position_last.at(test_joint_name)) / duration_current) - 1.0;
594 test_joint_limits.has_velocity_limits = true;
595 joint_limits.addLimit(test_joint_name, test_joint_limits);
596
597 EXPECT_FALSE(pilz_industrial_motion_planner::verifySampleJointLimits(position_last, velocity_last, position_current,
598 duration_last, duration_current, joint_limits));
599}
600
611TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testVerifySampleJointLimitsAccelerationViolation)
612{
613 const std::string test_joint_name{ "joint" };
614
615 double duration_current = 1.0;
616 double duration_last = 1.0;
617
618 std::map<std::string, double> position_last{ { test_joint_name, 2.0 } };
619 std::map<std::string, double> position_current{ { test_joint_name, 20.0 } };
620 double velocity_current =
621 ((position_current.at(test_joint_name) - position_last.at(test_joint_name)) / duration_current);
622 std::map<std::string, double> velocity_last{ { test_joint_name, 9.0 } };
624
626 // Calculate the max allowed velocity in such a way that it is always bigger
627 // than the current velocity.
628 test_joint_limits.max_velocity = velocity_current + 1.0;
629 test_joint_limits.has_velocity_limits = true;
630
631 double acceleration_current =
632 (velocity_current - velocity_last.at(test_joint_name)) / (duration_last + duration_current) * 2;
633 // Calculate the max allowed acceleration in such a way that it is always
634 // smaller than the current acceleration.
635 test_joint_limits.max_acceleration = acceleration_current - 1.0;
636 test_joint_limits.has_acceleration_limits = true;
637
638 joint_limits.addLimit(test_joint_name, test_joint_limits);
639
640 EXPECT_FALSE(pilz_industrial_motion_planner::verifySampleJointLimits(position_last, velocity_last, position_current,
641 duration_last, duration_current, joint_limits));
642}
643
654TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testVerifySampleJointLimitsDecelerationViolation)
655{
656 const std::string test_joint_name{ "joint" };
657
658 double duration_current = 1.0;
659 double duration_last = 1.0;
660
661 std::map<std::string, double> position_last{ { test_joint_name, 20.0 } };
662 std::map<std::string, double> position_current{ { test_joint_name, 2.0 } };
663 double velocity_current =
664 ((position_current.at(test_joint_name) - position_last.at(test_joint_name)) / duration_current);
665 std::map<std::string, double> velocity_last{ { test_joint_name, 19.0 } };
667
669 // Calculate the max allowed velocity in such a way that it is always bigger
670 // than the current velocity.
671 test_joint_limits.max_velocity = fabs(velocity_current) + 1.0;
672 test_joint_limits.has_velocity_limits = true;
673
674 double acceleration_current =
675 (velocity_current - velocity_last.at(test_joint_name)) / (duration_last + duration_current) * 2;
676 // Calculate the max allowed deceleration in such a way that it is always
677 // bigger than the current acceleration.
678 test_joint_limits.max_deceleration = acceleration_current + 1.0;
679 test_joint_limits.has_deceleration_limits = true;
680
681 joint_limits.addLimit(test_joint_name, test_joint_limits);
682
683 EXPECT_FALSE(pilz_industrial_motion_planner::verifySampleJointLimits(position_last, velocity_last, position_current,
684 duration_last, duration_current, joint_limits));
685}
686
701TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testGenerateJointTrajectoryWithInvalidCartesianTrajectory)
702{
703 // Create random test trajectory
704 // Note: 'path' is deleted by KDL::Trajectory_Segment
705 KDL::Path_RoundedComposite* path =
706 new KDL::Path_RoundedComposite(0.2, 0.01, new KDL::RotationalInterpolation_SingleAxis());
707 path->Add(KDL::Frame(KDL::Rotation::RPY(0, 0, 0), KDL::Vector(-1, 0, 0)));
708 path->Finish();
709 // Note: 'velprof' is deleted by KDL::Trajectory_Segment
710 KDL::VelocityProfile* vel_prof = new KDL::VelocityProfile_Trap(0.5, 0.1);
711 vel_prof->SetProfile(0, path->PathLength());
712 KDL::Trajectory_Segment kdl_trajectory(path, vel_prof);
713
715 std::string group_name{ "invalid_group_name" };
716 std::map<std::string, double> initial_joint_position;
717 double sampling_time{ 0.1 };
718 trajectory_msgs::msg::JointTrajectory joint_trajectory;
719 moveit_msgs::msg::MoveItErrorCodes error_code;
720 bool check_self_collision{ false };
721
723 planning_scene_, joint_limits, kdl_trajectory, group_name, tcp_link_, initial_joint_position, sampling_time,
724 joint_trajectory, error_code, check_self_collision));
725
726 std::map<std::string, double> initial_joint_velocity;
727
729 cart_traj.group_name = group_name;
730 cart_traj.link_name = tcp_link_;
732 cart_traj.points.push_back(cart_traj_point);
733
735 planning_scene_, joint_limits, cart_traj, group_name, tcp_link_, initial_joint_position, initial_joint_velocity,
736 joint_trajectory, error_code, check_self_collision));
737}
738
750TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testDetermineAndCheckSamplingTimeInvalidVectorSize)
751{
752 robot_trajectory::RobotTrajectoryPtr first_trajectory =
753 std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, planning_group_);
754 robot_trajectory::RobotTrajectoryPtr second_trajectory =
755 std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, planning_group_);
756 double epsilon{ 0.0 };
757 double sampling_time{ 0.0 };
758
759 moveit::core::RobotState rstate(robot_model_);
760 first_trajectory->insertWayPoint(0, rstate, 0.1);
761 second_trajectory->insertWayPoint(0, rstate, 0.1);
762
763 EXPECT_FALSE(pilz_industrial_motion_planner::determineAndCheckSamplingTime(first_trajectory, second_trajectory,
764 epsilon, sampling_time));
765}
766
778TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testDetermineAndCheckSamplingTimeCorrectSamplingTime)
779{
780 robot_trajectory::RobotTrajectoryPtr first_trajectory =
781 std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, planning_group_);
782 robot_trajectory::RobotTrajectoryPtr second_trajectory =
783 std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, planning_group_);
784 double epsilon{ 0.0001 };
785 double sampling_time{ 0.0 };
786 double expected_sampling_time{ 0.1 };
787
788 moveit::core::RobotState rstate(robot_model_);
789 first_trajectory->insertWayPoint(0, rstate, expected_sampling_time);
790 first_trajectory->insertWayPoint(1, rstate, expected_sampling_time);
791
792 second_trajectory->insertWayPoint(0, rstate, expected_sampling_time);
793 second_trajectory->insertWayPoint(1, rstate, expected_sampling_time);
794 second_trajectory->insertWayPoint(2, rstate, expected_sampling_time);
795
796 EXPECT_TRUE(pilz_industrial_motion_planner::determineAndCheckSamplingTime(first_trajectory, second_trajectory,
797 epsilon, sampling_time));
798 EXPECT_EQ(expected_sampling_time, sampling_time);
799}
800
812TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testDetermineAndCheckSamplingTimeViolateSamplingTime)
813{
814 robot_trajectory::RobotTrajectoryPtr first_trajectory =
815 std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, planning_group_);
816 robot_trajectory::RobotTrajectoryPtr second_trajectory =
817 std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, planning_group_);
818 double epsilon{ 0.0001 };
819 double sampling_time{ 0.0 };
820 double expected_sampling_time{ 0.1 };
821
822 moveit::core::RobotState rstate(robot_model_);
823 first_trajectory->insertWayPoint(0, rstate, expected_sampling_time);
824 first_trajectory->insertWayPoint(1, rstate, expected_sampling_time);
825 first_trajectory->insertWayPoint(2, rstate, expected_sampling_time);
826 // Violate sampling time
827 first_trajectory->insertWayPoint(2, rstate, expected_sampling_time + 1.0);
828 first_trajectory->insertWayPoint(3, rstate, expected_sampling_time);
829
830 second_trajectory->insertWayPoint(0, rstate, expected_sampling_time);
831 second_trajectory->insertWayPoint(1, rstate, expected_sampling_time);
832 second_trajectory->insertWayPoint(2, rstate, expected_sampling_time);
833 second_trajectory->insertWayPoint(3, rstate, expected_sampling_time);
834
835 EXPECT_FALSE(pilz_industrial_motion_planner::determineAndCheckSamplingTime(first_trajectory, second_trajectory,
836 epsilon, sampling_time));
837 EXPECT_EQ(expected_sampling_time, sampling_time);
838}
839
851TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testIsRobotStateEqualPositionUnequal)
852{
853 moveit::core::RobotState rstate_1 = moveit::core::RobotState(robot_model_);
854 moveit::core::RobotState rstate_2 = moveit::core::RobotState(robot_model_);
855
856 double default_joint_position[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
857 rstate_1.setJointGroupPositions(planning_group_, default_joint_position);
858 // Ensure that the joint positions of both robot states are different
859 default_joint_position[0] = default_joint_position[0] + 70.0;
860 rstate_2.setJointGroupPositions(planning_group_, default_joint_position);
861
862 double epsilon{ 0.0001 };
863 EXPECT_FALSE(pilz_industrial_motion_planner::isRobotStateEqual(rstate_1, rstate_2, planning_group_, epsilon));
864}
865
877TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testIsRobotStateEqualVelocityUnequal)
878{
879 moveit::core::RobotState rstate_1 = moveit::core::RobotState(robot_model_);
880 moveit::core::RobotState rstate_2 = moveit::core::RobotState(robot_model_);
881
882 // Ensure that the joint positions of both robot state are equal
883 double default_joint_position[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
884 rstate_1.setJointGroupPositions(planning_group_, default_joint_position);
885 rstate_2.setJointGroupPositions(planning_group_, default_joint_position);
886
887 double default_joint_velocity[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
888 rstate_1.setJointGroupVelocities(planning_group_, default_joint_velocity);
889 // Ensure that the joint velocites of both robot states are different
890 default_joint_velocity[1] = default_joint_velocity[1] + 10.0;
891 rstate_2.setJointGroupVelocities(planning_group_, default_joint_velocity);
892
893 double epsilon{ 0.0001 };
894 EXPECT_FALSE(pilz_industrial_motion_planner::isRobotStateEqual(rstate_1, rstate_2, planning_group_, epsilon));
895}
896
908TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testIsRobotStateEqualAccelerationUnequal)
909{
910 moveit::core::RobotState rstate_1 = moveit::core::RobotState(robot_model_);
911 moveit::core::RobotState rstate_2 = moveit::core::RobotState(robot_model_);
912
913 // Ensure that the joint positions of both robot state are equal
914 double default_joint_position[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
915 rstate_1.setJointGroupPositions(planning_group_, default_joint_position);
916 rstate_2.setJointGroupPositions(planning_group_, default_joint_position);
917
918 // Ensure that the joint velocities of both robot state are equal
919 double default_joint_velocity[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
920 rstate_1.setJointGroupVelocities(planning_group_, default_joint_velocity);
921 rstate_2.setJointGroupVelocities(planning_group_, default_joint_velocity);
922
923 double default_joint_acceleration[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
924 rstate_1.setJointGroupAccelerations(planning_group_, default_joint_acceleration);
925 // Ensure that the joint accelerations of both robot states are different
926 default_joint_acceleration[1] = default_joint_acceleration[1] + 10.0;
927 rstate_2.setJointGroupAccelerations(planning_group_, default_joint_acceleration);
928
929 double epsilon{ 0.0001 };
930 EXPECT_FALSE(pilz_industrial_motion_planner::isRobotStateEqual(rstate_1, rstate_2, planning_group_, epsilon));
931}
932
944TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testIsRobotStateStationaryVelocityUnequal)
945{
946 moveit::core::RobotState rstate_1 = moveit::core::RobotState(robot_model_);
947
948 // Ensure that the joint velocities are NOT zero
949 double default_joint_velocity[6] = { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
950 rstate_1.setJointGroupVelocities(planning_group_, default_joint_velocity);
951
952 double epsilon{ 0.0001 };
953 EXPECT_FALSE(pilz_industrial_motion_planner::isRobotStateStationary(rstate_1, planning_group_, epsilon));
954}
955
967TEST_F(TrajectoryFunctionsTestFlangeAndGripper, testIsRobotStateStationaryAccelerationUnequal)
968{
969 moveit::core::RobotState rstate_1 = moveit::core::RobotState(robot_model_);
970
971 // Ensure that the joint velocities are zero
972 double default_joint_velocity[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
973 rstate_1.setJointGroupVelocities(planning_group_, default_joint_velocity);
974
975 // Ensure that the joint acceleration are NOT zero
976 double default_joint_acceleration[6] = { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
977 rstate_1.setJointGroupAccelerations(planning_group_, default_joint_acceleration);
978
979 double epsilon{ 0.0001 };
980 EXPECT_FALSE(pilz_industrial_motion_planner::isRobotStateStationary(rstate_1, planning_group_, epsilon));
981}
982
983int main(int argc, char** argv)
984{
985 rclcpp::init(argc, argv);
986 testing::InitGoogleTest(&argc, argv);
987 return RUN_ALL_TESTS();
988}
std::unique_ptr< robot_model_loader::RobotModelLoader > rm_loader_
void SetUp() override
Create test scenario for trajectory functions.
random_numbers::RandomNumberGenerator rng_
moveit::core::RobotModelConstPtr robot_model_
std::map< std::string, double > zero_state_
planning_scene::PlanningSceneConstPtr planning_scene_
bool tfNear(const Eigen::Isometry3d &pose1, const Eigen::Isometry3d &pose2, double epsilon)
check if two transformations are close
Parametrized class for tests with and without gripper.
const std::vector< std::string > & getActiveJointModelNames() const
Get the names of the active joints in this group. These are the names of the joints returned by getJo...
const kinematics::KinematicsBaseConstPtr getSolverInstance() const
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition robot_state.h:90
void setVariablePositions(const double *position)
It is assumed positions is an array containing the new positions for all variables in this state....
void setJointGroupAccelerations(const std::string &joint_group_name, const double *gstate)
Given accelerations for the variables that make up a group, in the order found in the group (includin...
void setJointGroupVelocities(const std::string &joint_group_name, const double *gstate)
Given velocities for the variables that make up a group, in the order found in the group (including v...
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
Given positions for the variables that make up a group, in the order found in the group (including va...
const Eigen::Isometry3d & getFrameTransform(const std::string &frame_id, bool *frame_found=nullptr)
Get the transformation matrix from the model frame (root of model) to the frame identified by frame_i...
void setToRandomPositions()
Set all joints to random values. Values will be within default bounds.
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
void update(bool force=false)
Update all transforms.
bool setFromIK(const JointModelGroup *group, const geometry_msgs::msg::Pose &pose, double timeout=0.0, const GroupStateValidityCallbackFn &constraint=GroupStateValidityCallbackFn(), const kinematics::KinematicsQueryOptions &options=kinematics::KinematicsQueryOptions(), const kinematics::KinematicsBase::IKCostFn &cost_function=kinematics::KinematicsBase::IKCostFn())
If the group this state corresponds to is a chain and a solver is available, then the joint values ca...
Container for JointLimits, essentially a map with convenience functions. Adds the ability to as for l...
bool isRobotStateStationary(const moveit::core::RobotState &state, const std::string &group, double EPSILON)
check if the robot state have zero velocity/acceleration
bool determineAndCheckSamplingTime(const robot_trajectory::RobotTrajectoryPtr &first_trajectory, const robot_trajectory::RobotTrajectoryPtr &second_trajectory, double EPSILON, double &sampling_time)
Determines the sampling time and checks that both trajectroies use the same sampling time.
bool verifySampleJointLimits(const std::map< std::string, double > &position_last, const std::map< std::string, double > &velocity_last, const std::map< std::string, double > &position_current, double duration_last, double duration_current, const JointLimitsContainer &joint_limits)
verify the velocity/acceleration limits of current sample (based on backward difference computation) ...
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.
bool computePoseIK(const planning_scene::PlanningSceneConstPtr &scene, const std::string &group_name, const std::string &link_name, const Eigen::Isometry3d &pose, const std::string &frame_id, const std::map< std::string, double > &seed, std::map< std::string, double > &solution, bool check_self_collision=true, const double timeout=0.0)
compute the inverse kinematics of a given pose, also check robot self collision
bool isRobotStateEqual(const moveit::core::RobotState &state1, const moveit::core::RobotState &state2, const std::string &joint_group_name, double epsilon)
Check if the two robot states have the same joint position/velocity/acceleration.
bool computeLinkFK(const planning_scene::PlanningSceneConstPtr &scene, const std::string &link_name, const std::map< std::string, double > &joint_state, Eigen::Isometry3d &pose)
compute the pose of a link at give robot state
void checkRobotModel(const moveit::core::RobotModelConstPtr &robot_model, const std::string &group_name, const std::string &link_name)
A set of options for the kinematics solver.
std::vector< CartesianTrajectoryPoint > points
Extends joint_limits_interface::JointLimits with a deceleration parameter.
const std::string PARAM_PLANNING_GROUP_NAME("planning_group")
const std::string RANDOM_TEST_NUMBER("random_test_number")
int main(int argc, char **argv)
const std::string IK_FAST_LINK_NAME("ik_fast_link")
TEST_F(TrajectoryFunctionsTestFlangeAndGripper, TipLinkFK)
Test the forward kinematics function with simple robot poses for robot tip link using robot model wit...
const std::string ROBOT_TCP_LINK_NAME("tcp_link")
const std::string GROUP_TIP_LINK_NAME("group_tip_link")