Telescope Control Library

Dependents:   PushToGo-F429

EquatorialMount.h

Committer:
caoyuan9642
Date:
2018-08-19
Revision:
0:6cb2eaf8b133
Child:
2:2ee28add0821

File content as of revision 0:6cb2eaf8b133:

#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();

	/**
	 * 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;
	}

	const EqCalibration &getCalibration() const
	{
		return calibration;
	}

	int getNumAlignmentStar()
	{
		return num_alignment_stars;
	}

	osStatus addAlignmentStar(AlignmentStar as)
	{
		if (num_alignment_stars < MAX_AS_N)
		{
			alignment_stars[num_alignment_stars++] = as;
			return recalibrate();
		}
		else
			return osErrorResource;
	}

	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();
	}

	AlignmentStar *getAlignmentStar(int index)
	{
		if (index < 0 || index >= num_alignment_stars)
		{
			return NULL;
		}
		return &alignment_stars[index];
	}

	osStatus replaceAlignmentStar(int index, AlignmentStar as)
	{
		if (index < 0 || index >= num_alignment_stars)
		{
			return osErrorParameter;
		}
		alignment_stars[index] = as;
		return recalibrate();
	}

	/*Utility functions to convert between coordinate systems*/
	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;
	}

	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);
	}

	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);
	double getSlewSpeed();

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

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

	/**
	 * Print current position to STDOUT. Should call updatePosition to update the current position
	 */
	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);
	}

	void updatePosition();

	UTCClock& getClock() const
	{
		return clock;
	}

	const LocationCoordinates& getLocation() const
	{
		return location;
	}

};

#endif /*EQUATORIALMOUNT_H_*/