Управление моторами SkyWatcher

Этим летом мне удалось пару раз выбраться на природу вместе с поворотным устройством SkyWatcher AllView. И я в очередной раз убедился, что текущая схема подключения слишком хлопотная и ненадежная: сначала нужно подключить моторы к пульту управления SynScan, а потом отдельным USB кабелем подключить SynScan к Raspberry. При этом все эти USB контакты шатаются, их сдувает ветром, они короткие и их нужно подключать в определённой последовательности. Именно поэтому я решил сделать ещё один заход на прямое подключение к моторам. В прошлый раз я купил не тот провод и спалил плату контроллера. В этот раз я решил сделать всё аккуратно и осторожно.

EQDIR

Насколько я понял, моторы всех поворотных устройств SkyWatcher управляются по протоколу RS232. В одних используется разъём RJ11, в других - RJ45. Для RS232 нужно всего три контакта, поэтому нужно быть предельно внимательным какие контакты обжаты в RJ11. Оказывается, умельцы в Интернете уже разобрались и продают эти провода под кодовым названием EQDIR. Они стоят дороже обычных, но зато гарантированно совместимы с моторами SkyWatcher.

Помимо особенного RJ11, со стороны USB разъёма стоит чип FT232. Он отвечает за конвертацию USB протокола в RS232 и работает с уровнями сигнала ±5В. Это важно, потому что 3.3В недостаточно.

Протокол

После подключения Linux должен определить чип и создать TTY устройство.

$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

К нему можно подключиться следующей командой:

screen /dev/ttyUSB0 9600

Протокол работы с моторами текстовый и его описание можно найти на официальном сайте.

Например, получить версию прошивки можно следующей командой:

:e1\r
=020EA0\r

Основных отличий от протокола SynScan два:

  • Каждый мотор управляется отдельно
  • Позиция задаётся тиками шагового двигателя, а не углами

Несмотря на кажущуюся простоту, детали описаны крайне плохо. Например, совершенно непонятно, что такое CW и CCW. Чем отличается “Coarse GOTO” от “Normal GOTO”? Я попытался задать нужные команды, но моторы двигались очень медленно. Я не стал рисковать, боясь опять спалить контроллер, поэтому решил включить осциллограф и посмотреть какие команды отсылает пульт SynScan.

Анализ протокола с помощью осциллографа

Обычно для анализа протокола разрезают кабель и параллельно подключают щупы осциллографа. Мне совсем не хотелось портить дорогой кабель, поэтому я решил использовать два разъёма RJ11.

1 5 10 15 20 1 5 10 15 20 A B C D E F G H I J RX TX GND

К одному разъёму подключается SynScan. К другому - провод RJ11, который уже втыкается в поворотное устройство. Щупы осциллографа подключаются к дорожкам на макетной плате.

Как только всё подключено, нужно выбрать декодирование RS232 и попробовать выполнить любую команду:

На скриншоте выше я запросил версию прошивки первого мотора. Согласно протоколу SynScan - это последовательность байт: (byte) 'P', 1, 16, (byte) 254, 0, 0, 0, 2, которую SynScan, согласно осциллографу, преобразовал в :e1\r.

Кстати, уровни сигнала выглядят крайне необычно для RS232. Оказывается пульт передаёт данные уровнями 0 и 5В, а мотор отвечает 0 и 3.3В.

Итак, схема подключения работает. Можно попробовать по-переключать скорости.

Обычный GOTO

SynScan: B071C,071C

Мотор №2:

:K2\r		// Stop motion
:f2\r		// Inquire status
:j2\r		// Inquire position
:G200\r		// Set motion mode
:S2D75D80\r	// Set GOTO target
:J2\r		// Start motion

Точный GOTO

SynScan: b071C7100,071C7100

Мотор №2:

:K2\r		// Stop motion
:f2\r		// Inquire status
:j2\r		// Inquire position
:G200\r		// Set motion mode
:S2D95D80\r	// Set GOTO target
:J2\r		// Start motion

На самом деле ничем не отличается от “Обычного GOTO”, кроме того, что более точные углы конвертируются в более точные шаги двигателя. Непонятно, зачем нужно было делать менее точные команды.

Фиксированная скорость

Движение в определённую сторону с заданной скоростью. Скорость задаётся фиксированным числом от 1 до 9. Ниже пример для скорости №5.

SynScan: 'P' 2 16 36 5 0 0 0

Мотор №1:

:K1\r		// Stop motion
:f1\r		// Inquire status
:G111\r		// Set motion mode
:I11F0000\r	// Set step period
:J1\r		// Start motion

Заданная скорость

Движение в определённую сторону с заданной скоростью. Скорость задаётся в угловых секундах в секунду. Вот пример запроса для движения со скоростью 150 угловых секунд в секунду в положительную сторону:

SynScan: 'P' 3 16 6 2 88 0 0

Мотор №1:

:K1\r		// Stop motion
:f1\r		// Inquire status
:G110\r		// Set motion mode
:I1C70000\r	// Set step period
:J1\r		// Start motion

Получается, чтобы быстро двигать моторы нужно дополнительно слать “:G200\r”. Как только я переключил всё обратно на прямое подключение с помощью EQDIR, всё заработало как нужно.

Hamlib

r2cloud не работает напрямую с поворотными устройствами. Вместо этого используется промежуточный сервис rotctld(часть проекта Hamlib), который абстрагирует их за единым API. Соответственно, следующим шагом стало добавление протокола в этот проект.

На удивление весь процесс оказался простым и быстрым. Во-первых, мне удалось без особых проблем скопилировать проект под Mac и протестировать. Во-вторых, в Hamlib есть специальная папка rotators, где лежат реализации протокола для разных поворотных устройств. Достаточно было скопировать любой существующий и переименовать в нужных местах. Из интересного, я добавил кэширование CPR (Counts Per Revolution), чтобы уменьшить количество команд и увеличить скорость работы.

После компиляции подключиться можно следующим образом:

./tests/rotctl --model=2801 --rot-file=/dev/cu.usbserial-A10M67FQ

После чего, в появившемся терминале можно выполнять команды:

Rotator command: \get_info
Info: V020EA0

Rotator command: \get_pos
Azimuth: 0.00
Elevation: 0.00

Rotator command: \set_pos 0.0 0.0

Как только я тщательно протестировал код, пришло время создавать Pull Request. Но и тут я был приятно удивлён: он был смержен буквально на следующий день без единого комментария. Ура!

Результат

Для финального результата осталось совсем немного: