ETS for 2D space

An ET2 is one elementary \(\SE{2}\) transform: a rotation about, or a translation along, the x- or y-axis. The angle or distance is either a constant or, if it is left out, a variable, which makes the transform a joint. An ETS2 is a sequence of them. The three-dimensional equivalents are on the ETS for 3D space page.

We can use ETS to describes a planar arm that moves in 3D space.

>>> from roboticstoolbox import ET2
>>> e = ET2.R() * ET2.tx(1) * ET2.R() * ET2.tx(1)
>>> print(e)
R(q0) ⊕ tx(1) ⊕ R(q1) ⊕ tx(1)
>>> e.fkine([0.3, 0.4])
SE2(array([[ 0.7648, -0.6442,  1.7202],
           [ 0.6442,  0.7648,  0.9397],
           [ 0.    ,  0.    ,  1.    ]]))

Note

ETS2 has numerical inverse kinematics, ikine_LM(), but no Hessian or manipulability methods yet.

ET2: Elementary Transform

Creating an elementary transform

The constructors R, tx and ty take the same arguments as their 3D equivalents on the ETS for 3D space page: no argument for a joint, a number for a constant, 'deg' for a rotation in degrees, flip, jindex and qlim. The angle or distance can also be a joint descriptor string, with the same rules, see Joint descriptors.

>>> from roboticstoolbox import ET2
>>> ET2.R()                        # a joint
ET2.R()
>>> ET2.R(30, 'deg')               # a constant, degrees
ET2.R(param=0.5235987755982988)
>>> ET2.tx(flip=True, qlim=[0, 1]) # a flipped prismatic joint with limits
ET2.tx(flip=True, qlim=array([0., 1.]))
>>> e = ET2.R("q0") * ET2.tx(1) * ET2.R("-q1") * ET2.tx(1)
>>> e, e.jindices
([ET2.R(jindex=0), ET2.tx(param=1.0), ET2.R(jindex=1, flip=True), ET2.tx(param=1.0)], array([0, 1]))

R

Pure rotation

tx

Pure translation along the x-axis

ty

Pure translation along the y-axis

SE2

A static SE2

Information

kind

The transform type and axis

axis

The transform type and axis

ax

The Cartesian axis this transform acts along/about

param

Get the transform constant

isjoint

Test if ET is a joint

isflip

Test if ET joint is flipped

offset

Offset of a joint

isrotation

Test if ET is a rotation

istranslation

Test if ET is a translation

iselementary

Test if ET is an elementary transform

jindex

Get ET joint index

qlim

Joint limits

Kinematics

A

Evaluate an elementary transformation

inv

Inverse of ET

s

Motion subspace of the joint

Details

class ET2(**kwargs)[source]
property s: ndarray

Motion subspace of the joint

Returns:

the 3-vector \((v_x, v_y, \omega)\) that is the unit twist of the transform: a unit translation along x or y, or a unit rotation

classmethod R(param=None, unit='rad', *, eta=None, **kwargs)[source]

Pure rotation

Parameters:
  • param (float | None | str) – rotation angle, or a joint name such as "q2", see Joint descriptors

  • unit (str) – angular unit, “rad” [default] or “deg”

  • j – Explicit joint number within the robot

  • flip – Joint moves in opposite direction

Returns:

An elementary transform

Return type:

ET2

  • ET2.R(param) is an elementary rotation by a constant angle

  • ET2.R() is an elementary rotation by a variable angle, i.e. a revolute robot joint. j or flip can be set in this case.

Notes

  • In the 2D case this is rotation around the normal to the

    xy-plane.

See also

ET2(), isrotation()

classmethod tx(param=None, unit='rad', *, eta=None, **kwargs)[source]

Pure translation along the x-axis

Parameters:
  • param (float | None | str) – translation distance along the x-axis, or a joint name such as "q2", see Joint descriptors

  • j – Explicit joint number within the robot

  • flip – Joint moves in opposite direction

Returns:

An elementary transform

Return type:

ET2

  • ET2.tx(param) is an elementary translation along the x-axis by a distance constant

  • ET2.tx() is an elementary translation along the x-axis by a variable distance, i.e. a prismatic robot joint. j or flip can be set in this case.

classmethod ty(param=None, unit='rad', *, eta=None, **kwargs)[source]

Pure translation along the y-axis

Parameters:
  • param (float | None | str) – translation distance along the y-axis, or a joint name such as "q2", see Joint descriptors

  • j – Explicit joint number within the robot

  • flip – Joint moves in opposite direction

Returns:

An elementary transform

Return type:

