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