Module TeachMyAgent.environments.envs.bodies.walkers.BigQuadruBody

Expand source code
import numpy as np
from Box2D.b2 import edgeShape, circleShape, fixtureDef, polygonShape, revoluteJointDef, contactListener

from TeachMyAgent.environments.envs.bodies.walkers.WalkerAbstractBody import WalkerAbstractBody
from TeachMyAgent.environments.envs.utils.custom_user_data import CustomBodyUserData, CustomMotorUserData

HULL_POLYGONS = [
        [(-46, +13), (+6, +13), (+50, +5),
        (+50, -12), (-46, -12)]
    ]
HULL_BOTTOM_WIDTH = 96
SPEED_HIP     = 4
SPEED_KNEE    = 6

class BigQuadruBody(WalkerAbstractBody):
    '''
        New version of the Quadrupedal walker implemented in https://gym.openai.com/envs/BipedalWalker-v2/.

        In the initial version, the embodiment is created with an angle on legs, but position are not set according to this.
        This results in bodies with wrong positions that Box2D's solver has to reposition at the first step of the environment.
        This new version uses straight legs and fixed bad positions.
    '''
    def __init__(self, scale, motors_torque=300, nb_steps_under_water=600, reset_on_hull_critical_contact=False):
        '''
            Creates a bipedal walker

            Args:
                scale: Scale value used in the environment (to adapt the embodiment to its environment)
                motors_torque: Maximum torque the embodiment can use on its motors
                 nb_steps_under_water: How many consecutive steps the embodiment can survive under water
                reset_on_hull_critical_contact: Whether a contact detected with the head should stop the episode
        '''
        super(BigQuadruBody, self).__init__(scale, motors_torque, nb_steps_under_water)
        self.LEG_DOWN = 3 / self.SCALE  # 0 = center of hull
        self.LEG_W, self.LEG_H = 10 / self.SCALE, 51 / self.SCALE
        self.TORQUE_PENALTY = 0.00035 / 2 # 2 paris of legs
        self.reset_on_hull_critical_contact = reset_on_hull_critical_contact

        self.AGENT_WIDTH = HULL_BOTTOM_WIDTH / self.SCALE
        self.AGENT_HEIGHT = 25 / self.SCALE + \
                            self.LEG_H * 2 - self.LEG_DOWN
        self.AGENT_CENTER_HEIGHT = self.LEG_H * 2 + self.LEG_DOWN

    def draw(self, world, init_x, init_y, force_to_center):
        HULL_FIXTURES = [
            fixtureDef(
                shape=polygonShape(vertices=[(x / self.SCALE, y / self.SCALE) for x, y in polygon]),
                density=5.0,
                friction=0.1,
                categoryBits=0x20,
                maskBits=0x000F)
            for polygon in HULL_POLYGONS
        ]

        LEG_FD = fixtureDef(
            shape=polygonShape(box=(self.LEG_W / 2, self.LEG_H / 2)),
            density=1.0,
            restitution=0.0,
            categoryBits=0x20,
            maskBits=0x000F)

        LOWER_FD = fixtureDef(
            shape=polygonShape(box=(0.8 * self.LEG_W / 2, self.LEG_H / 2)),
            density=1.0,
            restitution=0.0,
            categoryBits=0x20,
            maskBits=0x000F)

        hull = world.CreateDynamicBody(
            position=(init_x, init_y),
            fixtures=HULL_FIXTURES
        )

        hull.color1 = (0.5, 0.4, 0.9)
        hull.color2 = (0.3, 0.3, 0.5)
        hull.ApplyForceToCenter((force_to_center, 0), True)

        hull.userData = CustomBodyUserData(True, is_contact_critical=self.reset_on_hull_critical_contact, name="hull")
        self.body_parts.append(hull)
        self.reference_head_object = hull

        for x_anchor in [-0.7, 0.5]:
            absolute_x = init_x + np.interp(x_anchor, [-1,1], [-HULL_BOTTOM_WIDTH / 2 / self.SCALE, HULL_BOTTOM_WIDTH / 2 / self.SCALE])
            for i in [-1, +1]:
                leg = world.CreateDynamicBody(
                    position=(absolute_x, init_y - self.LEG_H / 2 - self.LEG_DOWN),
                    #angle=(i * 0.05),
                    fixtures=LEG_FD
                )
                leg.color1 = (0.6 - i / 10., 0.3 - i / 10., 0.5 - i / 10.)
                leg.color2 = (0.4 - i / 10., 0.2 - i / 10., 0.3 - i / 10.)
                rjd = revoluteJointDef(
                    bodyA=hull,
                    bodyB=leg,
                    anchor=(absolute_x, init_y - self.LEG_DOWN),
                    enableMotor=True,
                    enableLimit=True,
                    maxMotorTorque=self.MOTORS_TORQUE,
                    motorSpeed=i,
                    lowerAngle=-0.8,
                    upperAngle=1.1,
                )

                leg.userData = CustomBodyUserData(False, name="leg")
                self.body_parts.append(leg)

                joint_motor = world.CreateJoint(rjd)
                joint_motor.userData = CustomMotorUserData(SPEED_HIP, False)
                self.motors.append(joint_motor)

                lower = world.CreateDynamicBody(
                    position=(absolute_x, init_y - self.LEG_H * 3 / 2 - self.LEG_DOWN),
                    #angle=(i * 0.05),
                    fixtures=LOWER_FD
                )
                lower.color1 = (0.6 - i / 10., 0.3 - i / 10., 0.5 - i / 10.)
                lower.color2 = (0.4 - i / 10., 0.2 - i / 10., 0.3 - i / 10.)
                rjd = revoluteJointDef(
                    bodyA=leg,
                    bodyB=lower,
                    anchor=(absolute_x, init_y - self.LEG_DOWN - self.LEG_H),
                    enableMotor=True,
                    enableLimit=True,
                    maxMotorTorque=self.MOTORS_TORQUE,
                    motorSpeed=1,
                    lowerAngle=-1.6,
                    upperAngle=-0.1,
                )

                lower.userData = CustomBodyUserData(True, name="lower")
                self.body_parts.append(lower)

                joint_motor = world.CreateJoint(rjd)
                joint_motor.userData = CustomMotorUserData(
                    SPEED_KNEE,
                    True,
                    contact_body=lower,
                    angle_correction=1.0)
                self.motors.append(joint_motor)

Classes

class BigQuadruBody (scale, motors_torque=300, nb_steps_under_water=600, reset_on_hull_critical_contact=False)

New version of the Quadrupedal walker implemented in https://gym.openai.com/envs/BipedalWalker-v2/.

In the initial version, the embodiment is created with an angle on legs, but position are not set according to this. This results in bodies with wrong positions that Box2D's solver has to reposition at the first step of the environment. This new version uses straight legs and fixed bad positions.

Creates a bipedal walker

Args

scale
Scale value used in the environment (to adapt the embodiment to its environment)
motors_torque
Maximum torque the embodiment can use on its motors
nb_steps_under_water: How many consecutive steps the embodiment can survive under water
reset_on_hull_critical_contact
Whether a contact detected with the head should stop the episode
Expand source code
class BigQuadruBody(WalkerAbstractBody):
    '''
        New version of the Quadrupedal walker implemented in https://gym.openai.com/envs/BipedalWalker-v2/.

        In the initial version, the embodiment is created with an angle on legs, but position are not set according to this.
        This results in bodies with wrong positions that Box2D's solver has to reposition at the first step of the environment.
        This new version uses straight legs and fixed bad positions.
    '''
    def __init__(self, scale, motors_torque=300, nb_steps_under_water=600, reset_on_hull_critical_contact=False):
        '''
            Creates a bipedal walker

            Args:
                scale: Scale value used in the environment (to adapt the embodiment to its environment)
                motors_torque: Maximum torque the embodiment can use on its motors
                 nb_steps_under_water: How many consecutive steps the embodiment can survive under water
                reset_on_hull_critical_contact: Whether a contact detected with the head should stop the episode
        '''
        super(BigQuadruBody, self).__init__(scale, motors_torque, nb_steps_under_water)
        self.LEG_DOWN = 3 / self.SCALE  # 0 = center of hull
        self.LEG_W, self.LEG_H = 10 / self.SCALE, 51 / self.SCALE
        self.TORQUE_PENALTY = 0.00035 / 2 # 2 paris of legs
        self.reset_on_hull_critical_contact = reset_on_hull_critical_contact

        self.AGENT_WIDTH = HULL_BOTTOM_WIDTH / self.SCALE
        self.AGENT_HEIGHT = 25 / self.SCALE + \
                            self.LEG_H * 2 - self.LEG_DOWN
        self.AGENT_CENTER_HEIGHT = self.LEG_H * 2 + self.LEG_DOWN

    def draw(self, world, init_x, init_y, force_to_center):
        HULL_FIXTURES = [
            fixtureDef(
                shape=polygonShape(vertices=[(x / self.SCALE, y / self.SCALE) for x, y in polygon]),
                density=5.0,
                friction=0.1,
                categoryBits=0x20,
                maskBits=0x000F)
            for polygon in HULL_POLYGONS
        ]

        LEG_FD = fixtureDef(
            shape=polygonShape(box=(self.LEG_W / 2, self.LEG_H / 2)),
            density=1.0,
            restitution=0.0,
            categoryBits=0x20,
            maskBits=0x000F)

        LOWER_FD = fixtureDef(
            shape=polygonShape(box=(0.8 * self.LEG_W / 2, self.LEG_H / 2)),
            density=1.0,
            restitution=0.0,
            categoryBits=0x20,
            maskBits=0x000F)

        hull = world.CreateDynamicBody(
            position=(init_x, init_y),
            fixtures=HULL_FIXTURES
        )

        hull.color1 = (0.5, 0.4, 0.9)
        hull.color2 = (0.3, 0.3, 0.5)
        hull.ApplyForceToCenter((force_to_center, 0), True)

        hull.userData = CustomBodyUserData(True, is_contact_critical=self.reset_on_hull_critical_contact, name="hull")
        self.body_parts.append(hull)
        self.reference_head_object = hull

        for x_anchor in [-0.7, 0.5]:
            absolute_x = init_x + np.interp(x_anchor, [-1,1], [-HULL_BOTTOM_WIDTH / 2 / self.SCALE, HULL_BOTTOM_WIDTH / 2 / self.SCALE])
            for i in [-1, +1]:
                leg = world.CreateDynamicBody(
                    position=(absolute_x, init_y - self.LEG_H / 2 - self.LEG_DOWN),
                    #angle=(i * 0.05),
                    fixtures=LEG_FD
                )
                leg.color1 = (0.6 - i / 10., 0.3 - i / 10., 0.5 - i / 10.)
                leg.color2 = (0.4 - i / 10., 0.2 - i / 10., 0.3 - i / 10.)
                rjd = revoluteJointDef(
                    bodyA=hull,
                    bodyB=leg,
                    anchor=(absolute_x, init_y - self.LEG_DOWN),
                    enableMotor=True,
                    enableLimit=True,
                    maxMotorTorque=self.MOTORS_TORQUE,
                    motorSpeed=i,
                    lowerAngle=-0.8,
                    upperAngle=1.1,
                )

                leg.userData = CustomBodyUserData(False, name="leg")
                self.body_parts.append(leg)

                joint_motor = world.CreateJoint(rjd)
                joint_motor.userData = CustomMotorUserData(SPEED_HIP, False)
                self.motors.append(joint_motor)

                lower = world.CreateDynamicBody(
                    position=(absolute_x, init_y - self.LEG_H * 3 / 2 - self.LEG_DOWN),
                    #angle=(i * 0.05),
                    fixtures=LOWER_FD
                )
                lower.color1 = (0.6 - i / 10., 0.3 - i / 10., 0.5 - i / 10.)
                lower.color2 = (0.4 - i / 10., 0.2 - i / 10., 0.3 - i / 10.)
                rjd = revoluteJointDef(
                    bodyA=leg,
                    bodyB=lower,
                    anchor=(absolute_x, init_y - self.LEG_DOWN - self.LEG_H),
                    enableMotor=True,
                    enableLimit=True,
                    maxMotorTorque=self.MOTORS_TORQUE,
                    motorSpeed=1,
                    lowerAngle=-1.6,
                    upperAngle=-0.1,
                )

                lower.userData = CustomBodyUserData(True, name="lower")
                self.body_parts.append(lower)

                joint_motor = world.CreateJoint(rjd)
                joint_motor.userData = CustomMotorUserData(
                    SPEED_KNEE,
                    True,
                    contact_body=lower,
                    angle_correction=1.0)
                self.motors.append(joint_motor)

Ancestors

Inherited members