diff --git a/Drone/Client.py b/Drone/Client.py index 71e403f..8b1a7b5 100755 --- a/Drone/Client.py +++ b/Drone/Client.py @@ -1,99 +1,207 @@ +from __future__ import print_function +import sys import socket -import play_animation +import struct +import random import time -import ntplib -from threading import Thread -sock = socket.socket() -serv = '192.168.1.10' # Change to server ip -port = 35001 -sock.connect((serv, port)) -sock.send(bytes('left', 'utf-8')) -command = '' +import threading +import ConfigParser +from contextlib import closing + +#import rospy + +#import play_animation + +random.seed() + +NTP_PACKET_FORMAT = "!12I" +NTP_DELTA = 2208988800L # 1970-01-01 00:00:00 +NTP_QUERY = '\x1b' + 47 * '\0' -def receive(): - global command - try: +def get_ntp_time(host, port): + with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) as s: + s.sendto(NTP_QUERY, (host, port)) + msg, address = s.recvfrom(1024) + unpacked = struct.unpack(NTP_PACKET_FORMAT, msg[0:struct.calcsize(NTP_PACKET_FORMAT)]) + return unpacked[10] + float(unpacked[11]) / 2**32 - NTP_DELTA + + +def reconnect(t=1): + print("Trying to connect to", host, ":", port, "...") + connected = False + global clientSocket + while not connected: + try: + clientSocket = socket.socket() + clientSocket.connect((host, port)) + connected = True + print("Connection successful") + except socket.error as e: + print("Waiting for connection:", e) + time.sleep(t) + + +def send_all(msg): + clientSocket.sendall(struct.pack('>I', len(msg)) + msg) + + +def recive_all(n): + data = b'' + while len(data) < n: + packet = clientSocket.recv(min(n - len(data), BUFFER_SIZE)) + if not packet: + return None + data += packet + return data + + +def recive_message(): + raw_msglen = recive_all(4) + if not raw_msglen: + return None + msglen = struct.unpack('>I', raw_msglen)[0] + msg = recive_all(msglen) + return msg + + +def form_command(command, args=()): + return " ".join([command, args]) + + +def parse_command(command_input): + args = command_input.split() + command = args.pop(0) + return command, args + + +def recive_file(filename): + print("Reciving file:", filename) + with open(filename, 'wb') as file: # TODO add directory while True: - data = str(sock.recv(1024)) - try: - if b'programm' in data: - anim = open('anim.csv', 'w') - data = data[data.index(b'programm') + 8:] - anim.write(data) - - while True: - data = str(sock.recv(1024)) - - if b'stop' in data: - anim.write(data[:data.index(b'stop')]) - break - else: - anim.write(data) - - else: - try: - sq = data.split('$$') - for i in range(len(sq) - 1): - print(sq[i]) - command = sq[i] - - except Exception as e: - print(e) - - except: - print('er') - sock.close() - except KeyboardInterrupt: - print("Shutting down") - - led.off() - sock.close() + data = recive_message() #clientSocket.recv(BUFFER_SIZE) + if data: + print(data) + if parse_command(data.decode("UTF-8"))[0] == "/endoffile": + print("File recived") + break + file.write(data) -def time_synch(): - c = ntplib.NTPClient() - response = c.request('ntp1.stratum2.ru') - return response.tx_time-time.time() +def write_to_config(section, option, value): + config.set(section, option, value) + with open(CONFIG_PATH, 'w') as file: + config.write(file) -def pl_anim(): - global command - play_animation.read_animation_file() - dtime = time_synch() - time.time() - ok = 0 - t_st=0 - while True: - - if 'begin_anim' in command: - t_st = int(command[command.index('('):]) - - if t_st == dtime+time.time: +def animation_player(running_event, stop_event): + print("Animation thread activated") + rate = rospy.Rate(1000 / 100) + play_animation.takeoff(TAKEOFF_HEIGHT) + for current_frame in play_animation.frame(): + running_event.wait() + if stop_event.is_set(): break - if 'synch' in command: - dtime=time_synch() - time.time() - print(dtime) - play_animation.takeoff() - for frame in play_animation.frame(): - if command != 'pause': - time.sleep(0.1) - play_animation.do_next_animation(frame) + play_animation.do_next_animation(current_frame) + rate.sleep() + else: + play_animation.land() + print("Animation ended") + print("Animation thread closed") -if __name__ == "__main__": - t_0 = Thread(target=receive) - t_0.daemon = True - t_0.start() - - t_1 = Thread(target=pl_anim) - t_1.daemon = True - t_1.start() - - - - +stop_animation_event = threading.Event() +running_animation_event = threading.Event() +animation_thread = threading.Thread(target=animation_player, args=(running_animation_event, stop_animation_event)) +def start_animation(): + play_animation.read_animation_file(animation_file) + print("Starting animation!") + resume_animation() + animation_thread.start() +def resume_animation(): + print("Resuming animation") + running_animation_event.set() + + +def pause_animation(): + print("Pausing animation") + running_animation_event.clear() + + +def stop_animation(): + stop_animation_event.set() + running_animation_event.clear() + print("Stopping animation") + animation_thread.join() + + +CONFIG_PATH = "client_config.ini" +config = ConfigParser.ConfigParser() +config.read(CONFIG_PATH) + + +port = int(config.get('SERVER', 'port')) +host = config.get('SERVER', 'host') +BUFFER_SIZE = int(config.get('SERVER', 'buffer_size')) +NTP_HOST = config.get('NTP', 'host') +NTP_PORT = int(config.get('NTP', 'port')) + +files_directory = config.get('FILETRANSFER', 'files_directory') +animation_file = config.get('COPTER', 'animation_file') + +COPTER_ID = config.get('COPTER', 'id') +if COPTER_ID == 'default': + COPTER_ID = 'copter' + str(random.randrange(9999)).zfill(4) + write_to_config('COPTER', 'id', COPTER_ID) + +TAKEOFF_HEIGHT = float(config.get('COPTER', 'takeoff_height')) + +print("Client started on copter:", COPTER_ID) +print("NTP time:", time.ctime(get_ntp_time(NTP_HOST, NTP_PORT))) +print("System time", time.ctime(time.time())) + +reconnect() + +print("Connected to server") + +try: + while True: + try: + message = recive_message() + if message: + message = message.decode("UTF-8") + command, args = parse_command(message) + print("Command from server:", command, args) + if command == "writefile": + recive_file(args[0]) + elif command == "starttime": + starttime = float(args[0]) + print("Starting on:", time.ctime(starttime)) + dt = starttime - get_ntp_time(NTP_HOST, NTP_PORT) + print("Until start:", dt) + rospy.Timer(rospy.Duration(dt), start_animation, oneshot=True) + elif command == 'request': + request_target = args[0] + print("Got request for:", request_target) + response = "" + if request_target == 'someshit': + response = "dont_have_any" + elif request_target == 'id': + response = COPTER_ID + send_all(bytes(form_command("response", response))) + print("Request responded with:", response) + + except socket.error: + print("Connection lost... reconnecting") + reconnect() + print("Re-connection successful") +except KeyboardInterrupt: + print("Shutdown on keyboard interrupt") +finally: + clientSocket.close() + diff --git a/Drone/client_config.ini b/Drone/client_config.ini new file mode 100644 index 0000000..71439a9 --- /dev/null +++ b/Drone/client_config.ini @@ -0,0 +1,17 @@ +[SERVER] +port = 25000 +host = 192.168.43.168 +buffer_size = 1024 + +[FILETRANSFER] +files_directory = files + +[NTP] +host = ntp1.stratum2.ru +port = 123 + +[COPTER] +id = copter6349 +takeoff_height = 1.75 +takeoff_timeout = 7 +animation_file = animation.csv diff --git a/Server/Server.py b/Server/Server.py index db7ed54..e23082f 100644 --- a/Server/Server.py +++ b/Server/Server.py @@ -1,388 +1,289 @@ -# -*- coding: utf-8 -*- . -"""Code by Alexandr Osherov 10 class, phone - +79251834732, email - allexandr2001@mail.ru """ -from PyQt5.QtWidgets import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * -from mpl_toolkits.mplot3d import Axes3D -import matplotlib.pyplot as plt -import time -import socket +from tkinter import * +from tkinter import ttk +from tkinter import filedialog +import ttkwidgets + import os -import easygui +import sys +import glob +import time +import struct +import socket import threading -from threading import Thread -import math -import requests -import json -import main_gui -import gui_telem -import ntplib -ip = [1, 2] -sq_rad = 0 -sq_cet = 0 -cr_rad = 0 -cr_cet = 0 -copters = 1 -conn = [] -conn_2 = [] -afile = '' -data = b'' -addr = [] -addr_2 = [] -coord = [] -d_time = 0 -size_scene=[2,2,2] -sock = socket.socket() +import collections +import configparser -sock.bind(('', 35001)) # назначается адресс и порт связи для отпраки команд на коптеры -sock.listen(1) - -sock_2 = socket.socket() -sock_2.bind(('', 35002)) # назначается адресс и порт связи для приема данных с коптеров -sock_2.listen(1) +# All imports sorted in pyramid -class Dialog(QMainWindow, gui_telem.Ui_Dialog): - def __init__(self): - super().__init__() - self.setupUi(self) +def auto_connect(): + while True: + ServerSocket.listen(1) + c, addr = ServerSocket.accept() + print("Got connection from:", str(addr)) + #client_thread = threading.Thread(target=on_new_client, args=(c, addr)) + #client_thread.start() - def up(self): - self.voltage_2.setText('1234567') + if not any(client_addr == addr[0] for client_addr in Client.clients.keys()): + client = Client(addr[0]) + print("New client") + else: + print("Reconnected client") + Client.clients[addr[0]].connect(c, addr) -class Widget(QMainWindow, main_gui.Ui_MainWindow): - def __init__(self): - super().__init__() - self.setupUi(self) - self.start_animation_button.clicked.connect(self.start_animation) - self.stop_swarm_but.clicked.connect(self.stop_swarm) - self.show_3d_scene_button.clicked.connect(self.show_3d) - self.disarm_all_button.clicked.connect(self.disarm) - self.turn_off_led_button.clicked.connect(self.off_leds) - self.turn_on_led_button.clicked.connect(self.on_leds) - self.upload_animation_button.clicked.connect(self.upload_animation) - self.land_all_button.clicked.connect(self.land) - self.take_off_button.clicked.connect(self.take_off) - #self.number_animation_copters.clicked.connect(self.number_animation) synch_button - self.synch_button.clicked.connect(self.synch) - self.take_off_n_button.clicked.connect(self.take_off_n) - self.land_n_button.clicked.connect(self.land_n) - self.disarm_n_button.clicked.connect(self.disarm_n) - self.land_spinBox.valueChanged.connect(self.land_led) - self.disarm_spinBox.valueChanged.connect(self.disarm_led) - self.take_off_spinBox.valueChanged.connect(self.take_off_led) - self.safty_button.clicked.connect(self.safty) - self.connect_button.clicked.connect(self.connect) - self.swarm_size_spinBox.valueChanged.connect(self.number_copters) +NTP_DELTA = 2208988800 # 1970-01-01 00:00:00 +NTP_QUERY = b'\x1b' + bytes(47) - - def receiver(self): - global copters - global addr - while True: +def get_ntp_time(ntp_host, ntp_port): + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: + s.sendto(NTP_QUERY, (ntp_host, ntp_port)) + msg, _ = s.recvfrom(1024) + return int.from_bytes(msg[-8:], 'big') / 2 ** 32 - NTP_DELTA + + +def requires_connect(f): + def wrapper(*args, **kwargs): + if args[0].connected: + return f(*args, **kwargs) + else: + print("Function requires client to be connected!") + return wrapper + + +class Client: + clients = {} + + def __init__(self, ip): + self.socket = None + self.addr = None + + self._send_queue = collections.deque() + self._received_queue = collections.deque() + self._request_queue = collections.OrderedDict() + + self.copter_id = None + self.malfunction = False + + Client.clients[ip] = self + + self.connected = False + + def connect(self, client_socket, client_addr): + print("Client connected") + self._send_queue = collections.deque() # comment for resuming queue after reconnection + + self.socket = client_socket + self.addr = client_addr + + self.socket.setblocking(0) + self.connected = True + client_thread = threading.Thread(target=self._run, args=()) + client_thread.start() + if self.copter_id is None: + self.copter_id = self.get_response("id") + print("Got copter id:", self.copter_id) + drone_list.insert("", "end", self.addr[0], text=self.copter_id) + + def _send_all(self, msg): + self.socket.sendall(struct.pack('>I', len(msg)) + msg) + + def _receive_all(self, n): + data = b'' + while len(data) < n: + packet = self.socket.recv(min(n - len(data), BUFFER_SIZE)) + if not packet: + return None + data += packet + return data + + def _receive_message(self): + raw_msglen = self._receive_all(4) + if not raw_msglen: + return None + msglen = struct.unpack('>I', raw_msglen)[0] + msg = self._receive_all(msglen) + return msg + + def _run(self): + while self.connected: try: - for k in range(copters): - a = requests.get('http://' + addr[k][0] + ':8081/aruco_map') - tem = json.loads(a.text) - - coord[k] = str(tem['x']) + ',' + str(tem['y']) + ',' + str(tem['z']) + ',' + \ - str(tem['mode']) + ',' + str(tem['armed']) + ',' + str(tem['frame_id']) + str( - tem['voltage']) + ',' + \ - str(tem['yaw']) + ',' + str(tem['pitch']) + ',' + str(tem['roll']) + ',' + \ - str(tem['vx']) + ',' + str(tem['vy']) + ',' + str(tem['vz']) - - #time.sleep(0.05) - - - except Exception as e: - pass - - def sender(self, com, num): - global conn - global conn_2 - global copters - print(com) - print(num) - try: - if num == 'all': - for i in range(copters): - conn[i].send(com + b'$$') - print(com + b'$$') - elif int(num) > 0: - conn[int(num) - 1].send(com + b'$$') - except: - pass - - def message(self, mes): - pass - - def connect(self): - global copters - global conn - global conn_2 - global addr - global addr_2 - global coord - - addr_2 = [] - - conn = [] - conn_2 = [] - - self.message('Try connect') - for i in range(copters): - conn.append(0) - addr.append(0) - coord.append('0') - - t_0 = Thread(target=self.connect_init) - t_0.daemon = True - t_0.start() - - def connect_init(self): - self.state_label.setText("
Wait
") - global copters - - global conn - global addr - global conn_2 - global addr_2 - - for i in range(copters): - conn[i], addr[i] = sock.accept() - print("connected_controllers:", addr[i]) - - self.disarm_spinBox.setMaximum(copters) - self.land_spinBox.setMaximum(copters) - self.take_off_spinBox.setMaximum(copters) - self.state_label.setText("Connect
") - - t = Thread(target=self.receiver) - t.daemon = True - t.start() - - def safty(self): - self.message('safty check') - self.sender(b'f.safety_check(False)', 'all') - - def take_off(self): - self.message('take off') - self.sender(b'f.takeoff(z=2, speed=2,speed_takeoff=2 , timeout=2)', 'all') - - def take_off_n(self): - self.message('take off n') - self.sender(b'f.takeoff()', str(self.take_off_spinBox.value())) - - def land(self): - self.message('land') - self.sender(b'f.land(preland=False)', 'all') - - def land_n(self): - self.message('land n') - self.sender(b'f.land(preland=False)', str(self.land_spinBox.value())) - - def disarm(self): - self.sender(b'f.arming(False)', 'all') - - def disarm_n(self): - self.sender(b'f.arming(False)', str(self.disarm_spinBox.value())) - - def off_leds(self): - self.sender(b'led.off()', 'all') - - def land_led(self): - self.sender(b'led.off()', 'all') - self.sender(b'led.fill(255,0,0)', self.land_spinBox.value()) - # print(1) - - def disarm_led(self): - self.sender(b'led.off()', 'all') - self.sender(b'led.fill(0,255,0)', self.disarm_spinBox.value()) - - def take_off_led(self): - self.sender(b'led.off()', 'all') - self.sender(b'led.fill(0,0,255)', self.take_off_spinBox.value()) - - def on_leds(self): - self.sender(b'led.fill(0,0,255)', 'all') - - def number_copters(self): - global copters - copters = self.swarm_size_spinBox.value() - - def upload_animation(self): - global afile - afile = easygui.fileopenbox(filetypes=["*.csv"],multiple=True) # вызов окна проводника для выбора файла - - def start_animation(self): - global afile - global d_time - for counter, sub_file in enumerate(afile): - f = open(sub_file, 'r') - prog = f.read() - self.sender(b'programm' + bytes(prog, 'utf-8')+b'stop', str(counter)) - time.sleep(0.1) - for i in range(len(afile)): - self.sender(bytes('begin_anim('+str(time.time()+d_time+10)+')','utf-8', str(counter))) - - t1 = Thread(target=self.start_retime) - t1.daemon = True - t1.start() - - - def start_retime(self): - for i in range(11): - time.sleep(1) - self.time_to_start_label.setText(""+str(10-i)+"
") - '''if i==10: - k=0 - while True: - k+=1 - time.sleep(0.2r) - self.time_to_start_label.setText(""+k*'.'+"
") - if k>3: - k=0'''# for ... animation - self.time_to_start_label.setText("Take off
") - time.sleep(2) - self.time_to_start_label.setText("") - - - - def stop_swarm(self): - pass - - def synch(self): - global d_time - self.sender(b'synch', 'all') - c = ntplib.NTPClient() - response = c.request('ntp1.stratum2.ru') - d_time = response.tx_time-time.time() - print(d_time) - - def show_3d(self): - global size_scene - global data - global copters - global coord - fig = plt.figure() - ax = fig.add_subplot(111, projection='3d') - updateDialog = Dialog() - updateDialog.show() - - while True: - s = str(self.console_textEdit.toPlainText()) - #print(s) - if '>' in s: - - print(s[:-2], s[s.index('>') - 1]) - self.console_textEdit.setText('') - if s[s.index('>') - 1] == '0': - self.sender(bytes(str(s[:s.index('>') - 1]), 'utf-8'), 'all') - #print(s[:s.index('>') - 1], 'all') + if self._send_queue: + msg = self._send_queue.popleft() + print("Send", msg, "to", self.addr) + self._send_all(msg) else: - self.sender(bytes(str(s[:s.index('>') - 1]), 'utf-8'), str(s[s.index('>') - 1])) - #print('sender', s[s.index('>') - 1]) - try: + msg = "ping" + #self._send_all(msg) - i = updateDialog.number_spinBox.value() - if i > 0: - i -= 1 - - coord_drone = [] - coord_drone = coord[i].split(',') - - updateDialog.z_2.setText("
" + coord_drone[ - 0] + "
") - updateDialog.x_2.setText("" + coord_drone[ - 1] + "
") - updateDialog.y_2.setText("" + coord_drone[ - 2] + "
") - updateDialog.mode_2.setText("" + coord_drone[ - 3] + "
") - updateDialog.armed_2.setText("" + coord_drone[ - 4] + "
") - updateDialog.frame_id_2.setText("" + coord_drone[ - 5] + "
") - updateDialog.voltage_2.setText("" + coord_drone[ - 6] + "
") - updateDialog.yaw2.setText("" + coord_drone[ - 7] + "
") - updateDialog.pitch_2.setText("" + coord_drone[ - 8] + "
") - updateDialog.roll_2.setText("" + coord_drone[ - 9] + "
") - updateDialog.vx_2.setText("" + coord_drone[ - 10] + "
") - updateDialog.vy_2.setText("" + coord_drone[ - 11] + "
") - updateDialog.vz_2.setText("" + coord_drone[ - 12] + "
") - except Exception as e: - # print(e) - pass - try: - - n = 0 - # set size of scene - - ax.set_xlim(0, size_scene[0]) - ax.set_ylim(0, size_scene[1]) - ax.set_zlim(0, size_scene[2]) - - ax.set_xlabel('x') - ax.set_ylabel('y') - ax.set_zlabel('z') - - plt.pause(0.01) - - ax.clear() - try: - for i in coord: - co = (0, 0, 0) - n += 1 - - if self.land_spinBox.value() == n: - co = (1, 0, 0) - if self.take_off_spinBox.value() == n: - co = (1, 0, 0) - if self.disarm_spinBox.value() == n: - co = (1, 0, 0) - - ax.scatter(float(i.split(',')[0]), float(i.split(',')[1]), float(i.split(',')[2]), s=50, c=co, - marker='.') - ax.text(float(i.split(',')[0]), float(i.split(',')[1]), float(i.split(',')[2]), str(n), size=10, - zorder=1, color=(0, 0, 0)) - - except Exception as e: - #print(e) + try: # check if data in buffer + check = self.socket.recv(BUFFER_SIZE, socket.MSG_PEEK) + if check: + received = self._receive_message() + if received: + received = received.decode("UTF-8") + print("Recived", received, "from", self.addr) + command, args = Client.parse_command(received) + if command == "response": + for key, value in self._request_queue.items(): + if not value: + self._request_queue[key] = args[0] + print("Request successfully closed") + break + else: + self._received_queue.appendleft(received) + except socket.error: pass - ax.set_xlim(0, size_scene[0]) - ax.set_ylim(0, size_scene[1]) - ax.set_zlim(0, size_scene[2]) - - - ax.set_xlabel('x') - ax.set_ylabel('y') - ax.set_zlabel('z') - - plt.draw() - except KeyboardInterrupt: - print('stop') + except socket.error as e: + print("Client error, disconnected", e) + self.connected = False + self.socket.close() break + # time.sleep(0.05) - plt.show() + @staticmethod + def form_command(command: str, args=()): # Change for different protocol + return " ".join([command, *args]) + + @staticmethod + def parse_command(command_input): + args = command_input.split() + command = args.pop(0) + return command, args + + @requires_connect + def send(self, *messages): + for message in messages: + self._send_queue.append(bytes(message, "UTF-8")) + + @staticmethod + def broadcast(message, force_all=False): + for client in Client.clients.values(): + if (not client.malfunction) or force_all: + client.send(message) + + @requires_connect + def send_file(self, filepath, dest_filename): + print("Sending file ", dest_filename) + self.send(Client.form_command("writefile", (dest_filename,))) + file = open(filepath, 'rb') + chunk = file.read(BUFFER_SIZE) + while chunk: + self._send_queue.append(chunk) + chunk = file.read(BUFFER_SIZE) + file.close() + self.send(Client.form_command("/endoffile")) + print("File sent") + + @requires_connect + def get_response(self, requested_value): + self._request_queue[requested_value] = "" + self.send(Client.form_command("request", (requested_value, ))) + + while not self._request_queue[requested_value]: + pass + + return self._request_queue.pop(requested_value) - -app = QApplication([]) -w = Widget() -w.show() - -app.exec() +# UI functions +def stop_swarm(): + Client.broadcast("stop") # для тестирования +def send_animations(): + path = filedialog.askdirectory(title="Animation directory") + if path: + print("Selected directory:", path) + files = [file for file in glob.glob(path+'/*.csv')] + names = [os.path.basename(file).split(".")[0] for file in files] + print(files) + for file, name in zip(files, names): + for copter in Client.clients.values(): + if name == copter.copter_id: + copter.send_file(file, "animation.csv") # TODO config + else: + print("Filename not matches with any drone connected") + #dr = next(iter(Client.clients.values())) # костыль для тестирования + #ANS = dr.get_response("someshit") + #print(ANS) + + +def send_starttime(dt=60): + timenow = time.time() + print('Now:', time.ctime(timenow), "+ dt =", dt) + Client.broadcast(Client.form_command("starttime", (str(timenow+dt), ))) + + +# UI build here +root = Tk() +root.wm_title("Drone swarm operation server") +root.style = ttk.Style() +root.style.theme_use("vista") + +leftFrame = Frame(root) +leftFrame.grid(row=0, column=0, padx=10, pady=10) +rightFrame = Frame(root) +rightFrame.grid(row=0, column=1, padx=10, pady=10) + +drone_list = ttkwidgets.CheckboxTreeview(leftFrame, columns=("addr", "connected")) +#drone_list["columns"] = ("addr") +#drone_list.column("name") #width=100 +#drone_list.column("addr") +drone_list.heading("#0", text="Drone name") +drone_list.heading("#1", text="Connection adress") +drone_list.heading("#2", text="Connection status") +drone_list.pack() + +button_frame = Frame(leftFrame, borderwidth=1, relief="solid") +button_frame.pack(fill=BOTH, expand=True) + +stop_all_btn = ttk.Button(button_frame, text="Stop swarm", command=stop_swarm) +stop_all_btn.pack(side=RIGHT, padx=5, pady=5) + +send_animation_btn = ttk.Button(button_frame, text="Send animations", command=send_animations) +send_animation_btn.pack(side=RIGHT, padx=5, pady=5) + +send_starttime_btn = ttk.Button(button_frame, text="Start animation after...", command=send_starttime) +send_starttime_btn.pack(side=RIGHT, padx=5, pady=5) + + +def gui_update(): + time.sleep(0.1) + + +# reading config +config = configparser.ConfigParser() +config.read("server_config.ini") + +port = int(config['SERVER']['port']) +BUFFER_SIZE = int(config['SERVER']['buffer_size']) +NTP_HOST = config['NTP']['host'] +NTP_PORT = int(config['NTP']['port']) + + +ServerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socket.socket() # +ServerSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +host = socket.gethostname() +ip = socket.gethostbyname_ex(host)[-1] + +print('Server started on', host, ip, ":", port) +#print('Now:', time.ctime(get_ntp_time(NTP_HOST, NTP_PORT))) +print('Waiting for clients...') +ServerSocket.bind((ip[-1], port)) + +autoconnect_thread = threading.Thread(target=auto_connect) +autoconnect_thread.daemon = True +autoconnect_thread.start() + + +if __name__ == '__main__': + try: + mainloop() + except KeyboardInterrupt: + print("Stopping server by keyboard interrupt") + finally: + ServerSocket.close() + print("Server shutdown") diff --git a/Server/back_1_rc.py b/Server/back_1_rc.py deleted file mode 100644 index e23970e..0000000 --- a/Server/back_1_rc.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- - -# Resource object code -# -# Created by: The Resource Compiler for PyQt5 (Qt v5.11.2) -# -# WARNING! All changes made in this file will be lost! - -from PyQt5 import QtCore - -qt_resource_data = b"\ -\x00\x00\x01\x01\ -\x00\ -\x00\x11\x27\x78\x9c\xeb\x0c\xf0\x73\xe7\xe5\x92\xe2\x62\x60\x60\ -\xe0\xf5\xf4\x70\x09\x62\x60\x60\x05\x32\x99\x2e\x70\x30\x01\x29\ -\x07\x79\x2f\x46\x20\xc5\x58\x1c\xe4\xee\xc4\xb0\xee\x9c\xcc\x4b\ -\x20\x87\x25\xdd\xd1\xd7\x91\x81\x61\x63\x3f\xf7\x9f\x44\x90\x52\ -\xce\x02\x8f\xc8\x62\x06\x06\xbe\xc3\x20\xcc\x78\x3c\x7f\x45\x0a\ -\x03\x83\xc0\x1e\x4f\x17\xc7\x90\x8a\xb8\xb7\xd7\x37\x0a\x1e\x32\ -\x60\x60\x71\x74\xe4\xcf\x73\xef\xf4\x2a\x4f\x2c\x5a\xd4\xc2\xa4\ -\xf0\xa0\x6c\xf2\x7c\xfd\x87\x71\xdf\x6b\xf9\x19\x7e\x74\xee\xfd\ -\x3e\xe7\xf3\x1c\xff\xec\xb5\xaf\x77\x9d\x63\x64\xf8\xd1\xf4\x3d\ -\x12\x68\xe4\x8f\x6c\x26\x09\x06\x86\x06\x16\x46\x1e\xa0\x13\x9a\ -\x18\xd8\x18\x18\x14\x1c\x19\x98\x19\x18\x26\x28\x34\x00\x9d\xe3\ -\x21\x70\x00\xa8\x46\x85\x23\x01\x48\x0a\xb1\x18\x80\x9c\x30\xaa\ -\x7c\x54\xf9\xa8\xf2\x51\xe5\xa3\xca\x47\x95\x8f\x2a\x1f\x55\x3e\ -\xaa\x7c\x54\xf9\xa8\xf2\x51\xe5\xa3\xca\x47\x95\x8f\x2a\x1f\x55\ -\x4e\xbc\x72\x96\x9e\x8f\x0c\x2f\xa5\x79\x56\x38\x34\x3f\xa9\x06\ -\x72\x19\x3c\x5d\xfd\x5c\xd6\x39\x25\x34\x01\x00\xe9\xcb\xf7\x1d\ -\ -" - -qt_resource_name = b"\ -\x00\x04\ -\x00\x06\x87\x9b\ -\x00\x62\ -\x00\x61\x00\x63\x00\x6b\ -\x00\x08\ -\x07\x9e\x5a\x47\ -\x00\x62\ -\x00\x61\x00\x63\x00\x6b\x00\x2e\x00\x70\x00\x6e\x00\x67\ -" - -qt_resource_struct_v1 = b"\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ -\x00\x00\x00\x0e\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ -" - -qt_resource_struct_v2 = b"\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x0e\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x64\x8d\x7d\xe9\xe9\ -" - -qt_version = [int(v) for v in QtCore.qVersion().split('.')] -if qt_version < [5, 8, 0]: - rcc_version = 1 - qt_resource_struct = qt_resource_struct_v1 -else: - rcc_version = 2 - qt_resource_struct = qt_resource_struct_v2 - -def qInitResources(): - QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) - -def qCleanupResources(): - QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) - -qInitResources() diff --git a/Server/gui/back.png b/Server/gui/back.png deleted file mode 100755 index 0a306ec..0000000 Binary files a/Server/gui/back.png and /dev/null differ diff --git a/Server/gui/back_1.qrc b/Server/gui/back_1.qrc deleted file mode 100755 index cbabc36..0000000 --- a/Server/gui/back_1.qrc +++ /dev/null @@ -1,5 +0,0 @@ -x=
")) - self.y_1.setText(_translate("Dialog", "y=
")) - self.z_1.setText(_translate("Dialog", "z=
")) - self.z_2.setText(_translate("Dialog", "0.000
")) - self.x_2.setText(_translate("Dialog", "0.000
")) - self.y_2.setText(_translate("Dialog", "0.000
")) - self.mode_2.setText(_translate("Dialog", "MANUALE
")) - self.armed_2.setText(_translate("Dialog", "False
")) - self.frame_id_1.setText(_translate("Dialog", "farme id=
armed=
")) - self.frame_id_2.setText(_translate("Dialog", "aruco_map
")) - self.mode_1.setText(_translate("Dialog", "mode=
")) - self.voltage_2.setText(_translate("Dialog", "0.000
")) - self.voltage_1.setText(_translate("Dialog", "voltage=
")) - self.roll_2.setText(_translate("Dialog", "0.000
")) - self.yaw_1.setText(_translate("Dialog", "yaw=
")) - self.pitch_1.setText(_translate("Dialog", "pitch=
")) - self.roll_1.setText(_translate("Dialog", "roll=
")) - self.pitch_2.setText(_translate("Dialog", "0.000
")) - self.yaw2.setText(_translate("Dialog", "0.000
")) - self.vy_1.setText(_translate("Dialog", "vy=
")) - self.vx_2.setText(_translate("Dialog", "0.000
")) - self.vz_1.setText(_translate("Dialog", "vz=
")) - self.vy_2.setText(_translate("Dialog", "0.000
")) - self.vz_2.setText(_translate("Dialog", "0.000
")) - self.vx_1.setText(_translate("Dialog", "vx=
")) - self.back.setText(_translate("Dialog", "
Control console
")) - self.turn_on_led_button.setText(_translate("MainWindow", "Turn on Leds")) - self.turn_off_led_button.setText(_translate("MainWindow", "Turn off Leds")) - self.stop_swarm_but.setText(_translate("MainWindow", "Stop swarm")) - self.connect_button.setText(_translate("MainWindow", "Connect")) - self.swarm_size_label.setText(_translate("MainWindow", "Swarm Size
")) - self.send_command_label.setText(_translate("MainWindow", "Send command
")) - self.console_textEdit.setHtml(_translate("MainWindow", "\n" -"\n" -"...
")) - self.show_3d_scene_button.setText(_translate("MainWindow", "Show 3d scene")) - self.upload_animation_button.setText(_translate("MainWindow", "Upload animation")) - self.state_label.setText(_translate("MainWindow", "Disconnect
")) - self.statement_swarm_label.setText(_translate("MainWindow", "Statement swarm")) - self.start_animation_button.setText(_translate("MainWindow", "Start animation")) - self.back_label.setText(_translate("MainWindow", "
")) - -import back_1_rc - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - MainWindow = QtWidgets.QMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) - diff --git a/Server/server_config.ini b/Server/server_config.ini new file mode 100644 index 0000000..061617e --- /dev/null +++ b/Server/server_config.ini @@ -0,0 +1,11 @@ +[SERVER] +port = 25000 +buffer_size = 1024 + +[NTP] +host = ntp1.stratum2.ru +port = 123 +#pool.ntp.org + +[FILETRANSFER] +animation = animation.csv \ No newline at end of file diff --git a/Server/telem_rc.py b/Server/telem_rc.py deleted file mode 100644 index 1cc6cff..0000000 --- a/Server/telem_rc.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- - -# Resource object code -# -# Created by: The Resource Compiler for PyQt5 (Qt v5.11.2) -# -# WARNING! All changes made in this file will be lost! - -from PyQt5 import QtCore - -qt_resource_data = b"\ -\x00\x00\x00\xe4\ -\x00\ -\x00\x04\x03\x78\x9c\xeb\x0c\xf0\x73\xe7\xe5\x92\xe2\x62\x60\x60\ -\xe0\xf5\xf4\x70\x09\x62\x60\x60\x52\x03\xb2\x3f\x70\x30\x01\xc9\ -\xdd\x21\x16\x20\x09\xc6\xe2\x20\x77\x27\x86\x75\xe7\x64\x5e\x02\ -\x39\x2c\xe9\x8e\xbe\x8e\x0c\x0c\x1b\xfb\xb9\xff\x24\xb2\x02\xf9\ -\x9c\x05\x1e\x91\xc5\x0c\x0c\x7c\x87\x41\x98\xf1\x78\xfe\x8a\x14\ -\x06\x06\xe6\x19\x9e\x2e\x8e\x21\x15\x71\x6f\x6f\x6d\x14\x3c\xac\ -\x20\xc0\xe0\xf8\x44\x4b\x73\xa2\x5d\xc6\x99\xc6\x2b\x4c\xe9\x67\ -\x2b\xcc\x1f\x3e\xfe\xff\x40\x68\xdd\xde\xef\x0c\x0d\x9f\xed\xce\ -\x73\x33\xb4\x7b\xf2\x31\x08\x9e\x64\x54\x50\xb2\x64\x70\x51\x61\ -\x6f\xe8\x78\xc2\x20\x30\x51\x86\x41\x69\x12\xb3\x83\x4b\x11\x43\ -\x87\xc7\xa0\x96\x64\x00\x81\x07\x7b\xd7\x59\x3e\x37\x2e\xba\x17\ -\xf5\x5a\x6e\xcd\x5f\xde\x39\x8f\xdb\x75\xfe\xdb\xff\xb4\x63\x18\ -\x1c\x2e\x1c\x95\x1c\x95\x84\x4a\x1e\x91\x88\x2f\xac\xe3\xd3\xe2\ -\x4e\x09\x0d\x01\x25\x5b\x4f\x57\x3f\x97\x75\x4e\x09\x4d\x00\xf2\ -\xc3\x05\x01\ -" - -qt_resource_name = b"\ -\x00\x05\ -\x00\x7a\xc2\xbd\ -\x00\x74\ -\x00\x65\x00\x6c\x00\x65\x00\x6d\ -\x00\x13\ -\x08\x4f\x8b\x27\ -\x00\x74\ -\x00\x65\x00\x6c\x00\x65\x00\x6d\x00\x5f\x00\x62\x00\x61\x00\x6b\x00\x67\x00\x72\x00\x6f\x00\x75\x00\x6e\x00\x64\x00\x2e\x00\x70\ -\x00\x6e\x00\x67\ -" - -qt_resource_struct_v1 = b"\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ -\x00\x00\x00\x10\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ -" - -qt_resource_struct_v2 = b"\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x10\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x64\xac\x7c\x9c\xca\ -" - -qt_version = [int(v) for v in QtCore.qVersion().split('.')] -if qt_version < [5, 8, 0]: - rcc_version = 1 - qt_resource_struct = qt_resource_struct_v1 -else: - rcc_version = 2 - qt_resource_struct = qt_resource_struct_v2 - -def qInitResources(): - QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) - -def qCleanupResources(): - QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) - -qInitResources()