Chapter 4: Serial-Chain Kinematics Structure
Lesson 4: Kinematic Constraints and DOF Counting (Grübler/Kutzbach)
This lesson develops a rigorous notion of mobility (degrees of freedom) for rigid-body mechanisms, starting from configuration-space and constraint equations and leading to the classical Grübler/Kutzbach formulas for planar and spatial mechanisms. We connect these formulas to the rank of the constraint Jacobian and show how to implement systematic DOF counting in Python, C++, Java, MATLAB/Simulink, and Wolfram Mathematica.
1. Kinematic Constraints and Mobility – Conceptual Overview
Consider a mechanical system modeled as a set of rigid links connected by ideal joints. We describe its posture by a vector of generalized coordinates \( q \in \mathbb{R}^n \). Kinematic constraints are algebraic relations between these coordinates (and possibly time) that must always be satisfied, such as loop-closure equations in a four-bar mechanism.
The configuration space of the mechanism is the set
\[ \mathcal{C} = \{\, q \in \mathbb{R}^n \mid \boldsymbol{\phi}(q,t) = \mathbf{0} \,\}, \]
where \( \boldsymbol{\phi}(q,t) \in \mathbb{R}^m \) collects all holonomic (position-level) constraint equations. Intuitively, each independent scalar constraint removes one degree of freedom (DOF). Under regularity conditions (independent constraints), the number of DOFs equals the dimension of the configuration space:
\[ \text{DOF} = \dim(\mathcal{C}). \]
For robot manipulators and mechanisms, mobility answers questions such as: How many independent actuator inputs are required to arbitrarily move the system? or Is the mechanism overconstrained or underconstrained?
flowchart TD
A["Describe mechanism (links, joints, motion type)"]
--> B["Choose model dimension lambda: 3 (planar) or 6 (spatial)"]
B --> C["Count links N (include ground as one link)"]
C --> D["For each joint j, determine joint DOF f_j"]
D --> E["Apply mobility formula: M = lambda*(N-1-J) + sum f_j"]
E --> F["Check consistency: constraints independent? special geometry?"]
F --> G["If needed, refine using constraint Jacobian rank"]
In the rest of the lesson we formalize these steps, derive the Grübler/Kutzbach formula mathematically, and show how to compute the DOF from the constraint Jacobian.
2. Configuration Space, Constraints, and the Constraint Jacobian
Let \( q = (q_1,\dots,q_n)^\top \) denote a set of generalized coordinates for our mechanism. Suppose we have \( m \) holonomic constraints encoded by \( \boldsymbol{\phi}(q,t) = \mathbf{0} \) with components \( \phi_k(q,t) = 0 \), \(k=1,\dots,m\).
The constraint Jacobian is the matrix
\[ \mathbf{J}_\phi(q,t) = \frac{\partial \boldsymbol{\phi}}{\partial q}(q,t) \in \mathbb{R}^{m \times n}, \quad \big(\mathbf{J}_\phi\big)_{kj} = \frac{\partial \phi_k}{\partial q_j}(q,t). \]
When the constraints are independent at a configuration \(q\), the rows of \( \mathbf{J}_\phi(q,t) \) are linearly independent and \( \operatorname{rank}(\mathbf{J}_\phi(q,t)) = r \le m \). The implicit function theorem (from multivariable calculus) implies that, locally, the constraint manifold can be parametrized by \( n-r \) free variables.
Therefore, the local dimension of the configuration space and the number of DOFs satisfy
\[ \text{DOF}(q) = \dim(\mathcal{C} \text{ near } q) = n - \operatorname{rank}(\mathbf{J}_\phi(q,t)). \]
If all constraints are independent everywhere (no singularities) and \( r = m \), this simplifies globally to
\[ \text{DOF} = n - m. \]
This rank-based formula is fundamental and works for both open-chain and closed-chain mechanisms. The classical Grübler/Kutzbach formula can be seen as a combinatorial way of performing the same counting for rigid-body mechanisms, using link and joint counts rather than explicit constraint equations.
3. Derivation of the Grübler/Kutzbach Mobility Formula
Consider a mechanism composed of \( N \) rigid bodies (links), including the ground. Each unconstrained rigid body in 3D space has \( \lambda = 6 \) DOFs (3 translational + 3 rotational), while in the planar case it has \( \lambda = 3 \) DOFs (2 translational + 1 rotational). In a suitable generalized coordinate description, we can idealize the system as
\[ n_{\text{free}} = \lambda (N - 1) \]
DOFs for the \( N-1 \) moving bodies after we fix the ground body.
Suppose the mechanism has \( J \) joints. Each joint connects two bodies and restricts their relative motion. Let \( f_j \) be the relative DOFs permitted by joint \(j\), and let \( c_j \) be the number of independent scalar constraints that joint imposes between the pair of bodies. For rigid bodies in a \( \lambda \)-DOF world,
\[ c_j = \lambda - f_j. \]
The total number of independent joint constraints is then \( \sum_{j=1}^J c_j \), giving
\[ \text{DOF} = \lambda (N - 1) - \sum_{j=1}^J c_j. \]
Substituting \( c_j = \lambda - f_j \) and simplifying,
\[ \begin{aligned} \text{DOF} &= \lambda (N - 1) - \sum_{j=1}^J (\lambda - f_j) \\ &= \lambda (N - 1) - \lambda J + \sum_{j=1}^J f_j \\ &= \lambda (N - 1 - J) + \sum_{j=1}^J f_j. \end{aligned} \]
This is the Grübler/Kutzbach mobility formula:
\[ M = \lambda (N - 1 - J) + \sum_{j=1}^J f_j, \]
where \(M\) denotes the mechanism mobility (number of DOFs).
For the two most common cases:
-
Spatial mechanisms (\( \lambda = 6 \)):
\[ M = 6 (N - 1 - J) + \sum_{j=1}^J f_j. \]
-
Planar mechanisms (\( \lambda = 3 \)):
\[ M = 3 (N - 1 - J) + \sum_{j=1}^J f_j. \]
The formula assumes:
- All joints are ideal and can be modeled as lower pairs (revolute, prismatic, etc.).
- All imposed constraints are independent (no hidden geometric dependencies).
- The ground is a single link.
When these assumptions fail, the formula may over- or under-estimate mobility; then the Jacobian rank method of Section 5 must be used.
4. Serial Chains, Closed Chains, and Worked Examples
4.1 Serial open-chain manipulators
For a purely serial open chain with \( J \) joints and no loops, the number of links is \( N = J + 1 \) (including the base). Substituting into the Grübler/Kutzbach formula gives
\[ M = \lambda \big((J+1) - 1 - J\big) + \sum_{j=1}^J f_j = \sum_{j=1}^J f_j. \]
Thus, for an ideal open-chain manipulator, the mobility equals the sum of the joint DOFs, as expected.
Example 1 (planar 2R arm):
- Planar mechanism: \( \lambda = 3 \).
- Links: base + 2 moving links, so \( N = 3 \).
- Joints: \( J = 2 \) planar revolute joints, each \( f_j = 1 \).
\[ M = 3 (3 - 1 - 2) + (1 + 1) = 3 \cdot 0 + 2 = 2. \]
This matches the intuitive result: two joint angles provide a 2D configuration.
4.2 Planar four-bar linkage
Consider a classical planar four-bar mechanism with four links (including ground) connected by four revolute joints forming a closed loop.
- Planar: \( \lambda = 3 \).
- Links: \( N = 4 \) (ground + three moving bars).
- Joints: \( J = 4 \) planar revolute joints, each \( f_j = 1 \).
\[ M = 3 (4 - 1 - 4) + (1 + 1 + 1 + 1) = 3 (-1) + 4 = 1. \]
The mechanism has one DOF, consistent with the fact that choosing a single input joint angle determines the entire configuration (subject to branch and assembly mode ambiguities).
4.3 Spatial 6R industrial manipulator
A standard 6R industrial arm has 6 revolute joints and one base link.
- Spatial: \( \lambda = 6 \).
- Links: base + 6 links, \( N = 7 \).
- Joints: \( J = 6 \), each \( f_j = 1 \).
\[ M = 6 (7 - 1 - 6) + 6 = 6 \cdot 0 + 6 = 6. \]
The arm can realize arbitrary end-effector poses in \( \mathrm{SE}(3) \) (subject to workspace limits), so 6 DOFs are necessary and sufficient.
4.4 Overconstrained and special mechanisms (cautionary note)
Certain mechanisms (e.g., some spatial linkages with special geometric conditions) are overconstrained: they contain more constraints than minimally required but still move due to geometry-induced dependencies. In such cases the simple application of the Grübler/Kutzbach formula may predict \( M = 0 \) even though the mechanism has a finite mobility. For these special mechanisms, one must explicitly construct the constraint equations and use the Jacobian rank approach of Section 5.
5. Mobility as \( n - \operatorname{rank}(\mathbf{J}_\phi) \): Rank-Based DOF Counting
Suppose we model the mechanism by generalized coordinates \( q \in \mathbb{R}^n \) and holonomic constraints \( \boldsymbol{\phi}(q) = \mathbf{0} \). Assume that near some configuration \( q^\ast \) the constraint Jacobian \( \mathbf{J}_\phi(q^\ast) \) has constant rank \( r = \operatorname{rank}(\mathbf{J}_\phi(q^\ast)) \).
Then, locally, we can reorder coordinates such that \( (q_1,\dots,q_n) \) is partitioned into \( (q_a, q_b) \), with \( q_a \in \mathbb{R}^{n-r} \) and \( q_b \in \mathbb{R}^{r} \), and the constraint equations can be solved for \( q_b = \psi(q_a) \). Thus the configuration manifold near \(q^\ast\) is
\[ \mathcal{C} \cap U = \big\{\, (q_a, \psi(q_a)) \mid q_a \in V \subset \mathbb{R}^{n-r} \,\big\}, \]
where \(U\) is a neighborhood of \(q^\ast\) in \(\mathbb{R}^n\) and \(V\) is a neighborhood of the free coordinates. Hence
\[ \dim(\mathcal{C} \cap U) = n - r = n - \operatorname{rank}(\mathbf{J}_\phi(q^\ast)). \]
This provides a robust way to check mobility numerically: construct the constraint equations, compute their Jacobian, and evaluate its rank at representative configurations.
flowchart TD
S["Choose generalized coordinates q"]
--> P["Write holonomic constraints phi(q) = 0"]
P --> J["Form constraint Jacobian J_phi(q) = dphi/dq"]
J --> R["Compute rank r = rank(J_phi)"]
R --> M["Compute DOF = n - r"]
M --> V["Verify at multiple configurations to detect singularities"]
In later dynamics chapters, the same Jacobian \( \mathbf{J}_\phi(q) \) will also appear in the formulation of constrained equations of motion (via Lagrange multipliers), so learning this rank-based approach now prepares you for constrained dynamics.
6. Programming Lab — Implementing Mobility Computation
In this section we show small, focused implementations of:
- Grübler/Kutzbach mobility computation given \( \lambda, N, J, f_j \).
- Rank-based DOF computation given a constraint Jacobian.
We illustrate this in Python (with numpy/sympy
and optionally roboticstoolbox), C++ (with
Eigen), Java (with a linear algebra library such as EJML),
MATLAB/Simulink (with Robotics System Toolbox / Simscape Multibody), and
Wolfram Mathematica.
6.1 Python implementation (with numpy and robotics
toolboxes)
import numpy as np
class Joint:
def __init__(self, dof: int, name: str = ""):
self.dof = dof
self.name = name
class Mechanism:
def __init__(self, n_links: int, joints, lambda_dim: int = 6):
"""
n_links: total links including ground
joints: iterable of Joint objects
lambda_dim: 6 for spatial, 3 for planar
"""
self.n_links = n_links
self.joints = list(joints)
self.lambda_dim = lambda_dim
@property
def n_joints(self) -> int:
return len(self.joints)
def mobility_gruebler(self) -> int:
lam = self.lambda_dim
N = self.n_links
J = self.n_joints
f_sum = sum(j.dof for j in self.joints)
return lam * (N - 1 - J) + f_sum
@staticmethod
def dof_from_constraints(J_phi: np.ndarray, tol: float = 1e-9) -> int:
"""
J_phi: m x n constraint Jacobian
DOF = n - rank(J_phi)
"""
rank = np.linalg.matrix_rank(J_phi, tol)
n = J_phi.shape[1]
return n - rank
# Example: planar 4-bar linkage
joints = [Joint(1, name=f"R{i}") for i in range(4)]
fourbar = Mechanism(n_links=4, joints=joints, lambda_dim=3)
print("4-bar mobility (Gruebler):", fourbar.mobility_gruebler())
# Example: constraint Jacobian for a simple loop q1 + q2 + q3 = constant
J_phi = np.array([[1.0, 1.0, 1.0]]) # 1 x 3, rank = 1
dof = Mechanism.dof_from_constraints(J_phi)
print("DOF from constraints:", dof)
In a richer Python robotics stack, you would embed this logic inside a
roboticstoolbox or pytransform3d model, using
symbolic expressions (via sympy) to construct constraint
Jacobians \( \mathbf{J}_\phi(q) \) for closed chains.
6.2 C++ implementation (with Eigen)
#include <iostream>
#include <vector>
#include <Eigen/Dense>
struct Joint {
int dof;
std::string name;
Joint(int f, const std::string& n) : dof(f), name(n) {}
};
class Mechanism {
public:
Mechanism(int n_links, int lambda_dim)
: N(n_links), lambda_dim(lambda_dim) {}
void addJoint(const Joint& j) {
joints.push_back(j);
}
int mobilityGruebler() const {
int J = static_cast<int>(joints.size());
int f_sum = 0;
for (const auto& j : joints) {
f_sum += j.dof;
}
return lambda_dim * (N - 1 - J) + f_sum;
}
static int dofFromConstraints(const Eigen::MatrixXd& Jphi, double tol = 1e-9) {
Eigen::FullPivLU<Eigen::MatrixXd> lu(Jphi);
int rank = lu.rank();
int n = static_cast<int>(Jphi.cols());
return n - rank;
}
private:
int N; // number of links (including ground)
int lambda_dim; // 6 for spatial, 3 for planar
std::vector<Joint> joints;
};
int main() {
// Planar 4-bar
Mechanism fourbar(4, 3);
for (int i = 0; i < 4; ++i) {
fourbar.addJoint(Joint(1, "R"));
}
std::cout << "4-bar mobility (Gruebler): "
<< fourbar.mobilityGruebler() << std::endl;
// Rank-based DOF
Eigen::MatrixXd Jphi(1, 3);
Jphi << 1.0, 1.0, 1.0;
int dof = Mechanism::dofFromConstraints(Jphi);
std::cout << "DOF from constraints: " << dof << std::endl;
return 0;
}
In large robotics projects, similar DOF counting utilities appear inside
libraries such as KDL (Kinematics and Dynamics Library), RBDL, and the
modeling layer of ROS-based systems, often using Eigen for
linear algebra.
6.3 Java implementation (with a linear algebra library, e.g., EJML)
import java.util.ArrayList;
import java.util.List;
// Minimal linear algebra can be provided by a library such as EJML.
// Here we focus on the combinatorial Gruebler/Kutzbach formula.
class Joint {
int dof;
String name;
Joint(int dof, String name) {
this.dof = dof;
this.name = name;
}
}
class Mechanism {
private int nLinks;
private int lambdaDim;
private List<Joint> joints = new ArrayList<>();
Mechanism(int nLinks, int lambdaDim) {
this.nLinks = nLinks;
this.lambdaDim = lambdaDim;
}
void addJoint(Joint j) {
joints.add(j);
}
int mobilityGruebler() {
int J = joints.size();
int fSum = 0;
for (Joint j : joints) {
fSum += j.dof;
}
return lambdaDim * (nLinks - 1 - J) + fSum;
}
}
public class MobilityDemo {
public static void main(String[] args) {
Mechanism planarArm = new Mechanism(3, 3); // planar 2R arm
planarArm.addJoint(new Joint(1, "R1"));
planarArm.addJoint(new Joint(1, "R2"));
System.out.println("Planar 2R mobility: " + planarArm.mobilityGruebler());
}
}
For full Jacobian-rank DOF analysis in Java, you would connect this combinatorial logic to a matrix library (EJML, Apache Commons Math) and a robotics modeling layer that can generate constraint equations for closed chains.
6.4 MATLAB / Simulink implementation
function M = mobilityGruebler(lambda_dim, N, joint_dofs)
%MOBILITYGRUEBLER Compute mechanism mobility using the Gruebler/Kutzbach formula.
% lambda_dim : 6 for spatial, 3 for planar
% N : number of links including ground
% joint_dofs : vector of joint DOFs f_j
J = numel(joint_dofs);
M = lambda_dim * (N - 1 - J) + sum(joint_dofs);
end
% Example: planar 4-bar
M4 = mobilityGruebler(3, 4, ones(1,4))
% Rank-based DOF from constraint Jacobian
function dof = dofFromConstraints(Jphi)
%Jphi: m x n constraint Jacobian
r = rank(Jphi);
n = size(Jphi, 2);
dof = n - r;
end
% Example constraint Jacobian for q1 + q2 + q3 = const
Jphi = [1 1 1];
dofJ = dofFromConstraints(Jphi)
In MATLAB, you often embed this logic within a
rigidBodyTree model (Robotics System Toolbox) or a
simscape.multibody model where the tool automatically
maintains constraint equations. Simulink diagrams then implement joints
and bodies, while scripts like the above provide analytical checks on
mechanism mobility.
6.5 Wolfram Mathematica implementation
(* Gruebler/Kutzbach mobility *)
mobility[lambda_, nLinks_, f_List] :=
lambda (nLinks - 1 - Length[f]) + Total[f];
(* Example: spatial 6R arm *)
mobility[6, 7, ConstantArray[1, 6]]
(* Rank-based DOF from holonomic constraints phi(q) == 0 *)
dofFromConstraints[phi_List, q_List] :=
Module[{Jphi, r, n},
Jphi = D[phi, {q}]; (* Jacobian matrix dphi/dq *)
r = MatrixRank[Jphi];
n = Length[q];
n - r
]
(* Example: one scalar loop constraint q1 + q2 + q3 == c *)
phi = {q1 + q2 + q3 - c};
q = {q1, q2, q3};
dofFromConstraints[phi, q]
Mathematica is particularly convenient for symbolic derivation of constraint Jacobians and can be used to verify DOF counts derived combinatorially for complex robot mechanisms.
7. Problems and Solutions
Problem 1 (Planar mechanisms: basic counting). For each planar mechanism below, compute the mobility \( M \) using the Grübler/Kutzbach formula.
- A planar 3R serial arm (3 revolute joints in a chain, fixed base).
- A planar 5-bar linkage: ground plus four moving links, five planar revolute joints forming a single closed loop (two joints at the ground, three between the moving links).
Solution.
(a) Planar 3R serial arm.
- \( \lambda = 3 \) (planar).
- Links: base + 3 links \( \Rightarrow N = 4 \).
- Joints: \( J = 3 \), each revolute \( f_j = 1 \).
\[ M = 3 (4 - 1 - 3) + (1 + 1 + 1) = 3 \cdot 0 + 3 = 3. \]
The arm has 3 DOFs, consistent with three independent joint angles.
(b) Planar 5-bar linkage.
- Links: ground + 4 moving links \( \Rightarrow N = 5 \).
- Joints: \( J = 5 \) planar revolute joints, all \( f_j = 1 \).
\[ M = 3 (5 - 1 - 5) + 5 = 3 (-1) + 5 = 2. \]
The 5-bar linkage is a 2-DOF mechanism; typically two joints are actuated while the others move passively to satisfy the loop constraints.
Problem 2 (Spatial 6R with an extra passive joint). Consider a spatial 6R industrial arm with base link and 6 revolute joints (as in Section 4.3), but an extra passive revolute joint is added at the end-effector so that the last link carries a small rotating tool. Assume all joints are 1-DOF revolute joints. Compute the mobility \( M \).
Solution.
We have:
- Spatial mechanism: \( \lambda = 6 \).
- Links: base + 7 links (6 links of the original arm plus one extra tool link), so \( N = 8 \).
- Joints: original 6 + 1 extra \( \Rightarrow J = 7 \), all with \( f_j = 1 \).
\[ M = 6 (8 - 1 - 7) + 7 = 6 \cdot 0 + 7 = 7. \]
The mechanism has 7 DOFs: 6 that position and orient the wrist frame plus 1 internal rotation for the tool around its axis. From a control standpoint, we typically treat this as a 6-DOF arm with one additional tool DOF.
Problem 3 (Rank-based DOF: simple loop constraint). A planar mechanism has three generalized coordinates \( q = (q_1, q_2, q_3) \) and a holonomic loop-closure constraint \( \phi(q) = q_1 + q_2 + q_3 - \alpha = 0 \), where \( \alpha \) is constant. Use the Jacobian rank approach to compute the DOF.
Solution.
The constraint Jacobian is
\[ \mathbf{J}_\phi(q) = \frac{\partial \phi}{\partial q} = \begin{bmatrix} 1 & 1 & 1 \end{bmatrix}. \]
The rank is \( \operatorname{rank}(\mathbf{J}_\phi) = 1 \), and the ambient dimension is \( n = 3 \). Therefore,
\[ \text{DOF} = n - \operatorname{rank}(\mathbf{J}_\phi) = 3 - 1 = 2. \]
Indeed, once the sum \( q_1 + q_2 + q_3 \) is fixed, any two of the coordinates can be chosen independently and the third is determined.
Problem 4 (Serial vs. closed-chain: comparison). Consider two mechanisms:
- A planar serial RRR arm (3 revolute joints in a chain).
- A planar closed-chain mechanism formed by connecting the end of an RR two-link chain back to the base via a third link and two revolute joints (overall, 4 moving links plus ground, and 5 revolute joints).
Compute the mobility of both and explain the difference physically.
Solution.
(a) Serial RRR arm.
- \( \lambda = 3 \), \( N = 4 \) (base + 3 links), \( J = 3 \), \( f_j = 1 \).
\[ M = 3 (4 - 1 - 3) + 3 = 3. \]
The arm has 3 independent joint angles.
(b) Closed-chain with 5 revolute joints.
- \( \lambda = 3 \).
- Links: ground + 4 moving links \( \Rightarrow N = 5 \).
- Joints: 5 planar revolute joints \( \Rightarrow J = 5, f_j = 1 \).
\[ M = 3 (5 - 1 - 5) + 5 = 3 (-1) + 5 = 2. \]
The closed chain has only 2 DOFs: the loop-closure introduces one constraint that reduces mobility compared to the open 3R chain. Physically, the loop creates a dependent relation between joint angles; only two can be chosen independently.
Problem 5 (Detecting an overconstrained prediction). A spatial mechanism is modeled with \( \lambda = 6 \), \( N = 6 \) links (including ground), and \( J = 7 \) 1-DOF joints. The Grübler/Kutzbach formula predicts \( M = 6 (6 - 1 - 7) + 7 = -5 \). Explain why this negative mobility is a red flag, and what you should do instead in such cases.
Solution.
A negative mobility value cannot represent a physical mechanism: DOFs are nonnegative. The calculation indicates that, under the modeling assumptions, the mechanism is overconstrained by at least 5 constraints. In reality, one of the following must be true:
- Some constraints are redundant (not independent) because of special geometry.
- The assumed joint models are not accurate (e.g., joints share axes or surfaces in a special way).
- The mechanism is actually rigid and does not move (\( M = 0 \)), but is modeled with too many joints.
In such cases, instead of relying on the Grübler/Kutzbach formula alone, you must:
- Write explicit constraint equations for the mechanism geometry.
- Compute the constraint Jacobian \( \mathbf{J}_\phi(q) \) at representative configurations.
- Use \( \text{DOF} = n - \operatorname{rank}(\mathbf{J}_\phi(q)) \) to determine the true mobility.
This rank-based analysis reveals whether the mechanism is truly rigid (\( M = 0 \)) or has some finite mobility despite being combinatorially overconstrained.
8. Summary
In this lesson we introduced kinematic constraints and the notion of mobility for rigid-body mechanisms. Starting from the configuration space \( \mathcal{C} = \{ q \mid \boldsymbol{\phi}(q,t) = \mathbf{0} \} \), we saw that the dimension of this manifold is \( n - \operatorname{rank}(\mathbf{J}_\phi) \), yielding a rank-based DOF formula.
We then derived the Grübler/Kutzbach mobility formula \( M = \lambda (N - 1 - J) + \sum f_j \) for planar and spatial mechanisms, and applied it to serial chains (where it reduces to \( M = \sum f_j \)), four-bar linkages, 5-bar linkages, and spatial manipulators. We emphasized the limitations of this combinatorial formula and the need for Jacobian rank analysis in overconstrained or special geometries.
Finally, we implemented these ideas in Python, C++, Java, MATLAB/Simulink, and Mathematica, giving practical tools to analyze mobility and constraints in software. In later chapters on dynamics and constrained systems, the same constraint Jacobian will reappear in the equations of motion, making this kinematic viewpoint critical for the rest of the course.
9. References
- Grübler, M. (1883). Allgemeine Eigenschaften der Zwangsgetriebe. Zeitschrift des Österreichischen Ingenieur- und Architekten-Vereins, 35, 167–173.
- Kutzbach, K. (1929). Mechanische Leitungsverzweigung: Grundlagen für eine Getriebelehre des Maschineningenieurs. Maschinenbau, 8, 710–716.
- Hartenberg, R. S., & Denavit, J. (1955). A kinematic notation for lower-pair mechanisms based on matrices. ASME Journal of Applied Mechanics, 22(2), 215–221.
- Hunt, K. H. (1978). Kinematic Geometry of Mechanisms. Oxford University Press.
- Erdman, A. G., Sandor, G. N., & Kota, S. (2001). Mechanism Design: Analysis and Synthesis, Vol. 1. Prentice Hall.
- Tsai, L.-W. (1999). Robot Analysis: The Mechanics of Serial and Parallel Manipulators. John Wiley & Sons.
- Angeles, J. (1997). Fundamentals of Robotic Mechanical Systems: Theory, Methods, and Algorithms. Springer.
- McCarthy, J. M. (2000). Geometric Design of Linkages. Springer.
- Waldron, K. J., & Kinzel, G. L. (1999). Kinematics, Dynamics, and Design of Machinery. John Wiley & Sons.
- Angeles, J., & Lopez-Cajún, C. (1992). Screw Theory and Its Application to Spatial Kinematics. Springer.