My Version of the Crealab MotorLib.
Fork of MotorLib by
Revision 24:932ea7bdc850, committed 2019-04-18
- Comitter:
- sepp_nepp
- Date:
- Thu Apr 18 12:12:48 2019 +0000
- Parent:
- 23:6060422cd6eb
- Commit message:
- Compiles
Changed in this revision
diff -r 6060422cd6eb -r 932ea7bdc850 CreaMot.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CreaMot.cpp Thu Apr 18 12:12:48 2019 +0000 @@ -0,0 +1,249 @@ +#include "CreaMot.h" + + // -------------------- CreaMot Class --------------------------- + +CreaMot::CreaMot(PinName _MPh[4]) { + initialization( _MPh , MOTOR_STEP_TIME_DEFAULT_US); +} + +CreaMot::CreaMot(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3) { + PinName _MPh[4] = {_MPh0, _MPh1, _MPh2, _MPh3}; + initialization( _MPh , MOTOR_STEP_TIME_DEFAULT_US); +} + +CreaMot::CreaMot(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3, uint32_t AStepTime_us) { + PinName _MPh[4] = {_MPh0, _MPh1, _MPh2, _MPh3}; + initialization( _MPh, AStepTime_us); +} + +void CreaMot::initialization(PinName _MPh[4], uint32_t AStepTime_us) { + + for (int ph=0; ph<4; ph++) { MPh[ph] = new DigitalOut(_MPh[ph]); } + + MotorOFF(); // Default state is all phases are OFF + StepPhase = 0; // initial phase is Zero + + setCommand(MOTOR_nop, CLOCKWISE, 0);// Default command is NOP, clockwise direction, 0 steps + + TickIsAttached = false; + StepTime_us = AStepTime_us;// duration in micro second for one step + + Steps_FullTurn = MOTOR_STEPS_FOR_A_TURN; // Default Calibration value + _callback = NULL; // No default Callback + + // All geometric information defaults to 0: + diam_cm = 0; // wheel diameter in centimeter + perim_cm = 0; // wheel perimeter in centimeter + degree_per_cm = 0; // rotation angle in degrees per cm circumference + defaultDirection = CLOCKWISE; +} + +// ***************************************************************** +// all following functions are based on centimeter information +// ***************************************************************** + +/* High Level: Run CreaMot for a given number of Dist_cm, Dist_cm<0 are run in opposite direction. */ +void CreaMot::RunDist_cm(bool AClockWise, float Dist_cm) +{ RunDegrees(AClockWise,Dist_cm * degree_per_cm); } + +/* High Level: Run CreaMot for a given number of Dist_cm in default direction. */ +void CreaMot::RunDist_cm(float Dist_cm) +{ RunDegrees(defaultDirection, Dist_cm * degree_per_cm); } + +/** Additional geometric information: set the wheel diameter, also sets perimeter and degrees per cm.*/ +void CreaMot::setDiamCM( float Adiam_cm) +{ diam_cm = Adiam_cm; + perim_cm = PI*diam_cm; + degree_per_cm=360.0f/perim_cm; +} + +/** Calculate the needed wheel angle from a turn angle and a turn_radius_cm */ +void CreaMot::RunTurnAngle(float turn_angle_deg, float turn_radius_cm) +{ // a turn radius smaller than 0 make no sense is not executed + if( turn_radius_cm>= 0 ) + RunDegrees( turn_angle_deg * PI_OVER_180 * turn_radius_cm * degree_per_cm); +} + +void CreaMot::setSpeed_cm_sec(float speed_cm_sec) +{ if (speed_cm_sec < MIN_SPEED_CM_SEC) // catch too small or negative speeds + setRotationPeriodSec( perim_cm / MIN_SPEED_CM_SEC); + else setRotationPeriodSec( perim_cm / speed_cm_sec ); +} + +// ***************************************************************** +// all following functions are agnostic of centimeter-information +// ***************************************************************** + +void CreaMot::RunInfinite(bool AClockWise) +{ setCommand(MOTOR_run, AClockWise, -1); + StartTick(); +} + +/* High Level: Run CreaMot for a given angle, angles<0 are run in opposite direction. */ +void CreaMot::RunDegrees(bool AClockWise, float angle_deg) { + RunSteps( AClockWise, (int32_t)(angle_deg * (float)Steps_FullTurn / 360.0f) ); +} + +/* High Level: Run CreaMot for a given angle in default direction, angles<0 are run in opposite direction. */ +void CreaMot::RunDegrees(float angle_deg) { + RunSteps( defaultDirection, (int32_t)(angle_deg * (float)Steps_FullTurn / 360.0f) ); +} + +/* High Level: Run CreaMot for a given number of steps, steps<0 are run in opposite direction. */ +void CreaMot::RunSteps(bool AClockWise, int32_t steps) +{ if (steps<0) { AClockWise = !AClockWise; steps=-steps; } + if (steps>0) + { setCommand( MOTOR_run, AClockWise, steps ); + StartTick(); } +} + +void CreaMot::PauseRun() +{ if (CurrCmd==MOTOR_run) CurrCmd = MOTOR_pause; } + +void CreaMot::RestartRun() +{ if (CurrCmd==MOTOR_pause) CurrCmd = MOTOR_run; } + +// not only halt the state machine but also set NSteps to 0 +void CreaMot::StopRun() +{ setCommand(MOTOR_stop,ClockWise,0); } + +void CreaMot::setCommand(motCmands aCmd, bool aClockWise, int32_t aNSteps) { + CurrCmd = aCmd; + ClockWise = aClockWise; + NStepsToDo = aNSteps; +}; + + +/******************************************************* + ** Ticker / Timing procedures + *******************************************************/ +//Get, set the scaling +uint32_t CreaMot::getStepsFullTurn() +{ return Steps_FullTurn; } + +void CreaMot::setStepsFullTurn(uint32_t StepsFullTurn) +{ Steps_FullTurn = StepsFullTurn; } + +void CreaMot::setRotationPeriodSec(float Seconds_Per_Turn) { + // rescale to usec and pass on to the next handler. + setStepTime_us( uint32_t(Seconds_Per_Turn / Steps_FullTurn * 1000000) ) ; +} +void CreaMot::setStepTime_us(uint32_t AStepTime_us) { + if(StepTime_us == AStepTime_us) return; // avoid futile activity + if (StepTime_us < MOTOR_STEP_TIME_MIN_US) // filter too small values + StepTime_us = MOTOR_STEP_TIME_MIN_US; + else StepTime_us = AStepTime_us; // or if OK then assign value + // if ticker already running recreate a new ticker; + if(TickIsAttached) { StopTick(); StartTick(); } + } + +void CreaMot::StartTick() { + if(!TickIsAttached) { + // Connect Interrupt routine in which the CreaMot and all the state machine is performed + MotorSysTick.attach_us(callback(this, &CreaMot::ProcessMotorStateMachine), StepTime_us); + // last=tuneTimings.read_us(); + TickIsAttached=true; + } +} + +void CreaMot::ProcessMotorStateMachine() +{ + switch(CurrCmd) { + case MOTOR_run: { + switch(CurrState) { + case Motor_OFF: + MotorON(); // First only turn on the CreaMot .. + break; + case Motor_ZERO: + case Motor_ON: + CurrState = Motor_RUN; + case Motor_RUN: + if (NStepsToDo==0) // No more steps to go + { CurrCmd = MOTOR_stop; + if (_callback) _callback.call(); } + else // More steps to go + { StepOnce(); + NStepsToDo--;} + break; + } // switch(CurrState) + } // case MOTOR_run + case MOTOR_stop: + StopTick(); + CurrCmd = MOTOR_nop; + MotorOFF(); + break; + case MOTOR_nop: + case MOTOR_pause: + default: break; + } // switch(CurrCmd) +} + +void CreaMot::StopTick() { + if(TickIsAttached) + { MotorSysTick.detach(); TickIsAttached=false; } +} + +/******************************************************* + ** all the low level direct CreaMot HW access + *******************************************************/ + + + void CreaMot::MotorTest() // Just to check that it make a full turn back and forth +{ + int i; + MotorON(); + for (i=0; i<Steps_FullTurn; i++) { + wait(0.005); + StepClkW(); + } + wait(0.5); + for (i=0; i<Steps_FullTurn; i++) { + wait(0.005); + StepCCW(); + } + MotorOFF(); +} + + /** Turn off all CreaMot Phases, no more current flowing */ +void CreaMot::MotorOFF() +{ for (int ph=0; ph<4; ph++) *MPh[ph] = 0; + CurrState=Motor_OFF; +} + +/** Turn on the CreaMot Phase, In the last used phase, memorized in StepPhases +* Equivalent to what previously the function "void Start();" did */ +void CreaMot::MotorON() +{ SetPhases(); // attention, does not change StepPhase! + if (StepPhase==0) CurrState=Motor_ZERO; + else CurrState=Motor_ON; +} + +/** CreaMot phases turned on and put to Zero Position*/ +void CreaMot::MotorZero() { + StepPhase = 0; // sets the phases to 0 + SetPhases(); + CurrState=Motor_ZERO; +} + +void CreaMot::StepOnce() // Move the CreaMot in the requested 'direction' +{ if (ClockWise) StepClkW(); else StepCCW(); +} + +void CreaMot::StepClkW() // Move the CreaMot one step Clockwise +{ if (StepPhase<7) StepPhase++; else StepPhase = 0; + SetPhases(); +} +void CreaMot::StepCCW() // Move the CreaMot one step Clockwise +{ if (StepPhase>0) StepPhase--; else StepPhase = 7; + SetPhases(); +} + +static const int MotPh[4][8] = + { {1, 1, 0, 0, 0, 0, 0, 1}, + {0, 1, 1, 1, 0, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0}, + {0, 0, 0, 0, 0, 1, 1, 1}}; + +void CreaMot::SetPhases() // Engage CreaMot Phases according to StepPhase +{ for (int ph=0; ph<4; ph++) { *MPh[ph] = MotPh[ph][StepPhase]; } } +
diff -r 6060422cd6eb -r 932ea7bdc850 CreaMot.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CreaMot.h Thu Apr 18 12:12:48 2019 +0000 @@ -0,0 +1,447 @@ +/** + * @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
diff -r 6060422cd6eb -r 932ea7bdc850 motor.cpp --- a/motor.cpp Wed Apr 17 21:48:14 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,252 +0,0 @@ -#include "motor.h" - - - // -------------------- CreaMot Class --------------------------- - -CreaMot::CreaMot(PinName _MPh[4]) { - initialization( _MPh , MOTOR_STEP_TIME_DEFAULT_US); -} - -CreaMot::CreaMot(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3) { - PinName _MPh[4] = {_MPh0, _MPh1, _MPh2, _MPh3}; - initialization( _MPh , MOTOR_STEP_TIME_DEFAULT_US); -} - -CreaMot::CreaMot(PinName _MPh0, PinName _MPh1, PinName _MPh2, PinName _MPh3, uint32_t AStepTime_us) { - PinName _MPh[4] = {_MPh0, _MPh1, _MPh2, _MPh3}; - initialization( _MPh, AStepTime_us); -} - -void CreaMot::initialization(PinName _MPh[4], uint32_t AStepTime_us) { - - for (int ph=0; ph<4; ph++) { MPh[ph] = new DigitalOut(_MPh[ph]); } - - MotorOFF(); // Default state is all phases are OFF - StepPhase = 0; // initial phase is Zero - - setStatus(MOTOR_nop, CLOCKWISE, 0);// Default command is NOP, clockwise direction, 0 steps - - TickIsAttached = false; - StepTime_us = AStepTime_us;// duration in micro second for one step - - Steps_FullTurn = MOTOR_STEPS_FOR_A_TURN; // Default Calibration value - _callback = NULL; // No default Callback - - // All geometric information defaults to 0: - rotate_angle_deg = 0; // calculated wheel rotation angle - diam_cm = 0; // wheel diameter in centimeter - perim_cm = 0; // wheel perimeter in centimeter - degree_per_cm = 0; // rotation angle in degrees per cm circumference - defaultDirection = CLOCKWISE; -} - -// ***************************************************************** -// all following functions are based on centimeter information -// ***************************************************************** - -/* High Level: Run CreaMot for a given number of Dist_cm, Dist_cm<0 are run in opposite direction. */ -void CreaMot::RunDist_cm (bool AClockWise, float Dist_cm); -{ RunDegrees(AClockWise, Dist_cm * degree_per_cm; ) } - -/* High Level: Run CreaMot for a given number of Dist_cm in default direction. */ -void CreaMot::RunDist_cm (float Dist_cm); -{ RunDegrees(defaultDirection, Dist_cm * degree_per_cm; ) } - -/** Additional geometric information: set the wheel diameter, also sets perimeter and degrees per cm.*/ -void CreaMot:setDiamCM( float Adiam_cm) /**< Helper; set diameter and perim to values */ -{ diam_cm = Adiam_cm; - perim_cm = PI*diam_cm; - degree_per_cm=360.0f/perim_cm; -} - -/** Helper: calculate the needed wheel angle from a turn angle and a turn_radius_cm */ -float CreaMot:RunTurnAngle(float turn_angle_deg, float turn_radius_cm) -{ // a turn radius smaller than 0 make no sense - if( turn_radius_cm>= 0 ) - rotate_angle_deg = turn_angle_deg * PI_OVER_180 * turn_radius_cm * degree_per_cm; - else rotate_angle_deg = 0; - return rotate_angle_deg; -} - -void CreaMot::setSpeed_cm_sec(float speed_cm_sec) -{ if (speed_cm_sec < MIN_SPEED_CM_SEC) // catch too small or negative speeds - setRotationPeriodSec( perim_cm / MIN_SPEED_CM_SEC); - else setRotationPeriodSec( perim_cm / speed_cm_sec ); -} - -// ***************************************************************** -// all following functions are agnostic of centimeter-information -// ***************************************************************** - -void CreaMot::RunInfinite(bool AClockWise) { - setStatus(MOTOR_run, AClockWise, -1); - StartTick(); -} - -/* High Level: Run CreaMot for a given angle, angles<0 are run in opposite direction. */ -void CreaMot::RunDegrees(bool AClockWise, float angle_deg) { - RunSteps( AClockWise, (int32_t)(angle_deg * (float)Steps_FullTurn / 360.0f) ); -} - -/* High Level: Run CreaMot for a given angle in default direction, angles<0 are run in opposite direction. */ -void CreaMot::RunDegrees(float angle_deg) { - RunSteps( defaultDirection, (int32_t)(angle_deg * (float)Steps_FullTurn / 360.0f) ); -} - -/* High Level: Run CreaMot for a given number of steps, steps<0 are run in opposite direction. */ -void CreaMot::RunSteps(bool AClockWise, int32_t steps) { - if (steps!=0) - { setStatus(MOTOR_run, AClockWise ^^ (steps<0), abs(steps)); - StartTick(); } -} - -void CreaMot::PauseRun() -{ if (CurrCmd==MOTOR_run) CurrCmd = MOTOR_pause; } - -void CreaMot::RestartRun() -{ if (CurrCmd==MOTOR_pause) CurrCmd = MOTOR_run; } - -void CreaMot::StopRun() -{ CurrCmd = MOTOR_stop; } - -MotStatus CreaMot::getStatus() { return Status; } - -/******************************************************* - ** Ticker / Timing procedures - *******************************************************/ -//Get, set the scaling -uint32_t CreaMot::getStepsFullTurn() -{ return Steps_FullTurn; } - -void CreaMot::setStepsFullTurn(uint32_t StepsFullTurn) -{ Steps_FullTurn = StepsFullTurn; } - -void CreaMot::setRotationPeriodSec(float Seconds_Per_Turn) { - // rescale to usec and pass on to the next handler. - setStepTime_us( uint32_t(Seconds_Per_Turn / Steps_FullTurn * 1000000) ) ; -} -void CreaMot::setStepTime_us(uint32_t AStepTime_us) { - if(StepTime_us == AStepTime_us) return; // avoid futile activity - if (StepTime_us < MOTOR_STEP_TIME_MIN_US) // filter too small values - StepTime_us = MOTOR_STEP_TIME_MIN_US; - else StepTime_us = AStepTime_us; // or if OK then assign value - // if ticker already running recreate a new ticker; - if(TickIsAttached) { StopTick(); StartTick(); } - } - -void CreaMot::StartTick() { - if(!TickIsAttached) { - // Connect Interrupt routine in which the CreaMot and all the state machine is performed - MotorSysTick.attach_us(callback(this, &CreaMot::ProcessMotorStateMachine), StepTime_us); - // last=tuneTimings.read_us(); - TickIsAttached=true; - } -} - -void CreaMot::ProcessMotorStateMachine() -{ - switch(CurrCmd) { - case MOTOR_run: { - switch(CurrState) { - case Motor_OFF: - MotorON(); // First only turn on the CreaMot .. - break; - case Motor_ZERO: - case Motor_ON: - CurrState = Motor_RUN; - case Motor_RUN: - if (NStepsToDo==0) // No more steps to go - { CurrCmd = MOTOR_stop; - if (_callback) _callback.call(); } - else // More steps to go - { StepOnce(); - NStepsToDo--;} - break; - } // switch(CurrState) - } // case MOTOR_run - case MOTOR_stop: - StopTick(); - CurrCmd = MOTOR_nop; - MotorOFF(); - break; - case MOTOR_nop: - case MOTOR_pause: - default: break; - } // switch(CurrCmd) -} - -void CreaMot::StopTick() { - if(TickIsAttached) - { MotorSysTick.detach(); TickIsAttached=false; } -} - -/******************************************************* - ** all the low level direct CreaMot HW access - *******************************************************/ - -void CreaMot::setStatus(motCmands aCmd, bool AClockWise, int32_t aNSteps) { - cmd = aCmd; - AClockWise = AClockWise; - NSteps = aNSteps; -}; - - - void CreaMot::MotorTest() // Just to check that it make a full turn back and forth -{ - int i; - MotorON(); - for (i=0; i<Steps_FullTurn; i++) { - wait(0.005); - StepClkW(); - } - wait(0.5); - for (i=0; i<Steps_FullTurn; i++) { - wait(0.005); - StepCCW(); - } - MotorOFF(); -} - - /** Turn off all CreaMot Phases, no more current flowing */ -void CreaMot::MotorOFF() -{ for (int ph=0; ph<4; ph++) *MPh[ph] = 0; - CurrState=Motor_OFF; -} - -/** Turn on the CreaMot Phase, In the last used phase, memorized in StepPhases -* Equivalent to what previously the function "void Start();" did */ -void CreaMot::MotorON() -{ SetPhases(); // attention, does not change StepPhase! - if (StepPhase==0) CurrState=Motor_ZERO; - else CurrState=Motor_ON; -} - -/** CreaMot phases turned on and put to Zero Position*/ -void CreaMot::MotorZero() { - StepPhase = 0; // sets the phases to 0 - SetPhases(); - CurrState=Motor_ZERO; -} - -void CreaMot::StepOnce() // Move the CreaMot in the Status 'direction' -{ if (Status.AClockWise) StepClkW(); else StepCCW(); -} - -void CreaMot::StepClkW() // Move the CreaMot one step Clockwise -{ if (StepPhase<7) StepPhase++; else StepPhase = 0; - SetPhases(); -} -void CreaMot::StepCCW() // Move the CreaMot one step Clockwise -{ if (StepPhase>0) StepPhase--; else StepPhase = 7; - SetPhases(); -} - -static const int MotPh[4][8] = - { {1, 1, 0, 0, 0, 0, 0, 1}, - {0, 1, 1, 1, 0, 0, 0, 0}, - {0, 0, 0, 1, 1, 1, 0, 0}, - {0, 0, 0, 0, 0, 1, 1, 1}}; - -void CreaMot::SetPhases() // Engage CreaMot Phases according to StepPhase -{ for (int ph=0; ph<4; ph++) { *MPh[ph] = MotPh[ph][StepPhase]; } } -
diff -r 6060422cd6eb -r 932ea7bdc850 motor.h --- a/motor.h Wed Apr 17 21:48:14 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,447 +0,0 @@ -/** - * @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 MOTOR_H -#define MOTOR_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 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] <turn_angle_deg> Given turn angle in degrees that should be run - * @param[in] <turn_radius_cm> Given Trun radius that should be run */ - float 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); - - - /** Calculated wheel Angle from calcAngle() Helper function */ - float rotate_angle_deg; - - /** 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; - - /** 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; - -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 int32_t The structure of CreaMot status registers. */ - int32_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(int32_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) ; - -private: - // 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 - int32_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 - motStates CurrState; /**< General state that the CreaMot state machine is in.*/ - motCmands CurrCmd; /**< Command asked to be executed currently by the state machine.*/ - void setStatus(motCmands aCmd, bool AClockWise, int32_t aNSteps); - /**< Helper; set Command, Direction and NSteps in one call. */ - - - /** 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