Skip to content

Commit 0e9b37d

Browse files
author
Felix Exner
committed
Restructure command interface exporting
Make passthrough command interfaces part of the joints and fix claiming conflicts
1 parent 934ccc5 commit 0e9b37d

File tree

5 files changed

+130
-99
lines changed

5 files changed

+130
-99
lines changed

ur_controllers/include/ur_controllers/passthrough_trajectory_controller.hpp

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -70,51 +70,33 @@
7070
namespace ur_controllers
7171
{
7272

73+
/*
74+
* 0.0: No trajectory to forward, the controller is idling and ready to receive a new trajectory.
75+
* 1.0: The controller has received and accepted a new trajecotry. When the state is 1.0, the controller will write a
76+
* point to the hardware interface.
77+
* 2.0: The hardware interface will read the point written from the controller. The state will switch between 1.0
78+
* and 2.0 until all points have been read by the hardware interface.
79+
* 3.0: The hardware interface has read all the points, and will now write all the points to the physical robot
80+
* controller.
81+
* 4.0: The robot is moving through the trajectory.
82+
* 5.0: The robot finished executing the trajectory.
83+
*/
7384
const double TRANSFER_STATE_IDLE = 0.0;
7485
const double TRANSFER_STATE_WAITING_FOR_POINT = 1.0;
7586
const double TRANSFER_STATE_TRANSFERRING = 2.0;
7687
const double TRANSFER_STATE_TRANSFER_DONE = 3.0;
7788
const double TRANSFER_STATE_IN_MOTION = 4.0;
7889
const double TRANSFER_STATE_DONE = 5.0;
90+
7991
using namespace std::chrono_literals; // NOLINT
8092

8193
enum CommandInterfaces
8294
{
83-
/* The PASSTHROUGH_TRAJECTORY_TRANSFER_STATE value is used to keep track of which stage the transfer is in.
84-
0.0: No trajectory to forward, the controller is idling and ready to receive a new trajectory.
85-
1.0: The controller has received and accepted a new trajecotry. When the state is 1.0, the controller will write a
86-
point to the hardware interface.
87-
2.0: The hardware interface will read the point written from the controller. The state will switch between 1.0
88-
and 2.0 until all points have been read by the hardware interface.
89-
3.0: The hardware interface has read all the points, and will now write all the points to the physical robot
90-
controller.
91-
4.0: The robot is moving through the trajectory.
92-
5.0: The robot finished executing the trajectory. */
93-
PASSTHROUGH_TRAJECTORY_TRANSFER_STATE = 0,
94-
/* The PASSTHROUGH_TRAJECTORY_ABORT value is used to indicate whether the trajectory has been cancelled from the
95-
* hardware interface.*/
96-
PASSTHROUGH_TRAJECTORY_ABORT = 1,
97-
/* Arrays to hold the values of a point. */
98-
PASSTHROUGH_TRAJECTORY_POSITIONS_ = 2,
99-
PASSTHROUGH_TRAJECTORY_VELOCITIES_ = 8,
100-
PASSTHROUGH_TRAJECTORY_ACCELERATIONS_ = 14,
101-
PASSTHROUGH_TRAJECTORY_TIME_FROM_START = 20
102-
};
103-
104-
enum StateInterfaces
105-
{
106-
/* State interface 0 - 17 are joint state interfaces*/
107-
108-
SPEED_SCALING_FACTOR = 18,
109-
};
110-
111-
// Struct to hold data that has to be transferred between realtime thread and non-realtime threads
112-
struct AsyncInfo
113-
{
114-
double transfer_state = 0;
115-
double abort = 0;
116-
double controller_running = 0;
117-
bool info_updated = false;
95+
// The PASSTHROUGH_TRAJECTORY_TRANSFER_STATE value is used to keep track of which stage the transfer is in.
96+
PASSTHROUGH_TRAJECTORY_TRANSFER_STATE = 18,
97+
// The PASSTHROUGH_TRAJECTORY_ABORT value is used to indicate whether the trajectory has been cancelled from the
98+
// hardware interface./
99+
PASSTHROUGH_TRAJECTORY_TIME_FROM_START = 19
118100
};
119101

120102
class PassthroughTrajectoryController : public controller_interface::ControllerInterface
@@ -199,6 +181,7 @@ class PassthroughTrajectoryController : public controller_interface::ControllerI
199181
static constexpr double NO_VAL = std::numeric_limits<double>::quiet_NaN();
200182

201183
std::optional<std::reference_wrapper<hardware_interface::LoanedStateInterface>> scaling_state_interface_;
184+
std::optional<std::reference_wrapper<hardware_interface::LoanedStateInterface>> abort_state_interface_;
202185

203186
rclcpp::Clock::SharedPtr clock_;
204187
};

