Ball Collision Simulation#

This example simulation shows how to use pybullet to render physics simulations in fury. In this example we render the collision between a blue ball and red ball and also display a message by confirming the collision.

First some imports.

import itertools

import numpy as np
import pybullet as p

import fury

client = p.connect(p.DIRECT)

Parameters and definition of red and blue balls.

red_radius = 0.5
blue_radius = 0.5
duration = 50

# Red Ball
red_ball_actor = fury.actor.sphere(
    centers=np.array([[0, 0, 0]]), colors=np.array([[1, 0, 0]]), radii=red_radius
)

red_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=red_radius)

red_ball = p.createMultiBody(
    baseMass=0.5,
    baseCollisionShapeIndex=red_ball_coll,
    basePosition=[10, 0, 0],
    baseOrientation=[0, 0, 0, 1],
)

# Blue ball
blue_ball_actor = fury.actor.sphere(
    centers=np.array([[0, 0, 0]]), colors=np.array([[0, 0, 1]]), radii=blue_radius
)

blue_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=blue_radius)

blue_ball = p.createMultiBody(
    baseMass=0.5,
    baseCollisionShapeIndex=blue_ball_coll,
    basePosition=[-10, 0, 0],
    baseOrientation=[0, 0, 0, 1],
)

We set the coefficient of restitution of both the balls to 0.6.

p.changeDynamics(red_ball, -1, restitution=0.6)
p.changeDynamics(blue_ball, -1, restitution=0.6)

We add all the actors to the scene.

scene = fury.window.Scene()
scene.add(fury.actor.axes())
scene.add(red_ball_actor)
scene.add(blue_ball_actor)

showm = fury.window.ShowManager(
    scene, size=(900, 700), reset_camera=False, order_transparent=True
)


counter = itertools.count()
/opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/sphinx_gallery/gen_rst.py:722: UserWarning: We'll no longer accept the way you call the __init__ function in future versions of FURY.

Here's how to call the Function __init__: __init__(self_value, scene='value', title='value', size='value', png_magnify='value', reset_camera='value', order_transparent='value', interactor_style='value', stereo='value', multi_samples='value', max_peels='value', occlusion_ratio='value')

  exec(self.code, self.fake_main.__dict__)

Method to sync objects.

def sync_actor(actor, multibody):
    pos, orn = p.getBasePositionAndOrientation(multibody)
    actor.SetPosition(*pos)
    orn_deg = np.degrees(p.getEulerFromQuaternion(orn))
    actor.SetOrientation(*orn_deg)


apply_force = True
tb = fury.ui.TextBlock2D(position=(0, 600), font_size=30, color=(1, 0.5, 0), text="")
scene.add(tb)
scene.set_camera(
    position=(0.30, -18.78, 0.89), focal_point=(0.15, 0.25, 0.40), view_up=(0, 0, 1.00)
)

Timer callback to sync and step simulation every second.

def timer_callback(_obj, _event):
    global apply_force
    cnt = next(counter)
    showm.render()
    red_pos, red_orn = p.getBasePositionAndOrientation(red_ball)
    blue_pos, blue_orn = p.getBasePositionAndOrientation(blue_ball)

    # Apply force for the first step of the simulation.
    if apply_force:
        p.applyExternalForce(
            red_ball, -1, forceObj=[-40000, 0, 0], posObj=red_pos, flags=p.WORLD_FRAME
        )

        p.applyExternalForce(
            blue_ball, -1, forceObj=[40000, 0, 0], posObj=blue_pos, flags=p.WORLD_FRAME
        )

        apply_force = 0

    sync_actor(blue_ball_actor, blue_ball)
    sync_actor(red_ball_actor, red_ball)

    # Get various collision information using `p.getContactPoints`.
    contact = p.getContactPoints(red_ball, blue_ball, -1, -1)
    if len(contact) != 0:
        tb.message = "Collision!!"

    p.stepSimulation()

    if cnt == 50:
        showm.exit()


showm.add_timer_callback(True, duration, timer_callback)

interactive = False

if interactive:
    showm.start()

fury.window.record(scene, size=(900, 700), out_path="viz_ball_collide.png")
viz ball collide
/opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/sphinx_gallery/gen_rst.py:722: UserWarning: We'll no longer accept the way you call the record function in future versions of FURY.

Here's how to call the Function record: record(scene='value', cam_pos='value', cam_focal='value', cam_view='value', out_path='value', path_numbering='value', n_frames='value', az_ang='value', magnification='value', size='value', reset_camera='value', screen_clip='value', stereo='value', verbose='value')

  exec(self.code, self.fake_main.__dict__)

Total running time of the script: (0 minutes 0.210 seconds)

Gallery generated by Sphinx-Gallery