app.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # License: BSD
00004 #   https://raw.github.com/robotics-in-concert/rocon_app_platform/master/rocon_appmanager/LICENSE
00005 #
00006 ##############################################################################
00007 # Imports
00008 ##############################################################################
00009 
00010 import os
00011 import yaml
00012 from roslib.packages import InvalidROSPkgException
00013 import rospy
00014 import roslaunch.parent
00015 import traceback
00016 import time
00017 import thread
00018 
00019 import utils
00020 from .exceptions import AppException, InvalidAppException
00021 
00022 ##############################################################################
00023 # Class
00024 ##############################################################################
00025 
00026 
00027 class App(object):
00028     '''
00029         Got many inspiration and imported from willow_app_manager
00030         implementation (Jihoon)
00031     '''
00032     path = None
00033     data = {}
00034 
00035     def __init__(self, resource_name):
00036         self.filename = ""
00037         self._connections = {}
00038         for connection_type in ['publishers', 'subscribers', 'services']:
00039             self._connections[connection_type] = []
00040         self._load_from_resource_name(resource_name)
00041 
00042     def __repr__(self):
00043         string = ""
00044         for d in self.data:
00045             string += d + " : " + str(self.data[d]) + "\n"
00046         return string
00047 
00048     def _load_from_resource_name(self, name):
00049         '''
00050           Loads from a ros resource name consisting of a package/app pair.
00051 
00052           @param name : unique identifier for the app, e.g. rocon_apps/chirp.
00053           @type str
00054 
00055           @raise InvalidAppException if the app definition was for some reason invalid.
00056         '''
00057         if not name:
00058             raise InvalidAppException("app name was invalid [%s]" % name)
00059         self.filename = utils.find_resource(name + '.app')
00060         self._load_from_app_file(self.filename, name)
00061 
00062     def _load_from_app_file(self, path, app_name):
00063         '''
00064           Open and read directly from the app definition file (.app file).
00065 
00066           @param path : full path to the .app file
00067           @param app_name : unique name for the app (comes from the .app filename)
00068         '''
00069         rospy.loginfo("App Manager : loading app '%s'" % app_name)  # str(path)
00070         self.filename = path
00071 
00072         with open(path, 'r') as f:
00073             data = {}
00074             app_data = yaml.load(f.read())
00075 
00076             for reqd in ['launch', 'interface', 'platform']:
00077                 if not reqd in app_data:
00078                     raise AppException("Invalid appfile format [" + path + "], missing required key [" + reqd + "]")
00079 
00080             data['name'] = app_name
00081             data['display'] = app_data.get('display', app_name)
00082             data['description'] = app_data.get('description', '')
00083             data['platform'] = app_data['platform']
00084             data['launch'] = self.loadFromFile(app_data['launch'], 'launch', app_name)
00085             data['interface'] = self._load_interface(self.loadFromFile(app_data['interface'], 'interface', app_name))
00086             if 'icon' not in app_data:
00087                 data['icon'] = None
00088             else:
00089                 data['icon'] = self.loadFromFile(app_data['icon'], 'icon', app_name)
00090             data['status'] = 'Ready'
00091 
00092         self.data = data
00093 
00094     def loadFromFile(self, path, log, app_name="Unknown"):
00095         try:
00096             data = utils.findResource(path)
00097             if not os.path.exists(data):
00098                 raise AppException("Invalid appfile [%s]: %s file does not exist." % (app_name, log))
00099             return data
00100         except ValueError as e:
00101             raise AppException("Invalid appfile [%s]: bad %s entry: %s" % (app_name, log, e))
00102             """
00103         except NotFoundException:
00104             raise AppException("App file [%s] feres to %s that is not installed"%(app_name,log))
00105             """
00106         except InvalidROSPkgException as e:
00107             raise AppException("App file [%s] feres to %s that is not installed: %s" % (app_name, log, str(e)))
00108 
00109     def _load_interface(self, data):
00110         d = {}
00111         keys = ['subscribers', 'publishers', 'services']
00112         with open(data, 'r') as f:
00113             y = yaml.load(f.read())
00114             y = y or {}
00115             try:
00116                 for k in keys:
00117                     raw_data = y.get(k, [])
00118 
00119                     # remote / in front of topics
00120                     new_data = []
00121                     for r in raw_data:
00122                         if r[0] == '/':
00123                             r = r[1:len(r)]
00124                         new_data.append(r)
00125                     d[k] = new_data
00126 
00127             except KeyError:
00128                 raise AppException("Invalid interface, missing keys")
00129 
00130         return d
00131 
00132     def start(self, robot_name, remappings=[]):
00133         data = self.data
00134         rospy.loginfo("Launching: %s" % (data['name']))
00135 
00136         # Starts app
00137         try:
00138             prefix = robot_name
00139 
00140             # Create roslaunch
00141             self._launch = roslaunch.parent.ROSLaunchParent(rospy.get_param("/run_id"),
00142                                                             [data['launch']],
00143                                                             is_core=False,
00144                                                             process_listeners=())
00145             self._launch._load_config()
00146 
00147             #print data['interface']
00148             self._connections = {}
00149 
00150             # Prefix with robot name by default (later pass in remap argument)
00151             remap_from_list = [remapping.remap_from for remapping in remappings]
00152             remap_to_list = [remapping.remap_to for remapping in remappings]
00153             for connection_type in ['publishers', 'subscribers', 'services']:
00154                 self._connections[connection_type] = []
00155                 for t in data['interface'][connection_type]:
00156                     remapped_name = prefix + '/' + t
00157                     indices = [i for i, x in enumerate(remap_from_list) if x == t]
00158                     if indices:
00159                         remapped_name = remap_to_list[indices[0]]
00160                     self._connections[connection_type].append(remapped_name)
00161                     for N in self._launch.config.nodes:
00162                         N.remap_args.append((t, remapped_name))
00163             self._launch.start()
00164 
00165             thread.start_new_thread(self.app_monitor, ())
00166             data['status'] = 'Running'
00167             return True, "Success", self._connections['subscribers'], self._connections['publishers'], self._connections['services']
00168 
00169         except Exception as e:
00170             print str(e)
00171             traceback.print_stack()
00172             rospy.loginfo("Error While launching " + data['launch'])
00173             data['status'] = "Error While launching " + data['launch']
00174             return False, "Error while launching " + data['name'], [], [], []
00175 
00176     def stop(self):
00177         data = self.data
00178 
00179         try:
00180             if self._launch:
00181                 try:
00182                     self._launch.shutdown()
00183                 finally:
00184                     self._launch = None
00185                     data['status'] = 'Ready'
00186                 rospy.loginfo("App Manager : stopped app [%s]" % data['name'])
00187         except Exception as e:
00188             print str(e)
00189             rospy.loginfo("Error while stopping " + data['name'])
00190             data['status'] = 'Error'
00191             return False, "Error while stopping " + data['name'], self._connections['subscribers'], self._connections['publishers'], self._connections['services']
00192 
00193         return True, "Success", self._connections['subscribers'], self._connections['publishers'], self._connections['services']
00194 
00195     def app_monitor(self):
00196         while self._launch:
00197             time.sleep(0.1)
00198             launch = self._launch
00199             if launch:
00200                 pm = launch.pm
00201                 if pm:
00202                     if pm.done:
00203                         time.sleep(1.0)
00204                         self.stop()
00205                         break
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends


rocon_appmanager
Author(s): Jihoon
autogenerated on Tue Jan 22 2013 12:59:53