poe-svelte-ui-lib 1.85.0 → 1.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  # WidgetMap
2
2
 
3
- Смарт-виджет «Карта»: где находятся объекты, куда они смотрят и как двигались. Каждый объект это одна группа полей устройства, на одной карте их может быть несколько. Карта на MapLibre.
3
+ Смарт-виджет «Карта»: где находятся объекты, куда они смотрят и как двигались. Каждый объект это одна группа полей устройства, на одной карте их может быть несколько. Ещё два режима строят миссию: «Маршрут» — обычный планировщик из точек с высотами, «Агро» — генератор миссии для агродрона. Аппараты из групп полей видны во всех режимах. Карта на MapLibre.
4
4
 
5
5
  ## Назначение
6
6
 
@@ -24,6 +24,7 @@
24
24
  | `Sat` | Число спутников |
25
25
  | `DevName` | Имя объекта, подпись маркера. Без него подписью будет имя группы |
26
26
  | `DevSN` | Серийный номер |
27
+ | `WPNum` | Номер текущей команды миссии. Нужен только режимам «Маршрут» и «Агро» для прогресса |
27
28
 
28
29
  Имена ключей общие с `WidgetPFD` и `WidgetDeviceInfo`. Одна отправка телеметрии кормит и карту, и пилотажный дисплей.
29
30
 
@@ -64,6 +65,90 @@ Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", dev, sizeof(dev)
64
65
 
65
66
  `isTest` включает имитацию шести аппаратов `SIM-1`-`SIM-6` без устройства. Они летают над одним районом Минска, в пределах пары километров, и обновляются раз в полсекунды. На связи всегда три аппарата. Через 40-100 секунд один из них пропадает, и его сразу сменяет тот, кто молчит дольше всех. Поэтому видно все состояния маркера: свежий, красный устаревший, скрытый и снова появившийся. При включении карта переходит к этому району. Пока режим включён, `value` и `groups` не учитываются. В конструкторе все остальные свойства становятся бледными и недоступными, пока имитацию не выключат.
66
67
 
