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 
206 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryShallowCopy)
207 {
208  bool deepcopy = false;
209 
210  robot_trajectory::RobotTrajectoryPtr trajectory;
211  robot_trajectory::RobotTrajectoryPtr trajectory_copy;
212 
213  initTestTrajectory(trajectory);
214  copyTrajectory(trajectory, trajectory_copy, deepcopy);
215  modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
216 
217  // Check that modifying the waypoint also modified the trajectory
218  moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
219  std::vector<double> trajectory_first_state_after_update;
220  trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
221 
222  // Get the first waypoint in the modified trajectory_copy
223  moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
224  std::vector<double> trajectory_copy_first_state_after_update;
225  trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
226  trajectory_copy_first_state_after_update);
227 
228  // Check that we updated the joint position correctly in the trajectory
229  EXPECT_EQ(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
230 }
231 
232 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDeepCopy)
233 {
234  bool deepcopy = true;
235 
236  robot_trajectory::RobotTrajectoryPtr trajectory;
237  robot_trajectory::RobotTrajectoryPtr trajectory_copy;
238 
239  initTestTrajectory(trajectory);
240  copyTrajectory(trajectory, trajectory_copy, deepcopy);
241  modifyFirstWaypointPtrAndCheckTrajectory(trajectory);
242 
243  // Check that modifying the waypoint also modified the trajectory
244  moveit::core::RobotState trajectory_first_waypoint_after_update = trajectory->getWayPoint(0);
245  std::vector<double> trajectory_first_state_after_update;
246  trajectory_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_, trajectory_first_state_after_update);
247 
248  // Get the first waypoint in the modified trajectory_copy
249  moveit::core::RobotState trajectory_copy_first_waypoint_after_update = trajectory_copy->getWayPoint(0);
250  std::vector<double> trajectory_copy_first_state_after_update;
251  trajectory_copy_first_waypoint_after_update.copyJointGroupPositions(arm_jmg_name_,
252  trajectory_copy_first_state_after_update);
253 
254  // Check that joint positions changed in the original trajectory but not the deep copy
255  EXPECT_NE(trajectory_first_state_after_update[0], trajectory_copy_first_state_after_update[0]);
256  // Check that the first waypoint duration changed in the original trajectory but not the deep copy
257  EXPECT_NE(trajectory->getWayPointDurationFromPrevious(0), trajectory_copy->getWayPointDurationFromPrevious(0));
258 }
259 
260 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryIterator)
261 {
262  robot_trajectory::RobotTrajectoryPtr trajectory;
263  initTestTrajectory(trajectory);
264 
265  ASSERT_EQ(5u, trajectory->size());
266  std::vector<double> positions;
267 
268  double start_pos = 0.0;
269 
270  for (size_t i = 0; i < trajectory->size(); ++i)
271  {
272  auto waypoint = trajectory->getWayPointPtr(i);
273  // modify joint values
274  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
275  start_pos = positions[0];
276  positions[0] += 0.01 * i;
277  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
278  }
279 
280  unsigned int count = 0;
281  for (const auto& waypoint_and_duration : *trajectory)
282  {
283  const auto& waypoint = waypoint_and_duration.first;
284  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
285  EXPECT_EQ(start_pos + count * 0.01, positions[0]);
286  count++;
287  }
288 
289  EXPECT_EQ(count, trajectory->size());
290 
291  // Consistency checks
292  EXPECT_EQ(trajectory->begin(), trajectory->begin());
293  EXPECT_EQ(trajectory->end(), trajectory->end());
294 
295  // trajectory has length 5; incrementing begin 5 times should reach the end
296  EXPECT_NE(trajectory->begin(), trajectory->end());
297  EXPECT_NE(++trajectory->begin(), trajectory->end());
298  EXPECT_NE(++(++trajectory->begin()), trajectory->end());
299  EXPECT_NE(++(++(++trajectory->begin())), trajectory->end());
300  EXPECT_NE(++(++(++(++trajectory->begin()))), trajectory->end());
301  EXPECT_EQ(++(++(++(++(++trajectory->begin())))), trajectory->end());
302 }
303 
304 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryLength)
305 {
306  robot_trajectory::RobotTrajectoryPtr trajectory;
307  initTestTrajectory(trajectory);
308  EXPECT_FLOAT_EQ(robot_trajectory::path_length(*trajectory), 0.0);
309 
310  // modify joint values so the smoothness is nonzero
311  std::vector<double> positions;
312  for (size_t i = 0; i < trajectory->size(); ++i)
313  {
314  auto waypoint = trajectory->getWayPointPtr(i);
315  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
316  positions[0] += 0.01 * i;
317  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
318  }
319  EXPECT_GT(robot_trajectory::path_length(*trajectory), 0.0);
320 }
321 
322 TEST_F(RobotTrajectoryTestFixture, RobotTrajectorySmoothness)
323 {
324  robot_trajectory::RobotTrajectoryPtr trajectory;
325  initTestTrajectory(trajectory);
326 
327  // modify joint values so the smoothness is nonzero
328  std::vector<double> positions;
329  for (size_t i = 0; i < trajectory->size(); ++i)
330  {
331  auto waypoint = trajectory->getWayPointPtr(i);
332  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
333  positions[0] += 0.01 * i;
334  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
335  }
336 
337  const auto smoothness = robot_trajectory::smoothness(*trajectory);
338  ASSERT_TRUE(smoothness.has_value());
339  EXPECT_GT(smoothness.value(), 0.0);
340 
341  // Check for empty trajectory
342  trajectory->clear();
343  EXPECT_FALSE(robot_trajectory::smoothness(*trajectory).has_value());
344 }
345 
346 TEST_F(RobotTrajectoryTestFixture, RobotTrajectoryDensity)
347 {
348  robot_trajectory::RobotTrajectoryPtr trajectory;
349  initTestTrajectory(trajectory);
350 
351  // If trajectory has all equal state, and length zero, density should be null.
352  auto density = robot_trajectory::waypoint_density(*trajectory);
353  ASSERT_FALSE(density.has_value());
354 
355  // modify joint values so the density is nonzero
356  std::vector<double> positions;
357  for (size_t i = 0; i < trajectory->size(); ++i)
358  {
359  auto waypoint = trajectory->getWayPointPtr(i);
360  waypoint->copyJointGroupPositions(arm_jmg_name_, positions);
361  positions[0] += 0.01 * i;
362  waypoint->setJointGroupPositions(arm_jmg_name_, positions);
363  }
364 
365  density = robot_trajectory::waypoint_density(*trajectory);
366  ASSERT_TRUE(density.has_value());
367  EXPECT_GT(density.value(), 0.0);
368 
369  // Check for empty trajectory
370  trajectory->clear();
371  density = robot_trajectory::waypoint_density(*trajectory);
372  EXPECT_FALSE(density.has_value());
373 }
374 
375 int main(int argc, char** argv)
376 {
377  testing::InitGoogleTest(&argc, argv);
378  return RUN_ALL_TESTS();
379 }
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)