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