Nimble Manual

2 minute read

Published:

Nimble Manual

Introduction

“Nimble is a toolkit for doing AI on human biomechanics (physically simulated realistic human bodies), written in C++ for speed, but with nice Python bindings. It focuses on studying real physical human bodies.Nimble started life as a general purpose differentiable physics engine, as a fork of the (not differentiable) DART physics engine.”

As the documentation writen by the authors said, Nimble can complete numerous tasks on physical simulation with AI.

However, if you have to use this physics engine just for simulation except for researching on Addbiomechanics Dataset, I would rather suggest you reconsidering another physics engine since the documentation hasn’t been updated for a long time, and any emails and issues sent to the authors will not be replied.

Fundamental functions

Firstly, you have to setup your simulation world.

import nimblephysics as nimble
world = nimble.simulation.World()
world.setGravity([0, -9.81, 0])
world.setTimeStep(0.001)

These codes will create a simulation world with gravity and simulation timestep, which is vital in calculating the kinematics and dynamics.

Let’s add a box! The type of object is called “Skeleton” in nimble.

box = nimble.dynamics.Skeleton()
boxJoint, boxBody = box.createTranslationalJoint2DAndBodyNodePair()
boxShape = boxBody.createShapeNode(nimble.dynamics.BoxShape([.1, .1, .1]))
boxVisual = boxShape.createVisualAspect()
boxVisual.setColor([0.5, 0.5, 0.5])

Moreover, you need a pre-defined urdf if you want to add ground to the simulation world.

ground: nimble.dynamics.Skeleton = world.loadSkeleton("your path to ground.urdf,here is an example: /hdd/junxuanl/Molign/data/ground.urdf")

After defining the box, Let’s visualize the simulation! The state is combined with positions and velocities. (state=[positions,velocities])

initialState = torch.tensor([0, -0.70, 2, 0])
//There are two dimesions of freedom for the box, so the shape of positions and velocities are both (2,1)
action = torch.zeros((world.getActionSize()))
//The shape of action is (2,1)
state = initialState
states = []

for _ in range(300):
    state = nimble.timestep(world, state, action)
    states.append(state)

gui = nimble.NimbleGUI(world)
gui.serve(8080) # host the GUI on localhost:8080
gui.loopStates(states) # tells the GUI to animate our list of states
gui.blockWhileServing() # block here so we don't exit the program

non-collision

It’s strange right? The box just crossed the ground. If you want to add collision to both of them, just use createCollisionAspect()

boxShape.createCollisionAspect()

floorBody: nimble.dynamics.BodyNode = ground.getBodyNode(0)
floorBody.getShapeNode(0).createCollisionAspect()

collision

Remember that the timestep of simulation can’t be too small!(for example, set it to 0.01s) Otherwise the box will still cross the ground.

fail-collision

To allow for the interaction and transfer of forces between objects (collisions), setRestitutionCoeff() is needed.

boxBody.setRestitutionCoeff(0.8)
floorBody.setRestitutionCoeff(0.8)

restitution

There are some cases in github repo, which are not written in the documentation.