ODE internal error crashes

I’m getting some odd ODE internal errors with code that used to work fine. I’m using panda 1.7.1 from SVN, Ubuntu 10.10 64 bit.

Crash 1, from the ODE example in the “Panda3D Developer’s Cookbook” pp 180-181:

    def updateODE(self,task):
        self.space.autoCollide()
        self.odeWorld.quickStep(globalClock.getDt())

error:

ODE INTERNAL ERROR 2: stepsize must be > 0 in dWorldQuickStep()

Crash 2:

  boxBody = OdeBody(world)
  M = OdeMass()
  M.setBox(50, 1, 1, 1)
  boxBody.setMass(M)

error:

ODE Message 2: mass must be > 0 in dMassCheck() File ../../../../../ode/src/mass.cpp Line 49
*** glibc detected *** python: malloc(): memory corruption: 0x0000000001ad6ab0 ***

Memory corruption errors also result from calling M.getMagnitude() or M.getInertialTensor() after the call to M.setBox().

Any chance it could be something like a single precision / double precision mismatch?

Haven’t been able to figure out what’s causing this yet, but for the moment I have a workaround just using pyODE. (http://pyode.sourceforge.net/)

This code crashes:

from direct.showbase.ShowBase import ShowBase
from panda3d.core import *
from panda3d.ode import *
import random

class App(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.smiley=loader.loadModel("smiley")
        self.smileyCount=0
        self.cam.setPos(0,-100,10)

        self.setupODE()
        self.addGround()

        taskMgr.doMethodLater(0.01,self.addSmiley,"AddSmiley")
        taskMgr.add(self.updateODE,"UpdateODE")

    def setupODE(self):
        self.odeWorld=OdeWorld()
        self.odeWorld.setGravity(0,0,-9.81)
        self.odeWorld.initSurfaceTable(1)
        self.odeWorld.setSurfaceEntry(0,0,200,0.7,0.2,0.9,0.00001,0.0,0.002)

        self.space=OdeSimpleSpace()
        self.space.setAutoCollideWorld(self.odeWorld)
        self.contacts=OdeJointGroup()

        self.space.setAutoCollideJointGroup(self.contacts)

    def addGround(self):
        cm=CardMaker("ground")
        cm.setFrame(-500,500,-500,500)
        ground=render.attachNewNode(cm.generate())
        ground.setColor(0.2,0.4,0.8)
        ground.lookAt(0,0,-1)
        groundGeom=OdePlaneGeom(self.space,Vec4(0,0,1,0))

    def addSmiley(self,task):
        sm=render.attachNewNode("smiley-instance")
        sm.setPos(random.uniform(-20,20),random.uniform(-30,30), random.uniform(10,30))
        self.smiley.instanceTo(sm)

        body=OdeBody(self.odeWorld)
        mass=OdeMass()
        mass.setSphereTotal(10,1)
        body.setMass(mass)
        body.setPosition(sm.getPos())
        geom=OdeSphereGeom(self.space,1)
        geom.setBody(body)
        sm.setPythonTag("body",body)
        self.smileyCount +=1
        if self.smileyCount == 1000:
            return task.done
        return task.again

    def updateODE(self,task):
        self.space.autoCollide()
        dt=globalClock.getDt()
        print dt
        
        self.odeWorld.quickStep(dt)

        for smiley in render.findAllMatches("smiley-instance"):
            body=smiley.getPythonTag("body")
            smiley.setPosQuat(body.getPosition(),Quat(body.getQuaternion()))
        self.contacts.empty()
        return task.again
        
a=App()
run()

ODE INTERNAL ERROR 2: stepsize must be > 0 in dWorldStep()
Aborted

But this seems to work:

'''
Panda's ODE seems messed up ... not sure why ... but what about this other, regular ODE Python wrapper?

yes, that works. weird!
'''

from direct.showbase.ShowBase import ShowBase
from panda3d.core import *
import ode
import random

class App(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.smiley=loader.loadModel("smiley")
        self.smileyCount=0
        self.cam.setPos(0,-100,10)

        self.setupODE()
        self.addGround()

        taskMgr.doMethodLater(0.01,self.addSmiley,"AddSmiley")
        taskMgr.add(self.updateODE,"UpdateODE")

    def setupODE(self):
        self.odeWorld=ode.World()
        self.odeWorld.setGravity((0,0,-9.81))
        self.odeWorld.setERP(0.8)
        self.odeWorld.setCFM(1E-5)

        self.space=ode.SimpleSpace()
        self.contacts=ode.JointGroup()
        self.bodies=[]
        self.geoms=[]

    def addGround(self):
        cm=CardMaker("ground")
        cm.setFrame(-500,500,-500,500)
        ground=render.attachNewNode(cm.generate())
        ground.setColor(0.2,0.4,0.8)
        ground.lookAt(0,0,-1)
        groundGeom=ode.GeomPlane(self.space,(0,0,1),0)
        self.geoms.append(groundGeom)

    def addSmiley(self,task):
        sm=render.attachNewNode("smiley-instance")
        sm.setPos(random.uniform(-20,20),random.uniform(-30,30), random.uniform(10,30))
        self.smiley.instanceTo(sm)

        body=ode.Body(self.odeWorld)
        mass=ode.Mass()
        mass.setSphereTotal(10,1)
        mass.mass=1.0
        body.setMass(mass)
        body.setPosition(sm.getPos())
        
        geom=ode.GeomSphere(self.space,1)
        geom.setBody(body)
        self.geoms.append(geom)
        self.bodies.append(body)
        sm.setPythonTag("body",body)
        self.smileyCount +=1

        if self.smileyCount == 1000:
            return task.done
        return task.again

    def updateODE(self,task):        
        dt=globalClock.getDt()


        self.space.collide((self.odeWorld,self.contacts),collisionCallback)
        self.odeWorld.step(dt)
        self.contacts.empty()
         
        for smiley in render.findAllMatches("smiley-instance"):
            body=smiley.getPythonTag("body")
            smiley.setPosQuat(body.getPosition(),Quat(body.getQuaternion()))
       
        return task.again

def collisionCallback (args,geom1,geom2):
    contacts=ode.collide(geom1,geom2)
    world,contactgroup=args
    for c in contacts:
        c.setBounce(0.2)
        c.setMu(5000)
        j = ode.ContactJoint(world, contactgroup, c)
        j.attach(geom1.getBody(), geom2.getBody())

a=App()
run()