# Revolute joints

Revolute joints are the most common ones in legged robots. Their equations of motion involve both joint coordinates \(\bfq\) and joint torques \(\bftau\):

But given a joint \(i\) connecting a link \(i\) to its parent \(\lambda(i)\), what is the definition of the joint angle \(q_i\) in \(\bfq\)? Or of the joint torque \(\tau_i\) in \(\bftau\)?

## Kinematics of a revolute joint

Our robot model typically consists in a kinematic tree rooted at a special
link, the *floating base* or *base link*. Each link is a rigid body connected to one or more
others by joints that prevent motion
in some axes while allowing it on some others. Here is the example of a
revolute joint at the elbow of a humanoid robot:

In general there are six degrees of freedom between two rigid bodies,
corresponding to the three translation and three rotation coordinates of their
relative pose. A revolute joint allows
rotation around one axis only, the *joint axis*, thus leaving one degree of
freedom while applying five degrees of constraint between the two bodies. Such
a joint is realized in practice by a rotary actuator, which looks like this:

Regardless of its design (brushless DC electric, series-elastic, quasi-direct
drive, …), the rotary actuator always has two main bodies when we look at it
from the outside: a stator and a rotor. The rotor rotates around (and is
typically symmetric around) the joint axis. The stator is attached to one link
and the rotor to the other, so that the actuator applies *joint torque* between
the two links. In the figure above we have attached the stator to the parent
link and the rotor to the child link, but it could very well have been the
other way round.

### Relative pose of the child link

The Plücker transform \(\bfX_{\lambda(i), i}\) from the child frame \(i\) to the parent frame \(\lambda(i)\) can be decomposed as follows:

In the URDF convention, the child frame coincides with the *joint frame*,
*i.e.* \(\bfX_{rotor, i} = \bfI_{6 \times 6}\). This is purely a
convention, for calculation purposes what matters is rather that
\(\bfX_{\lambda(i), stator}\) and \(\bfX_{rotor, i}\) do not depend on
the joint angle \(q_i\). The only varying part in the equation is then the
stator-to-rotor transform. Say we select the \(z\)-axis of the joint
(rotor) frame as our joint axis, so that our frames look like this:

The transform from the rotor frame to the stator frame is then:

That is, a pure rotation of angle \(q_i\) around the \(z\)-axis of the joint frame. In general, a revolute joint may rotate around any axis \(\bfe_i \neq \bfe_z\), but that's alright, we know how to write rotation matrices from their axis-angle representation ;-) In that case, the transform becomes:

Note that we didn't specify the frame of the Euclidean vector \(\bfe_i\) here. It is not a mistake yet since the rotation leaves this vector unchanged (\({}^{stator} \bfe_i = {}^{rotor} \bfe_i = \bfe_i\)), but we will make the frame explicit when we turn it into a motion vector.

### Velocity and velocity Jacobian of the link

The time derivative of the axis-angle rotation is \(\dot{\bfR}_{\bfe}(q) = \dot{q} \bfe \times \bfR_{\bfe}(q)\). Therefore, the time derivative of the transform from the rotor to the stator frame is:

\begin{align} \dot{\bfR}_{stator, rotor} & = \dot{q_i} \bfe_i \times \bfR_{stator, rotor} \\ \dot{\bfX}_{stator, rotor} & = \dot{q_i} \begin{bmatrix} \bfe_i \\ \bfzero_{3} \end{bmatrix} \times \bfX_{stator, rotor} = \dot{q_i} {}^{stator} \bfs_i \times \bfX_{stator, rotor} \end{align}where we defined the motion vector \({}^{stator} \bfs_i := [\bfe_i\ \bfzero_{3}]\). Let us now derivate the transform \(\bfX_{\lambda(i), i}\) from the link frame to its parent frame:

\begin{align} \dot{\bfX}_{\lambda(i), i} = {}^{\lambda(i)} (\bfv_i - \bfv_{\lambda(i)}) \times \bfX_{\lambda(i), i} & = \bfX_{\lambda(i), stator} \cdot \dot{\bfX}_{stator, rotor} \cdot \bfX_{rotor, i} \\ & = \dot{q}_i \bfX_{\lambda(i), stator} ({}^{stator} \bfs_i \times) \bfX_{stator, rotor} \bfX_{rotor, i} \\ & = \dot{q}_i {}^{\lambda(i)} \bfs_i \times \bfX_{\lambda(i), stator} \bfX_{stator, rotor} \bfX_{rotor, i} \\ & = \dot{q}_i {}^{\lambda(i)} \bfs_i \times \bfX_{\lambda(i), i} \end{align}This implies that \({}^{\lambda(i)} (\bfv_i - \bfv_{\lambda(i)}) = \dot{q}_i {}^{\lambda(i)} \bfs_i\), or equivalently in the world frame:

