Loading...

The Inverted Pendulum - Part 1

An inverted pendulum is simply a pendulum which has its centre of mass above its pivet point. The dynamic stabilisation of the inverted pendulum is a classic problem in control theory and is used to benchmark control strategies (see PID Tutorial). The T-Bot is an example of an inverted pendulum, as is SpaceX's reusable launch system.

Space X Falcon 9 and T-Bot Inverted Pendulum.

You might imagine, if you stabilise an inverted pendulum well enough it should stay balanced if undisturbed (maybe not in the case of a rocket!). You can test that theory using your T-Bot, a stop watch and the python code below.

Turn the T-Bot off and balance it as well as you can. Start the clock as soon as you let go. Stop it when you hear a thud. Alternatively, you can video the T-Bot falling, and use Camera Stopwatch Lite to measure the falling time. You can run the Python code below and use the fallingtime() function to work out what your starting displacement was.

The Inverted Pendulum

Where α is the angular acceleration, ω is the angular velocity and θ is the angle of the inverted pendulum with respect to the vertical axis and 𝑙 is the length of the inverted pendulum.

PID Plot

Import numpy and pyplot.

import numpy as np
import matplotlib.pyplot as plt
plt.ion()

Setup the functions.

################     Functions    ####################

def fallingtime(l,g,theta,theta2,dt):
	'''
	Calculates angular acceleration, angular velocity, velocity,
	and falling time for an inverted pendulum between two angles(in degrees)
	for a given length. Usage fallingtime(l,g,theta,theta2,dt)
	Returns angular acceleration, angular velocity, velocity, time.'''
	theta = theta*np.pi/180
	theta2 = theta2*np.pi/180
	omega = 0
	t=0
	while theta < theta2:
        # angular acceleration
		alpha =  np.sin(theta)*g/l
        # integrate angular acceleration to get angular velocity
		omega += alpha*dt
        # integrate angular velocity to get angle
		theta += omega*dt 
		# integrate dt to get time
		t += dt

    # return angular acceleration, angular velocity, velocity, time
	return(alpha,omega,l*omega,t)      

def v(l,g,theta):
    if theta != 0:
        return np.sqrt(2*g*(l-l*np.cos(theta*np.pi/180)))*theta/np.abs(theta)
    else:
        return 0.0


def falling(l,g,theta,theta2,dt):
	'''
	Calculates angular acceleration, angular velocity, velocity, and falling
	time for an inverted pendulum between two angles(in degrees) for a given
	length. Usage fallingtime(l,g,theta,theta2,dt) Returns angular acceleration,
	angular velocity, velocity, theta, and time up to each step in an array'''
       
	alpha_omega_v = np.array([[]]*5).T
	theta = theta*np.pi/180
	theta2 = theta2*np.pi/180
	omega = 0
	t=0
	while theta < theta2:
        # angular acceleration
		alpha =  np.sin(theta)*g/l
        # integrate angular acceleration to get angular velocity
		omega += alpha*dt 
        # integrate angular velocity to get angle
		theta += omega*dt 
        # integrate dt to get time
		t += dt                         
		alpha_omega_v = np.vstack((alpha_omega_v,[alpha, omega, omega*l,theta*180/np.pi,t]))                     
	return(alpha_omega_v)       # angular acceleration, angular velocity, velocity, time


def v(l,g,theta):
    if theta != 0:
        return np.sqrt(2*g*(l-l*np.cos(theta*np.pi/180)))*theta/np.abs(theta)
    else:
        return 0.0

Create the Data.

   
xdata = list(np.linspace(1.E-11, 50.e-7, 500))+list(np.linspace(60.E-7, 15.e-5,500))
ydata_earth = [fallingtime(0.08, g_earth,np.arcsin(x/8e-2)*180/np.pi, 90, 0.001)[3] for x in xdata]
ydata_moon = [fallingtime(0.08, g_moon,np.arcsin(x/8e-2)*180/np.pi, 90, 0.001)[3] for x in xdata]



Finally, plot the data!



plt.figure(figsize=(10, 4))

plt.title('Inverted Pendulum')
plt.plot(xdata, ydata_moon, c=(50/255.,50/255.,250/255.),linewidth = 2, label = 'Moon g = '+str(g_moon)+' ms^2')
plt.plot(xdata, ydata_earth,  c=(255/255.,10/255.,10/255.),linewidth = 2, label = 'Earth g = '+str(g_earth)+' ms^2')

plt.fill_between(xdata, 0, ydata_earth,facecolor=(100/255.,0/255.,0/255.),edgecolor=(191/255.,211/255.,255/255.), alpha = 0.6)
plt.fill_between(xdata, 0, ydata_moon,facecolor=(0/255.,0/255.,100/255.),edgecolor=(191/255.,211/255.,255/255.), alpha = 0.6)

plt.annotate('Atomic vibrational amplitude (10 pm)\nFalling time 2.17 s',xy=(1.E-11,2.16),xytext = (1.e-5,5), arrowprops = dict(facecolor=(0/255.,255/255.,63/255.),width=1,headwidth=7,shrink=0.01),)

plt.annotate('Width of H atom (100 pm)\nFalling time 1.96 s',xy=(1.E-10,2),xytext = (1.e-5,2.5), arrowprops = dict(facecolor='white',width=1,headwidth=7,shrink=0.01),)

plt.annotate('Average width of human hair (100 microns)\nFalling time 0.712 s',xy=(100.E-6,0.712),xytext = (60.e-6,3), arrowprops = dict(facecolor='orange',width=1,headwidth=7,shrink=0.01),)

plt.legend(loc = 'best',prop={ 'size': 8})
plt.xlabel('Initial horizontal displacement (m)')
plt.ylabel('Falling Time (s)')
#plt.axis('tight')
plt.xlim((xdata[0]-xdata[100]),(xdata[-1]+xdata[100]))
plt.subplots_adjust(bottom=0.15)
plt.savefig('Falling.svg')