ur_controllers/src/passthrough_trajectory_controller.cpp

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ controller_interface::InterfaceConfiguration PassthroughTrajectoryController::st
111111

112112
conf.names.push_back(passthrough_params_.speed_scaling_interface_name);
113113

114+
const std::string tf_prefix = passthrough_params_.tf_prefix;
115+
conf.names.push_back(tf_prefix + "passthrough_controller/passthrough_trajectory_abort");
116+
114117
return conf;
115118
}
116119

@@ -121,23 +124,14 @@ controller_interface::InterfaceConfiguration PassthroughTrajectoryController::co
121124

122125
const std::string tf_prefix = passthrough_params_.tf_prefix;
123126

124-
config.names.emplace_back(tf_prefix + "passthrough_controller/passthrough_trajectory_transfer_state");
125-
126-
config.names.emplace_back(tf_prefix + "passthrough_controller/passthrough_trajectory_abort");
127-
128-
for (size_t i = 0; i < number_of_joints_; ++i) {
129-
config.names.emplace_back(tf_prefix + "passthrough_controller/passthrough_trajectory_positions_" +
130-
std::to_string(i));
131-
}
132-
for (size_t i = 0; i < number_of_joints_; ++i) {
133-
config.names.emplace_back(tf_prefix + "passthrough_controller/passthrough_trajectory_velocities_" +
134-
std::to_string(i));
135-
}
136-
for (size_t i = 0; i < number_of_joints_; ++i) {
137-
config.names.emplace_back(tf_prefix + "passthrough_controller/passthrough_trajectory_accelerations_" +
138-
std::to_string(i));
127+
auto joint_names = passthrough_params_.joints;
128+
for (auto& joint_name : joint_names) {
129+
config.names.emplace_back(joint_name + "/passthrough_position");
130+
config.names.emplace_back(joint_name + "/passthrough_velocity");
131+
config.names.emplace_back(joint_name + "/passthrough_acceleration");
139132
}
140133

134+
config.names.emplace_back(tf_prefix + "passthrough_controller/passthrough_trajectory_transfer_state");
141135
config.names.emplace_back(tf_prefix + "passthrough_controller/passthrough_trajectory_time_from_start");
142136

143137
return config;
@@ -175,6 +169,19 @@ controller_interface::CallbackReturn PassthroughTrajectoryController::on_activat
175169
return controller_interface::CallbackReturn::ERROR;
176170
}
177171

172+
{
173+
const std::string interface_name = passthrough_params_.tf_prefix + "passthrough_controller/"
174+
"passthrough_trajectory_abort";
175+
auto it = std::find_if(state_interfaces_.begin(), state_interfaces_.end(),
176+
[&](auto& interface) { return (interface.get_name() == interface_name); });
177+
if (it != state_interfaces_.end()) {
178+
abort_state_interface_ = *it;
179+
} else {
180+
RCLCPP_ERROR(get_node()->get_logger(), "Did not find '%s' in state interfaces.", interface_name.c_str());
181+
return controller_interface::CallbackReturn::ERROR;
182+
}
183+
}
184+
178185
return ControllerInterface::on_activate(state);
179186
}
180187

