Chapter 1: Mobile Robot Modeling Scope and Assumptions

Lesson 1: What Makes Mobility Different from Manipulation

This lesson establishes the modeling scope of autonomous mobile robots by contrasting mobility with manipulation at the level of configuration spaces, actuation structure, and physical constraints. We formalize why mobile bases are typically underactuated and subject to rolling-contact constraints, and we prove (via an integrability test) that the canonical “no lateral slip” constraint is non-integrable, which is the mathematical root of many mobile-robot-specific phenomena (e.g., limited instantaneous motion, yet large reachable sets over time).

1. Conceptual Overview

A serial manipulator is usually modeled as a holonomic mechanical system where generalized coordinates are joint angles \( \mathbf{q} \in \mathbb{R}^n \): and the control inputs are joint torques or joint rates. A mobile robot, by contrast, is typically a rigid body moving in the plane with configuration \( \mathbf{x} = (x, y, \theta) \in SE(2) \) : but with fewer independent control inputs than configuration dimension because of rolling-contact constraints and actuator placement (e.g., wheels).

The key modeling difference can be summarized as:

  • Manipulation: direct actuation in generalized coordinates; constraints are usually geometric (joint limits) and holonomic; instantaneous motions span the configuration tangent space locally.
  • Mobility: actuation often produces velocities in the robot body frame, while wheel–ground contact imposes Pfaffian velocity constraints; the admissible instantaneous velocities form a lower-dimensional distribution in the tangent space (a mobile robot cannot “step sideways” without special wheels).
flowchart TD
  A["Modeling Goal"] --> B["Choose configuration variables"]
  B --> C["Manipulation: q in R^n (joint space)"]
  B --> D["Mobility: (x,y,theta) in SE(2) (base pose)"]
  C --> E["Inputs: joint torques/rates → qdot"]
  D --> F["Inputs: body-frame v,w \n(or wheel rates)"]
  E --> G["Constraints: joint limits \n(mostly geometric)"]
  F --> H["Constraints: rolling contact \n(no lateral slip)"]
  G --> I["Instantaneous motion locally \nspans configuration"]
  H --> J["Instantaneous motion restricted; \nreachable set still large over time"]
        

2. Configuration, Degrees of Freedom, and Actuation Structure

For a rigid mobile base on a flat ground plane, the minimal configuration is \( \mathbf{x} = (x, y, \theta) \): where \( (x,y) \) is position and \( \theta \) is yaw. A common kinematic control model for many wheeled bases uses body-frame linear and angular velocities \( \mathbf{u} = (v, \omega) \): and the mapping

\[ \begin{bmatrix} \dot{x} \\ \dot{y} \\ \dot{\theta} \end{bmatrix} = \begin{bmatrix} \cos\theta & 0 \\ \sin\theta & 0 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} v \\ \omega \end{bmatrix}. \]

The actuation dimension is 2 (inputs \( v,\omega \)) while the configuration dimension is 3 (variables \( x,y,\theta \)). This mismatch reflects a structural difference from typical manipulators, where control inputs are naturally defined per joint coordinate.

