Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 import roslib; roslib.load_manifest('goap')
00035
00036 from time import sleep
00037
00038 import rgoap
00039
00040 from common import Condition, WorldState, stringify, stringify_dict
00041 from memory import Memory
00042 from planning import Planner, PlanExecutor
00043
00044
00045 import logging
00046 _logger = logging.getLogger('rgoap')
00047
00048
00049
00050 class Runner(object):
00051 """
00052 self.memory: memory to be used for conditions and actions
00053 self.worldstate: the default/start worldstate
00054 self.actions: the actions this runner uses
00055 self.planner: the planner this runner uses
00056 """
00057
00058 def __init__(self, config_module=None):
00059 """
00060 param:config_module: a scenario/robot specific module to prepare setup,
00061 that has the following members:
00062 get_all_conditions() -> return a list of conditions
00063 get_all_actions() -> return a list of actions
00064 """
00065 self.memory = Memory()
00066 self.worldstate = WorldState()
00067 self.actions = set()
00068
00069 if config_module is not None:
00070 for condition in config_module.get_all_conditions(self.memory):
00071 Condition.add(condition)
00072 for action in config_module.get_all_actions(self.memory):
00073 self.actions.add(action)
00074
00075 self.planner = Planner(self.actions, self.worldstate, None)
00076
00077 self._last_goal = None
00078 self._preempt_requested = False
00079
00080
00081 def __repr__(self):
00082 return '<%s memory=%s worldstate=%s actions=%s planner=%s>' % (self.__class__.__name__,
00083 self.memory, self.worldstate, self.actions, self.planner)
00084
00085
00086 def request_preempt(self):
00087 self._preempt_requested = True
00088
00089 def preempt_requested(self):
00090 return self._preempt_requested
00091
00092 def service_preempt(self):
00093 self._preempt_requested = False
00094
00095
00096 def _update_worldstate(self):
00097 """update worldstate to reality"""
00098 Condition.initialize_worldstate(self.worldstate)
00099 _logger.info("worldstate initialized/updated to: %s", self.worldstate)
00100
00101 def _check_conditions(self):
00102
00103 for (condition, value) in self.worldstate._condition_values.iteritems():
00104 if value is None:
00105 _logger.warn("Condition still 'None': %s", condition)
00106
00107
00108 def update_and_plan(self, goal, tries=1, introspection=False):
00109 """update worldstate and call self.plan(...), repeating for
00110 number of tries or until a plan is found"""
00111 assert tries >= 1
00112 while tries > 0:
00113 tries -= 1
00114 self._update_worldstate()
00115 start_node = self.plan(goal, introspection)
00116 if start_node is not None:
00117 break
00118 if tries > 0:
00119 _logger.warn("Runner retrying in update_and_plan")
00120 return start_node
00121
00122
00123 def plan(self, goal, introspection=False):
00124 """plan for given goal and return start_node of plan or None"""
00125 self._check_conditions()
00126 return self.planner.plan(goal=goal)
00127
00128
00129
00130 def plan_and_execute_goals(self, goals):
00131 """Sort goals by usability and try to plan and execute one by one until
00132 one goal is achieved"""
00133 self._update_worldstate()
00134
00135
00136 goals.sort(key=lambda goal: goal.usability, reverse=True)
00137
00138 if _logger.isEnabledFor(logging.INFO):
00139 _logger.info("Available goals:\n%s", stringify(goals, '\n'))
00140
00141
00142 for goal in goals:
00143
00144 if self._last_goal is goal:
00145 continue
00146
00147 if self.preempt_requested():
00148 self.service_preempt()
00149 return 'preempted'
00150
00151 plan = self.plan(goal)
00152 if plan is None:
00153 continue
00154
00155
00156 self._last_goal = goal
00157 _logger.info("Executing most usable goal: %s", goal)
00158 _logger.info("With plan: %s", plan)
00159 outcome = self.execute(plan, introspection=True)
00160 _logger.info("Most usable goal returned: %s", outcome)
00161 if outcome == 'aborted':
00162 _logger.warn("Executed goal return 'aborted', trying next goal")
00163 continue
00164
00165 return outcome
00166
00167 _logger.error("For no goal a plan could be found!")
00168 outcome = 'aborted'
00169
00170 return outcome
00171
00172
00173 def update_and_plan_and_execute(self, goal, tries=1, introspection=False):
00174 """loop that updates, plans and executes until the goal is reached"""
00175 outcome = None
00176
00177 while not rgoap.is_shutdown():
00178 if self.preempt_requested():
00179 self.service_preempt()
00180 return 'preempted'
00181
00182 start_node = self.update_and_plan(goal, tries, introspection)
00183
00184 if start_node is None:
00185
00186 _logger.error("RGOAP Runner aborts, no plan found!")
00187 return 'aborted'
00188
00189 outcome = self.execute(start_node, introspection)
00190
00191 if outcome != 'aborted':
00192 break
00193
00194
00195 _logger.warn("RGOAP Runner execution fails, replanning..")
00196
00197 self._update_worldstate()
00198 if not goal.is_valid(self.worldstate):
00199 _logger.warn("Goal isn't valid in current worldstate")
00200 else:
00201 _logger.error("Though goal is valid in current worldstate, the plan execution failed!?")
00202
00203
00204 return outcome
00205
00206
00207 def execute(self, start_node, introspection=False):
00208 success = PlanExecutor().execute(start_node)
00209 return success
00210
00211 def print_worldstate_loop(self):
00212 while not rgoap.is_shutdown():
00213 self._update_worldstate()
00214 _logger.info("%s", self.worldstate)
00215 sleep(2)
00216