Telescope Control Library
Axis.h
- Committer:
- caoyu@caoyuan9642-desktop.MIT.EDU
- Date:
- 2018-09-24
- Revision:
- 19:fd854309cb4c
- Parent:
- 10:e356188d208e
File content as of revision 19:fd854309cb4c:
/* * Axis.h * * Created on: 2018��2��24�� * Author: caoyuan9642 */ #ifndef PUSHTOGO_AXIS_H_ #define PUSHTOGO_AXIS_H_ #include "StepperMotor.h" #include <math.h> #include "mbed.h" #include "CelestialMath.h" #include "TelescopeConfiguration.h" #include "PEC.h" //#define AXIS_SLEW_SIGNAL 0x00010000 #define AXIS_GUIDE_SIGNAL 0x00020000 #define AXIS_STOP_SIGNAL 0x00040000 #define AXIS_EMERGE_STOP_SIGNAL 0x00080000 #define AXIS_STOP_KEEPSPEED_SIGNAL 0x00100000 #define AXIS_SPEEDCHANGE_SIGNAL 0x00200000 /** * status of the Axis object */ typedef enum { AXIS_STOPPED = 0, AXIS_SLEWING, AXIS_TRACKING, AXIS_INERTIAL } axisstatus_t; typedef enum { AXIS_NOT_SLEWING, AXIS_SLEW_ACCELERATING, AXIS_SLEW_CONSTANT_SPEED, AXIS_SLEW_DECELERATING } axisslewstate_t; /** Define the rotation direction * AXIS_ROTATE_POSITIVE: +angle * AXIS_ROTATE_NEGATIVE: -angle */ typedef enum { AXIS_ROTATE_STOP = 0, AXIS_ROTATE_POSITIVE = 1, AXIS_ROTATE_NEGATIVE = 2 } axisrotdir_t; typedef enum { FINISH_COMPLETE = 0, FINISH_STOPPED = 1, FINISH_EMERG_STOPPED = 2, FINISH_ERROR = 4 } finishstate_t; class PEC; /** General Rotating Axis class * Handles low-level stepper timing, calculates the speed and distance to rotate * API provides comprehensive slewing, tracking and guiding. */ class Axis { public: /** * Create a RotationAxis object * @param stepsPerDeg Steps per degree of the stepper motor * @param stepper Pointer to stepper driver to use * @param name Name of the axis, for example "RA" or "DEC" */ Axis(double stepsPerDeg, StepperMotor *stepper, const char *name = "Axis"); virtual ~Axis(); friend class PEC; /** * Asynchronously perform a goto to a specified angle (in degrees) in the specified direction with slewing rate * @param dir Rotation direction * @param angleDeg Angle to rotate * @param withCorrection Use correction or not. If false, the mount will roughly slew to the target. A further correction step is needed (slewed again) if precision positioning is needed. Useful * for long slews where the target would have changed during the slew. * @return osStatus */ osStatus startSlewTo(axisrotdir_t dir, double angle, bool withCorrection = true) { msg_t *message = task_pool.alloc(); if (!message) { return osErrorNoMemory; } message->signal = msg_t::SIGNAL_SLEW_TO; message->value = angle; message->dir = dir; message->withCorrection = withCorrection; osStatus s; debug_if(0, "%s: CLR SLEW 0x%08x\n", axisName, Thread::gettid()); slew_finish_sem.wait(0); // Make sure the semaphore is cleared. THIS MUST BE DONE BEFORE THE MESSAGE IS ENQUEUED if ((s = task_queue.put(message)) != osOK) { task_pool.free(message); return s; } return osOK; } /** * Wait for a slew to finish. Must be called after and only once after a call to startSlewTo, from the same thread * @return Finish state of the slew, signaling whether there are errors or being stopped/emergency stopped */ finishstate_t waitForSlew() { debug_if(0, "%s: WAIT SLEW 0x%08x\n", axisName, Thread::gettid()); if (slew_finish_sem.wait() <= 0) { return FINISH_ERROR; } // Check mount status return slew_finish_state; } /** * Synchronously perform a goto to a specified angle (in degrees) in the specified direction with slewing rate * It will perform an acceleration, a GoTo, and a deceleration before returning * @param dir Rotation direction * @param angleDeg Angle to rotate * @return osStatus * @sa{startSlewTo} */ osStatus slewTo(axisrotdir_t dir, double angle) { osStatus s; if ((s = startSlewTo(dir, angle)) != osOK) return s; return waitForSlew(); } /** Perform a indefinite slewing, until stop() is called * @param dir Direction to start continuous slewing * @return osStatus * @sa{stop} */ osStatus startSlewingIndefinite(axisrotdir_t dir) { msg_t *message = task_pool.alloc(); if (!message) { return osErrorNoMemory; } message->signal = msg_t::SIGNAL_SLEW_INDEFINITE; message->dir = dir; message->withCorrection = false; osStatus s; if ((s = task_queue.put(message)) != osOK) { task_pool.free(message); return s; } return osOK; } /** Start tracking, until stop() is called * @param dir Direction to start continuous slewing * @return osStatus * @sa{RotationAxis::stop} */ osStatus startTracking(axisrotdir_t dir) { msg_t *message = task_pool.alloc(); if (!message) { return osErrorNoMemory; } message->signal = msg_t::SIGNAL_TRACK; message->dir = dir; osStatus s; if ((s = task_queue.put(message)) != osOK) { task_pool.free(message); return s; } return osOK; } /** * Guide on specified direction for specified time * @param dir Direction of guiding * @param time_ms Time to guide in milliseconds * @return osStatus */ osStatus guide(axisrotdir_t dir, int time_ms) { if (dir == AXIS_ROTATE_NEGATIVE) time_ms = -time_ms; // Put the guide pulse into the queue osStatus s; if ((s = guide_queue.put((void*) (time_ms))) != osOK) { return s; } task_thread->signal_set(AXIS_GUIDE_SIGNAL); // Signal the task thread to read the queue return osOK; } /** * Remove all queued commands if there are any. This function should be called if you want to ensure the mount if completely stopped */ void flushCommandQueue() { while (!task_queue.empty()) { osEvent evt = task_queue.get(0); if (evt.status == osEventMessage) { task_pool.free((msg_t*) evt.value.p); } } } /** * Stop slewing or tracking. Calling this function will stop the axis from slewing, or tracking * @note In the case of slewing, the axis will perform a deceleration and then stop * @note If there are queued commands, they will be run immediately afterwards */ void stop() { flushCommandQueue(); task_thread->signal_set(AXIS_STOP_SIGNAL); } /** * Perform an emergency stop. This should stop in ALL situations IMMEDIATELY without performing deceleration. * @note this call will kill all queued commands, so the mount will be fully stopped */ void emergency_stop() { flushCommandQueue(); task_thread->signal_set(AXIS_EMERGE_STOP_SIGNAL); } /** * Only takes effect when decelerating from a slew. Signals the axis to keep its current speed, and enters AXIS_INERTIAL state. * This state can be exited by performing another slew/slew_indefinite and stopped in the normal way */ void stopKeepSpeed() { task_thread->signal_set(AXIS_STOP_KEEPSPEED_SIGNAL); } /** Set current angle of the axis in degrees. * @param new angle * @note Must be called only when the axis is stopped, otherwise behavior is unexpected */ void setAngleDeg(double angle) { stepper->setStepCount(angle * stepsPerDeg); } /** Returns the current angle of the axis in degrees * @note Can be called in any context */ double getAngleDeg() { return remainder(stepper->getStepCount() / stepsPerDeg, 360); } /** Returns the axis status */ axisstatus_t getStatus() { return status; } /** Returns the current slew speed (only for indefinite slew) */ double getSlewSpeed() const { return slewSpeed; } /** Set slew speed of the axis (only for indefinite slew) * @param new slew speed in deg/s * @note Can now be called when a indefinite slew is in progress. * @note If called during a target slew, the speed will be updated on the next slew */ void setSlewSpeed(double slewSpeed) { if (slewSpeed > 0) this->slewSpeed = slewSpeed; task_thread->signal_set(AXIS_SPEEDCHANGE_SIGNAL); // Signal the thread to use the new speed during a indefinite slew } /** * Returns track speed of the axis in units of sidereal speed */ double getTrackSpeedSidereal() const { return trackSpeed / sidereal_speed; } /** Set track speed in sidereal speed * @param new track speed in sidereal rate * @note Must be called only when the axis is stopped */ void setTrackSpeedSidereal(double trackSpeed) { if (trackSpeed >= 0) { this->trackSpeed = trackSpeed * sidereal_speed; } } /** * Returns guide speed of the axis in units of sidereal speed */ double getGuideSpeedSidereal() const { return guideSpeed / sidereal_speed; } /** @param new guide speed in sidereal rate. * @note If called when a pulse guide is being performed, the value will be updated on the next pulse */ void setGuideSpeedSidereal(double guideSpeed) { if (guideSpeed > 0) this->guideSpeed = guideSpeed * sidereal_speed; } /** * Returns current speed (deg/s) of the axis */ double getCurrentSpeed() const { return currentSpeed; } /** * Returns which phase of slewing the axis is currently in */ axisslewstate_t getSlewState() const { return slewState; } /** * Returns current axis rotation direction */ axisrotdir_t getCurrentDirection() const { return currentDirection; } /** * Return true if a guiding pulse is being performed */ bool isGuiding() const { return guiding; } PEC* getPEC(){ return pec; } void setPEC(PEC* pec) { this->pec = pec; } bool isPECEnabled() const { return pecEnabled; } void setPECEnabled(bool pecEnabled) { this->pecEnabled = pecEnabled; } protected: typedef struct { enum sig_t { SIGNAL_SLEW_TO = 0, SIGNAL_SLEW_INDEFINITE, SIGNAL_TRACK } signal; double value; axisrotdir_t dir;bool withCorrection; } msg_t; /// Message for inter-thread communication /*Configurations*/ double stepsPerDeg; ///steps per degree StepperMotor *stepper; ///Pointer to stepper motor const char *axisName; /// Name of the axis char *taskName; /// Name of the thread /*Runtime values*/ volatile double currentSpeed; /// Current speed in deg/s volatile axisrotdir_t currentDirection; // Current direction double slewSpeed; /// Slewing speed in deg/s (only for indefinite slew) double trackSpeed; /// Tracking speed in deg/s (no accel/deceleration) double guideSpeed; /// Guide speed in deg/s. this amount will be subtracted/added to the trackSpeed volatile axisstatus_t status; /// State of the axis volatile axisslewstate_t slewState; /// Phase of slewing Thread *task_thread; ///Thread for executing all lower-level tasks Queue<msg_t, 16> task_queue; ///Queue of messages Queue<void, 16> guide_queue; ///Guide pulse queue MemoryPool<msg_t, 16> task_pool; ///MemoryPool for allocating messages Semaphore slew_finish_sem; /// Semaphore for signaling finished slew volatile finishstate_t slew_finish_state; /// Finish state of slew Timer tim; /// Timer bool guiding; /// isGuiding PEC *pec; /// PEC bool pecEnabled; /// Is pec enabled void task(); /// Task thread entrance /*Low-level functions for internal use*/ void slew(axisrotdir_t dir, double dest, bool indefinite, bool useCorrection); void track(axisrotdir_t dir); /*These functions can be overriden to provide mode selection before each type of operation is performed, such as microstepping and current setting*/ /// Change low-level mode before slewing virtual void slew_mode() { } /// Change low-level mode before tracking virtual void track_mode() { } /// Change low-level mode before correcting virtual void correction_mode() { } /// Change low-level mode before going idle virtual void idle_mode() { } } ; #endif /* PUSHTOGO_AXIS_H_ */