68
+
69
+ В режимах «Маршрут» и «Агро» `isTest` включает имитацию полёта по рассчитанной траектории. Аппарат летит по маршруту со скоростями его точек или по проходам «Агро» и оставляет голубой след. В «Агро» маркер — квадрокоптер, он зелёный, пока идёт распыление. Панель поверх карты показывает время полёта, процент пройденного пути, высоту, скорость и распыление; там же запуск и пауза, ускорение ×1, ×5, ×10 или ×25 (по умолчанию ×5) и полоса прокрутки пути: её перетаскивание ставит полёт на паузу, чтобы рассмотреть любое место траектории. Полёт запускается вручную кнопкой ▶ и останавливается в конце пути; повторный запуск начинает его заново. При любом изменении маршрута или полей аппарат возвращается в начало и встаёт на паузу. Аппараты из `groups` в это время не рисуются.
70
+ ## Режим «Маршрут»
71
+
72
+ `mode="route"` — обычный планировщик миссии: точки по порядку облёта, у каждой своя высота и скорость. Аппараты из `groups` рисуются поверх маршрута, как в режиме «Объекты».
73
+
74
+ 1. **«Изменить точки»** включает правку. Клик по карте добавляет точку в конец маршрута. Новая точка берёт высоту и скорость предыдущей, первая получает 30 м и 8 м/с. Esc или двойной клик заканчивают правку.
75
+ 2. В режиме правки точки можно перетаскивать. Потяните за середину отрезка, чтобы вставить точку между соседними. Правый клик удаляет точку. Без правки на карте видны только номера точек, их не сдвинуть случайно. Точку взлёта `H` можно перетаскивать всегда.
76
+ 3. Блок **«Итог»**: сверху расчёт (число точек, длина пути, время, наибольшая высота), ниже список точек с высотой, скоростью, расстоянием от предыдущей точки и удалением; порядок меняется перетаскиванием строки за ручку, как в списках панелей свойств, под ним флажок возврата с посадкой (RTL). Клик по номеру показывает точку на карте.
77
+
78
+ Миссия в формате QGC WPL 110: точка дома, `NAV_TAKEOFF` на высоту первой точки, точки маршрута со своими высотами, `DO_CHANGE_SPEED` перед точкой, где меняется скорость, в конце `RTL`, если включён возврат. Высоты отсчитываются от точки взлёта. Время: каждый отрезок со скоростью своей точки плюс набор высоты и посадка около 2.5 м/с.
79
+
80
+ План хранит владелец карты через `route` и `onRouteChange`. Без `route` показывается демо-облёт вокруг поля под Минском.
81
+
82
+ | Поле `IRoutePlan` | Описание |
83
+ |---|---|
84
+ | `start` | Точка взлёта, `[lng, lat]` |
85
+ | `points` | Точки `{ point: [lng, lat], alt, speed }`: высота в метрах над точкой взлёта, скорость на пути к точке в м/с |
86
+ | `returnHome` | Вернуться и сесть в конце (RTL) |
87
+
88
+ ### Прогресс в шапке
89
+
90
+ В «Маршруте» и «Агро» шапка показывает полоску и процент выполнения миссии. В режиме имитации это прогресс имитации. Без имитации прогресс считается по телеметрии первой группы карты: `WPNum` (номер команды миссии, которую выполняет автопилот) и положение аппарата. Если текущая команда служебная (скорость, распылитель), целью считается следующая точка. Внутри отрезка учитывается, сколько аппарат уже пролетел к цели. В «Маршруте» рядом видно «к точке 3/6» или «возврат», в «Агро» — сколько гектаров обработано. Прогресс верен, только если на борту та же миссия, что построена на карте. Без `WPNum` полоски нет.
91
+
92
+ ## Режим «Агро»
93
+
94
+ `mode="agro"` превращает карту в генератор миссии для агродрона. Оператор обводит на карте одно или несколько полей и запретные зоны, задаёт угол проходов и ширину захвата. Карта строит траекторию, которая покрывает все поля, обходит зоны и выключает распылитель на разворотах и переходах. Готовую миссию можно скачать, скопировать или отправить на борт в формате QGC WPL 110 для автопилота ArduPilot.
95
+
96
+ Аппараты из `groups` рисуются поверх миссии так же, как в режиме «Объекты»: маркер, карточка по клику и траектория, если она включена. План хранит владелец карты через `plan` и `onPlanChange`, миссия уходит наружу через `onSend`. Без `plan` показываются два демо-поля под Минском: в большом три запретные зоны, в малом вырез и дерево.
97
+
98
+ ### Как пользоваться
99
+
100
+ 1. **«Нарисовать поле»**: кликами по карте обведите участок. Контур замыкается кликом по первой точке, двойным кликом, Enter или кнопкой «Замкнуть». Backspace убирает последнюю точку, Esc сбрасывает начатый контур. Когда поле есть, кнопка называется **«Поля»**: в этом режиме клики по карте обводят ещё одно поле.
101
+ 2. **«Запретные зоны»**: обведите места, где нельзя лететь и распылять: деревья, опоры ЛЭП, постройки, водоёмы. Зон может быть сколько угодно.
102
+ 3. **Точка взлёта** (синяя) видна всегда, её можно перетащить в любой момент.
103
+ 4. В блоке **«Маршрут и внесение»** задайте ширину захвата, отступ от границ, высоту, скорость, норму внесения и объём бака. У каждого поля свой угол проходов: новое поле сразу получает лучший угол, «Подобрать» пересчитывает углы всех полей, а ползунок «Угол для всех полей» ставит всем один угол, например чтобы проходы шли вдоль рядов посадки. Угол отдельного поля правится в его строке в блоке «Итог».
104
+ 5. Блок **«Итог»** показывает контуры, площадь к обработке, покрытие, длину пути, время, расход раствора и число дозаправок.
105
+ 6. **«Скачать»**, **«Копировать»** или **«Отправить»** миссию.
106
+
107
+ Точки контуров видны и перетаскиваются, только пока нажата кнопка «Поля» или «Запретные зоны». Потяните за середину стороны, чтобы добавить точку. Правый клик удаляет точку. Поля и зоны удаляются крестиком в блоке «Итог». Режим выключается той же кнопкой, кнопкой «Готово» или Esc.
108
+
109
+ ### Как строится траектория
110
+
111
+ 1. Поле переводится в метры и поворачивается так, чтобы проходы шли вдоль оси.
112
+ 2. Для каждого прохода считаются свободные отрезки: внутри поля и вне зон, с отступом по всей ширине полосы.
113
+ 3. Отрезки собираются в участки: подряд идущие проходы, которые соединяются один к одному. Каждый участок облетается змейкой.
114
+ 4. Порядок участков и сторона входа выбираются точным перебором, если участков не больше 10. Если больше, используется жадный выбор с улучшением 2-opt.
115
+ 5. Переходы между участками идут по кратчайшему пути в обход зон с соблюдением отступа.
116
+ 6. Несколько полей облетаются по очереди: каждый раз ближайшее к текущему положению. Путь к первому полю, переходы между полями и возврат домой строятся по открытой местности в обход всех зон.
117
+
118
+ Расчёт занимает 15-30 мс, траектория пересчитывается на каждое изменение.
119
+
120
+ ### Миссия
121
+
122
+ - точка дома (точка взлёта или первая точка поля);
123
+ - `DO_CHANGE_SPEED` с заданной скоростью;
124
+ - точки маршрута на заданной высоте над точкой взлёта;
125
+ - команды распыления: включение в начале прохода, выключение в конце и перед вылетом.
126
+
127
+ | Режим распыления | Команда | Что нужно на борту |
128
+ |---|---|---|
129
+ | Распылитель ArduPilot | `DO_SPRAYER` (216) | `SPRAY_ENABLE=1`, выход насоса `SERVOx_FUNCTION=22` |
130
+ | Насос на выходе | `DO_SET_SERVO` (183) | канал и ШИМ вкл./выкл. задаются на карте |
131
+ | Без команд | нет | распылитель работает и на разворотах, участки обработаются дважды |
132
+
133
+ Кнопка «Отправить» неактивна, если не передан `onSend`. Во время отправки на ней «Отправка…», после успеха «Отправлено», при ошибке она краснеет. Время полёта считается по скорости плюс около 4 с на разворот. Покрытие — доля поля без зон, которая попадает под распыление: остальное съедают отступы.
134
+
135
+ ### План миссии (IMissionPlan)
136
+
137
+ | Поле | Описание |
138
+ |---|---|
139
+ | `fields` | Поля `{ contour: [lng, lat][], angle }`: контур и угол проходов, ° от севера по часовой |
140
+ | `holes` | Запретные зоны, массив контуров; зона относится к полю, внутри которого лежит её центр |
141
+ | `start` | Точка взлёта, `[lng, lat]` |
142
+ | `spacing` | Ширина захвата, м |
143
+ | `margin` | Отступ от границ и зон, м |
144
+ | `alt`, `speed` | Высота, м, и скорость, м/с |
145
+ | `returnHome` | Вернуться к точке взлёта в конце |
146
+ | `rate`, `tank` | Норма внесения, л/га, и объём бака, л |
147
+ | `sprayControl` | `sprayer`, `servo` или `none` |
148
+ | `servoChannel`, `servoOn`, `servoOff` | Канал и ШИМ насоса для режима `servo` |
149
+
150
+ Расчёт доступен и без карты: `planFields` (несколько полей), `planCoverage` (одно поле), `bestFieldAngle`, `toWaypointsFile` экспортируются из библиотеки.
151
+
67
152
  ## Пропсы
