Bicycle Balance Control Simulation


The model presented here is based on the model described here:

https://plot.ly/ipython-notebooks/bicycle-control-design/

eval_bicycle_rhs

The file eval_bicycle_rhs.m encodes the 1st order ordinary differential equations that govern the steer-roll dynamics of a bicycle. The steer and steer rate inputs are set to constants.

function xdot = eval_bicycle_rhs(t, x, r, p)

% unpack states
omega = x(1);
theta = x(2);
psi = x(3);

% unpack inputs
beta = r(1); % steer rate
delta = r(2); % steer angle

% unpack parameters
m = p(1);
g = p(2);
h = p(3);
a = p(4);
b = p(5);
v = p(6);
I = p(7);

% calculate the state derivatives
omegadot = (m*g*h*theta - m*h/b*(a*v*beta + v^2*delta))/(I + m*h^2);
thetadot = omega;
psidot = v/b*tan(delta);

% pack up the results
xdot = [omegadot; thetadot; psidot];

end

eval_bicycle_rhs2

The file eval_bicycle_rhs2.m encodes the 1st order ordinary differential equations that govern the steer-roll dynamics of a bicycle. The steer and steer rate inputs are calculated by an input function.

function xdot = eval_bicycle_rhs2(t, x, w, p)

% unpack states
omega = x(1);
theta = x(2);
psi = x(3);

% calculate r with the passed in function w(t, x, p)
r = w(t, x, p);

% unpack inputs
beta = r(1); % steer rate
delta = r(2); % steer angle

% unpack parameters
m = p(1);
g = p(2);
h = p(3);
a = p(4);
b = p(5);
v = p(6);
I = p(7);

% calculate the state derivatives
omegadot = (m*g*h*theta - m*h/b*(a*v*beta + v^2*delta))/(I + m*h^2);
thetadot = omega;
psidot = v/b*tan(delta);

% pack up the results
xdot = [omegadot; thetadot; psidot];

end

eval_steer_control_input.m

The file eval_steer_control_input.m encodes a PD controller that generates the steer and steer rate inputs.

function r = eval_steer_control_input(t, x, p)

% unpack the states
omega = x(1);
theta = x(2);

% unpack the control gains
kp = p(8);
kd = p(9);

% calculate the inputs
beta = kp*omega;
delta = kp*theta + kd*omega;

% pack up the inputs
r = [beta; delta];

end

bicycle_main.m

The file bicycle_main.m runs the simulation with the constant inputs and the inputs from the controller.

% this is the simulation we did in class of the bicycle balance model
x0 = [0; 0; 0];  % one initial condition for each state
ts = linspace(0, 4, 200);  % time values
r = [0; 5*pi/180];  % using constant values for the inputs
p = [87; 9.81; 1.0; 0.5; 1.0; 5.0; 3.28];  % pick numbers for parameters
eval_bicycle_rhs_anon = @(t, x) eval_bicycle_rhs(t, x, r, p);
[ts, xs] = ode45(eval_bicycle_rhs_anon, ts, x0);
figure(1)
plot(ts, xs*180/pi)
xlabel('Time [s]')
legend('\omega [deg/s]', '\theta [deg]', '\psi [deg]')

% this is a second simulation of the same model but it has an input function
x0 = [0; 5*pi/180; 0];
% add two more parameters for the control input (PD controller)
p(8) = 2.5; # proportional gain
p(9) = 0.5;  # derivative gain
eval_bicycle_rhs_anon2 = ...
    @(t, x) eval_bicycle_rhs2(t, x, @eval_steer_control_input, p);
[ts, xs] = ode45(eval_bicycle_rhs_anon2, ts, x0);
figure(2)
plot(ts, xs*180/pi)
xlabel('Time [s]')
legend('\omega [deg/s]', '\theta [deg]', '\psi [deg]')