For a planar 2R manipulator (two revolute joints), generalized coordinates are \( \mathbf{q} = (q_1, q_2): and (planar) end-effector position \( \mathbf{p} = (x_e, y_e) \): is

\[ \mathbf{p}(\mathbf{q}) = \begin{bmatrix} x_e \\ y_e \end{bmatrix} = \begin{bmatrix} \ell_1\cos q_1 + \ell_2\cos(q_1+q_2) \\ \ell_1\sin q_1 + \ell_2\sin(q_1+q_2) \end{bmatrix}. \]

Differentiating gives the standard Jacobian relationship \( \dot{\mathbf{p}} = \mathbf{J}(\mathbf{q})\dot{ \mathbf{q} } \):

\[ \begin{bmatrix} \dot{x}_e \\ \dot{y}_e \end{bmatrix} = \underbrace{ \begin{bmatrix} -\ell_1\sin q_1 - \ell_2\sin(q_1+q_2) & -\ell_2\sin(q_1+q_2) \\ \ell_1\cos q_1 + \ell_2\cos(q_1+q_2) & \ell_2\cos(q_1+q_2) \end{bmatrix}}_{\mathbf{J}(\mathbf{q})} \begin{bmatrix} \dot{q}_1 \\ \dot{q}_2 \end{bmatrix}. \]

In this manipulation example, the control inputs can be taken as \( \dot{q}_1, \dot{q}_2 \), which are directly compatible with the generalized coordinates. For mobility, the natural inputs are often body velocities (or wheel rates), and constraints appear at the velocity level.

3. Rolling Constraints as Pfaffian Constraints

A central modeling assumption for many wheeled robots is pure rolling (no lateral slip at the contact patch). For a body with heading \( \theta \): the lateral (sideways) velocity constraint can be written as:

\[ -\sin\theta \, \dot{x} + \cos\theta \, \dot{y} = 0. \]

Equivalently, in Pfaffian (1-form) form:

\[ \omega \;=\; -\sin\theta \, dx + \cos\theta \, dy, \quad \omega(\dot{\mathbf{x}})=0. \]

This is not a geometric “position constraint” such as \( h(x,y,\theta)=0 \); it restricts instantaneous velocities. The most important consequence is that the robot cannot realize arbitrary instantaneous planar velocity vectors, e.g. it cannot generate \( \dot{x}=0, \dot{y}\neq 0 \) at fixed \( \theta \) under this assumption.

4. Proof — The No-Slip Constraint is Non-Integrable (Nonholonomic)

We prove that the Pfaffian constraint \( \omega = -\sin\theta \, dx + \cos\theta \, dy \): is not integrable, hence it cannot be written (even locally) as \( dh = 0 \) for some scalar function \( h(x,y,\theta) \).

A necessary condition for integrability of a single Pfaffian constraint is \( d\omega \wedge \omega = 0 \): (a standard 1-form integrability test). Compute \( d\omega \). Since only \( \theta \) appears in the coefficients:

\[ d\omega = d(-\sin\theta)\wedge dx + d(\cos\theta)\wedge dy = (-\cos\theta \, d\theta)\wedge dx + (-\sin\theta \, d\theta)\wedge dy. \]

Now wedge with \( \omega \):

\[ \begin{aligned} d\omega \wedge \omega &= \left(-\cos\theta \, d\theta\wedge dx - \sin\theta \, d\theta\wedge dy\right) \wedge \left(-\sin\theta \, dx + \cos\theta \, dy\right) \\ &= \left(-\cos^2\theta\right)\, d\theta\wedge dx\wedge dy + \left(-\sin^2\theta\right)\, d\theta\wedge dx\wedge dy \\ &= -(\cos^2\theta+\sin^2\theta)\, d\theta\wedge dx\wedge dy = - d\theta\wedge dx\wedge dy \;\neq\; 0. \end{aligned} \]

Since \( d\omega \wedge \omega \neq 0 \), the constraint is non-integrable and therefore nonholonomic. This is the mathematical reason mobility differs from manipulation: the constraint restricts instantaneous motions but does not reduce the configuration space dimension in the same way a holonomic constraint would.

Practical interpretation: even though the robot cannot move sideways instantaneously, it can generate lateral displacement over time by composing admissible motions (e.g., “parallel parking”-type maneuvers).

5. Modeling Scope and Assumptions for This Course

To proceed lesson-by-lesson, we adopt a minimal but standard modeling scope for the early chapters:

  • Planar motion: base pose in \( SE(2) \), ignoring roll/pitch and vertical dynamics.
  • Rigid body base: the platform is a rigid body; compliance is neglected at first.
  • Rolling contact idealization: wheels enforce no-lateral-slip constraints unless stated otherwise.
  • Kinematic-first viewpoint: we begin with velocity-level models; dynamics/slip appear in later chapters.
  • Inputs: we often treat commanded body velocities \( (v,\omega) \) as “controls” in modeling, even though actuators are wheel torques/speeds; the mapping will be refined in later lessons.
flowchart TD
  S["Scope start"] --> P["Planar SE(2) pose (x,y,theta)"]
  P --> R["Rigid base assumption"]
  R --> C["Wheel-ground contact model"]
  C --> I["Ideal rolling: no lateral slip"]
  I --> K["Kinematic model: \nxdot = v cos(theta), ydot = v sin(theta), thetadot = w"]
  C --> N["Non-ideal effects deferred: \nslip, skid, compliance, terrain"]
  N --> D["Dynamics and interaction models \n(later chapters)"]
        

These assumptions are intentionally “first-order” and will be relaxed progressively. Importantly, they are sufficient to explain why planning, control, and estimation for mobile robots must respect velocity constraints that do not appear (in the same form) in classical manipulator modeling.

6. Implementation Mini-Lab — Mobility vs Manipulation in Code

The following code implements two minimal simulations: (i) a planar mobile base under \( (v,\omega) \) commands and (ii) a planar 2R manipulator under joint-rate commands. The output is CSV trajectories suitable for plotting or later reuse.

6.1 Python

File: Chapter1_Lesson1.py

"""Chapter1_Lesson1.py
Autonomous Mobile Robots (Control Engineering) — Chapter 1, Lesson 1
Lesson: What Makes Mobility Different from Manipulation

This script provides a minimal, self-contained numerical experiment that contrasts:
  (i) a planar mobile base (differential-drive kinematics) and
  (ii) a 2R planar manipulator (holonomic joint-space actuation).

It generates CSV files for both trajectories and (optionally) plots them.

Suggested robotics libraries to explore next (not required for this script):
  - roboticstoolbox-python (Peter Corke) for manipulator models and Jacobians
  - spatialmath-python for SE(2)/SE(3) utilities
  - ROS 2 (rclpy) for integration with real robots

Tested with: Python 3.10+
"""

from __future__ import annotations

import math
import csv
from dataclasses import dataclass
from typing import List, Tuple

import numpy as np

try:
    import matplotlib.pyplot as plt
    HAS_PLOT = True
except Exception:
    HAS_PLOT = False


@dataclass
class Pose2:
    x: float
    y: float
    theta: float  # yaw


def integrate_diff_drive(p0: Pose2, v: float, w: float, dt: float, steps: int) -> List[Pose2]:
    """Forward-Euler integration of the standard planar kinematic model:
        x_dot = v cos(theta), y_dot = v sin(theta), theta_dot = w
    """
    traj = [p0]
    p = Pose2(p0.x, p0.y, p0.theta)
    for _ in range(steps):
        p.x += dt * v * math.cos(p.theta)
        p.y += dt * v * math.sin(p.theta)
        p.theta += dt * w
        traj.append(Pose2(p.x, p.y, p.theta))
    return traj


def fk_2r(q1: float, q2: float, l1: float = 1.0, l2: float = 0.7) -> Tuple[float, float]:
    """Planar 2R forward kinematics (end-effector position)."""
    x = l1 * math.cos(q1) + l2 * math.cos(q1 + q2)
    y = l1 * math.sin(q1) + l2 * math.sin(q1 + q2)
    return x, y


def jacobian_2r(q1: float, q2: float, l1: float = 1.0, l2: float = 0.7) -> np.ndarray:
    """Planar 2R Jacobian for end-effector linear velocity: [x_dot; y_dot] = J(q) [q1_dot; q2_dot]."""
    s1 = math.sin(q1)
    c1 = math.cos(q1)
    s12 = math.sin(q1 + q2)
    c12 = math.cos(q1 + q2)

    j11 = -l1 * s1 - l2 * s12
    j12 = -l2 * s12
    j21 =  l1 * c1 + l2 * c12
    j22 =  l2 * c12
    return np.array([[j11, j12], [j21, j22]], dtype=float)


def simulate_2r(q10: float, q20: float, qdot1: float, qdot2: float, dt: float, steps: int) -> Tuple[np.ndarray, np.ndarray]:
    """Integrate joint angles and compute end-effector trajectory."""
    q1, q2 = q10, q20
    qs = np.zeros((steps + 1, 2), dtype=float)
    xs = np.zeros((steps + 1, 2), dtype=float)

    for k in range(steps + 1):
        qs[k, :] = [q1, q2]
        xs[k, :] = fk_2r(q1, q2)
        q1 += dt * qdot1
        q2 += dt * qdot2

    return qs, xs


def write_mobile_csv(path: str, traj: List[Pose2], dt: float) -> None:
    with open(path, "w", newline="") as f:
        w = csv.writer(f)
        w.writerow(["t", "x", "y", "theta"])
        for k, p in enumerate(traj):
            w.writerow([k * dt, p.x, p.y, p.theta])


def write_manip_csv(path: str, qs: np.ndarray, xs: np.ndarray, dt: float) -> None:
    with open(path, "w", newline="") as f:
        w = csv.writer(f)
        w.writerow(["t", "q1", "q2", "xe", "ye"])
        for k in range(qs.shape[0]):
            w.writerow([k * dt, qs[k, 0], qs[k, 1], xs[k, 0], xs[k, 1]])


def main() -> None:
    dt = 0.02
    T = 8.0
    steps = int(T / dt)

    # Mobile base inputs (body-frame): v (m/s), w (rad/s)
    v = 0.5
    w = 0.35
    mobile_traj = integrate_diff_drive(Pose2(0.0, 0.0, 0.0), v=v, w=w, dt=dt, steps=steps)
    write_mobile_csv("Chapter1_Lesson1_mobile.csv", mobile_traj, dt)

    # Manipulator joint-rate inputs: qdot (rad/s)
    qdot1, qdot2 = 0.25, -0.15
    qs, xs = simulate_2r(q10=0.2, q20=0.9, qdot1=qdot1, qdot2=qdot2, dt=dt, steps=steps)
    write_manip_csv("Chapter1_Lesson1_manipulator.csv", qs, xs, dt)

    # Demonstrate instantaneous vs integrable constraints:
    # - Mobile base cannot have arbitrary instantaneous (x_dot, y_dot) at fixed theta when lateral velocity is constrained.
    # - Manipulator can set any (q1_dot, q2_dot) instantaneously (actuation in joint space is holonomic).
    J = jacobian_2r(q1=qs[0, 0], q2=qs[0, 1])
    v_ee = J @ np.array([qdot1, qdot2])
    print("2R end-effector velocity at t=0:", v_ee)

    if HAS_PLOT:
        mx = [p.x for p in mobile_traj]
        my = [p.y for p in mobile_traj]

        plt.figure()
        plt.plot(mx, my)
        plt.axis("equal")
        plt.title("Mobile base trajectory (x-y)")
        plt.xlabel("x [m]")
        plt.ylabel("y [m]")

        plt.figure()
        plt.plot(xs[:, 0], xs[:, 1])
        plt.axis("equal")
        plt.title("2R manipulator end-effector trajectory (x-y)")
        plt.xlabel("x_e [m]")
        plt.ylabel("y_e [m]")

        plt.show()

    print("Wrote: Chapter1_Lesson1_mobile.csv and Chapter1_Lesson1_manipulator.csv")


if __name__ == "__main__":
    main()

6.2 C++

File: Chapter1_Lesson1.cpp

// Chapter1_Lesson1.cpp
// Autonomous Mobile Robots (Control Engineering) — Chapter 1, Lesson 1
// Lesson: What Makes Mobility Different from Manipulation
//
// Minimal C++17 simulation that contrasts:
//   (i) differential-drive mobile base planar kinematics
//   (ii) planar 2R manipulator kinematics
//
// Robotics libraries commonly used in C++ ecosystems (not required here):
//   - Eigen (linear algebra)
//   - ROS 2 (rclcpp) for robotics middleware
//   - GTSAM / Ceres for estimation (later chapters)
//
// Build:
//   g++ -std=c++17 -O2 -o Chapter1_Lesson1 Chapter1_Lesson1.cpp
//
// Run:
//   ./Chapter1_Lesson1
//
// Output:
//   Chapter1_Lesson1_mobile.csv
//   Chapter1_Lesson1_manipulator.csv

#include <cmath>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

struct Pose2 {
    double x;
    double y;
    double theta;
};

static std::vector<Pose2> integrate_diff_drive(const Pose2& p0, double v, double w, double dt, int steps) {
    std::vector<Pose2> traj;
    traj.reserve(static_cast<size_t>(steps) + 1);

    Pose2 p = p0;
    traj.push_back(p);

    for (int k = 0; k < steps; ++k) {
        p.x += dt * v * std::cos(p.theta);
        p.y += dt * v * std::sin(p.theta);
        p.theta += dt * w;
        traj.push_back(p);
    }
    return traj;
}

static void fk_2r(double q1, double q2, double l1, double l2, double& xe, double& ye) {
    xe = l1 * std::cos(q1) + l2 * std::cos(q1 + q2);
    ye = l1 * std::sin(q1) + l2 * std::sin(q1 + q2);
}

int main() {
    const double dt = 0.02;
    const double T  = 8.0;
    const int steps = static_cast<int>(T / dt);

    // Mobile base: body-frame controls v, w
    const double v = 0.5;
    const double w = 0.35;

    auto mobile_traj = integrate_diff_drive(Pose2{0.0, 0.0, 0.0}, v, w, dt, steps);

    {
        std::ofstream f("Chapter1_Lesson1_mobile.csv");
        f << "t,x,y,theta\\n";
        for (int k = 0; k < static_cast<int>(mobile_traj.size()); ++k) {
            const auto& p = mobile_traj[static_cast<size_t>(k)];
            f << (k * dt) << "," << p.x << "," << p.y << "," << p.theta << "\\n";
        }
    }

    // 2R manipulator: joint-rate controls qdot
    const double qdot1 = 0.25;
    const double qdot2 = -0.15;
    double q1 = 0.2;
    double q2 = 0.9;
    const double l1 = 1.0;
    const double l2 = 0.7;

    {
        std::ofstream f("Chapter1_Lesson1_manipulator.csv");
        f << "t,q1,q2,xe,ye\\n";
        for (int k = 0; k <= steps; ++k) {
            double xe = 0.0, ye = 0.0;
            fk_2r(q1, q2, l1, l2, xe, ye);
            f << (k * dt) << "," << q1 << "," << q2 << "," << xe << "," << ye << "\\n";

            q1 += dt * qdot1;
            q2 += dt * qdot2;
        }
    }

    std::cout << "Wrote CSV files for mobile base and 2R manipulator trajectories." << std::endl;
    return 0;
}

6.3 Java

File: Chapter1_Lesson1.java

// Chapter1_Lesson1.java
// Autonomous Mobile Robots (Control Engineering) — Chapter 1, Lesson 1
// Lesson: What Makes Mobility Different from Manipulation
//
// Minimal Java simulation that contrasts:
//   (i) differential-drive mobile base planar kinematics
//   (ii) planar 2R manipulator kinematics
//
// Robotics-related Java tooling (not required here):
//   - EJML (efficient matrix library) for linear algebra
//   - ROSJava / ros2-java bindings for ROS integration (project-dependent)
//
// Compile:
//   javac Chapter1_Lesson1.java
// Run:
//   java Chapter1_Lesson1
//
// Output:
//   Chapter1_Lesson1_mobile.csv
//   Chapter1_Lesson1_manipulator.csv

import java.io.FileWriter;
import java.io.IOException;

public class Chapter1_Lesson1 {

    static class Pose2 {
        double x, y, theta;
        Pose2(double x, double y, double theta) {
            this.x = x; this.y = y; this.theta = theta;
        }
    }

    static void fk2r(double q1, double q2, double l1, double l2, double[] outXY) {
        double xe = l1 * Math.cos(q1) + l2 * Math.cos(q1 + q2);
        double ye = l1 * Math.sin(q1) + l2 * Math.sin(q1 + q2);
        outXY[0] = xe;
        outXY[1] = ye;
    }

    public static void main(String[] args) throws IOException {
        final double dt = 0.02;
        final double T  = 8.0;
        final int steps = (int)Math.floor(T / dt);

        // Mobile base controls
        final double v = 0.5;
        final double w = 0.35;

        Pose2 p = new Pose2(0.0, 0.0, 0.0);
        try (FileWriter f = new FileWriter("Chapter1_Lesson1_mobile.csv")) {
            f.write("t,x,y,theta\\n");
            for (int k = 0; k <= steps; k++) {
                double t = k * dt;
                f.write(t + "," + p.x + "," + p.y + "," + p.theta + "\\n");

                // Euler step
                p.x += dt * v * Math.cos(p.theta);
                p.y += dt * v * Math.sin(p.theta);
                p.theta += dt * w;
            }
        }

        // Manipulator joint-rate controls
        double q1 = 0.2, q2 = 0.9;
        final double qdot1 = 0.25;
        final double qdot2 = -0.15;
        final double l1 = 1.0, l2 = 0.7;

        double[] xy = new double[2];
        try (FileWriter f = new FileWriter("Chapter1_Lesson1_manipulator.csv")) {
            f.write("t,q1,q2,xe,ye\\n");
            for (int k = 0; k <= steps; k++) {
                double t = k * dt;
                fk2r(q1, q2, l1, l2, xy);
                f.write(t + "," + q1 + "," + q2 + "," + xy[0] + "," + xy[1] + "\\n");

                q1 += dt * qdot1;
                q2 += dt * qdot2;
            }
        }

        System.out.println("Wrote CSV files for mobile base and 2R manipulator trajectories.");
    }
}

6.4 MATLAB / Simulink

File: Chapter1_Lesson1.m

% Chapter1_Lesson1.m
% Autonomous Mobile Robots (Control Engineering) — Chapter 1, Lesson 1
% Lesson: What Makes Mobility Different from Manipulation
%
% This MATLAB script:
%   (i) simulates a differential-drive planar kinematic model, and
%   (ii) simulates a planar 2R manipulator end-effector trajectory,
% then (optionally) creates a simple Simulink model programmatically.
%
% Robotics libraries/toolboxes to explore next:
%   - Robotics System Toolbox (SE(2)/SE(3), rigidBodyTree, etc.)
%   - Simulink for model-based design and control prototyping
%
% Output:
%   Chapter1_Lesson1_mobile.csv
%   Chapter1_Lesson1_manipulator.csv
%   Chapter1_Lesson1_Simulink.slx  (if Simulink available)

clear; clc;

dt = 0.02;
T  = 8.0;
steps = floor(T/dt);

%% Mobile base: x_dot = v cos(theta), y_dot = v sin(theta), theta_dot = w
v = 0.5;    % m/s
w = 0.35;   % rad/s

x = 0; y = 0; th = 0;
mobile = zeros(steps+1, 4); % [t x y theta]
for k = 0:steps
    t = k*dt;
    mobile(k+1,:) = [t x y th];

    x  = x  + dt * v * cos(th);
    y  = y  + dt * v * sin(th);
    th = th + dt * w;
end
writematrix([["t","x","y","theta"]; string(mobile)], "Chapter1_Lesson1_mobile.csv");

%% 2R manipulator: end-effector (xe,ye) and joint angles (q1,q2)
q1 = 0.2; q2 = 0.9;
qdot1 = 0.25; qdot2 = -0.15;
l1 = 1.0; l2 = 0.7;

manip = zeros(steps+1, 5); % [t q1 q2 xe ye]
for k = 0:steps
    t = k*dt;
    xe = l1*cos(q1) + l2*cos(q1+q2);
    ye = l1*sin(q1) + l2*sin(q1+q2);
    manip(k+1,:) = [t q1 q2 xe ye];

    q1 = q1 + dt*qdot1;
    q2 = q2 + dt*qdot2;
end
writematrix([["t","q1","q2","xe","ye"]; string(manip)], "Chapter1_Lesson1_manipulator.csv");

%% Plots
figure; plot(mobile(:,2), mobile(:,3)); axis equal; grid on;
title("Mobile base trajectory (x-y)"); xlabel("x [m]"); ylabel("y [m]");

figure; plot(manip(:,4), manip(:,5)); axis equal; grid on;
title("2R manipulator end-effector trajectory (x-y)"); xlabel("x_e [m]"); ylabel("y_e [m]");

%% (Optional) Build a tiny Simulink model: integrate x_dot, y_dot, theta_dot
% This demonstrates the modeling difference: mobile base evolves on SE(2) with
% trigonometric coupling; manipulator typically uses joint integrators.
try
    mdl = "Chapter1_Lesson1_Simulink";
    if bdIsLoaded(mdl), close_system(mdl, 0); end
    new_system(mdl); open_system(mdl);

    % Blocks
    add_block("simulink/Sources/Constant", mdl + "/v", "Value", "0.5");
    add_block("simulink/Sources/Constant", mdl + "/w", "Value", "0.35");
    add_block("simulink/Continuous/Integrator", mdl + "/Int_theta", "InitialCondition", "0");
    add_block("simulink/Math Operations/Trigonometric Function", mdl + "/cos", "Operator", "cos");
    add_block("simulink/Math Operations/Trigonometric Function", mdl + "/sin", "Operator", "sin");
    add_block("simulink/Math Operations/Product", mdl + "/v_cos");
    add_block("simulink/Math Operations/Product", mdl + "/v_sin");
    add_block("simulink/Continuous/Integrator", mdl + "/Int_x", "InitialCondition", "0");
    add_block("simulink/Continuous/Integrator", mdl + "/Int_y", "InitialCondition", "0");
    add_block("simulink/Sinks/To Workspace", mdl + "/ToW", "VariableName", "simout", "SaveFormat", "StructureWithTime");

    % Lines
    add_line(mdl, "w/1", "Int_theta/1");
    add_line(mdl, "Int_theta/1", "cos/1");
    add_line(mdl, "Int_theta/1", "sin/1");
    add_line(mdl, "v/1", "v_cos/1"); add_line(mdl, "cos/1", "v_cos/2");
    add_line(mdl, "v/1", "v_sin/1"); add_line(mdl, "sin/1", "v_sin/2");
    add_line(mdl, "v_cos/1", "Int_x/1");
    add_line(mdl, "v_sin/1", "Int_y/1");

    % Log outputs (x,y,theta) via Mux-like struct: send as separate signals to To Workspace
    add_line(mdl, "Int_x/1", "ToW/1", "autorouting", "on");
    add_line(mdl, "Int_y/1", "ToW/2", "autorouting", "on");
    add_line(mdl, "Int_theta/1", "ToW/3", "autorouting", "on");

    set_param(mdl, "StopTime", num2str(T));
    save_system(mdl, mdl + ".slx");
    % Users can run: sim(mdl)
    fprintf("Created Simulink model: %s.slx\\n", mdl);
catch ME
    fprintf("Simulink model build skipped (Simulink not available or error): %s\\n", ME.message);
end

disp("Wrote: Chapter1_Lesson1_mobile.csv and Chapter1_Lesson1_manipulator.csv");

6.5 Wolfram Mathematica

File: Chapter1_Lesson1.nb

(* Chapter1_Lesson1.nb
   Autonomous Mobile Robots (Control Engineering) — Chapter 1, Lesson 1
   Lesson: What Makes Mobility Different from Manipulation

   This Wolfram Notebook (in plain-text form) contains:
     1) A symbolic non-integrability check for the no-slip 1-form
     2) A short numerical simulation for a planar mobile base and a 2R manipulator
*)

Notebook[{
  Cell["Chapter 1, Lesson 1 — Mobility vs Manipulation", "Title"],
  Cell["1. Symbolic non-integrability check (Pfaffian 1-form)", "Section"],
  Cell[BoxData @ ToBoxes[
    HoldForm[
      (* No-slip lateral constraint for a body with yaw theta (planar):  ω = -Sin[θ] dx + Cos[θ] dy = 0 *)
      ω = -Sin[θ] dx + Cos[θ] dy;
    ]
  ], "Input"],
  Cell[BoxData @ ToBoxes[
    HoldForm[
      (* Compute dω ∧ ω; nonzero implies non-integrable (nonholonomic) *)
      dω = D[ω, θ] \[Wedge] dθ;  (* since ω depends on θ only; dx,dy treated as independent 1-forms *)
    ]
  ], "Input"],
  Cell[BoxData @ ToBoxes[
    HoldForm[
      Expand[ dω \[Wedge] ω ]
    ]
  ], "Input"],
  Cell["Expected outcome: proportional to dθ ∧ dx ∧ dy (nonzero).", "Text"],

  Cell["2. Numerical contrast: differential drive vs 2R manipulator", "Section"],
  Cell[BoxData @ ToBoxes[
    HoldForm[
      dt = 0.02; T = 8.0; steps = Floor[T/dt];
      v = 0.5; w = 0.35;
      pose = {0.0, 0.0, 0.0}; (* x,y,theta *)
      traj = Table[
        pose = {
          pose[[1]] + dt*v*Cos[pose[[3]]],
          pose[[2]] + dt*v*Sin[pose[[3]]],
          pose[[3]] + dt*w
        };
        pose
      , {steps}];
    ]
  ], "Input"],
  Cell[BoxData @ ToBoxes[
    HoldForm[
      (* 2R manipulator end-effector path under constant joint rates *)
      l1 = 1.0; l2 = 0.7;
      q = {0.2, 0.9}; qdot = {0.25, -0.15};
      fk[q_] := {l1 Cos[q[[1]]] + l2 Cos[q[[1]] + q[[2]]],
                l1 Sin[q[[1]]] + l2 Sin[q[[1]] + q[[2]]]};
      ee = Table[
        q = q + dt*qdot;
        fk[q]
      , {steps}];
    ]
  ], "Input"],
  Cell[BoxData @ ToBoxes[
    HoldForm[
      ListLinePlot[{traj[[All, {1, 2}]], ee}, PlotLegends -> {"mobile (x,y)", "manipulator EE (x,y)"},
        AspectRatio -> 1, GridLines -> Automatic]
    ]
  ], "Input"]
}]

