RigidBodyPhysics Example: Ball with Rope

From H3D.org

Jump to: navigation, search

This simple application demonstrates the use of RigidBodyPhysics engine. A ball and a haptics device are attached to both ends of a elastic rope. As you move around, the ball will float according to the constraint made by the rope.

Image:Note-tip.pngThis tutorial refers to the source code. You can download it from SVN at H3D release branch, or find it at H3D/RigidBodyPhysics/examples/ballwithrope/.

Alternatively, you can download the example here.

Contents

Development

General developement flow:

  • Create a ball (RigidBody object), attached to a SpringEffect
  • Implement force to push the ball towards haptics device
  • Implement damping
  • Add rope


Create force to the haptics device

Because we'll work with the haptics device, we need to explicitly declare it and assign a name

    <DeviceInfo>
      <AnyDevice DEF='device'>
        <Shape containerField='stylus'>
          <Appearance>
            <Material/>
          </Appearance>
          <Sphere radius='0.0025'/>
        </Shape>
      </AnyDevice>
    </DeviceInfo>

The above code also attach the haptics device pointer with a small sphere.

We then proceed to create the ball and its RigidBody's equivalence. After that, add a SpringEffect node and attach its position to the ball's position

In case you don't know, SpringEffect node gives a force to the haptics device based on the distance between it and a fixed point.

<SpringEffect DEF='spr' position='0 0 0' springConstant='40' startDistance='0.1' escapeDistance='1' deviceIndex='0'/>
<ROUTE fromNode="rbbox" fromField="position" toNode="spr" toField="position" />

From the code above, when the haptics device enters the radius of 0.1m within the desired position, SpringEffect (SE) is activated. It will add a force of springConstant * distance to the haptics device towards SpringEffect's position (which is also the ball's position)

Moving the ball

We add a force to the ball to make it move towards the haptics device. Note: According to dynamics physics, these 2 forces are equal but of opposite direction, so make sure the 2 constant are the same.

<ROUTE fromNode='device' fromField='weightedProxyPosition' toNode='PY' toField='devicemove' />
class DeviceMove(SFVec3f):
  def __init__(self, const):
    SFVec3f.__init__(self)
    self.const = const
  def update(self, event):
    global device
    devpos, = self.getRoutesIn()
    ballpos = rbball.position.getValue()
    # get pos of haptics device
    devpos = device.weightedProxyPosition.getValue()
    deltapos = ballpos - devpos
    return -self.const*deltapos
devicemove = DeviceMove(SpringDemo.INVERT_CONSTANT)
 

Damping factor

RigidBodyPhysics sometimes doesn't really follow dynamics law. So if we stop here, the ball will keep oscillating with greater and greater amplitude. That's why we need some force to dampen this movement. That is achieved by adding a force of opposite direction to the ball movement and propotional to its velocity.

<ROUTE fromNode="rbbox" fromField="linearVelocity" toNode="PY" toField="dampspring" />
class DampSpring(SFVec3f):
  def __init__(self, const):
    SFVec3f.__init__(self)
    self.const = const
  def update(self, event):
    v = event.getValue()
    return - self.const * v
dampspring = DampSpring(SpringDemo.DAMP_CONST)
 

Combine force

There are now 2 forces (2 SFVec3f objects) coming to the RigidBody object. However RigidBody.forces is of type MFVec3f. The code below will take care of that:

class SumForces( TypedField( MFVec3f, (SFVec3f, SFVec3f) ) ):
  def update( self, event ):
    routes = getRoutesIn( self )
    ans = []
    for r in routes:
      if isinstance( r, SFVec3f ):
        ans.append(r.getValue())
    return ans
sumforces = SumForces()
sumforces.route(rbball.forces)
devicemove.route(sumforces)
dampspring.route(sumforces)

Creating the rope

We use a LineSet and attach 2 end-points to it.

    <Shape>
      <LineSet vertexCount='2'>
        <Coordinate DEF='coorline' point='0 0 0 0 0 0' />
      </LineSet>
      <Appearance>
        <Material emissiveColor='0 0 1' />
      </Appearance>
    </Shape>
 
    <ROUTE fromNode="rbbox" fromField="position" toNode="PY" toField="drawline" />
    <ROUTE fromNode="device" fromField="weightedProxyPosition" toNode="PY" toField="drawline" />
class DrawLine(TypedField(MFVec3f, (SFVec3f, SFVec3f))):
  def update(self, event):
    arr = self.getRoutesIn()
    ans = []
    for f in arr:
      ans.append(f.getValue())
    return ans
drawline = DrawLine()
drawline.route(coorline.point)

Hula

You're done. Simple huh? Any issue please post on the forum.

Personal tools
go to