@@ -969,6 +969,91 @@ TEST_P(TestTrajectoryActionsTestParameterized, test_allow_nonzero_velocity_at_tr
969969 EXPECT_TRUE (gh_future.get ());
970970}
971971
972+ TEST_P (TestTrajectoryActionsTestParameterized, deactivate_controller_aborts_action)
973+ {
974+ // deactivate velocity tolerance
975+ std::vector<rclcpp::Parameter> params = {
976+ rclcpp::Parameter (" constraints.stopped_velocity_tolerance" , 0.0 )};
977+ SetUpExecutor (params, false , 1.0 , 0.0 );
978+
979+ // We use our own hardware thread here, as we want to make sure the controller is deactivated
980+ auto controller_thread = std::thread (
981+ [&]()
982+ {
983+ // controller hardware cycle update loop
984+ auto clock = rclcpp::Clock (RCL_STEADY_TIME);
985+ auto now_time = clock.now ();
986+ auto last_time = now_time;
987+ rclcpp::Duration wait = rclcpp::Duration::from_seconds (0.5 );
988+ auto end_time = last_time + wait;
989+ while (now_time < end_time)
990+ {
991+ now_time = now_time + rclcpp::Duration::from_seconds (0.01 );
992+ traj_controller_->update (now_time, now_time - last_time);
993+ last_time = now_time;
994+ std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
995+ }
996+ RCLCPP_INFO (node_->get_logger (), " Controller hardware thread finished" );
997+ traj_controller_->get_node ()->deactivate ();
998+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
999+ });
1000+
1001+ std::shared_future<typename GoalHandle::SharedPtr> gh_future;
1002+ // send goal
1003+ std::vector<double > point_positions{1.0 , 2.0 , 3.0 };
1004+ {
1005+ std::vector<JointTrajectoryPoint> points;
1006+ JointTrajectoryPoint point;
1007+ point.time_from_start = rclcpp::Duration::from_seconds (2.5 );
1008+ point.positions = point_positions;
1009+
1010+ points.push_back (point);
1011+
1012+ gh_future = sendActionGoal (points, 1.0 , goal_options_);
1013+ }
1014+
1015+ controller_thread.join ();
1016+
1017+ EXPECT_TRUE (gh_future.get ());
1018+ EXPECT_EQ (rclcpp_action::ResultCode::ABORTED, common_resultcode_);
1019+
1020+ auto state_ref = traj_controller_->get_state_reference ();
1021+ auto state = traj_controller_->get_state_feedback ();
1022+
1023+ // run an update
1024+ updateControllerAsync (rclcpp::Duration::from_seconds (0.01 ));
1025+
1026+ // There will be no active trajectory upon deactivation, so we can't use the expectCommandPoint
1027+ // method.
1028+ if (traj_controller_->has_position_command_interface ())
1029+ {
1030+ EXPECT_NEAR (state_ref.positions .at (0 ), joint_pos_[0 ], COMMON_THRESHOLD);
1031+ EXPECT_NEAR (state_ref.positions .at (1 ), joint_pos_[1 ], COMMON_THRESHOLD);
1032+ EXPECT_NEAR (state_ref.positions .at (2 ), joint_pos_[2 ], COMMON_THRESHOLD);
1033+ }
1034+
1035+ if (traj_controller_->has_velocity_command_interface ())
1036+ {
1037+ EXPECT_EQ (0.0 , joint_vel_[0 ]);
1038+ EXPECT_EQ (0.0 , joint_vel_[1 ]);
1039+ EXPECT_EQ (0.0 , joint_vel_[2 ]);
1040+ }
1041+
1042+ if (traj_controller_->has_acceleration_command_interface ())
1043+ {
1044+ EXPECT_EQ (0.0 , joint_acc_[0 ]);
1045+ EXPECT_EQ (0.0 , joint_acc_[1 ]);
1046+ EXPECT_EQ (0.0 , joint_acc_[2 ]);
1047+ }
1048+
1049+ if (traj_controller_->has_effort_command_interface ())
1050+ {
1051+ EXPECT_EQ (0.0 , joint_eff_[0 ]);
1052+ EXPECT_EQ (0.0 , joint_eff_[1 ]);
1053+ EXPECT_EQ (0.0 , joint_eff_[2 ]);
1054+ }
1055+ }
1056+
9721057// position controllers
9731058INSTANTIATE_TEST_SUITE_P (
9741059 PositionTrajectoryControllersActions, TestTrajectoryActionsTestParameterized,
0 commit comments