Точное управление антенной с помощью SkyWatcher Allview
Немного повозившись с протоколом SkyWatcher Allview, я понял, что алгоритм управления поворотным устройством можно улучшить. В текущем виде он выглядит следующим образом:
- Каждую секунду
- Рассчитывается положение спутника относительно текущей позиции
- Если оно отличается от предыдущего на заданную дельту (по-умолчанию 5°), то
- Отправляется команда на поворотное устройство с новыми координатами
Этот алгоритм достаточно простой и надёжный, но непонятно 5° - это минимальная ошибка или максимальная? А можно ли придумать такой алгоритм, который наводил бы антенну с точностью меньше одного градуса?
Тестирование
Прежде, чем делать более лучший алгоритм, нужно доказать, что он действительно лучший. А для этого нужно померить. В моём случае я измерял ошибку позиционирования моторов относительно положения спутника. Для этого я придумал следующее:
- Выбрать пролёт одного спутника и эмулировать его в реальном времени
- Запустить алгоритм и контролировать поворотное устройство
- На соседнем потоке раз в 100мс опрашивать позиции моторов и сохранять в файл вместе с текущим временем. 100мс - это в 10 раз больше периода расчёта алгоритма - достаточно, чтобы увидеть задержки протокола и прочие артефакты
- По завершению работы взять время и рассчитать позицию спутника
- Посчитать разницу между позицией мотора и предполагаемой позицией спутника
Текущий алгоритм
Для начала я прогнал текущий алгоритм.
Невероятно большая ошибка в середине из-за того, что поддерживаемый азимут в hamlib сконфигурирован от 0° до 360°. Поэтому вместо того, чтобы двигаться в обратную сторону от 0° до 359.99°, мотор начинается двигаться по часовой стрелке и делает почти полный круг.
С ошибкой угла (elevation) всё выглядит чуть лучше. Она ожидаемо плавает от 0° до чуть больше 5°. Этот небольшой выход за пределы объясняется тем, что в зените угловая скорость максимальна, поэтому пока алгоритм примет решение о движении, спутник пролетает некоторое расстояние.
Точное управление
Основная идея заключается в том, что моторы SkyWatcher Allview постоянно двигаются с некоторой заданной скоростью и таким образом постоянно направляют антенну на спутник. При этом во время пролёта над станцией угловая скорость меняется, поэтому весь интервал нужно разбить на небольшие отрезки, на которых моторы двигаются с разной скоростью.
SkyWatcher Allview позволяет задавать скорость моторов с точностью до секунд дуги в секунду (arcsec/sec), но протокол Hamlib это не поддерживает. Поэтому я решил подключаться к последовательному порту и отправлять команды напрямую из Java.
Помимо разной скорости, нужно ещё учитывать:
- задержки в протоколе между моторами и компьютером. Оба мотора управляются через один провод. Это значит, что один мотор всегда будет получать команды чуть позже и всегда отставать.
- SkyWatcher Allview работает в двух режимах: медленный и быстрый. Чтобы поменять скорость в медленном режиме достаточно лишь отправить новую скорость. А чтобы поменять скорость в быстром режиме, нужно остановить моторы и убедиться, что они остановились, выставить новую скорость и заново запустить моторы. А это несколько команд, каждая из которых добавляет задержку.
- смена направления движения требует полной остановки моторов
Первая версия показывает достаточно хорошие результаты. По крайней мере нет безумного вращения на 360°. Тем не менее, ошибка достаточно большая. Она особенно сильно накапливается, когда спутник подлетает к зениту. Это связано с тем, что я задаю скорость движения, а не абсолютное значение угла.
Чтобы это побороть, я стал добавил следующее условие: если мотор в быстром режиме, то считывать текущий угол, а не брать из предыдущего расчёта.
Результат стал значительно лучше.
Далее я решил попробовать компенсировать задержку в протоколе. Во-первых, положение мотора, которое я считываю каждые 100мс на самом деле устаревает на половину roundtrip. Во-вторых, позицию спутника можно рассчитать не через одну секунду, а через секунду и половину roundtrip.
Визуально не сильно изменилось.
Бонус: влияние TLE
Раз уж я решил плотно заняться точностью наведения антенны, почему бы не померить влияние TLE. Чем старше TLE, тем они менее точные. Но насколько менее точные? Для этого я:
- нашёл ближайший пролёт спутника
- посчитал азимут и угол на каждом 10-секундном интервале. Это будут эталонные позиции.
- а потом посчитал позицию спутника для всё более и более старых TLE и вычел их из эталонной
Результат получился следующий:
На графике видно, что TLE трёхдневной давности дают ошибку всего лишь в ~2°. Такая точностью вполне подходит для большинства спутников. Но уже T-7 (TLE полученные 7 дней назад) дают около 15°, что может сильно повлиять на приём сигнала.
Заключение
В результате всех оптимизаций мне действительно удалось придумать алгоритм, который управляет антенной с точностью до градуса. Даже для пролётов около зенита - самый сложный участок для AzEl моторов.
Но с другой стороны, чтобы внедрить этот алгоритм в r2cloud, нужно расширить протокол hamlib и учитывать особенности каждого мотора. На практике - это достаточно хлопотно и ценность сомнительна. Точность в 5° достаточна для большинства спутников. Например, Discovery Dish диаметром 70см можно наводить с точностью в ~18°, чтобы принять сигнал на частоте 1.6Ггц.