Tuesday, April 27, 2010

Visual Python

Hi World -
So I finished my Visual Python Project today. Python is a very cool 3-D programming module that John and my class is using to simulate some physics principles.
I created three such projects, "Newton's Cannon," "Ninja," and "Spring SHM."
1. Newton's Cannon
This is a simulation of Newton's classic thought experiment depicting the force of gravity as the key factor in celestial orbits. Using real-world scale objects and a very, very large wooden cannon as a substitute for Newton's proposed space gun atop a mountain, we launch four colorful cannonballs, each with a different initial velocity and trajectory. The program, like Newton's cannon, demonstrates gravity's role as the centripetal force in orbits about a planet and the idea of objects "falling around the earth."

from __future__ import division # The Decimal Rule
from visual import *
from visual.controls import *

# Sunlight
scene.lights = []
distant_light(direction=(10000000,200,1000), color=color.white)

# Dramatis Personae
World = frame()
Earth = sphere(frame=World, pos=(0,0,0), radius=6371000, color=color.white, material=materials.earth)
    # Newton's Super-Advanced/Practically-Magic Cannon
Wheel1 = cylinder(frame=World, pos=(500000,7200000,-1650000), axis=(0,0,1000000), radius=1000000, material=materials.wood)
Wheel2 = cylinder(frame=World, pos=(500000,7200000,650000), axis=(0,0,1000000), radius=1000000, material=materials.wood)
Barrel = cylinder(frame=World, pos=(0,7500000,0), axis=(1500000,1200000,0), radius=960000, material=materials.wood)
BarrelHole = cylinder(frame=World, pos=(0,7500000,0), axis =(1500000,1200000,0),radius= 900000, color=color.black)
World.pos = (0,0,0) # Origin
World.axis = (1,0,0) # Axial Tilt
    # Cannonball 1, A tired soul
Cb1 = sphere(pos=(0.001,7500000,0.001), radius=1000000, color=color.red, material=materials.plastic)
Cb1.velocity = vector(4320,0,36.36)
Cb1.trail = curve (color = Cb1.color)
    # Cannonball 2, "Icarus"
Cb2 = sphere(pos=(0.001,7500000,0.001), radius=1000000, color=color.yellow, material=materials.plastic)
Cb2.velocity = vector(4250, 4000, 36.36)
Cb2.trail = curve (color = Cb2.color)
    # The Little Cannonball that Couldn't
Cb3 = sphere (pos=(0.001, 7500000, 0.001), radius=1000000, color=color.green, material=materials.plastic)
Cb3.velocity = vector(6000, 4000, 36.36)
Cb3.trail = curve (color = Cb3.color)
    # The Champion
CbS = sphere (pos=(0.001, 7500000, 0.001), radius=1000000, color=color.white, material=materials.plastic)
CbS.velocity = vector(7500, 800, 36.36)
CbS.trail = curve (color = CbS.color)

# Constants
G = 6.67e-11                        # Gravitational Constant (m^3*kg^-1*s^-2)
m_ball = 1000000              # mass of cannonballs (kg)
m_earth = 5.9742e24         #  mass of earth (kg)
dt = 0.01                               # Time Step (s)

while True:
    rate(10000)
    World.rotate(angle = pi/43200, axis = (0,1,0), origin = (0,0,0))
    Cb1.trail.append (pos=Cb1.pos)
    Cb2.trail.append (pos = Cb2.pos)
    Cb3.trail.append (pos = Cb3.pos)
    CbS.trail.append (pos = CbS.pos)

# Forces
    # Cannonball 1
    ForceGravityEarthonCb1Mag = G*m_ball*m_earth/pow(Cb1.pos.mag,2)
    ForceGravityEarthonCb1Dir = norm(Earth.pos - Cb1.pos)
    ForceGravityEarthonCb1 = ForceGravityEarthonCb1Mag * ForceGravityEarthonCb1Dir
    # Cannonball 2
    ForceGravityEarthonCb2Mag = G*m_ball*m_earth/pow(Cb2.pos.mag,2)
    ForceGravityEarthonCb2Dir = norm(Earth.pos - Cb2.pos)
    ForceGravityEarthonCb2 = ForceGravityEarthonCb2Mag * ForceGravityEarthonCb2Dir
    # Cannonball 3
    ForceGravityEarthonCb3Mag = G*m_ball*m_earth/pow(Cb3.pos.mag,2)
    ForceGravityEarthonCb3Dir = norm(Earth.pos - Cb3.pos)
    ForceGravityEarthonCb3 = ForceGravityEarthonCb3Mag * ForceGravityEarthonCb3Dir
    # Cannonball S
    ForceGravityEarthonCbSMag = G*m_ball*m_earth/pow(CbS.pos.mag,2)
    ForceGravityEarthonCbSDir = norm(Earth.pos - CbS.pos)
    ForceGravityEarthonCbS = ForceGravityEarthonCbSMag * ForceGravityEarthonCbSDir

