Normal and tangential coordinates¶
In the normal and tangential coordinate system, the (vector) equation of motion
decomposes into the three scalar equations for the tangential (\(t\)), normal (\(n\)), and binormal (\(b\)) directons:
where \(F_i\) is a force in the \(i\) direction, \(m\) is the particle mass, \(v\) is the velocity, and \(\rho\) is the radius of curvature.
The tangential acceleration \(a_t\) is positive or negative in the direction of motion, the normal acceleration \(a_n\) is always positive in the normal direction, and the binormal acceleration \(a_b\) is always zero, because motion lies in the plane formed by the normal and tangential directions.
Example: race car at banking angle (no friction)¶
A Formula 1 race car of mass \(m\) = 740 kg is traveling on a track at constant velocity \(v\) = 60 m/s, where the radius of curvature is \(\rho\) = 400 m. What is the banking angle \(\theta\) necessary for the car to avoid sliding as it goes around this curve?
First, let’s draw a free-body diagram for the car:
Now, write the three scalar equations of motion for the car. The equation in the tangential direction does not really tell us much, since the car is moving at a constant speed in its direction of motion:
In the normal direction, the only force is the normal component of the resultant force:
and in the binormal direction, we have both the component of the resultant force and also the car’s weight, but the binormal acceleration is zero:
If we divide the latter equation from the former, we can solve for the banking angle:
For the parameters given:
import numpy as np
mass = 740 # kg
velocity = 60 # m/s
rho = 400 # m
g = 9.81 # m/s^2
theta = np.arctan(velocity**2 / (rho * g))
print(f'theta ={theta * 180/np.pi: .2f}°')
theta = 42.53°
Example: race car at banking angle (with friction)¶
Now, consider the same situation, but account for the effect of friction, which will counter the car’s motion in the outward direction. What is the new banking angle needed to avoid the car sliding in this case? Assume the coefficient of static friction is \(\mu_s = 0.2\).
mu = 0.2
In this case, we now have to account for components of the friction force in the normal and binormal directions, where the friction force is
In the normal direction, we have
and in the binormal direction
Combining the two equations (again, by dividing the first by the second) and recalling that \(f = \mu_s N_c\):
This is our equation to find the banking angle, but unfortunately it has no closed-form solution. So, how do we find \(\theta\)? Using a numerical method!
Method 1: manual iteration¶
We could first attack this problem by manually guessing and checking different values of \(\theta\), until the left-hand side of the equation equals the right-hand side. For example, trying different values from 20° to 40°:
# need to convert to radians
vals = np.arange(20, 41, 2) * np.pi / 180
print('Theta LHS RHS')
for theta in vals:
lhs = (np.sin(theta) + mu*np.cos(theta)) / (np.cos(theta) - mu*np.sin(theta))
rhs = velocity**2 / (rho*g)
print(f'{theta*180/np.pi: 4.1f}° {lhs: 5.3f} {rhs: 5.3f}')
Theta LHS RHS
20.0° 0.608 0.917
22.0° 0.657 0.917
24.0° 0.708 0.917
26.0° 0.762 0.917
28.0° 0.819 0.917
30.0° 0.879 0.917
32.0° 0.943 0.917
34.0° 1.011 0.917
36.0° 1.084 0.917
38.0° 1.163 0.917
40.0° 1.249 0.917
So, clearly the correct value is between 30° and 32°. A bit more manual iteration shows that the correct angle is just about 31.2°:
theta = 31.2 * np.pi / 180
lhs = (np.sin(theta) + mu*np.cos(theta)) / (np.cos(theta) - mu*np.sin(theta))
rhs = velocity**2 / (rho*g)
print(lhs, rhs)
0.9166501382856723 0.9174311926605505
Method 2: root_scalar
¶
Manually solving like this would be quite tedious; fortunately, there are numerical methods for solving scalar equations like this. We refer to this at root finding, since to solve we formulate the equation like \(F(x) = 0\), and find the value of the unknown variable that makes the function zero (i.e., the root).
In this case, we make the equation into the form
Then, to solve, we can use the root_scalar
function provided in the scipy.optimize
module,
which needs us to provide it with a function that returns \(F(\theta)\) for candidate values of \(\theta\) (with the goal of finding the one that makes \(F(\theta)=0\)), along with a few guess values:
from scipy.optimize import root_scalar
def f(theta):
'''This function evaluates the equation for finding theta.
'''
return (
(np.sin(theta) + mu*np.cos(theta)) / (np.cos(theta) - mu*np.sin(theta)) -
velocity**2 / (rho*g)
)
sol = root_scalar(f, x0=(20*np.pi/180), x1=(40*np.pi/180))
print(f'theta ={sol.root * 180/np.pi: .2f}°')
theta = 31.22°