moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
test_robot_trajectory.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2013, Willow Garage, Inc.
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 the Willow Garage 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/* Author: Ioan Sucan */
36
41#include <moveit_msgs/msg/robot_trajectory.hpp>
42#include <urdf_parser/urdf_parser.h>
43#include <gtest/gtest.h>
44
45class RobotTrajectoryTestFixture : public testing::Test
46{
47protected:
48 moveit::core::RobotModelConstPtr robot_model_;
49 moveit::core::RobotStatePtr robot_state_;
50 const std::string robot_model_name_ = "panda";
51 const std::string arm_jmg_name_ = "panda_arm";
52 const std::string arm_state_name_ = "ready";
53
54protected:
55 void SetUp() override
56 {
58 robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
59 robot_state_->setToDefaultValues();
60 robot_state_->setVariableVelocity(/*index*/ 0, /*value*/ 1.0);
61 robot_state_->setVariableAcceleration(/*index*/ 0, /*value*/ -0.1);
62 robot_state_->update();
63 }
64
65 void TearDown() override
66 {
67 }
68
69 void initTestTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
70 {
71 // Init a trajectory
72 ASSERT_TRUE(robot_model_->hasJointModelGroup(arm_jmg_name_))
73 << "Robot model does not have group: " << arm_jmg_name_;
74
75 trajectory = std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, arm_jmg_name_);
76
77 EXPECT_EQ(trajectory->getGroupName(), arm_jmg_name_) << "Generated trajectory group name does not match";
78 EXPECT_TRUE(trajectory->empty()) << "Generated trajectory not empty";
79
80 double duration_from_previous = 0.1;
81 std::size_t waypoint_count = 5;
82 for (std::size_t ix = 0; ix < waypoint_count; ++ix)
83 {
84 trajectory->addSuffixWayPoint(*robot_state_, duration_from_previous);
85 }
86
87 // Quick check that getDuration is working correctly
88 EXPECT_EQ(trajectory->getDuration(), duration_from_previous * waypoint_count)
89 << "Generated trajectory duration incorrect";
90 EXPECT_EQ(waypoint_count, trajectory->getWayPointDurations().size())
91 << "Generated trajectory has the wrong number of waypoints";
92 EXPECT_EQ(waypoint_count, trajectory->size());
93 }
94
95 void copyTrajectory(const robot_trajectory::RobotTrajectoryPtr& trajectory,
96 robot_trajectory::RobotTrajectoryPtr& trajectory_copy, bool deepcopy)
97 {
98 // Copy the trajectory
99 trajectory_copy = std::make_shared<robot_trajectory::RobotTrajectory>(*trajectory, deepcopy);
100 // Quick check that the getDuration values match
101 EXPECT_EQ(trajectory_copy->getDuration(), trajectory->getDuration());
102 EXPECT_EQ(trajectory_copy->getWayPointDurations().size(), trajectory->getWayPointDurations().size());
103 }
104
105 void modifyFirstWaypointPtrAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
106 {
108 // Get the first waypoint by POINTER, modify it, and check that the value WAS updated in trajectory
110 // Get the first waypoint by shared pointer
111 moveit::core::RobotStatePtr trajectory_first_waypoint = trajectory->getWayPointPtr(0);
112 // Get the first waypoint joint values
113 std::vector<double> trajectory_first_state;
114 trajectory_first_waypoint->copyJointGroupPositions(arm_jmg_name_, trajectory_first_state);
115
116 // Modify the first waypoint joint values
117 trajectory_first_state[0] += 0.01;
118 trajectory_first_waypoint->setJointGroupPositions(arm_jmg_name_, trajectory_first_state);
119
120 // Check that the trajectory's first waypoint was updated
121 moveit::core::RobotStatePtr trajectory_first_waypoint_after_update = trajectory->getWayPointPtr(0);
122 std::vector<double> trajectory_first_state_after_update;
123 trajectory_first_waypoint_after_update->copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
124 EXPECT_EQ(trajectory_first_state[0], trajectory_first_state_after_update[0]);
125
126 // Modify the first waypoint duration
127 double trajectory_first_duration_before_update = trajectory->getWayPointDurationFromPrevious(0);
128 double new_duration = trajectory_first_duration_before_update + 0.1;
129 trajectory->setWayPointDurationFromPrevious(0, new_duration);
130
131 // Check that the trajectory's first duration was updated
132 EXPECT_EQ(trajectory->getWayPointDurationFromPrevious(0), new_duration);
133 }
134
135 void modifyFirstWaypointAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
136 {
138 // Get the first waypoint by VALUE, modify it, and check that the value WAS NOT updated in trajectory
140 // Get the first waypoint by shared pointer
141 moveit::core::RobotState trajectory_first_waypoint = trajectory->getWayPoint(0);
142 // Get the first waypoint joint values
143 std::vector<double> trajectory_first_state;
144 trajectory_first_waypoint.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state);
145
146 // Modify the first waypoint joint values
147 trajectory_first_state[0] += 0.01;
148 trajectory_first_waypoint.setJointGroupPositions(arm_jmg_name_, trajectory_first_state);
149
150 // Check that the trajectory's first waypoint was updated
151 moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
152 std::vector<double> trajectory_first_state_after_update;
153 trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
154 EXPECT_NE(trajectory_first_state[0], trajectory_first_state_after_update[0]);
155 }
156};
157
158class OneRobot : public testing::Test
159{
160protected:
161 void SetUp() override
162 {
163 static const std::string MODEL2 =
164 "<?xml version=\"1.0\" ?>"
165 "<robot name=\"one_robot\">"
166 "<link name=\"base_link\">"
167 " <inertial>"
168 " <mass value=\"2.81\"/>"
169 " <origin rpy=\"0 0 0\" xyz=\"0.0 0.0 .0\"/>"
170 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
171 " </inertial>"
172 " <collision name=\"my_collision\">"
173 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
174 " <geometry>"
175 " <box size=\"1 2 1\" />"
176 " </geometry>"
177 " </collision>"
178 " <visual>"
179 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
180 " <geometry>"
181 " <box size=\"1 2 1\" />"
182 " </geometry>"
183 " </visual>"
184 "</link>"
185 "<joint name=\"panda_joint0\" type=\"continuous\">"
186 " <axis xyz=\"0 0 1\"/>"
187 " <parent link=\"base_link\"/>"
188 " <child link=\"link_a\"/>"
189 " <origin rpy=\" 0.0 0 0 \" xyz=\"0.0 0 0 \"/>"
190 "</joint>"
191 "<link name=\"link_a\">"
192 " <inertial>"
193 " <mass value=\"1.0\"/>"
194 " <origin rpy=\"0 0 0\" xyz=\"0.0 0.0 .0\"/>"
195 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
196 " </inertial>"
197 " <collision>"
198 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
199 " <geometry>"
200 " <box size=\"1 2 1\" />"
201 " </geometry>"
202 " </collision>"
203 " <visual>"
204 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
205 " <geometry>"
206 " <box size=\"1 2 1\" />"
207 " </geometry>"
208 " </visual>"
209 "</link>"
210 "<joint name=\"joint_b\" type=\"fixed\">"
211 " <parent link=\"link_a\"/>"
212 " <child link=\"link_b\"/>"
213 " <origin rpy=\" 0.0 -0.42 0 \" xyz=\"0.0 0.5 0 \"/>"
214 "</joint>"
215 "<link name=\"link_b\">"
216 " <inertial>"
217 " <mass value=\"1.0\"/>"
218 " <origin rpy=\"0 0 0\" xyz=\"0.0 0.0 .0\"/>"
219 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
220 " </inertial>"
221 " <collision>"
222 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
223 " <geometry>"
224 " <box size=\"1 2 1\" />"
225 " </geometry>"
226 " </collision>"
227 " <visual>"
228 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
229 " <geometry>"
230 " <box size=\"1 2 1\" />"
231 " </geometry>"
232 " </visual>"
233 "</link>"
234 " <joint name=\"panda_joint1\" type=\"prismatic\">"
235 " <axis xyz=\"1 0 0\"/>"
236 " <limit effort=\"100.0\" lower=\"0.0\" upper=\"0.09\" velocity=\"0.2\"/>"
237 " <safety_controller k_position=\"20.0\" k_velocity=\"500.0\" soft_lower_limit=\"0.0\" "
238 "soft_upper_limit=\"0.089\"/>"
239 " <parent link=\"link_b\"/>"
240 " <child link=\"link_c\"/>"
241 " <origin rpy=\" 0.0 0.42 0.0 \" xyz=\"0.0 -0.1 0 \"/>"
242 " </joint>"
243 "<link name=\"link_c\">"
244 " <inertial>"
245 " <mass value=\"1.0\"/>"
246 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 .0\"/>"
247 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
248 " </inertial>"
249 " <collision>"
250 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
251 " <geometry>"
252 " <box size=\"1 2 1\" />"
253 " </geometry>"
254 " </collision>"
255 " <visual>"
256 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
257 " <geometry>"
258 " <box size=\"1 2 1\" />"
259 " </geometry>"
260 " </visual>"
261 "</link>"
262 " <joint name=\"mim_f\" type=\"prismatic\">"
263 " <axis xyz=\"1 0 0\"/>"
264 " <limit effort=\"100.0\" lower=\"0.0\" upper=\"0.19\" velocity=\"0.2\"/>"
265 " <parent link=\"link_c\"/>"
266 " <child link=\"link_d\"/>"
267 " <origin rpy=\" 0.0 0.0 0.0 \" xyz=\"0.1 0.1 0 \"/>"
268 " <mimic joint=\"joint_f\" multiplier=\"1.5\" offset=\"0.1\"/>"
269 " </joint>"
270 " <joint name=\"joint_f\" type=\"prismatic\">"
271 " <axis xyz=\"1 0 0\"/>"
272 " <limit effort=\"100.0\" lower=\"0.0\" upper=\"0.19\" velocity=\"0.2\"/>"
273 " <parent link=\"link_d\"/>"
274 " <child link=\"link_e\"/>"
275 " <origin rpy=\" 0.0 0.0 0.0 \" xyz=\"0.1 0.1 0 \"/>"
276 " </joint>"
277 "<link name=\"link_d\">"
278 " <collision>"
279 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
280 " <geometry>"
281 " <box size=\"1 2 1\" />"
282 " </geometry>"
283 " </collision>"
284 " <visual>"
285 " <origin rpy=\"0 1 0\" xyz=\"0 0.1 0\"/>"
286 " <geometry>"
287 " <box size=\"1 2 1\" />"
288 " </geometry>"
289 " </visual>"
290 "</link>"
291 "<link name=\"link_e\">"
292 " <collision>"
293 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
294 " <geometry>"
295 " <box size=\"1 2 1\" />"
296 " </geometry>"
297 " </collision>"
298 " <visual>"
299 " <origin rpy=\"0 1 0\" xyz=\"0 0.1 0\"/>"
300 " <geometry>"
301 " <box size=\"1 2 1\" />"
302 " </geometry>"
303 " </visual>"
304 "</link>"
305 "</robot>";
306
307 static const std::string SMODEL2 =
308 "<?xml version=\"1.0\" ?>"
309 "<robot name=\"one_robot\">"
310 "<virtual_joint name=\"base_joint\" child_link=\"base_link\" parent_frame=\"odom_combined\" type=\"planar\"/>"
311 "<group name=\"panda_arm\">"
312 "<chain base_link=\"base_link\" tip_link=\"link_e\"/>"
313 "<joint name=\"base_joint\"/>"
314 "</group>"
315 "</robot>";
316
317 urdf::ModelInterfaceSharedPtr urdf_model = urdf::parseURDF(MODEL2);
318 srdf::ModelSharedPtr srdf_model = std::make_shared<srdf::Model>();
319 srdf_model->initString(*urdf_model, SMODEL2);
320 robot_model_ = std::make_shared<moveit::core::RobotModel>(urdf_model, srdf_model);
321 robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
322 robot_state_->setToDefaultValues();
323 robot_state_->setVariablePositions({ "panda_joint0" }, { -3.1416 });
324 robot_state_->setVariableVelocity(/*index*/ 0, /*value*/ 1.0);
325 robot_state_->setVariableAcceleration(/*index*/ 0, /*value*/ -0.1);
326 robot_state_->update();
327 }
328
329 void TearDown() override
330 {
331 }
332
333 void initTestTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
334 {
335 // Init a traj
336 ASSERT_TRUE(robot_model_->hasJointModelGroup(arm_jmg_name_))
337 << "Robot model does not have group: " << arm_jmg_name_;
338
339 trajectory = std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, arm_jmg_name_);
340
341 EXPECT_EQ(trajectory->getGroupName(), arm_jmg_name_) << "Generated trajectory group name does not match";
342 EXPECT_TRUE(trajectory->empty()) << "Generated trajectory not empty";
343
344 double duration_from_previous = 0.1;
345 std::size_t waypoint_count = 5;
346 for (std::size_t ix = 0; ix < waypoint_count; ++ix)
347 trajectory->addSuffixWayPoint(*robot_state_, duration_from_previous);
348 // Quick check that getDuration is working correctly
349 EXPECT_EQ(trajectory->getDuration(), duration_from_previous * waypoint_count)
350 << "Generated trajectory duration incorrect";
351 EXPECT_EQ(waypoint_count, trajectory->getWayPointDurations().size())
352 << "Generated trajectory has the wrong number of waypoints";
353 EXPECT_EQ(waypoint_count, trajectory->size());
354 }
355
356protected:
357 moveit::core::RobotModelConstPtr robot_model_;
358 moveit::core::RobotStatePtr robot_state_;
359 const std::string arm_jmg_name_ = "panda_arm";
360};
361
362TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByPtr)
363{
364 robot_trajectory::RobotTrajectoryPtr trajectory;
365 initTestTrajectory(trajectory);
366 modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
367}
368
369TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByValue)
370{
371 robot_trajectory::RobotTrajectoryPtr trajectory;
372 initTestTrajectory(trajectory);
373 modifyFirstWaypointAndCheckTrajectory(trajectory);
374}
375
377{
378 robot_trajectory::RobotTrajectoryPtr trajectory;
379 initTestTrajectory(trajectory);
380 moveit_msgs::msg::RobotTrajectory initial_trajectory_msg;
381 trajectory->getRobotTrajectoryMsg(initial_trajectory_msg);
382
383 trajectory->reverse().reverse();
384
385 moveit_msgs::msg::RobotTrajectory edited_trajectory_msg;
386 trajectory->getRobotTrajectoryMsg(edited_trajectory_msg);
387
388 EXPECT_EQ(initial_trajectory_msg, edited_trajectory_msg);
389}
390
392{
393 robot_trajectory::RobotTrajectoryPtr initial_trajectory;
394 initTestTrajectory(initial_trajectory);
395 moveit_msgs::msg::RobotTrajectory initial_trajectory_msg;
396 initial_trajectory->getRobotTrajectoryMsg(initial_trajectory_msg);
397
398 robot_trajectory::RobotTrajectory trajectory(robot_model_);
399 trajectory.setGroupName(arm_jmg_name_)
400 .clear()
401 .setRobotTrajectoryMsg(*robot_state_, initial_trajectory_msg)
402 .reverse()
403 .addSuffixWayPoint(*robot_state_, 0.1)
404 .addPrefixWayPoint(*robot_state_, 0.1)
405 .insertWayPoint(1, *robot_state_, 0.1)
406 .append(*initial_trajectory, 0.1);
407
408 EXPECT_EQ(trajectory.getGroupName(), arm_jmg_name_);
409 EXPECT_EQ(trajectory.getWayPointCount(), initial_trajectory->getWayPointCount() * 2 + 3);
410}
411
413{
414 robot_trajectory::RobotTrajectoryPtr initial_trajectory;
415 initTestTrajectory(initial_trajectory);
416 EXPECT_EQ(initial_trajectory->getWayPointCount(), size_t(5));
417
418 // Append to the first
419 robot_trajectory::RobotTrajectoryPtr traj2;
420 initTestTrajectory(traj2);
421 EXPECT_EQ(traj2->getWayPointCount(), size_t(5));
422
423 // After append() we should have 10 waypoints, all with 0.1s duration
424 const double expected_duration = 0.1;
425 initial_trajectory->append(*traj2, expected_duration, 0, 5);
426 EXPECT_EQ(initial_trajectory->getWayPointCount(), size_t(10));
427
428 EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(4), expected_duration);
429 EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(5), expected_duration);
430 EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(6), expected_duration);
431}
432
433TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryShallowCopy)
434{
435 bool deepcopy = false;
436
437 robot_trajectory::RobotTrajectoryPtr trajectory;
438 robot_trajectory::RobotTrajectoryPtr trajectory_copy;
439
440 initTestTrajectory(trajectory);
441 copyTrajectory(trajectory, trajectory_copy, deepcopy);
442 modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
443
444 // Check that modifying the waypoint also modified the trajectory
445 moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
446 std::vector<double> trajectory_first_state_after_update;
447 trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
448
449 // Get the first waypoint in the modified trajectory_copy
450 moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
451 std::vector<double> trajectory_copy_first_state_after_update;
452 trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
453 trajectory_copy_first_state_after_update);
454
455 // Check that we updated the joint position correctly in the trajectory
456 EXPECT_EQ(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
457}
458
459TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDeepCopy)
460{
461 bool deepcopy = true;
462
463 robot_trajectory::RobotTrajectoryPtr trajectory;
464 robot_trajectory::RobotTrajectoryPtr trajectory_copy;
465
466 initTestTrajectory(trajectory);
467 copyTrajectory(trajectory, trajectory_copy, deepcopy);
468 modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
469
470 // Check that modifying the waypoint also modified the trajectory
471 moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
472 std::vector<double> trajectory_first_state_after_update;
473 trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
474
475 // Get the first waypoint in the modified trajectory_copy
476 moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
477 std::vector<double> trajectory_copy_first_state_after_update;
478 trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
479 trajectory_copy_first_state_after_update);
480
481 // Check that joint positions changed in the original trajectory but not the deep copy
482 EXPECT_NE(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
483 // Check that the first waypoint duration changed in the original trajectory but not the deep copy
484 EXPECT_NE(trajectory->getWayPointDurationFromPrevious(0), trajectory_copy->getWayPointDurationFromPrevious(0));
485}
486
487TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryIterator)
488{
489 robot_trajectory::RobotTrajectoryPtr trajectory;
490 initTestTrajectory(trajectory);
491
492 ASSERT_EQ(5u, trajectory->size());
493 std::vector<double> positions;
494
495 double start_pos = 0.0;
496
497 for (size_t i = 0; i < trajectory->size(); ++i)
498 {
499 auto waypoint = trajectory->getWayPointPtr(i);
500 // modify joint values
501 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
502 start_pos = positions[0];
503 positions[0] += 0.01 * i;
504 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
505 }
506
507 unsigned int count = 0;
508 for (const auto& waypoint_and_duration : *trajectory)
509 {
510 const auto& waypoint = waypoint_and_duration.first;
511 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
512 EXPECT_EQ(start_pos + count * 0.01, positions[0]);
513 count++;
514 }
515
516 EXPECT_EQ(count, trajectory->size());
517
518 // Consistency checks
519 EXPECT_EQ(trajectory->begin(), trajectory->begin());
520 EXPECT_EQ(trajectory->end(), trajectory->end());
521
522 // trajectory has length 5; incrementing begin 5 times should reach the end
523 EXPECT_NE(trajectory->begin(), trajectory->end());
524 EXPECT_NE(++trajectory->begin(), trajectory->end());
525 EXPECT_NE(++(++trajectory->begin()), trajectory->end());
526 EXPECT_NE(++(++(++trajectory->begin())), trajectory->end());
527 EXPECT_NE(++(++(++(++trajectory->begin()))), trajectory->end());
528 EXPECT_EQ(++(++(++(++(++trajectory->begin())))), trajectory->end());
529}
530
531TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryLength)
532{
533 robot_trajectory::RobotTrajectoryPtr trajectory;
534 initTestTrajectory(trajectory);
535 EXPECT_FLOAT_EQ(robot_trajectory::pathLength(*trajectory), 0.0);
536
537 // modify joint values so the smoothness is nonzero
538 std::vector<double> positions;
539 for (size_t i = 0; i < trajectory->size(); ++i)
540 {
541 auto waypoint = trajectory->getWayPointPtr(i);
542 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
543 positions[0] += 0.01 * i;
544 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
545 }
546 EXPECT_GT(robot_trajectory::pathLength(*trajectory), 0.0);
547}
548
549TEST_F(RobotTrajectoryTestFixture, RobotTrajectorySmoothness)
550{
551 robot_trajectory::RobotTrajectoryPtr trajectory;
552 initTestTrajectory(trajectory);
553
554 // modify joint values so the smoothness is nonzero
555 std::vector<double> positions;
556 for (size_t i = 0; i < trajectory->size(); ++i)
557 {
558 auto waypoint = trajectory->getWayPointPtr(i);
559 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
560 positions[0] += 0.01 * i;
561 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
562 }
563
564 const auto smoothness = robot_trajectory::smoothness(*trajectory);
565 ASSERT_TRUE(smoothness.has_value());
566 EXPECT_GT(smoothness.value(), 0.0);
567
568 // Check for empty trajectory
569 trajectory->clear();
570 EXPECT_FALSE(robot_trajectory::smoothness(*trajectory).has_value());
571}
572
573TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDensity)
574{
575 robot_trajectory::RobotTrajectoryPtr trajectory;
576 initTestTrajectory(trajectory);
577
578 // If trajectory has all equal state, and length zero, density should be null.
579 auto density = robot_trajectory::waypointDensity(*trajectory);
580 ASSERT_FALSE(density.has_value());
581
582 // modify joint values so the density is nonzero
583 std::vector<double> positions;
584 for (size_t i = 0; i < trajectory->size(); ++i)
585 {
586 auto waypoint = trajectory->getWayPointPtr(i);
587 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
588 positions[0] += 0.01 * i;
589 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
590 }
591
592 density = robot_trajectory::waypointDensity(*trajectory);
593 ASSERT_TRUE(density.has_value());
594 EXPECT_GT(density.value(), 0.0);
595
596 // Check for empty trajectory
597 trajectory->clear();
598 density = robot_trajectory::waypointDensity(*trajectory);
599 EXPECT_FALSE(density.has_value());
600}
601
602TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryFindWayPointIndicesBetweenWaypoints)
603{
604 robot_trajectory::RobotTrajectoryPtr trajectory;
605 initTestTrajectory(trajectory);
606 EXPECT_EQ(trajectory->size(), 5);
607 EXPECT_EQ(trajectory->getDuration(), 0.5);
608
609 int before = -1;
610 int after = -1;
611 double blend = -1.0;
612
613 EXPECT_NO_THROW(trajectory->findWayPointIndicesForDurationAfterStart(0.15, before, after, blend));
614 EXPECT_EQ(before, 0);
615 EXPECT_EQ(after, 1);
616 EXPECT_NEAR(blend, /*between 0 and 1*/ 0.5, 1e-6);
617
618 EXPECT_NO_THROW(trajectory->findWayPointIndicesForDurationAfterStart(0.3, before, after, blend));
619 EXPECT_EQ(before, 1);
620 EXPECT_EQ(after, 2);
621 EXPECT_NEAR(blend, /*exactly at 2*/ 1.0, 1e-6);
622}
623
624TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryFindWayPointIndicesAtLastOfManyWaypoints)
625{
626 robot_trajectory::RobotTrajectoryPtr trajectory;
627 initTestTrajectory(trajectory);
628
629 int before = -1;
630 int after = -1;
631 double blend = -1.0;
632
633 const double total_duration = trajectory->getDuration();
634 EXPECT_NO_THROW(trajectory->findWayPointIndicesForDurationAfterStart(total_duration, before, after, blend));
635 EXPECT_EQ(before, 3);
636 EXPECT_EQ(after, 4);
637 EXPECT_DOUBLE_EQ(blend, 1.0);
638}
639
640TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryFindWayPointIndicesAfterLastWaypoint)
641{
642 robot_trajectory::RobotTrajectoryPtr trajectory;
643 initTestTrajectory(trajectory);
644
645 const double total_duration = trajectory->getDuration();
646 const double outbound_duration = total_duration + 100.0;
647 EXPECT_GT(outbound_duration, total_duration);
648
649 int before = -1;
650 int after = -1;
651 double blend = -1.0;
652 EXPECT_NO_THROW(trajectory->findWayPointIndicesForDurationAfterStart(outbound_duration, before, after, blend));
653 EXPECT_EQ(before, 4);
654 EXPECT_EQ(after, 4);
655 EXPECT_DOUBLE_EQ(blend, 1.0);
656}
657
658TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryFindWayPointIndicesEmptyWaypoints)
659{
660 robot_trajectory::RobotTrajectory empty_traj(robot_model_, arm_jmg_name_);
661 const double total_duration = empty_traj.getDuration();
662 EXPECT_DOUBLE_EQ(total_duration, 0.0);
663
664 const double outbound_duration = 1.0;
665 EXPECT_GT(outbound_duration, total_duration);
666
667 int before = -1;
668 int after = -1;
669 double blend = -1.0;
670 EXPECT_NO_THROW(empty_traj.findWayPointIndicesForDurationAfterStart(outbound_duration, before, after, blend));
671 EXPECT_EQ(before, 0);
672 EXPECT_EQ(after, 0);
673 EXPECT_DOUBLE_EQ(blend, 0.0);
674}
675
676TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryFindWayPointIndicesBeforeFirstWaypoint)
677{
678 robot_trajectory::RobotTrajectoryPtr trajectory;
679 initTestTrajectory(trajectory);
680
681 int before = -1;
682 int after = -1;
683 double blend = -1.0;
684
685 EXPECT_NO_THROW(trajectory->findWayPointIndicesForDurationAfterStart(-0.1, before, after, blend));
686 EXPECT_EQ(before, 0);
687 EXPECT_EQ(after, 0);
688 EXPECT_DOUBLE_EQ(blend, 0.0);
689}
690
691TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryFindWayPointIndicesAtLastOfSingleWaypoint)
692{
693 robot_trajectory::RobotTrajectory trajectory(robot_model_, arm_jmg_name_);
694 trajectory.addSuffixWayPoint(robot_state_, 0.0);
695
696 int before = -1;
697 int after = -1;
698 double blend = -1.0;
699
700 const double total_duration = trajectory.getDuration();
701 EXPECT_NO_THROW(trajectory.findWayPointIndicesForDurationAfterStart(total_duration, before, after, blend));
702 EXPECT_EQ(before, 0);
703 EXPECT_EQ(after, 0);
704 EXPECT_DOUBLE_EQ(blend, 1.0);
705}
706
708{
709 const double epsilon = 1e-4;
710
711 // An initial joint position needs unwinding
712 {
713 robot_trajectory::RobotTrajectoryPtr trajectory;
714 initTestTrajectory(trajectory);
715 moveit::core::RobotStatePtr& first_waypoint = trajectory->getFirstWayPointPtr();
716 const double random_large_angle = 20.2; // rad, should unwind to 1.350444 rad
717 first_waypoint->setVariablePosition("panda_joint0", random_large_angle);
718 first_waypoint->update();
719 trajectory->unwind();
720 EXPECT_NEAR(trajectory->getFirstWayPoint().getVariablePosition("panda_joint0"), 1.350444, epsilon);
721 }
722}
723
724TEST_F(OneRobot, UnwindFromState)
725{
726 const double epsilon = 1e-4;
727
728 // Unwind a trajectory from a robot state
729 {
730 robot_trajectory::RobotTrajectoryPtr trajectory;
731 initTestTrajectory(trajectory);
732 moveit::core::RobotState first_waypoint = trajectory->getFirstWayPoint();
733 // Wrap the continuous joint by 4PI as if this happened to be the current state of the robot
734 const double wrapped_angle = first_waypoint.getVariablePosition("panda_joint0") + 12.566371;
735 first_waypoint.setVariablePosition("panda_joint0", wrapped_angle);
736 first_waypoint.update();
737 // Unwind the trajectory from the wound up robot state
738 trajectory->unwind(first_waypoint);
739 EXPECT_NEAR(trajectory->getFirstWayPoint().getVariablePosition("panda_joint0"), wrapped_angle, epsilon);
740 }
741}
742
743TEST_F(OneRobot, MultiDofTrajectoryToJointStates)
744{
745 // GIVEN a RobotTrajectory with two waypoints of a robot model that has a multi-dof base joint
746 robot_trajectory::RobotTrajectory trajectory(robot_model_);
747 trajectory.addSuffixWayPoint(robot_state_, 0.01 /* dt */);
748 trajectory.addSuffixWayPoint(robot_state_, 0.01 /* dt */);
749
750 // WHEN converting the RobotTrajectory to a JointTrajectory message, including mdof variables
751 auto maybe_trajectory_msg = toJointTrajectory(trajectory, true /* include_mdof_joints */);
752
753 // WHEN the optional trajectory result is valid (always assumed)
754 ASSERT_TRUE(maybe_trajectory_msg.has_value());
755
756 const auto& traj = maybe_trajectory_msg.value();
757 const auto& joint_names = traj.joint_names;
758
759 size_t joint_variable_count = 0u;
760 for (const auto& active_joint : robot_model_->getActiveJointModels())
761 {
762 joint_variable_count += active_joint->getVariableCount();
763 }
764
765 // THEN all joints names should include the base joint variables
766 EXPECT_EQ(joint_names.size(), joint_variable_count);
767 EXPECT_TRUE(std::find(joint_names.begin(), joint_names.end(), "base_joint/x") != joint_names.end());
768 // THEN the size of the trajectory should equal the input size
769 ASSERT_EQ(traj.points.size(), 2u);
770 // THEN all positions size should equal the variable size
771 EXPECT_EQ(traj.points.at(0).positions.size(), joint_variable_count);
772 EXPECT_EQ(traj.points.at(1).positions.size(), joint_variable_count);
773}
774
775TEST_F(OneRobot, SetMultiDofTrajectory)
776{
777 // GIVEN a RobotTrajectory message with a multi-dof joint trajectory including velocities and accelerations
778 robot_trajectory::RobotTrajectory trajectory(robot_model_);
779 moveit_msgs::msg::RobotTrajectory trajectory_msg;
780
781 trajectory_msg.multi_dof_joint_trajectory.joint_names = { "base_joint" };
782
783 trajectory_msg.multi_dof_joint_trajectory.points.resize(1);
784 trajectory_msg.multi_dof_joint_trajectory.points[0].transforms.resize(1);
785 trajectory_msg.multi_dof_joint_trajectory.points[0].transforms[0].translation.x = 0.01;
786
787 trajectory_msg.multi_dof_joint_trajectory.points[0].velocities.resize(1);
788 trajectory_msg.multi_dof_joint_trajectory.points[0].velocities[0].linear.x = 0.02;
789 trajectory_msg.multi_dof_joint_trajectory.points[0].velocities[0].linear.y = 0.03;
790
791 trajectory_msg.multi_dof_joint_trajectory.points[0].accelerations.resize(1);
792 trajectory_msg.multi_dof_joint_trajectory.points[0].accelerations[0].linear.x = 0.04;
793 trajectory_msg.multi_dof_joint_trajectory.points[0].accelerations[0].linear.y = 0.05;
794
795 // WHEN setting that RobotTrajectory message for a RobotTrajectory
796 trajectory.setRobotTrajectoryMsg(*robot_state_, trajectory_msg);
797
798 // THEN positions should be set correctly in the RobotTrajectory waypoints
799 const auto wp = trajectory.getWayPoint(0);
800 EXPECT_EQ(wp.getVariablePosition("base_joint/x"), 0.01);
801
802 // THEN velocities should be set correctly in the RobotTrajectory waypoints
803 EXPECT_EQ(wp.getVariableVelocity("base_joint/x"), 0.02);
804 EXPECT_EQ(wp.getVariableVelocity("base_joint/y"), 0.03);
805
806 // THEN accelerations should be set correctly in the RobotTrajectory waypoints
807 EXPECT_EQ(wp.getVariableAcceleration("base_joint/x"), 0.04);
808 EXPECT_EQ(wp.getVariableAcceleration("base_joint/y"), 0.05);
809}
810int main(int argc, char** argv)
811{
812 testing::InitGoogleTest(&argc, argv);
813 return RUN_ALL_TESTS();
814}
void TearDown() override
const std::string arm_jmg_name_
void initTestTrajectory(robot_trajectory::RobotTrajectoryPtr &trajectory)
void SetUp() override
moveit::core::RobotStatePtr robot_state_
moveit::core::RobotModelConstPtr robot_model_
void modifyFirstWaypointPtrAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr &trajectory)
void copyTrajectory(const robot_trajectory::RobotTrajectoryPtr &trajectory, robot_trajectory::RobotTrajectoryPtr &trajectory_copy, bool deepcopy)
moveit::core::RobotModelConstPtr robot_model_
moveit::core::RobotStatePtr robot_state_
void modifyFirstWaypointAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr &trajectory)
void initTestTrajectory(robot_trajectory::RobotTrajectoryPtr &trajectory)
Representation of a robot's state. This includes position, velocity, acceleration and effort.
void setVariablePosition(const std::string &variable, double value)
Set the position of a single variable. An exception is thrown if the variable name is not known.
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...
void copyJointGroupPositions(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the position values of the variables that make up the group into another loca...
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.
Maintain a sequence of waypoints and the time durations between these waypoints.
RobotTrajectory & addPrefixWayPoint(const moveit::core::RobotState &state, double dt)
const std::string & getGroupName() const
RobotTrajectory & addSuffixWayPoint(const moveit::core::RobotState &state, double dt)
Add a point to the trajectory.
void findWayPointIndicesForDurationAfterStart(double duration, int &before, int &after, double &blend) const
Finds the waypoint indices before and after a duration from start.
RobotTrajectory & setRobotTrajectoryMsg(const moveit::core::RobotState &reference_state, const trajectory_msgs::msg::JointTrajectory &trajectory)
Copy the content of the trajectory message into this class. The trajectory message itself is not requ...
RobotTrajectory & append(const RobotTrajectory &source, double dt, size_t start_index=0, size_t end_index=std::numeric_limits< std::size_t >::max())
Add a specified part of a trajectory to the end of the current trajectory. The default (when start_in...
RobotTrajectory & setGroupName(const std::string &group_name)
const moveit::core::RobotState & getWayPoint(std::size_t index) const
RobotTrajectory & insertWayPoint(std::size_t index, const moveit::core::RobotState &state, double dt)
moveit::core::RobotModelPtr loadTestingRobotModel(const std::string &package_name, const std::string &urdf_relative_path, const std::string &srdf_relative_path)
Loads a robot model given a URDF and SRDF file in a package.
std::optional< double > waypointDensity(const RobotTrajectory &trajectory)
Calculate the waypoint density of a trajectory.
std::optional< double > smoothness(const RobotTrajectory &trajectory)
Calculate the smoothness of a given trajectory.
double pathLength(const RobotTrajectory &trajectory)
Calculate the path length of a given trajectory based on the accumulated robot state distances....
int main(int argc, char **argv)
TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByPtr)