Skip to content

Commit 8a5a746

Browse files
committed
Updated documentation and tests
1 parent 854cfb7 commit 8a5a746

9 files changed

Lines changed: 654 additions & 87 deletions

File tree

doc/architecture/trajectory_point_interface.rst

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,28 +41,53 @@ 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)
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 18 (see below).
48+
49+
6-11 trajectory point velocities (multiplied by ``MULT_JOINTSTATE``).
50+
51+
For all MOVEC variants this field is repurposed to carry the via point (same
52+
joint-vs-pose interpretation as the target at indices 0-5, see the motion type at
53+
index 18).
54+
55+
12-17 trajectory point accelerations (multiplied by ``MULT_JOINTSTATE``).
56+
57+
For all MOVEC variants:
58+
59+
- 12: velocity (multiplied by ``MULT_JOINTSTATE``)
60+
- 13: acceleration (multiplied by ``MULT_JOINTSTATE``)
61+
- 14: mode (multiplied by ``MULT_JOINTSTATE``)
62+
63+
18 trajectory point type. The base values below use the URScript command's "natural"
64+
target type (joints for ``movej`` / ``optimovej``, Cartesian pose for ``movel`` /
65+
``movep`` / ``movec`` / ``optimovel``). The ``*_POSE`` / ``*_JOINT`` variants indicate
66+
that the other target kind is being sent instead.
67+
68+
- 0: MOVEJ – ``movej`` to a joint target
69+
- 1: MOVEL – ``movel`` to a pose target
70+
- 2: MOVEP – ``movep`` to a pose target
71+
- 3: MOVEC – ``movec`` with pose via and pose target
72+
- 4: OPTIMOVEJ – ``optimovej`` to a joint target
73+
- 5: OPTIMOVEL – ``optimovel`` to a pose target
74+
- 6: MOVEJ_POSE – ``movej`` to a pose target (IK on the robot controller)
75+
- 7: MOVEL_JOINT – ``movel`` to the pose implied by a joint target (FK on the
76+
robot controller)
77+
- 8: MOVEP_JOINT – ``movep`` to the pose implied by a joint target (FK on the
78+
robot controller)
79+
- 9: MOVEC_JOINT – ``movec`` with joint via and joint target
80+
- 10: MOVEC_JOINT_POSE – ``movec`` with pose via and joint target
81+
- 11: MOVEC_POSE_JOINT – ``movec`` with joint via and pose target
82+
- 12: OPTIMOVEJ_POSE – ``optimovej`` to a pose target
83+
- 13: OPTIMOVEL_JOINT – ``optimovel`` to the pose implied by a joint target
84+
- 51: SPLINE
6185

6286
19 trajectory point time (in seconds, multiplied by ``MULT_TIME``)
6387
20 depending on trajectory point type
6488

65-
- MOVEJ, MOVEL, MOVEP and MOVEC: point blend radius (in meters, multiplied by ``MULT_TIME``)
89+
- All MOVE* and OPTIMOVE* variants: point blend radius (in meters, multiplied by
90+
``MULT_TIME``)
6691
- SPLINE: spline type (1: CUBIC, 2: QUINTIC)
6792
===== =====
6893

@@ -75,3 +100,13 @@ where
75100
With ``MULT_TIME`` being 1000000, the maximum duration that can be sent is 2147 seconds, while
76101
precision is cut off at 1 microsecond. (The same applies to the blend radius, respectively being
77102
max 2147 m and 1 μm precision.)
103+
104+
.. note::
105+
The ``*_POSE`` / ``*_JOINT`` motion-type variants let callers mix joint-space and Cartesian
106+
targets freely through the high-level APIs (see :ref:`instruction_executor` and the
107+
``urcl::MotionTarget`` type). On the wire the positions are always packed as a 6-tuple of
108+
``MULT_JOINTSTATE``-scaled integers; which physical quantity they represent (joint angles or
109+
Cartesian pose components) is determined solely by the motion type field at index 18. The
110+
corresponding mapping back to ``movej`` / ``movel`` / ``movep`` / ``movec`` / ``optimovej`` /
111+
``optimovel`` calls with either ``q`` or ``p[...]`` arguments is performed on the robot side
112+
by ``resources/external_control.urscript``.

doc/examples/instruction_executor.rst

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,37 @@ 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``.

