moveit2
The MoveIt Motion Planning Framework for ROS 2.
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 
44 class RobotTrajectoryTestFixture : public testing::Test
45 {
46 protected:
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 
53 protected:
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 
157 class OneRobot : public testing::Test
158 {
159 protected:
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 
355 protected:
356  moveit::core::RobotModelConstPtr robot_model_;
357  moveit::core::RobotStatePtr robot_state_;
358  const std::string arm_jmg_name_ = "panda_arm";
359 };
360 
361 TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByPtr)
362 {
363  robot_trajectory::RobotTrajectoryPtr trajectory;
364  initTestTrajectory(trajectory);
365  modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
366 }
367 
368 TEST_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 
432 TEST_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 
458 TEST_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 
486 TEST_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 
530 TEST_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 
548 TEST_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 
572 TEST_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 
601 TEST_F(OneRobot, Unwind)
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 
618 TEST_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 
637 int main(int argc, char** argv)
638 {
639  testing::InitGoogleTest(&argc, argv);
640  return RUN_ALL_TESTS();
641 }
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.
Definition: robot_state.h:188
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...
Definition: robot_state.h:583
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...
Definition: robot_state.h:669
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
Definition: robot_state.h:207
void update(bool force=false)
Update all transforms.
Maintain a sequence of waypoints and the time durations between these waypoints.
const std::string & getGroupName() const
RobotTrajectory & setGroupName(const std::string &group_name)
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 & insertWayPoint(std::size_t index, const moveit::core::RobotState &state, double dt)
RobotTrajectory & addPrefixWayPoint(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)