Skip to content

Commit 8bc55ff

Browse files
authored
Fix trajectory result in trajectory forward mode when no trajectory is running (#276)
Currently, when switching the control mode away from FORWARD, there will always a trajectory result CANCELED sent to the trajectory socket. This commit modifies the script code such that this will only be done when there actually is a trajectory running. It also adds a test for that.
1 parent 66b134e commit 8bc55ff

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

resources/external_control.urscript

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -698,9 +698,11 @@ while control_mode > MODE_STOPPED:
698698
# Clear remaining trajectory points
699699
if control_mode == MODE_FORWARD:
700700
kill thread_trajectory
701-
clear_remaining_trajectory_points()
702-
stopj(STOPJ_ACCELERATION)
703-
socket_send_int(TRAJECTORY_RESULT_CANCELED, "trajectory_socket")
701+
if trajectory_points_left > 0:
702+
clear_remaining_trajectory_points()
703+
stopj(STOPJ_ACCELERATION)
704+
socket_send_int(TRAJECTORY_RESULT_CANCELED, "trajectory_socket")
705+
end
704706
# Stop freedrive
705707
elif control_mode == MODE_FREEDRIVE:
706708
textmsg("Leaving freedrive mode")

tests/test_spline_interpolation.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <ur_client_library/ur/ur_driver.h>
3737
#include <ur_client_library/types.h>
3838

39+
#include <chrono>
3940
#include <iostream>
4041
#include <memory>
4142
#include <math.h>
@@ -56,10 +57,15 @@ bool g_HEADLESS = true;
5657
std::unique_ptr<ExampleRobotWrapper> g_my_robot;
5758

5859
bool g_trajectory_running;
60+
std::condition_variable g_trajectory_result_cv;
61+
std::mutex g_trajectory_result_mutex;
5962
control::TrajectoryResult g_trajectory_result;
6063
void handleTrajectoryState(control::TrajectoryResult state)
6164
{
65+
std::lock_guard<std::mutex> lk(g_trajectory_result_mutex);
66+
g_trajectory_result_cv.notify_one();
6267
g_trajectory_result = state;
68+
URCL_LOG_INFO("Received trajectory result %s", control::trajectoryResultToString(state).c_str());
6369
g_trajectory_running = false;
6470
}
6571

@@ -74,6 +80,12 @@ bool nearlyEqual(double a, double b, double eps = 1e-15)
7480
return c < eps || -c < eps;
7581
}
7682

83+
bool waitForTrajectoryResult(std::chrono::milliseconds timeout)
84+
{
85+
std::unique_lock<std::mutex> lk(g_trajectory_result_mutex);
86+
return g_trajectory_result_cv.wait_for(lk, timeout) == std::cv_status::no_timeout;
87+
}
88+
7789
class SplineInterpolationTest : public ::testing::Test
7890
{
7991
protected:
@@ -1085,6 +1097,52 @@ TEST_F(SplineInterpolationTest, physically_unfeasible_trajectory_quintic_spline)
10851097
}
10861098
}
10871099

1100+
TEST_F(SplineInterpolationTest, switching_control_mode_without_trajectory_produces_no_result)
1101+
{
1102+
// We start by putting the robot into trajectory control mode
1103+
ASSERT_TRUE(
1104+
g_my_robot->ur_driver_->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP));
1105+
1106+
// Then we switch to idle
1107+
ASSERT_TRUE(g_my_robot->ur_driver_->writeKeepalive(RobotReceiveTimeout::sec(2)));
1108+
1109+
EXPECT_FALSE(waitForTrajectoryResult(std::chrono::milliseconds(500)));
1110+
}
1111+
1112+
TEST_F(SplineInterpolationTest, switching_control_mode_with_trajectory_produces_result)
1113+
{
1114+
g_my_robot->stopConsumingRTDEData();
1115+
std::unique_ptr<rtde_interface::DataPackage> data_pkg;
1116+
g_my_robot->readDataPackage(data_pkg);
1117+
1118+
urcl::vector6d_t joint_positions_before;
1119+
ASSERT_TRUE(data_pkg->getData("target_q", joint_positions_before));
1120+
1121+
// Start consuming rtde packages to avoid pipeline overflows while testing that the control script aborts correctly
1122+
g_my_robot->startConsumingRTDEData();
1123+
// Create a trajectory that cannot be executed within the robots limits
1124+
std::vector<urcl::vector6d_t> s_pos, s_vel, s_acc;
1125+
urcl::vector6d_t first_point = {
1126+
joint_positions_before[0], joint_positions_before[1], joint_positions_before[2],
1127+
joint_positions_before[3], joint_positions_before[4], joint_positions_before[5] + 0.5
1128+
};
1129+
s_pos.push_back(first_point);
1130+
1131+
urcl::vector6d_t zeros = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
1132+
s_vel.push_back(zeros);
1133+
s_acc.push_back(zeros);
1134+
1135+
std::vector<double> s_time = { 0.02 };
1136+
sendTrajectory(s_pos, s_vel, s_acc, s_time);
1137+
g_my_robot->ur_driver_->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP, -1,
1138+
RobotReceiveTimeout::off());
1139+
1140+
// Then we switch to idle
1141+
ASSERT_TRUE(g_my_robot->ur_driver_->writeKeepalive(RobotReceiveTimeout::sec(2)));
1142+
1143+
EXPECT_TRUE(waitForTrajectoryResult(std::chrono::milliseconds(500)));
1144+
}
1145+
10881146
int main(int argc, char* argv[])
10891147
{
10901148
::testing::InitGoogleTest(&argc, argv);

0 commit comments

Comments
 (0)