Telescope Section
-----------------
The Telescope section of Poco deals with where the telescope is
pointing now, where it should be pointing, and how to get it from pointing
where it is now to where it should be. It also contains code to control
dome rotation and verify that moves will not damage the telescope.
The Telescope section is represented by the CTelescope and CAxis
classes. The CTelescope class is responsible for conversions between
encoder values all the way to celestial coordinates, everything in-between,
and all the way back again. Each instance of the CAxis class is responsible
for controlling motion on one axis of the telescope, including the dome
rotation.
There are several coordinate systems to use when pointing a telescope,
Poco keeps track of several. These are:
Mean Position - This is the position as read from a star catalog. These
include an epoch, but Poco can only deal with one epoch at a time.
This set of coordinates is also referred to as Celestial position.
This includes the guide camera correction.
Apparent Position - This the mean position corrected for precession,
nutation, and aberration.
Observed Position - This is the position that the encoders describe
in hour angle and declination (Apparent position corrected for
refraction, or the mechanical position corrected by the pointing
model.)
Mechanical - The raw encoder position in radians, XX and YY.
In addition, Poco tracks different sets of these coordinates. One for where
the telescope is, (the current position), and another for where the telescope
should be pointing, (the desired position). After doing a full set of
calculations, Poco has values for all the coordinate positions for both
desired and current position sets. It then uses these values to change the
position of the telescope.
The algorithm to control telescope movement resembles the following
pseudo code.
void CTelescope::controlInfoUpdate()
{
store last desired positions so desired velocity can be calculated
get the time difference between the last position reading and
the current position reading. (deltaTime)
if (this is the first position read from Control)
{
set desiredXX and desiredYY positions equal to the current XX and YY
positions to keep the telescope from moving at startup
}
cal m_sla.calcPrep() to build the matrix for mean to apparent,
apparent to observed, observed to apparent, and
apparent to mean conversions.
call convertCoordinates(&m_Current, m_tvCurrentRead, MECtoCEL) to
calculate all current coordinates based on the encoder readings
XX and YY. m_tvCurrentRead is the time the current position
information was read from Control.
if (tracking is on)
{
set PID loop target to RA and Dec (celestial coords)
add joystick corrections to m_Desired.RA and m_Desired.Dec
call convertCoordinates(&m_Desired, m_tvCurrentRead, CELtoMEC) to
calculate all desired coordinates based on RA and Dec. Most
importantly, we need desired XX and desired YY
} else (not tracking)
{
set PID loop target to XX and YY (mechanical coords)
add joystick corrections to m_fDesiredXX and m_fDesiredYY
call convertCoordinates(&m_Desired,m_tvCurrentRead, MECtoCEL) to
calculate all desired coordinates based on desired XX and YY
}
calculate desired velocities for X and Y axes
(desiredVelXX, desiredVelYY)
if (auto_dome)
calculate dome position.
tell each axis what it should do. This depends on m_nPaddleInUse
switch (m_nPaddleInUse) {
case CInterface::PAD_DISENGAGED:
{
XAxis->PID(m_Desired.m_fXX, desiredVelXX);
YAxis->PID(m_Desired.m_fYY, desiredVelYY);
ZAxis->PID(desiredDomePos, 0);
}
break;
case CInterface::PAD_ENGAGED:
m_pXAxis->checkPadEngaged();
m_pYAxis->checkPadEngaged();
break;
case CInterface::PAD_SWITCHING:
m_pXAxis->checkPadEngaged();
m_pYAxis->checkPadEngaged();
m_Desired.m_fXX = m_Current.m_fXX + m_pXAxis->coastToStopDistance();
m_Desired.m_fYY = m_Current.m_fYY + m_pYAxis->coastToStopDistance();
convertCoordinates(&m_Desired, m_tvCurrentRead, MECtoCEL);
m_nPaddleInUse = CInterface::PAD_DISENGAGED;
break;
}
pass all position values back to the Interface so it can tell other
processes what's going on.
}
int CTelescope::convertCoordinates(CTelCoordSet *pCoord, structTV tv, int conv)
{
Convert from celestial to mechanical or mechanical to celestial.
switch (conv) {
case CELtoMEC:
calculate all coordinates from celestial (or mean) RA and Dec
subtract the guide camera correction
add in nutation, precession, and aberration errors to
get apparent position.
add in refraction corrections to get observed position.
find XX and YY by using the pointing model
All coordinates for this set should now be defined.
break;
case MECtoCEL:
calculate all coordinates from XX and YY
run through the pointing model to get corrections for sag
and other errors caused by telescope position to get
observed position.
subtract the refraction correction to calculate apparent position
from observed position
subtract the nutation, precession and aberration errors from apparent
position
subtract the guide camera correction to get the celestial (or mean)
position
break;
}
return 0
}
The CTelescope class takes on different approaches to how the telescope
should move depending on if tracking is on or off, and if the paddle or
joystick is being used. If tracking is on, it moves the telescope according to
RA and Dec Values. If tracking is off, it moves the telescope according to XX
and YY values. It is possible to set the telescope position by just about
any of the available variables, but CTelescope then converts them and uses
the resulting RA and Dec or XX and YY to control movement. Or more accurately,
CTelescope passes these values on to the CAxis classes.
The CAxis class controls the telescope movement. There is one CAxis
object for each axis. The CAxis class is very flexible. Nearly all of its
parameters can be set in a configuration file and loaded at runtime. For the
Nickel telescope, the axes are configured to work with high speed slew motors
for large adjustments and low speed stepper motors for fine movements and
tracking. This same class can be used for dome control (where the dome has
only high speed slew motors) by setting the size of the window were the guide
motors take over to zero.
The CAxis class uses a mix of a PID loop for guide motor control and
a power level control scheme to control the slew motor. The whole algorithm
looks like this
CAxis::PID(desiredPos, desiredVel)
{
Force desiredPos to be within telescope movement limits.
deltaTime = most_recent_read_time - previous_read_time
if (ActiveMotorSystem == SLEWMOTOR ||
ActiveMotorSystem == SWITCHINGTOGUIDE)
{
Calculate the direction telescope needs to move.
if (moving in the wrong direction)
{
if (currentPos is within guide motor range)
{
stop the slew motors
start switching to guide motors.
} else
{
stop the slew motors
}
} else (the telescope is moving in the right direction)
{
if (currentPos is within guide motor range)
{
stop the slew motors.
start switching to guide motors.
} else (the telescope is still far away from where it needs to be)
{
Calculate how far the telescope will drift if power is cut off
(coastDistance)
stopPos = currentPos + coastDistance
if (the slew motor is on)
{
if (stopPos is short of the desiredPos)
{
calculate appropriate slew motor power (slewPower)
turn on slew with slewPower
} else (stopPos will at least reach desiredPos)
{
turn the motor off.
}
}
}
}
} else (active motor system is guide motor)
{
if (desiredPos is outside of guide range)
{
clear epsilonList and deltaTimeList
switch to slew motor
return
}
deltaPos = currentPos - PreviousPos.
add latest deltaTime to deltaTimeList
add latest deltaPos to epsilonList
del