Download package: the ZIP below contains the exact source files shown above (Python/C++/Java/MATLAB/Mathematica).

7. Problems and Solutions

Problem 1 (Actuation dimension vs configuration dimension): A planar mobile base has configuration \( (x,y,\theta) \). Under the kinematic control model with inputs \( (v,\omega) \), show that the instantaneous velocity space has dimension at most 2 at each configuration.

Solution: The kinematic map is

\[ \dot{\mathbf{x}} = \underbrace{ \begin{bmatrix} \cos\theta & 0 \\ \sin\theta & 0 \\ 0 & 1 \end{bmatrix}}_{\mathbf{B}(\theta)} \mathbf{u}, \quad \mathbf{u}= \begin{bmatrix} v \\ \omega \end{bmatrix}. \]

The column space of \( \mathbf{B}(\theta) \) is spanned by two vectors, hence \( \dim(\mathrm{Im}(\mathbf{B})) \le 2 \) for all \( \theta \). Therefore, the robot’s instantaneous velocity cannot span all of \( \mathbb{R}^3 \).

Problem 2 (Non-integrability test): For the 1-form \( \omega = -\sin\theta \, dx + \cos\theta \, dy \), compute \( d\omega \wedge \omega \) and conclude whether the constraint is integrable.

Solution: As shown in Section 4,

