Trajectory Joint Interface example
At first, we create a UrDriver object as usual:
66 bool headless_mode = true;
67 g_my_robot = std::make_unique<urcl::ExampleRobotWrapper>(robot_ip, OUTPUT_RECIPE, INPUT_RECIPE, headless_mode,
68 "external_control.urp");
69 if (!g_my_robot->isHealthy())
70 {
71 URCL_LOG_ERROR("Something in the robot initialization went wrong. Exiting. Please check the output above.");
72 return 1;
73 }
We use a small helper function to make sure that the reverse interface is active and connected before proceeding.
Initialization
As trajectory execution will be triggered asynchronously, we define a callback function to handle a finished trajectory. A trajectory is considered finished when the robot is no longer executing it, independent of whether it successfully reached its final point. The trajectory result will reflect whether it was executed successfully, was canceled upon request or failed for some reason.
50void trajDoneCallback(const urcl::control::TrajectoryResult& result)
51{
52 URCL_LOG_INFO("Trajectory done with result %s", urcl::control::trajectoryResultToString(result).c_str());
53 g_trajectory_done = true;
54}
That callback can be registered at the UrDriver object:
76 g_my_robot->getUrDriver()->registerTrajectoryDoneCallback(&trajDoneCallback);
MoveJ Trajectory
Then, in order to execute a trajectory, we need to define a trajectory as a sequence of points and
parameters. The following example shows execution of a 2-point trajectory using URScript’s
movej function:
80 {
81 g_trajectory_done = false;
82 // Trajectory definition
83 std::vector<urcl::vector6d_t> points{ { -1.57, -1.57, 0, 0, 0, 0 }, { -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 } };
84 std::vector<double> motion_durations{ 5.0, 2.0 };
85 std::vector<double> velocities{ 2.0, 2.3 };
86 std::vector<double> accelerations{ 2.5, 2.5 };
87 std::vector<double> blend_radii{ 0.1, 0.1 };
88
89 // Trajectory execution
90 g_my_robot->getUrDriver()->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_START,
91 static_cast<int>(points.size() * 2));
92 for (size_t i = 0; i < points.size(); i++)
93 {
94 g_my_robot->getUrDriver()->writeTrajectoryPoint(points[i], false, static_cast<float>(motion_durations[i]),
95 static_cast<float>(blend_radii[i]));
96 }
97
98 // Same motion, but parametrized with acceleration and velocity
99 motion_durations = { 0.0, 0.0 };
100 for (size_t i = 0; i < points.size(); i++)
101 {
102 g_my_robot->getUrDriver()->writeTrajectoryPoint(
103 points[i], static_cast<float>(accelerations[i]), static_cast<float>(velocities[i]), false,
104 static_cast<float>(motion_durations[i]), static_cast<float>(blend_radii[i]));
105 }
106
107 while (!g_trajectory_done)
108 {
109 std::this_thread::sleep_for(std::chrono::milliseconds(100));
110 g_my_robot->getUrDriver()->writeTrajectoryControlMessage(
111 urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP);
112 }
113 }
In fact, the path is followed twice, once parametrized by a segment duration and once using maximum
velocity / acceleration settings. If a duration > 0 is given for a segment, the velocity and
acceleration settings will be ignored as in the underlying URScript functions. In the example
above, each of the g_my_robot->getUrDriver()->writeTrajectoryPoint() calls will be translated into a
movej command in URScript.
While the trajectory is running, we need to tell the robot program that connection is still active
and we expect the trajectory to be running. This is being done by the
g_my_robot->getUrDriver()->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP);
call.
MoveL Trajectory
Similar to the movej-based trajectory, execution can be done interpolating in joint space:
118 {
119 g_trajectory_done = false;
120 // Trajectory definition
121 std::vector<urcl::vector6d_t> points{ { -0.203, 0.263, 0.559, 0.68, -1.083, -2.076 },
122 { -0.203, 0.463, 0.559, 0.68, -1.083, -2.076 } };
123 std::vector<double> motion_durations{ 5.0, 5.0 };
124 std::vector<double> velocities{ 2.0, 2.3 };
125 std::vector<double> accelerations{ 2.5, 2.5 };
126 std::vector<double> blend_radii{ 0.0, 0.0 };
127
128 // Trajectory execution of the path that goes through the points twice.
129 g_my_robot->getUrDriver()->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_START,
130 static_cast<int>(points.size() * 2));
131 for (size_t i = 0; i < points.size(); i++)
132 {
133 // setting the cartesian parameter makes it interpret the 6d vector as a pose and use movel
134 g_my_robot->getUrDriver()->writeTrajectoryPoint(points[i], true, static_cast<float>(motion_durations[i]),
135 static_cast<float>(blend_radii[i]));
136 }
137
138 // Same motion, but parametrized with acceleration and velocity
139 motion_durations = { 0.0, 0.0 };
140 for (size_t i = 0; i < points.size(); i++)
141 {
142 g_my_robot->getUrDriver()->writeTrajectoryPoint(
143 points[i], static_cast<float>(accelerations[i]), static_cast<float>(velocities[i]), true,
144 static_cast<float>(motion_durations[i]), static_cast<float>(blend_radii[i]));
145 }
146
147 while (!g_trajectory_done)
148 {
149 std::this_thread::sleep_for(std::chrono::milliseconds(100));
150 g_my_robot->getUrDriver()->writeTrajectoryControlMessage(
151 urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP);
152 }
153 }
Spline based interpolation
Similar to the Spline Interpolation example, the trajectory point interface can be used to execute motions using the spline interpolation:
158 {
159 g_trajectory_done = false;
160 // Trajectory definition
161 std::vector<urcl::vector6d_t> positions{ { -1.57, -1.57, 0, 0, 0, 0 },
162 { -1.57, -1.57, -1.57, 0, 0, 0 },
163 { -1.57, -1.57, 0, 0, 0, 0 },
164 { -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 } };
165 std::vector<urcl::vector6d_t> velocities{
166 { 0, 0, 0.0, 0, 0, 0 }, { 0, 0, 0.0, 0, 0, 0 }, { 0, 0, 1.5, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }
167 };
168 std::vector<double> motion_durations{ 3.0, 3.0, 3.0, 3.0 };
169
170 // Trajectory execution
171 g_my_robot->getUrDriver()->writeTrajectoryControlMessage(urcl::control::TrajectoryControlMessage::TRAJECTORY_START,
172 static_cast<int>(positions.size()));
173 for (size_t i = 0; i < positions.size(); i++)
174 {
175 g_my_robot->getUrDriver()->writeTrajectorySplinePoint(positions[i], velocities[i],
176 static_cast<float>(motion_durations[i]));
177 }
178
179 while (!g_trajectory_done)
180 {
181 std::this_thread::sleep_for(std::chrono::milliseconds(100));
182 g_my_robot->getUrDriver()->writeTrajectoryControlMessage(
183 urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP);
184 }
185 }