bdring / Grbl_Esp32

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

Closed-loop Spindle Control #265

Open BogdanTheGeek opened 5 years ago

BogdanTheGeek commented 5 years ago

I would like to implement a closed-loop PID control algorithm for the spindle PWM. I want to use a standard BLDC ESC with an external feedback source like a Hall sensor or an optical sensor to measure the RPM and adjust the PWM in order to get an accurate spindle speed.

The standard version of grbl doesn't implement this due to limited ram and timers I believe and at least for me this would be a huge "selling factor" for grbl_ESP32.

This could just be a task that runs in the background with fairly low priority. I mostly use the idf so I am not familiar with how much of that is accessible from the Arduino core.

Is this feature in the works or can I proceed to implement it? Any preferences with regards to which GPIO should be used for the feedback? EDIT: This also opens the possibility for a spindle stall detection and might save a lot of end mills.

karoria commented 5 years ago

Interesting idea. I am not a software guy but I will definitely use it if implemented.

bdring commented 5 years ago

I am interested to see how well this performs in Grbl_ESP32.

I think the features you need are in the Arduino core. All of the GPIO used in Grbl_ESP32 is written so the user can select it in a cpu_map. Try to use that method for your I/O.

BogdanTheGeek commented 5 years ago

I am not very familiar with the grbl source code and what timers and such I should use. I have written an implementation of my idea which should work, but I am not able to test it as my CNC is currently out of order. If I do a pull request could you, @bdring have a look over the code for any silly mistakes ? If someone volunteers their sensored(with any speed sensor) BLDC spindle for some testing and PID tuning I would be very tankful.

here is my fork for testing: https://github.com/BogdanTheGeek/Grbl_Esp32

bdring commented 5 years ago

We can do all initial testing via your fork. No need for a PR against devt or master at this time.

Use a defined constant for your timer number so it can be easily changed. Choose any number that is not currently used.

I think you should select a motor and encoder and do some basic testing before I do any testing or purchasing of hardware.

BogdanTheGeek commented 5 years ago

I have a sensored motor I could use to do some basic testing, I just need to wire it up to one of my esp32's. I will see what I can do over the weekend. Which timers aren't used?

bdring commented 5 years ago

There is only (1) timer interrupt right now. It is used for step generation.

#define STEP_TIMER_INDEX TIMER_0 
terjeio commented 5 years ago

I have been tinkering with spindle PID in my MSP432 grblHAL driver. A couple of tips:

  1. It may be possible to assign a counter input directly to the GPIO, if so no interrupt is needed. I am too lazy to check the ESP32 dataheet now, however most MCUs allow that.

  2. You really want to assign $-settings for the PID loop constants, reflashing for every change during tuning will be a pain.

  3. A more complete PID algorithm may be required, testing will tell...

Good luck!

BogdanTheGeek commented 5 years ago

Thanks for the tips @terjeio. I agree with you that pid settings should be accessible from grbl settings. As for the counter input I am not really sure what you mean by it. I would really love to find a way to not use interrupts as they are a pain with the ESP32 as you pretty much have to use queues as interrupts that do too much reset the esp32. Ive got some code running but its pretty wild. I have to do some debugging to see whats going on with the code. I really want to implement something that can be easily ported to other platforms but that also takes advantage of the ESP32's features.

terjeio commented 5 years ago

@BogdanTheGeek See chapter 17. PULSE_CNT in the tech ref. You can get rid of the pulse counting interrupt if using one of these counters. Perhaps a RMT channel can be used as well, or even a Timer if the clock input can be routed from a GPIO pin. You have to dig into the datasheet to find out. Of course you still need a timer to handle the sampling (in the spindle_pid_task()).

bdring commented 5 years ago

@BogdanTheGeek It depends on the encoder you have, but a pulse counter basically counts pulses on a pin without any code. You could then setup an RTOS task, that will not mess with the timing of steps, etc, to determine speed and apply a correction.

It would use esp_timer_get_time() and the count to determine the speed.

misan commented 5 years ago

