diff --git a/test/planning_utils.py b/test/planning_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..f09d096a4c9666e02baa2b689aa48ab060e88005 --- /dev/null +++ b/test/planning_utils.py @@ -0,0 +1,67 @@ +import gcode2contour as gc +import numpy as np +from gcode2contour import Position + + +class Action: + """ + An action can be a job, or moving between jobs. + + It has a start location, an end location, a time to execute + and when relevant, the associated job + """ + + def __init__(self, start_loc, end_loc, t, job=None): + self.start_location = start_loc + self.end_location = end_loc + self.time = t + self.job = job + + def travel_to(self, other_job): + """ + Calculate distance to another job + End position of this job to the start position of the other job + """ + return abs(self.end_location - other_job.start_location) + + def travel_from(self, other_job): + """ + Calculate distance to another job + Start position of this job to the end position of the other job + """ + return abs(self.start_location - other_job.end_location) + + +def contours2Actions(contours): + """ + Convert a list of contours into a list of actions + """ + + actions = [] + for c in contours: + actions.append(Action(c.pos[0], c.pos[-1], c.time[-1], c)) + + return actions + + +class Plan: + """ + stores the plan of the whole system so far + """ + + def __init__(self, robot_list): + """ + initiate at unplanned state + """ + + self.robots = robot_list + self.actions = {k:[] for k in robot_list} + self.time = {k:0 for k in robot_list} + + def __getitem__(self, robot): + return (self.actions[robot], self.times[robot]) + + def append(self, action, robot): + self.actions[robot].append(action) + self.time[robot] += action.time + diff --git a/test/scheduler.py b/test/scheduler.py index 244d4fd36358826e6763edb8ca52754818bfb162..18b4201adff2e554e6938b83edf24b7992280ba9 100644 --- a/test/scheduler.py +++ b/test/scheduler.py @@ -1,5 +1,6 @@ from DecMCTS import Tree import numpy.random as rand +from planning_utils import * # Creat a bunch of jobs # Each job has a time to do (in seconds?) @@ -9,24 +10,34 @@ n_jobs = 20 job_time_min = 0 job_time_max = 10 vel = 0.1 + rand.seed(1) -job_locs = [(x,y) for x,y in zip(rand.rand(n_jobs), rand.rand(n_jobs))] +job_locs = [Position(x,y,0) + for x,y in zip(rand.rand(n_jobs), rand.rand(n_jobs))] job_times = [job_time_min+(job_time_max-job_time_min)*t for t in rand.rand(n_jobs)] -def dist(p1,p2): - return ((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)**0.5 -travel_time = {(j1,j2):dist(job_locs[j1], job_locs[j2])/vel + +# This is the todo list for the decmcts scheduler +# - for now not considering dependencies +actions = [Action(job_locs[i], job_locs[i], job_times[i], job=i) + for i in range(n_jobs)] + +# Premptively calculate distance pairs +travel_time = {(j1,j2):actions[j1].travel_to(actions[j2])/vel for j1 in range(n_jobs) - for j2 in range(n_jobs)} + for j2 in range(n_jobs) + if j1!=j2} # Data needed for any calculations data = { - "job_locs": job_locs, - "job_times": job_times + "actions": actions "tt": travel_time } -# State For a particular robot class State: + """ + Stores the state of one robot for MCTS + """ + def __init__(self, start_pos): self.jobs = [] self.time_so_far = 0 @@ -40,21 +51,22 @@ class State: self.time_wasted += data["tt"][self.jobs[-1], self.jobs[-2]] self.current_pos = job_locs[new_job] - def state_storer(data, parent_state, action): if parent_state == None: return State((0,0)) # This state is also used Null action when calculating local reward - state = deepcopy(parent_state) + state = deepcopy(parent_state) # NOTE THIS WILL NEED TO CHANGE WITH CONTOURS state.append(action) return state # All actions not done by the current robot are considered available # actions of other robots are not considered def avail_actions(data, states, robot_id): + # NOTE THIS WILL NEED TO CHANGE WITH DEPENDENCY GRAPH return [j for j in list(range(n_jobs)) if j not in states[robot_id].jobs] # reward is inversely proportional to total time taken def reward(dat, states): + # TODO WILL NEED TO DO GREEDY ROLLOUT TO CALC REWARD time_wasted = [states[robot].time_wasted for robot in states] return 1/sum(each_robot_sum)