Загрузка данных


import asyncio
import json
import struct
import numpy as np
import cv2
import websockets
from playwright.sync_api import sync_playwright

ROBOT_IP = "10.10.10.10"
WS_URL = f"ws://{ROBOT_IP}:8765"
CAM_URL = f"http://{ROBOT_IP}:8889/cam/"
CMD_TOPIC = "/cmd_vel"

LINEAR_SPEED = 0.25
ANGULAR_SPEED = 0.6

# Переменные управления
channel_id = 1
ws_conn = None

async def send_twist(vx, wz):
    if ws_conn is None:
        return
    twist_data = {
        "linear": {"x": float(vx), "y": 0.0, "z": 0.0},
        "angular": {"x": 0.0, "y": 0.0, "z": float(wz)}
    }
    payload = json.dumps(twist_data).encode('utf-8')
    header = struct.pack("<BI", 1, channel_id)
    try:
        await ws_conn.send(header + payload)
    except Exception as e:
        pass

async def main():
    global ws_conn
    
    print(f"1. Подключение к Foxglove WebSocket {WS_URL}...")
    async with websockets.connect(WS_URL, subprotocols=["foxglove.websocket.v1"]) as ws:
        ws_conn = ws
        
        # Регистрируем топик скорости
        advertise_msg = {
            "op": "advertise",
            "channels": [{
                "id": channel_id,
                "topic": CMD_TOPIC,
                "encoding": "json",
                "schemaName": "geometry_msgs/msg/Twist"
            }]
        }
        await ws.send(json.dumps(advertise_msg))
        print("Управление подключено!")

        print(f"2. Подключение к видеопотоку WebRTC: {CAM_URL}...")
        with sync_playwright() as p:
            browser = p.chromium.launch(headless=True)
            page = browser.new_page()
            page.goto(CAM_URL)
            
            # Ждем появления тега video
            video_element = page.wait_for_selector("video", timeout=10000)
            print("\n==============================================")
            print(" ОКНО ВИДЕО ОТКРЫТО!")
            print(" Кликните на окно с видео и управляйте:")
            print("   W - вперед | S - назад | A/D - поворот")
            print("   Пробел - остановка | ESC/Q - выход")
            print("==============================================\n")

            current_vx = 0.0
            current_wz = 0.0

            try:
                while True:
                    # 1. Получаем скриншот текущего кадра из WebRTC video-тега
                    img_bytes = video_element.screenshot()
                    nparr = np.frombuffer(img_bytes, np.uint8)
                    frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

                    # 2. Рисуем подсказку поверх видео
                    cv2.putText(frame, f"Speed: Vx={current_vx:.1f}, Wz={current_wz:.1f}", 
                                (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
                    
                    cv2.imshow("RoboMarvel Live Camera & Control", frame)

                    # 3. Обработка клавиш в окне OpenCV
                    key = cv2.waitKey(20) & 0xFF

                    if key == ord('w') or key == ord('W') or key == 230:  # 'ц' на русской раскладке
                        current_vx, current_wz = LINEAR_SPEED, 0.0
                    elif key == ord('s') or key == ord('S') or key == 251:
                        current_vx, current_wz = -LINEAR_SPEED, 0.0
                    elif key == ord('a') or key == ord('A') or key == 244:
                        current_vx, current_wz = 0.0, ANGULAR_SPEED
                    elif key == ord('d') or key == ord('D') or key == 226:
                        current_vx, current_wz = 0.0, -ANGULAR_SPEED
                    elif key == ord(' '):  # Пробел - СТОП
                        current_vx, current_wz = 0.0, 0.0
                    elif key == 27 or key == ord('q'):  # ESC или Q
                        break

                    # Отправляем текущую скорость роботу
                    await send_twist(current_vx, current_wz)

            finally:
                await send_twist(0.0, 0.0)
                browser.close()
                cv2.destroyAllWindows()

if __name__ == "__main__":
    asyncio.run(main())