Tarek Lule / MotorLib

Fork of MotorLib by CreaLab

motor.h

Committer:
sepp_nepp
Date:
2018-11-01
Revision:
15:88fecbdd191c
Parent:
14:f0667bfc2e98
Child:
16:d818c1a4dafb

File content as of revision 15:88fecbdd191c:

/**
 * @file motor.h
 * @brief File containing Crealab Motor Library.
 
 * motor.h contains the class Motor, and related enums and structs.
 * Includes only "mbed.h"
 * Doxygens Tags are words preceeded by either a backslash @\ or by an at symbol @@.

 * @author Tarek Lule, Francois Druilhe, et al.
 * @date 01. Nov. 2018.
 * @see https://os.mbed.com/users/sepp_nepp/code/MotorLib/  */
 
 // -------------------- Motor ---------------------------
#ifndef MOTOR_H
#define MOTOR_H

#include "mbed.h"

#define MOTOR_STEP_TIME_MIN_US 700      // was MOTOR_STEP_TIME_MIN
#define MOTOR_STEP_TIME_DEFAULT_US 5000 // was MOTOR_STEP_TIME_DEFAULT
#define MOTOR_STEPS_FOR_A_TURN 4096

/** \enum motorStates 
* \brief Motor States of motor state machine
* 
* Motor_CALIB is deprecated, was removed from the enum structure */
typedef enum {
    Motor_OFF = 0,  /**< All phase currents is off, replaces Motor_STOP. */  
    Motor_ZERO,     /**< Motor at phase position 0 and ON, only reached by call of Zero() command. */  
    Motor_ON,       /**< Phases are engaged, but motor is not running, replaces Motor_PAUSE. */  
    Motor_RUN       /**< Phases are engaged, and motor state machine is running*/  
} motorStates;

/** \enum motorCommands 
* \brief Commands that are handled by the Motor state machine
* 
* These Commands are issued asynchonously by calling Motor class methods.
* They are executed in the state machine called by the ticker handler.

* OFF and STOP commands do not go through the state machine.

* MOTOR_restart is equivalent to and replaced by MOTOR_run.
*/
typedef enum { // Define Motor State Machine Commands
    MOTOR_nop = 0,  /**< No active command to execute. */
    MOTOR_run,      /**< Run Motor until Nsteps are achieved. */
    MOTOR_stop,     /**< Stop immediately all activity, turn off Motor. */
    MOTOR_pause     /**< Motor is temporarily paused from the state run. */
} motorCommands;

/** \enum motorDir 
* \brief Define Motor direction to be Clockwise or Anticlockwise 
*/
typedef enum motorDir {
    CLOCKWISE = 0,      /**< Turn Motor in clockwise direction. */
    COUNTERCLOCKWISE    /**< Turn Motor in anti-clockwise direction. */
} motorDir;

/** \struct MotStatus
* \brief Structure of Motor Status registers
* Is used by Motor Class to hold all Status 'Registers'. 
* The structure can be requested to get by Motor.getStatus(). */
typedef struct {
    motorStates  state; /**< General state that the moter state machine is in.*/
    motorCommands cmd;  /**< Command asked to be executed currently by the state machine.*/
    motorDir      dir;  /**< Direction that the motor is asked to run.*/
    int32_t       NSteps;/**< Number of steps left for the motor to run. 
    NSteps=0: all steps finsihed; NSteps<0: indicates to run "forever" */
    bool         TickIsAttached; /**< Indicates if Ticker is attached.
    Ticker is automatically attached while Motor is running, or paused; 
    detaches when finished a run, or stopped.  */
    /** Helper to set Command, Direction and NSteps in one call. */
    void set(motorCommands aCmd, motorDir aDir, int32_t  aNSteps);
} MotStatus;

