# PedalGeometry Kinematic Calculations and Lever-Arm Force Analysis in DIY Sim-Racing FFB Pedals

> Explore PedalGeometry kinematic calculations for DIY Sim-Racing FFB Pedals. Learn how to model pedal linkage, calculate angles, and analyze lever arm forces for optimal performance.

- Repository: [chrgri/diy-sim-racing-ffb-pedal](https://github.com/chrgri/diy-sim-racing-ffb-pedal)
- Tags: deep-dive
- Published: 2026-02-27

---

**The PedalGeometry kinematic calculations in the DIY Sim-Racing FFB Pedal repository compute the axial load-cell force by modeling the pedal linkage as a four-bar mechanism, applying the law of cosines to derive instantaneous pedal angles and resolving forces through torque equilibrium equations defined in [`Validation/PedalKinematics/main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/PedalKinematics/main.py).**

The `chrgri/diy-sim-racing-ffb-pedal` project implements a closed-loop force-feedback pedal system that relies on precise PedalGeometry kinematic calculations to translate motor torque into realistic pedal resistance. These calculations, contained within the validation scripts, model the mechanical linkage as a dynamic system to determine the required load-cell forces throughout the pedal travel range.

## Geometry Parameters and Linkage Dimensions

The kinematic model defines the pedal linkage using five primary geometric constants that describe the four-bar mechanism. These values are hardcoded at the top of [`Validation/PedalKinematics/main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/PedalKinematics/main.py):

| Symbol | Description | Value (mm) |
|--------|-------------|------------|
| `a` | Load-cell rod length (pivot-to-pivot) | **200** |
| `b` | Distance between pedal pivots (front-rear) | **120** |
| `c0` | Vertical offset of rear pivot from lower front pivot | **80** |
| `c1` | Horizontal offset of rear pivot from lower front pivot | **240** |
| `lengthTillPedal` | Distance from lower pivot to pedal face center | **220** |

```python
a = 200.0
b = 120.0
c0 = 80.0
c1 = 240.0
lengthTillPedal = b + 100

```

## Kinematic Chain and Pedal Angle Calculation

The PedalGeometry kinematic calculations model the pedal motion as the spindle translates linearly, altering the linkage geometry in real-time.

### Spindle Motion Dynamics

The spindle (or "sled") translates based on motor RPM and spindle pitch. The script calculates the linear velocity and displacement over time:

```python
v_sled = spinglePitch_inMm * (maxRpm / 60)      # mm/s

max_T   = 100 / v_sled                           # travel time for 100 mm stroke

t       = np.linspace(0, max_T, 1000)           # time vector

delta_c = v_sled * t                            # sled offset at each step

```

### Instantaneous Pivot Distance

As the sled moves, the horizontal distance between pivots changes, calculated using the Pythagorean theorem:

```python
c = np.sqrt(c0**2 + (c1 + delta_c)**2)

```

### Pedal Angle via Law of Cosines

The pedal angle **α** derives from the triangle formed by link lengths `a`, `b`, and `c`:

```python
nom = b**2 + c**2 - a**2
den = 2 * b * c
alpha = np.arccos(nom / den) * 180 / np.pi   # degrees

```

## Lever-Arm Force Calculations

The PedalGeometry kinematic calculations resolve the motor's spindle force into the axial pedal force that the load-cell must measure.

### Auxiliary Angles and Total Lever Angle

The angle **α₀** between the line `c` and the vertical offset `c₀` combines with **α** to form the total lever-arm angle **ϕ**:

```python
alpha0 = np.arcsin(c0 / c) * 180 / np.pi
phi = alpha + alpha0                         # total angle of the force lever

```

### Spindle Force Conversion

Motor torque **T** converts to linear spindle force **Fₐ** through the spindle pitch and mechanical efficiency **η**:

```python
F_a = 2 * np.pi * T / spinglePitch_inMm * eta * 1e3   # N

```

### Force Balance and Axial Pedal Force

The torque equilibrium around the rear pivot relates the spindle force **Fₐ**, the horizontal reaction **Fₗₚ**, and the axial pedal force **Fₚ**:

\[
\sin(\phi)\,F_{p} + F_{lp} = F_{a}
\]

With the geometric ratio:

\[
F_{lp} = \frac{\text{lengthTillPedal}}{b}\,F_{p}
\]

The implemented solution in [`main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/main.py) solves for **Fₚ**:

```python
F_p = F_a / (np.sin(phi * np.pi / 180) * lengthTillPedal / b)

```

This yields the instantaneous axial force that the load-cell must withstand throughout the pedal travel.

## Implementation in Python

The complete PedalGeometry kinematic calculations are implemented as a self-contained script. Below is the essential logic extracted from [`Validation/PedalKinematics/main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/PedalKinematics/main.py), demonstrating how to compute the full force envelope:

```python
import numpy as np
import matplotlib.pyplot as plt

# Geometry constants (mm)

a = 200.0
b = 120.0
c0 = 80.0
c1 = 240.0
lengthTillPedal = b + 100

# Motor/spindle parameters

maxRpm = 5000
spindle_pitch = 5.0  # mm/rev

eta = 0.83
T = 1.1  # Nm

# Kinematic simulation

v_sled = spindle_pitch * (maxRpm / 60)
max_T = 100 / v_sled
t = np.linspace(0, max_T, 1000)
delta_c = v_sled * t

# Instantaneous geometry

c = np.sqrt(c0**2 + (c1 + delta_c)**2)

# Pedal angle (law of cosines)

alpha = np.degrees(np.arccos((b**2 + c**2 - a**2) / (2 * b * c)))

# Lever angles

alpha0 = np.degrees(np.arcsin(c0 / c))
phi = alpha + alpha0

# Force calculations

F_a = 2 * np.pi * T / spindle_pitch * eta * 1e3  # Spindle force (N)

F_p = F_a / (np.sin(np.radians(phi)) * lengthTillPedal / b)  # Axial pedal force (N)

# Visualization

plt.figure(figsize=(10, 6))
plt.plot(t, F_p, label='Axial Pedal Force (N)', linewidth=2)
plt.xlabel('Time (s)')
plt.ylabel('Force (N)')
plt.title('Pedal Force vs. Time')
plt.grid(True)
plt.legend()
plt.show()

```

Running this script reproduces the **force-versus-time** curve that appears in the original repository's output, validating the mechanical design against the motor capabilities.

## Validation and Simulation Files

The PedalGeometry kinematic calculations serve as the foundation for broader system validation. The repository organizes related functionality across several files:

| File | Purpose |
|------|---------|
| [`Validation/PedalKinematics/main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/PedalKinematics/main.py) | Core kinematic model implementing the four-bar linkage geometry, pedal angle derivation via law of cosines, and axial force calculations. |
| [`Validation/SimulatePedalResponse.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/SimulatePedalResponse.py) | Dynamic system simulation incorporating mass-spring-damper dynamics and PI controller response, utilizing the calculated `F_p` as the reference force input. |
| [`Helper/obtainVersionString.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Helper/obtainVersionString.py) | Version management utility supporting the validation toolchain. |

These files demonstrate how the static geometric analysis feeds into real-time force-feedback control algorithms.

## Summary

- The **PedalGeometry kinematic calculations** in [`Validation/PedalKinematics/main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/PedalKinematics/main.py) model the pedal as a four-bar linkage with defined pivot offsets and rod lengths.
- **Pedal angle α** derives from the law of cosines applied to the instantaneous triangle formed by the load-cell rod `a`, pivot spacing `b`, and variable sled distance `c`.
- **Lever-arm angle ϕ** combines the pedal angle with the geometric offset angle α₀ to determine the effective force vector acting on the linkage.
- **Axial pedal force Fₚ** is calculated by resolving the spindle force Fₐ through the lever-arm geometry, yielding the load-cell reference force required for the force-feedback system.

## Frequently Asked Questions

### How are the PedalGeometry kinematic calculations implemented in the DIY FFB pedal software?

The calculations are implemented in [`Validation/PedalKinematics/main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/PedalKinematics/main.py) as a NumPy-based simulation that computes the pedal angle using the law of cosines and derives the axial force through lever-arm torque equilibrium. The script simulates the spindle translation over time to generate force-versus-travel curves that validate the mechanical design against motor capabilities.

### What geometric parameters define the pedal linkage kinematics?

The model uses five primary constants defined in the source code: the load-cell rod length `a` (200 mm), pivot spacing `b` (120 mm), vertical offset `c0` (80 mm), horizontal offset `c1` (240 mm), and the pedal face distance `lengthTillPedal` (220 mm). These dimensions form the four-bar linkage that governs the pedal motion throughout its travel range.

### How does the spindle motor torque translate to pedal force?

The motor torque `T` (1.1 Nm) converts to linear spindle force `F_a` through the formula `F_a = 2π × T / pitch × η`, accounting for the 5 mm spindle pitch and 83% mechanical efficiency. This spindle force is then resolved into the axial pedal force `F_p` by dividing by the geometric ratio involving the sine of the lever-arm angle `ϕ` and the pedal length ratio `lengthTillPedal / b`.

### Which file contains the core kinematic calculations for the pedal geometry?

The core PedalGeometry kinematic calculations reside in [`Validation/PedalKinematics/main.py`](https://github.com/chrgri/diy-sim-racing-ffb-pedal/blob/main/Validation/PedalKinematics/main.py). This file implements the four-bar linkage model, computes pedal angles via the law of cosines, calculates lever-arm angles, and resolves the spindle force into the axial pedal force that the load-cell must measure.