Instalación y entorno de desarrollo Se recomienda utilizar un entorno con conda para gestionar dependencias. En este caso, se asume que ya se ha creado un antorno llamado aloha:
conda activate aloha
pip install pybullet
Para evitar errores de compatibilidad con versiones de gym, se instala una versión específica:
pip install gym==0.23.1
Este paso es crucial si se intenta ejecutar ejemplos de entornos predefinidos como TF_HumanoidFlagrunHarderBulletEnv_v1_2017jul.
Adición del modelo UR10 a PyBullet El archivo URDF del robot UR10 debe colocarse en el directorio de datos de PyBullet. La ruta típica es:
/home/robot/anaconda3/envs/aloha/lib/python3.8/site-packages/pybullet_data/ur10/ur10.urdf
Este archivo puede obtenerse desde repositorios confiables o adaptarse desde modelos públicos. Una versión modificada está disponible en mi repositorio GitHub.
Una vez ubicado el archivo correctamente, se puede cargar el modelo con una sola línea:
robotId = p.loadURDF("ur10/ur10.urdf", useFixedBase=True)
Simulación básica con control interactivo A continuación, un ejemplo mínimo para iniciar la simulación y permitir manipulación con el mouse:
import pybullet as p
import pybullet_data
# Conexión al motor físico
physicsClient = p.connect(p.GUI)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.setGravity(0, 0, -9.81)
# Ajuste de cámara
p.resetDebugVisualizerCamera(cameraDistance=2, cameraYaw=0, cameraPitch=-40, cameraTargetPosition=[0.5, -0.9, 0.5])
# Carga del plano y del robot
planeId = p.loadURDF("plane.urdf")
robotId = p.loadURDF("ur10/ur10.urdf", useFixedBase=True)
# Posición inicial del robot
startPos = [0, 0, 0.625]
startOrientation = p.getQuaternionFromEuler([0, 0, 0])
p.resetBasePositionAndOrientation(robotId, startPos, startOrientation)
# Modo de tiempo real
p.setRealTimeSimulation(1)
while True:
p.stepSimulation()
time.sleep(1/240)
Este script permite visualizar el robot y mover su extremo mediante el ratón.
Incorporación de objetos personalizados con texturas y colisiones Para añadir objetos como tazas o platos con texturas (archivos .obj, .mtl, .png), es necesario definir tanto formas visuales como colisiones:
import pybullet as p
import pybullet_data as pd
import math
def load_custom_objects():
# Inicialización
physicsClient = p.connect(p.GUI)
p.setAdditionalSearchPath(pd.getDataPath())
p.setGravity(0, 0, -9.81)
p.resetDebugVisualizerCamera(cameraDistance=2, cameraYaw=0, cameraPitch=-40, cameraTargetPosition=[0.5, -0.9, 0.5])
# Escenario base
planeId = p.loadURDF("plane.urdf")
robotId = p.loadURDF("ur10/ur10.urdf", useFixedBase=True)
# Cargar mesa
tableUid = p.loadURDF("table/table.urdf", basePosition=[0, 0, 0])
# Rutas de los modelos personalizados
cup_path = "/home/robot/FoundationPose/my_policy_data/new_demo_02/new_cup_code/mesh/untitled.obj"
plate_path = "/home/robot/FoundationPose/my_policy_data/new_demo_02/new_plate/mesh/untitled.obj"
# Definir formas visuales y de colisión
cup_visual = p.createVisualShape(
shapeType=p.GEOM_MESH,
fileName=cup_path,
meshScale=[1, 1, 1]
)
cup_collision = p.createCollisionShape(
shapeType=p.GEOM_MESH,
fileName=cup_path,
meshScale=[1, 1, 1]
)
plate_visual = p.createVisualShape(
shapeType=p.GEOM_MESH,
fileName=plate_path,
meshScale=[1, 1, 1]
)
plate_collision = p.createCollisionShape(
shapeType=p.GEOM_MESH,
fileName=plate_path,
meshScale=[1, 1, 1]
)
# Crear cuerpos rígidos
cup_id = p.createMultiBody(
baseMass=0.5,
baseCollisionShapeIndex=cup_collision,
baseVisualShapeIndex=cup_visual,
basePosition=[-0.5, -0.3, 0.625],
baseOrientation=p.getQuaternionFromEuler([1.57, 0, 0])
)
plate_id = p.createMultiBody(
baseMass=0.5,
baseCollisionShapeIndex=plate_collision,
baseVisualShapeIndex=plate_visual,
basePosition=[-0.5, 0.3, 0.625],
baseOrientation=p.getQuaternionFromEuler([0, 0, 0])
)
# Posición inicial del robot sobre la mesa
p.resetBasePositionAndOrientation(robotId, [0, 0, 0.625], p.getQuaternionFromEuler([0, 0, 0]))
p.setRealTimeSimulation(1)
while True:
# Detección de colisiones entre robot y taza
contacts = p.getContactPoints(bodyA=robotId, bodyB=cup_id)
if contacts:
print("Colisión detectada: taza y brazo robótico")
p.stepSimulation()
time.sleep(1/240)
if __name__ == "__main__":
load_custom_objects()
Este código incluye detección de contacto en tiempo real y muestra cómo integrar modelos complejos con materiales y geometrías reales.
Integración de pinza Robotiq 85 y sensores La adición de la pinza Robotiq 85 requiere un archivo URDF modificado que incluya los grados de libertad del manipulador y sus sensores. Se deben definir:
- Canales de entrada/salida para el control de apertura/cierre.
- Sensores de fuerza/tacto (simulados o basados en contactos).
- Configuración de actuadores y limites de movimiento.
Esto se realiza mediante p.loadURDF() con el modelo adecuado y posterior configuración de motores usando p.setJointMotorControl.