From 253c2dac8b8b50fc767aae6a40c60e14de12b14b Mon Sep 17 00:00:00 2001 From: bdring Date: Sun, 17 May 2020 09:27:14 -0500 Subject: [PATCH] Added solenoid class --- Grbl_Esp32/Machines/motor_class_test.h | 33 ++++++ Grbl_Esp32/Machines/spi_daisy_4axis_xyyz.h | 1 - Grbl_Esp32/Machines/spi_daisy_4axis_xyz.h | 1 - Grbl_Esp32/Machines/spi_daisy_4axis_xyza.h | 1 - Grbl_Esp32/Machines/tmc2130_pen.h | 2 - Grbl_Esp32/Motors/MotorClass.cpp | 10 +- Grbl_Esp32/Motors/MotorClass.h | 34 ++++-- Grbl_Esp32/Motors/RcServoClass.cpp | 28 ++--- Grbl_Esp32/Motors/SolenoidClass.cpp | 119 +++++++++++++++++++++ Grbl_Esp32/Motors/SolenoidClass.h | 25 +++++ 10 files changed, 226 insertions(+), 28 deletions(-) create mode 100644 Grbl_Esp32/Motors/SolenoidClass.cpp create mode 100644 Grbl_Esp32/Motors/SolenoidClass.h diff --git a/Grbl_Esp32/Machines/motor_class_test.h b/Grbl_Esp32/Machines/motor_class_test.h index f2f783eb..a87d9bff 100644 --- a/Grbl_Esp32/Machines/motor_class_test.h +++ b/Grbl_Esp32/Machines/motor_class_test.h @@ -213,6 +213,7 @@ #define SPINDLE_TYPE SPINDLE_TYPE_NONE */ +/* // ======================= SPI 4 axis xxyz =========================== #define MACHINE_NAME "MotorClass Test 4x SPI XXYZ A Servo" #define N_AXIS 4 @@ -254,3 +255,35 @@ #define A_SERVO_RANGE_MAX 5.0 #define SPINDLE_TYPE SPINDLE_TYPE_NONE +*/ + + + +#define MACHINE_NAME "Solenoid test using TMC2130 pen" + +#define X_STEP_PIN GPIO_NUM_12 +#define X_DIRECTION_PIN GPIO_NUM_26 +#define X_TRINAMIC_DRIVER 2130 // Which Driver Type? +#define X_CS_PIN GPIO_NUM_17 //chip select +#define X_RSENSE TMC2130_RSENSE_DEFAULT + +#define Y_STEP_PIN GPIO_NUM_14 +#define Y_DIRECTION_PIN GPIO_NUM_25 +#define Y_TRINAMIC_DRIVER 2130 // Which Driver Type? +#define Y_CS_PIN GPIO_NUM_16 //chip select +#define Y_RSENSE TMC2130_RSENSE_DEFAULT + +// OK to comment out to use pin for other features +#define STEPPERS_DISABLE_PIN GPIO_NUM_13 + +#define Z_SOLENOID_PIN GPIO_NUM_27 // comment this out if PWM spindle/laser control. +#define Z_SOLENOID_MAX 5.0 +#define SOLENOID_ALLOW_DISABLE true // solenoid will turn off when motors diable + +#define X_LIMIT_PIN GPIO_NUM_32 +#define Y_LIMIT_PIN GPIO_NUM_4 +#define LIMIT_MASK B11 + +// defaults +#define DEFAULT_Z_STEPS_PER_MM 100.0 // This is used as the servo calibration +#define DEFAULT_Z_MAX_TRAVEL 300.0 // This is used as the servo calibration \ No newline at end of file diff --git a/Grbl_Esp32/Machines/spi_daisy_4axis_xyyz.h b/Grbl_Esp32/Machines/spi_daisy_4axis_xyyz.h index d4ba728d..2af32cc3 100644 --- a/Grbl_Esp32/Machines/spi_daisy_4axis_xyyz.h +++ b/Grbl_Esp32/Machines/spi_daisy_4axis_xyyz.h @@ -30,7 +30,6 @@ #endif #define N_AXIS 3 // can be 3 or 4. (if 3 install bypass jumper next to the A driver) -#define USE_TRINAMIC #define TRINAMIC_DAISY_CHAIN // Use SPI enable instead of the enable pin diff --git a/Grbl_Esp32/Machines/spi_daisy_4axis_xyz.h b/Grbl_Esp32/Machines/spi_daisy_4axis_xyz.h index 87662e62..377566c4 100644 --- a/Grbl_Esp32/Machines/spi_daisy_4axis_xyz.h +++ b/Grbl_Esp32/Machines/spi_daisy_4axis_xyz.h @@ -30,7 +30,6 @@ #endif #define N_AXIS 3 -#define USE_TRINAMIC #define TRINAMIC_DAISY_CHAIN // Use SPI enable instead of the enable pin diff --git a/Grbl_Esp32/Machines/spi_daisy_4axis_xyza.h b/Grbl_Esp32/Machines/spi_daisy_4axis_xyza.h index 5163fd65..88002eb7 100644 --- a/Grbl_Esp32/Machines/spi_daisy_4axis_xyza.h +++ b/Grbl_Esp32/Machines/spi_daisy_4axis_xyza.h @@ -30,7 +30,6 @@ #endif #define N_AXIS 4 // can be 3 or 4. (if 3 install bypass jumper next to the A driver) -#define USE_TRINAMIC #define TRINAMIC_DAISY_CHAIN // Use SPI enable instead of the enable pin diff --git a/Grbl_Esp32/Machines/tmc2130_pen.h b/Grbl_Esp32/Machines/tmc2130_pen.h index 84d103fe..d02c0ef8 100644 --- a/Grbl_Esp32/Machines/tmc2130_pen.h +++ b/Grbl_Esp32/Machines/tmc2130_pen.h @@ -35,8 +35,6 @@ #define X_LIMIT_PIN GPIO_NUM_32 #endif -#define USE_TRINAMIC // Using at least 1 trinamic driver - #define X_STEP_PIN GPIO_NUM_12 #define X_DIRECTION_PIN GPIO_NUM_26 #define X_TRINAMIC_DRIVER 2130 // Which Driver Type? diff --git a/Grbl_Esp32/Motors/MotorClass.cpp b/Grbl_Esp32/Motors/MotorClass.cpp index f7851000..64aff2c4 100644 --- a/Grbl_Esp32/Motors/MotorClass.cpp +++ b/Grbl_Esp32/Motors/MotorClass.cpp @@ -43,6 +43,7 @@ #include "StandardStepperClass.cpp" #include "UnipolarMotorClass.cpp" #include "RcServoClass.cpp" +#include "SolenoidClass.cpp" Motor* myMotor[6][2]; // number of axes (normal and ganged) static TaskHandle_t readSgTaskHandle = 0; // for realtime stallguard data diaplay @@ -121,6 +122,8 @@ void init_motors() { myMotor[Z_AXIS][0] = new UnipolarMotor(Z_AXIS, Z_PIN_PHASE_0, Z_PIN_PHASE_1, Z_PIN_PHASE_2, Z_PIN_PHASE_3); #elif defined(Z_STEP_PIN) myMotor[Z_AXIS][0] = new StandardStepper(Z_AXIS, Z_STEP_PIN, Z_DIRECTION_PIN); +#elif defined(Z_SOLENOID_PIN) + myMotor[Z_AXIS][0] = new Solenoid(Z_AXIS, Z_SOLENOID_PIN, Z_SOLENOID_MAX); #else myMotor[Z_AXIS][0] = new Nullmotor(); #endif @@ -244,8 +247,11 @@ void init_motors() { // certain motors need features to be turned on. Check them here for (uint8_t axis = X_AXIS; axis < N_AXIS; axis++) { for (uint8_t gang_index = 0; gang_index < 2; gang_index++) { - if (myMotor[axis][gang_index]->type_id == RC_SERVO_MOTOR) need_servo_task = true; - if (myMotor[axis][gang_index]->type_id == UNIPOLAR_MOTOR) motor_class_steps = true; + if (myMotor[axis][gang_index]->type_id == RC_SERVO_MOTOR || myMotor[axis][gang_index]->type_id == SOLENOID) + need_servo_task = true; + + if (myMotor[axis][gang_index]->type_id == UNIPOLAR_MOTOR) + motor_class_steps = true; } } diff --git a/Grbl_Esp32/Motors/MotorClass.h b/Grbl_Esp32/Motors/MotorClass.h index 64000737..0c1fa8c7 100644 --- a/Grbl_Esp32/Motors/MotorClass.h +++ b/Grbl_Esp32/Motors/MotorClass.h @@ -55,6 +55,7 @@ #include // https://github.com/teemuatlut/TMCStepper #include "TrinamicDriverClass.h" #include "RcServoClass.h" +#include "SolenoidClass.h" extern uint8_t rmt_chan_num[MAX_AXES][2]; extern rmt_item32_t rmtItem[2]; @@ -66,7 +67,8 @@ typedef enum { STANDARD_MOTOR, TRINAMIC_SPI_MOTOR, UNIPOLAR_MOTOR, - RC_SERVO_MOTOR + RC_SERVO_MOTOR, + SOLENOID } motor_class_id_t; // ========== global functions =================== @@ -108,7 +110,7 @@ class Motor { protected: uint8_t axis_index; // X_AXIS, etc uint8_t dual_axis_index; // 0 = primary 1=ganged - + bool _showError; bool _use_mpos = true; bool _is_homing; @@ -187,27 +189,41 @@ class RcServo : public Motor { public: RcServo(); RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max); - void config_message(); - void init(); + virtual void config_message(); + virtual void init(); void _write_pwm(uint32_t duty); - void set_disable(bool disable); - void update(); + virtual void set_disable(bool disable); + virtual void update(); void read_settings(); - private: + protected: void set_location(); void _get_calibration(); uint8_t _pwm_pin; uint8_t _channel_num; uint32_t _current_pwm_duty; + bool _disabled; float _position_min; float _position_max; // position in millimeters float _homing_position; - float servo_pulse_min; - float servo_pulse_max; + float _pwm_pulse_min; + float _pwm_pulse_max; +}; + +class Solenoid : public RcServo { + public: + Solenoid(); + Solenoid(uint8_t axis_index, gpio_num_t pwm_pin, float transition_poiont); + void config_message(); + void set_location(); + void update(); + void init(); + void set_disable(bool disable); + + float _transition_poiont; }; #endif diff --git a/Grbl_Esp32/Motors/RcServoClass.cpp b/Grbl_Esp32/Motors/RcServoClass.cpp index c6011adc..54f0780f 100644 --- a/Grbl_Esp32/Motors/RcServoClass.cpp +++ b/Grbl_Esp32/Motors/RcServoClass.cpp @@ -56,11 +56,8 @@ RcServo :: RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max) { this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged this->_pwm_pin = pwm_pin; _position_min = min; - _position_max = max; - set_axis_name(); - init(); - config_message(); - is_active = true; // as opposed to NullMotors, this is a real motor + _position_max = max; + init(); } void RcServo :: init() { @@ -69,6 +66,9 @@ void RcServo :: init() { ledcSetup(_channel_num, SERVO_PULSE_FREQ, SERVO_PULSE_RES_BITS); ledcAttachPin(_pwm_pin, _channel_num); _current_pwm_duty = 0; + is_active = true; // as opposed to NullMotors, this is a real motor + set_axis_name(); + config_message(); } void RcServo :: config_message() { @@ -94,11 +94,15 @@ void RcServo::_write_pwm(uint32_t duty) { // sets the PWM to zero. This allows most servos to be manually moved void RcServo::set_disable(bool disable) { - if (disable) + _disabled = disable; + if (_disabled) _write_pwm(0); } void RcServo::update() { + if (_disabled) + return; + set_location(); } @@ -128,7 +132,7 @@ void RcServo::set_location() { } // determine the pulse length - servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, servo_pulse_min, servo_pulse_max); + servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, _pwm_pulse_min, _pwm_pulse_max); _write_pwm(servo_pulse_len); } @@ -163,14 +167,14 @@ void RcServo::_get_calibration() { write_global_settings(); // they were changed, so write them } - servo_pulse_min = SERVO_MIN_PULSE; - servo_pulse_max = SERVO_MAX_PULSE; + _pwm_pulse_min = SERVO_MIN_PULSE; + _pwm_pulse_max = SERVO_MAX_PULSE; // apply inverts and store them in local variable if (bit_istrue(settings.dir_invert_mask, bit(axis_index))) { // normal direction _cal_min = 2.0 - (settings.steps_per_mm[axis_index] / 100.0); _cal_max = 2.0 - (settings.max_travel[axis_index] / -100.0); - swap(servo_pulse_min, servo_pulse_max); + swap(_pwm_pulse_min, _pwm_pulse_max); } else { // inverted direction _cal_min = (settings.steps_per_mm[axis_index] / 100.0); //_cal_max = 2.0 - (settings.max_travel[axis_index] / -100.0); @@ -179,7 +183,7 @@ void RcServo::_get_calibration() { //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration min%1.2f max %1.2f", _cal_min, _cal_max ); - servo_pulse_min *= _cal_min; - servo_pulse_max *= _cal_max; + _pwm_pulse_min *= _cal_min; + _pwm_pulse_max *= _cal_max; } diff --git a/Grbl_Esp32/Motors/SolenoidClass.cpp b/Grbl_Esp32/Motors/SolenoidClass.cpp new file mode 100644 index 00000000..04ed90c6 --- /dev/null +++ b/Grbl_Esp32/Motors/SolenoidClass.cpp @@ -0,0 +1,119 @@ +/* + The solenoid monitors the current position of the Axis + it is assigned to. It uses a max and max position value and a max and min pulse + length. + + The solenoid turns on when it is equal to or greater than _position_max + + Tests + - Does it turn on at the transition point? + - Doess hold duration an reduction work? + - Does $3 reverse the direction? + - Do homing work to move axis and set pulse currectly + - Does diable work? + + +*/ + +Solenoid :: Solenoid(uint8_t axis_index, gpio_num_t pwm_pin, float transition_poiont) { + type_id = SOLENOID; + this->axis_index = axis_index % MAX_AXES; + this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged + this->_pwm_pin = pwm_pin; + _transition_poiont = transition_poiont; + init(); +} + +void Solenoid :: init() { + //read_settings(); + _channel_num = sys_get_next_PWM_chan_num(); + ledcSetup(_channel_num, SOLENOID_PULSE_FREQ, SOLENOID_PULSE_RES_BITS); + ledcAttachPin(_pwm_pin, _channel_num); + _current_pwm_duty = 0; + is_active = true; // as opposed to NullMotors, this is a real motor + set_axis_name(); + config_message(); +} + +void Solenoid :: config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "%s Axis Solenoid Output:%d Max:%5.3fmm", + _axis_name, + _pwm_pin, + _transition_poiont); +} + +void Solenoid::set_disable(bool disable) { + if (disable && SOLENOID_ALLOW_DISABLE) + _write_pwm(0); + + _disabled = disable; +} + +void Solenoid::update() { + set_location(); +} + +void Solenoid::set_location() { + float solenoid_pos, mpos, offset; + uint32_t duty; + static uint8_t hold_counter; + static uint32_t last_duty = 0; + + if (_disabled && SOLENOID_ALLOW_DISABLE) + return; + + _pwm_pulse_min = SOLENOID_MIN_PULSE; + _pwm_pulse_max = SOLENOID_MAX_PULSE; + + // Is direction reversed via the $3 command? + if (bit_istrue(settings.dir_invert_mask, bit(axis_index))) // normal direction + swap(_pwm_pulse_min, _pwm_pulse_max); + + // $23 sets homing direction bit_true homes in positive direction + if (sys.state == STATE_HOMING) { + bool home_positive; + home_positive = bit_isfalse(settings.homing_dir_mask, bit(axis_index)); // no bit = home positive + + if (bit_istrue(settings.dir_invert_mask, bit(axis_index))) + home_positive = ! home_positive; + + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Solenoid Home Pos2:%d", _axis_name, home_positive); + + if (home_positive) + duty = _pwm_pulse_max; + else + duty = _pwm_pulse_min; + + } else { + mpos = system_convert_axis_steps_to_mpos(sys_position, axis_index); // get the axis machine position in mm + offset = gc_state.coord_system[axis_index] + gc_state.coord_offset[axis_index]; // get the current axis work offset + solenoid_pos = mpos - offset; // determine the current work position + + if (solenoid_pos >= _position_max) + duty = _pwm_pulse_max; + else + duty = _pwm_pulse_min; + } + + + if (duty != last_duty) { + hold_counter = 0; // reset the hold counter + last_duty = duty; // remember the duty + } else { + if (duty != SOLENOID_MIN_PULSE) { + if (hold_counter >= SOLENOID_HOLD_DELAY) { + duty *= (SOLENOID_HOLD_PERCENTAGE / 100.0); // apply the hold current + } else + hold_counter++; + } + } + + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Solenoid Pwm %d", _axis_name, duty); + + _write_pwm(duty); + + +} + diff --git a/Grbl_Esp32/Motors/SolenoidClass.h b/Grbl_Esp32/Motors/SolenoidClass.h new file mode 100644 index 00000000..c6674312 --- /dev/null +++ b/Grbl_Esp32/Motors/SolenoidClass.h @@ -0,0 +1,25 @@ + + +#define SOLENOID_PULSE_FREQ 5000 // 50Hz ...This is a standard analog servo value. Digital ones can repeat faster + +#define SOLENOID_PULSE_RES_BITS 10 // bits of resolution of PWM (16 is max) + +#ifndef SOLENOID_MIN_PULSE + #define SOLENOID_MIN_PULSE 0 +#endif + +#ifndef SOLENOID_MAX_PULSE + #define SOLENOID_MAX_PULSE 1024 +#endif + +#ifndef SOLENOID_HOLD_DELAY + #define SOLENOID_HOLD_DELAY 10 // task counts +#endif + +#ifndef SOLENOID_HOLD_PERCENTAGE + #define SOLENOID_HOLD_PERCENTAGE 60.0 // percent of SOLENOID_MAX_PULSE +#endif + +#ifndef SOLENOID_ALLOW_DISABLE + #define SOLENOID_ALLOW_DISABLE false +#endif \ No newline at end of file