planner_icaps2014.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 
00003 import csv
00004 import time
00005 import rospy
00006 import shutil
00007 
00008 from bwi_planning.srv import CostLearnerInterface, CostLearnerInterfaceRequest
00009 from std_srvs.srv import Empty
00010 
00011 from .action_executor_icaps2014 import ActionExecutorICAPS2014
00012 from .aton_icaps2014 import AtomICAPS2014
00013 from bwi_planning import ClingoWrapper
00014 
00015 def get_adjacent_door(atoms):
00016     for atom in atoms:
00017         if atom.name == "beside" and not atom.negated:
00018             return str(atom.value)
00019     return None
00020 
00021 def get_location(atoms):
00022     for atom in atoms:
00023         if atom.name == "at":
00024             return str(atom.value)
00025     return None
00026 
00027 def cast_boolean(s):
00028     return s in ['1','t','true','T','True','TRUE','y','Y','yes','Yes','YES']
00029 
00030 def read_table_from_file(file):
00031     t = {}
00032     csvfile = open(file, 'rb')
00033     csvreader = csv.reader(csvfile)
00034     first_row = True
00035     for row in csvreader:
00036         if first_row:
00037             column_headers = row
00038             first_row = False
00039             continue
00040         first_column = True
00041         for i,column_val in enumerate(row):
00042             if first_column:
00043                 t[column_val] = {}
00044                 row = t[column_val]
00045                 first_column = False
00046                 continue
00047             row[column_headers[i-1]] = cast_boolean(column_val)
00048 
00049     csvfile.close()
00050     return t
00051 
00052 def write_table_to_file(fluent_name, table, file_name, time=None):
00053     for row_name, row in table.iteritems():
00054         for column_name, value in row.iteritems():
00055             AtomICAPS2014
00056     atoms = [AtomICAPS2014(fluent_name, row_name+','+column_name, time, value)]
00057     table_file = open(file_name, 'w')
00058     for atom in atoms:
00059         table_file.write(str(atom) + '\n')
00060     table_file.close()
00061 
00062 class PlannerICAPS2014(object):
00063 
00064     def __init__(self):
00065         self.initialized = False
00066 
00067         self.dry_run = rospy.get_param("~dry_run", False)
00068         self.clingo_interface = ClingoWrapper(AtomICAPS2014)
00069         initial_file = rospy.get_param("~initial_file", None)
00070         self.query_file = rospy.get_param("~query_file")
00071         self.passto_file = rospy.get_param("~passto_file")
00072         self.knowinside_file = rospy.get_param("~knowinside_file")
00073         self.knows_file = rospy.get_param("~knows_file")
00074         self.domain_costs_file = rospy.get_param("~domain_costs_file", None)
00075         self.costs_file = rospy.get_param("~costs_file", None)
00076         self.enable_learning = rospy.get_param("~enable_learning", False)
00077 
00078         if self.dry_run and not initial_file:
00079             rospy.logfatal("Dry run requested, but no initial state provided." +
00080                            " Please set the ~initial_file param.")
00081             return
00082         self.initial_file = "/tmp/initial"
00083         if self.dry_run:
00084             rospy.loginfo("Supplied initial state written to: " + 
00085                           self.initial_file)
00086             shutil.copyfile(initial_file, self.initial_file)
00087 
00088         self.executor = ActionExecutorICAPS2014(self.dry_run, self.initial_file)
00089 
00090         if self.enable_learning: 
00091             rospy.wait_for_service('cost_learner/increment_episode')
00092             rospy.wait_for_service('cost_learner/add_sample')
00093             self.finalize_episode = \
00094                     rospy.ServiceProxy('cost_learner/increment_episode', Empty)
00095             self.add_sample = \
00096                     rospy.ServiceProxy('cost_learner/add_sample', 
00097                                        CostLearnerInterface)
00098             self.planning_times_file = rospy.get_param("~planning_times_file",
00099                                                        None)
00100 
00101         self.passto_table = read_table_from_file(self.passto_file)
00102         self.knowinside_table = read_table_from_file(self.knowinside_file)
00103         self.knows_table = read_table_from_file(self.knows_file)
00104         self.initialized = True
00105 
00106     def _construct_initial_state(self, previous_state, observations):
00107         """
00108           This is a poor man's belief merge function between the previous_state
00109           and observations. This needs to be replaced with proper belief merge
00110           algorithms as it impossible to cover every possible situation here
00111           using if/else statements
00112         """
00113 
00114         new_state = []
00115         removed_atoms = []
00116         for atom in previous_state:
00117             atom.time = 0
00118             add_atom = True
00119             for observation in observations:
00120                 if observation.conflicts_with(atom):
00121                     add_atom = False
00122             if add_atom:
00123                 new_state.append(atom)
00124             else:
00125                 removed_atoms.append(atom)
00126 
00127         if len(removed_atoms) != 0:
00128             display_message = "  Incomaptible members in previous state: " 
00129             for atom in removed_atoms:
00130                 display_message += str(atom) + " "
00131             rospy.logwarn(display_message)
00132 
00133         for observation in observations:
00134             observation.time = 0
00135             new_state.append(observation)
00136 
00137         initial_file = open(self.initial_file,"w")
00138         display_message = "  Constructed state: "
00139         for atom in new_state:
00140             initial_file.write(str(atom) + ".\n")
00141             display_message += str(atom) + " "
00142         initial_file.close()
00143         rospy.loginfo(display_message)
00144         rospy.loginfo("Constructed initial state written to: " + 
00145                       self.initial_file)
00146 
00147     def _send_finish(self):
00148         if self.enable_learning:
00149             self.finalize_episode()
00150 
00151     def start(self):
00152         if not self.initialized:
00153             return
00154         self.executor.sense_initial_state()
00155 
00156         # Write tables to file
00157         passto_file = '/tmp/passto'
00158         write_table_to_file('passto', self.passto_table, passto_file)
00159         knows_file = '/tmp/knows'
00160         write_table_to_file('knows', self.knows_table, knows_file)
00161         knowinside_file = '/tmp/knowinside'
00162         write_table_to_file('knowinside', self.knowinside_table,
00163                             knowinside_file, 0)
00164         first_run = True
00165         while True:
00166             additional_files = []
00167             if first_run:
00168                 additional_files = [passto_file,
00169                                     knowinside_file,
00170                                     knows_file]
00171                 first_run = False
00172             if self.domain_costs_file != None:
00173                 rospy.loginfo("Planning with cost optimization!!")
00174                 start_time = time.time()
00175                 plan_available, optimization, plan, states = \
00176                         self.clingo_interface.get_plan_costs([self.initial_file,
00177                               self.query_file,
00178                               self.costs_file,
00179                               self.domain_costs_file].extend(additional_files)
00180                         )
00181                 duration = time.time() - start_time
00182                 if self.enable_learning and self.planning_times_file:
00183                     ptf = open(self.planning_times_file, "a")
00184                     ptf.write(str(duration) + "\n")
00185                     ptf.close()
00186             else:
00187                 plan_available, optimization, plan, states = \
00188                         self.clingo_interface.get_plan([self.initial_file,
00189                                                       self.query_file].extend(additional_files))
00190             if not plan_available:
00191                 rospy.logfatal("No plan found to complete task!")
00192                 break
00193             rospy.loginfo("Found plan (optimization = %i): %s"%(optimization,
00194                                                                 plan))
00195 
00196             need_replan = False
00197             for action in plan:
00198                 current_state = [state for state in states
00199                                  if state.time == action.time]
00200                 next_state = [state for state in states
00201                               if state.time == action.time+1]
00202                 start_time = rospy.get_time()
00203                 success, observations = \
00204                         self.executor.execute_action(action, next_state, 
00205                                                      action.time+1) 
00206                 duration = rospy.get_time() - start_time
00207                 if self.enable_learning and action.name == "approach":
00208                     if success:
00209                         # Check to see if we were beside some door in start
00210                         # state and the location
00211                         req = CostLearnerInterfaceRequest()
00212                         req.location = get_location(current_state)
00213                         req.door_from = get_adjacent_door(current_state)
00214                         if req.door_from:
00215                             req.door_to = str(action.value)
00216                             req.cost = duration
00217                             self.add_sample(req)
00218                     else:
00219                         rospy.loginfo("Executed unsuccessful approach action.")
00220 
00221                 for observation in observations:
00222                     if observation not in next_state:
00223                         rospy.logwarn("  Unexpected observation: " + 
00224                                       str(observation))
00225                         need_replan = True
00226                         break
00227                 if need_replan:
00228                     break
00229 
00230             if need_replan:
00231                 self._construct_initial_state(current_state, observations)
00232                 continue
00233             
00234             rospy.loginfo("Plan successful!")
00235             self._send_finish()
00236             break
00237 
00238 


bwi_planning_icaps14
Author(s): Piyush Khandelwal , Fangkai Yang
autogenerated on Wed Aug 26 2015 10:55:00