Skip to content

Commit 3a8864c

Browse files
christophfroehlichbmagyar
authored andcommitted
[JTC] Reject trajectories with nonzero terminal velocity (#567)
* Reject receiving trajectory of last velocity point is non-zero * Update docs * Add tests * Change to parameterized test * Rename parameter * not true -> false --------- Co-authored-by: Bence Magyar <[email protected]> (cherry picked from commit 99b67d7)
1 parent 194e76c commit 3a8864c

File tree

5 files changed

+170
-3
lines changed

5 files changed

+170
-3
lines changed

joint_trajectory_controller/doc/userdoc.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ open_loop_control (boolean)
159159

160160
If this flag is set, the controller tries to read the values from the command interfaces on starting. If they have real numeric values, those will be used instead of state interfaces. Therefore it is important set command interfaces to NaN (std::numeric_limits<double>::quiet_NaN()) or state values when the hardware is started.
161161

162+
allow_nonzero_velocity_at_trajectory_end (boolean)
163+
If false, the last velocity point has to be zero or the goal will be rejected.
164+
165+
Default: true
166+
162167
constraints (structure)
163168
Default values for tolerances if no explicit values are states in JointTrajectory message.
164169

joint_trajectory_controller/src/joint_trajectory_controller.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ controller_interface::CallbackReturn JointTrajectoryController::on_init()
6767
return CallbackReturn::ERROR;
6868
}
6969

70+
// TODO(christophfroehlich): remove deprecation warning
71+
if (params_.allow_nonzero_velocity_at_trajectory_end)
72+
{
73+
RCLCPP_WARN(
74+
get_node()->get_logger(),
75+
"[Deprecated]: \"allow_nonzero_velocity_at_trajectory_end\" is set to "
76+
"true. The default behavior will change to false.");
77+
}
78+
7079
return CallbackReturn::SUCCESS;
7180
}
7281

@@ -1414,6 +1423,20 @@ bool JointTrajectoryController::validate_trajectory_msg(
14141423
}
14151424
}
14161425

1426+
if (!params_.allow_nonzero_velocity_at_trajectory_end)
1427+
{
1428+
for (size_t i = 0; i < trajectory.points.back().velocities.size(); ++i)
1429+
{
1430+
if (trajectory.points.back().velocities.at(i) != 0.)
1431+
{
1432+
RCLCPP_ERROR(
1433+
get_node()->get_logger(), "Velocity of last trajectory point of joint %s is not zero: %f",
1434+
trajectory.joint_names.at(i).c_str(), trajectory.points.back().velocities.at(i));
1435+
return false;
1436+
}
1437+
}
1438+
}
1439+
14171440
rclcpp::Duration previous_traj_time(0ms);
14181441
for (size_t i = 0; i < trajectory.points.size(); ++i)
14191442
{

joint_trajectory_controller/src/joint_trajectory_controller_parameters.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ joint_trajectory_controller:
7474
one_of<>: [["splines", "none"]],
7575
}
7676
}
77+
allow_nonzero_velocity_at_trajectory_end: {
78+
type: bool,
79+
default_value: true,
80+
description: "If false, the last velocity point has to be zero or the goal will be rejected",
81+
}
7782
gains:
7883
__map_joints:
7984
p: {

joint_trajectory_controller/test/test_trajectory_actions.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,130 @@ TEST_P(TestTrajectoryActionsTestParameterized, test_cancel_hold_position)
629629
}
630630
}
631631

