diff --git a/g2core/config_app.cpp b/g2core/config_app.cpp index 82987f80..783e6b67 100644 --- a/g2core/config_app.cpp +++ b/g2core/config_app.cpp @@ -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 }, diff --git a/g2core/settings/settings_othermill.h b/g2core/settings/settings_othermill.h index a2053889..2742800b 100644 --- a/g2core/settings/settings_othermill.h +++ b/g2core/settings/settings_othermill.h @@ -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 diff --git a/g2core/stepper.cpp b/g2core/stepper.cpp index b3612873..c4f7023d 100644 --- a/g2core/stepper.cpp +++ b/g2core/stepper.cpp @@ -146,8 +146,13 @@ void stepper_init() // setup motor power levels and apply power level to stepper drivers for (uint8_t motor=0; motorsetPowerLevel(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 diff --git a/g2core/stepper.h b/g2core/stepper.h index 9123d87f..fec26f25 100644 --- a/g2core/stepper.h +++ b/g2core/stepper.h @@ -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