The current design (2023) Main Unit runs on Teensy 3.2 and Teensy 4.0 boards. These are based on ARM Cortex processor, with peripherals (UART, timer, SPI, etc.). The stepper controllers are TMC2130 or TMC2160 from Trinamic in STEP/DIR mode.
The software is built with the Arduino framework (setup / loop) and consists of 3 main parts: the Main Loop, the Timer Loop and the Motor Interrupts. Without an operating system, it relies on global variables. To prevent concurrent variable accesses between the 3 contexts, it disables interrupts (cli / sei).
The Main loop runs every 10mS (sidereal). It polls for commands from both UARTs (SHC and USB), which handle identical commands based on the LX200 standard (Goto, track, guide etc) with proprietary extensions. It computes the positions and speeds of both axes, then checks for safety limits.
Positioning Mode (Goto)
Much of the code is common between Eq and Altaz mounts.
The simplified call sequence for a Goto RA/Dec command is as follows:
GotoEqu(HA, Dec) // LX200 command EquToHor(HA, Dec) // computes target Az/Alt goToHor(Az, Alt) // can also be called directly by LX200 command toInstrumentalDeg(Az, Alt) // matrix operation that computes axes positions as floating-point degrees predictTarget() // converts degrees to steps (long integers), taking into account the gear ratio Angle2InsrtAngle // corrects positions according to pier side if needed Goto(Axis1, Axis2) // check for errors, then sets targets for both axes
For retrieving current RA/Dec:
getEqu() // LX200 command :GR#, :GD# getHorApp() // retrieves axis positions in steps and converts to degrees toReferenceDeg() // matrix operation - converts axis degrees to sky Az/Alt HorTopoToEqu() // converts Az/Alt to HA/Dec
Mapping sky coordinates to axis angles
The difference between Eq and AltAz mounts is handled inside the alignment matrix operations (toInstrumentalDeg / toReferenceDeg) based on Toshimi Taki's 2004 paper. At initialization, the alignment matrix is initialized as follows:
- for AltAz mounts, Axis1 is Azimuth reversed by 180º, Axis2 is Altitude, so that in the Home position the optical tube is horizontal, pointing South.
- for Eq mounts, it converts Axis1/Axis2 to Altitude and Azimuth, so that in the Home position the optical tube points to the celestial pole.
The idea is to perform all Goto with the same (AltAz) code.
This simplifies somewhat the design, but it hides the amount of conversions going on behind the scenes (see tracking section below)
Mapping axis angles to steps
This mapping is not one-to-one: The same position (in steps) may represent 2 different axis angles, according to the hemisphere. This also applies to the direction of tracking.
The motor reverse bit is handled at the very lowest level so that the whole software uses the same coordinates for direct and reverse directions.
Slewing or centering is triggered by pressing direction keys. It moves the mount at predefined speeds in any direction, without a target. This is the call sequence:
MoveAxis1/2 // LX200 command MoveAxis1/2atRate (rate) // directy sets the motor timers
Tracking does not use a fixed velocity for the RA axis, but repeated positioning mode on a moving pseudo-target. For an Eq mount, it goes like this:
computeTrackingRate // :Te# LX200 command. This enters the tracking mode called by the main loop: do_compensation_calc() // Computes positions behind and ahead of the current position: for each position getEqu() getHorApp() // retrieves RA/Dec axis positions in steps and converts to degrees toReferenceDeg() // converts axis degrees to sky Az/Alt - matrix operation horAppToEqu() // convert Az/Alt to RA/Dec - trig operation equToHor() // convert RA/Dec to Az/Alt - trig operation toInstrumentalDeg() // convert Az/Alt to RA/Dec axis degrees - matrix operation instrtoStep() // axis degrees to steps compute difference between the 2 axis positions, derive a speed then set the motor timers
Guiding for astrophoto is performed either by signals on the ST4 connector emulating button presses, or by software commands. It increases or decreases the tracking speed on both axes.
The code is somewhat confusing because the term is used both for centering (SHC button presses) and for automatic guiding via software (PHD2 etc.)
enableST4GuideRate() // :Mgdnnnn# Pulse guide command PerformPulseGuiding() apply_GuidingA1() // modify the tracking pseudo-target
The timer loop is triggered by a hardware timer that runs every 10mS (sidereal). From the current mode (Goto, track, guide etc.) it computes and programs the periods (rates) for both motor interrupts.
There is one motor interrupt handler for each axis motor. Each one runs at a period determined by the axis speed and controls the STEP and DIR inputs of the TMC motor controller.