ODEDynamics: Falling Boxes

Author:Alex Dumitrache (alex@cimr.pub.ro)
Date:2010/05/05

This is a rewrite of the 3rd PyODE tutorial, originally by Matthias Baas.

The simulation will drop some boxes in the scene. After some time, the boxes will explode, they will be pulled back, and the cycle will repeat.

_images/boxes-drop.png

First, let’s create a scene and drop some boxes.

import random

# Create a ground plane
p = Plane(lx = 5, ly = 5)

# Set contact properties and initialize ODEDynamics
defaultContactProps = ODEContactProperties(bounce = 0.2, mu = 5000)
odeSim = ODEDynamics(gravity=9.81, substeps=2, cfm=1e-5, erp=0.8,
         defaultcontactproperties = defaultContactProps, use_quick_step = False, auto_add = True)

def rz(ang):
    """Elementary rotation around Z"""
    return mat3(1).rotate(ang, (0,0,1))

def drop_object():
    """Drop an object into the scene."""

    pos = (random.gauss(0,0.1), random.gauss(0,0.1), 3)
    rot = rz(random.uniform(0, 2*pi))
    b = Box(lx=1, ly=0.2, lz=0.2, pos=pos, rot=rot, mass=1000*1*0.2*0.2)

    odeSim.add(b)

# Drop a box every 20 frames
def onStepFrame():
    if int(scene.timer().frame) % 20 == 0:
       drop_object()

eventmanager.connect(STEP_FRAME, onStepFrame)

Save the program and run it.

After dropping too many boxes, the simulation will slow down, even if you have the latest Core i7 processor.

Let’s limit the number of boxes to 30 and add some special effects. We will also add a bit of damping; otherwise, ODE may crash due to numerical problems.

_images/boxes-explode.png

Be careful when using damping together with auto_add = True in ODEDynamics constructor: ODE will apply damping only to bodies created AFTER setting the world parameters!

# pyODE example 3: Collision detection
# Rewritten for cgkit/ODEDynamics by Alex Dumitrache
# Original code by Matthias Baas.

import random

objects = []
counter = 0
state = 0

# Create a ground plane
p = Plane(lx = 5, ly = 5)

# Set contact properties and initialize ODEDynamics
defaultContactProps = ODEContactProperties(bounce = 0.2, mu = 5000)
odeSim = ODEDynamics(gravity=9.81, substeps=2, cfm=1e-5, erp=0.8,
         defaultcontactproperties = defaultContactProps, use_quick_step = False, auto_add = True)

# Add a little damping to prevent ODE from crashing
odeSim.world.setLinearDamping(1e-5)
odeSim.world.setAngularDamping(1e-5)
odeSim.world.setMaxAngularSpeed(100)

def rz(ang):
    """Elementary rotation around Z"""
    return mat3(1).rotate(ang, (0,0,1))

def drop_object():
    """Drop an object into the scene."""

    pos = (random.gauss(0,0.1), random.gauss(0,0.1), 3)
    rot = rz(random.uniform(0, 2*pi))
    b = Box(lx=1, ly=0.2, lz=0.2, pos=pos, rot=rot, mass=1000*1*0.2*0.2)

    odeSim.add(b)
    objects.append(b)

def explosion():
    """Simulate an explosion.

    Every object is pushed away from the origin.
    The force is dependent on the objects distance from the origin.
    """
    for b in objects:
        l = b.pos
        d = abs(l)
        l = max(0, 20000*(1.0-0.2*d*d)) * vec3(l[0] / 4, l[1] / 4, l[2]).normalize()
        b.manip.addForce(l)

def pull():
    """Pull the objects back to the origin.

    Every object will be pulled back to the origin.
    Every couple of frames there'll be a thrust upwards so that
    the objects won't stick to the ground all the time.
    """
    for b in objects:
        b.manip.addForce(-500 * b.pos.normalize())
        if counter % 60 == 0:
            b.manip.addForce((0,0,5000))

def onStepFrame():
    global counter, state
    counter += 1

    # State 1: Drop objects
    if state==0:
        if counter==20:
            drop_object()
            counter = 0
        if len(objects) == 30:
            state=1
            counter=0
    # State 1: Explosion and pulling back the objects
    elif state==1:
        if counter==100:
            explosion()
        if counter>300:
            pull()
        if counter==500:
            counter=20

eventmanager.connect(STEP_FRAME, onStepFrame)

Download the script and run it using:

> python viewer.py -f 50 falling-boxes.py

Why -f 50 ? The original PyODE tutorial worked at 50 fps. By default, viewer.py uses 30 fps.

Exercises

  • Tweak the simulation parameters. For example, set mu = 0 and enjoy the storm :)
  • Try dropping boxes or spheres, at random
  • Make the simulation more attractive
  • Run the simulation at 100 fps and notice the different behavior. Try to make the simulation run in the same way, regardless of the fps
  • Run the simulation at 5 fps, notice the lack of accuracy in physics simulation, and fix it!
_images/balls-and-boxes.png

Next steps

Table Of Contents

Previous topic

ODEDynamics: Newton Ball Experiment

Next topic

Code Examples

This Page