68
153
 
69
154
  | Название | Тип | По умолчанию | Описание |
@@ -77,6 +162,12 @@ Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", dev, sizeof(dev)
77
162
  | `trackLength` | `number` | `1000` | Точек траектории. Можно связать через `bind:` |
78
163
  | `markerTimeout` | `number` | `30000` | Таймаут маркера, мс. Можно связать через `bind:` |
79
164
  | `isTest` | `boolean` | `false` | Режим имитации |
165
+ | `mode` | `"objects" \| "route" \| "agro"` | `"objects"` | Карта объектов, планировщик маршрута или генератор миссии для агродрона |
166
+ | `plan` | `IMissionPlan` | `DEFAULT_MISSION_PLAN` | План миссии в режиме «Агро». Можно связать через `bind:` |
167
+ | `onPlanChange` | `(plan) => void` | | Вызывается при каждом изменении плана |
168
+ | `route` | `IRoutePlan` | `DEFAULT_ROUTE_PLAN` | Маршрут в режиме «Маршрут». Можно связать через `bind:` |
169
+ | `onRouteChange` | `(route) => void` | | Вызывается при каждом изменении маршрута |
170
+ | `onSend` | `(mission, plan) => void \| Promise` | | Отправка миссии, `mission` — текст QGC WPL 110 |
80
171
  | `label.name` | `string` | | Заголовок. Пусто — «Карта» на языке пользователя |
