Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended python robot interfaces #36

Merged
merged 19 commits into from
Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions gym_ignition/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
sys.setdlopenflags(sys.getdlopenflags() | ctypes.RTLD_GLOBAL)
import gympp_bindings

# Import abstract classes
from gym_ignition.base.task import Task
from gym_ignition.base.robot import Robot

# =========================
# REGISTER THE ENVIRONMENTS
# =========================
Expand Down Expand Up @@ -48,8 +44,8 @@
id='CartPoleGymppy-Discrete-v0',
entry_point='gym_ignition.base.gazebo_env:GazeboEnv',
max_episode_steps=5000,
kwargs={'task': cartpole_discrete.CartPoleDiscrete,
'robot': sim.cartpole.CartPoleRobot,
kwargs={'task_cls': cartpole_discrete.CartPoleDiscrete,
'robot_cls': sim.cartpole.CartPoleRobot,
'sdf': "CartPole/CartPole.sdf",
'world': "DefaultEmptyWorld.world",
'rtf': max_float,
Expand All @@ -61,8 +57,8 @@
id='CartPoleGymppy-Continuous-v0',
entry_point='gym_ignition.base.gazebo_env:GazeboEnv',
max_episode_steps=5000,
kwargs={'task': cartpole_continuous.CartPoleContinuous,
'robot': sim.cartpole.CartPoleRobot,
kwargs={'task_cls': cartpole_continuous.CartPoleContinuous,
'robot_cls': sim.cartpole.CartPoleRobot,
'sdf': "CartPole/CartPole.sdf",
'world': "DefaultEmptyWorld.world",
'rtf': max_float,
Expand Down
68 changes: 42 additions & 26 deletions gym_ignition/base/gazebo_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
# GNU Lesser General Public License v2.1 or any later version.

import gym
from gym_ignition import base
from gym_ignition.base import task
from gym_ignition.utils import logger
from gym_ignition.utils.typing import *
from gym_ignition.base.robot import robot_abc
from gym_ignition import gympp_bindings as bindings


class GazeboEnv(gym.Wrapper):
metadata = {'render.modes': ['human']}

def __init__(self,
task: type,
robot : type,
task_cls: type,
robot_cls: type,
sdf: str,
world: str,
rtf: float,
Expand All @@ -25,8 +28,8 @@ def __init__(self,
# to accept user-defined parameters.
self._kwargs = kwargs

# Store the type of the class that provides gymppy.Robot interface
self._robot_cls = robot
# Store the type of the class that provides RobotABC interface
self._robot_cls = robot_cls

# SDF files
self._sdf = sdf
Expand All @@ -38,25 +41,35 @@ def __init__(self,
self._physics_rate = physics_rate
self._gazebo_wrapper = None

# Initialize the simulator and the robot
robot = self._get_robot()

# Build the environment
env = task(kwargs)
assert isinstance(env, base.task.Task), "'task' object must inherit from " \
"gymppy.Task"
assert isinstance(env, gym.Env), "'task' object must inherit from gym.Env"
env = task_cls(robot=robot, **kwargs)
assert isinstance(env, task.Task), \
"'task_cls' object must inherit from Task"

# Wrap the environment with this class
super().__init__(env=env)

# Seed the environment
self.seed()

@property
def unwrapped(self):
# The task is not a complete gym.Env environment since task objects implement
# the Task interface.
# This wrapper implements the step method using Ignition Gazebo. For this reason,
# the unwrapped environment is the gym.Env interface provided by this wrapper.
return self
def __getattr__(self, name):
# We need to override this method because gym.Wrapper has a custom implementation
# that forwards all the asked attributes to the wrapped class.
# Due to this reason, regular wrappers cannot have new public methods and
# attributes. This is a workaround that requires specifying all the new ones in
# the list below.
#
# This fix is needed after https:/openai/gym/issues/1554

exposed_public_attributes = ["gazebo"]

if name in exposed_public_attributes:
return self.__getattribute__(name)
else:
return getattr(self.env, name)

# ==========
# PROPERTIES
Expand Down Expand Up @@ -123,22 +136,25 @@ def gazebo(self) -> bindings.GazeboWrapper:
gazebo_initialized = self._gazebo_wrapper.initialize()
assert gazebo_initialized, "Failed to initialize ignition gazebo"

# ==============================
# INITIALIZE THE ROBOT INTERFACE
# ==============================
return self._gazebo_wrapper

def _get_robot(self):
if not self.gazebo:
raise Exception("Failed to instantiate the gazebo simulator")

# Get the robot name
model_names = self._gazebo_wrapper.getModelNames()
model_names = self.gazebo.getModelNames()
assert len(model_names) == 1, "The environment has more than one model"
model_name = model_names[0]

# Build the robot object
# TODO: robot_name arg is used only for the SingletonRobot implementation
self.env.robot = self._robot_cls(robot_name=model_name, **self._kwargs)
assert isinstance(self.env.robot, base.robot.Robot), \
"'robot' object must inherit from gymppy.Robot"
# TODO: robot_name arg is used only for the FactoryRobot implementation
logger.debug("Creating the robot object")
robot = self._robot_cls(robot_name=model_name, **self._kwargs)
assert isinstance(robot, robot_abc.RobotABC), \
"'robot' object must inherit from RobotABC"

return self._gazebo_wrapper
return robot

# ===============
# gym.Env METHODS
Expand All @@ -165,7 +181,7 @@ def step(self, action: Action) -> State:
# Get the reward
# TODO: use the wrapper method?
reward = self.env._get_reward()
assert reward, "Failed to get the reward"
assert reward is not None, "Failed to get the reward"

# Check termination
done = self.env._is_done()
Expand Down
89 changes: 0 additions & 89 deletions gym_ignition/base/robot.py

This file was deleted.

11 changes: 11 additions & 0 deletions gym_ignition/base/robot/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.
# This software may be modified and distributed under the terms of the
# GNU Lesser General Public License v2.1 or any later version.

from . import robot_abc
from . import robot_links
from . import robot_joints
from . import robot_contacts
from . import robot_baseframe
from .robot_joints import PID
from .robot_features import feature_detector, RobotFeatures
18 changes: 18 additions & 0 deletions gym_ignition/base/robot/robot_abc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (C) 2019 Istituto Italiano di Tecnologia (IIT). All rights reserved.
# This software may be modified and distributed under the terms of the
# GNU Lesser General Public License v2.1 or any later version.

import abc


class RobotABC(abc.ABC):
"""
The base interface of all robot objects
"""

def __init__(self, model_file: str = None) -> None:
# Optional model file associated with this object
self.model_file = model_file

@abc.abstractmethod
def valid(self) -> bool: ...
Loading