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 <gtest/gtest.h>
42 
43 class RobotTrajectoryTestFixture : public testing::Test
44 {
45 protected:
46  moveit::core::RobotModelConstPtr robot_model_;
47  moveit::core::RobotStatePtr robot_state_;
48  const std::string robot_model_name_ = "panda";
49  const std::string arm_jmg_name_ = "panda_arm";
50  const std::string arm_state_name_ = "ready";
51 
52 protected:
53  void SetUp() override
54  {
56  robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
57  robot_state_->setToDefaultValues();
58  robot_state_->setVariableVelocity(/*index*/ 0, /*value*/ 1.0);
59  robot_state_->setVariableAcceleration(/*index*/ 0, /*value*/ -0.1);
60  robot_state_->update();
61  }
62 
63  void TearDown() override
64  {
65  }
66 
67  void initTestTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
68  {
69  // Init a trajectory
70  ASSERT_TRUE(robot_model_->hasJointModelGroup(arm_jmg_name_))
71  << "Robot model does not have group: " << arm_jmg_name_;
72 
73  trajectory = std::make_shared<robot_trajectory::RobotTrajectory>(robot_model_, arm_jmg_name_);
74 
75  EXPECT_EQ(trajectory->getGroupName(), arm_jmg_name_) << "Generated trajectory group name does not match";
76  EXPECT_TRUE(trajectory->empty()) << "Generated trajectory not empty";
77 
78  double duration_from_previous = 0.1;
79  std::size_t waypoint_count = 5;
80  for (std::size_t ix = 0; ix < waypoint_count; ++ix)
81  {
82  trajectory->addSuffixWayPoint(*robot_state_, duration_from_previous);
83  }
84 
85  // Quick check that getDuration is working correctly
86  EXPECT_EQ(trajectory->getDuration(), duration_from_previous * waypoint_count)
87  << "Generated trajectory duration incorrect";
88  EXPECT_EQ(waypoint_count, trajectory->getWayPointDurations().size())
89  << "Generated trajectory has the wrong number of waypoints";
90  EXPECT_EQ(waypoint_count, trajectory->size());
91  }
92 
93  void copyTrajectory(const robot_trajectory::RobotTrajectoryPtr& trajectory,
94  robot_trajectory::RobotTrajectoryPtr& trajectory_copy, bool deepcopy)
95  {
96  // Copy the trajectory
97  trajectory_copy = std::make_shared<robot_trajectory::RobotTrajectory>(*trajectory, deepcopy);
98  // Quick check that the getDuration values match
99  EXPECT_EQ(trajectory_copy->getDuration(), trajectory->getDuration());
100  EXPECT_EQ(trajectory_copy->getWayPointDurations().size(), trajectory->getWayPointDurations().size());
101  }
102 
103  void modifyFirstWaypointPtrAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
104  {
106  // Get the first waypoint by POINTER, modify it, and check that the value WAS updated in trajectory
108  // Get the first waypoint by shared pointer
109  moveit::core::RobotStatePtr trajectory_first_waypoint = trajectory->getWayPointPtr(0);
110  // Get the first waypoint joint values
111  std::vector<double> trajectory_first_state;
112  trajectory_first_waypoint->copyJointGroupPositions(arm_jmg_name_, trajectory_first_state);
113 
114  // Modify the first waypoint joint values
115  trajectory_first_state[0] += 0.01;
116  trajectory_first_waypoint->setJointGroupPositions(arm_jmg_name_, trajectory_first_state);
117 
118  // Check that the trajectory's first waypoint was updated
119  moveit::core::RobotStatePtr trajectory_first_waypoint_after_update = trajectory->getWayPointPtr(0);
120  std::vector<double> trajectory_first_state_after_update;
121  trajectory_first_waypoint_after_update->copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
122  EXPECT_EQ(trajectory_first_state[0], trajectory_first_state_after_update[0]);
123 
124  // Modify the first waypoint duration
125  double trajectory_first_duration_before_update = trajectory->getWayPointDurationFromPrevious(0);
126  double new_duration = trajectory_first_duration_before_update + 0.1;
127  trajectory->setWayPointDurationFromPrevious(0, new_duration);
128 
129  // Check that the trajectory's first duration was updated
130  EXPECT_EQ(trajectory->getWayPointDurationFromPrevious(0), new_duration);
131  }
132 
133  void modifyFirstWaypointAndCheckTrajectory(robot_trajectory::RobotTrajectoryPtr& trajectory)
134  {
136  // Get the first waypoint by VALUE, modify it, and check that the value WAS NOT updated in trajectory
138  // Get the first waypoint by shared pointer
139  moveit::core::RobotState trajectory_first_waypoint = trajectory->getWayPoint(0);
140  // Get the first waypoint joint values
141  std::vector<double> trajectory_first_state;
142  trajectory_first_waypoint.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state);
143 
144  // Modify the first waypoint joint values
145  trajectory_first_state[0] += 0.01;
146  trajectory_first_waypoint.setJointGroupPositions(arm_jmg_name_, trajectory_first_state);
147 
148  // Check that the trajectory's first waypoint was updated
149  moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
150  std::vector<double> trajectory_first_state_after_update;
151  trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
152  EXPECT_NE(trajectory_first_state[0], trajectory_first_state_after_update[0]);
153  }
154 };
155 
156 TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByPtr)
157 {
158  robot_trajectory::RobotTrajectoryPtr trajectory;
159  initTestTrajectory(trajectory);
160  modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
161 }
162 
163 TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByValue)
164 {
165  robot_trajectory::RobotTrajectoryPtr trajectory;
166  initTestTrajectory(trajectory);
167  modifyFirstWaypointAndCheckTrajectory(trajectory);
168 }
169 
171 {
172  robot_trajectory::RobotTrajectoryPtr trajectory;
173  initTestTrajectory(trajectory);
174  moveit_msgs::msg::RobotTrajectory initial_trajectory_msg;
175  trajectory->getRobotTrajectoryMsg(initial_trajectory_msg);
176 
177  trajectory->reverse().reverse();
178 
179  moveit_msgs::msg::RobotTrajectory edited_trajectory_msg;
180  trajectory->getRobotTrajectoryMsg(edited_trajectory_msg);
181 
182  EXPECT_EQ(initial_trajectory_msg, edited_trajectory_msg);
183 }
184 
186 {
187  robot_trajectory::RobotTrajectoryPtr initial_trajectory;
188  initTestTrajectory(initial_trajectory);
189  moveit_msgs::msg::RobotTrajectory initial_trajectory_msg;
190  initial_trajectory->getRobotTrajectoryMsg(initial_trajectory_msg);
191 
192  robot_trajectory::RobotTrajectory trajectory(robot_model_);
193  trajectory.setGroupName(arm_jmg_name_)
194  .clear()
195  .setRobotTrajectoryMsg(*robot_state_, initial_trajectory_msg)
196  .reverse()
197  .addSuffixWayPoint(*robot_state_, 0.1)
198  .addPrefixWayPoint(*robot_state_, 0.1)
199  .insertWayPoint(1, *robot_state_, 0.1)
200  .append(*initial_trajectory, 0.1);
201 
202  EXPECT_EQ(trajectory.getGroupName(), arm_jmg_name_);
203  EXPECT_EQ(trajectory.getWayPointCount(), initial_trajectory->getWayPointCount() * 2 + 3);
204 }
205 
207 {
208  robot_trajectory::RobotTrajectoryPtr initial_trajectory;
209  initTestTrajectory(initial_trajectory);
210  EXPECT_EQ(initial_trajectory->getWayPointCount(), size_t(5));
211 
212  // Append to the first
213  robot_trajectory::RobotTrajectoryPtr traj2;
214  initTestTrajectory(traj2);
215  EXPECT_EQ(traj2->getWayPointCount(), size_t(5));
216 
217  // After append() we should have 10 waypoints, all with 0.1s duration
218  const double expected_duration = 0.1;
219  initial_trajectory->append(*traj2, expected_duration, 0, 5);
220  EXPECT_EQ(initial_trajectory->getWayPointCount(), size_t(10));
221 
222  EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(4), expected_duration);
223  EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(5), expected_duration);
224  EXPECT_EQ(initial_trajectory->getWayPointDurationFromPrevious(6), expected_duration);
225 }
226 
227 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryShallowCopy)
228 {
229  bool deepcopy = false;
230 
231  robot_trajectory::RobotTrajectoryPtr trajectory;
232  robot_trajectory::RobotTrajectoryPtr trajectory_copy;
233 
234  initTestTrajectory(trajectory);
235  copyTrajectory(trajectory, trajectory_copy, deepcopy);
236  modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
237 
238  // Check that modifying the waypoint also modified the trajectory
239  moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
240  std::vector<double> trajectory_first_state_after_update;
241  trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
242 
243  // Get the first waypoint in the modified trajectory_copy
244  moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
245  std::vector<double> trajectory_copy_first_state_after_update;
246  trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
247  trajectory_copy_first_state_after_update);
248 
249  // Check that we updated the joint position correctly in the trajectory
250  EXPECT_EQ(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
251 }
252 
253 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDeepCopy)
254 {
255  bool deepcopy = true;
256 
257  robot_trajectory::RobotTrajectoryPtr trajectory;
258  robot_trajectory::RobotTrajectoryPtr trajectory_copy;
259 
260  initTestTrajectory(trajectory);
261  copyTrajectory(trajectory, trajectory_copy, deepcopy);
262  modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
263 
264  // Check that modifying the waypoint also modified the trajectory
265  moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
266  std::vector<double> trajectory_first_state_after_update;
267  trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
268 
269  // Get the first waypoint in the modified trajectory_copy
270  moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
271  std::vector<double> trajectory_copy_first_state_after_update;
272  trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
273  trajectory_copy_first_state_after_update);
274 
275  // Check that joint positions changed in the original trajectory but not the deep copy
276  EXPECT_NE(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
277  // Check that the first waypoint duration changed in the original trajectory but not the deep copy
278  EXPECT_NE(trajectory->getWayPointDurationFromPrevious(0), trajectory_copy->getWayPointDurationFromPrevious(0));
279 }
280 
281 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryIterator)
282 {
283  robot_trajectory::RobotTrajectoryPtr trajectory;
284  initTestTrajectory(trajectory);
285 
286  ASSERT_EQ(5u, trajectory->size());
287  std::vector<double> positions;
288 
289  double start_pos = 0.0;
290 
291  for (size_t i = 0; i < trajectory->size(); ++i)
292  {
293  auto waypoint = trajectory->getWayPointPtr(i);
294  // modify joint values
295  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
296  start_pos = positions[0];
297  positions[0] += 0.01 * i;
298  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
299  }
300 
301  unsigned int count = 0;
302  for (const auto& waypoint_and_duration : *trajectory)
303  {
304  const auto& waypoint = waypoint_and_duration.first;
305  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
306  EXPECT_EQ(start_pos + count * 0.01, positions[0]);
307  count++;
308  }
309 
310  EXPECT_EQ(count, trajectory->size());
311 
312  // Consistency checks
313  EXPECT_EQ(trajectory->begin(), trajectory->begin());
314  EXPECT_EQ(trajectory->end(), trajectory->end());
315 
316  // trajectory has length 5; incrementing begin 5 times should reach the end
317  EXPECT_NE(trajectory->begin(), trajectory->end());
318  EXPECT_NE(++trajectory->begin(), trajectory->end());
319  EXPECT_NE(++(++trajectory->begin()), trajectory->end());
320  EXPECT_NE(++(++(++trajectory->begin())), trajectory->end());
321  EXPECT_NE(++(++(++(++trajectory->begin()))), trajectory->end());
322  EXPECT_EQ(++(++(++(++(++trajectory->begin())))), trajectory->end());
323 }
324 
325 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryLength)
326 {
327  robot_trajectory::RobotTrajectoryPtr trajectory;
328  initTestTrajectory(trajectory);
329  EXPECT_FLOAT_EQ(robot_trajectory::path_length(*trajectory), 0.0);
330 
331  // modify joint values so the smoothness is nonzero
332  std::vector<double> positions;
333  for (size_t i = 0; i < trajectory->size(); ++i)
334  {
335  auto waypoint = trajectory->getWayPointPtr(i);
336  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
337  positions[0] += 0.01 * i;
338  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
339  }
340  EXPECT_GT(robot_trajectory::path_length(*trajectory), 0.0);
341 }
342 
343 TEST_F(RobotTrajectoryTestFixture, RobotTrajectorySmoothness)
344 {
345  robot_trajectory::RobotTrajectoryPtr trajectory;
346  initTestTrajectory(trajectory);
347 
348  // modify joint values so the smoothness is nonzero
349  std::vector<double> positions;
350  for (size_t i = 0; i < trajectory->size(); ++i)
351  {
352  auto waypoint = trajectory->getWayPointPtr(i);
353  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
354  positions[0] += 0.01 * i;
355  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
356  }
357 
358  const auto smoothness = robot_trajectory::smoothness(*trajectory);
359  ASSERT_TRUE(smoothness.has_value());
360  EXPECT_GT(smoothness.value(), 0.0);
361 
362  // Check for empty trajectory
363  trajectory->clear();
364  EXPECT_FALSE(robot_trajectory::smoothness(*trajectory).has_value());
365 }
366 
367 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDensity)
368 {
369  robot_trajectory::RobotTrajectoryPtr trajectory;
370  initTestTrajectory(trajectory);
371 
372  // If trajectory has all equal state, and length zero, density should be null.
373  auto density = robot_trajectory::waypoint_density(*trajectory);
374  ASSERT_FALSE(density.has_value());
375 
376  // modify joint values so the density is nonzero
377  std::vector<double> positions;
378  for (size_t i = 0; i < trajectory->size(); ++i)
379  {
380  auto waypoint = trajectory->getWayPointPtr(i);
381  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
382  positions[0] += 0.01 * i;
383  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
384  }
385 
386  density = robot_trajectory::waypoint_density(*trajectory);
387  ASSERT_TRUE(density.has_value());
388  EXPECT_GT(density.value(), 0.0);
389 
390  // Check for empty trajectory
391  trajectory->clear();
392  density = robot_trajectory::waypoint_density(*trajectory);
393  EXPECT_FALSE(density.has_value());
394 }
395 
396 int main(int argc, char** argv)
397 {
398  testing::InitGoogleTest(&argc, argv);
399  return RUN_ALL_TESTS();
400 }
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 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:605
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:691
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.
double path_length(RobotTrajectory const &trajectory)
Calculate the path length of a given trajectory based on the accumulated robot state distances....
std::optional< double > waypoint_density(RobotTrajectory const &trajectory)
Calculate the waypoint density of a trajectory.
std::optional< double > smoothness(RobotTrajectory const &trajectory)
Calculate the smoothness of a given trajectory.
int main(int argc, char **argv)
TEST_F(RobotTrajectoryTestFixture, ModifyFirstWaypointByPtr)