My Version of the Crealab MotorLib.

Fork of MotorLib by CreaLab

motor.h

Committer:
sepp_nepp
Date:
2019-01-01
Revision:
21:588c5254437d
Parent:
20:492140a08f05
Child:
22:d2c742bdae16

File content as of revision 21:588c5254437d:

/**
 * @file motor.h
 * @brief File contains Crealab Motor Library.
 
 * motor.h contains the class Motor, and related enums and structs.
 * Includes only "mbed.h".
 
 * Rotation directions are now consistently called Clockwise, and Counterclockwise (CCW), 
 * instead of mix them with Left and Right. 
 * Doxygens Tags are 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      /**< Shortest Time between two motor steps = 0.7ms, was MOTOR_STEP_TIME_MIN*/
#define MOTOR_STEP_TIME_DEFAULT_US 5000 /**< Default Time between two motor steps = 5ms, was MOTOR_STEP_TIME_DEFAULT*/
#define MOTOR_STEPS_FOR_A_TURN 4096     /**< Default number of motor steps to complete a turn = 4096 steps  */

/** \enum motorStates 
* \brief Possible 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() procedure. */  
    Motor_ON,       /**< Phases are engaged, but Motor state machine stopped, replaces Motor_PAUSE. */  
    Motor_RUN       /**< Phases are engaged, and Motor state machine runs*/  
} motorStates;

/** \enum motorCommands 
* \brief Commands that are handled by the Motor state machine

* These Commands are issued asynchonously by call 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 {
    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 Gives Motor direction to be Clockwise or Anticlockwise 
*/
typedef enum  {
    CLOCKWISE = 0,      /**< Turn Motor in clockwise direction. */
    COUNTERCLOCKWISE    /**< Turn Motor in anti-clockwise direction. */
} motorDir;

/** \struct MotStatus
* \brief Structure of Motor Status registers.

* 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 motor 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 remain for the Motor to run. 
    NSteps=0: all steps finished; NSteps<0: indicates to run "forever" */
    bool         TickIsAttached; /**< Indicates if Ticker is attached.
    Ticker is automatically attached while Motor runs, or paused; 
    detaches when finished a run, or stopped.  */
    void set(motorCommands aCmd, motorDir aDir, int32_t  aNSteps); /**< Helper; set Command, Direction and NSteps in one call. */
} MotStatus;

/** ATTENTION UNDER CONSTRUCTION, DO NOT YET USE.
*
*Class of a Four Phase Stepper Motor.
*
*Perform Runs for number of steps, or given amount angle, but also Low-Level steps. 
*
*High-Level Run functions have 'Run' in their name.
*They rely on tickers and return immediately after ticker is set up. 
*A state-machine evaluates commands versus the Motor state at every tick.
*When End of Run is detected tickers stop, and Motor turns off. 
*
*Callbacks can be attached to react to 'end of run' 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 conflict situations.
*    Long Callback code may impair this and any other Ticker functions that run in your application.
*
*Low-Level functions directly talk to the hardware without ticker. 
*Use of Low-Level functions while tickers still run may lead to unexpected behavior. 
*/
class Motor
{
public:
    /** Motor Class Creator
    *
    * Creates the class, initiallizes all fields, creates Phase Pins.  
    * Time between two steps defaults here to MOTOR_STEP_TIME_DEFAULT_US=5000usec.
    *
    @code
       PinName MotPhases[] = {PB_1, PB_15, PB_14, PB_13};
       Motor MotorName(MotPhases); // Call this creator for example like this:  
    @endcode 
    * 
    * @param _MPh Array of Names of the 4 Digital Pins of type PinNames 
    */
    Motor(PinName _MPh[4] );
    
    /** Motor Class Creator
    *
    * Creates the class, initiallizes all fields, creates Phase Pins.  
    * Time between two steps defaults here to MOTOR_STEP_TIME_DEFAULT_US=5000usec.
    *
    @code
      // Call this creator for example like this:
       Motor MotorName(PB_1, PB_15, PB_14, PB_13);
    @endcode 
    * 
    * @param <_MPh0, _MPh1, _MPh2, _MPh3> List of Names of the 4 Digital Pins of type PinNames    
    */
    Motor(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3);
    
