From 9988299a11ecdfa47c594bda5e7b9256e7cfaad9 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 02:28:19 +0300 Subject: [PATCH 01/43] Drone: Add gps frame broadcast prototype --- Drone/copter_client.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 4349565..d4d7477 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -33,6 +33,16 @@ from geometry_msgs.msg import Point, Quaternion, TransformStamped from tf.transformations import quaternion_from_euler, euler_from_quaternion, quaternion_multiply import tf2_ros +from geographiclib.geodesic import Geodesic + +Earth = Geodesic.WGS84 + +def dist(x, y): + return math.sqrt(x**2+y**2) + +def azi(x, y): + return 90 - math.atan2(y,x)*180/math.pi + static_bloadcaster = tf2_ros.StaticTransformBroadcaster() emergency = False @@ -98,13 +108,12 @@ class CopterClient(client.Client): from FlightLib import LedLib LedLib.init_led(self.config.led_pin) task_manager_instance.start() # TODO move to self + start_subscriber() + telemetry.start_loop() if self.config.copter_frame_id == "floor": self.start_floor_frame_broadcast() elif self.config.copter_frame_id == "gps": self.start_gps_frame_broadcast() - start_subscriber() - - telemetry.start_loop() super(CopterClient, self).start() def start_floor_frame_broadcast(self): @@ -120,7 +129,22 @@ class CopterClient(client.Client): static_bloadcaster.sendTransform(trans) def start_gps_frame_broadcast(self): - return + gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread") + gps_frame_thread.start() + + def gps_frame_broadcast_loop(self): + rate = rospy.Rate(1) + while not rospy.is_shutdown(): + telem = telemetry.ros_telemetry + if telem is not None: + if math.isnan(telem.lat) or math.isnan(telem.lon) or math.isnan(telem.x) or math.isnan(telem.y): + logger.info("Can't get position from telemetry") + else: + new = Earth.Direct(telem.lat, telem.lon, azi(-telem.x,-telem.y), dist(telem.x,telem.y)) + lat_init = new['lat2'] + lon_init = new['lon2'] + logger.info("Initial lat: {} | lon: {}".format(lat_init, lon_init)) + def restart_service(name): os.system("systemctl restart {}".format(name)) From e399915c782d49063cc9606f6a4d93c86c05df97 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 02:40:58 +0300 Subject: [PATCH 02/43] Drone: Fix telemetry get --- Drone/copter_client.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index d4d7477..803a67f 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -135,7 +135,7 @@ class CopterClient(client.Client): def gps_frame_broadcast_loop(self): rate = rospy.Rate(1) while not rospy.is_shutdown(): - telem = telemetry.ros_telemetry + telem = telemetry.get_ros_telemetry() if telem is not None: if math.isnan(telem.lat) or math.isnan(telem.lon) or math.isnan(telem.x) or math.isnan(telem.y): logger.info("Can't get position from telemetry") @@ -144,6 +144,7 @@ class CopterClient(client.Client): lat_init = new['lat2'] lon_init = new['lon2'] logger.info("Initial lat: {} | lon: {}".format(lat_init, lon_init)) + rate.sleep() def restart_service(name): @@ -802,6 +803,9 @@ class Telemetry: self.time_delta = time.time() self.round_telemetry() + def get_ros_telemetry(self): + return self.ros_telemetry + def update_telemetry_slow(self): self.animation_id = animation.get_id() self.git_version = self.get_git_version() From 7311e5b59aca9d4b6d8e4276df06826a84e9eb51 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 02:45:03 +0300 Subject: [PATCH 03/43] Drone: Update copter client --- Drone/copter_client.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 803a67f..4b56886 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -94,6 +94,7 @@ class CopterClient(client.Client): super(CopterClient, self).__init__(config_path) self.load_config() self.frames = {} + self.telemetry = None def load_config(self): super(CopterClient, self).load_config() @@ -109,7 +110,8 @@ class CopterClient(client.Client): LedLib.init_led(self.config.led_pin) task_manager_instance.start() # TODO move to self start_subscriber() - telemetry.start_loop() + self.telemetry = Telemetry() + self.telemetry.start_loop() if self.config.copter_frame_id == "floor": self.start_floor_frame_broadcast() elif self.config.copter_frame_id == "gps": @@ -135,7 +137,7 @@ class CopterClient(client.Client): def gps_frame_broadcast_loop(self): rate = rospy.Rate(1) while not rospy.is_shutdown(): - telem = telemetry.get_ros_telemetry() + telem = self.telemetry.get_ros_telemetry() if telem is not None: if math.isnan(telem.lat) or math.isnan(telem.lon) or math.isnan(telem.x) or math.isnan(telem.y): logger.info("Can't get position from telemetry") @@ -943,7 +945,6 @@ def emergency_callback(data): if __name__ == "__main__": - telemetry = Telemetry() copter_client = CopterClient() task_manager = tasking.TaskManager() rospy.Subscriber('/emergency', Bool, emergency_callback) From 3f0990173f4b46c083d72a0529906fe17c38efe1 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 02:58:29 +0300 Subject: [PATCH 04/43] Drone: Add gps frame broadcast --- Drone/copter_client.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 4b56886..d61314d 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -131,6 +131,14 @@ class CopterClient(client.Client): static_bloadcaster.sendTransform(trans) def start_gps_frame_broadcast(self): + trans = TransformStamped() + trans.transform.translation.x = 0 + trans.transform.translation.y = 0 + trans.transform.translation.z = 0 + trans.transform.rotation = Quaternion(*quaternion_from_euler(0,0,0)) + trans.header.frame_id = "map" + trans.child_frame_id = self.config.copter_frame_id + static_bloadcaster.sendTransform(trans) gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread") gps_frame_thread.start() From 67d77694b2d6d5ac614c118986cea35ce22a1865 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 16:27:00 +0300 Subject: [PATCH 05/43] Drone: Add gps xy and dy counting --- Drone/copter_client.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index d61314d..4bb98fc 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -43,7 +43,10 @@ def dist(x, y): def azi(x, y): return 90 - math.atan2(y,x)*180/math.pi -static_bloadcaster = tf2_ros.StaticTransformBroadcaster() +def get_xy(dist, azi): + return dist*math.sin(azi), dist*cos(azi) + +static_broadcaster = tf2_ros.StaticTransformBroadcaster() emergency = False @@ -119,6 +122,8 @@ class CopterClient(client.Client): super(CopterClient, self).start() def start_floor_frame_broadcast(self): + if self.config.floor_frame_parent == "gps": + self.start_gps_frame_broadcast() trans = TransformStamped() trans.transform.translation.x = self.config.floor_frame_translation[0] trans.transform.translation.y = self.config.floor_frame_translation[1] @@ -128,7 +133,7 @@ class CopterClient(client.Client): math.radians(self.config.floor_frame_rotation[2]))) trans.header.frame_id = self.config.floor_frame_parent trans.child_frame_id = self.config.copter_frame_id - static_bloadcaster.sendTransform(trans) + static_broadcaster.sendTransform(trans) def start_gps_frame_broadcast(self): trans = TransformStamped() @@ -138,22 +143,28 @@ class CopterClient(client.Client): trans.transform.rotation = Quaternion(*quaternion_from_euler(0,0,0)) trans.header.frame_id = "map" trans.child_frame_id = self.config.copter_frame_id - static_bloadcaster.sendTransform(trans) + static_broadcaster.sendTransform(trans) gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread") gps_frame_thread.start() def gps_frame_broadcast_loop(self): rate = rospy.Rate(1) while not rospy.is_shutdown(): - telem = self.telemetry.get_ros_telemetry() + telem = FlightLib.get_telemetry_locked(frame_id = "map") if telem is not None: if math.isnan(telem.lat) or math.isnan(telem.lon) or math.isnan(telem.x) or math.isnan(telem.y): logger.info("Can't get position from telemetry") else: - new = Earth.Direct(telem.lat, telem.lon, azi(-telem.x,-telem.y), dist(telem.x,telem.y)) - lat_init = new['lat2'] - lon_init = new['lon2'] - logger.info("Initial lat: {} | lon: {}".format(lat_init, lon_init)) + #pos_init = Earth.Direct(telem.lat, telem.lon, azi(-telem.x,-telem.y), dist(telem.x,telem.y)) + #lat_init = pos_init['lat2'] + #lon_init = pos_init['lon2'] + #logger.info("Initial lat: {} | lon: {}".format(lat_init, lon_init)) + geo_delta = Earth.Inverse(telem.lat, telem.lon, self.config.gps_lat, self.config.gps_lon) + dx, dy = get_xy(geo_delta['s12'], geo_delta['azi2']) + gps_dx = telem.x + dx + gps_dy = telem.y + dy + logger.info("GPS frame dx: {} | dy: {}".format(gps_dx, gps_dy)) + rate.sleep() From 69bb8d7158981268a57b06cc089729c7e330a041 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 16:56:50 +0300 Subject: [PATCH 06/43] Drone: Update configspec for GPS --- Drone/config/spec/configspec_client.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Drone/config/spec/configspec_client.ini b/Drone/config/spec/configspec_client.ini index a6d56d5..4678684 100644 --- a/Drone/config/spec/configspec_client.ini +++ b/Drone/config/spec/configspec_client.ini @@ -58,8 +58,8 @@ translation = float_list(default=list(0.0, 0.0, 0.0), min=3, max=3) rotation = float_list(default=list(0.0, 0.0, 0.0), min=3, max=3) [GPS FRAME] -lat = float(default=0) -lon = float(default=0) +lat = string(default=0) +lon = string(default=0) yaw = float(default=0) [ANIMATION] From 95917545c299cc8ca757b7f839de508f155c9e65 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 16:57:55 +0300 Subject: [PATCH 07/43] Drone: Update getting GPS frame values --- Drone/copter_client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 4bb98fc..6a6426e 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -159,7 +159,9 @@ class CopterClient(client.Client): #lat_init = pos_init['lat2'] #lon_init = pos_init['lon2'] #logger.info("Initial lat: {} | lon: {}".format(lat_init, lon_init)) - geo_delta = Earth.Inverse(telem.lat, telem.lon, self.config.gps_lat, self.config.gps_lon) + lat = float(self.config.gps_frame_lat) + lon = float(self.config.gps_frame_lon) + geo_delta = Earth.Inverse(telem.lat, telem.lon, lat, lon) dx, dy = get_xy(geo_delta['s12'], geo_delta['azi2']) gps_dx = telem.x + dx gps_dy = telem.y + dy From 1f70520ac5d3ca2e5dcd4177e9e9209c07758daf Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 17:02:26 +0300 Subject: [PATCH 08/43] Drone: Fix typo --- 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 6a6426e..bc015e2 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -44,7 +44,7 @@ def azi(x, y): return 90 - math.atan2(y,x)*180/math.pi def get_xy(dist, azi): - return dist*math.sin(azi), dist*cos(azi) + return dist*math.sin(azi), dist*math.cos(azi) static_broadcaster = tf2_ros.StaticTransformBroadcaster() From bef932871f237c75cd26e5e2e94ec8be3958083e Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 16:51:57 +0000 Subject: [PATCH 09/43] Drone: Fix GPS delta position counting --- Drone/copter_client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index bc015e2..8cd4f36 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -44,7 +44,7 @@ def azi(x, y): return 90 - math.atan2(y,x)*180/math.pi def get_xy(dist, azi): - return dist*math.sin(azi), dist*math.cos(azi) + return dist*math.sin(math.radians(azi)), dist*math.cos(math.radians(azi)) static_broadcaster = tf2_ros.StaticTransformBroadcaster() @@ -162,7 +162,8 @@ class CopterClient(client.Client): lat = float(self.config.gps_frame_lat) lon = float(self.config.gps_frame_lon) geo_delta = Earth.Inverse(telem.lat, telem.lon, lat, lon) - dx, dy = get_xy(geo_delta['s12'], geo_delta['azi2']) + logger.info("dist: {} | azi: {}".format(geo_delta['s12'], geo_delta['azi1'])) + dx, dy = get_xy(geo_delta['s12'], geo_delta['azi1']) gps_dx = telem.x + dx gps_dy = telem.y + dy logger.info("GPS frame dx: {} | dy: {}".format(gps_dx, gps_dy)) From 72e1d1e9164978fd016028b8e2a13445cace6cae Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 21 May 2020 20:07:47 +0300 Subject: [PATCH 10/43] Drone: Add GPS frame static broadcast --- Drone/copter_client.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 8cd4f36..83534d4 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -142,7 +142,7 @@ class CopterClient(client.Client): trans.transform.translation.z = 0 trans.transform.rotation = Quaternion(*quaternion_from_euler(0,0,0)) trans.header.frame_id = "map" - trans.child_frame_id = self.config.copter_frame_id + trans.child_frame_id = "gps" static_broadcaster.sendTransform(trans) gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread") gps_frame_thread.start() @@ -155,10 +155,6 @@ class CopterClient(client.Client): if math.isnan(telem.lat) or math.isnan(telem.lon) or math.isnan(telem.x) or math.isnan(telem.y): logger.info("Can't get position from telemetry") else: - #pos_init = Earth.Direct(telem.lat, telem.lon, azi(-telem.x,-telem.y), dist(telem.x,telem.y)) - #lat_init = pos_init['lat2'] - #lon_init = pos_init['lon2'] - #logger.info("Initial lat: {} | lon: {}".format(lat_init, lon_init)) lat = float(self.config.gps_frame_lat) lon = float(self.config.gps_frame_lon) geo_delta = Earth.Inverse(telem.lat, telem.lon, lat, lon) @@ -167,6 +163,15 @@ class CopterClient(client.Client): gps_dx = telem.x + dx gps_dy = telem.y + dy logger.info("GPS frame dx: {} | dy: {}".format(gps_dx, gps_dy)) + trans = TransformStamped() + trans.transform.translation.x = gps_dx + trans.transform.translation.y = gps_dy + trans.transform.translation.z = 0 + trans.transform.rotation = Quaternion(*quaternion_from_euler(0,0, + math.radians(self.config.gps_frame_yaw))) + trans.header.frame_id = "map" + trans.child_frame_id = "gps" + static_broadcaster.sendTransform(trans) rate.sleep() From 9f22603ecb286f18cffd3290fb20d89883c2db1b Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sat, 23 May 2020 15:56:43 +0300 Subject: [PATCH 11/43] Drone: Update animation_lib module --- Drone/animation_lib.py | 346 ++++++++++++++++++++++------------------- 1 file changed, 188 insertions(+), 158 deletions(-) diff --git a/Drone/animation_lib.py b/Drone/animation_lib.py index 2018fdb..6d2c4ad 100644 --- a/Drone/animation_lib.py +++ b/Drone/animation_lib.py @@ -1,6 +1,8 @@ +import os import time import csv import copy +import numpy import rospy import logging import threading @@ -15,165 +17,211 @@ try: except ImportError: print("Can't import LedLib") -import tasking_lib as tasking - logger = logging.getLogger(__name__) interrupt_event = threading.Event() -anim_id = "Empty id" +def moving(f1, f2, delta, x = True, y = True, z = True): + return ((abs(f1['x'] - f2['x']) > delta) and x + or (abs(f1['y'] - f2['y']) > delta) and y + or (abs(f1['z'] - f2['z']) > delta) and z) -# TODO refactor as class -# TODO separate code for frames transformations (e.g. for gps) +class Animation(object): + def __init__(self, config = None, filepath = "animation.csv"): + self.id = None + self.static_begin_time = None + self.takeoff_time = None + self.original_frames = None + self.static_begin_frames = None + self.takeoff_frames = None + self.route_frames = None + self.land_frames = None + self.static_end_frames = None + self.output_frames = None + self.output_frames_min_z = None + self.filepath = filepath + if config is not None: + self.update_frames(config, filepath) -def get_id(filepath="animation.csv"): - global anim_id - try: - animation_file = open(filepath) - except IOError: - logger.debug("File {} can't be opened".format(filepath)) - anim_id = "No animation" - return anim_id - else: - with animation_file: - csv_reader = csv.reader( - animation_file, delimiter=',', quotechar='|' - ) - row_0 = csv_reader.next() - if len(row_0) == 1: - anim_id = row_0[0] - logger.debug("Got animation_id: {}".format(anim_id)) - else: - anim_id = "Empty id" - logger.debug("No animation id in file") - return anim_id - -def get_start_xy(filepath="animation.csv", x_ratio=1, y_ratio=1, z_ratio=1): - try: - animation_file = open(filepath) - except IOError: - logger.debug("File {} can't be opened".format(filepath)) - anim_id = "No animation" - return float('nan'), float('nan') - else: - with animation_file: - csv_reader = csv.reader( - animation_file, delimiter=',', quotechar='|' - ) - try: - row_frame = csv_reader.next() - except: - return float('nan'), float('nan') - if len(row_frame) == 1: - anim_id = row_frame[0] - logger.debug("Got animation_id: {}".format(row_frame[0])) - row_frame = csv_reader.next() - if len(row_frame) == 2: - logger.debug("Got frame delay: {}".format(row_frame[1])) - row_frame - csv_reader.next() - try: - frame_number, x, y, z, yaw, red, green, blue = row_frame - except: - return float('nan'), float('nan') - return float(x)*x_ratio, float(y)*y_ratio - - -def load_animation(filepath="animation.csv", default_delay = 0.1, x0=0, y0=0, z0=0, x_ratio=1, y_ratio=1, z_ratio=1): - imported_frames = [] - global anim_id - try: - animation_file = open(filepath) - except IOError: - logger.debug("File {} can't be opened".format(filepath)) - anim_id = "No animation" - else: - with animation_file: - current_frame_delay = default_delay - csv_reader = csv.reader( - animation_file, delimiter=',', quotechar='|' - ) - row_0 = csv_reader.next() - if len(row_0) == 1: - anim_id = row_0[0] - logger.debug("Got animation_id: {}".format(anim_id)) - elif len(row_0) == 2: - current_frame_delay = float(row_0[1]) - logger.debug("Got new frame delay: {}".format(current_frame_delay)) - else: - logger.debug("No animation id in file") - frame_number, x, y, z, yaw, red, green, blue = row_0 - imported_frames.append({ - 'number': int(frame_number), - 'x': x_ratio*float(x) + x0, - 'y': y_ratio*float(y) + y0, - 'z': z_ratio*float(z) + z0, - 'yaw': float(yaw), - 'red': int(red), - 'green': int(green), - 'blue': int(blue), - 'delay': current_frame_delay - }) - for row in csv_reader: - if len(row) == 2: - current_frame_delay = float(row[1]) + def load(self, delay=0.1, filepath="animation.csv"): + self.original_frames = [] + self.corrected_frames = [] + self.filepath = filepath + try: + animation_file = open(filepath) + except IOError: + logger.debug("File {} can't be opened".format(filepath)) + self.id = "No animation" + else: + with animation_file: + current_frame_delay = delay + csv_reader = csv.reader( + animation_file, delimiter=',', quotechar='|' + ) + row_0 = csv_reader.next() + if len(row_0) == 1: + self.id = row_0[0] + logger.debug("Got animation_id: {}".format(self.id)) + elif len(row_0) == 2: + current_frame_delay = float(row_0[1]) + logger.debug("Got new frame delay: {}".format(current_frame_delay)) else: - frame_number, x, y, z, yaw, red, green, blue = row - imported_frames.append({ + logger.debug("No animation id in file") + frame_number, x, y, z, yaw, red, green, blue = row_0 + self.original_frames.append({ 'number': int(frame_number), - 'x': x_ratio*float(x) + x0, - 'y': y_ratio*float(y) + y0, - 'z': z_ratio*float(z) + z0, + 'x': float(x), + 'y': float(y), + 'z': float(z), 'yaw': float(yaw), 'red': int(red), 'green': int(green), 'blue': int(blue), 'delay': current_frame_delay }) - return imported_frames + for row in csv_reader: + if len(row) == 2: + current_frame_delay = float(row[1]) + logger.debug("Got new frame delay: {}".format(current_frame_delay)) + else: + frame_number, x, y, z, yaw, red, green, blue = row + self.original_frames.append({ + 'number': int(frame_number), + 'x': float(x), + 'y': float(y), + 'z': float(z), + 'yaw': float(yaw), + 'red': int(red), + 'green': int(green), + 'blue': int(blue), + 'delay': current_frame_delay + }) + self.split_animation() -def correct_animation(frames, frame_delay=0.1, min_takeoff_height=0.5, move_delta=0.01, check_takeoff=True, check_land=True): - corrected_frames = copy.deepcopy(frames) - start_action = 'takeoff' - frames_to_start = 0 - time_to_start = 0 - if len(corrected_frames) == 0: - raise Exception('Nothing to correct!') - # Check takeoff - # If copter takes off in animation file, copter must be armed first and then all animation can be played - if (corrected_frames[0]['z'] < min_takeoff_height) and check_takeoff: - start_action = 'arm' - # If the first point is low, then detect moment to arm, - # delete all points, where copter is standing, and count time_delta - for i in range(len(corrected_frames)-1): - if corrected_frames[i-frames_to_start+1]['z'] - corrected_frames[i-frames_to_start]['z'] > move_delta: + ''' + Split animation into 5 parts: static_begin, takeoff, route, land, static_end + * static_begin and static_end are arrays of frames in the beginning and the end of animation, + where the drone doesn't move + * takeoff and land are arrays of frames after and before static frames of animation, + where the drone doesn't move in xy plane, and it's z coordinate only increases or decreases, respectively. + * route is the rest of the animation + Count static_begin_time and takeoff_time + ''' + def split_animation(self, move_delta=0.01): + if len(self.original_frames) == 0: + return + frames = copy.deepcopy(self.original_frames) + self.static_begin_frames = [] + self.takeoff_frames = [] + self.route_frames = [] + self.land_frames = [] + self.static_end_frames = [] + self.static_begin_time = 0 + self.takeoff_time = 0 + i = 0 # Moving index from the beginning + # Select static begin frames + while i < len(frames) - 1: + if moving(frames[i], frames[i+1], move_delta): break - time_to_start += corrected_frames[i-frames_to_start]['delay'] - del corrected_frames[i-frames_to_start] - frames_to_start += 1 - start_delay = time_to_start - # Check Land - # If copter lands in animation, landing points can be deleted - if (corrected_frames[len(corrected_frames)-1]['z'] < min_takeoff_height) and check_land: - for i in range(len(corrected_frames)-1,0,-1): - # print i - if abs(corrected_frames[i-1]['z'] - corrected_frames[i]['z']) < move_delta: + self.static_begin_time += frames[i]['delay'] + i += 1 + self.static_begin_frames = frames[:i+1] + frames = frames[i+1:] + i = 0 + # Select takeoff frames + while i < len(frames) - 1: + if moving(frames[i], frames[i+1], move_delta, z = False) or frames[i]['z'] - frames[i+1]['z'] <= 0: break - del corrected_frames[i] - for i in range(len(corrected_frames)-1,0,-1): - if (abs(corrected_frames[i-1]['x'] - corrected_frames[i]['x']) > move_delta or - abs(corrected_frames[i-1]['y'] - corrected_frames[i]['y']) > move_delta): + self.takeoff_time += frames[i]['delay'] + i += 1 + self.takeoff_frames = frames[:i+1] + frames = frames[i+1:] + i = len(frames) - 1 # Moving index from the end + # Select static end frames + while i >= 0: + if moving(frames[i], frames[i-1], move_delta): break - del corrected_frames[i] - return corrected_frames, start_action, start_delay + i -= 1 + self.static_end_frames = frames[i:] + frames = frames[:i] + i -= len(frames) - 1 + # Select land frames + while i >= 0: + if moving(frames[i], frames[i-1], move_delta, z = False) or frames[i-1]['z'] - frames[i]['z'] >= 0: + break + i -= 1 + self.land_frames = frames[i:] + # Get route frames + self.route_frames = frames[:i] -# Needs for test -def save_corrected_animation(frames, filename="corrected_animation.csv"): - corrected_animation = open(filename, mode='w+') - csv_writer = csv.writer(corrected_animation, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) - for frame in frames: - csv_writer.writerow([frame['number'],frame['x'], frame['y'], frame['z'], frame['delay']]) - # print frame - corrected_animation.close() + def make_output_frames(self, static_begin, takeoff, route, land, static_end): + self.output_frames = [] + if static_begin: + self.output_frames += self.static_begin_frames + if takeoff: + self.output_frames += self.takeoff_frames + if route: + self.output_frames += self.route_frames + if land: + self.output_frames += self.land_frames + if static_end: + self.output_frames += self.static_end_frames + self.output_frames_min_z = min(self.output_frames, key = lambda p: p['z'])['z'] + + def update_frames(self, config, filepath): + self.load(config.animation_frame_delay, filepath) + self.make_output_frames(config.animation_output_static_begin, + config.animation_output_takeoff, + config.animation_output_route, + config.animation_output_land, + config.animation_output_static_end) + + def get_scaled_output(self, ratio = (1,1,1), offset = (0,0,0)): + x0, y0, z0 = offset + x_ratio, y_ratio, z_ratio = ratio + scaled_frames = copy.deepcopy(self.output_frames) + for frame in scaled_frames: + frame['x'] = x_ratio*frame['x'] + x0 + frame['y'] = y_ratio*frame['y'] + y0 + frame['z'] = z_ratio*frame['z'] + z0 + return scaled_frames + + def get_scaled_output_min_z(self, ratio = (1,1,1), offset = (0,0,0)): + x0, y0, z0 = offset + x_ratio, y_ratio, z_ratio = ratio + return self.output_frames_min_z*z_ratio + z0 + + def get_start_point(self, ratio = (1,1,1), offset = (0,0,0)): + x0, y0, z0 = offset + x_ratio, y_ratio, z_ratio = ratio + first_frame = self.output_frames[0] + x = x_ratio*first_frame['x'] + x0 + y = y_ratio*first_frame['y'] + y0 + z = z_ratio*first_frame['z'] + z0 + return x, y, z + + def get_start_action(self, start_action, current_height, takeoff_level): + if start_action is 'auto': + if current_height > takeoff_level: + return 'takeoff' + else: + return 'play' + elif start_action in ('takeoff', 'play'): + return start_action + else: + return 'error' + + def check_ground(self, ground_level = 0, ratio = (1,1,1), offset = (0,0,0)): + return ground_level <= self.get_scaled_output_min_z(ratio, offset) + + # Need for tests + def save_corrected_animation(self): + name, ext = os.path.splitext(self.filepath) + filepath = name + '_corrected' + ext + with open(filepath, mode='w+') as corrected_animation: + csv_writer = csv.writer(corrected_animation, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) + for frame in self.corrected_frames: + csv_writer.writerow([frame['number'], frame['x'], frame['y'], frame['z'], frame['red'], frame['green'], frame['blue'], frame['delay']]) def convert_frame(frame): return ((frame['x'], frame['y'], frame['z']), (frame['red'], frame['green'], frame['blue']), frame['yaw']) @@ -189,24 +237,6 @@ try: if color: LedLib.fill(*color) - - - - def execute_animation(frames, frame_delay, frame_id='aruco_map', use_leds=True, flight_func=FlightLib.navto, - interrupter=interrupt_event): - next_frame_time = 0 - for frame in frames: - if interrupter.is_set(): - logger.warning("Animation playing function interrupted!") - interrupter.clear() - return - execute_frame(*convert_frame(frame), frame_id=frame_id, use_leds=use_leds, flight_func=flight_func, - interrupter=interrupter) - - next_frame_time += frame_delay - tasking.wait(next_frame_time, interrupter) - - def takeoff(z=1.5, safe_takeoff=True, frame_id='map', timeout=5.0, use_leds=True, interrupter=interrupt_event): if use_leds: From fa897d6e52a0020828b8c8e4da128cf28166cf0c Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Tue, 26 May 2020 10:40:18 +0300 Subject: [PATCH 12/43] Update addon and modify example animation --- blender-addon/addon.py | 30 +++++------ blender-addon/examples/basic.blend | Bin 0 -> 453148 bytes blender-addon/examples/basic/clever-1.csv | 51 +++++++++++++++++++ blender-addon/examples/two_drones_test.blend | Bin 669372 -> 0 bytes 4 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 blender-addon/examples/basic.blend create mode 100644 blender-addon/examples/basic/clever-1.csv delete mode 100644 blender-addon/examples/two_drones_test.blend diff --git a/blender-addon/addon.py b/blender-addon/addon.py index 221e6cf..e0cb41f 100644 --- a/blender-addon/addon.py +++ b/blender-addon/addon.py @@ -8,13 +8,13 @@ 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), + "name": "clever-show animation (.csv)", + "author": "Artem Vasiunik & Arthur Golubtsov", + "version": (0, 5, 0), "blender": (2, 80, 0), #"api": 36079, - "location": "File > Export > CSV Drone Swarm Animation Exporter (.csv)", - "description": "Export > CSV Drone Swarm Animation Exporter (.csv)", + "location": "File > Export > clever-show animation (.csv)", + "description": "Export > clever-show animation (.csv)", "warning": "", "wiki_url": "https://github.com/CopterExpress/clever-show/blob/master/blender-addon/README.md", "tracker_url": "https://github.com/CopterExpress/clever-show/issues", @@ -23,20 +23,20 @@ bl_info = { class ExportCsv(Operator, ExportHelper): - bl_idname = "export_swarm_anim.folder" - bl_label = "Export Drone Swarm animation" + bl_idname = "export_animation.folder" + bl_label = "Export clever-show animation" filename_ext = '' use_filter_folder = True use_namefilter: bpy.props.BoolProperty( name="Use name filter for objects", - default=True, + default=False, ) drones_name: bpy.props.StringProperty( name="Name identifier", description="Name identifier for all drone objects", - default="copter" + default="clever" ) show_warnings: bpy.props.BoolProperty( @@ -61,7 +61,7 @@ class ExportCsv(Operator, ExportHelper): filepath: StringProperty( name="File Path", - description="File path used for exporting CSV files", + description="File path used for exporting csv files", maxlen=1024, subtype='DIR_PATH', default="" @@ -96,11 +96,11 @@ class ExportCsv(Operator, ExportHelper): 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) @@ -135,9 +135,7 @@ class ExportCsv(Operator, ExportHelper): round(rot_z, 5), *rgb, ]) - - - + if speed_exeeded: self.report({'WARNING'}, "Drone '%s' speed limits exeeded" % drone_obj.name) if distance_exeeded: @@ -195,7 +193,7 @@ def calc_distance(start_point, end_point): def menu_func(self, context): self.layout.operator( ExportCsv.bl_idname, - text="CSV Drone Swarm Animation Exporter (.csv)" + text="clever-show animation (.csv)" ) diff --git a/blender-addon/examples/basic.blend b/blender-addon/examples/basic.blend new file mode 100644 index 0000000000000000000000000000000000000000..39d58b0e6c9a7b75a920b3ba45debca017b8470b GIT binary patch literal 453148 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 nf$YyhY={8|m*5WI6|IdGx(G7)|Ts;)en%CUk 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ν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%0D|dQNQRpL6)mNcjlj+ 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 MTQ`cu(|!N`50`DY!vFvP From 673cd20a43a00b5694db3adbaec09cee10a211b8 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Wed, 27 May 2020 15:34:07 +0300 Subject: [PATCH 13/43] Update animation lib and client specification --- Drone/animation_lib.py | 183 +++++++++++++++--------- Drone/config/spec/configspec_client.ini | 6 + 2 files changed, 121 insertions(+), 68 deletions(-) diff --git a/Drone/animation_lib.py b/Drone/animation_lib.py index 6d2c4ad..b75e745 100644 --- a/Drone/animation_lib.py +++ b/Drone/animation_lib.py @@ -6,7 +6,6 @@ import numpy import rospy import logging import threading -import ConfigParser try: from FlightLib import FlightLib @@ -21,13 +20,66 @@ logger = logging.getLogger(__name__) interrupt_event = threading.Event() -def moving(f1, f2, delta, x = True, y = True, z = True): - return ((abs(f1['x'] - f2['x']) > delta) and x - or (abs(f1['y'] - f2['y']) > delta) and y - or (abs(f1['z'] - f2['z']) > delta) and z) +def moving(f1, f2, delta, x=True, y=True, z=True): + return ((abs(f1.x - f2.x) > delta) and x + or (abs(f1.y - f2.y) > delta) and y + or (abs(f1.z - f2.z) > delta) and z) + +def get_numbers(frames): + numbers = [] + if frames: + for frame in frames: + numbers.append(frame.number) + return numbers + +class Frame(object): + params_dict = { + "number": None, + "x": None, + "y": None, + "z": None, + "yaw": None, + "red": None, + "green": None, + "blue": None, + "delay": None, + } + def __init__(self, csv_row=None, delay=None): + for key, value in self.params_dict.items(): + setattr(self, key, value) + if csv_row: + self.load_csv_row(csv_row) + if delay: + self.delay = delay + + def load_csv_row(self, csv_row): + number, x, y, z, yaw, red, green, blue = csv_row + self.number = int(number) + self.x = float(x) + self.y = float(y) + self.z = float(z) + self.yaw = float(yaw) + self.red = int(red) + self.green = int(green) + self.blue = int(blue) + + def get_pos(self): + if None in [self.x, self.y, self.z]: + return [] + else: + return [self.x, self.y, self.z] + + def get_color(self): + if None in [self.red, self.green, self.blue]: + return [] + else: + return [self.red, self.green, self.blue] + + def pose_is_valid(self): + return self.get_pos() and (self.yaw is not None) class Animation(object): - def __init__(self, config = None, filepath = "animation.csv"): + def __init__(self, config=None, filepath="animation.csv"): self.id = None self.static_begin_time = None self.takeoff_time = None @@ -43,7 +95,7 @@ class Animation(object): if config is not None: self.update_frames(config, filepath) - def load(self, delay=0.1, filepath="animation.csv"): + def load(self, filepath="animation.csv", delay=0.1): self.original_frames = [] self.corrected_frames = [] self.filepath = filepath @@ -67,42 +119,32 @@ class Animation(object): logger.debug("Got new frame delay: {}".format(current_frame_delay)) else: logger.debug("No animation id in file") - frame_number, x, y, z, yaw, red, green, blue = row_0 - self.original_frames.append({ - 'number': int(frame_number), - 'x': float(x), - 'y': float(y), - 'z': float(z), - 'yaw': float(yaw), - 'red': int(red), - 'green': int(green), - 'blue': int(blue), - 'delay': current_frame_delay - }) + try: + frame = Frame(row_0, current_frame_delay) + except ValueError as e: + logger.error("Can't parse row in csv file. {}".format(e)) + return + else: + self.original_frames.append(frame) for row in csv_reader: if len(row) == 2: current_frame_delay = float(row[1]) logger.debug("Got new frame delay: {}".format(current_frame_delay)) else: - frame_number, x, y, z, yaw, red, green, blue = row - self.original_frames.append({ - 'number': int(frame_number), - 'x': float(x), - 'y': float(y), - 'z': float(z), - 'yaw': float(yaw), - 'red': int(red), - 'green': int(green), - 'blue': int(blue), - 'delay': current_frame_delay - }) + try: + frame = Frame(row, current_frame_delay) + except ValueError as e: + logger.error("Can't parse row in csv file. {}".format(e)) + return + else: + self.original_frames.append(frame) self.split_animation() ''' Split animation into 5 parts: static_begin, takeoff, route, land, static_end - * static_begin and static_end are arrays of frames in the beginning and the end of animation, + * static_begin and static_end are chains of frames in the beginning and the end of animation, where the drone doesn't move - * takeoff and land are arrays of frames after and before static frames of animation, + * takeoff and land are chains of frames after and before static frames of animation, where the drone doesn't move in xy plane, and it's z coordinate only increases or decreases, respectively. * route is the rest of the animation Count static_begin_time and takeoff_time @@ -123,36 +165,41 @@ class Animation(object): while i < len(frames) - 1: if moving(frames[i], frames[i+1], move_delta): break - self.static_begin_time += frames[i]['delay'] + self.static_begin_time += frames[i].delay i += 1 - self.static_begin_frames = frames[:i+1] - frames = frames[i+1:] - i = 0 + if i > 0: + self.static_begin_frames = frames[:i+1] + frames = frames[i+1:] + i = 0 # Select takeoff frames while i < len(frames) - 1: - if moving(frames[i], frames[i+1], move_delta, z = False) or frames[i]['z'] - frames[i+1]['z'] <= 0: + if moving(frames[i], frames[i+1], move_delta, z = False) or (frames[i+1].z - frames[i].z <= 0): break - self.takeoff_time += frames[i]['delay'] + self.takeoff_time += frames[i].delay i += 1 - self.takeoff_frames = frames[:i+1] - frames = frames[i+1:] + if i > 0: + self.takeoff_frames = frames[:i+1] + frames = frames[i+1:] i = len(frames) - 1 # Moving index from the end # Select static end frames while i >= 0: if moving(frames[i], frames[i-1], move_delta): break i -= 1 - self.static_end_frames = frames[i:] - frames = frames[:i] - i -= len(frames) - 1 + if i < len(frames) - 1: + self.static_end_frames = frames[i+1:] + frames = frames[:i+1] + i = len(frames) - 1 # Select land frames while i >= 0: - if moving(frames[i], frames[i-1], move_delta, z = False) or frames[i-1]['z'] - frames[i]['z'] >= 0: + if moving(frames[i], frames[i-1], move_delta, z = False) or (frames[i-1].z - frames[i].z <= 0): break i -= 1 - self.land_frames = frames[i:] + if i < len(frames) - 1: + self.land_frames = frames[i+1:] + frames = frames[:i+1] # Get route frames - self.route_frames = frames[:i] + self.route_frames = frames def make_output_frames(self, static_begin, takeoff, route, land, static_end): self.output_frames = [] @@ -166,24 +213,25 @@ class Animation(object): self.output_frames += self.land_frames if static_end: self.output_frames += self.static_end_frames - self.output_frames_min_z = min(self.output_frames, key = lambda p: p['z'])['z'] + self.output_frames_min_z = min(self.output_frames, key = lambda p: p.z).z def update_frames(self, config, filepath): - self.load(config.animation_frame_delay, filepath) - self.make_output_frames(config.animation_output_static_begin, - config.animation_output_takeoff, - config.animation_output_route, - config.animation_output_land, - config.animation_output_static_end) + self.load(filepath, config.animation_frame_delay) + if self.original_frames: + self.make_output_frames(config.animation_output_static_begin, + config.animation_output_takeoff, + config.animation_output_route, + config.animation_output_land, + config.animation_output_static_end) def get_scaled_output(self, ratio = (1,1,1), offset = (0,0,0)): x0, y0, z0 = offset x_ratio, y_ratio, z_ratio = ratio scaled_frames = copy.deepcopy(self.output_frames) for frame in scaled_frames: - frame['x'] = x_ratio*frame['x'] + x0 - frame['y'] = y_ratio*frame['y'] + y0 - frame['z'] = z_ratio*frame['z'] + z0 + frame.x = x_ratio*frame.x + x0 + frame.y = y_ratio*frame.y + y0 + frame.z = z_ratio*frame.z + z0 return scaled_frames def get_scaled_output_min_z(self, ratio = (1,1,1), offset = (0,0,0)): @@ -195,9 +243,9 @@ class Animation(object): x0, y0, z0 = offset x_ratio, y_ratio, z_ratio = ratio first_frame = self.output_frames[0] - x = x_ratio*first_frame['x'] + x0 - y = y_ratio*first_frame['y'] + y0 - z = z_ratio*first_frame['z'] + z0 + x = x_ratio*first_frame.x + x0 + y = y_ratio*first_frame.y + y0 + z = z_ratio*first_frame.z + z0 return x, y, z def get_start_action(self, start_action, current_height, takeoff_level): @@ -221,20 +269,19 @@ class Animation(object): with open(filepath, mode='w+') as corrected_animation: csv_writer = csv.writer(corrected_animation, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) for frame in self.corrected_frames: - csv_writer.writerow([frame['number'], frame['x'], frame['y'], frame['z'], frame['red'], frame['green'], frame['blue'], frame['delay']]) - -def convert_frame(frame): - return ((frame['x'], frame['y'], frame['z']), (frame['red'], frame['green'], frame['blue']), frame['yaw']) + csv_writer.writerow([frame.number, frame.x, frame.y, frame.z, frame.red, frame.green, frame.blue, frame.delay]) try: - def execute_frame(point=(), color=(), yaw=float('Nan'), frame_id='aruco_map', use_leds=True, + def execute_frame(frame, frame_id='aruco_map', use_leds=True, flight_func=FlightLib.navto, auto_arm=False, flight_kwargs=None, interrupter=interrupt_event): if flight_kwargs is None: flight_kwargs = {} - - flight_func(*point, yaw=yaw, frame_id=frame_id, auto_arm=auto_arm, interrupter=interrupt_event, **flight_kwargs) + if frame.pose_is_valid(): + flight_func(x=frame.x, y=frame.y, z=frame.z, yaw=frame.yaw, frame_id=frame_id, auto_arm=auto_arm, interrupter=interrupt_event, **flight_kwargs) + else: + logger.debug("Frame pose is not valid for flying") if use_leds: - if color: + if frame.get_color: LedLib.fill(*color) def takeoff(z=1.5, safe_takeoff=True, frame_id='map', timeout=5.0, use_leds=True, diff --git a/Drone/config/spec/configspec_client.ini b/Drone/config/spec/configspec_client.ini index 4678684..6e8ac74 100644 --- a/Drone/config/spec/configspec_client.ini +++ b/Drone/config/spec/configspec_client.ini @@ -71,6 +71,12 @@ frame_delay = float(default=0.1, min=0.01) ratio = float_list(default=list(1.0, 1.0, 1.0), min=3, max=3) # Available options: 'animation', 'nan' or a number in degrees yaw = string(default=180.0) + [[OUTPUT]] + static_begin = boolean(default=False) + takeoff = boolean(default=True) + route = boolean(default=True) + land = boolean(default=False) + static_end = boolean(default=False) [LED] use = boolean(default=False) From d34e53110b037a6e07d753696fcd519393ed54e1 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Wed, 27 May 2020 15:38:14 +0300 Subject: [PATCH 14/43] Add tests for animation_lib --- tests/animation_1.csv | 51 ++ tests/animation_2.csv | 1066 +++++++++++++++++++++++++++++++++++++++ tests/animation_3.csv | 12 + tests/animation_test.py | 76 +++ 4 files changed, 1205 insertions(+) create mode 100644 tests/animation_1.csv create mode 100755 tests/animation_2.csv create mode 100644 tests/animation_3.csv create mode 100644 tests/animation_test.py diff --git a/tests/animation_1.csv b/tests/animation_1.csv new file mode 100644 index 0000000..e7e37cb --- /dev/null +++ b/tests/animation_1.csv @@ -0,0 +1,51 @@ +basic +1,0.0,0.0,0.0,0.0,204,2,0 +2,0.0,0.0,0.0,0.0,204,9,1 +3,0.0,0.0,0.0,0.0,204,21,2 +4,0.0,0.0,0.0,0.0,204,37,3 +5,0.0,0.0,0.0,0.0,204,56,4 +6,0.0,0.0,0.0,0.0,204,77,5 +7,0.0,0.0,0.0,0.0,204,97,6 +8,0.0,0.0,0.0,0.0,204,116,6 +9,0.0,0.0,0.0,0.0,204,131,7 +10,0.0,0.0,0.0,0.0,204,143,7 +11,0.0,0.0,0.1,0.0,199,153,7 +12,0.0,0.0,0.2,0.0,185,163,6 +13,0.0,0.0,0.3,0.0,163,172,6 +14,0.0,0.0,0.4,0.0,134,181,5 +15,0.0,0.0,0.5,0.0,102,188,5 +16,0.0,0.0,0.6,0.0,69,194,4 +17,0.0,0.0,0.7,0.0,40,199,3 +18,0.0,0.0,0.8,0.0,18,201,3 +19,0.0,0.0,0.9,0.0,4,203,2 +20,0.0,0.0,1.0,0.0,0,204,2 +21,0.02217,0.0,1.0,0.0,0,204,2 +22,0.08889,0.0,1.0,0.0,0,204,2 +23,0.19737,0.0,1.0,0.0,0,204,2 +24,0.33926,0.0,1.0,0.0,0,204,2 +25,0.5,0.0,1.0,0.0,0,204,2 +26,0.66074,0.0,1.0,0.0,0,204,2 +27,0.80263,0.0,1.0,0.0,0,204,2 +28,0.91111,0.0,1.0,0.0,0,204,2 +29,0.97783,0.0,1.0,0.0,0,204,2 +30,1.0,0.0,1.0,0.0,0,204,2 +31,1.0,0.0,0.9,0.0,3,204,2 +32,1.0,0.0,0.8,0.0,14,204,2 +33,1.0,0.0,0.7,0.0,32,204,2 +34,1.0,0.0,0.6,0.0,56,204,1 +35,1.0,0.0,0.5,0.0,84,204,1 +36,1.0,0.0,0.4,0.0,112,204,0 +37,1.0,0.0,0.3,0.0,138,204,0 +38,1.0,0.0,0.2,0.0,159,204,0 +39,1.0,0.0,0.1,0.0,175,204,0 +40,1.0,0.0,0.0,0.0,183,204,0 +41,1.0,0.0,0.0,0.0,188,199,0 +42,1.0,0.0,0.0,0.0,192,185,0 +43,1.0,0.0,0.0,0.0,196,163,0 +44,1.0,0.0,0.0,0.0,199,135,0 +45,1.0,0.0,0.0,0.0,201,102,0 +46,1.0,0.0,0.0,0.0,202,69,0 +47,1.0,0.0,0.0,0.0,203,40,0 +48,1.0,0.0,0.0,0.0,203,18,0 +49,1.0,0.0,0.0,0.0,203,5,0 +50,1.0,0.0,0.0,0.0,204,0,0 diff --git a/tests/animation_2.csv b/tests/animation_2.csv new file mode 100755 index 0000000..addc6f0 --- /dev/null +++ b/tests/animation_2.csv @@ -0,0 +1,1066 @@ +parad +0,-1.00519,2.65699,0.21,-2.76315,7,255,0 +1,-1.00519,2.65699,0.21,-2.76315,7,255,0 +2,-1.00519,2.65699,0.21,-2.76315,7,255,0 +3,-1.00519,2.65699,0.21,-2.76315,7,255,0 +4,-1.00519,2.65699,0.21,-2.76315,7,255,0 +5,-1.00519,2.65699,0.21,-2.76315,7,255,0 +6,-1.00519,2.65699,0.21,-2.76315,7,255,0 +7,-1.00519,2.65699,0.21,-2.76315,7,255,0 +8,-1.00519,2.65699,0.21,-2.76315,7,255,0 +9,-1.00519,2.65699,0.21,-2.76315,7,255,0 +10,-1.00519,2.65699,0.21,-2.76315,7,255,0 +11,-1.00519,2.65699,0.21,-2.76315,7,255,0 +12,-1.00519,2.65699,0.21,-2.76315,7,255,0 +13,-1.00519,2.65699,0.21,-2.76315,7,255,0 +14,-1.00519,2.65699,0.21,-2.76315,7,255,0 +15,-1.00519,2.65699,0.21,-2.76315,7,255,0 +16,-1.00519,2.65699,0.21,-2.76315,7,255,0 +17,-1.00519,2.65699,0.21,-2.76315,7,255,0 +18,-1.00519,2.65699,0.21,-2.76315,7,255,0 +19,-1.00519,2.65699,0.21,-2.76315,7,255,0 +20,-1.00519,2.65699,0.21,-2.76315,7,255,0 +21,-1.00519,2.65699,0.21,-2.76315,7,255,0 +22,-1.00519,2.65699,0.21,-2.76315,7,255,0 +23,-1.00519,2.65699,0.21,-2.76315,7,255,0 +24,-1.00519,2.65699,0.21,-2.76315,7,255,0 +25,-1.00519,2.65699,0.21,-2.76315,7,255,0 +26,-1.00519,2.65699,0.21,-2.76315,7,255,0 +27,-1.00519,2.65699,0.21,-2.76315,7,255,0 +28,-1.00519,2.65699,0.21,-2.76315,7,255,0 +29,-1.00519,2.65699,0.21,-2.76315,7,255,0 +30,-1.00519,2.65699,0.21,-2.76315,7,255,0 +31,-1.00519,2.65699,0.21,-2.76315,7,255,0 +32,-1.00519,2.65699,0.21,-2.76315,7,255,0 +33,-1.00519,2.65699,0.21,-2.76315,7,255,0 +34,-1.00519,2.65699,0.21,-2.76315,7,255,0 +35,-1.00519,2.65699,0.21,-2.76315,7,255,0 +36,-1.00519,2.65699,0.21,-2.76315,7,255,0 +37,-1.00519,2.65699,0.21,-2.76315,7,255,0 +38,-1.00519,2.65699,0.21,-2.76315,7,255,0 +39,-1.00519,2.65699,0.21,-2.76315,7,255,0 +40,-1.00519,2.65699,0.21,-2.76315,7,255,0 +41,-1.00519,2.65699,0.21,-2.76315,7,255,0 +42,-1.00519,2.65699,0.21,-2.76315,7,255,0 +43,-1.00519,2.65699,0.21,-2.76315,7,255,0 +44,-1.00519,2.65699,0.21,-2.76315,7,255,0 +45,-1.00519,2.65699,0.21,-2.76315,7,255,0 +46,-1.00519,2.65699,0.21,-2.76315,7,255,0 +47,-1.00519,2.65699,0.21,-2.76315,7,255,0 +48,-1.00519,2.65699,0.21,-2.76315,7,255,0 +49,-1.00519,2.65699,0.21,-2.76315,7,255,0 +50,-1.00519,2.65699,0.21,-2.76315,7,255,0 +51,-1.00519,2.65699,0.21,-2.76315,7,255,0 +52,-1.00519,2.65699,0.21,-2.76315,7,255,0 +53,-1.00519,2.65699,0.21,-2.76315,7,255,0 +54,-1.00519,2.65699,0.21,-2.76315,7,255,0 +55,-1.00519,2.65699,0.21,-2.76315,7,255,0 +56,-1.00519,2.65699,0.21,-2.76315,7,255,0 +57,-1.00519,2.65699,0.21,-2.76315,7,255,0 +58,-1.00519,2.65699,0.21,-2.76315,7,255,0 +59,-1.00519,2.65699,0.21,-2.76315,7,255,0 +60,-1.00519,2.65699,0.21,-2.76315,7,255,0 +61,-1.00519,2.65699,0.21,-2.76315,7,255,0 +62,-1.00519,2.65699,0.21,-2.76315,7,255,0 +63,-1.00519,2.65699,0.21,-2.76315,7,255,0 +64,-1.00519,2.65699,0.21,-2.76315,7,255,0 +65,-1.00519,2.65699,0.21,-2.76315,7,255,0 +66,-1.00519,2.65699,0.21,-2.76315,7,255,0 +67,-1.00519,2.65699,0.21,-2.76315,7,255,0 +68,-1.00519,2.65699,0.21,-2.76315,7,255,0 +69,-1.00519,2.65699,0.21,-2.76315,7,255,0 +70,-1.00519,2.65699,0.21,-2.76315,7,255,0 +71,-1.00519,2.65699,0.21,-2.76315,7,255,0 +72,-1.00519,2.65699,0.21,-2.76315,7,255,0 +73,-1.00519,2.65699,0.21,-2.76315,7,255,0 +74,-1.00519,2.65699,0.21,-2.76315,7,255,0 +75,-1.00519,2.65699,0.21,-2.76315,7,255,0 +76,-1.00519,2.65699,0.21,-2.76315,7,255,0 +77,-1.00519,2.65699,0.21,-2.76315,7,255,0 +78,-1.00519,2.65699,0.21,-2.76315,7,255,0 +79,-1.00519,2.65699,0.21,-2.76315,7,255,0 +80,-1.00519,2.65699,0.21,-2.76315,7,255,0 +81,-1.00519,2.65699,0.21,-2.76315,7,255,0 +82,-1.00519,2.65699,0.21,-2.76315,7,255,0 +83,-1.00519,2.65699,0.21,-2.76315,7,255,0 +84,-1.00519,2.65699,0.21,-2.76315,7,255,0 +85,-1.00519,2.65699,0.21,-2.76315,7,255,0 +86,-1.00519,2.65699,0.21,-2.76315,7,255,0 +87,-1.00519,2.65699,0.21,-2.76315,7,255,0 +88,-1.00519,2.65699,0.21,-2.76315,7,255,0 +89,-1.00519,2.65699,0.21,-2.76315,7,255,0 +90,-1.00519,2.65699,0.21,-2.76315,7,255,0 +91,-1.00519,2.65699,0.21,-2.76315,7,255,0 +92,-1.00519,2.65699,0.21,-2.76315,7,255,0 +93,-1.00519,2.65699,0.21,-2.76315,7,255,0 +94,-1.00519,2.65699,0.21,-2.76315,7,255,0 +95,-1.00519,2.65699,0.21,-2.76315,7,255,0 +96,-1.00519,2.65699,0.21,-2.76315,7,255,0 +97,-1.00519,2.65699,0.21,-2.76315,7,255,0 +98,-1.00519,2.65699,0.21,-2.76315,7,255,0 +99,-1.00519,2.65699,0.21,-2.76315,7,255,0 +100,-1.00519,2.65699,0.21,-2.76315,7,255,0 +101,-1.00519,2.65699,0.21,-2.76315,7,255,0 +102,-1.00519,2.65699,0.21,-2.76315,7,255,0 +103,-1.00519,2.65699,0.21,-2.76315,7,255,0 +104,-1.00519,2.65699,0.21,-2.76315,7,255,0 +105,-1.00519,2.65699,0.21,-2.76315,7,255,0 +106,-1.00519,2.65699,0.21,-2.76315,7,255,0 +107,-1.00519,2.65699,0.21,-2.76315,7,255,0 +108,-1.00519,2.65699,0.21,-2.76315,7,255,0 +109,-1.00519,2.65699,0.21,-2.76315,7,255,0 +110,-1.00519,2.65699,0.21,-2.76315,7,255,0 +111,-1.00519,2.65699,0.21,-2.76315,7,255,0 +112,-1.00519,2.65699,0.21,-2.76315,7,255,0 +113,-1.00519,2.65699,0.21,-2.76315,7,255,0 +114,-1.00519,2.65699,0.21,-2.76315,7,255,0 +115,-1.00519,2.65699,0.21,-2.76315,7,255,0 +116,-1.00519,2.65699,0.21,-2.76315,7,255,0 +117,-1.00519,2.65699,0.21,-2.76315,7,255,0 +118,-1.00519,2.65699,0.21,-2.76315,7,255,0 +119,-1.00519,2.65699,0.21,-2.76315,7,255,0 +120,-1.00519,2.65699,0.21,-2.76315,7,255,0 +121,-1.00519,2.65699,0.21,-2.76315,7,255,0 +122,-1.00519,2.65699,0.21,-2.76315,7,255,0 +123,-1.00519,2.65699,0.21,-2.76315,7,255,0 +124,-1.00519,2.65699,0.21,-2.76315,7,255,0 +125,-1.00519,2.65699,0.21,-2.76315,7,255,0 +126,-1.00519,2.65699,0.21,-2.76315,7,255,0 +127,-1.00519,2.65699,0.21,-2.76315,7,255,0 +128,-1.00519,2.65699,0.21,-2.76315,7,255,0 +129,-1.00519,2.65699,0.21,-2.76315,7,255,0 +130,-1.00519,2.65699,0.21,-2.76315,7,255,0 +131,-1.00519,2.65699,0.21,-2.76315,7,255,0 +132,-1.00519,2.65699,0.21,-2.76315,7,255,0 +133,-1.00519,2.65699,0.21,-2.76315,7,255,0 +134,-1.00519,2.65699,0.21,-2.76315,7,255,0 +135,-1.00519,2.65699,0.21,-2.76315,7,255,0 +136,-1.00519,2.65699,0.21,-2.76315,7,255,0 +137,-1.00519,2.65699,0.21,-2.76315,7,255,0 +138,-1.00519,2.65699,0.21,-2.76315,7,255,0 +139,-1.00519,2.65699,0.21,-2.76315,7,255,0 +140,-1.00519,2.65699,0.21,-2.76315,7,255,0 +141,-1.00519,2.65699,0.21,-2.76315,7,255,0 +142,-1.00519,2.65699,0.21,-2.76315,7,255,0 +143,-1.00519,2.65699,0.21,-2.76315,7,255,0 +144,-1.00519,2.65699,0.21,-2.76315,7,255,0 +145,-1.00519,2.65699,0.21,-2.76315,7,255,0 +146,-1.00519,2.65699,0.21,-2.76315,7,255,0 +147,-1.00519,2.65699,0.21,-2.76315,7,255,0 +148,-1.00519,2.65699,0.21,-2.76315,7,255,0 +149,-1.00519,2.65699,0.21,-2.76315,7,255,0 +150,-1.00519,2.65699,0.21,-2.76315,7,255,0 +151,-1.00519,2.65699,0.21,-2.76315,7,255,0 +152,-1.00519,2.65699,0.21,-2.76315,7,255,0 +153,-1.00519,2.65699,0.21,-2.76315,7,255,0 +154,-1.00519,2.65699,0.21,-2.76315,7,255,0 +155,-1.00519,2.65699,0.21,-2.76315,7,255,0 +156,-1.00519,2.65699,0.21,-2.76315,7,255,0 +157,-1.00519,2.65699,0.21,-2.76315,7,255,0 +158,-1.00519,2.65699,0.21,-2.76315,7,255,0 +159,-1.00519,2.65699,0.21,-2.76315,7,255,0 +160,-1.00519,2.65699,0.21,-2.76315,7,255,0 +161,-1.00519,2.65699,0.21,-2.76315,7,255,0 +162,-1.00519,2.65699,0.21,-2.76315,7,255,0 +163,-1.00519,2.65699,0.21,-2.76315,7,255,0 +164,-1.00519,2.65699,0.21,-2.76315,7,255,0 +165,-1.00519,2.65699,0.21,-2.76315,7,255,0 +166,-1.00519,2.65699,0.21,-2.76315,7,255,0 +167,-1.00519,2.65699,0.21,-2.76315,7,255,0 +168,-1.00519,2.65699,0.21,-2.76315,7,255,0 +169,-1.00519,2.65699,0.21,-2.76315,7,255,0 +170,-1.00519,2.65699,0.21,-2.76315,7,255,0 +171,-1.00519,2.65699,0.21,-2.76315,7,255,0 +172,-1.00519,2.65699,0.21,-2.76315,7,255,0 +173,-1.00519,2.65699,0.21,-2.76315,7,255,0 +174,-1.00519,2.65699,0.21,-2.76315,7,255,0 +175,-1.00519,2.65699,0.21,-2.76315,7,255,0 +176,-1.00519,2.65699,0.21,-2.76315,7,255,0 +177,-1.00519,2.65699,0.21,-2.76315,7,255,0 +178,-1.00519,2.65699,0.21,-2.76315,7,255,0 +179,-1.00519,2.65699,0.21,-2.76315,7,255,0 +180,-1.00519,2.65699,0.21,-2.76315,7,255,0 +181,-1.00519,2.65699,0.21,-2.76315,7,255,0 +182,-1.00519,2.65699,0.21,-2.76315,7,255,0 +183,-1.00519,2.65699,0.21,-2.76315,7,255,0 +184,-1.00519,2.65699,0.21,-2.76315,7,255,0 +185,-1.00519,2.65699,0.21,-2.76315,7,255,0 +186,-1.00519,2.65699,0.21,-2.76315,7,255,0 +187,-1.00519,2.65699,0.21,-2.76315,7,255,0 +188,-1.00519,2.65699,0.21,-2.76315,7,255,0 +189,-1.00519,2.65699,0.21,-2.76315,7,255,0 +190,-1.00519,2.65699,0.21,-2.76315,7,255,0 +191,-1.00519,2.65699,0.21,-2.76315,7,255,0 +192,-1.00519,2.65699,0.21,-2.76315,7,255,0 +193,-1.00519,2.65699,0.21,-2.76315,7,255,0 +194,-1.00519,2.65699,0.21,-2.76315,7,255,0 +195,-1.00519,2.65699,0.21,-2.76315,7,255,0 +196,-1.00519,2.65699,0.21,-2.76315,7,255,0 +197,-1.00519,2.65699,0.21,-2.76315,7,255,0 +198,-1.00519,2.65699,0.21,-2.76315,7,255,0 +199,-1.00519,2.65699,0.21,-2.76315,7,255,0 +200,-1.00519,2.65699,0.21,-2.76315,7,255,0 +201,-1.00519,2.65699,0.21,-2.76315,7,255,0 +202,-1.00519,2.65699,0.21,-2.76315,7,255,0 +203,-1.00519,2.65699,0.21,-2.76315,7,255,0 +204,-1.00519,2.65699,0.21,-2.76315,7,255,0 +205,-1.00519,2.65699,0.21,-2.76315,7,255,0 +206,-1.00519,2.65699,0.21,-2.76315,7,255,0 +207,-1.00519,2.65699,0.21,-2.76315,7,255,0 +208,-1.00519,2.65699,0.21,-2.76315,7,255,0 +209,-1.00519,2.65699,0.21,-2.76315,7,255,0 +210,-1.00519,2.65699,0.21,-2.76315,7,255,0 +211,-1.00519,2.65699,0.21,-2.76315,7,255,0 +212,-1.00519,2.65699,0.21,-2.76315,7,255,0 +213,-1.00519,2.65699,0.21,-2.76315,7,255,0 +214,-1.00519,2.65699,0.21,-2.76315,7,255,0 +215,-1.00519,2.65699,0.21,-2.76315,7,255,0 +216,-1.00519,2.65699,0.21,-2.76315,7,255,0 +217,-1.00519,2.65699,0.21,-2.76315,7,255,0 +218,-1.00519,2.65699,0.21,-2.76315,7,255,0 +219,-1.00519,2.65699,0.21,-2.76315,7,255,0 +220,-1.00519,2.65699,0.21,-2.76315,7,255,0 +221,-1.00519,2.65699,0.21,-2.76315,7,255,0 +222,-1.00519,2.65699,0.21,-2.76315,7,255,0 +223,-1.00519,2.65699,0.21,-2.76315,7,255,0 +224,-1.00519,2.65699,0.21,-2.76315,7,255,0 +225,-1.00519,2.65699,0.21,-2.76315,7,255,0 +226,-1.00519,2.65699,0.21,-2.76315,7,255,0 +227,-1.00519,2.65699,0.21,-2.76315,7,255,0 +228,-1.00519,2.65699,0.21,-2.76315,7,255,0 +229,-1.00519,2.65699,0.21,-2.76315,7,255,0 +230,-1.00519,2.65699,0.21,-2.76315,7,255,0 +231,-1.00519,2.65699,0.21,-2.76315,7,255,0 +232,-1.00519,2.65699,0.21,-2.76315,7,255,0 +233,-1.00519,2.65699,0.21,-2.76315,7,255,0 +234,-1.00519,2.65699,0.21,-2.76315,7,255,0 +235,-1.00519,2.65699,0.21,-2.76315,7,255,0 +236,-1.00519,2.65699,0.21,-2.76315,7,255,0 +237,-1.00519,2.65699,0.21,-2.76315,7,255,0 +238,-1.00519,2.65699,0.21,-2.76315,7,255,0 +239,-1.00519,2.65699,0.21,-2.76315,7,255,0 +240,-1.00519,2.65699,0.21,-2.76315,7,255,0 +241,-1.00519,2.65699,0.21,-2.76315,7,255,0 +242,-1.00519,2.65699,0.21,-2.76315,7,255,0 +243,-1.00519,2.65699,0.21,-2.76315,7,255,0 +244,-1.00519,2.65699,0.21,-2.76315,7,255,0 +245,-1.00519,2.65699,0.21,-2.76315,7,255,0 +246,-1.00519,2.65699,0.21,-2.76315,7,255,0 +247,-1.00519,2.65699,0.21,-2.76315,7,255,0 +248,-1.00519,2.65699,0.21,-2.76315,7,255,0 +249,-1.00519,2.65699,0.21,-2.76315,7,255,0 +250,-1.00519,2.65699,0.21,-2.76315,7,255,0 +251,-1.00519,2.65699,0.21,-2.76315,7,255,0 +252,-1.00519,2.65699,0.21,-2.76315,7,255,0 +253,-1.00519,2.65699,0.21,-2.76315,7,255,0 +254,-1.00519,2.65699,0.21,-2.76315,7,255,0 +255,-1.00519,2.65699,0.21,-2.76315,7,255,0 +256,-1.00519,2.65699,0.21,-2.76315,7,255,0 +257,-1.00519,2.65699,0.21,-2.76315,7,255,0 +258,-1.00519,2.65699,0.21,-2.76315,7,255,0 +259,-1.00519,2.65699,0.21,-2.76315,7,255,0 +260,-1.00519,2.65699,0.21,-2.76315,7,255,0 +261,-1.00519,2.65699,0.21,-2.76315,7,255,0 +262,-1.00519,2.65699,0.21,-2.76315,7,255,0 +263,-1.00519,2.65699,0.21,-2.76315,7,255,0 +264,-1.00519,2.65699,0.21,-2.76315,7,255,0 +265,-1.00519,2.65699,0.21,-2.76315,7,255,0 +266,-1.00519,2.65699,0.21,-2.76315,7,255,0 +267,-1.00519,2.65699,0.21,-2.76315,7,255,0 +268,-1.00519,2.65699,0.21,-2.76315,7,255,0 +269,-1.00519,2.65699,0.21,-2.76315,7,255,0 +270,-1.00519,2.65699,0.21,-2.76315,7,255,0 +271,-1.00519,2.65699,0.24386,-2.76315,7,255,0 +272,-1.00519,2.65699,0.30495,-2.76315,7,255,0 +273,-1.00519,2.65699,0.36315,-2.76315,7,255,0 +274,-1.00519,2.65699,0.41951,-2.76315,7,255,0 +275,-1.00519,2.65699,0.47568,-2.76315,7,255,0 +276,-1.00519,2.65699,0.53229,-2.76315,7,255,0 +277,-1.00519,2.65699,0.58898,-2.76315,7,255,0 +278,-1.00519,2.65699,0.64513,-2.76315,7,255,0 +279,-1.00519,2.65699,0.70179,-2.76315,7,255,0 +280,-1.00519,2.65699,0.75979,-2.76315,7,255,0 +281,-1.00519,2.65699,0.81297,-2.76315,7,255,0 +282,-1.00519,2.65699,0.86881,-2.76315,7,255,0 +283,-1.00519,2.65699,0.93843,-2.76315,7,255,0 +284,-1.00453,2.65334,0.9872,-2.76315,7,255,0 +285,-1.00118,2.61466,1.0,-2.76315,7,255,0 +286,-0.99839,2.52817,1.0,-2.76315,7,255,0 +287,-0.99588,2.44199,1.0,-2.76315,7,255,0 +288,-0.99316,2.37257,1.0,-2.76315,7,255,0 +289,-0.99048,2.297,1.0,-2.76315,7,255,0 +290,-0.98782,2.21961,1.0,-2.76315,7,255,0 +291,-0.98515,2.14444,1.0,-2.76315,7,255,0 +292,-0.98247,2.06873,1.0,-2.76315,7,255,0 +293,-0.9798,1.9928,1.0,-2.76315,7,255,0 +294,-0.97713,1.91706,1.0,-2.76315,7,255,0 +295,-0.97446,1.84129,1.0,-2.76315,7,255,0 +296,-0.97178,1.7655,1.0,-2.76315,7,255,0 +297,-0.96911,1.68972,1.0,-2.76315,7,255,0 +298,-0.96644,1.61394,1.0,-2.76315,7,255,0 +299,-0.96377,1.53816,1.0,-2.76315,7,255,0 +300,-0.96109,1.46238,1.0,-2.76315,7,255,0 +301,-0.95842,1.3866,1.0,-2.76315,7,255,0 +302,-0.95575,1.31083,1.0,-2.76315,7,255,0 +303,-0.95308,1.23504,1.0,-2.76315,7,255,0 +304,-0.9504,1.15926,1.0,-2.76315,7,255,0 +305,-0.94773,1.08349,1.0,-2.76315,7,255,0 +306,-0.94506,1.00771,1.0,-2.76315,7,255,0 +307,-0.94239,0.93192,1.0,-2.76315,7,255,0 +308,-0.93971,0.85615,1.0,-2.76315,7,255,0 +309,-0.93704,0.78037,1.0,-2.76315,7,255,0 +310,-0.93437,0.70458,1.0,-2.76315,7,255,0 +311,-0.9317,0.62881,1.0,-2.76315,7,255,0 +312,-0.92902,0.55304,1.0,-2.76315,7,255,0 +313,-0.92636,0.47725,1.0,-2.76315,7,255,0 +314,-0.92366,0.40136,1.0,-2.76315,7,255,0 +315,-0.92101,0.32571,1.0,-2.76315,7,255,0 +316,-0.91843,0.2505,1.0,-2.76315,7,255,0 +317,-0.91542,0.17384,1.0,-2.76315,7,255,0 +318,-0.91299,0.09409,1.0,-2.76315,7,255,0 +319,-0.90963,0.02185,1.0,-2.76315,7,255,0 +320,-0.87383,0.00163,1.0,-2.76315,7,255,0 +321,-0.77046,0.0,1.0,-2.76315,7,255,0 +322,-0.69735,0.0,1.0,-2.76315,7,255,0 +323,-0.63239,0.0,1.0,-2.76315,7,255,0 +324,-0.55624,0.0,1.0,-2.76315,7,255,0 +325,-0.48324,0.0,1.0,-2.76315,7,255,0 +326,-0.41137,0.0,1.0,-2.76315,7,255,0 +327,-0.33828,0.0,1.0,-2.76315,7,255,0 +328,-0.26549,0.0,1.0,-2.76315,7,255,0 +329,-0.19282,0.0,1.0,-2.76315,7,255,0 +330,-0.12004,0.0,1.0,-2.76315,7,255,0 +331,-0.04728,0.0,1.0,-2.76315,7,255,0 +332,0.02546,0.0,1.0,-2.76315,7,255,0 +333,0.09822,0.0,1.0,-2.76315,7,255,0 +334,0.17097,0.0,1.0,-2.76315,7,255,0 +335,0.24373,0.0,1.0,-2.76315,7,255,0 +336,0.31648,0.0,1.0,-2.76315,7,255,0 +337,0.38924,0.0,1.0,-2.76315,7,255,0 +338,0.46199,0.0,1.0,-2.76315,7,255,0 +339,0.53475,0.0,1.0,-2.76315,7,255,0 +340,0.6075,0.0,1.0,-2.76315,7,255,0 +341,0.68025,0.0,1.0,-2.76315,7,255,0 +342,0.75301,0.0,1.0,-2.76315,7,255,0 +343,0.82576,0.0,1.0,-2.76315,7,255,0 +344,0.89852,0.0,1.0,-2.76315,7,255,0 +345,0.97127,0.0,1.0,-2.76315,7,255,0 +346,1.04403,0.0,1.0,-2.76315,7,255,0 +347,1.11678,0.0,1.0,-2.76315,7,255,0 +348,1.18953,0.0,1.0,-2.76315,7,255,0 +349,1.26229,0.0,1.0,-2.76315,7,255,0 +350,1.33504,0.0,1.0,-2.76315,7,255,0 +351,1.4078,0.0,1.0,-2.76315,7,255,0 +352,1.48055,0.0,1.0,-2.76315,7,255,0 +353,1.55331,0.0,1.0,-2.76315,7,255,0 +354,1.62606,0.0,1.0,-2.76315,7,255,0 +355,1.69881,0.0,1.0,-2.76315,7,255,0 +356,1.77157,0.0,1.0,-2.76315,7,255,0 +357,1.84432,0.0,1.0,-2.76315,7,255,0 +358,1.91707,0.0,1.0,-2.76315,7,255,0 +359,1.98983,0.0,1.0,-2.76315,7,255,0 +360,2.06258,0.0,1.0,-2.76315,7,255,0 +361,2.13534,0.0,1.0,-2.76315,7,255,0 +362,2.20809,0.0,1.0,-2.76315,7,255,0 +363,2.28084,0.0,1.0,-2.76315,7,255,0 +364,2.3536,0.0,1.0,-2.76315,7,255,0 +365,2.42635,0.0,1.0,-2.76315,7,255,0 +366,2.49911,0.0,1.0,-2.76315,7,255,0 +367,2.57186,0.0,1.0,-2.76315,7,255,0 +368,2.64461,0.0,1.0,-2.76315,7,255,0 +369,2.71737,0.0,1.0,-2.76315,7,255,0 +370,2.79012,0.0,1.0,-2.76315,7,255,0 +371,2.86288,0.0,1.0,-2.76315,7,255,0 +372,2.93563,0.0,1.0,-2.76315,7,255,0 +373,3.00839,0.0,1.0,-2.76315,7,255,0 +374,3.08114,0.0,1.0,-2.76315,7,255,0 +375,3.15389,0.0,1.0,-2.76315,7,255,0 +376,3.22665,0.0,1.0,-2.76315,7,255,0 +377,3.2994,0.0,1.0,-2.76315,7,255,0 +378,3.37216,0.0,1.0,-2.76315,7,255,0 +379,3.44492,0.0,1.0,-2.76315,7,255,0 +380,3.51765,0.0,1.0,-2.76315,7,255,0 +381,3.59042,0.0,1.0,-2.76315,7,255,0 +382,3.66323,0.0,1.0,-2.76315,7,255,0 +383,3.73581,0.0,1.0,-2.76315,7,255,0 +384,3.80863,0.0,1.0,-2.76315,7,255,0 +385,3.88208,0.0,1.0,-2.76315,7,255,0 +386,3.95309,0.0,1.0,-2.76315,7,255,0 +387,4.02606,0.0,1.0,-2.76315,7,255,0 +388,4.10654,-0.02619,1.03815,-2.766,7,255,0 +389,4.17222,-0.07,1.10188,-2.76964,7,255,0 +390,4.21934,-0.10777,1.15672,-2.77183,7,255,0 +391,4.26563,-0.144,1.20926,-2.77475,7,255,0 +392,4.31231,-0.18027,1.26178,-2.77798,7,255,0 +393,4.3582,-0.21679,1.31456,-2.78112,7,255,0 +394,4.40386,-0.25346,1.36747,-2.78438,7,255,0 +395,4.44921,-0.29032,1.42055,-2.78777,7,255,0 +396,4.49413,-0.3274,1.47382,-2.79127,7,255,0 +397,4.53865,-0.36469,1.52728,-2.7949,7,255,0 +398,4.5828,-0.40218,1.58092,-2.79865,7,255,0 +399,4.62655,-0.43987,1.63474,-2.80252,7,255,0 +400,4.66991,-0.47776,1.68872,-2.80652,7,255,0 +401,4.71287,-0.51586,1.74289,-2.81066,7,255,0 +402,4.75539,-0.55417,1.79725,-2.81494,7,255,0 +403,4.79746,-0.59271,1.8518,-2.81938,7,255,0 +404,4.83905,-0.63148,1.90655,-2.82397,7,255,0 +405,4.88015,-0.67049,1.9615,-2.82875,7,255,0 +406,4.92073,-0.70975,2.01666,-2.83371,7,255,0 +407,4.96076,-0.74927,2.07204,-2.83887,7,255,0 +408,5.00021,-0.78905,2.12764,-2.84425,7,255,0 +409,5.03906,-0.82911,2.18347,-2.84985,7,255,0 +410,5.07727,-0.86945,2.23954,-2.8557,7,255,0 +411,5.11481,-0.91009,2.29584,-2.86182,7,255,0 +412,5.15163,-0.95103,2.35239,-2.86822,7,255,0 +413,5.18772,-0.99229,2.40919,-2.87493,7,255,0 +414,5.22301,-1.03387,2.46625,-2.88196,7,255,0 +415,5.25747,-1.07579,2.52357,-2.88936,7,255,0 +416,5.29105,-1.11805,2.58116,-2.89714,7,255,0 +417,5.32371,-1.16067,2.63901,-2.90533,7,255,0 +418,5.35538,-1.20365,2.69714,-2.91397,7,255,0 +419,5.38603,-1.24701,2.75554,-2.9231,7,255,0 +420,5.41557,-1.29075,2.81421,-2.93275,7,255,0 +421,5.44396,-1.33489,2.87316,-2.94297,7,255,0 +422,5.47112,-1.37943,2.93238,-2.95382,7,255,0 +423,5.49698,-1.42437,2.99186,-2.96534,7,255,0 +424,5.52148,-1.46973,3.05161,-2.97757,7,255,0 +425,5.54449,-1.51552,3.11161,-2.99065,7,255,0 +426,5.56591,-1.56175,3.17188,-3.00459,7,255,0 +427,5.58555,-1.60846,3.23241,-3.0195,7,255,0 +428,5.60301,-1.65558,3.29306,-3.03606,7,255,0 +429,5.61879,-1.70323,3.35405,-3.05318,7,255,0 +430,5.63399,-1.75332,3.41792,-3.07028,7,255,0 +431,5.64777,-1.81252,3.49266,-3.0953,7,255,0 +432,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +433,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +434,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +435,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +436,5.65455,-1.84833,3.53759,-3.11273,7,255,0 +437,5.65455,-1.79891,3.53759,-3.11273,7,255,0 +438,5.65455,-1.72513,3.53759,-3.11273,7,255,0 +439,5.65455,-1.66957,3.53759,-3.11273,7,255,0 +440,5.65455,-1.61072,3.53759,-3.11273,7,255,0 +441,5.65455,-1.55011,3.53759,-3.11273,7,255,0 +442,5.65455,-1.49082,3.53759,-3.11273,7,255,0 +443,5.65456,-1.43129,3.53759,-3.11273,7,255,0 +444,5.65456,-1.37163,3.53759,-3.11273,7,255,0 +445,5.65456,-1.31206,3.53759,-3.11273,7,255,0 +446,5.65456,-1.25248,3.53759,-3.11273,7,255,0 +447,5.65456,-1.19289,3.53759,-3.11273,7,255,0 +448,5.65456,-1.13331,3.53759,-3.11273,7,255,0 +449,5.65456,-1.07373,3.53758,-3.11273,7,255,0 +450,5.65456,-1.01414,3.53758,-3.11273,7,255,0 +451,5.65456,-0.95456,3.53758,-3.11273,7,255,0 +452,5.65456,-0.89497,3.53758,-3.11273,7,255,0 +453,5.65456,-0.83539,3.53758,-3.11273,7,255,0 +454,5.65456,-0.7758,3.53758,-3.11273,7,255,0 +455,5.65456,-0.71622,3.53758,-3.11273,7,255,0 +456,5.65456,-0.65663,3.53758,-3.11273,7,255,0 +457,5.65456,-0.59705,3.53758,-3.11273,7,255,0 +458,5.65456,-0.53746,3.53758,-3.11273,7,255,0 +459,5.65456,-0.47788,3.53758,-3.11273,7,255,0 +460,5.65456,-0.41829,3.53758,-3.11273,7,255,0 +461,5.65456,-0.35871,3.53758,-3.11273,7,255,0 +462,5.65456,-0.29912,3.53758,-3.11273,7,255,0 +463,5.65456,-0.23954,3.53758,-3.11273,7,255,0 +464,5.65456,-0.17996,3.53758,-3.11273,7,255,0 +465,5.65456,-0.12037,3.53758,-3.11273,7,255,0 +466,5.65456,-0.06079,3.53758,-3.11273,7,255,0 +467,5.65456,-0.0012,3.53758,-3.11273,7,255,0 +468,5.65456,0.05838,3.53758,-3.11273,7,255,0 +469,5.65456,0.11797,3.53758,-3.11273,7,255,0 +470,5.65456,0.17755,3.53758,-3.11273,7,255,0 +471,5.65456,0.23714,3.53758,-3.11273,7,255,0 +472,5.65456,0.29672,3.53758,-3.11273,7,255,0 +473,5.65456,0.35631,3.53758,-3.11273,7,255,0 +474,5.65456,0.41589,3.53758,-3.11273,7,255,0 +475,5.65456,0.47548,3.53758,-3.11273,7,255,0 +476,5.65456,0.53506,3.53757,-3.11273,7,255,0 +477,5.65456,0.59465,3.53757,-3.11273,7,255,0 +478,5.65457,0.65423,3.53757,-3.11273,7,255,0 +479,5.65457,0.71381,3.53757,-3.11273,7,255,0 +480,5.65457,0.7734,3.53757,-3.11273,7,255,0 +481,5.65457,0.83298,3.53757,-3.11273,7,255,0 +482,5.65457,0.89257,3.53757,-3.11273,7,255,0 +483,5.65457,0.95215,3.53757,-3.11273,7,255,0 +484,5.65457,1.01174,3.53757,-3.11273,7,255,0 +485,5.65457,1.07132,3.53757,-3.11273,7,255,0 +486,5.65457,1.13091,3.53757,-3.11273,7,255,0 +487,5.65457,1.19049,3.53756,-3.11273,7,255,0 +488,5.65457,1.25008,3.53756,-3.11273,7,255,0 +489,5.65458,1.30966,3.53756,-3.11273,7,255,0 +490,5.65458,1.36925,3.53756,-3.11273,7,255,0 +491,5.65458,1.42883,3.53756,-3.11273,7,255,0 +492,5.65458,1.48841,3.53756,-3.11273,7,255,0 +493,5.65458,1.548,3.53756,-3.11273,7,255,0 +494,5.65458,1.60764,3.53756,-3.11273,7,255,0 +495,5.65459,1.66702,3.53755,-3.11486,7,255,0 +496,5.65574,1.72639,3.53755,3.11304,7,255,0 +497,5.66228,1.78358,3.53755,2.83459,7,255,0 +498,5.6874,1.82462,3.53755,2.39285,7,255,0 +499,5.73331,1.84438,3.53755,1.98516,7,255,0 +500,5.78976,1.85001,3.53755,1.7291,7,255,0 +501,5.84936,1.85028,3.53754,1.61928,7,255,0 +502,5.9089,1.85028,3.53754,1.59963,7,255,0 +503,5.96848,1.85028,3.53754,1.59962,7,255,0 +504,6.02807,1.85027,3.53754,1.59962,7,255,0 +505,6.08765,1.85027,3.53754,1.59962,7,255,0 +506,6.14723,1.85026,3.53753,1.59962,7,255,0 +507,6.20682,1.85025,3.53753,1.59962,7,255,0 +508,6.26641,1.85024,3.53753,1.59962,7,255,0 +509,6.32599,1.85023,3.53753,1.59961,7,255,0 +510,6.38558,1.85022,3.53753,1.59961,7,255,0 +511,6.44516,1.85021,3.53752,1.59961,7,255,0 +512,6.50474,1.8502,3.53752,1.59961,7,255,0 +513,6.56433,1.85019,3.53752,1.59961,7,255,0 +514,6.62391,1.85018,3.53752,1.59961,7,255,0 +515,6.6835,1.85017,3.53751,1.59961,7,255,0 +516,6.74308,1.85017,3.53751,1.59961,7,255,0 +517,6.80267,1.85016,3.53751,1.59961,7,255,0 +518,6.86225,1.85015,3.53751,1.5996,7,255,0 +519,6.92184,1.85014,3.5375,1.5996,7,255,0 +520,6.98142,1.85013,3.5375,1.5996,7,255,0 +521,7.04101,1.85013,3.5375,1.5996,7,255,0 +522,7.10059,1.85012,3.53749,1.5996,7,255,0 +523,7.16018,1.85011,3.53749,1.5996,7,255,0 +524,7.21976,1.8501,3.53749,1.5996,7,255,0 +525,7.27935,1.8501,3.53748,1.5996,7,255,0 +526,7.33893,1.85009,3.53748,1.5996,7,255,0 +527,7.39851,1.85008,3.53748,1.5996,7,255,0 +528,7.4581,1.85007,3.53747,1.5996,7,255,0 +529,7.51768,1.85007,3.53747,1.5996,7,255,0 +530,7.57727,1.85006,3.53747,1.5996,7,255,0 +531,7.63685,1.85005,3.53746,1.5996,7,255,0 +532,7.69644,1.85004,3.53746,1.5996,7,255,0 +533,7.75602,1.85004,3.53746,1.59959,7,255,0 +534,7.81561,1.85003,3.53745,1.59959,7,255,0 +535,7.87519,1.85002,3.53745,1.59959,7,255,0 +536,7.93478,1.85001,3.53745,1.59959,7,255,0 +537,7.99436,1.85,3.53744,1.59959,7,255,0 +538,8.05395,1.85,3.53744,1.59959,7,255,0 +539,8.11353,1.84999,3.53743,1.59959,7,255,0 +540,8.17312,1.84998,3.53743,1.59959,7,255,0 +541,8.2327,1.84997,3.53743,1.59959,7,255,0 +542,8.29228,1.84996,3.53742,1.59959,7,255,0 +543,8.35187,1.84996,3.53742,1.59959,7,255,0 +544,8.41145,1.84995,3.53741,1.59959,7,255,0 +545,8.47104,1.84994,3.53741,1.59959,7,255,0 +546,8.53063,1.84993,3.53741,1.59959,7,255,0 +547,8.59021,1.84992,3.5374,1.59959,7,255,0 +548,8.64979,1.84992,3.5374,1.59959,7,255,0 +549,8.70938,1.84991,3.5374,1.59959,7,255,0 +550,8.76896,1.8499,3.53739,1.59959,7,255,0 +551,8.82855,1.84989,3.53739,1.59959,7,255,0 +552,8.88813,1.84988,3.53738,1.59959,7,255,0 +553,8.94772,1.84988,3.53738,1.59959,7,255,0 +554,9.0073,1.84987,3.53738,1.59959,7,255,0 +555,9.06689,1.84986,3.53737,1.59959,7,255,0 +556,9.12647,1.84985,3.53737,1.59959,7,255,0 +557,9.18606,1.84985,3.53737,1.59959,7,255,0 +558,9.24564,1.84984,3.53736,1.59959,7,255,0 +559,9.30522,1.84983,3.53736,1.59959,7,255,0 +560,9.36481,1.84982,3.53735,1.59959,7,255,0 +561,9.42439,1.84981,3.53735,1.59959,7,255,0 +562,9.48398,1.84981,3.53735,1.59959,7,255,0 +563,9.54356,1.8498,3.53734,1.59959,7,255,0 +564,9.60315,1.84979,3.53734,1.59959,7,255,0 +565,9.66273,1.84978,3.53734,1.59959,7,255,0 +566,9.72232,1.84978,3.53733,1.59959,7,255,0 +567,9.7819,1.84977,3.53733,1.59959,7,255,0 +568,9.84149,1.84976,3.53733,1.59959,7,255,0 +569,9.90107,1.84975,3.53732,1.59959,7,255,0 +570,9.96066,1.84974,3.53732,1.59959,7,255,0 +571,10.02024,1.84974,3.53731,1.59959,7,255,0 +572,10.07983,1.84973,3.53731,1.59959,7,255,0 +573,10.13941,1.84972,3.53731,1.59959,7,255,0 +574,10.199,1.84971,3.5373,1.59959,7,255,0 +575,10.25858,1.8497,3.5373,1.59959,7,255,0 +576,10.31816,1.8497,3.53729,1.59959,7,255,0 +577,10.37775,1.84969,3.53729,1.59959,7,255,0 +578,10.43733,1.84968,3.53729,1.59959,7,255,0 +579,10.49692,1.84967,3.53728,1.59959,7,255,0 +580,10.5565,1.84967,3.53728,1.59959,7,255,0 +581,10.61609,1.84966,3.53727,1.59959,7,255,0 +582,10.67567,1.84965,3.53727,1.59959,7,255,0 +583,10.73526,1.84964,3.53727,1.59959,7,255,0 +584,10.79484,1.84963,3.53726,1.59959,7,255,0 +585,10.85443,1.84963,3.53726,1.59959,7,255,0 +586,10.91401,1.84962,3.53725,1.59959,7,255,0 +587,10.9736,1.84961,3.53725,1.59959,7,255,0 +588,11.03318,1.8496,3.53724,1.59959,7,255,0 +589,11.09277,1.8496,3.53724,1.59959,7,255,0 +590,11.15235,1.84959,3.53724,1.59959,7,255,0 +591,11.21194,1.84958,3.53723,1.59959,7,255,0 +592,11.27152,1.84957,3.53723,1.59959,7,255,0 +593,11.33111,1.84956,3.53723,1.59958,7,255,0 +594,11.39069,1.84956,3.53722,1.59958,7,255,0 +595,11.45028,1.84955,3.53722,1.59958,7,255,0 +596,11.50986,1.84954,3.53722,1.59958,7,255,0 +597,11.56944,1.84953,3.53721,1.59958,7,255,0 +598,11.62903,1.84952,3.53721,1.59958,7,255,0 +599,11.68862,1.84952,3.53721,1.59958,7,255,0 +600,11.7482,1.84951,3.53721,1.59958,7,255,0 +601,11.80779,1.8495,3.5372,1.59958,7,255,0 +602,11.86737,1.84949,3.5372,1.59958,7,255,0 +603,11.92696,1.84948,3.5372,1.59958,7,255,0 +604,11.98654,1.84947,3.5372,1.59957,7,255,0 +605,12.04613,1.84946,3.5372,1.59957,7,255,0 +606,12.10571,1.84946,3.5372,1.59957,7,255,0 +607,12.16529,1.84945,3.53719,1.59957,7,255,0 +608,12.22488,1.84944,3.53719,1.59957,7,255,0 +609,12.28446,1.84944,3.53719,1.59957,7,255,0 +610,12.34405,1.84943,3.53719,1.59957,7,255,0 +611,12.40363,1.84943,3.53719,1.59957,7,255,0 +612,12.46322,1.84943,3.53719,1.59956,7,255,0 +613,12.5228,1.84942,3.53719,1.59956,7,255,0 +614,12.58239,1.84942,3.53719,1.59956,7,255,0 +615,12.64197,1.84942,3.53719,1.59956,7,255,0 +616,12.70156,1.84941,3.53719,1.59956,7,255,0 +617,12.76113,1.8494,3.53718,1.59956,7,255,0 +618,12.82075,1.84938,3.53718,1.59952,7,255,0 +619,12.88031,1.84936,3.53718,1.59853,7,255,0 +620,12.93977,1.84932,3.53718,1.57955,7,255,0 +621,12.99975,1.8492,3.53718,1.53822,7,255,0 +622,13.05807,1.84683,3.53718,1.39467,7,255,0 +623,13.10874,1.8321,3.53718,1.02962,7,255,0 +624,13.14285,1.79679,3.53718,0.55984,7,255,0 +625,13.15555,1.74517,3.53718,0.18196,7,255,0 +626,13.15648,1.6865,3.53718,0.04504,7,255,0 +627,13.15648,1.62648,3.53718,0.0302,7,255,0 +628,13.15648,1.56702,3.53718,0.02887,7,255,0 +629,13.15648,1.50746,3.53717,0.02886,7,255,0 +630,13.15648,1.44785,3.53717,0.02886,7,255,0 +631,13.15648,1.38827,3.53717,0.02886,7,255,0 +632,13.15648,1.32869,3.53717,0.02886,7,255,0 +633,13.15648,1.2691,3.53717,0.02885,7,255,0 +634,13.15648,1.20952,3.53717,0.02885,7,255,0 +635,13.15648,1.14993,3.53717,0.02885,7,255,0 +636,13.15649,1.09035,3.53717,0.02885,7,255,0 +637,13.15648,1.03076,3.53717,0.02885,7,255,0 +638,13.15649,0.97118,3.53717,0.02885,7,255,0 +639,13.15649,0.9116,3.53717,0.02884,7,255,0 +640,13.15649,0.85201,3.53717,0.02884,7,255,0 +641,13.15649,0.79243,3.53717,0.02884,7,255,0 +642,13.15649,0.73284,3.53716,0.02884,7,255,0 +643,13.15649,0.67326,3.53716,0.02884,7,255,0 +644,13.15649,0.61367,3.53716,0.02884,7,255,0 +645,13.15649,0.55409,3.53716,0.02884,7,255,0 +646,13.15649,0.4945,3.53716,0.02884,7,255,0 +647,13.15649,0.43492,3.53716,0.02883,7,255,0 +648,13.15649,0.37533,3.53716,0.02883,7,255,0 +649,13.1565,0.31575,3.53716,0.02883,7,255,0 +650,13.1565,0.25616,3.53716,0.02883,7,255,0 +651,13.1565,0.19658,3.53716,0.02883,7,255,0 +652,13.1565,0.137,3.53716,0.02883,7,255,0 +653,13.1565,0.07741,3.53716,0.02883,7,255,0 +654,13.1565,0.01783,3.53716,0.02883,7,255,0 +655,13.1565,-0.04176,3.53716,0.02883,7,255,0 +656,13.1565,-0.10134,3.53716,0.02883,7,255,0 +657,13.1565,-0.16093,3.53715,0.02883,7,255,0 +658,13.1565,-0.22051,3.53715,0.02883,7,255,0 +659,13.1565,-0.2801,3.53715,0.02883,7,255,0 +660,13.1565,-0.33968,3.53715,0.02883,7,255,0 +661,13.15651,-0.39926,3.53715,0.02883,7,255,0 +662,13.15651,-0.45885,3.53715,0.02883,7,255,0 +663,13.15651,-0.51843,3.53715,0.02883,7,255,0 +664,13.15651,-0.57802,3.53715,0.02883,7,255,0 +665,13.15651,-0.6376,3.53715,0.02883,7,255,0 +666,13.15651,-0.69719,3.53715,0.02883,7,255,0 +667,13.15651,-0.75677,3.53715,0.02882,7,255,0 +668,13.15651,-0.81636,3.53715,0.02882,7,255,0 +669,13.15651,-0.87594,3.53715,0.02882,7,255,0 +670,13.15651,-0.93553,3.53715,0.02882,7,255,0 +671,13.15651,-0.99511,3.53715,0.02882,7,255,0 +672,13.15651,-1.05469,3.53715,0.02882,7,255,0 +673,13.15651,-1.11428,3.53715,0.02882,7,255,0 +674,13.15652,-1.17386,3.53715,0.02882,7,255,0 +675,13.15652,-1.23344,3.53714,0.02882,7,255,0 +676,13.15652,-1.29303,3.53714,0.02882,7,255,0 +677,13.15652,-1.35262,3.53714,0.02882,7,255,0 +678,13.15652,-1.41219,3.53714,0.02882,7,255,0 +679,13.15652,-1.47179,3.53714,0.02882,7,255,0 +680,13.15652,-1.53141,3.53714,0.02882,7,255,0 +681,13.15652,-1.59085,3.53714,0.02882,7,255,0 +682,13.15652,-1.65054,3.53714,0.02774,7,255,0 +683,13.15644,-1.71064,3.53714,-0.01199,7,255,0 +684,13.15416,-1.76717,3.53714,-0.20779,7,255,0 +685,13.13611,-1.81192,3.53714,-0.58791,7,255,0 +686,13.09665,-1.83671,3.53714,-1.05263,7,255,0 +687,13.04295,-1.84623,3.53714,-1.37746,7,255,0 +688,12.98346,-1.84808,3.53714,-1.50019,7,255,0 +689,12.9238,-1.84831,3.53714,-1.53617,7,255,0 +690,12.86434,-1.84831,3.53714,-1.54141,7,255,0 +691,12.80472,-1.84831,3.53714,-1.54193,7,255,0 +692,12.74513,-1.84831,3.53714,-1.54193,7,255,0 +693,12.68556,-1.84831,3.53714,-1.54193,7,255,0 +694,12.62597,-1.84831,3.53714,-1.54193,7,255,0 +695,12.56638,-1.84831,3.53714,-1.54193,7,255,0 +696,12.5068,-1.84831,3.53714,-1.54193,7,255,0 +697,12.44722,-1.84831,3.53714,-1.54193,7,255,0 +698,12.38763,-1.84831,3.53713,-1.54193,7,255,0 +699,12.32805,-1.84831,3.53713,-1.54193,7,255,0 +700,12.26846,-1.84831,3.53713,-1.54193,7,255,0 +701,12.20887,-1.84831,3.53713,-1.54193,7,255,0 +702,12.14929,-1.84831,3.53713,-1.54193,7,255,0 +703,12.08971,-1.84831,3.53713,-1.54193,7,255,0 +704,12.03012,-1.84831,3.53713,-1.54193,7,255,0 +705,11.97054,-1.84831,3.53713,-1.54193,7,255,0 +706,11.91095,-1.84831,3.53713,-1.54193,7,255,0 +707,11.85137,-1.84831,3.53713,-1.54193,7,255,0 +708,11.79178,-1.84831,3.53713,-1.54193,7,255,0 +709,11.7322,-1.84831,3.53713,-1.54193,7,255,0 +710,11.67261,-1.84831,3.53713,-1.54193,7,255,0 +711,11.61303,-1.84831,3.53713,-1.54193,7,255,0 +712,11.55344,-1.84831,3.53713,-1.54193,7,255,0 +713,11.49385,-1.84831,3.53713,-1.54193,7,255,0 +714,11.43427,-1.84831,3.53713,-1.54193,7,255,0 +715,11.37469,-1.84831,3.53713,-1.54193,7,255,0 +716,11.3151,-1.84831,3.53713,-1.54193,7,255,0 +717,11.25552,-1.84831,3.53713,-1.54193,7,255,0 +718,11.19593,-1.84832,3.53713,-1.54193,7,255,0 +719,11.13635,-1.84832,3.53713,-1.54193,7,255,0 +720,11.07676,-1.84832,3.53713,-1.54193,7,255,0 +721,11.01718,-1.84832,3.53713,-1.54193,7,255,0 +722,10.95759,-1.84832,3.53713,-1.54193,7,255,0 +723,10.89801,-1.84832,3.53713,-1.54193,7,255,0 +724,10.83842,-1.84832,3.53713,-1.54193,7,255,0 +725,10.77884,-1.84832,3.53713,-1.54193,7,255,0 +726,10.71925,-1.84832,3.53713,-1.54193,7,255,0 +727,10.65967,-1.84832,3.53713,-1.54193,7,255,0 +728,10.60008,-1.84832,3.53713,-1.54193,7,255,0 +729,10.5405,-1.84832,3.53713,-1.54193,7,255,0 +730,10.48091,-1.84832,3.53713,-1.54193,7,255,0 +731,10.42133,-1.84832,3.53713,-1.54193,7,255,0 +732,10.36174,-1.84832,3.53712,-1.54193,7,255,0 +733,10.30216,-1.84832,3.53712,-1.54193,7,255,0 +734,10.24257,-1.84832,3.53712,-1.54193,7,255,0 +735,10.18299,-1.84832,3.53712,-1.54193,7,255,0 +736,10.1234,-1.84832,3.53712,-1.54193,7,255,0 +737,10.06382,-1.84832,3.53712,-1.54193,7,255,0 +738,10.00423,-1.84832,3.53712,-1.54193,7,255,0 +739,9.94465,-1.84832,3.53712,-1.54193,7,255,0 +740,9.88506,-1.84832,3.53712,-1.54193,7,255,0 +741,9.82548,-1.84832,3.53712,-1.54193,7,255,0 +742,9.76589,-1.84832,3.53712,-1.54193,7,255,0 +743,9.70631,-1.84832,3.53712,-1.54193,7,255,0 +744,9.64673,-1.84832,3.53712,-1.54193,7,255,0 +745,9.58714,-1.84832,3.53712,-1.54193,7,255,0 +746,9.52755,-1.84832,3.53712,-1.54193,7,255,0 +747,9.46797,-1.84832,3.53712,-1.54193,7,255,0 +748,9.40839,-1.84832,3.53712,-1.54193,7,255,0 +749,9.3488,-1.84832,3.53712,-1.54193,7,255,0 +750,9.28922,-1.84832,3.53712,-1.54193,7,255,0 +751,9.22963,-1.84832,3.53712,-1.54193,7,255,0 +752,9.17004,-1.84832,3.53712,-1.54193,7,255,0 +753,9.11046,-1.84832,3.53712,-1.54193,7,255,0 +754,9.05088,-1.84832,3.53712,-1.54193,7,255,0 +755,8.99129,-1.84832,3.53712,-1.54193,7,255,0 +756,8.93171,-1.84832,3.53712,-1.54193,7,255,0 +757,8.87212,-1.84832,3.53712,-1.54193,7,255,0 +758,8.81254,-1.84832,3.53712,-1.54193,7,255,0 +759,8.75295,-1.84832,3.53712,-1.54193,7,255,0 +760,8.69337,-1.84832,3.53712,-1.54193,7,255,0 +761,8.63378,-1.84832,3.53712,-1.54193,7,255,0 +762,8.5742,-1.84832,3.53712,-1.54193,7,255,0 +763,8.51461,-1.84832,3.53712,-1.54193,7,255,0 +764,8.45503,-1.84832,3.53712,-1.54193,7,255,0 +765,8.39544,-1.84832,3.53712,-1.54193,7,255,0 +766,8.33586,-1.84832,3.53712,-1.54193,7,255,0 +767,8.27627,-1.84832,3.53712,-1.54193,7,255,0 +768,8.21669,-1.84832,3.53712,-1.54193,7,255,0 +769,8.1571,-1.84832,3.53712,-1.54193,7,255,0 +770,8.09752,-1.84832,3.53712,-1.54193,7,255,0 +771,8.03793,-1.84832,3.53712,-1.54193,7,255,0 +772,7.97835,-1.84832,3.53712,-1.54193,7,255,0 +773,7.91876,-1.84832,3.53712,-1.54193,7,255,0 +774,7.85918,-1.84832,3.53712,-1.54193,7,255,0 +775,7.79959,-1.84832,3.53712,-1.54193,7,255,0 +776,7.74001,-1.84832,3.53712,-1.54193,7,255,0 +777,7.68043,-1.84832,3.53712,-1.54193,7,255,0 +778,7.62084,-1.84832,3.53712,-1.54193,7,255,0 +779,7.56125,-1.84832,3.53712,-1.54193,7,255,0 +780,7.50167,-1.84832,3.53712,-1.54193,7,255,0 +781,7.44208,-1.84832,3.53712,-1.54193,7,255,0 +782,7.3825,-1.84832,3.53712,-1.54193,7,255,0 +783,7.32291,-1.84832,3.53712,-1.54193,7,255,0 +784,7.26333,-1.84832,3.53712,-1.54193,7,255,0 +785,7.20374,-1.84832,3.53712,-1.54193,7,255,0 +786,7.14416,-1.84832,3.53712,-1.54193,7,255,0 +787,7.08457,-1.84832,3.53712,-1.54193,7,255,0 +788,7.02499,-1.84832,3.53712,-1.54193,7,255,0 +789,6.96541,-1.84832,3.53712,-1.54193,7,255,0 +790,6.90582,-1.84832,3.53712,-1.54193,7,255,0 +791,6.84623,-1.84832,3.53712,-1.54193,7,255,0 +792,6.78665,-1.84833,3.53712,-1.54193,7,255,0 +793,6.72706,-1.84833,3.53712,-1.54193,7,255,0 +794,6.66748,-1.84833,3.53712,-1.54193,7,255,0 +795,6.6079,-1.84833,3.53712,-1.54193,7,255,0 +796,6.54831,-1.84833,3.53712,-1.54193,7,255,0 +797,6.48873,-1.84833,3.53712,-1.54193,7,255,0 +798,6.42914,-1.84833,3.53712,-1.54193,7,255,0 +799,6.36956,-1.84833,3.53712,-1.54193,7,255,0 +800,6.30997,-1.84833,3.53712,-1.54193,7,255,0 +801,6.25038,-1.84833,3.53712,-1.54193,7,255,0 +802,6.1908,-1.84833,3.53712,-1.54193,7,255,0 +803,6.13123,-1.84833,3.53712,-1.54193,7,255,0 +804,6.07158,-1.84833,3.53712,-1.54193,7,255,0 +805,6.01204,-1.84833,3.53712,-1.54193,7,255,0 +806,5.95275,-1.84833,3.53712,-1.54193,7,255,0 +807,5.89215,-1.84833,3.53712,-1.54193,7,255,0 +808,5.83329,-1.84833,3.53712,-1.54193,7,255,0 +809,5.77773,-1.84833,3.53712,-1.54193,7,255,0 +810,5.70396,-1.84833,3.53712,-1.54193,7,255,0 +811,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +812,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +813,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +814,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +815,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +816,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +817,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +818,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +819,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +820,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +821,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +822,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +823,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +824,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +825,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +826,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +827,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +828,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +829,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +830,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +831,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +832,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +833,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +834,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +835,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +836,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +837,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +838,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +839,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +840,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +841,5.65454,-1.84833,3.53712,-1.54193,7,255,0 +842,5.65454,-1.84833,3.53715,-1.54193,7,255,0 +843,5.65454,-1.84833,3.53721,-1.54193,7,255,0 +844,5.65454,-1.84833,3.53726,-1.54193,7,255,0 +845,5.65454,-1.84833,3.5373,-1.54193,7,255,0 +846,5.65454,-1.84833,3.53735,-1.54193,7,255,0 +847,5.65454,-1.84833,3.5374,-1.54193,7,255,0 +848,5.65454,-1.84833,3.53746,-1.54193,7,255,0 +849,5.65454,-1.84833,3.53749,-1.54193,7,255,0 +850,5.65454,-1.84833,3.53751,-1.54193,7,255,0 +851,5.65454,-1.84833,3.53752,-1.54193,7,255,0 +852,5.65454,-1.84833,3.53753,-3.11273,7,255,0 +853,5.65454,-1.84833,3.53754,-3.11273,7,255,0 +854,5.65454,-1.84833,3.53755,-3.11273,7,255,0 +855,5.65454,-1.84833,3.53756,-3.11273,7,255,0 +856,5.65454,-1.84833,3.53756,-3.11273,7,255,0 +857,5.65454,-1.84833,3.53757,-3.11273,7,255,0 +858,5.65454,-1.84833,3.53757,-3.11273,7,255,0 +859,5.65454,-1.84833,3.53758,-3.11273,7,255,0 +860,5.65454,-1.84833,3.53758,-3.11273,7,255,0 +861,5.65454,-1.84833,3.53758,-3.11273,7,255,0 +862,5.65454,-1.84833,3.53758,-3.11273,7,255,0 +863,5.65454,-1.84833,3.53758,-3.11273,7,255,0 +864,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +865,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +866,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +867,5.65454,-1.84833,3.53759,-3.11273,7,255,0 +868,5.65049,-1.82643,3.51012,-3.10193,7,255,0 +869,5.6412,-1.78182,3.454,-3.0815,7,255,0 +870,5.63027,-1.74017,3.4012,-3.06561,7,255,0 +871,5.61879,-1.70323,3.35405,-3.05319,7,255,0 +872,5.60705,-1.66743,3.30825,-3.0404,7,255,0 +873,5.59457,-1.63197,3.26272,-3.02754,7,255,0 +874,5.58083,-1.59674,3.21726,-3.01564,7,255,0 +875,5.56591,-1.56175,3.17188,-3.00459,7,255,0 +876,5.55,-1.52703,3.12665,-2.99406,7,255,0 +877,5.53318,-1.49257,3.08158,-2.984,7,255,0 +878,5.51549,-1.45835,3.03665,-2.97444,7,255,0 +879,5.49698,-1.42437,2.99186,-2.96534,7,255,0 +880,5.47771,-1.39062,2.94722,-2.95664,7,255,0 +881,5.45769,-1.35711,2.90273,-2.94832,7,255,0 +882,5.43697,-1.32382,2.85839,-2.94036,7,255,0 +883,5.41557,-1.29075,2.81421,-2.93275,7,255,0 +884,5.39352,-1.25791,2.77018,-2.92546,7,255,0 +885,5.37084,-1.22528,2.7263,-2.91847,7,255,0 +886,5.34756,-1.19287,2.68258,-2.91176,7,255,0 +887,5.32371,-1.16067,2.63901,-2.90533,7,255,0 +888,5.29931,-1.12867,2.5956,-2.89914,7,255,0 +889,5.27437,-1.09687,2.55233,-2.8932,7,255,0 +890,5.24894,-1.06527,2.50922,-2.88748,7,255,0 +891,5.22301,-1.03387,2.46625,-2.88196,7,255,0 +892,5.19661,-1.00265,2.42343,-2.87665,7,255,0 +893,5.16977,-0.97162,2.38076,-2.87153,7,255,0 +894,5.1425,-0.94076,2.33823,-2.86659,7,255,0 +895,5.11481,-0.91009,2.29584,-2.86182,7,255,0 +896,5.08672,-0.87958,2.25359,-2.85721,7,255,0 +897,5.05825,-0.84924,2.21147,-2.85275,7,255,0 +898,5.02941,-0.81907,2.16949,-2.84843,7,255,0 +899,5.00021,-0.78905,2.12764,-2.84425,7,255,0 +900,4.97068,-0.75919,2.08592,-2.84019,7,255,0 +901,4.94082,-0.72948,2.04432,-2.83626,7,255,0 +902,4.91064,-0.69991,2.00285,-2.83245,7,255,0 +903,4.88015,-0.67049,1.9615,-2.82875,7,255,0 +904,4.84938,-0.64121,1.92026,-2.82515,7,255,0 +905,4.81832,-0.61207,1.87915,-2.82165,7,255,0 +906,4.78698,-0.58306,1.83814,-2.81825,7,255,0 +907,4.75539,-0.55417,1.79725,-2.81494,7,255,0 +908,4.72354,-0.52542,1.75647,-2.81171,7,255,0 +909,4.69144,-0.49678,1.71579,-2.80857,7,255,0 +910,4.65911,-0.46827,1.67521,-2.80551,7,255,0 +911,4.62655,-0.43987,1.63474,-2.80252,7,255,0 +912,4.59377,-0.41158,1.59436,-2.79961,7,255,0 +913,4.56077,-0.38341,1.55408,-2.79676,7,255,0 +914,4.52756,-0.35535,1.5139,-2.79398,7,255,0 +915,4.49413,-0.3274,1.47382,-2.79127,7,255,0 +916,4.46048,-0.29957,1.43385,-2.78864,7,255,0 +917,4.4266,-0.27186,1.39398,-2.78607,7,255,0 +918,4.39247,-0.24428,1.35423,-2.78355,7,255,0 +919,4.3582,-0.21679,1.31456,-2.78112,7,255,0 +920,4.32383,-0.18938,1.27495,-2.77877,7,255,0 +921,4.28909,-0.16211,1.23548,-2.77639,7,255,0 +922,4.2539,-0.13496,1.19615,-2.77395,7,255,0 +923,4.21934,-0.10777,1.15672,-2.77183,7,255,0 +924,4.18494,-0.07986,1.11621,-2.77023,7,255,0 +925,4.14273,-0.04879,1.07106,-2.76811,7,255,0 +926,4.08671,-0.016,1.02331,-2.76493,7,255,0 +927,4.02606,0.0,1.0,-2.76315,7,255,0 +928,3.97066,0.0,1.0,-2.76315,7,255,0 +929,3.91803,0.0,1.0,-2.76315,7,255,0 +930,3.86381,0.0,1.0,-2.76315,7,255,0 +931,3.80863,0.0,1.0,-2.76315,7,255,0 +932,3.75394,0.0,1.0,-2.76315,7,255,0 +933,3.69956,0.0,1.0,-2.76315,7,255,0 +934,3.64504,0.0,1.0,-2.76315,7,255,0 +935,3.59042,0.0,1.0,-2.76315,7,255,0 +936,3.53584,0.0,1.0,-2.76315,7,255,0 +937,3.48129,0.0,1.0,-2.76315,7,255,0 +938,3.42673,0.0,1.0,-2.76315,7,255,0 +939,3.37216,0.0,1.0,-2.76315,7,255,0 +940,3.31759,0.0,1.0,-2.76315,7,255,0 +941,3.26303,0.0,1.0,-2.76315,7,255,0 +942,3.20846,0.0,1.0,-2.76315,7,255,0 +943,3.15389,0.0,1.0,-2.76315,7,255,0 +944,3.09933,0.0,1.0,-2.76315,7,255,0 +945,3.04476,0.0,1.0,-2.76315,7,255,0 +946,2.9902,0.0,1.0,-2.76315,7,255,0 +947,2.93563,0.0,1.0,-2.76315,7,255,0 +948,2.88107,0.0,1.0,-2.76315,7,255,0 +949,2.8265,0.0,1.0,-2.76315,7,255,0 +950,2.77194,0.0,1.0,-2.76315,7,255,0 +951,2.71737,0.0,1.0,-2.76315,7,255,0 +952,2.6628,0.0,1.0,-2.76315,7,255,0 +953,2.60824,0.0,1.0,-2.76315,7,255,0 +954,2.55367,0.0,1.0,-2.76315,7,255,0 +955,2.49911,0.0,1.0,-2.76315,7,255,0 +956,2.44454,0.0,1.0,-2.76315,7,255,0 +957,2.38998,0.0,1.0,-2.76315,7,255,0 +958,2.33541,0.0,1.0,-2.76315,7,255,0 +959,2.28084,0.0,1.0,-2.76315,7,255,0 +960,2.22628,0.0,1.0,-2.76315,7,255,0 +961,2.17171,0.0,1.0,-2.76315,7,255,0 +962,2.11715,0.0,1.0,-2.76315,7,255,0 +963,2.06258,0.0,1.0,-2.76315,7,255,0 +964,2.00802,0.0,1.0,-2.76315,7,255,0 +965,1.95345,0.0,1.0,-2.76315,7,255,0 +966,1.89888,0.0,1.0,-2.76315,7,255,0 +967,1.84432,0.0,1.0,-2.76315,7,255,0 +968,1.78975,0.0,1.0,-2.76315,7,255,0 +969,1.73519,0.0,1.0,-2.76315,7,255,0 +970,1.68063,0.0,1.0,-2.76315,7,255,0 +971,1.62606,0.0,1.0,-2.76315,7,255,0 +972,1.57149,0.0,1.0,-2.76315,7,255,0 +973,1.51693,0.0,1.0,-2.76315,7,255,0 +974,1.46236,0.0,1.0,-2.76315,7,255,0 +975,1.4078,0.0,1.0,-2.76315,7,255,0 +976,1.35323,0.0,1.0,-2.76315,7,255,0 +977,1.29867,0.0,1.0,-2.76315,7,255,0 +978,1.2441,0.0,1.0,-2.76315,7,255,0 +979,1.18953,0.0,1.0,-2.76315,7,255,0 +980,1.13497,0.0,1.0,-2.76315,7,255,0 +981,1.0804,0.0,1.0,-2.76315,7,255,0 +982,1.02584,0.0,1.0,-2.76315,7,255,0 +983,0.97127,0.0,1.0,-2.76315,7,255,0 +984,0.9167,0.0,1.0,-2.76315,7,255,0 +985,0.86214,0.0,1.0,-2.76315,7,255,0 +986,0.80757,0.0,1.0,-2.76315,7,255,0 +987,0.75301,0.0,1.0,-2.76315,7,255,0 +988,0.69844,0.0,1.0,-2.76315,7,255,0 +989,0.64388,0.0,1.0,-2.76315,7,255,0 +990,0.58931,0.0,1.0,-2.76315,7,255,0 +991,0.53475,0.0,1.0,-2.76315,7,255,0 +992,0.48018,0.0,1.0,-2.76315,7,255,0 +993,0.42561,0.0,1.0,-2.76315,7,255,0 +994,0.37105,0.0,1.0,-2.76315,7,255,0 +995,0.31648,0.0,1.0,-2.76315,7,255,0 +996,0.26192,0.0,1.0,-2.76315,7,255,0 +997,0.20735,0.0,1.0,-2.76315,7,255,0 +998,0.15279,0.0,1.0,-2.76315,7,255,0 +999,0.09822,0.0,1.0,-2.76315,7,255,0 +1000,0.04365,0.0,1.0,-2.76315,7,255,0 +1001,-0.01091,0.0,1.0,-2.76315,7,255,0 +1002,-0.06547,0.0,1.0,-2.76315,7,255,0 +1003,-0.12004,0.0,1.0,-2.76315,7,255,0 +1004,-0.17463,0.0,1.0,-2.76315,7,255,0 +1005,-0.22918,0.0,1.0,-2.76315,7,255,0 +1006,-0.28366,0.0,1.0,-2.76315,7,255,0 +1007,-0.33828,0.0,1.0,-2.76315,7,255,0 +1008,-0.39314,0.0,1.0,-2.76315,7,255,0 +1009,-0.44752,0.0,1.0,-2.76315,7,255,0 +1010,-0.50114,0.0,1.0,-2.76315,7,255,0 +1011,-0.55624,0.0,1.0,-2.76315,7,255,0 +1012,-0.61376,0.0,1.0,-2.76315,7,255,0 +1013,-0.66693,0.0,1.0,-2.76315,7,255,0 +1014,-0.7127,0.0,1.0,-2.76315,7,255,0 +1015,-0.77046,0.0,1.0,-2.76315,7,255,0 +1016,-0.85023,0.00069,1.0,-2.76315,7,255,0 +1017,-0.90212,0.0055,1.0,-2.76315,7,255,0 +1018,-0.9114,0.03656,1.0,-2.76315,7,255,0 +1019,-0.91299,0.09409,1.0,-2.76315,7,255,0 +1020,-0.91465,0.15423,1.0,-2.76315,7,255,0 +1021,-0.917,0.21249,1.0,-2.76315,7,255,0 +1022,-0.91909,0.26934,1.0,-2.76315,7,255,0 +1023,-0.92101,0.32571,1.0,-2.76315,7,255,0 +1024,-0.92299,0.3824,1.0,-2.76315,7,255,0 +1025,-0.92502,0.43932,1.0,-2.76315,7,255,0 +1026,-0.92703,0.4962,1.0,-2.76315,7,255,0 +1027,-0.92902,0.55304,1.0,-2.76315,7,255,0 +1028,-0.93103,0.60986,1.0,-2.76315,7,255,0 +1029,-0.93303,0.66669,1.0,-2.76315,7,255,0 +1030,-0.93504,0.72353,1.0,-2.76315,7,255,0 +1031,-0.93704,0.78037,1.0,-2.76315,7,255,0 +1032,-0.93905,0.8372,1.0,-2.76315,7,255,0 +1033,-0.94105,0.89403,1.0,-2.76315,7,255,0 +1034,-0.94306,0.95087,1.0,-2.76315,7,255,0 +1035,-0.94506,1.00771,1.0,-2.76315,7,255,0 +1036,-0.94706,1.06454,1.0,-2.76315,7,255,0 +1037,-0.94907,1.12137,1.0,-2.76315,7,255,0 +1038,-0.95107,1.17821,1.0,-2.76315,7,255,0 +1039,-0.95308,1.23504,1.0,-2.76315,7,255,0 +1040,-0.95508,1.29188,1.0,-2.76315,7,255,0 +1041,-0.95709,1.34871,1.0,-2.76315,7,255,0 +1042,-0.95909,1.40555,1.0,-2.76315,7,255,0 +1043,-0.96109,1.46238,1.0,-2.76315,7,255,0 +1044,-0.9631,1.51922,1.0,-2.76315,7,255,0 +1045,-0.9651,1.57605,1.0,-2.76315,7,255,0 +1046,-0.96711,1.63289,1.0,-2.76315,7,255,0 +1047,-0.96911,1.68972,1.0,-2.76315,7,255,0 +1048,-0.97112,1.74656,1.0,-2.76315,7,255,0 +1049,-0.97312,1.80339,1.0,-2.76315,7,255,0 +1050,-0.97512,1.86024,1.0,-2.76315,7,255,0 +1051,-0.97713,1.91706,1.0,-2.76315,7,255,0 +1052,-0.97913,1.97386,1.0,-2.76315,7,255,0 +1053,-0.98114,2.03073,1.0,-2.76315,7,255,0 +1054,-0.98314,2.08772,1.0,-2.76315,7,255,0 +1055,-0.98515,2.14444,1.0,-2.76315,7,255,0 +1056,-0.98715,2.20073,1.0,-2.76315,7,255,0 +1057,-0.98915,2.2579,1.0,-2.76315,7,255,0 +1058,-0.99115,2.3165,1.0,-2.76315,7,255,0 +1059,-0.99316,2.37257,1.0,-2.76315,7,255,0 +1060,-0.99521,2.42414,1.0,-2.76315,7,255,0 +1061,-0.99521000000000004,2.42414,1.0,0,0,0,0 +1062,-1.0301400000000001,2.4494266666666666,1.0,0,0,0,0 +1063,-1.06507,2.4747133333333333,1.0,0,0,0,0 +1064,-1.1000000000000001,2.5,1.0,0,0,0,0 diff --git a/tests/animation_3.csv b/tests/animation_3.csv new file mode 100644 index 0000000..1f725db --- /dev/null +++ b/tests/animation_3.csv @@ -0,0 +1,12 @@ +route +20,0.0,0.0,1.0,0.0,0,204,2 +21,0.02217,0.0,1.0,0.0,0,204,2 +22,0.08889,0.0,1.0,0.0,0,204,2 +23,0.19737,0.0,1.0,0.0,0,204,2 +24,0.33926,0.0,1.0,0.0,0,204,2 +25,0.5,0.0,1.0,0.0,0,204,2 +26,0.66074,0.0,1.0,0.0,0,204,2 +27,0.80263,0.0,1.0,0.0,0,204,2 +28,0.91111,0.0,1.0,0.0,0,204,2 +29,0.97783,0.0,1.0,0.0,0,204,2 +30,1.0,0.0,1.0,0.0,0,204,2 diff --git a/tests/animation_test.py b/tests/animation_test.py new file mode 100644 index 0000000..decf80a --- /dev/null +++ b/tests/animation_test.py @@ -0,0 +1,76 @@ +import os +import sys +import shutil + +# Add parent dir to PATH to import config +import inspect +current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +parent_dir = os.path.dirname(current_dir) +sys.path.insert(0, parent_dir) +sys.path.insert(0, os.path.join(parent_dir,"Drone")) + +from config import ConfigManager + +config_path = 'animation_config/config' +spec_path = os.path.join(config_path,'spec') +if not os.path.exists(spec_path): + try: + os.makedirs(spec_path) + except OSError: + print("Creation of the directory {} failed".format(spec_path)) + else: + print("Successfully created the directory {}".format(spec_path)) + +shutil.copy("../Drone/config/spec/configspec_client.ini", spec_path) + +config = ConfigManager() +config.load_config_and_spec(os.path.join(config_path,'client.ini')) + +assert config.config_name == "client" + +import animation_lib + +a = animation_lib.Animation(config, "animation_1.csv") + +assert a.id == 'basic' +assert a.original_frames[0].get_pos() == [0.,0.,0.] +assert a.original_frames[0].get_color() == [204,2,0] +assert a.original_frames[0].pose_is_valid() + +# print animation_lib.get_numbers(a.static_begin_frames) +# print animation_lib.get_numbers(a.takeoff_frames) +# print animation_lib.get_numbers(a.route_frames) +# print animation_lib.get_numbers(a.land_frames) +# print animation_lib.get_numbers(a.static_end_frames) + +assert animation_lib.get_numbers(a.static_begin_frames) == range(1,11) +assert animation_lib.get_numbers(a.takeoff_frames) == range(11,21) +assert animation_lib.get_numbers(a.route_frames) == range(21,31) +assert animation_lib.get_numbers(a.land_frames) == range(31, 41) +assert animation_lib.get_numbers(a.static_end_frames) == range(41, 51) + +a.update_frames(config, "animation_2.csv") + +assert a.id == 'parad' +assert a.original_frames[269].get_pos() == [-1.00519,2.65699,0.21] +assert a.original_frames[269].get_color() == [7,255,0] +assert a.original_frames[269].pose_is_valid() +assert animation_lib.get_numbers(a.static_begin_frames) == range(271) +assert animation_lib.get_numbers(a.takeoff_frames) == range(271,285) +assert animation_lib.get_numbers(a.route_frames) == range(285,1065) +assert animation_lib.get_numbers(a.land_frames) == [] +assert animation_lib.get_numbers(a.static_end_frames) == [] + +a.update_frames(config, "animation_3.csv") + +assert a.id == 'route' +assert a.original_frames[9].get_pos() == [0.97783,0.0,1.0] +assert a.original_frames[9].get_color() == [0,204,2] +assert a.original_frames[9].pose_is_valid() +assert animation_lib.get_numbers(a.static_begin_frames) == [] +assert animation_lib.get_numbers(a.takeoff_frames) == [] +assert animation_lib.get_numbers(a.route_frames) == range(20,31) +assert animation_lib.get_numbers(a.land_frames) == [] +assert animation_lib.get_numbers(a.static_end_frames) == [] + +shutil.rmtree('animation_config') From a8e808b2af02477da8aa19a60066859433a317cf Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 28 May 2020 10:21:34 +0300 Subject: [PATCH 15/43] tests: Update tests for animation_lib --- Drone/animation_lib.py | 28 ++++++----- tests/animation_test.py | 102 ++++++++++++++++++++++++++-------------- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/Drone/animation_lib.py b/Drone/animation_lib.py index b75e745..3519d1e 100644 --- a/Drone/animation_lib.py +++ b/Drone/animation_lib.py @@ -81,8 +81,8 @@ class Frame(object): class Animation(object): def __init__(self, config=None, filepath="animation.csv"): self.id = None - self.static_begin_time = None - self.takeoff_time = None + self.static_begin_time = 0 + self.takeoff_time = 0 self.original_frames = None self.static_begin_frames = None self.takeoff_frames = None @@ -138,7 +138,7 @@ class Animation(object): return else: self.original_frames.append(frame) - self.split_animation() + self.split_animation() ''' Split animation into 5 parts: static_begin, takeoff, route, land, static_end @@ -150,9 +150,6 @@ class Animation(object): Count static_begin_time and takeoff_time ''' def split_animation(self, move_delta=0.01): - if len(self.original_frames) == 0: - return - frames = copy.deepcopy(self.original_frames) self.static_begin_frames = [] self.takeoff_frames = [] self.route_frames = [] @@ -160,26 +157,33 @@ class Animation(object): self.static_end_frames = [] self.static_begin_time = 0 self.takeoff_time = 0 + if len(self.original_frames) == 0: + return + frames = copy.deepcopy(self.original_frames) i = 0 # Moving index from the beginning # Select static begin frames while i < len(frames) - 1: + self.static_begin_time += frames[i].delay if moving(frames[i], frames[i+1], move_delta): break - self.static_begin_time += frames[i].delay i += 1 if i > 0: self.static_begin_frames = frames[:i+1] frames = frames[i+1:] i = 0 + else: + self.static_begin_time = 0 # Select takeoff frames while i < len(frames) - 1: + self.takeoff_time += frames[i].delay if moving(frames[i], frames[i+1], move_delta, z = False) or (frames[i+1].z - frames[i].z <= 0): break - self.takeoff_time += frames[i].delay i += 1 if i > 0: self.takeoff_frames = frames[:i+1] frames = frames[i+1:] + else: + self.takeoff_time = 0 i = len(frames) - 1 # Moving index from the end # Select static end frames while i >= 0: @@ -203,6 +207,7 @@ class Animation(object): def make_output_frames(self, static_begin, takeoff, route, land, static_end): self.output_frames = [] + self.output_frames_min_z = None if static_begin: self.output_frames += self.static_begin_frames if takeoff: @@ -213,12 +218,13 @@ class Animation(object): self.output_frames += self.land_frames if static_end: self.output_frames += self.static_end_frames - self.output_frames_min_z = min(self.output_frames, key = lambda p: p.z).z + if self.output_frames: + self.output_frames_min_z = min(self.output_frames, key = lambda p: p.z).z def update_frames(self, config, filepath): + self.__init__() self.load(filepath, config.animation_frame_delay) - if self.original_frames: - self.make_output_frames(config.animation_output_static_begin, + self.make_output_frames(config.animation_output_static_begin, config.animation_output_takeoff, config.animation_output_route, config.animation_output_land, diff --git a/tests/animation_test.py b/tests/animation_test.py index decf80a..955af02 100644 --- a/tests/animation_test.py +++ b/tests/animation_test.py @@ -1,6 +1,7 @@ import os import sys import shutil +from pytest import approx # Add parent dir to PATH to import config import inspect @@ -30,47 +31,78 @@ assert config.config_name == "client" import animation_lib -a = animation_lib.Animation(config, "animation_1.csv") +a = animation_lib.Animation() + +def test_animation_1(): + a.update_frames(config, "animation_1.csv") + assert a.id == 'basic' + assert a.original_frames[0].get_pos() == [0.,0.,0.] + assert a.original_frames[0].get_color() == [204,2,0] + assert a.original_frames[0].pose_is_valid() + assert animation_lib.get_numbers(a.static_begin_frames) == range(1,11) + assert animation_lib.get_numbers(a.takeoff_frames) == range(11,21) + assert animation_lib.get_numbers(a.route_frames) == range(21,31) + assert animation_lib.get_numbers(a.land_frames) == range(31, 41) + assert animation_lib.get_numbers(a.static_end_frames) == range(41, 51) + assert animation_lib.get_numbers(a.output_frames) == range(11,31) + assert approx(a.static_begin_time) == 1 + assert approx(a.takeoff_time) == 1 + assert approx(a.output_frames_min_z) == 0.1 + +def test_animation_2(): + a.update_frames(config, "animation_2.csv") + assert a.id == 'parad' + assert a.original_frames[269].get_pos() == [-1.00519,2.65699,0.21] + assert a.original_frames[269].get_color() == [7,255,0] + assert a.original_frames[269].pose_is_valid() + assert animation_lib.get_numbers(a.static_begin_frames) == range(271) + assert animation_lib.get_numbers(a.takeoff_frames) == range(271,285) + assert animation_lib.get_numbers(a.route_frames) == range(285,1065) + assert animation_lib.get_numbers(a.land_frames) == [] + assert animation_lib.get_numbers(a.static_end_frames) == [] + assert animation_lib.get_numbers(a.output_frames) == range(271, 1065) + assert approx(a.static_begin_time) == 27.1 + assert approx(a.takeoff_time) == 1.4 + assert approx(a.output_frames_min_z) == 0.24386 + +def test_animation_3(): + a.update_frames(config, "animation_3.csv") + assert a.id == 'route' + assert a.original_frames[9].get_pos() == [0.97783,0.0,1.0] + assert a.original_frames[9].get_color() == [0,204,2] + assert a.original_frames[9].pose_is_valid() + assert animation_lib.get_numbers(a.static_begin_frames) == [] + assert animation_lib.get_numbers(a.takeoff_frames) == [] + assert animation_lib.get_numbers(a.route_frames) == range(20,31) + assert animation_lib.get_numbers(a.land_frames) == [] + assert animation_lib.get_numbers(a.static_end_frames) == [] + assert approx(a.static_begin_time) == 0 + assert approx(a.takeoff_time) == 0 + assert approx(a.output_frames_min_z) == 1 + +def test_animation_no_file(): + a.update_frames(config, "zzz.csv") + assert a.id == 'No animation' + assert a.original_frames == [] + assert a.output_frames == [] + assert animation_lib.get_numbers(a.static_begin_frames) == [] + assert animation_lib.get_numbers(a.takeoff_frames) == [] + assert animation_lib.get_numbers(a.route_frames) == [] + assert animation_lib.get_numbers(a.land_frames) == [] + assert animation_lib.get_numbers(a.static_end_frames) == [] + assert a.static_begin_time == 0 + assert a.takeoff_time == 0 + assert a.output_frames_min_z is None -assert a.id == 'basic' -assert a.original_frames[0].get_pos() == [0.,0.,0.] -assert a.original_frames[0].get_color() == [204,2,0] -assert a.original_frames[0].pose_is_valid() # print animation_lib.get_numbers(a.static_begin_frames) # print animation_lib.get_numbers(a.takeoff_frames) # print animation_lib.get_numbers(a.route_frames) # print animation_lib.get_numbers(a.land_frames) # print animation_lib.get_numbers(a.static_end_frames) - -assert animation_lib.get_numbers(a.static_begin_frames) == range(1,11) -assert animation_lib.get_numbers(a.takeoff_frames) == range(11,21) -assert animation_lib.get_numbers(a.route_frames) == range(21,31) -assert animation_lib.get_numbers(a.land_frames) == range(31, 41) -assert animation_lib.get_numbers(a.static_end_frames) == range(41, 51) - -a.update_frames(config, "animation_2.csv") - -assert a.id == 'parad' -assert a.original_frames[269].get_pos() == [-1.00519,2.65699,0.21] -assert a.original_frames[269].get_color() == [7,255,0] -assert a.original_frames[269].pose_is_valid() -assert animation_lib.get_numbers(a.static_begin_frames) == range(271) -assert animation_lib.get_numbers(a.takeoff_frames) == range(271,285) -assert animation_lib.get_numbers(a.route_frames) == range(285,1065) -assert animation_lib.get_numbers(a.land_frames) == [] -assert animation_lib.get_numbers(a.static_end_frames) == [] - -a.update_frames(config, "animation_3.csv") - -assert a.id == 'route' -assert a.original_frames[9].get_pos() == [0.97783,0.0,1.0] -assert a.original_frames[9].get_color() == [0,204,2] -assert a.original_frames[9].pose_is_valid() -assert animation_lib.get_numbers(a.static_begin_frames) == [] -assert animation_lib.get_numbers(a.takeoff_frames) == [] -assert animation_lib.get_numbers(a.route_frames) == range(20,31) -assert animation_lib.get_numbers(a.land_frames) == [] -assert animation_lib.get_numbers(a.static_end_frames) == [] +# print animation_lib.get_numbers(a.output_frames) +# print a.static_begin_time +# print a.takeoff_time +# print a.output_frames_min_z shutil.rmtree('animation_config') From 63847de0d9182239854772175ddd58a3f1040c82 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Thu, 28 May 2020 12:25:57 +0300 Subject: [PATCH 16/43] tests: Update --- Drone/animation_lib.py | 46 ++++++++++++++++++++++++----------------- tests/animation_test.py | 21 +++++++++++++++---- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Drone/animation_lib.py b/Drone/animation_lib.py index 3519d1e..a505db4 100644 --- a/Drone/animation_lib.py +++ b/Drone/animation_lib.py @@ -32,6 +32,17 @@ def get_numbers(frames): numbers.append(frame.number) return numbers +def get_start_action(start_action, current_height, takeoff_level): + if start_action is 'auto': + if current_height > takeoff_level: + return 'takeoff' + else: + return 'play' + elif start_action in ('takeoff', 'play'): + return start_action + else: + return 'error' + class Frame(object): params_dict = { "number": None, @@ -80,6 +91,11 @@ class Frame(object): class Animation(object): def __init__(self, config=None, filepath="animation.csv"): + self.reset(filepath) + if config is not None: + self.update_frames(config, filepath) + + def reset(self, filepath): self.id = None self.static_begin_time = 0 self.takeoff_time = 0 @@ -92,8 +108,6 @@ class Animation(object): self.output_frames = None self.output_frames_min_z = None self.filepath = filepath - if config is not None: - self.update_frames(config, filepath) def load(self, filepath="animation.csv", delay=0.1): self.original_frames = [] @@ -222,7 +236,7 @@ class Animation(object): self.output_frames_min_z = min(self.output_frames, key = lambda p: p.z).z def update_frames(self, config, filepath): - self.__init__() + self.reset(filepath) self.load(filepath, config.animation_frame_delay) self.make_output_frames(config.animation_output_static_begin, config.animation_output_takeoff, @@ -234,36 +248,30 @@ class Animation(object): x0, y0, z0 = offset x_ratio, y_ratio, z_ratio = ratio scaled_frames = copy.deepcopy(self.output_frames) - for frame in scaled_frames: - frame.x = x_ratio*frame.x + x0 - frame.y = y_ratio*frame.y + y0 - frame.z = z_ratio*frame.z + z0 + if scaled_frames: + for frame in scaled_frames: + frame.x = x_ratio*frame.x + x0 + frame.y = y_ratio*frame.y + y0 + frame.z = z_ratio*frame.z + z0 return scaled_frames def get_scaled_output_min_z(self, ratio = (1,1,1), offset = (0,0,0)): + if self.output_frames_min_z is None: + return None x0, y0, z0 = offset x_ratio, y_ratio, z_ratio = ratio return self.output_frames_min_z*z_ratio + z0 def get_start_point(self, ratio = (1,1,1), offset = (0,0,0)): + if not self.output_frames: + return [] x0, y0, z0 = offset x_ratio, y_ratio, z_ratio = ratio first_frame = self.output_frames[0] x = x_ratio*first_frame.x + x0 y = y_ratio*first_frame.y + y0 z = z_ratio*first_frame.z + z0 - return x, y, z - - def get_start_action(self, start_action, current_height, takeoff_level): - if start_action is 'auto': - if current_height > takeoff_level: - return 'takeoff' - else: - return 'play' - elif start_action in ('takeoff', 'play'): - return start_action - else: - return 'error' + return [x, y, z] def check_ground(self, ground_level = 0, ratio = (1,1,1), offset = (0,0,0)): return ground_level <= self.get_scaled_output_min_z(ratio, offset) diff --git a/tests/animation_test.py b/tests/animation_test.py index 955af02..a3fee6a 100644 --- a/tests/animation_test.py +++ b/tests/animation_test.py @@ -2,6 +2,7 @@ import os import sys import shutil from pytest import approx +import pytest # Add parent dir to PATH to import config import inspect @@ -36,7 +37,7 @@ a = animation_lib.Animation() def test_animation_1(): a.update_frames(config, "animation_1.csv") assert a.id == 'basic' - assert a.original_frames[0].get_pos() == [0.,0.,0.] + assert approx(a.original_frames[0].get_pos()) == [0,0,0] assert a.original_frames[0].get_color() == [204,2,0] assert a.original_frames[0].pose_is_valid() assert animation_lib.get_numbers(a.static_begin_frames) == range(1,11) @@ -48,13 +49,16 @@ def test_animation_1(): assert approx(a.static_begin_time) == 1 assert approx(a.takeoff_time) == 1 assert approx(a.output_frames_min_z) == 0.1 + assert approx(a.get_scaled_output(ratio=[1,2,3], offset=[4,5,6])[0].get_pos()) == [4.,5.,6.3] + assert approx(a.get_scaled_output_min_z(ratio=[1,2,3], offset=[4,5,6])) == 6.3 + assert approx(a.get_start_point(ratio=[1,2,3], offset=[4,5,6])) == [4.,5.,6.3] def test_animation_2(): a.update_frames(config, "animation_2.csv") assert a.id == 'parad' - assert a.original_frames[269].get_pos() == [-1.00519,2.65699,0.21] - assert a.original_frames[269].get_color() == [7,255,0] - assert a.original_frames[269].pose_is_valid() + assert approx(a.original_frames[271].get_pos()) == [-1.00519,2.65699,0.24386] + assert a.original_frames[271].get_color() == [7,255,0] + assert a.original_frames[271].pose_is_valid() assert animation_lib.get_numbers(a.static_begin_frames) == range(271) assert animation_lib.get_numbers(a.takeoff_frames) == range(271,285) assert animation_lib.get_numbers(a.route_frames) == range(285,1065) @@ -64,6 +68,9 @@ def test_animation_2(): assert approx(a.static_begin_time) == 27.1 assert approx(a.takeoff_time) == 1.4 assert approx(a.output_frames_min_z) == 0.24386 + assert approx(a.get_scaled_output(ratio=[1,2,3], offset=[4,5,6])[0].get_pos()) == [2.99481, 10.31398, 6.73158] + assert approx(a.get_scaled_output_min_z(ratio=[1,2,3], offset=[4,5,6])) == 6.73158 + assert approx(a.get_start_point(ratio=[1,2,3], offset=[4,5,6])) == [2.99481, 10.31398, 6.73158] def test_animation_3(): a.update_frames(config, "animation_3.csv") @@ -79,6 +86,9 @@ def test_animation_3(): assert approx(a.static_begin_time) == 0 assert approx(a.takeoff_time) == 0 assert approx(a.output_frames_min_z) == 1 + assert approx(a.get_scaled_output(ratio=[1,2,3], offset=[4,5,6])[0].get_pos()) == [4,5,9] + assert approx(a.get_scaled_output_min_z(ratio=[1,2,3], offset=[4,5,6])) == 9 + assert approx(a.get_start_point(ratio=[1,2,3], offset=[4,5,6])) == [4,5,9] def test_animation_no_file(): a.update_frames(config, "zzz.csv") @@ -93,6 +103,9 @@ def test_animation_no_file(): assert a.static_begin_time == 0 assert a.takeoff_time == 0 assert a.output_frames_min_z is None + assert a.get_scaled_output(ratio=[1,2,3], offset=[4,5,6]) == [] + assert a.get_scaled_output_min_z(ratio=[1,2,3], offset=[4,5,6]) is None + assert a.get_start_point(ratio=[1,2,3], offset=[4,5,6]) == [] # print animation_lib.get_numbers(a.static_begin_frames) From d775ea4e8b79a48bffa80bc2d2d6d4991fbc8585 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 29 May 2020 12:27:31 +0300 Subject: [PATCH 17/43] Drone: update animation_lib and tests --- Drone/animation_lib.py | 112 ++++++++++++++++++++++++++++++---------- tests/animation_test.py | 2 +- 2 files changed, 86 insertions(+), 28 deletions(-) diff --git a/Drone/animation_lib.py b/Drone/animation_lib.py index a505db4..ae14b79 100644 --- a/Drone/animation_lib.py +++ b/Drone/animation_lib.py @@ -1,7 +1,8 @@ import os -import time import csv import copy +import math +import time import numpy import rospy import logging @@ -32,17 +33,6 @@ def get_numbers(frames): numbers.append(frame.number) return numbers -def get_start_action(start_action, current_height, takeoff_level): - if start_action is 'auto': - if current_height > takeoff_level: - return 'takeoff' - else: - return 'play' - elif start_action in ('takeoff', 'play'): - return start_action - else: - return 'error' - class Frame(object): params_dict = { "number": None, @@ -86,6 +76,10 @@ class Frame(object): else: return [self.red, self.green, self.blue] + def set_yaw(self, yaw): + if yaw != "animation": + self.yaw = math.radians(float(yaw)) + def pose_is_valid(self): return self.get_pos() and (self.yaw is not None) @@ -97,27 +91,34 @@ class Animation(object): def reset(self, filepath): self.id = None - self.static_begin_time = 0 - self.takeoff_time = 0 + self.start_delay = 0 self.original_frames = None self.static_begin_frames = None + self.static_begin_time = 0 self.takeoff_frames = None + self.takeoff_time = 0 self.route_frames = None + self.route_time = 0 self.land_frames = None + self.land_time = 0 self.static_end_frames = None + self.static_end_time = 0 self.output_frames = None self.output_frames_min_z = None self.filepath = filepath + self.state = None - def load(self, filepath="animation.csv", delay=0.1): + def load(self, filepath="animation.csv", config = None): self.original_frames = [] self.corrected_frames = [] self.filepath = filepath + self.state = "OK" + delay = config.animation_frame_delay try: animation_file = open(filepath) except IOError: logger.debug("File {} can't be opened".format(filepath)) - self.id = "No animation" + self.state = "No animation" else: with animation_file: current_frame_delay = delay @@ -133,13 +134,20 @@ class Animation(object): logger.debug("Got new frame delay: {}".format(current_frame_delay)) else: logger.debug("No animation id in file") + self.id = "No animation id" try: frame = Frame(row_0, current_frame_delay) except ValueError as e: logger.error("Can't parse row in csv file. {}".format(e)) + self.state = "Bad animation file" return - else: - self.original_frames.append(frame) + try: + frame.set_yaw(config.animation_yaw) + except ValueError as e: + logger.error("Can't set yaw from configuration") + self.state = "Bad yaw from config" + return + self.original_frames.append(frame) for row in csv_reader: if len(row) == 2: current_frame_delay = float(row[1]) @@ -149,9 +157,15 @@ class Animation(object): frame = Frame(row, current_frame_delay) except ValueError as e: logger.error("Can't parse row in csv file. {}".format(e)) + self.state = "Bad animation file" return - else: - self.original_frames.append(frame) + try: + frame.set_yaw(config.animation_yaw) + except ValueError as e: + logger.error("Can't set yaw from configuration") + self.state = "Bad yaw from config" + return + self.original_frames.append(frame) self.split_animation() ''' @@ -171,6 +185,8 @@ class Animation(object): self.static_end_frames = [] self.static_begin_time = 0 self.takeoff_time = 0 + self.route_time = 0 + self.land_time = 0 if len(self.original_frames) == 0: return frames = copy.deepcopy(self.original_frames) @@ -201,6 +217,7 @@ class Animation(object): i = len(frames) - 1 # Moving index from the end # Select static end frames while i >= 0: + self.static_end_time += frames[i].delay if moving(frames[i], frames[i-1], move_delta): break i -= 1 @@ -208,28 +225,48 @@ class Animation(object): self.static_end_frames = frames[i+1:] frames = frames[:i+1] i = len(frames) - 1 + else: + self.static_end_time = 0 # Select land frames while i >= 0: + self.land_time += frames[i].delay if moving(frames[i], frames[i-1], move_delta, z = False) or (frames[i-1].z - frames[i].z <= 0): break i -= 1 if i < len(frames) - 1: self.land_frames = frames[i+1:] frames = frames[:i+1] + else: + self.land_time = 0 # Get route frames self.route_frames = frames + for frame in self.route_frames: + self.route_time += frame.delay def make_output_frames(self, static_begin, takeoff, route, land, static_end): self.output_frames = [] self.output_frames_min_z = None + self.start_delay = 0. + if not self.original_frames: + return + if not static_begin and not takeoff and not route and not land and not static_end: + return if static_begin: self.output_frames += self.static_begin_frames + if not static_begin: + self.start_delay += self.static_begin_time if takeoff: self.output_frames += self.takeoff_frames + if not static_begin and not takeoff: + self.start_delay += self.takeoff_time if route: self.output_frames += self.route_frames + if not static_begin and not takeoff and not route: + self.start_delay += self.route_time if land: self.output_frames += self.land_frames + if not static_begin and not takeoff and not route and not land: + self.start_delay += self.land_time if static_end: self.output_frames += self.static_end_frames if self.output_frames: @@ -237,14 +274,14 @@ class Animation(object): def update_frames(self, config, filepath): self.reset(filepath) - self.load(filepath, config.animation_frame_delay) + self.load(filepath, config) self.make_output_frames(config.animation_output_static_begin, config.animation_output_takeoff, config.animation_output_route, config.animation_output_land, config.animation_output_static_end) - def get_scaled_output(self, ratio = (1,1,1), offset = (0,0,0)): + def get_scaled_output(self, ratio=(1,1,1), offset=(0,0,0)): x0, y0, z0 = offset x_ratio, y_ratio, z_ratio = ratio scaled_frames = copy.deepcopy(self.output_frames) @@ -255,14 +292,14 @@ class Animation(object): frame.z = z_ratio*frame.z + z0 return scaled_frames - def get_scaled_output_min_z(self, ratio = (1,1,1), offset = (0,0,0)): + def get_scaled_output_min_z(self, ratio=(1,1,1), offset=(0,0,0)): if self.output_frames_min_z is None: return None - x0, y0, z0 = offset - x_ratio, y_ratio, z_ratio = ratio + z0 = offset[2] + z_ratio = ratio[2] return self.output_frames_min_z*z_ratio + z0 - def get_start_point(self, ratio = (1,1,1), offset = (0,0,0)): + def get_start_point(self, ratio=(1,1,1), offset=(0,0,0)): if not self.output_frames: return [] x0, y0, z0 = offset @@ -273,9 +310,30 @@ class Animation(object): z = z_ratio*first_frame.z + z0 return [x, y, z] - def check_ground(self, ground_level = 0, ratio = (1,1,1), offset = (0,0,0)): + def check_ground(self, ground_level=0, ratio=(1,1,1), offset=(0,0,0)): return ground_level <= self.get_scaled_output_min_z(ratio, offset) + def get_start_action(self, start_action, current_height, takeoff_level, + ground_level, ratio=(1,1,1), offset=(0,0,0)): + # Check output frames + if not self.output_frames: + return 'error: empty output frames' + if math.isnan(current_height): + return 'error: bad current_height' + # Check that bottom point of animation is higher than ground level + if ground_level > self.get_scaled_output_min_z(ratio, offset): + return 'error: some animation points are lower than ground level' + # Select start action + if start_action is 'auto': + if self.get_start_point(ratio, offset)[2] - current_height > takeoff_level: + return 'takeoff' + else: + return 'play' + elif start_action in ('takeoff', 'play'): + return start_action + else: + return 'error' + # Need for tests def save_corrected_animation(self): name, ext = os.path.splitext(self.filepath) diff --git a/tests/animation_test.py b/tests/animation_test.py index a3fee6a..5fde3b8 100644 --- a/tests/animation_test.py +++ b/tests/animation_test.py @@ -92,7 +92,7 @@ def test_animation_3(): def test_animation_no_file(): a.update_frames(config, "zzz.csv") - assert a.id == 'No animation' + assert a.id == None assert a.original_frames == [] assert a.output_frames == [] assert animation_lib.get_numbers(a.static_begin_frames) == [] From 4c5032b97585964fbce984a6aeaeab7deb804875 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Fri, 29 May 2020 12:28:28 +0300 Subject: [PATCH 18/43] Drone: Rewrite copter_client with new animation module --- Drone/config/spec/configspec_client.ini | 30 +- Drone/copter_client.py | 397 +++++++++++++----------- 2 files changed, 232 insertions(+), 195 deletions(-) diff --git a/Drone/config/spec/configspec_client.ini b/Drone/config/spec/configspec_client.ini index 6e8ac74..1574baa 100644 --- a/Drone/config/spec/configspec_client.ini +++ b/Drone/config/spec/configspec_client.ini @@ -39,11 +39,11 @@ decrease_thrust_after = float(default=5.0, min=0) [COPTER] frame_id = string(default=map) +arming_time = float(default=0.5) takeoff_height = float(default=1.0) takeoff_time = float(default=5.0, min=0) -safe_takeoff = boolean(default=False) reach_first_point_time = float(default=5.0, min=0) -land_time = float(default=1.0, min=0) +land_delay = float(default=1.0, min=0) land_timeout = float(default=10.0, min=0) # __list__ x y z common_offset = float_list(default=list(0, 0, 0), min=3, max=3) @@ -63,20 +63,28 @@ lon = string(default=0) yaw = float(default=0) [ANIMATION] -takeoff_detection = boolean(default=True) -land_detection = boolean(default=True) +# Available options: +# 'auto' - automatic action selection from 'takeoff' or 'fly' based on current copter level +# 'takeoff' - takeoff to first output animation point after static_begin_time then execute 'takeoff logic' +# 'fly' - execute animation frames after static_begin_time +start_action = string(default=auto) +takeoff_level = float(default=0.5) +ground_level = float(default=0) frame_delay = float(default=0.1, min=0.01) # Animation ratio (x, y, z) # __list__ x y z ratio = float_list(default=list(1.0, 1.0, 1.0), min=3, max=3) -# Available options: 'animation', 'nan' or a number in degrees +# Available options: +# 'animation' - take yaw from animation +# 'nan' - don't change yaw during flight +# or a number in degrees yaw = string(default=180.0) - [[OUTPUT]] - static_begin = boolean(default=False) - takeoff = boolean(default=True) - route = boolean(default=True) - land = boolean(default=False) - static_end = boolean(default=False) +[[OUTPUT]] +static_begin = boolean(default=False) +takeoff = boolean(default=True) +route = boolean(default=True) +land = boolean(default=False) +static_end = boolean(default=False) [LED] use = boolean(default=False) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 83534d4..8b87daf 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -9,7 +9,10 @@ import numpy try: from clever import srv except ImportError: - from clover import srv + try: + from clover import srv + except ImportError: + print("Can't import clever or clover") import datetime import logging @@ -17,8 +20,17 @@ import threading import psutil import subprocess from collections import namedtuple +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler -from FlightLib import FlightLib +try: + from FlightLib import FlightLib +except ImportError: + print("Can't import FlightLib") +try: + from FlightLib import LedLib +except ImportError: + print("Can't import LedLib") import client @@ -46,6 +58,12 @@ def azi(x, y): def get_xy(dist, azi): return dist*math.sin(math.radians(azi)), dist*math.cos(math.radians(azi)) +def valid(pos): + for coord in pos: + if math.isnan(coord): + return False + return True + static_broadcaster = tf2_ros.StaticTransformBroadcaster() emergency = False @@ -96,8 +114,8 @@ class CopterClient(client.Client): def __init__(self, config_path="config/client.ini"): super(CopterClient, self).__init__(config_path) self.load_config() - self.frames = {} self.telemetry = None + self.animation = animation.Animation(self.config, "animation.csv") def load_config(self): super(CopterClient, self).load_config() @@ -111,7 +129,7 @@ class CopterClient(client.Client): if self.config.led_use: from FlightLib import LedLib LedLib.init_led(self.config.led_pin) - task_manager_instance.start() # TODO move to self + task_manager_instance.start() start_subscriber() self.telemetry = Telemetry() self.telemetry.start_loop() @@ -158,11 +176,11 @@ class CopterClient(client.Client): lat = float(self.config.gps_frame_lat) lon = float(self.config.gps_frame_lon) geo_delta = Earth.Inverse(telem.lat, telem.lon, lat, lon) - logger.info("dist: {} | azi: {}".format(geo_delta['s12'], geo_delta['azi1'])) + #logger.info("dist: {} | azi: {}".format(geo_delta['s12'], geo_delta['azi1'])) dx, dy = get_xy(geo_delta['s12'], geo_delta['azi1']) gps_dx = telem.x + dx gps_dy = telem.y + dy - logger.info("GPS frame dx: {} | dy: {}".format(gps_dx, gps_dy)) + #logger.info("GPS frame dx: {} | dy: {}".format(gps_dx, gps_dy)) trans = TransformStamped() trans.transform.translation.x = gps_dx trans.transform.translation.y = gps_dy @@ -314,13 +332,13 @@ def _execute(*args, **kwargs): def _response_id(*args, **kwargs): new_id = kwargs.get("new_id", None) if new_id is not None: - old_id = client.active_client.client_id + old_id = copter.client_id if new_id != old_id: - client.active_client.config.set('PRIVATE', 'id', new_id, write=True) - client.active_client.client_id = new_id + copter.config.set('PRIVATE', 'id', new_id, write=True) + copter.client_id = new_id if new_id != '/hostname': - if client.active_client.config.system_restart_after_rename: - hostname = client.active_client.client_id + if copter.config.system_restart_after_rename: + hostname = copter.client_id configure_hostname(hostname) configure_hosts(hostname) configure_bashrc(hostname) @@ -347,28 +365,14 @@ def _response_selfcheck(*args, **kwargs): @messaging.request_callback("telemetry") def _response_telemetry(*args, **kwargs): - telemetry.update() - return telemetry.create_msg_contents() + copter.telemetry.update() + return copter.telemetry.create_msg_contents() @messaging.request_callback("anim_id") def _response_animation_id(*args, **kwargs): # Load animation - result = animation.get_id() - if result != 'No animation': - logger.debug("Saving corrected animation") - offset = numpy.array(client.active_client.config.private_offset) + numpy.array(client.active_client.config.copter_common_offset) - frames = animation.load_animation(os.path.abspath("animation.csv"), client.active_client.config.animation_frame_delay, - offset[0], offset[1], offset[2], *client.active_client.config.animation_ratio) - # Correct start and land frames in animation - corrected_frames, start_action, start_delay = animation.correct_animation(frames, - check_takeoff=client.active_client.config.animation_takeoff_detection, - check_land=client.active_client.config.animation_land_detection, - ) - logger.debug("Start action: {}".format(start_action)) - # Save corrected animation - animation.save_corrected_animation(corrected_frames) - return result + return copter.animation.id @messaging.request_callback("batt_voltage") @@ -405,9 +409,9 @@ def _response_cal_status(*args, **kwargs): @messaging.request_callback("position") def _response_position(*args, **kwargs): - telem = FlightLib.get_telemetry_locked(client.active_client.config.copter_frame_id) + telem = copter.telemetry.ros_telemetry return "{:.2f} {:.2f} {:.2f} {:.1f} {}".format( - telem.x, telem.y, telem.z, math.degrees(telem.yaw), client.active_client.config.copter_frame_id) + telem.x, telem.y, telem.z, math.degrees(telem.yaw), copter.config.copter_frame_id) @messaging.request_callback("calibrate_gyro") @@ -436,60 +440,61 @@ def _command_test(*args, **kwargs): print("stdout test") +@messaging.message_callback("update_animation") +def _command_update_animation(*args, **kwargs): + copter.animation.update_frames(copter.config, "animation.csv") + + @messaging.message_callback("move_start") def _command_move_start_to_current_position(*args, **kwargs): - x_start, y_start = animation.get_start_xy(os.path.abspath("animation.csv"), - *client.active_client.config.animation_ratio) - logger.debug("x_start = {}, y_start = {}".format(x_start, y_start)) - if not math.isnan(x_start): - telem = FlightLib.get_telemetry_locked(client.active_client.config.copter_frame_id) - logger.debug("x_telem = {}, y_telem = {}".format(telem.x, telem.y)) - if not math.isnan(telem.x): - client.active_client.config.set('PRIVATE', 'offset', - [telem.x - x_start, telem.y - y_start, client.active_client.config.private_offset[2]], - write=True) - logger.info("Set start delta: {:.2f} {:.2f}".format(client.active_client.config.private_offset[0], - client.active_client.config.private_offset[1])) - else: - logger.debug("Wrong telemetry") + offset = numpy.array(copter.config.private_offset) + numpy.array(copter.config.copter_common_offset) + try: + xs, ys, zs = copter.animation.get_start_point(copter.config.ratio, offset) + except ValueError: + logger.error("Can't get start point. Check animation file!") else: - logger.debug("Wrong animation file") + logger.debug("start x = {}, y = {}".format(xs, ys)) + telem = copter.telemetry.ros_telemetry + logger.debug("telemetry x = {}, y = {}".format(telem.x, telem.y)) + if valid([telem.x, telem.y, telem.z]): + copter.config.set('PRIVATE', 'offset', + [telem.x - xs, telem.y - ys, copter.config.private_offset[2]], write=True) + logger.info("Set start delta: {:.2f} {:.2f}".format(copter.config.private_offset[0], + copter.config.private_offset[1])) + else: + logger.error("Wrong telemetry") @messaging.message_callback("reset_start") def _command_reset_start(*args, **kwargs): - client.active_client.config.set('PRIVATE', 'offset', - [0, 0, client.active_client.config.private_offset[2]], - write=True) - logger.info("Reset start to {:.2f} {:.2f}".format(client.active_client.config.private_offset[0], - client.active_client.config.private_offset[1])) + copter.config.set('PRIVATE', 'offset', + [0, 0, copter.config.private_offset[2]], write=True) + logger.info("Reset start to {:.2f} {:.2f}".format(copter.config.private_offset[0], + copter.config.private_offset[1])) @messaging.message_callback("set_z_to_ground") def _command_set_z(*args, **kwargs): - telem = FlightLib.get_telemetry_locked(client.active_client.config.copter_frame_id) - client.active_client.config.set('PRIVATE', 'offset', - [client.active_client.config.private_offset[0], client.active_client.config.private_offset[1], telem.z], - write=True) - logger.info("Set z offset to {:.2f}".format(client.active_client.config.private_offset[2])) + telem = copter.telemetry.ros_telemetry + if valid([telem.x, telem.y, telem.z]): + copter.config.set('PRIVATE', 'offset', + [copter.config.private_offset[0], copter.config.private_offset[1], telem.z], write=True) + logger.info("Set z offset to {:.2f}".format(copter.config.private_offset[2])) + else: + logger.error("Wrong telemetry") @messaging.message_callback("reset_z_offset") def _command_reset_z(*args, **kwargs): - client.active_client.config.set('PRIVATE', 'offset', - [client.active_client.config.private_offset[0], client.active_client.config.private_offset[1], 0], - write=True) - logger.info("Reset z offset to {:.2f}".format(client.active_client.config.private_offset[2])) + copter.config.set('PRIVATE', 'offset', + [copter.config.private_offset[0], copter.config.private_offset[1], 0], write=True) + logger.info("Reset z offset to {:.2f}".format(copter.config.private_offset[2])) @messaging.message_callback("update_repo") def _command_update_repo(*args, **kwargs): - os.system("mv /home/pi/clever-show/Drone/client_config.ini /home/pi/clever-show/Drone/client_config_tmp.ini") - os.system("git reset --hard HEAD") - os.system("git checkout master") os.system("git fetch") os.system("git pull --rebase") - os.system("mv /home/pi/clever-show/Drone/client_config_tmp.ini /home/pi/clever-show/Drone/client_config.ini") os.system("chown -R pi:pi /home/pi/clever-show") @@ -512,7 +517,7 @@ def _command_service_restart(*args, **kwargs): @messaging.message_callback("repair_chrony") def _command_chrony_repair(*args, **kwargs): - repair_chrony(client.active_client.config.server_host) + repair_chrony(copter.config.server_host) @messaging.message_callback("led_test") @@ -527,13 +532,12 @@ def _command_led_fill(*args, **kwargs): r = kwargs.get("red", 0) g = kwargs.get("green", 0) b = kwargs.get("blue", 0) - LedLib.fill(r, g, b) @messaging.message_callback("flip") def _copter_flip(*args, **kwargs): - FlightLib.flip(frame_id=client.active_client.config.copter_frame_id) + FlightLib.flip(frame_id=copter.config.copter_frame_id) @messaging.message_callback("takeoff") @@ -541,30 +545,36 @@ def _command_takeoff(*args, **kwargs): logger.info("Takeoff at {}".format(datetime.datetime.now())) task_manager.add_task(0, 0, animation.takeoff, task_kwargs={ - "z": client.active_client.config.copter_takeoff_height, - "timeout": client.active_client.config.copter_takeoff_time, - "safe_takeoff": client.active_client.config.copter_safe_takeoff, - "use_leds": client.active_client.config.led_use & client.active_client.config.led_takeoff_indication, - } - ) + "z": copter.config.copter_takeoff_height, + "timeout": copter.config.copter_takeoff_time, + "safe_takeoff": False, + "use_leds": copter.config.led_use & copter.config.led_takeoff_indication, + }) @messaging.message_callback("takeoff_z") def _command_takeoff_z(*args, **kwargs): - z_str = kwargs.get("z", None) - if z_str is not None: - telem = FlightLib.get_telemetry_locked(client.active_client.config.copter_frame_id) - logger.info("Takeoff to z = {} at {}".format(z_str, datetime.datetime.now())) - task_manager.add_task(0, 0, FlightLib.reach_point, - task_kwargs={ - "x": telem.x, - "y": telem.y, - "z": float(z_str), - "frame_id": client.active_client.config.copter_frame_id, - "timeout": client.active_client.config.copter_takeoff_time, - "auto_arm": True, - } - ) + try: + z = float(kwargs.get("z", None)) + except TypeError: + logger.error("takeoff_z: No z argument!") + except ValueError: + logger.error("takeoff_z: Wrong z argument!") + else: + telem = FlightLib.get_telemetry_locked(copter.config.copter_frame_id) + if valid([telem.x, telem.y, telem.z]): + logger.info("Takeoff to z = {} at {}".format(z, datetime.datetime.now())) + task_manager.add_task(0, 0, FlightLib.reach_point, + task_kwargs={ + "x": telem.x, + "y": telem.y, + "z": z, + "frame_id": copter.config.copter_frame_id, + "timeout": copter.config.copter_takeoff_time, + "auto_arm": True, + }) + else: + logger.error("Wrong telemetry!") @messaging.message_callback("land") @@ -572,12 +582,11 @@ def _command_land(*args, **kwargs): task_manager.reset() task_manager.add_task(0, 0, animation.land, task_kwargs={ - "z": client.active_client.config.copter_takeoff_height, - "timeout": client.active_client.config.copter_takeoff_time, - "frame_id": client.active_client.config.copter_frame_id, - "use_leds": client.active_client.config.led_use & client.active_client.config.led_land_indication, - } - ) + "z": copter.config.copter_takeoff_height, + "timeout": copter.config.copter_land_timeout, + "frame_id": copter.config.copter_frame_id, + "use_leds": copter.config.led_use & copter.config.led_land_indication, + }) @messaging.message_callback("emergency_land") @@ -591,8 +600,7 @@ def _command_disarm(*args, **kwargs): task_manager.add_task(-5, 0, FlightLib.arming_wrapper, task_kwargs={ "state": False - } - ) + }) @messaging.message_callback("stop") @@ -612,109 +620,104 @@ def _command_resume(*args, **kwargs): @messaging.message_callback("start") def _play_animation(*args, **kwargs): - start_time = float(kwargs["time"]) - # Check if animation file is available - if animation.get_id() == 'No animation': - logger.error("Can't start animation without animation file!") + + # Validate start_time + try: + start_time = float(kwargs["time"]) + except ValueError: + logger.error("start: Wrong time argument!") + return + except KeyError: + logger.error("start: No time argument!") return + # Check animation state + if copter.animation.state is not "OK": + logger.error("start: Bad animation state") + return + + # Get output frames + offset = numpy.array(copter.config.private_offset) + numpy.array(copter.config.copter_common_offset) + frames = copter.animation.get_scaled_output(copter.config.animation_ratio, offset) + if not frames: + logger.error("start: No frames in animation!") + return + + # Get current telemetry + telem = copter.telemetry.ros_telemetry + if not valid([telem.x, telem.y, telem.z]): + logger.error("start: Position is not valid!") + return + + # Get start action and delay + start_action, start_delay = copter.telemetry.start_action_and_delay + + # Reset task manager task_manager.reset(interrupt_next_task=False) - logger.info("Start time = {}, wait for {} seconds".format(start_time, start_time - time.time())) - # Load animation - offset = numpy.array(client.active_client.config.private_offset) + numpy.array(client.active_client.config.copter_common_offset) - frames = animation.load_animation(os.path.abspath("animation.csv"), client.active_client.config.animation_frame_delay, - offset[0], offset[1], offset[2], *client.active_client.config.animation_ratio) - # Correct start and land frames in animation - corrected_frames, start_action, start_delay = animation.correct_animation(frames, - check_takeoff=client.active_client.config.animation_takeoff_detection, - check_land=client.active_client.config.animation_land_detection, - ) - # Choose start action + # Set animation logic if start_action == 'takeoff': - # Takeoff first - task_manager.add_task(start_time, 0, animation.takeoff, + # Takeoff first at start_time + start_delay_time + takeoff_time = start_time + start_delay + task_manager.add_task(takeoff_time, 0, animation.takeoff, task_kwargs={ - "z": client.active_client.config.copter_takeoff_height, - "timeout": client.active_client.config.copter_takeoff_time, - "safe_takeoff": client.active_client.config.copter_safe_takeoff, - # "frame_id": client.active_client.config.copter_frame_id, - "use_leds": client.active_client.config.led_use & client.active_client.config.led_takeoff_indication, - } - ) + "z": copter.config.copter_takeoff_height, + "timeout": copter.config.copter_takeoff_time, + "safe_takeoff": False, + "use_leds": copter.config.led_use & copter.config.led_takeoff_indication, + }) # Fly to first point - rfp_time = start_time + client.active_client.config.copter_takeoff_time - if client.active_client.config.animation_yaw == "animation": - yaw = frame["yaw"] - else: - yaw = math.radians(float(client.active_client.config.animation_yaw)) + rfp_time = takeoff_time + copter.config.copter_takeoff_time task_manager.add_task(rfp_time, 0, animation.execute_frame, task_kwargs={ - "point": animation.convert_frame(corrected_frames[0])[0], - "color": animation.convert_frame(corrected_frames[0])[1], - "yaw": yaw, - "frame_id": client.active_client.config.copter_frame_id, - "use_leds": client.active_client.config.led_use, + "frame": frames[0], + "frame_id": copter.config.copter_frame_id, + "use_leds": copter.config.led_use, "flight_func": FlightLib.reach_point, - } - ) + }) # Calculate first frame start time - frame_time = rfp_time + client.active_client.config.copter_reach_first_point_time + frame_time = rfp_time + copter.config.copter_reach_first_point_time elif start_action == 'arm': # Calculate start time - start_time += start_delay - frame_time = start_time # + 1.0 - point, color, yaw = animation.convert_frame(corrected_frames[0]) - task_manager.add_task(frame_time, 0, animation.execute_frame, + arm_time = start_time + start_delay # + 1.0 + task_manager.add_task(arm_time, 0, animation.execute_frame, task_kwargs={ - "point": point, - "color": color, - "frame_id": client.active_client.config.copter_frame_id, - "use_leds": client.active_client.config.led_use, + "frame": frames[0], + "frame_id": copter.config.copter_frame_id, + "use_leds": copter.config.led_use, "flight_func": FlightLib.navto, "auto_arm": True, - } - ) + }) # Calculate first frame start time - frame_time += corrected_frames[0]["delay"] # TODO Think about arming time - logger.debug(task_manager.task_queue) + frame_time = arm_time + copter.config.copter_arming_time + logger.debug("Start queue {}".format(task_manager.task_queue)) # Play animation file - for frame in corrected_frames: - point, color, yaw = animation.convert_frame(frame) - if client.active_client.config.animation_yaw == "animation": - yaw = frame["yaw"] - else: - yaw = math.radians(float(client.active_client.config.animation_yaw)) + for frame in frames: task_manager.add_task(frame_time, 0, animation.execute_frame, task_kwargs={ - "point": point, - "color": color, - "yaw": yaw, - "frame_id": client.active_client.config.copter_frame_id, - "use_leds": client.active_client.config.led_use, + "frame": frame, + "frame_id": copter.config.copter_frame_id, + "use_leds": copter.config.led_use, "flight_func": FlightLib.navto, - } - ) - frame_time += frame["delay"] - + }) + frame_time += frame.delay # Calculate land_time - land_time = frame_time + client.active_client.config.copter_land_time + land_time = frame_time + copter.config.copter_land_delay # Land task_manager.add_task(land_time, 0, animation.land, task_kwargs={ - "timeout": client.active_client.config.copter_land_timeout, - "frame_id": client.active_client.config.copter_frame_id, - "use_leds": client.active_client.config.led_use & client.active_client.config.led_land_indication, - }, - ) + "timeout": copter.config.copter_land_timeout, + "frame_id": copter.config.copter_frame_id, + "use_leds": copter.config.led_use & copter.config.led_land_indication, + }) # noinspection PyAttributeOutsideInit class Telemetry: params_default_dict = { "git_version": None, - "animation_id": None, + "animation_info": None, "battery": None, "armed": False, "fcu_status": None, @@ -723,6 +726,7 @@ class Telemetry: "selfcheck": None, "current_position": None, "start_position": None, + "start_action_and_delay": None, "last_task": None, "time_delta": None, "config_version": None, @@ -759,16 +763,16 @@ class Telemetry: @classmethod def get_config_version(cls): - return "{} V{}".format(client.active_client.config.config_name, client.active_client.config.config_version) + return "{} V{}".format(copter.config.config_name, copter.config.config_version) @classmethod def get_start_position(cls): - x_start, y_start = animation.get_start_xy(os.path.abspath("animation.csv"), - *client.active_client.config.animation_ratio) - offset = numpy.array(client.active_client.config.private_offset) + numpy.array(client.active_client.config.copter_common_offset) + x_start, y_start, z_start = animation.get_start_pos(os.path.abspath("animation.csv"), + *copter.config.animation_ratio) + offset = numpy.array(copter.config.private_offset) + numpy.array(copter.config.copter_common_offset) x = x_start + offset[0] y = y_start + offset[1] - z = offset[2] + z = z_start + offset[2] if not FlightLib._check_nans(x, y, z): return x, y, z return 'NO_POS' @@ -807,14 +811,25 @@ class Telemetry: def get_position(cls, ros_telemetry): x, y, z = ros_telemetry.x, ros_telemetry.y, ros_telemetry.z if not math.isnan(x): - return x, y, z, math.degrees(ros_telemetry.yaw), client.active_client.config.copter_frame_id + return x, y, z, math.degrees(ros_telemetry.yaw), copter.config.copter_frame_id return 'NO_POS' + def get_ros_telemetry(self): + return self.ros_telemetry + + def get_start_action_and_delay(self) + offset = numpy.array(copter.config.private_offset) + numpy.array(copter.config.copter_common_offset) + start_action = copter.animation.get_start_action( + copter.config.animation_start_action, self.ros_telemetry.z, + copter.config.animation_takeoff_level, copter.config.animation_ground_level, + copter.config.animation_ratio, offset) + start_delay = copter.animation.start_delay + return start_action, start_delay + def update_telemetry_fast(self): - self.start_position = self.get_start_position() self.last_task = task_manager.get_current_task() try: - self.ros_telemetry = FlightLib.get_telemetry_locked(client.active_client.config.copter_frame_id) + self.ros_telemetry = FlightLib.get_telemetry_locked(copter.config.copter_frame_id) if self.ros_telemetry.connected: self.armed = self.ros_telemetry.armed self.mode = self.ros_telemetry.mode @@ -832,13 +847,12 @@ class Telemetry: self.time_delta = time.time() self.round_telemetry() - def get_ros_telemetry(self): - return self.ros_telemetry - def update_telemetry_slow(self): - self.animation_id = animation.get_id() + self.animation_info = [copter.animation.id, copter.animation.state] self.git_version = self.get_git_version() self.config_version = self.get_config_version() + self.start_position = self.get_start_position() + self.start_action_and_delay = self.get_start_action_and_delay() try: self.calibration_status = get_calibration_status() self.fcu_status = get_sys_status() @@ -905,7 +919,7 @@ class Telemetry: def transmit_message(self): # todo if connected try: - client.active_client.server_connection.send_message('telemetry', kwargs={'value': self.create_msg_contents()}) + copter.server_connection.send_message('telemetry', kwargs={'value': self.create_msg_contents()}) except AttributeError as e: logger.debug(e) @@ -935,7 +949,7 @@ class Telemetry: self.update_telemetry_fast() self.check_failsafe_and_interruption() - if client.active_client.config.telemetry_transmit and client.active_client.connected: + if copter.config.telemetry_transmit and copter.connected: self.transmit_message() rate.sleep() @@ -944,14 +958,14 @@ class Telemetry: rate = rospy.Rate(1) while not rospy.is_shutdown(): self.update_telemetry_slow() - if client.active_client.config.telemetry_log_resources: + if copter.config.telemetry_log_resources: self.log_cpu_and_memory() rate.sleep() def start_loop(self): - if client.active_client.config.telemetry_frequency > 0: + if copter.config.telemetry_frequency > 0: telemetry_thread = threading.Thread(target=self._update_loop, name="Telemetry getting thread", - args=(client.active_client.config.telemetry_frequency,)) # TODO MOVE? Daemon? + args=(copter.config.telemetry_frequency,)) # TODO MOVE? Daemon? slow_telemetry_thread = threading.Thread(target=self._slow_update_loop, name="Slow telemetry getting thread") slow_telemetry_thread.start() @@ -971,8 +985,23 @@ def emergency_callback(data): emergency = data.data +class AnimationEventHandler(FileSystemEventHandler): + def on_any_event(self, event): + logger.info('{} is {}'.format(event.src_path, event.event_type)) + if event.src_path == "./animation.csv" and event.event_type == "modified": + copter.animation.update_frames(copter.config, "animation.csv") + + if __name__ == "__main__": - copter_client = CopterClient() + copter = CopterClient() task_manager = tasking.TaskManager() rospy.Subscriber('/emergency', Bool, emergency_callback) - copter_client.start(task_manager) + copter.start(task_manager) + event_handler = AnimationEventHandler() + observer = Observer() + observer.schedule(event_handler, ".") + observer.start() + while not rospy.is_shutdown: + rospy.sleep(1) + observer.stop() + observer.join() From 414314deb60445b746f1256a941624be8d205edc Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sat, 30 May 2020 21:26:26 +0300 Subject: [PATCH 19/43] animation: Fix bugs, add get_start_yaw --- Drone/animation_lib.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Drone/animation_lib.py b/Drone/animation_lib.py index ae14b79..f96fd46 100644 --- a/Drone/animation_lib.py +++ b/Drone/animation_lib.py @@ -310,6 +310,11 @@ class Animation(object): z = z_ratio*first_frame.z + z0 return [x, y, z] + def get_start_yaw(self): + if not self.output_frames: + return float('nan') + return math.degrees(self.output_frames[0].yaw) + def check_ground(self, ground_level=0, ratio=(1,1,1), offset=(0,0,0)): return ground_level <= self.get_scaled_output_min_z(ratio, offset) @@ -324,12 +329,12 @@ class Animation(object): if ground_level > self.get_scaled_output_min_z(ratio, offset): return 'error: some animation points are lower than ground level' # Select start action - if start_action is 'auto': + if start_action == 'auto': if self.get_start_point(ratio, offset)[2] - current_height > takeoff_level: return 'takeoff' else: - return 'play' - elif start_action in ('takeoff', 'play'): + return 'fly' + elif start_action in ('takeoff', 'fly'): return start_action else: return 'error' From c1d8667b3732f9e2cc033ce52d9430bbc3897063 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sat, 30 May 2020 21:31:28 +0300 Subject: [PATCH 20/43] copter_client: Fix telemetry sending --- Drone/copter_client.py | 60 ++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 8b87daf..d45ea8d 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -650,8 +650,11 @@ def _play_animation(*args, **kwargs): return # Get start action and delay - start_action, start_delay = copter.telemetry.start_action_and_delay - + try: + start_action, start_delay = copter.telemetry.start_action_and_delay + except ValueError: + logger.error("start: Can't get animation start position and delay") + return # Reset task manager task_manager.reset(interrupt_next_task=False) @@ -726,7 +729,6 @@ class Telemetry: "selfcheck": None, "current_position": None, "start_position": None, - "start_action_and_delay": None, "last_task": None, "time_delta": None, "config_version": None, @@ -765,17 +767,23 @@ class Telemetry: def get_config_version(cls): return "{} V{}".format(copter.config.config_name, copter.config.config_version) - @classmethod - def get_start_position(cls): - x_start, y_start, z_start = animation.get_start_pos(os.path.abspath("animation.csv"), - *copter.config.animation_ratio) + def get_start_position(self): offset = numpy.array(copter.config.private_offset) + numpy.array(copter.config.copter_common_offset) - x = x_start + offset[0] - y = y_start + offset[1] - z = z_start + offset[2] - if not FlightLib._check_nans(x, y, z): - return x, y, z - return 'NO_POS' + try: + x, y, z = copter.animation.get_start_point(copter.config.animation_ratio, offset) + except ValueError: + return [float('nan'),float('nan'),float('nan'),float('nan'),'error: no start pos in animation',float('nan')] + else: + start_delay = copter.animation.start_delay + yaw = copter.animation.get_start_yaw() + if not self.ros_telemetry: + start_action = 'error: no telemetry data' + else: + start_action = copter.animation.get_start_action( + copter.config.animation_start_action, self.ros_telemetry.z, + copter.config.animation_takeoff_level, copter.config.animation_ground_level, + copter.config.animation_ratio, offset) + return [x,y,z,yaw,start_action,start_delay] @classmethod def get_battery(cls, ros_telemetry): @@ -809,7 +817,10 @@ class Telemetry: @classmethod def get_position(cls, ros_telemetry): - x, y, z = ros_telemetry.x, ros_telemetry.y, ros_telemetry.z + try: + x, y, z = ros_telemetry.x, ros_telemetry.y, ros_telemetry.z + except AttributeError: + return 'NO_POS' if not math.isnan(x): return x, y, z, math.degrees(ros_telemetry.yaw), copter.config.copter_frame_id return 'NO_POS' @@ -817,15 +828,6 @@ class Telemetry: def get_ros_telemetry(self): return self.ros_telemetry - def get_start_action_and_delay(self) - offset = numpy.array(copter.config.private_offset) + numpy.array(copter.config.copter_common_offset) - start_action = copter.animation.get_start_action( - copter.config.animation_start_action, self.ros_telemetry.z, - copter.config.animation_takeoff_level, copter.config.animation_ground_level, - copter.config.animation_ratio, offset) - start_delay = copter.animation.start_delay - return start_action, start_delay - def update_telemetry_fast(self): self.last_task = task_manager.get_current_task() try: @@ -852,7 +854,6 @@ class Telemetry: self.git_version = self.get_git_version() self.config_version = self.get_config_version() self.start_position = self.get_start_position() - self.start_action_and_delay = self.get_start_action_and_delay() try: self.calibration_status = get_calibration_status() self.fcu_status = get_sys_status() @@ -988,20 +989,21 @@ def emergency_callback(data): class AnimationEventHandler(FileSystemEventHandler): def on_any_event(self, event): logger.info('{} is {}'.format(event.src_path, event.event_type)) - if event.src_path == "./animation.csv" and event.event_type == "modified": - copter.animation.update_frames(copter.config, "animation.csv") + # logger.info(os.path.splitext(event.src_path)) + if os.path.splitext(event.src_path)[-1] == '.csv' and event.event_type != "deleted": + if os.path.exists("animation.csv"): + logger.info("Update frames from animation.csv") + copter.animation.update_frames(copter.config, "animation.csv") if __name__ == "__main__": copter = CopterClient() task_manager = tasking.TaskManager() rospy.Subscriber('/emergency', Bool, emergency_callback) - copter.start(task_manager) event_handler = AnimationEventHandler() observer = Observer() observer.schedule(event_handler, ".") observer.start() - while not rospy.is_shutdown: - rospy.sleep(1) + copter.start(task_manager) observer.stop() observer.join() From 57280d0ea4643d4ba6225a356e66387574ddc609 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sat, 30 May 2020 21:33:57 +0300 Subject: [PATCH 21/43] Server: Update default widths in configspec --- Server/config/spec/configspec_server.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Server/config/spec/configspec_server.ini b/Server/config/spec/configspec_server.ini index 7242d1d..6a191c8 100644 --- a/Server/config/spec/configspec_server.ini +++ b/Server/config/spec/configspec_server.ini @@ -17,17 +17,17 @@ config_version = float(default='1.0') [[[DEFAULT]]] copter_id = preset_param(default=list(True, 100)) git_version = preset_param(default=list(True, 75)) - config_version = preset_param(default=list(True, 140)) - animation_id = preset_param(default=list(True, 100)) + config_version = preset_param(default=list(True, 105)) + animation_info = preset_param(default=list(True, 100)) battery = preset_param(default=list(True, 100)) fcu_status = preset_param(default=list(True, 100)) calibration_status = preset_param(default=list(True, 65)) mode = preset_param(default=list(True, 100)) selfcheck = preset_param(default=list(True, 65)) current_position = preset_param(default=list(True, 250)) - start_position = preset_param(default=list(True, 150)) - last_task = preset_param(default=list(True, 250)) - time_delta = preset_param(default=list(True, 100)) + start_position = preset_param(default=list(True, 240)) + last_task = preset_param(default=list(True, 275)) + time_delta = preset_param(default=list(True, 70)) [[[__many__]]] __many__ = preset_param From 5297ee0385744f020f78363d1a497a316bff1c0d Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sat, 30 May 2020 21:37:43 +0300 Subject: [PATCH 22/43] copter_table_models: Handle telemetry --- Server/copter_table_models.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index 5af3894..c609cda 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -81,16 +81,19 @@ class ModelChecks: def check_ver(item): if not ModelChecks.check_git: return True - + version = get_git_version() if version is not None: return version == item return True -@ModelChecks.column_check("animation_id") +@ModelChecks.column_check("animation_info") def check_anim(item): - return str(item) != 'No animation' + if item: + return str(item[1]) == 'OK' + else: + return False @ModelChecks.column_check("battery") @@ -150,6 +153,7 @@ def check_start_pos(item, context): delta = get_distance(get_position(context.current_position), get_position(context.start_position)) + if math.isnan(delta): return False @@ -157,7 +161,7 @@ def check_start_pos(item, context): def get_position(position): - if position != 'NO_POS' and position[0] != 'nan': # float('nan')? + if not isinstance(position, str) and position[0] != float('nan'): return position[:3] return [float('nan')] * 3 @@ -276,6 +280,17 @@ def place_id(value): msgbox.exec_() return None +@ModelFormatter.view_formatter("animation_info") +def view_animation_info(value): + try: + id, state = value + except ValueError: + return "" + else: + if state == 'OK': + return id + else: + return state @ModelFormatter.place_formatter("battery") def place_battery(value): @@ -314,8 +329,11 @@ def view_current_position(value): @ModelFormatter.view_formatter("start_position") def view_start_position(value): if isinstance(value, list): - x, y, z = value - return f"{x: .2f} {y: .2f} {z: .2f}" + x, y, z, yaw, action, delay = value + if action in ['fly', 'takeoff']: + return f"{x: .2f} {y: .2f} {z: .2f} {int(yaw): d} {action} {delay: .1f}" + else: + return f"{action}" return value @@ -340,14 +358,14 @@ class CopterDataModel(QtCore.QAbstractTableModel): columns_dict = {'copter_id': 'copter ID', 'git_version': 'version', 'config_version': 'configuration', - 'animation_id': ' animation ID ', + 'animation_info': 'animation ID', 'battery': ' battery ', 'fcu_status': 'FCU status', 'calibration_status': 'sensors', 'mode': ' mode ', 'selfcheck': ' checks ', 'current_position': 'current x y z yaw frame_id', - 'start_position': ' start x y z ', + 'start_position': 'start x y z yaw action delay', 'last_task': 'last task', 'time_delta': 'dt', } From 494c30fad054186270d057cd48bc60fc675bdbe4 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sat, 30 May 2020 21:38:08 +0300 Subject: [PATCH 23/43] Update tests --- tests/animation_4.csv | 161 ++++++++++++++++++++++++++++++++++++++++ tests/animation_test.py | 21 +++++- 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 tests/animation_4.csv diff --git a/tests/animation_4.csv b/tests/animation_4.csv new file mode 100644 index 0000000..530caf5 --- /dev/null +++ b/tests/animation_4.csv @@ -0,0 +1,161 @@ +two_drones_test +1,0.2,1.4,1.0,0.15708,0,0,0 +2,0.2,1.4,1.0,0.15708,0,0,0 +3,0.2,1.4,1.0,0.15708,0,0,0 +4,0.2,1.4,1.0,0.15708,0,0,0 +5,0.2,1.4,1.0,0.15708,0,0,0 +6,0.2,1.4,1.0,0.15708,0,0,0 +7,0.2,1.4,1.0,0.15708,0,0,0 +8,0.2,1.4,1.0,0.15708,0,0,0 +9,0.2,1.4,1.0,0.15708,0,0,0 +10,0.2,1.4,1.0,0.15708,0,0,0 +11,0.20441,1.4,1.0,0.15708,0,0,0 +12,0.21774,1.4,1.0,0.15708,0,0,0 +13,0.24002,1.4,1.0,0.15708,0,0,0 +14,0.27111,1.4,1.0,0.15708,0,0,0 +15,0.31063,1.4,1.0,0.15708,0,0,0 +16,0.3579,1.4,1.0,0.15708,0,0,0 +17,0.41193,1.4,1.0,0.15708,0,0,0 +18,0.47141,1.4,1.0,0.15708,0,0,0 +19,0.53472,1.4,1.0,0.15708,0,0,0 +20,0.6,1.4,1.0,0.15708,0,0,0 +21,0.66528,1.4,1.0,0.15708,0,0,0 +22,0.72859,1.4,1.0,0.15708,0,0,0 +23,0.78807,1.4,1.0,0.15708,0,0,0 +24,0.8421,1.4,1.0,0.15708,0,0,0 +25,0.88937,1.4,1.0,0.15708,0,0,0 +26,0.92889,1.4,1.0,0.15708,0,0,0 +27,0.95998,1.4,1.0,0.15708,0,0,0 +28,0.98226,1.4,1.0,0.15708,0,0,0 +29,0.99559,1.4,1.0,0.15708,0,0,0 +30,1.0,1.4,1.0,0.15708,0,0,0 +31,1.0,1.40441,1.0,0.15708,0,0,0 +32,1.0,1.41774,1.0,0.15708,0,0,0 +33,1.0,1.44002,1.0,0.15708,0,0,0 +34,1.0,1.47111,1.0,0.15708,0,0,0 +35,1.0,1.51063,1.0,0.15708,0,0,0 +36,1.0,1.5579,1.0,0.15708,0,0,0 +37,1.0,1.61193,1.0,0.15708,0,0,0 +38,1.0,1.67141,1.0,0.15708,0,0,0 +39,1.0,1.73472,1.0,0.15708,0,0,0 +40,1.0,1.8,1.0,0.15708,0,0,0 +41,1.0,1.86528,1.0,0.15708,0,0,0 +42,1.0,1.92859,1.0,0.15708,0,0,0 +43,1.0,1.98807,1.0,0.15708,0,0,0 +44,1.0,2.0421,1.0,0.15708,0,0,0 +45,1.0,2.08937,1.0,0.15708,0,0,0 +46,1.0,2.12889,1.0,0.15708,0,0,0 +47,1.0,2.15998,1.0,0.15708,0,0,0 +48,1.0,2.18226,1.0,0.15708,0,0,0 +49,1.0,2.19559,1.0,0.15708,0,0,0 +50,1.0,2.2,1.0,0.15708,0,0,0 +51,0.99559,2.2,1.0,0.15708,0,0,0 +52,0.98226,2.2,1.0,0.15708,0,0,0 +53,0.95998,2.2,1.0,0.15708,0,0,0 +54,0.92889,2.2,1.0,0.15708,0,0,0 +55,0.88937,2.2,1.0,0.15708,0,0,0 +56,0.8421,2.2,1.0,0.15708,0,0,0 +57,0.78807,2.2,1.0,0.15708,0,0,0 +58,0.72859,2.2,1.0,0.15708,0,0,0 +59,0.66528,2.2,1.0,0.15708,0,0,0 +60,0.6,2.2,1.0,0.15708,0,0,0 +61,0.53472,2.2,1.0,0.15708,0,0,0 +62,0.47141,2.2,1.0,0.15708,0,0,0 +63,0.41193,2.2,1.0,0.15708,0,0,0 +64,0.3579,2.2,1.0,0.15708,0,0,0 +65,0.31063,2.2,1.0,0.15708,0,0,0 +66,0.27111,2.2,1.0,0.15708,0,0,0 +67,0.24002,2.2,1.0,0.15708,0,0,0 +68,0.21774,2.2,1.0,0.15708,0,0,0 +69,0.20441,2.2,1.0,0.15708,0,0,0 +70,0.2,2.2,1.0,0.15708,0,0,0 +71,0.2,2.19559,1.0,0.15708,0,0,0 +72,0.2,2.18226,1.0,0.15708,0,0,0 +73,0.2,2.15998,1.0,0.15708,0,0,0 +74,0.2,2.12889,1.0,0.15708,0,0,0 +75,0.2,2.08937,1.0,0.15708,0,0,0 +76,0.2,2.0421,1.0,0.15708,0,0,0 +77,0.2,1.98807,1.0,0.15708,0,0,0 +78,0.2,1.92859,1.0,0.15708,0,0,0 +79,0.2,1.86528,1.0,0.15708,0,0,0 +80,0.2,1.8,1.0,0.15708,0,0,0 +81,0.2,1.73472,1.0,0.15708,0,0,0 +82,0.2,1.67141,1.0,0.15708,0,0,0 +83,0.2,1.61193,1.0,0.15708,0,0,0 +84,0.2,1.5579,1.0,0.15708,0,0,0 +85,0.2,1.51063,1.0,0.15708,0,0,0 +86,0.2,1.47111,1.0,0.15708,0,0,0 +87,0.2,1.44002,1.0,0.15708,0,0,0 +88,0.2,1.41774,1.0,0.15708,0,0,0 +89,0.2,1.40441,1.0,0.15708,0,0,0 +90,0.2,1.4,1.0,0.15708,0,0,0 +91,0.2062,1.4,1.0,0.15708,0,0,0 +92,0.22355,1.4,1.0,0.15708,0,0,0 +93,0.25043,1.4,1.0,0.15708,0,0,0 +94,0.28553,1.4,1.0,0.15708,0,0,0 +95,0.32771,1.4,1.0,0.15708,0,0,0 +96,0.3759,1.4,1.0,0.15708,0,0,0 +97,0.42903,1.4,1.0,0.15708,0,0,0 +98,0.48579,1.4,1.0,0.15708,0,0,0 +99,0.54421,1.4,1.0,0.15708,0,0,0 +100,0.6,1.4,1.0,0.15708,0,0,0 +101,0.66257,1.40492,1.025,0.15708,0,0,0 +102,0.72361,1.41958,1.05,0.31416,0,0,0 +103,0.7816,1.4436,1.075,0.47124,0,0,0 +104,0.83511,1.47639,1.1,0.62832,0,0,0 +105,0.88284,1.51716,1.125,0.7854,0,0,0 +106,0.92361,1.56489,1.15,0.94248,0,0,0 +107,0.9564,1.6184,1.175,1.09956,0,0,0 +108,0.98042,1.67639,1.2,1.25664,0,0,0 +109,0.99508,1.73743,1.225,1.41372,0,0,0 +110,1.0,1.8,1.25,1.5708,0,0,0 +111,0.99508,1.86257,1.275,1.72788,0,0,0 +112,0.98042,1.92361,1.3,1.88496,0,0,0 +113,0.9564,1.9816,1.325,2.04204,0,0,0 +114,0.92361,2.03511,1.35,2.19912,0,0,0 +115,0.88284,2.08284,1.375,2.35619,0,0,0 +116,0.83511,2.12361,1.4,2.51327,0,0,0 +117,0.7816,2.1564,1.425,2.67035,0,0,0 +118,0.72361,2.18042,1.45,2.82743,0,0,0 +119,0.66257,2.19508,1.475,2.98451,0,0,0 +120,0.6,2.2,1.5,-3.14159,0,0,0 +121,0.53743,2.19508,1.525,-2.98451,0,0,0 +122,0.47639,2.18042,1.55,-2.82743,0,0,0 +123,0.4184,2.1564,1.575,-2.67035,0,0,0 +124,0.36489,2.12361,1.6,-2.51327,0,0,0 +125,0.31716,2.08284,1.625,-2.35619,0,0,0 +126,0.27639,2.03511,1.65,-2.19911,0,0,0 +127,0.2436,1.9816,1.675,-2.04203,0,0,0 +128,0.21958,1.92361,1.7,-1.88495,0,0,0 +129,0.20492,1.86257,1.725,-1.72788,0,0,0 +130,0.2,1.8,1.75,-1.5708,0,0,0 +131,0.20492,1.73743,1.775,-1.41372,0,0,0 +132,0.21958,1.67639,1.8,-1.25664,0,0,0 +133,0.2436,1.6184,1.825,-1.09956,0,0,0 +134,0.27639,1.56489,1.85,-0.94248,0,0,0 +135,0.31716,1.51716,1.875,-0.7854,0,0,0 +136,0.36489,1.47639,1.9,-0.62832,0,0,0 +137,0.4184,1.4436,1.925,-0.47124,0,0,0 +138,0.47639,1.41958,1.95,-0.31416,0,0,0 +139,0.53743,1.40492,1.975,-0.15708,0,0,0 +140,0.6,1.4,2.0,0.0,0,0,0 +141,0.6,1.4,2.0,0.0,0,0,0 +142,0.6,1.4,2.0,0.0,0,0,0 +143,0.6,1.4,2.0,0.0,0,0,0 +144,0.6,1.4,2.0,0.0,0,0,0 +145,0.6,1.4,2.0,0.0,0,0,0 +146,0.6,1.4,2.0,0.0,0,0,0 +147,0.6,1.4,2.0,0.0,0,0,0 +148,0.6,1.4,2.0,0.0,0,0,0 +149,0.6,1.4,2.0,0.0,0,0,0 +150,0.6,1.4,2.0,0.0,0,0,0 +151,0.6,1.4,2.0,0.0,0,0,0 +152,0.6,1.4,2.0,0.0,0,0,0 +153,0.6,1.4,2.0,0.0,0,0,0 +154,0.6,1.4,2.0,0.0,0,0,0 +155,0.6,1.4,2.0,0.0,0,0,0 +156,0.6,1.4,2.0,0.0,0,0,0 +157,0.6,1.4,2.0,0.0,0,0,0 +158,0.6,1.4,2.0,0.0,0,0,0 +159,0.6,1.4,2.0,0.0,0,0,0 +160,0.6,1.4,2.0,0.0,0,0,0 diff --git a/tests/animation_test.py b/tests/animation_test.py index 5fde3b8..ce0abd7 100644 --- a/tests/animation_test.py +++ b/tests/animation_test.py @@ -75,7 +75,7 @@ def test_animation_2(): def test_animation_3(): a.update_frames(config, "animation_3.csv") assert a.id == 'route' - assert a.original_frames[9].get_pos() == [0.97783,0.0,1.0] + assert approx(a.original_frames[9].get_pos()) == [0.97783,0.0,1.0] assert a.original_frames[9].get_color() == [0,204,2] assert a.original_frames[9].pose_is_valid() assert animation_lib.get_numbers(a.static_begin_frames) == [] @@ -90,6 +90,25 @@ def test_animation_3(): assert approx(a.get_scaled_output_min_z(ratio=[1,2,3], offset=[4,5,6])) == 9 assert approx(a.get_start_point(ratio=[1,2,3], offset=[4,5,6])) == [4,5,9] +def test_animation_4(): + a.update_frames(config, "animation_4.csv") + assert a.id == 'two_drones_test' + assert approx(a.original_frames[11].get_pos()) == [0.21774,1.4,1.0] + assert a.original_frames[11].get_color() == [0,0,0] + assert a.original_frames[11].pose_is_valid() + assert animation_lib.get_numbers(a.static_begin_frames) == range(1,12) + assert animation_lib.get_numbers(a.takeoff_frames) == [] + assert animation_lib.get_numbers(a.route_frames) == range(12,141) + assert animation_lib.get_numbers(a.land_frames) == [] + assert animation_lib.get_numbers(a.static_end_frames) == range(141,161) + assert animation_lib.get_numbers(a.output_frames) == range(12,141) + assert approx(a.static_begin_time) == 1.1 + assert approx(a.takeoff_time) == 0 + assert approx(a.output_frames_min_z) == 1 + assert approx(a.get_scaled_output(ratio=[1,2,3], offset=[4,5,6])[0].get_pos()) == [4.21774,7.8,9] + assert approx(a.get_scaled_output_min_z(ratio=[1,2,3], offset=[4,5,6])) == 9 + assert approx(a.get_start_point(ratio=[1,2,3], offset=[4,5,6])) == [4.21774,7.8,9] + def test_animation_no_file(): a.update_frames(config, "zzz.csv") assert a.id == None From e6fa25e27e283718f10bd216e0cf80c25869cab2 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sat, 30 May 2020 21:39:06 +0300 Subject: [PATCH 24/43] Update update_configspec script not to rewrite default values from existiong configspec --- update_configspec.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/update_configspec.py b/update_configspec.py index 590b32d..e1d2bf2 100644 --- a/update_configspec.py +++ b/update_configspec.py @@ -1,14 +1,34 @@ +import os +import shutil import config from Server.copter_table_models import CopterDataModel -cfg_server = config.ConfigObj('SERVER/config/spec/configspec_server.ini', list_values=False) -widths = {"copter_id": 150} -default_width = 100 +from config import ConfigManager, ConfigObj -default = {key: f"preset_param(default=list(True, {widths.get(key, default_width)}))" +config_path = 'temp_config/config' +spec_path = os.path.join(config_path,'spec') +if not os.path.exists(spec_path): + try: + os.makedirs(spec_path) + except OSError: + print("Creation of the directory {} failed".format(spec_path)) + else: + print("Successfully created the directory {}".format(spec_path)) + +shutil.copy("Server/config/spec/configspec_server.ini", spec_path) + +config = ConfigManager() +config.load_config_and_spec(os.path.join(config_path,'server.ini')) + +preset_params = config.table_presets_default +default_param = (True, 100) + +default = {key: f"preset_param(default=list{preset_params.get(key, default_param)})" for key in CopterDataModel.columns} +cfg_server = ConfigObj('Server/config/spec/configspec_server.ini', list_values=False) cfg_server['TABLE']['PRESETS']['DEFAULT'] = default - cfg_server.write() -print('Server configspec updated') + +print('Server configspec updated!') +shutil.rmtree('temp_config') From a5170aa204eba22cb2f6f2c4a98e0ed8df26e0cc Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 09:21:32 +0300 Subject: [PATCH 25/43] Drone: Fix starting animation --- Drone/copter_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index d45ea8d..ace4ed2 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -651,7 +651,7 @@ def _play_animation(*args, **kwargs): # Get start action and delay try: - start_action, start_delay = copter.telemetry.start_action_and_delay + start_action, start_delay = copter.telemetry.start_position[-2:] except ValueError: logger.error("start: Can't get animation start position and delay") return @@ -681,7 +681,7 @@ def _play_animation(*args, **kwargs): # Calculate first frame start time frame_time = rfp_time + copter.config.copter_reach_first_point_time - elif start_action == 'arm': + elif start_action == 'fly': # Calculate start time arm_time = start_time + start_delay # + 1.0 task_manager.add_task(arm_time, 0, animation.execute_frame, From d4d51231b3d8b8227627e2a1b40053603444202e Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 09:23:08 +0300 Subject: [PATCH 26/43] Server: Update UI to implement fly to point button and send animation action --- Server/server_gui.py | 45 ++++++++++++++++----------- Server/server_gui.ui | 72 ++++++++++++++++++++++++++------------------ 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/Server/server_gui.py b/Server/server_gui.py index 448c60a..79532a6 100644 --- a/Server/server_gui.py +++ b/Server/server_gui.py @@ -13,7 +13,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(1360, 816) + MainWindow.resize(1360, 869) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setEnabled(True) self.centralwidget.setObjectName("centralwidget") @@ -44,30 +44,22 @@ class Ui_MainWindow(object): self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize) self.verticalLayout.setObjectName("verticalLayout") self.formLayout = QtWidgets.QFormLayout() - self.formLayout.setLabelAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop) + self.formLayout.setLabelAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.formLayout.setFormAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop) self.formLayout.setObjectName("formLayout") self.start_text = QtWidgets.QLabel(self.centralwidget) self.start_text.setLayoutDirection(QtCore.Qt.RightToLeft) - self.start_text.setAlignment(QtCore.Qt.AlignCenter) + self.start_text.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) self.start_text.setObjectName("start_text") self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.start_text) self.start_delay_spin = QtWidgets.QSpinBox(self.centralwidget) self.start_delay_spin.setObjectName("start_delay_spin") self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.start_delay_spin) - self.music_text = QtWidgets.QLabel(self.centralwidget) - self.music_text.setLayoutDirection(QtCore.Qt.RightToLeft) - self.music_text.setObjectName("music_text") - self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.music_text) self.music_delay_spin = QtWidgets.QDoubleSpinBox(self.centralwidget) self.music_delay_spin.setDecimals(1) self.music_delay_spin.setMaximum(1000.0) self.music_delay_spin.setObjectName("music_delay_spin") self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.music_delay_spin) - self.music_play_text = QtWidgets.QLabel(self.centralwidget) - self.music_play_text.setLayoutDirection(QtCore.Qt.RightToLeft) - self.music_play_text.setObjectName("music_play_text") - self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.music_play_text) self.music_checkbox = QtWidgets.QCheckBox(self.centralwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -82,6 +74,14 @@ class Ui_MainWindow(object): self.music_checkbox.setChecked(False) self.music_checkbox.setObjectName("music_checkbox") self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.music_checkbox) + self.music_text = QtWidgets.QLabel(self.centralwidget) + self.music_text.setLayoutDirection(QtCore.Qt.RightToLeft) + self.music_text.setObjectName("music_text") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.music_text) + self.music_play_text = QtWidgets.QLabel(self.centralwidget) + self.music_play_text.setLayoutDirection(QtCore.Qt.RightToLeft) + self.music_play_text.setObjectName("music_play_text") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.music_play_text) self.verticalLayout.addLayout(self.formLayout) self.line = QtWidgets.QFrame(self.centralwidget) self.line.setFrameShape(QtWidgets.QFrame.HLine) @@ -186,7 +186,10 @@ class Ui_MainWindow(object): self.formLayout_4.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_2) self.flip_button = QtWidgets.QPushButton(self.centralwidget) self.flip_button.setObjectName("flip_button") - self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.flip_button) + self.formLayout_4.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.flip_button) + self.fly_button = QtWidgets.QPushButton(self.centralwidget) + self.fly_button.setObjectName("fly_button") + self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.fly_button) self.verticalLayout.addLayout(self.formLayout_4) self.line_4 = QtWidgets.QFrame(self.centralwidget) self.line_4.setFrameShape(QtWidgets.QFrame.HLine) @@ -212,7 +215,7 @@ class Ui_MainWindow(object): self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 1360, 25)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1360, 22)) self.menubar.setObjectName("menubar") self.menuOptions = QtWidgets.QMenu(self.menubar) self.menuOptions.setObjectName("menuOptions") @@ -301,6 +304,8 @@ class Ui_MainWindow(object): self.action_configure_columns.setObjectName("action_configure_columns") self.actionSomething = QtWidgets.QAction(MainWindow) self.actionSomething.setObjectName("actionSomething") + self.action_send_animation = QtWidgets.QAction(MainWindow) + self.action_send_animation.setObjectName("action_send_animation") self.menuMusic_2.addAction(self.action_select_music_file) self.menuMusic_2.addAction(self.action_play_music) self.menuMusic_2.addAction(self.action_stop_music) @@ -319,10 +324,12 @@ class Ui_MainWindow(object): self.menuTable.addSeparator() self.menuTable.addAction(self.action_configure_columns) self.menuSend.addAction(self.action_send_animations) + self.menuSend.addAction(self.action_send_calibrations) + self.menuSend.addSeparator() + self.menuSend.addAction(self.action_send_aruco_map) + self.menuSend.addAction(self.action_send_animation) self.menuSend.addAction(self.action_send_configurations) self.menuSend.addAction(self.action_send_launch_file) - self.menuSend.addAction(self.action_send_aruco_map) - self.menuSend.addAction(self.action_send_calibrations) self.menuSend.addAction(self.action_send_fcu_parameters) self.menuSend.addSeparator() self.menuSend.addAction(self.action_send_any_file) @@ -357,8 +364,8 @@ class Ui_MainWindow(object): MainWindow.setWindowTitle(_translate("MainWindow", "Clever Drone Show")) self.start_text.setText(_translate("MainWindow", " Start after")) self.start_delay_spin.setSuffix(_translate("MainWindow", " s")) - self.music_text.setText(_translate("MainWindow", " Music after")) self.music_delay_spin.setSuffix(_translate("MainWindow", " s")) + self.music_text.setText(_translate("MainWindow", " Music after")) self.music_play_text.setText(_translate("MainWindow", " Play music")) self.check_button.setText(_translate("MainWindow", "Preflight check")) self.start_button.setText(_translate("MainWindow", "Start animation")) @@ -374,6 +381,7 @@ class Ui_MainWindow(object): self.z_checkbox.setText(_translate("MainWindow", " Z =")) self.z_spin.setSuffix(_translate("MainWindow", " m")) self.flip_button.setText(_translate("MainWindow", "Flip")) + self.fly_button.setText(_translate("MainWindow", "Fly to point")) self.reboot_fcu.setText(_translate("MainWindow", "Reboot FCU")) self.calibrate_gyro.setText(_translate("MainWindow", "Calibrate gyro")) self.calibrate_level.setText(_translate("MainWindow", "Calibrate level")) @@ -389,7 +397,7 @@ class Ui_MainWindow(object): self.action_send_aruco_map.setText(_translate("MainWindow", "Aruco map")) self.action_update_client_repo.setText(_translate("MainWindow", "Update clever-show git")) self.actionSend_launch_file_for_clever.setText(_translate("MainWindow", "Send launch file for clever")) - self.action_send_launch_file.setText(_translate("MainWindow", "Launch files")) + self.action_send_launch_file.setText(_translate("MainWindow", "Launch files folder")) self.action_restart_clever.setText(_translate("MainWindow", "clever")) self.action_restart_clever_show.setText(_translate("MainWindow", "clever-show")) self.action_select_all_rows.setText(_translate("MainWindow", "Select all drones")) @@ -410,7 +418,7 @@ class Ui_MainWindow(object): self.action_send_calibrations.setText(_translate("MainWindow", "Camera calibrations")) self.action_reboot_all.setText(_translate("MainWindow", "Reboot")) self.action_restart_chrony.setText(_translate("MainWindow", "chrony")) - self.action_send_fcu_parameters.setText(_translate("MainWindow", "FCU parameters")) + self.action_send_fcu_parameters.setText(_translate("MainWindow", "FCU parameters file")) self.action_toggle_select.setText(_translate("MainWindow", "Toggle select")) self.action_toggle_select.setShortcut(_translate("MainWindow", "Ctrl+A")) self.action_select_all.setText(_translate("MainWindow", "Select all")) @@ -424,3 +432,4 @@ class Ui_MainWindow(object): self.action_restart_server.setText(_translate("MainWindow", "Restart server")) self.action_configure_columns.setText(_translate("MainWindow", "Configure columns")) self.actionSomething.setText(_translate("MainWindow", "something")) + self.action_send_animation.setText(_translate("MainWindow", "Animation")) diff --git a/Server/server_gui.ui b/Server/server_gui.ui index e00e6f4..d193528 100644 --- a/Server/server_gui.ui +++ b/Server/server_gui.ui @@ -7,7 +7,7 @@ 0 0 1360 - 816 + 869 @@ -71,7 +71,7 @@ - Qt::AlignHCenter|Qt::AlignTop + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::AlignHCenter|Qt::AlignTop @@ -85,7 +85,7 @@ Start after - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -96,16 +96,6 @@ - - - - Qt::RightToLeft - - - Music after - - - @@ -119,16 +109,6 @@ - - - - Qt::RightToLeft - - - Play music - - - @@ -157,6 +137,26 @@ + + + + Qt::RightToLeft + + + Music after + + + + + + + Qt::RightToLeft + + + Play music + + + @@ -367,13 +367,20 @@ - + Flip + + + + Fly to point + + + @@ -426,7 +433,7 @@ 0 0 1360 - 25 + 22 @@ -470,10 +477,12 @@ Send + + + + - - @@ -538,7 +547,7 @@ - Launch files + Launch files folder @@ -639,7 +648,7 @@ - FCU parameters + FCU parameters file @@ -707,6 +716,11 @@ something + + + Animation + + start_delay_spin From 0c54b97b2b0ec7f28e9d315e468f9960ef1c7ae8 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 09:39:39 +0300 Subject: [PATCH 27/43] Server: Add send animation action handler --- Server/server_qt.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Server/server_qt.py b/Server/server_qt.py index 2c315a8..cef05e1 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -161,6 +161,7 @@ class MainWindow(QtWidgets.QMainWindow): self.ui.action_send_animations.triggered.connect(self.send_animations) self.ui.action_send_calibrations.triggered.connect(self.send_calibrations) + self.ui.action_send_animation.triggered.connect(self.send_animation) self.ui.action_send_configurations.triggered.connect(self.send_config) self.ui.action_send_aruco_map.triggered.connect(self.send_aruco) self.ui.action_send_launch_file.triggered.connect(self.send_launch) @@ -481,6 +482,10 @@ class MainWindow(QtWidgets.QMainWindow): self.send_directory_files("Select directory with animations", ('.csv', '.txt'), match_id=True, client_path="", client_filename="animation.csv") + @pyqtSlot() + def send_animation(self): + self.send_files("Select animation file", "Animation files (*.csv)", onefile=True, client_filename="animation.csv") + @pyqtSlot() def send_calibrations(self): self.send_directory_files("Select directory with calibrations", ('.yaml', ), match_id=True, From 010c13b28c93150352c392465b13208f40586bb6 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 09:54:17 +0300 Subject: [PATCH 28/43] Server: Remove fly to point button --- Server/server_gui.py | 6 +----- Server/server_gui.ui | 9 +-------- Server/server_qt.py | 4 ---- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/Server/server_gui.py b/Server/server_gui.py index 79532a6..a163801 100644 --- a/Server/server_gui.py +++ b/Server/server_gui.py @@ -186,10 +186,7 @@ class Ui_MainWindow(object): self.formLayout_4.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_2) self.flip_button = QtWidgets.QPushButton(self.centralwidget) self.flip_button.setObjectName("flip_button") - self.formLayout_4.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.flip_button) - self.fly_button = QtWidgets.QPushButton(self.centralwidget) - self.fly_button.setObjectName("fly_button") - self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.fly_button) + self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.flip_button) self.verticalLayout.addLayout(self.formLayout_4) self.line_4 = QtWidgets.QFrame(self.centralwidget) self.line_4.setFrameShape(QtWidgets.QFrame.HLine) @@ -381,7 +378,6 @@ class Ui_MainWindow(object): self.z_checkbox.setText(_translate("MainWindow", " Z =")) self.z_spin.setSuffix(_translate("MainWindow", " m")) self.flip_button.setText(_translate("MainWindow", "Flip")) - self.fly_button.setText(_translate("MainWindow", "Fly to point")) self.reboot_fcu.setText(_translate("MainWindow", "Reboot FCU")) self.calibrate_gyro.setText(_translate("MainWindow", "Calibrate gyro")) self.calibrate_level.setText(_translate("MainWindow", "Calibrate level")) diff --git a/Server/server_gui.ui b/Server/server_gui.ui index d193528..f6c70c1 100644 --- a/Server/server_gui.ui +++ b/Server/server_gui.ui @@ -367,20 +367,13 @@ - + Flip - - - - Fly to point - - - diff --git a/Server/server_qt.py b/Server/server_qt.py index cef05e1..6627a74 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -112,10 +112,6 @@ class MainWindow(QtWidgets.QMainWindow): self.init_model() - # self.statusBar = QStatusBar() - # self.setStatusBar(self.statusBar) - # self.statusBar.showMessage("Hey", 2000) - self.register_callbacks() self.player = QtMultimedia.QMediaPlayer() From 022a2ae20d58b2baadd7c0ae01d72e53abd805e2 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 11:55:10 +0300 Subject: [PATCH 29/43] Drone: Add config update monitoring --- Drone/copter_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index ace4ed2..8c615e6 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -990,7 +990,7 @@ class AnimationEventHandler(FileSystemEventHandler): def on_any_event(self, event): logger.info('{} is {}'.format(event.src_path, event.event_type)) # logger.info(os.path.splitext(event.src_path)) - if os.path.splitext(event.src_path)[-1] == '.csv' and event.event_type != "deleted": + if (os.path.splitext(event.src_path)[-1] == '.csv' and event.event_type != "deleted") or event.src_path.split('/')[-1] == 'client.ini': if os.path.exists("animation.csv"): logger.info("Update frames from animation.csv") copter.animation.update_frames(copter.config, "animation.csv") @@ -1002,7 +1002,7 @@ if __name__ == "__main__": rospy.Subscriber('/emergency', Bool, emergency_callback) event_handler = AnimationEventHandler() observer = Observer() - observer.schedule(event_handler, ".") + observer.schedule(event_handler, ".", recursive=True) observer.start() copter.start(task_manager) observer.stop() From 3db15f672236b33891f37581a9f72212ae7226cd Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 11:55:37 +0300 Subject: [PATCH 30/43] Server: Fix yaw handling --- Server/copter_table_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index c609cda..211e3bd 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -322,7 +322,7 @@ def view_selfcheck(value): def view_current_position(value): if isinstance(value, list): x, y, z, yaw, frame = value - return f"{x: .2f} {y: .2f} {z: .2f} {int(yaw): d} {frame}" + return f"{x: .2f} {y: .2f} {z: .2f} {yaw: .0f} {frame}" return value @@ -331,7 +331,7 @@ def view_start_position(value): if isinstance(value, list): x, y, z, yaw, action, delay = value if action in ['fly', 'takeoff']: - return f"{x: .2f} {y: .2f} {z: .2f} {int(yaw): d} {action} {delay: .1f}" + return f"{x: .2f} {y: .2f} {z: .2f} {yaw: .0f} {action} {delay: .1f}" else: return f"{action}" return value From 1a686cdf933910fdfa16922cde928421a426b711 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 11:56:37 +0300 Subject: [PATCH 31/43] Drone: Update requirements --- Drone/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Drone/requirements.txt b/Drone/requirements.txt index f46bac3..260a5f8 100644 --- a/Drone/requirements.txt +++ b/Drone/requirements.txt @@ -1,3 +1,4 @@ selectors2 psutil configobj +watchdog From 19ffb1bf58cfe726bf930de1ec93d2a62792d935 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 17:54:01 +0300 Subject: [PATCH 32/43] Drone: Make observer daemon --- Drone/copter_client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 8c615e6..437a327 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -1003,7 +1003,8 @@ if __name__ == "__main__": event_handler = AnimationEventHandler() observer = Observer() observer.schedule(event_handler, ".", recursive=True) + observer.daemon = True observer.start() copter.start(task_manager) - observer.stop() - observer.join() + #observer.stop() + #observer.join() From c311a9d4e2d9c31a33981d7cc8ac44c5d169def8 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 18:10:33 +0300 Subject: [PATCH 33/43] Drone: Turn off observer for tests --- Drone/copter_client.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 437a327..075b147 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -1000,11 +1000,11 @@ if __name__ == "__main__": copter = CopterClient() task_manager = tasking.TaskManager() rospy.Subscriber('/emergency', Bool, emergency_callback) - event_handler = AnimationEventHandler() - observer = Observer() - observer.schedule(event_handler, ".", recursive=True) - observer.daemon = True - observer.start() + #event_handler = AnimationEventHandler() + #observer = Observer() + #observer.schedule(event_handler, ".", recursive=True) + #observer.daemon = True + #observer.start() copter.start(task_manager) #observer.stop() #observer.join() From db6c16599dae9b75a9e7de4498c1411c3c66fb4b Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Sun, 31 May 2020 18:19:24 +0300 Subject: [PATCH 34/43] Server: Fix handling start position --- Server/copter_table_models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index 211e3bd..aa4917a 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -145,6 +145,10 @@ def check_time_delta(item): @ModelChecks.column_check("start_position", pass_context=True) def check_start_pos(item, context): + if len(item) == 6: + if not item[4] in ["takeoff", "fly"]: + return False + if ModelChecks.start_pos_delta_max == 0: return True From f38dbe08cdf11e435b9134fa132a7266fcda77bb Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 04:56:24 +0300 Subject: [PATCH 35/43] Drone: Make threads be daemons --- Drone/copter_client.py | 6 +++--- Drone/tasking_lib.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 075b147..d258358 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -162,7 +162,7 @@ class CopterClient(client.Client): trans.header.frame_id = "map" trans.child_frame_id = "gps" static_broadcaster.sendTransform(trans) - gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread") + gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread", daemon=True) gps_frame_thread.start() def gps_frame_broadcast_loop(self): @@ -966,9 +966,9 @@ class Telemetry: def start_loop(self): if copter.config.telemetry_frequency > 0: telemetry_thread = threading.Thread(target=self._update_loop, name="Telemetry getting thread", - args=(copter.config.telemetry_frequency,)) # TODO MOVE? Daemon? + args=(copter.config.telemetry_frequency,), daemon=True) # TODO MOVE? Daemon? slow_telemetry_thread = threading.Thread(target=self._slow_update_loop, - name="Slow telemetry getting thread") + name="Slow telemetry getting thread", daemon=True) slow_telemetry_thread.start() telemetry_thread.start() else: diff --git a/Drone/tasking_lib.py b/Drone/tasking_lib.py index c64dbcb..743e940 100644 --- a/Drone/tasking_lib.py +++ b/Drone/tasking_lib.py @@ -31,8 +31,8 @@ class TaskManager(object): self.task_queue = [] self._counter = itertools.count() # unique sequence count - self._processor_thread = threading.Thread(target=self._task_processor, name="Task processing thread") - self._processor_thread.daemon = True + self._processor_thread = threading.Thread(target=self._task_processor, name="Task processing thread", daemon=True) + #self._processor_thread.daemon = True self._task_queue_lock = threading.RLock() self._running_event = threading.Event() From c924f3ad0193fb7d5cf20b8f43ec4e9b80adb555 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 05:06:02 +0300 Subject: [PATCH 36/43] Drone: Fix daemon argument --- Drone/copter_client.py | 13 ++++++++----- Drone/tasking_lib.py | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index d258358..fc6604c 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -162,7 +162,8 @@ class CopterClient(client.Client): trans.header.frame_id = "map" trans.child_frame_id = "gps" static_broadcaster.sendTransform(trans) - gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread", daemon=True) + gps_frame_thread = threading.Thread(target=self.gps_frame_broadcast_loop, name="GPS frame broadcast thread") + gps_frame_thread.daemon = True gps_frame_thread.start() def gps_frame_broadcast_loop(self): @@ -966,11 +967,13 @@ class Telemetry: def start_loop(self): if copter.config.telemetry_frequency > 0: telemetry_thread = threading.Thread(target=self._update_loop, name="Telemetry getting thread", - args=(copter.config.telemetry_frequency,), daemon=True) # TODO MOVE? Daemon? - slow_telemetry_thread = threading.Thread(target=self._slow_update_loop, - name="Slow telemetry getting thread", daemon=True) - slow_telemetry_thread.start() + args=(copter.config.telemetry_frequency,)) + telemetry_thread.daemon = True telemetry_thread.start() + slow_telemetry_thread = threading.Thread(target=self._slow_update_loop, + name="Slow telemetry getting thread") + slow_telemetry_thread.daemon = True + slow_telemetry_thread.start() else: logger.info("Telemetry loop is not created because of zero or negative telemetry frequency") diff --git a/Drone/tasking_lib.py b/Drone/tasking_lib.py index 743e940..c64dbcb 100644 --- a/Drone/tasking_lib.py +++ b/Drone/tasking_lib.py @@ -31,8 +31,8 @@ class TaskManager(object): self.task_queue = [] self._counter = itertools.count() # unique sequence count - self._processor_thread = threading.Thread(target=self._task_processor, name="Task processing thread", daemon=True) - #self._processor_thread.daemon = True + self._processor_thread = threading.Thread(target=self._task_processor, name="Task processing thread") + self._processor_thread.daemon = True self._task_queue_lock = threading.RLock() self._running_event = threading.Event() From 708e8ad3d6bf8811c3ecdb5644cc935634d946d6 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 05:30:24 +0300 Subject: [PATCH 37/43] Drone: Turn on file observer --- Drone/copter_client.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index fc6604c..6c9444b 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -1003,11 +1003,9 @@ if __name__ == "__main__": copter = CopterClient() task_manager = tasking.TaskManager() rospy.Subscriber('/emergency', Bool, emergency_callback) - #event_handler = AnimationEventHandler() - #observer = Observer() - #observer.schedule(event_handler, ".", recursive=True) - #observer.daemon = True - #observer.start() + event_handler = AnimationEventHandler() + observer = Observer() + observer.schedule(event_handler, ".", recursive=True) + observer.daemon = True + observer.start() copter.start(task_manager) - #observer.stop() - #observer.join() From 22073c0e808f40d45486695ee10e4810bc196646 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 08:01:26 +0300 Subject: [PATCH 38/43] Server: Update default logging level for server_qt --- 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 6627a74..daac548 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -288,7 +288,7 @@ class MainWindow(QtWidgets.QMainWindow): try: col = self.model.columns.index(key) except ValueError: - logging.error(f"No column {key} present!") + logging.debug(f"No column {key} present!") else: row_data = self.model.get_row_by_attr("client", client) row_num = self.model.get_row_index(row_data) @@ -647,7 +647,7 @@ if __name__ == "__main__": msgbox_handler.setLevel(logging.CRITICAL) logging.basicConfig( - level=logging.DEBUG, + level=logging.INFO, format="%(asctime)s [%(name)-7.7s] [%(threadName)-19.19s] [%(levelname)-7.7s] %(message)s", handlers=[ logging.FileHandler("server_logs/{}.log".format(now)), From 8e7ee15da94e09038be91311df4639bbb0983b45 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 08:01:51 +0300 Subject: [PATCH 39/43] Server: Fix config getting from copter --- Server/copter_table.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Server/copter_table.py b/Server/copter_table.py index 2a1df89..f216432 100644 --- a/Server/copter_table.py +++ b/Server/copter_table.py @@ -226,8 +226,8 @@ class CopterTableWidget(QTableView): @pyqtSlot(QtCore.QPoint) def open_menu(self, point): menu = QMenu(self) - index = self.indexAt(point) - item = self.model.get_row_data(index) + id = self.indexAt(point).siblingAtColumn(0).data() + item = self.model.get_row_by_attr('copter_id', id) edit_config = QAction("Edit config") edit_config.triggered.connect(partial(self.edit_copter_config, item)) From b8f6210bbadc6273dc3a29986423adf5cb216de6 Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 10:31:29 +0300 Subject: [PATCH 40/43] Drone: Make base client loop to thread --- Drone/copter_client.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 6c9444b..6b32daa 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -137,7 +137,10 @@ class CopterClient(client.Client): self.start_floor_frame_broadcast() elif self.config.copter_frame_id == "gps": self.start_gps_frame_broadcast() - super(CopterClient, self).start() + client_thread = threading.Thread(target=super(CopterClient, self).start, name="Client thread") + client_thread.daemon = True + client_thread.start() + #super(CopterClient, self).start() def start_floor_frame_broadcast(self): if self.config.floor_frame_parent == "gps": @@ -1009,3 +1012,5 @@ if __name__ == "__main__": observer.daemon = True observer.start() copter.start(task_manager) + while not rospy.is_shutdown(): + rospy.sleep(0.1) From 6473607df413a18c46ac6d7cf03ed998198b709f Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 10:32:12 +0300 Subject: [PATCH 41/43] Server: Change clover service name for restarting --- Server/server_qt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/server_qt.py b/Server/server_qt.py index daac548..bb0cb4a 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -168,7 +168,7 @@ class MainWindow(QtWidgets.QMainWindow): self.ui.action_retrive_any_file.triggered.connect(b_partial(self.request_any_file, client_path=None)) self.ui.action_restart_clever.triggered.connect( - b_partial(self.send_to_selected, "service_restart", command_kwargs={"name": "clever"})) + b_partial(self.send_to_selected, "service_restart", command_kwargs={"name": "clover"})) self.ui.action_restart_clever_show.triggered.connect(self.restart_clever_show) self.ui.action_restart_chrony.triggered.connect(self.restart_chrony) self.ui.action_reboot_all.triggered.connect(b_partial(self.send_to_selected, "reboot_all")) From 187f6e09eb2d0ece396d2c59e50f8a350e14618c Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 13:24:40 +0300 Subject: [PATCH 42/43] Drone: Add variants for restarting clever service --- Drone/copter_client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 6b32daa..03c5d31 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -516,6 +516,9 @@ def _command_reboot(*args, **kwargs): @messaging.message_callback("service_restart") def _command_service_restart(*args, **kwargs): service = kwargs["name"] + if service=="clover": + restart_service("clever") + restart_service("clover@{}".format(copter.client_id)) restart_service(service) From 9e3553e4aa051d01c500f888f0707e57b0b6986c Mon Sep 17 00:00:00 2001 From: Arthur Golubtsov Date: Mon, 1 Jun 2020 13:28:42 +0300 Subject: [PATCH 43/43] Drone: Fix clever-show service handle --- Drone/copter_client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Drone/copter_client.py b/Drone/copter_client.py index 03c5d31..5c87562 100644 --- a/Drone/copter_client.py +++ b/Drone/copter_client.py @@ -518,7 +518,8 @@ def _command_service_restart(*args, **kwargs): service = kwargs["name"] if service=="clover": restart_service("clever") - restart_service("clover@{}".format(copter.client_id)) + if service=="clever-show": + restart_service("clever-show@{}".format(copter.client_id)) restart_service(service)