ET2

  • ET2.ty(param) is an elementary translation along the y-axis by a distance constant

  • ET2.ty() is an elementary translation along the y-axis by a variable distance, i.e. a prismatic robot joint. j or flip can be set in this case.

See also

ET2()

classmethod SE2(T, **kwargs)[source]

A static SE2

Parameters:

T (ndarray | SE2) – The SE2 transformation matrix

Returns:

An elementary transform

Return type:

ET2

SymPy:

supported

A(q=0.0)

Evaluate an elementary transformation

Parameters:

q (float | Symbol) – Is used if this ET is variable (a joint)

Returns:

The SE(3) or SE(2) matrix value of the ET

Return type:

ndarray

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx(1)
>>> e.A()
array([[1., 0., 0., 1.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])
>>> e = ET.tx()
>>> e.A(0.7)
array([[1. , 0. , 0. , 0.7],
       [0. , 1. , 0. , 0. ],
       [0. , 0. , 1. , 0. ],
       [0. , 0. , 0. , 1. ]])

Pure-Python evaluation, shared by ET2 and used by ET as the fallback when the compiled acceleration struct can’t be used.

property ax: str | None

The Cartesian axis this transform acts along/about

Returns:

"x", "y", or "z" for an elementary transform, otherwise None (e.g. ET2’s rotation, which has no axis letter, or a compound/arbitrary SE3/SE2 transform)

Return type:

str or None

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx(1)
>>> e.ax
'x'
>>> e = ET.Rx(90, 'deg')
>>> e.ax
'x'
property axis: str

The transform type and axis

Deprecated since version 1.4.0: Use kind instead. axis is kept as an alias and will not be repurposed to mean something else in a future release.

Returns:

The transform type and axis

Return type:

str

property eta: float | Symbol | None

Get the transform constant

Deprecated since version 1.4.0: eta (η) is the name used in the original Elementary Transform Sequence paper; kept as a permanent alias for param, which is otherwise identical.

Returns:

The constant value if set

Return type:

float or Sym or None

Setter accepts:

float | Symbol

inv()

Inverse of ET

Returns:

Inverse of the ET

Return type:

Any

The inverse of a given ET.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz(2.5)
>>> print(e)
Rz(143.2°)
>>> print(e.inv())
Rz(-143.2°)
property iselementary: bool

Test if ET is an elementary transform

Returns:

True if an elementary transform

Return type:

bool

Notes

  • ET’s may not actually be “elementary”, it can be a complex

    mix of rotations and translations.

See also

compile()

property isflip: bool

Test if ET joint is flipped

Returns:

True if joint is flipped

Return type:

bool

A flipped joint uses the negative of the joint variable, ie. it rotates or moves in the opposite direction.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx()
>>> e.A(1)
array([[1., 0., 0., 1.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])
>>> eflip = ET.tx(flip=True)
>>> eflip.A(1)
array([[ 1.,  0.,  0., -1.],
       [ 0.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  1.]])
property isjoint: bool

Test if ET is a joint

Returns:

True if a joint

Return type:

bool

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx(1)
>>> e.isjoint
False
>>> e = ET.tx()
>>> e.isjoint
True
property isrotation: bool

Test if ET is a rotation

Returns:

True if a rotation

Return type:

bool

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx(1)
>>> e.isrotation
False
>>> e = ET.Rx()
>>> e.isrotation
True
property istranslation: bool

Test if ET is a translation

Returns:

True if a translation

Return type:

bool

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx(1)
>>> e.istranslation
True
>>> e = ET.Rx()
>>> e.istranslation
False
property jindex: int | None

Get ET joint index

Returns:

The assigned joint index

Return type:

int or None

Allows an ET to be associated with a numbered joint in a robot.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx()
>>> print(e)
tx(q)
>>> e = ET.tx(jindex=3)
>>> print(e)
tx(q3)
>>> print(e.jindex)
3
Setter accepts:

Any

property kind: str

The transform type and axis

Returns:

The transform type and axis, e.g. "Rx", "tx", "SE3"

Return type:

str

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx(1)
>>> e.kind
'tx'
>>> e = ET.Rx(90, 'deg')
>>> e.kind
'Rx'
property offset: float | Symbol

Offset of a joint

Returns:

the offset, zero unless one has been set

Raises:

TypeError – on set, if the transform is not a joint

A joint transforms by \(\pm q + a\): the joint variable, negated if the joint is flipped, plus the offset \(a\). This is the offset of a Denavit-Hartenberg link, and it is what remains of a constant transform of the same kind that is merged into a joint, see merge(). The joint limits qlim are limits on \(q\), not on \(\pm q + a\).

The offset may be symbolic. It is zero if it is exactly zero or, for a rotation, a whole number of turns of a symbolic angle.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz()
>>> e.offset = 0.5
>>> print(e)
Rz(q + 28.65°)
>>> e.A(0.1)
array([[ 0.8253, -0.5646,  0.    ,  0.    ],
       [ 0.5646,  0.8253,  0.    ,  0.    ],
       [ 0.    ,  0.    ,  1.    ,  0.    ],
       [ 0.    ,  0.    ,  0.    ,  1.    ]])
>>> print(e.inv())
Rz(q - 28.65°)

Note

A joint with an offset is evaluated by the Python code, not the compiled code, so it is slower. ik_LM, ik_NR and ik_GN, which need the compiled code, do not accept it.

property param: float | Symbol | None

Get the transform constant

Returns:

The constant value if set

Return type:

float or Sym or None

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tx(1)
>>> e.param
1.0
>>> e = ET.Rx(90, 'deg')
>>> e.param
1.5707963267948966
>>> e = ET.ty()
>>> e.param

Notes

  • If the value was given in degrees it will be converted and

    stored internally in radians

  • Historically called eta (η), after the notation used in the

    original Elementary Transform Sequence paper (Haviland & Corke, “Manipulator Differential Kinematics”). eta is kept as a deprecated alias below.

Setter accepts:

float | Symbol

property qlim: ndarray | None

Joint limits

Returns:

the joint limits as a 2-vector [lower, upper], or None if the transform has no limits

Setter accepts:

ndarray | Sequence[float] | None

ETS: Elementary Transform Sequence

An ETS2 is a list-like object, with the same list methods as the ETS. Joint descriptors are the same as for the 3D case, see Joint descriptors.

Information

n

Number of joints

m

Number of transforms

structure

Joint structure string

joints

Get a list of the variable ETs with this ETS

joint_idx

Get index of joint transforms

jindices

Get an array of joint indices

jindex_set

Get set of joint indices

qlim

Get/Set Joint limits

random_q

Generate a random valid joint configuration

Modification

insert

Insert value

inv

Inverse of ETS

fixjoint

Return an independent ETS2 with the specified joint held constant.

split

Split ETS into link segments

swap

Swap two adjacent transforms, in place

swapped

Swap two adjacent transforms, returning a copy

merge

Merge two adjacent transforms into one, in place

merged

Merge two adjacent transforms, returning a copy

compile

Compile an ETS2

List operations

A sequence is a list of elementary transforms, so it has the methods of a list. Those that change it do so in place.

Method

Does

append()

adds an elementary transform to the end

extend()

adds the transforms of another sequence to the end

pop

removes and returns the transform at an index, by default the last

remove()

removes the first transform that is equal to the given one

reverse()

reverses the order of the transforms, which is not the inverse of the sequence, see inv()

clear

removes all the transforms

count

the number of transforms equal to the given one

index

the index of the first transform equal to the given one

Kinematics

fkine

Forward kinematics

eval

Forward kinematics (returns raw ndarray)

jacob0

Manipulator Jacobian in the base frame

jacobe

Jacobian in end-effector frame

ikine_LM

Levenberg-Marquardt numerical inverse kinematics solver

Other

plot

Plot the sequence as a robot

teach

Interactively explore the sequence as a robot

Details

class ETS2(arg=None)[source]

This class implements an elementary transform sequence (ETS) for 2D

Parameters:

arg (list[ETS2 | ET2] | list[ET2] | list[ETS2] | ET2 | ETS2 | None) – Function to compute ET value

An instance can contain an elementary transform (ET) or an elementary transform sequence (ETS). It has list-like properties by subclassing UserList, which means we can perform indexing, slicing pop, insert, as well as using it as an iterator over its values.

  • ETS() an empty ETS list

  • ET2.XY(η) is a constant elementary transform

  • ET2.XY(η, 'deg') as above but the angle is expressed in degrees

  • ET2.XY() is a joint variable, the value is left free until evaluation time

  • ET2.XY(jindex=J) as above but the joint index is explicitly given, this might correspond to the joint number of a multi-joint robot.

  • ET2.XY(flip=True) as above but the joint moves in the opposite sense

where XY is one of R, tx, ty.

Example

>>> from roboticstoolbox import ET2
>>> e = ET2.R(0.3) * ET2.tx(2)  # an ETS2
>>> len(e)                      # of length 2
2
>>> e[1]                        # an ET2 indexed from the ETS2
ET2.tx(param=2.0)
References:
  • Kinematic Derivatives using the Elementary Transform Sequence, J. Haviland and P. Corke

See also

r, tx, ty

fixjoint(j, value, unit='rad')[source]

Return an independent ETS2 with the specified joint held constant.

j is the zero-based position among joint ETs, independent of their jindex values. Remaining joints retain explicit global jindices; automatically indexed joints are renumbered to fill the gap. Joint limits and flip flags are preserved. The original is not modified.

Parameters:
  • j (int) – index of the joint to fix

  • value (float) – fixed joint coordinate, in radians/degrees or metres

  • unit (str) – angular unit for rotational joints, “rad” [default] or “deg”

Return type:

ETS2

Returns:

ETS2 with one fewer joint

Raises:

ValueError – for an invalid joint position or angular unit

Fixing a flipped revolute joint preserves the other joint as a variable:

>>> from roboticstoolbox import ET2
>>> ets = ET2.R(flip=True) * ET2.tx(1) * ET2.R()
>>> fixed = ets.fixjoint(0, 90, unit="deg")
>>> fixed.n, ets.n
(1, 2)
>>> (1, 2)
(1, 2)

Added in version 1.5.0.

compile()[source]

Compile an ETS2

Return type:

ETS2

Returns:

optimised ETS2

Perform constant folding for faster evaluation. Consecutive constant ETs are compounded, leading to a constant ET which is denoted by SE3 when displayed.

See also

isconstant

insert(i, arg)[source]

Insert value

Parameters:
  • i (int) – position to insert at

  • arg (ET2 | ETS2) – the elementary transform or sequence to insert

Return type:

None

Inserts an ET or ETS into the ET sequence. The inserted value is at position i.

Example:

>>> from roboticstoolbox import ET2
>>> e = ET2.R() * ET2.tx(1) * ET2.R() * ET2.tx(1)
>>> f = ET2.R()
>>> e.insert(2, f)
>>> e
[ET2.R(jindex=0), ET2.tx(param=1.0), ET2.R(), ET2.R(jindex=1), ET2.tx(param=1.0)]
fkine(q=None, base=None, tool=None, include_base=True)[source]

Forward kinematics

Parameters:
Returns:

transformation matrix representing the end-effector pose

Return type:

SE2

T = ets.fkine(q) evaluates forward kinematics for the robot at joint configuration q.

Trajectory operation: If q has multiple rows (mxn), it is considered a trajectory and the result is an SE2 instance with m values.

Note

  • The robot’s base tool transform, if set, is incorporated into the result.

  • A tool transform, if provided, is incorporated into the result.

  • Works from the end-effector link to the base

References

  • Kinematic Derivatives using the Elementary Transform Sequence, J. Haviland and P. Corke

eval(q=None, base=None, tool=None, include_base=True)[source]

Forward kinematics (returns raw ndarray)

Parameters:
Returns:

transformation matrix representing the end-effector pose

Return type:

ndarray

T = ets.eval(q) evaluates forward kinematics for the robot at joint configuration q, returning the raw ndarray.

Trajectory operation: If q has multiple rows (mxn), it is considered a trajectory and the result is an ndarray of shape (m,3,3).

Note

  • The robot’s base tool transform, if set, is incorporated into the result.

  • A tool transform, if provided, is incorporated into the result.

  • Works from the end-effector link to the base

References

  • Kinematic Derivatives using the Elementary Transform Sequence, J. Haviland and P. Corke

jacob0(q)[source]

Manipulator Jacobian in the base frame

Parameters:

q (ndarray | Sequence[float]) – the joint coordinates

Return type:

ndarray

Returns:

the Jacobian, rows are \((v_x, v_y, \omega)\), one column per joint

Note

This is a simple, not efficient, implementation.

append(value)

S.append(value) – append value to the end of the sequence

extend(values)

S.extend(iterable) – extend sequence by appending elements from the iterable

inv()

Inverse of ETS

The inverse of a given ETS. It is computed as the inverse of the individual ETs in the reverse order.

\[(\mathbf{E}_0, \mathbf{E}_1 \cdots \mathbf{E}_{n-1} )^{-1} = (\mathbf{E}_{n-1}^{-1}, \mathbf{E}_{n-2}^{-1} \cdots \mathbf{E}_0^{-1}{n-1} )\]
Return type:

Self

Returns:

Inverse of the ETS

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz(jindex=2) * ET.tx(1) * ET.Rx(jindex=3,flip=True) * ET.tx(1)
>>> print(e)
Rz(q2) ⊕ tx(1) ⊕ Rx(-q3) ⊕ tx(1)
>>> print(e.inv())
tx(-1) ⊕ Rx(q3) ⊕ tx(-1) ⊕ Rz(-q2)

Notes

  • It is essential to use explicit joint indices to account for

    the reversed order of the transforms.

jacobe(q)[source]

Jacobian in end-effector frame

Parameters:

q (ndarray | Sequence[float]) – joint coordinates

Returns:

Jacobian matrix

Return type:

Any

jacobe(q) is the manipulator Jacobian matrix which maps joint velocity to end-effector spatial velocity.

End-effector spatial velocity \(\nu = (v_x, v_y, \omega)^T\) is related to joint velocity by \({}^{e}\nu = {}^{e}\mathbf{J}_0(q) \dot{q}\).

See also

jacob0(), hessian0

jindex_set()

Get set of joint indices

Returns:

set of unique joint indices

Return type:

set[int]

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz(jindex=1) * ET.tx(jindex=2) * ET.Rz(jindex=1) * ET.tx(1)
>>> e.jindex_set()
{1, 2}
property jindices: ndarray

Get an array of joint indices

Returns:

array of unique joint indices

Return type:

ndarray

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz(jindex=1) * ET.tx(jindex=2) * ET.Rz(jindex=1) * ET.tx(1)
>>> e.jindices
array([1, 2, 1])
joint_idx()

Get index of joint transforms

Returns:

indices of transforms that are joints

Return type:

ndarray

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz() * ET.tx(1) * ET.Rz() * ET.tx(1)
>>> e.joint_idx()
array([0, 2])
joints()

Get a list of the variable ETs with this ETS

Returns:

list of ETs that are joints

Return type:

list[ETT]

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz() * ET.tx(1) * ET.Rz() * ET.tx(1)
>>> e.joints()
[ET.Rz(jindex=0), ET.Rz(jindex=1)]
property m: int

Number of transforms

Returns:

the number of transforms in the ETS

Return type:

int

Counts the number of transforms in the ETS.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rx() * ET.tx(1) * ET.tz()
>>> e.m
3
merge(i)

Merge two adjacent transforms into one, in place

Parameters:

i (int) – index of the first transform

Raises:
  • IndexError – if i and i+1 are not both in the sequence

  • ValueError – if the transforms are not of the same kind, or both are joints

Return type:

None

Replaces the transforms at indices i and i+1 with a single transform. This changes the sequence it is called on and returns None; use merged() to get a modified copy and leave the original alone.

The two transforms must be of the same kind, for example two tx or two Rz. There are two cases:

  • Two constants become a constant whose parameter is the sum of the two.

  • A joint and a constant become the same joint, with the constant added to its offset, so Rz(q) * Rz(a) is Rz(q + a). The joint keeps its jindex, flip and qlim.

Two joints cannot be merged, since they are two variables.

The parameters and offsets may be numeric or symbolic, or one of each. If two constants add up to nothing the transform is removed altogether, rather than being left as a transform that does nothing. An offset that adds up to nothing is zero but the joint stays. The sum is nothing if it is

  • exactly zero, for example tx(x) * tx(-x) with x a SymPy symbol, or Rx(5) * Rx(-5)

  • for a rotation, a whole number of turns of a symbolic angle, for example Rz(pi/2) * Rz(3*pi/2) with pi from SymPy. A floating point sum such as Rz(pi/2) * Rz(3*pi/2) using math.pi is not exactly zero, so the rotation is kept.

Merging does not look at the neighbours of the result, so if removing a transform leaves two mergeable ones adjacent, call merge() again.

Examples

>>> from roboticstoolbox import ET
>>> from math import pi
>>> e = ET.Rz() * ET.tx(1) * ET.tx(2) * ET.Rz(1)
>>> print(e)
Rz(q) ⊕ tx(1) ⊕ tx(2) ⊕ Rz(57.3°)
>>> e.merge(1)
>>> print(e)
Rz(q) ⊕ tx(3) ⊕ Rz(57.3°)
>>> e = ET.tx(1) * ET.Rx(0.1) * ET.Rx(pi/2) * ET.tx(2)
>>> print(e)
tx(1) ⊕ Rx(5.73°) ⊕ Rx(90°) ⊕ tx(2)
>>> e.merge(1)
>>> print(e)
tx(1) ⊕ Rx(95.73°) ⊕ tx(2)
>>> e = ET.tx(1) * ET.Rx(0.5) * ET.Rx(-0.5) * ET.tx(2)
>>> e.merge(1)
>>> print(e)
tx(1) ⊕ tx(2)

A constant merged into a joint becomes its offset, which may be symbolic:

>>> from roboticstoolbox import ET
>>> from spatialmath.base import symbol
>>> a = symbol("a")
>>> e = ET.tx(1) * ET.Rz() * ET.Rz(a) * ET.tx(2)
>>> e.merge(1)
>>> print(e)
tx(1) ⊕ Rz(q + a) ⊕ tx(2)
>>> e = ET.Rz(-a) * ET.Rz() * ET.Rz(a)
>>> e.merge(1)
>>> print(e)
Rz(-a) ⊕ Rz(q + a)
>>> e.merge(0)
>>> print(e)
Rz(q)

Changed in version 1.5.0: A joint can be merged with a constant, and a transform that adds up to nothing is removed.

See also

merged() swap()

merged(i)

Merge two adjacent transforms, returning a copy

Parameters:

i (int) – index of the first transform

Return type:

Self

Returns:

a copy of the sequence with transforms i and i+1 merged

Raises:
  • IndexError – if i and i+1 are not both in the sequence

  • ValueError – if the transforms are not of the same kind, or both are joints

The sequence it is called on is not changed. See merge() for which transforms can be merged and when the result is removed.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz() * ET.tx(1) * ET.tx(2) * ET.Rz(1)
>>> print(e.merged(1))
Rz(q) ⊕ tx(3) ⊕ Rz(57.3°)
>>> print(e)
Rz(q) ⊕ tx(1) ⊕ tx(2) ⊕ Rz(57.3°)

Added in version 1.5.0.

See also

merge() swapped()

property n: int

Number of joints

Returns:

the number of joints in the ETS

Return type:

int

Counts the number of joints in the ETS.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rx() * ET.tx(1) * ET.tz()
>>> e.n
2

See also

joints()

plot(*args, **kwargs)

Plot the sequence as a robot

The sequence is wrapped in a Robot (Robot2 for a planar sequence) and its plot method is called, which see for the arguments.

Return type:

None

property qlim: ndarray

Get/Set Joint limits

Limits are extracted from the link objects. If joints limits are not set for:

  • a revolute joint [-𝜋. 𝜋] is returned

  • a prismatic joint an exception is raised

Parameters:

new_qlim (ndarray(2,n)) – new joint limits to set

Returns:

array of joint limit values

Return type:

ndarray(2,n)

Raises:

ValueError – unset limits for a prismatic joint

Examples

>>> import roboticstoolbox as rtb
>>> robot = rtb.models.DH.Puma560()
>>> robot.qlim
array([[-2.7925, -0.7854, -3.927 , -1.9199, -1.7453, -4.6426],
       [ 2.7925,  3.927 ,  0.7854,  2.9671,  1.7453,  4.6426]])
Setter accepts:

ndarray | Sequence[float]

random_q(i=1)

Generate a random valid joint configuration

Parameters:

i (int) – number of configurations to generate

Returns:

random joint configuration

Return type:

ndarray

Generates a random q vector within the joint limits defined by self.qlim.

Examples

>>> import roboticstoolbox as rtb
>>> robot = rtb.models.Panda()
>>> ets = robot.ets()
>>> q = ets.random_q()
>>> q
array([ 0.0693,  0.1806, -2.7405, -2.4115,  0.3134,  3.3791,  1.2632])
remove(value)

S.remove(value) – remove first occurrence of value. Raise ValueError if the value is not present.

reverse()

S.reverse() – reverse IN PLACE

split(method='last')

Split ETS into link segments

Parameters:

method (str) – one of "first" or "last" (default).

Return type:

list[Self]

Returns:

[base, *segments, gripper] – a list of length n_joints + 2. base/gripper are empty ETS when the method has no concept of one.

Split an ETS into segments representing links, plus a base and gripper segment. Unpack with base, *segments, gripper = ets.split(method).

The behaviour depends on the method argument:

  • "first": each link segment begins with a joint and continues upto, but not including the next joint. Any constant ET before the first joint are part of the base. There are no gripper ET, they are included in the last link segment.

  • "last": each link segment ends with a joint and include all ET after the previous joint. Any constant ET after the last joint are part of the gripper. There are no base ET, they are included in the first link segment.

>>> from roboticstoolbox import ET
>>> e = ET.tz(1) * ET.Rx("q1") * ET.tx(2) * ET.Ry("q2") * ET.ty(3) * ET.Rz("q3") * ET.tz(4)
>>> base, *segments, gripper = e.split("first")
>>> print("|".join(str(_) for _ in segments), f"+ base={str(base)}, gripper={str(gripper)}")
Rx(q1) ⊕ tx(2)|Ry(q2) ⊕ ty(3)|Rz(q3) ⊕ tz(4) + base=tz(1), gripper=SE3()
>>> base, *segments, gripper = e.split("last")
>>> print("|".join(str(_) for _ in segments), f"+ base={str(base)}, gripper={str(gripper)}")
tz(1) ⊕ Rx(q1)|tx(2) ⊕ Ry(q2)|ty(3) ⊕ Rz(q3) + base=SE3(), gripper=tz(4)
property structure: str

Joint structure string

A string comprising the characters ‘R’ or ‘P’ which indicate the types of joints in order from left to right.

Returns:

a string indicating the joint types

Return type:

str

Examples

>>> from roboticstoolbox import ET
>>> e = ET.tz() * ET.tx(1) * ET.Rz() * ET.tx(1)
>>> e.structure
'PR'
swap(i)

Swap two adjacent transforms, in place

Parameters:

i (int) – index of the first transform

Raises:
  • IndexError – if i and i+1 are not both in the sequence

  • ValueError – if the two transforms cannot be swapped

Return type:

None

Swaps the transforms at indices i and i+1 without changing what the sequence means. This changes the sequence it is called on and returns None; use swapped() to get a modified copy and leave the original alone.

There are two ways the transforms can swap.

They commute, so they trade places unchanged. Two transforms commute if they are

  • of the same kind, for example two translations along x

  • both translations, along any axes

  • a rotation and a translation along the axis of that rotation, for example Rz and tz

One is a constant quarter or half turn, a rotation \(R\) of \(\pm 90^\circ\) or \(180^\circ\). The other transform \(B\) is carried across it by being turned with it, since \(R B = (R B R^{-1}) R\). The rotation is unchanged, and the other transform moves to the other side of it and changes axis, and its sign if the axis comes out reversed. For example Rx(90°) ⊕ ty(d) is tz(d) ⊕ Rx(90°), and Rx(90°) ⊕ Ry(q) is Rz(q) ⊕ Rx(90°). The other transform may be a translation or a rotation, a joint or a constant. A joint keeps its jindex and qlim; if its axis comes out reversed it is flipped, and its offset changes sign.

A rotation is a quarter turn if it is a whole number of quarter turns of a symbolic angle, such as pi/2 or 3*pi/2 with pi from SymPy, or a float that is within \(10^{-9}\) of one, which a model loaded from a file will have. The new transform takes its parameter from the old one by a change of sign only, so it is as exact as the old one.

Anything else, such as a rotation that is not a quarter turn and a translation along a different axis, does not swap and raises ValueError, as do two quarter turns about different axes, since either could be the one that is carried across.

Note

Joints may be swapped. Each joint keeps its jindex, so the order of the elements of q is unchanged even though the joints now appear in the opposite order in the sequence.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz() * ET.tx(1) * ET.ty(2) * ET.Rz(1)
>>> print(e)
Rz(q) ⊕ tx(1) ⊕ ty(2) ⊕ Rz(57.3°)
>>> e.swap(1)
>>> print(e)
Rz(q) ⊕ ty(2) ⊕ tx(1) ⊕ Rz(57.3°)
>>> e = ET.Rz() * ET.tz(1) * ET.Rx() * ET.Rz(1)
>>> e.swap(0)
>>> print(e)
tz(1) ⊕ Rz(q0) ⊕ Rx(q1) ⊕ Rz(57.3°)

A quarter turn carries the other transform with it:

>>> from math import pi
>>> e = ET.Rx(pi / 2) * ET.ty(1) * ET.tx(2)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'ET' is not defined
>>> print(e)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'e' is not defined
>>> e.swap(0)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'e' is not defined
>>> print(e)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'e' is not defined
>>> e = ET.Rx(pi / 2) * ET.Ry()
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'ET' is not defined
>>> e.swap(0)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'e' is not defined
>>> print(e)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'e' is not defined
>>> e = ET.Rx(-pi / 2) * ET.Ry()
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'ET' is not defined
>>> e.swap(0)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'e' is not defined
>>> print(e)
!! [RUNBLOCK-ERROR] ets/ETS2.py:docstring of roboticstoolbox.ets._ETS.BaseETS.swap:712
    NameError: name 'e' is not defined

Changed in version 1.5.0: A transform can be swapped across a constant quarter or half turn.

See also

swapped() merge()

swapped(i)

Swap two adjacent transforms, returning a copy

Parameters:

i (int) – index of the first transform

Return type:

Self

Returns:

a copy of the sequence with transforms i and i+1 swapped

Raises:
  • IndexError – if i and i+1 are not both in the sequence

  • ValueError – if the two transforms do not commute

The sequence it is called on is not changed. See swap() for which transforms can be swapped.

Examples

>>> from roboticstoolbox import ET
>>> e = ET.Rz() * ET.tx(1) * ET.ty(2) * ET.Rz(1)
>>> print(e.swapped(1))
Rz(q) ⊕ ty(2) ⊕ tx(1) ⊕ Rz(57.3°)
>>> print(e)
Rz(q) ⊕ tx(1) ⊕ ty(2) ⊕ Rz(57.3°)

Added in version 1.5.0.

See also

swap() merged()

teach(*args, **kwargs)

Interactively explore the sequence as a robot

The sequence is wrapped in a Robot (Robot2 for a planar sequence) and its teach method is called, which see for the arguments.

Return type:

None

ikine_LM(Tep, q0=None, ilimit=30, slimit=100, tol=1e-06, mask=None, joint_limits=True, seed=None, k=1.0)[source]

Levenberg-Marquardt numerical inverse kinematics solver

Parameters:
  • Tep (ndarray | SE2) – the desired end-effector pose, an SE2 or a 3x3 array, or a pose trajectory, an SE2 with several values or an (N, 3, 3) array

  • q0 (ndarray | Sequence[float] | None) – the initial joint coordinates, a vector (n,), or a matrix (m, n) whose rows are the starting points of the first m searches (any further searches start from random coordinates within the joint limits)

  • ilimit (int) – maximum iterations allowed per search

  • slimit (int) – maximum search attempts before failure

  • tol (float) – maximum allowed residual error E

  • mask (ndarray | Sequence[float] | None) – a 3-vector weighting the (x, y, θ) error priority, for example [1, 1, 0] to solve for position only

  • joint_limits (bool) – reject solutions with joint limit violations

  • seed (int | None) – seed for the RNG used to generate random joint configurations

  • k (float) – gain λ of Chan’s damping matrix, see below

Return type:

IKSolution

Returns:

the solution, see IKSolution

Raises:

ValueError – Tep is not a 3x3 pose or an (N, 3, 3) trajectory, mask is not a 3-vector, q0 has the wrong number of columns, or a joint has an infinite limit so no random configuration can be drawn

sol = ets.ikine_LM(Tep) are the joint coordinates (n) corresponding to the planar end-effector pose Tep. The solver is the planar counterpart of ETS.ikine_LM(): the pose error is the 3-vector \(\vec{e} = (\Delta x, \Delta y, \Delta\theta)\) in the world frame, the residual is \(E = \tfrac{1}{2} \vec{e}^\top \mat{W}_e \vec{e}\) with \(\mat{W}_e = \text{diag}(\text{mask})\), and each step is

\[\vec{q}_{k+1} = \vec{q}_k + \left( \mat{J}^\top \mat{W}_e \mat{J} + \lambda E_k \mat{1}_n \right)^{-1} \mat{J}^\top \mat{W}_e \vec{e}\]

where \(\mat{J}\) is jacob0(). Because E is quadratic, tol bounds the pose error only to roughly \(\sqrt{2 \cdot \text{tol}}\); tighten it if a specific linear-scale accuracy is needed.

Each search starts from a row of q0, or a random configuration drawn within the joint limits, and runs for at most ilimit iterations; up to slimit searches are made before the solver gives up. A solution that lies outside the joint limits is rejected when joint_limits is True, and the search continues.

Trajectory operation: for a trajectory of N poses the solver is run once per pose, each from the same starting points, and the returned q has shape (N, n). success is True only if every pose was solved, iterations and searches are summed, residual is the largest over the poses and reason is that of the last failed pose.

Example:

>>> import roboticstoolbox as rtb
>>> from roboticstoolbox.ets.ET2 import R, tx
>>> ets = R() * tx(1) * R() * tx(1)
>>> Tep = ets.fkine([0.3, 0.7])
>>> sol = ets.ikine_LM(Tep, seed=0)
>>> sol.success
True
>>> ets.fkine(sol.q)
SE2(array([[ 0.5403, -0.8415,  1.4956],
           [ 0.8415,  0.5403,  1.137 ],
           [ 0.    ,  0.    ,  1.    ]]))

References

  • J. Haviland, and P. Corke. “Manipulator Differential Kinematics Part I: Kinematics, Velocity, and Applications.” arXiv preprint arXiv:2207.01796 (2022).

Added in version 1.5.0.