Official Python Interface for the Bullet Physics SDK specialized for Robotics Simulation and Reinforcement Learning
—
Save and restore simulation states, log data for analysis, and manage user-defined data attachments. Essential for reproducible experiments, data collection, and simulation checkpointing.
def saveState(physicsClientId=0):
"""
Save complete world state to memory.
Args:
physicsClientId (int, optional): Physics client ID
Returns:
int: State unique ID for later restoration
"""
def restoreState(stateId, fileName=None, physicsClientId=0):
"""
Restore world state from saved state ID or file.
Args:
stateId (int): State unique ID (if restoring from memory)
fileName (str, optional): File name (if restoring from file)
physicsClientId (int, optional): Physics client ID
"""
def removeState(stateId, physicsClientId=0):
"""
Remove saved state from memory.
Args:
stateId (int): State unique ID to remove
physicsClientId (int, optional): Physics client ID
"""
def loadBullet(bulletFileName, physicsClientId=0):
"""
Load world state from .bullet file.
Args:
bulletFileName (str): Path to .bullet file
physicsClientId (int, optional): Physics client ID
Returns:
list: List of loaded object IDs
"""
def saveBullet(bulletFileName, physicsClientId=0):
"""
Save complete world state to .bullet file.
Args:
bulletFileName (str): Output .bullet file path
physicsClientId (int, optional): Physics client ID
"""
def saveWorld(worldFileName, physicsClientId=0):
"""
Save world as approximate Python script.
Args:
worldFileName (str): Output Python file path
physicsClientId (int, optional): Physics client ID
"""def startStateLogging(loggingType, fileName, objectUniqueIds=None, maxLogDof=None, bodyUniqueIdA=None, bodyUniqueIdB=None, linkIndexA=None, linkIndexB=None, physicsClientId=0):
"""
Start logging simulation data to file.
Args:
loggingType (int): Type of logging (STATE_LOGGING_VIDEO_MP4, etc.)
fileName (str): Output file name
objectUniqueIds (list, optional): Objects to log
maxLogDof (int, optional): Maximum degrees of freedom to log
Returns:
int: Logging unique ID
"""
def stopStateLogging(loggingUniqueId, physicsClientId=0):
"""
Stop data logging.
Args:
loggingUniqueId (int): Logging unique ID from startStateLogging
physicsClientId (int, optional): Physics client ID
"""def addUserData(bodyUniqueId, key, value, linkIndex=-1, visualShapeIndex=-1, physicsClientId=0):
"""
Add or update user data entry for object.
Args:
bodyUniqueId (int): Object unique ID
key (str): Data key identifier
value (str): Data value
linkIndex (int, optional): Link index (-1 for base)
visualShapeIndex (int, optional): Visual shape index
physicsClientId (int, optional): Physics client ID
Returns:
int: User data unique ID
"""
def getUserData(userDataId, physicsClientId=0):
"""
Get user data value by ID.
Args:
userDataId (int): User data unique ID
physicsClientId (int, optional): Physics client ID
Returns:
str: User data value
"""
def getUserDataId(bodyUniqueId, key, linkIndex=-1, visualShapeIndex=-1, physicsClientId=0):
"""
Get user data ID by key.
Args:
bodyUniqueId (int): Object unique ID
key (str): Data key identifier
linkIndex (int, optional): Link index
visualShapeIndex (int, optional): Visual shape index
physicsClientId (int, optional): Physics client ID
Returns:
int: User data unique ID
"""
def removeUserData(userDataId, physicsClientId=0):
"""
Remove user data entry.
Args:
userDataId (int): User data unique ID
physicsClientId (int, optional): Physics client ID
"""
def getNumUserData(bodyUniqueId, physicsClientId=0):
"""
Get number of user data entries for object.
Args:
bodyUniqueId (int): Object unique ID
physicsClientId (int, optional): Physics client ID
Returns:
int: Number of user data entries
"""
def getUserDataInfo(bodyUniqueId, userDataIndex, physicsClientId=0):
"""
Get user data information by index.
Args:
bodyUniqueId (int): Object unique ID
userDataIndex (int): User data index (0 to getNumUserData-1)
physicsClientId (int, optional): Physics client ID
Returns:
tuple: (userDataId, key, bodyUniqueId, linkIndex, visualShapeIndex)
"""
def syncUserData(bodyUniqueIds=None, physicsClientId=0):
"""
Synchronize user data from server.
Args:
bodyUniqueIds (list, optional): Specific objects to sync
physicsClientId (int, optional): Physics client ID
"""import pybullet as p
import time
p.connect(p.GUI)
p.setGravity(0, 0, -9.81)
# Set up initial scene
p.loadURDF("plane.urdf")
cube_id = p.loadURDF("cube_small.urdf", [0, 0, 1])
robot_id = p.loadURDF("r2d2.urdf", [1, 0, 1])
# Simulate for a while
for i in range(100):
p.stepSimulation()
time.sleep(1./240.)
# Save current state
state_id = p.saveState()
print(f"Saved state with ID: {state_id}")
# Continue simulation and make changes
p.applyExternalForce(cube_id, -1, [10, 0, 0], [0, 0, 0], p.WORLD_FRAME)
for i in range(100):
p.stepSimulation()
time.sleep(1./240.)
cube_pos, _ = p.getBasePositionAndOrientation(cube_id)
print(f"Cube position after force: {cube_pos}")
# Restore to saved state
p.restoreState(state_id)
# Verify restoration
cube_pos_restored, _ = p.getBasePositionAndOrientation(cube_id)
print(f"Cube position after restore: {cube_pos_restored}")
# Clean up
p.removeState(state_id)import pybullet as p
p.connect(p.GUI)
p.setGravity(0, 0, -9.81)
# Create scene
plane_id = p.loadURDF("plane.urdf")
cube_id = p.loadURDF("cube_small.urdf", [0, 0, 1])
# Save to file
p.saveBullet("my_simulation.bullet")
print("Saved simulation to bullet file")
# Save as Python script (approximate)
p.saveWorld("recreate_simulation.py")
print("Saved world recreation script")
# Reset and load from file
p.resetSimulation()
loaded_objects = p.loadBullet("my_simulation.bullet")
print(f"Loaded objects: {loaded_objects}")import pybullet as p
import time
p.connect(p.GUI)
p.setGravity(0, 0, -9.81)
# Set up scene
plane_id = p.loadURDF("plane.urdf")
robot_id = p.loadURDF("r2d2.urdf", [0, 0, 1])
# Start video logging
video_log = p.startStateLogging(
loggingType=p.STATE_LOGGING_VIDEO_MP4,
fileName="simulation_video.mp4"
)
# Start generic robot state logging
robot_log = p.startStateLogging(
loggingType=p.STATE_LOGGING_GENERIC_ROBOT,
fileName="robot_states.txt",
objectUniqueIds=[robot_id],
maxLogDof=7
)
# Run simulation with logging
num_joints = p.getNumJoints(robot_id)
joint_indices = list(range(num_joints))
for step in range(500):
# Apply some control
if num_joints > 0:
target_positions = [0.1 * step * ((-1) ** i) for i in range(num_joints)]
p.setJointMotorControlArray(
robot_id, joint_indices, p.POSITION_CONTROL,
targetPositions=target_positions
)
p.stepSimulation()
time.sleep(1./240.)
# Stop logging
p.stopStateLogging(video_log)
p.stopStateLogging(robot_log)
print("Logging completed")import pybullet as p
p.connect(p.GUI)
plane_id = p.loadURDF("plane.urdf")
robot_id = p.loadURDF("r2d2.urdf", [0, 0, 1])
# Add user data to robot
metadata_id = p.addUserData(robot_id, "robot_type", "R2-D2")
config_id = p.addUserData(robot_id, "max_speed", "2.5")
author_id = p.addUserData(robot_id, "created_by", "Luke Skywalker")
# Retrieve user data
robot_type = p.getUserData(metadata_id)
max_speed = p.getUserData(config_id)
print(f"Robot type: {robot_type}, Max speed: {max_speed}")
# Find user data by key
speed_id = p.getUserDataId(robot_id, "max_speed")
speed_value = p.getUserData(speed_id)
print(f"Found max_speed: {speed_value}")
# List all user data
num_data = p.getNumUserData(robot_id)
print(f"Robot has {num_data} user data entries:")
for i in range(num_data):
data_info = p.getUserDataInfo(robot_id, i)
data_id, key, body_id, link_idx, shape_idx = data_info
value = p.getUserData(data_id)
print(f" {key}: {value}")
# Remove user data
p.removeUserData(config_id)
print(f"Removed max_speed data, now has {p.getNumUserData(robot_id)} entries")
# Sync user data (useful in multi-client scenarios)
p.syncUserData([robot_id])# State logging types
p.STATE_LOGGING_VIDEO_MP4 # MP4 video recording
p.STATE_LOGGING_GENERIC_ROBOT # Robot state data
p.STATE_LOGGING_CONTACT_POINTS # Contact point information
p.STATE_LOGGING_VR_CONTROLLERS # VR controller states
p.STATE_LOGGING_MINITAUR # Minitaur-specific loggingInstall with Tessl CLI
npx tessl i tessl/pypi-pybullet