# Kinematics
    # Cannonball 1
    Cb1.acceleration = ForceGravityEarthonCb1/m_ball
    Cb1.velocity = Cb1.velocity + Cb1.acceleration*dt
    Cb1.pos = Cb1.pos + Cb1.velocity*dt
    # Cannonball 2
    Cb2.acceleration = ForceGravityEarthonCb2/m_ball
    Cb2.velocity = Cb2.velocity + Cb2.acceleration*dt
    Cb2.pos = Cb2.pos + Cb2.velocity*dt
    # Cannonball 3
    Cb3.acceleration = ForceGravityEarthonCb3/m_ball
    Cb3.velocity = Cb3.velocity + Cb3.acceleration*dt
    Cb3.pos = Cb3.pos + Cb3.velocity*dt   
    # Cannonball S
    CbS.acceleration = ForceGravityEarthonCbS/m_ball
    CbS.velocity = CbS.velocity + CbS.acceleration*dt
    CbS.pos = CbS.pos + CbS.velocity*dt   

# Stop/Land Functions
    if Cb1.pos.mag <= 6371000:
        Cb1.velocity = vector(0,0,0)
        Cb1.rotate(angle = pi/43200, axis = (0,1,0), origin = (0,0,0))
       
    if Cb2.pos.mag <= 6371000:
        Cb2.velocity = vector(0,0,0)
        Cb2.rotate(angle = pi/43200, axis = (0,1,0), origin = (0,0,0))
       
    if Cb3.pos.mag <= 6371000:
        Cb3.velocity = vector(0,0,0)
        Cb3.rotate(angle = pi/43200, axis = (0,1,0), origin = (0,0,0))

    if CbS.pos.mag <= 6371000:
        CbS.velocity = vector(0,0,0)
        CbS.rotate(angle = pi/43200, axis = (0,1,0), origin = (0,0,0))


2. Ninja
This project features a ninja trapped in a dark room. He is scared, tired, hungry, and simply does not want to deal with any more danger. So what does he do? Launch one of his shuriken at the wooden generator level he knows is somewhere along the wall to get the power back on, of course! The ninja sim features projectile motion, use of rotational inertia and the application of conservation of angular momentum in the absence of external torques to help celebrate the ninja's newfound enlightenment and wonderful understanding of physical principles.

from __future__ import division # The Decimal Rule
from visual import *

# Setting
floor = box(length=200, height=0.5, width=40, material=materials.marble)
wall1 = box(pos=(0,10,-20), length=200, height=20, width=0.5, color=color.red, opacity=0.2)
wall2 = box(pos=(0,10,20), length=200, height=20, width=0.5, color=color.red, opacity=0.2)
wall3 = box(pos=(-100,10,0), length=0.5, height=20, width=40, color=color.red, opacity=0.2)
wall4 = box(pos=(100,10,0), length=0.5, height=20, width=40, color=color.red, opacity=0.2)
    # Mood Lighting
lamp = local_light(pos=(40,30,0), color=color.red)
box(pos=lamp.pos, length=2, height=2, width=2, color=color.white, material=materials.emissive)

# Dramatis Persona
 # White Ninja
Ninja = frame()
sphere(frame=Ninja, pos=(1.2,14,0), radius=1.333, color=color.white)
cylinder(frame=Ninja, pos=(0,8,0), axis=(1.2,5,0), radius= 1.667, color=color.white)
ellipsoid(frame=Ninja, pos=(1.2,4,2), axis=(2,1,2.5), length=1, height=10, width=2.8, color=color.white)
ellipsoid(frame=Ninja, pos=(1.2,4,-2), axis=(2,1,-2.5), length=1, height=10, width=2.8, color=color.white)
RArm = ellipsoid(frame=Ninja, pos=(2.9,12,2), length=5, height = 1.8, width=1.8,  color=color.white)
ellipsoid(frame=Ninja, pos=(0.8,12,-3), length=1.8, height = 1.8, width=5, color=color.white)
I_RArm = 125 # Moment of Inertia of Right Arm (kg*m^2)
omega_RArm= -pi/100
Ninja.pos = (0,0.5,0)

# All About Shuriken
shuriken = frame()
shuriken.color = color.black
cylinder(frame=shuriken, pos=(0,0,0), axis=(0,0.25,0), radius=0.5, material=materials.emissive)
box(frame=shuriken, pos=(0.5,0.125,0.25), length=1, width=0.25, height=0.25, material=materials.emissive)
box(frame=shuriken, pos=(-0.5,0.125,-0.25), length=1, width=0.25, height=0.25, material=materials.emissive)
box(frame=shuriken, pos=(-0.25,0.125,0.5), length=0.25, width=1, height=0.25, material=materials.emissive)
box(frame=shuriken, pos=(0.25,0.125,-0.5), length=0.25, width=1, height=0.25, material=materials.emissive)
shuriken.pos = RArm.pos
shuriken.axis = (0,0,1)
shuriken.velocity = vector(80,0,0)
m_shuriken =  0.5  # Mass of Shuriken (kg)
I_shuriken =  0.85413  # Rotational Inertia of Shuriken (kg*m^2)
omega_shuriken = pi/6 # Angular Velocity of Shuriken (rad*s^-1)

