def get_compabitible_task_for_agent(self, agent, queue): compatible_task_list = TaskQueue() for task in self.tasks.get_queue(): if task.is_agent_compatible(agent): compatible_task_list.enqueue(task) if compatible_task_list.is_empty(): print "No compatible tasks found for agent %s" %agent.name return None return compatible_task_list
class Agent(): def __init__(self, name, pose=Pose(), size=(1.0, 1.0, 1.0), capabilities=[], movement_speed=0.1): # Tuple contain the x,y,z coordinates of the agent self.pose = pose # Rospy pose data structure, used in Unity to determine space self.name = name # Name of this particular agent, needs to be unique self.size = size # the x,y,z size of the agent self.task_queue = TaskQueue() self.capabilities = capabilities self.status = "" self.current_action = "idle" self.movement_speed = movement_speed self.is_at_task = False self.ros_controller = ROSController() def get_pose(self): return self.pose ## TODO, fill in this with a custom message. def get_message(self): pass def add_task(self, task): self.task_queue.enqueue(task) def get_task(self): return self.task_queue.peek() def set_current_task(self, task): self.is_at_task = False self.task_queue.prioritise(task) def update_status(self): if self.task_queue.is_empty(): self.status = "%s is idle." % self.name else: task_name = self.task_queue.peek().name self.status = "%s is %s task[ %s ] currently." % ( self.name, self.current_action, task_name) def get_status(self): self.update_status() return self.status def go_to_current_task(self): if self.pose.position == self.task_queue.peek().pose.position: print("Agent %s is currently at the it's current task!" % self.name) self.is_at_task = True return True self.current_action = "moving to task" self.move_towards_target(self.task_queue.peek().pose.position) return False def move_towards_target(self, target_pos): target_diff_x = target_pos.x - self.pose.position.x target_diff_y = target_pos.y - self.pose.position.y target_diff_z = target_pos.z - self.pose.position.z self.pose.position.x += self.get_move_vector(target_diff_x) self.pose.position.y += self.get_move_vector(target_diff_y) self.pose.position.z += self.get_move_vector(target_diff_z) direction_y = math.atan2(self.get_move_vector(target_diff_y), self.get_move_vector(target_diff_x)) quat = quaternion_from_euler(0, direction_y, 0) self.pose.orientation.x = quat[0] self.pose.orientation.y = quat[1] self.pose.orientation.z = quat[2] self.pose.orientation.w = quat[3] def get_move_vector(self, target_x): if abs(target_x) > self.movement_speed: if target_x < 0: return -self.movement_speed else: return self.movement_speed return target_x def complete_current_task(self): if self.task_queue.peek().is_completed(): print("Current task %s being done by %s has been completed." % (self.task_queue.peek().name, self.name)) self.ros_controller.publish_string_update_message( "%s has been completed by %s" % (self.task_queue.peek().name, self.name)) self.task_queue.dequeue() self.is_at_task = False self.current_action = "completed task" return True print "Current task %s has not yet been completed by agent %s." % ( self.task_queue.peek().name, self.name) return False # OVERRIDE THIS FUNCTION WITH SPECIFIC AGENT FUNCTION def do_work(self): pass
class GameWorld(): def __init__(self, size=(100, 100), agents=[], tasks=TaskQueue(), AI_ON=True): self.size = size self.ai_on = False; self.agents = agents self.tasks = tasks self.map = np.ones(size) self.user_priority_queue = TaskQueue() self.world_task_queue = TaskQueue() self.generate_agents() self.generate_world_tasks() if(self.ai_on): self.assign_tasks() self.ros_controller = ROSController() self.restart = False #self.agents[0].task_queue.prioritise(self.world_task_queue.get_queue()[0]) def update(self): # Prints the tasks in each of the agent queues for debugging reasons. #for agent in self.agents: # print ("Agent: %s has the tasks: %s" % (agent.name, ",".join([t.name for t in agent.task_queue.get_queue()]))) if not self.world_task_queue.is_empty(): #print("Publishing tasks") self.ros_controller.publish_tasks(self.world_task_queue.get_queue()) #print("Publishing Agents") self.ros_controller.publish_agents(self.agents) ## This checks if the game is meant to run yet if self.ros_controller.game_start: if(self.ai_on): timer = Timer() self.check_scenario_complete() for agent in self.agents: agent.do_work() if self.ros_controller.recieved_assign_message: #print("I SHOULDN'T HAVE A ASSIGN MESSAGE YET: %s" % self.ros_controller.recieved_assign_message) self.ros_controller.recieved_assign_message = False assigned_agent = self.find_agent_in_list(self.ros_controller.user_assign_task[0]) assigned_task = self.find_task_in_queue(self.ros_controller.user_assign_task[1]) assigned_agent.add_task(assigned_task) print("Assigned agent %s to do task %s" % (assigned_agent.name, assigned_task.name)) if self.ros_controller.recieved_move_message: self.ros_controller.recieved_move_message = False assigned_agent = self.find_agent_in_list(self.ros_controller.user_assign_move[0]) pose = self.pose_constructor(float(self.ros_controller.user_assign_move[1][0]), float(self.ros_controller.user_assign_move[1][1]),0,0,0,0,1) assigned_agent.set_current_task(MoveTask("TempMoveTask", "Agent needs to move to this spot", end_pose=pose, agent=assigned_agent)) print("Assigned agent %s to move to %s" %(assigned_agent.name, pose)) # DEBUG STUFF! # print("!!!!!!CURRENT LOCATION OF AGENTS AND THEIR TARGETS!!!!!!") # for agent in self.agents: # # print("AGENT: %s - Position:\n %s \n TASK: %s - Position:\n %s" % (agent.name, # agent.pose.position, # agent.task_queue.peek().name, # agent.task_queue.peek().pose.position)) # print("---------------------------------------------------------") def find_task_in_queue(self, task_name): for task in self.world_task_queue.get_queue(): if task.name == task_name: return task print("Could not find the task..") return None def find_agent_in_list(self, agent_name): for agent in self.agents: print("ListAgent: %s == InputAgent: %s = %s" % (agent.name, agent_name, agent.name == agent_name) ) if agent.name == agent_name: return agent print [ agent.name for agent in self.agents] print "Could not find the agent!" return None def check_scenario_complete(self): for t in self.world_task_queue.get_queue(): if not t.is_complete: return False timer = Timer() while not self.ros_controller.got_end_confirmation: message = String() message.data = "finished" self.ros_controller.publish_update_message(message) message.data = "end time|%s" %timer.get_elasped_time() self.ros_controller.publish_update_message(message) time.sleep(0.05) print("All assigned tasks have been completed!") self.restart = True def add_agent(self, agent): self.agents.append(agent) def add_task(self, task): self.tasks.enqueue(task) self.world_task_queue.enqueue(task) def get_nearest_tasks(self, agent): nearest_task = None # Finds the furthest possible distance between two points of a rectangluar grid. nearest_dist = math.sqrt(math.pow(self.size[0], 2) + math.pow(self.size[1], 2)) for task in agent.task_queue.get_queue(): if not task.assigned_agent: dist = math.sqrt(math.pow(task.pose.position.x - agent.pose.position.x, 2) + math.pow(task.pose.position.y - agent.pose.position.y, 2) + math.pow(task.pose.position.z - agent.pose.position.z, 2)) if dist < nearest_dist: nearest_task = task # Ensures no "current task" is assigned to multiple agents, #self.tasks.remove(nearest_task) task.assigned_agent = agent return nearest_task def sort_nearest_tasks(self, agent, queue): compatible_list = [task for task in queue.queue if task.is_agent_compatible(agent)] dist_list = [] for task in compatible_list: dist = math.sqrt(math.pow(task.pose.position.x - agent.pose.position.x, 2) + math.pow(task.pose.position.y - agent.pose.position.y, 2) + math.pow(task.pose.position.z - agent.pose.position.z, 2)) dist_list.append(dist) zipped = zip(dist_list, compatible_list) zipped.sort() dist_list, sorted_list = zip(*zipped) queue.queue = list(sorted_list) return queue def get_compabitible_task_for_agent(self, agent, queue): compatible_task_list = TaskQueue() for task in self.tasks.get_queue(): if task.is_agent_compatible(agent): compatible_task_list.enqueue(task) if compatible_task_list.is_empty(): print "No compatible tasks found for agent %s" %agent.name return None return compatible_task_list def assign_tasks(self): for agent in self.agents: # Unneccessary but whatever. task_queue = copy.copy(self.world_task_queue) agent.task_queue = self.sort_nearest_tasks(agent, task_queue) def generate_agents(self, num_of_agents=0): pose1 = Pose() pose1.position.x = 0 self.add_agent(ConstructionAgent('Construction Agent 1', self.pose_constructor(60, 50, 0, 0, 0, 0, 1))) self.add_agent(ConstructionAgent('Construction Agent 2', self.pose_constructor(40, 50, 0, 0, 0, 0, 1))) self.add_agent(ConstructionAgent('Construction Agent 3', self.pose_constructor(50, 40, 0, 0, 0, 0, 1))) self.add_agent(TransportAgent('Transport Agent 1', pose=self.pose_constructor(50, 60, 0, 0, 0, 0, 1))) def pose_constructor(self, posX, posY, posZ, quadX, quadY, quadZ, quadW): tempPose = Pose() tempPose.position.x = posX tempPose.position.y = posY tempPose.position.z = posZ tempPose.orientation.x = quadX tempPose.orientation.y = quadY tempPose.orientation.z = quadZ tempPose.orientation.w = quadW return tempPose def generate_world_tasks(self, no_of_task=0): self.add_task(ConstructionTask('Construction Task 1',"Construction required in this area", pose=self.pose_constructor(50, 10, 0, 0, 0, 0, 1))) self.add_task(ConstructionTask('Construction Task 2', "Construction required in this area", pose=self.pose_constructor(60, 20, 0, 0, 0, 0, 1))) self.add_task(ConstructionTask('Construction Task 3', "Construction required in this area", pose=self.pose_constructor(40, 27, 0, 0, 0, 0, 1))) self.add_task(ConstructionTask('Construction Task 4', "Construction required in this area", pose=self.pose_constructor(10, 65, 0, 0, 0, 0, 1))) self.add_task(ConstructionTask('Construction Task 5', "Construction required in this area", pose=self.pose_constructor(65, 40, 0, 0, 0, 0, 1))) self.add_task(ConstructionTask('Construction Task 6', "Construction required in this area", pose=self.pose_constructor(15, 50, 0, 0, 0, 0, 1))) self.add_task(TransportTask('Transport Task 1', "Transport required", pose=self.pose_constructor(45, 65, 0, 0, 0, 0, 1), end_pose=self.pose_constructor(10, 80, 0, 0, 0, 0, 1))) self.add_task(TransportTask('Transport Task 2', "Transport required", pose=self.pose_constructor(15, 75, 0, 0, 0, 0, 1), end_pose=self.pose_constructor(30, 10, 0, 0, 0, 0, 1))) self.add_task(TransportTask('Transport Task 3', "Transport required", pose=self.pose_constructor(55, 70, 0, 0, 0, 0, 1), end_pose=self.pose_constructor(35, 80, 0, 0, 0, 0, 1)))