NOTE: I use the prefix "vec" to mark that a variable is a vector. For example, vecV would be a vector and V would be its modulus.

First, we define the path we want the centre of the vehicle to follow. I chose tho define it in polar coordinates because it was handy to describe a spiral.

/home/adria/Desktop/coords.png

The coordinates of the centre of the vehicle, P, can be obtained by turning the polar form into cartesian:

vecP:r(t)*matrix([cos(phi(t))],[sin(phi(t))]);

We can obtain the speed vector, VP, by differentiating against time:

vecVP:diff(vecP,t);

eq0:VP=trigsimp(ratsimp(sqrt(vecVP[1][1]^2+vecVP[2][1]^2)));

Let's keep this aside and deal with the vehicle now. The vehicle has two wheels, the direction of the axes of the wheels are fixed to the chassis. If the wheels don't slide, their centres can only move perpendicular to their axes. The only way for the vehicle to maneuvre is to have the wheels spin at different speeds. Different combinations of wheel speeds give different linear and rotational speeds of the vehicle.

/home/adria/Desktop/vehicle.png

 The speed of the centre of the vehicle, G: middle point between the wheels, can be written as:

eq1:VG=(VL+VR)/2;

where VR and VL are the speeds of the centre of the right wheel and the left wheel respectively.

The rotational speed of the vehicle can be written as:

eq2:diff(theta(t),t)=(VR-VL)/d;

where d is the distance between the wheels.

The vector of the speed of the centre of the vehicle is:

vecVG:VG*matrix([cos(theta)],[sin(theta)]);

We want to solve the "inverse kinematics problem", that is: we want to find out how do we have to turn the wheels in order to follow the desired path. The "mechanism" we are analysing is non-holonomous, which makes it impossible to find a formula that gives the angle of the wheels as a function of the desired position. However, we can obtain a formula that tells us the speed of the wheels we need as a function of the speed of the vehicle. This can be done be equating VP and VG and solving for the speeds. The equations involve trigonometric functions, which normally makes this process quite painful.

Before equations vecVP and vecVG, it is useful to apply a rotation to these vectors (we change their reference frame to a new one). The rotation matrix is defined as:

R(theta):=matrix([cos(theta),sin(theta)],[-sin(theta),cos(theta)]);

I will call the new vectors "prima" with the suffix "p":

vecVGp:R(theta).vecVG;

This can be further simplified:

vecVGp:trigsimp(vecVGp);

vecVPp:R(theta).vecVP;

If we equate the second component, "y", of VGp and VPp, we obtain the tangent of theta as a function of the polar coordinates of the desired path and their first derivatives:

eq3:vecVGp[2][1]=vecVPp[2][1];

The tangent can be obtained by solving for cos(theta)/sin(theta) in the previous equation.

tempsin:coeff(rhs(eq3),cos(theta),1);

tempcos:-coeff(rhs(eq3),sin(theta),1);

tan(theta) would be tempsin/tempcos but rather than solving for the tangent, it is more useful for us to find the sine and the cosine themselves.

tempsincos:trigreduce(ratsimp(sqrt(tempsin^2+tempcos^2)));

sol_sin_theta:tempsin/tempsincos;

sol_cos_theta:tempcos/tempsincos;

We could now obtain the derivative of the angle by doing sqrt((d/dt sin(theta))^2+(d/dt cos(theta))^2). This leads to a long equation:

trigsimp(ratsimp(sqrt(diff(sol_sin_theta,t)^2+diff(sol_cos_theta,t)^2)));

I must confess I became lazy at this point and instead of using this expression in my script, I decided to calculate the derivative numerically by first obtaining the angle doing the arctangent from the sine and the cosine.

Going back to the inverse kinematics, once we know the speed of the centre of the vehicle (VG=VP) and the rotational speed of the vehicle (d/dt theta), we can obtain the speed of the centre of each wheel from equations eq1 and eq2:

expand(solve([eq1,eq2],[VR,VL]));

Once we know the speed of the centre of the wheel, we can obtain the rotational speed of each wheel by dividing this by the radius of the wheel:

eq4:omega_r=VR/R_wheel;

eq5:omega_l=VL/R_wheel;