bdring / Grbl_Esp32

A port of Grbl CNC Firmware for ESP32
GNU General Public License v3.0
1.7k stars 531 forks source link

Add support for RC ESC driven spindle? #148

Closed xnaron closed 5 years ago

xnaron commented 5 years ago

Could support be added for enabling control of an RC ESC driven spindle?

bdring commented 5 years ago

An RC ESC (Electronic Speed Control) runs just like a hobby servo. It is a 50Hz PWM with a pulse length from 1ms to 2ms.

Since the spindle is already on a PWM channel we can just tweak a few settings in the cpu_map.h to get it to work.

Here is an example cpu_map that works. there is only one issue. (see end of post)

#ifdef CPU_MAP_ESP32_ESC_SPINDLE
    // This is the CPU Map for the ESP32 CNC Controller R2  

      // It is OK to comment out any step and direction pins. This
    // won't affect operation except that there will be no output
        // form the pins. Grbl will virtually move the axis. This could 
        // be handy if you are using a servo, etc. for another axis.
        #define CPU_MAP_NAME "CPU_MAP_ESP32"    

        #define X_STEP_PIN          GPIO_NUM_12
        #define X_DIRECTION_PIN     GPIO_NUM_26
        #define X_RMT_CHANNEL       0

        #define Y_STEP_PIN          GPIO_NUM_14
        #define Y_DIRECTION_PIN     GPIO_NUM_25
        #define Y_RMT_CHANNEL       1

        #define Z_STEP_PIN          GPIO_NUM_27     
        #define Z_DIRECTION_PIN     GPIO_NUM_33          
        #define Z_RMT_CHANNEL       2       

        // OK to comment out to use pin for other features
        #define STEPPERS_DISABLE_PIN GPIO_NUM_13        

        // *** the flood coolant feature code is activated by defining this pins
        // *** Comment it out to use the pin for other features
        #define COOLANT_FLOOD_PIN   GPIO_NUM_16         
        //#define COOLANT_MIST_PIN      GPIO_NUM_21

        // If SPINDLE_PWM_PIN is commented out, this frees up the pin, but Grbl will still
        // use a virtual spindle. Do not comment out the other parameters for the spindle.
        #define SPINDLE_PWM_PIN    GPIO_NUM_17 
        #define SPINDLE_PWM_CHANNEL 0

        // RC ESC Based Spindle 
        // An ESC works like a hobby servo with 50Hz PWM 1ms to 2 ms pulse range        
        #define SPINDLE_PWM_BASE_FREQ 50 // Hz for ESC
        #define SPINDLE_PWM_BIT_PRECISION 16   // 16 bit required for ESC
        #define SPINDLE_PULSE_RES_COUNT 65535

        #define ESC_MIN_PULSE_SEC 0.001 // min pulse in seconds (OK to tune this one)
        #define ESC_MAX_PULSE_SEC 0.002 // max pulse in seconds (OK to tune this one)       
        #define ESC_TIME_PER_BIT  ((1.0 / (float)SPINDLE_PWM_BASE_FREQ) / ((float)SPINDLE_PULSE_RES_COUNT) ) // seconds

        #define SPINDLE_PWM_OFF_VALUE    (uint16_t)(SERVO_MIN_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
        #define SPINDLE_PWM_MAX_VALUE    (uint16_t)(SERVO_MAX_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts

        #ifndef SPINDLE_PWM_MIN_VALUE
                #define SPINDLE_PWM_MIN_VALUE   SPINDLE_PWM_OFF_VALUE   // Must be greater than zero.
        #endif

        #define SPINDLE_PWM_RANGE         (SPINDLE_PWM_MAX_VALUE-SPINDLE_PWM_MIN_VALUE)

        #define SPINDLE_ENABLE_PIN  GPIO_NUM_22         

        // if these spindle function pins are defined, they will be activated in the code
        // comment them out to use the pins for other functions
        //#define SPINDLE_ENABLE_PIN    GPIO_NUM_16
        //#define SPINDLE_DIR_PIN           GPIO_NUM_16     

        #define X_LIMIT_PIN         GPIO_NUM_2  
        #define Y_LIMIT_PIN         GPIO_NUM_4  
        #define Z_LIMIT_PIN         GPIO_NUM_15     
        #define LIMIT_MASK          B111

        #define PROBE_PIN           GPIO_NUM_32  

        #define CONTROL_SAFETY_DOOR_PIN   GPIO_NUM_35  // needs external pullup
        #define CONTROL_RESET_PIN         GPIO_NUM_34  // needs external pullup
        #define CONTROL_FEED_HOLD_PIN     GPIO_NUM_36  // needs external pullup 
        #define CONTROL_CYCLE_START_PIN   GPIO_NUM_39  // needs external pullup         

#endif

The only issue is spindle_stop() has a hard coded 0 when I think you want a 1ms pulse. I had to change it to SPINDLE_PWM_OFF_VALUE. (see below).


