You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5.5 KiB

Испытательный UDP-протокол

1. Назначение

Этот backend нужен для испытаний, когда проект должен отправлять состояние цели в блок наведения по UDP в локальной сети.

В проекте этот режим включается через:

AUTOPILOT_BACKEND = "proto_udp"
PROTO_UDP_ENABLE = True

или через env:

FPV_AUTOPILOT_BACKEND=proto_udp
FPV_PROTO_UDP_ENABLE=1

2. Куда это встроено

Реализация находится в:

  • autopilot_bridge.py

Новый backend называется:

  • proto_udp

3. Транспорт

  • протокол: UDP
  • адрес: PROTO_UDP_HOST
  • порт: PROTO_UDP_PORT

По умолчанию:

PROTO_UDP_HOST = "127.0.0.1"
PROTO_UDP_PORT = 5005

4. Формат пакета

Формат упаковки:

<BBBhhbbB

Это little-endian бинарный пакет фиксированной длины.

Поля идут в таком порядке:

  1. descriptor
  2. object_id
  3. target_state
  4. offset_y_px
  5. offset_x_px
  6. offset_y_pct
  7. offset_x_pct
  8. bbox_area_pct

5. Таблица полей

descriptor

  • тип: uint8
  • стандартное значение: 1
  • задается через PROTO_UDP_DESCRIPTOR

object_id

  • тип: uint8
  • диапазон: 0..255
  • 0, если цели нет

target_state

  • тип: uint8
  • значения:
    • 0 — цели нет
    • 1 — цель есть, идет обычная детекция/сопровождение
    • 3 — детекция потеряна, но проект удерживает цель трекингом

Значение 2 в пользовательском протоколе зарезервировано под сценарий "несколько целей". Текущая реализация проекта его не отправляет, потому что runtime всегда выбирает одну основную цель.

offset_y_px

  • тип: int16
  • знак:
    • вверх +
    • вниз -

offset_x_px

  • тип: int16
  • знак:
    • вправо +
    • влево -

offset_y_pct

  • тип: int8
  • диапазон: -100..100
  • считается относительно половины высоты кадра

offset_x_pct

  • тип: int8
  • диапазон: -100..100
  • считается относительно половины ширины кадра

bbox_area_pct

  • тип: uint8
  • диапазон: 0..100
  • отношение площади bbox к площади кадра в процентах

6. Что отправляется при отсутствии цели

Если цели нет, пакет отправляется с нулями:

  • object_id = 0
  • target_state = 0
  • все offsets = 0
  • bbox_area_pct = 0

Это соответствует вашему описанию:

если цели нет, все значения остаются нулевыми

7. Как вычисляются значения

Смещение в пикселях

Берется из guidance-точки:

  • aim_x
  • aim_y

Относительно центра кадра:

  • offset_x_px = aim_x - center_x
  • offset_y_px = center_y - aim_y

То есть знак сделан так, чтобы:

  • вправо было положительным;
  • вверх было положительным.

Смещение в процентах

Нормируется к половине размера кадра:

  • по X к frame_w / 2
  • по Y к frame_h / 2

И затем ограничивается до -100..100.

Площадь bbox

Используются:

  • box_w
  • box_h
  • frame_w
  • frame_h

Формула:

bbox_area_pct = 100 * (box_w * box_h) / (frame_w * frame_h)

8. Включение в локальном запуске

PowerShell

$env:FPV_AUTOPILOT_BACKEND = "proto_udp"
$env:FPV_PROTO_UDP_ENABLE = "1"
$env:FPV_PROTO_UDP_HOST = "192.168.1.50"
$env:FPV_PROTO_UDP_PORT = "5005"
python main.py

Bash

export FPV_AUTOPILOT_BACKEND=proto_udp
export FPV_PROTO_UDP_ENABLE=1
export FPV_PROTO_UDP_HOST=192.168.1.50
export FPV_PROTO_UDP_PORT=5005
python3 main.py

9. Включение в Docker

В docker-compose.yml:

FPV_AUTOPILOT_BACKEND: "proto_udp"
FPV_PROTO_UDP_ENABLE: "1"
FPV_PROTO_UDP_HOST: "192.168.1.50"
FPV_PROTO_UDP_PORT: "5005"

10. Пример приема пакета на Python

import socket
import struct

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 5005))

while True:
    data, addr = sock.recvfrom(1024)
    descriptor, object_id, target_state, off_y_px, off_x_px, off_y_pct, off_x_pct, bbox_area_pct = struct.unpack(
        "<BBBhhbbB", data
    )
    print(addr, descriptor, object_id, target_state, off_y_px, off_x_px, off_y_pct, off_x_pct, bbox_area_pct)

11. Что важно проверить на стенде

  1. Совпадает ли порядок байтов с ожидаемым приемником.
  2. Совпадает ли знак вертикали и горизонтали.
  3. Устраивает ли блок значение target_state = 3 при удержании без детекции.
  4. Не нужен ли вам в будущем отдельный режим target_state = 2.