Telescope Control Library

Dependents:   PushToGo-F429

EquatorialMount.h

Committer:
caoyuan9642
Date:
2018-08-27
Revision:
4:b8ad57bbf9e1
Parent:
2:2ee28add0821
Child:
9:d0413a9b1386

File content as of revision 4:b8ad57bbf9e1:

#ifndef EQUATORIALMOUNT_H_
#define EQUATORIALMOUNT_H_

class EquatorialMount;

#include "Axis.h"
#include "Mount.h"
#include "UTCClock.h"
#include "LocationProvider.h"
#include "CelestialMath.h"

#define MAX_AS_N 10 // Max number of alignment stars

/**
 * Direction of nudge
 */
typedef enum
{
	NUDGE_NONE = 0,
	NUDGE_EAST = 1,
	NUDGE_WEST = 2,
	NUDGE_NORTH = 4,
	NUDGE_SOUTH = 8,

	NUDGE_NORTHWEST = NUDGE_NORTH | NUDGE_WEST,
	NUDGE_SOUTHWEST = NUDGE_SOUTH | NUDGE_WEST,
	NUDGE_NORTHEAST = NUDGE_NORTH | NUDGE_EAST,
	NUDGE_SOUTHEAST = NUDGE_SOUTH | NUDGE_EAST,
} nudgedir_t;

/**
 * Direction of guide
 */
typedef enum
{
	GUIDE_EAST = 1, GUIDE_WEST = 2, GUIDE_NORTH = 3, GUIDE_SOUTH = 4,
} guidedir_t;

/**
 * Object that represents an equatorial mount with two perpendicular axis called RA and Dec.
 */
class EquatorialMount: public Mount
{

protected:
	Axis &ra;   /// RA Axis
	Axis &dec;  /// DEC Axis

	UTCClock &clock; /// Clock

	Mutex mutex_update; /// Mutex to lock position updating
	Mutex mutex_execution; /// Mutex to lock motion related functions

	LocationCoordinates location;   /// Current location (GPS coordinates)
	bool south;	/// If we are in south semisphere
	MountCoordinates curr_pos; /// Current Position in mount coordinates (offset from the index positions)
	EquatorialCoordinates curr_pos_eq; /// Current Position in the equatorial coordinates (absolute pointing direction in the sky)
	nudgedir_t curr_nudge_dir;
	double nudgeSpeed;

	pierside_t pier_side;      /// Side of pier. 1: East
	EqCalibration calibration;
	AlignmentStar alignment_stars[MAX_AS_N];
	int num_alignment_stars;

public:

	/**
	 * Create an EquatorialMount object which controls two axis
	 * @param ra RA Axis
	 * @param dec DEC Axis
	 * @note cone_value, ma_alt, ma_azi,off_ra, off_dec will be init to zero, i.e. assuming a perfectly aligned mount pointing at RA=DEC=0
	 * @note This class assumes that the rotating direction of both axis are correct.
	 *       This should be done using the invert option when initializing the RotationAxis objects
	 * @sa RotationAxis
	 */
	EquatorialMount(Axis &ra, Axis &dec, UTCClock &clk,
			LocationCoordinates loc);
	virtual ~EquatorialMount()
	{
	}

	/**
	 *   Perform a Go-To to specified equatorial coordinates in the sky
	 *   @param  ra_dest RA coordinate in degree.
	 *   @return osOK if no error
	 */
	osStatus goTo(double ra_dest, double dec_dest);
	osStatus goTo(EquatorialCoordinates dest);
	osStatus goToMount(MountCoordinates mc, bool withCorrection = true);
	osStatus goToIndex()
	{
		return goToMount(MountCoordinates(0, 0));
	}

	osStatus startNudge(nudgedir_t);
	osStatus stopNudge();

	osStatus startTracking();
	osStatus stopTracking();

	mountstatus_t getStatus();
	/**
	 * Guide on specified direction for specified time
	 */
	osStatus guide(guidedir_t dir, int ms);

