mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-09-07 04:40:43 +02:00
Devt (#571)
* Handles Tranimic drivers errors better - If an unsupported driver is specified, it will give a message and not crash. * Cleaned up unused files Got rid of old unipolar files Got rid of servo axis feature - it is a motor class now Got rid of solenoid pen feature - never really used and it should be a motor class if it is. * Fix ENABLE_AUTHENTICATION (#569) * Fixed authentication code. * Removed another const cast Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com> * Fix step leakage with inverted steps (#570) * Fix step leakage with inverted steps * Update build date for merge Co-authored-by: Bart Dring <bdring@buildlog.net> Co-authored-by: Stefan de Bruijn <atlaste@users.noreply.github.com> Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com> Co-authored-by: Mitch Bradley <wmb@firmworks.com> Co-authored-by: Bart Dring <bdring@buildlog.net>
This commit is contained in:
@@ -45,12 +45,7 @@ void grbl_init() {
|
|||||||
#ifdef USE_PEN_SERVO
|
#ifdef USE_PEN_SERVO
|
||||||
servo_init();
|
servo_init();
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_SERVO_AXES
|
|
||||||
init_servos();
|
|
||||||
#endif
|
|
||||||
#ifdef USE_PEN_SOLENOID
|
|
||||||
solenoid_init();
|
|
||||||
#endif
|
|
||||||
#ifdef USE_MACHINE_INIT
|
#ifdef USE_MACHINE_INIT
|
||||||
machine_init(); // user supplied function for special initialization
|
machine_init(); // user supplied function for special initialization
|
||||||
#endif
|
#endif
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
// Grbl versioning system
|
// Grbl versioning system
|
||||||
|
|
||||||
#define GRBL_VERSION "1.3a"
|
#define GRBL_VERSION "1.3a"
|
||||||
#define GRBL_VERSION_BUILD "20200823"
|
#define GRBL_VERSION_BUILD "20200828"
|
||||||
|
|
||||||
//#include <sdkconfig.h>
|
//#include <sdkconfig.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@@ -85,12 +85,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "SolenoidPen.h"
|
|
||||||
|
|
||||||
#ifdef USE_SERVO_AXES
|
|
||||||
# include "ServoAxis.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_I2S_OUT
|
#ifdef USE_I2S_OUT
|
||||||
# include "I2SOut.h"
|
# include "I2SOut.h"
|
||||||
#endif
|
#endif
|
||||||
|
83
Grbl_Esp32/src/Machines/3_pack_v1.h
Normal file
83
Grbl_Esp32/src/Machines/3_pack_v1.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#pragma once
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
/*
|
||||||
|
3_pack_v1.h
|
||||||
|
|
||||||
|
Covers all V1 versions V1p0, V1p1, etc
|
||||||
|
|
||||||
|
Part of Grbl_ESP32
|
||||||
|
Pin assignments for the ESP32 I2S 6-axis board
|
||||||
|
|
||||||
|
2020 - Bart Dring
|
||||||
|
|
||||||
|
Grbl_ESP32 is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
Grbl is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Grbl_ESP32. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#define MACHINE_NAME "3 Pack Controller V1"
|
||||||
|
|
||||||
|
|
||||||
|
#define USE_STEPSTICK // makes sure MS1,2,3 !reset and !sleep are set
|
||||||
|
|
||||||
|
#define X_STEPPER_MS3 GPIO_NUM_4 // X_CS (works for all drivers on this board)
|
||||||
|
|
||||||
|
#define X_STEP_PIN GPIO_NUM_32
|
||||||
|
#define X_DIRECTION_PIN GPIO_NUM_27
|
||||||
|
|
||||||
|
#define Y_STEP_PIN GPIO_NUM_33
|
||||||
|
#define Y_DIRECTION_PIN GPIO_NUM_26
|
||||||
|
|
||||||
|
#define Z_STEP_PIN GPIO_NUM_25
|
||||||
|
#define Z_DIRECTION_PIN GPIO_NUM_17
|
||||||
|
|
||||||
|
#define STEPPERS_DISABLE_PIN GPIO_NUM_16
|
||||||
|
|
||||||
|
/* Socket #1 ref
|
||||||
|
#1 GPIO_NUM_36 // Input Only (X_LIMIT_PIN)
|
||||||
|
#2 GPIO_NUM_39 // Input Only (Y_LIMIT_PIN)
|
||||||
|
#4 GPIO_NUM_34 // Input Only (Z_LIMIT_PIN)
|
||||||
|
#4 GPIO_NUM_35 // Input Only
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Socket #2 ref
|
||||||
|
#1 GPIO_NUM_2
|
||||||
|
#2 GPIO_NUM_21
|
||||||
|
#4 GPIO_NUM_22
|
||||||
|
#4 N/C
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Socket #3 ref
|
||||||
|
#1 GPIO_NUM_14
|
||||||
|
#2 GPIO_NUM_13
|
||||||
|
#4 GPIO_NUM_15
|
||||||
|
#4 GPIO_NUM_12
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Socket #1
|
||||||
|
#define X_LIMIT_PIN GPIO_NUM_36
|
||||||
|
#define Y_LIMIT_PIN GPIO_NUM_39
|
||||||
|
#define Z_LIMIT_PIN GPIO_NUM_34
|
||||||
|
#define PROBE_PIN GPIO_NUM_35
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Socket #3 5V Output
|
||||||
|
#define SPINDLE_TYPE SPINDLE_TYPE_LASER
|
||||||
|
#define SPINDLE_OUTPUT_PIN GPIO_NUM_14 // labeled SpinPWM
|
||||||
|
#define SPINDLE_ENABLE_PIN GPIO_NUM_13 // labeled SpinEnbl
|
||||||
|
#define COOLANT_MIST_PIN GPIO_NUM_15
|
||||||
|
#define COOLANT_FLOOD_PIN GPIO_NUM_12
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Socket #3 5V Output
|
||||||
|
#define USER_DIGITAL_PIN_1 GPIO_NUM_14
|
||||||
|
#define USER_DIGITAL_PIN_2 GPIO_NUM_13
|
||||||
|
#define USER_DIGITAL_PIN_3 GPIO_NUM_15
|
||||||
|
#define USER_DIGITAL_PIN_4 GPIO_NUM_12
|
@@ -132,14 +132,10 @@
|
|||||||
// === Servos
|
// === Servos
|
||||||
// To use a servo motor on an axis, do not define step and direction
|
// To use a servo motor on an axis, do not define step and direction
|
||||||
// pins for that axis, but instead include a block like this:
|
// pins for that axis, but instead include a block like this:
|
||||||
//#define USE_SERVO_AXES
|
|
||||||
|
|
||||||
//#define SERVO_Z_PIN GPIO_NUM_15 // It cannot be used when JTAG debugging
|
//#define SERVO_Z_PIN GPIO_NUM_15 // It cannot be used when JTAG debugging
|
||||||
//#define SERVO_Z_RANGE_MIN 0.0
|
//#define SERVO_Z_RANGE_MIN 0.0
|
||||||
//#define SERVO_Z_RANGE_MAX 5.0
|
//#define SERVO_Z_RANGE_MAX 5.0
|
||||||
//#define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
|
|
||||||
//#define SERVO_Z_HOME_POS SERVO_Z_RANGE_MAX // move to max during homing
|
|
||||||
//#define SERVO_Z_MPOS false // will not use mpos, uses work coordinates
|
|
||||||
|
|
||||||
// === Homing cycles
|
// === Homing cycles
|
||||||
// The default homing order is Z first (HOMING_CYCLE_0),
|
// The default homing order is Z first (HOMING_CYCLE_0),
|
||||||
|
@@ -52,20 +52,13 @@
|
|||||||
// C is a servo
|
// C is a servo
|
||||||
|
|
||||||
// servos
|
// servos
|
||||||
#define USE_SERVO_AXES
|
|
||||||
#define SERVO_Z_PIN GPIO_NUM_22
|
#define SERVO_Z_PIN GPIO_NUM_22
|
||||||
#define SERVO_Z_RANGE_MIN 0.0
|
#define SERVO_Z_RANGE_MIN 0.0
|
||||||
#define SERVO_Z_RANGE_MAX 5.0
|
#define SERVO_Z_RANGE_MAX 5.0
|
||||||
#define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
|
|
||||||
#define SERVO_Z_HOME_POS SERVO_Z_RANGE_MAX // move to max during homing
|
|
||||||
#define SERVO_Z_MPOS false // will not use mpos, uses work coordinates
|
|
||||||
|
|
||||||
#define SERVO_C_PIN GPIO_NUM_2
|
#define SERVO_C_PIN GPIO_NUM_2
|
||||||
#define SERVO_C_RANGE_MIN 0.0
|
#define SERVO_C_RANGE_MIN 0.0
|
||||||
#define SERVO_C_RANGE_MAX 5.0
|
#define SERVO_C_RANGE_MAX 5.0
|
||||||
#define SERVO_C_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
|
|
||||||
#define SERVO_C_HOME_POS SERVO_C_RANGE_MAX // move to max during homing
|
|
||||||
#define SERVO_C_MPOS false // will not use mpos, uses work coordinates
|
|
||||||
|
|
||||||
// limit switches
|
// limit switches
|
||||||
#define X_LIMIT_PIN GPIO_NUM_21
|
#define X_LIMIT_PIN GPIO_NUM_21
|
||||||
|
@@ -52,7 +52,6 @@
|
|||||||
#define Y_LIMIT_PIN GPIO_NUM_4
|
#define Y_LIMIT_PIN GPIO_NUM_4
|
||||||
|
|
||||||
#define USING_SERVO // uncomment to use this feature
|
#define USING_SERVO // uncomment to use this feature
|
||||||
//#define USING_SOLENOID // uncomment to use this feature
|
|
||||||
|
|
||||||
#ifdef USING_SERVO
|
#ifdef USING_SERVO
|
||||||
#define Z_SERVO_PIN GPIO_NUM_27
|
#define Z_SERVO_PIN GPIO_NUM_27
|
||||||
@@ -60,11 +59,6 @@
|
|||||||
#define Z_SERVO_RANGE_MAX 10.0
|
#define Z_SERVO_RANGE_MAX 10.0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USING_SOLENOID
|
|
||||||
#define USE_PEN_SOLENOID
|
|
||||||
#define SOLENOID_PEN_PIN GPIO_NUM_16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SPINDLE_TYPE SPINDLE_TYPE_NONE
|
#define SPINDLE_TYPE SPINDLE_TYPE_NONE
|
||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
|
@@ -130,14 +130,10 @@
|
|||||||
// === Servos
|
// === Servos
|
||||||
// To use a servo motor on an axis, do not define step and direction
|
// To use a servo motor on an axis, do not define step and direction
|
||||||
// pins for that axis, but instead include a block like this:
|
// pins for that axis, but instead include a block like this:
|
||||||
// #define USE_SERVO_AXES
|
|
||||||
|
|
||||||
// #define SERVO_Z_PIN GPIO_NUM_22
|
// #define SERVO_Z_PIN GPIO_NUM_22
|
||||||
// #define SERVO_Z_RANGE_MIN 0.0
|
// #define SERVO_Z_RANGE_MIN 0.0
|
||||||
// #define SERVO_Z_RANGE_MAX 5.0
|
// #define SERVO_Z_RANGE_MAX 5.0
|
||||||
// #define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
|
|
||||||
// #define SERVO_Z_HOME_POS SERVO_Z_RANGE_MAX // move to max during homing
|
|
||||||
// #define SERVO_Z_MPOS false // will not use mpos, uses work coordinates
|
|
||||||
|
|
||||||
// === Homing cycles
|
// === Homing cycles
|
||||||
// The default homing order is Z first (HOMING_CYCLE_0),
|
// The default homing order is Z first (HOMING_CYCLE_0),
|
||||||
|
@@ -57,22 +57,10 @@
|
|||||||
#define STEPPERS_DISABLE_PIN GPIO_NUM_13
|
#define STEPPERS_DISABLE_PIN GPIO_NUM_13
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Define one of these 2 options for spindle or servo
|
// Define one of these 2 options for spindle or servo
|
||||||
#define USE_SERVO_AXES
|
#define Z_SERVO_PIN GPIO_NUM_27 // comment this out if PWM spindle/laser control.
|
||||||
//#define USE_SPINDLE
|
#define Z_SERVO_RANGE_MIN 0.0
|
||||||
|
#define Z_SERVO_RANGE_MAX 5.0
|
||||||
#ifdef USE_SERVO_AXES
|
|
||||||
#define SPINDLE_TYPE SPINDLE_TYPE_NONE
|
|
||||||
|
|
||||||
#define Z_SERVO_PIN GPIO_NUM_27 // comment this out if PWM spindle/laser control.
|
|
||||||
#define Z_SERVO_RANGE_MIN 0.0
|
|
||||||
#define Z_SERVO_RANGE_MAX 5.0
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define SPINDLE_TYPE SPINDLE_TYPE_PWM
|
|
||||||
#define SPINDLE_OUTPUT_PIN GPIO_NUM_27
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// #define X_LIMIT_PIN See version section at beginning of file
|
// #define X_LIMIT_PIN See version section at beginning of file
|
||||||
#define Y_LIMIT_PIN GPIO_NUM_4
|
#define Y_LIMIT_PIN GPIO_NUM_4
|
||||||
|
@@ -52,10 +52,11 @@ namespace Motors {
|
|||||||
|
|
||||||
motor_class_id_t type_id;
|
motor_class_id_t type_id;
|
||||||
uint8_t is_active = false;
|
uint8_t is_active = false;
|
||||||
|
uint8_t has_errors = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint8_t axis_index; // X_AXIS, etc
|
uint8_t axis_index; // X_AXIS, etc
|
||||||
uint8_t dual_axis_index; // 0 = primary 1=ganged
|
uint8_t dual_axis_index; // 0 = primary 1=ganged
|
||||||
|
|
||||||
bool _showError;
|
bool _showError;
|
||||||
bool _use_mpos = true;
|
bool _use_mpos = true;
|
||||||
|
@@ -220,8 +220,9 @@ void init_motors() {
|
|||||||
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Using StepStick Mode");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Using StepStick Mode");
|
||||||
|
|
||||||
uint8_t ms3_pins[MAX_N_AXIS][2] = { { X_STEPPER_MS3, X2_STEPPER_MS3 }, { Y_STEPPER_MS3, Y2_STEPPER_MS3 }, { Z_STEPPER_MS3, Z2_STEPPER_MS3 },
|
uint8_t ms3_pins[MAX_N_AXIS][2] = { { X_STEPPER_MS3, X2_STEPPER_MS3 }, { Y_STEPPER_MS3, Y2_STEPPER_MS3 },
|
||||||
{ A_STEPPER_MS3, A2_STEPPER_MS3 }, { B_STEPPER_MS3, B2_STEPPER_MS3 }, { C_STEPPER_MS3, C2_STEPPER_MS3 } };
|
{ Z_STEPPER_MS3, Z2_STEPPER_MS3 }, { A_STEPPER_MS3, A2_STEPPER_MS3 },
|
||||||
|
{ B_STEPPER_MS3, B2_STEPPER_MS3 }, { C_STEPPER_MS3, C2_STEPPER_MS3 } };
|
||||||
|
|
||||||
for (int axis = 0; axis < N_AXIS; axis++) {
|
for (int axis = 0; axis < N_AXIS; axis++) {
|
||||||
for (int gang_index = 0; gang_index < 2; gang_index++) {
|
for (int gang_index = 0; gang_index < 2; gang_index++) {
|
||||||
@@ -333,8 +334,9 @@ void motors_set_disable(bool disable) {
|
|||||||
|
|
||||||
// now loop through all the motors to see if they can individually diable
|
// now loop through all the motors to see if they can individually diable
|
||||||
for (uint8_t gang_index = 0; gang_index < MAX_GANGED; gang_index++) {
|
for (uint8_t gang_index = 0; gang_index < MAX_GANGED; gang_index++) {
|
||||||
for (uint8_t axis = X_AXIS; axis < N_AXIS; axis++)
|
for (uint8_t axis = X_AXIS; axis < N_AXIS; axis++) {
|
||||||
myMotor[axis][gang_index]->set_disable(disable);
|
myMotor[axis][gang_index]->set_disable(disable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,16 +44,17 @@ namespace Motors {
|
|||||||
_homing_mode = TRINAMIC_HOMING_MODE;
|
_homing_mode = TRINAMIC_HOMING_MODE;
|
||||||
_homing_mask = 0; // no axes homing
|
_homing_mask = 0; // no axes homing
|
||||||
|
|
||||||
|
set_axis_name();
|
||||||
|
|
||||||
if (_driver_part_number == 2130)
|
if (_driver_part_number == 2130)
|
||||||
tmcstepper = new TMC2130Stepper(cs_pin, _r_sense, spi_index);
|
tmcstepper = new TMC2130Stepper(cs_pin, _r_sense, spi_index);
|
||||||
else if (_driver_part_number == 5160)
|
else if (_driver_part_number == 5160)
|
||||||
tmcstepper = new TMC5160Stepper(cs_pin, _r_sense, spi_index);
|
tmcstepper = new TMC5160Stepper(cs_pin, _r_sense, spi_index);
|
||||||
else {
|
else {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Trinamic unsupported p/n:%d", _driver_part_number);
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Axis Unsupported Trinamic part number TMC%d", _axis_name, _driver_part_number);
|
||||||
|
has_errors = true; // as opposed to NullMotors, this is a real motor
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_axis_name();
|
|
||||||
|
|
||||||
init_step_dir_pins(); // from StandardStepper
|
init_step_dir_pins(); // from StandardStepper
|
||||||
|
|
||||||
@@ -70,6 +71,9 @@ namespace Motors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TrinamicDriver::init() {
|
void TrinamicDriver::init() {
|
||||||
|
if (has_errors)
|
||||||
|
return;
|
||||||
|
|
||||||
SPI.begin(); // this will get called for each motor, but does not seem to hurt anything
|
SPI.begin(); // this will get called for each motor, but does not seem to hurt anything
|
||||||
|
|
||||||
tmcstepper->begin();
|
tmcstepper->begin();
|
||||||
@@ -78,7 +82,7 @@ namespace Motors {
|
|||||||
set_mode(false);
|
set_mode(false);
|
||||||
|
|
||||||
_homing_mask = 0;
|
_homing_mask = 0;
|
||||||
is_active = true; // as opposed to NullMotors, this is a real motor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -98,6 +102,8 @@ namespace Motors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TrinamicDriver::test() {
|
bool TrinamicDriver::test() {
|
||||||
|
if (has_errors)
|
||||||
|
return false;
|
||||||
switch (tmcstepper->test_connection()) {
|
switch (tmcstepper->test_connection()) {
|
||||||
case 1:
|
case 1:
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check connection", _axis_name);
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check connection", _axis_name);
|
||||||
@@ -148,6 +154,8 @@ namespace Motors {
|
|||||||
float hold (as a percentage of run)
|
float hold (as a percentage of run)
|
||||||
*/
|
*/
|
||||||
void TrinamicDriver::read_settings() {
|
void TrinamicDriver::read_settings() {
|
||||||
|
if (has_errors)
|
||||||
|
return;
|
||||||
uint16_t run_i_ma = (uint16_t)(axis_settings[axis_index]->run_current->get() * 1000.0);
|
uint16_t run_i_ma = (uint16_t)(axis_settings[axis_index]->run_current->get() * 1000.0);
|
||||||
float hold_i_percent;
|
float hold_i_percent;
|
||||||
|
|
||||||
@@ -175,6 +183,8 @@ namespace Motors {
|
|||||||
Coolstep mode, so it will need to switch to Coolstep when homing
|
Coolstep mode, so it will need to switch to Coolstep when homing
|
||||||
*/
|
*/
|
||||||
void TrinamicDriver::set_mode(bool isHoming) {
|
void TrinamicDriver::set_mode(bool isHoming) {
|
||||||
|
if (has_errors)
|
||||||
|
return;
|
||||||
if (isHoming)
|
if (isHoming)
|
||||||
_mode = TRINAMIC_HOMING_MODE;
|
_mode = TRINAMIC_HOMING_MODE;
|
||||||
else
|
else
|
||||||
@@ -216,6 +226,8 @@ namespace Motors {
|
|||||||
This is the stallguard tuning info. It is call debug, so it could be generic across all classes.
|
This is the stallguard tuning info. It is call debug, so it could be generic across all classes.
|
||||||
*/
|
*/
|
||||||
void TrinamicDriver::debug_message() {
|
void TrinamicDriver::debug_message() {
|
||||||
|
if (has_errors)
|
||||||
|
return;
|
||||||
uint32_t tstep = tmcstepper->TSTEP();
|
uint32_t tstep = tmcstepper->TSTEP();
|
||||||
|
|
||||||
if (tstep == 0xFFFFF || tstep < 1) // if axis is not moving return
|
if (tstep == 0xFFFFF || tstep < 1) // if axis is not moving return
|
||||||
@@ -247,7 +259,8 @@ namespace Motors {
|
|||||||
// this can use the enable feature over SPI. The dedicated pin must be in the enable mode,
|
// this can use the enable feature over SPI. The dedicated pin must be in the enable mode,
|
||||||
// but that can be hardwired that way.
|
// but that can be hardwired that way.
|
||||||
void TrinamicDriver::set_disable(bool disable) {
|
void TrinamicDriver::set_disable(bool disable) {
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Axis disable %d", _axis_name, disable);
|
if (has_errors)
|
||||||
|
return;
|
||||||
|
|
||||||
digitalWrite(disable_pin, disable);
|
digitalWrite(disable_pin, disable);
|
||||||
|
|
||||||
|
@@ -1,382 +0,0 @@
|
|||||||
/*
|
|
||||||
ServoAxis.cpp
|
|
||||||
Part of Grbl_ESP32
|
|
||||||
|
|
||||||
copyright (c) 2018 - Bart Dring. This file was intended for use on the ESP32
|
|
||||||
CPU. Do not use this with Grbl for atMega328P
|
|
||||||
|
|
||||||
Grbl is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Grbl is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
See ServoAxis.h for more details
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Grbl.h"
|
|
||||||
|
|
||||||
#include "ServoAxis.h"
|
|
||||||
|
|
||||||
#ifdef USE_SERVO_AXES
|
|
||||||
|
|
||||||
static TaskHandle_t servosSyncTaskHandle = 0;
|
|
||||||
|
|
||||||
# ifdef SERVO_X_PIN
|
|
||||||
ServoAxis X_Servo_Axis(X_AXIS, SERVO_X_PIN);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Y_PIN
|
|
||||||
ServoAxis Y_Servo_Axis(Y_AXIS, SERVO_Y_PIN);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Z_PIN
|
|
||||||
ServoAxis Z_Servo_Axis(Z_AXIS, SERVO_Z_PIN);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef SERVO_A_PIN
|
|
||||||
ServoAxis A_Servo_Axis(A_AXIS, SERVO_A_PIN);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_B_PIN
|
|
||||||
ServoAxis B_Servo_Axis(B_AXIS, SERVO_B_PIN);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_C_PIN
|
|
||||||
ServoAxis C_Servo_Axis(C_AXIS, SERVO_C_PIN);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
void init_servos() {
|
|
||||||
// ======================== X Axis ===========================
|
|
||||||
# ifdef SERVO_X_PIN
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "X Servo range %4.3f to %4.3f", SERVO_X_RANGE_MIN, SERVO_X_RANGE_MAX);
|
|
||||||
X_Servo_Axis.init();
|
|
||||||
X_Servo_Axis.set_range(SERVO_X_RANGE_MIN, SERVO_X_RANGE_MAX);
|
|
||||||
# ifdef SERVO_X_HOMING_TYPE
|
|
||||||
X_Servo_Axis.set_homing_type(SERVO_X_HOMING_TYPE);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_X_HOME_POS
|
|
||||||
X_Servo_Axis.set_homing_position(SERVO_X_HOME_POS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_X_MPOS // value should be true or false
|
|
||||||
X_Servo_Axis.set_use_mpos(SERVO_X_MPOS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_X_DISABLE_ON_ALARM
|
|
||||||
set_disable_on_alarm(SERVO_X_DISABLE_ON_ALARM);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_X_DISABLE_WITH_STEPPERS
|
|
||||||
set_disable_with_steppers(SERVO_X_DISABLE_WITH_STEPPERS);
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
// ======================== Y Axis ===========================
|
|
||||||
# ifdef SERVO_Y_PIN
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Y Servo range %4.3f to %4.3f", SERVO_Y_RANGE_MIN, SERVO_Y_RANGE_MAX);
|
|
||||||
Y_Servo_Axis.init();
|
|
||||||
Y_Servo_Axis.set_range(SERVO_Y_RANGE_MIN, SERVO_Y_RANGE_MAX);
|
|
||||||
# ifdef SERVO_Y_HOMING_TYPE
|
|
||||||
Y_Servo_Axis.set_homing_type(SERVO_Y_HOMING_TYPE);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Y_HOME_POS
|
|
||||||
Y_Servo_Axis.set_homing_position(SERVO_Y_HOME_POS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Y_MPOS // value should be true or false
|
|
||||||
Y_Servo_Axis.set_use_mpos(SERVO_Y_MPOS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Y_DISABLE_ON_ALARM
|
|
||||||
set_disable_on_alarm(SERVO_Y_DISABLE_ON_ALARM);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Y_DISABLE_WITH_STEPPERS
|
|
||||||
set_disable_with_steppers(SERVO_Y_DISABLE_WITH_STEPPERS);
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
// ======================== Z Axis ===========================
|
|
||||||
# ifdef SERVO_Z_PIN
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Z Servo range %4.3f to %4.3f", SERVO_Z_RANGE_MIN, SERVO_Z_RANGE_MAX);
|
|
||||||
Z_Servo_Axis.init();
|
|
||||||
Z_Servo_Axis.set_range(SERVO_Z_RANGE_MIN, SERVO_Z_RANGE_MAX);
|
|
||||||
# ifdef SERVO_Z_HOMING_TYPE
|
|
||||||
Z_Servo_Axis.set_homing_type(SERVO_Z_HOMING_TYPE);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Z_HOME_POS
|
|
||||||
Z_Servo_Axis.set_homing_position(SERVO_Z_HOME_POS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Z_MPOS // value should be true or false
|
|
||||||
Z_Servo_Axis.set_use_mpos(SERVO_Z_MPOS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Z_DISABLE_ON_ALARM
|
|
||||||
set_disable_on_alarm(SERVO_Z_DISABLE_ON_ALARM);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Z_DISABLE_WITH_STEPPERS
|
|
||||||
set_disable_with_steppers(SERVO_Z_DISABLE_WITH_STEPPERS);
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
// ======================== A Axis ===========================
|
|
||||||
# ifdef SERVO_A_PIN
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "A Servo range %4.3f to %4.3f", SERVO_A_RANGE_MIN, SERVO_A_RANGE_MAX);
|
|
||||||
A_Servo_Axis.init();
|
|
||||||
A_Servo_Axis.set_range(SERVO_A_RANGE_MIN, SERVO_A_RANGE_MAX);
|
|
||||||
# ifdef SERVO_A_HOMING_TYPE
|
|
||||||
A_Servo_Axis.set_homing_type(SERVO_A_HOMING_TYPE);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_A_HOME_POS
|
|
||||||
A_Servo_Axis.set_homing_position(SERVO_A_HOME_POS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_A_MPOS // value should be true or false
|
|
||||||
A_Servo_Axis.set_use_mpos(SERVO_A_MPOS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_A_DISABLE_ON_ALARM
|
|
||||||
set_disable_on_alarm(SERVO_A_DISABLE_ON_ALARM);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_A_DISABLE_WITH_STEPPERS
|
|
||||||
set_disable_with_steppers(SERVO_A_DISABLE_WITH_STEPPERS);
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
// ======================== B Axis ===========================
|
|
||||||
# ifdef SERVO_B_PIN
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "B Servo range %4.3f to %4.3f", SERVO_B_RANGE_MIN, SERVO_B_RANGE_MAX);
|
|
||||||
B_Servo_Axis.init();
|
|
||||||
B_Servo_Axis.set_range(SERVO_B_RANGE_MIN, SERVO_B_RANGE_MAX);
|
|
||||||
# ifdef SERVO_B_HOMING_TYPE
|
|
||||||
B_Servo_Axis.set_homing_type(SERVO_B_HOMING_TYPE);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_B_HOME_POS
|
|
||||||
B_Servo_Axis.set_homing_position(SERVO_B_HOME_POS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_B_MPOS // value should be true or false
|
|
||||||
B_Servo_Axis.set_use_mpos(SERVO_B_MPOS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_B_DISABLE_ON_ALARM
|
|
||||||
set_disable_on_alarm(SERVO_B_DISABLE_ON_ALARM);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_B_DISABLE_WITH_STEPPERS
|
|
||||||
set_disable_with_steppers(SERVO_B_DISABLE_WITH_STEPPERS);
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
// ======================== C Axis ===========================
|
|
||||||
# ifdef SERVO_C_PIN
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "C Servo range %4.3f to %4.3f", SERVO_C_RANGE_MIN, SERVO_C_RANGE_MAX);
|
|
||||||
C_Servo_Axis.init();
|
|
||||||
C_Servo_Axis.set_range(SERVO_C_RANGE_MIN, SERVO_C_RANGE_MAX);
|
|
||||||
# ifdef SERVO_C_HOMING_TYPE
|
|
||||||
C_Servo_Axis.set_homing_type(SERVO_C_HOMING_TYPE);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_C_HOME_POS
|
|
||||||
C_Servo_Axis.set_homing_position(SERVO_C_HOME_POS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_C_MPOS // value should be true or false
|
|
||||||
C_Servo_Axis.set_use_mpos(SERVO_C_MPOS);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_C_DISABLE_ON_ALARM
|
|
||||||
set_disable_on_alarm(SERVO_C_DISABLE_ON_ALARM);
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_C_DISABLE_WITH_STEPPERS
|
|
||||||
set_disable_with_steppers(SERVO_C_DISABLE_WITH_STEPPERS);
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
// setup a task that will calculate the determine and set the servo positions
|
|
||||||
xTaskCreatePinnedToCore(servosSyncTask, // task
|
|
||||||
"servosSyncTask", // name for task
|
|
||||||
4096, // size of task stack
|
|
||||||
NULL, // parameters
|
|
||||||
1, // priority
|
|
||||||
&servosSyncTaskHandle,
|
|
||||||
0 // core
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is the task
|
|
||||||
void servosSyncTask(void* pvParameters) {
|
|
||||||
TickType_t xLastWakeTime;
|
|
||||||
const TickType_t xServoFrequency = SERVO_TIMER_INT_FREQ; // in ticks (typically ms)
|
|
||||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
|
||||||
while (true) { // don't ever return from this or the task dies
|
|
||||||
# ifdef SERVO_X_PIN
|
|
||||||
X_Servo_Axis.set_location();
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Y_PIN
|
|
||||||
Y_Servo_Axis.set_location();
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_Z_PIN
|
|
||||||
Z_Servo_Axis.set_location();
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_A_PIN
|
|
||||||
A_Servo_Axis.set_location();
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_B_PIN
|
|
||||||
B_Servo_Axis.set_location();
|
|
||||||
# endif
|
|
||||||
# ifdef SERVO_C_PIN
|
|
||||||
C_Servo_Axis.set_location();
|
|
||||||
# endif
|
|
||||||
vTaskDelayUntil(&xLastWakeTime, xServoFrequency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Class Stuff ================================= //
|
|
||||||
|
|
||||||
ServoAxis::ServoAxis(uint8_t axis, uint8_t pin_num) { // constructor
|
|
||||||
_axis = axis;
|
|
||||||
_pin_num = pin_num;
|
|
||||||
_channel_num = sys_get_next_PWM_chan_num();
|
|
||||||
_showError = true; // this will be used to show calibration error only once
|
|
||||||
_use_mpos = true; // default is to use the machine position rather than work position
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServoAxis::init() {
|
|
||||||
_cal_is_valid();
|
|
||||||
ledcSetup(_channel_num, _pwm_freq, _pwm_resolution_bits);
|
|
||||||
ledcAttachPin(_pin_num, _channel_num);
|
|
||||||
disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServoAxis::set_location() {
|
|
||||||
// These are the pulse lengths for the minimum and maximum positions
|
|
||||||
// Note: Some machines will have the physical max/min inverted with pulse length max/min due to invert setting $3=...
|
|
||||||
float servo_pulse_min, servo_pulse_max;
|
|
||||||
float min_pulse_cal, max_pulse_cal; // calibration values in percent 110% = 1.1
|
|
||||||
uint32_t servo_pulse_len;
|
|
||||||
float servo_pos, mpos, offset;
|
|
||||||
// skip location if we are in alarm mode
|
|
||||||
if (_disable_on_alarm && (sys.state == STATE_ALARM)) {
|
|
||||||
disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// track the disable status of the steppers if desired.
|
|
||||||
if (_disable_with_steppers && get_stepper_disable()) {
|
|
||||||
disable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((_homing_type == SERVO_HOMING_TARGET) && (sys.state == STATE_HOMING)) {
|
|
||||||
servo_pos = _homing_position; // go to servos home position
|
|
||||||
} else {
|
|
||||||
mpos = system_convert_axis_steps_to_mpos(sys_position, _axis); // get the axis machine position in mm
|
|
||||||
if (_use_mpos)
|
|
||||||
servo_pos = mpos;
|
|
||||||
else {
|
|
||||||
offset = gc_state.coord_system[_axis] + gc_state.coord_offset[_axis]; // get the current axis work offset
|
|
||||||
servo_pos = mpos - offset; // determine the current work position
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 1. Get the pulse ranges of the servos
|
|
||||||
// 2. Invert if selected in the settings
|
|
||||||
// 3. Get the calibration values from the settings
|
|
||||||
// 4. Adjust the calibration offset direction of the cal based on the direction
|
|
||||||
// 5. Apply the calibrarion
|
|
||||||
servo_pulse_min = SERVO_MIN_PULSE;
|
|
||||||
servo_pulse_max = SERVO_MAX_PULSE;
|
|
||||||
if (bit_istrue(dir_invert_mask->get(), bit(_axis))) // this allows the user to change the direction via settings
|
|
||||||
swap(servo_pulse_min, servo_pulse_max);
|
|
||||||
// get the calibration values
|
|
||||||
if (_cal_is_valid()) { // if calibration settings are OK then apply them
|
|
||||||
// apply a calibration
|
|
||||||
// the cals apply differently if the direction is reverse (i.e. longer pulse is lower position)
|
|
||||||
if (bit_isfalse(dir_invert_mask->get(), bit(_axis))) { // normal direction
|
|
||||||
min_pulse_cal = 2.0 - (axis_settings[_axis]->steps_per_mm->get() / 100.0);
|
|
||||||
max_pulse_cal = (axis_settings[_axis]->max_travel->get() / 100.0);
|
|
||||||
} else { // inverted direction
|
|
||||||
min_pulse_cal = (axis_settings[_axis]->steps_per_mm->get() / 100.0);
|
|
||||||
max_pulse_cal = 2.0 - (axis_settings[_axis]->max_travel->get() / -100.0);
|
|
||||||
}
|
|
||||||
} else { // settings are not valid so don't apply any calibration
|
|
||||||
min_pulse_cal = 1.0;
|
|
||||||
max_pulse_cal = 1.0;
|
|
||||||
}
|
|
||||||
// apply the calibrations
|
|
||||||
servo_pulse_min *= min_pulse_cal;
|
|
||||||
servo_pulse_max *= max_pulse_cal;
|
|
||||||
// determine the pulse length
|
|
||||||
servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, servo_pulse_min, servo_pulse_max);
|
|
||||||
_write_pwm(servo_pulse_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServoAxis::_write_pwm(uint32_t duty) {
|
|
||||||
if (ledcRead(_channel_num) != duty) // only write if it is changing
|
|
||||||
ledcWrite(_channel_num, duty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets the PWM to zero. This allows most servos to be manually moved
|
|
||||||
void ServoAxis::disable() {
|
|
||||||
_write_pwm(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks to see if calibration values are in an acceptable range
|
|
||||||
// vebose = true if you want an error sent to serial port
|
|
||||||
bool ServoAxis::_cal_is_valid() {
|
|
||||||
bool settingsOK = true;
|
|
||||||
if ((axis_settings[_axis]->steps_per_mm->get() < SERVO_CAL_MIN) || (axis_settings[_axis]->steps_per_mm->get() > SERVO_CAL_MAX)) {
|
|
||||||
if (_showError) {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration ($10%d) value error. Reset to 100", _axis);
|
|
||||||
char reset_val[] = "100";
|
|
||||||
axis_settings[_axis]->steps_per_mm->setStringValue(reset_val);
|
|
||||||
}
|
|
||||||
settingsOK = false;
|
|
||||||
}
|
|
||||||
// Note: Max travel is set positive via $$, but stored as a negative number
|
|
||||||
auto travel = -axis_settings[_axis]->max_travel->get();
|
|
||||||
if ((travel < -SERVO_CAL_MAX) || travel > -SERVO_CAL_MIN) {
|
|
||||||
if (_showError) {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration ($13%d) value error. Reset to 100", _axis);
|
|
||||||
char reset_val[] = "-100"; // stored as a negative
|
|
||||||
axis_settings[_axis]->max_travel->setStringValue(reset_val);
|
|
||||||
}
|
|
||||||
settingsOK = false;
|
|
||||||
}
|
|
||||||
_showError = false; // to show error once
|
|
||||||
return settingsOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Use this to set the max and min position in mm of the servo
|
|
||||||
This is used when mapping pulse length to the position
|
|
||||||
*/
|
|
||||||
void ServoAxis::set_range(float min, float max) {
|
|
||||||
if (min < max) {
|
|
||||||
_position_min = min;
|
|
||||||
_position_max = max;
|
|
||||||
} else
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Error setting range. Min not smaller than max");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sets the mode the servo will be in during homing
|
|
||||||
See servo_axis.h for SERVO_HOMING_xxxxx types
|
|
||||||
*/
|
|
||||||
void ServoAxis::set_homing_type(uint8_t homing_type) {
|
|
||||||
if (homing_type <= SERVO_HOMING_TARGET)
|
|
||||||
_homing_type = homing_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Use this to set the homing position the servo will be commanded to go if
|
|
||||||
the current homing mode is SERVO_HOMING_TARGET
|
|
||||||
*/
|
|
||||||
void ServoAxis::set_homing_position(float homing_position) {
|
|
||||||
_homing_position = homing_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Use this to set the disable on alarm feature. If true, then hobby servo PWM
|
|
||||||
will be disable in Grbl alarm mode (like before homing). Typical hobby servo
|
|
||||||
can be moved by hand in this mode
|
|
||||||
*/
|
|
||||||
void ServoAxis::set_disable_on_alarm(bool disable_on_alarm) {
|
|
||||||
_disable_on_alarm = disable_on_alarm;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServoAxis::set_disable_with_steppers(bool disable_with_steppers) {
|
|
||||||
_disable_with_steppers = disable_with_steppers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
If true, servo position will alway be calculated in machine position
|
|
||||||
Offsets will not be applied
|
|
||||||
*/
|
|
||||||
void ServoAxis::set_use_mpos(bool use_mpos) {
|
|
||||||
_use_mpos = use_mpos;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,101 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
ServoAxis.h
|
|
||||||
Part of Grbl_ESP32
|
|
||||||
|
|
||||||
copyright (c) 2019 - Bart Dring. This file was intended for use on the ESP32
|
|
||||||
CPU. Do not use this with Grbl for atMega328P
|
|
||||||
|
|
||||||
Grbl is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Grbl is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Servo Axis Class
|
|
||||||
|
|
||||||
The Servo axis feature allows you to use a hobby servo on any axis.
|
|
||||||
This is done using a repeating RTOS task. Grbl continues to calculate
|
|
||||||
the position of the axis in real time. The task looks at the current position of
|
|
||||||
the axis and calculates the required PWM value to go to that location. You define the travel
|
|
||||||
of the servo in millimeters.
|
|
||||||
|
|
||||||
Grbl still uses the acceleration and speed values you have in the settings, so it
|
|
||||||
will coordinate servo axes with stepper motor axes. This assumes these values are within the
|
|
||||||
capabilities of the servo
|
|
||||||
|
|
||||||
Usage
|
|
||||||
|
|
||||||
1. In config.h un-comment #define USE_SERVO_AXES
|
|
||||||
|
|
||||||
2. In the machine definition file in Machines/, define servo pins and PWM channels like this ....
|
|
||||||
#define SERVO_Y_PIN GPIO_NUM_14
|
|
||||||
|
|
||||||
undefine any step and direction pins associated with that axis
|
|
||||||
|
|
||||||
3. In servo_axis.cpp init_servos() function, configure servos like this ....
|
|
||||||
X_Servo_Axis.set_range(0.0, 20.0); // millimeter
|
|
||||||
X_Servo_Axis.set_homing_type(SERVO_HOMING_OFF);
|
|
||||||
X_Servo_Axis.set_disable_on_alarm(true);
|
|
||||||
|
|
||||||
|
|
||||||
The positions can be calibrated using the settings. $10x (resolution) settings adjust the minimum
|
|
||||||
position and $13x (max travel) settings adjust the maximum position. If the servo is traveling
|
|
||||||
backwards from what you want, you can use the $3 direction setting to compensate.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Motors/RcServoSettings.h"
|
|
||||||
|
|
||||||
#define SERVO_HOMING_OFF 0 // servo is off during homing
|
|
||||||
#define SERVO_HOMING_TARGET 1 // servo is send to a location during homing
|
|
||||||
|
|
||||||
extern float my_location;
|
|
||||||
|
|
||||||
void init_servos();
|
|
||||||
void servosSyncTask(void* pvParameters);
|
|
||||||
|
|
||||||
class ServoAxis {
|
|
||||||
public:
|
|
||||||
ServoAxis(uint8_t axis, uint8_t pin_num); // constructor
|
|
||||||
void init();
|
|
||||||
void set_location();
|
|
||||||
void disable(); // sets PWM to 0% duty cycle. Most servos can be manually moved in this state
|
|
||||||
void set_range(float min, float max);
|
|
||||||
void set_homing_type(uint8_t homing_type);
|
|
||||||
void set_homing_position(float homing_position);
|
|
||||||
void set_disable_on_alarm(bool disable_on_alarm);
|
|
||||||
void set_disable_with_steppers(bool disable_with_steppers);
|
|
||||||
void set_use_mpos(bool use_mpos);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int _axis; // these should be assign in constructor using Grbl X_AXIS type values
|
|
||||||
int _pin_num; // The GPIO pin being used
|
|
||||||
int _channel_num; // The PWM channel
|
|
||||||
bool _showError;
|
|
||||||
|
|
||||||
uint32_t _pwm_freq = SERVO_PULSE_FREQ;
|
|
||||||
uint32_t _pwm_resolution_bits = SERVO_PULSE_RES_BITS;
|
|
||||||
float _pulse_min = SERVO_MIN_PULSE; // in pwm counts
|
|
||||||
float _pulse_max = SERVO_MAX_PULSE; // in pwm counts
|
|
||||||
float _position_min = SERVO_POSITION_MIN_DEFAULT; // position in millimeters
|
|
||||||
float _position_max = SERVO_POSITION_MAX_DEFAULT; // position in millimeters
|
|
||||||
|
|
||||||
uint8_t _homing_type = SERVO_HOMING_OFF;
|
|
||||||
float _homing_position = SERVO_POSITION_MAX_DEFAULT;
|
|
||||||
bool _disable_on_alarm = true;
|
|
||||||
bool _disable_with_steppers = false;
|
|
||||||
bool _use_mpos = true;
|
|
||||||
|
|
||||||
bool _validate_cal_settings();
|
|
||||||
void _write_pwm(uint32_t duty);
|
|
||||||
bool _cal_is_valid(); // checks to see if calibration values are in acceptable range
|
|
||||||
};
|
|
@@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
SolenoidPen.cpp
|
|
||||||
Part of Grbl_ESP32
|
|
||||||
|
|
||||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
|
||||||
CPU. Do not use this with Grbl for atMega328P
|
|
||||||
|
|
||||||
Grbl is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Grbl is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include "Grbl.h"
|
|
||||||
|
|
||||||
#ifdef USE_PEN_SOLENOID
|
|
||||||
|
|
||||||
int8_t solenoid_pwm_chan_num;
|
|
||||||
|
|
||||||
static TaskHandle_t solenoidSyncTaskHandle = 0;
|
|
||||||
|
|
||||||
// used to delay turn on
|
|
||||||
bool solenoid_pen_enable;
|
|
||||||
uint16_t solenoide_hold_count;
|
|
||||||
|
|
||||||
void solenoid_init() {
|
|
||||||
grbl_send(CLIENT_SERIAL, "[MSG:Solenoid Mode]\r\n"); // startup message
|
|
||||||
//validate_servo_settings(true); // display any calibration errors
|
|
||||||
solenoid_pen_enable = false; // start delay has not completed yet.
|
|
||||||
solenoide_hold_count = 0; // initialize
|
|
||||||
// setup PWM channel
|
|
||||||
solenoid_pwm_chan_num = sys_get_next_PWM_chan_num();
|
|
||||||
ledcSetup(solenoid_pwm_chan_num, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
|
|
||||||
ledcAttachPin(SOLENOID_PEN_PIN, solenoid_pwm_chan_num);
|
|
||||||
solenoid_disable(); // start it it off
|
|
||||||
// setup a task that will calculate the determine and set the servo position
|
|
||||||
xTaskCreatePinnedToCore(solenoidSyncTask, // task
|
|
||||||
"solenoidSyncTask", // name for task
|
|
||||||
4096, // size of task stack
|
|
||||||
NULL, // parameters
|
|
||||||
1, // priority
|
|
||||||
&solenoidSyncTaskHandle,
|
|
||||||
0 // core
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// turn off the PWM (0 duty)
|
|
||||||
void solenoid_disable() {
|
|
||||||
ledcWrite(solenoid_pwm_chan_num, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is the task
|
|
||||||
void solenoidSyncTask(void* pvParameters) {
|
|
||||||
int32_t current_position[N_AXIS]; // copy of current location
|
|
||||||
float m_pos[N_AXIS]; // machine position in mm
|
|
||||||
TickType_t xLastWakeTime;
|
|
||||||
const TickType_t xSolenoidFrequency = SOLENOID_TIMER_INT_FREQ; // in ticks (typically ms)
|
|
||||||
uint16_t solenoid_delay_counter = 0;
|
|
||||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
|
||||||
while (true) { // don't ever return from this or the task dies
|
|
||||||
if (!solenoid_pen_enable) {
|
|
||||||
solenoid_delay_counter++;
|
|
||||||
solenoid_pen_enable = (solenoid_delay_counter > SOLENOID_TURNON_DELAY);
|
|
||||||
} else {
|
|
||||||
memcpy(current_position, sys_position, sizeof(sys_position)); // get current position in step
|
|
||||||
system_convert_array_steps_to_mpos(m_pos, current_position); // convert to millimeters
|
|
||||||
calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
|
|
||||||
}
|
|
||||||
vTaskDelayUntil(&xLastWakeTime, xSolenoidFrequency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate and set the PWM value for the servo
|
|
||||||
void calc_solenoid(float penZ) {
|
|
||||||
uint32_t solenoid_pen_pulse_len;
|
|
||||||
if (!solenoid_pen_enable) // only proceed if startup delay as expired
|
|
||||||
return;
|
|
||||||
if (penZ < 0 && (sys.state != STATE_ALARM)) { // alarm also makes it go up
|
|
||||||
solenoide_hold_count = 0; // reset this count
|
|
||||||
solenoid_pen_pulse_len = 0; //
|
|
||||||
} else {
|
|
||||||
if (solenoide_hold_count < SOLENOID_PULSE_LEN_HOLD) {
|
|
||||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_UP;
|
|
||||||
solenoide_hold_count++;
|
|
||||||
} else
|
|
||||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD;
|
|
||||||
}
|
|
||||||
// skip setting value if it is unchanged
|
|
||||||
if (ledcRead(solenoid_pwm_chan_num) == solenoid_pen_pulse_len)
|
|
||||||
return;
|
|
||||||
// update the PWM value
|
|
||||||
// ledcWrite appears to have issues with interrupts, so make this a critical section
|
|
||||||
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
portENTER_CRITICAL(&myMutex);
|
|
||||||
ledcWrite(solenoid_pwm_chan_num, solenoid_pen_pulse_len);
|
|
||||||
portEXIT_CRITICAL(&myMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
SolenoidPen.h
|
|
||||||
Part of Grbl_ESP32
|
|
||||||
|
|
||||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
|
||||||
CPU. Do not use this with Grbl for atMega328P
|
|
||||||
|
|
||||||
Grbl is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Grbl is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Usage notes:
|
|
||||||
This is designed to use a solenoid to lift a pen.
|
|
||||||
When the current Z location is below zero the pen is down
|
|
||||||
If the Z goes to zero or above the pen goes up.
|
|
||||||
There are two power levels, the initial pull up strength, then the hold strength
|
|
||||||
|
|
||||||
|
|
||||||
Note: There is a still a virtual Z axis that has a finite speed.
|
|
||||||
If your gcode is commanding long travels in Z, there will be delays
|
|
||||||
between solenoid states as the Z "travels" to the location that will
|
|
||||||
change the state.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SOLENOID_PWM_FREQ
|
|
||||||
# define SOLENOID_PWM_FREQ 5000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SOLENOID_PWM_RES_BITS
|
|
||||||
# define SOLENOID_PWM_RES_BITS 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SOLENOID_TURNON_DELAY
|
|
||||||
# define SOLENOID_TURNON_DELAY (SOLENOID_TIMER_INT_FREQ / 2)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SOLENOID_PULSE_LEN_UP
|
|
||||||
# define SOLENOID_PULSE_LEN_UP 255
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SOLENOID_HOLD_DELAY
|
|
||||||
# define SOLENOID_HOLD_DELAY (SOLENOID_TIMER_INT_FREQ / 2) // in task counts...after this delay power will change to hold level
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SOLENOID_PULSE_LEN_HOLD
|
|
||||||
# define SOLENOID_PULSE_LEN_HOLD 80 // solenoid hold level ... typically a lower value to prevent overheating
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SOLENOID_TIMER_INT_FREQ
|
|
||||||
# define SOLENOID_TIMER_INT_FREQ 50
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void solenoid_init();
|
|
||||||
void solenoid_disable();
|
|
||||||
void solenoidSyncTask(void* pvParameters);
|
|
||||||
void calc_solenoid(float penZ);
|
|
@@ -98,10 +98,6 @@ static volatile uint8_t segment_buffer_tail;
|
|||||||
static uint8_t segment_buffer_head;
|
static uint8_t segment_buffer_head;
|
||||||
static uint8_t segment_next_head;
|
static uint8_t segment_next_head;
|
||||||
|
|
||||||
// Step and direction port invert masks.
|
|
||||||
static uint8_t step_port_invert_mask;
|
|
||||||
static uint8_t dir_port_invert_mask;
|
|
||||||
|
|
||||||
// Used to avoid ISR nesting of the "Stepper Driver Interrupt". Should never occur though.
|
// Used to avoid ISR nesting of the "Stepper Driver Interrupt". Should never occur though.
|
||||||
static volatile uint8_t busy;
|
static volatile uint8_t busy;
|
||||||
|
|
||||||
@@ -420,7 +416,6 @@ static void stepper_pulse_func() {
|
|||||||
// Generate pulse (at least one pulse)
|
// Generate pulse (at least one pulse)
|
||||||
// The pulse resolution is limited by I2S_OUT_USEC_PER_PULSE
|
// The pulse resolution is limited by I2S_OUT_USEC_PER_PULSE
|
||||||
//
|
//
|
||||||
st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask
|
|
||||||
i2s_out_push_sample(pulse_microseconds->get() / I2S_OUT_USEC_PER_PULSE);
|
i2s_out_push_sample(pulse_microseconds->get() / I2S_OUT_USEC_PER_PULSE);
|
||||||
set_stepper_pins_on(0); // turn all off
|
set_stepper_pins_on(0); // turn all off
|
||||||
return;
|
return;
|
||||||
@@ -429,7 +424,6 @@ static void stepper_pulse_func() {
|
|||||||
#ifdef USE_RMT_STEPS
|
#ifdef USE_RMT_STEPS
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask
|
|
||||||
// wait for step pulse time to complete...some of it should have expired during code above
|
// wait for step pulse time to complete...some of it should have expired during code above
|
||||||
while (esp_timer_get_time() - step_pulse_start_time < pulse_microseconds->get()) {
|
while (esp_timer_get_time() - step_pulse_start_time < pulse_microseconds->get()) {
|
||||||
NOP(); // spin here until time to turn off step
|
NOP(); // spin here until time to turn off step
|
||||||
@@ -476,8 +470,6 @@ void st_wake_up() {
|
|||||||
// Enable stepper drivers.
|
// Enable stepper drivers.
|
||||||
motors_set_disable(false);
|
motors_set_disable(false);
|
||||||
stepper_idle = false;
|
stepper_idle = false;
|
||||||
// Initialize stepper output bits to ensure first ISR call does not step.
|
|
||||||
st.step_outbits = step_port_invert_mask;
|
|
||||||
// Initialize step pulse timing from settings. Here to ensure updating after re-writing.
|
// Initialize step pulse timing from settings. Here to ensure updating after re-writing.
|
||||||
#ifdef STEP_PULSE_DELAY
|
#ifdef STEP_PULSE_DELAY
|
||||||
// Step pulse delay handling is not require with ESP32...the RMT function does it.
|
// Step pulse delay handling is not require with ESP32...the RMT function does it.
|
||||||
@@ -510,8 +502,8 @@ void st_reset() {
|
|||||||
segment_buffer_head = 0; // empty = tail
|
segment_buffer_head = 0; // empty = tail
|
||||||
segment_next_head = 1;
|
segment_next_head = 1;
|
||||||
busy = false;
|
busy = false;
|
||||||
st_generate_step_dir_invert_masks();
|
st.step_outbits = 0;
|
||||||
st.dir_outbits = dir_port_invert_mask; // Initialize direction bits to default.
|
st.dir_outbits = dir_invert_mask->get(); // Initialize direction bits to default.
|
||||||
// TODO do we need to turn step pins off?
|
// TODO do we need to turn step pins off?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,6 +708,7 @@ void st_go_idle() {
|
|||||||
motors_set_disable(false);
|
motors_set_disable(false);
|
||||||
|
|
||||||
set_stepper_pins_on(0);
|
set_stepper_pins_on(0);
|
||||||
|
st.step_outbits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by planner_recalculate() when the executing block is updated by the new plan.
|
// Called by planner_recalculate() when the executing block is updated by the new plan.
|
||||||
@@ -760,22 +753,6 @@ void st_parking_restore_buffer() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Generates the step and direction port invert masks used in the Stepper Interrupt Driver.
|
|
||||||
void st_generate_step_dir_invert_masks() {
|
|
||||||
/*
|
|
||||||
uint8_t idx;
|
|
||||||
step_port_invert_mask = 0;
|
|
||||||
dir_port_invert_mask = 0;
|
|
||||||
for (idx=0; idx<N_AXIS; idx++) {
|
|
||||||
if (bit_istrue(step_invert_mask->get(),bit(idx))) { step_port_invert_mask |= get_step_pin_mask(idx); }
|
|
||||||
if (bit_istrue(dir_invert_mask->get(),bit(idx))) { dir_port_invert_mask |= get_direction_pin_mask(idx); }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// simpler with ESP32, but let's do it here for easier change management
|
|
||||||
step_port_invert_mask = step_invert_mask->get();
|
|
||||||
dir_port_invert_mask = dir_invert_mask->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increments the step segment buffer block data ring buffer.
|
// Increments the step segment buffer block data ring buffer.
|
||||||
static uint8_t st_next_block_index(uint8_t block_index) {
|
static uint8_t st_next_block_index(uint8_t block_index) {
|
||||||
block_index++;
|
block_index++;
|
||||||
|
@@ -97,9 +97,6 @@ void st_wake_up();
|
|||||||
// Immediately disables steppers
|
// Immediately disables steppers
|
||||||
void st_go_idle();
|
void st_go_idle();
|
||||||
|
|
||||||
// Generate the step and direction port invert masks.
|
|
||||||
void st_generate_step_dir_invert_masks();
|
|
||||||
|
|
||||||
// Reset the stepper subsystem variables
|
// Reset the stepper subsystem variables
|
||||||
void st_reset();
|
void st_reset();
|
||||||
|
|
||||||
|
@@ -592,8 +592,8 @@ namespace WebUI {
|
|||||||
String sadminPassword = admin_password->get();
|
String sadminPassword = admin_password->get();
|
||||||
String suserPassword = user_password->get();
|
String suserPassword = user_password->get();
|
||||||
|
|
||||||
if (!((sUser == DEFAULT_ADMIN_LOGIN && sPassword == sadminPassword) ||
|
if (!(sUser == DEFAULT_ADMIN_LOGIN && sPassword == sadminPassword) ||
|
||||||
(sUser == DEFAULT_USER_LOGIN && sPassword == suserPassword)) {
|
(sUser == DEFAULT_USER_LOGIN && sPassword == suserPassword)) {
|
||||||
msg_alert_error = true;
|
msg_alert_error = true;
|
||||||
smsg = "Error: Incorrect password";
|
smsg = "Error: Incorrect password";
|
||||||
code = 401;
|
code = 401;
|
||||||
@@ -607,13 +607,19 @@ namespace WebUI {
|
|||||||
//change password
|
//change password
|
||||||
if (_webserver->hasArg("PASSWORD") && _webserver->hasArg("USER") && _webserver->hasArg("NEWPASSWORD") &&
|
if (_webserver->hasArg("PASSWORD") && _webserver->hasArg("USER") && _webserver->hasArg("NEWPASSWORD") &&
|
||||||
(msg_alert_error == false)) {
|
(msg_alert_error == false)) {
|
||||||
|
|
||||||
String newpassword = _webserver->arg("NEWPASSWORD");
|
String newpassword = _webserver->arg("NEWPASSWORD");
|
||||||
if (COMMANDS::isLocalPasswordValid((char*)newpassword.c_str())) {
|
|
||||||
|
char pwdbuf[MAX_LOCAL_PASSWORD_LENGTH + 1];
|
||||||
|
newpassword.toCharArray(pwdbuf, MAX_LOCAL_PASSWORD_LENGTH + 1);
|
||||||
|
|
||||||
|
if (COMMANDS::isLocalPasswordValid(pwdbuf)) {
|
||||||
err_t err;
|
err_t err;
|
||||||
|
|
||||||
if (sUser == DEFAULT_ADMIN_LOGIN) {
|
if (sUser == DEFAULT_ADMIN_LOGIN) {
|
||||||
err = admin_password->setStringValue(newpassword);
|
err = admin_password->setStringValue(pwdbuf);
|
||||||
} else {
|
} else {
|
||||||
err = user_password->setStringValue(newpassword);
|
err = user_password->setStringValue(pwdbuf);
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
msg_alert_error = true;
|
msg_alert_error = true;
|
||||||
|
@@ -1,214 +0,0 @@
|
|||||||
/*
|
|
||||||
unipolar.cpp
|
|
||||||
Part of Grbl_ESP32
|
|
||||||
|
|
||||||
copyright (c) 2019 - Bart Dring. This file was intended for use on the ESP32
|
|
||||||
CPU. Do not use this with Grbl for atMega328P
|
|
||||||
|
|
||||||
Grbl is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Grbl is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Unipolar Class
|
|
||||||
|
|
||||||
This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One
|
|
||||||
is typically tied to a voltage, while the other 4 are switched to ground in a
|
|
||||||
sequence
|
|
||||||
|
|
||||||
To take a step simply call the step(step, direction) function.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include "grbl.h"
|
|
||||||
|
|
||||||
#ifdef USE_UNIPOLAR
|
|
||||||
|
|
||||||
// assign the I/O pins used for each coil of the motors
|
|
||||||
#ifdef X_UNIPOLAR
|
|
||||||
Unipolar X_Unipolar(X_PIN_PHASE_0, X_PIN_PHASE_1, X_PIN_PHASE_2, X_PIN_PHASE_3, true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Y_UNIPOLAR
|
|
||||||
Unipolar Y_Unipolar(Y_PIN_PHASE_0, Y_PIN_PHASE_1, Y_PIN_PHASE_2, Y_PIN_PHASE_3, true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Z_UNIPOLAR
|
|
||||||
Unipolar Z_Unipolar(Z_PIN_PHASE_0, Z_PIN_PHASE_1, Z_PIN_PHASE_2, Z_PIN_PHASE_3, true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void unipolar_init() {
|
|
||||||
#ifdef X_UNIPOLAR
|
|
||||||
X_Unipolar.init();
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "X unipolar");
|
|
||||||
#endif
|
|
||||||
#ifdef Y_UNIPOLAR
|
|
||||||
Y_Unipolar.init();
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Y unipolar");
|
|
||||||
#endif
|
|
||||||
#ifdef Z_UNIPOLAR
|
|
||||||
Z_Unipolar.init();
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Z unipolar");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void unipolar_step(uint8_t step_mask, uint8_t dir_mask) {
|
|
||||||
#ifdef X_UNIPOLAR
|
|
||||||
X_Unipolar.step(step_mask & bit(X_AXIS), dir_mask & bit(X_AXIS));
|
|
||||||
#endif
|
|
||||||
#ifdef Y_UNIPOLAR
|
|
||||||
Y_Unipolar.step(step_mask & bit(Y_AXIS), dir_mask & bit(Y_AXIS));
|
|
||||||
#endif
|
|
||||||
#ifdef Z_UNIPOLAR
|
|
||||||
Z_Unipolar.step(step_mask & bit(Z_AXIS), dir_mask & bit(ZX_AXIS));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void unipolar_disable(bool disable) {
|
|
||||||
#ifdef X_UNIPOLAR
|
|
||||||
X_Unipolar.set_enabled(!disable);
|
|
||||||
#endif
|
|
||||||
#ifdef Y_UNIPOLAR
|
|
||||||
Y_Unipolar.set_enabled(!disable);
|
|
||||||
#endif
|
|
||||||
#ifdef Z_UNIPOLAR
|
|
||||||
Z_Unipolar.set_enabled(!disable);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Unipolar::Unipolar(uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3, bool half_step) { // constructor
|
|
||||||
_pin_phase0 = pin_phase0;
|
|
||||||
_pin_phase1 = pin_phase1;
|
|
||||||
_pin_phase2 = pin_phase2;
|
|
||||||
_pin_phase3 = pin_phase3;
|
|
||||||
_half_step = half_step;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unipolar::init() {
|
|
||||||
pinMode(_pin_phase0, OUTPUT);
|
|
||||||
pinMode(_pin_phase1, OUTPUT);
|
|
||||||
pinMode(_pin_phase2, OUTPUT);
|
|
||||||
pinMode(_pin_phase3, OUTPUT);
|
|
||||||
_current_phase = 0;
|
|
||||||
set_enabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unipolar::set_enabled(bool enabled) {
|
|
||||||
if (enabled == _enabled)
|
|
||||||
return; // no change
|
|
||||||
_enabled = enabled;
|
|
||||||
if (!enabled) {
|
|
||||||
digitalWrite(_pin_phase0, 0);
|
|
||||||
digitalWrite(_pin_phase1, 0);
|
|
||||||
digitalWrite(_pin_phase2, 0);
|
|
||||||
digitalWrite(_pin_phase3, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
To take a step set step to true and set the driection
|
|
||||||
|
|
||||||
step is included so that st.step_outbits can be used to determine if a
|
|
||||||
step is required on this axis
|
|
||||||
*/
|
|
||||||
void Unipolar::step(bool step, bool dir_forward) {
|
|
||||||
uint8_t _phase[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // temporary phase values...all start as off
|
|
||||||
uint8_t phase_max;
|
|
||||||
if (_half_step)
|
|
||||||
phase_max = 7;
|
|
||||||
else
|
|
||||||
phase_max = 3;
|
|
||||||
if (!step)
|
|
||||||
return; // a step is not required on this interrupt
|
|
||||||
if (!_enabled)
|
|
||||||
return; // don't do anything, phase is not changed or lost
|
|
||||||
if (dir_forward) { // count up
|
|
||||||
if (_current_phase == phase_max)
|
|
||||||
_current_phase = 0;
|
|
||||||
else
|
|
||||||
_current_phase++;
|
|
||||||
} else { // count down
|
|
||||||
if (_current_phase == 0)
|
|
||||||
_current_phase = phase_max;
|
|
||||||
else
|
|
||||||
_current_phase--;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
8 Step : A – AB – B – BC – C – CD – D – DA
|
|
||||||
4 Step : AB – BC – CD – DA (Usual application)
|
|
||||||
|
|
||||||
Step IN4 IN3 IN2 IN1
|
|
||||||
A 0 0 0 1
|
|
||||||
AB 0 0 1 1
|
|
||||||
B 0 0 1 0
|
|
||||||
BC 0 1 1 0
|
|
||||||
C 0 1 0 0
|
|
||||||
CD 1 1 0 0
|
|
||||||
D 1 0 0 0
|
|
||||||
DA 1 0 0 1
|
|
||||||
*/
|
|
||||||
if (_half_step) {
|
|
||||||
switch (_current_phase) {
|
|
||||||
case 0:
|
|
||||||
_phase[0] = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_phase[0] = 1;
|
|
||||||
_phase[1] = 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_phase[1] = 1;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_phase[1] = 1;
|
|
||||||
_phase[2] = 1;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
_phase[2] = 1;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
_phase[2] = 1;
|
|
||||||
_phase[3] = 1;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
_phase[3] = 1;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
_phase[3] = 1;
|
|
||||||
_phase[0] = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (_current_phase) {
|
|
||||||
case 0:
|
|
||||||
_phase[0] = 1;
|
|
||||||
_phase[1] = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_phase[1] = 1;
|
|
||||||
_phase[2] = 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_phase[2] = 1;
|
|
||||||
_phase[3] = 1;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_phase[3] = 1;
|
|
||||||
_phase[0] = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
digitalWrite(_pin_phase0, _phase[0]);
|
|
||||||
digitalWrite(_pin_phase1, _phase[1]);
|
|
||||||
digitalWrite(_pin_phase2, _phase[2]);
|
|
||||||
digitalWrite(_pin_phase3, _phase[3]);
|
|
||||||
}
|
|
||||||
#endif
|
|
@@ -1,53 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
grbl_unipolar.h
|
|
||||||
Part of Grbl_ESP32
|
|
||||||
|
|
||||||
copyright (c) 2019 - Bart Dring. This file was intended for use on the ESP32
|
|
||||||
CPU. Do not use this with Grbl for atMega328P
|
|
||||||
|
|
||||||
Grbl is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Grbl is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Unipolar Class
|
|
||||||
|
|
||||||
This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One
|
|
||||||
is typically tied to a voltage, while the other 4 are switched to ground in a
|
|
||||||
sequence
|
|
||||||
|
|
||||||
To take a step simply call the step(direction) function. It will take
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
void unipolar_init();
|
|
||||||
void unipolar_step(uint8_t step_mask, uint8_t dir_mask);
|
|
||||||
void unipolar_disable(bool enable);
|
|
||||||
|
|
||||||
class Unipolar {
|
|
||||||
public:
|
|
||||||
Unipolar(uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3, bool half_step); // constructor
|
|
||||||
void set_enabled(bool enabled);
|
|
||||||
void step(bool step, bool dir_forward);
|
|
||||||
void init();
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t _current_phase = 0;
|
|
||||||
bool _enabled = false;
|
|
||||||
bool _half_step = true; // default is half step, full step
|
|
||||||
uint8_t _pin_phase0;
|
|
||||||
uint8_t _pin_phase1;
|
|
||||||
uint8_t _pin_phase2;
|
|
||||||
uint8_t _pin_phase3;
|
|
||||||
|
|
||||||
};
|
|
Reference in New Issue
Block a user