Gantry Crane

Simulation in Sympy


Projects Blog Articles All About


Let’s say you have a simple gantry crane with the circle indicating the controllable hoist, Figure (a). You want move the payload, W, from the starting position to the final position f. You could push the forward button for the hoist until the payload arrives at f, but when you get there the payload would be swinging. This is highly undesirable. An uncontrolled swinging payload is the last thing a crane operator wants. Dr. Smith’s idea is to break up the command into two commands. The first command would move the hoist to position m, Figure (b). As the payload swings due to the motion, the hoist pauses until“…one-half cycle of the natural transient period of the pendulum.” —Dr. Smith the payload reaches the final position. The second command will move the hoist quickly to the final position and the payload will experience little to zero sway. This concept is very simple in theory, but very powerful in controlling unwanted motion. Lets dig into the concept a little more and see how this idea became Input Shaping. Let’s begin by replicating the gantry crane model in Sympy:

Gantry Crane with Controllable Hoist

cartpen

from sympy import symbols, init_printing
import sympy
import sympy.physics.mechanics as me
from pydy.system import System
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
init_printing()

Let’s assign some arbitrary variables.

Length = 0.5 #meters
payload = 0.01 #kg
hoist = 1.0 #kg
# Create the Main Frame
A = me.ReferenceFrame('A')

# Create the symbols
x, y, theta, f = me.dynamicsymbols('x y theta f')
x_dot, y_dot, theta_dot = me.dynamicsymbols('x_dot y_dot theta_dot')

M, m, g, t = sympy.symbols('M m g t')
L1 = sympy.symbols('L1')

# Orient the other frames
B = A.orientnew('B', 'Axis', [theta, A.z])

# Create the Origin
Origin = me.Point('Origin')
Origin.set_pos(Origin, 0)
Origin.set_vel(A, 0)

# Create the hoist and payload points
P0 = me.Point('P0')
P1 = me.Point('P1')

# Set the hoist and payload positions
P0.set_pos(Origin, x * A.x)
P1.set_pos(P0, -L1 * B.y)
P0.set_vel(A, x_dot * A.x)
P1.v2pt_theory(P0, A, B)

I am not describing the hoist with a vertical dimension. It will only move in the X directions. The speed of the payload in Frame A: \[ x_{dot}\mathbf{\hat{a}_x} + L_{1} \dot{\theta}\mathbf{\hat{b}_x} \]

# Set up the kinematic differential equations
kde = [x_dot - x.diff(t),
       theta_dot - theta.diff(t)]

# Create the Particles
Pa0 = me.Particle('Pa0', P0, M)
Pa1 = me.Particle('Pa1', P1, m)
payload_gravity = (P1, -m * g * A.y)
payload_normal = (P1, m * g * B.y)
payload_on_hoist = (P0, -m * g * B.y)

forcing = (P0, f * A.x)

loads = [payload_gravity,
         payload_normal,
         payload_on_hoist,
         forcing]

This is how we will control the crane. This is a force (impulse) in Newtons that is applied to the hoist. The hoist has no friction so we need to apply a force in the opposite direction to stop it. The function allows us to specify the impulse amplitudes, the times applied, and the duration for each (although they need to be the same duration). Just to demonstrate what the force looks like, I’ll plot bang([5,-5],[1,3],1, sim_time).

def bang(Amps, Times, Interval, t):
    '''
    This function will issue impulses at the times given
    '''
    n = np.size(Amps)
    F = []
    for i in range(n):
        Fi = Amps[i]
        Ti = Times[i]
        fi = Fi * (t >= Ti) * (t <= Ti + Interval)
        F.append(fi)
    f = sum(F)
    return f

plt.plot(sim_time,bang([5,-5],[1,3],1, sim_time))
Impulse Plotting

bang

# Setting up the coordinates, speeds, and creating KanesMethod
coordinates = [x, theta]
speeds = [x_dot, theta_dot]
kane = me.KanesMethod(A, coordinates, speeds, kde)

# Creating Fr and Fr_star
fr, frstar = kane.kanes_equations([Pa0, Pa1], loads)

# Creating the PyDy System
sys = System(kane)

At first, we can tilt the payload and let it freely swing. Because there is no rotational damping crane’s oscillations will continue forever. Let’s run the simulation and look at the crane response.

# Assigning all the constants
runtime = 15

sys.constants = {m: payload,
                 M: hoist,
                 g: 9.81,
                 L1: Length}
sys.initial_conditions = {x:0, theta:0.78}
sys.specifieds={f:lambda y, t:bang([5,-5],[1,3],1, t)}

sys.times = np.linspace(0.0, runtime, runtime*30)
sys.generate_ode_function(generator='cython')
sim_time = np.linspace(0.0, runtime, runtime*30)
resp = sys.integrate()

The pendulum response will have a period very close to a simple pendulum. However, because the hoist can move—the pendulum’s motion will be influenced by the hoist. This is called a Multiple Degree of Freedom System. For a simple pendulum with a length of 0.5m, the natural frequency is \(\omega = \sqrt{\frac{gravity}{length}} \)Rad/s or 0.705Hz.

zeros = sim_time[np.argwhere(np.isclose(resp[:,1], 0, atol=0.1))]
x_resp = resp[:,0]
theta_resp = resp[:,1]
fig, ax = plt.subplots()

ax.scatter(zeros, np.zeros_like(zeros))
plt.plot(sim_time, np.rad2deg(resp[:,1]), label='Unshaped')
plt.xlabel(r'Time (s)')
plt.ylabel(r'Angle (deg)')
Payload Response and Zeros

payloadandzeros

On the plot, the dots are plotted when the angle is zero. With these zeros we can calculate the period. The first dot occurs at 0.367s. A full period later, on the third dot, the time is 1.837s. This makes the period 1.47s or 0.68Hz. This is very close to our expected frequency of 0.7Hz. However, because of the dynamic coupling the payload will never exactly match a simple pendulum. Now, let’s rerun the simulation with the payload at rest, but let’s hit the hoist with our previous bang function. Below is the response of the hoist to the input we gave.

Hoist Response

hoistresponse

It is interesting to see the displacement curve form through the mathematics we outlined when creating the model. There are essentially 5 sections to this curve. Initially, the hoist is at rest at 0 distance. At 1s the force is applied and the distance increases with a slight curve—this indicates a constant acceleration, a linear increase in velocity, and a quadratic increase in displacement. At 2s, the force is stopped and the hoist continues at a constant velocity. At 3s, a force in the opposite direction is given and the hoist decelerates before finally resting at 10m.

Payload Response

payloadresponse

The payload response is shown with the same colored sections. The payload is clearly affected by the gantry’s motion. After the gantry has stopped moving at 4s, the payload swings freely at almost 60deg off center. This is obviously unacceptable. A payload swinging freely like this would be an extreme hazard to anyone near the crane not to mention damaging to the crane itself. We will not be attempting to control the motion of the payload during the commands. The command shaping technique we are using is only concerned with the motion at the end of the commands. For this example, we want to stop the oscillation after t = 5s. What happens between t = 1 and t = 5 does not concern this technique.

After t =5s, the payload response is that of an undamped second-order system. Second-order systems are very well known and their responses have similar characteristics. In fact, we can generalize the payload response into a broad “second-order system” response. We can then use this information to make instructions on how to alter our bang command to stop the payload oscillations.

Payload Animation Response

payloadaniresponse

… to be continued

Created: 10 Apr 2020