00001
00002
00003 import os
00004 import rospy
00005 import signal
00006 import subprocess
00007 import threading
00008 import time
00009
00010 from .atom import Atom
00011
00012 def parse_plan(plan_string, atom_class):
00013 atoms = [atom_class(word) for word in plan_string.split()]
00014 plan = [atom for atom in atoms if atom.type == Atom.ACTION]
00015 states = [atom for atom in atoms if atom.type == Atom.FLUENT]
00016 plan = sorted(plan, key=lambda atom: atom.time)
00017 states = sorted(states, key=lambda atom: atom.time)
00018 return plan,states
00019
00020 class ClingoCommand(object):
00021
00022 def __init__(self, cmd, outfile):
00023 self.cmd = cmd
00024 self.process = None
00025 self.outfile = outfile
00026
00027 def run(self, timeout):
00028 rospy.logdebug("Running command: " + self.cmd)
00029 def target():
00030 self.process = subprocess.Popen(self.cmd, shell=True,
00031 stdout=self.outfile,
00032 preexec_fn=os.setsid)
00033 self.process.communicate()
00034
00035 thread = threading.Thread(target=target)
00036 thread.start()
00037
00038 thread.join(timeout)
00039 if thread.is_alive():
00040 os.killpg(self.process.pid, signal.SIGTERM)
00041 thread.join()
00042 rospy.logdebug("Process RetCode: " + str(self.process.returncode))
00043 self.outfile.close()
00044 return self.process.returncode
00045
00046 class ClingoWrapper(object):
00047
00048 def __init__(self, atom_class):
00049 self.clingo_timeout = rospy.get_param("~clingo_timeout", 60)
00050 self.clingo_steps = rospy.get_param("~clingo_steps", 15)
00051 self.clingo_threads = rospy.get_param("~clingo_threads", 6)
00052 rospy.loginfo("Clingo: Using " + str(self.clingo_threads) + " threads" +
00053 " for " + str(self.clingo_timeout) + " seconds. max_len" +
00054 " is set to " + str(self.clingo_steps))
00055 self.domain_semantics_file = rospy.get_param("~domain_semantics_file")
00056 self.rigid_knowledge_file = rospy.get_param("~rigid_knowledge_file")
00057 self.atom_class = atom_class
00058
00059 def get_plan(self, additional_files):
00060
00061 start_time = time.time()
00062
00063 for n in range(self.clingo_steps):
00064
00065 additional_files_str = " ".join(additional_files)
00066 out_file = open("result", "w")
00067 clingo_command = ClingoCommand("gringo -c n=" + str(n) +
00068 " " + self.domain_semantics_file +
00069 " " + self.rigid_knowledge_file +
00070 " " + additional_files_str +
00071 " | rosrun clasp clasp -t " +
00072 str(self.clingo_threads), out_file)
00073 ret_code = clingo_command.run(self.clingo_timeout)
00074
00075
00076 out_file = open("result","r")
00077 linelist = []
00078 no_plan_available = False
00079 for line in out_file:
00080 linelist.append(line)
00081 if line[:13] == "UNSATISFIABLE":
00082 no_plan_available = True
00083 break
00084 if line[:11] == "SATISFIABLE":
00085 optimization = n
00086 plan_line = linelist[-2]
00087
00088 out_file.close()
00089 if no_plan_available:
00090 continue
00091
00092 try:
00093 plan, states = parse_plan(plan_line, self.atom_class)
00094 except ValueError as e:
00095 rospy.logerr("Received plan from clasp, but unable to parse plan:" +
00096 plan_line)
00097 rospy.logerr(" Error: " + str(e))
00098 return False, 0, None, None
00099
00100 end_time = time.time()
00101 rospy.loginfo("Planning took %ss." % str(end_time - start_time))
00102
00103 return True, optimization, plan, states
00104 return False, 0, None, None
00105
00106 def get_plan_costs(self, additional_files):
00107
00108 start_time = time.time()
00109
00110
00111 additional_files_str = " ".join(additional_files)
00112 result_file_str = "/tmp/result"
00113 out_file = open(result_file_str, "w")
00114 clingo_command = ClingoCommand("gringo -c n=" + str(self.clingo_steps) +
00115 " " + self.domain_semantics_file +
00116 " " + self.rigid_knowledge_file +
00117 " " + additional_files_str +
00118 " | rosrun clasp clasp -t " +
00119 str(self.clingo_threads), out_file)
00120 ret_code = clingo_command.run(self.clingo_timeout)
00121 rospy.loginfo("Clingo output written to " + result_file_str)
00122
00123
00124 linelist = []
00125 plan_line = None
00126 out_file = open(result_file_str,"r")
00127 for line in out_file:
00128 linelist.append(line)
00129 if line == "UNSATISFIABLE\n":
00130 out_file.close()
00131 return False, 0, None, None
00132 if line[:13] == "Optimization:" and linelist[-2][:9] != " Optimum":
00133 optimization_line = linelist[-1]
00134 optimization = int(optimization_line.split(' ')[1])
00135 plan_line = linelist[-2]
00136
00137 if not plan_line:
00138 rospy.loginfo("Unable to parse clasp output. Check " +
00139 result_file_str)
00140 return False, 0, None, None
00141
00142 try:
00143 plan, states = parse_plan(plan_line, self.atom_class)
00144
00145 except ValueError as e:
00146 rospy.logerr("Received plan from clasp, but unable to parse plan:" +
00147 plan_line)
00148 rospy.logerr(" Error: " + str(e))
00149 return False, 0, None, None
00150
00151 out_file.close()
00152
00153 end_time = time.time()
00154 rospy.loginfo("Planning took %ss." % str(end_time - start_time))
00155
00156 return True, optimization, plan, states
00157