/** ATTENTION UNDER CONSTRUCTION, DO NOT YET USE
* Class of a Four Phase Stepper Motor
*Handles single steps but also running a number of steps, or given amount angle.
*
*Higher level function rely on ticker and a state-machine evaluating new incoming commands versus the motor state at every tick.
*
*Callbacks can be attached to react to 'end of run' events. 
*
*Lower level functions directly talk to the hardware without ticker.
*/
class Motor
{
public:
    /** Class Creator. 
    * Receives the names of the 4 Digital Pins in an array of PinNames.
    * the time in between two steps defaults here to MOTOR_STEP_TIME_DEFAULT_US=5000usec.
    * Uses Ticker callback to handle step times.
    * Call this creator for example like this:
    * @code
    *    PinName MotPhases[] = {PB_1, PB_15, PB_14, PB_13};
    *    Motor MotorName(MotPhases);
    * @endcode */
    Motor(PinName _MPh[4] );
    /** Class Creator.
    * receives the names of the 4 Digital Pins.
    *  Uses Ticker callback to handle step times.
    *  the time between two steps defaults here to MOTOR_STEP_TIME_DEFAULT_US=5000usec.
    * Call this creator for example like this:
    * @code
    *    Motor MotorName(PB_1, PB_15, PB_14, PB_13);
    * @endcode */
    Motor(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3);
    /** Class Creator: 
    *  receives the names of the 4 Digital Pins.
    *  Uses Ticker callback to handle step times.
    *  aStepTime_us is the time in usec between two steps, thats used initially. */
    Motor(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3, uint32_t aStepTime_us);
private:
    // void initialization(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3, uint32_t aStepTime_us);
    void initialization(PinName _MPh[4], uint32_t aStepTime_us);
public:
    /** Attach a basic Callback function.
     * @param <mIT> Callback function, not member of a class.
     *  It is only called when a Run Command reaches it's target.
     *  It is not called when the Motor is stopped by calling Stop Function, or any other events.
     * Attention: the attached Callback is called within a Ticker Callback.
     *    Your code you execute in the Callback should be short, must not use waits, or any long routines.
     *    Do not call any motor run commands in the callback, as it creates conflicting situations.
     *    Long Callback code may impair this and any other Ticker functions that are running in your application. */
    void setMotorCallback(void (*mIT)());

    /** Attaching a Callback function, member of a class.
     *  It is only called when a Run Command reaches it's target.
     *  It is not called when the Motor is stopped by calling Stop Function.
     * at note Attention: the attached Callback is called within a Ticker Callback.
     *    Your code you execute in the Callback should be short, must not use waits, or any long routines.
     *    Do not call any motor run commands in the callback, as it creates conflicting situations.
     *    Long Callback code may impair this and any other Ticker functions that are running in your application.
    at note AText
    @code
    // Class Creator:
     AClass::AClass(Class Creation Parameters)
    {   ...
        // Attach callback function:
        MotorInstance->setMotorCallback(this, &AClass::CallBackMemberFunction);
        ...
    }

    // Simple callback function
    void AClass::CallBackMemberFunction()
    {
        endMove=true;
    }
    @endcode
    */
    template<typename T>
    void setMotorCallback(T *object, void (T::*member)(void)) {
        _callback = callback(object,member);
    }

    /** Removing the Callback function that may have been attached previously. */
    void removeMotorCallback();

    /** RunSteps Main Motor Running Function.
    * Runs motor for a number Nsteps>0 of steps; Nsteps<=0 will not be executed.
    * Given Direction can be: CLOCKWISE, or COUNTERCLOCKWISE.
    * Call Pause() or Stop() to pause or end the motor running prematurely.
    * While running: Uses ticker; State = first Motor_ON then Motor_RUN; cmd=MOTOR_run.
    * At the end: calls the Callback, stops ticker; State = Motor_OFF. */
    void RunSteps    (motorDir direction, uint32_t Nsteps);

    /** RunDegrees = Main Motor Running Function.
    * Runs motor for a given angle>0 in degrees; Angles<=0 will not be executed.
    * Given Dicection can be: CLOCKWISE, or COUNTERCLOCKWISE.
    * Call Pause() or Stop() to pause or end the motor running prematurely.
    * While running: Uses ticker; State = first Motor_ON then Motor_RUN; cmd=MOTOR_run.
    * At the end: calls the Callback, stops ticker; State = Motor_OFF; cmd=MOTOR_stop then MOTOR_nop. */
    void RunDegrees  (motorDir direction, float angle);

