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 <urdf_parser/urdf_parser.h>
42#include <gtest/gtest.h>
43
44class RobotTrajectoryTestFixture : public testing::Test
45{
46protected:
47 moveit::core::RobotModelConstPtr robot_model_;
48 moveit::core::RobotStatePtr robot_state_;
49 const std::string robot_model_name_ = "panda";
50 const std::string arm_jmg_name_ = "panda_arm";
51 const std::string arm_state_name_ = "ready";
52
53protected:
54 void SetUp() override
55 {
57 robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
58 robot_state_->setToDefaultValues();
59 robot_state_->setVariableVelocity(/*index*/ 0, /*value*/ 1.0);
60 robot_state_->setVariableAcceleration(/*index*/ 0, /*value*/ -0.1);
61 robot_state_->update();
62 }
63
64 void TearDown() override
65 {
66 }
67
68 void initTestTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
69 {
70 // Init a trajectory
71 ASSERT_TRUE(robot_model_->hasJointModelGroup(arm_jmg_name_))
72 << "Robot model does not have group: " << arm_jmg_name_;
73
74 trajectory = std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, arm_jmg_name_);
75
76 EXPECT_EQ(trajectory->getGroupName(), arm_jmg_name_) << "Generated trajectory group name does not match";
77 EXPECT_TRUE(trajectory->empty()) << "Generated trajectory not empty";
78
79 double duration_from_previous = 0.1;
80 std::size_t waypoint_count = 5;
81 for (std::size_t ix = 0; ix < waypoint_count; ++ix)
82 {
83 trajectory->addSuffixWayPoint(*robot_state_, duration_from_previous);
84 }
85
86 // Quick check that getDuration is working correctly
87 EXPECT_EQ(trajectory->getDuration(), duration_from_previous * waypoint_count)
88 << "Generated trajectory duration incorrect";
89 EXPECT_EQ(waypoint_count, trajectory->getWayPointDurations().size())
90 << "Generated trajectory has the wrong number of waypoints";
91 EXPECT_EQ(waypoint_count, trajectory->size());
92 }
93
94 void copyTrajectory(const robot_trajectory::RobotTrajectoryPtr& trajectory,
95 robot_trajectory::RobotTrajectoryPtr& trajectory_copy, bool deepcopy)
96 {
97 // Copy the trajectory
98 trajectory_copy = std::make_shared<robot_trajectory::RobotTrajectory>(*trajectory, deepcopy);
99 // Quick check that the getDuration values match
100 EXPECT_EQ(trajectory_copy->getDuration(), trajectory->getDuration());
101 EXPECT_EQ(trajectory_copy->getWayPointDurations().size(), trajectory->getWayPointDurations().size());
102 }
103
104 void modifyFirstWaypointPtrAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
105 {
107 // Get the first waypoint by POINTER, modify it, and check that the value WAS updated in trajectory
109 // Get the first waypoint by shared pointer
110 moveit::core::RobotStatePtr trajectory_first_waypoint = trajectory->getWayPointPtr(0);
111 // Get the first waypoint joint values
112 std::vector<double> trajectory_first_state;
113 trajectory_first_waypoint->copyJointGroupPositions(arm_jmg_name_, trajectory_first_state);
114
115 // Modify the first waypoint joint values
116 trajectory_first_state[0] += 0.01;
117 trajectory_first_waypoint->setJointGroupPositions(arm_jmg_name_, trajectory_first_state);
118
119 // Check that the trajectory's first waypoint was updated
120 moveit::core::RobotStatePtr trajectory_first_waypoint_after_update = trajectory->getWayPointPtr(0);
121 std::vector<double> trajectory_first_state_after_update;
122 trajectory_first_waypoint_after_update->copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
123 EXPECT_EQ(trajectory_first_state[0], trajectory_first_state_after_update[0]);
124
125 // Modify the first waypoint duration
126 double trajectory_first_duration_before_update = trajectory->getWayPointDurationFromPrevious(0);
127 double new_duration = trajectory_first_duration_before_update + 0.1;
128 trajectory->setWayPointDurationFromPrevious(0, new_duration);
129
130 // Check that the trajectory's first duration was updated
131 EXPECT_EQ(trajectory->getWayPointDurationFromPrevious(0), new_duration);
132 }
133
134 void modifyFirstWaypointAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
135 {
137 // Get the first waypoint by VALUE, modify it, and check that the value WAS NOT updated in trajectory
139 // Get the first waypoint by shared pointer
140 moveit::core::RobotState trajectory_first_waypoint = trajectory->getWayPoint(0);
141 // Get the first waypoint joint values
142 std::vector<double> trajectory_first_state;
143 trajectory_first_waypoint.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state);
144
145 // Modify the first waypoint joint values
146 trajectory_first_state[0] += 0.01;
147 trajectory_first_waypoint.setJointGroupPositions(arm_jmg_name_, trajectory_first_state);
148
149 // Check that the trajectory's first waypoint was updated
150 moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
151 std::vector<double> trajectory_first_state_after_update;
152 trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
153 EXPECT_NE(trajectory_first_state[0], trajectory_first_state_after_update[0]);
154 }
155};
156
157class OneRobot : public testing::Test
158{
159protected:
160 void SetUp() override
161 {
162 static const std::string MODEL2 =
163 "<?xml version=\"1.0\" ?>"
164 "<robot name=\"one_robot\">"
165 "<link name=\"base_link\">"
166 " <inertial>"
167 " <mass value=\"2.81\"/>"
168 " <origin rpy=\"0 0 0\" xyz=\"0.0 0.0 .0\"/>"
169 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
170 " </inertial>"
171 " <collision name=\"my_collision\">"
172 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
173 " <geometry>"
174 " <box size=\"1 2 1\" />"
175 " </geometry>"
176 " </collision>"
177 " <visual>"
178 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
179 " <geometry>"
180 " <box size=\"1 2 1\" />"
181 " </geometry>"
182 " </visual>"
183 "</link>"
184 "<joint name=\"panda_joint0\" type=\"continuous\">"
185 " <axis xyz=\"0 0 1\"/>"
186 " <parent link=\"base_link\"/>"
187 " <child link=\"link_a\"/>"
188 " <origin rpy=\" 0.0 0 0 \" xyz=\"0.0 0 0 \"/>"
189 "</joint>"
190 "<link name=\"link_a\">"
191 " <inertial>"
192 " <mass value=\"1.0\"/>"
193 " <origin rpy=\"0 0 0\" xyz=\"0.0 0.0 .0\"/>"
194 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
195 " </inertial>"
196 " <collision>"
197 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
198 " <geometry>"
199 " <box size=\"1 2 1\" />"
200 " </geometry>"
201 " </collision>"
202 " <visual>"
203 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
204 " <geometry>"
205 " <box size=\"1 2 1\" />"
206 " </geometry>"
207 " </visual>"
208 "</link>"
209 "<joint name=\"joint_b\" type=\"fixed\">"
210 " <parent link=\"link_a\"/>"
211 " <child link=\"link_b\"/>"
212 " <origin rpy=\" 0.0 -0.42 0 \" xyz=\"0.0 0.5 0 \"/>"
213 "</joint>"
214 "<link name=\"link_b\">"
215 " <inertial>"
216 " <mass value=\"1.0\"/>"
217 " <origin rpy=\"0 0 0\" xyz=\"0.0 0.0 .0\"/>"
218 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
219 " </inertial>"
220 " <collision>"
221 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
222 " <geometry>"
223 " <box size=\"1 2 1\" />"
224 " </geometry>"
225 " </collision>"
226 " <visual>"
227 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
228 " <geometry>"
229 " <box size=\"1 2 1\" />"
230 " </geometry>"
231 " </visual>"
232 "</link>"
233 " <joint name=\"panda_joint1\" type=\"prismatic\">"
234 " <axis xyz=\"1 0 0\"/>"
235 " <limit effort=\"100.0\" lower=\"0.0\" upper=\"0.09\" velocity=\"0.2\"/>"
236 " <safety_controller k_position=\"20.0\" k_velocity=\"500.0\" soft_lower_limit=\"0.0\" "
237 "soft_upper_limit=\"0.089\"/>"
238 " <parent link=\"link_b\"/>"
239 " <child link=\"link_c\"/>"
240 " <origin rpy=\" 0.0 0.42 0.0 \" xyz=\"0.0 -0.1 0 \"/>"
241 " </joint>"
242 "<link name=\"link_c\">"
243 " <inertial>"
244 " <mass value=\"1.0\"/>"
245 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 .0\"/>"
246 " <inertia ixx=\"0.1\" ixy=\"-0.2\" ixz=\"0.5\" iyy=\"-.09\" iyz=\"1\" izz=\"0.101\"/>"
247 " </inertial>"
248 " <collision>"
249 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
250 " <geometry>"
251 " <box size=\"1 2 1\" />"
252 " </geometry>"
253 " </collision>"
254 " <visual>"
255 " <origin rpy=\"0 0 0\" xyz=\"0.0 0 0\"/>"
256 " <geometry>"
257 " <box size=\"1 2 1\" />"
258 " </geometry>"
259 " </visual>"
260 "</link>"
261 " <joint name=\"mim_f\" type=\"prismatic\">"
262 " <axis xyz=\"1 0 0\"/>"
263 " <limit effort=\"100.0\" lower=\"0.0\" upper=\"0.19\" velocity=\"0.2\"/>"
264 " <parent link=\"link_c\"/>"
265 " <child link=\"link_d\"/>"
266 " <origin rpy=\" 0.0 0.0 0.0 \" xyz=\"0.1 0.1 0 \"/>"
267 " <mimic joint=\"joint_f\" multiplier=\"1.5\" offset=\"0.1\"/>"
268 " </joint>"
269 " <joint name=\"joint_f\" type=\"prismatic\">"
270 " <axis xyz=\"1 0 0\"/>"
271 " <limit effort=\"100.0\" lower=\"0.0\" upper=\"0.19\" velocity=\"0.2\"/>"
272 " <parent link=\"link_d\"/>"
273 " <child link=\"link_e\"/>"
274 " <origin rpy=\" 0.0 0.0 0.0 \" xyz=\"0.1 0.1 0 \"/>"
275 " </joint>"
276 "<link name=\"link_d\">"
277 " <collision>"
278 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
279 " <geometry>"
280 " <box size=\"1 2 1\" />"
281 " </geometry>"
282 " </collision>"
283 " <visual>"
284 " <origin rpy=\"0 1 0\" xyz=\"0 0.1 0\"/>"
285 " <geometry>"
286 " <box size=\"1 2 1\" />"
287 " </geometry>"
288 " </visual>"
289 "</link>"
290 "<link name=\"link_e\">"
291 " <collision>"
292 " <origin rpy=\"0 0 0\" xyz=\"0 0 0\"/>"
293 " <geometry>"
294 " <box size=\"1 2 1\" />"
295 " </geometry>"
296 " </collision>"
297 " <visual>"
298 " <origin rpy=\"0 1 0\" xyz=\"0 0.1 0\"/>"
299 " <geometry>"
300 " <box size=\"1 2 1\" />"
301 " </geometry>"
302 " </visual>"
303 "</link>"
304 "</robot>";
305
306 static const std::string SMODEL2 =
307 "<?xml version=\"1.0\" ?>"
308 "<robot name=\"one_robot\">"
309 "<virtual_joint name=\"base_joint\" child_link=\"base_link\" parent_frame=\"odom_combined\" type=\"planar\"/>"
310 "<group name=\"panda_arm\">"
311 "<chain base_link=\"base_link\" tip_link=\"link_e\"/>"
312 "<joint name=\"base_joint\"/>"
313 "</group>"
314 "</robot>";
315
316 urdf::ModelInterfaceSharedPtr urdf_model = urdf::parseURDF(MODEL2);
317 srdf::ModelSharedPtr srdf_model = std::make_shared<srdf::Model>();
318 srdf_model->initString(*urdf_model, SMODEL2);
319 robot_model_ = std::make_shared<moveit::core::RobotModel>(urdf_model, srdf_model);
320 robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
321 robot_state_->setToDefaultValues();
322 robot_state_->setVariablePositions({ "panda_joint0" }, { -3.1416 });
323 robot_state_->setVariableVelocity(/*index*/ 0, /*value*/ 1.0);
324 robot_state_->setVariableAcceleration(/*index*/ 0, /*value*/ -0.1);
325 robot_state_->update();
326 }
327
328 void TearDown() override
329 {
330 }
331
332 void initTestTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
333 {
334 // Init a traj
335 ASSERT_TRUE(robot_model_->hasJointModelGroup(arm_jmg_name_))
336 << "Robot model does not have group: " << arm_jmg_name_;
337
338 trajectory = std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, arm_jmg_name_);
339
340 EXPECT_EQ(trajectory->getGroupName(), arm_jmg_name_) << "Generated trajectory group name does not match";
341 EXPECT_TRUE(trajectory->empty()) << "Generated trajectory not empty";
342
343 double duration_from_previous = 0.1;
344 std::size_t waypoint_count = 5;
345 for (std::size_t ix = 0; ix < waypoint_count; ++ix)
346 trajectory->addSuffixWayPoint(*robot_state_, duration_from_previous);
347 // Quick check that getDuration is working correctly
348 EXPECT_EQ(trajectory->getDuration(), duration_from_previous * waypoint_count)
349 << "Generated trajectory duration incorrect";
350 EXPECT_EQ(waypoint_count, trajectory->getWayPointDurations().size())
351 << "Generated trajectory has the wrong number of waypoints";
352 EXPECT_EQ(waypoint_count, trajectory->size());
353 }
354
355protected:
356 moveit::core::RobotModelConstPtr robot_model_;
357 moveit::core::RobotStatePtr robot_state_;
358 const std::string arm_jmg_name_ = "panda_arm";
359};
360
361TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByPtr)
362{
363 robot_trajectory::RobotTrajectoryPtr trajectory;
364 initTestTrajectory(trajectory);
365 modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
366}
367
368TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByValue)
369{
370 robot_trajectory::RobotTrajectoryPtr trajectory;
371 initTestTrajectory(trajectory);
372 modifyFirstWaypointAndCheckTrajectory(trajectory);
373}
374
376{
377 robot_trajectory::RobotTrajectoryPtr trajectory;
378 initTestTrajectory(trajectory);
379 moveit_msgs::msg::RobotTrajectory initial_trajectory_msg;
380 trajectory->getRobotTrajectoryMsg(initial_trajectory_msg);
381
382 trajectory->reverse().reverse();
383
384 moveit_msgs::msg::RobotTrajectory edited_trajectory_msg;
385 trajectory->getRobotTrajectoryMsg(edited_trajectory_msg);
386
387 EXPECT_EQ(initial_trajectory_msg, edited_trajectory_msg);
388}
389
391{
392 robot_trajectory::RobotTrajectoryPtr initial_trajectory;
393 initTestTrajectory(initial_trajectory);
394 moveit_msgs::msg::RobotTrajectory initial_trajectory_msg;
395 initial_trajectory->getRobotTrajectoryMsg(initial_trajectory_msg);
396
397 robot_trajectory::RobotTrajectory trajectory(robot_model_);
398 trajectory.setGroupName(arm_jmg_name_)
399 .clear()
400 .setRobotTrajectoryMsg(*robot_state_, initial_trajectory_msg)
401 .reverse()
402 .addSuffixWayPoint(*robot_state_, 0.1)
403 .addPrefixWayPoint(*robot_state_, 0.1)
404 .insertWayPoint(1, *robot_state_, 0.1)
405 .append(*initial_trajectory, 0.1);
406
407 EXPECT_EQ(trajectory.getGroupName(), arm_jmg_name_);
408 EXPECT_EQ(trajectory.getWayPointCount(), initial_trajectory->getWayPointCount() * 2 + 3);
409}
410
412{
413 robot_trajectory::RobotTrajectoryPtr initial_trajectory;
414 initTestTrajectory(initial_trajectory);
415 EXPECT_EQ(initial_trajectory->getWayPointCount(), size_t(5));
416
417 // Append to the first
418 robot_trajectory::RobotTrajectoryPtr traj2;
419 initTestTrajectory(traj2);
420 EXPECT_EQ(traj2->getWayPointCount(), size_t(5));
421
422 // After append() we should have 10 waypoints, all with 0.1s duration
423 const double expected_duration = 0.1;
424 initial_trajectory->append(*traj2, expected_duration, 0, 5);
425 EXPECT_EQ(initial_trajectory->getWayPointCount(), size_t(10));
426
427 EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(4), expected_duration);
428 EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(5), expected_duration);
429 EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(6), expected_duration);
430}
431
432TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryShallowCopy)
433{
434 bool deepcopy = false;
435
436 robot_trajectory::RobotTrajectoryPtr trajectory;
437 robot_trajectory::RobotTrajectoryPtr trajectory_copy;
438
439 initTestTrajectory(trajectory);
440 copyTrajectory(trajectory, trajectory_copy, deepcopy);
441 modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
442
443 // Check that modifying the waypoint also modified the trajectory
444 moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
445 std::vector<double> trajectory_first_state_after_update;
446 trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
447
448 // Get the first waypoint in the modified trajectory_copy
449 moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
450 std::vector<double> trajectory_copy_first_state_after_update;
451 trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
452 trajectory_copy_first_state_after_update);
453
454 // Check that we updated the joint position correctly in the trajectory
455 EXPECT_EQ(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
456}
457
458TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDeepCopy)
459{
460 bool deepcopy = true;
461
462 robot_trajectory::RobotTrajectoryPtr trajectory;
463 robot_trajectory::RobotTrajectoryPtr trajectory_copy;
464
465 initTestTrajectory(trajectory);
466 copyTrajectory(trajectory, trajectory_copy, deepcopy);
467 modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
468
469 // Check that modifying the waypoint also modified the trajectory
470 moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
471 std::vector<double> trajectory_first_state_after_update;
472 trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
473
474 // Get the first waypoint in the modified trajectory_copy
475 moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
476 std::vector<double> trajectory_copy_first_state_after_update;
477 trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
478 trajectory_copy_first_state_after_update);
479
480 // Check that joint positions changed in the original trajectory but not the deep copy
481 EXPECT_NE(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
482 // Check that the first waypoint duration changed in the original trajectory but not the deep copy
483 EXPECT_NE(trajectory->getWayPointDurationFromPrevious(0), trajectory_copy->getWayPointDurationFromPrevious(0));
484}
485
486TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryIterator)
487{
488 robot_trajectory::RobotTrajectoryPtr trajectory;
489 initTestTrajectory(trajectory);
490
491 ASSERT_EQ(5u, trajectory->size());
492 std::vector<double> positions;
493
494 double start_pos = 0.0;
495
496 for (size_t i = 0; i < trajectory->size(); ++i)
497 {
498 auto waypoint = trajectory->getWayPointPtr(i);
499 // modify joint values
500 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
501 start_pos = positions[0];
502 positions[0] += 0.01 * i;
503 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
504 }
505
506 unsigned int count = 0;
507 for (const auto& waypoint_and_duration : *trajectory)
508 {
509 const auto& waypoint = waypoint_and_duration.first;
510 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
511 EXPECT_EQ(start_pos + count * 0.01, positions[0]);
512 count++;
513 }
514
515 EXPECT_EQ(count, trajectory->size());
516
517 // Consistency checks
518 EXPECT_EQ(trajectory->begin(), trajectory->begin());
519 EXPECT_EQ(trajectory->end(), trajectory->end());
520
521 // trajectory has length 5; incrementing begin 5 times should reach the end
522 EXPECT_NE(trajectory->begin(), trajectory->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_EQ(++(++(++(++(++trajectory->begin())))), trajectory->end());
528}
529
530TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryLength)
531{
532 robot_trajectory::RobotTrajectoryPtr trajectory;
533 initTestTrajectory(trajectory);
534 EXPECT_FLOAT_EQ(robot_trajectory::pathLength(*trajectory), 0.0);
535
536 // modify joint values so the smoothness is nonzero
537 std::vector<double> positions;
538 for (size_t i = 0; i < trajectory->size(); ++i)
539 {
540 auto waypoint = trajectory->getWayPointPtr(i);
541 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
542 positions[0] += 0.01 * i;
543 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
544 }
545 EXPECT_GT(robot_trajectory::pathLength(*trajectory), 0.0);
546}
547
548TEST_F(RobotTrajectoryTestFixture, RobotTrajectorySmoothness)
549{
550 robot_trajectory::RobotTrajectoryPtr trajectory;
551 initTestTrajectory(trajectory);
552
553 // modify joint values so the smoothness is nonzero
554 std::vector<double> positions;
555 for (size_t i = 0; i < trajectory->size(); ++i)
556 {
557 auto waypoint = trajectory->getWayPointPtr(i);
558 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
559 positions[0] += 0.01 * i;
560 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
561 }
562
563 const auto smoothness = robot_trajectory::smoothness(*trajectory);
564 ASSERT_TRUE(smoothness.has_value());
565 EXPECT_GT(smoothness.value(), 0.0);
566
567 // Check for empty trajectory
568 trajectory->clear();
569 EXPECT_FALSE(robot_trajectory::smoothness(*trajectory).has_value());
570}
571
572TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDensity)
573{
574 robot_trajectory::RobotTrajectoryPtr trajectory;
575 initTestTrajectory(trajectory);
576
577 // If trajectory has all equal state, and length zero, density should be null.
578 auto density = robot_trajectory::waypointDensity(*trajectory);
579 ASSERT_FALSE(density.has_value());
580
581 // modify joint values so the density is nonzero
582 std::vector<double> positions;
583 for (size_t i = 0; i < trajectory->size(); ++i)
584 {
585 auto waypoint = trajectory->getWayPointPtr(i);
586 waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
587 positions[0] += 0.01 * i;
588 waypoint->setJointGroupPositions(arm_jmg_name_, positions);
589 }
590
591 density = robot_trajectory::waypointDensity(*trajectory);
592 ASSERT_TRUE(density.has_value());
593 EXPECT_GT(density.value(), 0.0);
594
595 // Check for empty trajectory
596 trajectory->clear();
597 density = robot_trajectory::waypointDensity(*trajectory);
598 EXPECT_FALSE(density.has_value());
599}
600
602{
603 const double epsilon = 1e-4;
604
605 // An initial joint position needs unwinding
606 {
607 robot_trajectory::RobotTrajectoryPtr trajectory;
608 initTestTrajectory(trajectory);
609 moveit::core::RobotStatePtr& first_waypoint = trajectory->getFirstWayPointPtr();
610 const double random_large_angle = 20.2; // rad, should unwind to 1.350444 rad
611 first_waypoint->setVariablePosition("panda_joint0", random_large_angle);
612 first_waypoint->update();
613 trajectory->unwind();
614 EXPECT_NEAR(trajectory->getFirstWayPoint().getVariablePosition("panda_joint0"), 1.350444, epsilon);
615 }
616}
617
618TEST_F(OneRobot, UnwindFromState)
619{
620 const double epsilon = 1e-4;
621
622 // Unwind a trajectory from a robot state
623 {
624 robot_trajectory::RobotTrajectoryPtr trajectory;
625 initTestTrajectory(trajectory);
626 moveit::core::RobotState first_waypoint = trajectory->getFirstWayPoint();
627 // Wrap the continuous joint by 4PI as if this happened to be the current state of the robot
628 const double wrapped_angle = first_waypoint.getVariablePosition("panda_joint0") + 12.566371;
629 first_waypoint.setVariablePosition("panda_joint0", wrapped_angle);
630 first_waypoint.update();
631 // Unwind the trajectory from the wound up robot state
632 trajectory->unwind(first_waypoint);
633 EXPECT_NEAR(trajectory->getFirstWayPoint().getVariablePosition("panda_joint0"), wrapped_angle, epsilon);
634 }
635}
636
637TEST_F(OneRobot, MultiDofTrajectoryToJointStates)
638{
639 // GIVEN a RobotTrajectory with two waypoints of a robot model that has a multi-dof base joint
640 robot_trajectory::RobotTrajectory trajectory(robot_model_);
641 trajectory.addSuffixWayPoint(robot_state_, 0.01 /* dt */);
642 trajectory.addSuffixWayPoint(robot_state_, 0.01 /* dt */);
643
644 // WHEN converting the RobotTrajectory to a JointTrajectory message, including mdof variables
645 auto maybe_trajectory_msg = toJointTrajectory(trajectory, true /* include_mdof_joints */);
646
647 // WHEN the optional trajectory result is valid (always assumed)
648 ASSERT_TRUE(maybe_trajectory_msg.has_value());
649
650 const auto traj = maybe_trajectory_msg.value();
651 const auto& joint_names = traj.joint_names;
652
653 size_t joint_variable_count = 0u;
654 for (const auto& active_joint : robot_model_->getActiveJointModels())
655 {
656 joint_variable_count += active_joint->getVariableCount();
657 }
658
659 // THEN all joints names should include the base joint variables
660 EXPECT_EQ(joint_names.size(), joint_variable_count);
661 EXPECT_TRUE(std::find(joint_names.begin(), joint_names.end(), "base_joint/x") != joint_names.end());
662 // THEN the size of the trajectory should equal the input size
663 ASSERT_EQ(traj.points.size(), 2u);
664 // THEN all positions size should equal the variable size
665 EXPECT_EQ(traj.points.at(0).positions.size(), joint_variable_count);
666 EXPECT_EQ(traj.points.at(1).positions.size(), joint_variable_count);
667}
668
669int main(int argc, char** argv)
670{
671 testing::InitGoogleTest(&argc, argv);
672 return RUN_ALL_TESTS();
673}
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.
Definition robot_state.h:90
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.
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)
RobotTrajectory & insertWayPoint(std::size_t index, const moveit::core::RobotState &state, double dt)
moveit::core::RobotModelPtr loadTestingRobotModel(const std::string &robot_name)
Loads a robot from moveit_resources.
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)