From d6ccac056781ac64cd34eee7c68faad5ccb71e51 Mon Sep 17 00:00:00 2001 From: ivymerfe <82306640+ivymerfe@users.noreply.github.com> Date: Sat, 4 Oct 2025 13:08:30 +0700 Subject: [PATCH] update --- FITonyashkii/public/app.js | 116 ++++++++++++++++++++++++---- FITonyashkii/server/beacons.txt | 16 ++-- FITonyashkii/server/config.py | 1 + FITonyashkii/server/rssi_filter.py | 2 +- FITonyashkii/server/rssi_locator.py | 4 +- FITonyashkii/server/server.py | 9 ++- FITonyashkii/server/solver.py | 4 +- 7 files changed, 123 insertions(+), 29 deletions(-) diff --git a/FITonyashkii/public/app.js b/FITonyashkii/public/app.js index c99c6e4..64972e1 100644 --- a/FITonyashkii/public/app.js +++ b/FITonyashkii/public/app.js @@ -29,7 +29,9 @@ class MapInterface { this.gridSize = 50; this.cellSize = 30; + // Route state this.routeActive = false; + this.routeData = []; // массив точек маршрута {x, y} this.setupCanvas(); this.setupEventListeners(); @@ -249,22 +251,25 @@ class MapInterface { } } - startRoute() { + +// Модифицируйте метод startRoute +startRoute() { if (this.ws && this.ws.readyState === WebSocket.OPEN) { - const message = { - type: "start_route", - }; + const message = { + type: "start_route", + }; - this.ws.send(JSON.stringify(message)); - this.routeActive = true; - this.updateRouteButton(); - this.showNotification("Маршрут начат!"); + this.ws.send(JSON.stringify(message)); + this.routeActive = true; + this.routeData = []; + this.updateRouteButton(); + this.showNotification("Маршрут начат!"); - console.log("Начало маршрута:", message); + console.log("Начало маршрута:", message); } else { - this.showNotification("Нет подключения к серверу", true); + this.showNotification("Нет подключения к серверу", true); } - } +} finishRoute() { if (this.ws && this.ws.readyState === WebSocket.OPEN) { @@ -296,6 +301,56 @@ class MapInterface { } } + addRoutePoint(x, y) { + if (this.routeActive) { + this.routeData.push({ x, y }); + } + } + + drawRoute() { + if (!this.routeData || this.routeData.length < 2) return; + + this.ctx.strokeStyle = "#a824c9"; + this.ctx.lineWidth = 4 * this.scale; + this.ctx.lineJoin = "round"; + this.ctx.lineCap = "round"; + this.ctx.setLineDash([]); + + this.ctx.beginPath(); + + const firstPoint = this.scalePos(this.routeData[0].x, this.routeData[0].y); + this.ctx.moveTo(firstPoint.x, firstPoint.y); + + for (let i = 1; i < this.routeData.length; i++) { + const point = this.scalePos(this.routeData[i].x, this.routeData[i].y); + this.ctx.lineTo(point.x, point.y); + } + + this.ctx.stroke(); + + if (this.routeData.length > 0) { + const startPoint = this.scalePos(this.routeData[0].x, this.routeData[0].y); + this.ctx.fillStyle = "#2ecc71"; + this.ctx.beginPath(); + this.ctx.arc(startPoint.x, startPoint.y, 5 * this.scale, 0, Math.PI * 2); + this.ctx.fill(); + + } + + // Рисуем конечную точку другим цветом + if (this.routeData.length > 1) { + const endPoint = this.scalePos( + this.routeData[this.routeData.length - 1].x, + this.routeData[this.routeData.length - 1].y + ); + this.ctx.fillStyle = "#e74c3c"; // красный для финиша + this.ctx.beginPath(); + this.ctx.arc(endPoint.x, endPoint.y, 5 * this.scale, 0, Math.PI * 2); + this.ctx.fill(); + + } + } + toggleGrid() { this.showGrid = !this.showGrid; } @@ -408,10 +463,26 @@ class MapInterface { } } else if (data.playerPosition && data.objects) { // Full map data format + const prevX = this.playerPosition.x; + const prevY = this.playerPosition.y; + this.playerPosition = data.playerPosition; this.objects = data.objects; this.statusValues = data.statusValues || []; + // Автоматически добавляем точку в маршрут при движении + if (this.routeActive) { + const distance = Math.sqrt( + Math.pow(this.playerPosition.x - prevX, 2) + + Math.pow(this.playerPosition.y - prevY, 2) + ); + + // Добавляем точку только если перемещение значительное + if (distance > 0.1) { + this.addRoutePoint(this.playerPosition.x, this.playerPosition.y); + } + } + const messageLine = document.getElementById("messageLine"); if (data.messageLine) { messageLine.textContent = data.messageLine; @@ -420,7 +491,23 @@ class MapInterface { } } else if (data.x !== undefined && data.y !== undefined) { // Simple position update + const prevX = this.playerPosition.x; + const prevY = this.playerPosition.y; + this.playerPosition = { x: data.x, y: data.y }; + + // Автоматически добавляем точку в маршрут при движении + if (this.routeActive) { + const distance = Math.sqrt( + Math.pow(this.playerPosition.x - prevX, 2) + + Math.pow(this.playerPosition.y - prevY, 2) + ); + + // Добавляем точку только если перемещение значительное + if (distance > 0.5) { + this.addRoutePoint(this.playerPosition.x, this.playerPosition.y); + } + } } else if (data.type === "error") { console.error("Ошибка сервера:", data.message); this.showNotification("Ошибка: " + data.message, true); @@ -517,6 +604,9 @@ class MapInterface { this.drawGrid(); } + // Draw route (добавляем эту строку) + this.drawRoute(); + // Draw objects this.drawObjects(); @@ -528,7 +618,7 @@ class MapInterface { scalePos(x, y) { return { x: x * this.cellSize * this.scale + this.offsetX, - y: y * this.cellSize * this.scale * -1 + this.offsetY, + y: -y * this.cellSize * this.scale + this.offsetY, }; } @@ -658,4 +748,4 @@ document.addEventListener("visibilitychange", function () { ) { window.mapInterface.connect(); } -}); +}); \ No newline at end of file diff --git a/FITonyashkii/server/beacons.txt b/FITonyashkii/server/beacons.txt index e75c267..07f787e 100644 --- a/FITonyashkii/server/beacons.txt +++ b/FITonyashkii/server/beacons.txt @@ -1,9 +1,9 @@ -Name;X;Y -beacon_1;-7.2;-4.8 -beacon_2;3;-4.8 -beacon_3;9.6;-0.6 -beacon_4;-13.8;-1.8 -beacon_5;-9;4.2 -beacon_6;6;9 -beacon_7;-13.2;10.8 +Name;X;Y +beacon_1;-7.2;-4.8 +beacon_2;3;-4.8 +beacon_3;9.6;-0.6 +beacon_4;-13.8;-1.8 +beacon_5;-9;4.2 +beacon_6;6;9 +beacon_7;-13.2;10.8 beacon_8;-3;2.4 \ No newline at end of file diff --git a/FITonyashkii/server/config.py b/FITonyashkii/server/config.py index f545ae7..6ce126d 100644 --- a/FITonyashkii/server/config.py +++ b/FITonyashkii/server/config.py @@ -1,2 +1,3 @@ MIN_DISTANCE_TO_UPDATE_ROUTE = 1.0 # meters +BROADCAST_FREQUENCY = 1.0 diff --git a/FITonyashkii/server/rssi_filter.py b/FITonyashkii/server/rssi_filter.py index 323e5f5..a23cd5b 100644 --- a/FITonyashkii/server/rssi_filter.py +++ b/FITonyashkii/server/rssi_filter.py @@ -6,7 +6,7 @@ class KalmanFilterManager: def __init__(self): self.filters: Dict[str, Any] = {} - self.measurement_uncertainty = 100 + self.measurement_uncertainty = 120 def initialize_kalman_filter(self): # Initialize the Kalman Filter diff --git a/FITonyashkii/server/rssi_locator.py b/FITonyashkii/server/rssi_locator.py index 40894a0..4d032c0 100644 --- a/FITonyashkii/server/rssi_locator.py +++ b/FITonyashkii/server/rssi_locator.py @@ -50,5 +50,5 @@ def on_data(self, device_name: str, rssi: int, tx_power: int = -46): position = self.solver.get_position(self.filtered_rssi) # print(position) if position: - self.x = 0.9 * self.x + 0.1*position[0] - self.y = 0.9 * self.y + 0.1*position[1] + self.x = 0.95 * self.x + 0.05 * position[0] + self.y = 0.95 * self.y + 0.05 * position[1] diff --git a/FITonyashkii/server/server.py b/FITonyashkii/server/server.py index 0a4a851..d2d0bd3 100644 --- a/FITonyashkii/server/server.py +++ b/FITonyashkii/server/server.py @@ -53,7 +53,6 @@ def __init__( async def websocket_handler(self, websocket): self.connected_clients.add(websocket) print(f"WebSocket client connected from {websocket.remote_address}") - await self.broadcast_state() try: async for message in websocket: try: @@ -192,6 +191,11 @@ async def broadcast_state(self): await client.send(message) except websockets.exceptions.ConnectionClosed: self.connected_clients.discard(client) + + async def broadcast_task(self): + while True: + await self.broadcast_state() + await asyncio.sleep(config.BROADCAST_FREQUENCY) def update(self, udp_data): current_time = int(datetime.now().timestamp()) @@ -221,8 +225,6 @@ def update(self, udp_data): if distance >= config.MIN_DISTANCE_TO_UPDATE_ROUTE: self.route_data.append((self.locator.x, self.locator.y)) - asyncio.create_task(self.broadcast_state()) - class UDPServerProtocol(asyncio.DatagramProtocol): def __init__(self, server): self.server = server @@ -257,6 +259,7 @@ async def start(self): print(f"Starting WebSocket server on ws://{self.ws_host}:{self.ws_port}") await websockets.serve(self.websocket_handler, self.ws_host, self.ws_port) asyncio.create_task(self.udp_server()) + asyncio.create_task(self.broadcast_task()) await asyncio.Future() # Run forever diff --git a/FITonyashkii/server/solver.py b/FITonyashkii/server/solver.py index 96abe5c..4898d28 100644 --- a/FITonyashkii/server/solver.py +++ b/FITonyashkii/server/solver.py @@ -2,7 +2,7 @@ class Solver: - def __init__(self, beacons: Iterable, tx: int = -65, n: float = 1.5): + def __init__(self, beacons: Iterable, tx: int = -65, n: float = 1.0): self.beacons = { beacon.name: (float(beacon.x), float(beacon.y)) for beacon in beacons } @@ -23,7 +23,7 @@ def get_position(self, rssies: Dict): x, y = self.beacons[beacon_name] distance = float(self.get_distance(beacon_rssi)) # Use inverse distance as weight (closer beacons have more influence) - weight = 1.0 / (distance + 0.1) # Add small value to avoid division by zero + weight = 1.0 / (distance + 0.05) # Add small value to avoid division by zero weighted_x += x * weight weighted_y += y * weight total_weight += weight