Added Idle Power Support, Fixes #8

This commit is contained in:
Matt Staniszewski
2019-10-28 17:20:18 -04:00
committed by Rob Giseburt
parent 2fc74165c9
commit 46bd526805
4 changed files with 104 additions and 22 deletions

View File

@@ -235,7 +235,7 @@ const cfgItem_t cfgArray[] = {
{ "1","1pl", _fip, 3, st_print_pl, st_get_pl, st_set_pl, &st_cfg.mot[MOTOR_1].power_level, M1_POWER_LEVEL },
{ "1","1ep", _iip, 0, st_print_ep, st_get_ep, st_set_ep, nullptr, M1_ENABLE_POLARITY },
{ "1","1sp", _iip, 0, st_print_sp, st_get_sp, st_set_sp, nullptr, M1_STEP_POLARITY },
// { "1","1pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, &st_cfg.mot[MOTOR_1].power_idle, M1_POWER_IDLE },
{ "1","1pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, nullptr, M1_POWER_LEVEL_IDLE },
// { "1","1mt", _fip, 2, st_print_mt, st_get_mt, st_set_mt, &st_cfg.mot[MOTOR_1].motor_timeout, M1_MOTOR_TIMEOUT },
#ifdef MOTOR_1_IS_TRINAMIC
{ "1","1ts", _i0, 0, tx_print_nul, motor_1.get_ts_fn, set_ro, &motor_1, 0 },
@@ -269,7 +269,7 @@ const cfgItem_t cfgArray[] = {
{ "2","2pl", _fip, 3, st_print_pl, st_get_pl, st_set_pl, &st_cfg.mot[MOTOR_2].power_level, M2_POWER_LEVEL },
{ "2","2ep", _iip, 0, st_print_ep, st_get_ep, st_set_ep, nullptr, M2_ENABLE_POLARITY },
{ "2","2sp", _iip, 0, st_print_sp, st_get_sp, st_set_sp, nullptr, M2_STEP_POLARITY },
// { "2","2pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, &st_cfg.mot[MOTOR_2].power_idle, M2_POWER_IDLE },
{ "2","2pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, nullptr, M2_POWER_LEVEL_IDLE },
// { "2","2mt", _fip, 2, st_print_mt, st_get_mt, st_set_mt, &st_cfg.mot[MOTOR_2].motor_timeout, M2_MOTOR_TIMEOUT },
#ifdef MOTOR_2_IS_TRINAMIC
{ "2","2ts", _i0, 0, tx_print_nul, motor_2.get_ts_fn, set_ro, &motor_2, 0 },
@@ -303,7 +303,7 @@ const cfgItem_t cfgArray[] = {
{ "3","3pl", _fip, 3, st_print_pl, st_get_pl, st_set_pl, &st_cfg.mot[MOTOR_3].power_level, M3_POWER_LEVEL },
{ "3","3ep", _iip, 0, st_print_ep, st_get_ep, st_set_ep, nullptr, M3_ENABLE_POLARITY },
{ "3","3sp", _iip, 0, st_print_sp, st_get_sp, st_set_sp, nullptr, M3_STEP_POLARITY },
// { "3","3pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, &st_cfg.mot[MOTOR_3].power_idle, M3_POWER_IDLE },
{ "3","3pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, nullptr, M3_POWER_LEVEL_IDLE },
// { "3","3mt", _fip, 2, st_print_mt, st_get_mt, st_set_mt, &st_cfg.mot[MOTOR_3].motor_timeout, M3_MOTOR_TIMEOUT },
#ifdef MOTOR_3_IS_TRINAMIC
{ "3","3ts", _i0, 0, tx_print_nul, motor_3.get_ts_fn, set_ro, &motor_3, 0 },
@@ -337,7 +337,7 @@ const cfgItem_t cfgArray[] = {
{ "4","4pl", _fip, 3, st_print_pl, st_get_pl, st_set_pl, &st_cfg.mot[MOTOR_4].power_level, M4_POWER_LEVEL },
{ "4","4ep", _iip, 0, st_print_ep, st_get_ep, st_set_ep, nullptr, M4_ENABLE_POLARITY },
{ "4","4sp", _iip, 0, st_print_sp, st_get_sp, st_set_sp, nullptr, M4_STEP_POLARITY },
// { "4","4pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, &st_cfg.mot[MOTOR_4].power_idle, M4_POWER_IDLE },
{ "4","4pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, nullptr, M4_POWER_LEVEL_IDLE },
// { "4","4mt", _fip, 2, st_print_mt, st_get_mt, st_set_mt, &st_cfg.mot[MOTOR_4].motor_timeout, M4_MOTOR_TIMEOUT },
#ifdef MOTOR_4_IS_TRINAMIC
{ "4","4ts", _i0, 0, tx_print_nul, motor_4.get_ts_fn, set_ro, &motor_4, 0 },
@@ -371,7 +371,7 @@ const cfgItem_t cfgArray[] = {
{ "5","5pl", _fip, 3, st_print_pl, st_get_pl, st_set_pl, &st_cfg.mot[MOTOR_5].power_level, M5_POWER_LEVEL },
{ "5","5ep", _iip, 0, st_print_ep, st_get_ep, st_set_ep, nullptr, M5_ENABLE_POLARITY },
{ "5","5sp", _iip, 0, st_print_sp, st_get_sp, st_set_sp, nullptr, M5_STEP_POLARITY },
// { "5","5pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, &st_cfg.mot[MOTOR_5].power_idle, M5_POWER_IDLE },
{ "5","5pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, nullptr, M5_POWER_LEVEL_IDLE },
// { "5","5mt", _fip, 2, st_print_mt, st_get_mt, st_set_mt, &st_cfg.mot[MOTOR_5].motor_timeout, M5_MOTOR_TIMEOUT },
#ifdef MOTOR_5_IS_TRINAMIC
{ "5","5ts", _i0, 0, tx_print_nul, motor_5.get_ts_fn, set_ro, &motor_5, 0 },
@@ -405,7 +405,7 @@ const cfgItem_t cfgArray[] = {
{ "6","6pl", _fip, 3, st_print_pl, st_get_pl, st_set_pl, &st_cfg.mot[MOTOR_6].power_level, M6_POWER_LEVEL },
{ "6","6ep", _iip, 0, st_print_ep, st_get_ep, st_set_ep, nullptr, M6_ENABLE_POLARITY },
{ "6","6sp", _iip, 0, st_print_sp, st_get_sp, st_set_sp, nullptr, M6_STEP_POLARITY },
// { "6","6pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, &st_cfg.mot[MOTOR_6].power_idle, M6_POWER_IDLE },
{ "6","6pi", _fip, 3, st_print_pi, st_get_pi, st_set_pi, nullptr, M6_POWER_LEVEL_IDLE },
// { "6","6mt", _fip, 2, st_print_mt, st_get_mt, st_set_mt, &st_cfg.mot[MOTOR_6].motor_timeout, M6_MOTOR_TIMEOUT },
#ifdef MOTOR_6_IS_TRINAMIC
{ "6","6ts", _i0, 0, tx_print_nul, motor_6.get_ts_fn, set_ro, &motor_6, 0 },

View File

@@ -107,7 +107,7 @@
#define MOTOR_POWER_LEVEL_Z_IDLE 0.15
#define MOTOR_POWER_LEVEL_DISABLED 0.05
#define MOTOR_POWER_MODE MOTOR_POWERED_IN_CYCLE
#define MOTOR_POWER_MODE MOTOR_POWER_REDUCED_WHEN_IDLE
#define MOTOR_POWER_TIMEOUT 2.00 // motor power timeout in seconds
#define M1_MOTOR_MAP AXIS_X_EXTERNAL // 1ma

View File

@@ -146,8 +146,13 @@ void stepper_init()
// setup motor power levels and apply power level to stepper drivers
for (uint8_t motor=0; motor<MOTORS; motor++) {
Motors[motor]->setPowerLevel(st_cfg.mot[motor].power_level);
st_run.mot[motor].power_level_dynamic = st_cfg.mot[motor].power_level;
if (Motors[motor]->getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
Motors[motor]->setPowerLevel(st_cfg.mot[motor].power_level_idle);
st_run.mot[motor].power_level_dynamic = st_cfg.mot[motor].power_level_idle;
} else {
Motors[motor]->setPowerLevel(st_cfg.mot[motor].power_level);
st_run.mot[motor].power_level_dynamic = st_cfg.mot[motor].power_level;
}
}
board_stepper_init();
stepper_reset(); // reset steppers to known state
@@ -243,7 +248,7 @@ stat_t st_motor_power_callback() // called by controller
// manage power for each motor individually
for (uint8_t motor = MOTOR_1; motor < MOTORS; motor++) {
Motors[motor]->periodicCheck(have_actually_stopped);
Motors[motor]->periodicCheck(have_actually_stopped, motor);
}
return (STAT_OK);
}
@@ -452,6 +457,8 @@ void st_request_load_move()
static void _load_move()
{
bool waitForVref = false;
// Be aware that dda_ticks_downcount must equal zero for the loader to run.
// So the initial load must also have this set to zero as part of initialization
if (st_runtime_isbusy()) {
@@ -510,6 +517,10 @@ static void _load_move()
// Enable the stepper and start/update motor power management
motor_1.enable();
if(motor_1.getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
motor_1.setPowerLevel(st_cfg.mot[MOTOR_1].power_level);
waitForVref = true;
}
SET_ENCODER_STEP_SIGN(MOTOR_1, st_pre.mot[MOTOR_1].step_sign);
} else { // Motor has 0 steps; might need to energize motor for power mode processing
@@ -528,6 +539,10 @@ static void _load_move()
motor_2.setDirection(st_pre.mot[MOTOR_2].direction);
}
motor_2.enable();
if(motor_2.getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
motor_2.setPowerLevel(st_cfg.mot[MOTOR_2].power_level);
waitForVref = true;
}
SET_ENCODER_STEP_SIGN(MOTOR_2, st_pre.mot[MOTOR_2].step_sign);
} else {
st_run.mot[MOTOR_2].substep_increment_increment = 0;
@@ -544,6 +559,10 @@ static void _load_move()
motor_3.setDirection(st_pre.mot[MOTOR_3].direction);
}
motor_3.enable();
if(motor_3.getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
motor_3.setPowerLevel(st_cfg.mot[MOTOR_3].power_level);
waitForVref = true;
}
SET_ENCODER_STEP_SIGN(MOTOR_3, st_pre.mot[MOTOR_3].step_sign);
} else {
st_run.mot[MOTOR_3].substep_increment_increment = 0;
@@ -560,6 +579,10 @@ static void _load_move()
motor_4.setDirection(st_pre.mot[MOTOR_4].direction);
}
motor_4.enable();
if(motor_4.getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
motor_4.setPowerLevel(st_cfg.mot[MOTOR_4].power_level);
waitForVref = true;
}
SET_ENCODER_STEP_SIGN(MOTOR_4, st_pre.mot[MOTOR_4].step_sign);
} else {
st_run.mot[MOTOR_4].substep_increment_increment = 0;
@@ -576,6 +599,10 @@ static void _load_move()
motor_5.setDirection(st_pre.mot[MOTOR_5].direction);
}
motor_5.enable();
if(motor_5.getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
motor_5.setPowerLevel(st_cfg.mot[MOTOR_5].power_level);
waitForVref = true;
}
SET_ENCODER_STEP_SIGN(MOTOR_5, st_pre.mot[MOTOR_5].step_sign);
} else {
st_run.mot[MOTOR_5].substep_increment_increment = 0;
@@ -592,6 +619,10 @@ static void _load_move()
motor_6.setDirection(st_pre.mot[MOTOR_6].direction);
}
motor_6.enable();
if(motor_6.getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
motor_6.setPowerLevel(st_cfg.mot[MOTOR_6].power_level);
waitForVref = true;
}
SET_ENCODER_STEP_SIGN(MOTOR_6, st_pre.mot[MOTOR_6].step_sign);
} else {
st_run.mot[MOTOR_6].substep_increment_increment = 0;
@@ -600,6 +631,11 @@ static void _load_move()
ACCUMULATE_ENCODER(MOTOR_6);
#endif
// Wait for Vref to settle with new power level
if (waitForVref) {
st_prep_out_of_band_dwell(MOTOR_VREF_RC_TIMEOUT_USEC);
}
//**** do this last ****
st_run.dda_ticks_downcount = st_pre.dda_ticks;
@@ -939,6 +975,7 @@ static float _set_motor_steps_per_unit(nvObj_t *nv)
* st_set_pm() - set motor power mode
* st_get_pm() - get motor power mode
* st_set_pl() - set motor power level
* st_set_pi() - set motor idle power level
*/
/*
@@ -1079,23 +1116,39 @@ stat_t st_set_pm(nvObj_t *nv)
/*
* st_get_pl() - get motor power level
* st_get_pi() - get motor idle power level
* st_set_pl() - set motor power level
* st_set_pi() - set motor idle power level
*
* Input value may vary from 0.000 to 1.000 The setting is scaled to allowable PWM range.
* This function sets both the scaled and dynamic power levels, and applies the
* scaled value to the vref.
*/
stat_t st_get_pl(nvObj_t *nv) { return(get_float(nv, st_cfg.mot[_motor(nv->index)].power_level)); }
stat_t st_get_pi(nvObj_t *nv) { return(get_float(nv, st_cfg.mot[_motor(nv->index)].power_level_idle)); }
stat_t st_set_pl(nvObj_t *nv)
{
uint8_t m = _motor(nv->index);
ritorno(set_float_range(nv, st_cfg.mot[m].power_level, 0.0, 1.0));
st_cfg.mot[m].power_level = nv->value_flt;
st_run.mot[m].power_level_dynamic = st_cfg.mot[m].power_level;
Motors[m]->setPowerLevel(st_cfg.mot[m].power_level);
if(Motors[m]->getPowerState() != MOTOR_IDLE || Motors[m]->getPowerMode() != MOTOR_POWER_REDUCED_WHEN_IDLE) {
st_run.mot[m].power_level_dynamic = st_cfg.mot[m].power_level;
Motors[m]->setPowerLevel(st_cfg.mot[m].power_level);
}
return(STAT_OK);
}
stat_t st_set_pi(nvObj_t *nv) {
uint8_t m = _motor(nv->index);
ritorno(set_float_range(nv, st_cfg.mot[m].power_level_idle, 0.0, 1.0));
st_cfg.mot[m].power_level_idle = nv->value_flt;
if(Motors[m]->getPowerState() == MOTOR_IDLE && Motors[m]->getPowerMode() == MOTOR_POWER_REDUCED_WHEN_IDLE) {
st_run.mot[m].power_level_dynamic = st_cfg.mot[m].power_level_idle;
Motors[m]->setPowerLevel(st_cfg.mot[m].power_level_idle);
}
return (STAT_OK);
}
/*
* st_get_pwr() - get current motor power
*
@@ -1250,8 +1303,9 @@ static const char fmt_0su[] = "[%s%s] m%s steps per unit %17.5f steps per%s\n";
static const char fmt_0po[] = "[%s%s] m%s polarity%18d [0=normal,1=reverse]\n";
static const char fmt_0ep[] = "[%s%s] m%s enable polarity%11d [0=active HIGH,1=active LOW]\n";
static const char fmt_0sp[] = "[%s%s] m%s step polarity%13d [0=active HIGH,1=active LOW]\n";
static const char fmt_0pm[] = "[%s%s] m%s power management%10d [0=disabled,1=always on,2=in cycle,3=when moving]\n";
static const char fmt_0pm[] = "[%s%s] m%s power management%10d [0=disabled,1=always on,2=in cycle,3=when moving,4=reduced when idle]\n";
static const char fmt_0pl[] = "[%s%s] m%s motor power level%13.3f [0.000=minimum, 1.000=maximum]\n";
static const char fmt_0pi[] = "[%s%s] m%s motor idle power level%13.3f [0.000=minimum, 1.000=maximum]\n";
static const char fmt_pwr[] = "[%s%s] Motor %c power level:%12.3f\n";
void st_print_me(nvObj_t *nv) { text_print(nv, fmt_me);} // TYPE_NULL - message only
@@ -1292,6 +1346,7 @@ void st_print_ep(nvObj_t *nv) { _print_motor_int(nv, fmt_0ep);}
void st_print_sp(nvObj_t *nv) { _print_motor_int(nv, fmt_0sp);}
void st_print_pm(nvObj_t *nv) { _print_motor_int(nv, fmt_0pm);}
void st_print_pl(nvObj_t *nv) { _print_motor_flt(nv, fmt_0pl);}
void st_print_pi(nvObj_t *nv) { _print_motor_flt(nv, fmt_0pi);}
void st_print_pwr(nvObj_t *nv){ _print_motor_pwr(nv, fmt_pwr);}
#endif // __TEXT_MODE

View File

@@ -281,14 +281,18 @@ typedef enum {
MOTOR_DISABLED = 0, // motor enable is deactivated
MOTOR_ALWAYS_POWERED, // motor is always powered while machine is ON
MOTOR_POWERED_IN_CYCLE, // motor fully powered during cycles, de-powered out of cycle
MOTOR_POWERED_ONLY_WHEN_MOVING // motor only powered while moving - idles shortly after it's stopped - even in cycle
MOTOR_POWERED_ONLY_WHEN_MOVING, // motor only powered while moving - idles shortly after it's stopped - even in cycle
MOTOR_POWER_REDUCED_WHEN_IDLE // enable Vref current reduction for idle
} stPowerMode;
#define MOTOR_POWER_MODE_MAX_VALUE MOTOR_POWERED_ONLY_WHEN_MOVING
#define MOTOR_POWER_MODE_MAX_VALUE MOTOR_POWER_REDUCED_WHEN_IDLE
// Min/Max timeouts allowed for motor disable. Allow for inertial stop; must be non-zero
#define MOTOR_TIMEOUT_SECONDS_MIN (float)0.1 // seconds !!! SHOULD NEVER BE ZERO !!!
#define MOTOR_TIMEOUT_SECONDS_MAX (float)4294967 // (4294967295/1000) -- for conversion to uint32_t
// 1 dog year (7 weeks)
#define MOTOR_VREF_RC_TIMEOUT_USEC (float)5000.0 // how long it takes vref to stabilize after changing it
// Step generation constants
#define STEP_INITIAL_DIRECTION DIRECTION_CW
@@ -352,7 +356,8 @@ typedef struct cfgMotor { // per-motor configs
uint8_t motor_map; // map motor to axis
uint32_t microsteps; // microsteps to apply for each axis (ex: 8)
uint8_t polarity; // 0=normal polarity, 1=reverse motor direction
float power_level; // set 0.000 to 1.000 for PMW vref setting
float power_level; // set 0.000 to 1.000 for PWM vref setting
float power_level_idle; // set 0.000 to 1.000 for PWM vref idle setting
float step_angle; // degrees per whole step (ex: 1.8)
float travel_rev; // mm or deg of travel per motor revolution
float steps_per_unit; // microsteps per mm (or degree) of travel
@@ -482,13 +487,18 @@ public:
return _power_mode;
};
virtual stPowerState getPowerState()
{
return _power_state;
};
virtual float getCurrentPowerLevel(uint8_t motor)
{
if (_power_state == MOTOR_OFF) {
return (0.0);
}
if (_power_state == MOTOR_IDLE) {
return (0.0);
return (st_cfg.mot[motor].power_level_idle);
}
return (st_cfg.mot[motor].power_level);
};
@@ -539,7 +549,14 @@ public:
}
this->_disableImpl();
_motor_disable_timeout.clear();
_power_state = MOTOR_IDLE; // or MOTOR_OFF
_power_state = MOTOR_OFF;
};
// idle motor partially energized for torque maintenance
void idle(uint8_t motor)
{
setPowerLevel(st_cfg.mot[motor].power_level_idle);
_power_state = MOTOR_IDLE;
};
// turn off motor is only powered when moving
@@ -549,6 +566,8 @@ public:
if (_power_mode == MOTOR_POWERED_IN_CYCLE) {
this->enable();
_power_state = MOTOR_POWER_TIMEOUT_START;
} else if (_power_mode == MOTOR_POWER_REDUCED_WHEN_IDLE) {
_power_state = MOTOR_POWER_TIMEOUT_START;
} else if (_power_mode == MOTOR_POWERED_ONLY_WHEN_MOVING) {
if (_power_state == MOTOR_RUNNING) {
_power_state = MOTOR_POWER_TIMEOUT_START;
@@ -556,7 +575,7 @@ public:
}
};
virtual void periodicCheck(bool have_actually_stopped) // can be overridden
virtual void periodicCheck(bool have_actually_stopped, uint8_t motor) // can be overridden
{
if (_was_enabled) {
_motor_disable_timeout_ms = st_cfg.motor_power_timeout * 1000.0;
@@ -569,7 +588,7 @@ public:
// start timeouts initiated during a load so the loader does not need to burn these cycles
if (_power_state == MOTOR_POWER_TIMEOUT_START && _power_mode != MOTOR_ALWAYS_POWERED) {
_power_state = MOTOR_POWER_TIMEOUT_COUNTDOWN;
if (_power_mode == MOTOR_POWERED_IN_CYCLE) {
if (_power_mode == MOTOR_POWERED_IN_CYCLE || _power_mode == MOTOR_POWER_REDUCED_WHEN_IDLE) {
_motor_disable_timeout.set(_motor_disable_timeout_ms);
} else if (_power_mode == MOTOR_POWERED_ONLY_WHEN_MOVING) {
_motor_disable_timeout.set(st_cfg.motor_power_timeout * 1000.0);
@@ -579,8 +598,12 @@ public:
// count down and time out the motor
if (_power_state == MOTOR_POWER_TIMEOUT_COUNTDOWN) {
if (_motor_disable_timeout.isPast()) {
disable();
sr_request_status_report(SR_REQUEST_TIMED);
if (_power_mode == MOTOR_POWER_REDUCED_WHEN_IDLE) {
idle(motor);
} else {
disable();
}
sr_request_status_report(SR_REQUEST_TIMED);
}
}
};
@@ -658,7 +681,9 @@ stat_t st_get_sp(nvObj_t *nv);
stat_t st_get_pm(nvObj_t *nv);
stat_t st_set_pm(nvObj_t *nv);
stat_t st_get_pl(nvObj_t *nv);
stat_t st_get_pi(nvObj_t *nv);
stat_t st_set_pl(nvObj_t *nv);
stat_t st_set_pi(nvObj_t *nv);
stat_t st_get_pwr(nvObj_t *nv);
@@ -680,6 +705,7 @@ stat_t st_get_dw(nvObj_t *nv);
void st_print_sp(nvObj_t *nv);
void st_print_pm(nvObj_t *nv);
void st_print_pl(nvObj_t *nv);
void st_print_pi(nvObj_t *nv);
void st_print_pwr(nvObj_t *nv);
void st_print_mt(nvObj_t *nv);
void st_print_me(nvObj_t *nv);
@@ -697,6 +723,7 @@ stat_t st_get_dw(nvObj_t *nv);
#define st_print_sp tx_print_stub
#define st_print_pm tx_print_stub
#define st_print_pl tx_print_stub
#define st_print_pi tx_print_stub
#define st_print_pwr tx_print_stub
#define st_print_mt tx_print_stub
#define st_print_me tx_print_stub