Bowling

Activity Information

Learning Goals

  • Interpret, edit, and add to the code of a computational model of a bowling ball
  • Apply the momentum principle to an object in motion
  • Apply the principles of rotational kinematics to an object in motion
  • Use mathematical representations to support the claim that the total momentum of a system of objects is conserved when there is no net force on the system (HS-PS2-2)

Prior Knowledge Required

  • Vectors
  • Momentum Principle
  • Kinematics (linear and rotational)

Code Manipulation

  • Create code from mathematical equations
  • Copy / Paste code
  • Create if / else statements

Activity

Handout – Bowling

Your team at Bowl & Co. (a very real and not made up company) has been tasked with finishing a bowling simulation stolen from your rival Bowl Bros Ltd. (another very real company).

The stolen code can be found here. (click remix to save your own version)

The blue region of the lane is frictionless, but the wooden section has a coefficient of kinetic friction of 0.2 with the bowling ball.

Your code should realistically show the motion of the ball through its movement on the lane. It should start out with no rotation and start to turn once it is on the wooden surface. Remember, if the tangential rotational velocity is the same as the translational velocity, there will no longer be friction.

This link might be helpful for getting the ball to rotate.

Your code should also create two graphs, one of the linear and angular velocities of the ball vs time, and one of the translational, rotational, and total energies of the ball vs time.

Code

Link

GlowScript 3.0 VPython
#setting the scene - these can be changed as necessary for your screen size
scene.width = 1200
scene.height = 800
scene.range = 2                 #set the scale of the view - smaller number zoom in, bigger numbers zoom out

#define some variables
r = 0.10                        #radius of ball in meters
m1 = 7                          #mass of ball in kg
v1 = -10                        #initial horizontal velocity of ball
d = 4                           #horizontal position of ball at the start in meters
s = 7                           #half-length of friction portion of lane
g = 10                          #gravitational field strength - N/kg
t = 0                           #initialize value for time in seconds
dt = 0.001                      #value of the time-step in seconds
rte = 400                       #value for the "rate" in the loops
muk = 0.2                       #coeffiecient of kinetic friction
alpha = (5*muk*g/(2*r))         #angular acceleration of ball (moment of inertia for solid sphere - 2/5mr***2)
Ffric = m1 * g * muk            #frictional force on ball
rotvel = 0                      #initialize the rotational velocity of ball


#create some objects
ground1 = box(pos = vec(d/2,-r/4,0), size = vec(d,r/2,d/4), color = vec(0,0,4), texture = textures.wood)        #create the lane for the ball to slide on without friction
ground2 = box(pos = vec(-s,-r/4,0), size = vec(2 * s,r/2,d/4), texture = textures.wood)                         #create the lane for the ball to slide with friction
ball = sphere(pos = vec(d,r,0), radius = r, mass = m1, velocity = vec(v1,0,0), texture=textures.gravel)        #create ball with a texture to be able so see the rotation
scene.camera.follow(ball)                                                                                      #have the camera follow the ball


# define graph of motion
grph = graph(title='Velocity vs Time', xtitle='Time (s)', ytitle='Velocity')            #create graph
velgraph = gcurve(color=color.red,  width = 5, label='Linear Velocity (m/s)')           #define the curve for linear velocity
rotgraph = gcurve(color=color.blue,   width = 5, label='Angular Velocity (rad/s)')      #define the curve for angular velocity

#calculate the momentum of the ball
ball.p = ball.mass * ball.velocity                                      #initial momentum of ball


#get loopy to make things happen!
while ball.pos.x >= -(2 * s) + r:                                       #do this loop while the ball is on the lane
    rate(rte)                                                           #set the rate
    ball.pos = ball.pos + (ball.p/ball.mass) * dt                       #calculate the position of ball based on its momentum and the time increment

    velgraph.plot(t, -mag(ball.p/ball.mass))                            #graph of linear velocity vs time
    rotgraph.plot(t, rotvel)                                            #graph of rotational velocity vs time - counterclockwise is positive
    
    t = t + dt            

Answer Key

Handout

Detecting when the ball is on the wood surface

To do this we can add an if statement in the while loop that is only true when the ball is on the wooden section of the lane:

