Commit e5aae54c authored by Jayant Khatkar's avatar Jayant Khatkar

moved scheduler files to different repo

parent 2afd8445
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
from DecMCTS import Tree
from copy import copy, deepcopy
import numpy as np
import numpy.random as rand
from planning_utils import *
import matplotlib.pyplot as plt
# Creat a bunch of jobs
# Each job has a time to do (in seconds?)
# Each job has an x-y location (0-1 m)
# Each job pair has a time to travel between them (fixed velocity m/s)
n_jobs = 20
job_time_min = 0
job_time_max = 10
vel = 0.1
rand.seed(1)
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)]
# 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):j1.travel_to(j2)/vel
for j1 in actions
for j2 in actions
if j1 is not j2}
# Data needed for any calculations
data = {
"actions": set(actions),
"tt": travel_time,
"mean_tt": sum(travel_time.values())/len(travel_time)
}
class State:
"""
Stores the state of one robot for MCTS
"""
def __init__(self, start_pos):
self.actions = []
self.time_so_far = 0
self.time_wasted = 0
self.current_pos = start_pos
def append(self, new_job):
self.actions.append(new_job)
if len(self.actions)>1:
self.time_so_far += data["tt"][self.actions[-1], self.actions[-2]] \
+ new_job.time
self.time_wasted += data["tt"][self.actions[-1], self.actions[-2]]
else:
self.time_wasted = \
Action(Position(0,0,0),Position(0,0,0),0).travel_to(new_job)/vel
self.time_so_far = new_job.time + self.time_wasted
self.current_pos = new_job.end_location
def state_storer(data, parent_state, action):
if parent_state == None:
return State(Position(0,0,0)) # This state is also used Null action when calculating local reward
state = State(action.start_location)
state.actions = copy(parent_state.actions)
state.time_so_far = parent_state.time_so_far
state.time_wasted = parent_state.time_wasted
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, state, robot_id):
# NOTE THIS WILL NEED TO CHANGE WITH DEPENDENCY GRAPH
return [j for j in data["actions"] if j not in state.actions]
# reward is inversely proportional to total time taken
def reward(dat, states):
# TODO DO GREEDY ROLLOUT TO CALC REWARD ??
# Reward is 1/(estimation of total time wasted)
# the estimation is a sum of:
# 1- time wasted so far in the plan
# 2- estimated time wasted in doing the remaining jobs
# This is the number of remaining jobs * mean travel time
# 3- time diff between each robot and the robot with longest plan
# 4- Duplicate executions of jobs
done_jobs = sum([states[robot].actions for robot in states], [])
time_wasted_1 = sum([states[robot].time_wasted for robot in states])
time_wasted_2 = len(data["actions"] - set(done_jobs))*data["mean_tt"]
t_so_far= [states[robot].time_so_far for robot in states]
time_wasted_3 = sum(max(t_so_far) - np.array(t_so_far))
time_wasted_4 = sum([a.time for a in done_jobs if done_jobs.count(a)>1])/2
return -(time_wasted_1 + time_wasted_2 + time_wasted_3 + time_wasted_4)
# Communicate top n nodes of the MCTS tree
comm_n = 5
n_robots = 2
def trees2Plan(trees):
"""
extract the best action sequence from each tree
and convert it into a Plan object
"""
plan = Plan(list(range(len(trees))))
for i in range(len(trees)):
plan.actions[i] = trees[i].my_act_dist.best_action().actions
plan.time[i] = trees[i].my_act_dist.best_action().time_so_far
return plan
# Plot function
def plot_actions(actions, plan = None):
"""
Plot actions
- actions - list of actions
"""
xs = [p.start_location[0] for p in actions]
ys = [p.start_location[1] for p in actions]
max_size = 50
min_size = 10
ss = [p.time for p in actions]
ss = [(p-min(ss))*(max_size-min_size)+min_size for p in ss]
plt.scatter(xs, ys, s = ss)
if plan is not None:
for r in plan.robots:
xs = [0]+[p.start_location[0] for p in plan.actions[r]]
ys = [0]+[p.start_location[1] for p in plan.actions[r]]
plt.plot(xs,ys)
plt.show()
if __name__=="__main__":
trees = [None]*n_robots
for i in range(n_robots):
trees[i] = Tree(data, reward, avail_actions, state_storer, comm_n, i)
for i in range(200):
trees[0].grow()
trees[1].grow()
trees[0].receive_comms(trees[1].send_comms(), 1)
trees[1].receive_comms(trees[0].send_comms(), 0)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment