Jiayu Ye bio photo

Jiayu Ye

Describe your self.

Email Facebook Github

This post will review more details in kinematics.

Notations

\[\begin{aligned} q &= \text{Joint state, position} \\ \dot{q} &= \text{Joint velocity} \\ \ddot{q} &= \text{Joint acceleration} \\ X^G &= f_{kin}^G(q) \\ dX^G &= J^G(q)dq \end{aligned}\]

Angular Velocity and Rotation Matrix

Firstly, note that $\dot{q}$ contains two component, joint translational velocity and rotational velocity $\omega$.

\[\dot{q} = \begin{equation*}{}^AV^B_C = \begin{bmatrix} {}^A\omega^B_C \\ {}^A\text{v}^B_C \end{bmatrix}.\end{equation*}\]

while velocity is straight-forward in 3-d space, angular velocity need proper introduction.

  • Elementary School angular velocity: In 2d, angular movement can be parameterized as $(r, \phi)$, where angular velocity is $\dot{\phi}$. While note that the rotation axis is the imaginery z-axis.
  • Undergrad angular velocity: In 3d, angular velocity is defined by a cross product of $r$ and $v$, intuitively rotating around the normal axis defined by the plane spanned by $r$ and $v$. It can be parametrized by a vector $(\omega_x, \omega_y, \omega_z)$ and $v = \omega \times r$.

For example, $\omega=(0,0,1)$ and $r=(1,0,0)$, which is $(0,1,0)$.

rotation

Now we can connect the angular velocity and rotation matrix. Consider a rotation matrix $R(t)$ that rotate points from a fixed point $p^A$ to $p^B$, both expressed in world frame.

\[p^B (t) = R(t) p^A\]

then take derative on both side.

\[v^B = \dfrac{dR(t)}{dt} p^A + R(t) \dfrac{p^A}{dt} = \dot{R(t)} p^A\]

While by definition of angular velocity

\[v^B = \omega \times p^B = \omega \times (R(t) p^A) = [\omega ]_{\times} R(t) p^A \quad [\omega]_\times = \begin{bmatrix} 0 & -\omega_z & \omega_y \\ \omega_z & 0 & -\omega_x \\ -\omega_y & \omega_x & 0 \end{bmatrix}\]

Hence

\[\dot{R(t)} = [\omega ]_{\times} R(t) \quad [\omega ]_{\times} = \dot{R(t)} R(t)^T\]

given $RR^T=I$ for any rotation matrix. We can use a planar robot to illustrate.

import numpy as np
import matplotlib.pyplot as plt
import sympy as sp

# --- Symbolic Verification ---
t = sp.symbols('t')
theta = sp.Function('theta')(t)

# Planar rotation around Z
R = sp.Matrix([
    [sp.cos(theta), -sp.sin(theta), 0],
    [sp.sin(theta),  sp.cos(theta), 0],
    [0,             0,              1]
])

# Time derivative of R
R_dot = R.diff(t)

# Compute Omega_skew = R_dot * R.T
Omega_skew = sp.simplify(R_dot * R.T)

print("Symbolic [omega]_x = R_dot * R^T:")
sp.pprint(Omega_skew)

# Symbolic [omega]_x = R_dot * R^T:
# ⎡           d          ⎤
# ⎢   0      -──(θ(t))  0⎥
# ⎢           dt         ⎥
# ⎢                      ⎥
# ⎢d                     ⎥
# ⎢──(θ(t))      0      0⎥
# ⎢dt                    ⎥
# ⎢                      ⎥
# ⎣   0          0      0⎦

Note the [0,1] is $-\dot{\theta}$, and we can plot the trajectory like and code below

rotation2

# ==========================================
# PART 2: Numerical Simulation
# ==========================================
# Setup time and motion profile (Variable angular velocity)
time_steps = np.linspace(0.0*np.pi, 1.0*np.pi, 50)
theta_vals = 0.2 * time_steps**2   # Angle theta(t)
omega_vals = 0.4 * time_steps      # Angular velocity omega(t)

# Fixed point in Body Frame (e.g., robot end-effector at rest)
pA = np.array([1.0, 0, 0])

# Lists to store history for plotting
pB_list = []      # Position trajectory
v_from_Rdot = []  # Velocity from R_dot * pA
v_from_Cross = [] # Velocity from omega x pB

for i, th in enumerate(theta_vals):
    om = omega_vals[i]
    
    # 1. Numerical Rotation Matrix
    R_num = np.array([
        [np.cos(th), -np.sin(th), 0],
        [np.sin(th),  np.cos(th), 0],
        [0,           0,          1]
    ])
    
    # 2. Numerical Derivative of R (R_dot)
    # d(cos)/dt = -sin * theta_dot
    R_dot_num = np.array([
        [-np.sin(th)*om, -np.cos(th)*om, 0],
        [ np.cos(th)*om, -np.sin(th)*om, 0],
        [ 0,             0,              0]
    ])
    
    # 3. Calculate Positions and Velocities
    pB = R_num @ pA
    
    # Method A: Matrix Derivative
    v1 = R_dot_num @ pA
    
    # Method B: Cross Product
    omega_vec = np.array([0, 0, om])
    v2 = np.cross(omega_vec, pB)
    
    # Store results
    pB_list.append(pB)
    v_from_Rdot.append(v1)
    v_from_Cross.append(v2)

# Convert lists to arrays for easier slicing
pB_arr = np.array(pB_list)
v_Rdot_arr = np.array(v_from_Rdot)
v_Cross_arr = np.array(v_from_Cross)

# ==========================================
# PART 3: Plotting Code
# ==========================================
plt.figure(figsize=(6, 5))

# Plot the path of the point
plt.plot(pB_arr[:, 0], pB_arr[:, 1], 'k--', alpha=0.6, label='Trajectory of pB')

# Plot velocity vectors at specific intervals (every 8th step)
indices = np.arange(0, len(time_steps), 6)
for idx in indices:
    # Origin of arrow
    x, y = pB_arr[idx, 0], pB_arr[idx, 1]
    # Velocity components (scaled by 0.5 for visual clarity)
    dx, dy = v_Rdot_arr[idx, 0] * 0.5, v_Rdot_arr[idx, 1] * 0.5
    
    plt.arrow(x, y, dx, dy, head_width=0.05, color='r', length_includes_head=True)

# Add dummy entry for legend to represent the arrows
plt.plot([], [], 'r-', label='Velocity Vector (v)')

# Plot origin
plt.scatter([0], [0], color='black', label='Origin (Joint)')
plt.axis('equal')
plt.title('Planar Robot Motion')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(True, linestyle=':', alpha=0.6)

plt.show()