while ball.pos.x >= -(2 * s) + r:                                       
    rate(rte)                                                            
    ball.pos = ball.pos + (ball.p/ball.mass) * dt  
                      
    if ball.pos.x <= 0: 

Changing the linear momentum

We know that a change in linear momentum is equal to the net force multiplied by time. In this case, the frictional force is the only force that is present, so multiplying that by dt will give us our change in linear momentum for each iteration of the loop:


while ball.pos.x >= -(2 * s) + r:                                       
    rate(rte)                                                            
    ball.pos = ball.pos + (ball.p/ball.mass) * dt         
               
    if ball.pos.x <= 0: 

         ball.p = ball.p + vec((Ffric * dt),0,0)

Adding Rotation

The change in rotational (or angular) velocity is given by the initial angular velocity plus the angular acceleration (alpha) times time. In the code that looks like this:



while ball.pos.x >= -(2 * s) + r:                                       
    rate(rte)                                                            
    ball.pos = ball.pos + (ball.p/ball.mass) * dt         
               
    if ball.pos.x <= 0: 

         ball.p = ball.p + vec((Ffric * dt),0,0)
         rotvel = rotvel + alpha * dt

Now we need to use this rotational velocity to rotate the ball. To do this we will use obj.rotate. We want it to rotate with respect to the the z-axis so we will use axis = vec(0,0,1). The angle that the ball should rotate will be the rotational velocity times time, which is similar to how the ball’s change in position is calculated:


while ball.pos.x >= -(2 * s) + r:                                       
    rate(rte)                                                            
    ball.pos = ball.pos + (ball.p/ball.mass) * dt         
               
    if ball.pos.x <= 0: 

         ball.p = ball.p + vec((Ffric * dt),0,0)
         rotvel = rotvel + alpha * dt
         ball.rotate(axis = vec(0,0,1), angle = rotvel * dt )

The ball now starts to move as we expect, but ends up rotating to quickly by the time its at the end of the lane. To fix this, we can add an if-else statement in the loop, nested within the first if statement:



while ball.pos.x >= -(2 * s) + r:                                       
    rate(rte)                                                            
    ball.pos = ball.pos + (ball.p/ball.mass) * dt         
               
    if ball.pos.x <= 0: 
         
         if rotvel * r >= -ball.p.x/ball.mass:
              ball.rotate(axis = vec(0,0,1), angle = rotvel * dt )

         else:

              ball.p = ball.p + vec((Ffric * dt),0,0)
              rotvel = rotvel + alpha * dt
              ball.rotate(axis = vec(0,0,1), angle = rotvel * dt )

rotvel * r represents the tangential velocity of the ball from rotation and ball.p.x/ball.mass represents the translational velocity of the ball.

Adding Graphs

The velocity graph is already done, so we can copy the syntax from that to initialize an energy graph:

egrph = graph(title='Energy vs Time', xtitle='Time (s)', ytitle='Energy (J)')    
kegraph = gcurve(color=color.red, width = 5, label='Translational Kinetic Energy (J)')
rotkegraph = gcurve(color=color.blue, width = 5, label='Rotational Kinetic Energy (J)')
totalgraph = gcurve(color=color.green, width = 5, label='Total Energy (J)')

Lastly we need to calculate the translational kinetic energy, rotational kinetic energy, and total energy and plot them, all in the while loop:

tke = 0.5*ball.mass*(mag(ball.p/ball.mass))**2                       #translational kinetic energy = 1/2mv^2
    rke = 0.5*((2/5)*(ball.mass*r**2))*((rotvel)**2)                     #rotational kinetic energy = 1/2Iw^2
    kegraph.plot(t, tke)                                                 #translational kinetic energy
    rotkegraph.plot(t, rke)                                              #graph of rotational kinetic energy
    totalgraph.plot(t, tke+rke)   

Code

Link

GlowScript 3.0 VPython
#setting the scene - these can be changed as necessary for your screen size
scene.width = 1200
scene.height = 800
scene.range = 2.5               #set the scale of the view - smaller number zoom in, bigger numbers zoom out

