| Version 3 (modified by , 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.
