My Version of the Crealab MotorLib.
Fork of MotorLib by
CreaMot.cpp
- Committer:
- sepp_nepp
- Date:
- 2019-04-18
- Revision:
- 24:932ea7bdc850
File content as of revision 24:932ea7bdc850:
#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]; } }