    /** Motor Class Creator
    *
    * Creates the class, initiallizes all fields, creates Phase Pins.  
    * Time between two steps is passed as parameter.
    *
    @code
      // Call this creator for example like this:
       Motor MotorName(PB_1, PB_15, PB_14, PB_13);
    @endcode 
    *
    * @param <_MPh0, _MPh1, _MPh2, _MPh3> List of Names of the 4 Digital Pins of type PinNames    
    * @param <aStepTime_us> Lthe time in usec between two steps, thats used initially.   
    */
    Motor(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3, uint32_t aStepTime_us);

private:
    // deprecated: 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.
    *
    * Only called when a Run Command reaches it's requested end.
    * Not called when the Motor is stopped by a call of Stop Function, or any other events.
    * For use see precautions at Class description above. 
    * Formerly called setMotorCallback()
    *
    @code
    // Simple callback function, state variable endMove can be polled elsewhere
    void CallBackFunction()
    { endMove=true; }

    // main routine
    void main()
    {   ...
        // Attach callback function:
        MotorInstance->callbackSet(CallBackFunction);
        ...
        while (true) {
            ....
        if (endMove) // poll the endMove flag
               { ... } // react to Movement End
               
            ....
        }
    }
    @endcode
    * @param <*CBfunction> Callback function, must not be member of a class.

    */
    void callbackSet(void (*CBfunction)(void));

    /** Attach a Callback function, member of a class.
    * Only called when a Run Command reaches it's requested end.
    * Not called when the Motor is stopped by a call of Stop Function, or any other events.
    * For use see precautions at Class description above. 
    * @param <*object> Class pointer which possesses callback member.
    * @param <*CBmember> Pointer to callback function, member of Class.
    * 
    @code
    // Class Creator:
     AClass::AClass(Class Creation Parameters)
    {   ...
        // Attach callback function:
        MotorInstance->setMotorCallback(this, &AClass::CallBackMemberFunction);
        ...  
    }

    // Simple callback function, state variable endMove can be polled by main thread
    void AClass::CallBackMemberFunction()
    {  endMove=true;  }
    @endcode
    */
    template<typename T>
    void callbackSet(T *object, void (T::*CBmember)(void)) {
        _callback = callback(object,CBmember);
    }

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

    /** High Level: Run Motor for a number of Steps.
    * 
    * During Run: Uses ticker; State: first Motor_ON then Motor_RUN; cmd=MOTOR_run.
    * Call Pause() or Stop() to pause or end the run prematurely.
    * At the end: calls the Callback, stops ticker; State: Motor_OFF.
    * @param[in] <Direction> Given Direction, can be: CLOCKWISE, or COUNTERCLOCKWISE.
    * @param[in] <Nsteps> Number of steps to run for; must be >0 ; Nsteps<=0 will not be executed.    
    */
   void RunSteps (motorDir Direction, uint32_t Nsteps);

    /** High Level: Run Motor for a given angle
    
    * Runs Motor for a given angle in given direction. 
    * Call Pause() or Stop() to pause or end the Motor run prematurely.
    * While run: Uses ticker; State: first Motor_ON then Motor_RUN; cmd=MOTOR_run.
    * At end: calls attached Callback, stops ticker; State: Motor_OFF; cmd=MOTOR_stop then MOTOR_nop.
    * @param[in] <Direction> Given Direction, can be: CLOCKWISE, or COUNTERCLOCKWISE.
    * @param[in] <angle_deg> Angle>0 to rotate for, in degrees, Angles<=0 are not executed.     
    */
   void RunDegrees  (motorDir Direction, float angle_deg);

    /** High Level: Run Motor "unlimited"
    
    * Runs Motor with out limit in given direction, precisely runs 4Billion Steps.
    * While run: Uses ticker; State: first Motor_ON then Motor_RUN; cmd=MOTOR_run.
    * Call Pause() or Stop() to pause or end the Motor run.
    * @param[in] <Direction> Given Direction, can be: CLOCKWISE, or COUNTERCLOCKWISE.
    */
    void RunInfinite (motorDir Direction);

    /** High Level: Pause a motor Run.
     * Put Motor into Pause state, Run is suspended, but only effective if Status.cmd=MOTOR_run.
     * Retains the number of steps that remain to be run if restarting run.
     * While paused: still uses ticker; State: Motor_RUN; cmd=MOTOR_pause.
     * Use RestartRun(); to continue. */
    void PauseRun();

