• Observer and feedback controller design for rear wheel speed control.

  • Design notes:

    • US Digital optical encoder has 50 CPR of encoder shaft.
    • 100:25 wheel to encoder gearing implies 200 CPR of wheel.
    • Detecting rising and falling edges of A or B channels results in 400 CPR of wheel (half quadrature).
    • Detecting rising and falling edges of A and B channels results in 800 CPR (full quadrature).
    • Wheel angle measurement uses full quadrature. One timer count represents 2*pi/800 radians
    • Wheel speed measurement uses half quadrature. One cycle between a rising and falling edge represents 2*pi/400 radians.
    • Encoder rising and falling edges occur asynchronously from main control loop.
    • Absolute position of wheel is generally not of interest.
    • Speed of wheel is of primary interest because bicycle dynamics are dependent upon speed.

In [13]:
from sympy import symbols, Poly
import numpy as np

c, J, kT, T, s, w, x, z, I = symbols('c J kT T s w x z I')
#bilinear_transform = {s : 2/T*(z-1)/(z+1)}
forward_difference_transform = {s : (z-1)/T}

# Continuous time transfer function from I(s) to w(s) of the following plant
# model:
#   dw/dt = -c/J*w + kT/J*I
G_s = kT/J/(s + c/J)

G_z_num, G_z_den = G_s.subs(forward_difference_transform).as_numer_denom()
G_z_den = Poly(G_z_den, z)

G_z_num = Poly(G_z_num / G_z_den.LC(), z) # divide by leading coefficient of den
G_z_den = G_z_den.monic()                 # make denominator monic
assert(G_z_den.coeffs()[0] == 1)
print(G_z_num)
print(G_z_den)
print(G_z_num / G_z_den)

A = - G_z_den.coeffs()[1]
B = G_z_num.coeffs()[0]
C = 1


Poly(T*kT/J, z, domain='ZZ(J,T,kT)')
Poly(z + (-J + T*c)/J, z, domain='ZZ(c,J,T)')
T*kT/(J*(z + (-J + T*c)/J))

In [14]:
for n, m in [('A', A), ('B', B), ('C', C)]: print(n + " = " + str(m))


A = -(-J + T*c)/J
B = T*kT/J
C = 1

In [2]: