Skip to content

Commit 8f35234

Browse files
authored
[Instruction Executor], [wire-breaking] Allow joint and pose targets for all motion functions (UniversalRobots#491)
All script functions interfaced through the InstructionExecutor allow their targets to be either defined as joint array or as poses. This change makes the same interface available on the c++ Instruction executor. See the example for different calls. This effectively breaks the wire protocol for the trajectory point interface. If users have their own external_control script code implementations, they should update them accordingly.
1 parent c7a549e commit 8f35234

26 files changed

Lines changed: 2209 additions & 349 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ endif()
1717

1818

1919
add_library(urcl
20+
src/types.cpp
2021
src/comm/tcp_socket.cpp
2122
src/comm/tcp_server.cpp
2223
src/control/motion_primitives.cpp

doc/architecture/instruction_executor.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ to point motions easily accessible. Currently, it supports the following instruc
1616
* Execute OptimoveL point to point motions (For PolyScope 5.21 / PolyScope 10.8 and later)
1717
* Execute sequences consisting of the motion primitives above
1818

19+
Joint and Cartesian targets
20+
---------------------------
21+
22+
Every motion function comes in two flavours:
23+
24+
* A "native" overload whose parameter is the target type that matches the underlying URScript
25+
command (``vector6d_t`` for ``moveJ`` / ``optimoveJ``, ``urcl::Pose`` for ``moveL``, ``moveP``,
26+
``moveC`` and ``optimoveL``). Braced-initializer-list calls such as
27+
``moveJ({ q1, q2, q3, q4, q5, q6 })`` bind to this overload and keep the behaviour from older
28+
releases.
29+
* A ``urcl::MotionTarget`` overload that accepts either a ``urcl::Q`` (joint configuration) or a
30+
``urcl::Pose`` (Cartesian pose). This lets the same function perform a motion whose target type
31+
does not match the URScript command's natural argument, e.g. ``moveJ(urcl::Pose{...})`` to reach
32+
a Cartesian target with a joint-interpolated motion, or ``moveL(urcl::Q{...})`` to perform a
33+
linear tool-space motion towards the pose implied by a joint configuration.
34+
35+
An ``urcl::Pose`` may optionally carry ``q_near`` (``std::optional<urcl::Q>``), a joint configuration
36+
hint for inverse kinematic solver to select the desired joint angle solution,
37+
when the pose is sent over the trajectory interface; see :ref:`trajectory_point_interface`.
38+
1939
The Instruction Executor uses the :ref:`trajectory_point_interface` and the
2040
:ref:`reverse_interface`
2141
for sending motion instructions to the robot. Hence, it requires a :ref:`ur_driver` object.

doc/architecture/trajectory_point_interface.rst

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,29 +41,71 @@ representations in 21 datafields. The data fields have the following meaning:
4141
===== =====
4242
index meaning
4343
===== =====
44-
0-5 trajectory point positions (Multiplied by ``MULT_JOINTSTATE``)
45-
6-11 trajectory point velocities (Multiplied by ``MULT_JOINTSTATE``). For MOVEC, this contains the "via pose".
46-
12-17 trajectory point accelerations (Multiplied by ``MULT_JOINTSTATE``).
47-
48-
For MOVEC:
49-
50-
- 12: velocity (Multiplied by ``MULT_JOINTSTATE``)
51-
- 13: acceleration (Multiplied by ``MULT_JOINTSTATE``)
52-
- 14: mode (Multiplied by ``MULT_JOINTSTATE``)
53-
54-
18 trajectory point type
55-
56-
- 0: MOVEJ
57-
- 1: MOVEL
58-
- 2: MOVEP
59-
- 3: MOVEC
60-
- 51: SPLINE)
61-
62-
19 trajectory point time (in seconds, multiplied by ``MULT_TIME``)
63-
20 depending on trajectory point type
64-
65-
- MOVEJ, MOVEL, MOVEP and MOVEC: point blend radius (in meters, multiplied by ``MULT_TIME``)
66-
- SPLINE: spline type (1: CUBIC, 2: QUINTIC)
44+
0-5 trajectory point positions (multiplied by ``MULT_JOINTSTATE``).
45+
46+
Interpreted as joint positions [rad] or as a Cartesian pose ([m, m, m, rad, rad, rad])
47+
depending on the motion type at index 20 (see below).
48+
49+
6-11 Depending on the motion type, this represents either
50+
51+
- Joint hint ``q_near`` (six joint positions in radians, ``MULT_JOINTSTATE``-scaled) when
52+
the motion target is a Cartesian ``urcl::Pose`` with ``Pose::q_near`` set on the library
53+
side. The bundled ``external_control.urscript`` applies this hint for ``MOVEJ_POSE`` and
54+
``OPTIMOVEJ_POSE`` (``get_inverse_kin`` seed); other pose motion types still receive the
55+
block on the wire but ignore it in the default script.
56+
57+
- For all MOVEC variants this field contains the via point (same
58+
joint-vs-pose interpretation as the target at indices 0-5, see the motion type at
59+
index 20).
60+
- trajectory point velocities (multiplied by ``MULT_JOINTSTATE``) for spline joint types
61+
62+
12-17 Depending on the motion type, this represents either
63+
64+
- trajectory point accelerations (multiplied by ``MULT_JOINTSTATE``) for spline joint
65+
types.
66+
67+
- for all other motion types
68+
69+
- 12: velocity (multiplied by ``MULT_JOINTSTATE``)
70+
- 13: acceleration (multiplied by ``MULT_JOINTSTATE``)
71+
- 14: Depending on motion type:
72+
73+
- ``MOVEC_*``: arc mode (multiplied by ``MULT_JOINTSTATE``)
74+
- Other non-spline primitives with a Cartesian ``Pose`` target: ``1.0`` or ``0.0``
75+
(scaled by ``MULT_JOINTSTATE``) indicating whether indices 6–11 carry ``q_near``.
76+
The bundled URScript consumes ``q_near`` for ``MOVEJ_POSE`` and ``OPTIMOVEJ_POSE``
77+
only; the flag and joint block are still defined this way for all such pose motions.
78+
79+
18 segment duration (seconds, multiplied by ``MULT_TIME``; integer microseconds on the wire).
80+
81+
19 depending on trajectory point type
82+
83+
- All MOVE* and OPTIMOVE* variants: point blend radius (in meters, multiplied by
84+
``MULT_TIME``)
85+
- SPLINE: spline type (1: CUBIC, 2: QUINTIC; raw integer, not ``MULT_TIME``-scaled)
86+
87+
20 trajectory point type. The base values below use the URScript command's "natural"
88+
target type (joints for ``movej`` / ``optimovej``, Cartesian pose for ``movel`` /
89+
``movep`` / ``movec`` / ``optimovel``). The ``*_POSE`` / ``*_JOINT`` variants indicate
90+
that the other target kind is being sent instead.
91+
92+
- 0: MOVEJ – ``movej`` to a joint target
93+
- 1: MOVEL – ``movel`` to a pose target
94+
- 2: MOVEP – ``movep`` to a pose target
95+
- 3: MOVEC – ``movec`` with pose via and pose target
96+
- 4: OPTIMOVEJ – ``optimovej`` to a joint target
97+
- 5: OPTIMOVEL – ``optimovel`` to a pose target
98+
- 6: MOVEJ_POSE – ``movej`` to a pose target (IK on the robot controller)
99+
- 7: MOVEL_JOINT – ``movel`` to the pose implied by a joint target (FK on the
100+
robot controller)
101+
- 8: MOVEP_JOINT – ``movep`` to the pose implied by a joint target (FK on the
102+
robot controller)
103+
- 9: MOVEC_JOINT – ``movec`` with joint via and joint target
104+
- 10: MOVEC_JOINT_POSE – ``movec`` with pose via and joint target
105+
- 11: MOVEC_POSE_JOINT – ``movec`` with joint via and pose target
106+
- 12: OPTIMOVEJ_POSE – ``optimovej`` to a pose target
107+
- 13: OPTIMOVEL_JOINT – ``optimovel`` to the pose implied by a joint target
108+
- 51: SPLINE - Cubic or quintic spline.
67109
===== =====
68110

69111
where
@@ -75,3 +117,13 @@ where
75117
With ``MULT_TIME`` being 1000000, the maximum duration that can be sent is 2147 seconds, while
76118
precision is cut off at 1 microsecond. (The same applies to the blend radius, respectively being
77119
max 2147 m and 1 μm precision.)
120+
121+
.. note::
122+
The ``*_POSE`` / ``*_JOINT`` motion-type variants let callers mix joint-space and Cartesian
123+
targets freely through the high-level APIs (see :ref:`instruction_executor` and the
124+
``urcl::MotionTarget`` type). On the wire the positions are always packed as a 6-tuple of
125+
``MULT_JOINTSTATE``-scaled integers; which physical quantity they represent (joint angles or
126+
Cartesian pose components) is determined solely by the motion type field at index 20. The
127+
corresponding mapping back to ``movej`` / ``movel`` / ``movep`` / ``movec`` / ``optimovej`` /
128+
``optimovel`` calls with either ``q`` or ``p[...]`` arguments is performed on the robot side
129+
by ``resources/external_control.urscript``.

doc/examples/instruction_executor.rst

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,41 @@ functions, so the parameter descriptions for them apply, as well. Particularly,
5050
choose between either a time-based execution or an acceleration / velocity parametrization
5151
for some move functions. The latter will be ignored if a time > 0 is given.
5252

53+
Each motion primitive can be constructed either with its "native" target type (``vector6d_t`` for
54+
``MoveJ`` / ``OptimoveJ``, ``urcl::Pose`` for ``MoveL`` / ``MoveP`` / ``MoveC`` / ``OptimoveL``)
55+
or with a ``urcl::MotionTarget``, which can hold either a ``urcl::Q`` (joint configuration) or a
56+
``urcl::Pose`` (Cartesian pose). This makes it possible, for example, to use a
57+
``MoveLPrimitive`` with a joint configuration – the robot will then compute the forward
58+
kinematics on the controller and linearly interpolate in tool space towards the resulting pose.
59+
5360
Please refer to the script manual for details.
5461

5562
Execute a single motion
5663
-----------------------
5764

58-
To run a single motion, the ``InstructionExecutor`` provides the methods ``moveJ(...)`` and
59-
``moveL(...)``:
65+
To run a single motion, the ``InstructionExecutor`` provides the methods ``moveJ(...)``,
66+
``moveL(...)``, ``moveP(...)``, ``moveC(...)``, ``optimoveJ(...)`` and ``optimoveL(...)``:
6067

6168
.. literalinclude:: ../../examples/instruction_executor.cpp
6269
:language: c++
6370
:caption: examples/instruction_executor.cpp
6471
:linenos:
6572
:lineno-match:
6673
:start-at: double goal_time_sec = 2.0;
67-
:end-before: g_my_robot->getUrDriver()->stopControl();
74+
:end-before: return 0;
6875

6976
Again, time parametrization has priority over acceleration / velocity parameters.
77+
78+
Each motion function has two overloads: one taking the "natural" target type
79+
(``vector6d_t`` for ``moveJ`` / ``optimoveJ``, ``urcl::Pose`` for the other motions), and one
80+
taking a ``urcl::MotionTarget``. Passing a braced-initializer-list of six doubles selects the
81+
natural overload, so ``moveJ({ ... })`` continues to be interpreted as joint positions and
82+
``moveL({ ... })`` as a Cartesian pose. To select the other interpretation, wrap the values in
83+
``urcl::Q{...}`` or ``urcl::Pose{...}`` explicitly – for example,
84+
``moveJ(urcl::Pose{...})`` performs a ``movej`` towards a Cartesian target and
85+
``moveL(urcl::Q{...})`` performs a ``movel`` towards the pose implied by a joint configuration.
86+
The same rules apply to ``moveP``, ``moveC``, ``optimoveJ`` and ``optimoveL``.
87+
88+
For Cartesian targets, ``urcl::Pose`` may optionally set ``q_near`` (a ``urcl::Q``): a joint-space
89+
hint forwarded on the trajectory socket for inverse kinematics. The bundled external-control
90+
URScript uses it for ``movej`` / ``optimovej`` to a pose; see :ref:`trajectory_point_interface`.

examples/instruction_executor.cpp

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ int main(int argc, char* argv[])
8989

9090
std::make_shared<urcl::control::MoveLPrimitive>(urcl::Pose(-0.203, 0.263, 0.559, 0.68, -1.083, -2.076), 0.1,
9191
std::chrono::seconds(2)),
92+
std::make_shared<urcl::control::MoveLPrimitive>(urcl::Q{ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 0.1,
93+
std::chrono::seconds(2)),
9294
std::make_shared<urcl::control::MovePPrimitive>(urcl::Pose{ -0.203, 0.463, 0.559, 0.68, -1.083, -2.076 }, 0.1, 0.4,
9395
0.4),
9496
std::make_shared<urcl::control::OptimoveJPrimitive>(urcl::vector6d_t{ -1.57, -1.57, 1.6, -0.5, 0.4, 0.3 }, 0.1, 0.4,
@@ -100,17 +102,52 @@ int main(int argc, char* argv[])
100102

101103
double goal_time_sec = 2.0;
102104

103-
// acceleration / velocity parametrization
104-
instruction_executor->moveJ({ -1.57, -1.57, 0, 0, 0, 0 }, 2.0, 2.0);
105-
// goal time parametrization -- acceleration and velocity will be ignored
105+
// acceleration / velocity parametrization brace-init style will be interpreted as joint
106+
// positions
107+
instruction_executor->moveJ({ -1.742, -1.726, -2.214, -0.773, 1.572, -0.171 }, 2.0, 2.0);
108+
109+
// Passing a pose to moveJ will make it internally solve inverse kinematics.
110+
instruction_executor->moveJ(urcl::Pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0 }, 2.0, 2.0);
111+
112+
// To provide a q_near hint for the IK solver a joint configuration near the target can be added to a pose.
113+
urcl::Pose target_pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0 };
114+
target_pose.setQNear(urcl::Q{ -1.7, -4, 1.5, -1, 1.5, 0 });
115+
instruction_executor->moveJ(target_pose, 2.0, 2.0);
116+
117+
// q_near can also be set directly upon pose construction
118+
instruction_executor->moveJ(
119+
urcl::Pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0, urcl::Q{ -1.7, -4, 1.5, -1, 1.5, 0 } }, 2.0, 2.0);
120+
121+
// goal time parametrization -- acceleration and velocity will be scaled to meed the goal time.
106122
instruction_executor->moveJ({ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 0.1, 0.1, goal_time_sec);
107-
// acceleration / velocity parametrization
108-
instruction_executor->moveL({ -0.203, 0.263, 0.559, 0.68, -1.083, -2.076 }, 1.5, 1.5);
109-
// goal time parametrization -- acceleration and velocity will be ignored
110-
instruction_executor->moveL({ -0.203, 0.463, 0.559, 0.68, -1.083, -2.076 }, 0.1, 0.1, goal_time_sec);
111123

112-
instruction_executor->moveP({ -0.203, 0.463, 0.759, 0.68, -1.083, -2.076 }, 1.5, 1.5);
124+
// moveL calls with brace-init style is interpreted as a pose
125+
instruction_executor->moveL({ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.5, 1.5);
126+
// A pose can also be explicitly passed to moveL
127+
instruction_executor->moveL(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.5, 1.5);
128+
// moveL can also accept a joint position target, if explicitly wrapped into a urcl::Q object
129+
instruction_executor->moveL(urcl::Q{ -1.572, -1.686, 1.707, -0.833, 0.782, 0.479 }, 1.5, 1.5, goal_time_sec);
130+
131+
// moveJ can also accept a Cartesian pose, when given explicitly
132+
instruction_executor->moveJ(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 0.1, 0.1, goal_time_sec);
133+
134+
// moveP can also be called with brace-init (interpreted as pose) or explicitly using a Pose or Q
135+
instruction_executor->moveP({ -0.2, 0.363, 0.559, 0.68, -1.083, -2.076 }, 0.2, 0.2);
136+
instruction_executor->moveP(urcl::Pose{ -0.0203, 0.303, 0.559, 0.68, -1.083, -2.076 }, 0.2, 0.2);
137+
instruction_executor->moveP(urcl::Q{ -1.57, -1.83, 1.707, -0.833, 0.782, 0.479 }, 0.2, 0.2);
138+
139+
// For moveC via and target can be a Pose or Q. When brace-init style lists are given, values are
140+
// interpreted as Pose.
141+
instruction_executor->moveC(urcl::Pose{ -0.1, 0.463, 0.559, 0.68, -1.083, -2.076 },
142+
urcl::Pose{ -0.3203, 0.303, 0.559, 0.68, -1.083, -2.076 });
143+
instruction_executor->moveC(urcl::Pose{ -0.1, 0.463, 0.559, 0.68, -1.083, -2.076 },
144+
urcl::Q{ -1.57, -1.83, 1.707, -0.833, 0.782, 0.479 });
145+
146+
// For optimove functions, the same target rules as for moveJ and moveL apply.
147+
instruction_executor->optimoveJ({ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 1.0, 1.0);
148+
instruction_executor->optimoveL(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.0, 1.0);
149+
instruction_executor->optimoveL(urcl::Q{ -1.572, -1.686, 1.707, -0.833, 0.782, 0.479 }, 1.0, 1.0);
150+
instruction_executor->optimoveJ(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.0, 1.0);
113151

114-
g_my_robot->getUrDriver()->stopControl();
115152
return 0;
116-
}
153+
}

0 commit comments

Comments
 (0)