Skip to content

Commit dba3fb2

Browse files
urfeexmergify[bot]
authored andcommitted
Start executing passthrough trajectories earlier than all points are transferred. (#1313)
* Start executing passthrough trajectories earlier than all points are transferred. When transferring trajectories with many waypoints it can take quite a while until all points are transferred from the controller to the hardware interface, especially on lower hardware_interface update rates. With this change, execution starts as soon as enough trajectory points are transferred to fill 5 control cycles. This PR effectively allows reducing the hardware_interface update_rate when using the passthrough_trajectory_controller significantly. This will reduce the networking requirements improving the overall user experience. * Make sure we acknowledge a new trajectory before sending points If we miss the new trajectory, wen cannot resize the vectors appropriately. (cherry picked from commit 14f80ac) # Conflicts: # ur_controllers/src/passthrough_trajectory_controller.cpp # ur_robot_driver/urdf/ur.ros2_control.xacro
1 parent 5ba9b5c commit dba3fb2

File tree

5 files changed

+425
-51
lines changed

5 files changed

+425
-51
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
@@ -81,6 +81,7 @@ namespace ur_controllers
8181
* 5.0: The robot finished executing the trajectory.
8282
*/
8383
const double TRANSFER_STATE_IDLE = 0.0;
84+
const double TRANSFER_STATE_NEW_TRAJECTORY = 6.0;
8485
const double TRANSFER_STATE_WAITING_FOR_POINT = 1.0;
8586
const double TRANSFER_STATE_TRANSFERRING = 2.0;
8687
const double TRANSFER_STATE_TRANSFER_DONE = 3.0;
@@ -174,6 +175,7 @@ class PassthroughTrajectoryController : public controller_interface::ControllerI
174175

175176
std::optional<std::reference_wrapper<hardware_interface::LoanedStateInterface>> scaling_state_interface_;
176177
std::optional<std::reference_wrapper<hardware_interface::LoanedCommandInterface>> abort_command_interface_;
178+
std::optional<std::reference_wrapper<hardware_interface::LoanedCommandInterface>> trajectory_size_command_interface_;
177179
std::optional<std::reference_wrapper<hardware_interface::LoanedCommandInterface>> transfer_command_interface_;
178180
std::optional<std::reference_wrapper<hardware_interface::LoanedCommandInterface>> time_from_start_command_interface_;
179181

ur_controllers/src/passthrough_trajectory_controller.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ controller_interface::InterfaceConfiguration PassthroughTrajectoryController::co
130130
config.names.push_back(tf_prefix + "trajectory_passthrough/abort");
131131
config.names.emplace_back(tf_prefix + "trajectory_passthrough/transfer_state");
132132
config.names.emplace_back(tf_prefix + "trajectory_passthrough/time_from_start");
133+
config.names.emplace_back(tf_prefix + "trajectory_passthrough/trajectory_size");
133134

134135
return config;
135136
}
@@ -178,6 +179,19 @@ controller_interface::CallbackReturn PassthroughTrajectoryController::on_activat
178179
}
179180
}
180181