include/ur_client_library/control/motion_primitives.h

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,36 @@ namespace urcl
4242
namespace control
4343
{
4444

45+
/*!
46+
* \brief Discriminator for the motion primitive type sent over the trajectory interface.
47+
*
48+
* The base values (``MOVEJ``, ``MOVEL``, ``MOVEP``, ``MOVEC``, ``OPTIMOVEJ``, ``OPTIMOVEL``) use
49+
* their "natural" target type for the URScript command (joint configuration for ``movej`` /
50+
* ``optimovej``, Cartesian pose for ``movel`` / ``movep`` / ``movec`` / ``optimovel``). The
51+
* additional ``*_POSE`` and ``*_JOINT`` entries indicate that the *other* target kind was
52+
* requested, e.g. ``MOVEJ_POSE`` performs a ``movej`` towards a Cartesian pose, and
53+
* ``MOVEC_POSE_JOINT`` performs a ``movec`` whose via point is a Cartesian pose and whose target
54+
* is a joint configuration.
55+
*
56+
* These values must stay in sync with the ``MOTION_TYPE_*`` constants in
57+
* ``resources/external_control.urscript``.
58+
*/
4559
enum class MotionType : uint8_t
4660
{
47-
MOVEJ = 0,
48-
MOVEL = 1,
49-
MOVEP = 2,
50-
MOVEC = 3,
51-
OPTIMOVEJ = 4,
52-
OPTIMOVEL = 5,
53-
MOVEJ_POSE = 6,
54-
MOVEL_JOINT = 7,
55-
MOVEP_JOINT = 8,
56-
MOVEC_JOINT = 9,
57-
MOVEC_JOINT_POSE = 10,
58-
MOVEC_POSE_JOINT = 11,
59-
OPTIMOVEJ_POSE = 12,
60-
OPTIMOVEL_JOINT = 13,
61+
MOVEJ = 0, //!< ``movej`` towards a joint configuration.
62+
MOVEL = 1, //!< ``movel`` towards a Cartesian pose.
63+
MOVEP = 2, //!< ``movep`` towards a Cartesian pose.
64+
MOVEC = 3, //!< ``movec`` with via and target as Cartesian poses.
65+
OPTIMOVEJ = 4, //!< ``optimovej`` towards a joint configuration.
66+
OPTIMOVEL = 5, //!< ``optimovel`` towards a Cartesian pose.
67+
MOVEJ_POSE = 6, //!< ``movej`` towards a Cartesian pose.
68+
MOVEL_JOINT = 7, //!< ``movel`` towards a joint configuration.
69+
MOVEP_JOINT = 8, //!< ``movep`` towards a joint configuration.
70+
MOVEC_JOINT = 9, //!< ``movec`` with via and target both as joint configurations.
71+
MOVEC_JOINT_POSE = 10, //!< ``movec`` with a Cartesian via and a joint target.
72+
MOVEC_POSE_JOINT = 11, //!< ``movec`` with a joint via and a Cartesian target.
73+
OPTIMOVEJ_POSE = 12, //!< ``optimovej`` towards a Cartesian pose.
74+
OPTIMOVEL_JOINT = 13, //!< ``optimovel`` towards a joint configuration.
6175
SPLINE = 51,
6276
UNKNOWN = 255
6377
};
@@ -96,6 +110,14 @@ struct MoveJPrimitive : public MotionPrimitive
96110
this->velocity = velocity;
97111
this->blend_radius = blend_radius;
98112
}
113+
/*!
114+
* \brief Construct a MoveJ primitive from a \ref urcl::MotionTarget.
115+
*
116+
* If ``target`` holds a \ref urcl::Q, ``type`` is set to \ref MotionType::MOVEJ and
117+
* ``target_joint_configuration`` is populated. If ``target`` holds a \ref urcl::Pose, ``type``
118+
* is set to \ref MotionType::MOVEJ_POSE and ``target_pose`` is populated instead; the robot
119+
* will internally solve inverse kinematics to reach the pose with a ``movej``.
120+
*/
99121
MoveJPrimitive(const urcl::MotionTarget& target, const double blend_radius = 0,
100122
const std::chrono::duration<double> duration = std::chrono::milliseconds(0),
101123
const double acceleration = 1.4, const double velocity = 1.04)
@@ -139,6 +161,15 @@ struct MoveLPrimitive : public MotionPrimitive
139161
this->velocity = velocity;
140162
this->blend_radius = blend_radius;
141163
}
164+
/*!
165+
* \brief Construct a MoveL primitive from a \ref urcl::MotionTarget.
166+
*
167+
* If ``target`` holds a \ref urcl::Pose, ``type`` is set to \ref MotionType::MOVEL. If it
168+
* holds a \ref urcl::Q, ``type`` is set to \ref MotionType::MOVEL_JOINT and the configuration
169+
* is stored in ``target_joint_configuration``. The robot will still execute a tool-space
170+
* linear motion, resolving the joint configuration to its forward kinematics pose on the
171+
* controller.
172+
*/
142173
MoveLPrimitive(const urcl::MotionTarget& target, const double blend_radius = 0,
143174
const std::chrono::duration<double> duration = std::chrono::milliseconds(0),
144175
const double acceleration = 1.4, const double velocity = 1.04)
@@ -179,6 +210,12 @@ struct MovePPrimitive : public MotionPrimitive
179210
this->velocity = velocity;
180211
this->blend_radius = blend_radius;
181212
}
213+
/*!
214+
* \brief Construct a MoveP primitive from a \ref urcl::MotionTarget.
215+
*
216+
* Analogous to \ref MoveJPrimitive / \ref MoveLPrimitive: a \ref urcl::Pose selects
217+
* \ref MotionType::MOVEP, a \ref urcl::Q selects \ref MotionType::MOVEP_JOINT.
218+
*/
182219
MovePPrimitive(const MotionTarget& target, const double blend_radius = 0, const double acceleration = 1.4,
183220
const double velocity = 1.04)
184221
{
@@ -220,6 +257,18 @@ struct MoveCPrimitive : public MotionPrimitive
220257
this->mode = mode;
221258
}
222259

