class App(Frame): def __init__(self, master, write_sockets, read_socket): """ write_sockets: list of 3 sockets already connected to the robots """ Frame.__init__(self, master) # game_state contains all the real time information about the game self.game_state = State(home_robots=[ Robot(rid=0, team=1, color="blue", sock=write_sockets[0]), Robot(rid=1, team=1, color="red", sock=write_sockets[1]), Robot(rid=2, team=1, color="pink", sock=write_sockets[2]) ], away_robots=[ Robot(rid=0, team=2), Robot(rid=1, team=2), Robot(rid=2, team=2) ], ball=Ball()) self.master = master self.read_socket = read_socket # Threads for listening data and updating ui # self.listener = Thread(target=self.listen_data) # self.listener.start() self.dato_0 = Label(master, text="1", fg="Black", font=("Helvetica", 30), padx=100) self.dato_0.grid(column=0) self.instrucciones_0 = [] self.instrucciones_0.append( Button(master, text="Turn off", command=lambda: self.sendInstruction( "0", [self.game_state.home_robots[0].socket]), font=('Helvetica', 16))) self.instrucciones_0.append( Button(master, text="Turn on", command=lambda: self.sendInstruction( "1", [self.game_state.home_robots[0].socket]), font=('Helvetica', 16))) for i in self.instrucciones_0: i.grid(column=0) self.dato_1 = Label(master, text="1", fg="Black", font=("Helvetica", 30), padx=100) self.dato_1.grid(column=1) self.instrucciones_1 = [] self.instrucciones_1.append( Button(master, text="Turn off", command=lambda: self.sendInstruction( "0", [self.game_state.home_robots[1].socket]), font=('Helvetica', 16))) self.instrucciones_1.append( Button(master, text="Turn on", command=lambda: self.sendInstruction( "1", [self.game_state.home_robots[1].socket]), font=('Helvetica', 16))) for i in self.instrucciones_1: i.grid(column=1) self.dato_2 = Label(master, text="2", fg="Black", font=("Helvetica", 30), padx=100) self.dato_2.grid(column=2) self.instrucciones_2 = [] self.instrucciones_2.append( Button(master, text="Turn off", command=lambda: self.sendInstruction( "0", [self.game_state.home_robots[2].socket]), font=('Helvetica', 16))) self.instrucciones_2.append( Button(master, text="Turn on", command=lambda: self.sendInstruction( "1", [self.game_state.home_robots[2].socket]), font=('Helvetica', 16))) for i in self.instrucciones_2: i.grid(column=2) # Sends to all robots self.dato_3 = Label(master, text="ALL", fg="red", font=("Helvetica", 30, "bold"), padx=100) self.dato_3.grid(column=3) self.instrucciones_3 = [] self.instrucciones_3.append( Button(master, text="Turn off", command=lambda: self.sendInstruction( "0", [robot.socket for robot in self.game_state.home_robots]), font=('Helvetica', 16))) self.instrucciones_3.append( Button(master, text="Turn on", command=lambda: self.sendInstruction( "1", [robot.socket for robot in self.game_state.home_robots]), font=('Helvetica', 16))) for i in self.instrucciones_3: i.grid(column=3) # Match details score = f"{self.game_state.home_goals} - {self.game_state.away_goals}" self.score = Label(master, text=score, fg="green", font=("Helvetica", 40, "bold"), padx=150) self.score.grid(column=4) self.update_data() def listen(self): self.read_socket.listen(0) while True: client, addr = self.read_socket.accept() while True: content = client.recv(45) # Serialized protobuff data if len(content) == 0: break else: self.game_state.update(content) print("new message") client.close() def sendInstruction(self, instruction, sockets): """ instruction: string with instruction, full documentation is in notion. destinations: list with tuples (ip, port) """ for sock in sockets: sock.send(instruction.encode("utf-8")) print(f"sent {instruction} to {sock.getpeername()}.") def update_data(self): """ Updates GUI in real time based on data received by the sockets. 1.- Reads from ground and vision sockets 2.- Parses the data 3.- Updates self.game_state """ # TODO: (total sockets) - Benchmark read_socket (1) vs one socket for each reading (3) self.dato_0.configure(text=self.game_state.home_robots[0].x) self.dato_1.configure(text=self.game_state.home_robots[1].x) self.dato_2.configure(text=self.game_state.home_robots[2].x) score = f"{self.game_state.home_goals} - {self.game_state.away_goals}" self.score.configure(text=score) self.after(50, self.update_data)
class Main(tk.Tk): def __init__(self, read_socket): super().__init__() style = ttk.Style() style.theme_use("clam") style.configure("Dashboard.TFrame", background=COLOR_LIGHT_BACKGROUND) style.configure("BackgroundRED.TFrame", background="red") style.configure("BackgroundBLUE.TFrame", background="blue") style.configure("BackgroundGREEN.TFrame", background="green") style.configure("BackgroundYELLOW.TFrame", background="yellow") style.configure("BackgroundPURPLE.TFrame", background="purple") style.configure("BackgroundWHITE.TFrame", background="white") style.configure("BackgroundORANGE.TFrame", background="orange") style.configure("BackgroundPINK.TFrame", background="pink") style.configure("Background.TFrame", background=COLOR_PRIMARY) style.configure("Dashboard.TLabel", background=COLOR_LIGHT_BACKGROUND, foreground=COLOR_DARK_TEXT, font="Courier 46") style.configure("LightText.TLabel", background=COLOR_PRIMARY, foreground=COLOR_LIGHT_TEXT, font=("TkDefaultFont", 11)) style.configure("Button.TButton", background=[COLOR_SECONDARY], foreground=COLOR_LIGHT_TEXT, font=("TkDefaultFont", 11)) style.configure("info_button.TButton", background="black", foreground="white", font=("TkDefaultFont", 11)) style.map("Button.TButton", background=[("active", COLOR_PRIMARY), ("disabled", COLOR_LIGHT_TEXT)]) SCREEN_WIDTH = self.winfo_screenwidth() SCREEN_HEIGHT = self.winfo_screenheight() self["background"] = COLOR_PRIMARY self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) container = ttk.Frame(self) container["height"] = SCREEN_HEIGHT container["width"] = SCREEN_WIDTH container.grid() container.columnconfigure(0, weight=1) self.frames = {} self.is_powered_on = False settings_frame = Settings(container, self, lambda: self.show_frame(Dashboard), height=SCREEN_HEIGHT, width=SCREEN_WIDTH) dashboard_frame = Dashboard(container, self, lambda: self.show_frame(Settings), height=SCREEN_HEIGHT, width=SCREEN_WIDTH) settings_frame.grid(row=0, column=0, sticky="NESW") dashboard_frame.grid(row=0, column=0, sticky="NESW") self.frames[Settings] = settings_frame self.frames[Dashboard] = dashboard_frame self.show_frame(Dashboard) self.title('ALPHA SOCCER FC v1.0') self.geometry(f"{SCREEN_WIDTH}x{SCREEN_HEIGHT}") self.resizable(False, False) print(SCREEN_HEIGHT, SCREEN_WIDTH) self.global_state = State(home_robots=[ Robot(rid=0, team=1, color="blue", sock=None, x=0, y=0, yaw=0), Robot(rid=1, team=1, color="green", sock=None, x=0, y=0, yaw=0), Robot(rid=2, team=1, color="red", sock=None, x=0, y=0, yaw=0) ], away_robots=[ Robot(rid=0, team=2, color="blue", sock=None, x=0, y=0, yaw=0), Robot(rid=1, team=2, color="green", sock=None, x=0, y=0, yaw=0), Robot(rid=2, team=2, color="red", sock=None, x=0, y=0, yaw=0) ], ball=Ball()) self.read_socket = read_socket self.update() def show_frame(self, container): frame = self.frames[container] frame.tkraise() def update(self): #Team 1 self.frames[Dashboard].team1.robot1.x.set( self.global_state.home_robots[0].x) self.frames[Dashboard].team1.robot1.y.set( self.global_state.home_robots[0].y) self.frames[Dashboard].team1.robot1.vision_angle.set( self.global_state.home_robots[0].yaw) self.frames[Dashboard].team1.robot2.x.set( self.global_state.home_robots[1].x) self.frames[Dashboard].team1.robot2.y.set( self.global_state.home_robots[1].y) self.frames[Dashboard].team1.robot2.vision_angle.set( self.global_state.home_robots[1].yaw) self.frames[Dashboard].team1.robot3.x.set( self.global_state.home_robots[2].x) self.frames[Dashboard].team1.robot3.y.set( self.global_state.home_robots[2].y) self.frames[Dashboard].team1.robot3.vision_angle.set( self.global_state.home_robots[2].yaw) #Team 2 self.frames[Dashboard].team2.robot1.y.set( self.global_state.away_robots[0].y) self.frames[Dashboard].team2.robot1.x.set( self.global_state.away_robots[0].x) self.frames[Dashboard].team2.robot2.y.set( self.global_state.away_robots[1].y) self.frames[Dashboard].team2.robot2.x.set( self.global_state.away_robots[1].x) self.frames[Dashboard].team2.robot3.y.set( self.global_state.away_robots[2].y) self.frames[Dashboard].team2.robot3.x.set( self.global_state.away_robots[2].x) #Ball self.frames[Dashboard].ball.x.set(self.global_state.ball.x) self.frames[Dashboard].ball.y.set(self.global_state.ball.y) self.after(30, self.update) def listen(self): self.read_socket.listen(0) while True: client, addr = self.read_socket.accept() while True: content = client.recv(45) # Serialized protobuff data if len(content) == 0: break else: self.global_state.update(content) client.close()