#define some variables
r = 0.10                        #radius of ball in meters
m1 = 7                          #mass of ball in kg
v1 = -10                        #initial horizontal velocity of ball
d = 4                           #horizontal position of ball at the start in meters
s = 7                           #half-length of friction portion of lane
g = 10                          #gravitational field strength - N/kg
t = 0                           #initialize value for time in seconds
dt = 0.001                      #value of the time-step in seconds
rte = 400                       #value for the "rate" in the loops
muk = 0.2                       #coeffiecient of kinetic friction
alpha = (5*muk*g/(2*r))         #angular acceleration of ball (moment of inertia for solid sphere - 2/5mr**2)
Ffric = m1 * g * muk           #frictional force on ball
rotvel = 0                      #initialize the rotational velocity of ball


#create some objects
ground1 = box(pos = vec(d/2,-r/4,0), size = vec(d,r/2,d/4), color = vec(0,0,4), texture = textures.wood)        #create the lane for the ball to slide on without friction
ground2 = box(pos = vec(-s,-r/4,0), size = vec(2 * s,r/2,d/4), texture = textures.wood)                         #create the lane for the ball to slide with friction
ball = sphere(pos = vec(d,r,0), radius = r, mass = m1, velocity = vec(v1,0,0), texture=textures.gravel)        #create ball with a texture to be able so see the rotation
scene.camera.follow(ball)                                                                                      #have the camera follow the ball


# define graph of motion
grph = graph(title='Velocity vs Time', xtitle='Time (s)', ytitle='Velocity')            #create graph
velgraph = gcurve(color=color.red,  width = 5, label='Linear Velocity (m/s)')           #define the curve for linear velocity
rotgraph = gcurve(color=color.blue,   width = 5, label='Angular Velocity (rad/s)')      #define the curve for angular velocity

egrph = graph(title='Energy vs Time', xtitle='Time (s)', ytitle='Energy (J)')           #create a second graph for energy
kegraph = gcurve(color=color.red, width = 5, label='Translational Kinetic Energy (J)')  #define curve for kinetic energy
rotkegraph = gcurve(color=color.blue, width = 5, label='Rotational Kinetic Energy (J)') #define curve for rotational kinetic energy
totalgraph = gcurve(color=color.green, width = 5, label='Total Energy (J)')             #define curve for rotational kinetic energy

#calculate the momentum of the ball
ball.p = ball.mass * ball.velocity                                      #initial momentum of ball


#get loopy to make things happen!
while ball.pos.x >= -(2 * s) + r:                                        #do this loop while the ball is on the lane
    rate(rte)                                                            #set the rate
    ball.pos = ball.pos + (ball.p/ball.mass) * dt                        #calculate the position of ball based on its momentum and the time increment

    if ball.pos.x <= 0:                                                  #check to see if the ball is in the portion of the lane where there is friction

        if rotvel * r >= -ball.p.x/ball.mass:                            #test to see if angular velocity matches the linear velocity - if so:
            ball.rotate(axis = vec(0,0,1), angle = rotvel * dt )         #ball rotates

        else:                                                            #have the rotation rate of the ball increase and the velocity of the ball decrease:
            ball.p = ball.p + vec((Ffric * dt),0,0)                     #kinetic friction force acting on ball as it slides changing the momentum of ball
            rotvel = rotvel + alpha * dt                                 #increment the angular velocity using the angular acceleration
            ball.rotate(axis = vec(0,0,1), angle = rotvel * dt )         #determine how much the ball rotates

    velgraph.plot(t, mag(ball.p/ball.mass))                              #graph of linear velocity vs time
    rotgraph.plot(t, rotvel)                                             #graph of rotational velocity vs time - counterclockwise is positive
    
    
    tke = 0.5*ball.mass*(mag(ball.p/ball.mass))**2                       #translational kinetic energy = 1/2mv^2
    rke = 0.5*((2/5)*(ball.mass*r**2))*((rotvel)**2)                     #rotational kinetic energy = 1/2Iw^2
    kegraph.plot(t, tke)                                                 #translational kinetic energy
    rotkegraph.plot(t, rke)                                              #graph of rotational kinetic energy
    totalgraph.plot(t, tke+rke)                                          #total energy
    

    t = t + dt                                                           #increment the time