Проект собирает гибридную монтировку из двух физических осей и публикует наружу один LX200-совместимый endpoint:
- RA управляется через SynScan/SkyWatcher backend;
- DEC управляется через самодельный контроллер на Arduino + TMC2209;
- клиент (
INDI,KStars,Ekos) видит это как одну монтировку.
Текущая архитектура построена вокруг связки LX200SimpleServer -> SkyLX200 -> Combiner -> AxisRA/AxisDEC -> Motor backends.
LX200 client
-> LX200SimpleServer
-> LX200Handler.handle()
-> SkyLX200
-> Combiner
-> AxisRA
-> SkyWatcherMotor
-> SerialLine
-> AxisDEC
-> TMC2209Motor
-> SerialLine
-> PolarCompensator
Отдельно существует HTTP monitor infrastructure:
MonitorMixin objects
-> MonitorRegistry
-> MonitorRequestHandler / ThreadingHTTPServer
-> SSE + static UI
В src/__main__.py web server сейчас запускается отдельно и с пустым registry, то есть это заготовка инфраструктуры, а не полноценный production monitor.
Точка сборки текущего runtime:
- ищет serial-устройства;
- создаёт
SkyWatcherMotorиTMC2209Motor; - оборачивает их в
AxisRAиAxisDEC; - соединяет оси через
Combiner; - создаёт
SkyLX200; - поднимает
LX200SimpleServer; - параллельно стартует
MonitorServer, но без зарегистрированных monitor objects.
LX200SimpleServer поднимает TCP-сервер и работает на уровне байтового протокола LX200:
- принимает поток команд
:<cmd>#; - отдельно обрабатывает alignment query (
0x06); - декодирует команду и передаёт её в
lx200.handle(...); - сериализует ответ обратно в LX200-формат.
Сервер не знает ничего о конкретной механике RA/DEC, но пока ещё допускает несколько одновременных клиентов на одном handler instance.
Протокольный и доменный слой LX200.
Содержит:
LX200Commandsс поддерживаемыми командами;- базовый контракт
LX200Base; LX200Handler, который:- хранит target RA/DEC;
- парсит LX200-команды;
- маршрутизирует команды в доменные методы;
- ведёт список активных manual-move направлений для
Qe/Qw/Qn/Qs.
Этот файл больше не содержит отдельного axis-specific handler слоя: общая логика оси живёт в src/sky/axis.py.
SkyLX200 является адаптером между LX200-командами и двухосевой моделью Combiner.
Он:
- проксирует
connect()/stop()вCombiner; - читает и синхронизирует координаты;
- запускает
goto_to(...); - переключает preset-скорости guide/center/find/max;
- маршрутизирует ручные движения и guide pulse-команды по направлениям.
Combiner связывает RA и DEC оси в одну логическую монтировку.
Ответственность:
- объединять
AxisRAиAxisDEC; - отдавать общую позицию
PointCoordinates; - запускать
goto_to,move,halt_*,set_sky_speed; - пересчитывать guide speed по длительности pulse;
- координировать
PolarCompensator.
PolarCompensator в текущем коде не просто хранит смещение полюса, а использует повторяющиеся guide-команды как вход для оценки ошибки полярного выравнивания и затем возвращает corrective speeds обратно в Combiner.set_sky_speed(...).
Здесь живёт фактическое общее ядро RA/DEC.
Axis:
- хранит логическую позицию mount;
- хранит текущую целевую sky-speed;
- держит очередь
AxisCommand; - запускает фоновый
_motion_convertorthread; - переводит доменные команды (
change_speed,move,goto_to,halt_*) в операции мотора; - периодически компенсирует логическую координату по фактическому смещению мотора.
Есть две конкретные реализации:
AxisRAповерхHa/HaPerSecond;AxisDECповерхDec/DecPerSecond.
Текущая модель оси не оформлена как отдельная state machine таблица. Поведение строится вокруг:
- текущего
AxisMotionMode; - очереди команд;
- блокировки мотора;
- фоновой компенсации позиции при отсутствии новых команд.
Низкоуровневый драйвер SkyWatcher/SynScan RA-мотора.
Он отвечает за:
- serial-команды mount controller;
- чтение статуса и позиции;
- run-mode и goto-mode;
- конвертацию между шагами и
Ha; - выбор low-speed / high-speed режимов.
Низкоуровневый Python backend для DEC-контроллера на Arduino.
Он отвечает за:
- line-based serial protocol;
- парсинг статуса
phase/mode/position/...; - команды
position,speed,acceleration,direction,delta,run,stop,mode,set; - конвертацию между шагами и
Dec.
Общий serial transport:
- поиск устройства по шаблону;
- line-based запросы с timeout;
- reconnect/reset helper-методы для железа.
Доменные типы и арифметика:
Ha,Dec,AxisPos;HaPerSecond,DecPerSecond,Second;- parsing / formatting / wrapping;
- инварианты для координат и скоростей.
Независимый стек веб-мониторинга:
MonitorField,MonitorAction,MonitorGroup;MonitorMixinдля декларативного описания monitor surface;MonitorRegistryс polling diff loop;MonitorRequestHandlerиMonitorServer;- SSE endpoint
/events; - static UI в
src/web_control/static.
Этот слой существует отдельно от LX200 runtime и пока не подключён к живым объектам в src/__main__.py.
Прошивка Arduino для DEC-контроллера:
- управляет TMC2209;
- исполняет line-based serial protocol;
- экспортирует статус, конфигурацию и команды движения для
TMC2209Motor.
LX200SimpleServer.serve_forever()запускает TCP listener.- Перед входом в accept loop сервер вызывает
sky_lx200.connect(). SkyLX200.connect()делегирует подключение вCombiner.connect().Combiner.connect()подключает обе оси и запускает поток полярной компенсации.
- Клиент отправляет
:<cmd>#. LX200SimpleServerвыделяет команду из byte stream.LX200Handler.handle()превращает первые символы вLX200Commands.LX200Handler._do_handle()вызывает доменный метод.SkyLX200проксирует вызов вCombiner, а тот уже в нужную ось или в обе оси сразу.- Ответ сериализуется назад в LX200-формат.
Sr/Sdтолько обновляют target RA/DEC внутриLX200Handler.CMвызываетsync_telescope(...)с сохранёнными target values.MSзапускаетgoto_to(...), но response path дляMSпока остаётся упрощённым и возвращаетFalse.
Каждая ось хранит:
- логическую mount-позицию (
_ra_position/_dec_position); - последнюю известную позицию мотора;
- текущую sky-speed;
- очередь команд;
- текущий
AxisMotionMode; - служебное состояние для manual move и GOTO.
Движение оси состоит из двух переплетённых путей:
- command path:
- публичные методы кладут
AxisCommandв очередь; _motion_convertorвычитывает команду и выполняет нужную моторную операцию;
- публичные методы кладут
- compensation path:
- когда очередь пуста,
_motion_convertorчитает положение мотора; - сравнивает ожидаемое и фактическое смещение;
- корректирует логическую mount-позицию.
- когда очередь пуста,
Именно поэтому клиент видит не raw encoder state, а логическую координату после компенсации tracking / guide / halt.
- tracking по умолчанию построен вокруг sidereal speed;
- ручное движение east/west меняет скорость относительно tracking;
- SkyWatcher backend сам хранит часть motion state mount'а;
- goto выполняется через delta-based команды mount controller.
- базовый tracking rate обычно
0; - speed является signed относительно north/south;
- backend напрямую управляет
direction,speed,acceleration,mode,run; - goto использует target mode контроллера.
В проекте несколько фоновых потоков:
LX200SimpleServer: отдельный thread на клиента;AxisRAиAxisDEC: по одному_motion_convertorthread на ось;Combiner: thread полярной компенсации;MonitorRegistry: polling diff thread;ThreadingHTTPServer: отдельные HTTP request threads.
Синхронизация строится в основном на:
threading.RLockвокруг операций мотора;queue.Queueдля команд оси;threading.EventвнутриCombinerиPolarCompensator.
По умолчанию pytest собирает только:
src/tests/hwдля hardware/integration сценариев;src/tests/unitsдля быстрых проверок без железа.
src/tests/old содержит архивные тесты и больше не участвует в обычном прогоне.
LX200Handler._do_handle()всё ещё смешивает parsing и command orchestration.- Ответ на
MSпока не оформлен как полноценный LX200 status/result. - Общий status contract для SkyWatcher и TMC2209 ещё не унифицирован.
- При переходе DEC через полюс RA пока не зеркалится на
+12h. - Web monitor пока не связан с живыми runtime object instances в
src/__main__.py.