def initUI(self): self.parent.title("Buttons") self.style = Style() self.style.theme_use("default") frame = Frame(self, relief=GROOVE, borderwidth=5) frame.pack(fill=BOTH, expand=1) self.pack(fill = BOTH, expand = 1) self.imageLabel = Label(frame, image = "") self.imageLabel.pack(fill=BOTH, expand=1) closeButton = Button(self, text="Close") closeButton.pack(side=RIGHT) okButton = Button(self, text="OK") okButton.pack(side=RIGHT) options = [item for item in dir(cv2.cv) if item.startswith("CV_CAP_PROP")] option = OptionMenu(self, self.key, *options) self.key.set(options[0]) option.pack(side="left") spin = Spinbox(self, from_=0, to=1, increment=0.05) self.val = spin.get() spin.pack(side="left")
class StarterWindow(Tk): def __init__(self): Tk.__init__(self) self.wm_title("FRCA QBase Reader - Start Menu") self.exambtn = Button(self, text="start an exam", command=self.startExam) self.exambtn.pack() self.maxquestvar = IntVar() self.maxquest = Spinbox(self, from_=1, to=1667, width=4, textvariable=self.maxquestvar) self.maxquest.pack() self.questbtn = Button(self, text="start single questions", command=self.startQuestions) self.questbtn.pack() self.um = """User manual:\n Start either an exam or single questions\n Go to next question either with mouse or the <right arrow>\n Toggle checkboxes either with mouse or <keyboard buttons 1-5>\n In single question mode, show answer either with mouse or <return>\n In exam mode, results will display after the set question number\n Text can be made bigger/smaller with <Up> or <Down> keyboard arrows""" self.usermanual = Label(self, text=self.um, justify=LEFT) self.usermanual.pack() def startExam(self): call(["python", "exam.py", str(self.maxquestvar.get())]) def startQuestions(self): call(["python", "quest_by_quest.py"])
def ventanaImprimir(self): t = Toplevel(self) t.wm_title("Imprimir") Label(t, text="Numero de Copias por etiqueta").pack() w = Spinbox(t, from_=1, to=10) w.pack() buttonImprimir = Button(t, text="Imprimir", command=lambda:self.imprimir(int(w.get()),t)) buttonImprimir.pack()
def buscar(): root = Tkinter.Toplevel() jorn = Spinbox(root, from_=0, to=50) def boton(): listar(jorn.get()) but = Tkinter.Button(root, text="Buscar", command=boton) jorn.pack(side=LEFT) but.pack(side=RIGHT) root.mainloop()
def init_slow_time(root): slow_time_frame = Frame(root) slow_time_frame.pack(fill=X) slow_time_label = Label(slow_time_frame, text='Slowing time [0; 10] sec:') slow_time_label.pack(side='left') slow_time = Spinbox(slow_time_frame, from_=0, to=10, width=4) slow_time.delete(0, 1) slow_time.insert(0, 5) slow_time.pack(side='right') return slow_time_frame, slow_time_label, slow_time
def init_speed_sup(root): speed_sup_frame = Frame(root) speed_sup_frame.pack(fill=X) speed_sup_label = Label(speed_sup_frame, text='Max initial speed [0; 200]:') speed_sup_label.pack(side='left') speed_sup = Spinbox(speed_sup_frame, from_=0, to=200, width=4) speed_sup.delete(0, 1) speed_sup.insert(0, 60) speed_sup.pack(side='right') return speed_sup_frame, speed_sup_label, speed_sup
def init_speed_inf(root): speed_inf_frame = Frame(root) speed_inf_frame.pack(fill=X) speed_inf_label = Label(speed_inf_frame, text='Min initial speed [0; 200]:') speed_inf_label.pack(side='left') speed_inf = Spinbox(speed_inf_frame, from_=0, to=200, width=4) speed_inf.delete(0, 1) speed_inf.insert(0, 30) speed_inf.pack(side='right') return speed_inf_frame, speed_inf_label, speed_inf
def init_range_of_vision(root): range_of_vision_frame = Frame(root) range_of_vision_frame.pack(fill=X) range_of_vision_label = Label(range_of_vision_frame, text='Range of vision [1; 10] (in cars):') range_of_vision_label.pack(side='left') range_of_vision = Spinbox(range_of_vision_frame, from_=1, to=10, width=4) range_of_vision.delete(0, 1) range_of_vision.insert(0, 3) range_of_vision.pack(side='right') return range_of_vision_frame, range_of_vision_label, range_of_vision
def init_spawn_sup(root): spawn_sup_frame = Frame(root) spawn_sup_frame.pack(fill=X) spawn_sup_label = Label(spawn_sup_frame, text='Max spawn interval [0; 10] sec:') spawn_sup_label.pack(side='left') spawn_sup = Spinbox(spawn_sup_frame, from_=0, to=10, width=4) spawn_sup.delete(0, 1) spawn_sup.insert(0, 5) spawn_sup.pack(side='right') return spawn_sup_frame, spawn_sup_label, spawn_sup
def init_slow_factor(root): slow_factor_frame = Frame(root) slow_factor_frame.pack(fill=X) slow_factor_label = Label(slow_factor_frame, text='Slowing factor [0; 1]:') slow_factor_label.pack(side='left') slow_factor = Spinbox(slow_factor_frame, from_=0, to=1, width=4, increment=0.1) slow_factor.delete(0, 3) slow_factor.insert(0, 0.5) slow_factor.pack(side='right') return slow_factor_frame, slow_factor_label, slow_factor
def listar(n): conn = sqlite3.connect('marca.db') root = Tkinter.Toplevel() frame = Frame(root) frame2 = Frame(root) cursor = conn.execute("SELECT PARTIDO from CRONICAS WHERE JORNADA LIKE '" + n + "'") partidos = [] for c in cursor: partidos.append(c[0]) def cambio(): cursor = conn.execute( "SELECT CRONICA FROM CRONICAS WHERE PARTIDO LIKE '" + partido.get() + "'") for row in cursor: sql = "SELECT * FROM GOLES WHERE CRONICA LIKE '%" + row[0] + "%'" cursor = conn.execute(sql) lista.delete(0, END) i = 0 for row in cursor: i += 1 lista.insert( i, "EQUIPO: " + row[0] + " JUGADOR: " + row[1] + " MINUTO: " + row[2]) partido = Spinbox(frame, values=partidos, command=cambio) etiq = Label(frame, text="Elija Partido:") barra = Scrollbar(frame2) lista = Listbox(frame2, width=80, height=8) frame.pack(side=LEFT) frame2.pack(side=LEFT) lista.pack(side=LEFT, fill=BOTH) barra.pack(side=RIGHT, fill=Y) barra.config(command=lista.yview) etiq.pack(side=TOP) partido.pack(side=RIGHT) root.mainloop() conn.close()
def choose_cutoff(data, time): import matplotlib.pyplot as plt import numpy as np # import Tkinter as tk import sys from Tkinter import Spinbox, Tk, Button, LEFT # , mainloop # from Tkinter import * global choose choose = True # i = 0 global cut cut = 100 # global l_line # l_line = plt.axvline(cut) def combine_funcs(*funcs): def combined_func(*args, **kwargs): for f in funcs: f(*args, **kwargs) return combined_func def destroywindows(**kwargs): for m in kwargs: m.destroy() for f in kwargs: f.close() # master.destroy() def setvalues(var, value): var = value return var def choosefalse(): global choose choose = False # print(choose) def spintocut(): global cut cut = int(cutspin.get()) # print(cut) # def callback(): # print("something") # global l_line # l_line(cut) # l_line = plt.axvline(cut) # plt.draw() # plt.ion() # plt.pause(0.05) # plt.figure('data') # plt.plot(data) # plt.show(block=False) # # plt.draw() while choose is True: plt.figure('data') plt.plot(data) # l_line = plt.axvline(cut) plt.axvline(np.shape(data)[0] - cut) # plt.draw() plt.show(block=False) # plt.ion() # plt.pause(0.05) # print(choose) # print(cut) master = Tk() # print(type(data[0])) cutspin = Spinbox(master, from_=0, to=np.shape(data)[0], textvariable=cut) # , command=callback) cutspin.delete(0) cutspin.insert(0, cut) cutspin.pack() # print(type(cutspin)) # print(cutspin.get()) applyButton = Button(master, text='apply', command=combine_funcs(spintocut, plt.close, master.destroy)) applyButton.pack(side=LEFT) goonButton = Button(master, text='go on', command=combine_funcs(master.destroy, plt.close, choosefalse)) goonButton.pack(side=LEFT) quitButton = Button(master, text='quit', command=sys.exit) quitButton.pack(side=LEFT) master.mainloop() # Tk.update() # plt.update() # plt.show(block=False) # l_left.remove() # l_right.remove() # plt.draw() cutoff = cut return cutoff
def refreshWidget(self): #print "refresh" self.card_win.pack_forget() #Card window self.card_win = PanedWindow(self.card_win.master, orient=VERTICAL) self.card_win.pack(side=TOP, expand=True, fill=BOTH, pady=2, padx=2) #Create the name zone name_zone = PanedWindow(self.card_win, orient=HORIZONTAL) name = StringVar() name.set(self.name) from deck_creation import blocked_creature def modifName(*args): old = self.name in blocked_creature self.name = name.get() if old or self.name in blocked_creature: self.refreshWidget() name.trace("w", modifName) name_wid = Entry(name_zone, width=30, textvariable=name) name_wid.pack() name_zone.add(name_wid) #Create the cost ad star stringvar #print int(floor(self.getCost())) self.cost = StringVar() self.stars = StringVar() cost_wid = Label(None, textvariable=self.cost, background='red', width=5, anchor=W) star_wid = Label(None, textvariable=self.stars, background='blue', anchor=E) self.cost.set(str(int(floor(self.getCost())))) self.stars.set("*" * self.getStars()) #Add them in name zone name_zone.add(cost_wid) name_zone.add(star_wid) #Create an Image Zone image_zone = Button(self.card_win, command=self.choosePhoto) if hasattr(self, "photofile") and self.photofile: print "Image: ", self.photofile try: img = Image.open(self.photofile) except: decomp = self.photofile.split('/') for i in range(1, 6): try: fname = "/".join(decomp[-i:]) print "try to open", fname img = Image.open(fname) self.photofile = fname break except: self.photofile = None if self.photofile: w, h = img.size if w > 300 or h > 200: img = img.resize((w / 2, h / 2), Image.LINEAR) image_zone.image = ImageTk.PhotoImage(img) image_zone.config(image=image_zone.image) #print "IMAGE CHANGED" else: from os import path fname = self.name.replace(" ", "_") if path.isfile("Cards/" + fname + ".png"): image_zone.config(text='image can be taken from\n' + "Cards/" + fname + ".png", background='white', anchor=CENTER) else: image_zone.config(text='clic to choose image', background='white', anchor=CENTER) image_zone.pack # POWER ZONE power_zone = PanedWindow(self.card_win, orient=VERTICAL) #fenetre=self.card_win.master def removePowerCreator(px): def removePower(*args): #print 'avant',list_pow self.bonus.remove(px) #print 'apres',list_pow #self.card_win.pack_forget() self.refreshWidget() return removePower for p in self.bonus: powline = PanedWindow(self.card_win, orient=HORIZONTAL) pow_wid = p.initWidget(powline) powline.add(pow_wid) removepow = Button(powline, text="X", command=removePowerCreator(p), anchor=E) removepow.pack() powline.add(removepow) power_zone.add(powline) def addPower(*args): name = addBonus.get() print "added :", name import cardPowers self.bonus += [eval('cardPowers.' + name + '()')] self.bonus[-1].parent = self.bonus self.bonus[-1].card = self #self.card_win.pack_forget() self.refreshWidget() #Add bonus Option menu addBonus = StringVar(power_zone) addBonus.set("add bonus") # default value if not self.pv: addBonus_wid = getSpellMenu(power_zone, addBonus) else: addBonus_wid = getBonusMenu(power_zone, addBonus) addBonus.trace('w', addPower) if self.pv > 0 or len(self.bonus) == 0: addBonus_wid.pack() #Add this to power zone power_zone.add(addBonus_wid) #Create save zone save_zone = PanedWindow(self.card_win, orient=HORIZONTAL) lv = int(localopen("progression", "r").read()) if self.monster_type != "all" and not (lv < 8 and self.name in blocked_creature): save_wid = Button(save_zone, text="Save", command=self.postAndSave) elif self.monster_type != "all": save_wid = Button(save_zone, text="creature in campaign", command=None) else: save_wid = Button(save_zone, text="nead type", command=None) save_wid.pack() #Create the open button save_zone.pack() if Card.monster_list.keys(): self.opening = StringVar(save_zone) self.opening.set("Open") choice = Card.monster_list.keys() choice.sort() #print all_monsters.keys() open_wid = OptionMenu(save_zone, self.opening, *choice) self.opening.trace('w', self.Open) open_wid.pack() save_zone.add(open_wid) if Card.monster_list.keys(): self.delete = StringVar(save_zone) self.delete.set("Delete") choice = Card.monster_list.keys() choice.sort() delete_wid = OptionMenu(save_zone, self.delete, *choice) self.delete.trace('w', self.clicDelete) delete_wid.pack() save_zone.add(delete_wid) #Create the type button self.category = StringVar(save_zone) self.category.set(self.monster_type) choice = [ file2name(t, "_monsters.sav") for t in glob.glob("CardFiles/*_monsters.sav") ] if "recup" in choice: choice.remove("recup") #print all_monsters.keys() category_wid = OptionMenu(save_zone, self.category, *choice) self.category.trace('w', self.setFile) category_wid.pack() #Add it to save zone save_zone.add(save_wid) save_zone.add(category_wid) #Create a new Strength zone for att and pv strength_zone = PanedWindow(self.card_win, orient=HORIZONTAL) att = StringVar() att.set(str(self.att)) pv = StringVar() pv.set(str(self.pv)) def modifiedAttPv(*args): print "modifiedAttPv" self.pv = int(pv.get()) if self.pv < 1 and self.is_spell == False: if len(self.bonus) == 0: self.is_spell = True self.refreshWidget() else: self.pv = 1 self.refreshWidget() if self.pv > 0 and self.is_spell == True: if len(self.bonus) == 0: self.is_spell = False self.refreshWidget() else: self.pv = 0 self.refreshWidget() self.att = int(att.get()) self.getCost() att_wid = Spinbox(strength_zone, from_=0, to=1000, textvariable=att, command=modifiedAttPv) att_wid.pack() strength_zone.add(att_wid) strength_zone.add( Label(strength_zone, text=' ', background='white', anchor=CENTER)) pv_wid = Spinbox(strength_zone, from_=0, to=1000, textvariable=pv, command=modifiedAttPv) pv_wid.pack() strength_zone.add(pv_wid) #Put it all in window self.card_win.add(name_zone) self.card_win.add(image_zone) self.card_win.add(power_zone) self.card_win.add(strength_zone) self.card_win.add(save_zone) self.card_win.pack()
class AntroidGUI(Tk): def __init__(self): Tk.__init__(self) self.protocol("WM_DELETE_WINDOW", self.myquit) self.etat = True self.readstate = True self.title("Antroid Map") self.turns = {} self.selectTurn = -1 self.caselength = 10 self.CaseMarge = 20 self.var = StringVar() self.initGUI() def initGUI(self): frame = Frame(self, width=630, height=500) self.panel = PanedWindow(frame, orient=HORIZONTAL) self.LeftFrame(self.panel) self.RightFrame(self.panel) self.panel.add(self.LFrame) self.panel.add(self.RFrame) self.panel.pack() frame.pack() def LeftFrame(self, parent): self.LFrame = Frame(parent, width=500, height=500) self.maptroid = Canvas(self.LFrame, bg='black', width=500, height=500) if self.selectTurn >= 0: self.printMap() self.maptroid.pack() self.LFrame.pack() def RightFrame(self, parent): self.RFrame = Frame(parent, width=130, height=500) if self.selectTurn >= 0: self.printInfo() self.FrameInfo = None self.updateT = True self.RFrame.pack() def setreadstate(self, readstate): self.readstate = readstate def addTurn(self, turnnumber, turnvalue): self.turns[turnnumber] = turnvalue self.updateGui(turnnumber) return self.etat def updateGui(self, turn): self.selectTurn = turn self.updateMap() self.updateInfo() def updateMap(self): self.maptroid.delete(ALL) self.printMap() def updateInfo(self): if self.FrameInfo: if self.updateT: self.frameT.destroy() self.printTurn() self.frameAnts.destroy() self.frameAnt.destroy() self.printAnts() self.updateT = True else: self.printInfo() def updateSpin_turn(self): turn = int(self.Spin_T.get()) self.updateT = False self.updateGui(turn) def validateTurn(self, event): try: turn = int(self.Spin_T.get()) except ValueError: turn = self.selectTurn if turn in self.turns.keys(): if turn != self.selectTurn: self.updateT = False self.updateGui(turn) else: turn = self.selectTurn def choiceAnt(self, event): i = self.listbox.curselection() id_a = self.listbox.get(i) self.frameAnt.destroy() self.printInfoAnt(int(id_a)) def printInfo(self): self.FrameInfo = Frame(self.RFrame) self.printTurn() self.printAnts() self.FrameInfo.pack() def printTurn(self): frameS = PanedWindow(self.FrameInfo, orient=HORIZONTAL) turns = Label(frameS, text="Tour :") self.var.set(str(self.selectTurn)) self.Spin_T = Spinbox(frameS, values=self.turns.keys(), command=self.updateSpin_turn, textvariable=self.var) self.Spin_T.bind('<Return>', self.validateTurn) turns.pack() self.Spin_T.pack() frameS.add(turns) frameS.add(self.Spin_T) frameS.pack() self.frameT = frameS def printAnts(self): frameAnts = Frame(self.FrameInfo) Text_A = Label(frameAnts, text="Fourmie :") s1 = Scrollbar(frameAnts) l1 = Listbox(frameAnts) id_ants = self.checkAnts() for i in id_ants: l1.insert(i, str(i)) s1.config(command=l1.yview) l1.config(yscrollcommand=s1.set) l1.bind('<ButtonRelease-1>', self.choiceAnt) self.listbox = l1 Text_A.pack(side=TOP) l1.pack(side=LEFT) s1.pack(side=RIGHT) frameAnts.pack() self.printInfoAnt(id_ants[0]) self.frameAnts = frameAnts def printInfoAnt(self, i): self.frameAnt = PanedWindow(self.FrameInfo, orient=VERTICAL) t_Ant = Label(self.frameAnt, text="Information Ant : %d" % (i)) (t_brain, t_energie, t_acide) = self.getInfoAnt(i) a_b = Label(self.frameAnt, text=t_brain) a_e = Label(self.frameAnt, text=t_energie) a_a = Label(self.frameAnt, text=t_acide) t_Ant.pack(side=TOP) self.frameAnt.add(t_Ant) self.frameAnt.add(a_b) self.frameAnt.add(a_e) self.frameAnt.add(a_a) self.frameAnt.pack() def printMap(self): turn = self.turns[self.selectTurn] # Information on this turn config = turn[0] Yants = turn[1] EAnts = turn[2] InitMap = turn[3] Cases = turn[4] (MaxX, MaxY, N) = InitMap self.MinX = 0 self.MinY = 0 MaxX_map = MaxX * self.caselength + (self.CaseMarge * 2) MaxY_map = MaxY * self.caselength + (self.CaseMarge * 2) #configure canvas self.maptroid.config(scrollregion=(0, 0, MaxX_map, MaxY_map)) x1 = self.CaseMarge y1 = self.CaseMarge x2 = MaxX * self.caselength + self.CaseMarge y2 = MaxY * self.caselength + self.CaseMarge self.maptroid.create_rectangle(x1, y1, x2, y2, fill="white") # affiche case for case in Cases: self.printCase(case) # affiche your ants for ant in Yants: # nb A : Your Ant 'ID X Y DX DY E A B' (id_a, x, y, dx, dy, e, a, b) = ant self.printAnt((x, y, dx, dy, b)) # affiche enemy ants for ant in EAnts: self.printAnt(ant) #to move map self.maptroid.bind('<ButtonPress-1>', self.grab) self.maptroid.bind('<B1-Motion>', self.drag) self.maptroid.bind('<MouseWheel>', self.mapZoom) self.maptroid.bind("<Button-4>", self.mapZoom) self.maptroid.bind("<Button-5>", self.mapZoom) def printCase(self, case): (x, y, c, s) = case (x1, y1, x2, y2) = self.getPoint(x, y) color = COLOR[c][s] if c % 2 == 0: self.maptroid.create_rectangle(x1, y1, x2, y2, fill=color) else: self.maptroid.create_rectangle(x1, y1, x2, y2, fill=COLOR[GRASS][s]) self.maptroid.create_oval(x1, y1, x2, y2, fill=color) def printAnt(self, ant): (x, y, dx, dy, brain) = ant (x1, y1, x2, y2) = self.getPoint(x, y) self.maptroid.create_oval(x1, y1, x2, y2, fill="red4") def getPoint(self, x, y): x1 = (x - self.MinX) * self.caselength + self.CaseMarge y1 = (y - self.MinY) * self.caselength + self.CaseMarge x2 = x1 + self.caselength y2 = y1 + self.caselength return (x1, y1, x2, y2) def grab(self, event): self._y = event.y self._x = event.x def drag(self, event): self.maptroid.yview('scroll', self._y - event.y, 'units') self.maptroid.xview('scroll', self._x - event.x, 'units') self._y = event.y self._x = event.x def mapZoom(self, event): # respond to Linux or Windows wheel event if event.num == 5 or event.delta == -120: self.caselength -= 5 self.caselength = max(self.caselength, 10) if event.num == 4 or event.delta == 120: self.caselength += 5 self.caselength = min(self.caselength, 40) self.CaseMarge = self.caselength self.updateMap() def getInfoAnt(self, id_ant): turn = self.turns[self.selectTurn] YAnt = turn[1] B_Text = "Brain :" E_Text = "Energie :" A_Text = "Acide :" for ant in YAnt: (id_a, x, y, dx, dy, e, a, b) = ant if b != 1: b = 0 if (id_ant == id_a): B_Text = "Brain : " + BRAIN[b] E_Text = "Energie : %d" % (e) A_Text = "Acide : %d" % (a) return (B_Text, E_Text, A_Text) def checkAnts(self): turn = self.turns[self.selectTurn] YAnt = turn[1] ants_id = [] for ant in YAnt: (id_a, x, y, dx, dy, e, a, b) = ant ants_id.append(id_a) return ants_id def myquit(self): self.etat = False if not self.readstate: self.quit()
def create_entry(_main_row_, _desc_txt, _def_txt_, t_len, ckbc=None, fn=None): ''' creates a tkinter entry ''' _row_ = Frame(_main_row_) if ckbc <> None and fn <> None: label0 = Label(_row_, width=3, text=" ", anchor='w') cvar = IntVar() label1 = Checkbutton(_row_, width=0, variable=cvar, command=fn, anchor='w') label2 = Label(_row_, width=t_len, text=_desc_txt + " ", anchor='w') ckbc.append([cvar, label1]) else: label0 = Label(_row_, width=3, text=" >", anchor='w') label1 = Label(_row_, width=t_len, text=_desc_txt, anchor='w') label2 = Label(_row_, width=2, text=" :", anchor='w') if type(_def_txt_) == str: Ent_It = Entry(_row_) #, width=13) Ent_It.insert('end', _def_txt_) elif type(_def_txt_) in [list, tuple]: if type(_def_txt_[1]) in [set]: _nums_ = [str(x) for x in sorted(list(_def_txt_[1]))] Ent_It = StringVar() aux_spin = Spinbox(_row_, textvariable=Ent_It, values=tuple(_nums_)) Ent_It.set(_def_txt_[0]) else: Ent_It = StringVar() aux_ddl = Drop_Down_List( _row_, textvariable=Ent_It, values=tuple(_def_txt_[1]), #state = "readonly" ) aux_ddl.bind("<Key>", lambda e: "break") # Magic Ent_It.set(_def_txt_[0]) finalspace = Label(_row_, width=5, text=" ", anchor='w') # Just packing label0.pack(side='left', padx=1) label1.pack(side='left', padx=6) label2.pack(side='left', padx=0) if type(_def_txt_) == str: Ent_It.pack(side='left', expand=True, fill=X) elif type(_def_txt_) in [list, tuple] and type(_def_txt_[1]) == set: aux_spin.pack(side='left', expand=True, fill=X) else: aux_ddl.pack(side='left', expand=True, fill=X) finalspace.pack(side='right', padx=0) _row_.pack(side='top', fill=X, pady=3) # For tracing purposes list appending return Ent_It
class Outlier4dfp(Frame): def __init__(self, parent, filename=None, filename_roi=None, filename_csv=None, dirname=None, obj_return_value=None): Frame.__init__(self, parent) self.parent = parent self.obj_return_value = obj_return_value # check filenames if filename is None or not os.path.isfile(filename): if dirname is not None: filename = tkFileDialog.askopenfilename(initialdir=dirname) else: filename = tkFileDialog.askopenfilename() if not os.path.isfile(filename): parent.destroy() return if filename_roi is None or not os.path.isfile(filename_roi): if dirname is not None: filename_roi = tkFileDialog.askopenfilename(initialdir=dirname) else: filename_roi = tkFileDialog.askopenfilename() if not os.path.isfile(filename_roi): parent.destroy() return if dirname is None: self.dirname = os.path.dirname(filename) else: self.dirname = dirname if filename_csv is None: filename_csv = os.path.join( self.dirname, filename_wo_ext(os.path.basename(filename)) + '.csv') self.filename = filename self.filename_roi = filename_roi self.filename_csv = filename_csv self.dat = nib.load(filename).get_data() self.shape = self.dat.shape print self.shape dz = self.shape[2] df = self.shape[-1] self.badenc = np.zeros((dz, df), dtype=np.int16) self.prev = np.zeros((dz, df), dtype=np.int16) self.z = 0 self.initUI() self.run() #if filename_csv is not None and os.path.isfile(filename_csv): # self.run_read() def reset(self): dz = self.shape[2] df = self.shape[-1] self.badenc[:, :] = np.zeros((dz, df), dtype=np.int16) self.prev[:, :] = np.zeros((dz, df), dtype=np.int16) def make_checkbox_all(self, frame, width=4, ncol=20): self.lst_checkbox_slices_values = [] self.lst_checkbox_slices = [] ii = 0 for z in range(self.shape[2]): self.lst_checkbox_slices_values.append( [BooleanVar() for f in range(self.shape[3])]) boxes = [ Checkbutton(frame, text=str('%s' % f), variable=self.lst_checkbox_slices_values[z][f], width=width) for f in range(self.shape[3]) ] jj = 0 for f in range(self.shape[3]): btn = boxes[f] btn.grid(row=z, column=f) jj += 1 if ncol is not None and ncol <= jj: ii += 1 jj = 0 self.lst_checkbox_slices.append(boxes) if jj > 0: ii += 1 def make_checkbox(self, frame, width=4, ncol=20): #self.lst_checkbox_slices_values = [BooleanVar() for f in range(self.shape[3])] self.lst_checkbox_slices_values = [ IntVar() for f in range(self.shape[3]) ] self.lst_checkbox_slices = [ Checkbutton(frame, text=str('%s' % f), variable=self.lst_checkbox_slices_values[f], width=width, command=functools.partial(self.click_check, f)) for f in range(self.shape[3]) ] ii = 0 jj = 0 for f in range(self.shape[3]): btn = self.lst_checkbox_slices[f] btn.grid(row=ii, column=jj) jj += 1 if ncol is not None and ncol <= jj: jj = 0 ii += 1 if jj > 0: ii += 1 def click_check(self, f): value = self.lst_checkbox_slices_values[f].get() if value == 1: value = 0 else: value = 1 self.lst_checkbox_slices_values[f].set(value) self.badenc[self.z, f] = value print self.z, f, self.badenc[self.z, f] def set_z(self, z=None): if z is None: z = self.z else: self.z = z for i in range(len(self.lst_checkbox_slices_values)): chkbox = self.lst_checkbox_slices_values[i] # FIXME # avail chkbox if self.prev[z, i] > 0 or self.badenc[z, i] > 0: to_check = True to_check = 1 self.lst_checkbox_slices[i].select() else: to_check = False to_check = 0 self.lst_checkbox_slices[i].deselect() chkbox.set(to_check) # avail def run(self): dat = self.dat roi = nib.load(self.filename_roi).get_data().astype(bool) print dat.shape print roi.shape dz = self.shape[2] df = self.shape[3] self.values = np.zeros((dz, df), dtype=dat.dtype) for z in range(dz): for f in range(df): self.values[z, f] = dat[:, :, z, f][roi[:, :, z]].mean() self.draw_slice() def draw_slice(self): z = self.z df = self.shape[3] print z #r = self.frame_graph.axes.boxplot(self.values.T) sorted_values = np.sort(self.values[z, :]) q1 = sorted_values[df / 4] q2 = sorted_values[df / 2] q3 = sorted_values[df - df / 4] iqr = q3 - q1 #if1 = q1 - 1.5*iqr #if2 = q3 + 1.5*iqr of1 = q1 - 3 * iqr of2 = q3 + 3 * iqr xx = np.arange(df) z_mean = self.values[z, :].mean() z_std = self.values[z, :].std() #z_min = self.values[z,:].min() #z_max = self.values[z,:].max() #self.frame_graph.axes.hold(False) self.frame_graph.axes.clear() self.frame_graph.axes.plot([0, df], [z_mean, z_mean], 'k-') #self.frame_graph.axes.hold(True) self.frame_graph.axes.plot([0, df], [z_mean + 1 * z_std, z_mean + 1 * z_std], 'y--') self.frame_graph.axes.plot([0, df], [z_mean + 2 * z_std, z_mean + 2 * z_std], 'g--') self.frame_graph.axes.plot([0, df], [z_mean + 3 * z_std, z_mean + 3 * z_std], 'b--') self.frame_graph.axes.plot([0, df], [of2, of2], 'r-') for f in range(df): if self.prev[z, f] > 0: self.frame_graph.axes.plot(f, self.values[z, f], 'ko') self.frame_graph.axes.text(f + 0.2, self.values[z, f], str(f)) elif of1 < self.values[z, f] < of2: #if self.values[z,f] < z_mean + 3*z_std: self.frame_graph.axes.plot(f, self.values[z, f], 'bo') if self.values[z, f] > z_mean + 3 * z_std: self.frame_graph.axes.text(f + 0.2, self.values[z, f], str(f)) else: self.frame_graph.axes.plot(f, self.values[z, f], 'ro') self.frame_graph.axes.text(f + 0.2, self.values[z, f], str(f)) self.frame_graph.draw() self.set_z(z) def run_read(self): filename = tkFileDialog.askopenfilename(initialdir=self.dirname) if filename == '': return with open(filename) as f: values = [[int(tmp) for tmp in line.strip().split(',')] for line in f.readlines()] self.prev[:, :] = values def run_save(self): filename = tkFileDialog.asksaveasfilename( initialdir=os.path.dirname(self.filename_csv), initialfile=os.path.basename(self.filename_csv)) if filename == '': return dz = self.shape[2] df = self.shape[-1] badenc = self.badenc.copy() badenc[self.prev > 0] = 1 with open(filename, 'w') as f: for z in range(dz): f.write('%s\n' % (','.join([str(tmp) for tmp in badenc[z, :]]))) with open(os.path.join(self.dirname, 'badenc.dat'), 'wb') as fout: if False: for z in range(dz): row = struct.pack('i' * df, *badenc[z, :]) fout.write(row) fout.write('%s %s\n' % (dz, df)) for z in range(dz): row = ' '.join(str(tmp) for tmp in badenc[z, :]) fout.write('%s\n' % row) if self.obj_return_value is not None: self.obj_return_value.delete(0, len(self.obj_return_value.get())) self.obj_return_value.insert(0, filename) def initUI(self): self.frame_top = Frame(self) self.frame_graph = MplCanvas(self) self.frame_bottom = Frame(self) Label(self.frame_top, text='Z = ').pack(side=LEFT) self.spin_z = Spinbox(self.frame_top, from_=0, to=self.shape[2] - 1, increment=1, command=self.change_z) self.spin_z.pack(side=LEFT) self.make_checkbox(self.frame_bottom, width=4) Label(self.frame_top, text=' CSV').pack(side=LEFT) self.txt_filename_csv = Entry(self.frame_top) self.txt_filename_csv.pack(side=LEFT) self.button_read = Button(self.frame_top, text='Read', command=self.run_read) self.button_read.pack(side=LEFT) self.button_save = Button(self.frame_top, text='Save', command=self.run_save) self.button_save.pack(side=LEFT) Label(self.frame_top, text=' ').pack(side=LEFT) button_reset = Button(self.frame_top, text='Reset', command=self.reset).pack(side=LEFT) self.frame_top.pack(side=TOP) self.frame_graph.get_tk_widget().pack(fill=BOTH, expand=TRUE) self.frame_bottom.pack(fill=BOTH, expand=TRUE) self.pack(fill=BOTH, expand=True) def change_z(self): self.z = int(self.spin_z.get()) self.draw_slice() def reset_box(self, box, text): box.delete(0, len(box.get())) box.insert(0, text)
class Cockpit(ttkFrame): ''' Remote controller GUI ''' KEY_ANG_SPEED = "ang-speed" KEY_ANGLES = "angles" KEY_ACCEL = "accel" PID_KEYS = ["P", "I", "D"] DEFAULT_DRONE_IP = "192.168.1.130" DEFAULT_DRONE_PORT = 2121 DIR_NONE = 0 DIR_VERTICAL = 1 DIR_HORIZONTAL = 2 MAX_ACCEL = 10.0 #TODO angles. Replace by m/s² MAX_ACCEL_Z = 0.1 #m/s² MAX_ANGLE_SPEED = 50.0 #º/s def __init__(self, parent, isDummy = False, droneIp = DEFAULT_DRONE_IP, dronePort = DEFAULT_DRONE_PORT): ''' Constructor ''' ttkFrame.__init__(self, parent) self._started = IntVar() self._integralsEnabled = IntVar() self._target = [0.0] * 4 self._selectedPidConstats = "--" self._pidConstants = { Cockpit.KEY_ANG_SPEED:{ "X":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Y":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Z":{ "P": 0.0, "I": 0.0, "D": 0.0 } }, Cockpit.KEY_ANGLES: { "X":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Y":{ "P": 0.0, "I": 0.0, "D": 0.0 } }, Cockpit.KEY_ACCEL:{ "X":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Y":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Z":{ "P": 0.0, "I": 0.0, "D": 0.0 } } } self.parent = parent self.initUI() self._controlKeysLocked = False if not isDummy: self._link = INetLink(droneIp, dronePort) else: self._link = ConsoleLink() self._link.open() self._updateInfoThread = Thread(target=self._updateInfo) self._updateInfoThreadRunning = False self._readingState = False self._start() def initUI(self): self.parent.title("Drone control") self.style = Style() self.style.theme_use("default") self.pack(fill=BOTH, expand=1) self.parent.bind_all("<Key>", self._keyDown) self.parent.bind_all("<KeyRelease>", self._keyUp) if system() == "Linux": self.parent.bind_all("<Button-4>", self._onMouseWheelUp) self.parent.bind_all("<Button-5>", self._onMouseWheelDown) else: #case of Windows self.parent.bind_all("<MouseWheel>", self._onMouseWheel) #Commands commandsFrame = tkFrame(self) commandsFrame.grid(column=0, row=0, sticky="WE") self._startedCB = Checkbutton(commandsFrame, text="On", variable=self._started, command=self._startedCBChanged) self._startedCB.pack(side=LEFT, padx=4) self._integralsCB = Checkbutton(commandsFrame, text="Int.", variable=self._integralsEnabled, \ command=self._integralsCBChanged, state=DISABLED) self._integralsCB.pack(side=LEFT, padx=4) self._quitButton = Button(commandsFrame, text="Quit", command=self.exit) self._quitButton.pack(side=LEFT, padx=2, pady=2) # self._angleLbl = Label(commandsFrame, text="Angle") # self._angleLbl.pack(side=LEFT, padx=4) # # self._angleEntry = Entry(commandsFrame, state=DISABLED) # self._angleEntry.pack(side=LEFT) #Info infoFrame = tkFrame(self) infoFrame.grid(column=1, row=1, sticky="E", padx=4) #Throttle Label(infoFrame, text="Throttle").grid(column=0, row=0, sticky="WE") self._throttleTexts = [StringVar(),StringVar(),StringVar(),StringVar()] Entry(infoFrame, textvariable=self._throttleTexts[3], state=DISABLED, width=5).grid(column=0, row=1) Entry(infoFrame, textvariable=self._throttleTexts[0], state=DISABLED, width=5).grid(column=1, row=1) Entry(infoFrame, textvariable=self._throttleTexts[2], state=DISABLED, width=5).grid(column=0, row=2) Entry(infoFrame, textvariable=self._throttleTexts[1], state=DISABLED, width=5).grid(column=1, row=2) #Angles Label(infoFrame, text="Angles").grid(column=0, row=3, sticky="WE") self._angleTexts = [StringVar(),StringVar(),StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._angleTexts[index], state=DISABLED, width=5).grid(column=index, row=4) #Accels Label(infoFrame, text="Accels").grid(column=0, row=5, sticky="WE") self._accelTexts = [StringVar(),StringVar(),StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._accelTexts[index], state=DISABLED, width=5).grid(column=index, row=6) #Speeds Label(infoFrame, text="Speeds").grid(column=0, row=7, sticky="WE") self._speedTexts = [StringVar(),StringVar(),StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._speedTexts[index], state=DISABLED, width=5).grid(column=index, row=8) #Height Label(infoFrame, text="Height").grid(column=0, row=9, sticky="W") self._heightText = StringVar() Entry(infoFrame, state=DISABLED, width=5).grid(column=1, row=9) #control controlFrame = tkFrame(self) controlFrame.grid(column=0, row=1, sticky="W") self._throttle = DoubleVar() self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=-100.0, \ tickinterval=0, variable=self._throttle, \ length=200, showvalue=1, \ state=DISABLED, command=self._onThrustScaleChanged) self._thrustScale.bind("<Double-Button-1>", self._onThrustScaleDoubleButton1, "+") self._thrustScale.grid(column=0) self._shiftCanvas = Canvas(controlFrame, bg="white", height=400, width=400, \ relief=SUNKEN) self._shiftCanvas.bind("<Button-1>", self._onMouseButton1) #self._shiftCanvas.bind("<ButtonRelease-1>", self._onMouseButtonRelease1) self._shiftCanvas.bind("<B1-Motion>", self._onMouseButton1Motion) self._shiftCanvas.bind("<Double-Button-1>", self._onMouseDoubleButton1) self._shiftCanvas.bind("<Button-3>", self._onMouseButton3) #self._shiftCanvas.bind("<ButtonRelease-3>", self._onMouseButtonRelease3) self._shiftCanvas.bind("<B3-Motion>", self._onMouseButton3Motion) self._shiftCanvas.grid(row=0,column=1, padx=2, pady=2) self._shiftCanvas.create_oval(2, 2, 400, 400, outline="#ff0000") self._shiftCanvas.create_line(201, 2, 201, 400, fill="#ff0000") self._shiftCanvas.create_line(2, 201, 400, 201, fill="#ff0000") self._shiftMarker = self._shiftCanvas.create_oval(197, 197, 205, 205, outline="#0000ff", fill="#0000ff") self._yaw = DoubleVar() self._yawScale = Scale(controlFrame, orient=HORIZONTAL, from_=-100.0, to=100.0, \ tickinterval=0, variable=self._yaw, \ length=200, showvalue=1, \ command=self._onYawScaleChanged) self._yawScale.bind("<Double-Button-1>", self._onYawScaleDoubleButton1, "+") self._yawScale.grid(row=1, column=1) self._controlKeyActive = False #PID calibration pidCalibrationFrame = tkFrame(self) pidCalibrationFrame.grid(column=0, row=2, sticky="WE"); self._pidSelected = StringVar() self._pidSelected.set("--") self._pidListBox = OptionMenu(pidCalibrationFrame, self._pidSelected, "--", \ Cockpit.KEY_ANG_SPEED, Cockpit.KEY_ANGLES, Cockpit.KEY_ACCEL, \ command=self._onPidListBoxChanged) self._pidListBox.pack(side=LEFT, padx=2) self._pidListBox.config(width=10) self._axisSelected = StringVar() self._axisSelected.set("--") self._axisListBox = OptionMenu(pidCalibrationFrame, self._axisSelected, "--", "X", "Y", "Z", \ command=self._onAxisListBoxChanged) self._axisListBox.pack(side=LEFT, padx=2) self._axisListBox.config(state=DISABLED) Label(pidCalibrationFrame, text="P").pack(side=LEFT, padx=(14, 2)) self._pidPString = StringVar() self._pidPString.set("0.00") self._pidPSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=100.0, increment=0.01, state=DISABLED, \ textvariable=self._pidPString, command=self._onPidSpinboxChanged) self._pidPSpinbox.pack(side=LEFT, padx=2) Label(pidCalibrationFrame, text="I").pack(side=LEFT, padx=(14, 2)) self._pidIString = StringVar() self._pidIString.set("0.00") self._pidISpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=100.0, increment=0.01, state=DISABLED, \ textvariable=self._pidIString, command=self._onPidSpinboxChanged) self._pidISpinbox.pack(side=LEFT, padx=2) Label(pidCalibrationFrame, text="D").pack(side=LEFT, padx=(14, 2)) self._pidDString = StringVar() self._pidDString.set("0.00") self._pidDSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=100.0, increment=0.01, state=DISABLED, \ textvariable=self._pidDString, command=self._onPidSpinboxChanged) self._pidDSpinbox.pack(side=LEFT, padx=2) #debug debugFrame = tkFrame(self) debugFrame.grid(column=0, row=3, sticky="WE") self._debugMsg = Message(debugFrame, anchor="nw", justify=LEFT, relief=SUNKEN, width=300) self._debugMsg.pack(fill=BOTH, expand=1) def _start(self): self._readDroneConfig() def exit(self): self._link.send({"key": "close", "data": None}) self._stopUpdateInfoThread() self._link.close() self.quit() def _updateTarget(self): markerCoords = self._shiftCanvas.coords(self._shiftMarker) coords = ((markerCoords[0] + markerCoords[2]) / 2, (markerCoords[1] + markerCoords[3]) / 2) self._target[1] = float(coords[0] - 201) * Cockpit.MAX_ACCEL / 200.0 self._target[0] = float(coords[1] - 201) * Cockpit.MAX_ACCEL / 200.0 #Remote control uses clockwise angle, but the drone's referece system uses counter-clockwise angle self._target[2] = -self._yaw.get() * Cockpit.MAX_ANGLE_SPEED / 100.0 self._target[3] = self._throttle.get() * Cockpit.MAX_ACCEL_Z / 100.0 self._sendTarget() def _keyDown(self, event): if event.keysym == "Escape": self._throttle.set(0) self._started.set(0) self._thrustScale.config(state=DISABLED) self._stopUpdateInfoThread() self._sendIsStarted() elif event.keysym.startswith("Control"): self._controlKeyActive = True elif not self._controlKeysLocked and self._controlKeyActive: if event.keysym == "Up": self._thrustScaleUp() elif event.keysym == "Down": self._thrustScaleDown() elif event.keysym == "Left": self._yawLeft() elif event.keysym == "Right": self._yawRight() elif event.keysym == "space": self._yawReset() self._thrustReset() elif not self._controlKeysLocked and not self._controlKeyActive: if event.keysym == "Up": self._moveShiftCanvasMarker((0,-5)) elif event.keysym == "Down": self._moveShiftCanvasMarker((0,5)) elif event.keysym == "Left": self._moveShiftCanvasMarker((-5,0)) elif event.keysym == "Right": self._moveShiftCanvasMarker((5,0)) elif event.keysym == "space": self._resetShiftCanvasMarker() def _keyUp(self, eventArgs): if eventArgs.keysym.startswith("Control"): self._controlKeyActive = False def _onMouseButton1(self, eventArgs): self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _onMouseButtonRelease1(self, eventArgs): self._shiftCanvas.coords(self._shiftMarker, 197, 197, 205, 205) def _limitCoordsToSize(self, coords, size): if coords[0] > size: x = size elif coords[0] < 0: x = 0 else: x = coords[0] if coords[1] > size: y = size elif coords[1] < 0: y = 0 else: y = coords[1] return (x,y) def _moveShiftCanvasMarker(self, shift): lastCoords = self._shiftCanvas.coords(self._shiftMarker) newCoords = (lastCoords[0] + shift[0], lastCoords[1] + shift[1]) newCoords = self._limitCoordsToSize(newCoords, 400) self._shiftCanvas.coords(self._shiftMarker, newCoords[0], newCoords[1], newCoords[0] + 8, newCoords[1] + 8) self._updateTarget() def _resetShiftCanvasMarker(self): self._shiftCanvas.coords(self._shiftMarker, 197, 197, 205, 205) self._updateTarget() def _onMouseButton1Motion(self, eventArgs): deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1]) self._moveShiftCanvasMarker(deltaCoords) self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _onMouseDoubleButton1(self, eventArgs): self._resetShiftCanvasMarker() def _onMouseButton3(self, eventArgs): self._lastMouseCoords = (eventArgs.x, eventArgs.y) self._mouseDirection = Cockpit.DIR_NONE def _onMouseButtonRelease3(self, eventArgs): self._shiftCanvas.coords(self._shiftMarker, 197, 197, 205, 205) def _onMouseButton3Motion(self, eventArgs): deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1]) if self._mouseDirection == Cockpit.DIR_NONE: if abs(deltaCoords[0]) > abs(deltaCoords[1]): self._mouseDirection = Cockpit.DIR_HORIZONTAL else: self._mouseDirection = Cockpit.DIR_VERTICAL if self._mouseDirection == Cockpit.DIR_HORIZONTAL: deltaCoords = (deltaCoords[0], 0) else: deltaCoords = (0, deltaCoords[1]) self._moveShiftCanvasMarker(deltaCoords) self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _thrustScaleUp(self): if self._started.get(): newValue = self._thrustScale.get() + 1 self._thrustScale.set(newValue) self._updateTarget() def _thrustScaleDown(self): if self._started.get(): newValue = self._thrustScale.get() - 1 self._thrustScale.set(newValue) self._updateTarget() def _thrustReset(self): if self._started.get(): self._thrustScale.set(0.0) self._updateTarget() def _onThrustScaleDoubleButton1(self, eventArgs): self._thrustReset() return "break" def _yawRight(self): newValue = self._yaw.get() + 1 self._yaw.set(newValue) self._updateTarget() def _yawLeft(self): newValue = self._yaw.get() - 1 self._yaw.set(newValue) self._updateTarget() def _yawReset(self): self._yaw.set(0) self._updateTarget() def _onMouseWheelUp(self, eventArgs): if not self._controlKeyActive: self._thrustScaleUp() else: self._yawRight() def _onMouseWheelDown(self, eventArgs): if not self._controlKeyActive: self._thrustScaleDown() else: self._yawLeft() def _onMouseWheel(self, eventArgs): factor = int(eventArgs.delta/120) if not self._controlKeyActive: if self._started.get(): newValue = self._thrustScale.get() + factor self._thrustScale.set(newValue) self._updateTarget() else: newValue = self._yaw.get() + factor self._yaw.set(newValue) self._updateTarget() def _onYawScaleChanged(self, eventArgs): self._updateTarget() def _onYawScaleDoubleButton1(self, eventArgs): self._yawReset() return "break" def _startedCBChanged(self): if not self._started.get(): self._throttle.set(0) self._thrustScale.config(state=DISABLED) self._integralsCB.config(state=DISABLED) self._stopUpdateInfoThread() else: self._thrustScale.config(state="normal") self._integralsCB.config(state="normal") self._startUpdateInfoThread() self._sendIsStarted() def _integralsCBChanged(self): self._link.send({"key": "integrals", "data":self._integralsEnabled.get() != 0}) def _onThrustScaleChanged(self, eventArgs): self._updateTarget() def _sendTarget(self): self._link.send({"key": "target", "data": self._target}) def _sendIsStarted(self): isStarted = self._started.get() != 0 self._link.send({"key": "is-started", "data": isStarted}) def _sendPidCalibrationData(self): if self._pidSelected.get() != "--" and self._axisSelected.get() != "--": pidData = { "pid": self._pidSelected.get(), "axis": self._axisSelected.get(), "p": float(self._pidPSpinbox.get()), "i": float(self._pidISpinbox.get()), "d": float(self._pidDSpinbox.get())} self._link.send({"key": "pid-calibration", "data": pidData}) def _updatePidCalibrationData(self): pid = self._pidSelected.get() axis = self._axisSelected.get() if pid != "--" and axis != "--": self._pidConstants[pid][axis]["P"] = float(self._pidPSpinbox.get()) self._pidConstants[pid][axis]["I"] = float(self._pidISpinbox.get()) self._pidConstants[pid][axis]["D"] = float(self._pidDSpinbox.get()) def _readDroneConfig(self): self._link.send({"key": "read-drone-config", "data": None}, self._onDroneConfigRead) def _readDroneState(self): if not self._readingState: self._readingState = True self._link.send({"key": "read-drone-state", "data": None}, self._onDroneStateRead) def _readPidConfigItem(self, message, cockpitKey, axises, configKeys): for i in range(len(axises)): for j in range(len(Cockpit.PID_KEYS)): self._pidConstants[cockpitKey][axises[i]][Cockpit.PID_KEYS[j]] = message[configKeys[j]][i] def _onDroneConfigRead(self, message): #TODO Show current configuration within the GUI (at least relevant settings) if message: #Angle-speeds self._readPidConfigItem(message, Cockpit.KEY_ANG_SPEED, ["X", "Y", "Z"], \ [Configuration.PID_ANGLES_SPEED_KP, \ Configuration.PID_ANGLES_SPEED_KI, \ Configuration.PID_ANGLES_SPEED_KD]) #Angles self._readPidConfigItem(message, Cockpit.KEY_ANGLES, ["X", "Y"], \ [Configuration.PID_ANGLES_KP, \ Configuration.PID_ANGLES_KI, \ Configuration.PID_ANGLES_KD]) #Accels self._readPidConfigItem(message, Cockpit.KEY_ACCEL, ["X", "Y", "Z"], \ [Configuration.PID_ACCEL_KP, \ Configuration.PID_ACCEL_KI, \ Configuration.PID_ACCEL_KD]) def _onDroneStateRead(self, state): if state: for index in range(4): self._throttleTexts[index].set("{0:.3f}".format(state["_throttles"][index])) for index in range(3): self._accelTexts[index].set("{0:.3f}".format(state["_accels"][index])) self._angleTexts[index].set("{0:.3f}".format(state["_angles"][index])) else: self._stopUpdateInfoThread() self._readingState = False def _onPidSpinboxChanged(self): self._updatePidCalibrationData() self._sendPidCalibrationData() def _onPidListBoxChanged(self, pid): self._axisSelected.set("--") self._pidPString.set("--") self._pidIString.set("--") self._pidDString.set("--") self._pidPSpinbox.config(state=DISABLED) self._pidISpinbox.config(state=DISABLED) self._pidDSpinbox.config(state=DISABLED) self._selectedPidConstats = pid if pid == "--": self._axisListBox.config(state=DISABLED) self._controlKeysLocked = False else: self._axisListBox.config(state="normal") self._controlKeysLocked = True def _onAxisListBoxChanged(self, axis): if axis == "--" or (self._selectedPidConstats == Cockpit.KEY_ANGLES and axis == "Z"): self._pidPString.set("--") self._pidIString.set("--") self._pidDString.set("--") self._pidPSpinbox.config(state=DISABLED) self._pidISpinbox.config(state=DISABLED) self._pidDSpinbox.config(state=DISABLED) self._controlKeysLocked = axis != "--" else: self._pidPString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["P"])) self._pidIString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["I"])) self._pidDString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["D"])) self._pidPSpinbox.config(state="normal") self._pidISpinbox.config(state="normal") self._pidDSpinbox.config(state="normal") self._controlKeysLocked = True def _updateInfo(self): while self._updateInfoThreadRunning: self._readDroneState() time.sleep(1.0) def _startUpdateInfoThread(self): self._updateInfoThreadRunning = True if not self._updateInfoThread.isAlive(): self._updateInfoThread.start() def _stopUpdateInfoThread(self): self._updateInfoThreadRunning = False if self._updateInfoThread.isAlive(): self._updateInfoThread.join()
class Cockpit(ttkFrame): ''' Remote device GUI ''' #TODO: 20160415 DPM - Set these values from configuration file #--- config THROTTLE_BY_USER = True THROTTLE_RESOLUTION = 0.1 # Joystick enabled or not, if any JOYSTICK_ENABLED = True DEFAULT_DRONE_IP = "192.168.1.130" DEFAULT_DRONE_PORT = 2121 #--- end config KEY_ANG_SPEED = "ang-speed" KEY_ANGLES = "angles" KEY_ACCEL = "accel" PID_KEYS = ["P", "I", "D"] DIR_NONE = 0 DIR_VERTICAL = 1 DIR_HORIZONTAL = 2 def __init__(self, parent, isDummy=False, droneIp=DEFAULT_DRONE_IP, dronePort=DEFAULT_DRONE_PORT): ''' Constructor ''' ttkFrame.__init__(self, parent) self._target = [0.0] * 4 self._selectedPidConstats = "--" self._pidConstants = { Cockpit.KEY_ANG_SPEED: { "X": { "P": 0.0, "I": 0.0, "D": 0.0 }, "Y": { "P": 0.0, "I": 0.0, "D": 0.0 }, "Z": { "P": 0.0, "I": 0.0, "D": 0.0 } }, Cockpit.KEY_ANGLES: { "X": { "P": 0.0, "I": 0.0, "D": 0.0 }, "Y": { "P": 0.0, "I": 0.0, "D": 0.0 } }, Cockpit.KEY_ACCEL: { "X": { "P": 0.0, "I": 0.0, "D": 0.0 }, "Y": { "P": 0.0, "I": 0.0, "D": 0.0 }, "Z": { "P": 0.0, "I": 0.0, "D": 0.0 } } } self.parent = parent self.initUI() self._controlKeysLocked = False if not isDummy: self._link = INetLink(droneIp, dronePort) else: self._link = ConsoleLink() self._link.open() self._updateInfoThread = Thread(target=self._updateInfo) self._updateInfoThreadRunning = False self._readingState = False self._start() def initUI(self): self.parent.title("Drone control") self.style = Style() self.style.theme_use("default") self.pack(fill=BOTH, expand=1) self.parent.bind_all("<Key>", self._keyDown) self.parent.bind_all("<KeyRelease>", self._keyUp) if system() == "Linux": self.parent.bind_all("<Button-4>", self._onMouseWheelUp) self.parent.bind_all("<Button-5>", self._onMouseWheelDown) else: #case of Windows self.parent.bind_all("<MouseWheel>", self._onMouseWheel) #Commands commandsFrame = tkFrame(self) commandsFrame.grid(column=0, row=0, sticky="WE") self._started = IntVar() self._startedCB = Checkbutton(commandsFrame, text="On", variable=self._started, command=self._startedCBChanged) self._startedCB.pack(side=LEFT, padx=4) # self._integralsCB = Checkbutton(commandsFrame, text="Int.", variable=self._integralsEnabled, \ # command=self._integralsCBChanged, state=DISABLED) # self._integralsCB.pack(side=LEFT, padx=4) self._quitButton = Button(commandsFrame, text="Quit", command=self.exit) self._quitButton.pack(side=LEFT, padx=2, pady=2) # self._angleLbl = Label(commandsFrame, text="Angle") # self._angleLbl.pack(side=LEFT, padx=4) # # self._angleEntry = Entry(commandsFrame, state=DISABLED) # self._angleEntry.pack(side=LEFT) #Info infoFrame = tkFrame(self) infoFrame.grid(column=1, row=1, sticky="NE", padx=4) #Throttle Label(infoFrame, text="Throttle").grid(column=0, row=0, sticky="WE") self._throttleTexts = [ StringVar(), StringVar(), StringVar(), StringVar() ] Entry(infoFrame, textvariable=self._throttleTexts[3], state=DISABLED, width=5).grid(column=0, row=1) Entry(infoFrame, textvariable=self._throttleTexts[0], state=DISABLED, width=5).grid(column=1, row=1) Entry(infoFrame, textvariable=self._throttleTexts[2], state=DISABLED, width=5).grid(column=0, row=2) Entry(infoFrame, textvariable=self._throttleTexts[1], state=DISABLED, width=5).grid(column=1, row=2) #Angles Label(infoFrame, text="Angles").grid(column=0, row=3, sticky="WE") self._angleTexts = [StringVar(), StringVar(), StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._angleTexts[index], state=DISABLED, width=5).grid(column=index, row=4) #Accels Label(infoFrame, text="Accels").grid(column=0, row=5, sticky="WE") self._accelTexts = [StringVar(), StringVar(), StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._accelTexts[index], state=DISABLED, width=5).grid(column=index, row=6) #Speeds Label(infoFrame, text="Speeds").grid(column=0, row=7, sticky="WE") self._speedTexts = [StringVar(), StringVar(), StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._speedTexts[index], state=DISABLED, width=5).grid(column=index, row=8) #Height Label(infoFrame, text="Height").grid(column=0, row=9, sticky="E") self._heightText = StringVar() Entry(infoFrame, textvariable=self._heightText, state=DISABLED, width=5).grid(column=1, row=9) #Loop rate Label(infoFrame, text="Loop @").grid(column=0, row=10, sticky="E") self._loopRateText = StringVar() Entry(infoFrame, textvariable=self._loopRateText, state=DISABLED, width=5).grid(column=1, row=10) Label(infoFrame, text="Hz").grid(column=2, row=10, sticky="W") #control controlFrame = tkFrame(self) controlFrame.grid(column=0, row=1, sticky="W") self._throttle = DoubleVar() if Cockpit.THROTTLE_BY_USER: self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=0.0, \ tickinterval=0, variable=self._throttle, resolution=Cockpit.THROTTLE_RESOLUTION, \ length=200, showvalue=1, \ state=DISABLED, command=self._onThrustScaleChanged) else: self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=-100.0, \ tickinterval=0, variable=self._throttle, \ length=200, showvalue=1, \ state=DISABLED, command=self._onThrustScaleChanged) self._thrustScale.bind("<Double-Button-1>", self._onThrustScaleDoubleButton1, "+") self._thrustScale.grid(column=0) self._shiftCanvas = Canvas(controlFrame, bg="white", height=400, width=400, \ relief=SUNKEN) self._shiftCanvas.bind("<Button-1>", self._onMouseButton1) #self._shiftCanvas.bind("<ButtonRelease-1>", self._onMouseButtonRelease1) self._shiftCanvas.bind("<B1-Motion>", self._onMouseButton1Motion) self._shiftCanvas.bind("<Double-Button-1>", self._onMouseDoubleButton1) self._shiftCanvas.bind("<Button-3>", self._onMouseButton3) #self._shiftCanvas.bind("<ButtonRelease-3>", self._onMouseButtonRelease3) self._shiftCanvas.bind("<B3-Motion>", self._onMouseButton3Motion) self._shiftCanvas.grid(row=0, column=1, padx=2, pady=2) self._shiftCanvas.create_oval(1, 1, 400, 400, outline="#ff0000") self._shiftCanvas.create_line(200, 2, 200, 400, fill="#ff0000") self._shiftCanvas.create_line(2, 200, 400, 200, fill="#ff0000") self._shiftMarker = self._shiftCanvas.create_oval(196, 196, 204, 204, outline="#0000ff", fill="#0000ff") self._yaw = DoubleVar() self._yawScale = Scale(controlFrame, orient=HORIZONTAL, from_=-100.0, to=100.0, \ tickinterval=0, variable=self._yaw, \ length=200, showvalue=1, \ command=self._onYawScaleChanged) self._yawScale.bind("<Double-Button-1>", self._onYawScaleDoubleButton1, "+") self._yawScale.grid(row=1, column=1) self._controlKeyActive = False #PID calibration pidCalibrationFrame = tkFrame(self) pidCalibrationFrame.grid(column=0, row=2, sticky="WE") self._pidSelected = StringVar() self._pidSelected.set("--") self._pidListBox = OptionMenu(pidCalibrationFrame, self._pidSelected, "--", \ Cockpit.KEY_ANG_SPEED, Cockpit.KEY_ANGLES, Cockpit.KEY_ACCEL, \ command=self._onPidListBoxChanged) self._pidListBox.pack(side=LEFT, padx=2) self._pidListBox.config(width=10) self._axisSelected = StringVar() self._axisSelected.set("--") self._axisListBox = OptionMenu(pidCalibrationFrame, self._axisSelected, "--", "X", "Y", "Z", \ command=self._onAxisListBoxChanged) self._axisListBox.pack(side=LEFT, padx=2) self._axisListBox.config(state=DISABLED) Label(pidCalibrationFrame, text="P").pack(side=LEFT, padx=(14, 2)) self._pidPString = StringVar() self._pidPString.set("0.00") self._pidPSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \ textvariable=self._pidPString, command=self._onPidSpinboxChanged) self._pidPSpinbox.pack(side=LEFT, padx=2) Label(pidCalibrationFrame, text="I").pack(side=LEFT, padx=(14, 2)) self._pidIString = StringVar() self._pidIString.set("0.00") self._pidISpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \ textvariable=self._pidIString, command=self._onPidSpinboxChanged) self._pidISpinbox.pack(side=LEFT, padx=2) Label(pidCalibrationFrame, text="D").pack(side=LEFT, padx=(14, 2)) self._pidDString = StringVar() self._pidDString.set("0.00") self._pidDSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \ textvariable=self._pidDString, command=self._onPidSpinboxChanged) self._pidDSpinbox.pack(side=LEFT, padx=2) #debug debugFrame = tkFrame(self) debugFrame.grid(column=0, row=3, sticky="WE") self._debugMsg = Message(debugFrame, anchor="nw", justify=LEFT, relief=SUNKEN, width=300) self._debugMsg.pack(fill=BOTH, expand=1) def _start(self): self._readDroneConfig() if Cockpit.JOYSTICK_ENABLED: self._joystickManager = JoystickManager.getInstance() self._joystickManager.start() joysticks = self._joystickManager.getJoysticks() if len(joysticks) != 0: self._joystick = joysticks[0] self._joystick.onAxisChanged += self._onJoystickAxisChanged self._joystick.onButtonPressed += self._onJoystickButtonPressed else: self._joystick = None def _onJoystickAxisChanged(self, sender, index): if self._started.get() and sender == self._joystick: axisValue = self._joystick.getAxisValue(index) if index == 0: self._yaw.set(axisValue) self._updateTarget() elif index == 1 and not Cockpit.THROTTLE_BY_USER: thrust = -axisValue self._throttle.set(thrust) self._updateTarget() elif index == 2 and Cockpit.THROTTLE_BY_USER: rowThrottle = (axisValue + 100.0) / 2.0 if rowThrottle < 10.0: throttle = rowThrottle * 6.0 elif rowThrottle < 90.0: throttle = 60.0 + ((rowThrottle - 10.0) / 8.0) else: throttle = 70.0 + (rowThrottle - 90.0) * 3.0 self._throttle.set(throttle) self._sendThrottle() elif index == 3: x = 196 + axisValue * 2 lastCoords = self._shiftCanvas.coords(self._shiftMarker) coords = (x, lastCoords[1]) self._plotShiftCanvasMarker(coords) elif index == 4: y = 196 + axisValue * 2 lastCoords = self._shiftCanvas.coords(self._shiftMarker) coords = (lastCoords[0], y) self._plotShiftCanvasMarker(coords) def _onJoystickButtonPressed(self, sender, index): if sender == self._joystick and index == 7: if self._started.get() == 0: self._startedCB.select() else: self._startedCB.deselect() # Tkinter's widgets seem not to be calling the event-handler # when they are changed programmatically. Therefore, the # even-handler is called explicitly here. self._startedCBChanged() def exit(self): self._link.send({"key": "close", "data": None}) self._stopUpdateInfoThread() self._link.close() if Cockpit.JOYSTICK_ENABLED: self._joystickManager.stop() self.quit() def _updateTarget(self): markerCoords = self._shiftCanvas.coords(self._shiftMarker) coords = ((markerCoords[0] + markerCoords[2]) / 2, (markerCoords[1] + markerCoords[3]) / 2) self._target[0] = float( coords[1] - 200) / 2.0 # X-axis angle / X-axis acceleration self._target[1] = float( coords[0] - 200) / 2.0 # Y-axis angle / Y-axis acceleration #Remote control uses clockwise angle, but the drone's referece system uses counter-clockwise angle self._target[2] = -self._yaw.get() # Z-axis angular speed # Z-axis acceleration (thrust). Only when the motor throttle is not controlled by user directly if Cockpit.THROTTLE_BY_USER: self._target[3] = 0.0 else: self._target[3] = self._throttle.get() self._sendTarget() def _keyDown(self, event): if event.keysym == "Escape": self._throttle.set(0) self._started.set(0) self._thrustScale.config(state=DISABLED) self._stopUpdateInfoThread() self._sendIsStarted() elif event.keysym.startswith("Control"): self._controlKeyActive = True elif not self._controlKeysLocked and self._controlKeyActive: if event.keysym == "Up": self._thrustScaleUp() elif event.keysym == "Down": self._thrustScaleDown() elif event.keysym == "Left": self._yawLeft() elif event.keysym == "Right": self._yawRight() elif event.keysym == "space": self._yawReset() if not Cockpit.THROTTLE_BY_USER: self._thrustReset() elif not self._controlKeysLocked and not self._controlKeyActive: if event.keysym == "Up": self._moveShiftCanvasMarker((0, -5)) elif event.keysym == "Down": self._moveShiftCanvasMarker((0, 5)) elif event.keysym == "Left": self._moveShiftCanvasMarker((-5, 0)) elif event.keysym == "Right": self._moveShiftCanvasMarker((5, 0)) elif event.keysym == "space": self._resetShiftCanvasMarker() def _keyUp(self, eventArgs): if eventArgs.keysym.startswith("Control"): self._controlKeyActive = False def _onMouseButton1(self, eventArgs): self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _onMouseButtonRelease1(self, eventArgs): self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204) def _limitCoordsToSize(self, coords, size, width): maxSize = size - (width / 2.0) minSize = -(width / 2.0) if coords[0] > maxSize: x = maxSize elif coords[0] < minSize: x = minSize else: x = coords[0] if coords[1] > maxSize: y = maxSize elif coords[1] < minSize: y = minSize else: y = coords[1] return (x, y) def _plotShiftCanvasMarker(self, coords): coords = self._limitCoordsToSize(coords, 400, 8) self._shiftCanvas.coords(self._shiftMarker, coords[0], coords[1], coords[0] + 8, coords[1] + 8) self._updateTarget() def _moveShiftCanvasMarker(self, shift): lastCoords = self._shiftCanvas.coords(self._shiftMarker) newCoords = (lastCoords[0] + shift[0], lastCoords[1] + shift[1]) self._plotShiftCanvasMarker(newCoords) def _resetShiftCanvasMarker(self): self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204) self._updateTarget() def _onMouseButton1Motion(self, eventArgs): deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1]) self._moveShiftCanvasMarker(deltaCoords) self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _onMouseDoubleButton1(self, eventArgs): self._resetShiftCanvasMarker() def _onMouseButton3(self, eventArgs): self._lastMouseCoords = (eventArgs.x, eventArgs.y) self._mouseDirection = Cockpit.DIR_NONE def _onMouseButtonRelease3(self, eventArgs): self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204) def _onMouseButton3Motion(self, eventArgs): deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1]) if self._mouseDirection == Cockpit.DIR_NONE: if abs(deltaCoords[0]) > abs(deltaCoords[1]): self._mouseDirection = Cockpit.DIR_HORIZONTAL else: self._mouseDirection = Cockpit.DIR_VERTICAL if self._mouseDirection == Cockpit.DIR_HORIZONTAL: deltaCoords = (deltaCoords[0], 0) else: deltaCoords = (0, deltaCoords[1]) self._moveShiftCanvasMarker(deltaCoords) self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _thrustScaleUp(self): #TODO: 20160526 DPM: El valor de incremento de aceleración (1.0) puede ser muy alto if self._started.get(): newValue = self._thrustScale.get() \ + (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0) self._thrustScale.set(newValue) self._updateTarget() def _thrustScaleDown(self): #TODO: 20160526 DPM: El valor de decremento de aceleración (1.0) puede ser muy alto if self._started.get(): newValue = self._thrustScale.get() \ - (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0) self._thrustScale.set(newValue) self._updateTarget() def _thrustReset(self): if self._started.get(): self._thrustScale.set(0.0) self._updateTarget() def _onThrustScaleDoubleButton1(self, eventArgs): self._thrustReset() return "break" def _yawRight(self): newValue = self._yaw.get() + 1 self._yaw.set(newValue) self._updateTarget() def _yawLeft(self): newValue = self._yaw.get() - 1 self._yaw.set(newValue) self._updateTarget() def _yawReset(self): self._yaw.set(0) self._updateTarget() def _onMouseWheelUp(self, eventArgs): if not self._controlKeyActive: self._thrustScaleUp() else: self._yawRight() def _onMouseWheelDown(self, eventArgs): if not self._controlKeyActive: self._thrustScaleDown() else: self._yawLeft() def _onMouseWheel(self, eventArgs): factor = eventArgs.delta / (1200.0 if Cockpit.THROTTLE_BY_USER and not self._controlKeyActive else 120.0) if not self._controlKeyActive: if self._started.get(): newValue = self._thrustScale.get() + factor self._thrustScale.set(newValue) self._updateTarget() else: newValue = self._yaw.get() + factor self._yaw.set(newValue) self._updateTarget() def _onYawScaleChanged(self, eventArgs): self._updateTarget() def _onYawScaleDoubleButton1(self, eventArgs): self._yawReset() return "break" def _startedCBChanged(self): if not self._started.get(): self._throttle.set(0) self._thrustScale.config(state=DISABLED) #self._integralsCB.config(state=DISABLED) self._stopUpdateInfoThread() else: self._thrustScale.config(state="normal") #self._integralsCB.config(state="normal") self._startUpdateInfoThread() self._sendIsStarted() # def _integralsCBChanged(self): # # self._link.send({"key": "integrals", "data":self._integralsEnabled.get() != 0}) # def _onThrustScaleChanged(self, eventArgs): if Cockpit.THROTTLE_BY_USER: self._sendThrottle() else: self._updateTarget() def _sendThrottle(self): self._link.send({"key": "throttle", "data": self._throttle.get()}) def _sendTarget(self): self._link.send({"key": "target", "data": self._target}) def _sendIsStarted(self): isStarted = self._started.get() != 0 self._link.send({"key": "is-started", "data": isStarted}) def _sendPidCalibrationData(self): if self._pidSelected.get() != "--" and self._axisSelected.get( ) != "--": pidData = { "pid": self._pidSelected.get(), "axis": self._axisSelected.get(), "p": float(self._pidPSpinbox.get()), "i": float(self._pidISpinbox.get()), "d": float(self._pidDSpinbox.get()) } self._link.send({"key": "pid-calibration", "data": pidData}) def _updatePidCalibrationData(self): pid = self._pidSelected.get() axis = self._axisSelected.get() if pid != "--" and axis != "--": self._pidConstants[pid][axis]["P"] = float(self._pidPSpinbox.get()) self._pidConstants[pid][axis]["I"] = float(self._pidISpinbox.get()) self._pidConstants[pid][axis]["D"] = float(self._pidDSpinbox.get()) def _readDroneConfig(self): self._link.send({ "key": "read-drone-config", "data": None }, self._onDroneConfigRead) def _readDroneState(self): if not self._readingState: self._readingState = True self._link.send({ "key": "read-drone-state", "data": None }, self._onDroneStateRead) def _readPidConfigItem(self, message, cockpitKey, axises, configKeys): for i in range(len(axises)): for j in range(len(Cockpit.PID_KEYS)): self._pidConstants[cockpitKey][axises[i]][ Cockpit.PID_KEYS[j]] = message[configKeys[j]][i] def _onDroneConfigRead(self, message): #TODO Show current configuration within the GUI (at least relevant settings) if message: #Angle-speeds self._readPidConfigItem(message, Cockpit.KEY_ANG_SPEED, ["X", "Y", "Z"], \ [Configuration.PID_ANGLES_SPEED_KP, \ Configuration.PID_ANGLES_SPEED_KI, \ Configuration.PID_ANGLES_SPEED_KD]) #Angles self._readPidConfigItem(message, Cockpit.KEY_ANGLES, ["X", "Y"], \ [Configuration.PID_ANGLES_KP, \ Configuration.PID_ANGLES_KI, \ Configuration.PID_ANGLES_KD]) #Accels self._readPidConfigItem(message, Cockpit.KEY_ACCEL, ["X", "Y", "Z"], \ [Configuration.PID_ACCEL_KP, \ Configuration.PID_ACCEL_KI, \ Configuration.PID_ACCEL_KD]) def _onDroneStateRead(self, state): if state: for index in range(4): self._throttleTexts[index].set("{0:.3f}".format( state["_throttles"][index])) for index in range(3): self._accelTexts[index].set("{0:.3f}".format( state["_accels"][index])) self._angleTexts[index].set("{0:.3f}".format( state["_angles"][index])) currentPeriod = state["_currentPeriod"] if currentPeriod > 0.0: freq = 1.0 / currentPeriod self._loopRateText.set("{0:.3f}".format(freq)) else: self._loopRateText.set("--") else: self._stopUpdateInfoThread() self._readingState = False def _onPidSpinboxChanged(self): self._updatePidCalibrationData() self._sendPidCalibrationData() def _onPidListBoxChanged(self, pid): self._axisSelected.set("--") self._pidPString.set("--") self._pidIString.set("--") self._pidDString.set("--") self._pidPSpinbox.config(state=DISABLED) self._pidISpinbox.config(state=DISABLED) self._pidDSpinbox.config(state=DISABLED) self._selectedPidConstats = pid if pid == "--": self._axisListBox.config(state=DISABLED) self._controlKeysLocked = False else: self._axisListBox.config(state="normal") self._controlKeysLocked = True def _onAxisListBoxChanged(self, axis): if axis == "--" or (self._selectedPidConstats == Cockpit.KEY_ANGLES and axis == "Z"): self._pidPString.set("--") self._pidIString.set("--") self._pidDString.set("--") self._pidPSpinbox.config(state=DISABLED) self._pidISpinbox.config(state=DISABLED) self._pidDSpinbox.config(state=DISABLED) self._controlKeysLocked = axis != "--" else: self._pidPString.set("{:.2f}".format( self._pidConstants[self._selectedPidConstats][axis]["P"])) self._pidIString.set("{:.2f}".format( self._pidConstants[self._selectedPidConstats][axis]["I"])) self._pidDString.set("{:.2f}".format( self._pidConstants[self._selectedPidConstats][axis]["D"])) self._pidPSpinbox.config(state="normal") self._pidISpinbox.config(state="normal") self._pidDSpinbox.config(state="normal") self._controlKeysLocked = True def _updateInfo(self): while self._updateInfoThreadRunning: self._readDroneState() time.sleep(1.0) def _startUpdateInfoThread(self): self._updateInfoThreadRunning = True if not self._updateInfoThread.isAlive(): self._updateInfoThread.start() def _stopUpdateInfoThread(self): self._updateInfoThreadRunning = False if self._updateInfoThread.isAlive(): self._updateInfoThread.join()
class TTTUI(object): default_ply = 6 neither_color = '#%02x%02x%02x' % (255, 255, 255) # white player_color = '#%02x%02x%02x' % (62, 188, 0) # green computer_color = '#%02x%02x%02x' % (192, 35, 3) # red win_color = '#%02x%02x%02x' % (25, 111, 254) # blue def __init__(self): # TTT related self.ttt = Board(ply=9) self.human_first = True # UI related self.root = Tk() self.root.resizable(0, 0) self.root.title("3D TTT") # TTT frames self.ttt_frames = [Frame(self.root) for x in range(3)] for i in range(3): self.ttt_frames[i].grid(row=0, column=i) self.button_pos = dict() self._init_board() # control frame self.control_frame = Frame(self.root, padx=5, pady=5) self.control_frame.grid(row=1, column=1) self.new_game_btn = Button(self.control_frame, text='New Game', \ command=lambda: self.reset()) self.new_game_btn.pack(side=LEFT, fill=BOTH, expand=True) self.toggle_human_first_btn = Button(self.control_frame, \ text='Human First', command=lambda: self.toggle_human_first()) self.toggle_human_first_btn.pack(side=RIGHT, fill=BOTH, expand=True) self.ply_box = Spinbox(self.control_frame, from_=1, to=20, \ textvariable=self.ttt.difficulty, command=lambda: self.reset()) self.ply_box.pack(side=RIGHT, fill=BOTH, expand=True) # start UI self.update_pieces() self.start() self.root.mainloop() def toggle_human_first(self): self.human_first = not self.human_first self.toggle_human_first_btn.config(text='Human First' if \ self.human_first else 'Computer First') self.reset() def _find_button(self, frame, r, c): for child in frame.children.values(): info = child.grid_info() if info['row'] == r and info['column'] == c: return child return None def update_pieces(self): player_pieces = self.ttt.get_moves(self.ttt.human) computer_pieces = self.ttt.get_moves(self.ttt.ai) cnt = 0 for b, board in enumerate(self.ttt.board): for r, row in enumerate(board): for c, col in enumerate(row): color = self.neither_color text = '-' occupied = False if cnt in player_pieces: color = self.player_color text = self.ttt.human if cnt in computer_pieces: color = self.computer_color text = self.ttt.ai if self.ttt.complete and cnt in self.ttt.winning_combo: color = self.win_color btn = self.button_pos[cnt] btn.config(text=text, bg=color, state=DISABLED if \ occupied else NORMAL) cnt += 1 def place_human(self, position): if position in self.ttt.allowed_moves and not self.ttt.complete: self.ttt.move(position, self.ttt.human) self.ttt.human_turn = False self.update_pieces() self.place_computer() def place_computer(self): if not self.ttt.complete: self.ttt.computers_move() self.update_pieces() def reset(self): self.ttt.reset() self.ttt.difficulty = self.default_ply if not \ self.ply_box.get().isdigit() else int(self.ply_box.get()) self.ttt.human_turn = self.human_first self.update_pieces() self.start() def _init_board(self): cnt = 0 for b, board in enumerate(self.ttt.board): for x, row in enumerate(board): for y, cell in enumerate(row): padding = (0, 0) if y == 2 and b != 2: padding = (0, 12) btn = Button(self.ttt_frames[b], width=8, height=4, \ command=lambda x=cell: self.place_human(x)) btn.grid(row=x, column=y, padx=padding) self.button_pos[cnt] = btn cnt += 1 def start(self): if not self.ttt.human_turn: self.place_computer()
class ToolBar(Frame): def __init__(self, root, printer, settings, logger, *arg): self.app = root self.printer = printer self.settings = settings self.logger = logger self.app.printing = False self.app.connected = False self.app.paused = False Frame.__init__(self, root, *arg) topBar = Frame(self) topBar.grid(row=1, column=1, columnspan=3, sticky=W) speedBar = Frame(self) speedBar.grid(row=1, column=5, sticky=E) bottomBar = Frame(self) bottomBar.grid(row=2, column=1, columnspan=6, sticky=W+E) self.bPort = Button(topBar, text="Port", width=BWIDTH, command=self.doPort) self.bPort.pack(side=LEFT, padx=2, pady=2) ports = self.scanSerial() self.spPort = Spinbox(topBar, values=ports, state="readonly") self.spPort.pack(side=LEFT, padx=2, pady=2) l = Label(topBar, text=" @ ") l.pack(side=LEFT, padx=2, pady=2) self.spBaud = Spinbox(topBar, values=baudChoices) self.spBaud.pack(side=LEFT, padx=2, pady=2) self.spBaud.delete(0, END) self.spBaud.insert(0, 115200) self.spBaud.config(state="readonly") self.bConnectMode = CM_CONNECT self.bConnect = Button(topBar, text=connectText[CM_CONNECT], width=BWIDTH, command=self.doConnect) self.bConnect.pack(side=LEFT, padx=2, pady=2) if len(ports) == 0: self.bConnect.config(state=DISABLED) else: self.bConnect.config(state=NORMAL) self.bReset = Button(topBar, text="Reset", width=BWIDTH, command=self.doReset, state=DISABLED) self.bReset.pack(side=LEFT, padx=2, pady=2) l = Label(speedBar, text="Speed:", justify=RIGHT) l.grid(row=1, column=1, sticky=E) self._speedJob = None self.currentSpeed = self.app.FeedMultiply self.scSpeed = Scale(speedBar, from_=MINSPEED, to=MAXSPEED, orient=HORIZONTAL, command=self.updateSpeedCommand) self.scSpeed.grid(row=1, column=2) self.scSpeed.set(self.currentSpeed); l = Label(speedBar, text="Fan:", width=10, anchor=E, justify=RIGHT) l.grid(row=1, column=3, sticky=E) self._fanJob = None self.currentFanSpeed = self.app.FanSpeed self.scFan = Scale(speedBar, from_=0, to=255, orient=HORIZONTAL, command=self.updateFanSpeedCommand) self.scFan.grid(row=1, column=4) self.scFan.set(self.currentFanSpeed); if self.settings.speedcommand is not None: self.cbvAssertFan = IntVar() if self.settings.forcefanspeed: self.cbvAssertFan.set(1) else: self.cbvAssertFan.set(0) self.cbAssertFan = Checkbutton(speedBar, text="Force", variable=self.cbvAssertFan, command=self.clickAssertFan) self.cbAssertFan.grid(row=1, column=5) self.bSliceMode = SM_SLICE self.bSlice = Button(bottomBar, text=sliceText[SM_SLICE], width=BWIDTH*2, command=self.doSlice) self.bSlice.pack(side=LEFT, padx=2, pady=2) self.bLoad = Button(bottomBar, text="Load GCode", width=BWIDTH, command=self.doLoad) self.bLoad.pack(side=LEFT, padx=2, pady=2) self.setSliceText() self.bSD = Button(bottomBar, text="SD", width=BWIDTH, command=self.doSD, state=DISABLED) self.bSD.pack(side=LEFT, padx=2, pady=2) self.bPrintMode = PR_PRINT self.bPrint = Button(bottomBar, text=printText[PR_PRINT], width=BWIDTH, command=self.doPrint, state=DISABLED) self.bPrint.pack(side=LEFT, padx=2, pady=2) self.bPauseMode = PM_PAUSE self.bPause = Button(bottomBar, text=pauseText[PM_PAUSE], width=BWIDTH, command=self.doPause, state=DISABLED) self.bPause.pack(side=LEFT, padx=2, pady=2) self.bAbandon = Button(bottomBar, text="Abandon SD Print", width=BWIDTH+8, command=self.doAbandon, state=DISABLED) self.bAbandon.pack(side=LEFT, padx=2, pady=2) self.cbvLiftOnPause = IntVar() if self.settings.liftonpause: self.cbvLiftOnPause.set(1) else: self.cbvLiftOnPause.set(0) self.cbLiftOnPause = Checkbutton(bottomBar, text="Lift Head/Retract on Pause", variable=self.cbvLiftOnPause, command=self.clickLiftOnPause) self.cbLiftOnPause.pack(side=LEFT, padx=2) self.cbvResumeAtPause = IntVar() if self.settings.resumeatpausepoint: self.cbvResumeAtPause.set(1) else: self.cbvResumeAtPause.set(0) self.cbResumeAtPause = Checkbutton(bottomBar, text="Resume print at pause point", variable=self.cbvResumeAtPause, command=self.clickResumeAtPause) self.cbResumeAtPause.pack(side=LEFT, padx=2) def clickAssertFan(self): if self.cbvAssertFan.get() == 1: self.settings.forcefanspeed = True self.settings.setModified() else: self.settings.forcefanspeed = False self.settings.setModified() def clickLiftOnPause(self): if self.cbvLiftOnPause.get() == 1: self.settings.liftonpause = True self.settings.setModified() else: self.settings.liftonpause = False self.settings.setModified() def clickResumeAtPause(self): if self.cbvResumeAtPause.get() == 1: self.settings.resumeatpausepoint = True self.settings.setModified() else: self.settings.resumeatpausepoint = False self.settings.setModified() def setSliceText(self): if self.settings.slicer == SLIC3R: sl = "slic3r:%s" % self.app.slic3r.getProfile() else: sl = "skeinforge:%s" % self.app.skeinforge.getProfile() sliceText[SM_SLICE] = "Slice (%s)" % sl if self.bSliceMode == SM_SLICE: self.bLoad.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) lt = len(sliceText[SM_SLICE])+2 if lt < BWIDTH: lt = BWIDTH self.bSlice.config(text=sliceText[SM_SLICE], width=lt) def updateSpeedCommand(self, *arg): if self._speedJob: self.app.master.after_cancel(self._speedJob) self._speedJob = self.app.master.after(500, self.updateSpeed) def updateSpeed(self, *arg): v = self.scSpeed.get() self.setSpeed(v) def setSpeed(self, v): if v < MINSPEED or v > MAXSPEED: self.logger.logMsg("Attempt to change speed outside of allowable range (%d-%d)" % (MINSPEED, MAXSPEED)) elif int(v) != self.currentSpeed: if self.app.connected: self.currentSpeed = int(v) self.logger.logMsg("changing speed percentage to %d%%" % self.currentSpeed) cmd = "M220 S%d" % self.currentSpeed self.printer.send_now(cmd) else: self.logger.logMsg("Printer is off-line") self.scSpeed.set(self.currentSpeed) def updateFanSpeedCommand(self, *arg): if self._fanJob: self.app.master.after_cancel(self._fanJob) self._fanJob = self.app.master.after(500, self.updateFanSpeed) def updateFanSpeed(self, *arg): v = self.scFan.get() self.setFanSpeed(v) self.app.FanSpeed = v def forceFanSpeed(self, v): self.currentFanSpeed = -1 self.setFanSpeed(v) def setFanSpeed(self, v): if int(v) != self.currentFanSpeed: if self.app.connected: self.currentFanSpeed = int(v) cmd = "M106 S%d" % self.currentFanSpeed self.printer.send_now(cmd) else: self.logger.logMsg("Printer is off-line") self.scFan.set(self.currentFanSpeed) def syncSpeeds(self): self.currentSpeed = self.app.FeedMultiply self.scSpeed.set(self.currentSpeed) self.currentFanSpeed = self.app.FanSpeed self.scFan.set(self.currentFanSpeed) def initializeToolbar(self): self.bReset.config(state=DISABLED) self.bSliceMode = SM_SLICE self.bSlice.config(text=sliceText[SM_SLICE]) self.bLoad.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) if not self.app.sdprinting and not self.app.sdpaused: self.bPrintMode = PR_PRINT self.bPrint.config(text=printText[PR_PRINT], state=DISABLED) self.bPauseMode = PM_PAUSE self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED) def setSDPrint(self): self.bPause.config(text=pauseText[PM_PAUSE], state=NORMAL) self.bPauseMode = PM_PAUSE self.bPrint.config(text=printText[PR_PRINT], state=DISABLED) self.bPrintMode = PR_PRINT self.bAbandon.config(state=NORMAL) def clearSDPrint(self): self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED) self.bPauseMode = PM_PAUSE self.bPrint.config(text=printText[PR_PRINT], state=DISABLED) self.bPrintMode = PR_PRINT self.bAbandon.config(state=DISABLED) self.checkAllowPrint() def setCancelMode(self): self.bSliceMode = SM_CANCEL self.bSlice.config(text=sliceText[SM_CANCEL], width=BWIDTH) self.bLoad.config(state=DISABLED) self.app.allowLoadGCodeMenu(False) self.app.allowSliceMenu(False) def setLoading(self, flag): if flag: self.bLoad.config(state=DISABLED) self.bSlice.config(state=DISABLED) self.app.allowLoadGCodeMenu(False) self.app.allowSliceMenu(False) else: self.bLoad.config(state=NORMAL) self.bSlice.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) self.app.allowSliceMenu(True) def clearCancelMode(self): self.bSliceMode = SM_SLICE lt = len(sliceText[SM_SLICE])+2 if lt < BWIDTH: lt = BWIDTH self.bSlice.config(text=sliceText[SM_SLICE], width=lt) self.bLoad.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) self.app.allowSliceMenu(True) def doConnect(self): if self.bConnectMode == CM_CONNECT: port = self.spPort.get() baud = int(self.spBaud.get()) self.printer.onlinecb = self.onlinecb try: self.printer.connect(port, baud) except SerialException: self.logger.logMsg("Unable to open printer port %s" % port) else: if self.app.printing: self.logger.logMsg("Please wait until printing has finished or is paused") else: self.printer.disconnect() self.printer.onlinecb = None self.app.printerConnected(False) # self.app.connected = False self.bConnectMode = CM_CONNECT self.bConnect.config(text=connectText[CM_CONNECT]) self.bReset.config(state=DISABLED) self.bSD.config(state=DISABLED) if self.app.paused: self.bPrint.config(text=printText[PR_PRINT], state=DISABLED) self.bPrintMode = PR_PRINT self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED) self.bPauseMode = PM_PAUSE self.app.printing = False self.app.paused = False def doReset(self): if tkMessageBox.askyesno("Reset?", "Are you sure you want to reset the printer?", parent=self.app): self.printer.reset() self.printer.printing = 0 self.app.printing = False self.bSlice.config(state=NORMAL) self.bLoad.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) self.app.allowSliceMenu(True) self.bPrintMode = PR_PRINT self.bPrint.config(text=printText[PR_PRINT], state=NORMAL) if self.app.paused: self.printer.paused = 0 self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED) self.bPauseMode = PM_PAUSE self.app.paused = False def onlinecb(self): self.logger.logMsg("Printer is on-line") self.app.printerConnected(True) # self.app.connected = True self.bConnectMode = CM_DISCONNECT self.bConnect.config(text=connectText[CM_DISCONNECT]) self.bReset.config(state=NORMAL) self.bSD.config(state=NORMAL) self.checkAllowPrint() def checkAllowPrint(self): if self.app.connected and len(self.app.gcode) != 0 and not self.app.printing and not self.app.sdprinting: self.bPrint.config(text=printText[PR_PRINT], state=NORMAL) self.bPrintMode = PR_PRINT def printComplete(self): self.app.endTime = time.time() self.app.elapsedTime = self.app.endTime - self.app.startTime self.logger.logMsg("Printing completed at %s" % time.strftime('%H:%M:%S', time.localtime())) self.logger.logMsg("Total elapsed time: %s" % formatElapsed(self.app.elapsedTime)) self.bPrintMode = PR_PRINT self.bPrint.config(text=printText[PR_PRINT], state=NORMAL) self.bPauseMode = PM_PAUSE self.bPause.config(text=pauseText[PM_PAUSE], state=DISABLED) self.app.printing = False self.bSlice.config(state=NORMAL) self.bLoad.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) self.app.allowSliceMenu(True) self.app.paused = False self.app.gc.updatePrintProgress(0) self.app.closeAllReports() if self.settings.endprintmacro is not None: self.app.doMacro(name=self.settings.endprintmacro, silent=True) def doPause(self): if self.bPauseMode == PM_PAUSE: if self.app.printing: self.app.paused = True self.printer.pause() elif self.app.sdprinting: self.app.sdpaused = True self.printer.send_now("M25") self.app.sdprinting = False self.bPause.config(text=pauseText[PM_RESUME]) self.bPauseMode = PM_RESUME self.bPrint.config(text=printText[PR_RESTART], state=NORMAL) self.bPrintMode = PR_RESTART else: if self.app.sdpaused: self.printer.send_now("M24") self.app.sdpaused = False self.app.sdprinting = True self.bPause.config(text=pauseText[PM_PAUSE]) self.bPauseMode = PM_PAUSE self.bPrint.config(text=printText[PR_PRINT], state=DISABLED) self.bPrintMode = PR_PRINT else: self.hitPrint = False if self.settings.resumeatpausepoint: self.printer.send_now("G1 X%s Y%s F%s" % (self.app.pausePoint[XAxis], self.app.pausePoint[YAxis], self.settings.xyfeed)) self.printer.send_now("G1 Z%s F%s" % (self.app.pausePoint[ZAxis], self.settings.zfeed)) self.printer.send_now("G92 E%s" % self.app.pausePoint[EAxis]) self.printer.send_now("G1 F%s" % self.settings.xyfeed) self.printer.startcb = self.startcb self.printer.resume() def doAbandon(self): self.printer.send_now("M25") self.app.sdpaused = False self.app.sdprinting = False self.clearSDPrint() def doSlice(self): if self.bSliceMode == SM_SLICE: self.bLoad.config(state=DISABLED) self.app.allowLoadGCodeMenu(False) self.app.openSTLFile() else: self.app.slicerCancel = True self.bLoad.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) def doLoad(self): self.app.openGCodeFile() def doPrint(self): if self.app.sdpaused: self.printer.send_now("M26 S0") self.printer.send_now("M24") self.app.sdpaused = False self.app.sdprinting = True self.bPause.config(text=pauseText[PM_PAUSE]) self.bPauseMode = PM_PAUSE self.bPrint.config(text=printText[PR_PRINT], state=DISABLED) self.bPrintMode = PR_PRINT else: if len(self.app.gcode) == 0: self.logger.logMsg("Nothing to print") else: #if not self.app.paused: self.app.gc.updatePrintProgress(0, restart=True) self.bPauseMode = PM_PAUSE self.bPause.config(text=pauseText[PM_PAUSE], state=NORMAL) self.hitPrint = True self.printer.startcb = self.startcb self.printer.startprint(self.app.gcode) def startcb(self): self.printer.startcb = None if not self.app.paused: self.app.startTime = time.time() self.logger.logMsg("Printing Started at %s" % time.strftime('%H:%M:%S', time.localtime(self.app.startTime))) self.app.printing = True self.bSlice.config(state=DISABLED) self.bLoad.config(state=DISABLED) self.app.allowLoadGCodeMenu(False) self.app.allowSliceMenu(False) self.bPrint.config(text=printText[PR_RESTART], state=DISABLED) self.bPrintMode = PR_RESTART self.printer.endcb = self.endcb else: if self.hitPrint: self.app.startTime = time.time() self.logger.logMsg("Printing restarted at %s" % time.strftime('%H:%M:%S', time.localtime())) else: self.logger.logMsg("Printing resumed at %s" % time.strftime('%H:%M:%S', time.localtime())) self.bPause.config(text=pauseText[PM_PAUSE]) self.bPauseMode = PM_PAUSE self.app.printing = True self.bSlice.config(state=DISABLED) self.bLoad.config(state=DISABLED) self.app.allowLoadGCodeMenu(False) self.app.allowSliceMenu(False) self.app.paused = False self.bPrint.config(state=DISABLED) self.printer.endcb = self.endcb def endcb(self): self.printer.endcb = None if not self.app.paused: self.printComplete() if self.app.sduploading: self.app.sduploading = False self.printer.send_now("M29") else: self.app.event_generate(MWM_REQUESTPOSITIONREPORT) # record the current printer position and how many intervals were willing to wait fo the response self.maxWait114 = MAXWAIT114; self.waitPos = self.printer.queueindex self.check114Response() def check114Response(self) : # tick off 1 interval, and make sure we haven't either received the report or we've waited max intervals self.maxWait114 -= 1 if self.app.m114count == 0 or self.maxWait114 <= 0: # one way or the other we're done waiting here if self.maxWait114 <= 0: self.app.m114count = 0 self.logger.logMsg("Location report not received - proceeding") self.app.pausePoint[XAxis] = self.app.location[XAxis] self.app.pausePoint[YAxis] = self.app.location[YAxis] self.app.pausePoint[ZAxis] = self.app.location[ZAxis] self.app.pausePoint[EAxis] = self.app.location[EAxis] self.logger.logMsg("Pause location: X:%f Y:%f Z:%f E:%f" % (self.app.pausePoint[XAxis], self.app.pausePoint[YAxis], self.app.pausePoint[ZAxis], self.app.pausePoint[EAxis])) if self.settings.liftonpause: self.printer.send_now("G1 E%s F%s" % (self.app.pausePoint[EAxis]-2, self.settings.efeed)) self.printer.send_now("G1 Z%s F%s" % (self.app.pausePoint[ZAxis]+10, self.settings.zfeed)) self.bPause.config(text=pauseText[PM_RESUME]) self.bPauseMode = PM_RESUME self.app.printing = False self.bSlice.config(state=NORMAL) self.bLoad.config(state=NORMAL) self.app.allowLoadGCodeMenu(True) self.app.allowSliceMenu(True) if self.app.sduploading: self.bPrint.config(text=printText[PR_PRINT], state=DISABLED) self.bPrintMode = PR_PRINT else: self.bPrint.config(text=printText[PR_RESTART], state=NORMAL) self.bPrintMode = PR_RESTART else: # we still are waiting for the report, but reset everything if the printer is still moving if self.waitPos != self.printer.queueindex: self.waitPos = self.printer.queueindex self.maxWait114 = MAXWAIT114 self.app.master.after(500, self.check114Response) def doPort(self): l = self.scanSerial() self.spPort.config(values=l) if len(l) == 0: self.bConnect.config(state=DISABLED) else: self.bConnect.config(state=NORMAL) def scanSerial(self): """scan for available ports. return a list of device names.""" baselist=[] if os.name=="nt": try: key=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"HARDWARE\\DEVICEMAP\\SERIALCOMM") i=0 while(1): baselist+=[_winreg.EnumValue(key,i)[1]] i+=1 except: pass return baselist+glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') +glob.glob("/dev/tty.*")+glob.glob("/dev/cu.*")+glob.glob("/dev/rfcomm*") def doSD(self): self.app.doSD()
def run(self): # run the whole app self.root = tk.Tk() self.root2 = tk.Tk() self.root3 = tk.Tk() self.root.title('Keyboard Simulation') # keyboard setup self.canvas = tk.Canvas(self.root, width=self.winWidth, height=self.winHeight) self.canvas.pack(side=LEFT) # self.S = Scrollbar(self.root2) self.T = Text(self.root2, height=4, width=50) self.S.pack(side=RIGHT, fill=Y, expand=True) self.T.pack(side=LEFT, fill=Y, expand=True) #self.S.pack() #self.T.pack() self.S.config(command=self.T.yview) self.T.config(yscrollcommand=self.S.set) self.T.delete(1.0, END) self.T.insert(END, self.inputText) self.T.see(END) l = Label(self.root3, text="Hover time Limit:", state='disabled') l.pack() w = Spinbox(self.root3, from_=0, to=10) w.pack() w.delete(0, "end") w.insert(0, 4) l2 = Label(self.root3, text="Hover select progress:") l2.pack() self.progress = ttk.Progressbar(self.root3, orient="horizontal", length=200, mode="determinate") self.progress["value"] = 0 self.progress["maximum"] = 10 self.progress.pack() def hv_toggle(): if self.hv_btn.config('text')[-1] == "Hover Select: On": self.hv_btn.config(text="Hover Select: off") self.hoverOn = not self.hoverOn else: self.hv_btn.config(text="Hover Select: On") self.hoverOn = not self.hoverOn self.hv_btn = tk.Button(self.root3, text="Hover Select: On", command=hv_toggle) self.hv_btn.pack() def ck_toggle(): if self.ck_btn.config('text')[-1] == "Click Select: On": self.ck_btn.config(text="Click Select: off") self.clickOn = not self.clickOn else: self.ck_btn.config(text="Click Select: On") self.clickOn = not self.clickOn self.ck_btn = tk.Button(self.root3, text="Click Select: On", command=ck_toggle) self.ck_btn.pack() #self.hoverlimit = int(w.get()) if self.clickOn: self.root.bind('<Button-1>', self.clickEvent) def timerFired(): try: self.hoverlimit = int(w.get()) except: pass self.progress["value"] = self.progress[ "maximum"] * self.hoverDt / self.hoverlimit self.lightUpHovering() self.movementLogging() if self.hoverOn: self.hoverSelect() self.redrawAll() self.canvas.after(self.dt, timerFired) self.appStartTime = time.time() timerFired() self.root.protocol("WM_DELETE_WINDOW", self.exitEvent) self.root2.protocol("WM_DELETE_WINDOW", self.exitEvent) self.root3.protocol("WM_DELETE_WINDOW", self.exitEvent) self.root.mainloop() # This call BLOCKS self.root2.mainloop() self.root3.mainloop()
class Cockpit(ttkFrame): ''' Remote device GUI ''' #TODO: 20160415 DPM - Set these values from configuration file #--- config THROTTLE_BY_USER = True THROTTLE_RESOLUTION = 0.1 # Joystick enabled or not, if any JOYSTICK_ENABLED = True DEFAULT_DRONE_IP = "192.168.1.130" DEFAULT_DRONE_PORT = 2121 #--- end config KEY_ANG_SPEED = "ang-speed" KEY_ANGLES = "angles" KEY_ACCEL = "accel" PID_KEYS = ["P", "I", "D"] DIR_NONE = 0 DIR_VERTICAL = 1 DIR_HORIZONTAL = 2 def __init__(self, parent, isDummy = False, droneIp = DEFAULT_DRONE_IP, dronePort = DEFAULT_DRONE_PORT): ''' Constructor ''' ttkFrame.__init__(self, parent) self._target = [0.0] * 4 self._selectedPidConstats = "--" self._pidConstants = { Cockpit.KEY_ANG_SPEED:{ "X":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Y":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Z":{ "P": 0.0, "I": 0.0, "D": 0.0 } }, Cockpit.KEY_ANGLES: { "X":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Y":{ "P": 0.0, "I": 0.0, "D": 0.0 } }, Cockpit.KEY_ACCEL:{ "X":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Y":{ "P": 0.0, "I": 0.0, "D": 0.0 }, "Z":{ "P": 0.0, "I": 0.0, "D": 0.0 } } } self.parent = parent self.initUI() self._controlKeysLocked = False if not isDummy: self._link = INetLink(droneIp, dronePort) else: self._link = ConsoleLink() self._link.open() self._updateInfoThread = Thread(target=self._updateInfo) self._updateInfoThreadRunning = False self._readingState = False self._start() def initUI(self): self.parent.title("Drone control") self.style = Style() self.style.theme_use("default") self.pack(fill=BOTH, expand=1) self.parent.bind_all("<Key>", self._keyDown) self.parent.bind_all("<KeyRelease>", self._keyUp) if system() == "Linux": self.parent.bind_all("<Button-4>", self._onMouseWheelUp) self.parent.bind_all("<Button-5>", self._onMouseWheelDown) else: #case of Windows self.parent.bind_all("<MouseWheel>", self._onMouseWheel) #Commands commandsFrame = tkFrame(self) commandsFrame.grid(column=0, row=0, sticky="WE") self._started = IntVar() self._startedCB = Checkbutton(commandsFrame, text="On", variable=self._started, command=self._startedCBChanged) self._startedCB.pack(side=LEFT, padx=4) # self._integralsCB = Checkbutton(commandsFrame, text="Int.", variable=self._integralsEnabled, \ # command=self._integralsCBChanged, state=DISABLED) # self._integralsCB.pack(side=LEFT, padx=4) self._quitButton = Button(commandsFrame, text="Quit", command=self.exit) self._quitButton.pack(side=LEFT, padx=2, pady=2) # self._angleLbl = Label(commandsFrame, text="Angle") # self._angleLbl.pack(side=LEFT, padx=4) # # self._angleEntry = Entry(commandsFrame, state=DISABLED) # self._angleEntry.pack(side=LEFT) #Info infoFrame = tkFrame(self) infoFrame.grid(column=1, row=1, sticky="NE", padx=4) #Throttle Label(infoFrame, text="Throttle").grid(column=0, row=0, sticky="WE") self._throttleTexts = [StringVar(),StringVar(),StringVar(),StringVar()] Entry(infoFrame, textvariable=self._throttleTexts[3], state=DISABLED, width=5).grid(column=0, row=1) Entry(infoFrame, textvariable=self._throttleTexts[0], state=DISABLED, width=5).grid(column=1, row=1) Entry(infoFrame, textvariable=self._throttleTexts[2], state=DISABLED, width=5).grid(column=0, row=2) Entry(infoFrame, textvariable=self._throttleTexts[1], state=DISABLED, width=5).grid(column=1, row=2) #Angles Label(infoFrame, text="Angles").grid(column=0, row=3, sticky="WE") self._angleTexts = [StringVar(),StringVar(),StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._angleTexts[index], state=DISABLED, width=5).grid(column=index, row=4) #Accels Label(infoFrame, text="Accels").grid(column=0, row=5, sticky="WE") self._accelTexts = [StringVar(),StringVar(),StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._accelTexts[index], state=DISABLED, width=5).grid(column=index, row=6) #Speeds Label(infoFrame, text="Speeds").grid(column=0, row=7, sticky="WE") self._speedTexts = [StringVar(),StringVar(),StringVar()] for index in range(3): Entry(infoFrame, textvariable=self._speedTexts[index], state=DISABLED, width=5).grid(column=index, row=8) #Height Label(infoFrame, text="Height").grid(column=0, row=9, sticky="E") self._heightText = StringVar() Entry(infoFrame, textvariable=self._heightText, state=DISABLED, width=5).grid(column=1, row=9) #Loop rate Label(infoFrame, text="Loop @").grid(column=0, row=10, sticky="E") self._loopRateText = StringVar() Entry(infoFrame, textvariable=self._loopRateText, state=DISABLED, width=5).grid(column=1, row=10) Label(infoFrame, text="Hz").grid(column=2, row=10, sticky="W") #control controlFrame = tkFrame(self) controlFrame.grid(column=0, row=1, sticky="W") self._throttle = DoubleVar() if Cockpit.THROTTLE_BY_USER: self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=0.0, \ tickinterval=0, variable=self._throttle, resolution=Cockpit.THROTTLE_RESOLUTION, \ length=200, showvalue=1, \ state=DISABLED, command=self._onThrustScaleChanged) else: self._thrustScale = Scale(controlFrame, orient=VERTICAL, from_=100.0, to=-100.0, \ tickinterval=0, variable=self._throttle, \ length=200, showvalue=1, \ state=DISABLED, command=self._onThrustScaleChanged) self._thrustScale.bind("<Double-Button-1>", self._onThrustScaleDoubleButton1, "+") self._thrustScale.grid(column=0) self._shiftCanvas = Canvas(controlFrame, bg="white", height=400, width=400, \ relief=SUNKEN) self._shiftCanvas.bind("<Button-1>", self._onMouseButton1) #self._shiftCanvas.bind("<ButtonRelease-1>", self._onMouseButtonRelease1) self._shiftCanvas.bind("<B1-Motion>", self._onMouseButton1Motion) self._shiftCanvas.bind("<Double-Button-1>", self._onMouseDoubleButton1) self._shiftCanvas.bind("<Button-3>", self._onMouseButton3) #self._shiftCanvas.bind("<ButtonRelease-3>", self._onMouseButtonRelease3) self._shiftCanvas.bind("<B3-Motion>", self._onMouseButton3Motion) self._shiftCanvas.grid(row=0,column=1, padx=2, pady=2) self._shiftCanvas.create_oval(1, 1, 400, 400, outline="#ff0000") self._shiftCanvas.create_line(200, 2, 200, 400, fill="#ff0000") self._shiftCanvas.create_line(2, 200, 400, 200, fill="#ff0000") self._shiftMarker = self._shiftCanvas.create_oval(196, 196, 204, 204, outline="#0000ff", fill="#0000ff") self._yaw = DoubleVar() self._yawScale = Scale(controlFrame, orient=HORIZONTAL, from_=-100.0, to=100.0, \ tickinterval=0, variable=self._yaw, \ length=200, showvalue=1, \ command=self._onYawScaleChanged) self._yawScale.bind("<Double-Button-1>", self._onYawScaleDoubleButton1, "+") self._yawScale.grid(row=1, column=1) self._controlKeyActive = False #PID calibration pidCalibrationFrame = tkFrame(self) pidCalibrationFrame.grid(column=0, row=2, sticky="WE"); self._pidSelected = StringVar() self._pidSelected.set("--") self._pidListBox = OptionMenu(pidCalibrationFrame, self._pidSelected, "--", \ Cockpit.KEY_ANG_SPEED, Cockpit.KEY_ANGLES, Cockpit.KEY_ACCEL, \ command=self._onPidListBoxChanged) self._pidListBox.pack(side=LEFT, padx=2) self._pidListBox.config(width=10) self._axisSelected = StringVar() self._axisSelected.set("--") self._axisListBox = OptionMenu(pidCalibrationFrame, self._axisSelected, "--", "X", "Y", "Z", \ command=self._onAxisListBoxChanged) self._axisListBox.pack(side=LEFT, padx=2) self._axisListBox.config(state=DISABLED) Label(pidCalibrationFrame, text="P").pack(side=LEFT, padx=(14, 2)) self._pidPString = StringVar() self._pidPString.set("0.00") self._pidPSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \ textvariable=self._pidPString, command=self._onPidSpinboxChanged) self._pidPSpinbox.pack(side=LEFT, padx=2) Label(pidCalibrationFrame, text="I").pack(side=LEFT, padx=(14, 2)) self._pidIString = StringVar() self._pidIString.set("0.00") self._pidISpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \ textvariable=self._pidIString, command=self._onPidSpinboxChanged) self._pidISpinbox.pack(side=LEFT, padx=2) Label(pidCalibrationFrame, text="D").pack(side=LEFT, padx=(14, 2)) self._pidDString = StringVar() self._pidDString.set("0.00") self._pidDSpinbox = Spinbox(pidCalibrationFrame, width=5, from_=0.0, to=10000.0, increment=0.01, state=DISABLED, \ textvariable=self._pidDString, command=self._onPidSpinboxChanged) self._pidDSpinbox.pack(side=LEFT, padx=2) #debug debugFrame = tkFrame(self) debugFrame.grid(column=0, row=3, sticky="WE") self._debugMsg = Message(debugFrame, anchor="nw", justify=LEFT, relief=SUNKEN, width=300) self._debugMsg.pack(fill=BOTH, expand=1) def _start(self): self._readDroneConfig() if Cockpit.JOYSTICK_ENABLED: self._joystickManager = JoystickManager.getInstance() self._joystickManager.start() joysticks = self._joystickManager.getJoysticks() if len(joysticks) != 0: self._joystick = joysticks[0] self._joystick.onAxisChanged += self._onJoystickAxisChanged self._joystick.onButtonPressed += self._onJoystickButtonPressed else: self._joystick = None def _onJoystickAxisChanged(self, sender, index): if self._started.get() and sender == self._joystick: axisValue = self._joystick.getAxisValue(index) if index == 0: self._yaw.set(axisValue) self._updateTarget() elif index == 1 and not Cockpit.THROTTLE_BY_USER: thrust = -axisValue self._throttle.set(thrust) self._updateTarget() elif index == 2 and Cockpit.THROTTLE_BY_USER: rowThrottle = (axisValue + 100.0)/2.0 if rowThrottle < 10.0: throttle = rowThrottle * 6.0 elif rowThrottle < 90.0: throttle = 60.0 + ((rowThrottle - 10.0) / 8.0) else: throttle = 70.0 + (rowThrottle - 90.0) * 3.0 self._throttle.set(throttle) self._sendThrottle() elif index == 3: x = 196 + axisValue * 2 lastCoords = self._shiftCanvas.coords(self._shiftMarker) coords = (x, lastCoords[1]) self._plotShiftCanvasMarker(coords) elif index == 4: y = 196 + axisValue * 2 lastCoords = self._shiftCanvas.coords(self._shiftMarker) coords = (lastCoords[0], y) self._plotShiftCanvasMarker(coords) def _onJoystickButtonPressed(self, sender, index): if sender == self._joystick and index == 7: if self._started.get() == 0: self._startedCB.select() else: self._startedCB.deselect() # Tkinter's widgets seem not to be calling the event-handler # when they are changed programmatically. Therefore, the # even-handler is called explicitly here. self._startedCBChanged() def exit(self): self._link.send({"key": "close", "data": None}) self._stopUpdateInfoThread() self._link.close() if Cockpit.JOYSTICK_ENABLED: self._joystickManager.stop() self.quit() def _updateTarget(self): markerCoords = self._shiftCanvas.coords(self._shiftMarker) coords = ((markerCoords[0] + markerCoords[2]) / 2, (markerCoords[1] + markerCoords[3]) / 2) self._target[0] = float(coords[1] - 200) / 2.0 # X-axis angle / X-axis acceleration self._target[1] = float(coords[0] - 200) / 2.0 # Y-axis angle / Y-axis acceleration #Remote control uses clockwise angle, but the drone's referece system uses counter-clockwise angle self._target[2] = -self._yaw.get() # Z-axis angular speed # Z-axis acceleration (thrust). Only when the motor throttle is not controlled by user directly if Cockpit.THROTTLE_BY_USER: self._target[3] = 0.0 else: self._target[3] = self._throttle.get() self._sendTarget() def _keyDown(self, event): if event.keysym == "Escape": self._throttle.set(0) self._started.set(0) self._thrustScale.config(state=DISABLED) self._stopUpdateInfoThread() self._sendIsStarted() elif event.keysym.startswith("Control"): self._controlKeyActive = True elif not self._controlKeysLocked and self._controlKeyActive: if event.keysym == "Up": self._thrustScaleUp() elif event.keysym == "Down": self._thrustScaleDown() elif event.keysym == "Left": self._yawLeft() elif event.keysym == "Right": self._yawRight() elif event.keysym == "space": self._yawReset() if not Cockpit.THROTTLE_BY_USER: self._thrustReset() elif not self._controlKeysLocked and not self._controlKeyActive: if event.keysym == "Up": self._moveShiftCanvasMarker((0,-5)) elif event.keysym == "Down": self._moveShiftCanvasMarker((0,5)) elif event.keysym == "Left": self._moveShiftCanvasMarker((-5,0)) elif event.keysym == "Right": self._moveShiftCanvasMarker((5,0)) elif event.keysym == "space": self._resetShiftCanvasMarker() def _keyUp(self, eventArgs): if eventArgs.keysym.startswith("Control"): self._controlKeyActive = False def _onMouseButton1(self, eventArgs): self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _onMouseButtonRelease1(self, eventArgs): self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204) def _limitCoordsToSize(self, coords, size, width): maxSize = size-(width/2.0) minSize = -(width/2.0) if coords[0] > maxSize: x = maxSize elif coords[0] < minSize: x = minSize else: x = coords[0] if coords[1] > maxSize: y = maxSize elif coords[1] < minSize: y = minSize else: y = coords[1] return (x,y) def _plotShiftCanvasMarker(self, coords): coords = self._limitCoordsToSize(coords, 400, 8) self._shiftCanvas.coords(self._shiftMarker, coords[0], coords[1], coords[0] + 8, coords[1] + 8) self._updateTarget() def _moveShiftCanvasMarker(self, shift): lastCoords = self._shiftCanvas.coords(self._shiftMarker) newCoords = (lastCoords[0] + shift[0], lastCoords[1] + shift[1]) self._plotShiftCanvasMarker(newCoords) def _resetShiftCanvasMarker(self): self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204) self._updateTarget() def _onMouseButton1Motion(self, eventArgs): deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1]) self._moveShiftCanvasMarker(deltaCoords) self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _onMouseDoubleButton1(self, eventArgs): self._resetShiftCanvasMarker() def _onMouseButton3(self, eventArgs): self._lastMouseCoords = (eventArgs.x, eventArgs.y) self._mouseDirection = Cockpit.DIR_NONE def _onMouseButtonRelease3(self, eventArgs): self._shiftCanvas.coords(self._shiftMarker, 196, 196, 204, 204) def _onMouseButton3Motion(self, eventArgs): deltaCoords = (eventArgs.x - self._lastMouseCoords[0], eventArgs.y - self._lastMouseCoords[1]) if self._mouseDirection == Cockpit.DIR_NONE: if abs(deltaCoords[0]) > abs(deltaCoords[1]): self._mouseDirection = Cockpit.DIR_HORIZONTAL else: self._mouseDirection = Cockpit.DIR_VERTICAL if self._mouseDirection == Cockpit.DIR_HORIZONTAL: deltaCoords = (deltaCoords[0], 0) else: deltaCoords = (0, deltaCoords[1]) self._moveShiftCanvasMarker(deltaCoords) self._lastMouseCoords = (eventArgs.x, eventArgs.y) def _thrustScaleUp(self): #TODO: 20160526 DPM: El valor de incremento de aceleración (1.0) puede ser muy alto if self._started.get(): newValue = self._thrustScale.get() \ + (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0) self._thrustScale.set(newValue) self._updateTarget() def _thrustScaleDown(self): #TODO: 20160526 DPM: El valor de decremento de aceleración (1.0) puede ser muy alto if self._started.get(): newValue = self._thrustScale.get() \ - (Cockpit.THROTTLE_RESOLUTION if Cockpit.THROTTLE_BY_USER else 1.0) self._thrustScale.set(newValue) self._updateTarget() def _thrustReset(self): if self._started.get(): self._thrustScale.set(0.0) self._updateTarget() def _onThrustScaleDoubleButton1(self, eventArgs): self._thrustReset() return "break" def _yawRight(self): newValue = self._yaw.get() + 1 self._yaw.set(newValue) self._updateTarget() def _yawLeft(self): newValue = self._yaw.get() - 1 self._yaw.set(newValue) self._updateTarget() def _yawReset(self): self._yaw.set(0) self._updateTarget() def _onMouseWheelUp(self, eventArgs): if not self._controlKeyActive: self._thrustScaleUp() else: self._yawRight() def _onMouseWheelDown(self, eventArgs): if not self._controlKeyActive: self._thrustScaleDown() else: self._yawLeft() def _onMouseWheel(self, eventArgs): factor = eventArgs.delta/(1200.0 if Cockpit.THROTTLE_BY_USER and not self._controlKeyActive else 120.0) if not self._controlKeyActive: if self._started.get(): newValue = self._thrustScale.get() + factor self._thrustScale.set(newValue) self._updateTarget() else: newValue = self._yaw.get() + factor self._yaw.set(newValue) self._updateTarget() def _onYawScaleChanged(self, eventArgs): self._updateTarget() def _onYawScaleDoubleButton1(self, eventArgs): self._yawReset() return "break" def _startedCBChanged(self): if not self._started.get(): self._throttle.set(0) self._thrustScale.config(state=DISABLED) #self._integralsCB.config(state=DISABLED) self._stopUpdateInfoThread() else: self._thrustScale.config(state="normal") #self._integralsCB.config(state="normal") self._startUpdateInfoThread() self._sendIsStarted() # def _integralsCBChanged(self): # # self._link.send({"key": "integrals", "data":self._integralsEnabled.get() != 0}) # def _onThrustScaleChanged(self, eventArgs): if Cockpit.THROTTLE_BY_USER: self._sendThrottle() else: self._updateTarget() def _sendThrottle(self): self._link.send({"key": "throttle", "data": self._throttle.get()}) def _sendTarget(self): self._link.send({"key": "target", "data": self._target}) def _sendIsStarted(self): isStarted = self._started.get() != 0 self._link.send({"key": "is-started", "data": isStarted}) def _sendPidCalibrationData(self): if self._pidSelected.get() != "--" and self._axisSelected.get() != "--": pidData = { "pid": self._pidSelected.get(), "axis": self._axisSelected.get(), "p": float(self._pidPSpinbox.get()), "i": float(self._pidISpinbox.get()), "d": float(self._pidDSpinbox.get())} self._link.send({"key": "pid-calibration", "data": pidData}) def _updatePidCalibrationData(self): pid = self._pidSelected.get() axis = self._axisSelected.get() if pid != "--" and axis != "--": self._pidConstants[pid][axis]["P"] = float(self._pidPSpinbox.get()) self._pidConstants[pid][axis]["I"] = float(self._pidISpinbox.get()) self._pidConstants[pid][axis]["D"] = float(self._pidDSpinbox.get()) def _readDroneConfig(self): self._link.send({"key": "read-drone-config", "data": None}, self._onDroneConfigRead) def _readDroneState(self): if not self._readingState: self._readingState = True self._link.send({"key": "read-drone-state", "data": None}, self._onDroneStateRead) def _readPidConfigItem(self, message, cockpitKey, axises, configKeys): for i in range(len(axises)): for j in range(len(Cockpit.PID_KEYS)): self._pidConstants[cockpitKey][axises[i]][Cockpit.PID_KEYS[j]] = message[configKeys[j]][i] def _onDroneConfigRead(self, message): #TODO Show current configuration within the GUI (at least relevant settings) if message: #Angle-speeds self._readPidConfigItem(message, Cockpit.KEY_ANG_SPEED, ["X", "Y", "Z"], \ [Configuration.PID_ANGLES_SPEED_KP, \ Configuration.PID_ANGLES_SPEED_KI, \ Configuration.PID_ANGLES_SPEED_KD]) #Angles self._readPidConfigItem(message, Cockpit.KEY_ANGLES, ["X", "Y"], \ [Configuration.PID_ANGLES_KP, \ Configuration.PID_ANGLES_KI, \ Configuration.PID_ANGLES_KD]) #Accels self._readPidConfigItem(message, Cockpit.KEY_ACCEL, ["X", "Y", "Z"], \ [Configuration.PID_ACCEL_KP, \ Configuration.PID_ACCEL_KI, \ Configuration.PID_ACCEL_KD]) def _onDroneStateRead(self, state): if state: for index in range(4): self._throttleTexts[index].set("{0:.3f}".format(state["_throttles"][index])) for index in range(3): self._accelTexts[index].set("{0:.3f}".format(state["_accels"][index])) self._angleTexts[index].set("{0:.3f}".format(state["_angles"][index])) currentPeriod = state["_currentPeriod"] if currentPeriod > 0.0: freq = 1.0/currentPeriod self._loopRateText.set("{0:.3f}".format(freq)) else: self._loopRateText.set("--") else: self._stopUpdateInfoThread() self._readingState = False def _onPidSpinboxChanged(self): self._updatePidCalibrationData() self._sendPidCalibrationData() def _onPidListBoxChanged(self, pid): self._axisSelected.set("--") self._pidPString.set("--") self._pidIString.set("--") self._pidDString.set("--") self._pidPSpinbox.config(state=DISABLED) self._pidISpinbox.config(state=DISABLED) self._pidDSpinbox.config(state=DISABLED) self._selectedPidConstats = pid if pid == "--": self._axisListBox.config(state=DISABLED) self._controlKeysLocked = False else: self._axisListBox.config(state="normal") self._controlKeysLocked = True def _onAxisListBoxChanged(self, axis): if axis == "--" or (self._selectedPidConstats == Cockpit.KEY_ANGLES and axis == "Z"): self._pidPString.set("--") self._pidIString.set("--") self._pidDString.set("--") self._pidPSpinbox.config(state=DISABLED) self._pidISpinbox.config(state=DISABLED) self._pidDSpinbox.config(state=DISABLED) self._controlKeysLocked = axis != "--" else: self._pidPString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["P"])) self._pidIString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["I"])) self._pidDString.set("{:.2f}".format(self._pidConstants[self._selectedPidConstats][axis]["D"])) self._pidPSpinbox.config(state="normal") self._pidISpinbox.config(state="normal") self._pidDSpinbox.config(state="normal") self._controlKeysLocked = True def _updateInfo(self): while self._updateInfoThreadRunning: self._readDroneState() time.sleep(1.0) def _startUpdateInfoThread(self): self._updateInfoThreadRunning = True if not self._updateInfoThread.isAlive(): self._updateInfoThread.start() def _stopUpdateInfoThread(self): self._updateInfoThreadRunning = False if self._updateInfoThread.isAlive(): self._updateInfoThread.join()
def refreshWidget(self) : #print "refresh" self.card_win.pack_forget() #Card window self.card_win = PanedWindow(self.card_win.master, orient=VERTICAL) self.card_win.pack(side=TOP, expand=True, fill=BOTH, pady=2, padx=2) #Create the name zone name_zone=PanedWindow(self.card_win, orient=HORIZONTAL) name = StringVar() name.set(self.name) def modifName(*args) : self.name=name.get() name.trace("w", modifName) name_wid=Entry(name_zone, width=30,textvariable=name) name_wid.pack() name_zone.add(name_wid) #Create the cost ad star stringvar #print int(floor(self.getCost())) self.cost=StringVar() self.stars=StringVar() cost_wid=Label(None, textvariable=self.cost, background='red',width=5, anchor=W) star_wid=Label(None, textvariable=self.stars, background='blue', anchor=E) self.cost.set(str(int(floor(self.getCost())))) self.stars.set("*"*self.getStars()) #Add them in name zone name_zone.add(cost_wid) name_zone.add(star_wid) #Create an Image Zone image_zone=Button(self.card_win, command=self.choosePhoto) if hasattr(self,"photofile") and self.photofile : print "Image: ",self.photofile try : img=Image.open(self.photofile) except : decomp=self.photofile.split('/') for i in range(1,6) : try : fname="/".join(decomp[-i:]) print "try to open",fname img=Image.open(fname) self.photofile=fname break except : self.photofile=None if self.photofile : w, h = img.size if w>300 or h>200 : img=img.resize((w/2,h/2),Image.LINEAR) image_zone.image=ImageTk.PhotoImage(img) image_zone.config(image=image_zone.image) #print "IMAGE CHANGED" else : from os import path name=self.name.replace(" ","_") if path.isfile("Cards/"+name+".png") : image_zone.config(text='image can be taken from\n'+"Cards/"+name+".png",background='white',anchor=CENTER) else : image_zone.config(text='clic to choose image',background='white',anchor=CENTER) image_zone.pack # POWER ZONE power_zone=PanedWindow(self.card_win, orient=VERTICAL) #fenetre=self.card_win.master def removePowerCreator(px) : def removePower(*args) : #print 'avant',list_pow self.bonus.remove(px) #print 'apres',list_pow #self.card_win.pack_forget() self.refreshWidget() return removePower for p in self.bonus : powline = PanedWindow(self.card_win, orient=HORIZONTAL) pow_wid=p.initWidget(powline) powline.add(pow_wid) removepow=Button(powline, text="X", command=removePowerCreator(p), anchor=E) removepow.pack() powline.add(removepow) power_zone.add(powline) def addPower(*args) : name=addBonus.get() print "added :",name import cardPowers self.bonus+=[eval('cardPowers.'+name+'()')] self.bonus[-1].parent=self.bonus self.bonus[-1].card=self #self.card_win.pack_forget() self.refreshWidget() #Add bonus Option menu addBonus = StringVar(power_zone) addBonus.set("add bonus") # default value if not self.pv: addBonus_wid = getSpellMenu(power_zone, addBonus) else: addBonus_wid = getBonusMenu(power_zone, addBonus) addBonus.trace('w', addPower) if self.pv>0 or len(self.bonus)==0 : addBonus_wid.pack() #Add this to power zone power_zone.add(addBonus_wid) #Create save zone save_zone = PanedWindow(self.card_win, orient=HORIZONTAL) if self.monster_type != "all": save_wid = Button(save_zone, text="Save", command=self.postAndSave) else: save_wid = Button(save_zone, text="---", command=None) save_wid.pack() #Create the open button save_zone.pack() if Card.monster_list.keys(): self.opening = StringVar(save_zone) self.opening.set("Open") choice = Card.monster_list.keys() choice.sort() #print all_monsters.keys() open_wid = OptionMenu(save_zone, self.opening,*choice) self.opening.trace('w', self.Open) open_wid.pack() save_zone.add(open_wid) if Card.monster_list.keys(): self.delete = StringVar(save_zone) self.delete.set("Delete") choice = Card.monster_list.keys() choice.sort() delete_wid = OptionMenu(save_zone, self.delete,*choice) self.delete.trace('w', self.clicDelete) delete_wid.pack() save_zone.add(delete_wid) #Create the type button self.category = StringVar(save_zone) self.category.set(self.monster_type) choice = [t[t.index("\\")+1:t.index("_monsters.sav")] for t in glob.glob("CardFiles/*_monsters.sav")] if "recup" in choice: choice.remove("recup") #print all_monsters.keys() category_wid = OptionMenu(save_zone, self.category,*choice) self.category.trace('w', self.setFile) category_wid.pack() #Add it to save zone save_zone.add(save_wid) save_zone.add(category_wid) #Create a new Strength zone for att and pv strength_zone=PanedWindow(self.card_win, orient=HORIZONTAL) att=StringVar() att.set(str(self.att)) pv=StringVar() ; pv.set(str(self.pv)) def modifiedAttPv(*args) : self.pv=int(pv.get()) if self.pv<1 and self.is_spell==False : if len(self.bonus)==0 : self.is_spell=True self.refreshWidget() else : self.pv=1 self.refreshWidget() if self.pv>0 and self.is_spell==True : if len(self.bonus)==0 : self.is_spell=False self.refreshWidget() else : self.pv=0 self.refreshWidget() self.att=int(att.get()) self.getCost() att_wid = Spinbox(strength_zone, from_=0, to=1000,textvariable=att,command=modifiedAttPv) att_wid.pack() strength_zone.add(att_wid) strength_zone.add(Label(strength_zone, text=' ', background='white', anchor=CENTER)) pv_wid = Spinbox(strength_zone, from_=0, to=1000,textvariable=pv,command=modifiedAttPv) pv_wid.pack() strength_zone.add(pv_wid) #Put it all in window self.card_win.add(name_zone) self.card_win.add(image_zone) self.card_win.add(power_zone) self.card_win.add(strength_zone) self.card_win.add(save_zone) self.card_win.pack()
class ChargenColor: def __init__(self, parent): self.colorNegative = [] self.colorNeutral = [] self.colorPositive = [] self.scaleNegative = 0.0 self.scalePositive = 0.0 self.cNegative = '#ff0000' self.cNeutral = '#000000' self.cPositive = '#0000ff' self.minNegativeLbl = Label(rootC, text='Min Found: -') self.maxPositiveLbl = Label(rootC, text='Max Found: -') self.scaleLbl = Label(rootC, text='Scale: - to -') self.sclSelectPositive = Spinbox(rootC) self.sclSelectPositive.insert(0, 0.0) self.sclSelectNegative = Spinbox(rootC) self.sclSelectNegative.insert(0, 0.0) self.buttonNegativeCharge = Button( rootC, text='Negative Charge Color', command=self.chooseNegativeCharge) self.buttonNeutralCharge = Button( rootC, text='Neutral Charge Color', command=self.chooseNeutralCharge) self.buttonPositiveCharge = Button( rootC, text='Positive Charge Color', command=self.choosePositiveCharge) self.buttonBG = Button( rootC, text='Background Color', command=self.chooseBackground) self.buttonUpdateColor = Button( rootC, text='Update', command=self.updateColor) self.title = Label(rootC, text="Select your colors") self.buttonClose = Button(rootC, text="Close", command=rootC.destroy) self.buttonBG.pack() self.title.pack() self.buttonNegativeCharge.pack() self.buttonNeutralCharge.pack() self.buttonPositiveCharge.pack() self.minNegativeLbl.pack() self.maxPositiveLbl.pack() self.scaleLbl.pack() self.sclSelectNegative.pack() self.sclSelectPositive.pack() self.buttonUpdateColor.pack() self.buttonClose.pack() def chooseNegativeCharge(self): self.colorNegative = askcolor( color=self.cNegative, title="Negative Charge Color") self.buttonNegativeCharge.config(fg=self.colorNegative[1]) self.cNegative = self.colorNegative[1] def chooseNeutralCharge(self): self.colorNeutral = askcolor( color=self.cNeutral, title="Neutral Charge Color") self.buttonNeutralCharge.config(fg=self.colorNeutral[1]) self.cNeutral = self.colorNeutral[1] def choosePositiveCharge(self): self.colorPositive = askcolor( color=self.cPositive, title="Positive Charge Color") self.buttonPositiveCharge.config(fg=self.colorPositive[1]) self.cPositive = self.colorPositive[1] def chooseBackground(self): bgcolor = askcolor( color=self.cPositive, title="Positive Charge Color") cmd.set_color("bg_chargy_color", bgcolor[0]) cmd.bg_color("bg_chargy_color") def updateColor(self): selection = 'all' stored.atoms_charge = [] stored.atoms_colors = [] cmd.map_new('chargyc_map', selection="(all)") if not self.colorNeutral: tkMessageBox.showerror("Error", "Set Neutral Color, Please") return if not self.colorNegative: tkMessageBox.showerror("Error", "Set Negative Color, Please") return if not self.colorPositive: tkMessageBox.showerror("Error", "Set Positive Color, Please") return cmd.iterate_state(1, '(' + selection + ')', 'stored.atoms_charge.append(partial_charge)') _i = 0 minValue = None maxValue = None while _i < len(stored.atoms_charge): color = [] if _i == 0: maxValue = stored.atoms_charge[_i] minValue = stored.atoms_charge[_i] if(stored.atoms_charge[_i] > maxValue): maxValue = stored.atoms_charge[_i] if stored.atoms_charge[_i] < minValue: minValue = stored.atoms_charge[_i] _i += 1 self.minNegativeLbl["text"] = 'Min Found: ' + str(round(minValue, 3)) self.maxPositiveLbl["text"] = 'Max Found: ' + str(round(maxValue, 3)) if(self.scaleNegative == 0.0 and self.scalePositive == 0.0): self.scaleNegative = round(minValue, 3) self.scalePositive = round(maxValue, 3) self.sclSelectNegative.delete(0, "end") self.sclSelectPositive.delete(0, "end") self.sclSelectNegative.insert(0, round(minValue, 3)) self.sclSelectPositive.insert(0, round(maxValue, 3)) else: self.scaleNegative = float(self.sclSelectNegative.get()) self.scalePositive = float(self.sclSelectPositive.get()) minValue = float(self.sclSelectNegative.get()) maxValue = float(self.sclSelectPositive.get()) self.scaleLbl["text"] = 'Scale: ' + str( self.scaleNegative) + ' to ' + str(self.scalePositive) middleValue = 0 if(maxValue < 0): maxValue = 0 if(minValue > 0): minValue = 0 _i = 0 while _i < len(stored.atoms_charge): color = [] cmd.set_color("neutral_color", self.colorNeutral[0]) cmd.set_color("positive_color", self.colorPositive[0]) cmd.set_color("negative_color", self.colorNegative[0]) if(stored.atoms_charge[_i] >= middleValue): if(stored.atoms_charge[_i] == middleValue): cmd.set_color(str(_i) + "_color", self.colorNeutral[0]) else: cmd.set_color(str(_i) + "_color", self.getColor( self.colorNeutral[0], self.colorPositive[0], maxValue, stored.atoms_charge[_i] if stored.atoms_charge[_i] < maxValue else maxValue)) else: cmd.set_color(str(_i) + "_color", self.getColor( self.colorNeutral[0], self.colorNegative[0], abs(minValue), abs(stored.atoms_charge[_i]) if abs(stored.atoms_charge[_i]) < abs(minValue) else abs(minValue))) index = cmd.get_color_index(str(_i) + "_color") stored.atoms_colors.append(index) _i += 1 cmd.alter_state(1, '(' + selection + ')', "color=stored.atoms_colors.pop(0)") cmd.ramp_new('chargy_ramp', 'chargyc_map', range=[self.scaleNegative, ((self.scaleNegative+self.scalePositive)/2.0), self.scalePositive], color=['negative_color', 'neutral_color', 'positive_color']) def getColor(self, color, colorMax, step, index): colorStep = [0, 0, 0] colorStep[0] = ((colorMax[0]-color[0])/step) colorStep[1] = ((colorMax[1]-color[1])/step) colorStep[2] = ((colorMax[2]-color[2])/step) return [ 1.0 if (color[0] + (colorStep[0]*index)) / 255.0 >= 1 else (color[0] + (colorStep[0]*index))/255.0, 1.0 if (color[1] + (colorStep[1]*index)) / 255.0 >= 1 else (color[1] + (colorStep[1]*index))/255.0, 1.0 if (color[2] + (colorStep[2]*index)) / 255.0 >= 1 else (color[2] + (colorStep[2]*index))/255.0 ]
class AntroidGUI(Tk): def __init__(self): Tk.__init__(self) self.protocol("WM_DELETE_WINDOW", self.myquit) self.etat = True self.readstate = True self.title("Antroid Map") self.turns = {} self.selectTurn = -1 self.caselength = 10 self.CaseMarge = 20 self.var = StringVar() self.initGUI() def initGUI(self): frame = Frame(self, width =630, height = 500) self.panel = PanedWindow(frame, orient=HORIZONTAL) self.LeftFrame(self.panel) self.RightFrame(self.panel) self.panel.add(self.LFrame) self.panel.add(self.RFrame) self.panel.pack() frame.pack() def LeftFrame(self, parent): self.LFrame=Frame(parent, width = 500, height = 500) self.maptroid = Canvas(self.LFrame,bg='black',width=500,height=500) if self.selectTurn >= 0: self.printMap() self.maptroid.pack() self.LFrame.pack() def RightFrame(self, parent): self.RFrame = Frame(parent, width = 130, height = 500) if self.selectTurn >= 0: self.printInfo() self.FrameInfo = None self.updateT = True self.RFrame.pack() def setreadstate(self, readstate): self.readstate = readstate def addTurn(self, turnnumber, turnvalue): self.turns[turnnumber] = turnvalue self.updateGui(turnnumber) return self.etat def updateGui(self, turn): self.selectTurn = turn self.updateMap() self.updateInfo() def updateMap(self): self.maptroid.delete(ALL) self.printMap() def updateInfo(self): if self.FrameInfo: if self.updateT: self.frameT.destroy() self.printTurn() self.frameAnts.destroy() self.frameAnt.destroy() self.printAnts() self.updateT = True else: self.printInfo() def updateSpin_turn(self): turn = int(self.Spin_T.get()) self.updateT = False self.updateGui(turn) def validateTurn(self, event): try: turn = int(self.Spin_T.get()) except ValueError: turn = self.selectTurn if turn in self.turns.keys(): if turn != self.selectTurn: self.updateT = False self.updateGui(turn) else: turn = self.selectTurn def choiceAnt(self,event): i = self.listbox.curselection() id_a = self.listbox.get(i) self.frameAnt.destroy() self.printInfoAnt(int(id_a)) def printInfo(self): self.FrameInfo=Frame(self.RFrame) self.printTurn() self.printAnts() self.FrameInfo.pack() def printTurn(self): frameS = PanedWindow(self.FrameInfo, orient=HORIZONTAL) turns = Label(frameS, text="Tour :") self.var.set(str(self.selectTurn)) self.Spin_T = Spinbox(frameS, values=self.turns.keys(), command = self.updateSpin_turn ,textvariable=self.var) self.Spin_T.bind('<Return>', self.validateTurn) turns.pack() self.Spin_T.pack() frameS.add(turns) frameS.add(self.Spin_T) frameS.pack() self.frameT = frameS def printAnts(self): frameAnts = Frame(self.FrameInfo) Text_A = Label(frameAnts, text="Fourmie :") s1 = Scrollbar(frameAnts) l1 = Listbox(frameAnts) id_ants = self.checkAnts() for i in id_ants: l1.insert(i, str(i)) s1.config(command = l1.yview) l1.config(yscrollcommand = s1.set) l1.bind('<ButtonRelease-1>',self.choiceAnt) self.listbox = l1 Text_A.pack(side = TOP) l1.pack(side = LEFT) s1.pack(side = RIGHT) frameAnts.pack() self.printInfoAnt(id_ants[0]) self.frameAnts = frameAnts def printInfoAnt(self, i): self.frameAnt = PanedWindow(self.FrameInfo, orient=VERTICAL) t_Ant = Label(self.frameAnt, text="Information Ant : %d" %(i)) (t_brain,t_energie,t_acide) = self.getInfoAnt(i) a_b = Label(self.frameAnt, text=t_brain) a_e = Label(self.frameAnt, text=t_energie) a_a = Label(self.frameAnt, text=t_acide) t_Ant.pack(side = TOP) self.frameAnt.add(t_Ant) self.frameAnt.add(a_b) self.frameAnt.add(a_e) self.frameAnt.add(a_a) self.frameAnt.pack() def printMap(self): turn = self.turns[self.selectTurn] # Information on this turn config = turn[0] Yants = turn[1] EAnts = turn[2] InitMap = turn[3] Cases = turn[4] (MaxX,MaxY,N) = InitMap self.MinX = 0 self.MinY = 0 MaxX_map = MaxX * self.caselength + (self.CaseMarge *2) MaxY_map = MaxY * self.caselength + (self.CaseMarge *2) #configure canvas self.maptroid.config(scrollregion=(0,0,MaxX_map,MaxY_map)) x1 = self.CaseMarge y1 = self.CaseMarge x2 = MaxX * self.caselength + self.CaseMarge y2 = MaxY * self.caselength +self.CaseMarge self.maptroid.create_rectangle(x1, y1, x2, y2, fill="white") # affiche case for case in Cases: self.printCase(case) # affiche your ants for ant in Yants: # nb A : Your Ant 'ID X Y DX DY E A B' (id_a,x,y,dx,dy,e,a,b) = ant self.printAnt((x,y,dx,dy,b)) # affiche enemy ants for ant in EAnts: self.printAnt(ant) #to move map self.maptroid.bind('<ButtonPress-1>',self.grab) self.maptroid.bind('<B1-Motion>',self.drag) self.maptroid.bind('<MouseWheel>',self.mapZoom) self.maptroid.bind("<Button-4>", self.mapZoom) self.maptroid.bind("<Button-5>", self.mapZoom) def printCase(self, case): (x,y,c,s) = case (x1, y1, x2, y2) = self.getPoint(x, y) color = COLOR[c][s] if c%2 == 0: self.maptroid.create_rectangle(x1, y1, x2, y2, fill=color) else: self.maptroid.create_rectangle(x1, y1, x2, y2, fill=COLOR[GRASS][s]) self.maptroid.create_oval(x1, y1, x2, y2, fill=color) def printAnt(self, ant): (x,y,dx,dy,brain) = ant (x1, y1, x2, y2) = self.getPoint(x, y) self.maptroid.create_oval(x1, y1, x2, y2, fill="red4") def getPoint(self, x, y): x1 = (x - self.MinX) * self.caselength + self.CaseMarge y1 = (y - self.MinY) * self.caselength + self.CaseMarge x2 = x1 + self.caselength y2 = y1 + self.caselength return (x1, y1, x2, y2) def grab(self,event): self._y = event.y self._x = event.x def drag(self, event): self.maptroid.yview('scroll',self._y-event.y,'units') self.maptroid.xview('scroll',self._x-event.x,'units') self._y = event.y self._x = event.x def mapZoom(self, event): # respond to Linux or Windows wheel event if event.num == 5 or event.delta == -120: self.caselength -= 5 self.caselength = max(self.caselength, 10) if event.num == 4 or event.delta == 120: self.caselength += 5 self.caselength = min(self.caselength, 40) self.CaseMarge = self.caselength self.updateMap() def getInfoAnt(self,id_ant): turn = self.turns[self.selectTurn] YAnt = turn[1] B_Text = "Brain :" E_Text = "Energie :" A_Text = "Acide :" for ant in YAnt: (id_a,x,y,dx,dy,e,a,b) = ant if b != 1 : b = 0 if(id_ant == id_a): B_Text = "Brain : " + BRAIN[b] E_Text = "Energie : %d" % (e) A_Text = "Acide : %d" % (a) return (B_Text,E_Text,A_Text) def checkAnts(self): turn = self.turns[self.selectTurn] YAnt = turn[1] ants_id = [] for ant in YAnt: (id_a,x,y,dx,dy,e,a,b) = ant ants_id.append(id_a) return ants_id def myquit(self): self.etat = False if not self.readstate: self.quit()