Skip to content

Commit

Permalink
Refactored Deepbots: DeepbotsEnv & Robot Class
Browse files Browse the repository at this point in the history
fixed typo

shortened imports

refactored robots dir

rm -r setup

from deepbots.robots import RobotEmitterReceiverCSV

added CSVSupervisorEnv and shortened import path

renamed class name & file name

Inherited from Webots Robot class

Refactored SupervisorEnv name to DeepbotsEnv

Renamed to snake case
  • Loading branch information
KelvinYang0320 authored and tsampazk committed Jan 11, 2023
1 parent 3ae23e6 commit 511ea45
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 97 deletions.
2 changes: 2 additions & 0 deletions deepbots/robots/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from deepbots.robots.controllers.csv_robot import CSVRobot
from deepbots.robots.controllers.emitter_receiver_robot import EmitterReceiverRobot
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from collections.abc import Iterable

from deepbots.robots.controllers.robot_emitter_receiver import \
RobotEmitterReceiver
from deepbots.robots.controllers.emitter_receiver_robot import \
EmitterReceiverRobot


class RobotEmitterReceiverCSV(RobotEmitterReceiver):
class CSVRobot(EmitterReceiverRobot):
"""
Basic implementation of a robot that can emit and receive messages to/from
the supervisor in string utf-8 form that are Comma Separated Values,
Expand Down Expand Up @@ -39,8 +39,8 @@ def initialize_comms(self, emitter_name, receiver_name):
supervisor node
:return: The initialized emitter and receiver references
"""
emitter = self.robot.getDevice(emitter_name)
receiver = self.robot.getDevice(receiver_name)
emitter = self.getDevice(emitter_name)
receiver = self.getDevice(receiver_name)
receiver.enable(self.timestep)
return emitter, receiver

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
from controller import Robot


