From cab8b51ec84cdd0a979dfba90e362ba7e1284517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9verin=20Lemaignan?= Date: Mon, 8 Apr 2013 14:29:58 +0200 Subject: [PATCH] First template for actuators Test it with: morse add actuator Demonstrate a synchronous service and an asynchronous one Current implementation of default_action is not great (looks more like a sensor) --- bin/morse.in | 5 +- .../src/@env@/actuators/@name@.py.tpl | 62 ++++++++++++++ .../src/@env@/builder/actuators/@name@.py.tpl | 8 ++ data/templates/src/@env@/robots/@name@.py.tpl | 10 ++- src/morse/environments.py | 83 +++++++++++++++++-- 5 files changed, 157 insertions(+), 11 deletions(-) diff --git a/bin/morse.in b/bin/morse.in index e5844ac36..e33bcf2aa 100755 --- a/bin/morse.in +++ b/bin/morse.in @@ -16,7 +16,7 @@ formatter = logging.Formatter("* %(message)s\n") log_handler.setFormatter(formatter) logger.addHandler(log_handler) -logger.setLevel(logging.DEBUG) +logger.setLevel(logging.INFO) ## try: @@ -539,7 +539,8 @@ def add_component(args): except MorseEnvironmentError as e: logger.error("%s" % e) sys.exit(1) - logger.info("A new %s called <%s> has been added to <%s>." % (type, name, args.env)) + + logger.debug("A new %s called <%s> has been added to <%s>." % (type, name, args.env)) def prelaunch(): diff --git a/data/templates/src/@env@/actuators/@name@.py.tpl b/data/templates/src/@env@/actuators/@name@.py.tpl index e69de29bb..b736c5efa 100644 --- a/data/templates/src/@env@/actuators/@name@.py.tpl +++ b/data/templates/src/@env@/actuators/@name@.py.tpl @@ -0,0 +1,62 @@ +import logging; logger = logging.getLogger("morse." + __name__) + +import morse.core.actuator + +from morse.core.services import service, async_service, interruptible +from morse.core import status +from morse.helpers.components import add_data, add_property + +class @classname@(morse.core.actuator.Actuator): + _name = "@classname@" + _short_desc = "@shortdesc@" + + # define here the data fields required by your actuator + # format is: field name, initial value, type, description + add_data('counter', 0, 'int', 'A dummy counter, for testing purposes') + + def __init__(self, obj, parent=None): + logger.info("%s initialization" % obj.name) + # Call the constructor of the parent class + super(self.__class__, self).__init__(obj, parent) + + # Do here actuator specific initializations + + self._target_count = 0 # dummy internal variable, for testing purposes + + logger.info('Component initialized') + + @service + def get_counter(self): + """ This is a sample service. + + Simply returns the value of the internal counter. + + You can access it as a RPC service from clients. + """ + logger.info("%s counter is %s" % (self.name, self.local_data['counter'])) + + return self.local_data['counter'] + + @interruptible + @async_service + def async_test(self, value): + """ This is a sample asynchronous service. + + Returns when the internal counter reaches ``value``. + + You can access it as a RPC service from clients. + """ + self._target_count = value + + def default_action(self): + """ Main loop of the actuator. + + Implements the component behaviour + """ + + # check if we have an on-going asynchronous tasks... + if self._target_count and self.local_data['counter'] > self._target_count: + self.completed(status.SUCCESS, self.local_data['counter']) + + # implement here the behaviour of your actuator + self.local_data['counter'] += 1 diff --git a/data/templates/src/@env@/builder/actuators/@name@.py.tpl b/data/templates/src/@env@/builder/actuators/@name@.py.tpl index e69de29bb..eafb5fba5 100644 --- a/data/templates/src/@env@/builder/actuators/@name@.py.tpl +++ b/data/templates/src/@env@/builder/actuators/@name@.py.tpl @@ -0,0 +1,8 @@ +from morse.builder.creator import ActuatorCreator + +class @classname@(ActuatorCreator): + def __init__(self, name=None): + ActuatorCreator.__init__(self, name, \ + "@env@.actuators.@name@.@classname@",\ + "@name@") + diff --git a/data/templates/src/@env@/robots/@name@.py.tpl b/data/templates/src/@env@/robots/@name@.py.tpl index 93347861d..da88ac4c6 100644 --- a/data/templates/src/@env@/robots/@name@.py.tpl +++ b/data/templates/src/@env@/robots/@name@.py.tpl @@ -5,10 +5,12 @@ class @classname@(morse.core.robot.Robot): """ Class definition for the @name@ robot.""" def __init__(self, obj, parent=None): - """ Constructor method. - Receives the reference to the Blender object. - Optionally it gets the name of the object's parent, - but that information is not currently used for a robot. """ + """ Constructor method + + Receives the reference to the Blender object. + Optionally it gets the name of the object's parent, + but that information is not currently used for a robot. + """ logger.info('%s initialization' % obj.name) super(self.__class__,self).__init__(obj, parent) diff --git a/src/morse/environments.py b/src/morse/environments.py index 0bda13011..4d3baf129 100755 --- a/src/morse/environments.py +++ b/src/morse/environments.py @@ -62,8 +62,8 @@ def pyprint(code): ################### NEW_ROBOT_MSG = [""" -A template for a new robot called <{name}> has been added to the -<{env}> environment. +A template for a new robot called <{name}> has been +added to the <{env}> environment. ---------------------------------------------------------- To complete the equipment of your robot, edit: @@ -92,6 +92,59 @@ def pyprint(code): Happy simulation! """] +NEW_ACTUATOR_MSG = [""" +A template for a new actuator called <{name}> has been +added to the <{env}> environment. + +---------------------------------------------------------- +Edit {prefix}/src/actuators/{name}.py to implement the +behaviour of your actuator. + +---------------------------------------------------------- +To use it on your robot, edit your robot description in +{prefix}/src/builder/robots/ +and add these lines: + +""", ("""from {env}.builder.actuators import {classname} + +# create a new {name} actuator +{name} = {classname}() + +robot.append({name}) + +""", 'python'), +"""---------------------------------------------------------- +Happy simulation! +"""] + +NEW_SENSOR_MSG = [""" +A template for a new sensor called <{name}> has been +added to the <{env}> environment. + +---------------------------------------------------------- +Edit {prefix}/src/sensors/{name}.py to implement the +behaviour of your sensor. + +---------------------------------------------------------- +To use it on your robot, edit your robot description in +{prefix}/src/builder/robots/ +and add these lines: + +""", ("""from {env}.builder.sensors import {classname} + +# create a new {name} sensor +{name} = {classname}() + +robot.append({name}) + +""", 'python'), +"""---------------------------------------------------------- +Happy simulation! +"""] + + +################################################################# + class Environment(): def __init__(self, morse_prefix, env_name, env_path = None): @@ -223,7 +276,7 @@ def add_component(self, cmpttype, name): safename = self._make_safe_name(name) if safename != name: - logger.warning("Replace name <%s> by suitable identifier: " + logger.warning("Replaced name <%s> by suitable identifier: " "<%s>" % (name, safename)) if cmpttype == "robot": @@ -238,8 +291,28 @@ def add_component(self, cmpttype, name): classname = safename.capitalize(), \ env = self.env) elif cmpttype == "sensor": - self._install_files(SENSOR, name = safename) + desc = input("Enter a short description for sensor <%s>: " % safename) + self._install_files(SENSOR, \ + name = safename, \ + classname = safename.capitalize(), \ + env = self.env, \ + shortdesc = desc) + self._print_info_msg(NEW_SNESOR_MSG, \ + prefix= self.abspath, \ + name = safename, \ + classname = safename.capitalize(), \ + env = self.env) elif cmpttype == "actuator": - self._install_files(ACTUATOR, name = safename) + desc = input("Enter a short description for actuator <%s>: " % safename) + self._install_files(ACTUATOR, \ + name = safename, \ + classname = safename.capitalize(), \ + env = self.env, \ + shortdesc = desc) + self._print_info_msg(NEW_ACTUATOR_MSG, \ + prefix= self.abspath, \ + name = safename, \ + classname = safename.capitalize(), \ + env = self.env) else: raise MorseEnvironmentError("Unknown component type %s" % cmpttype)