    /** RunInfinite = Main Motor Running Function:
    * Runs motor "unlimited", more precisely it runs 4Billion Steps.
    * Dicection can be: CLOCKWISE, or COUNTERCLOCKWISE.
    * While running: Uses ticker; State = first Motor_ON then Motor_RUN; cmd=MOTOR_run.
    * Call Pause() or Stop() to pause or end the motor running.*/
    void RunInfinite (motorDir direction);

    /** Pause puts Motor into Pause state, stepping is suspended.
     * Only effective if Status.cmd=MOTOR_run.
     * Retains the number of steps that remain to be run.
     * While pausing: still uses ticker; State = Motor_RUN; cmd=MOTOR_pause.
     * Use Restart(); to continue. */
    void Pause();

    /** Restart continues with the paused stepping activity.
     * Only effective if Status.cmd=MOTOR_pause, otherwise no action.
     * Status afterwards is same as afterRun commands. */
    void Restart();

    /** Stop completely ends any running/stepping activity.
    * Does not call the Callback function.
    * Emits first cmd=MOTOR_stop then cmd=MOTOR_nop.
    * Aftewards: ticker is detached; State = Motor_OFF; */
    void Stop();
    /** Access all motor status registers.
    See documentation of MotStatus Structure.
    @return <MotStatus> The full structure of Motor status registers. 
    */
    MotStatus getStatus();
public: // All the ticker timing related parameters
    /** Get number of Steps per Full turn.
     *  Defaults to MOTOR_STEPS_FOR_A_TURN = 4096.
     *  Needed to translate from degrees to number of steps.
     *  Old Name was: getCalibration, but not good explicit name. */
    uint32_t getStepsFullTurn();

    /** Set number of Steps per Full turn.
     *  Defaults to MOTOR_STEPS_FOR_A_TURN = 4096.
     *  Needed to translate from degrees to number of steps.
     *  Old Name was: setCalibration, but not good explicit name. */
    void setStepsFullTurn(uint32_t StepsFullTurn);

    /** Set the time in microseconds between two motor steps.
     *  Was previously called setStepTime(), but was not clear which units.   */
    void setStepTime_us(uint32_t aStepTime_us);

    /** Set the time in seconds to get one full turn, rotation of 360°.
     * e.g. setRotationPeriodSec( 20.0 ); then motor will do 360° in 20 seconds.
     * was previously called setSpeed().  */
    void setRotationPeriodSec(float Seconds_Per_Turn) ;

private:
    // all the  Ticker and Timing procedures, used to run the motor for a duration
    void StartTick();
    void ProcessMotorStateMachine();
    // The call back function pointer that is called when the Processor
    // State Machine reaches its end.
    Callback<void()> _callback;
    void StopTick();
    MotStatus Status;
    timestamp_t StepTime_us;  // Time in µs for one motor step
    Ticker      MotorSysTick; // System Timer for Motor

public: // all the low level direct motor HW access, States are immediately reached
    /** Turn off all motor Phases, no more current flowing.
     *   Equivalent to what previously the function "void Stop();" did .  */
    void MotorOFF();
    /** Turn on the motor Phase, In the last used phase, memorized in StepPhases
     *  Equivalent to what previously the function "void Start();" did.  */
    void MotorON();
    /** Motor phases turned on and put to Zero Position. */
    void MotorZero();
    void TestMotor();
private:
    /** Motor advances one step rotating in direction of variable direction. */
    void StepOnce();
    /** Motor advances one step rotating left. */
    void StepLeft();
    /** Motor advances one step rotating right. */
    void StepRight();
    /** Engage Motor Phases according to MotorIndex. */
    void SetPhases(); // Engage Motor Phases according to StepPhase

    DigitalOut *MPh[4];       // Digital outputs, one per phase
    int        StepPhase;     //  Motor Phase Variable, counts up and down with every step
    uint32_t   Steps_FullTurn;// Number of step for a complete turn

private: /* Deprecated, unused members of the class
    void SetDirection(motorDir direction); // direction is set anyway by all the other commands
    Timer tuneTimings;
    uint32_t last;
    */
};

#endif