260 lines
8.1 KiB
Python
260 lines
8.1 KiB
Python
from google_map import GoogleMap
|
||
from pathlib import Path
|
||
from position import Position
|
||
from simulator import Simulator
|
||
from time import sleep
|
||
from trajectory_drawer import TrajectoryDrawer
|
||
from utility import cv2_to_pil
|
||
from vision_chunk import VisionChunk
|
||
from visualization import VisualizationManager
|
||
from yandex_map import YandexMap
|
||
|
||
import argparse
|
||
import autopilot
|
||
import constants
|
||
import cv2
|
||
import matplotlib.pyplot as plt
|
||
import numpy as np
|
||
import pickle
|
||
import random
|
||
import utility
|
||
|
||
def get_map(map_name: str = 'google', initial_lat=49.103814, initial_lon=55.794258, initial_zoom=18):
|
||
if map_name == 'google': return GoogleMap(initial_lat, initial_lon, initial_zoom)
|
||
if map_name == 'yandex': return YandexMap(initial_lat, initial_lon, initial_zoom)
|
||
return None
|
||
|
||
def make_global_photo(filename, initial_zoom=13, map_name: str = 'google'):
|
||
online_map: YandexMap | GoogleMap = get_map(map_name, initial_zoom=initial_zoom)
|
||
online_map.save_photo(filename)
|
||
online_map.destroy()
|
||
|
||
def get_trajectory_points(bg_img: str) -> list[(float, float)]:
|
||
trajectoryDrawer = TrajectoryDrawer(bg_img)
|
||
trajectoryDrawer.show()
|
||
trajectoryDrawer.wait()
|
||
points = list(map(lambda p: [p[0] / trajectoryDrawer.img.shape[1], p[1] / trajectoryDrawer.img.shape[0]], trajectoryDrawer.points))
|
||
return points
|
||
|
||
def build(name: str, map_name: str = 'google'):
|
||
|
||
# Создание папки с информацией о маршруте
|
||
dir = Path('trajectories')
|
||
if not dir.exists(): dir.mkdir()
|
||
dir /= name
|
||
assert not dir.exists()
|
||
dir.mkdir()
|
||
dir_chunks = dir / 'chunks'
|
||
dir_chunks.mkdir()
|
||
|
||
make_global_photo('map.jpg', 15, map_name)
|
||
points = get_trajectory_points('map.jpg')
|
||
online_map: YandexMap | GoogleMap = get_map(map_name, initial_zoom=15)
|
||
|
||
|
||
width, height = online_map.get_size()
|
||
points_coords = np.array(list(map(lambda p: [
|
||
(p[0] - points[0][0]) * width, (points[0][1] - p[1]) * height
|
||
], points)))
|
||
|
||
points_coords *= online_map.pixel_ratio
|
||
|
||
# Начнём симуляцию полёта с первой точки
|
||
online_map.make_as_center(*points[0])
|
||
sleep(3)
|
||
online_map.scroll(0.5, 0.5, 10, True)
|
||
sleep(2)
|
||
geo = online_map.get_geolocation()
|
||
online_map.open(geo['lat'], geo['lon'], 18)
|
||
sleep(20)
|
||
|
||
points_coords_pixel = points_coords.copy() / online_map.pixel_ratio
|
||
|
||
pilot = autopilot.AutoPilot(points_coords_pixel, pixel_ratio=online_map.pixel_ratio)
|
||
simulator = Simulator(online_map)
|
||
pilot.target_idx = 0
|
||
|
||
pilot.pos = simulator.pos.copy()
|
||
command = pilot.make_command()
|
||
|
||
positions: list[Position] = []
|
||
|
||
print("points_coords_pixel:", points_coords_pixel)
|
||
for i in range(5000):
|
||
|
||
if command.stop:
|
||
break
|
||
|
||
chunk = simulator.get_chunk()
|
||
pilot.pos = simulator.pos.copy()
|
||
command = pilot.make_command()
|
||
command.velocity /= online_map.pixel_ratio
|
||
|
||
print("Position:", simulator.pos)
|
||
|
||
# Save Image
|
||
chunk.save_image(dir_chunks / f"chunk_{len(positions)}.png")
|
||
|
||
positions.append(simulator.pos.copy() * online_map.pixel_ratio)
|
||
|
||
simulator.handle(command.dangle, command.velocity)
|
||
if i == 0 and map_name == 'google':
|
||
simulator.pos.x = 0
|
||
simulator.pos.y = 0
|
||
sleep(1.5)
|
||
|
||
data = {
|
||
'points': points_coords,
|
||
'chunk_positions': positions,
|
||
'initial_geolocation': geo
|
||
}
|
||
|
||
print(points_coords)
|
||
|
||
file_positions = dir / 'positions.pkl'
|
||
with file_positions.open('wb') as file:
|
||
pickle.dump(data, file)
|
||
|
||
print("WRITE POINTS:", points)
|
||
|
||
sleep(15)
|
||
online_map.destroy()
|
||
|
||
def run(name: str, map_name: str = 'yandex'):
|
||
dir = Path('trajectories')
|
||
assert dir.exists()
|
||
dir /= name
|
||
assert dir.exists()
|
||
dir_chunks = dir / 'chunks'
|
||
file_positions = dir / 'positions.pkl'
|
||
|
||
with file_positions.open('rb') as file:
|
||
data = pickle.load(file)
|
||
|
||
initial_geolocation = data['initial_geolocation']
|
||
|
||
lat = initial_geolocation['lat']
|
||
lon = initial_geolocation['lon']
|
||
online_map: YandexMap | GoogleMap = get_map(map_name, lat, lon, 18)
|
||
sleep(2)
|
||
|
||
chunks: list[VisionChunk] = []
|
||
for i in range(len(data['chunk_positions'])):
|
||
chunk = VisionChunk.load_image(dir_chunks / f"chunk_{i}.png")
|
||
chunk.pos = data['chunk_positions'][i] / online_map.pixel_ratio
|
||
chunks.append(chunk)
|
||
|
||
points = data['points'] / online_map.pixel_ratio
|
||
print("READ POINTS:", points)
|
||
|
||
vis_manager = VisualizationManager()
|
||
pilot = autopilot.AutoPilot(points, chunks, vis_manager, online_map.pixel_ratio)
|
||
simulator = Simulator(online_map)
|
||
pilot.target_idx = 0
|
||
|
||
chunk = simulator.get_chunk()
|
||
command = pilot.handle(chunk)
|
||
|
||
vis_manager.update_display()
|
||
vis_manager.pause(1)
|
||
|
||
vis_manager.set_target_points(points)
|
||
|
||
proc_time = np.array([])
|
||
|
||
errors = []
|
||
|
||
sleep(1)
|
||
|
||
for i in range(10000000000):
|
||
if i > 0:
|
||
simulator.set_pitch(np.sin(i / 10) * 5)
|
||
simulator.set_roll(np.sin(i / 15) * 5)
|
||
simulator.set_zoom(1.0 + np.sin(i / 10) * 0.3)
|
||
|
||
if command.stop:
|
||
break
|
||
|
||
chunk = simulator.get_chunk()
|
||
command = pilot.handle(chunk)
|
||
command.velocity /= online_map.pixel_ratio
|
||
|
||
proc_time = np.append(proc_time, command.proccessing_time)
|
||
|
||
# Save Image
|
||
chunk.save_image(Path('images') / f"photo_{i}.png")
|
||
|
||
vis_manager.update_display()
|
||
vis_manager.pause(0.2)
|
||
|
||
vis_manager.set_target_index(pilot.target_idx)
|
||
vis_manager.update_drone_trajectory(pilot.pos.x * online_map.pixel_ratio, pilot.pos.y * online_map.pixel_ratio)
|
||
vis_manager.update_global_map(simulator.pos.x * online_map.pixel_ratio, simulator.pos.y * online_map.pixel_ratio)
|
||
vis_manager.update_error_plot(i, pilot.pos.x * online_map.pixel_ratio, pilot.pos.y * online_map.pixel_ratio, simulator.pos.x * online_map.pixel_ratio, simulator.pos.y * online_map.pixel_ratio)
|
||
|
||
errors.append(np.hypot((pilot.pos.x - simulator.pos.x) * online_map.pixel_ratio, (pilot.pos.y - simulator.pos.y) * online_map.pixel_ratio))
|
||
|
||
vis_manager.update_display()
|
||
vis_manager.pause(0.2)
|
||
|
||
last_proc_times = proc_time[-10:]
|
||
print(F"Image #{i}")
|
||
print("Average FPS:", 1 / last_proc_times.mean())
|
||
print("Pilot coords:", pilot.pos)
|
||
print("Simulator coords:", simulator.pos)
|
||
sleep(0.5)
|
||
simulator.handle(command.dangle, command.velocity)
|
||
if i == 0 and map_name == 'google':
|
||
simulator.pos.x = 0
|
||
simulator.pos.y = 0
|
||
|
||
print("Errors:", errors)
|
||
print("MSE:", (np.array(errors) ** 2).mean())
|
||
print("RMSE:", (np.array(errors) ** 2).mean() ** 0.5)
|
||
print("Average FPS:", 1 / proc_time.mean())
|
||
vis_manager.show_final()
|
||
|
||
def main(mode: str, name: str):
|
||
if name is None:
|
||
name = utility.generate_folder_name()
|
||
|
||
if mode == 'build' or mode == 'standalone':
|
||
build(name)
|
||
|
||
if mode == 'run' or mode == 'standalone':
|
||
run(name)
|
||
|
||
def parse_args():
|
||
"""Парсер аргументов командной строки"""
|
||
parser = argparse.ArgumentParser(description='Обработка траекторий')
|
||
|
||
# Добавляем обязательный аргумент --mode
|
||
parser.add_argument(
|
||
'--mode',
|
||
type=str,
|
||
required=True,
|
||
choices=['standalone', 'build', 'run'],
|
||
help='Режим работы: standalone, build или run'
|
||
)
|
||
|
||
# Добавляем опциональный аргумент --name
|
||
parser.add_argument(
|
||
'--name',
|
||
type=str,
|
||
help='Название траектории (обязательно для режимов build и run)'
|
||
)
|
||
|
||
# Парсим аргументы
|
||
args = parser.parse_args()
|
||
|
||
# Проверяем, что для build и run указан --name
|
||
if args.mode in ['build', 'run'] and not args.name:
|
||
parser.error(f"--name обязателен для режима {args.mode}")
|
||
|
||
return args
|
||
|
||
if __name__ == "__main__":
|
||
args = parse_args()
|
||
main(args.mode, args.name)
|
||
|