@@ -190,8 +197,8 @@ controller_interface::return_type PassthroughTrajectoryController::update(const
190197
if (current_transfer_state != TRANSFER_STATE_IDLE) {
191198
// Check if the trajectory has been aborted from the hardware interface. E.g. the robot was stopped on the teach
192199
// pendant.
193-
if (command_interfaces_[PASSTHROUGH_TRAJECTORY_ABORT].get_value() == 1.0 && current_index_ > 0) {
194-
RCLCPP_INFO(get_node()->get_logger(), "Trajectory aborted hardware, aborting action.");
200+
if (abort_state_interface_->get().get_value() == 1.0 && current_index_ > 0) {
201+
RCLCPP_INFO(get_node()->get_logger(), "Trajectory aborted by hardware, aborting action.");
195202
std::shared_ptr<control_msgs::action::FollowJointTrajectory::Result> result =
196203
std::make_shared<control_msgs::action::FollowJointTrajectory::Result>();
197204
active_goal->setAborted(result);
@@ -222,23 +229,25 @@ controller_interface::return_type PassthroughTrajectoryController::update(const
222229

223230
// Write the positions for each joint of the robot
224231
auto joint_names_internal = joint_names_.readFromRT();
232+
// We've added the joint interfaces matching the order of the joint names so we can safely access
233+
// them by the index.
225234
for (size_t i = 0; i < number_of_joints_; i++) {
226-
command_interfaces_[CommandInterfaces::PASSTHROUGH_TRAJECTORY_POSITIONS_ + i].set_value(
235+
command_interfaces_[i * 3].set_value(
227236
active_joint_traj_.points[current_index_].positions[joint_mapping->at(joint_names_internal->at(i))]);
228237
// Optionally, also write velocities and accelerations for each joint.
229238
if (active_joint_traj_.points[current_index_].velocities.size() > 0) {
230-
command_interfaces_[CommandInterfaces::PASSTHROUGH_TRAJECTORY_VELOCITIES_ + i].set_value(
239+
command_interfaces_[i * 3 + 1].set_value(
231240
active_joint_traj_.points[current_index_].velocities[joint_mapping->at(joint_names_internal->at(i))]);
241+
if (active_joint_traj_.points[current_index_].accelerations.size() > 0) {
242+
command_interfaces_[i * 3 + 2].set_value(
243+
active_joint_traj_.points[current_index_]
244+
.accelerations[joint_mapping->at(joint_names_internal->at(i))]);
245+
} else {
246+
command_interfaces_[i * 3 + 2].set_value(NO_VAL);
247+
}
232248
} else {
233-
command_interfaces_[CommandInterfaces::PASSTHROUGH_TRAJECTORY_VELOCITIES_].set_value(NO_VAL);
234-
}
235-
236-
if (active_joint_traj_.points[current_index_].accelerations.size() > 0) {
237-
command_interfaces_[CommandInterfaces::PASSTHROUGH_TRAJECTORY_ACCELERATIONS_ + i].set_value(
238-
active_joint_traj_.points[current_index_]
239-
.accelerations[joint_mapping->at(joint_names_internal->at(i))]);
240-
} else {
241-
command_interfaces_[CommandInterfaces::PASSTHROUGH_TRAJECTORY_ACCELERATIONS_ + i].set_value(NO_VAL);
249+
command_interfaces_[i * 3 + 1].set_value(NO_VAL);
250+
command_interfaces_[i * 3 + 2].set_value(NO_VAL);
242251
}
243252
}
244253
// Tell hardware interface that this point is ready to be read.

ur_robot_driver/include/ur_robot_driver/hardware_interface.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ class URPositionHardwareInterface : public hardware_interface::SystemInterface
249249

250250
urcl::RobotReceiveTimeout receive_timeout_ = urcl::RobotReceiveTimeout::millisec(20);
251251

252-
const std::string PASSTHROUGH_TRAJECTORY_CONTROLLER = "passthrough_controller/passthrough_trajectory_positions_";
252+
const std::string PASSTHROUGH_TRAJECTORY_CONTROLLER = "passthrough";
253253
};
254254
} // namespace ur_robot_driver
255255

ur_robot_driver/src/hardware_interface.cpp

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
#include "ur_client_library/exceptions.h"
4646
#include "ur_client_library/ur/tool_communication.h"
4747

48-
#include "rclcpp/rclcpp.hpp"
48+
#include <rclcpp/logging.hpp>
4949
#include "hardware_interface/types/hardware_interface_type_values.hpp"
5050
#include "ur_robot_driver/hardware_interface.hpp"
5151
#include "ur_robot_driver/urcl_log_handler.hpp"
@@ -101,9 +101,9 @@ URPositionHardwareInterface::on_init(const hardware_interface::HardwareInfo& sys
101101
trajectory_joint_accelerations_.clear();
102102

103103
for (const hardware_interface::ComponentInfo& joint : info_.joints) {
104-
if (joint.command_interfaces.size() != 2) {
104+
if (joint.command_interfaces.size() != 5) {
105105
RCLCPP_FATAL(rclcpp::get_logger("URPositionHardwareInterface"),
106-
"Joint '%s' has %zu command interfaces found. 2 expected.", joint.name.c_str(),
106+
"Joint '%s' has %zu command interfaces found. 5 expected.", joint.name.c_str(),
107107
joint.command_interfaces.size());
108108
return hardware_interface::CallbackReturn::ERROR;
109109
}
@@ -236,6 +236,9 @@ std::vector<hardware_interface::StateInterface> URPositionHardwareInterface::exp
236236
state_interfaces.emplace_back(
237237
hardware_interface::StateInterface(tf_prefix + "gpio", "program_running", &robot_program_running_copy_));
238238

239+
state_interfaces.emplace_back(hardware_interface::StateInterface(
240+
tf_prefix + "passthrough_controller", "passthrough_trajectory_abort", &passthrough_trajectory_abort_));
241+
239242
return state_interfaces;
240243
}
241244

@@ -248,6 +251,15 @@ std::vector<hardware_interface::CommandInterface> URPositionHardwareInterface::e
248251

249252
command_interfaces.emplace_back(hardware_interface::CommandInterface(
250253
info_.joints[i].name, hardware_interface::HW_IF_VELOCITY, &urcl_velocity_commands_[i]));
254+
255+
command_interfaces.emplace_back(hardware_interface::CommandInterface(info_.joints[i].name, "passthrough_position",
256+
&passthrough_trajectory_positions_[i]));
257+
258+
command_interfaces.emplace_back(hardware_interface::CommandInterface(info_.joints[i].name, "passthrough_velocity",
259+
&passthrough_trajectory_velocities_[i]));
260+
261+
command_interfaces.emplace_back(hardware_interface::CommandInterface(
262+
info_.joints[i].name, "passthrough_acceleration", &passthrough_trajectory_accelerations_[i]));
251263
}
252264
// Obtain the tf_prefix from the urdf so that we can have the general interface multiple times
253265
// NOTE using the tf_prefix at this point is some kind of workaround. One should actually go through the list of gpio
@@ -283,6 +295,8 @@ std::vector<hardware_interface::CommandInterface> URPositionHardwareInterface::e
283295
hardware_interface::CommandInterface(tf_prefix + "payload", "cog.z", &payload_center_of_gravity_[2]));
284296
command_interfaces.emplace_back(
285297
hardware_interface::CommandInterface(tf_prefix + "payload", "payload_async_success", &payload_async_success_));
298+
command_interfaces.emplace_back(hardware_interface::CommandInterface(
299+
tf_prefix + "passthrough_controller", "passthrough_trajectory_abort", &passthrough_trajectory_abort_));
286300

287301
for (size_t i = 0; i < 18; ++i) {
288302
command_interfaces.emplace_back(hardware_interface::CommandInterface(
@@ -307,27 +321,6 @@ std::vector<hardware_interface::CommandInterface> URPositionHardwareInterface::e
307321
"passthrough_trajectory_transfer_state",
308322
&passthrough_trajectory_transfer_state_));
309323

310-
command_interfaces.emplace_back(hardware_interface::CommandInterface(
311-
tf_prefix + "passthrough_controller", "passthrough_trajectory_abort", &passthrough_trajectory_abort_));
312-
313-
for (size_t i = 0; i < 6; ++i) {
314-
command_interfaces.emplace_back(hardware_interface::CommandInterface(
315-
tf_prefix + "passthrough_controller", "passthrough_trajectory_positions_" + std::to_string(i),
316-
&passthrough_trajectory_positions_[i]));
317-
}
318-
319-
for (size_t i = 0; i < 6; ++i) {
320-
command_interfaces.emplace_back(hardware_interface::CommandInterface(
321-
tf_prefix + "passthrough_controller", "passthrough_trajectory_velocities_" + std::to_string(i),
322-
&passthrough_trajectory_velocities_[i]));
323-
}
324-
325-
for (size_t i = 0; i < 6; ++i) {
326-
command_interfaces.emplace_back(hardware_interface::CommandInterface(
327-
tf_prefix + "passthrough_controller", "passthrough_trajectory_accelerations_" + std::to_string(i),
328-
&passthrough_trajectory_accelerations_[i]));
329-
}
330-
331324
command_interfaces.emplace_back(hardware_interface::CommandInterface(tf_prefix + "passthrough_controller",
332325
"passthrough_trajectory_time_from_start",
333326
&passthrough_trajectory_time_from_start_));
@@ -853,20 +846,11 @@ hardware_interface::return_type URPositionHardwareInterface::prepare_command_mod
853846
if (key == info_.joints[i].name + "/" + hardware_interface::HW_IF_VELOCITY) {
854847
start_modes_.push_back(hardware_interface::HW_IF_VELOCITY);
855848
}
856-
if (key == tf_prefix + PASSTHROUGH_TRAJECTORY_CONTROLLER + std::to_string(i)) {
849+
if (key == info_.joints[i].name + "/" + PASSTHROUGH_TRAJECTORY_CONTROLLER + "_position") {
857850
start_modes_.push_back(PASSTHROUGH_TRAJECTORY_CONTROLLER);
858851
}
859852
}
860853
}
861-
// set new mode to all interfaces at the same time
862-
if (start_modes_.size() != 0 && start_modes_.size() != 6) {
863-
ret_val = hardware_interface::return_type::ERROR;
864-
}
865-
866-
// all start interfaces must be the same - can't mix position and velocity control
867-
if (start_modes_.size() != 0 && !std::equal(start_modes_.begin() + 1, start_modes_.end(), start_modes_.begin())) {
868-
ret_val = hardware_interface::return_type::ERROR;
869-
}
870854

871855
// Stopping interfaces
872856
// add stop interface per joint in tmp var for later check
@@ -878,14 +862,61 @@ hardware_interface::return_type URPositionHardwareInterface::prepare_command_mod
878862
if (key == info_.joints[i].name + "/" + hardware_interface::HW_IF_VELOCITY) {
879863
stop_modes_.push_back(StoppingInterface::STOP_VELOCITY);
880864
}
881-
if (key == PASSTHROUGH_TRAJECTORY_CONTROLLER + std::to_string(i)) {
865+
if (key == info_.joints[i].name + "/" + PASSTHROUGH_TRAJECTORY_CONTROLLER + "_position") {
882866
stop_modes_.push_back(StoppingInterface::STOP_PASSTHROUGH);
883867
}
884868
}
885869
}
870+
871+
// set new mode to all interfaces at the same time
872+
if (start_modes_.size() != 0 && start_modes_.size() != 6) {
873+
RCLCPP_ERROR(get_logger(), "Either none or all joint interfaces must be started at once.");
874+
ret_val = hardware_interface::return_type::ERROR;
875+
}
876+
877+
if (position_controller_running_ &&
878+
std::none_of(stop_modes_.begin(), stop_modes_.end(),
879+
[](auto item) { return item == StoppingInterface::STOP_POSITION; }) &&
880+
std::any_of(start_modes_.begin(), start_modes_.end(), [this](auto& item) {
881+
return (item == hardware_interface::HW_IF_VELOCITY || item == PASSTHROUGH_TRAJECTORY_CONTROLLER);
882+
})) {
883+
RCLCPP_ERROR(get_logger(), "Start of velocity or passthrough interface requested while there is the position "
884+
"interface running.");
885+
ret_val = hardware_interface::return_type::ERROR;
886+
}
887+
888+
if (velocity_controller_running_ &&
889+
std::none_of(stop_modes_.begin(), stop_modes_.end(),
890+
[](auto item) { return item == StoppingInterface::STOP_VELOCITY; }) &&
891+
std::any_of(start_modes_.begin(), start_modes_.end(), [this](auto& item) {
892+
return (item == hardware_interface::HW_IF_POSITION || item == PASSTHROUGH_TRAJECTORY_CONTROLLER);
893+
})) {
894+
RCLCPP_ERROR(get_logger(), "Start of position or passthrough interface requested while there is the velocity "
895+
"interface running.");
896+
ret_val = hardware_interface::return_type::ERROR;
897+
}
898+
899+
if (passthrough_trajectory_controller_running_ &&
900+
std::none_of(stop_modes_.begin(), stop_modes_.end(),
901+
[](auto item) { return item == StoppingInterface::STOP_PASSTHROUGH; }) &&
902+
std::any_of(start_modes_.begin(), start_modes_.end(), [](auto& item) {
903+
return (item == hardware_interface::HW_IF_VELOCITY || item == hardware_interface::HW_IF_POSITION);
904+
})) {
905+
RCLCPP_ERROR(get_logger(), "Start of position or velocity interface requested while there is the passthrough "
906+
"interface running.");
907+
ret_val = hardware_interface::return_type::ERROR;
908+
}
909+
910+
// all start interfaces must be the same - can't mix position and velocity control
911+
if (start_modes_.size() != 0 && !std::equal(start_modes_.begin() + 1, start_modes_.end(), start_modes_.begin())) {
912+
RCLCPP_ERROR(get_logger(), "Can't mix different control domains for joint control.");
913+
ret_val = hardware_interface::return_type::ERROR;
914+
}
915+
886916
// stop all interfaces at the same time
887917
if (stop_modes_.size() != 0 &&
888918
(stop_modes_.size() != 6 || !std::equal(stop_modes_.begin() + 1, stop_modes_.end(), stop_modes_.begin()))) {
919+
RCLCPP_ERROR(get_logger(), "Either none or all joint interfaces must be stopped at once.");
889920
ret_val = hardware_interface::return_type::ERROR;
890921
}
891922

ur_robot_driver/urdf/ur.ros2_control.xacro

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,14 @@
227227
<gpio name="${tf_prefix}system_interface">
228228
<state_interface name="initialized"/>
229229
</gpio>
230+
231+
<gpio name="${tf_prefix}passthrough_controller">
232+
<command_interface name="passthrough_trajectory_transfer_state"/>
233+
<command_interface name="passthrough_trajectory_time_from_start"/>
234+
<state_interface name="passthrough_trajectory_abort"/>
235+
</gpio>
236+
237+
230238
</ros2_control>
231239
</xacro:macro>
232240
</robot>

0 commit comments

Comments
 (0)