\[ d\omega = -\cos\theta \, d\theta\wedge dx - \sin\theta \, d\theta\wedge dy, \quad d\omega\wedge\omega = - d\theta\wedge dx\wedge dy \neq 0. \]

Since \( d\omega\wedge\omega \neq 0 \), the constraint is non-integrable (nonholonomic).

Problem 3 (Body velocity to world velocity): Suppose a mobile robot has body-frame forward speed \( v \) and yaw rate \( \omega \). Derive the world-frame velocities \( \dot{x},\dot{y},\dot{\theta} \).

Solution: The body forward axis is oriented at heading \( \theta \), so

\[ \dot{x} = v\cos\theta,\quad \dot{y} = v\sin\theta,\quad \dot{\theta}=\omega. \]

Problem 4 (Manipulator Jacobian vs base kinematics): For the planar 2R manipulator with forward kinematics \( x_e = \ell_1\cos q_1 + \ell_2\cos(q_1+q_2) \), \( y_e = \ell_1\sin q_1 + \ell_2\sin(q_1+q_2) \), derive \( \mathbf{J}(\mathbf{q}) \).

Solution: Differentiate w.r.t. \( q_1,q_2 \):

\[ \mathbf{J}(\mathbf{q}) = \begin{bmatrix} \frac{\partial x_e}{\partial q_1} & \frac{\partial x_e}{\partial q_2} \\ \frac{\partial y_e}{\partial q_1} & \frac{\partial y_e}{\partial q_2} \end{bmatrix} = \begin{bmatrix} -\ell_1\sin q_1 - \ell_2\sin(q_1+q_2) & -\ell_2\sin(q_1+q_2) \\ \ell_1\cos q_1 + \ell_2\cos(q_1+q_2) & \ell_2\cos(q_1+q_2) \end{bmatrix}. \]

