Forward kinematics can be used for odometry calculation in mobile robots, we can estimate the new pose of the robot from wheel encoder measurements.
Continued with the state equations from the unicycle model ,
{ x ˙ = v cos θ y ˙ = v sin θ θ ˙ = ω \begin{cases}
\begin{aligned}
\dot{x} &= v\cos{\theta} \\
\dot{y} &= v\sin{\theta} \\[0.2ex]
\dot{\theta} &= \omega
\end{aligned}
\end{cases} ⎩ ⎨ ⎧ x ˙ y ˙ θ ˙ = v cos θ = v sin θ = ω
To calculate the robot pose, we take the integration of the differential equations
x ( t ) = x ( 0 ) + ∫ 0 t v ( τ ) cos ( θ ( τ ) ) d τ y ( t ) = y ( 0 ) + ∫ 0 t v ( τ ) sin ( θ ( τ ) ) d τ θ ( t ) = θ ( 0 ) + ∫ 0 t ω ( τ ) d τ \begin{aligned}
x(t) &= x(0) + \int_0^t v(\tau)\cos{\big(\theta(\tau)\big)}\,\mathrm{d}\tau \\
y(t) &= y(0) + \int_0^t v(\tau)\sin{\big(\theta(\tau)\big)}\,\mathrm{d}\tau \\
\theta(t) &= \theta(0) + \int_0^t \omega(\tau)\,\mathrm{d}\tau
\end{aligned} x ( t ) y ( t ) θ ( t ) = x ( 0 ) + ∫ 0 t v ( τ ) cos ( θ ( τ ) ) d τ = y ( 0 ) + ∫ 0 t v ( τ ) sin ( θ ( τ ) ) d τ = θ ( 0 ) + ∫ 0 t ω ( τ ) d τ
or
x ( t 2 ) = x ( t 1 ) + ∫ t 1 t 2 v ( t ) cos ( θ ( t ) ) d t y ( t 2 ) = y ( t 1 ) + ∫ t 1 t 2 v ( t ) sin ( θ ( t ) ) d t θ ( t 2 ) = θ ( t 1 ) + ∫ t 1 t 2 ω ( t ) d t \begin{aligned}
x(t_2) &= x(t_1) + \int_{t_1}^{t_2} v(t)\cos{\big(\theta(t)\big)}\,\mathrm{d}t \\
y(t_2) &= y(t_1) + \int_{t_1}^{t_2} v(t)\sin{\big(\theta(t)\big)}\,\mathrm{d}t \\
\theta(t_2) &= \theta(t_1) + \int_{t_1}^{t_2} \omega(t)\,\mathrm{d}t
\end{aligned} x ( t 2 ) y ( t 2 ) θ ( t 2 ) = x ( t 1 ) + ∫ t 1 t 2 v ( t ) cos ( θ ( t ) ) d t = y ( t 1 ) + ∫ t 1 t 2 v ( t ) sin ( θ ( t ) ) d t = θ ( t 1 ) + ∫ t 1 t 2 ω ( t ) d t
In practice, the equations can't be solved analytically since measurements can only be taken at distinct time points, we have to discretize the problem.
A differential equation can be numerically approximated by applying Euler's method
Consider the following differential equation where x x x represents the state of the system and u u u represents control inputs,
d x d t = f ( x , u ) \frac{\mathrm{d}x}{\mathrm{d}t} = f(x, u) d t d x = f ( x , u )
The first-order Taylor expansion is
x ( t + Δ t ) ≈ x ( t ) + f ( x , u ) Δ t x(t + \Delta t) \approx x(t) + f(x, u)\Delta t x ( t + Δ t ) ≈ x ( t ) + f ( x , u ) Δ t
If we choose Δ t \Delta t Δ t to be the sampling interval, then the time variable would be k Δ t k\Delta t k Δ t for integer values of k k k
x ( ( k + 1 ) Δ t ) ≈ x ( k Δ t ) + f ( x ( k Δ t ) , u ( k Δ t ) ) Δ t x\big((k+1)\Delta t\big) \approx x(k\Delta t) + f\big(x(k\Delta t), u(k\Delta t)\big)\Delta t x ( ( k + 1 ) Δ t ) ≈ x ( k Δ t ) + f ( x ( k Δ t ) , u ( k Δ t ) ) Δ t
To simplified the notation, denote t k ≡ k Δ t t_k \equiv k\Delta t t k ≡ k Δ t and x k ≡ x ( t k ) = x ( k Δ t ) x_k \equiv x(t_k) = x(k\Delta t) x k ≡ x ( t k ) = x ( k Δ t ) , we obtain the differene equation
x k + 1 = x k + f ( x k , u k ) Δ t x_{k+1} = x_k + f(x_k, u_k)\Delta t x k + 1 = x k + f ( x k , u k ) Δ t
If we apply the above result directly to the very first state equations, we get
x k + 1 = x k + v k cos ( θ k ) Δ t y k + 1 = y k + v k sin ( θ k ) Δ t θ k + 1 = θ k + ω k Δ t \begin{aligned}
x_{k+1} &= x_k + v_k \cos{(\theta_k)}\Delta t \\
y_{k+1} &= y_k + v_k \sin{(\theta_k)}\Delta t \\
\theta_{k+1} &= \theta_k + \omega_k \Delta t
\end{aligned} x k + 1 y k + 1 θ k + 1 = x k + v k cos ( θ k ) Δ t = y k + v k sin ( θ k ) Δ t = θ k + ω k Δ t
We can do better if we start from the integration equations, v v v and w w w are still assumed constants during sampling time but not θ \theta θ this time
θ ( t 2 ) = θ ( t 1 ) + ∫ t 1 t 2 ω ( t 1 ) d t = θ ( t 1 ) + ω ( t 1 ) ( t 2 − t 1 ) x ( t 2 ) = x ( t 1 ) + ∫ t 1 t 2 v ( t 1 ) cos ( θ ( t ) ) d t = x ( t 1 ) + v ( t 1 ) ∫ t 1 t 2 cos ( θ ( t 1 ) + ω ( t 1 ) ( t − t 1 ) ) d t = x ( t 1 ) + v ( t 1 ) ω ( t 1 ) sin ( θ ( t 1 ) + ω ( t 1 ) ( t − t 1 ) ) ∣ t 1 t 2 = x ( t 1 ) + v ( t 1 ) ω ( t 1 ) ( sin ( θ ( t 1 ) + ω ( t 1 ) ( t 2 − t 1 ) ) − sin ( θ ( t 1 ) ) ) y ( t 2 ) = y ( t 1 ) + ∫ t 1 t 2 v ( t 1 ) sin ( θ ( t ) ) d t = y ( t 1 ) − v ( t 1 ) ω ( t 1 ) ( cos ( θ ( t 1 ) + ω ( t 1 ) ( t 2 − t 1 ) ) − cos ( θ ( t 1 ) ) ) \begin{aligned}
\theta(t_2) &= \theta(t_1) + \int_{t_1}^{t_2} \omega(t_1)\,\mathrm{d}t = \theta(t_1) + \omega(t_1)(t_2 - t_1) \\[2ex]
x(t_2) &= x(t_1) + \int_{t_1}^{t_2} v(t_1)\cos{\big(\theta(t)\big)}\,\mathrm{d}t \\[2ex]
&= x(t_1) + v(t_1)\int_{t_1}^{t_2} \cos{\big(\theta(t_1) + \omega(t_1)(t - t_1)\big)}\,\mathrm{d}t \\[2ex]
&= x(t_1) + \frac{v(t_1)}{\omega(t_1)} \left.\sin{\big(\theta(t_1) + \omega(t_1)(t - t_1)\big)}\right|_{t_1}^{t_2} \\[2ex]
&= x(t_1) + \frac{v(t_1)}{\omega(t_1)} \Big(\sin{\big(\theta(t_1) + \omega(t_1)(t_2 - t_1)}\big) - \sin{\big(\theta(t_1)\big)}\Big) \\[2ex]
y(t_2) &= y(t_1) + \int_{t_1}^{t_2} v(t_1)\sin{\big(\theta(t)\big)}\,\mathrm{d}t \\[2ex]
&= y(t_1) - \frac{v(t_1)}{\omega(t_1)} \Big(\cos{\big(\theta(t_1) + \omega(t_1)(t_2 - t_1)}\big) - \cos{\big(\theta(t_1)\big)}\Big)
\end{aligned} θ ( t 2 ) x ( t 2 ) y ( t 2 ) = θ ( t 1 ) + ∫ t 1 t 2 ω ( t 1 ) d t = θ ( t 1 ) + ω ( t 1 ) ( t 2 − t 1 ) = x ( t 1 ) + ∫ t 1 t 2 v ( t 1 ) cos ( θ ( t ) ) d t = x ( t 1 ) + v ( t 1 ) ∫ t 1 t 2 cos ( θ ( t 1 ) + ω ( t 1 ) ( t − t 1 ) ) d t = x ( t 1 ) + ω ( t 1 ) v ( t 1 ) sin ( θ ( t 1 ) + ω ( t 1 ) ( t − t 1 ) ) t 1 t 2 = x ( t 1 ) + ω ( t 1 ) v ( t 1 ) ( sin ( θ ( t 1 ) + ω ( t 1 ) ( t 2 − t 1 ) ) − sin ( θ ( t 1 ) ) ) = y ( t 1 ) + ∫ t 1 t 2 v ( t 1 ) sin ( θ ( t ) ) d t = y ( t 1 ) − ω ( t 1 ) v ( t 1 ) ( cos ( θ ( t 1 ) + ω ( t 1 ) ( t 2 − t 1 ) ) − cos ( θ ( t 1 ) ) )
Now substitute t 1 t_1 t 1 with t k t_k t k , t 2 t_2 t 2 with t k + 1 t_{k+1} t k + 1 , we finally arrived with
x k + 1 = x k + v k ω k ( sin ( θ k + ω k Δ t ) − sin θ k ) y k + 1 = y k − v k ω k ( cos ( θ k + ω k Δ t ) − cos θ k ) θ k + 1 = θ k + ω k Δ t \begin{aligned}
x_{k+1} &= x_k + \frac{v_k}{\omega_k} \big(\sin{(\theta_k + \omega_k \Delta t}) - \sin{\theta_k}\big) \\
y_{k+1} &= y_k - \frac{v_k}{\omega_k} \big(\cos{(\theta_k + \omega_k \Delta t}) - \cos{\theta_k}\big) \\
\theta_{k+1} &= \theta_k + \omega_k \Delta t
\end{aligned} x k + 1 y k + 1 θ k + 1 = x k + ω k v k ( sin ( θ k + ω k Δ t ) − sin θ k ) = y k − ω k v k ( cos ( θ k + ω k Δ t ) − cos θ k ) = θ k + ω k Δ t
There is another way to view the problem, since the position of I C C = ( x − R sin θ , y + R cos θ ) \mathrm{ICC} = (x - R\sin{\theta}, y + R\cos{\theta}) ICC = ( x − R sin θ , y + R cos θ )
ICC R θ ωΔt θ θ + ωΔt
We have
[ x k − R sin θ k y k + R cos θ k ] = [ x k + 1 − R sin ( θ k + ω k Δ t ) y k + 1 + R cos ( θ k + ω k Δ t ) ] \begin{bmatrix}
x_k - R\sin{\theta_k} \\[1ex]
y_k + R\cos{\theta_k}
\end{bmatrix}
=
\begin{bmatrix}
x_{k+1} - R\sin{(\theta_k + \omega_k \Delta t)} \\[1ex]
y_{k+1} + R\cos{(\theta_k + \omega_k \Delta t)}
\end{bmatrix} [ x k − R sin θ k y k + R cos θ k ] = [ x k + 1 − R sin ( θ k + ω k Δ t ) y k + 1 + R cos ( θ k + ω k Δ t ) ]
hence
x k + 1 = x k + R ( sin ( θ k + ω k Δ t ) − sin θ k ) y k + 1 = y k − R ( cos ( θ k + ω k Δ t ) − cos θ k ) \begin{aligned}
x_{k+1} &= x_k + R \big(\sin{(\theta_k + \omega_k \Delta t}) - \sin{\theta_k}\big) \\
y_{k+1} &= y_k - R \big(\cos{(\theta_k + \omega_k \Delta t}) - \cos{\theta_k}\big)
\end{aligned} x k + 1 y k + 1 = x k + R ( sin ( θ k + ω k Δ t ) − sin θ k ) = y k − R ( cos ( θ k + ω k Δ t ) − cos θ k )
substitute R = v k ω k R = \frac{v_k}{\omega_k} R = ω k v k gives the same result
Most wheel encoders provide us with the tick counts information, the tick might be a change in magnetic field for hall effect encoders or a signal received from photodetector for optical encoders, assume each wheel has N N N ticks per revolution, the wheel angular velocity is
ϕ = 2 π Δ t i c k N \phi = 2\pi \frac{\Delta \mathrm{tick}}{N} ϕ = 2 π N Δ tick
Recall the relationship between unicycle model and differential drive model
{ v = v R + v L 2 = r 2 ( ϕ R + ϕ L ) ω = v R − v L L = r L ( ϕ R − ϕ L ) \begin{cases}
\begin{aligned}
v &= \frac{v_R + v_L}{2} = \frac{r}{2}(\phi_R + \phi_L) \\[2ex]
\omega &= \frac{v_R - v_L}{L} = \frac{r}{L}(\phi_R - \phi_L)
\end{aligned}
\end{cases} ⎩ ⎨ ⎧ v ω = 2 v R + v L = 2 r ( ϕ R + ϕ L ) = L v R − v L = L r ( ϕ R − ϕ L )
Now we know how to turn wheel encoder measurments to robot movements
Finally here's a real world implementation taken from gazebo diff drive plugin
gazebo_ros_pkgs/gazebo_plugins/src/gazebo_ros_diff_drive.cpp
void GazeboRosDiffDrive :: UpdateOdometryEncoder ()
double vl = joints_ [ LEFT ]-> GetVelocity ( 0 );
double vr = joints_ [ RIGHT ]-> GetVelocity ( 0 );
#if GAZEBO_MAJOR_VERSION >= 8
common :: Time current_time = parent -> GetWorld ()-> SimTime ();
common :: Time current_time = parent -> GetWorld ()-> GetSimTime ();
double seconds_since_last_update = ( current_time - last_odom_update_ ). Double ();
last_odom_update_ = current_time ;
double b = wheel_separation_ ;
// Book: Sigwart 2011 Autonompus Mobile Robots page:337
double sl = vl * ( wheel_diameter_ / 2.0 ) * seconds_since_last_update ;
double sr = vr * ( wheel_diameter_ / 2.0 ) * seconds_since_last_update ;
double dx = ( ssum ) / 2.0 * cos ( pose_encoder_ . theta + ( sdiff ) / ( 2.0 * b ) );
double dy = ( ssum ) / 2.0 * sin ( pose_encoder_ . theta + ( sdiff ) / ( 2.0 * b ) );
double dtheta = ( sdiff ) / b ;
pose_encoder_ . theta += dtheta ;
double w = dtheta / seconds_since_last_update ;
double v = sqrt ( dx * dx + dy * dy ) / seconds_since_last_update ;
Most of the lines are direct translations from equations, the only different part are highlighted,
Δ x = v L + v R 2 Δ t cos ( θ + v R − v L 2 L ) = v cos ( θ + ω 2 ) Δ t Δ y = v sin ( θ + ω 2 ) Δ t \begin{aligned}
\Delta x &= \frac{v_L + v_R}{2}\Delta t \cos{(\theta + \frac{v_R - v_L}{2 L})} = v \cos{(\theta + \frac{\omega}{2})} \Delta t \\[2ex]
\Delta y &= v \sin{(\theta + \frac{\omega}{2})} \Delta t
\end{aligned} Δ x Δ y = 2 v L + v R Δ t cos ( θ + 2 L v R − v L ) = v cos ( θ + 2 ω ) Δ t = v sin ( θ + 2 ω ) Δ t
They are very close to the result of our first attempt,
x k + 1 = x k + v k cos ( θ k ) Δ t y k + 1 = y k + v k sin ( θ k ) Δ t \begin{aligned}
x_{k+1} &= x_k + v_k \cos{(\theta_k)}\Delta t \\
y_{k+1} &= y_k + v_k \sin{(\theta_k)}\Delta t \\
\end{aligned} x k + 1 y k + 1 = x k + v k cos ( θ k ) Δ t = y k + v k sin ( θ k ) Δ t
It seems they use the trapezoidal rule for approximation.