class RobotEmitterReceiver:
class EmitterReceiverRobot(Robot):
"""
This RobotEmitterReceiver implements only the most basic run method, that
This EmitterReceiverRobot implements only the most basic run method, that
steps the robot and calls the handle_emitter, handle_receiver methods that
are needed for communication with the supervisor.
This class must be inherited by all robot controllers created by the user
and the handle_emitter, handle_receiver, initialize_comms methods are all
abstract and need to be implemented according to their docstrings. For a
simpler RobotController that implements the methods in a basic form
inherit the RobotEmitterReceiverCSV subclass or other emitter-receiver
inherit the CSVRobot subclass or other emitter-receiver
subclasses.
"""
def __init__(self,
Expand All @@ -35,10 +35,10 @@ def __init__(self,
:param timestep: int, positive or None
"""
self.robot = Robot()
super().__init__()

if timestep is None:
self.timestep = int(self.robot.getBasicTimeStep())
self.timestep = int(self.getBasicTimeStep())
else:
self.timestep = timestep

Expand Down Expand Up @@ -78,8 +78,8 @@ def initialize_comms(self, emitter_name, receiver_name):
A basic example implementation can be:
emitter = self.robot.getDevice("emitter")
receiver = self.robot.getDevice("receiver")
emitter = self.getDevice("emitter")
receiver = self.getDevice("receiver")
receiver.enable(self.timestep)
return emitter, receiver
Expand Down Expand Up @@ -113,6 +113,6 @@ def run(self):
This method should be called by a robot manager to run the robot.
"""
while self.robot.step(self.timestep) != -1:
while self.step(self.timestep) != -1:
self.handle_receiver()
self.handle_emitter()
Empty file removed deepbots/setup/__init__.py
Empty file.
Empty file removed deepbots/setup/deepworlds_setup.py
Empty file.
4 changes: 4 additions & 0 deletions deepbots/supervisor/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from deepbots.supervisor.controllers.robot_supervisor_env import RobotSupervisorEnv
from deepbots.supervisor.controllers.csv_supervisor_env import CSVSupervisorEnv
from deepbots.supervisor.controllers.deepbots_supervisor_env import DeepbotsSupervisorEnv
from deepbots.supervisor.controllers.emitter_receiver_supervisor_env import EmitterReceiverSupervisorEnv
61 changes: 61 additions & 0 deletions deepbots/supervisor/controllers/csv_supervisor_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from collections.abc import Iterable

from deepbots.supervisor.controllers.emitter_receiver_supervisor_env import EmitterReceiverSupervisorEnv


class CSVSupervisorEnv(EmitterReceiverSupervisorEnv):
"""
This class implements the emitter-receiver scheme using Comma Separated
Values.
"""
def __init__(self,
emitter_name="emitter",
receiver_name="receiver",
timestep=None):
"""
The constructor just passes the arguments provided to the parent
class contructor.
:param emitter_name: The name of the emitter device on the
supervisor node
:param receiver_name: The name of the receiver device on the
supervisor node
:param timestep: The supervisor controller timestep
"""
super(CSVSupervisorEnv, self).__init__(emitter_name, receiver_name,
timestep)

def handle_emitter(self, action):
"""
Implementation of the handle_emitter method expecting an iterable
with Comma Separated Values (CSV).
:param action: Whatever the use-case uses as an action, e.g.
an integer representing discrete actions
:type action: Iterable, for multiple values the CSV format is
required, e.g. [0, 1] for two actions
"""
assert isinstance(action, Iterable), \
"The action object should be Iterable"

message = (",".join(map(str, action))).encode("utf-8")
self.emitter.send(message)

def handle_receiver(self):
"""
Implementation of the handle_receiver method expecting an iterable
with Comma Separated Values (CSV).
:return: Returns the message received from the robot, returns None
if no message is received
:rtype: List of string values
"""
if self.receiver.getQueueLength() > 0:
try:
string_message = self.receiver.getString()
except AttributeError:
string_message = self.receiver.getData().decode("utf-8")
self.receiver.nextPacket()
return string_message.split(",")
else:
return None
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from controller import Supervisor


class SupervisorEnv(Supervisor, gym.Env):
class DeepbotsSupervisorEnv(Supervisor, gym.Env):
"""
This class is the highest class in deepbots class hierarchy, inheriting
both the Webots Supervisor controller and the basic gym.Env.
Expand All @@ -18,7 +18,7 @@ class SupervisorEnv(Supervisor, gym.Env):
compatible with reinforcement learning agents that work with
the gym interface. Moreover, a problem-agnostic reset method is
provided. Please use any of the children supervisor classes to be
inherited by your own class, such as the RobotSupervisor class.
inherited by your own class, such as the RobotSupervisorEnv class.
Nevertheless, advanced users can inherit this class to create
their own supervisor classes if they wish.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from collections.abc import Iterable
from warnings import warn, simplefilter

from deepbots.supervisor.controllers.supervisor_env import SupervisorEnv
from deepbots.supervisor.controllers.deepbots_supervisor_env import DeepbotsSupervisorEnv
from controller import Supervisor


class SupervisorEmitterReceiver(SupervisorEnv):
class EmitterReceiverSupervisorEnv(DeepbotsSupervisorEnv):
"""
This is the base class for the emitter - receiver scheme.
Expand All @@ -26,7 +25,7 @@ def __init__(self,
supervisor node
:param timestep: The supervisor controller timestep
"""
super(SupervisorEmitterReceiver, self).__init__()
super(EmitterReceiverSupervisorEnv, self).__init__()

if timestep is None:
self.timestep = int(self.getBasicTimeStep())
Expand Down Expand Up @@ -116,61 +115,3 @@ def timestep(self, value):
:param value: The new controller timestep in milliseconds
"""
self._timestep = int(value)


class SupervisorCSV(SupervisorEmitterReceiver):
"""
This class implements the emitter-receiver scheme using Comma Separated
Values.
"""
def __init__(self,
emitter_name="emitter",
receiver_name="receiver",
timestep=None):
"""
The constructor just passes the arguments provided to the parent
class contructor.
:param emitter_name: The name of the emitter device on the
supervisor node
:param receiver_name: The name of the receiver device on the
supervisor node
:param timestep: The supervisor controller timestep
"""
super(SupervisorCSV, self).__init__(emitter_name, receiver_name,
timestep)

def handle_emitter(self, action):
"""
Implementation of the handle_emitter method expecting an iterable
with Comma Separated Values (CSV).
:param action: Whatever the use-case uses as an action, e.g.
an integer representing discrete actions
:type action: Iterable, for multiple values the CSV format is
required, e.g. [0, 1] for two actions
"""
assert isinstance(action, Iterable), \
"The action object should be Iterable"

message = (",".join(map(str, action))).encode("utf-8")
self.emitter.send(message)

def handle_receiver(self):
"""
Implementation of the handle_receiver method expecting an iterable
with Comma Separated Values (CSV).
:return: Returns the message received from the robot, returns None
if no message is received
:rtype: List of string values
"""
if self.receiver.getQueueLength() > 0:
try:
string_message = self.receiver.getString()
except AttributeError:
string_message = self.receiver.getData().decode("utf-8")
self.receiver.nextPacket()
return string_message.split(",")
else:
return None
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from warnings import warn, simplefilter
from deepbots.supervisor.controllers.supervisor_env import SupervisorEnv
from deepbots.supervisor.controllers.deepbots_supervisor_env import DeepbotsSupervisorEnv
from controller import Supervisor


class RobotSupervisor(SupervisorEnv):
class RobotSupervisorEnv(DeepbotsSupervisorEnv):
"""
The RobotSupervisor class implements both a robot controller and a
The RobotSupervisorEnv class implements both a robot controller and a
supervisor RL environment, referred to as Robot-Supervisor scheme.
This class can be used when there is no need to separate the Robot
Expand All @@ -18,17 +18,17 @@ class RobotSupervisor(SupervisorEnv):
The user needs to implement the regular methods for the environment,
reward(), get_observations(), get_default_observation, etc., from
SupervisorEnv according to their use-case in addition to the method
DeepbotsSupervisorEnv according to their use-case in addition to the method
apply_action() introduced here.
apply_action():
(similar to use_message_data() of RobotEmitterReceiverCSV)
(similar to use_message_data() of CSVRobot)
This method takes an action argument and translates it to a robot
action, e.g. motor speeds.
Note that apply_action() is called during step().
"""
def __init__(self, timestep=None):
super(RobotSupervisor, self).__init__()
super(RobotSupervisorEnv, self).__init__()

if timestep is None:
self.timestep = int(self.getBasicTimeStep())
Expand Down
2 changes: 2 additions & 0 deletions deepbots/supervisor/wrappers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from deepbots.supervisor.wrappers.keyboard_printer import KeyboardPrinter
from deepbots.supervisor.wrappers.tensorboard_wrapper import TensorboardLogger
14 changes: 7 additions & 7 deletions deepbots/supervisor/wrappers/keyboard_printer.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from controller import Keyboard

from deepbots.supervisor.controllers.supervisor_env import SupervisorEnv
from deepbots.supervisor.controllers.deepbots_supervisor_env import DeepbotsSupervisorEnv


class KeyboardPrinter(SupervisorEnv):
class KeyboardPrinter(DeepbotsSupervisorEnv):
def __init__(self, controller):
self.controller = controller
self.keyboard = Keyboard()
self.keyboard.enable(self.controller.timestep)

def step(self, action):
observation, reward, isDone, info = self.controller.step(action)
observation, reward, is_done, info = self.controller.step(action)
key = self.keyboard.getKey()
# DEBUG CONTROLS
if key == Keyboard.CONTROL + ord("A"):
Expand All @@ -23,13 +23,13 @@ def step(self, action):
print()
print("Observations: ", self.controller.observation)

return observation, reward, isDone, info
return observation, reward, is_done, info

def is_done(self):
isDone = self.controller.is_done()
if isDone:
is_done = self.controller.is_done()
if is_done:
print("Done")
return isDone
return is_done

def get_observations(self):
return self.controller.get_observations()
Expand Down
14 changes: 7 additions & 7 deletions deepbots/supervisor/wrappers/tensorboard_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import numpy as np
from tensorboardX import SummaryWriter

from deepbots.supervisor.controllers.supervisor_env import SupervisorEnv
from deepbots.supervisor.controllers.deepbots_supervisor_env import DeepbotsSupervisorEnv


class TensorboardLogger(SupervisorEnv):
class TensorboardLogger(DeepbotsSupervisorEnv):
def __init__(self,
controller,
log_dir="logs/results",
Expand All @@ -29,7 +29,7 @@ def __init__(self,
self.file_writer = SummaryWriter(log_dir, flush_secs=30)

def step(self, action):
observation, reward, isDone, info = self.controller.step(action)
observation, reward, is_done, info = self.controller.step(action)

if (self.v_action > 1):
self.file_writer.add_histogram(
Expand All @@ -47,7 +47,7 @@ def step(self, action):
self.file_writer.add_scalar("Rewards/Per Global Step", reward,
self.step_global)

if (isDone):
if (is_done):
self.file_writer.add_scalar(
"Is Done/Per Reset step",
self.step_cntr,
Expand All @@ -60,13 +60,13 @@ def step(self, action):
self.step_cntr += 1
self.step_global += 1

return observation, reward, isDone, info
return observation, reward, is_done, info

def is_done(self):
isDone = self.controller.is_done()
is_done = self.controller.is_done()

self.file_writer.flush()
return isDone
return is_done

def get_observations(self):
obs = self.controller.get_observations()
Expand Down

0 comments on commit 511ea45

Please sign in to comment.