260+
/*!
261+
* \brief Construct a MoveC primitive from two \ref urcl::MotionTarget values.
262+
*
263+
* Every combination of \ref urcl::Pose and \ref urcl::Q for the via point and the target is
264+
* supported and mapped to the corresponding \ref MotionType (``MOVEC``,
265+
* ``MOVEC_JOINT``, ``MOVEC_POSE_JOINT``, or ``MOVEC_JOINT_POSE``). When a joint configuration
266+
* is used for either role, only the corresponding joint member is populated and the pose
267+
* member is set to a default-constructed \ref urcl::Pose.
268+
*
269+
* \throws urcl::UrException if either variant is ever extended with an alternative that is
270+
* not handled here.
271+
*/
223272
MoveCPrimitive(const MotionTarget& via_point, const MotionTarget& target, const double blend_radius = 0,
224273
const double acceleration = 1.4, const double velocity = 1.04, const int32_t mode = 0)
225274
{
@@ -326,6 +375,12 @@ struct OptimoveJPrimitive : public MotionPrimitive
326375
this->velocity = velocity_fraction;
327376
}
328377

378+
/*!
379+
* \brief Construct an OptimoveJ primitive from a \ref urcl::MotionTarget.
380+
*
381+
* A \ref urcl::Q selects \ref MotionType::OPTIMOVEJ, a \ref urcl::Pose selects
382+
* \ref MotionType::OPTIMOVEJ_POSE.
383+
*/
329384
OptimoveJPrimitive(const MotionTarget& target, const double blend_radius = 0,
330385
const double acceleration_fraction = 0.3, const double velocity_fraction = 0.3)
331386
{
@@ -366,6 +421,12 @@ struct OptimoveLPrimitive : public MotionPrimitive
366421
this->acceleration = acceleration_fraction;
367422
this->velocity = velocity_fraction;
368423
}
424+
/*!
425+
* \brief Construct an OptimoveL primitive from a \ref urcl::MotionTarget.
426+
*
427+
* A \ref urcl::Pose selects \ref MotionType::OPTIMOVEL, a \ref urcl::Q selects
428+
* \ref MotionType::OPTIMOVEL_JOINT.
429+
*/
369430
OptimoveLPrimitive(const MotionTarget& target, const double blend_radius = 0,
370431
const double acceleration_fraction = 0.3, const double velocity_fraction = 0.3)
371432
{

include/ur_client_library/exceptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,13 @@ class UnsupportedMotionType : public UrException
217217
}
218218
};
219219

220+
/*!
221+
* \brief Thrown when data received from or passed through the library does not match the
222+
* expected structure or value range.
223+
*
224+
* Examples include motion targets whose variant alternative is not handled by the corresponding
225+
* primitive constructor.
226+
*/
220227
class InvalidData : public UrException
221228
{
222229
public:

include/ur_client_library/types.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ using vector6d_t = std::array<double, 6>;
3434
using vector6int32_t = std::array<int32_t, 6>;
3535
using vector6uint32_t = std::array<uint32_t, 6>;
3636

37+
/*!
38+
* \brief A joint configuration (6 joint positions in radians).
39+
*
40+
* This is a strong type around a \ref vector6d_t meant to unambiguously express "this 6-tuple
41+
* represents joint values", as opposed to a Cartesian pose. It is primarily used together with
42+
* \ref MotionTarget to select between joint-space and Cartesian-space targets when calling
43+
* motion functions that can accept either.
44+
*
45+
* Unlike raw initializer lists (``{...}``) which may bind to either \ref vector6d_t or
46+
* \ref Pose, wrapping values in ``urcl::Q{...}`` always forces a joint-target interpretation.
47+
*/
3748
struct Q
3849
{
3950
constexpr Q(double q1, double q2, double q3, double q4, double q5, double q6) : values{ q1, q2, q3, q4, q5, q6 }
@@ -65,6 +76,20 @@ struct Pose
6576
}
6677
};
6778

79+
/*!
80+
* \brief A tagged union representing either a joint target (\ref Q) or a Cartesian target
81+
* (\ref Pose).
82+
*
83+
* ``MotionTarget`` is used throughout the motion API (e.g.
84+
* \ref InstructionExecutor::moveJ "InstructionExecutor::moveJ" and the ``Move*Primitive``
85+
* constructors) to let callers choose at call site whether a motion should be parametrized in
86+
* joint space or in Cartesian space without needing separate overloads for every combination.
87+
*
88+
* The overloads that take a ``MotionTarget`` are provided alongside explicit \ref vector6d_t and
89+
* \ref Pose overloads so that plain braced-initializer calls keep binding to the previous
90+
* behaviour; only explicitly constructed \ref Q or \ref Pose values (or an already-built
91+
* ``MotionTarget``) select the variant-based path.
92+
*/
6893
using MotionTarget = std::variant<Q, Pose>;
6994

7095
template <class T, std::size_t N>

0 commit comments

Comments
 (0)