From a5021d4b6e133c04a16732cdaa9e7baf089c221a Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 16 Jun 2019 17:08:01 +0300 Subject: [PATCH 01/35] Modify flip function to work better in aruco_map frame with both Clever 3 & 4 --- Drone/FlightLib/FlightLib.py | 8 ++++---- Drone/copter_client.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Drone/FlightLib/FlightLib.py b/Drone/FlightLib/FlightLib.py index 334caeb..b08e59b 100644 --- a/Drone/FlightLib/FlightLib.py +++ b/Drone/FlightLib/FlightLib.py @@ -359,10 +359,10 @@ def takeoff(z=Z_TAKEOFF, speed=SPEED_TAKEOFF, frame_id='body', freq=FREQUENCY, #print("Takeoff succeeded!") return 'success' -def flip(min_z = FLIP_MIN_Z): #TODO Flip in different directions +def flip(min_z = FLIP_MIN_Z, frame_id = FRAME_ID): #TODO Flip in different directions logger.info("Flip started!") - start_telemetry = get_telemetry() # memorize starting position + start_telemetry = get_telemetry(frame_id=frame_id) # memorize starting position if start_telemetry.z < min_z - TOLERANCE: logger.warning("Can't do flip! Flip failed!") @@ -377,9 +377,9 @@ def flip(min_z = FLIP_MIN_Z): #TODO Flip in different directions while True: telem = get_telemetry() - if -math.pi + 0.1 < telem.roll < -0.2: + if abs(telem.roll) > math.pi/2: break logger.info('Flip succeeded!') #print('Flip succeeded!') - navto(x=start_telemetry.x, y=start_telemetry.y, z=start_telemetry.z, yaw=start_telemetry.yaw) # finish flip + navto(x=start_telemetry.x, y=start_telemetry.y, z=start_telemetry.z, yaw=start_telemetry.yaw, frame_id=frame_id) # finish flip diff --git a/Drone/copter_client.py b/Drone/copter_client.py index facecb4..8f2bbdc 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -108,7 +108,7 @@ def _command_emergency_led_fill(**kwargs): @messaging.message_callback("flip") def _copter_flip(): - FlightLib.flip() + FlightLib.flip(frame_id=client.active_client.FRAME_ID) @messaging.message_callback("takeoff") def _command_takeoff(**kwargs): From 657d4c72bb367e4fd0f4313cdf56a93d9401bc85 Mon Sep 17 00:00:00 2001 From: artem30801 <38689676+artem30801@users.noreply.github.com> Date: Sat, 22 Jun 2019 11:49:38 +0300 Subject: [PATCH 02/35] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..f3d5c41 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From d7e8e29f803462e8f8f8f244e2773c10da94f439 Mon Sep 17 00:00:00 2001 From: Artem30801 Date: Tue, 25 Jun 2019 18:35:39 +0300 Subject: [PATCH 03/35] Display fix --- Server/server.py | 2 +- Server/server_qt.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Server/server.py b/Server/server.py index 897d2b3..1ae4ca6 100644 --- a/Server/server.py +++ b/Server/server.py @@ -159,7 +159,7 @@ class Server: logging.info("Got connection from: {}".format(str(addr))) conn.setblocking(False) - if not any(client_addr == addr[0] for client_addr in Client.clients.keys()): + if not any([client_addr == addr[0] for client_addr in Client.clients.keys()]): client = Client(addr[0]) logging.info("New client") else: diff --git a/Server/server_qt.py b/Server/server_qt.py index 02060d5..9d8c5fb 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -112,15 +112,15 @@ class MainWindow(QtWidgets.QMainWindow): if col == 1: data = value elif col == 2: - data = "{} V.".format(round(float(value), 3)) + data = "{}".format(round(float(value), 3)) elif col == 3: batt_percent = ((float(value) - 3.2) / (4.2 - 3.2)) * 100 # TODO config - data = "{} %".format(round(batt_percent, 3)) + data = "{}".format(round(batt_percent, 3)) elif col == 4: data = str(value) elif col == 5: data = time.ctime(int(value)) - data2 = "{} sec.".format(round(int(value) - time.time(), 3)) + data2 = "{}".format(round(int(value) - time.time(), 3)) self.signals.update_data_signal.emit(row, col + 1, data2) else: print("No column matched for response") From cd9baa6a095fa7ec25e767691b3d5f87867c5c98 Mon Sep 17 00:00:00 2001 From: Artem30801 Date: Tue, 25 Jun 2019 18:46:04 +0300 Subject: [PATCH 04/35] Fixed sel unregister issue --- Server/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/server.py b/Server/server.py index 1ae4ca6..51f6e27 100644 --- a/Server/server.py +++ b/Server/server.py @@ -140,7 +140,7 @@ class Server: self.sel.register(self.server_socket, selectors.EVENT_READ | selectors.EVENT_WRITE, data=None) while self.client_processor_thread_running.is_set(): - events = self.sel.select(timeout=0) + events = self.sel.select() for key, mask in events: if key.data is None: self._connect_client(key.fileobj) From ed02db6dbf4aa6ab5e453353ecdac848916fac10 Mon Sep 17 00:00:00 2001 From: Artem30801 Date: Tue, 25 Jun 2019 19:23:55 +0300 Subject: [PATCH 05/35] Fix for python <3.6 --- Server/copter_table_models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index 527c8ae..976e0b3 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -1,14 +1,15 @@ import sys import re -from operator import itemgetter +import collections from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import Qt as Qt class CopterData: - class_attrs = {'copter_id': None, 'anim_id': None, 'batt_v': None, 'batt_p': None, 'selfcheck': None, - 'time_utc': None, "time_delta": None, "client": None, "checked": 0} + class_attrs = collections.OrderedDict([('copter_id', None), ('anim_id', None), ('batt_v', None), ('batt_p', None), + ('selfcheck', None), ('time_utc', None), ("time_delta", None), + ("client", None), ("checked", 0)], ) def __init__(self, **kwargs): self.attrs = self.class_attrs.copy() From 85bfcd181fb686cd9ac37774e508863b9461bf67 Mon Sep 17 00:00:00 2001 From: artem30801 <38689676+artem30801@users.noreply.github.com> Date: Wed, 26 Jun 2019 00:28:58 +0300 Subject: [PATCH 06/35] Quick fix (probably) --- Drone/copter_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index ac22c1f..7c2d680 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -193,7 +193,7 @@ def _play_animation(**kwargs): frame_time = rfp_time + client.active_client.RFP_TIME frame_delay = 0.125 # TODO from animation file for frame in frames: - point, color = animation.convert_frame(frame) # TODO add param to calculate delta + point, color, yaw = animation.convert_frame(frame) # TODO add param to calculate delta task_manager.add_task(frame_time, 0, animation.execute_frame, task_kwargs={ "point": point, From c04bff12ac17f30ba2cce409641101bbac86ef2a Mon Sep 17 00:00:00 2001 From: Artem30801 Date: Wed, 26 Jun 2019 20:11:01 +0300 Subject: [PATCH 07/35] added on_broadcast() for client-side --- Drone/client.py | 4 ++++ Drone/copter_client.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Drone/client.py b/Drone/client.py index 8b5d6fe..f824e5e 100644 --- a/Drone/client.py +++ b/Drone/client.py @@ -175,10 +175,14 @@ class Client(object): ConfigOption("SERVER", "port", self.server_port), ConfigOption("SERVER", "host", self.server_host)) logger.info("Binding to new IP: {}:{}".format(self.server_host, self.server_port)) + self.on_broadcast_bind() break finally: broadcast_client.close() + def on_broadcast_bind(self): + pass + def _process_connections(self): while True: events = self.selector.select(timeout=1) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 7c2d680..9c21ac5 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -41,6 +41,10 @@ class CopterClient(client.Client): self.USE_LEDS = self.config.getboolean('PRIVATE', 'use_leds') self.LED_PIN = self.config.getint('PRIVATE', 'led_pin') + def on_broadcast_bind(self): + #TODO change chony config + _command_service_restart(name="chrony") + def start(self, task_manager_instance): client.logger.info("Init ROS node") rospy.init_node('Swarm_client', anonymous=True) From fe76cdfe087276ce50fa0413fadad502d4707a0c Mon Sep 17 00:00:00 2001 From: Artem30801 Date: Thu, 27 Jun 2019 11:06:20 +0300 Subject: [PATCH 08/35] Added chrony ip configuration on start; close #20 --- Drone/copter_client.py | 46 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 9c21ac5..e12855f 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -42,8 +42,8 @@ class CopterClient(client.Client): self.LED_PIN = self.config.getint('PRIVATE', 'led_pin') def on_broadcast_bind(self): - #TODO change chony config - _command_service_restart(name="chrony") + configure_chrony_ip(self.server_host) + restart_service("chrony") def start(self, task_manager_instance): client.logger.info("Init ROS node") @@ -56,6 +56,43 @@ class CopterClient(client.Client): super(CopterClient, self).start() +def restart_service(name): + os.system("systemctl restart {}".format(name)) + + +def configure_chrony_ip(ip, path="/etc/chrony/chrony.conf", ip_index=1): + try: + with open(path, 'r') as f: + raw_content = f.read() + except IOError as e: + print("Reading error {}".format(e)) + return False + + content = raw_content.split(" ") + + try: + current_ip = content[ip_index] + except IndexError: + print("Something wrong with config") + return False + + if "." not in current_ip: + print("That's not ip!") + return False + + if current_ip != ip: + content[ip_index] = ip + + try: + with open(path, 'w') as f: + f.write(" ".join(content)) + except IOError: + print("Error writing") + return False + + return True + + @messaging.request_callback("selfcheck") def _response_selfcheck(): check = FlightLib.selfcheck() @@ -79,12 +116,13 @@ def _response_cell(): @messaging.message_callback("test") def _command_test(**kwargs): - print("test") + logger.info("logging info test") + print("stdout test") @messaging.message_callback("service_restart") def _command_service_restart(**kwargs): - os.system("systemctl restart {}".format(kwargs["name"])) + restart_service(kwargs["name"]) @messaging.message_callback("led_test") From d973d7c3ed713bbb9f19cc63eb992b2cf79cd385 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Tue, 2 Jul 2019 16:08:58 +0300 Subject: [PATCH 09/35] Update .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 88cd199..f9b589a 100644 --- a/.gitignore +++ b/.gitignore @@ -109,7 +109,7 @@ Drone/test_animation/ Drone/animation.csv Drone/client_logs images/ - +.vscode/ \.idea/ Drone/_copter_client_old_\.py From 0a2f259517732a21b413517129fba6641885892b Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 4 Jul 2019 22:51:32 +0300 Subject: [PATCH 10/35] Activate optical flow positioning by default --- builder/image-configure.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/image-configure.sh b/builder/image-configure.sh index 8f96540..3ad8cf5 100755 --- a/builder/image-configure.sh +++ b/builder/image-configure.sh @@ -44,7 +44,7 @@ sed -i '/' /h sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/aruco.launch sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch -#sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch +sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch echo_stamp "Image was configured!" "SUCCESS" From 686cc2f25628c4d0dc4b577ea3a16a9c7085cb38 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 4 Jul 2019 22:53:39 +0300 Subject: [PATCH 11/35] service: Remove requirement of clever service --- builder/assets/clever-show.service | 1 - 1 file changed, 1 deletion(-) diff --git a/builder/assets/clever-show.service b/builder/assets/clever-show.service index 0c57193..5297b18 100644 --- a/builder/assets/clever-show.service +++ b/builder/assets/clever-show.service @@ -1,6 +1,5 @@ [Unit] Description=Clever Show Client Service -Requires=clever.service After=clever.service [Service] From bfe705f10d811d2f33bd94cb53cf79844aed067e Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 5 Jul 2019 14:23:36 +0300 Subject: [PATCH 12/35] Update table model and signal emitting condition --- Server/copter_table_models.py | 21 ++++++++++++++++----- Server/server_qt.py | 8 +++++--- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index 976e0b3..5251ef4 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -31,7 +31,7 @@ class CopterDataModel(QtCore.QAbstractTableModel): def __init__(self, parent=None): super(CopterDataModel, self).__init__(parent) - self.headers = ('copter ID', 'animation ID', 'battery (V.)', 'battery (%)', 'selfcheck', 'time UTC', "time delta") + self.headers = ('copter ID', 'animation ID', 'battery V', 'battery %', 'selfcheck', 'time delta') self.data_contents = [] def insertRows(self, contents, position='last', parent=QtCore.QModelIndex()): @@ -62,6 +62,7 @@ class CopterDataModel(QtCore.QAbstractTableModel): return self.headers[section] def data(self, index, role=Qt.DisplayRole): + self.selected_ready_signal.emit(set(self.user_selected()).issubset(self.selfchecked_ready())) row = index.row() col = index.column() #print('row {}, col {}, role {}'.format(row, col, role)) @@ -94,8 +95,6 @@ class CopterDataModel(QtCore.QAbstractTableModel): if role == Qt.CheckStateRole: self.data_contents[index.row()].checked = value - # check if all selected are selfcheck and ok (ready) - self.selected_ready_signal.emit(set(self.user_selected()).issubset(self.selfchecked_ready())) elif role == Qt.EditRole: self.data_contents[index.row()][index.column()] = value @@ -136,6 +135,8 @@ def col_check(col): def check_anim(item): if not item: return None + if str(item) == 'No animation': + return False else: return True @@ -151,13 +152,14 @@ def check_bat_v(item): @col_check(3) -def check_bat_v(item): +def check_bat_p(item): if not item: return None - if float(item) > 15: # todo config + if float(item) > 30: # todo config return True else: return False + #return True #For testing @col_check(4) @@ -169,6 +171,15 @@ def check_selfcheck(item): else: return False +@col_check(5) +def check_time_delta(item): + if not item: + return None + if abs(float(item)) < 1: + return True + else: + return False + def all_checks(copter_item): for col, check in CopterDataModel.checks.items(): diff --git a/Server/server_qt.py b/Server/server_qt.py index 9d8c5fb..cfe69fa 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -119,9 +119,11 @@ class MainWindow(QtWidgets.QMainWindow): elif col == 4: data = str(value) elif col == 5: - data = time.ctime(int(value)) - data2 = "{}".format(round(int(value) - time.time(), 3)) - self.signals.update_data_signal.emit(row, col + 1, data2) + #data = time.ctime(int(value)) + data = "{}".format(round(float(value) - time.time(), 3)) + if abs(float(data)) > 1: + Client.get_by_id(copter_id).send_message("repair_chrony") + #self.signals.update_data_signal.emit(row, col + 1, data2) else: print("No column matched for response") return From 0c7982aa891eef09d971f05b47b8b4cc460097bd Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 5 Jul 2019 14:24:33 +0300 Subject: [PATCH 13/35] Add repair_chrony message callback --- Drone/copter_client.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index e12855f..fcb3721 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -124,6 +124,11 @@ def _command_test(**kwargs): def _command_service_restart(**kwargs): restart_service(kwargs["name"]) +@messaging.message_callback("repair_chrony") +def _command_chrony_repair(): + configure_chrony_ip(client.active_client.server_host) + restart_service("chrony") + @messaging.message_callback("led_test") def _command_led_test(**kwargs): From d5dc7203f34f20c89d82f20fdf38a1e3da90b5af Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 5 Jul 2019 14:25:35 +0300 Subject: [PATCH 14/35] service: Set KillSignal to SIGKILL to kill all processes in service --- builder/assets/clever-show.service | 1 + 1 file changed, 1 insertion(+) diff --git a/builder/assets/clever-show.service b/builder/assets/clever-show.service index 5297b18..c93c431 100644 --- a/builder/assets/clever-show.service +++ b/builder/assets/clever-show.service @@ -6,6 +6,7 @@ After=clever.service WorkingDirectory=/home/pi/CleverSwarm/Drone EnvironmentFile=/lib/systemd/system/roscore.env ExecStart=/usr/bin/python /home/pi/CleverSwarm/Drone/copter_client.py +KillSignal=SIGKILL Restart=on-failure RestartSec=3 From f724e9e830ae44520d9f8216ff3e31e21ea5399a Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 5 Jul 2019 15:41:06 +0300 Subject: [PATCH 15/35] Server: Add separate check for takeoff button --- Server/copter_table_models.py | 13 ++++++++++++- Server/server_qt.py | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index 5251ef4..e93fc16 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -28,6 +28,7 @@ class CopterData: class CopterDataModel(QtCore.QAbstractTableModel): checks = {} selected_ready_signal = QtCore.pyqtSignal(bool) + selected_takeoff_ready_signal = QtCore.pyqtSignal(bool) def __init__(self, parent=None): super(CopterDataModel, self).__init__(parent) @@ -50,6 +51,10 @@ class CopterDataModel(QtCore.QAbstractTableModel): contents = contents or self.data_contents return filter(lambda x: all_checks(x), contents) + def takeoff_ready(self, contents=()): + contents = contents or self.data_contents + return filter(lambda x: takeoff_checks(x), contents) + def rowCount(self, n=None): return len(self.data_contents) @@ -62,7 +67,6 @@ class CopterDataModel(QtCore.QAbstractTableModel): return self.headers[section] def data(self, index, role=Qt.DisplayRole): - self.selected_ready_signal.emit(set(self.user_selected()).issubset(self.selfchecked_ready())) row = index.row() col = index.column() #print('row {}, col {}, role {}'.format(row, col, role)) @@ -86,6 +90,8 @@ class CopterDataModel(QtCore.QAbstractTableModel): def update_model(self, index=QtCore.QModelIndex()): #self.modelReset.emit() + self.selected_ready_signal.emit(set(self.user_selected()).issubset(self.selfchecked_ready())) + self.selected_takeoff_ready_signal.emit(set(self.user_selected()).issubset(self.takeoff_ready())) self.dataChanged.emit(index, index, (QtCore.Qt.EditRole,)) @QtCore.pyqtSlot() @@ -187,6 +193,11 @@ def all_checks(copter_item): return False return True +def takeoff_checks(copter_item): + for i in range(3): + if not check_selfcheck(copter_item[2+i]): + return False + return True class CopterProxyModel(QtCore.QSortFilterProxyModel): def __init__(self, parent=None): diff --git a/Server/server_qt.py b/Server/server_qt.py index cfe69fa..6e56d41 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -68,7 +68,7 @@ class MainWindow(QtWidgets.QMainWindow): # Connect model signals to UI self.model.selected_ready_signal.connect(self.ui.start_button.setEnabled) - self.model.selected_ready_signal.connect(self.ui.takeoff_button.setEnabled) + self.model.selected_takeoff_ready_signal.connect(self.ui.takeoff_button.setEnabled) def client_connected(self, client: Client): self.signals.add_client_signal.emit(CopterData(copter_id=client.copter_id, client=client)) From 445567850ab9a3d6045a5fb1ca173f901246369c Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 5 Jul 2019 18:34:38 +0300 Subject: [PATCH 16/35] Drone: Increase linear speed check limit --- Drone/FlightLib/FlightLib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Drone/FlightLib/FlightLib.py b/Drone/FlightLib/FlightLib.py index ac37f91..cb653a1 100644 --- a/Drone/FlightLib/FlightLib.py +++ b/Drone/FlightLib/FlightLib.py @@ -107,7 +107,7 @@ def check_connection(): @check("Linear velocity estimation") -def check_linear_speeds(speed_limit=0.1): +def check_linear_speeds(speed_limit=0.15): telemetry = get_telemetry(frame_id='body') if _check_nans(telemetry.vx, telemetry.vy, telemetry.vz): From 7c34cfcde539cc39eb630d3215d398e995d8ebb0 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 5 Jul 2019 18:36:48 +0300 Subject: [PATCH 17/35] Server: Repaired bugs with takeoff ready check, confirmation_required decorators, resume time sending --- Server/copter_table_models.py | 2 +- Server/server_qt.py | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index e93fc16..57fe84f 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -195,7 +195,7 @@ def all_checks(copter_item): def takeoff_checks(copter_item): for i in range(3): - if not check_selfcheck(copter_item[2+i]): + if not CopterDataModel.checks[2+i](copter_item[2+i]): return False return True diff --git a/Server/server_qt.py b/Server/server_qt.py index 6e56d41..ed3339f 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -27,7 +27,8 @@ def confirmation_required(text="Are you sure?", label="Confirm operation?"): ) if reply == QMessageBox.Yes: print("Dialog accepted") - return f(*args, **kwargs) + #print(args) + return f(args[0]) else: print("Dialog declined") @@ -77,7 +78,7 @@ class MainWindow(QtWidgets.QMainWindow): # Connecting self.ui.check_button.clicked.connect(self.selfcheck_selected) self.ui.start_button.clicked.connect(self.send_starttime) - self.ui.pause_button.clicked.connect(self.pause_resume_all) + self.ui.pause_button.clicked.connect(self.pause_resume_selected) self.ui.stop_button.clicked.connect(self.stop_all) self.ui.emergency_button.clicked.connect(self.emergency) @@ -130,24 +131,24 @@ class MainWindow(QtWidgets.QMainWindow): self.signals.update_data_signal.emit(row, col, data) - @pyqtSlot() @confirmation_required("This operation will takeoff selected copters with delay and start animation. Proceed?") - def send_starttime(self): + @pyqtSlot() + def send_starttime(self, **kwargs): dt = self.ui.start_delay_spin.value() for copter in self.model.user_selected(): if all_checks(copter): server.send_starttime(copter.client, dt) - @pyqtSlot() @confirmation_required("This operation will takeoff copters immediately. Proceed?") - def takeoff_selected(self): + @pyqtSlot() + def takeoff_selected(self, **kwargs): for copter in self.model.user_selected(): if all_checks(copter): copter.client.send_message("takeoff") - @pyqtSlot() @confirmation_required("This operation will flip(!!!) copters immediately. Proceed?") - def flip(self): + @pyqtSlot() + def flip(self, **kwargs): for copter in self.model.user_selected(): if all_checks(copter): copter.client.send_message("flip") @@ -162,17 +163,19 @@ class MainWindow(QtWidgets.QMainWindow): Client.broadcast_message("stop") @pyqtSlot() - def pause_resume_all(self): + def pause_resume_selected(self): if self.ui.pause_button.text() == 'Pause': - Client.broadcast_message('pause') + for copter in self.model.user_selected(): + copter.client.send_message("pause") self.ui.pause_button.setText('Resume') else: - self._resume_all() + self._resume_selected() - @confirmation_required("This operation will resume ALL copter tasks with given delay. Proceed?") - def _resume_all(self): - dt = self.ui.start_delay_spin.value() - Client.broadcast_message('resume', {"time": 0 if dt == 0 else server.time_now()}) + #@confirmation_required("This operation will resume ALL copter tasks with given delay. Proceed?") + def _resume_selected(self, **kwargs): + time_gap = 0.1 + for copter in self.model.user_selected(): + copter.client.send_message('resume', {"time": server.time_now() + time_gap}) self.ui.pause_button.setText('Pause') @pyqtSlot() From f35126440210cca93e3f21c95f661b07ddd8dc42 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 11:32:33 +0300 Subject: [PATCH 18/35] Simplify bug report template --- .github/ISSUE_TEMPLATE/bug_report.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f3d5c41..377da27 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,11 +7,10 @@ assignees: '' --- -**Describe the bug** +**The bug description** A clear and concise description of what the bug is. -**To Reproduce** -Steps to reproduce the behavior: +**Steps to reproduce the behavior** 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -23,16 +22,8 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] +**Version** +v0.3-alpha.2 (for example) -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. +**Additional information** +Add any other information about the problem here. \ No newline at end of file From 2523f0b60f5b41f29c152d9e974dc0740a585808 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 11:37:18 +0300 Subject: [PATCH 19/35] Update feauture request template --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 11fc491..6f8ddbc 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,7 +7,7 @@ assignees: '' --- -**Is your feature request related to a problem? Please describe.** +**Request description** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** From 3e283222cb8ec5916320ff4d9b096be6c0f18bd8 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 11:59:45 +0300 Subject: [PATCH 20/35] Add blender-csv-animation addon v0.4.0 --- blender-addon/README.md | 25 +++++ blender-addon/addon.py | 213 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 blender-addon/README.md create mode 100644 blender-addon/addon.py diff --git a/blender-addon/README.md b/blender-addon/README.md new file mode 100644 index 0000000..5c594ba --- /dev/null +++ b/blender-addon/README.md @@ -0,0 +1,25 @@ +# blender-csv-animation +A Blender extension that export paths of objects in blender animation to a csv files + +## CSV file format +First row is the animation filename. +Every next row of the file contains following information about an object: +- frame number, +- x coordinate, +- y coordinate, +- z coordinate, +- rotaion around z-axis angle (yaw for copter), +- rgb. + +## How to use it +Clone or download this repository +```bash +git clone https://github.com/artem30801/blender-csv-animation +``` +Open Blender and install the addon: +1) Open User Prerences windows using main menu or shortcut (Ctrl + Alt + U): Files - User Preferences +2) Under Add-ons tab click Install Add-on from File... +3) Choose addon.py file from the directory of this repository +4) Enable the Add-on + +Use [official docs](https://docs.blender.org/manual/en/latest/preferences/addons.html) for getting additional information diff --git a/blender-addon/addon.py b/blender-addon/addon.py new file mode 100644 index 0000000..1a9d527 --- /dev/null +++ b/blender-addon/addon.py @@ -0,0 +1,213 @@ +import os +import csv +import math + +import bpy +from bpy_extras.io_utils import ExportHelper +from bpy.types import Operator +from bpy.props import StringProperty, BoolProperty, FloatProperty, IntProperty + +bl_info = { + "name": "Export > CSV Drone Swarm Animation Exporter (.csv)", + "author": "Artem Vasiunik", + "version": (0, 4, 0), + "blender": (2, 80, 0), + #"api": 36079, + "location": "File > Export > CSV Drone Swarm Animation Exporter (.csv)", + "description": "Export > CSV Drone Swarm Animation Exporter (.csv)", + "warning": "", + "wiki_url": "https://github.com/artem30801/blender-csv-animation/blob/master/README.md", + "tracker_url": "https://github.com/artem30801/blender-csv-animation/issues", + "category": "Import-Export" +} + + +class ExportCsv(Operator, ExportHelper): + bl_idname = "export_swarm_anim.folder" + bl_label = "Export Drone Swarm animation" + filename_ext = '' + use_filter_folder = True + + use_namefilter: bpy.props.BoolProperty( + name="Use name filter for objects", + default=True, + ) + + drones_name: bpy.props.StringProperty( + name="Name identifier", + description="Name identifier for all drone objects", + default="copter" + ) + + show_warnings: bpy.props.BoolProperty( + name="Show detailed animation warnings", + default=False, + ) + + speed_warning_limit: bpy.props.FloatProperty( + name="Speed limit", + description="Limit of drone movement speed (m/s)", + unit='VELOCITY', + default=3, + min=0, + ) + drone_distance_limit: bpy.props.FloatProperty( + name="Distance limit", + description="Closest possible distance between drones (m)", + unit='LENGTH', + default=1.5, + min=0, + ) + + filepath: StringProperty( + name="File Path", + description="File path used for exporting CSV files", + maxlen=1024, + subtype='DIR_PATH', + default="" + ) + + def execute(self, context): + + create_folder_if_does_not_exist(self.filepath) + scene = context.scene + objects = context.visible_objects + + drone_objects = [] + if self.use_namefilter: + for drone_obj in objects: + if self.drones_name.lower() in drone_obj.name.lower(): + drone_objects.append(drone_obj) + else: + drone_objects = objects + + frame_start = scene.frame_start + frame_end = scene.frame_end + + for drone_obj in drone_objects: + with open(os.path.join(self.filepath, '{}.csv'.format(drone_obj.name.lower())), 'w') as csv_file: + animation_file_writer = csv.writer( + csv_file, + delimiter=',', + quotechar='|', + quoting=csv.QUOTE_MINIMAL + ) + speed_exeeded = False + distance_exeeded = False + + prev_x, prev_y, prev_z = 0, 0, 0 + + animation_file_writer.writerow([ + os.path.splitext(bpy.path.basename(bpy.data.filepath))[0] + ]) + + for frame_number in range(frame_start, frame_end + 1): + scene.frame_set(frame_number) + rgb = get_rgb_from_object(drone_obj) + x, y, z = drone_obj.matrix_world.to_translation() + rot_z = drone_obj.matrix_world.to_euler('XYZ')[2] + + speed = calc_speed((x, y, z), (prev_x, prev_y, prev_z)) if frame_number != frame_start else 1 + prev_x, prev_y, prev_z = x, y, z + + if speed > self.speed_warning_limit: + speed_exeeded = True + if self.show_warnings: + self.report({'WARNING'}, + "Speed of drone '%s' is greater than %s m/s (%s m/s) on frame %s" % + (drone_obj.name, round(self.speed_warning_limit, 5), round(speed, 5), frame_number)) + + for second_drone_obj in drone_objects: + if second_drone_obj is not drone_obj: + x2, y2, z2 = second_drone_obj.matrix_world.to_translation() + distance = calc_distance((x, y, z), (x2, y2, z2)) + if distance < self.drone_distance_limit: + distance_exeeded = True + if self.show_warnings: + self.report({'WARNING'}, + "Distance beteween drones '%s' and '%s' is less than %s m (%s m) on frame %s" % + (drone_obj.name, second_drone_obj.name, + round(self.drone_distance_limit, 5), round(distance, 5), frame_number)) + + animation_file_writer.writerow([ + str(frame_number), + round(x, 5), round(y, 5), round(z, 5), + round(rot_z, 5), + *rgb, + ]) + + + + if speed_exeeded: + self.report({'WARNING'}, "Drone '%s' speed limits exeeded" % drone_obj.name) + if distance_exeeded: + self.report({'WARNING'}, "Drone '%s' distance limits exeeded" % drone_obj.name) + self.report({'WARNING'}, "Animation file exported for drone '%s'" % drone_obj.name) + return {'FINISHED'} + + +def create_folder_if_does_not_exist(folder_path): + if os.path.isdir(folder_path): + return + os.mkdir(folder_path) + + +def get_rgb_from_object(obj): + rgb = [0, 0, 0] + try: + if len(obj.material_slots) > 0: + print('material slots true') + for slot in obj.material_slots: + if "led_color" in slot.name.lower(): + print('led color') + if slot.material.use_nodes: + for node in slot.material.node_tree.nodes: + if node.type in ('EMISSION', 'BSDF_DIFFUSE'): + alpha = node.inputs[0].default_value[3] + for component in range(3): + rgb[component] = int(node.inputs[0].default_value[component] * alpha * 255) + else: + print('no led color') + for component in range(3): + rgb[component] = int(slot.material.diffuse_color[component] * 255) + + except AttributeError: + pass + finally: + return rgb + + +def calc_speed(start_point, end_point): + time_delta = 0.1 + distance = calc_distance(start_point, end_point) + return distance / time_delta + + +def calc_distance(start_point, end_point): + distance = math.sqrt( + (start_point[0] - end_point[0]) ** 2 + + (start_point[1] - end_point[1]) ** 2 + + (start_point[2] - end_point[2]) ** 2 + ) + return distance + + +def menu_func(self, context): + self.layout.operator( + ExportCsv.bl_idname, + text="CSV Drone Swarm Animation Exporter (.csv)" + ) + + +def register(): + bpy.utils.register_class(ExportCsv) + bpy.types.TOPBAR_MT_file_export.append(menu_func) + + +def unregister(): + bpy.utils.unregister_class(ExportCsv) + bpy.types.TOPBAR_MT_file_export.remove(menu_func) + + +if __name__ == "__main__": + register() From 3e3658491a152593812752c9afa0d24bf96456db Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 12:20:17 +0300 Subject: [PATCH 21/35] Initial documentation commit --- docs/blender-addon.md | 23 +++++++++++++++++++++++ docs/client.md | 0 docs/image-building | 0 docs/server.md | 0 docs/start-tutorial.md | 0 5 files changed, 23 insertions(+) create mode 100644 docs/blender-addon.md create mode 100644 docs/client.md create mode 100644 docs/image-building create mode 100644 docs/server.md create mode 100644 docs/start-tutorial.md diff --git a/docs/blender-addon.md b/docs/blender-addon.md new file mode 100644 index 0000000..8c8b009 --- /dev/null +++ b/docs/blender-addon.md @@ -0,0 +1,23 @@ +# Установка и настройка аддона +## Установка +1. Скачайте [аддон](https://github.com/artem30801/blender-csv-animation) для экспорта анимации из Blender в полётные пути для коптеров. +2. Скачайте и установите согласно инструкциям последнюю версию Blender 2.8 (beta) с [оффициального сайта](https://builder.blender.org/download/) или при использовании OS Linux через команду терминала: +```bash +snap install blender --channel=beta --classic +``` +3. Откройте Blender, в верхнем меню выберите `Edit > Preferences`. В открывшемся окне настроек в боковой панели выберите пункт `Add-ons`. Нажмите на кнопку `Install...` в верхнем правом углу окна. В диалоговом окне откройте путь к папке со склонированным репозиторием проекта и выберите файл `addon.py` по пути [`blender-csv-animation/addon.py`](https://github.com/artem30801/blender-csv-animation/blob/master/addon.py). Нажмите `Install Add-on from file...`. Аддон установлен. +## Активация +В выпадающем списке `All` выберите пункт `User`. Поставьте "галочку" напротив аддона `Import-Export: Export > CSV Drone Swarm Animation Exporter` для активации аддона. Аддон активирован и готов к работе. Выполнение этих операций не понадобится при дальнейших запусках Blender. +## Дополнительно +Для деактивации аддона уберите "галочку" напротив имени аддона, как описано в предыдущем пункте. Для получения дополнительных сведений (версия, путь к файлу...) нажмите знак стрелочки слева от поля активации. В развернувшемся блоке так же есть кнопки: `Documentation` - ведет на страницу документации аддона (вы тут); `Report a bug` - ведет на страницу багтрекера на репозитории аддона; `Remove` - удалят (деинсталлирует) аддон (перед установокой новой версии рекомендуется удалить старую). +# Подготовка и создание анимации дронов +... +[Пример](https://github.com/artem30801/blender-csv-animation/blob/master/Examples/copter_base_animation.blend) можно использовать в качестве шаблона. +# Экпорт при помощи аддона +Для вызова диалогового окна экспорта нажмите в верхнем меню `File > Export > CSV Drone Swarm Animation Exporter`. В открывшемся окне экспорта необходимо выбрать целевой путь экспорта и название папки, которую создаст аддон в процессе экспорта. В боковом меню доступна панель параметров экспорта: +* `Use name filter for objects` - при отключении этого параметра будут экспортированы _все видимые объекты_ +* `Name identifier` +* `Show detailed animation warnings` - +* `Speed limit` - при нарушении указанного ограничения по скорости передвижения дронов будут выведены предупреждения +* `Distance limit` - при нарушении указанной минимальной дистанции между дронами будут выведены предупреждения +После настройки (при необходимости) нужных параметров нажмите кнопку `Export Drone Swarm animation` \ No newline at end of file diff --git a/docs/client.md b/docs/client.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/image-building b/docs/image-building new file mode 100644 index 0000000..e69de29 diff --git a/docs/server.md b/docs/server.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/start-tutorial.md b/docs/start-tutorial.md new file mode 100644 index 0000000..e69de29 From e5ff50458518a98718ba89765b477f310865a74b Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 13:11:24 +0300 Subject: [PATCH 22/35] Update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 68673b6..38e9c1e 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,16 @@ -# CleverSwarm -Програмное обеспечение для запуска шоу дронов под управлением Raspberry Pi с пакетом COEX Clever. - -[![Build Status](https://travis-ci.org/artem30801/CleverSwarm.svg?branch=master)](https://travis-ci.org/artem30801/CleverSwarm) +# clever-show +Програмное обеспечение для запуска шоу дронов под управлением Raspberry Pi с пакетом COEX [Clever](https://github.com/copterexpress/clever). ### Пакет включает в себя: -* Набор ПО для дрона, включащее в себя библиотеку для автономного полёта, модуль для воспроизведения анимаций и клиентское приложение для удаленного синхронизированного управления -* Серверное приложение для удаленного синхронизированного управления дронами и удобной передачи анимации +* [Набор ПО для дрона](https://github.com/artem30801/CleverSwarm/tree/master/Drone), включащее в себя библиотеку для автономного полёта, модуль для воспроизведения анимаций и клиентское приложение для удаленного синхронизированного управления +* [Серверное приложение](https://github.com/artem30801/CleverSwarm/tree/master/Server) для удаленного синхронизированного управления дронами и удобной настройки системы для воспроизведения анимации +* [Аддон для Blender 2.8](https://github.com/artem30801/CleverSwarm/tree/master/blender-addon) для преобразования анимации полёта коптеров, созданной в Blender, в файлы полётов для каждого коптера +* [Образ для Raspberry Pi](https://github.com/artem30801/CleverSwarm/releases/latest) для быстрого запуска ПО на коптере +[![Build Status](https://travis-ci.org/artem30801/CleverSwarm.svg?branch=master)](https://travis-ci.org/artem30801/CleverSwarm) ## Установка Скачайте или склонируйте этот репозиторий на компьютер и дроны: ```bash git clone https://github.com/artem30801/CleverSwarm.git ``` -Для дальнейших инструкций перейдите на Wiki +Для дальнейших инструкций перейдите в папку [docs](https://github.com/artem30801/CleverSwarm/tree/master/docs). From 14c989a0e98f9011a44b3b5817422491183c2832 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 14:58:11 +0300 Subject: [PATCH 23/35] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 38e9c1e..ff12512 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # clever-show +[![Build Status](https://travis-ci.org/artem30801/CleverSwarm.svg?branch=master)](https://travis-ci.org/artem30801/CleverSwarm) + Програмное обеспечение для запуска шоу дронов под управлением Raspberry Pi с пакетом COEX [Clever](https://github.com/copterexpress/clever). ### Пакет включает в себя: @@ -6,7 +8,6 @@ * [Серверное приложение](https://github.com/artem30801/CleverSwarm/tree/master/Server) для удаленного синхронизированного управления дронами и удобной настройки системы для воспроизведения анимации * [Аддон для Blender 2.8](https://github.com/artem30801/CleverSwarm/tree/master/blender-addon) для преобразования анимации полёта коптеров, созданной в Blender, в файлы полётов для каждого коптера * [Образ для Raspberry Pi](https://github.com/artem30801/CleverSwarm/releases/latest) для быстрого запуска ПО на коптере -[![Build Status](https://travis-ci.org/artem30801/CleverSwarm.svg?branch=master)](https://travis-ci.org/artem30801/CleverSwarm) ## Установка Скачайте или склонируйте этот репозиторий на компьютер и дроны: From cc2dc93203b23f2d9857d31808a2d4ef248f9279 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 14:22:16 +0300 Subject: [PATCH 24/35] blender-addon: Update README.md --- blender-addon/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blender-addon/README.md b/blender-addon/README.md index 5c594ba..50a5992 100644 --- a/blender-addon/README.md +++ b/blender-addon/README.md @@ -14,7 +14,7 @@ Every next row of the file contains following information about an object: ## How to use it Clone or download this repository ```bash -git clone https://github.com/artem30801/blender-csv-animation +git clone https://github.com/artem30801/CleverSwarm.git ``` Open Blender and install the addon: 1) Open User Prerences windows using main menu or shortcut (Ctrl + Alt + U): Files - User Preferences From c16ba87d10453bd967c347ea3373b79fb0d564b2 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 8 Jul 2019 17:03:08 +0300 Subject: [PATCH 25/35] builder: Add ability to move custom files from clever-config directory to clever image --- builder/assets/animation_map.txt | 25 ------- builder/clever-config/launch/aruco.launch | 37 ++++++++++ builder/clever-config/launch/clever.launch | 71 +++++++++++++++++++ .../clever-config/launch/main_camera.launch | 37 ++++++++++ builder/clever-config/map/animation_map.txt | 8 +++ builder/image-build.sh | 7 +- builder/image-configure.sh | 10 +-- 7 files changed, 160 insertions(+), 35 deletions(-) delete mode 100644 builder/assets/animation_map.txt create mode 100644 builder/clever-config/launch/aruco.launch create mode 100644 builder/clever-config/launch/clever.launch create mode 100644 builder/clever-config/launch/main_camera.launch create mode 100644 builder/clever-config/map/animation_map.txt diff --git a/builder/assets/animation_map.txt b/builder/assets/animation_map.txt deleted file mode 100644 index 8e04a74..0000000 --- a/builder/assets/animation_map.txt +++ /dev/null @@ -1,25 +0,0 @@ -0 0.3375 0.0 4.6 0 0 0 0 -1 0.3375 1.15 4.6 0 0 0 0 -2 0.3375 2.3 4.6 0 0 0 0 -3 0.3375 3.45 4.6 0 0 0 0 -4 0.3375 4.6 4.6 0 0 0 0 -5 0.3375 0.0 3.45 0 0 0 0 -6 0.3375 1.15 3.45 0 0 0 0 -7 0.3375 2.3 3.45 0 0 0 0 -8 0.3375 3.45 3.45 0 0 0 0 -9 0.3375 4.6 3.45 0 0 0 0 -10 0.3375 0.0 2.3 0 0 0 0 -11 0.3375 1.15 2.3 0 0 0 0 -12 0.3375 2.3 2.3 0 0 0 0 -13 0.3375 3.45 2.3 0 0 0 0 -14 0.3375 4.6 2.3 0 0 0 0 -15 0.3375 0.0 1.15 0 0 0 0 -16 0.3375 1.15 1.15 0 0 0 0 -17 0.3375 2.3 1.15 0 0 0 0 -18 0.3375 3.45 1.15 0 0 0 0 -19 0.3375 4.6 1.15 0 0 0 0 -20 0.3375 0.0 0.0 0 0 0 0 -21 0.3375 1.15 0.0 0 0 0 0 -22 0.3375 2.3 0.0 0 0 0 0 -23 0.3375 3.45 0.0 0 0 0 0 -24 0.3375 4.6 0.0 0 0 0 0 diff --git a/builder/clever-config/launch/aruco.launch b/builder/clever-config/launch/aruco.launch new file mode 100644 index 0000000..d7754d9 --- /dev/null +++ b/builder/clever-config/launch/aruco.launch @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/builder/clever-config/launch/clever.launch b/builder/clever-config/launch/clever.launch new file mode 100644 index 0000000..1020ea2 --- /dev/null +++ b/builder/clever-config/launch/clever.launch @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/builder/clever-config/launch/main_camera.launch b/builder/clever-config/launch/main_camera.launch new file mode 100644 index 0000000..92bec22 --- /dev/null +++ b/builder/clever-config/launch/main_camera.launch @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/builder/clever-config/map/animation_map.txt b/builder/clever-config/map/animation_map.txt new file mode 100644 index 0000000..9a54274 --- /dev/null +++ b/builder/clever-config/map/animation_map.txt @@ -0,0 +1,8 @@ +107 0.33 0 0 0 0 0 0 +106 0.33 0.77 0 0 0 0 0 +105 0.33 0 0.77 0 0 0 0 +104 0.33 0.77 0.77 0 0 0 0 +103 0.33 0 1.54 0 0 0 0 +102 0.33 0.77 1.54 0 0 0 0 +101 0.33 0 2.31 0 0 0 0 +100 0.33 0.77 2.31 0 0 0 0 diff --git a/builder/image-build.sh b/builder/image-build.sh index 5432a5f..e2f70d5 100755 --- a/builder/image-build.sh +++ b/builder/image-build.sh @@ -30,10 +30,12 @@ echo_stamp() { REPO_DIR="/mnt" SCRIPTS_DIR="${REPO_DIR}/builder" +CONFIG_DIR="${SCRIPTS_DIR}/clever-config" IMAGES_DIR="${REPO_DIR}/images" [[ ! -d ${SCRIPTS_DIR} ]] && (echo_stamp "Directory ${SCRIPTS_DIR} doesn't exist" "ERROR"; exit 1) [[ ! -d ${IMAGES_DIR} ]] && mkdir ${IMAGES_DIR} && echo_stamp "Directory ${IMAGES_DIR} was created successful" "SUCCESS" +[[ ! -d ${CONFIG_DIR} ]] && mkdir ${CONFIG_DIR} && echo_stamp "Directory ${CONFIG_DIR} was created successful" "SUCCESS" if [[ -z ${TRAVIS_TAG} ]]; then IMAGE_VERSION="$(cd ${REPO_DIR}; git log --format=%h -1)"; else IMAGE_VERSION="${TRAVIS_TAG}"; fi # IMAGE_VERSION="${TRAVIS_TAG:=$(cd ${REPO_DIR}; git log --format=%h -1)}" @@ -105,7 +107,10 @@ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" # Copy service file for clever show client img-chroot ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clever-show.service' '/lib/systemd/system/' -img-chroot ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/animation_map.txt' '/home/pi/catkin_ws/src/clever/aruco_pose/map/' + +# Copy config files for clever +if [[ -d "${CONFIG_DIR}/launch" ]]; then img-chroot ${IMAGE_PATH} copy ${CONFIG_DIR}'/launch' '/home/pi/catkin_ws/src/clever/clever'; fi +if [[ -d "${CONFIG_DIR}/map" ]]; then img-chroot ${IMAGE_PATH} copy ${CONFIG_DIR}'/map' '/home/pi/catkin_ws/src/clever/aruco_pose'; fi # Shrink image img-resize ${IMAGE_PATH} diff --git a/builder/image-configure.sh b/builder/image-configure.sh index 3ad8cf5..f7e0885 100755 --- a/builder/image-configure.sh +++ b/builder/image-configure.sh @@ -23,7 +23,7 @@ echo_stamp() { } # rename wifi ssid -sed -i "s/NEW_SSID='CLEVER/NEW_SSID='CleverShow/" /root/init_rpi.sh +sed -i "s/NEW_SSID='CLEVER/NEW_SSID='CLEVERSHOW/" /root/init_rpi.sh # add sudoers variables to make sudo works with ros (for led strip) grep -qxF 'Defaults env_keep += "ROS_LOG_DIR"' /etc/sudoers || cat << EOT >> /etc/sudoers @@ -38,13 +38,5 @@ Defaults env_keep += "ROS_HOME" Defaults env_keep += "ROS_LOG_DIR" EOT -# configure aruco.launch and clever.launch (for positioning with aruco map) -sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/aruco.launch -sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/aruco.launch -sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/aruco.launch -sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch -sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch -sed -i '/' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch - echo_stamp "Image was configured!" "SUCCESS" From c84d5501f83c0ecaee0bfef3c80aee39c31c5eab Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 12 Jul 2019 17:19:43 +0300 Subject: [PATCH 26/35] Fix merge conflict --- Drone/FlightLib/FlightLib.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Drone/FlightLib/FlightLib.py b/Drone/FlightLib/FlightLib.py index 57a7443..cb653a1 100644 --- a/Drone/FlightLib/FlightLib.py +++ b/Drone/FlightLib/FlightLib.py @@ -396,8 +396,5 @@ def flip(min_z = FLIP_MIN_Z, frame_id = FRAME_ID): #TODO Flip in different direc logger.info('Flip succeeded!') #print('Flip succeeded!') navto(x=start_telemetry.x, y=start_telemetry.y, z=start_telemetry.z, yaw=start_telemetry.yaw, frame_id=frame_id) # finish flip -<<<<<<< HEAD -======= return True ->>>>>>> alpha From 07d47bbfc2af4db8cd23573995a4c8a3818a7deb Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 18 Jul 2019 16:20:05 +0300 Subject: [PATCH 27/35] Change checks type for takeoff and flip actions --- Server/server_qt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/server_qt.py b/Server/server_qt.py index ed3339f..1d3247d 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -143,14 +143,14 @@ class MainWindow(QtWidgets.QMainWindow): @pyqtSlot() def takeoff_selected(self, **kwargs): for copter in self.model.user_selected(): - if all_checks(copter): + if takeoff_checks(copter): copter.client.send_message("takeoff") @confirmation_required("This operation will flip(!!!) copters immediately. Proceed?") @pyqtSlot() def flip(self, **kwargs): for copter in self.model.user_selected(): - if all_checks(copter): + if takeoff_checks(copter): copter.client.send_message("flip") @pyqtSlot() From b3ffa26132d3606a25dca946d47b6418d4e7bd2d Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 22 Jul 2019 00:33:13 +0300 Subject: [PATCH 28/35] builder: remove git depth from .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9fe38dd..5603a77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ env: - if [[ -z ${TRAVIS_TAG} ]]; then IMAGE_VERSION="${TRAVIS_COMMIT}}"; else IMAGE_VERSION="${TRAVIS_TAG}"; fi - IMAGE_NAME="$(basename -s '.git' ${TARGET_REPO})_${IMAGE_VERSION}.img" git: - depth: 50 + depth: false jobs: fast_finish: true include: From eee8e831d96644a1e33a8b066f3863272eea5c85 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 22 Jul 2019 02:30:25 +0300 Subject: [PATCH 29/35] docs: Rename article file about image building --- docs/{image-building => image-building.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{image-building => image-building.md} (100%) diff --git a/docs/image-building b/docs/image-building.md similarity index 100% rename from docs/image-building rename to docs/image-building.md From c03d0d61bd9f49d88ca868b90c7e50eafc4bf204 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 22 Jul 2019 02:31:22 +0300 Subject: [PATCH 30/35] Server: add chrony example configuration file --- Server/chrony.conf | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Server/chrony.conf diff --git a/Server/chrony.conf b/Server/chrony.conf new file mode 100644 index 0000000..bccbf9e --- /dev/null +++ b/Server/chrony.conf @@ -0,0 +1,5 @@ +server master iburst +driftfile /var/lib/chrony/drift +allow 192.168.0.0/16 +makestep 1.0 3 +rtcsync \ No newline at end of file From 4947efe19f6181b590e3bb8268fb2ebf08388f51 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 22 Jul 2019 02:49:59 +0300 Subject: [PATCH 31/35] docs: Add start tutorial --- docs/start-tutorial.md | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/docs/start-tutorial.md b/docs/start-tutorial.md index e69de29..104243c 100644 --- a/docs/start-tutorial.md +++ b/docs/start-tutorial.md @@ -0,0 +1,50 @@ +# Инструкция по настройке и запуску клиента и сервера + +## Список оборудования +Данное ПО предназначено для управления несколькими квадракоптерами с компьютера-сервера. Для полноценной работы необходимо следующее оборудование: +* Один или несколько квадрокоптеров, работающих на базе ПО [Клевер](https://github.com/copterexpress/clever). +* Компьютер с операционной системой Linux. +* Wifi роутер, работающий на частоте 2.4 ГГц, либо 5.8 ГГц, если эту частоту поддерживают wifi модули коптеров и компьютера. + +## Подготовка ПО +Скачайте на компьютер последний образ (CleverSwarm-XXX.img.zip) и исходный код (Source code) из последнего [релиза](https://github.com/artem30801/CleverSwarm/releases/latest). Разархивируйте исходный код в удобную директорию. + +## Настройка роутера +Для управления одним или несколькими коптерами требуется подключение коптеров и сервера к одной сети. Для этого требуется отдельный wifi роутер с известным SSID и паролем. Подключите компьютер, который будет использоваться в качестве сервера, к сети роутера и узнайте его ip адрес - он понадобится для дальнейшей настройки. + +## Настройка и запуск клиента + +* Запишите образ на microSD карту, используя [Etcher](https://www.balena.io/etcher/). +* Вставьте флешку в Raspberry Pi, включите коптер. Дождитесь появления сети `CLEVERSHOW-XXXX`. +* Подключитесь к сети коптера, используя пароль `cleverwifi`. +* Настройте коптер, чтобы корректно работал режим позиции. По-умолчанию образ сконфигурирован для получения позиции с камеры с помощью aruco-маркеров и optical flow. Камера направлена вниз и вперёд, загружена тестовая карта меток. Если ваш способ позиционирования отличается - можно либо настроить данный образ, либо [собрать образ](image-building.md) со своими настройками. +* Перейдите в директорию клиента и запустите скрипт настройки клиента +```bash +cd ~/CleverSwarm/Drone +sudo ./client_setup.sh +``` +* Выполните скрипт настройки клиента с указанными параметрами - SSID, пароль точки доступа, имя коптера, ip сервера. +* Коптер переключится в режим клиента указанной точки доступа и настроит автозапуск клиента copter_client.py + +Документация по клиентской части находится [здесь](client.md). + +## Настройка и запуск сервера + +* Установите [chrony](https://chrony.tuxfamily.org/index.html), Python 3 и PyQt5 на ваш компьютер +```bash +sudo apt install chrony python3 python3-pip +pip3 install PyQt5 +``` +* Подключитесь к wifi сети роутера, к которому подключены коптеры. +* Скопируйте [файл настроек chrony](../Server/chrony.conf) в `/etc/chrony/chrony.conf`. Если ip адрес сети начинается не с `192.168.`, то исправьте адрес после слова allow в скопированном файле настроек. +* Перезапустите сервис chrony +```bash +sudo systemctl restart chrony +``` +* Перейдите в директорию сервера из директории с исходным кодом и запустите сервер +```bash +cd source-code-dir/Server +python3 server_qt.py +``` + +Документация по серверной части находится [здесь](server.md). \ No newline at end of file From aa206a7f0148b0590ab977d8713ea9bfd2cde7ac Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 22 Jul 2019 02:59:22 +0300 Subject: [PATCH 32/35] Update README.md --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ff12512..ff3c0a0 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,7 @@ * [Аддон для Blender 2.8](https://github.com/artem30801/CleverSwarm/tree/master/blender-addon) для преобразования анимации полёта коптеров, созданной в Blender, в файлы полётов для каждого коптера * [Образ для Raspberry Pi](https://github.com/artem30801/CleverSwarm/releases/latest) для быстрого запуска ПО на коптере -## Установка -Скачайте или склонируйте этот репозиторий на компьютер и дроны: -```bash -git clone https://github.com/artem30801/CleverSwarm.git -``` -Для дальнейших инструкций перейдите в папку [docs](https://github.com/artem30801/CleverSwarm/tree/master/docs). +## Документация +Инструкция по запуску ПО находится [здесь](docs/start-tutorial.md). + +Подробная документация расположена в папке [docs](https://github.com/artem30801/CleverSwarm/tree/master/docs). From 0d5e25921a8487e9a0a2ff10bdce7ee63f5e9f2c Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 22 Jul 2019 04:16:04 +0300 Subject: [PATCH 33/35] docs: Add image building article --- docs/image-building.md | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/image-building.md b/docs/image-building.md index e69de29..748ef30 100644 --- a/docs/image-building.md +++ b/docs/image-building.md @@ -0,0 +1,46 @@ +# Сборка модифицированного образа + +Иногда возникает необходимость собрать образ с настройками коптера, отличными от релизной версии образа. Есть несколько способов это сделать. + +## Подготовка к сборке +Установите [docker](https://www.docker.com): +```bash +sudo apt install docker.io +``` + +## Локальная сборка с изменением настроек Клевера + +* Замените файлы настроек Клевера (launch файлы и карту) в [папке](../builder/clever-config) `builder/clever-config` в директории с исходным кодом CleverSwarm. +* Соберите свой образ с помощью docker: +```bash +cd source-dir +sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 +``` + +## Ручная настройка образа + +* Разархивируйте файл со скачанным образом, перейдите в директорию с этим образом, и войдите в консоль сборщика образа с помощью команды: +```bash +cd image-dir +sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-chroot /mnt/ +``` + где - имя файла образа. + В открывшемся терминале с помощью стандартных программ (nano, git, cp, apt-get) вы можете донастроить образ. +* Внешние файлы вы можете перенести в образ с помощью команды: +```bash +sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-chroot /mnt/ copy /mnt/ +``` + где - файл, который нужно перенести в образ (расположение относительно папки с образом, например `../builder/assets/clever-show.service`), а - путь в образе, куда нужно переместить файл. +* Если в образе не хватает места для всех необходимых файлов, можно расширить образ с помощью команды: +```bash +sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-resize /mnt/ max +``` + где - размер в байтах. Например 5G будет означать 5GB, а 5M - 5MB. +* После расширения образа его можно сжать до минимального размера + 10МB командой +```bash +sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-resize /mnt/ min +``` + +## Изменение скриптов сборки + +Статья по изменению скриптов сборки образа и создания кастомной сборки написана [здесь](https://clever.copterexpress.com/ru/image_building.html) \ No newline at end of file From c6fe2e76f246336df7f9c579babf491f253d1d2a Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 22 Jul 2019 04:21:13 +0300 Subject: [PATCH 34/35] docs: image-building - fix style --- docs/image-building.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/image-building.md b/docs/image-building.md index 748ef30..855f3a9 100644 --- a/docs/image-building.md +++ b/docs/image-building.md @@ -24,18 +24,17 @@ sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-t cd image-dir sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-chroot /mnt/ ``` - где - имя файла образа. - В открывшемся терминале с помощью стандартных программ (nano, git, cp, apt-get) вы можете донастроить образ. +где `` - имя файла образа. В открывшемся терминале с помощью стандартных программ (nano, git, cp, apt-get) вы можете донастроить образ. * Внешние файлы вы можете перенести в образ с помощью команды: ```bash sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-chroot /mnt/ copy /mnt/ ``` - где - файл, который нужно перенести в образ (расположение относительно папки с образом, например `../builder/assets/clever-show.service`), а - путь в образе, куда нужно переместить файл. +где `` - файл, который нужно перенести в образ (расположение относительно папки с образом, например `../builder/assets/clever-show.service`), а `` - путь в образе, куда нужно переместить файл. * Если в образе не хватает места для всех необходимых файлов, можно расширить образ с помощью команды: ```bash sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-resize /mnt/ max ``` - где - размер в байтах. Например 5G будет означать 5GB, а 5M - 5MB. +где `` - размер в байтах. Например 5G будет означать 5GB, а 5M - 5MB. * После расширения образа его можно сжать до минимального размера + 10МB командой ```bash sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-resize /mnt/ min From bba9ff72a6cc9332c813418b6df689be550b8375 Mon Sep 17 00:00:00 2001 From: artem30801 <38689676+artem30801@users.noreply.github.com> Date: Fri, 26 Jul 2019 11:24:07 +0300 Subject: [PATCH 35/35] docs/server.md updated from https://stackedit.io/ --- docs/server.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/server.md b/docs/server.md index e69de29..cbf66cb 100644 --- a/docs/server.md +++ b/docs/server.md @@ -0,0 +1,4 @@ +#Установка и настройка серв + \ No newline at end of file