wiki:Tutorial2UsingThe3DSimulator

Version 4 (modified by fma, 8 years ago) ( diff )

--

Tutorial 2: Using the 3D simulator

Files for this tutorial are available in ​py4bot/examples/tutorial_2/

Here, we will see how to use the 3D simulation stuff.

As before, we create a new empty dir in our home dir:

$ mkdir tutorial_2
$ cd tutorial_2

Let's create another hexapod.py file:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import math

import visual

from py4bot.api import *

import settings

Nothing fancy, here.

class Hexapod3D(Robot3D):
    def _createBody(self):
        return Body(settings.LEGS_ORIGIN)

    def _createLegs(self):
        legs = {}
        legIk = {}
        for legIndex in settings.LEGS_INDEX:
            legs[legIndex] = Leg3Dof(legIndex, {'coxa': Coxa(), 'femur': Femur(), 'tibia': Tibia()}, settings.FEET_NEUTRAL[legIndex])
            legIk[legIndex] = Leg3DofIk(settings.LEGS_GEOMETRY[legIndex])

        return legs, legIk

Same as before, except that we inherits from Robot3D, instead of Robot.

    def _createActuatorPool(self):
        driver = Driver3D()
        pool = ActuatorPool(driver)

        num = 0
        for leg in self._legs.values():

            # Create joints actuators
            coxa3D = Coxa3D(leg.coxa, num, settings.LEGS_GEOMETRY[leg.index]['coxa'])
            pool.add(coxa3D)
            num += 1

            femur3D = Femur3D(leg.femur, num, settings.LEGS_GEOMETRY[leg.index]['femur'])
            pool.add(femur3D)
            num += 1

            tibia3D = Tibia3D(leg.tibia, num, settings.LEGS_GEOMETRY[leg.index]['tibia'])
            pool.add(tibia3D)
            num += 1

            # Init 3D view
            coxa3D.frame = self._body3D
            femur3D.frame = coxa3D
            tibia3D.frame = femur3D

            coxa3D.pos = (settings.LEGS_ORIGIN[leg.index]['x'], 0, -settings.LEGS_ORIGIN[leg.index]['y'])
            femur3D.pos = (settings.LEGS_GEOMETRY[leg.index]['coxa'], 0, 0)
            tibia3D.pos = (settings.LEGS_GEOMETRY[leg.index]['femur'], 0, 0)

            coxa3D.rotate(angle=math.radians(settings.LEGS_ORIGIN[leg.index]['gamma0']), axis=(0, 1, 0))

        return pool

Here, we use specific 3D actuators: Coxa3D, Femur3D, Tibia3D; they all use the ​VPython library to represent themselves on the screen.

Note that we don't use a custom actuator mapping; nums are automatically incremented.

We also need to configure the hierarchy, and the relative positions of the actuators.

Note: this may change in the future; I'm working on a simpler way to do all this.

class Gamepad(RemoteControl):
    def _createFrontend(self):
        return Thrustmaster(settings.THRUSTMASTER_PATH)

    def _buildComponents(self):
        self._addConfig("walk")
        self._addConfig("body")

        self._addComponent(Button, command=self.selectNextConfig, key="button_008", trigger="hold")
        self._addComponent(Button, command=self.selectPreviousConfig, key="button_009", trigger="hold")

        self._addComponent(Button, command=self.robot.incBodyPosition, key="button_004", mapper=MapperSetValue(dz=+5))
        self._addComponent(Button, command=self.robot.incBodyPosition, key="button_005", mapper=MapperSetValue(dz=-5))
        self._addComponent(Joystick, configs="walk", command=GaitSequencer().walk, keys=("analog_02", "analog_03", "analog_00"), mapper=MapperWalk())

        self._addComponent(Analog, configs="body", command=self.robot.setBodyExtraPosition, key="analog_00", mapper=MapperSetMultiply('yaw', coef=-15))
        self._addComponent(Analog, configs="body", command=self.robot.setBodyExtraPosition, key="analog_03", mapper=MapperSetMultiply('pitch', coef=-15))
        self._addComponent(Analog, configs="body", command=self.robot.setBodyExtraPosition, key="analog_02", mapper=MapperSetMultiply('roll', coef=15))

Same as before...