81
172
  | `wrapperClass` | `string` | `""` | Классы обёртки |
82
173
  | `componentClass` | `string` | `""` | Мастер-цвет `bg-*` шапки |
@@ -87,14 +178,20 @@ Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", dev, sizeof(dev)
87
178
 
88
179
  ```svelte
89
180
  <UI.WidgetMap groups={["MAV", "GNSS"]} value={{ MAV: mav, GNSS: gnss }} height={400} trackEnabled />
181
+
182
+ <UI.WidgetMap mode="route" bind:route groups={["MAV"]} value={{ MAV: mav }} onSend={(mission) => sendToDevice(mission)} />
183
+
184
+ <UI.WidgetMap mode="agro" bind:plan groups={["MAV"]} value={{ MAV: mav }} onSend={(mission) => sendToDevice(mission)} />
90
185
  ```
91
186
 
92
187
  В DevCloud и WebApp `value` собирает `GUIPreview`: для каждой группы читает переменные `<ModSN>|<группа>.<ключ>`.
93
188
 
94
189
  ## Панель свойств (WidgetMapProps.svelte)
95
190
 
96
- В конструкторе задают заголовок, группы через пробел, мастер-цвет, высоту карты (S, M, L, XL: 250, 400, 600, 800 пикселей), иконку маркера и начальные значения траектории.
191
+ В конструкторе задают режим («Объекты», «Маршрут» или «Агро»), заголовок, группы через пробел, мастер-цвет, высоту карты (S, M, L, XL: 250, 400, 600, 800 пикселей), иконку маркера и начальные значения траектории. Группы, иконка маркера, траектория и имитация действуют во всех режимах.
97
192
 
98
193
  ## Внутреннее устройство
99
194
 
100
195
  В папке `mapWrapper/` лежат тонкие Svelte-обёртки над MapLibre GL: `MapLibre`, `Marker`, `Popup`, `Line`, элементы управления и `CustomControl` для своих кнопок поверх карты.
196
+
197
+ В папке `mission/` лежат режимы построения миссии: `MapRoute.svelte` и `route.ts` (режим «Маршрут»), `MapAgro.svelte` (интерфейс режима «Агро»), `coverage.ts` (расчёт траектории и выгрузка миссии), `plan.ts` (тип плана и план по умолчанию), `MissionLayers.svelte` (слои карты и перетаскивание точек).