	/*Calibration related functions*/
	
	/**
	 * Clear calibration, use current latitude for the polar axis
	 */
	void clearCalibration()
	{
		num_alignment_stars = 0;
		calibration = EqCalibration();
		calibration.pa.alt = location.lat;
	}
	
	/** 
	 * Clear calibration except axis offsets, use current latitude for the polar axis
	 */
	void clearCalibrationExceptOffsets()
	{
		num_alignment_stars = 0;
		calibration.cone = 0;
		calibration.pa.alt = location.lat;
		calibration.pa.azi = 0;
	}

	/**
	* Get calibration
	* @return Current calibration
	*/
	const EqCalibration &getCalibration() const
	{
		return calibration;
	}
	
	/**
	* Set calibration
	* @param calib New Calibration
	*/
	void setCalibration(const EqCalibration &calib){
		calibration = calib;
	}

	/** @return number of alignment stars
	*/
	int getNumAlignmentStar()
	{
		return num_alignment_stars;
	}

	/** Add an alignment star
	* @return osStatus error if no more star can be added
	*/
	osStatus addAlignmentStar(const AlignmentStar &as)
	{
		if (num_alignment_stars < MAX_AS_N)
		{
			alignment_stars[num_alignment_stars++] = as;
			return recalibrate();
		}
		else
			return osErrorResource;
	}

	/** Remove an alignment star
	* @param index # of star to remove, starting from 0
	* @return osStatus error if no more star can be deleted
	*/
	osStatus removeAlignmentStar(int index)
	{
		if (index < 0 || index >= num_alignment_stars)
		{
			return osErrorParameter;
		}
		for (; index < num_alignment_stars - 1; index++)
		{
			alignment_stars[index] = alignment_stars[index + 1];
		}
		num_alignment_stars--;
		return recalibrate();
	}

	/** Get alignment star
	* @param index # of star to get
	* @return pointer to that alignment star if found, NULL if doesn't exist
	*/
	AlignmentStar *getAlignmentStar(int index)
	{
		if (index < 0 || index >= num_alignment_stars)
		{
			return NULL;
		}
		return &alignment_stars[index];
	}

	/** Replace an alignment star with another
	* @param index # of star to replace
	* @param as new star to add. Will be copied by value
	* @return error if star not found
	*/
	osStatus replaceAlignmentStar(int index, const AlignmentStar &as)
	{
		if (index < 0 || index >= num_alignment_stars)
		{
			return osErrorParameter;
		}
		alignment_stars[index] = as;
		return recalibrate();
	}
	
	/** Force all alignment stars to be perfected aligned according to the current calibration
	* Useful during a polar alignment procedure
	* @note This will throw off all the alignment stars if the error is too big or calibration is wrong
	*/
	void forceAlignment();

	/**
	* Convert EQ coordinates to mount coodinates using current calibration. Utility function
	* @param eq EQ coordinate to convert
	* @return mount coordinates
	*/
	MountCoordinates convertToMountCoordinates(const EquatorialCoordinates &eq)
	{
		LocalEquatorialCoordinates leq =
				CelestialMath::equatorialToLocalEquatorial(eq, clock.getTime(),
						location);
		// Apply PA misalignment
		leq = CelestialMath::applyMisalignment(leq, calibration.pa, location);
		// Apply Cone error
		leq = CelestialMath::applyConeError(leq, calibration.cone);
		// Convert to Mount coordinates. Automatically determine the pier side, then apply offset
		return CelestialMath::localEquatorialToMount(leq, PIER_SIDE_AUTO)
				+ calibration.offset;
	}