    /** High Level: Restart a Paused Run.
     * Restart the Run that was launched before calling PuaseRun. 
     * Only effective if Status.cmd=MOTOR_pause, otherwise no re/action.
     * Status afterwards is same as afterRun commands. */
    void RestartRun();

    /** High Level: End any Run.
    * Force stop of any ongoing run, but does not call the Callback function.
    * Only effective if Status.cmd=MOTOR_run, otherwise no re/action.
    * Emits first cmd=MOTOR_stop then cmd=MOTOR_nop.
    * Aftewards: ticker is detached; State: Motor_OFF; */
    void StopRun();
    
public: // All the ticker timing related parameters

    /** MidLevel: Get Motor status
    *
    * Gets the Status of the different internal mechanisms. 
    * See documentation of MotStatus Structure.
    * @return MotStatus The structure of Motor status registers. */
    MotStatus getStatus();

    /** MidLevel: Get number of Steps per Full turn
    
    * Defaults to MOTOR_STEPS_FOR_A_TURN = 4096.
    * Used by RunDegrees() to translate from angle in degrees to number of steps.
    * Old Name was: getCalibration, but that was not a good explicit name. 
    * @return  uint32_t The structure of Motor status registers. */
    uint32_t getStepsFullTurn();

    /** MidLevel: Set number of Steps per Full turn.
    
    * Defaults is MOTOR_STEPS_FOR_A_TURN = 4096.
    * Used by RunDegrees() to translate from degrees to number of steps.
    * Old Name was: setCalibration, but not good explicit name.
    * @param <StepsFullTurn> Number of steps needed to complete a full motor turn
    */
    void setStepsFullTurn(uint32_t StepsFullTurn);

    /** Mid Level: Get the Motor step time. 
    
    * Step time is time between two Motor steps, and is given in microseconds
    * and is passed to the ticker as delay time. 
    * So the larger the value the slower the motor speed.  
    * Defaults to MOTOR_STEP_TIME_DEFAULT_US = 5000.
    * @return  uint32_t The structure of Motor status registers.
    */
    uint32_t getStepTime_us;
    
    /** Set the time in microseconds between two Motor steps.
    *  Defaults to MOTOR_STEP_TIME_DEFAULT_US = 5000usec.
    *  Filters values below Minimum Value = 700.
    *  Passed to the ticker as delay time.
    *  Can be called while ticker is running, and takes immediate effect. 
    *  Was previously called setStepTime(), but was not clear which units.  
    * @param <aStepTime_us> the time in microseconds between two Motor steps
    */
    void setStepTime_us(uint32_t aStepTime_us);

    /** Set the time in seconds to get one full turn, rotation of 360°.
    * was previously called setSpeed().  
    * @param <Seconds_Per_Turn> Period of Rotation, e.g. if =20.0 then Motor will do 360° in 20 seconds.
    */
    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
    uint32_t   Steps_FullTurn;// Number of step for a complete turn

public: // all the low level direct Motor HW access, States are immediately reached

    /** Low Level: Run one full turn clockwise then anticlockwise. 
    * After: State: Motor_OFF.
    * Blocking function, returns back only after end of full movement. 
    */
    void MotorTest();

    /** Low Level: turn off all Motor Phases
    * No more current flows, reduces holding force.
    * After: State: Motor_OFF.
    * StepPhases memorizes the last used phase.
    * Equivalent what previously the function "void Stop();" did .  */
    void MotorOFF();
    
    /** Low Level: turn on the Motor Phases in the last used phase.
    * The last used phase is held in StepPhases.
    * After: State: Motor_ON, or Motor_ZERO if StepPhases==0
    * Equivalent to what previously the function "void Start();" did.  */
    void MotorON();
    
    /** Low Level: Advance Motor one step, rotates in direction of variable direction. */
    void StepOnce();
    
    /** Low Level: Advance Motor one step, rotates CounterClockwise. */
    void StepCCW();
    
    /** Low Level: Advance Motor one step, rotates Clockwise. */
    void StepClkW();
    
    /** Low Level: turn on the Motor Phases in Zero Position. 
     * After: State: Motor_ZERO, StepPhases==0
     */
    void MotorZero();
    
    
private:

    /** Low Level: Engage Motor Phases according to MotorIndex. */
    void SetPhases(); 

    DigitalOut *MPh[4];       // Digital outputs, one per phase
    int        StepPhase;     // Motor Phase Variable, counts up and down with every step
};

#endif