In manipulation, \( \dot{\mathbf{q}} \) can be chosen freely (within actuator limits). In mobility, the analogous “free choice” does not exist for \( (\dot{x},\dot{y},\dot{\theta}) \) because rolling constraints restrict feasible instantaneous velocities.

Problem 5 (Holonomic vs nonholonomic intuition): Consider a constraint \( h(x,y,\theta)=0 \) that removes one degree of freedom in configuration space. Explain how this differs from \( -\sin\theta \, \dot{x} + \cos\theta \, \dot{y} = 0 \) in terms of reachable configurations.

Solution: A holonomic constraint \( h=0 \) restricts the set of allowable configurations to a 2D surface embedded in \( \mathbb{R}^3 \), so unreachable configurations exist regardless of time. The nonholonomic constraint restricts instantaneous velocities but does not necessarily remove configurations from the reachable set; it restricts the paths that connect configurations. Over time, composing admissible motions can reach configurations that are not reachable via a single instantaneous direction (e.g., lateral displacement achieved through maneuvering).

8. Summary

Mobility differs from manipulation primarily because wheel–ground contact introduces velocity-level constraints that are non-integrable. As a result, mobile bases are often underactuated in configuration coordinates and cannot generate arbitrary instantaneous planar velocities, even though they can reach many configurations through time-composed maneuvers. These scope assumptions (planar pose, rigid base, rolling constraints) will be used as the baseline model for subsequent lessons, where we will formalize state variables and the sensing–estimation–navigation pipeline.

9. References

  1. Brockett, R.W. (1983). Asymptotic stability and feedback stabilization. Differential Geometric Control Theory, 181–191.
  2. Campion, G., Bastin, G., & D’Andrea-Novel, B. (1996). Structural properties and classification of kinematic and dynamic models of wheeled mobile robots. IEEE Transactions on Robotics and Automation, 12(1), 47–62.
  3. Laumond, J.-P. (1998). Robot Motion Planning and Control. (Foundational treatments of nonholonomic mobility; cited for historical context.)
  4. Murray, R.M., & Sastry, S.S. (1993). Nonholonomic motion planning: steering using sinusoids. IEEE Transactions on Automatic Control, 38(5), 700–716.
  5. Kelly, R., Santibáñez, V., & Loria, A. (2005). Control of robot manipulators in joint space. Springer Tracts in Advanced Robotics. (Manipulator contrast reference.)