Tutorial 00: Introduction

Tutorial Description

This tutorial covers creating the backend of a new project using condynsate. In this tutorial, we will cover how to:

  1. Import physics objects in the condynsate physics environment.

  2. Test that physics objects behave as expected.

We will accomplish these goals by importing a cube 1 meter above a solid ground plane, starting the physics engine, then observing the dynamics of the cube. Note that this project will not coverhow to create your own .URDF files. Instead, we recommend reviewing https://wiki.ros.org/urdf.

Imports

To begin, we import the required dependencies. In general, for projects that will simulate the physics of a set of urdf objects, the only module needed from the condynsate project is condynsate.simulator. Note that we also import condynsate.__assets__ so that we can load and use a condynsate default cube .URDF file.

[1]:
from condynsate import Simulator as con_sim
from condynsate import __assets__ as assets

To see what default .URDF files are available to us, we can list the keys of assets:

[2]:
assets.keys()
[2]:
dict_keys(['cart', 'check_img', 'concrete_img', 'cube', 'double_pendulum', 'gyro', 'pendulum', 'plane_big', 'sphere', 'target_arrow', 'wheel'])

Building the Project Class

The Project class is that object that front end users interact with. In its simplest form, the Project class contains two class functions: __init__ and run. In __init__ the physics engine is initialized, .URDF files are imported into the engine, and initial conditions are set. In run initial conditions are reset, and the physics engine is turned on.

[3]:
class Project():
    def __init__(self):
        '''
        ##################################################################
        STEP 1: Initialize an instance of the condynsate.simulator class.
        Note that for this project, we do not want to use animation.
        This means that we do not want to plot things in real time.
        To avoid condynsate from assuming that we want to do this and
        running some things in the background that take compute power,
        we simply set the animation flag in the initialization function
        to be false. We also do not want to use the keyboard for
        interactivity, so we set keyboard to False.
        ##################################################################
        '''
        self.s = con_sim(animation = False,
                        keyboard  = False)

        '''
        ##################################################################
        STEP 2: Add solid ground to the physics environment. Condynsate
        already includes several default .URDF files that are listed in
        the  condynsate.__assets__ variable. To load any one of these,
        we simply  select the path to the asset we want and call the
        load_urdf function.

        load_urdf has 5 arguments. urdf_path tells the function where the
        .URDF file is that we want to load. For the ground we will use
        'plane_big'.

        position and wxyz_quaternion define the position and orientation
        in which the URDF object will be placed. These positions and
        orientations are defined around the parent axes of the URDF
        object. By setting position = [0, 0, 0] and
        wxyz_quaternion = [1, 0, 0, 0], we place the plane at (0, 0, 0)
        aligned to the XY plane.

        By setting fixed = True, we are telling the simulator NOT to
        update the physics of the base of the object. It will still have
        collision, but no other forces, including gravity, will affect it.

        By setting update_vis = False, we are telling the simulator NOT
        to send updates to the visualizer for this object. This flag is
        usually set to False for unjointed, fixed URDFs to reduce the
        amount of compute power required by the visualization
        ##################################################################
        '''
        self.ground = self.s.load_urdf(urdf_path = assets['plane_big'],
                                       position = [0., 0., 0.],
                                       wxyz_quaternion = [1., 0., 0., 0],
                                       fixed = True,
                                       update_vis = False)

        '''
        ##################################################################
        STEP 3: Load a cube into the simulator as a physics object. For
        this we will use the 'cube' asset.

        By setting position = [0, 0, 1.5] and
        wxyz_quaternion = [1, 0, 0, 0], we place the cube at (0, 0, 1.5)
        in the orientation defined by the URDF parent axes. As it turns
        out, the cube is 1x1x1, so that a center position of [0, 0, 1.5]
        places the bottom of the cube exactly 1 meter above the ground.

        By setting fixed = False, we are telling the simulator apply
        physics to this .URDF when the engine is running.

        By setting update_vis = True, we are telling the simulator to
        send updates to the visualizer for this object. This is usually
        set to  true when an object is not fixed and will change its
        position and/or orientation.
        ##################################################################
        '''
        self.cube = self.s.load_urdf(urdf_path = assets['cube'],
                                     position = [0., 0., 1.5],
                                     wxyz_quaternion = [1., 0., 0., 0],
                                     fixed = False,
                                     update_vis = True)

    def run(self, max_time=None):
        '''
        ##################################################################
        Now that we have created an initialization function, we move on
        to the run function. This function will run a physics simulation
        using condynsate. Essentially, we will do two things:
            1) Reset the simulation environment to the initial
               conditions. Whereas this will not do anything for this
               particular example, it is best practice to always call
               condynsate.simulator.reset before running a simulation
               loop.
            3) Run a simulation to completion. In this case, completion
               is defined as the simulator reaching max_time. We will
               describe how to do this using a while loop and
               condynsate.simulator.step below.
        ##################################################################
        '''

        '''
        ##################################################################
        STEP 1: Reset the simulator. It is best practice to do this at
        the beginning of every run function.
        ##################################################################
        '''
        # Reset the simulator.
        self.s.reset()

        '''
        ##################################################################
        STEP 2: Run the simulation loop. condynsate.simulator cannot run
        an entire simulation by itself. Instead, it can take one time
        step of 0.01 seconds. Therefore, the way we run an entire
        simulation is to place the condynsate.simulator.step function
        inside a while loop that executes until the boolean flag
        condynsate.simulator.is_done is True. Note that this flag will
        automatically be set to true when max_time is reached or, if
        the keyboard is enabled, when the user presses the esc key.
        If the max_time argument to  is None, is_done will not be set
        to true until the esc key is pressed. Further, if max_time is
        None AND keyboard interactivity is disabled, max_time fails safe
        to 10 seconds.
        ##################################################################
        '''
        # Run the simulation loop until done
        while(not self.s.is_done):
            ret_code = self.s.step(max_time = max_time)

Running the Project Class

Now that we have made the Project class, we can test it by initializing it and then calling the run function. Remember to press the enter key to start the simulation and the esc key to end the simulation.

[4]:
# Create an instance of the Project class.
proj = Project()

# Run the simulation. max_time defines when the simulation automatically terminates.
# Set to None for unlimited runtime terminated by user keypress.
proj.run(max_time = 2.0)
You can open the visualizer by visiting the following URL:
http://127.0.0.1:7002/static/

Challenge

This tutorial is now complete. For an added challenge, think of how you would modify __init__ so that two cubes, one above the other, are loaded but only the top one has physics applied to it.