target=frame()
target_plank = box(frame=target, length=0.1, width=10, height=20, material=materials.wood)
target.pos=(100,10,0)
m_target = 50 # Mass of Target (kg)
I_target = 500# Rotational Inertia of Shuriken (kg*m^2)
omega_target = 0 # Initial Angular Velocity of Target (rad*s^-1)

# Constants:
t = 0 # Initial Time
g = 9.8 # acceleration due to gravity (m/s/s)
dt = 0.01 # Time Step (s)

# Forces   
while True:
    rate(100)
    t = t + dt

    L_shuriken = (shuriken.pos.z-target.pos.z)*(m_shuriken*shuriken.velocity.x) + I_shuriken*omega_shuriken
    shuriken.rotate(angle=omega_shuriken, axis=(0,1,0), origin=shuriken.pos)
    L_target_1 = (I_target*omega_target + L_shuriken)
   
       
    # Forces
    if shuriken.pos.y <= (floor.pos.y + 0.25):
        Fnorm_shuriken = vector(0, m_shuriken*g, 0)
        omega_shuriken = 0
        shuriken.velocity.y=shuriken.velocity.x=0
    else:
            Fnorm_shuriken = vector(0,0,0)
            Ffriction_shuriken = vector(0,0,0)
        
    Fg_shuriken = vector(0,-m_shuriken*g,0)
    Fnet_shuriken = Fg_shuriken+Fnorm_shuriken
   
    # Kinematics - Shuriken
    shuriken.acceleration = Fnet_shuriken/m_shuriken
    shuriken.velocity = shuriken.velocity + shuriken.acceleration*dt
    shuriken.pos = shuriken.pos + shuriken.velocity*dt

    # Shuriken Stop
    if shuriken.pos.x >= target.pos.x:
        omega_shuriken=0
        Fnorm_shuriken = vector(0,m_shuriken*g,0)
        shuriken.velocity=vector(0,0,0)
        omega_target = L_target_1/I_target

    shuriken.rotate(angle=omega_target, axis=(0,1,0), origin=target.pos)
    target.rotate(angle=omega_target, axis=(0,1,0), origin=target.pos)

    # "The Power's Back On!"
    if omega_target >=0.1:
        wall1.color= wall2.color = wall3.color = wall4.color = lamp.color = color.white

3. Spring SHM
This project is a demonstration of Hooke's Law and how the restoring force of a spring on a mass (wooden block) results in simple harmonic motion. Notable features are the ability to change the block's initial displacement and/or velocity and measure their effects on amplitude. While it isn't as noticeable, the program also shows the role of Newton's second law of motion in defining acceleration's relationship to force.

from visual import *
from visual.controls import * # Activates Control Capacity
from visual.graph import * # Activates Graphing Capacity

# The Simple Harmonic Motion of a Pendulum
    # by Ronald Martin
    # AP Physics - 1st Period, St. Ignatius College Prep.

scene.autoscale = False

# Setting
box(pos=(0,-2.5,0), length=40, height=0.5, width=10, color=color.green) # Floor
Wall = box(pos=(-20.25,-0.25,0), length=0.5, width=10, height=5, color=color.blue)

# Dramatis Personae 1:
x_0 = 0 # block's initial displacement (m)
block = box(pos=(x_0+2.5,0,0), length=5, height=5, width=5, material=materials.wood)
m_block = 10 # Mass of Block (kg)
block.velocity = vector(4,0,0) # Initial Velocity of block (m/s)

Spring = helix(pos=(-20,0,0), radius=2, color=color.yellow)
k = Spring.coils = 20 # Spring Constant (kg/s/s)& Number of Coils

# Constants of Nature
t = 0 # Initial Time (s)
dt = 0.01 # Time Step (s)
g = 9.81 # Acceleration due to gravity (m/s/s)
mu_k = 0.05 # Coefficient of Kinetic Friction

while True:
    rate(100)
    time = t+dt

    # Dramatis Personae (cont'd):
    deltasp =  block.pos-vector(2.5,0,0) # Compression/Stretching of String (m)
    Spring.axis = (block.pos.x-2.5-Wall.pos.x+0.25,0,0) # Spring Cosmetic

    # Forces and Kinematics
    F_g_block = vector(0, -m_block*g, 0)
    F_normal = vector(0, m_block*g, 0)
    F_sp = -k*deltasp
    F_net = F_g_block + F_normal + F_sp

    block.acceleration = F_net/m_block
    block.velocity = block.velocity + block.acceleration*dt
    block.pos = block.pos + block.velocity*dt

If only I could make a video... but alas, CamStudio refuses to work. Maybe later.