	/**
	* Convert mount coordinates to EQ coodinates using current calibration. Utility function
	* @param mc Mount coordinate to convert
	* @return EQ coordinates
	*/
	EquatorialCoordinates convertToEqCoordinates(const MountCoordinates &mc)
	{
		LocalEquatorialCoordinates leq = CelestialMath::mountToLocalEquatorial(
				mc - calibration.offset);
		leq = CelestialMath::deapplyConeError(leq, calibration.cone);
		leq = CelestialMath::deapplyMisalignment(leq, calibration.pa, location);
		return CelestialMath::localEquatorialToEquatorial(leq, clock.getTime(),
				location);
	}


	/**
	* Use alignment stars to recalculate the calibration. 
	* @return osStatus
	*/
	osStatus recalibrate();

	/**
	 * Call emergency stop of the Axis objects
	 * @note This function can be called from any context (including ISR) to perform a hard stop of the mount
	 */
	void emergencyStop();

	/**
	 * Call stop of the Axis objects
	 * @note This function can be called from any context (including ISR) to perform a soft stop of the mount
	 */
	void stopAsync();

	/** BLOCKING. Cannot be called in ISR.
	 * Call stop of the Axis objects and wait until they are stopped.
	 * @note This function can be called from any context (including ISR) to perform a soft stop of the mount
	 */
	void stopSync();

	/**
	 * Get current equatorial coordinates
	 * @return current equatorial coordinates
	 */
	const EquatorialCoordinates &getEquatorialCoordinates()
	{
		updatePosition();
		return curr_pos_eq;
	}

	/**
	 * Get current mount coordinates
	 * @return current mount coordinates
	 */
	const MountCoordinates &getMountCoordinates()
	{
		updatePosition();
		return curr_pos;
	}

	/**
	 * Make an alignment star object using the provided reference star, current mount position, and current time
	 * @param star_ref Reference star position
	 * @return AlignmentStar object representing the alignment star
	 */
	AlignmentStar makeAlignmentStar(const EquatorialCoordinates star_ref)
	{
		updatePosition();
		return AlignmentStar(star_ref, curr_pos, clock.getTime());
	}

	/**
	 * Align the current mount using an array of alignment stars. Support up to 10 stars.
	 * @note If n=1, will only correct for Index offset
	 * If n=2, will correct for index offset and polar misalignment
	 * If n>=3, will correct for index offset, pa misalignment and cone error
	 * @param n # of alignment stars to use
	 * @param as Array of alignment stars
	 * @return osOK if successfully converged and updated the values
	 */
	osStatus align(int n, const AlignmentStar as[]);

	/**
	 * Set slew rate of both axis
	 * @param rate new speed
	 */
	void setSlewSpeed(double rate);
	
	/** @return current slew speed
	*/
	double getSlewSpeed();

	/**
	 * Set tracking speed of RA axis
	 * @param rate new speed in sidereal rate
	 */
	void setTrackSpeedSidereal(double rate);
	
	/** @return current track speed in sidereal units
	*/
	double getTrackSpeedSidereal();

	/**
	 * Set guiding speed of RA axis
	 * @param rate new speed in sidereal rate
	 */
	void setGuideSpeedSidereal(double rate);
	
	/** @return current guide speed in sidereal units
	*/
	double getGuideSpeedSidereal();

	/**
	 * Print current position to stream. 
	 */
	void printPosition(FILE *stream = stdout)
	{
		fprintf(stream, "Mount: RA=%7.2f, DEC=%7.2f %c\n", curr_pos.ra_delta,
				curr_pos.dec_delta,
				(curr_pos.side == PIER_SIDE_WEST) ? 'W' : 'E');
		fprintf(stream, "EQ:    RA=%7.2f, DEC=%7.2f\n", curr_pos_eq.ra,
				curr_pos_eq.dec);
	}

	/**
	* Update current pointing direction from low-level encoders/counters.
	* @note should be called before printing the position using printPosition
	*/
	void updatePosition();

	/** Get current time source
	*/
	UTCClock& getClock() const
	{
		return clock;
	}

	/** @return get current location coodinates.
	*/
	const LocationCoordinates& getLocation() const
	{
		return location;
	}
	
};

#endif /*EQUATORIALMOUNT_H_*/