From c060dfad06c2264b4d298296ed37d9b55bda7d8b Mon Sep 17 00:00:00 2001 From: Kevin D Date: Fri, 13 Feb 2026 18:55:07 -0800 Subject: [PATCH] respect geofence, move from socket to async/await --- aerpaw/client/uav_runner.py | 60 +++++++++++++++++-------------------- aerpaw/config/server.yaml | 37 +++++++++++++++-------- 2 files changed, 52 insertions(+), 45 deletions(-) diff --git a/aerpaw/client/uav_runner.py b/aerpaw/client/uav_runner.py index 553ad1d..2c83576 100644 --- a/aerpaw/client/uav_runner.py +++ b/aerpaw/client/uav_runner.py @@ -22,7 +22,6 @@ from enum import IntEnum from pathlib import Path import asyncio import os -import socket import struct import yaml @@ -65,26 +64,22 @@ def get_environment(): return env -def recv_exactly(sock: socket.socket, n: int) -> bytes: - """Receive exactly n bytes from socket.""" - data = b'' - while len(data) < n: - chunk = sock.recv(n - len(data)) - if not chunk: - raise ConnectionError("Connection closed while receiving data") - data += chunk +async def recv_exactly(reader: asyncio.StreamReader, n: int) -> bytes: + """Receive exactly n bytes from async stream.""" + data = await reader.readexactly(n) return data -def recv_message_type(sock: socket.socket) -> MessageType: +async def recv_message_type(reader: asyncio.StreamReader) -> MessageType: """Receive a single-byte message type.""" - data = recv_exactly(sock, 1) + data = await recv_exactly(reader, 1) return MessageType(data[0]) -def send_message_type(sock: socket.socket, msg_type: MessageType): +async def send_message_type(writer: asyncio.StreamWriter, msg_type: MessageType): """Send a single-byte message type.""" - sock.sendall(bytes([msg_type])) + writer.write(bytes([msg_type])) + await writer.drain() class UAVRunner(BasicRunner): @@ -116,23 +111,21 @@ class UAVRunner(BasicRunner): print(f"[UAV] Connecting to controller at {self.server_ip}:{self.server_port}") # Retry connection up to 10 times (~30 seconds total) - sock = None + reader, writer = None, None for attempt in range(10): try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.settimeout(5) - sock.connect((self.server_ip, self.server_port)) - sock.settimeout(None) + reader, writer = await asyncio.wait_for( + asyncio.open_connection(self.server_ip, self.server_port), + timeout=5, + ) print(f"[UAV] Connected to controller") break - except (ConnectionRefusedError, socket.timeout, OSError) as e: - if sock: - sock.close() + except (ConnectionRefusedError, asyncio.TimeoutError, OSError) as e: print(f"[UAV] Connection attempt {attempt + 1}/10 failed: {e}") if attempt < 9: await asyncio.sleep(3) - if sock is None or sock.fileno() == -1: + if reader is None: print("[UAV] Failed to connect to controller after 10 attempts") return @@ -145,12 +138,12 @@ class UAVRunner(BasicRunner): # Command loop - handle TARGET, RTL, LAND, READY from controller waypoint_num = 0 while True: - msg_type = recv_message_type(sock) + msg_type = await recv_message_type(reader) print(f"[UAV] Received: {msg_type.name}") if msg_type == MessageType.TARGET: # Read 24 bytes of coordinates (3 little-endian doubles) - data = recv_exactly(sock, 24) + data = await recv_exactly(reader, 24) enu_x, enu_y, enu_z = struct.unpack('