Degrees Of Freedom
A completely unconstrained rigid body in 3D space has 6 Degrees of Freedom (DOF): three translational (moving along X, Y, Z axes) and three rotational (pitch, yaw, roll around the axes).
Rigid Body DOF:
1# A rigid body in 3D has 6 Degrees of Freedom2# 3 Translation (X, Y, Z) and 3 Rotation (Roll, Pitch, Yaw)34class RigidBody:5 def __init__(self):6 self.position = [0.0, 0.0, 0.0] # X, Y, Z7 self.rotation = [0.0, 0.0, 0.0] # Rx, Ry, Rz89 def transform_matrix(self):10 # Standard 4x4 homogenous translation matrix using position coordinates11 tx, ty, tz = self.position12 return [13 [1.0, 0.0, 0.0, tx],14 [0.0, 1.0, 0.0, ty],15 [0.0, 0.0, 1.0, tz],16 [0.0, 0.0, 0.0, 1.0]17 ]
Applying constraints reduces the degrees of freedom. A prismatic slider joint restricts all rotation and two axes of translation, leaving only 1 DOF (movement along a single line).
Prismatic Joint:
1# Prismatic (Translational) Joint2# Constrains 5 DOFs, leaving only 1 translational DOF.34class PrismaticJoint:5 def __init__(self, axis=[1, 0, 0]):6 self.axis = axis7 self.translation = 0.0 # The single degree of freedom89 def get_position(self):10 return [self.translation * a for a in self.axis]
A revolute (hinge) joint constrains all translation and two axes of rotation, leaving only 1 rotational DOF. This forms the basis of most robotic arms.
Revolute Joint:
1# Revolute (Rotational) Joint2# Constrains 5 DOFs, leaving 1 rotational DOF.34class RevoluteJoint:5 def __init__(self, axis=[0, 1, 0]):6 self.axis = axis7 self.angle = 0.0 # The single rotational degree of freedom89 def get_rotation_matrix(self):10 # Returns a rotation matrix around the Y axis11 # by self.angle radians.12 import math13 c = math.cos(self.angle)14 s = math.sin(self.angle)15 return [16 [c, 0, s],17 [0, 1, 0],18 [-s, 0, c]19 ]
A spherical joint (like a shoulder or hip) has 3 rotational DOFs. It constrains translation completely but allows free rotation in any direction.
Spherical Joint:
1# Spherical Joint (Ball and Socket)2# Constrains 3 translational DOFs, leaving 3 rotational DOFs.34class SphericalJoint:5 def __init__(self):6 self.angles = [0.0, 0.0, 0.0] # Pitch, Yaw, Roll78 def get_rotation_matrix(self):9 # Applies Euler rotation sequence (Z-Y-X) using self.angles10 import math11 rx, ry, rz = self.angles12 cx, sx = math.cos(rx), math.sin(rx)13 cy, sy = math.cos(ry), math.sin(ry)14 cz, sz = math.cos(rz), math.sin(rz)15 return [16 [cy*cz, -cy*sz, sy],17 [cx*sz + sx*sy*cz, cx*cz - sx*sy*sz, -sx*cy],18 [sx*sz - cx*sy*cz, sx*cz + cx*sy*sz, cx*cy]19 ]
By linking multiple joints sequentially, we create a kinematic chain. The total DOF of the chain is the sum of the DOFs of all individual joints (assuming no closed loops).
Serial Chain:
1# Kinematic Chain2# Connecting multiple DOFs sequentially creates a robot arm.34class KinematicChain:5 def __init__(self):6 self.joints = []78 def add_joint(self, joint):9 self.joints.append(joint)1011 def total_dof(self):12 return sum(j.dof for j in self.joints)
As joints rotate, the coordinate space of all subsequent links is transformed. We compute the final position by accumulating (multiplying) the transformation matrices from the base to the end effector.
Matrix Multiplication:
1# Transform Accumulation2# Calculating the end effector pose by multiplying matrices.34def calculate_fk(chain_matrices):5 T = IdentityMatrix()6 for matrix in chain_matrices:7 T = T * matrix # Matrix multiplication8 return T910# The position of the final node is non-linear w.r.t the joint angles11# due to trigonometric functions in the rotation matrices.
In real robotics, DOFs are subject to limits. A joint cannot rotate freely through its own base structure. Clamping algorithms ensure the theoretical kinematics respect physical boundaries.
Joint Limits:
1# Clamping Joint Limits2# Physical joints cannot rotate infinitely due to collisions and wires.34def clamp(val, min_val, max_val):5 return max(min_val, min(val, max_val))67class LimitedJoint:8 def __init__(self, limit_min=-90, limit_max=90):9 self.min = limit_min10 self.max = limit_max11 self._angle = 01213 def set_angle(self, target):14 # Enforce physical constraints15 self._angle = clamp(target, self.min, self.max)