182+
{
183+
const std::string interface_name = passthrough_params_.tf_prefix + "trajectory_passthrough/"
184+
"trajectory_size";
185+
auto it = std::find_if(command_interfaces_.begin(), command_interfaces_.end(),
186+
[&](auto& interface) { return (interface.get_name() == interface_name); });
187+
if (it != command_interfaces_.end()) {
188+
trajectory_size_command_interface_ = *it;
189+
} else {
190+
RCLCPP_ERROR(get_node()->get_logger(), "Did not find '%s' in command interfaces.", interface_name.c_str());
191+
return controller_interface::CallbackReturn::ERROR;
192+
}
193+
}
194+
181195
const std::string tf_prefix = passthrough_params_.tf_prefix;
182196
{
183197
const std::string interface_name = tf_prefix + "trajectory_passthrough/transfer_state";
@@ -247,7 +261,13 @@ controller_interface::return_type PassthroughTrajectoryController::update(const
247261
active_trajectory_elapsed_time_ = rclcpp::Duration(0, 0);
248262
max_trajectory_time_ =
249263
rclcpp::Duration::from_seconds(duration_to_double(active_joint_traj_.points.back().time_from_start));
264+
<<<<<<< HEAD
250265
transfer_command_interface_->get().set_value(TRANSFER_STATE_WAITING_FOR_POINT);
266+
=======
267+
write_success &= transfer_command_interface_->get().set_value(TRANSFER_STATE_NEW_TRAJECTORY);
268+
write_success &=
269+
trajectory_size_command_interface_->get().set_value(static_cast<double>(active_joint_traj_.points.size()));
270+
>>>>>>> 14f80ac (Start executing passthrough trajectories earlier than all points are transferred. (#1313))
251271
}
252272
auto active_goal_time_tol = goal_time_tolerance_.readFromRT();
253273
auto joint_mapping = joint_trajectory_mapping_.readFromRT();

ur_robot_driver/include/ur_robot_driver/hardware_interface.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,7 @@ class URPositionHardwareInterface : public hardware_interface::SystemInterface
167167
void stop_force_mode();
168168
void check_passthrough_trajectory_controller();
169169
void trajectory_done_callback(urcl::control::TrajectoryResult result);
170-
bool has_accelerations(std::vector<std::array<double, 6>> accelerations);
171-
bool has_velocities(std::vector<std::array<double, 6>> velocities);
170+
bool is_valid_joint_information(std::vector<std::array<double, 6>> data);
172171

173172
urcl::vector6d_t urcl_position_commands_;
174173
urcl::vector6d_t urcl_position_commands_old_;
@@ -240,6 +239,7 @@ class URPositionHardwareInterface : public hardware_interface::SystemInterface
240239
// Passthrough trajectory controller interface values
241240
double passthrough_trajectory_transfer_state_;
242241
double passthrough_trajectory_abort_;
242+
double passthrough_trajectory_size_;
243243
bool passthrough_trajectory_controller_running_;
244244
urcl::vector6d_t passthrough_trajectory_positions_;
245245
urcl::vector6d_t passthrough_trajectory_velocities_;

ur_robot_driver/src/hardware_interface.cpp

Lines changed: 97 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "ur_client_library/exceptions.h"
4646
#include "ur_client_library/ur/tool_communication.h"
4747
#include "ur_client_library/ur/version_information.h"
48+
#include "ur_client_library/ur/robot_receive_timeout.h"
4849

4950
#include <rclcpp/logging.hpp>
5051
#include "hardware_interface/types/hardware_interface_type_values.hpp"
@@ -93,9 +94,10 @@ URPositionHardwareInterface::on_init(const hardware_interface::HardwareInfo& sys
9394
freedrive_mode_abort_ = 0.0;
9495
passthrough_trajectory_transfer_state_ = 0.0;
9596
passthrough_trajectory_abort_ = 0.0;
96-
trajectory_joint_positions_.clear();
97-
trajectory_joint_velocities_.clear();
98-
trajectory_joint_accelerations_.clear();
97+
passthrough_trajectory_size_ = 0.0;
98+
trajectory_joint_positions_.reserve(32768);
99+
trajectory_joint_velocities_.reserve(32768);
100+
trajectory_joint_accelerations_.reserve(32768);
99101

100102
for (const hardware_interface::ComponentInfo& joint : info_.joints) {
101103
if (joint.command_interfaces.size() != 2) {
@@ -381,6 +383,9 @@ std::vector<hardware_interface::CommandInterface> URPositionHardwareInterface::e
381383
command_interfaces.emplace_back(
382384
hardware_interface::CommandInterface(tf_prefix + PASSTHROUGH_GPIO, "abort", &passthrough_trajectory_abort_));
383385

386+
command_interfaces.emplace_back(hardware_interface::CommandInterface(tf_prefix + PASSTHROUGH_GPIO, "trajectory_size",
387+
&passthrough_trajectory_size_));
388+
384389
for (size_t i = 0; i < 6; ++i) {
385390
command_interfaces.emplace_back(hardware_interface::CommandInterface(tf_prefix + PASSTHROUGH_GPIO,
386391
"setpoint_positions_" + std::to_string(i),
@@ -540,6 +545,9 @@ URPositionHardwareInterface::on_configure(const rclcpp_lifecycle::State& previou
540545
driver_config.handle_program_state =
541546
std::bind(&URPositionHardwareInterface::handleRobotProgramState, this, std::placeholders::_1);
542547
ur_driver_ = std::make_unique<urcl::UrDriver>(driver_config);
548+
if (ur_driver_->getControlFrequency() != info_.rw_rate) {
549+
ur_driver_->resetRTDEClient(output_recipe_filename, input_recipe_filename, info_.rw_rate);
550+
}
543551
} catch (urcl::ToolCommNotAvailable& e) {
544552
RCLCPP_FATAL_STREAM(rclcpp::get_logger("URPositionHardwareInterface"), "See parameter use_tool_communication");
545553

@@ -786,7 +794,9 @@ hardware_interface::return_type URPositionHardwareInterface::write(const rclcpp:
786794
ur_driver_->writeFreedriveControlMessage(urcl::control::FreedriveControlMessage::FREEDRIVE_NOOP);
787795

788796
} else if (passthrough_trajectory_controller_running_) {
789-
ur_driver_->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP);
797+
ur_driver_->writeTrajectoryControlMessage(
798+
urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP, 0,
799+
urcl::RobotReceiveTimeout::millisec(1000 * 5.0 / static_cast<double>(info_.rw_rate)));
790800
check_passthrough_trajectory_controller();
791801
} else {
792802
ur_driver_->writeKeepalive();
@@ -1335,59 +1345,102 @@ void URPositionHardwareInterface::stop_force_mode()
13351345
void URPositionHardwareInterface::check_passthrough_trajectory_controller()
13361346
{
13371347
static double last_time = 0.0;
1348+
static size_t point_index_received = 0;
1349+
static size_t point_index_sent = 0;
1350+
static bool trajectory_started = false;
13381351
// See passthrough_trajectory_controller.hpp for an explanation of the passthrough_trajectory_transfer_state_ values.
13391352

13401353
// We should abort and are not in state IDLE
13411354
if (passthrough_trajectory_abort_ == 1.0 && passthrough_trajectory_transfer_state_ != 0.0) {
13421355
ur_driver_->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_CANCEL);
1356+
} else if (passthrough_trajectory_transfer_state_ == 6.0) {
1357+
if (passthrough_trajectory_size_ != trajectory_joint_positions_.size()) {
1358+
RCLCPP_INFO(get_logger(), "Got a new trajectory with %lu points.",
1359+
static_cast<size_t>(passthrough_trajectory_size_));
1360+
trajectory_joint_positions_.resize(passthrough_trajectory_size_);
1361+
trajectory_joint_velocities_.resize(passthrough_trajectory_size_);
1362+
trajectory_joint_accelerations_.resize(passthrough_trajectory_size_);
1363+
trajectory_times_.resize(passthrough_trajectory_size_);
1364+
point_index_received = 0;
1365+
point_index_sent = 0;
1366+
trajectory_started = false;
1367+
last_time = 0.0;
1368+
passthrough_trajectory_transfer_state_ = 1.0;
1369+
}
13431370
} else if (passthrough_trajectory_transfer_state_ == 2.0) {
13441371
passthrough_trajectory_abort_ = 0.0;
1345-
trajectory_joint_positions_.push_back(passthrough_trajectory_positions_);
1372+
trajectory_joint_positions_[point_index_received] = passthrough_trajectory_positions_;
13461373

1347-
trajectory_times_.push_back(passthrough_trajectory_time_from_start_ - last_time);
1374+
trajectory_times_[point_index_received] = passthrough_trajectory_time_from_start_ - last_time;
13481375
last_time = passthrough_trajectory_time_from_start_;
13491376

1350-
if (!std::isnan(passthrough_trajectory_velocities_[0])) {
1351-
trajectory_joint_velocities_.push_back(passthrough_trajectory_velocities_);
1352-
}
1353-
if (!std::isnan(passthrough_trajectory_accelerations_[0])) {
1354-
trajectory_joint_accelerations_.push_back(passthrough_trajectory_accelerations_);
1355-
}
1377+
trajectory_joint_velocities_[point_index_received] = passthrough_trajectory_velocities_;
1378+
trajectory_joint_accelerations_[point_index_received] = passthrough_trajectory_accelerations_;
1379+
1380+
point_index_received++;
13561381
passthrough_trajectory_transfer_state_ = 1.0;
1357-
/* When all points have been read, write them to the physical robot controller.*/
1382+
1383+
// Once we received enough points so we can move for at least 5 cycles, we start executing
1384+
if ((passthrough_trajectory_time_from_start_ > 5.0 / static_cast<double>(info_.rw_rate) ||
1385+
point_index_received == passthrough_trajectory_size_ - 1) &&
1386+
!trajectory_started) {
1387+
ur_driver_->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_START,
1388+
trajectory_joint_positions_.size());
1389+
trajectory_started = true;
1390+
}
13581391
} else if (passthrough_trajectory_transfer_state_ == 3.0) {
1359-
/* Tell robot controller how many points are in the trajectory. */
1360-
ur_driver_->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_START,
1361-
trajectory_joint_positions_.size());
1392+
passthrough_trajectory_abort_ = 0.0;
1393+
passthrough_trajectory_transfer_state_ = 4.0;
1394+
} else if (passthrough_trajectory_transfer_state_ == 4.0) {
1395+
if (point_index_sent == trajectory_joint_positions_.size()) {
1396+
trajectory_joint_positions_.clear();
1397+
trajectory_joint_accelerations_.clear();
1398+
trajectory_joint_velocities_.clear();
1399+
trajectory_times_.clear();
1400+
last_time = 0.0;
1401+
}
1402+
}
1403+
1404+
// We basically get a setpoint from the controller in each cycle. We send all the points that we
1405+
// already received down to the hardware.
1406+
if (trajectory_started && point_index_sent <= trajectory_joint_positions_.size() &&
1407+
point_index_sent < point_index_received) {
1408+
bool error = false;
13621409
/* Write the appropriate type of point depending on the combination of positions, velocities and accelerations. */
1363-
if (!has_velocities(trajectory_joint_velocities_) && !has_accelerations(trajectory_joint_accelerations_)) {
1364-
for (size_t i = 0; i < trajectory_joint_positions_.size(); i++) {
1365-
ur_driver_->writeTrajectorySplinePoint(trajectory_joint_positions_[i], urcl::vector6d_t{ 0, 0, 0, 0, 0, 0 },
1366-
trajectory_times_[i]);
1367-
}
1368-
} else if (has_velocities(trajectory_joint_velocities_) && !has_accelerations(trajectory_joint_accelerations_)) {
1369-
for (size_t i = 0; i < trajectory_joint_positions_.size(); i++) {
1370-
ur_driver_->writeTrajectorySplinePoint(trajectory_joint_positions_[i], trajectory_joint_velocities_[i],
1371-
trajectory_times_[i]);
1372-
}
1373-
} else if (!has_velocities(trajectory_joint_velocities_) && has_accelerations(trajectory_joint_accelerations_)) {
1374-
for (size_t i = 0; i < trajectory_joint_positions_.size(); i++) {
1375-
ur_driver_->writeTrajectorySplinePoint(trajectory_joint_positions_[i], trajectory_joint_accelerations_[i],
1376-
trajectory_times_[i]);
1377-
}
1378-
} else if (has_velocities(trajectory_joint_velocities_) && has_accelerations(trajectory_joint_accelerations_)) {
1379-
for (size_t i = 0; i < trajectory_joint_positions_.size(); i++) {
1380-
ur_driver_->writeTrajectorySplinePoint(trajectory_joint_positions_[i], trajectory_joint_velocities_[i],
1381-
trajectory_joint_accelerations_[i], trajectory_times_[i]);
1410+
for (size_t i = point_index_sent; i < point_index_received; i++) {
1411+
if (is_valid_joint_information(trajectory_joint_positions_)) {
1412+
if (!is_valid_joint_information(trajectory_joint_velocities_) &&
1413+
!is_valid_joint_information(trajectory_joint_accelerations_)) {
1414+
ur_driver_->writeTrajectorySplinePoint(trajectory_joint_positions_[i], urcl::vector6d_t{ 0, 0, 0, 0, 0, 0 },
1415+
trajectory_times_[i]);
1416+
} else if (is_valid_joint_information(trajectory_joint_velocities_) &&
1417+
!is_valid_joint_information(trajectory_joint_accelerations_)) {
1418+
ur_driver_->writeTrajectorySplinePoint(trajectory_joint_positions_[i], trajectory_joint_velocities_[i],
1419+
trajectory_times_[i]);
1420+
} else if (!is_valid_joint_information(trajectory_joint_velocities_) &&
1421+
is_valid_joint_information(trajectory_joint_accelerations_)) {
1422+
RCLCPP_ERROR(get_logger(), "Accelerations but no velocities given. If you want to specify accelerations with "
1423+
"a 0 velocity, please do that explicitly.");
1424+
error = true;
1425+
break;
1426+
1427+
} else if (is_valid_joint_information(trajectory_joint_velocities_) &&
1428+
is_valid_joint_information(trajectory_joint_accelerations_)) {
1429+
ur_driver_->writeTrajectorySplinePoint(trajectory_joint_positions_[i], trajectory_joint_velocities_[i],
1430+
trajectory_joint_accelerations_[i], trajectory_times_[i]);
1431+
}
1432+
} else {
1433+
RCLCPP_ERROR(get_logger(), "Trajectory points without position information are not supported.");
1434+
error = true;
1435+
break;
13821436
}
1437+
point_index_sent++;
1438+
}
1439+
if (error) {
1440+
passthrough_trajectory_abort_ = 1.0;
1441+
passthrough_trajectory_transfer_state_ = 5.0;
1442+
return;
13831443
}
1384-
trajectory_joint_positions_.clear();
1385-
trajectory_joint_accelerations_.clear();
1386-
trajectory_joint_velocities_.clear();
1387-
trajectory_times_.clear();
1388-
last_time = 0.0;
1389-
passthrough_trajectory_abort_ = 0.0;
1390-
passthrough_trajectory_transfer_state_ = 4.0;
13911444
}
13921445
}
13931446

@@ -1402,14 +1455,9 @@ void URPositionHardwareInterface::trajectory_done_callback(urcl::control::Trajec
14021455
return;
14031456
}
14041457

1405-
bool URPositionHardwareInterface::has_velocities(std::vector<std::array<double, 6>> velocities)
1406-
{
1407-
return (velocities.size() > 0);
1408-
}
1409-
1410-
bool URPositionHardwareInterface::has_accelerations(std::vector<std::array<double, 6>> accelerations)
1458+
bool URPositionHardwareInterface::is_valid_joint_information(std::vector<std::array<double, 6>> data)
14111459
{
1412-
return (accelerations.size() > 0);
1460+
return (data.size() > 0 && !std::isnan(data[0][0]));
14131461
}
14141462

14151463
} // namespace ur_robot_driver

0 commit comments

Comments
 (0)