1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-09-02 19:02:35 +02:00

Added solenoid class

This commit is contained in:
bdring
2020-05-17 09:27:14 -05:00
parent 68495f9d45
commit 253c2dac8b
10 changed files with 226 additions and 28 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -30,7 +30,6 @@
#endif
#define N_AXIS 3
#define USE_TRINAMIC
#define TRINAMIC_DAISY_CHAIN
// Use SPI enable instead of the enable pin

View File

@@ -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

View File

@@ -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?

View File

@@ -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;
}
}

View File

@@ -55,6 +55,7 @@
#include <TMCStepper.h> // 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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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