632+
TEST_P(TestTrajectoryActionsTestParameterized, test_allow_nonzero_velocity_at_trajectory_end_true)
633+
{
634+
std::vector<rclcpp::Parameter> params = {
635+
rclcpp::Parameter("allow_nonzero_velocity_at_trajectory_end", true)};
636+
SetUpExecutor(params);
637+
SetUpControllerHardware();
638+
639+
std::shared_future<typename GoalHandle::SharedPtr> gh_future;
640+
// send goal with nonzero last velocities
641+
{
642+
std::vector<JointTrajectoryPoint> points;
643+
JointTrajectoryPoint point1;
644+
point1.time_from_start = rclcpp::Duration::from_seconds(0.0);
645+
point1.positions.resize(joint_names_.size());
646+
point1.velocities.resize(joint_names_.size());
647+
648+
point1.positions[0] = 4.0;
649+
point1.positions[1] = 5.0;
650+
point1.positions[2] = 6.0;
651+
point1.velocities[0] = 4.0;
652+
point1.velocities[1] = 5.0;
653+
point1.velocities[2] = 6.0;
654+
points.push_back(point1);
655+
656+
JointTrajectoryPoint point2;
657+
point2.time_from_start = rclcpp::Duration::from_seconds(0.1);
658+
point2.positions.resize(joint_names_.size());
659+
point2.velocities.resize(joint_names_.size());
660+
661+
point2.positions[0] = 7.0;
662+
point2.positions[1] = 8.0;
663+
point2.positions[2] = 9.0;
664+
point2.velocities[0] = 4.0;
665+
point2.velocities[1] = 5.0;
666+
point2.velocities[2] = 6.0;
667+
points.push_back(point2);
668+
669+
gh_future = sendActionGoal(points, 1.0, goal_options_);
670+
}
671+
controller_hw_thread_.join();
672+
673+
// will be accepted despite nonzero last point
674+
EXPECT_TRUE(gh_future.get());
675+
EXPECT_EQ(rclcpp_action::ResultCode::SUCCEEDED, common_resultcode_);
676+
}
677+
678+
TEST_P(TestTrajectoryActionsTestParameterized, test_allow_nonzero_velocity_at_trajectory_end_false)
679+
{
680+
std::vector<rclcpp::Parameter> params = {
681+
rclcpp::Parameter("allow_nonzero_velocity_at_trajectory_end", false)};
682+
SetUpExecutor(params);
683+
SetUpControllerHardware();
684+
685+
std::shared_future<typename GoalHandle::SharedPtr> gh_future;
686+
// send goal with nonzero last velocities
687+
{
688+
std::vector<JointTrajectoryPoint> points;
689+
JointTrajectoryPoint point1;
690+
point1.time_from_start = rclcpp::Duration::from_seconds(0.0);
691+
point1.positions.resize(joint_names_.size());
692+
point1.velocities.resize(joint_names_.size());
693+
694+
point1.positions[0] = 4.0;
695+
point1.positions[1] = 5.0;
696+
point1.positions[2] = 6.0;
697+
point1.velocities[0] = 4.0;
698+
point1.velocities[1] = 5.0;
699+
point1.velocities[2] = 6.0;
700+
points.push_back(point1);
701+
702+
JointTrajectoryPoint point2;
703+
point2.time_from_start = rclcpp::Duration::from_seconds(0.1);
704+
point2.positions.resize(joint_names_.size());
705+
point2.velocities.resize(joint_names_.size());
706+
707+
point2.positions[0] = 7.0;
708+
point2.positions[1] = 8.0;
709+
point2.positions[2] = 9.0;
710+
point2.velocities[0] = 4.0;
711+
point2.velocities[1] = 5.0;
712+
point2.velocities[2] = 6.0;
713+
points.push_back(point2);
714+
715+
gh_future = sendActionGoal(points, 1.0, goal_options_);
716+
}
717+
controller_hw_thread_.join();
718+
719+
EXPECT_FALSE(gh_future.get());
720+
721+
// send goal with last velocity being zero
722+
{
723+
std::vector<JointTrajectoryPoint> points;
724+
JointTrajectoryPoint point1;
725+
point1.time_from_start = rclcpp::Duration::from_seconds(0.0);
726+
point1.positions.resize(joint_names_.size());
727+
point1.velocities.resize(joint_names_.size());
728+
729+
point1.positions[0] = 4.0;
730+
point1.positions[1] = 5.0;
731+
point1.positions[2] = 6.0;
732+
point1.velocities[0] = 4.0;
733+
point1.velocities[1] = 5.0;
734+
point1.velocities[2] = 6.0;
735+
points.push_back(point1);
736+
737+
JointTrajectoryPoint point2;
738+
point2.time_from_start = rclcpp::Duration::from_seconds(0.1);
739+
point2.positions.resize(joint_names_.size());
740+
point2.velocities.resize(joint_names_.size());
741+
742+
point2.positions[0] = 7.0;
743+
point2.positions[1] = 8.0;
744+
point2.positions[2] = 9.0;
745+
point2.velocities[0] = 0.0;
746+
point2.velocities[1] = 0.0;
747+
point2.velocities[2] = 0.0;
748+
points.push_back(point2);
749+
750+
gh_future = sendActionGoal(points, 1.0, goal_options_);
751+
}
752+
753+
EXPECT_TRUE(gh_future.get());
754+
}
755+
632756
// position controllers
633757
INSTANTIATE_TEST_SUITE_P(
634758
PositionTrajectoryControllersActions, TestTrajectoryActionsTestParameterized,

joint_trajectory_controller/test/test_trajectory_controller.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ TEST_P(TrajectoryControllerTestParameterized, configure_state_ignores_commands)
6565
{
6666
rclcpp::executors::MultiThreadedExecutor executor;
6767
SetUpTrajectoryController(executor);
68+
traj_controller_->get_node()->set_parameter(
69+
rclcpp::Parameter("allow_nonzero_velocity_at_trajectory_end", true));
6870

6971
// const auto future_handle_ = std::async(std::launch::async, spin, &executor);
7072

@@ -202,7 +204,9 @@ TEST_P(TrajectoryControllerTestParameterized, activate)
202204
TEST_P(TrajectoryControllerTestParameterized, cleanup)
203205
{
204206
rclcpp::executors::MultiThreadedExecutor executor;
205-
SetUpAndActivateTrajectoryController(executor);
207+
std::vector<rclcpp::Parameter> params = {
208+
rclcpp::Parameter("allow_nonzero_velocity_at_trajectory_end", true)};
209+
SetUpAndActivateTrajectoryController(executor, true, params);
206210

207211
// send msg
208212
constexpr auto FIRST_POINT_TIME = std::chrono::milliseconds(250);
@@ -259,6 +263,8 @@ TEST_P(TrajectoryControllerTestParameterized, correct_initialization_using_param
259263
{
260264
rclcpp::executors::MultiThreadedExecutor executor;
261265
SetUpTrajectoryController(executor, false);
266+
traj_controller_->get_node()->set_parameter(
267+
rclcpp::Parameter("allow_nonzero_velocity_at_trajectory_end", true));
262268

263269
// This call is replacing the way parameters are set via launch
264270
SetParameters();
@@ -511,7 +517,9 @@ TEST_P(TrajectoryControllerTestParameterized, position_error_not_normalized)
511517
{
512518
rclcpp::executors::MultiThreadedExecutor executor;
513519
constexpr double k_p = 10.0;
514-
SetUpAndActivateTrajectoryController(executor, true, {}, true, k_p, 0.0, false);
520+
std::vector<rclcpp::Parameter> params = {
521+
rclcpp::Parameter("allow_nonzero_velocity_at_trajectory_end", true)};
522+
SetUpAndActivateTrajectoryController(executor, true, params, true, k_p, 0.0, false);
515523
subscribeToState();
516524

517525
size_t n_joints = joint_names_.size();
@@ -609,7 +617,9 @@ TEST_P(TrajectoryControllerTestParameterized, position_error_normalized)
609617
{
610618
rclcpp::executors::MultiThreadedExecutor executor;
611619
constexpr double k_p = 10.0;
612-
SetUpAndActivateTrajectoryController(executor, true, {}, true, k_p, 0.0, true);
620+
std::vector<rclcpp::Parameter> params = {
621+
rclcpp::Parameter("allow_nonzero_velocity_at_trajectory_end", true)};
622+
SetUpAndActivateTrajectoryController(executor, true, params, true, k_p, 0.0, true);
613623
subscribeToState();
614624

615625
size_t n_joints = joint_names_.size();

0 commit comments

Comments
 (0)