Update de grbl avec un plus grand buffer et un peu de doc en plus
This commit is contained in:
153
Grbl_Esp32-master/doc/Commands.txt
Normal file
153
Grbl_Esp32-master/doc/Commands.txt
Normal file
@ -0,0 +1,153 @@
|
||||
This file defines the [ESP...] style commands. They can be used via serial, Bluetooth or Wifi
|
||||
These are used for basic wireless settings as well as SD card commands
|
||||
|
||||
Some commands need to be authenticated with a password. Authentication
|
||||
is optional via #define ENABLE_AUTHENTICATION in the config.h file.
|
||||
The default password is "admin"
|
||||
|
||||
============== Examples (assumes "admin" password): ===============
|
||||
|
||||
Command: [ESP800]pwd=admin
|
||||
Reply: FW version:1.1f # FW target:grbl-embedded # FW HW:Direct SD # primary sd:/sd # secondary sd:none # authentication:yes # webcommunication: Sync: 81# hostname:grblesp
|
||||
|
||||
Command: [ESP111]
|
||||
Reply: 192.168.1.11
|
||||
|
||||
Command: [ESP121]pwd=admin
|
||||
Reply: 80
|
||||
|
||||
Command: [ESP121]pwd=admin
|
||||
Reply: 80
|
||||
|
||||
Command: [ESP121]81 pwd=admin
|
||||
Reply: ok
|
||||
|
||||
Command: [ESP121]pwd=admin
|
||||
Reply: 81
|
||||
|
||||
=============== Command Reference ========================
|
||||
|
||||
|
||||
* Set/Get STA SSID
|
||||
[ESP100]<SSID>pwd=<admin password>
|
||||
|
||||
* Set STA Password
|
||||
[ESP101]<Password>pwd=<admin password>
|
||||
|
||||
* Set/Get STA IP mode (DHCP/STATIC)
|
||||
[ESP102]<mode>pwd=<admin password>
|
||||
|
||||
* Set/Get STA IP/Mask/GW
|
||||
[ESP103]IP=<IP> MSK=<IP> GW=<IP> pwd=<admin password>
|
||||
|
||||
* Set/Get AP SSID
|
||||
[ESP105]<SSID>pwd=<admin password>
|
||||
|
||||
* Change AP Password
|
||||
[ESP106]<Password>pwd=<admin password>
|
||||
|
||||
* Set/Get AP IP
|
||||
[ESP107]<IP>pwd=<admin password>
|
||||
|
||||
* Set/Get AP channel
|
||||
[ESP108]<channel>pwd=<admin password>
|
||||
|
||||
* Set/Get radio state which can be STA, AP, BT, OFF
|
||||
[ESP110]<state>pwd=<admin password>
|
||||
|
||||
* Get current IP
|
||||
[ESP111]<header answer>
|
||||
|
||||
* Get/Set hostname
|
||||
[ESP112]<Hostname> pwd=<admin password>
|
||||
|
||||
* Get/Set immediate Radio (WiFi/BT) state which can be ON, OFF
|
||||
[ESP115]<state>pwd=<admin password>
|
||||
|
||||
* Get/Set HTTP state which can be ON, OFF
|
||||
[ESP120]<state>pwd=<admin password>
|
||||
|
||||
* Get/Set HTTP port
|
||||
[ESP121]<port>pwd=<admin password>
|
||||
|
||||
* Get/Set Telnet state which can be ON, OFF
|
||||
[ESP130]<state>pwd=<admin password>
|
||||
|
||||
* Get/Set Telnet port
|
||||
[ESP131]<port>pwd=<admin password>
|
||||
|
||||
* Get/Set btname
|
||||
[ESP140]< Bluetooth name> pwd=<admin password>
|
||||
|
||||
* Get SD Card Status
|
||||
[ESP200] pwd=<user/admin password>
|
||||
|
||||
* Get SD Card Content
|
||||
[ESP210] pwd=<user/admin password>
|
||||
|
||||
* Delete SD Card file / directory
|
||||
[ESP215]<file/dir name>pwd=<user/admin password>
|
||||
|
||||
* Print SD file
|
||||
[ESP220] <Filename> pwd=<user/admin password>
|
||||
|
||||
*Get full EEPROM settings content
|
||||
but do not give any passwords
|
||||
[ESP400] pwd=<user/admin password>
|
||||
|
||||
*Set EEPROM setting
|
||||
position in EEPROM, type: B(byte), I(integer/long), S(string), A(IP address / mask)
|
||||
[ESP401]P=<position> T=<type> V=<value> pwd=<user/admin password>
|
||||
Positions:
|
||||
HOSTNAME_ENTRY "ESP_HOSTNAME" String
|
||||
STA_SSID_ENTRY "STA_SSID" String
|
||||
STA_PWD_ENTRY "STA_PWD" String
|
||||
STA_IP_ENTRY "STA_IP" IP
|
||||
STA_GW_ENTRY "STA_GW" IP
|
||||
STA_MK_ENTRY "STA_MK" IP
|
||||
ESP_WIFI_MODE "WIFI_MODE" Byte (0=OFF, STA=1, AP=2)
|
||||
AP_SSID_ENTRY "AP_SSID" String
|
||||
AP_PWD_ENTRY "AP_PWD" String
|
||||
AP_IP_ENTRY "AP_IP" IP
|
||||
AP_CHANNEL_ENTRY "AP_CHANNEL" Byte
|
||||
HTTP_ENABLE_ENTRY "HTTP_ON" Byte (0=Disabled, 1=Enabled)
|
||||
HTTP_PORT_ENTRY "HTTP_PORT" Integer
|
||||
TELNET_ENABLE_ENTRY "TELNET_ON" Byte (0=Disabled, 1=Enabled)
|
||||
TELNET_PORT_ENTRY "TELNET_PORT" Integer
|
||||
STA_IP_MODE_ENTRY "STA_IP_MODE" Byte (0=DHCP, 1=STATIC)
|
||||
|
||||
*Get available AP list (limited to 30)
|
||||
output is JSON or plain text according parameter
|
||||
[ESP410] pwd=<user/admin password>
|
||||
|
||||
*Get current settings of ESP3D
|
||||
output is JSON or plain text according parameter
|
||||
[ESP420]pwd=<user/admin password>
|
||||
|
||||
* Restart ESP
|
||||
[ESP444]RESTART pwd=<admin password>
|
||||
|
||||
* Change / Reset user password
|
||||
[ESP555]<password>pwd=<admin password>
|
||||
if no password set it use default one
|
||||
|
||||
* Send Notification
|
||||
[ESP600]msg [pwd=<admin password>]
|
||||
|
||||
* Set/Get Notification settings
|
||||
[ESP610]type=<NONE/PUSHOVER/EMAIL/LINE> T1=<token1> T2=<token2> TS=<Settings> [pwd=<admin password>]
|
||||
Get will give type and settings only, not the protected T1/T2
|
||||
|
||||
* Read SPIFFS file and send each line to serial
|
||||
[ESP700]<filename> pwd=<user/admin password>
|
||||
|
||||
* Format SPIFFS
|
||||
[ESP710]FORMAT pwd=<admin password>
|
||||
|
||||
* SPIFFS total size and used size
|
||||
[ESP720]<header answer> pwd=<user/admin password>
|
||||
|
||||
* Get fw version and basic information
|
||||
[ESP800]<header answer>
|
||||
|
||||
|
10
Grbl_Esp32-master/doc/csv/alarm_codes_en_US.csv
Normal file
10
Grbl_Esp32-master/doc/csv/alarm_codes_en_US.csv
Normal file
@ -0,0 +1,10 @@
|
||||
"Alarm Code in v1.1+"," Alarm Message in v1.0-"," Alarm Description"
|
||||
"1","Hard limit","Hard limit has been triggered. Machine position is likely lost due to sudden halt. Re-homing is highly recommended."
|
||||
"2","Soft limit","Soft limit alarm. G-code motion target exceeds machine travel. Machine position retained. Alarm may be safely unlocked."
|
||||
"3","Abort during cycle","Reset while in motion. Machine position is likely lost due to sudden halt. Re-homing is highly recommended."
|
||||
"4","Probe fail","Probe fail. Probe is not in the expected initial state before starting probe cycle when G38.2 and G38.3 is not triggered and G38.4 and G38.5 is triggered."
|
||||
"5","Probe fail","Probe fail. Probe did not contact the workpiece within the programmed travel for G38.2 and G38.4."
|
||||
"6","Homing fail","Homing fail. The active homing cycle was reset."
|
||||
"7","Homing fail","Homing fail. Safety door was opened during homing cycle."
|
||||
"8","Homing fail","Homing fail. Pull off travel failed to clear limit switch. Try increasing pull-off setting or check wiring."
|
||||
"9","Homing fail","Homing fail. Could not find limit switch within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring."
|
|
22
Grbl_Esp32-master/doc/csv/build_option_codes_en_US.csv
Normal file
22
Grbl_Esp32-master/doc/csv/build_option_codes_en_US.csv
Normal file
@ -0,0 +1,22 @@
|
||||
OPT: Code, Build-Option Description,State
|
||||
V,Variable spindle,Enabled
|
||||
N,Line numbers,Enabled
|
||||
M,Mist coolant M7,Enabled
|
||||
C,CoreXY,Enabled
|
||||
P,Parking motion,Enabled
|
||||
Z,Homing force origin,Enabled
|
||||
H,Homing single axis commands,Enabled
|
||||
T,Two limit switches on axis,Enabled
|
||||
A,Allow feed rate overrides in probe cycles,Enabled
|
||||
D,Use spindle direction as enable pin,Enabled
|
||||
0,Spindle enable off when speed is zero,Enabled
|
||||
S,Software limit pin debouncing,Enabled
|
||||
R,Parking override control,Enabled
|
||||
+,Safety door input pin,Enabled
|
||||
*,Restore all EEPROM command,Disabled
|
||||
$,Restore EEPROM `$` settings command,Disabled
|
||||
#,Restore EEPROM parameter data command,Disabled
|
||||
I,Build info write user string command,Disabled
|
||||
E,Force sync upon EEPROM write,Disabled
|
||||
W,Force sync upon work coordinate offset change,Disabled
|
||||
L,Homing initialization auto-lock,Disabled
|
|
44
Grbl_Esp32-master/doc/csv/error_codes_en_US.csv
Normal file
44
Grbl_Esp32-master/doc/csv/error_codes_en_US.csv
Normal file
@ -0,0 +1,44 @@
|
||||
"Error Code in v1.1+","Error Message in v1.0-","Error Description"
|
||||
"1","Expected command letter","G-code words consist of a letter and a value. Letter was not found."
|
||||
"2","Bad number format","Missing the expected G-code word value or numeric value format is not valid."
|
||||
"3","Invalid statement","Grbl '$' system command was not recognized or supported."
|
||||
"4","Value < 0","Negative value received for an expected positive value."
|
||||
"5","Setting disabled","Homing cycle failure. Homing is not enabled via settings."
|
||||
"6","Value < 3 usec","Minimum step pulse time must be greater than 3usec."
|
||||
"7","EEPROM read fail. Using defaults","An EEPROM read failed. Auto-restoring affected EEPROM to default values."
|
||||
"8","Not idle","Grbl '$' command cannot be used unless Grbl is IDLE. Ensures smooth operation during a job."
|
||||
"9","G-code lock","G-code commands are locked out during alarm or jog state."
|
||||
"10","Homing not enabled","Soft limits cannot be enabled without homing also enabled."
|
||||
"11","Line overflow","Max characters per line exceeded. Received command line was not executed."
|
||||
"12","Step rate > 30kHz","Grbl '$' setting value cause the step rate to exceed the maximum supported."
|
||||
"13","Check Door","Safety door detected as opened and door state initiated."
|
||||
"14","Line length exceeded","Build info or startup line exceeded EEPROM line length limit. Line not stored."
|
||||
"15","Travel exceeded","Jog target exceeds machine travel. Jog command has been ignored."
|
||||
"16","Invalid jog command","Jog command has no '=' or contains prohibited g-code."
|
||||
"17","Setting disabled","Laser mode requires PWM output."
|
||||
"20","Unsupported command","Unsupported or invalid g-code command found in block."
|
||||
"21","Modal group violation","More than one g-code command from same modal group found in block."
|
||||
"22","Undefined feed rate","Feed rate has not yet been set or is undefined."
|
||||
"23","Invalid gcode ID:23","G-code command in block requires an integer value."
|
||||
"24","Invalid gcode ID:24","More than one g-code command that requires axis words found in block."
|
||||
"25","Invalid gcode ID:25","Repeated g-code word found in block."
|
||||
"26","Invalid gcode ID:26","No axis words found in block for g-code command or current modal state which requires them."
|
||||
"27","Invalid gcode ID:27","Line number value is invalid."
|
||||
"28","Invalid gcode ID:28","G-code command is missing a required value word."
|
||||
"29","Invalid gcode ID:29","G59.x work coordinate systems are not supported."
|
||||
"30","Invalid gcode ID:30","G53 only allowed with G0 and G1 motion modes."
|
||||
"31","Invalid gcode ID:31","Axis words found in block when no command or current modal state uses them."
|
||||
"32","Invalid gcode ID:32","G2 and G3 arcs require at least one in-plane axis word."
|
||||
"33","Invalid gcode ID:33","Motion command target is invalid."
|
||||
"34","Invalid gcode ID:34","Arc radius value is invalid."
|
||||
"35","Invalid gcode ID:35","G2 and G3 arcs require at least one in-plane offset word."
|
||||
"36","Invalid gcode ID:36","Unused value words found in block."
|
||||
"37","Invalid gcode ID:37","G43.1 dynamic tool length offset is not assigned to configured tool length axis."
|
||||
"38","Invalid gcode ID:38","Tool number greater than max supported value."
|
||||
"39","Parameter P exceeded max ID:39","Parameter P exceeded max"
|
||||
"60","SD failed to mount"
|
||||
"61","SD card failed to open file for reading"
|
||||
"62","SD card failed to open directory"
|
||||
"63","SD Card directory not found"
|
||||
"64","SD Card file empty"
|
||||
"70","Bluetooth failed to start"
|
Can't render this file because it has a wrong number of fields in line 39.
|
46
Grbl_Esp32-master/doc/csv/setting_codes_en_US.csv
Normal file
46
Grbl_Esp32-master/doc/csv/setting_codes_en_US.csv
Normal file
@ -0,0 +1,46 @@
|
||||
"$-Code"," Setting"," Units"," Setting Description"
|
||||
"0","Step pulse time","microseconds","Sets time length per step. Minimum 3usec."
|
||||
"1","Step idle delay","milliseconds","Sets a short hold delay when stopping to let dynamics settle before disabling steppers. Value 255 keeps motors enabled with no delay."
|
||||
"2","Step pulse invert","mask","Inverts the step signal. Set axis bit to invert (00000ZYX)."
|
||||
"3","Step direction invert","mask","Inverts the direction signal. Set axis bit to invert (00000ZYX)."
|
||||
"4","Invert step enable pin","boolean","Inverts the stepper driver enable pin signal."
|
||||
"5","Invert limit pins","boolean","Inverts the all of the limit input pins."
|
||||
"6","Invert probe pin","boolean","Inverts the probe input pin signal."
|
||||
"10","Status report options","mask","Alters data included in status reports."
|
||||
"11","Junction deviation","millimeters","Sets how fast Grbl travels through consecutive motions. Lower value slows it down."
|
||||
"12","Arc tolerance","millimeters","Sets the G2 and G3 arc tracing accuracy based on radial error. Beware: A very small value may effect performance."
|
||||
"13","Report in inches","boolean","Enables inch units when returning any position and rate value that is not a settings value."
|
||||
"20","Soft limits enable","boolean","Enables soft limits checks within machine travel and sets alarm when exceeded. Requires homing."
|
||||
"21","Hard limits enable","boolean","Enables hard limits. Immediately halts motion and throws an alarm when switch is triggered."
|
||||
"22","Homing cycle enable","boolean","Enables homing cycle. Requires limit switches on all axes."
|
||||
"23","Homing direction invert","mask","Homing searches for a switch in the positive direction. Set axis bit (00000ZYX) to search in negative direction."
|
||||
"24","Homing locate feed rate","mm/min","Feed rate to slowly engage limit switch to determine its location accurately."
|
||||
"25","Homing search seek rate","mm/min","Seek rate to quickly find the limit switch before the slower locating phase."
|
||||
"26","Homing switch debounce delay","milliseconds","Sets a short delay between phases of homing cycle to let a switch debounce."
|
||||
"27","Homing switch pull-off distance","millimeters","Retract distance after triggering switch to disengage it. Homing will fail if switch isn't cleared."
|
||||
"30","Maximum spindle speed","RPM","Maximum spindle speed. Sets PWM to 100% duty cycle."
|
||||
"31","Minimum spindle speed","RPM","Minimum spindle speed. Sets PWM to 0.4% or lowest duty cycle."
|
||||
"32","Laser-mode enable","boolean","Enables laser mode. Consecutive G1/2/3 commands will not halt when spindle speed is changed."
|
||||
"33","Spindle PWM Freq","16-bit","Spindle PWM Freq"
|
||||
"34","Spindle PWM Off Value","16-bit","Spindle PWM Off Value"
|
||||
"35","Spindle PWM Min Value","16-bit","Spindle PWM Min Value"
|
||||
"36","Spindle PWM Max Value","16-bit","Spindle PWM Max Value"
|
||||
"80-84","User integer Values","unsigned 16-bit","Reserved for custom machine use"
|
||||
"90-94","User Floating point value","float","Reserved for custom machine use"
|
||||
"100","X-axis travel resolution","step/mm","X-axis travel resolution in steps per millimeter."
|
||||
"101","Y-axis travel resolution","step/mm","Y-axis travel resolution in steps per millimeter."
|
||||
"102","Z-axis travel resolution","step/mm","Z-axis travel resolution in steps per millimeter."
|
||||
"110","X-axis maximum rate","mm/min","X-axis maximum rate. Used as G0 rapid rate."
|
||||
"111","Y-axis maximum rate","mm/min","Y-axis maximum rate. Used as G0 rapid rate."
|
||||
"112","Z-axis maximum rate","mm/min","Z-axis maximum rate. Used as G0 rapid rate."
|
||||
"120","X-axis acceleration","mm/sec^2","X-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
|
||||
"121","Y-axis acceleration","mm/sec^2","Y-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
|
||||
"122","Z-axis acceleration","mm/sec^2","Z-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
|
||||
"130","X-axis maximum travel","millimeters","Maximum X-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
|
||||
"131","Y-axis maximum travel","millimeters","Maximum Y-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
|
||||
"132","Z-axis maximum travel","millimeters","Maximum Z-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
|
||||
"140-145","Motor run current","Amps","Motor run current for SPI (Trinamic) type motors"
|
||||
"150-155","Motor hold current","Percent","Hold current in percent of run current for SPI (Trinamic) type motors"
|
||||
"160-165","Motor microstepping","micros/step","Number of microsteps per step for SPI (Trinamic) type motors"
|
||||
"170-175","Motor Stallguard Value","0-255","Value of Stallguard setting for SPI (Trinamic) type motors"
|
||||
|
|
373
Grbl_Esp32-master/doc/script/fit_nonlinear_spindle.py
Normal file
373
Grbl_Esp32-master/doc/script/fit_nonlinear_spindle.py
Normal file
@ -0,0 +1,373 @@
|
||||
"""
|
||||
---------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2018 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
---------------------
|
||||
"""
|
||||
|
||||
|
||||
"""
|
||||
This Python script produces a continuous piece-wise line fit of actual spindle speed over
|
||||
programmed speed/PWM, which must be measured and provided by the user. A plot of the data
|
||||
and line fit will be auto-generated and saved in the working directory as 'line_fit.png'.
|
||||
|
||||
REQUIREMENTS:
|
||||
- Python 2.7 or 3.x with SciPy, NumPy, and Matplotlib Python Libraries
|
||||
|
||||
- For the most people, the easiest way to run this script is on the free cloud service
|
||||
https://repl.it/site/languages/python3. No account necessary. Unlimited runs.
|
||||
|
||||
- Last checked on 4/5/2018. This site has been regularly evolving and becoming more
|
||||
powerful. Things may not work exactly as shown. Please report any issues.
|
||||
|
||||
- To use, go to the website and start the Python REPL. Copy and paste this script into
|
||||
the main.py file in the browser editor. Click 'Run' and a solution should appear in
|
||||
the text output in the REPL console window. You can edit the script directly in the
|
||||
browser and re-run the script as many times as you need. A free account is only
|
||||
necessary if you want to save files on their servers.
|
||||
|
||||
- This script will also automatically generate a png image with the plot of the data
|
||||
with the piece-wise linear fit over it, but this will not show up by default on this
|
||||
website. To enable this, just click the 'Add File' icon and create a dummy file.
|
||||
Name it anything, like dummy.py. Leave this file blank. Doing this places the REPL
|
||||
in multiple file mode and will enable viewing the plot. Click the 'Run' icon. The
|
||||
solution will be presented again in the console, and the data plot will appear in
|
||||
the file list called 'line_fit.png'. Click the file to view the plot.
|
||||
|
||||
- For offline Python installs, most Mac and Linux computers have Python pre-installed
|
||||
with the required libraries. If not, a quick google search will show you how to
|
||||
install them. For Windows, Python installations are bit more difficult. Anaconda and
|
||||
Pyzo seem to work well.
|
||||
|
||||
USAGE:
|
||||
- First, make sure you are using the stock build of Grbl for the 328p processor. Most
|
||||
importantly, the SPINDLE_PWM_MAX_VALUE and SPINDLE_PWM_MIN_VALUE should be unaltered
|
||||
from defaults, otherwise change them back to 255.0 and 1.0 respectively for this test.
|
||||
|
||||
- Next, program the max and min rpm Grbl settings to '$30=255' and '$31=1'. This sets
|
||||
the internal PWM values equal to 'S' spindle speed for the standard Grbl build.
|
||||
|
||||
- Check if your spindle does not turn on at very low voltages by setting 'S' spindle
|
||||
speed to 'S1'. If it does not turn on or turns at a non-useful rpm, increase 'S' by
|
||||
one until it does. Write down this 'S' value for later. You'll start the rpm data
|
||||
collection from this point onward and will need to update the SPINDLE_PWM_MIN_VALUE
|
||||
in cpu_map.h afterwards.
|
||||
|
||||
- Collect actual spindle speed with a tachometer or similar means over a range of 'S'
|
||||
and PWM values. Start by setting the spindle 'S' speed to the minimum useful 'S' from
|
||||
the last step and measure and record actual spindle rpm. Next, increase 'S' spindle
|
||||
speed over equally sized intervals and repeat the measurement. Increments of 20 rpm
|
||||
should be more than enough, but decrease increment size, if highly nonlinear. Complete
|
||||
the data collection the 'S' spindle speed equal to '$30' max rpm, or at the max useful
|
||||
rpm, and record the actual rpm output. Make sure to collect rpm data all the way
|
||||
throughout useful output rpm. The actual operating range within this model may be set
|
||||
later within Grbl with the '$30' and '$31' settings.
|
||||
|
||||
- In some cases, spindle PWM output can have discontinuities or not have a useful rpm
|
||||
in certain ranges. For example, a known controller board has the spindle rpm drop
|
||||
completely at voltages above ~4.5V. If you have discontinuities like this at the low
|
||||
or high range of rpm, simply trim them from the data set. Don't include them. For
|
||||
Grbl to compensate, you'll need to alter the SPINDLE_PWM_MIN_VALUE and/or
|
||||
SPINDLE_PWM_MAX_VALUE in cpu_map.h to where your data set ends. This script will
|
||||
indicate if you need to do that in the solution output.
|
||||
|
||||
- Keep in mind that spindles without control electronics can slow down drastically when
|
||||
cutting and under load. How much it slows down is dependent on a lot of factors, such
|
||||
as feed rate, chip load, cutter diameter, flutes, cutter type, lubricant/coolant,
|
||||
material being cut, etc. Even spindles with controllers can still slow down if the
|
||||
load is higher than the max current the controller can provide. It's recommended to
|
||||
frequently re-check and measure actual spindle speed during a job. You can always use
|
||||
spindle speed overrides to tweak it temporarily to the desired speed.
|
||||
|
||||
- Edit this script and enter the measured rpm values and their corresponding 'S' spindle
|
||||
speed values in the data arrays below. Set the number of piecewise lines you would
|
||||
like to use, from one to four lines. For most cases, four lines is perfectly fine.
|
||||
In certain scenarios (laser engraving), this may significantly degrade performance and
|
||||
should be reduced if possible.
|
||||
|
||||
- Run the Python script. Visually assess the line fit from the plot. It will not likely
|
||||
to what you want on the first go. Dial things in by altering the line fit junction
|
||||
points 'PWM_pointX' in this script to move where the piecewise line junctions are
|
||||
located along the plot x-axis. It may be desired to tweak the junction points so the
|
||||
model solution is more accurate in the region that the spindle typically running.
|
||||
Re-run the script and tweak the junction points until you are satified with the model.
|
||||
|
||||
- Record the solution and enter the RPM_POINT and RPM_LINE values into config.h. Set the
|
||||
number of piecewise lines used in this model in config.h. Also set the '$30' and '$31'
|
||||
max and min rpm values to the solution values or in a range between them in Grbl '$'
|
||||
settings. And finally, alter the SPINDLE_PWM_MIN_VALUE in cpu_map.h, if your spindle
|
||||
needs to be above a certain voltage to produce a useful low rpm.
|
||||
|
||||
- Once the solution is entered. Recompile and flash Grbl. This solution model is only
|
||||
valid for this particular set of data. If the machine is altered, you will need to
|
||||
perform this experiment again and regenerate a new model here.
|
||||
|
||||
OUTPUT:
|
||||
The solver produces a set of values that define the piecewise fit and can be used by
|
||||
Grbl to quickly and efficiently compute spindle PWM output voltage for a desired RPM.
|
||||
|
||||
The first two are the RPM_MAX ($30) and RPM_MIN ($31) Grbl settings. These must be
|
||||
programmed into Grbl manually or setup in defaults.h for new systems. Altering these
|
||||
values within Grbl after a piece-wise linear model is installed will not change alter
|
||||
model. It will only alter the range of spindle speed rpm values Grbl output.
|
||||
|
||||
For example, if the solver produces an RPM_MAX of 9000 and Grbl is programmed with
|
||||
$30=8000, S9000 may be programmed, but Grbl will only produce the output voltage to run
|
||||
at 8000 rpm. In other words, Grbl will only output voltages the range between
|
||||
max(RPM_MIN,$31) and min(RPM_MAX,$30).
|
||||
|
||||
The remaining values define the slopes and offsets of the line segments and the junction
|
||||
points between line segments, like so for n_pieces=3:
|
||||
|
||||
PWM_output = RPM_LINE_A1 * rpm - RPM_LINE_B1 [ RPM_MIN < rpm < RPM_POINT12 ]
|
||||
PWM_output = RPM_LINE_A2 * rpm - RPM_LINE_B2 [ RPM_POINT12 < rpm < RPM_POINT23 ]
|
||||
PWM_output = RPM_LINE_A3 * rpm - RPM_LINE_B3 [ RPM_POINT23 < rpm < RPM_MAX ]
|
||||
|
||||
NOTE: The script solves in terms of PWM but the final equations and values are expressed
|
||||
in terms of rpm in the form 'PWM = a*rpm - b'.
|
||||
|
||||
"""
|
||||
|
||||
from scipy import optimize
|
||||
import numpy as np
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
# Configure spindle PWM line fit solver
|
||||
|
||||
n_pieces = 4 # Number of line segments used for data fit. Only 1 to 4 line segments supported.
|
||||
|
||||
# Programmed 'S' spindle speed values. Must start with minimum useful PWM or 'S' programmed
|
||||
# value and end with the maximum useful PWM or 'S' programmed value. Order of the array must
|
||||
# be synced with the RPM_measured array below.
|
||||
# NOTE: ** DO NOT USE DATA FROM AN EXISTING PIECEWISE LINE FIT. USE DEFAULT GRBL MODEL ONLY. **
|
||||
PWM_set = np.array([2,18,36,55,73,91,109,127,146,164,182,200,218,237,254], dtype=float)
|
||||
|
||||
# Actual RPM measured at the spindle. Must be in the ascending value and equal in length
|
||||
# as the PWM_set array. Must include the min and max measured rpm output in the first and
|
||||
# last array entries, respectively.
|
||||
RPM_measured = np.array([213.,5420,7145,8282,9165,9765,10100,10500,10700,10900,11100,11250,11400,11550,11650], dtype=float)
|
||||
|
||||
# Configure line fit points by 'S' programmed rpm or PWM value. Values must be between
|
||||
# PWM_max and PWM_min. Typically, alter these values to space the points evenly between
|
||||
# max and min PWM range. However, they may be tweaked to maximize accuracy in the places
|
||||
# you normally operate for highly nonlinear curves. Plot to visually assess how well the
|
||||
# solution fits the data.
|
||||
PWM_point1 = 20.0 # (S) Point between segments 0 and 1. Used when n_pieces >= 2.
|
||||
PWM_point2 = 80.0 # (S) Point between segments 1 and 2. Used when n_pieces >= 3.
|
||||
PWM_point3 = 150.0 # (S) Point between segments 2 and 3. Used when n_pieces = 4.
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
|
||||
# Advanced settings
|
||||
|
||||
# The optimizer requires an initial guess of the solution. Change value if solution fails.
|
||||
slope_i = 100.0; # > 0.0
|
||||
|
||||
PWM_max = max(PWM_set) # Maximum PWM set in measured range
|
||||
PWM_min = min(PWM_set) # Minimum PWM set in measured range
|
||||
plot_figure = True # Set to False, if matplotlib is not available.
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
# DO NOT ALTER ANYTHING BELOW.
|
||||
|
||||
def piecewise_linear_1(x,b,k1):
|
||||
return np.piecewise(x, [(x>=PWM_min)&(x<=PWM_max)], [lambda x:k1*(x-PWM_min)+b])
|
||||
|
||||
def piecewise_linear_2(x,b,k1,k2):
|
||||
c = [b,
|
||||
b+k1*(PWM_point1-PWM_min)]
|
||||
funcs = [lambda x:k1*(x-PWM_min)+c[0],
|
||||
lambda x:k2*(x-PWM_point1)+c[1]]
|
||||
conds = [(x<PWM_point1)&(x>=PWM_min),
|
||||
(x<=PWM_max)&(x>=PWM_point1)]
|
||||
return np.piecewise(x, conds, funcs)
|
||||
|
||||
def piecewise_linear_3(x,b,k1,k2,k3):
|
||||
c = [b,
|
||||
b+k1*(PWM_point1-PWM_min),
|
||||
b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1)]
|
||||
funcs = [lambda x:k1*(x-PWM_min)+c[0],
|
||||
lambda x:k2*(x-PWM_point1)+c[1],
|
||||
lambda x:k3*(x-PWM_point2)+c[2]]
|
||||
conds = [(x<PWM_point1)&(x>=PWM_min),
|
||||
(x<PWM_point2)&(x>=PWM_point1),
|
||||
(x<=PWM_max)&(x>=PWM_point2)]
|
||||
return np.piecewise(x, conds, funcs)
|
||||
|
||||
def piecewise_linear_4(x,b,k1,k2,k3,k4):
|
||||
c = [b,
|
||||
b+k1*(PWM_point1-PWM_min),
|
||||
b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1),
|
||||
b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1)+k3*(PWM_point3-PWM_point2)]
|
||||
funcs = [lambda x:k1*(x-PWM_min)+c[0],
|
||||
lambda x:k2*(x-PWM_point1)+c[1],
|
||||
lambda x:k3*(x-PWM_point2)+c[2],
|
||||
lambda x:k4*(x-PWM_point3)+c[3]]
|
||||
conds = [(x<PWM_point1)&(x>=PWM_min),
|
||||
(x<PWM_point2)&(x>=PWM_point1),
|
||||
(x<PWM_point3)&(x>=PWM_point2),
|
||||
(x<=PWM_max)&(x>=PWM_point3)]
|
||||
return np.piecewise(x, conds, funcs)
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
|
||||
print("\nCONFIG:")
|
||||
print(" N_pieces: %i" % n_pieces)
|
||||
print(" PWM_min: %.1f" % PWM_min)
|
||||
print(" PWM_max: %.1f" % PWM_max)
|
||||
if n_pieces > 1:
|
||||
print(" PWM_point1: %.1f" % PWM_point1)
|
||||
if n_pieces > 2:
|
||||
print(" PWM_point2: %.1f" % PWM_point2)
|
||||
if n_pieces > 3:
|
||||
print(" PWM_point3: %.1f" % PWM_point3)
|
||||
print(" N_data: %i" % len(RPM_measured))
|
||||
print(" PWM_set: ", PWM_set)
|
||||
print(" RPM_measured: ", RPM_measured)
|
||||
|
||||
if n_pieces == 1:
|
||||
piece_func = piecewise_linear_1
|
||||
p_initial = [RPM_measured[0],slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1]]
|
||||
b = [ p[0]-p[1]*PWM_min]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)]
|
||||
|
||||
elif n_pieces == 2:
|
||||
piece_func = piecewise_linear_2
|
||||
p_initial = [RPM_measured[0],slope_i,slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1],p[2]]
|
||||
b = [ p[0]-p[1]*PWM_min,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_max-PWM_point1)]
|
||||
|
||||
elif n_pieces == 3:
|
||||
piece_func = piecewise_linear_3
|
||||
p_initial = [RPM_measured[0],slope_i,slope_i,slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1],p[2],p[3]]
|
||||
b = [ p[0]-p[1]*PWM_min,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)-p[3]*PWM_point2]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_max-PWM_point2) ]
|
||||
|
||||
elif n_pieces == 4:
|
||||
piece_func = piecewise_linear_4
|
||||
p_initial = [RPM_measured[0],slope_i,slope_i,slope_i,slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1],p[2],p[3],p[4]]
|
||||
b = [ p[0]-p[1]*PWM_min,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)-p[3]*PWM_point2,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2)-p[4]*PWM_point3 ]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2)+p[4]*(PWM_max-PWM_point3) ]
|
||||
|
||||
else :
|
||||
print("ERROR: Unsupported number of pieces. Check and alter n_pieces")
|
||||
quit()
|
||||
|
||||
print("\nSOLUTION:\n\n[Update these #define values and uncomment]\n[ENABLE_PIECEWISE_LINEAR_SPINDLE in config.h.]")
|
||||
print("#define N_PIECES %.0f" % n_pieces)
|
||||
print("#define RPM_MAX %.1f" % rpm[-1])
|
||||
print("#define RPM_MIN %.1f" % rpm[0])
|
||||
|
||||
if n_pieces > 1:
|
||||
print("#define RPM_POINT12 %.1f" % rpm[1])
|
||||
if n_pieces > 2:
|
||||
print("#define RPM_POINT23 %.1f" %rpm[2])
|
||||
if n_pieces > 3:
|
||||
print("#define RPM_POINT34 %.1f" %rpm[3])
|
||||
|
||||
print("#define RPM_LINE_A1 %.6e" % (1./a[0]))
|
||||
print("#define RPM_LINE_B1 %.6e" % (b[0]/a[0]))
|
||||
if n_pieces > 1:
|
||||
print("#define RPM_LINE_A2 %.6e" % (1./a[1]))
|
||||
print("#define RPM_LINE_B2 %.6e" % (b[1]/a[1]))
|
||||
if n_pieces > 2:
|
||||
print("#define RPM_LINE_A3 %.6e" % (1./a[2]))
|
||||
print("#define RPM_LINE_B3 %.6e" % (b[2]/a[2]))
|
||||
if n_pieces > 3:
|
||||
print("#define RPM_LINE_A4 %.6e" % (1./a[3]))
|
||||
print("#define RPM_LINE_B4 %.6e" % (b[3]/a[3]))
|
||||
|
||||
print("\n[To operate over full model range, manually write these]")
|
||||
print("['$' settings or alter values in defaults.h. Grbl will]")
|
||||
print("[operate between min($30,RPM_MAX) and max($31,RPM_MIN)]")
|
||||
print("$30=%.1f (rpm max)" % rpm[-1])
|
||||
print("$31=%.1f (rpm min)" % rpm[0])
|
||||
|
||||
if (PWM_min > 1)|(PWM_max<255):
|
||||
print("\n[Update the following #define values in cpu_map.h]")
|
||||
if (PWM_min >1) :
|
||||
print("#define SPINDLE_PWM_MIN_VALUE %.0f" % PWM_min)
|
||||
if PWM_max <255:
|
||||
print("#define SPINDLE_PWM_MAX_VALUE %.0f" % PWM_max)
|
||||
else:
|
||||
print("\n[No cpu_map.h changes required.]")
|
||||
print("\n")
|
||||
|
||||
test_val = (1./a[0])*rpm[0] - (b[0]/a[0])
|
||||
if test_val < 0.0 :
|
||||
print("ERROR: Solution is negative at RPM_MIN. Adjust junction points or increase n_pieces.\n")
|
||||
|
||||
if plot_figure:
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111)
|
||||
xd = np.linspace(PWM_min, PWM_max, 10000)
|
||||
ax.plot(PWM_set, RPM_measured, "o")
|
||||
ax.plot(xd, piece_func(xd, *p),'g')
|
||||
plt.xlabel("Programmed PWM")
|
||||
plt.ylabel("Measured RPM")
|
||||
|
||||
# Check solution by plotting in terms of rpm.
|
||||
# x = np.linspace(rpm[0], rpm[1], 10000)
|
||||
# ax.plot((1./a[0])*x-(b[0]/a[0]),x,'r:')
|
||||
# if n_pieces > 1:
|
||||
# x = np.linspace(rpm[1], rpm[2], 10000)
|
||||
# ax.plot((1./a[1])*x-(b[1]/a[1]),x,'r:')
|
||||
# if n_pieces > 2:
|
||||
# x = np.linspace(rpm[2], rpm[3], 10000)
|
||||
# ax.plot((1./a[2])*x-(b[2]/a[2]),x,'r:')
|
||||
# if n_pieces > 3:
|
||||
# x = np.linspace(rpm[3], rpm[-1], 10000)
|
||||
# ax.plot((1./a[3])*x-(b[3]/a[3]),x,'r:')
|
||||
|
||||
fig.savefig("line_fit.png")
|
BIN
Grbl_Esp32-master/doc/script/piecewise_example.png
Normal file
BIN
Grbl_Esp32-master/doc/script/piecewise_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
66
Grbl_Esp32-master/doc/script/simple_stream.py
Normal file
66
Grbl_Esp32-master/doc/script/simple_stream.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
"""\
|
||||
Simple g-code streaming script for grbl
|
||||
|
||||
Provided as an illustration of the basic communication interface
|
||||
for grbl. When grbl has finished parsing the g-code block, it will
|
||||
return an 'ok' or 'error' response. When the planner buffer is full,
|
||||
grbl will not send a response until the planner buffer clears space.
|
||||
|
||||
G02/03 arcs are special exceptions, where they inject short line
|
||||
segments directly into the planner. So there may not be a response
|
||||
from grbl for the duration of the arc.
|
||||
|
||||
---------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012 Sungeun K. Jeon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
---------------------
|
||||
"""
|
||||
|
||||
import serial
|
||||
import time
|
||||
|
||||
# Open grbl serial port
|
||||
s = serial.Serial('/dev/tty.usbmodem1811',115200)
|
||||
|
||||
# Open g-code file
|
||||
f = open('grbl.gcode','r');
|
||||
|
||||
# Wake up grbl
|
||||
s.write("\r\n\r\n")
|
||||
time.sleep(2) # Wait for grbl to initialize
|
||||
s.flushInput() # Flush startup text in serial input
|
||||
|
||||
# Stream g-code to grbl
|
||||
for line in f:
|
||||
l = line.strip() # Strip all EOL characters for consistency
|
||||
print 'Sending: ' + l,
|
||||
s.write(l + '\n') # Send g-code block to grbl
|
||||
grbl_out = s.readline() # Wait for grbl response with carriage return
|
||||
print ' : ' + grbl_out.strip()
|
||||
|
||||
# Wait here until grbl is finished to close serial port and file.
|
||||
raw_input(" Press <Enter> to exit and disable grbl.")
|
||||
|
||||
# Close file and serial port
|
||||
f.close()
|
||||
s.close()
|
202
Grbl_Esp32-master/doc/script/stream.py
Normal file
202
Grbl_Esp32-master/doc/script/stream.py
Normal file
@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env python
|
||||
"""\
|
||||
|
||||
Stream g-code to grbl controller
|
||||
|
||||
This script differs from the simple_stream.py script by
|
||||
tracking the number of characters in grbl's serial read
|
||||
buffer. This allows grbl to fetch the next line directly
|
||||
from the serial buffer and does not have to wait for a
|
||||
response from the computer. This effectively adds another
|
||||
buffer layer to prevent buffer starvation.
|
||||
|
||||
CHANGELOG:
|
||||
- 20170531: Status report feedback at 1.0 second intervals.
|
||||
Configurable baudrate and report intervals. Bug fixes.
|
||||
- 20161212: Added push message feedback for simple streaming
|
||||
- 20140714: Updated baud rate to 115200. Added a settings
|
||||
write mode via simple streaming method. MIT-licensed.
|
||||
|
||||
TODO:
|
||||
- Add realtime control commands during streaming.
|
||||
|
||||
---------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2017 Sungeun K. Jeon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
---------------------
|
||||
"""
|
||||
|
||||
import serial
|
||||
import re
|
||||
import time
|
||||
import sys
|
||||
import argparse
|
||||
import threading
|
||||
|
||||
RX_BUFFER_SIZE = 128
|
||||
BAUD_RATE = 115200
|
||||
ENABLE_STATUS_REPORTS = True
|
||||
REPORT_INTERVAL = 1.0 # seconds
|
||||
|
||||
is_run = True # Controls query timer
|
||||
|
||||
# Define command line argument interface
|
||||
parser = argparse.ArgumentParser(description='Stream g-code file to grbl. (pySerial and argparse libraries required)')
|
||||
parser.add_argument('gcode_file', type=argparse.FileType('r'),
|
||||
help='g-code filename to be streamed')
|
||||
parser.add_argument('device_file',
|
||||
help='serial device path')
|
||||
parser.add_argument('-q','--quiet',action='store_true', default=False,
|
||||
help='suppress output text')
|
||||
parser.add_argument('-s','--settings',action='store_true', default=False,
|
||||
help='settings write mode')
|
||||
parser.add_argument('-c','--check',action='store_true', default=False,
|
||||
help='stream in check mode')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Periodic timer to query for status reports
|
||||
# TODO: Need to track down why this doesn't restart consistently before a release.
|
||||
def send_status_query():
|
||||
s.write('?')
|
||||
|
||||
def periodic_timer() :
|
||||
while is_run:
|
||||
send_status_query()
|
||||
time.sleep(REPORT_INTERVAL)
|
||||
|
||||
|
||||
# Initialize
|
||||
s = serial.Serial(args.device_file,BAUD_RATE)
|
||||
f = args.gcode_file
|
||||
verbose = True
|
||||
if args.quiet : verbose = False
|
||||
settings_mode = False
|
||||
if args.settings : settings_mode = True
|
||||
check_mode = False
|
||||
if args.check : check_mode = True
|
||||
|
||||
# Wake up grbl
|
||||
print "Initializing Grbl..."
|
||||
s.write("\r\n\r\n")
|
||||
|
||||
# Wait for grbl to initialize and flush startup text in serial input
|
||||
time.sleep(2)
|
||||
s.flushInput()
|
||||
|
||||
if check_mode :
|
||||
print "Enabling Grbl Check-Mode: SND: [$C]",
|
||||
s.write("$C\n")
|
||||
while 1:
|
||||
grbl_out = s.readline().strip() # Wait for grbl response with carriage return
|
||||
if grbl_out.find('error') >= 0 :
|
||||
print "REC:",grbl_out
|
||||
print " Failed to set Grbl check-mode. Aborting..."
|
||||
quit()
|
||||
elif grbl_out.find('ok') >= 0 :
|
||||
if verbose: print 'REC:',grbl_out
|
||||
break
|
||||
|
||||
start_time = time.time();
|
||||
|
||||
# Start status report periodic timer
|
||||
if ENABLE_STATUS_REPORTS :
|
||||
timerThread = threading.Thread(target=periodic_timer)
|
||||
timerThread.daemon = True
|
||||
timerThread.start()
|
||||
|
||||
# Stream g-code to grbl
|
||||
l_count = 0
|
||||
error_count = 0
|
||||
if settings_mode:
|
||||
# Send settings file via simple call-response streaming method. Settings must be streamed
|
||||
# in this manner since the EEPROM accessing cycles shut-off the serial interrupt.
|
||||
print "SETTINGS MODE: Streaming", args.gcode_file.name, " to ", args.device_file
|
||||
for line in f:
|
||||
l_count += 1 # Iterate line counter
|
||||
# l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
|
||||
l_block = line.strip() # Strip all EOL characters for consistency
|
||||
if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
|
||||
s.write(l_block + '\n') # Send g-code block to grbl
|
||||
while 1:
|
||||
grbl_out = s.readline().strip() # Wait for grbl response with carriage return
|
||||
if grbl_out.find('ok') >= 0 :
|
||||
if verbose: print " REC<"+str(l_count)+": \""+grbl_out+"\""
|
||||
break
|
||||
elif grbl_out.find('error') >= 0 :
|
||||
if verbose: print " REC<"+str(l_count)+": \""+grbl_out+"\""
|
||||
error_count += 1
|
||||
break
|
||||
else:
|
||||
print " MSG: \""+grbl_out+"\""
|
||||
else:
|
||||
# Send g-code program via a more agressive streaming protocol that forces characters into
|
||||
# Grbl's serial read buffer to ensure Grbl has immediate access to the next g-code command
|
||||
# rather than wait for the call-response serial protocol to finish. This is done by careful
|
||||
# counting of the number of characters sent by the streamer to Grbl and tracking Grbl's
|
||||
# responses, such that we never overflow Grbl's serial read buffer.
|
||||
g_count = 0
|
||||
c_line = []
|
||||
for line in f:
|
||||
l_count += 1 # Iterate line counter
|
||||
l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
|
||||
# l_block = line.strip()
|
||||
c_line.append(len(l_block)+1) # Track number of characters in grbl serial read buffer
|
||||
grbl_out = ''
|
||||
while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
|
||||
out_temp = s.readline().strip() # Wait for grbl response
|
||||
if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
|
||||
print " MSG: \""+out_temp+"\"" # Debug response
|
||||
else :
|
||||
if out_temp.find('error') >= 0 : error_count += 1
|
||||
g_count += 1 # Iterate g-code counter
|
||||
if verbose: print " REC<"+str(g_count)+": \""+out_temp+"\""
|
||||
del c_line[0] # Delete the block character count corresponding to the last 'ok'
|
||||
s.write(l_block + '\n') # Send g-code block to grbl
|
||||
if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
|
||||
# Wait until all responses have been received.
|
||||
while l_count > g_count :
|
||||
out_temp = s.readline().strip() # Wait for grbl response
|
||||
if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
|
||||
print " MSG: \""+out_temp+"\"" # Debug response
|
||||
else :
|
||||
if out_temp.find('error') >= 0 : error_count += 1
|
||||
g_count += 1 # Iterate g-code counter
|
||||
del c_line[0] # Delete the block character count corresponding to the last 'ok'
|
||||
if verbose: print " REC<"+str(g_count)+": \""+out_temp + "\""
|
||||
|
||||
# Wait for user input after streaming is completed
|
||||
print "\nG-code streaming finished!"
|
||||
end_time = time.time();
|
||||
is_run = False;
|
||||
print " Time elapsed: ",end_time-start_time,"\n"
|
||||
if check_mode :
|
||||
if error_count > 0 :
|
||||
print "CHECK FAILED:",error_count,"errors found! See output for details.\n"
|
||||
else :
|
||||
print "CHECK PASSED: No errors found in g-code program.\n"
|
||||
else :
|
||||
print "WARNING: Wait until Grbl completes buffered g-code blocks before exiting."
|
||||
raw_input(" Press <Enter> to exit and disable Grbl.")
|
||||
|
||||
# Close file and serial port
|
||||
f.close()
|
||||
s.close()
|
Reference in New Issue
Block a user