brax
brax copied to clipboard
Issue with bodies flying apart in simulation [Question]
I am trying to implement my own simulation of a robot claw. I have an issue where for some reason all the bodies are exploding. This is odd to me because it only happens when I include all bodies together, pictured below. If I only include one claw it works just fine and all the joints work as expected. But for some reason I don't understand including both claws will cause the bodies to spontaneously explode away from each other at high speed. Additionally I have found that I can include both claws if I don't include a link to the ground plane. Is this a problem with my approach or is this a bug? I am unsure how investigate further and would appreciate any advice.
import functools
import time
from IPython.display import HTML, Image
import gym
try:
import brax
except ImportError:
from IPython.display import clear_output
!pip install git+https://github.com/google/brax.git@main
clear_output()
import brax
from brax import envs
from brax import jumpy as jp
from brax.envs import to_torch
from brax.io import html
from brax.io import image
import numpy as np
right_claw = True
left_claw = True
conf = brax.Config(dt=0.05, substeps=20, angular_damping=-0.05, dynamics_mode='pbd')
conf.gravity.z = -9.8
ground = conf.bodies.add(name='floor', mass=1)
ground.frozen.all = True
ground.inertia.x = 1
ground.inertia.y = 1
ground.inertia.z = 1
plane = ground.colliders.add().plane
plane.SetInParent()
link1 = conf.bodies.add(name='link1', mass=1)
cap = link1.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link2 = conf.bodies.add(name='link2', mass=1)
cap = link2.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.3
cap.SetInParent()
cap = link2.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
cap = link2.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link2.colliders[0].rotation.y = 90.0
link2.colliders[1].rotation.x = 90.0
link2.colliders[2].rotation.x = 90
link2.colliders[1].position.x = 0.1
link2.colliders[2].position.x = -0.1
if (right_claw):
link3 = conf.bodies.add(name='link3', mass=1)
cap = link3.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link3.colliders[0].rotation.y = 90.0
link4 = conf.bodies.add(name='link4', mass=1)
cap = link4.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link4.colliders[0].rotation.y = 90.0
link5 = conf.bodies.add(name='link5', mass=1)
cap = link5.colliders.add().capsule
cap.radius = 0.05
cap.length = 1
cap.SetInParent()
cap = link5.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
cap = link5.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link5.colliders[0].rotation.x = 90.0
link5.colliders[1].rotation.x = 90.0
link5.colliders[1].rotation.y = 45
link5.colliders[1].position.x = -0.15
link5.colliders[1].position.y = 0.6
link5.colliders[2].rotation.x = 90.0
link5.colliders[2].position.x = -0.30
link5.colliders[2].position.y = 0.5 + 0.28 + 0.15
if(left_claw):
link6 = conf.bodies.add(name='link6', mass=1)
cap = link6.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link6.colliders[0].rotation.y = 90.0
link7 = conf.bodies.add(name='link7', mass=1)
cap = link7.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link7.colliders[0].rotation.y = 90.0
link8 = conf.bodies.add(name='link8', mass=1)
cap = link8.colliders.add().capsule
cap.radius = 0.05
cap.length = 1
cap.SetInParent()
cap = link8.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
cap = link8.colliders.add().capsule
cap.radius = 0.05
cap.length = 0.5
cap.SetInParent()
link8.colliders[0].rotation.x = 90.0
link8.colliders[1].rotation.x = 90.0
link8.colliders[1].rotation.y = -45
link8.colliders[1].position.x = 0.15
link8.colliders[1].position.y = 0.6
link8.colliders[2].rotation.x = 90.0
link8.colliders[2].position.x = 0.30
link8.colliders[2].position.y = 0.5 + 0.28 + 0.15
joint1 = conf.joints.add(name='joint1', parent='floor', child='link1', angular_damping=50.0)
joint1.angle_limit.add(min=-360, max=360)
joint1.parent_offset.z = 0.25
joint1.rotation.y=90
joint2 = conf.joints.add(name='joint2', parent='link1', child='link2', angular_damping = 50.0)
joint2.angle_limit.add(min=-360, max=360)
joint2.parent_offset.z = 0.2
joint2.rotation.x = 90
if(right_claw):
joint3 = conf.joints.add(name='joint3', parent='link2', child='link3', angular_damping=50.0)
joint3.angle_limit.add(min=-75, max=75)
joint3.parent_offset.y = -0.2
joint3.parent_offset.x = 0.1
joint3.child_offset.x = -0.2
joint3.rotation.y = -90
joint4 = conf.joints.add(name='joint4', parent='link2', child='link4', angular_damping=50.0)
joint4.angle_limit.add(min=-360, max=360)
joint4.parent_offset.y = 0.2
joint4.parent_offset.x = 0.1
joint4.child_offset.x = -0.2
joint4.rotation.y = -90
joint5 = conf.joints.add(name='joint5', parent='link3', child='link5', angular_damping=50.0)
joint5.angle_limit.add(min=-360, max=360)
joint5.parent_offset.x = 0.2
joint5.child_offset.y = -0.45
joint5.rotation.y = -90
joint6 = conf.joints.add(name='joint6', parent='link4', child='link5', angular_damping=50.0)
joint6.angle_limit.add(min=-360, max=360)
joint6.parent_offset.x = 0.2
joint6.child_offset.y = -0.05
joint6.rotation.y = -90
if(left_claw):
joint7 = conf.joints.add(name='joint7', parent='link2', child='link6', angular_damping=50.0)
joint7.angle_limit.add(min=-75, max=75)
joint7.parent_offset.y = -0.2
joint7.parent_offset.x = -0.1
joint7.child_offset.x = 0.2
joint7.rotation.y = 90
joint8 = conf.joints.add(name='joint8', parent='link2', child='link7', angular_damping=50.0)
joint8.angle_limit.add(min=-360, max=360)
joint8.parent_offset.y = 0.2
joint8.parent_offset.x = -0.1
joint8.child_offset.x = 0.2
joint8.rotation.y = 90
joint9 = conf.joints.add(name='joint9', parent='link6', child='link8', angular_damping=50.0)
joint9.angle_limit.add(min=-360, max=360)
joint9.parent_offset.x = -0.2
joint9.child_offset.y = -0.45
joint9.rotation.y = 90
joint10 = conf.joints.add(name='joint10', parent='link7', child='link8', angular_damping=50.0)
joint10.angle_limit.add(min=-360, max=360)
joint10.parent_offset.x = -0.2
joint10.child_offset.y = -0.05
joint10.rotation.y = 90
actuator1 = conf.actuators.add(name='joint1', joint='joint1', strength=100.).torque
actuator1.SetInParent()
actuator2 = conf.actuators.add(name='joint2', joint='joint2', strength=100.).torque
actuator2.SetInParent()
if(right_claw):
actuator3 = conf.actuators.add(name='joint3', joint='joint3', strength=100.).torque
actuator3.SetInParent()
if(left_claw):
actuator4 = conf.actuators.add(name='joint7', joint='joint7', strength=100.).torque
actuator4.SetInParent()
sys = brax.System(conf)
qps = [sys.default_qp()]
for i in range(100):
qps.append(sys.step(qps[-1], [0, 0, 1, 1])[0])
HTML(html.render(sys, qps))
Is the angular damping supposed to take negative values? Not sure, just shooting from the hip.
Ive had similar issues, when dealing with situations where multiple contacts can be generated between a single pair of bodies; they are updated together which compromises unconditional stability. Hacking in some contact compliance can be one simple fix; but im not positive thats your issue here.
EDIT: that is, fiddle a positive constant into here instead of the zero. Note you might need to do this in to TwoWayCollider class lower in the code as well if the problem arises between the two bodies rather than with the ground plane.