class Crops(dict): switch_template = HD.loadTemplates('crops', 'switch*') def __init__(self, device, tasklist): self.log = MyLogger('Crops', LOG_LEVEL=logging.INFO) self.device = device self.tasklist = tasklist self.data = [] self.settings = [] self.updateListData() def updateListData(self): settings = HD.loadJSON('crops') resources = HD.loadJSON('resources') count = {} if len(resources) and "crops" in resources and len(settings): if resources['crops'] != self.data or settings != self.settings: self.log.error("Changes found") self.log.error(settings) self.log.error(self.settings) self.log.error(resources['crops']) self.log.error(self.data) self.data = resources['crops'] self.settings = settings for crop in self.values(): crop.enabled = False for newcrop in self.data: crop = newcrop['crop'] if crop not in count: count[crop] = 0 count[crop] += 1 name = f"Crop {crop} [{count[crop]}]" if crop in self.settings: if name not in self: self[name] = Crop(self.device, self.tasklist, crop) data = self.settings[crop].copy() data.update(newcrop) data['name'] = name data['log'] = self.log data['enabled'] = True self.log.debug(f"location: {newcrop['location']}") data['position'] = self.device.getPos( newcrop['location']) self.log.debug(f"position: {data['position']}") data['temp_switch'] = self.switch_template data['update'] = self.updateListData for key, value in data.items(): setattr(self[name], key, value)
class Trees(dict): def __init__(self, device, tasklist): self.log = MyLogger('TREES', LOG_LEVEL=logging.INFO) self.device = device self.tasklist = tasklist self.data = [] self.settings = [] self.updateListData() def updateListData(self): self.log.debug('updating data') settings = HD.loadJSON('trees') resources = HD.loadJSON('resources') count = {} if len(resources) and "trees" in resources and len(settings): self.log.debug('data is valid') if resources['trees'] != self.data or settings != self.settings: self.data = resources['trees'] self.settings = settings for fruit in self.values(): fruit.enabled = False for newfruit in self.data: fruit = newfruit['fruit'] self.log.debug(f'fruit: {fruit}') if fruit not in count: count[fruit] = 0 count[fruit] += 1 self.log.debug(f"amount: {newfruit['amount']}") for i in range(newfruit['amount']): name = f"{fruit} [{count[fruit]}-{i}]" self.log.debug(f"name: {name}") if fruit in self.settings: if name not in self: self[name] = Tree(self.device, self.tasklist, fruit) data = self.settings[fruit].copy() data['log'] = self.log data['name'] = name data['enabled'] = True data['position'] = self.device.getPos( newfruit['location']) data['templates'] = HD.loadTemplateMap( 'trees', fruit) data['update'] = self.updateListData for key, value in data.items(): setattr(self[name], key, value)
class Shop(HD): def __init__(self, device, tasklist): HD.__init__(self, device, tasklist, 'money') self.log=MyLogger('shop', LOG_LEVEL=logging.DEBUG) self.tasklist.addtask(20, f"checking for items to sell", self.image, self.checkItems) self.shoplist=Shoplist(self) self.position=HD.getPos([-15,0]) self.slots=4 self.max_slots=4 self.atshop=False self.temp_shop=self.device.loadTemplates('shop','') def add(self, product, min_amount=6,sell=False): self.products.append(ShopItem(product, min_amount)) def checkItems(self): self.atshop=False wait=10 if self.max_slots>self.slots: self.checkShop() self.atshop=True try: json_data=HD.loadJSON('sell') for product,data in data.items(): wished,scheduled=self.tasklist.getWish(product) #check if prodruct needs to be ordered if (scheduled-wished<data['maximum']-self.slots*data['amount']) and data['order']: self.log.debug(f'need more {product}') self.tasklist.addWish(product,data['maximum']-(scheduled-wished)) if -wished>data['minimum']+data['amount']: available=-wished-data['minimum'] stocks=int(available/data['amount']) if stocks<self.slots: self.slots-= stocks else: stocks=self.slots self.slots=0 if stocks: self.log.debug(f'i can sell some') self.shoplist.add(product,stocks, **data) wait=2 except Exception as e: self.log.error(e) finally: self.tasklist.addtask(wait, f"checking for items to sell", self.image, self.checkItems) self.sellItems() def sellItems(self): self.log.debug('selling items') try: if not len(shoplist): raise Exception("No items to sell") if not self.atshop or self.open_shop(): raise Exception("Shop is not open") spots=self.device.locate_item(self.temp_create, 0.85) for product,data in self.shoplist.items(): if product in self.temp_products: while self.shoplist[product].stock: if not len(spots): raise Exception("No free spot to sell items"): location=spots.pop() self.device.tap(location) location=self.device.locate_item(self.temp_products[product],.85, one=True) if not len(location): raise Exception("Could not find product in list") self.device.tap(location) self.log.debug('item should be selected by now') if not len(locations): raise except Exception as e: self.log.error(e) def checkShop(self): self.log.debug('checking Shop') try: if not self.open_shop(): raise Exception("Shop is not open") locations=self.device.locate_item(self.temp_sold, 0.85) if not len(locations): raise Exception("Could not find sold items") for location in locations: self.device.tap(location) except Exception as e: self.log.error(e) def open_shop(self): try: self.move_to() location = self.device.locate_item(self.temp_shop, .85, one = True) if not len(location): raise Exception("Could not locate shop") self.device.tap(location) self.atshop=True return True except Exception as e: self.log.error('OPEN SHOP') self.log.error(e) return False
class Adb_Device(): device = None touch = "/dev/input/event6" res_x, res_y = [1600, 900] max = 32767 output = ShowOutput() lastscreen = None def __init__(self): self.log = MyLogger('ADB', LOG_LEVEL=logging.INFO) client = Client(host='127.0.0.1', port=5037) self.log.debug(client.version()) devices = client.devices() if len(devices) == 0: self.log.debug("no devices") quit() self.device = devices[0] self.log.debug(f'updating info for {self.device}') number = 5 touch_id = 0 lines = self.device.shell('getevent -p').split("\n") for line in lines: if "/dev/input" in line: number = line[-1] if "Touch" in line: touch_id = number self.touch = f"sendevent /dev/input/event{number}" if "max" in line and "ABS" in line and number == touch_id: values = line.split(', ') for value in values: if "max" in value: self.max = int(value[4:]) self.log.debug(f"found max: {self.max}") @staticmethod def correct(list1, list2): newlist = [] dx = list2[0][0] - list1[0][0] dy = list2[0][1] - list1[0][1] for x, y in list1: newlist.append([x + dx, y + dy]) return newlist @staticmethod def getClosest(list, vector): x_target, y_target = vector winner = list[0] score = 99999 for loc in list: x, y = loc newscore = (x_target - x)**2 + (y_target - y)**2 if newscore < score: winner = [x, y] score = newscore return winner @staticmethod def checkClose(x1, y1, list, tol_x=30, tol_y=16): for location in list: x2, y2 = location if (isclose(x1, x2, abs_tol=tol_x) and isclose(y1, y2, abs_tol=tol_y)): return True else: return False @staticmethod def getClose(list, x1, y1, tol_x, tol_y): newlist = [] for vector in list: x2, y2 = vector if (isclose(x1, x2, abs_tol=tol_x) and isclose(y1, y2, abs_tol=tol_y)): newlist.append(vector) return newlist def release_all(self): shellcmd = f"{self.touch} 3 57 -1 && {self.touch} 0 2 0 && {self.touch} 0 0 0" self.device.shell(shellcmd) def zoom_out(self): y = 0.35 x_c = .5 dx = 0.25 steps = [] for i in range(10): x1 = x_c - dx * (10 - i) / 11 x2 = x_c + dx * (10 - i) / 11 steps.append(f"{self.touch} 3 57 0") steps.append(f"{self.touch} 3 53 {int(x1*self.max)}") steps.append(f"{self.touch} 3 54 {int(y*self.max)}") steps.append(f"{self.touch} 0 2 0") steps.append(f"{self.touch} 3 57 1") steps.append(f"{self.touch} 3 53 {int(x2*self.max)}") steps.append(f"{self.touch} 3 54 {int(y*self.max)}") steps.append(f"{self.touch} 0 2 0") steps.append(f"{self.touch} 0 0 0") shellcmd = " && ".join(steps) self.device.shell(shellcmd) self.release_all() self.release_all() sleep(.1) # cmd=f"{self.touch} 3 57 2 && {self.touch} 3 53 {int((x_c-dx)*self.max)} && {self.touch} 3 54 {int(y*self.max)}" # self.device.shell(cmd) # self.device.shell(f"input swipe {(x_c+dx)*self.res_x} {(y)*self.res_y} {(x_c-dx)*self.res_x} {(y)*self.res_y} 2000") # self.release_all() # self.release_all() def printScreen(self): screencap = self.device.screencap() screenshot_file = path.join('images', 'screen.png') with open(screenshot_file, 'wb') as f: f.write(screencap) def tap(self, x, y): self.device.shell(f'input tap {x} {y}') sleep(.3) def trace(self, waypoints, size=0, pressure=0): eventlist = [] for waypoint in waypoints: x, y = waypoint eventlist.append(f"{self.touch} 3 57 0") eventlist.append(f"{self.touch} 3 53 {int(x*self.max/self.res_x)}") eventlist.append(f"{self.touch} 3 54 {int(y*self.max/self.res_y)}") if size: eventlist.append(f"{self.touch} 3 48 {size}") if pressure: eventlist.append(f"{self.touch} 3 58 {pressure}") eventlist.append(f"{self.touch} 0 2 0") eventlist.append(f"{self.touch} 0 0 0") # for event in eventlist: # self.device.shell(event) shellcmd = " && ".join(eventlist) self.device.shell(shellcmd) self.release_all() # self.device.shell(shellcmd) def move(self, x, y): self.log.debug('moving') border_x = self.scale_X(500) border_y = self.scale_Y(300) center_x = self.scale_X(800) center_y = self.scale_Y(450) while (x or y): if x < 0: dx = x if x > -border_x else -border_x else: dx = x if x < border_x else border_x if y < 0: dy = y if y > -border_y else -border_y else: dy = y if y < border_y else border_y self.swipe(self.res_x / 2 + dx, self.res_y / 2 + dy, center_x, center_y, 500) x = x - dx y = y - dy def swipe(self, x1, y1, x2, y2, speed=300): self.device.shell(f'input swipe {x1} {y1} {x2} {y2} {speed}') sleep(.3) def center(self, x, y): self.swipe(x, y, self.res_x / 2, self.res_y / 2, 500) def load_screen_img(self): screenshot_file = path.join('images', 'screen.png') return cv2.imread(screenshot_file) @staticmethod def show_img(img): cv2.imshow('Test', img) cv2.waitKey(0) # waits until a key is pressed cv2.destroyAllWindows() # destroys the window showing image def load_screenCap(self): screencap = self.device.screencap() img_bytes = bytes(screencap) self.lastscreen = cv2.imdecode(np.fromstring(img_bytes, np.uint8), cv2.IMREAD_COLOR) # self.show_img(img) return self.lastscreen # screenshot_file=path.join('images','screen.png') # with open(screenshot_file, 'wb') as f: # f.write(screencap) # sleep(.1) # return cv2.imread(screenshot_file) def get_match(self, template, img, threshold, margin): loc = [] if len(template.data): result = cv2.matchTemplate(img, template.data, cv2.TM_CCOEFF_NORMED) max = np.max(result) # self.log.debug(template.file) # self.log.debug(f"offset: {template.offset}") # self.log.debug(f"max: {max}") if (max >= threshold): min = max - margin if ( max - margin >= threshold) else threshold loc = np.where(result >= min) return loc def check_present(self, template_dict, threshold=0.75, margin=0.05): img = self.load_screenCap() list = [] for name, template in template_dict.items(): if len(self.get_match(template, img, threshold, margin)): list.append(name) return list #calculate new x or y, if device has an other resolution than 1600:900 def scale_X(self, x): return x * self.res_x / 1600 def scale_Y(self, y): return y * self.res_y / 900 #calculate a new location based on location and the given vector #vector[x,y]=[0,1]=NE -> -X (screen) and -Y (screen) #vector[1] positive = NW -> dx = positive, dy= negative def getPos(self, vector, location=[0, 0], multiplier=1): x, y = location dx = int(self.scale_X(47) * (vector[0] - vector[1]) * multiplier) dy = int(self.scale_Y(23.5) * -(vector[0] + vector[1]) * multiplier) return [x + dx, y + dy] #get color of pixel on this location def getColor(self, location): x, y = location img = self.lastscreen (b, g, r) = img[y, x] return [r, g, b] def locate_item(self, templates, threshold=0.75, margin=0.05, one=False, offset=[30, 16], last=False): result_file = path.join('images', 'result.png') img_base = self.lastscreen if last else self.load_screenCap() img_result = img_base loclist = [] for template in templates: self.log.debug(template) loc = self.get_match(template, img_base, threshold, margin) if len(loc) and len(loc[0]): for pt in zip(*loc[::-1]): # Switch collumns and rows cv2.rectangle(img_result, pt, (pt[0] + template.w, pt[1] + template.h), (0, 0, 255), 2) x, y = np.add(pt, template.offset).astype(int) if not self.checkClose(x, y, loclist, *offset): self.log.debug(f"found on {x},{y} ") self.log.debug(f"point={pt}") cv2.rectangle(img_result, pt, (pt[0] + template.w, pt[1] + template.h), (255, 0, 255), 2) loclist.append([x, y]) for vector in loclist: x, y = vector cv2.circle(img_result, (x, y), 10, (0, 255, 0), -1) # cv2.imwrite(result_file, img_result) self.output.update(img_result) if one and len(loclist): target = [self.res_x / 2, self.res_y / 2] loclist = self.getClosest(loclist, target) return loclist
class agent(): def __init__(self, logfile): self.log = MyLogger(logfile) self.createModel() ''' create model for every traffic light ''' def createModel(self): self.model = {} for tl in ni.trafficLights: dims = util.getDims() self.model[tl] = singleModel(dims) def clearRecord(self): del self.record gc.collect() def addRecord(self, step, addEdgeRecord = True, addTrafficLightRecord = True, addVehicleRecord = True): self.record['step'] = step if addEdgeRecord: util.addEdgeRecord(traci, self.record['edge'], step) if addTrafficLightRecord: util.addTrafficLightRecord(traci, self.record['trafficlight'], step) if addVehicleRecord: util.addVehicleRecord(traci, self.record['vehicle'], step) ''' self.record record details for the whole network on every step ''' def createRecord(self): self.record = {} self.record['edge'] = {} self.record['trafficlight'] = {} self.record['vehicle'] = {} # get edge record self.record['edge']['speed'],self.record['edge']['number'] ,self.record['edge']['halting'] = util.getEdgeRecord() # get tl record self.record['trafficlight']['phase'],self.record['trafficlight']['duration'] = util.getTrafficLightRecord() # get vehicle record self.record['vehicle']['edge'],self.record['vehicle']['waittime'] = util.getVehicleRecord() self.record['step'] = -1 self.record['state'] = util.getStateRecord() def getPreProcessData(self, totaldays): preData = {} for i in ni.trafficLights: preData[i] = [] sumoCmd = ["sumo", "-c", ni.sumocfg, "--ignore-route-errors", "--time-to-teleport", "600"] for i in range(totaldays): self.log.debug('collecting preprocess data: ' + str(i) + ' days') getNewDemand() traci.start(sumoCmd) self.createRecord() step = 0 while step < 7200: self.addRecord(step, addVehicleRecord = False) step += 1 for tl in ni.trafficLights: flag = util.adjustFlag(tl, self.record) if flag: feature = util.getFeature(tl, self.record) preData[tl].append(feature) traci.simulationStep() traci.close() #self.clearRecord() if (i+1)%10 == 0: for tl in ni.trafficLights: a = np.array(preData[tl]) a = np.array(a) file = 'preprocess/' +tl np.save(file, a) #torch.save(preData, 'preprocess.pt') def train(self, totaldays): self.loadScaler() savedays = 4 starttraindays = 3 sumoCmd = ["sumo", "-c", ni.sumocfg, "--ignore-route-errors", "--time-to-teleport", "600"] for i in range(totaldays): getNewDemand() self.createRecord() self.log.debug('train ' + str(i) + ' epoch') traci.start(sumoCmd) step = 0 while step < 7200: self.simulation(traci, step) step += 1 if i >= starttraindays: for tl in ni.trafficLights: self.model[tl].train(tl ,self.log) traci.close() if (i+1)%savedays == 0: savefile = 'model/'+'version'+str(int((i+1)/savedays)) + '_' self.log.debug('save model, reward and step in ' + savefile) for tl in ni.trafficLights: file = savefile + tl self.model[tl].save(file) def clearRecord(self): self.createRecord() def simulation(self, traci, step): self.addRecord(step) for tl in ni.trafficLights: self.adjustTrafficLight(traci, tl) traci.simulationStep() def adjustTrafficLight(self, traci, tl, record = True): flag = util.adjustFlag(tl, self.record) if flag: step = self.record['step'] feature = util.getFeature(tl, self.record) feature = self.transform(tl, feature) reward = util.getReward(tl, self.record) qvalue = self.model[tl].forward(feature) action, actionset = util.getAction(tl, qvalue.data, self.record, epsilon = 0.1) self.record['state'][tl].append([feature, action, reward, step, actionset]) self.addexperience(tl) self.executeAction(tl, action, step) def transform(self, tl, feature): feature = self.scaler[tl].transform([feature]) array = torch.FloatTensor(feature) array = torch.squeeze(array) array = autograd.Variable(array) return array def executeAction(self, tl, action, step): phase = self.record['trafficlight']['phase'][tl][step] if phase == 0 and action == 0: traci.trafficlights.setPhaseDuration(tl, ni.actionDuration) if phase == 4 and action == 0: traci.trafficlights.setPhaseDuration(tl, 0) if phase == 0 and action == 1: traci.trafficlights.setPhaseDuration(tl, 0) if phase == 4 and action == 1: traci.trafficlights.setPhaseDuration(tl, ni.actionDuration) def addexperience(self, tl): if len(self.record['state'][tl]) > 1: current = self.record['state'][tl][-1] last = self.record['state'][tl][-2] laststep = last[3] self.model[tl].append([last[0], last[1], current[0], last[2], current[4], laststep]) def loadScaler(self): self.scaler = {} for tl in ni.trafficLights: file = 'preprocess/'+tl+'.npy' data = np.load(file) print(np.shape(data)) self.log.debug('loading pre process scaler : '+ file) self.scaler[tl] = prep.StandardScaler().fit(data) def evaluation(self): pass
class model(): def __init__(self, loggerfile, modelfile = False): self.logger = MyLogger(loggerfile) self.trafficLights = ni.trafficLights self.linkEdges = ni.linkEdges if modelfile == False: self.model = self.createModel() else: self.logger.debug(' load model : ' + modelfile) self.model = torch.load(modelfile) self.actionMap = self.createActionMap() def createActionMap(self): map = {'inttostr':{},'strtoint':{}} tlLen = len(self.trafficLights) maxid = 3 ** tlLen for i in range(maxid): strid = "" mx = i for j in range(tlLen): st = int(mx%3) strid += str(st) mx = int(mx/3) map['inttostr'][i] = strid map['strtoint'][strid] = i return map def createModel(self): tlNum = len(self.trafficLights) dim = 0 for tl in self.trafficLights: dim += len(self.linkEdges[tl]['in']) dims = 0 dims += dim if ni.useHalting: dims += dim if ni.useSpeed: dims += dim if ni.usePhase: dims += tlNum self.dims = dims self.actions = 3 ** tlNum return QValueMap(dims, dims*2, 3 ** tlNum) def save(self, file): rewardlist = self.memory.reward step = self.memory.step torch.save(rewardlist, 'reward/reward.pt') torch.save(step, 'reward/step.pts') torch.save(self.trainRecord['loss'], 'loss/' + file + '_loss.pt') torch.save(self.model, 'model/' + file + '.pt') def train(self, totaldays, modellast = ''): self.loadPreProcessScaler(ni.preProcessDataFile) self.logger.debug(" ----------------------------- train -----------------------------") sumoBinary = "sumo" sumoCmd = [sumoBinary, "-c", ni.sumocfg, "--ignore-route-errors"] targetmodel = deepcopy(self.model) optimizer = optim.Adam(self.model.parameters(), lr=0.001) gamma = 0.95 exchange = 500 exchangeDays = 5 modellast += str(gamma) tua = 0.01 minibatch = 128 loss_function = nn.MSELoss(size_average = False) totalloss = 0 evaluationDays = 4 self.trainCnt = 0 self.createTrainRecord() self.memory = memory(100000, 128) for i in range(totaldays): self.createRecord() getNewDemands(ni.generateTrips, ni.netXml, ni.tripsXml, ni.rouXml) traci.start(sumoCmd) step = 0 self.logger.debug("train days : "+str(i)) while step < 7200: flag = self.simulation(traci, step, record = True) step += 1 loss = self.trainModel(targetmodel, optimizer, loss_function, gamma = gamma, minibatch = minibatch) if loss > 0: totalloss += loss self.trainRecord['loss'].append(loss) if self.trainCnt>0 and self.trainCnt%exchange == 0 and totalloss > 0: self.logger.debug(" --------- soft copy parameters --------- ") soft_update(self.model, targetmodel, tua) self.logger.debug(" totalloss :" + str(totalloss/exchange)) totalloss = 0 traci.close() if i > 0 and (i+1)%evaluationDays == 0: self.logger.debug(" version: " + str(int((i+1)/evaluationDays)) + " days: " + str(i)) self.hiddenRecord() self.evaluation() self.loadRecord() self.logger.debug(" --------- save model -----------") modelfile = 'version_' + str(int((i+1)/evaluationDays)) + '_' + modellast self.save(modelfile) self.clearTrainRecord() #self.getCsvTrafficLight('csv/test.csv') def clearTrainRecord(self): self.trainRecord['state'] = [] self.trainRecord['dataLen'] = 0 def hiddenRecord(self): self.hidden = {} self.hidden['trainRecord'] = self.trainRecord self.hidden['record'] = self.record def loadRecord(self): self.record = self.hidden['record'] self.trainRecord = self.hidden['trainRecord'] def getMeanWaitTime(self): step = self.record['step'] maxid = self.record['maxid'][step] return sum(self.record['vehiclewaittime'][:,step])/(maxid+1) def evaluation(self): self.loadPreProcessScaler(ni.preProcessDataFile) sumoBinary = "sumo" sumoCmd = [sumoBinary, "-c", ni.sumocfg, "--ignore-route-errors"] getNewDemands(ni.generateTrips, ni.netXml, ni.tripsXml, ni.rouXml) self.createRecord() self.createTrainRecord() step = 0 traci.start(sumoCmd) while step < 7200: self.simulation(traci, step, record = False, epsilon = 0) step += 1 traci.close() meanwaittime = self.getMeanWaitTime() self.getCsvTrafficLight('csv/model.csv') self.createRecord() step = 0 traci.start(sumoCmd) while step < 7200: self.addRecord(traci, step) traci.simulationStep() step += 1 traci.close() fixmeanwaittime = self.getMeanWaitTime() self.getCsvTrafficLight('csv/fix.csv', action = False) self.logger.debug(" fix : " + str(fixmeanwaittime) + " model: " + str(meanwaittime)) def loadPreProcessScaler(self, file): data = np.load(file) #print(np.shape(data)) self.logger.debug('loading pre process scaler : '+ file) self.scaler = prep.StandardScaler().fit(data) def getPreProcessData(self, totaldays, file): sumoBinary = "sumo" sumoCmd = [sumoBinary, "-c", ni.sumocfg, "--ignore-route-errors"] totalfeature = [] for i in range(totaldays): getNewDemands(ni.generateTrips, ni.netXml, ni.tripsXml, ni.rouXml) self.logger.debug('collecting days: '+str(i) + ' data') traci.start(sumoCmd) step = 0 self.clearRecord() while step < 7200: self.addRecord(traci, step, getwaittime = False) adjustFlag = self.getAdjustFlag() if adjustFlag: feature = self.getFeatureList() totalfeature.append(feature) traci.simulationStep() step += 1 traci.close() tf = np.array(totalfeature) np.save(file, tf) def getCsvTrafficLight(self, file, action = True): lent = len(self.trafficLights) if action: array = np.zeros((7300,lent*2+1)) else: array = np.zeros((7300,lent*2)) cols = [] for tl in self.trafficLights: cols.append(tl + 'p') cols.append(tl + 'd') if action: cols.append('action') for i in range(7200): for j in range(lent): tl = self.trafficLights[j] array[i,j*2+0] = self.record['phase'][tl][i] array[i,j*2+1] = self.record['duration'][tl][i] array[i,-1] = -1 if action: for i in range(self.trainRecord['dataLen']): d = self.trainRecord['state'][i-1] a = d[1] step = d[2] array[step,lent*2] = a dataFrame = DataFrame(array, columns = cols) dataFrame.to_csv(file) def trainModel(self, targetmodel, optimizer, loss_function, gamma = 0.1, minibatch = 128): ln = self.memory.getMemoryLen() if ln < 5000: return -1 self.trainCnt += 1 indexlist = self.memory.sample() input = torch.FloatTensor(len(indexlist), self.dims) inputtarget = torch.FloatTensor(len(indexlist), self.dims) target = torch.FloatTensor(len(indexlist), self.actions) for j in range(len(indexlist)): data = indexlist[j] s = data[0] a = data[1] sn = data[2] r = data[3] input[j,:] = torch.squeeze(s.data) inputtarget[j,:] = torch.squeeze(sn.data) input = autograd.Variable(input) inputtarget = autograd.Variable(inputtarget) qs = self.model(input) qsn = targetmodel(inputtarget) qsdata = torch.squeeze(qs.data) qsndata = torch.squeeze(qsn.data) target = qsdata.clone() for j in range(len(indexlist)): data = indexlist[j] a = data[1] r = data[3] actionset = data[4] target[j,a] = r + gamma*max(torch.index_select(qsndata[j,:],0,torch.LongTensor(actionset))) #target[j,a] = r + gamma*max(qsndata[j,:]) target = autograd.Variable(target) loss = loss_function(qs, target) loss.backward() for param in self.model.parameters(): param.grad.data.clamp_(-1, 1) optimizer.step() optimizer.zero_grad() return loss.data[0] def sample(self, batch): lt = [] num = self.trainRecord['dataLen'] - 1 for i in range(batch): p = random.uniform(0,num) lt.append(int(p)) return lt def simulation(self, traci, step, record = False, epsilon = 0.05): self.addRecord(traci, step) adjustFlag = self.getAdjustFlag() flag = False if adjustFlag: self.adjustTrafficLights(traci, record = record, epsilon = epsilon) flag = True traci.simulationStep() return flag def adjustTrafficLights(self, traci, record, epsilon = 0.05): feature = self.getFeature() #print(feature) qvalue = self.model(feature) action,actionset = self.getAction(qvalue.data, epsilon) self.executeAction(traci,action) if record: self.trainRecord['dataLen'] += 1 option = ni.option if self.trainRecord['dataLen'] == 1: laststep = 0 else: laststep = self.trainRecord['state'][-1][2] step = self.record['step'] reward = self.getReward(infor = [laststep, step, 0.02], options = option) self.trainRecord['state'].append([feature, action, step, actionset, reward]) if self.trainRecord['dataLen'] > 1: lastdata = self.trainRecord['state'][-2] lastfeature = lastdata[0] lastaction = lastdata[1] laststep = lastdata[2] lastreward = lastdata[4] experience = [lastfeature, lastaction, feature, reward, actionset, laststep] self.memory.append(experience) def getReward(self, infor, options): if options == 1: laststep = infor[0] epsilon = infor[1] step = self.record['step'] assert( step > laststep ) waittime = epsilon * sum(self.record['vehiclewaittime'][:,step] - self.record['vehiclewaittime'][:,laststep])/(step-laststep) return 0-waittime if options == 2: llstep = infor[0] laststep = infor[1] step = self.record['step'] assert( laststep > llstep ) lastmeanwait = sum(self.record['vehiclewaittime'][:,llstep])/(self.record['maxid'][llstep]+1) meanwait = sum(self.record['vehiclewaittime'][:,laststep])/(self.record['maxid'][laststep]+1) return lastmeanwait - meanwait if options == 3: llstep = infor[0] laststep = infor[1] epsilon = infor[2] assert( laststep > llstep ) waittime = epsilon * sum(self.record['vehiclewaittime'][:,laststep] - self.record['vehiclewaittime'][:,llstep])/(laststep-llstep) return 0-waittime if options == 4: llstep = infor[0] laststep = infor[1] epsilon = infor[2] assert( laststep > llstep ) waittime = sum(self.record['vehiclewaittime'][:,laststep] - self.record['vehiclewaittime'][:,llstep])/(laststep-llstep)/(self.record['currentNum'][llstep]+1) return 0-waittime def executeAction(self,traci,action): straction = self.actionMap['inttostr'][action] for i in range(len(straction)): inti = int(straction[i]) #print(i) tl = self.trafficLights[i] phase = self.record['phase'][tl][-1] if inti == 0: if phase == 0: traci.trafficlights.setPhaseDuration(tl, ni.actionDuration) if phase == 4: traci.trafficlights.setPhaseDuration(tl, 0) if inti == 1: if phase == 0: traci.trafficlights.setPhaseDuration(tl, 0) if phase == 4: traci.trafficlights.setPhaseDuration(tl, ni.actionDuration) if inti == 2: pass def getAction(self, qvalue, epsilon): nophase = [] for tl in self.trafficLights: phase = self.record['phase'][tl][-1] if phase != 0 and phase != 4: nophase.append(2) else: duration = self.record['duration'][tl][-1] if duration < 20: if phase == 0: nophase.append(0) else: nophase.append(1) elif duration > 190: if phase == 0: nophase.append(1) else: nophase.append(0) else: nophase.append(-1) actionset = self.getActionSet(nophase) #self.logger.DEBUG("") action = actionset[0] maxvalue = qvalue[action] p = random.uniform(0,1) if p > epsilon: for a in actionset: value = qvalue[a] if value > maxvalue: action = a maxvalue = value return action,actionset else: pa = random.uniform(0,len(actionset)) pa = int(pa) return actionset[pa],actionset def getActionSet(self, nophase): strlist = [""] for i in nophase: lt = [] p = i if p == -1: for j in strlist: lt.append(j+"0") lt.append(j+"1") else: for j in strlist: lt.append(j+str(p)) strlist = lt actionset = [] for st in strlist: id = self.actionMap['strtoint'][st] actionset.append(id) return actionset def getFeatureList(self): featureList = [] for tl in self.trafficLights: for edge in self.linkEdges[tl]['in']: featureList.append(self.record['vehicleNum'][edge][-1]) if ni.useHalting: for tl in self.trafficLights: for edge in self.linkEdges[tl]['in']: featureList.append(self.record['haltingNum'][edge][-1]) if ni.useSpeed: for tl in self.trafficLights: for edge in self.linkEdges[tl]['in']: featureList.append(self.record['speed'][edge][-1]) if ni.usePhase: for tl in self.trafficLights: featureList.append(self.record['phase'][tl][-1]) return featureList def getFeature(self): featureList = self.getFeatureList() feature = self.scaler.transform([featureList]) array = torch.FloatTensor(feature) array = torch.squeeze(array) array = autograd.Variable(array) return array def getAdjustFlag(self): for tl in self.trafficLights: phase = self.record['phase'][tl][-1] if phase == 0 or phase == 4: duration = self.record['duration'][tl][-1] if duration > 1 and (duration+1)%self.record['maxduration'] == 0: return True return False def addRecord(self, traci, step, getwaittime = True): self.record['step'] = step ''' get states of traffic lights and edge ''' for tl in self.trafficLights: phase = traci.trafficlights.getPhase(tl) self.record['phase'][tl].append(phase) ''' get duration ''' if step == 0: self.record['duration'][tl].append(0) else: lastPhase = self.record['phase'][tl][-2] if phase == lastPhase: duration = self.record['duration'][tl][-1] + 1 self.record['duration'][tl].append(duration) else: self.record['duration'][tl].append(0) for edge in self.linkEdges[tl]['in']: #print(edge) haltingNum = traci.edge.getLastStepHaltingNumber(edge) vehicleNum = traci.edge.getLastStepVehicleNumber(edge) speed = traci.edge.getLastStepMeanSpeed(edge) self.record['haltingNum'][edge].append(haltingNum) self.record['vehicleNum'][edge].append(vehicleNum) self.record['speed'][edge].append(speed) ''' get vehicle wait time ''' if getwaittime: if step > 0: self.record['vehiclewaittime'][:,step] = self.record['vehiclewaittime'][:,step-1] idlist = traci.vehicle.getIDList() self.record['currentNum'][step] = len(idlist) for id in idlist: wait = traci.vehicle.getAccumulatedWaitingTime(id) intid = int(id) self.record['vehiclewaittime'][intid, step] = max(self.record['vehiclewaittime'][intid, step], wait) self.record['maxid'][step] = max(self.record['maxid'][step], intid) def createTrainRecord(self): self.trainRecord = {} self.trainRecord['state'] = [] self.trainRecord['data'] = [] self.trainRecord['dataLen'] = 0 self.trainRecord['maxLen'] = 100000 self.trainRecord['loss'] = [] def createRecord(self): self.record = {} self.record['vehicleNum'] = {} self.record['haltingNum'] = {} self.record['speed'] = {} self.record['step'] = 0 self.record['maxduration'] = ni.actionDuration self.record['vehiclewaittime'] = np.zeros((5000, 7300)) self.record['maxid'] = np.zeros(7300) self.record['currentNum'] = np.zeros(7300) self.record['phase'] = {} self.record['duration'] = {} for tl in self.trafficLights: self.record['phase'][tl] = [] self.record['duration'][tl] = [] for edge in self.linkEdges[tl]['in']: self.record['vehicleNum'][edge] = [] self.record['haltingNum'][edge] = [] self.record['speed'][edge] = [] def clearRecord(self): self.createRecord()
class Board(HD): def __init__(self, device, tasklist): HD.__init__(self, device, tasklist, 'board') self.device = device self.tasklist = tasklist self.log = MyLogger('Board', LOG_LEVEL=logging.INFO) self.nextcheck = 0.1 self.image = path.join('images', 'board', 'car_button_C.png') self.base_template = HD.loadTemplates('board', 'base') self.complete_templates = HD.loadTemplates('board', 'check') # self.card_template=HD.loadTemplates('board','pins') self.product_templates = {} self.car = [1335, 775] self.bin = [1175, 780] self.cards = [] for location in [[290, 290], [535, 290], [775, 290], [290, 520], [535, 520], [775, 520], [290, 730], [535, 730], [775, 730]]: self.cards.append(Card(tasklist, location)) self.product_images = [] self.checkImages() self.tasklist.addtask(self.nextcheck, 'board', self.image, self.check) def checkImages(self): newimages = glob(path.join('images', 'products', '*.png')) if newimages != self.product_images: self.log.debug('loading new templates') for file in newimages: filename = path.split(file)[-1] product = path.splitext(filename)[0] self.log.debug(f"found: {product}") self.product_templates[product] = Template(file) sleep(.5) self.product_images = newimages def getCard(self, location): list = [] for card in self.cards: list.append(card.location) location = self.device.getClosest(list, location) idx = list.index(location) return self.cards[idx] def collect(self, location): card = self.getCard(location) self.device.tap(*location) self.device.tap(*self.car) card.reset() def checkComplete(self): self.log.debug('checking complete') checks = self.device.locate_item(self.complete_templates, .85) if len(checks): self.collect(checks[0]) self.nextcheck = .3 return True return False def check(self): self.log.debug('checking board') self.checkImages() skiplist = HD.loadJSON('skip') self.nextcheck = 1 if self.reset_screen(): location = self.device.locate_item(self.base_template, .75, one=True) self.log.debug(location) if len(location) and self.open(location): if not self.checkComplete(): self.log.debug('update board info') for card in self.cards: x, y = card.location self.device.tap(x, y) sleep(.1) products = self.device.check_present( self.product_templates, .93) for product in products: if product in skiplist: self.device.tap(*self.bin) card.reset() break self.log.debug(f'found: {product}') card.add(product) self.nextcheck = 5 self.checkComplete() self.check_cross() self.tasklist.addtask(self.nextcheck, 'board', self.image, self.check)
class HD(): # this needs to be placed inside of an update function to be able to change pictures while running home = None def __init__(self, device, tasklist, item): self.log = MyLogger('HD', LOG_LEVEL=logging.INFO) self.device = device self.tasklist = tasklist self.scheduled = False file = path.join('images', 'products', f'{item}.png') self.image = file if path.isfile(file) else path.join( 'images', 'no_image.png') self.jobs = 0 self.waiting = 0 self.loadImages() def loadImages(self): for name in [ 'home', 'cross', 'info', 'plus', 'grass', 'diamond', 'again', 'arrows', 'cont' ]: setattr(self, name, self.loadTemplates('base', name)) @staticmethod def loadJSON(filename): file = path.join('data', f'{filename}.json') try: if path.isfile(file): with open(file) as json_file: data = json.load(json_file) except Exception as e: print(f"ERROR {filename}") print(e) data = [] sleep(5) finally: return data @staticmethod def loadTemplates(map, name): list = [] filelist = glob(path.join(getcwd(), 'images', map, f'{name}*.png')) for file in filelist: list.append(Template(file)) return list @staticmethod def loadTemplateMap(map, product): list = [] filelist = glob(path.join(getcwd(), 'images', map, product, '*.png')) for file in filelist: list.append(Template(file)) return list @staticmethod def setData(item, data): for key, value in data.items(): setattr(item, key, value) @staticmethod def getPos(location): x, y = location pos_x = (47 * x - 47 * y) pos_y = int(-23.5 * x - 23.5 * y) return [pos_x, pos_y] #return time in minutes def getWaitTime(self): if self.waiting: waittime = self.waiting - int(time()) if waittime > 0: return waittime / 60 return 0 def setWaittime(self, wait): self.waiting = int(time() + wait * 60) def move_to(self): self.log.debug(f'moving to location: {self.position}') pos_x, pos_y = self.position self.device.move(pos_x, pos_y) sleep(.2) def move_from(self): pos_x, pos_y = self.position self.device.move(-pos_x, -pos_y) def onscreen(self, product): self.log.debug(f"checking for {product}") templates = TemplateLibrary( path.join('images', 'products', 'big', '*.png')) if product in templates: self.log.debug(f"Template is found") if len(self.device.locate_item([templates[product]], last=True)): return True return False def check_cross(self): locations = self.device.locate_item(self.cross, .45) if len(locations): x, y = locations[0] self.device.tap(x, y) return True return False def check_connection(self): locations = self.device.locate_item(self.again, .60) if len(locations): x, y = locations[0] self.device.tap(x, y) sleep(1) def check_lvl_up(self): locations = self.device.locate_item(self.cont, .75) if len(locations): x, y = locations[0] self.device.tap(x, y) sleep(1) def check_plus(self): locations = self.device.locate_item(self.plus, .85) if len(locations): return True return False def check_diamond(self): locations = self.device.locate_item(self.diamond, .85) if len(locations): return True return False def check_moved(self): locations = self.device.locate_item(self.arrows, .85) if len(locations): sleep(.3) self.click_green() def click_green(self): self.log.debug('click on grass') location = self.device.locate_item(self.grass, .45, one=True) if len(location): x, y = location self.device.tap(x, y) def open(self, location): x, y = location self.device.tap(x, y) sleep(.1) if not self.check_open(): self.device.tap(x, y) sleep(.1) if not self.check_open(): self.tasklist.addtask(5, 'board', self.image, self.check) return False return True def check_open(self): locations = self.device.locate_item(self.cross, .45) if len(locations): return True return False def check_home(self): locations = self.device.locate_item(self.home, .85) if not len(locations): self.log.debug('ohoh') return False return locations def reset_screen(self): self.log.debug('cleaning') locations = self.check_home() count = 0 while not locations or count >= 3: self.check_connection() self.check_moved() self.check_lvl_up() if not self.check_cross(): for x in range(4): self.device.swipe(200, 150, 1000, 600, 100) self.check_cross() self.device.zoom_out() self.check_cross() self.device.swipe(1000, 600, 500, 450, 400) locations = self.check_home() count += 1 self.loadImages() if not locations: return False x, y = locations[0] self.log.debug(f'home: {x},{y}') if not (isclose(x, 800, abs_tol=100) and isclose(y, 550, abs_tol=75)): self.device.swipe(x, y, 800, 550, 1000) sleep(.1) self.log.debug('cleaning done') return True def tap_and_trace(self, locations, item_x=0, item_y=0): self.log.debug('tap and trace') x, y = locations[0] self.device.tap(x, y) waypoints = [[x + item_x, y + item_y]] + locations self.device.trace(waypoints, size=50) sleep(.5) def trace(self, locations, item_x=0, item_y=0): self.log.debug('trace') x, y = locations[0] waypoints = [[x + item_x, y + item_y]] + locations self.device.trace(waypoints, size=150) sleep(.2)