Official Python Interface for the Bullet Physics SDK specialized for Robotics Simulation and Reinforcement Learning
—
Comprehensive joint control capabilities including position, velocity, and torque control with PD controllers, multi-DOF joint support, and force/torque sensing. Essential for robotic manipulation, locomotion, and precise motion control.
Query joint properties, constraints, and current state for control and analysis.
def getNumJoints(bodyUniqueId, physicsClientId=0):
"""
Get number of joints for a multibody.
Args:
bodyUniqueId (int): Body unique ID
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Returns:
int: Number of joints in the body
"""
def getJointInfo(bodyUniqueId, jointIndex, physicsClientId=0):
"""
Get comprehensive joint information.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index (0 to getNumJoints-1)
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Returns:
tuple: Joint information containing:
- jointIndex (int): Joint index
- jointName (str): Joint name from URDF
- jointType (int): Joint type constant (p.JOINT_REVOLUTE, etc.)
- qIndex (int): Position index in generalized coordinates
- uIndex (int): Velocity index in generalized coordinates
- flags (int): Joint flags
- jointDamping (float): Joint damping coefficient
- jointFriction (float): Joint friction coefficient
- jointLowerLimit (float): Lower position limit
- jointUpperLimit (float): Upper position limit
- jointMaxForce (float): Maximum force/torque
- jointMaxVelocity (float): Maximum velocity
- linkName (str): Link name from URDF
- jointAxis (list): Joint axis in local frame [x, y, z]
- parentFramePos (list): Position in parent frame [x, y, z]
- parentFrameOrn (list): Orientation in parent frame [x, y, z, w]
- parentIndex (int): Parent link index
"""
def getJointState(bodyUniqueId, jointIndex, physicsClientId=0):
"""
Get current joint state including position, velocity, and forces.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Returns:
tuple: Joint state containing:
- jointPosition (float): Current joint position
- jointVelocity (float): Current joint velocity
- jointReactionForces (list): Reaction forces/torques [Fx, Fy, Fz, Mx, My, Mz]
- appliedJointMotorTorque (float): Applied motor torque
"""
def getJointStates(bodyUniqueId, jointIndices, physicsClientId=0):
"""
Get multiple joint states efficiently.
Args:
bodyUniqueId (int): Body unique ID
jointIndices (list): List of joint indices
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Returns:
list: List of joint state tuples (same format as getJointState)
"""Support for joints with multiple degrees of freedom (spherical joints, planar joints).
def getJointStateMultiDof(bodyUniqueId, jointIndex, physicsClientId=0):
"""
Get multi-DOF joint state (for spherical and planar joints).
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Returns:
tuple: Multi-DOF joint state containing:
- jointPosition (list): Position values (length depends on DOF)
- jointVelocity (list): Velocity values
- jointReactionForces (list): Reaction forces/torques
- appliedJointMotorTorque (list): Applied motor torques
"""
def getJointStatesMultiDof(bodyUniqueId, jointIndices, physicsClientId=0):
"""
Get multiple multi-DOF joint states efficiently.
Returns:
list: List of multi-DOF joint state tuples
"""Reset joint positions and velocities directly for initialization and testing.
def resetJointState(bodyUniqueId, jointIndex, targetValue, targetVelocity=0, physicsClientId=0):
"""
Reset joint state immediately (teleport).
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
targetValue (float): Target joint position
targetVelocity (float, optional): Target joint velocity. Defaults to 0.
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
This function immediately sets joint state without physics simulation.
Use for initialization or testing scenarios.
"""
def resetJointStateMultiDof(bodyUniqueId, jointIndex, targetValue, targetVelocity=None, physicsClientId=0):
"""
Reset multi-DOF joint state immediately.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
targetValue (list): Target joint positions
targetVelocity (list, optional): Target joint velocities
physicsClientId (int, optional): Physics client ID. Defaults to 0.
"""
def resetJointStatesMultiDof(bodyUniqueId, jointIndices, targetValues, targetVelocities=None, physicsClientId=0):
"""
Reset multiple multi-DOF joints efficiently.
"""Advanced motor control with multiple control modes and precise parameter tuning.
def setJointMotorControl2(bodyUniqueId, jointIndex, controlMode, targetPosition=None, targetVelocity=None, force=None, positionGain=None, velocityGain=None, maxVelocity=None, physicsClientId=0):
"""
Set joint motor control with advanced parameters.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
controlMode (int): Control mode constant:
- p.POSITION_CONTROL: Position control with PD controller
- p.VELOCITY_CONTROL: Velocity control
- p.TORQUE_CONTROL: Direct torque control
- p.PD_CONTROL: Pure PD control
- p.STABLE_PD_CONTROL: Stable PD control
targetPosition (float, optional): Target position (position control modes)
targetVelocity (float, optional): Target velocity (velocity/position control)
force (float, optional): Maximum force/torque to apply
positionGain (float, optional): Position gain (Kp) for PD control
velocityGain (float, optional): Velocity gain (Kd) for PD control
maxVelocity (float, optional): Maximum velocity limit
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
Different control modes require different parameter combinations:
- POSITION_CONTROL: targetPosition, force, positionGain, velocityGain
- VELOCITY_CONTROL: targetVelocity, force
- TORQUE_CONTROL: force (direct torque)
- PD_CONTROL: targetPosition, targetVelocity, force, positionGain, velocityGain
"""
def setJointMotorControlArray(bodyUniqueId, jointIndices, controlMode, targetPositions=None, targetVelocities=None, forces=None, positionGains=None, velocityGains=None, physicsClientId=0):
"""
Set motor control for multiple joints efficiently.
Args:
bodyUniqueId (int): Body unique ID
jointIndices (list): List of joint indices
controlMode (int): Control mode for all joints
targetPositions (list, optional): List of target positions
targetVelocities (list, optional): List of target velocities
forces (list, optional): List of maximum forces
positionGains (list, optional): List of position gains
velocityGains (list, optional): List of velocity gains
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
More efficient than individual setJointMotorControl2 calls.
All parameter lists must match length of jointIndices.
"""
def setJointMotorControlMultiDof(bodyUniqueId, jointIndex, controlMode, targetPosition=None, targetVelocity=None, force=None, positionGain=None, velocityGain=None, physicsClientId=0):
"""
Set motor control for multi-DOF joints.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
controlMode (int): Control mode
targetPosition (list, optional): Target positions for each DOF
targetVelocity (list, optional): Target velocities for each DOF
force (list, optional): Maximum forces for each DOF
positionGain (list, optional): Position gains for each DOF
velocityGain (list, optional): Velocity gains for each DOF
physicsClientId (int, optional): Physics client ID. Defaults to 0.
"""
def setJointMotorControlMultiDofArray(bodyUniqueId, jointIndices, controlMode, targetPositions=None, targetVelocities=None, forces=None, positionGains=None, velocityGains=None, physicsClientId=0):
"""
Set motor control for multiple multi-DOF joints efficiently.
"""Enable and configure joint force/torque sensors for feedback control and analysis.
def enableJointForceTorqueSensor(bodyUniqueId, jointIndex, enableSensor, physicsClientId=0):
"""
Enable or disable joint force/torque sensor.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
enableSensor (int): 1 to enable sensor, 0 to disable
physicsClientId (int, optional): Physics client ID. Defaults to 0.
Note:
When enabled, getJointState returns accurate reaction forces.
Adds computational overhead, so only enable when needed.
"""PID position controller with optional velocity feedforward.
Direct velocity control with maximum force limiting.
Direct force/torque application without position or velocity control.
Pure proportional-derivative control without built-in integrator.
Mathematically stable PD controller for improved performance.
import pybullet as p
import time
p.connect(p.GUI)
robotId = p.loadURDF("pr2_gripper.urdf")
# Get joint information
numJoints = p.getNumJoints(robotId)
for i in range(numJoints):
info = p.getJointInfo(robotId, i)
print(f"Joint {i}: {info[1]} (Type: {info[2]})")
# Position control for multiple joints
jointIndices = [0, 1, 2]
targetPositions = [0.5, -0.3, 0.8]
for step in range(1000):
p.setJointMotorControlArray(robotId,
jointIndices,
p.POSITION_CONTROL,
targetPositions=targetPositions,
forces=[100, 100, 100])
p.stepSimulation()
time.sleep(1./240.)import pybullet as p
p.connect(p.GUI)
robotId = p.loadURDF("kuka_iiwa/model.urdf")
# High-performance PD control with custom gains
jointIndex = 1
targetPosition = 1.57 # 90 degrees
# Tuned PD gains for precise control
positionGain = 0.3 # Kp
velocityGain = 1.0 # Kd
for step in range(1000):
# Get current joint state for monitoring
jointState = p.getJointState(robotId, jointIndex)
currentPos = jointState[0]
currentVel = jointState[1]
# Apply PD control
p.setJointMotorControl2(robotId,
jointIndex,
p.PD_CONTROL,
targetPosition=targetPosition,
targetVelocity=0,
force=100,
positionGain=positionGain,
velocityGain=velocityGain)
p.stepSimulation()
# Print error for monitoring
if step % 100 == 0:
error = targetPosition - currentPos
print(f"Step {step}: Position error = {error:.4f}")import pybullet as p
import math
p.connect(p.GUI)
robotId = p.loadURDF("kuka_iiwa/model.urdf")
jointIndex = 2
scanSpeed = 0.5 # rad/s
for step in range(2000):
# Sinusoidal velocity profile for scanning
targetVelocity = scanSpeed * math.sin(step * 0.01)
p.setJointMotorControl2(robotId,
jointIndex,
p.VELOCITY_CONTROL,
targetVelocity=targetVelocity,
force=50)
p.stepSimulation()import pybullet as p
p.connect(p.GUI)
robotId = p.loadURDF("pr2_gripper.urdf")
# Enable force sensors for feedback
for i in range(p.getNumJoints(robotId)):
p.enableJointForceTorqueSensor(robotId, i, 1)
# Gravity compensation loop
for step in range(1000):
# Get current joint positions and velocities
numJoints = p.getNumJoints(robotId)
jointPositions = []
jointVelocities = []
for i in range(numJoints):
state = p.getJointState(robotId, i)
jointPositions.append(state[0])
jointVelocities.append(state[1])
# Calculate gravity compensation torques
gravityTorques = p.calculateInverseDynamics(robotId,
jointPositions,
[0] * numJoints, # Zero velocity
[0] * numJoints) # Zero acceleration
# Apply gravity compensation
for i in range(numJoints):
p.setJointMotorControl2(robotId, i, p.TORQUE_CONTROL, force=gravityTorques[i])
p.stepSimulation()import pybullet as p
p.connect(p.GUI)
# Create object with spherical joint
sphericalJointId = 0 # Assuming spherical joint at index 0
# Multi-DOF position control
targetPositions = [0.5, 0.3, 0.1] # 3 DOF for spherical joint
targetVelocities = [0, 0, 0]
forces = [10, 10, 10]
positionGains = [0.3, 0.3, 0.3]
velocityGains = [1, 1, 1]
for step in range(1000):
p.setJointMotorControlMultiDof(robotId,
sphericalJointId,
p.POSITION_CONTROL,
targetPosition=targetPositions,
targetVelocity=targetVelocities,
force=forces,
positionGain=positionGains,
velocityGain=velocityGains)
# Monitor multi-DOF joint state
if step % 100 == 0:
state = p.getJointStateMultiDof(robotId, sphericalJointId)
print(f"Spherical joint positions: {state[0]}")
p.stepSimulation()import pybullet as p
import numpy as np
p.connect(p.GUI)
robotId = p.loadURDF("kuka_iiwa/model.urdf")
# Define trajectory waypoints
waypoints = [
[0, 0, 0, 0, 0, 0, 0], # Home position
[0.5, -0.5, 0.8, -1.2, 0, 0.5, 0], # Waypoint 1
[1.0, 0, 1.5, -0.8, 0.3, -0.2, 0], # Waypoint 2
[0, 0, 0, 0, 0, 0, 0] # Return home
]
# Trajectory parameters
totalSteps = 2000
stepsPerSegment = totalSteps // (len(waypoints) - 1)
jointIndices = list(range(7)) # 7-DOF arm
for step in range(totalSteps):
# Calculate current segment and interpolation factor
segment = min(step // stepsPerSegment, len(waypoints) - 2)
t = (step % stepsPerSegment) / stepsPerSegment
# Linear interpolation between waypoints
currentWaypoint = waypoints[segment]
nextWaypoint = waypoints[segment + 1]
targetPositions = []
for i in range(len(jointIndices)):
pos = currentWaypoint[i] + t * (nextWaypoint[i] - currentWaypoint[i])
targetPositions.append(pos)
# Apply position control
p.setJointMotorControlArray(robotId,
jointIndices,
p.POSITION_CONTROL,
targetPositions=targetPositions,
forces=[100] * len(jointIndices))
p.stepSimulation()
# Monitor progress
if step % 200 == 0:
print(f"Step {step}, Segment {segment}, t={t:.2f}")def applyExternalForce(objectUniqueId, linkIndex, forceObj, posObj, flags, physicsClientId=0):
"""
Apply external force to an object or link.
Args:
objectUniqueId (int): Object unique ID
linkIndex (int): Link index (-1 for base)
forceObj (list): Force vector [Fx, Fy, Fz] in Newtons
posObj (list): Position where force is applied [x, y, z]
flags (int): Reference frame flag (WORLD_FRAME or LINK_FRAME)
physicsClientId (int, optional): Physics client ID
"""
def applyExternalTorque(objectUniqueId, linkIndex, torqueObj, flags, physicsClientId=0):
"""
Apply external torque to an object or link.
Args:
objectUniqueId (int): Object unique ID
linkIndex (int): Link index (-1 for base)
torqueObj (list): Torque vector [Tx, Ty, Tz] in Newton-meters
flags (int): Reference frame flag (WORLD_FRAME or LINK_FRAME)
physicsClientId (int, optional): Physics client ID
"""
def resetBaseVelocity(objectUniqueId, linearVelocity, angularVelocity, physicsClientId=0):
"""
Reset base linear and angular velocity.
Args:
objectUniqueId (int): Object unique ID
linearVelocity (list): Linear velocity [vx, vy, vz]
angularVelocity (list): Angular velocity [wx, wy, wz]
physicsClientId (int, optional): Physics client ID
"""
def resetJointState(bodyUniqueId, jointIndex, targetValue, targetVelocity=0, physicsClientId=0):
"""
Reset joint position and velocity.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
targetValue (float): Target joint position
targetVelocity (float, optional): Target joint velocity
physicsClientId (int, optional): Physics client ID
"""
def resetJointStateMultiDof(bodyUniqueId, jointIndex, targetValue, targetVelocity=None, physicsClientId=0):
"""
Reset multi-DOF joint state.
Args:
bodyUniqueId (int): Body unique ID
jointIndex (int): Joint index
targetValue (list): Target joint values
targetVelocity (list, optional): Target joint velocities
physicsClientId (int, optional): Physics client ID
"""import pybullet as p
import time
p.connect(p.GUI)
p.setGravity(0, 0, -9.81)
p.loadURDF("plane.urdf")
# Load objects
cube_id = p.loadURDF("cube_small.urdf", [0, 0, 1])
robot_id = p.loadURDF("r2d2.urdf", [1, 0, 1])
# Apply force to cube in world coordinates
for i in range(1000):
# Apply upward force to counteract gravity plus extra lift
p.applyExternalForce(
objectUniqueId=cube_id,
linkIndex=-1, # Base link
forceObj=[0, 0, 15], # Upward force in Newtons
posObj=[0, 0, 0], # At center of mass
flags=p.WORLD_FRAME
)
# Apply spinning torque to robot
p.applyExternalTorque(
objectUniqueId=robot_id,
linkIndex=-1,
torqueObj=[0, 0, 0.5], # Z-axis torque
flags=p.WORLD_FRAME
)
p.stepSimulation()
time.sleep(1./240.)
# Reset object velocities
p.resetBaseVelocity(cube_id, [0, 0, 0], [0, 0, 0])
p.resetBaseVelocity(robot_id, [0, 0, 0], [0, 0, 0])
# Reset joint to specific state
if p.getNumJoints(robot_id) > 0:
p.resetJointState(robot_id, 0, 0.5, 0) # Joint 0 to 0.5 rad, zero velocityInstall with Tessl CLI
npx tessl i tessl/pypi-pybullet