void spindle_stop()
{       
  spindle_set_enable(false);
    #ifdef SPINDLE_PWM_PIN
        grbl_analogWrite(SPINDLE_PWM_CHANNEL, SPINDLE_PWM_OFF_VALUE);
    #endif
}
'''

If you can test this, I can create a pull request.
xnaron commented 5 years ago

It works but the spindle runs at low speed when it should be off (M3 S0) . I think this ESC has a wider range than a normal one. I tried lowering ESC_MIN_PULSE_SEC to 0.0007 and then 0.0002 but neither worked. M3 S1000 is about full speed on the spindle. I tried setting the spindle_set_enable back to stock of zero but that did not work either as the esc would not arm. Any other suggestions to lower the pulse length?

109JB commented 5 years ago

On an RC servo the PWM is not 50Hz. It is 25 Hz as the signal is a 1 to 2 ms pulse over a 40 ms period. 40 ms is 25 Hz. Don't have any idea if this could have anything to do with the problem, but I know a faster PWM rate causes a servo to buzz. No idea if a ESC is the same.

bdring commented 5 years ago

In general the spec for analog servos is 20ms or 50Hz. You are right it can vary a lot. Some digital servos like it a lot faster.

Do you have a link to the ESC you are using? At the slow speed, is it the same speed at those lower pulse lengths?

bdring commented 5 years ago

I found an error. I used defined values from other servo features in the code, but forgot to rename them. This meant if you changed from the default pulse length, the code did not actually change.

Change "SERVO" to "ESC" so these lines look like this in the cpu_map.

#define SPINDLE_PWM_OFF_VALUE    (uint16_t)(ESC_MIN_PULSE_SEC / ESC_TIME_PER_BIT) // in timer counts
#define SPINDLE_PWM_MAX_VALUE    (uint16_t)(ESC_MIN_PULSE_SEC / ESC_TIME_PER_BIT) // in timer counts

Here are so logic plots to show it works now.

Off

image

500RPM (50%)

image

1000 RPM (100%)

image

Here is off with min pulse at 0.0005 sec

image

xnaron commented 5 years ago

It's not working as expected for me. I will have to put the logic analyzer on it and see what I am getting. I noticed that the signal seems to change when I job the x axis. The esc goes into a beeping mode like the signal was lost. I am wondering if you can reproduce by measuring again after moving an axis.

xnaron commented 5 years ago

`

define SPINDLE_PWM_BASE_FREQ 50 // Hz for ESC

#define SPINDLE_PWM_BIT_PRECISION 16   // 16 bit required for ESC
#define SPINDLE_PULSE_RES_COUNT 65535

#define ESC_MIN_PULSE_SEC 0.0007 // min pulse in seconds (OK to tune this one)
#define ESC_MAX_PULSE_SEC 0.0018 // max pulse in seconds (OK to tune this one)   
#define ESC_TIME_PER_BIT  ((1.0 / (float)SPINDLE_PWM_BASE_FREQ) / ((float)SPINDLE_PULSE_RES_COUNT) ) // seconds

#define SPINDLE_PWM_OFF_VALUE    (uint16_t)(ESC_MIN_PULSE_SEC / ESC_TIME_PER_BIT) // in timer counts
#define SPINDLE_PWM_MAX_VALUE    (uint16_t)(ESC_MIN_PULSE_SEC / ESC_TIME_PER_BIT) // in timer counts

`

image

That is what I have and now I can't change the speed it always looks like the screenshot above. (trying M3 S100, M3 S500, M3 S1000 etc.... the signal stays as above

If I move an axis I loose the pwm signal and it looks like below (ex: jog x axis over 1mm)

image

$0=3 $1=255 $2=0 $3=0 $4=0 $5=0 $6=0 $10=3 $11=0.010 $12=0.002 $13=0 $20=0 $21=1 $22=1 $23=0 $24=25.000 $25=1000.000 $26=250 $27=1.000 $30=10000.000 $31=0.000 $32=0 $100=160.700 $101=160.700 $102=100.000 $110=8000.000 $111=8000.000 $112=500.000 $120=500.000 $121=500.000 $122=200.000 $130=170.000 $131=260.000 $132=20.000

bdring commented 5 years ago

I found two issues.

  1. Change these lines in cpu_map.h to the code below.
#define SPINDLE_PWM_OFF_VALUE    (uint16_t)(ESC_MIN_PULSE_SEC / ESC_TIME_PER_BIT) // in timer counts
#define SPINDLE_PWM_MAX_VALUE    (uint16_t)(ESC_MAX_PULSE_SEC / ESC_TIME_PER_BIT) // in timer counts
  1. Grbl has a laser mode where the laser power (uses spindle PWM) is compensated for speed. I think it is making some changes during moves when it is not in laser mode. Be sure $32=0.

Surround the spindle speed adjustment with a check for laser mode ( line 258 in stepper.cpp)

if (st_prep_block->is_pwm_rate_adjusted) {
    spindle_set_speed(st.exec_segment->spindle_pwm);
}

This is likely related to the 0 speed not being at 0 duty.

Thank you for your patience with this issue. Can you tell me the ESC and motor you are using? I would like to get one to help me test. (and maybe build a PCB machine)

xnaron commented 5 years ago

With the changes above it works perfectly now. The ESC is one I had on hand that I bought about 8 years ago from Hobbyking (see pic). I had flashed it with custom firmware for quadcopters. It requires a pulse length between 700us and ~1800us. Your code above works perfectly and there is no issue now that the laser mode check is in place. The motor is another one I had on hand for quad copters. It was quite old as well. I removed the labels from them all when I was balancing them. The specs for the PCBEater motors are KV rating anywhere between 900 to 1200KV with dimensions of 28mm or less diameter and ~28mm high. The motor should have a ~3mm shaft that protrudes out the side closest to the wires (see pic). I am searching for a source for the motors and will be posting as soon as I find one. The esc is a commodity item and any 25a or greater one would work.

Thanks again for making the changes so quickly.

image

image

bdring commented 5 years ago

Awsome.