Skip to content

Commit 3d44cf5

Browse files
URJalaurfeex
authored andcommitted
Add retry for realtime boxes outside realtime thread.
1 parent 576ba6a commit 3d44cf5

File tree

2 files changed

+148
-41
lines changed

2 files changed

+148
-41
lines changed

ur_controllers/include/ur_controllers/passthrough_trajectory_controller.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ class PassthroughTrajectoryController : public controller_interface::ControllerI
159159
bool check_goal_positions(std::shared_ptr<const control_msgs::action::FollowJointTrajectory::Goal> goal);
160160
bool check_goal_velocities(std::shared_ptr<const control_msgs::action::FollowJointTrajectory::Goal> goal);
161161
bool check_goal_accelerations(std::shared_ptr<const control_msgs::action::FollowJointTrajectory::Goal> goal);
162+
std::optional<RealtimeGoalHandlePtr> get_rt_goal_from_non_rt();
163+
bool set_rt_goal_from_non_rt(RealtimeGoalHandlePtr& rt_goal);
162164

163165
trajectory_msgs::msg::JointTrajectory active_joint_traj_;
164166
// std::vector<control_msgs::msg::JointTolerance> path_tolerance_;

ur_controllers/src/passthrough_trajectory_controller.cpp

Lines changed: 146 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,74 @@
5454
namespace ur_controllers
5555
{
5656

57+
template <class RTBox>
58+
auto get_rt_box_from_non_rt(RTBox& rt_box)
59+
{
60+
int tries = 0;
61+
auto return_val = rt_box.try_get();
62+
while (!return_val.has_value()) {
63+
if (tries > 9) {
64+
RCLCPP_ERROR(rclcpp::get_logger("PassthroughTrajectoryController"), "Failed to get value from realtime box.");
65+
return decltype(return_val){};
66+
}
67+
RCLCPP_WARN(rclcpp::get_logger("PassthroughTrajectoryController"), "Waiting for value to be set in realtime box, "
68+
"retrying...");
69+
rclcpp::sleep_for(std::chrono::milliseconds(50));
70+
return_val = rt_box.try_get();
71+
tries++;
72+
}
73+
return return_val;
74+
}
75+
76+
template <class RTBox, class ValueType>
77+
bool set_rt_box_from_non_rt(RTBox& rt_box, const ValueType& value)
78+
{
79+
int tries = 0;
80+
while (!rt_box.try_set(value)) {
81+
if (tries > 9) {
82+
RCLCPP_ERROR(rclcpp::get_logger("PassthroughTrajectoryController"), "Failed to get value from realtime box.");
83+
return false;
84+
}
85+
RCLCPP_WARN(rclcpp::get_logger("PassthroughTrajectoryController"), "Waiting for value to be set in realtime box, "
86+
"retrying...");
87+
rclcpp::sleep_for(std::chrono::milliseconds(50));
88+
tries++;
89+
}
90+
return true;
91+
}
92+
93+
std::optional<PassthroughTrajectoryController::RealtimeGoalHandlePtr>
94+
PassthroughTrajectoryController::get_rt_goal_from_non_rt()
95+
{
96+
RealtimeGoalHandlePtr active_goal = nullptr;
97+
int tries = 0;
98+
while (!rt_active_goal_.try_get([&active_goal](const RealtimeGoalHandlePtr& goal) { active_goal = goal; })) {
99+
if (tries > 9) {
100+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to get active goal from realtime box.");
101+
return std::nullopt;
102+
}
103+
RCLCPP_WARN(get_node()->get_logger(), "Waiting for active goal to be read, retrying...");
104+
rclcpp::sleep_for(std::chrono::milliseconds(50));
105+
tries++;
106+
}
107+
return active_goal;
108+
}
109+
110+
bool PassthroughTrajectoryController::set_rt_goal_from_non_rt(RealtimeGoalHandlePtr& rt_goal)
111+
{
112+
int tries = 0;
113+
while (!rt_active_goal_.try_set([&rt_goal](RealtimeGoalHandlePtr& goal) { goal = rt_goal; })) {
114+
if (tries > 9) {
115+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set active goal in realtime box.");
116+
return false;
117+
}
118+
RCLCPP_WARN(get_node()->get_logger(), "Waiting for active goal to be set, retrying...");
119+
rclcpp::sleep_for(std::chrono::milliseconds(50));
120+
tries++;
121+
}
122+
return true;
123+
}
124+
57125
double duration_to_double(const builtin_interfaces::msg::Duration& duration)
58126
{
59127
return duration.sec + (duration.nanosec / 1000000000.0);
@@ -65,14 +133,18 @@ controller_interface::CallbackReturn PassthroughTrajectoryController::on_init()
65133
passthrough_params_ = passthrough_param_listener_->get_params();
66134
current_index_ = 0;
67135
auto joint_names = passthrough_params_.joints;
68-
joint_names_.try_set(joint_names);
136+
if (!set_rt_box_from_non_rt(joint_names_, joint_names)) {
137+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set joint names in realtime box.");
138+
return controller_interface::CallbackReturn::ERROR;
139+
}
69140
number_of_joints_ = joint_names.size();
70141
state_interface_types_ = passthrough_params_.state_interfaces;
71142
scaling_factor_ = 1.0;
72143
clock_ = get_node()->get_clock();
73144
return controller_interface::CallbackReturn::SUCCESS;
74145
}
75146

147+
// Not part of real time loop
76148
controller_interface::CallbackReturn
77149
PassthroughTrajectoryController::on_configure(const rclcpp_lifecycle::State& previous_state)
78150
{
@@ -83,12 +155,11 @@ PassthroughTrajectoryController::on_configure(const rclcpp_lifecycle::State& pre
83155

84156
joint_state_interface_names_.reserve(number_of_joints_ * state_interface_types_.size());
85157

86-
auto joint_names_internal = joint_names_.try_get();
87-
if (!joint_names_internal) {
88-
RCLCPP_ERROR(get_node()->get_logger(), "Joint names could not be read, cannot configure controller.");
158+
auto joint_names_internal = get_rt_box_from_non_rt(joint_names_);
159+
if (!joint_names_internal.has_value()) {
160+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to get joint names from realtime box.");
89161
return controller_interface::CallbackReturn::ERROR;
90162
}
91-
92163
for (const auto& joint_name : *joint_names_internal) {
93164
for (const auto& interface_type : state_interface_types_) {
94165
joint_state_interface_names_.emplace_back(joint_name + "/" + interface_type);
@@ -458,9 +529,9 @@ bool PassthroughTrajectoryController::check_goal_tolerances(
458529
std::shared_ptr<const control_msgs::action::FollowJointTrajectory::Goal> goal)
459530
{
460531
auto& tolerances = goal->goal_tolerance;
461-
auto joint_names_internal = joint_names_.try_get();
462-
if (!joint_names_internal) {
463-
RCLCPP_ERROR(get_node()->get_logger(), "Joint names could not be read, cannot check tolerances.");
532+
auto joint_names_internal = get_rt_box_from_non_rt(joint_names_);
533+
if (!joint_names_internal.has_value()) {
534+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to get joint names from realtime box.");
464535
return false;
465536
}
466537

@@ -567,26 +638,26 @@ rclcpp_action::CancelResponse PassthroughTrajectoryController::goal_cancelled_ca
567638
const std::shared_ptr<rclcpp_action::ServerGoalHandle<control_msgs::action::FollowJointTrajectory>> goal_handle)
568639
{
569640
// Check that cancel request refers to currently active goal (if any)
570-
RealtimeGoalHandlePtr active_goal = nullptr;
571-
while (!rt_active_goal_.try_get([&active_goal](const RealtimeGoalHandlePtr& goal) { active_goal = goal; })) {
572-
// Wait until we can read the active goal from the realtime buffer
573-
RCLCPP_WARN(get_node()->get_logger(), "Waiting for active goal to be set, retrying cancel request.");
574-
rclcpp::sleep_for(std::chrono::milliseconds(50));
641+
auto goal = get_rt_goal_from_non_rt();
642+
if (!goal.has_value()) {
643+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to get goal handle.");
644+
return rclcpp_action::CancelResponse::REJECT;
575645
}
646+
RealtimeGoalHandlePtr active_goal = goal.value();
576647

577648
if (active_goal && active_goal->gh_ == goal_handle) {
578649
RCLCPP_INFO(get_node()->get_logger(), "Cancelling active trajectory requested.");
579650

651+
auto new_goal = RealtimeGoalHandlePtr();
652+
if (!set_rt_goal_from_non_rt(new_goal)) {
653+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to reset active goal, cancel request failed.");
654+
return rclcpp_action::CancelResponse::REJECT;
655+
}
656+
580657
// Mark the current goal as canceled
581658
auto result = std::make_shared<FollowJTrajAction::Result>();
582659
active_goal->setCanceled(result);
583660

584-
while (!rt_active_goal_.try_set([](RealtimeGoalHandlePtr& goal) { goal = RealtimeGoalHandlePtr(); })) {
585-
// Wait until we can set the active goal to nullptr
586-
RCLCPP_WARN(get_node()->get_logger(), "Waiting for active goal to be set, retrying cancel request.");
587-
rclcpp::sleep_for(std::chrono::milliseconds(50));
588-
}
589-
590661
trajectory_active_ = false;
591662
}
592663
return rclcpp_action::CancelResponse::ACCEPT;
@@ -601,21 +672,40 @@ void PassthroughTrajectoryController::goal_accepted_callback(
601672
current_index_ = 0;
602673

603674
// TODO(fexner): Merge goal tolerances with default tolerances
604-
bool write_success =
605-
joint_trajectory_mapping_.try_set(create_joint_mapping(goal_handle->get_goal()->trajectory.joint_names));
606-
if (!write_success) {
607-
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set joint trajectory mapping.");
675+
auto map = create_joint_mapping(goal_handle->get_goal()->trajectory.joint_names);
676+
if (map.empty()) {
677+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to create joint trajectory mapping, aborting goal.");
678+
auto result = std::make_shared<control_msgs::action::FollowJointTrajectory::Result>();
679+
result->error_code =
680+
control_msgs::action::FollowJointTrajectory::Result::INVALID_JOINTS; // Not entirely sure, if this is the
681+
// correct error code.
682+
result->error_string = "Failed to create joint mapping.";
683+
goal_handle->abort(result);
684+
return;
685+
}
686+
687+
if (!set_rt_box_from_non_rt(joint_trajectory_mapping_, map)) {
688+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set joint trajectory mapping in realtime box.");
689+
auto result = std::make_shared<control_msgs::action::FollowJointTrajectory::Result>();
690+
result->error_code = control_msgs::action::FollowJointTrajectory::Result::INVALID_JOINTS;
691+
result->error_string = "Failed to set joint trajectory mapping.";
692+
goal_handle->abort(result);
608693
return;
609694
}
610695

611696
// sort goal tolerances to match internal joint order
612697
std::vector<control_msgs::msg::JointTolerance> goal_tolerances;
613698
if (!goal_handle->get_goal()->goal_tolerance.empty()) {
614-
auto joint_names_internal = joint_names_.try_get();
615-
if (!joint_names_internal) {
616-
RCLCPP_ERROR(get_node()->get_logger(), "Joint names could not be read, cannot set goal tolerances.");
699+
auto joint_names_internal = get_rt_box_from_non_rt(joint_names_);
700+
if (!joint_names_internal.has_value()) {
701+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to get joint names, aborting goal.");
702+
auto result = std::make_shared<control_msgs::action::FollowJointTrajectory::Result>();
703+
result->error_code = control_msgs::action::FollowJointTrajectory::Result::INVALID_JOINTS;
704+
result->error_string = "Failed to get joint names.";
705+
goal_handle->abort(result);
617706
return;
618707
}
708+
619709
std::stringstream ss;
620710
ss << "Using goal tolerances\n";
621711
for (auto& joint_name : *joint_names_internal) {
@@ -630,39 +720,52 @@ void PassthroughTrajectoryController::goal_accepted_callback(
630720
}
631721
RCLCPP_INFO_STREAM(get_node()->get_logger(), ss.str());
632722
}
633-
write_success = goal_tolerance_.try_set(goal_tolerances);
634-
if (!write_success) {
635-
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set goal tolerances.");
723+
724+
if (!set_rt_box_from_non_rt(goal_tolerance_, goal_tolerances)) {
725+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set goal tolerances in realtime box.");
726+
auto result = std::make_shared<control_msgs::action::FollowJointTrajectory::Result>();
727+
result->error_code = control_msgs::action::FollowJointTrajectory::Result::INVALID_GOAL;
728+
result->error_string = "Failed to set goal tolerances.";
729+
goal_handle->abort(result);
636730
return;
637731
}
638732

639-
write_success = goal_time_tolerance_.try_set(goal_handle->get_goal()->goal_time_tolerance);
640-
if (!write_success) {
641-
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set goal time tolerance.");
733+
if (!set_rt_box_from_non_rt(goal_time_tolerance_, goal_handle->get_goal()->goal_time_tolerance)) {
734+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set goal time tolerance in realtime box.");
735+
auto result = std::make_shared<control_msgs::action::FollowJointTrajectory::Result>();
736+
result->error_code = control_msgs::action::FollowJointTrajectory::Result::INVALID_GOAL;
737+
result->error_string = "Failed to set goal time tolerance.";
738+
goal_handle->abort(result);
642739
return;
643740
}
741+
644742
RCLCPP_INFO_STREAM(get_node()->get_logger(),
645743
"Goal time tolerance: " << duration_to_double(goal_handle->get_goal()->goal_time_tolerance)
646744
<< " sec");
647745

746+
RealtimeGoalHandlePtr rt_goal = std::make_shared<RealtimeGoalHandle>(goal_handle);
747+
if (!set_rt_goal_from_non_rt(rt_goal)) {
748+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set active goal, aborting goal.");
749+
auto result = std::make_shared<control_msgs::action::FollowJointTrajectory::Result>();
750+
result->error_code = control_msgs::action::FollowJointTrajectory::Result::INVALID_GOAL;
751+
result->error_string = "Failed to set active goal.";
752+
goal_handle->abort(result);
753+
return;
754+
}
755+
648756
// Action handling will be done from the timer callback to avoid those things in the realtime
649757
// thread. First, we delete the existing (if any) timer by resetting the pointer and then create a new
650758
// one.
651759
//
652-
RealtimeGoalHandlePtr rt_goal = std::make_shared<RealtimeGoalHandle>(goal_handle);
653760
rt_goal->execute();
654-
bool write_success;
655-
write_success = rt_active_goal_.try_set([&rt_goal](RealtimeGoalHandlePtr& goal) { goal = rt_goal; });
656-
if (!write_success) {
657-
RCLCPP_ERROR(get_node()->get_logger(), "Failed to set active goal.");
658-
}
659761
goal_handle_timer_.reset();
660762
goal_handle_timer_ = get_node()->create_wall_timer(action_monitor_period_.to_chrono<std::chrono::nanoseconds>(),
661763
std::bind(&RealtimeGoalHandle::runNonRealtime, rt_goal));
662764
trajectory_active_ = true;
663765
return;
664766
}
665767

768+
// Called from RT thread
666769
bool PassthroughTrajectoryController::check_goal_tolerance()
667770
{
668771
auto goal_tolerance = goal_tolerance_.try_get();
@@ -737,9 +840,10 @@ std::unordered_map<std::string, size_t>
737840
PassthroughTrajectoryController::create_joint_mapping(const std::vector<std::string>& joint_names) const
738841
{
739842
std::unordered_map<std::string, size_t> joint_mapping;
740-
auto joint_names_internal = joint_names_.try_get();
741-
if (!joint_names_internal) {
742-
RCLCPP_ERROR(get_node()->get_logger(), "Could not get joint names, cannot create joint mapping.");
843+
auto joint_names_internal = get_rt_box_from_non_rt(joint_names_);
844+
if (!joint_names_internal.has_value()) {
845+
RCLCPP_ERROR(get_node()->get_logger(), "Failed to get joint names from realtime box.");
846+
return joint_mapping;
743847
}
744848

745849
for (auto& joint_name : *joint_names_internal) {
@@ -750,6 +854,7 @@ PassthroughTrajectoryController::create_joint_mapping(const std::vector<std::str
750854
}
751855
return joint_mapping;
752856
}
857+
753858
} // namespace ur_controllers
754859

755860
#include "pluginlib/class_list_macros.hpp"

0 commit comments

Comments
 (0)