Точное управление антенной с помощью 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Ггц.