This one seems a relevant example https://github.com/DavidAntliff/esp32-freqcount I grabbed from this thread https://www.esp32.com/viewtopic.php?f=2&t=2935&sid=01bba7f5f57e7a88d7d91962e551bca8&start=10

On Sat, Oct 26, 2019 at 2:54 AM bdring notifications@github.com wrote:

@BogdanTheGeek https://github.com/BogdanTheGeek It depends on the encoder you have, but a pulse counter basically counts pulses on a pin without any code. You could then setup an RTOS task, that will not mess with the timing of steps, etc, to determine speed and apply a correction.

It would use esp_timer_get_time() and the count to determine the speed.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bdring/Grbl_Esp32/issues/265?email_source=notifications&email_token=AADRZSBNLGKEEQXEGFUNT73QQOILXA5CNFSM4JE7TNZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECJ35VA#issuecomment-546553556, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADRZSDVDWGWEAOBUHFXGB3QQOILXANCNFSM4JE7TNZA .

BogdanTheGeek commented 5 years ago

I really like the idea of not using interrupts and I think a combination of the pulse counter and the RTC is the way to go as even microcontrollers that do not have RTOS can implement similar things. I also thought of using the MCPWM and capture the signals, but the code for controlling an ESC is already implemented with ledc and works well as it is.

BogdanTheGeek commented 5 years ago

Can anyone help me with the $settings? I dont know where to add them and how to make them show in the web interface and all that. I imagine I would have to use some ifdef to only include them if CPU_MAP uses a feedback pin, but I am not sure of all the places this ifdef should be.

terjeio commented 5 years ago

In settings.h add the new variables, preferably at the end of the settings_t struct. Since this needs to be extended they will likely(?) get a default value of all bits set to 1 unless reflashing clears the settings and thus triggers a call to settings_restore() in settings.cpp. I do not know how ESP32 is set up in this regard, if settings survives a reflash you have to handle that, see below.

Add sensible default values in defaults.h and set use them to set the initial values in settings_restore(). Also add them to settings_store_global_setting() in settings.cpp and report_grbl_settings() in report.cpp.

If settings survives a reflash I would add code to read_global_settings() in settings.cpp, test for all bits set (or if values are outside a reasonable range) and apply the default values if so. Another option is to change SETTINGS_VERSION in settings.h when these are added - this ensures that the settings are reset to default values on the first reflash after the PID option is changed.

I do not know if the web interface will pick up the new settings automatically.

bdring commented 5 years ago

I have been avoiding changing the settings because it will break a lot of gcode senders. Many do not use robust parsing methods and break with the tiniest change.

With that said, go ahead and make any change you want. I will sort out the the sender issues later. I suggest using $3x type numbers because that is where the current spindle features are.

Possibly there could be a #define ORIGINAL_SETTINGS_ONLY type option. It would only report the original settings but support changes to all, if you need to pick that option for your preferred sender.

WebUI does not support them, but probably can ignore extra ones. It needs to know the description (in many languages) to support them.

terjeio commented 5 years ago

A bit OT but related to badly implemented senders: I have just pre-released a config app for Grbl (Windows only) that IMO simplifies setup, no need to figure out stuff like bitfields or refer to documentation. A complete sender will follow later...

Edit: Forgot to mention that the complete sender has a PID log viewer, when tuning it is very informative to be able to see graphically what the step response is. The downside is that it requires more firmware changes...

jschoch commented 5 years ago

Not sure if this is the right place to leave this but G76/G96 would be nice to have and it would allow me to get rid of my centroid acorn and it's terrible software. Seems like the issues you'd have with "closed loop" stepper control are related.

I have also read that folks trying to use "hybrid closed loop steppers" have sync issues. For example X has to adjust due to some momentary skip and now it is a few ticks ahead/behind the other steppers. The only way to deal with this is to fault out as far as I know. If grbl saw the change the same code that would deal with G96 would be able to do some compensation.

There are a bunch of semi tested grbl forks that implement some form of spindle sync. @terjeio has commented on a bunch of them.