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.

233 lines
5.5 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Испытательный UDP-протокол
## 1. Назначение
Этот backend нужен для испытаний, когда проект должен отправлять состояние цели в блок наведения по UDP в локальной сети.
В проекте этот режим включается через:
```text
AUTOPILOT_BACKEND = "proto_udp"
PROTO_UDP_ENABLE = True
```
или через env:
```text
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`
По умолчанию:
```python
PROTO_UDP_HOST = "127.0.0.1"
PROTO_UDP_PORT = 5005
```
## 4. Формат пакета
Формат упаковки:
```text
<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`
Формула:
```text
bbox_area_pct = 100 * (box_w * box_h) / (frame_w * frame_h)
```
## 8. Включение в локальном запуске
### PowerShell
```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
```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`:
```yaml
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
```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`.