39 #include <gtest/gtest.h>
53 void setAccelerationLimits(
const moveit::core::RobotModelPtr& robot_model)
55 const std::vector<moveit::core::JointModel*> joint_models = robot_model->getActiveJointModels();
56 for (
auto& joint_model : joint_models)
58 std::vector<moveit_msgs::msg::JointLimits> joint_bounds_msg(joint_model->getVariableBoundsMsg());
60 for (
auto& joint_bound : joint_bounds_msg)
62 joint_bound.has_acceleration_limits =
true;
63 joint_bound.max_acceleration = 1.0;
65 joint_model->setVariableBounds(joint_bounds_msg);
70 TEST(time_optimal_trajectory_generation, test1)
72 Eigen::VectorXd waypoint(4);
73 std::list<Eigen::VectorXd> waypoints;
75 waypoint << 1424.0, 984.999694824219, 2126.0, 0.0;
76 waypoints.push_back(waypoint);
77 waypoint << 1423.0, 985.000244140625, 2126.0, 0.0;
78 waypoints.push_back(waypoint);
80 Eigen::VectorXd max_velocities(4);
81 max_velocities << 1.3, 0.67, 0.67, 0.5;
82 Eigen::VectorXd max_accelerations(4);
83 max_accelerations << 0.00249, 0.00249, 0.00249, 0.00249;
85 Trajectory trajectory(
Path(waypoints, 100.0), max_velocities, max_accelerations, 10.0);
86 EXPECT_TRUE(trajectory.
isValid());
87 EXPECT_DOUBLE_EQ(40.080256821829849, trajectory.
getDuration());
90 EXPECT_DOUBLE_EQ(1424.0, trajectory.
getPosition(0.0)[0]);
91 EXPECT_DOUBLE_EQ(984.999694824219, trajectory.
getPosition(0.0)[1]);
92 EXPECT_DOUBLE_EQ(2126.0, trajectory.
getPosition(0.0)[2]);
93 EXPECT_DOUBLE_EQ(0.0, trajectory.
getPosition(0.0)[3]);
102 const double traj_duration = trajectory.
getDuration();
103 EXPECT_NEAR(0.0, trajectory.
getVelocity(0.0)[0], 0.1);
104 EXPECT_NEAR(0.0, trajectory.
getVelocity(traj_duration)[0], 0.1);
107 TEST(time_optimal_trajectory_generation, test2)
109 Eigen::VectorXd waypoint(4);
110 std::list<Eigen::VectorXd> waypoints;
112 waypoint << 1427.0, 368.0, 690.0, 90.0;
113 waypoints.push_back(waypoint);
114 waypoint << 1427.0, 368.0, 790.0, 90.0;
115 waypoints.push_back(waypoint);
116 waypoint << 952.499938964844, 433.0, 1051.0, 90.0;
117 waypoints.push_back(waypoint);
118 waypoint << 452.5, 533.0, 1051.0, 90.0;
119 waypoints.push_back(waypoint);
120 waypoint << 452.5, 533.0, 951.0, 90.0;
121 waypoints.push_back(waypoint);
123 Eigen::VectorXd max_velocities(4);
124 max_velocities << 1.3, 0.67, 0.67, 0.5;
125 Eigen::VectorXd max_accelerations(4);
126 max_accelerations << 0.002, 0.002, 0.002, 0.002;
128 Trajectory trajectory(
Path(waypoints, 100.0), max_velocities, max_accelerations, 10.0);
129 EXPECT_TRUE(trajectory.
isValid());
130 EXPECT_DOUBLE_EQ(1922.1418427445944, trajectory.
getDuration());
133 EXPECT_DOUBLE_EQ(1427.0, trajectory.
getPosition(0.0)[0]);
134 EXPECT_DOUBLE_EQ(368.0, trajectory.
getPosition(0.0)[1]);
135 EXPECT_DOUBLE_EQ(690.0, trajectory.
getPosition(0.0)[2]);
136 EXPECT_DOUBLE_EQ(90.0, trajectory.
getPosition(0.0)[3]);
145 const double traj_duration = trajectory.
getDuration();
146 EXPECT_NEAR(0.0, trajectory.
getVelocity(0.0)[0], 0.1);
147 EXPECT_NEAR(0.0, trajectory.
getVelocity(traj_duration)[0], 0.1);
150 TEST(time_optimal_trajectory_generation, test3)
152 Eigen::VectorXd waypoint(4);
153 std::list<Eigen::VectorXd> waypoints;
155 waypoint << 1427.0, 368.0, 690.0, 90.0;
156 waypoints.push_back(waypoint);
157 waypoint << 1427.0, 368.0, 790.0, 90.0;
158 waypoints.push_back(waypoint);
159 waypoint << 952.499938964844, 433.0, 1051.0, 90.0;
160 waypoints.push_back(waypoint);
161 waypoint << 452.5, 533.0, 1051.0, 90.0;
162 waypoints.push_back(waypoint);
163 waypoint << 452.5, 533.0, 951.0, 90.0;
164 waypoints.push_back(waypoint);
166 Eigen::VectorXd max_velocities(4);
167 max_velocities << 1.3, 0.67, 0.67, 0.5;
168 Eigen::VectorXd max_accelerations(4);
169 max_accelerations << 0.002, 0.002, 0.002, 0.002;
171 Trajectory trajectory(
Path(waypoints, 100.0), max_velocities, max_accelerations);
172 EXPECT_TRUE(trajectory.
isValid());
173 EXPECT_DOUBLE_EQ(1919.5597888812974, trajectory.
getDuration());
176 EXPECT_DOUBLE_EQ(1427.0, trajectory.
getPosition(0.0)[0]);
177 EXPECT_DOUBLE_EQ(368.0, trajectory.
getPosition(0.0)[1]);
178 EXPECT_DOUBLE_EQ(690.0, trajectory.
getPosition(0.0)[2]);
179 EXPECT_DOUBLE_EQ(90.0, trajectory.
getPosition(0.0)[3]);
188 const double traj_duration = trajectory.
getDuration();
189 EXPECT_NEAR(0.0, trajectory.
getVelocity(0.0)[0], 0.1);
190 EXPECT_NEAR(0.0, trajectory.
getVelocity(traj_duration)[0], 0.1);
194 TEST(time_optimal_trajectory_generation, testCustomLimits)
196 constexpr
auto robot_name{
"panda" };
197 constexpr
auto group_name{
"panda_arm" };
200 ASSERT_TRUE(robot_model) <<
"Failed to load robot model" << robot_name;
201 setAccelerationLimits(robot_model);
202 auto group = robot_model->getJointModelGroup(group_name);
203 ASSERT_TRUE(
group) <<
"Failed to load joint model group " << group_name;
207 const double delta_t = 0.1;
216 std::unordered_map<std::string, double> vel_limits{ {
"panda_joint1", 1.3 }, {
"panda_joint2", 2.3 },
217 {
"panda_joint3", 3.3 }, {
"panda_joint4", 4.3 },
218 {
"panda_joint5", 5.3 }, {
"panda_joint6", 6.3 },
219 {
"panda_joint7", 7.3 } };
220 std::unordered_map<std::string, double> accel_limits{ {
"panda_joint1", 1.3 }, {
"panda_joint2", 2.3 },
221 {
"panda_joint3", 3.3 }, {
"panda_joint4", 4.3 },
222 {
"panda_joint5", 5.3 }, {
"panda_joint6", 6.3 },
223 {
"panda_joint7", 7.3 } };
224 ASSERT_TRUE(totg.
computeTimeStamps(trajectory, vel_limits, accel_limits)) <<
"Failed to compute time stamps";
228 TEST(time_optimal_trajectory_generation, testLargeAccel)
230 double path_tolerance = 0.1;
231 double resample_dt = 0.1;
232 Eigen::VectorXd waypoint(6);
233 std::list<Eigen::VectorXd> waypoints;
234 Eigen::VectorXd max_velocities(6);
235 Eigen::VectorXd max_accelerations(6);
239 waypoint << 1.6113056281076339,
240 -0.21400163389235427,
242 9.9653618690354051e-12,
245 waypoints.push_back(waypoint);
247 waypoint << 1.6088016187976597,
248 -0.21792862470933924,
250 0.00010424017303217738,
253 waypoints.push_back(waypoint);
255 waypoint << 1.5887695443178671,
256 -0.24934455124521923,
258 0.00093816147756670078,
261 waypoints.push_back(waypoint);
263 waypoint << 1.1647412393815282,
264 -0.91434018564402375,
266 0.018590164397622583,
269 waypoints.push_back(waypoint);
272 max_velocities << 0.89535390627300004,
279 max_accelerations << 0.82673490883799994,
287 Trajectory parameterized(
Path(waypoints, path_tolerance), max_velocities, max_accelerations, 0.001);
289 ASSERT_TRUE(parameterized.
isValid());
291 size_t sample_count = std::ceil(parameterized.
getDuration() / resample_dt);
292 for (
size_t sample = 0; sample <= sample_count; ++sample)
295 double t = std::min(parameterized.
getDuration(), sample * resample_dt);
298 ASSERT_EQ(acceleration.size(), 6);
299 for (std::size_t i = 0; i < 6; ++i)
300 EXPECT_NEAR(acceleration(i), 0.0, 100.0) <<
"Invalid acceleration at position " << sample_count <<
'\n';
306 TEST(time_optimal_trajectory_generation, testLastWaypoint)
308 constexpr
auto robot_name{
"panda" };
309 constexpr
auto group_name{
"panda_arm" };
312 ASSERT_TRUE(robot_model) <<
"Failed to load robot model" << robot_name;
313 setAccelerationLimits(robot_model);
314 auto group = robot_model->getJointModelGroup(group_name);
315 ASSERT_TRUE(
group) <<
"Failed to load joint model group " << group_name;
320 auto add_waypoint = [&](
const std::vector<double>& waypoint) {
324 add_waypoint({ 0.000000000, 0.000000000, 0, 0, 0, 0, 0 });
325 add_waypoint({ 0.009521808, 0.009521808, 0, 0, 0, 0, 0 });
326 add_waypoint({ 0.011902261, 0.011902261, 0, 0, 0, 0, 0 });
327 add_waypoint({ 0.016663165, 0.016663165, 0, 0, 0, 0, 0 });
328 add_waypoint({ 0.026184973, 0.026184973, 0, 0, 0, 0, 0 });
329 add_waypoint({ 0.034516555, 0.034516555, 0, 0, 0, 0, 0 });
331 const std::vector<double> expected_last_waypoint = { 0.034516555, 0.034516555, 0, 0, 0, 0, 0 };
332 add_waypoint(expected_last_waypoint);
335 ASSERT_TRUE(totg.
computeTimeStamps(trajectory)) <<
"Failed to compute time stamps";
337 std::vector<double> actual_last_waypoint;
339 EXPECT_TRUE(std::equal(actual_last_waypoint.cbegin(), actual_last_waypoint.cend(), expected_last_waypoint.cbegin(),
340 expected_last_waypoint.cend(), [](
const double rhs,
const double lhs) {
341 return std::abs(rhs - lhs) < std::numeric_limits<double>::epsilon();
345 TEST(time_optimal_trajectory_generation, testPluginAPI)
347 constexpr
auto robot_name{
"panda" };
348 constexpr
auto group_name{
"panda_arm" };
351 ASSERT_TRUE(robot_model) <<
"Failed to load robot model" << robot_name;
352 setAccelerationLimits(robot_model);
353 auto group = robot_model->getJointModelGroup(group_name);
354 ASSERT_TRUE(
group) <<
"Failed to load joint model group " << group_name;
373 constexpr
size_t totg_iterations = 10;
376 moveit_msgs::msg::RobotTrajectory first_trajectory_msg_start, first_trajectory_msg_end;
384 ASSERT_EQ(test_bounds.size(), original_bounds.size());
385 for (
size_t bound_idx = 0; bound_idx < test_bounds.at(0)->size(); ++bound_idx)
387 ASSERT_EQ(test_bounds.at(0)->at(bound_idx).max_velocity_, original_bounds.at(0)->at(bound_idx).max_velocity_);
388 ASSERT_EQ(test_bounds.at(0)->at(bound_idx).min_velocity_, original_bounds.at(0)->at(bound_idx).min_velocity_);
389 ASSERT_EQ(test_bounds.at(0)->at(bound_idx).velocity_bounded_,
390 original_bounds.at(0)->at(bound_idx).velocity_bounded_);
392 ASSERT_EQ(test_bounds.at(0)->at(bound_idx).max_acceleration_,
393 original_bounds.at(0)->at(bound_idx).max_acceleration_);
394 ASSERT_EQ(test_bounds.at(0)->at(bound_idx).min_acceleration_,
395 original_bounds.at(0)->at(bound_idx).min_acceleration_);
396 ASSERT_EQ(test_bounds.at(0)->at(bound_idx).acceleration_bounded_,
397 original_bounds.at(0)->at(bound_idx).acceleration_bounded_);
402 ASSERT_TRUE(totg.
computeTimeStamps(test_trajectory)) <<
"Failed to compute time stamps";
407 for (
size_t i = 0; i < totg_iterations; ++i)
410 EXPECT_TRUE(totg_success) <<
"Failed to compute time stamps with a same TOTG instance in iteration " << i;
417 moveit_msgs::msg::RobotTrajectory second_trajectory_msg_start, second_trajectory_msg_end;
423 ASSERT_TRUE(totg.
computeTimeStamps(test_trajectory)) <<
"Failed to compute time stamps";
429 for (
size_t i = 0; i < totg_iterations; ++i)
433 EXPECT_TRUE(totg_success) <<
"Failed to compute time stamps with a new TOTG instance in iteration " << i;
440 ASSERT_EQ(first_trajectory_msg_start, second_trajectory_msg_start);
441 ASSERT_EQ(first_trajectory_msg_end, second_trajectory_msg_end);
444 moveit_msgs::msg::RobotTrajectory third_trajectory_msg_end;
448 ASSERT_TRUE(totg.
computeTimeStamps(trajectory)) <<
"Failed to compute time stamps";
451 for (
size_t i = 0; i < totg_iterations; ++i)
455 ASSERT_TRUE(totg_success) <<
"Failed to compute timestamps on a new TOTG instance in iteration " << i;
462 ASSERT_EQ(first_trajectory_msg_end, third_trajectory_msg_end);
465 TEST(time_optimal_trajectory_generation, testFixedNumWaypoints)
468 constexpr
size_t desired_num_waypoints = 42;
470 constexpr
auto robot_name{
"panda" };
471 constexpr
auto group_name{
"panda_arm" };
474 ASSERT_TRUE(robot_model) <<
"Failed to load robot model" << robot_name;
475 setAccelerationLimits(robot_model);
476 auto group = robot_model->getJointModelGroup(group_name);
477 ASSERT_TRUE(
group) <<
"Failed to load joint model group " << group_name;
481 const double delta_t = 0.1;
489 <<
"Failed to compute time stamps";
494 TEST(time_optimal_trajectory_generation, testSingleDofDiscontinuity)
497 Eigen::VectorXd waypoint(1);
498 std::list<Eigen::VectorXd> waypoints;
500 const double start_position = 1.881943;
501 waypoint << start_position;
502 waypoints.push_back(waypoint);
503 waypoint << 2.600542;
504 waypoints.push_back(waypoint);
506 Eigen::VectorXd max_velocities(1);
507 max_velocities << 4.54;
508 Eigen::VectorXd max_accelerations(1);
509 max_accelerations << 28.0;
511 Trajectory trajectory(
Path(waypoints, 0.1 ), max_velocities, max_accelerations,
513 EXPECT_TRUE(trajectory.
isValid());
516 const double traj_duration = trajectory.
getDuration();
517 EXPECT_NEAR(0.320681, traj_duration, 1e-3);
520 EXPECT_DOUBLE_EQ(start_position, trajectory.
getPosition(0.0)[0]);
522 EXPECT_NEAR(0.0, trajectory.
getVelocity(0.0)[0], 0.1);
523 EXPECT_NEAR(0.0, trajectory.
getVelocity(traj_duration)[0], 0.1);
526 for (
double time = 0; time < traj_duration; time += 0.01)
529 double t_switch = 0.1603407;
532 EXPECT_NEAR(trajectory.
getAcceleration(time)[0], max_accelerations[0], 1e-3) <<
"Time: " << time;
534 else if (time > t_switch)
536 EXPECT_NEAR(trajectory.
getAcceleration(time)[0], -max_accelerations[0], 1e-3) <<
"Time: " << time;
541 TEST(time_optimal_trajectory_generation, testRelevantZeroMaxAccelerationsInvalidateTrajectory)
543 const Eigen::Vector2d max_velocity(1, 1);
544 const Path path(std::list<Eigen::VectorXd>{ Eigen::Vector2d(0, 0), Eigen::Vector2d(1, 1) });
546 EXPECT_FALSE(
Trajectory(path, max_velocity, Eigen::Vector2d(0, 1)).isValid());
547 EXPECT_FALSE(
Trajectory(path, max_velocity, Eigen::Vector2d(1, 0)).isValid());
548 EXPECT_FALSE(
Trajectory(path, max_velocity, Eigen::Vector2d(0, 0)).isValid());
551 TEST(time_optimal_trajectory_generation, testIrrelevantZeroMaxAccelerationsDontInvalidateTrajectory)
553 const Eigen::Vector2d max_velocity(1, 1);
555 EXPECT_TRUE(
Trajectory(
Path(std::list<Eigen::VectorXd>{ Eigen::Vector2d(0, 0), Eigen::Vector2d(0, 1) }), max_velocity,
556 Eigen::Vector2d(0, 1))
558 EXPECT_TRUE(
Trajectory(
Path(std::list<Eigen::VectorXd>{ Eigen::Vector2d(0, 0), Eigen::Vector2d(1, 0) }), max_velocity,
559 Eigen::Vector2d(1, 0))
563 TEST(time_optimal_trajectory_generation, testTimeStepZeroMakesTrajectoryInvalid)
565 EXPECT_FALSE(
Trajectory(
Path(std::list<Eigen::VectorXd>{ Eigen::Vector2d(0, 0), Eigen::Vector2d(1, 1) }),
566 Eigen::Vector2d(1, 1), Eigen::Vector2d(1, 1),
571 int main(
int argc,
char** argv)
573 testing::InitGoogleTest(&argc, argv);
574 return RUN_ALL_TESTS();
Representation of a robot's state. This includes position, velocity, acceleration and effort.
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...
void setToDefaultValues()
Set all joints to their default positions. The default position is 0, or if that is not within bounds...
Maintain a sequence of waypoints and the time durations between these waypoints.
const moveit::core::RobotModelConstPtr & getRobotModel() const
void getRobotTrajectoryMsg(moveit_msgs::msg::RobotTrajectory &trajectory, const std::vector< std::string > &joint_filter=std::vector< std::string >()) const
RobotTrajectory & addSuffixWayPoint(const moveit::core::RobotState &state, double dt)
Add a point to the trajectory.
std::size_t getWayPointCount() const
double getWayPointDurationFromPrevious(std::size_t index) const
double getDuration() const
const moveit::core::RobotState & getLastWayPoint() const
bool computeTimeStamps(robot_trajectory::RobotTrajectory &trajectory, const double max_velocity_scaling_factor=1.0, const double max_acceleration_scaling_factor=1.0) const override
Compute a trajectory with waypoints spaced equally in time (according to resample_dt_)....
Eigen::VectorXd getAcceleration(double time) const
Return the acceleration vector for a given point in time.
bool isValid() const
Call this method after constructing the object to make sure the trajectory generation succeeded witho...
Eigen::VectorXd getPosition(double time) const
Return the position/configuration vector for a given point in time.
double getDuration() const
Returns the optimal duration of the trajectory.
Eigen::VectorXd getVelocity(double time) const
Return the velocity vector for a given point in time.
moveit::core::RobotModelPtr loadTestingRobotModel(const std::string &robot_name)
Loads a robot from moveit_resources.
std::vector< const JointModel::Bounds * > JointBoundsVector
bool totgComputeTimeStamps(const size_t num_waypoints, robot_trajectory::RobotTrajectory &trajectory, const double max_velocity_scaling_factor=1.0, const double max_acceleration_scaling_factor=1.0)
Compute a trajectory with the desired number of waypoints. Resampling the trajectory doesn't change t...
int main(int argc, char **argv)
TEST(time_optimal_trajectory_generation, test1)