where \(\bfs_i(\bfq) = \bfX_{world, \lambda(i)}(\bfq) {}^{\lambda(i)} \bfs_i\) maps the joint velocity \(\dot{q}_i \in \mathbb{R}\) to the link's spatial velocity \(\bfv_i \in \textsf{M}^6\). The calculation of this motion vector \(\bfs_i\), which we have seen here in the particular case of a revolute joint, can actually be carried out for any type of joint: given a joint \(j\) with \(n_j\) degrees of freedom and joint coordinates \(\bfq_j \in \mathbb{R}^{n_j}\), there exists a \(6 \times n_j\) matrix \(\bfS(\bfq)\) of motion vectors such that \(\bfv_i = \bfv_{\lambda(i)} + \bfS(\bfq) \dot{\bfq}_j\). Going all the way up to the root of the kinematic tree, we see that these successive motion vectors make up the Jacobian of the link:

where \(\bfJ_i(\bfq)\) is the \(6 \times n\) spatial Jacobian matrix of our link \(i\), and this formula hides under the rug an ordering and flattening of the joint coordinate vectors \([\bfq_{base}, \ldots, q_i, \ldots]\) into the generalized coordinates \(\bfq\) (libraries like Pinocchio let us access both). Rigid body libraries factor computations for better performance, but in essence the Jacobian matrix routinely used in inverse kinematics is the matrix thus derived.

## Dynamics of a revolute joint

While kinematics derives from the composition of transforms \(\bfX_{CA} = \bfX_{CB} \bfX_{BA}\), dynamics derives from the Newton-Euler equations of rigid bodies:

where \(\bfa_i\) is the spatial acceleration of the link, \(\bfI_i\) its spatial inertia matrix, and \(\bfw^{net}_i\) the net spatial force applied to it. The left-hand side represents the inertia and motion of the link, while the right-hand side represents forces. Let us focus on the latter to see how the joint torque \(\tau_i\) appears there.

### Forces acting on the link

By convention, we write \(\bfw_{i}\) the spatial force vector representing
forces applied by the *parent* link \(\lambda(i)\) onto link \(i\). The
net force applied on the link is then:

where \(\bfw^{ext}_i\) is the sum of external forces applied to the link, for instance gravity applied at its center of mass, or external forces exerted by a collision.

The force \(\bfw_i\) consists of two components:

**Joint forces:**\(\bfw_i^{joint} = (\bfs_i \cdot \bfw_i) \bfs_i\) act along the joint degrees of freedom. (Note that \(\| \bfs_i \| = 1\).) Since the dot product of two vectors does not depend on the frame they are expressed in, we can evaluate \((\bfs_i \cdot \bfw_i)\) in the joint frame:

**Internal forces:**\(\bfw_i^{int} = {}^i \bfs_i \times {}^i \bfw_i \times {}^i \bfs_i = \bfw_i - ({}^i \bfs_i \cdot {}^i \bfw_i) {}^i \bfs_i\),*a.k.a.*"everything else". These are the linear forces and torques transmitted through the mounting of the joint (screws, contacts between parts, any device that implements a degree of constraint). They don't affect the robot's motion, but they may be relevant to other robotic activities such as "making sure things don't break".

This shows how, if our rotary actuator is able to control the torque \(\tau_i\), this torque affects the equation of motion of link \(i\) via \(\bfw_i^{joint} = \tau_i \bfs_i\). For other types of joints a similar relationship holds, although it is generally written the other way round as \(\bftau_i = \bfS_i^\top \bfw^{joint}_i = \bfS_i^\top \bfw_i\) (with internal forces in the nullspace of \(\bfS_i^\top\)).

Note that, from the usual convention that \(\bfw_i\) is the torque applied
by the parent onto the child link, the torque \(\tau_i\) is similarly
applied *to* our link \(i\) by the joint. By Newton's law of
action-reaction, an opposite torque \(-\tau_i\) is applied to the parent
link \(\lambda(i)\).

## To go further

You can take a bite at the knee torque of a lumped mass problem to check whether you are at ease with the kinematics and dynamics of revolute joints. The formulas we have seen here are presented for other types of joints in Roy Featherstone's Rigid Body Dynamics Algorithms. Check out in particular sections 3.5 (Joint Constraints) and 4.4 (Joint Models).

## Discussion

There are no comments yet. Feel free to leave a reply using the form below.