def main():
    def addGait(gaitClass, gaitName):
        group = settings.GAIT_LEGS_GROUPS[gaitName]
        params = settings.GAIT_PARAMS['default']
        for key1, value1 in settings.GAIT_PARAMS[gaitName].items():
            for key2, value2 in value1.items():
                params[key1][key2] = value2
        gait = gaitClass(gaitName, group, params)
        GaitManager().add(gait)

    scene = visual.display(width=settings.SCENE_WIDTH, height=settings.SCENE_HEIGHT)
    ground = visual.box(axis=(0, 1, 0), pos=(0, 0, 0), length=0.1, height=500, width=500, color=visual.color.gray(0.75), opacity=0.5)

    addGait(GaitTripod, "tripod")
    addGait(GaitTetrapod, "tetrapod")
    addGait(GaitRiple, "riple")
    addGait(GaitWave, "metachronal")
    addGait(GaitWave, "wave")
    GaitManager().select("riple")

    robot = Hexapod3D()

    remote = Gamepad(robot)

    GaitSequencer().start()
    remote.start()

    robot.setBodyPosition(z=30)

    robot.mainLoop()

    remote.stop()
    remote.join()
    GaitSequencer().stop()
    GaitSequencer().join()

if __name__ == "__main__":
    main()

The only difference, here, is the scene size init, and the ground addition (optional).

Settings

# -*- coding: utf-8 -*-

from py4bot.common import config


# Legs index
LEGS_INDEX = ('RF', 'RM', 'RR', 'LR', 'LM', 'LF')

# Legs geometry
LEGS_GEOMETRY = {
    'RM': {'coxa': 25, 'femur': 45, 'tibia': 65},
    'RF': {'coxa': 25, 'femur': 45, 'tibia': 65},
    'LF': {'coxa': 25, 'femur': 45, 'tibia': 65},
    'LM': {'coxa': 25, 'femur': 45, 'tibia': 65},
    'LR': {'coxa': 25, 'femur': 45, 'tibia': 65},
    'RR': {'coxa': 25, 'femur': 45, 'tibia': 65}
}

# Legs origin
LEGS_ORIGIN = {
    'RM': {'x':  35., 'y':   0., 'gamma0' :   0.},
    'RF': {'x':  35., 'y':  65., 'gamma0' :  30.},
    'LF': {'x': -35., 'y':  65., 'gamma0' : 150.},
    'LM': {'x': -35., 'y':   0., 'gamma0' : 180.},
    'LR': {'x': -35., 'y': -65., 'gamma0' : 210.},
    'RR': {'x':  35., 'y': -65., 'gamma0' : 330.},
}

# Legs feet neutral position
FEET_NEUTRAL = {
    'RM': LEGS_GEOMETRY['RM']['coxa'] + LEGS_GEOMETRY['RM']['femur'],
    'RF': LEGS_GEOMETRY['RF']['coxa'] + LEGS_GEOMETRY['RF']['femur'],
    'LF': LEGS_GEOMETRY['LF']['coxa'] + LEGS_GEOMETRY['LF']['femur'],
    'LM': LEGS_GEOMETRY['LM']['coxa'] + LEGS_GEOMETRY['LM']['femur'],
    'LR': LEGS_GEOMETRY['LR']['coxa'] + LEGS_GEOMETRY['LR']['femur'],
    'RR': LEGS_GEOMETRY['RR']['coxa'] + LEGS_GEOMETRY['RR']['femur'],
}

# Gaits
GAIT_LEGS_GROUPS = {
    'tripod':      (('RM', 'LF', 'LR'), ('RF', 'LM', 'RR')),
    'tetrapod':    (('RR', 'LM'), ('RF', 'LR'), ('RM', 'LF')),
    'riple':       (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)),
    'metachronal': (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)),
    'wave':        (('RR',), ('RM',), ('RF',), ('LR',), ('LM',), ('LF',))
}

# Gaits parameters
GAIT_PARAMS = {
    'default': {
        'length': {
            'min': 5.,
            'max': 40.
        },
        'angle': {
            'min': 0.5,
            'max': 5.
        },
        'height': {
            'min': 20.,
            'max': 40.
        },
        'speed': {
            'min': 25.,
            'max': 250.
        }
    },
    'tripod': {},
    'tetrapod': {},
    'riple': {},
    'metachronal': {},
    'wave': {}
}

# Gamepad path
THRUSTMASTER_PATH = "/dev/input/by-id/usb-Mega_World_Thrustmaster_dual_analog_3.2-event-joystick"

# VPython scene default size
SCENE_WIDTH = 640
SCENE_HEIGHT = 480

We removed the servos mapping/calibration, as we don't need them anymore, and we just added the scene default size.

In the next tutorial, we will see how to fine tune SERVOS_CALIBRATION table.

Note: See TracWiki for help on using the wiki.