Official Python Interface for the Bullet Physics SDK specialized for Robotics Simulation and Reinforcement Learning
—
Configure simulation parameters, gravity, time stepping, and advanced physics engine settings for optimal performance and realistic behavior. Essential for tuning simulations for specific applications and achieving desired accuracy-performance trade-offs.
Set global forces that affect all objects in the simulation.
def setGravity(gravX, gravY, gravZ, physicsClientId=0):
"""
Set gravity acceleration vector for the simulation.
Args:
gravX (float): Gravity acceleration in X direction (m/s²)
gravY (float): Gravity acceleration in Y direction (m/s²)
gravZ (float): Gravity acceleration in Z direction (m/s²)
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
Earth gravity: [0, 0, -9.81]
Moon gravity: [0, 0, -1.62]
Zero gravity: [0, 0, 0]
Custom directions: e.g., [0, -9.81, 0] for Y-up coordinate system
"""Control simulation timing and temporal resolution.
def setTimeStep(timeStep, physicsClientId=0):
"""
Set simulation time step size.
Args:
timeStep (float): Time step in seconds (typically 1/240 to 1/60)
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
Smaller time steps provide higher accuracy but slower simulation.
Common values:
- 1/240 (0.00416s): High precision, good for complex simulations
- 1/120 (0.00833s): Good balance of speed and accuracy
- 1/60 (0.01667s): Fast simulation, lower accuracy
"""Configure contact behavior and error correction.
def setDefaultContactERP(defaultContactERP, physicsClientId=0):
"""
Set default Error Recovery Parameter for contact constraints.
Args:
defaultContactERP (float): ERP value (0.0 to 1.0)
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
ERP controls how quickly interpenetration is resolved.
Higher values = faster resolution but less stability.
Typical range: 0.1 to 0.8
"""Fine-tune internal physics engine behavior for performance and accuracy.
def setPhysicsEngineParameter(fixedTimeStep=None, numSolverIterations=None, useSplitImpulse=None, splitImpulsePenetrationThreshold=None, numSubSteps=None, collisionFilterMode=None, contactBreakingThreshold=None, maxNumCmdPer1ms=None, enableFileCaching=None, restitutionVelocityThreshold=None, erp=None, contactERP=None, frictionERP=None, enableConeFriction=None, deterministicOverlappingPairs=None, allowedCcdPenetration=None, jointFeedbackMode=None, solverResidualThreshold=None, contactSlop=None, enableSAT=None, constraintSolverType=None, minimumSolverIslandSize=None, reportSolverAnalytics=None, warmStartingFactor=None, articulatedWarmStartingFactor=None, physicsClientId=0):
"""
Set advanced physics engine parameters for fine-tuning performance and behavior.
Args:
fixedTimeStep (float, optional): Fixed time step size override
numSolverIterations (int, optional): Number of constraint solver iterations (default: 50)
useSplitImpulse (int, optional): Use split impulse for penetration recovery (0/1)
splitImpulsePenetrationThreshold (float, optional): Threshold for split impulse activation
numSubSteps (int, optional): Number of sub-steps per simulation step (default: 1)
collisionFilterMode (int, optional): Collision filtering mode
contactBreakingThreshold (float, optional): Distance threshold for contact breaking
maxNumCmdPer1ms (int, optional): Maximum commands processed per millisecond
enableFileCaching (int, optional): Enable file caching for faster loading (0/1)
restitutionVelocityThreshold (float, optional): Velocity threshold for restitution
erp (float, optional): Global error recovery parameter
contactERP (float, optional): Contact-specific ERP
frictionERP (float, optional): Friction-specific ERP
enableConeFriction (int, optional): Enable cone friction model (0/1)
deterministicOverlappingPairs (int, optional): Deterministic overlapping pair handling (0/1)
allowedCcdPenetration (float, optional): Allowed penetration for CCD
jointFeedbackMode (int, optional): Joint feedback computation mode
solverResidualThreshold (float, optional): Solver convergence threshold
contactSlop (float, optional): Contact slop parameter for stability
enableSAT (int, optional): Enable Separating Axis Theorem (0/1)
constraintSolverType (int, optional): Constraint solver algorithm type
minimumSolverIslandSize (int, optional): Minimum size for solver islands
reportSolverAnalytics (int, optional): Enable solver analytics reporting (0/1)
warmStartingFactor (float, optional): Warm starting factor for solver
articulatedWarmStartingFactor (float, optional): Warm starting for articulated bodies
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
These parameters significantly affect simulation behavior and performance.
Modify carefully and test thoroughly. Default values work well for most applications.
"""
def getPhysicsEngineParameters(physicsClientId=0):
"""
Get current physics engine parameters.
Args:
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Returns:
dict: Dictionary containing all current physics engine parameters
"""Control experimental and advanced simulation features.
def setInternalSimFlags(flags, physicsClientId=0):
"""
Set internal simulation flags (experimental features).
Args:
flags (int): Bitwise combination of internal simulation flags
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Warning:
These are experimental features that may change or be removed.
Use with caution in production code.
"""import pybullet as p
def setupHighPrecisionPhysics():
"""Configure physics for maximum accuracy."""
p.setTimeStep(1./240.) # Small time step
p.setGravity(0, 0, -9.81)
p.setPhysicsEngineParameter(
numSolverIterations=100, # More solver iterations
useSplitImpulse=1,
splitImpulsePenetrationThreshold=-0.001,
contactBreakingThreshold=0.001,
solverResidualThreshold=1e-7,
numSubSteps=1
)import pybullet as p
def setupHighPerformancePhysics():
"""Configure physics for maximum speed."""
p.setTimeStep(1./60.) # Larger time step
p.setGravity(0, 0, -9.81)
p.setPhysicsEngineParameter(
numSolverIterations=20, # Fewer iterations
useSplitImpulse=0,
enableFileCaching=1,
numSubSteps=1,
deterministicOverlappingPairs=0
)import pybullet as p
def setupRoboticsPhysics():
"""Configure physics optimized for robotics applications."""
p.setTimeStep(1./240.)
p.setGravity(0, 0, -9.81)
p.setPhysicsEngineParameter(
numSolverIterations=50,
useSplitImpulse=1,
splitImpulsePenetrationThreshold=-0.004,
contactBreakingThreshold=0.001,
restitutionVelocityThreshold=0.2,
enableConeFriction=1,
warmStartingFactor=0.85
)import pybullet as p
def setupSoftBodyPhysics():
"""Configure physics for soft body simulation."""
p.setTimeStep(1./240.)
p.setGravity(0, 0, -9.81)
p.setPhysicsEngineParameter(
numSolverIterations=150, # More iterations for soft bodies
useSplitImpulse=1,
numSubSteps=4, # More sub-steps for stability
contactBreakingThreshold=0.0001,
solverResidualThreshold=1e-6
)import pybullet as p
p.connect(p.GUI)
# Standard Earth-like physics
p.setGravity(0, 0, -9.81)
p.setTimeStep(1./240.)
# Load objects and run simulation
robotId = p.loadURDF("pr2_gripper.urdf")
for step in range(1000):
p.stepSimulation()import pybullet as p
p.connect(p.GUI)
# Simulate low gravity environment (Moon-like)
p.setGravity(0, 0, -1.62) # Moon gravity
p.setTimeStep(1./240.)
# Or simulate microgravity
# p.setGravity(0, 0, -0.01)
# Load objects - they will fall slowly
cubeId = p.loadURDF("cube.urdf", [0, 0, 2])
for step in range(2000): # Longer simulation to see slow motion
p.stepSimulation()import pybullet as p
import time
p.connect(p.DIRECT) # No GUI for maximum performance
# Performance-optimized settings
p.setTimeStep(1./60.) # Larger time step
p.setGravity(0, 0, -9.81)
# Optimize physics engine
p.setPhysicsEngineParameter(
numSolverIterations=20, # Reduce solver iterations
enableFileCaching=1, # Enable caching
deterministicOverlappingPairs=0, # Faster collision detection
useSplitImpulse=0 # Disable for speed
)
# Load many objects for stress test
objects = []
for i in range(100):
x = (i % 10) * 0.5
y = (i // 10) * 0.5
objId = p.loadURDF("cube.urdf", [x, y, 1])
objects.append(objId)
# Measure performance
start_time = time.time()
num_steps = 1000
for step in range(num_steps):
p.stepSimulation()
end_time = time.time()
elapsed = end_time - start_time
fps = num_steps / elapsed
print(f"Simulation FPS: {fps:.1f}")
print(f"Simulated time: {num_steps * (1./60.):.2f} seconds")
print(f"Real time: {elapsed:.2f} seconds")
print(f"Speed ratio: {(num_steps * (1./60.)) / elapsed:.1f}x real-time")import pybullet as p
import numpy as np
def testPhysicsAccuracy(timeStep, solverIterations):
"""Test physics accuracy with different parameters."""
p.resetSimulation()
p.setTimeStep(timeStep)
p.setGravity(0, 0, -9.81)
p.setPhysicsEngineParameter(numSolverIterations=solverIterations)
# Drop object from known height
cubeId = p.loadURDF("cube.urdf", [0, 0, 5])
# Theoretical time to fall: t = sqrt(2h/g) = sqrt(10/9.81) ≈ 1.01s
theoretical_time = np.sqrt(10 / 9.81)
positions = []
times = []
for step in range(int(theoretical_time * 1.5 / timeStep)):
p.stepSimulation()
pos, _ = p.getBasePositionAndOrientation(cubeId)
positions.append(pos[2])
times.append(step * timeStep)
# Stop when object hits ground
if pos[2] < 0.05:
actual_time = step * timeStep
break
error = abs(actual_time - theoretical_time)
return actual_time, theoretical_time, error
# Test different configurations
configs = [
(1./240., 50), # Standard
(1./120., 50), # Faster time step
(1./240., 20), # Fewer iterations
(1./240., 100), # More iterations
]
print("TimeStep | Iterations | Actual | Theoretical | Error")
print("-" * 50)
for timeStep, iterations in configs:
p.connect(p.DIRECT)
actual, theoretical, error = testPhysicsAccuracy(timeStep, iterations)
print(f"{timeStep:8.5f} | {iterations:10d} | {actual:6.3f} | {theoretical:11.3f} | {error:5.3f}")
p.disconnect()import pybullet as p
p.connect(p.GUI)
p.setGravity(0, 0, -9.81)
# Start with standard settings
p.setTimeStep(1./240.)
p.setPhysicsEngineParameter(numSolverIterations=50)
robotId = p.loadURDF("kuka_iiwa/model.urdf")
simulation_phase = 0
step_count = 0
for total_step in range(3000):
# Change physics parameters during simulation
if total_step == 1000:
print("Switching to high precision mode...")
p.setPhysicsEngineParameter(
numSolverIterations=100,
solverResidualThreshold=1e-7
)
simulation_phase = 1
elif total_step == 2000:
print("Switching to high performance mode...")
p.setTimeStep(1./120.)
p.setPhysicsEngineParameter(
numSolverIterations=20,
solverResidualThreshold=1e-4
)
simulation_phase = 2
p.stepSimulation()
# Monitor performance impact
if total_step % 500 == 0:
print(f"Step {total_step}, Phase {simulation_phase}")import pybullet as p
p.connect(p.GUI)
p.setGravity(0, 0, -9.81)
# Load objects for contact testing
planeId = p.loadURDF("plane.urdf")
cubeId = p.loadURDF("cube.urdf", [0, 0, 2])
# Experiment with different contact parameters
contact_configs = [
{"erp": 0.2, "description": "Soft contacts"},
{"erp": 0.8, "description": "Stiff contacts"},
{"contactBreakingThreshold": 0.001, "description": "Precise contacts"},
{"restitutionVelocityThreshold": 0.1, "description": "Low restitution threshold"}
]
for i, config in enumerate(contact_configs):
p.resetSimulation()
p.setGravity(0, 0, -9.81)
# Apply configuration
p.setPhysicsEngineParameter(**{k: v for k, v in config.items() if k != "description"})
# Reload objects
planeId = p.loadURDF("plane.urdf")
cubeId = p.loadURDF("cube.urdf", [0, 0, 2])
print(f"\nTesting: {config['description']}")
# Run simulation and monitor contacts
max_force = 0
for step in range(500):
p.stepSimulation()
contacts = p.getContactPoints(cubeId, planeId)
if contacts:
force = contacts[0][9] # Normal force
max_force = max(max_force, force)
print(f"Maximum contact force: {max_force:.2f} N")Install with Tessl CLI
npx tessl i tessl/pypi-pybullet