My Version of the Crealab MotorLib.
Fork of MotorLib by
CreaMot.h
- Committer:
- sepp_nepp
- Date:
- 2019-04-18
- Revision:
- 24:932ea7bdc850
File content as of revision 24:932ea7bdc850:
/**
* @file CreaMot.h
* \brief File contains Crealab CreaMot Library.
* CreaMot.h contains the class CreaMot, and related enums and structs.
* Includes only "mbed.h".
*
* MotStatus structure is dissolved into the CreaMot Class
*
* 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/ */
// -------------------- CreaMot ---------------------------
#ifndef CREAMOT_H
#define CREAMOT_H
#include "mbed.h"
#define MOTOR_STEP_TIME_MIN_US 700 /**< Shortest Time between two CreaMot steps = 0.7ms, was MOTOR_STEP_TIME_MIN*/
#define MOTOR_STEP_TIME_DEFAULT_US 5000 /**< Default Time between two CreaMot steps = 5ms, was MOTOR_STEP_TIME_DEFAULT*/
#define MOTOR_STEPS_FOR_A_TURN 4096 /**< Default number of CreaMot steps to complete a turn = 4096 steps */
#define CLOCKWISE true /**< Constant for Clockwise direction */
#define COUNTERCLOCKWISE false /**< Constant for Counter-Clockwise direction */
#define MAX_SPEED_CM_SEC 30.0f /**< Clamp maximum advancement speed = 30cm/sec, was MAX_SPEED */
#define MIN_SPEED_CM_SEC 0.001f /**< Clamp minimum advancement speed = 10um/sec */
#define PI 3.141592f /** PI needed to calcuate from angle to distances */
#define PI_OVER_180 (PI/180.0f) /** needed to translate from angle to circumference */
/** \enum motStates
* \brief Possible States of CreaMot 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, /**< CreaMot at phase position 0 and ON, only reached by call of Zero() procedure. */
Motor_ON, /**< Phases are engaged, but CreaMot state machine stopped, replaces Motor_PAUSE. */
Motor_RUN /**< Phases are engaged, and CreaMot state machine runs*/
} motStates;
/** \enum motCmands
* \brief Commands that are handled by the CreaMot state machine
*
* These Commands are issued asynchonously by calling CreaMot 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 CreaMot until Nsteps are achieved. */
MOTOR_stop, /**< Stop immediately all activity, turn off CreaMot. */
MOTOR_pause /**< CreaMot is temporarily paused from the state run. */
} motCmands;
/** ATTENTION UNDER CONSTRUCTION, DO NOT YET USE.
*
* Class of a Four Phase Stepper CreaMot.
*
* 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 the one ongoing command versus the CreaMot state at every tick.
* When End of Run is detected tickers stop, and CreaMot turns off.
*
* To define the speed of the CreaMot set the variable StepTime_us, either by
* a) Using the createor CreaMot(...., uint32_t AStepTime_us);
* b) Calling function setStepTime_us(uint32_t AStepTime_us); any time
* c) or leave it to the default value MOTOR_STEP_TIME_DEFAULT_US = 5000
*
* To be able to run the CreaMot for a given angle, set the number of steps per full turn
* with the function "setStepsFullTurn"
* That value defaults to MOTOR_STEPS_FOR_A_TURN = 4096
*
* To be able to run the CreaMot for a given perimeter distance in centimeters,
* set the wheel diameter with the function setDiamCM( float Adiam_cm);
*
* 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 CreaMot 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.
*
* NB: all times are uint32_t, step numbers are int32_t
*/
class CreaMot
{
public:
/** CreaMot Class Creator
*
* Creates the class, initiallizes all fields, creates Phase Pins.
* Time between two steps defaults here to MOTOR_STEP_TIME_DEFAULT_US = 5000usec.
* Pin names are used to create digital outputs: Pin0 = new DigitalOut(_MPh0)
*
@code
PinName MotPhases[] = {PB_1, PB_15, PB_14, PB_13};
CreaMot MotorName(MotPhases); // Call this creator for example like this:
@endcode
*
* @param _MPh Array of Names of the 4 Digital Pins of type PinNames
*/
CreaMot(PinName _MPh[4] );
/** CreaMot Class Creator
*
* Creates the class, initiallizes all fields, creates Phase Pins.
* Time between two steps defaults here to MOTOR_STEP_TIME_DEFAULT_US=5000usec.
* Pin names are used to create digital outputs: Pin0 = new DigitalOut(_MPh0)
*
@code
// Call this creator for example like this:
CreaMot 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
*/
CreaMot(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3);
/** CreaMot Class Creator
*
* Creates the class, initiallizes all fields, creates Phase Pins.
* Time between two steps is passed as parameter.
* Pin names are used to create digital outputs: Pin0 = new DigitalOut(_MPh0)
*
@code
// Call this creator for example like this:
CreaMot MotorName(PB_1, PB_15, PB_14, PB_13, 6000);
@endcode
*
* @param <_MPh0, _MPh1, _MPh2, _MPh3> List of Names of the 4 Digital Pins of type PinNames
* @param <AStepTime_us> the time in usec between two steps, thats used initially.
*/
CreaMot(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.
*
* A callback is called when the current Command reaches it's requested end.
* Not called when the CreaMot 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)) {_callback = CBfunction;};
/** Attach a Callback function, member of a class.
* Only called when a Run Command reaches it's requested end.
* Not called when the CreaMot 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() { _callback = NULL; };
public:
// *********************************************************************
// all following functions use wheel diameter to achieve cm distance
// *********************************************************************
/** High Level: Run CreaMot for a given number of centimeters.
*
* Runs CreaMot for a given wheel circumference in cimeters in given direction.
* You must setup the perimeter and diameter with setDiam(Adiam_cm) in advance, otherwise no reaction.
* Call Pause() or Stop() to pause or end the CreaMot 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] <AClockWise> Given Direction, true for CLOCKWISE, false for COUNTERCLOCKWISE.
* @param[in] <Dist_cm> Circumference to rotate for, in cm, Dist_cm<0 are run in opposite direction.
*/
void RunDist_cm (bool AClockWise, float Dist_cm);
/** High Level: Run CreaMot for a given number of centimeters in default direction.
* Same as RunDist_cm(AClockWise,Dist_cm) but uses Default diretion.*/
void RunDist_cm (float Dist_cm);
/** High Level: Run CreaMot for a turn angle around a turn_radius_cm in default direction
*
* Runs CreaMot for a given turn angle in degrees with a given turn radius.
* in default direction. Negative angles are rotated in opposite direction.
* turn-radius must be positive. Zero or negative radius are not executed.
* You must setup the perimeter and diameter with setDiam(Adiam_cm) in advance, otherwise no reaction.
* Call Pause() or Stop() to pause or end the CreaMot 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] <turn_angle_deg> Given turn angle in degrees that should be run
* @param[in] <turn_radius_cm> Given Trun radius that should be run */
void RunTurnAngle(float turn_angle_deg, float turn_radius_cm);
/** Additional geometric information: set the wheel diameter, also sets perimeter and degrees per cm.*/
void setDiamCM( float Adiam_cm);
/** Set CreaMot speed in centimeter/sec, based on perimeter in cm */
void setSpeed_cm_sec(float speed_cm_sec);
/** Default rotation direction that serves as local storage, but not as actual direction */
bool defaultDirection;
/** State value that is used and managed by the class owner.
* Used for example by Creabot library to indicate if this is the left or right CreaMot. */
char StateValue;
private:
/** Additional geometric information: wheel diameter in centimeter */
float diam_cm;
/** Additional geometric information: wheel perimeter in centimeter */
float perim_cm;
/** Additional geometric information: rotation angle in degrees per cm circumference */
float degree_per_cm;
public:
// *****************************************************************
// following functions are agnostic of wheel dimensions in centimeters
// *****************************************************************
/** High Level: Run CreaMot for a given angle.
*
* Runs CreaMot for a given angle in given direction.
* Angles<0 are run in opposite direction.
* Call Pause() or Stop() to pause or end the CreaMot run prematurely.
* While running: 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] <AClockWise> Given Direction, true for CLOCKWISE, false for COUNTERCLOCKWISE.
* @param[in] <angle_deg> Angle>0 to rotate for, in degrees, Angles<0 are run in opposite direction.
*/
void RunDegrees (bool AClockWise, float angle_deg);
/** High Level: Run CreaMot for a given angle in default direction
* for details see RunDegrees (bool AClockWise, float angle_deg);
*/
void RunDegrees (float angle_deg);
/** High Level: Run CreaMot 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] <AClockWise> Given Direction, true for CLOCKWISE, false for COUNTERCLOCKWISE.
* @param[in] <Nsteps> Number of steps to run for; Nsteps<0 are run in opposite direction!
*/
void RunSteps (bool AClockWise, int32_t Nsteps);
/** High Level: Run CreaMot "unlimited"
*
* Runs CreaMot 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 CreaMot run.
* @param[in] <AClockWise> Given Direction, true for CLOCKWISE, false for COUNTERCLOCKWISE.
*/
void RunInfinite (bool AClockWise);
/** High Level: Pause a CreaMot Run.
* Put CreaMot 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 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 number of motor steps needed for a full turn. */
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 CreaMot turn
*/
void setStepsFullTurn(uint32_t StepsFullTurn);
/** Mid Level: Get the CreaMot step time.
* Step time is time between two CreaMot steps, and is given in microseconds
* and is passed to the ticker as delay time.
* So the larger the value the slower the CreaMot speed.
* Defaults to MOTOR_STEP_TIME_DEFAULT_US = 5000.
* @return uint32_t The structure of CreaMot status registers.
*/
uint32_t getStepTime_us();
/** Set the time in microseconds between two CreaMot 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 CreaMot 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 CreaMot will do 360° in 20 seconds.
*/
void setRotationPeriodSec(float Seconds_Per_Turn) ;
motStates CurrState; /**< General state that the CreaMot state machine is in.*/
motCmands CurrCmd; /**< Command asked to be executed currently by the state machine.*/
private:
void setCommand(motCmands aCmd, bool aClockWise, int32_t aNSteps);
/**< Helper; set Command, Direction and NSteps in one call. */
// all the Ticker and Timing procedures, used to run the CreaMot 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();
timestamp_t StepTime_us; // Time in µs for one CreaMot step
Ticker MotorSysTick; // System Timer for CreaMot
uint32_t Steps_FullTurn; // Number of step for a complete turn
bool ClockWise; /**< Direction that the CreaMot is asked to run. True if Clockwise */
int32_t NStepsToDo; /**< Number of steps remain for the CreaMot 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 CreaMot runs, or paused;
detaches when finished a run, or stopped. */
public: // all the low level direct CreaMot 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 CreaMot 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 CreaMot 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 CreaMot one step, rotates in direction of variable AClockWise. */
void StepOnce();
/** Low Level: Advance CreaMot one step, rotates CounterClockwise. */
void StepCCW();
/** Low Level: Advance CreaMot one step, rotates Clockwise. */
void StepClkW();
/** Low Level: turn on the CreaMot Phases in Zero Position.
* After: State: Motor_ZERO, StepPhases==0
*/
void MotorZero();
private:
/** Low Level: Engage CreaMot Phases according to MotorIndex. */
void SetPhases();
DigitalOut *MPh[4]; // Digital outputs, one per phase
int StepPhase; // CreaMot Phase Variable, counts up and down with every step
};
#endif
