Front-Wheel Drive (FWD) Kinematics
Forward and inverse kinematics for front-wheel drive robots with Ackermann steering geometry.
Overview
Front-Wheel Drive (FWD) combines steering and driving at the front wheels, similar to most cars.
Advantages:
- Car-like steering (intuitive)
- Good forward traction
- Simpler than four-wheel steering
- Predictable handling
Disadvantages:
- Cannot rotate in place
- Larger turning radius
- Limited maneuverability in tight spaces
- Front wheel wear
Robot Configuration
1 Front (Steered + Driven)
2 β
3 βββββββββββ
4 β β± β² β β Steered wheels
5 β β
6 β β’ β β Center of rotation
7 β β
8 β β β β β Rear wheels (passive)
9 βββββββββββ
Parameters:
- $L$: Wheelbase (distance between front and rear axles)
- $\delta$: Steering angle
- $v$: Linear velocity
- $r$: Wheel radius
Interactive FWD Simulator
Forward Kinematics
Ackermann Steering Equations
Given steering angle $\delta$ and velocity $v$:
$$ \omega = \frac{v \tan\delta}{L} $$
$$ R = \frac{L}{\tan\delta} $$
Where:
- $\omega$: Angular velocity
- $R$: Turning radius
- $L$: Wheelbase
Pose Update
$$ \dot{x} = v \cos\theta $$
$$ \dot{y} = v \sin\theta $$
$$ \dot{\theta} = \omega = \frac{v \tan\delta}{L} $$
Python Implementation
1import numpy as np
2
3class FrontWheelDrive:
4 def __init__(self, wheelbase=0.5, wheel_radius=0.1):
5 """
6 Args:
7 wheelbase: Distance between front and rear axles (m)
8 wheel_radius: Radius of wheels (m)
9 """
10 self.L = wheelbase
11 self.r = wheel_radius
12
13 # State: [x, y, theta]
14 self.state = np.array([0.0, 0.0, 0.0])
15
16 def forward_kinematics(self, v, delta, dt):
17 """
18 Update robot pose from velocity and steering angle
19
20 Args:
21 v: Linear velocity (m/s)
22 delta: Steering angle (rad)
23 dt: Time step (s)
24
25 Returns:
26 Updated pose [x, y, theta]
27 """
28 x, y, theta = self.state
29
30 # Calculate angular velocity
31 if abs(delta) < 1e-6:
32 # Straight line motion
33 omega = 0
34 else:
35 omega = v * np.tan(delta) / self.L
36
37 # Update pose
38 x += v * np.cos(theta) * dt
39 y += v * np.sin(theta) * dt
40 theta += omega * dt
41
42 # Normalize angle
43 theta = np.arctan2(np.sin(theta), np.cos(theta))
44
45 self.state = np.array([x, y, theta])
46 return self.state.copy()
47
48 def get_turning_radius(self, delta):
49 """Calculate turning radius for given steering angle"""
50 if abs(delta) < 1e-6:
51 return float('inf')
52 return self.L / np.tan(delta)
53
54 def get_min_turning_radius(self, max_steering_angle=np.pi/3):
55 """Get minimum turning radius"""
56 return self.L / np.tan(max_steering_angle)
57
58# Example
59robot = FrontWheelDrive(wheelbase=0.5, wheel_radius=0.1)
60
61# Straight line
62for _ in range(100):
63 robot.forward_kinematics(v=1.0, delta=0, dt=0.01)
64
65print(f"After straight motion: {robot.state}")
66
67# Turn
68robot.state = np.array([0.0, 0.0, 0.0])
69for _ in range(100):
70 robot.forward_kinematics(v=1.0, delta=np.pi/6, dt=0.01)
71
72print(f"After turning: {robot.state}")
Inverse Kinematics
From Desired Path to Control Inputs
Given desired turning radius $R$ and velocity $v$:
$$ \delta = \arctan\left(\frac{L}{R}\right) $$
Implementation
1def inverse_kinematics(self, v_desired, R_desired):
2 """
3 Compute steering angle for desired turning radius
4
5 Args:
6 v_desired: Desired linear velocity (m/s)
7 R_desired: Desired turning radius (m)
8 - Positive: turn left
9 - Negative: turn right
10 - Infinity: straight line
11
12 Returns:
13 (v, delta): velocity and steering angle
14 """
15 if abs(R_desired) > 1000: # Effectively straight
16 delta = 0
17 else:
18 delta = np.arctan(self.L / R_desired)
19
20 return v_desired, delta
21
22# Add to FrontWheelDrive class
23FrontWheelDrive.inverse_kinematics = inverse_kinematics
24
25# Example: Turn with 2m radius
26robot = FrontWheelDrive(wheelbase=0.5)
27v, delta = robot.inverse_kinematics(v_desired=1.0, R_desired=2.0)
28print(f"For R=2m: v={v:.2f} m/s, Ξ΄={np.degrees(delta):.1f}Β°")
Ackermann Geometry
Proper Ackermann Steering
For proper turning without wheel slip, inner and outer wheels need different steering angles:
$$ \cot\delta_o - \cot\delta_i = \frac{W}{L} $$
Where:
- $\delta_o$: Outer wheel steering angle
- $\delta_i$: Inner wheel steering angle
- $W$: Track width
Implementation
1def ackermann_angles(self, delta_center, track_width=0.4):
2 """
3 Calculate individual wheel steering angles
4
5 Args:
6 delta_center: Center steering angle (rad)
7 track_width: Distance between left and right wheels (m)
8
9 Returns:
10 (delta_inner, delta_outer): Steering angles for inner and outer wheels
11 """
12 if abs(delta_center) < 1e-6:
13 return 0, 0
14
15 # Turning radius at center
16 R = self.L / np.tan(delta_center)
17
18 # Inner wheel (sharper angle)
19 R_inner = R - track_width / 2
20 delta_inner = np.arctan(self.L / R_inner)
21
22 # Outer wheel (gentler angle)
23 R_outer = R + track_width / 2
24 delta_outer = np.arctan(self.L / R_outer)
25
26 return delta_inner, delta_outer
27
28# Add to class
29FrontWheelDrive.ackermann_angles = ackermann_angles
30
31# Example
32robot = FrontWheelDrive(wheelbase=0.5)
33delta_inner, delta_outer = robot.ackermann_angles(delta_center=np.pi/6, track_width=0.4)
34print(f"Inner wheel: {np.degrees(delta_inner):.1f}Β°")
35print(f"Outer wheel: {np.degrees(delta_outer):.1f}Β°")
Path Following
Pure Pursuit Controller
1def pure_pursuit(self, target_x, target_y, lookahead_distance=1.0):
2 """
3 Pure pursuit path following algorithm
4
5 Args:
6 target_x, target_y: Target point coordinates
7 lookahead_distance: Lookahead distance (m)
8
9 Returns:
10 Steering angle to reach target
11 """
12 x, y, theta = self.state
13
14 # Transform target to robot frame
15 dx = target_x - x
16 dy = target_y - y
17
18 # Rotate to robot frame
19 dx_robot = dx * np.cos(theta) + dy * np.sin(theta)
20 dy_robot = -dx * np.sin(theta) + dy * np.cos(theta)
21
22 # Calculate curvature
23 curvature = 2 * dy_robot / (lookahead_distance ** 2)
24
25 # Calculate steering angle
26 delta = np.arctan(curvature * self.L)
27
28 # Limit steering angle
29 max_delta = np.pi / 3
30 delta = np.clip(delta, -max_delta, max_delta)
31
32 return delta
33
34# Add to class
35FrontWheelDrive.pure_pursuit = pure_pursuit
Advantages and Limitations
Advantages
- Intuitive: Similar to car driving
- Good traction: Driven wheels pull the robot
- Predictable: Well-understood dynamics
- Simple: Fewer actuators than 4WD
Limitations
- Turning radius: Cannot turn as sharply as differential drive
- No zero-radius turns: Cannot rotate in place
- Parking: Difficult in tight spaces
- Wheel wear: Front wheels wear faster
Applications
- Autonomous cars: Most self-driving cars use FWD or AWD
- Delivery robots: Street navigation
- Agricultural robots: Row following
- Warehouse AGVs: Aisle navigation
- Outdoor robots: Natural terrain
Further Reading
Related Snippets
- Denavit-Hartenberg (DH) Parameters
Denavit-Hartenberg convention for systematically describing robot manipulator β¦ - DH Parameter Examples and Common Configurations
Practical examples of DH parameter configurations for common robot manipulators β¦ - Four-Wheel Independent Drive Kinematics
Forward and inverse kinematics for four-wheel independent drive robots with β¦ - Jacobian Matrices for Forward and Inverse Kinematics
Jacobian matrices relate joint velocities to end-effector velocities, essential β¦ - Mecanum Wheel Kinematics
Forward and inverse kinematics for mecanum wheel robots, enabling β¦ - Rear-Wheel Drive (RWD) Kinematics
Forward and inverse kinematics for rear-wheel drive robots with front-wheel β¦ - Two-Wheel Balancing Robot Kinematics and Control
Kinematics and control for two-wheel self-balancing robots (inverted pendulum on β¦ - Two-Wheel Differential Drive Robot Kinematics
Forward and inverse kinematics for two-wheel differential drive robots, the most β¦