Lot of refactoring for the future. CoreXY support.

- Rudimentary CoreXY kinematics support. Didn’t test, but homing and
feed holds should work. See config.h. Please report successes and
issues as we find bugs.

- G40 (disable cutter comp) is now “supported”. Meaning that Grbl will
no longer issue an error when typically sent in g-code program header.

- Refactored coolant and spindle state setting into separate functions
for future features.

- Configuration option for fixing homing behavior when there are two
limit switches on the same axis sharing an input pin.

- Created a new “grbl.h” that will eventually be used as the main
include file for Grbl. Also will help simply uploading through the
Arduino IDE

- Separated out the alarms execution flags from the realtime (used be
called runtime) execution flag variable. Now reports exactly what
caused the alarm. Expandable for new alarms later on.

- Refactored the homing cycle to support CoreXY.

- Applied @EliteEng updates to Mega2560 support. Some pins were
reconfigured.

- Created a central step to position and vice versa function. Needed
for non-traditional cartesian machines. Should make it easier later.

- Removed the new CPU map for the Uno. No longer going to used. There
will be only one configuration to keep things uniform.
This commit is contained in:
Sonny Jeon 2015-01-14 22:14:52 -07:00
parent 7e67395463
commit 9be7b3d930
45 changed files with 529 additions and 15886 deletions

View File

@ -2,7 +2,7 @@
config.h - compile time configuration
Part of Grbl v0.9
Copyright (c) 2013-2014 Sungeun K. Jeon
Copyright (c) 2013-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -43,9 +43,9 @@
// Default cpu mappings. Grbl officially supports the Arduino Uno only. Other processor types
// may exist from user-supplied templates or directly user-defined in cpu_map.h
#define CPU_MAP_ATMEGA328P_TRADITIONAL // Arduino Uno CPU
#define CPU_MAP_ATMEGA328P // Arduino Uno CPU
// Define runtime command special characters. These characters are 'picked-off' directly from the
// Define realtime command special characters. These characters are 'picked-off' directly from the
// serial read data stream and are not passed to the grbl line execution parser. Select characters
// that do not and must not exist in the streamed g-code program. ASCII control characters may be
// used, if they are available per user setup. Also, extended ASCII codes (>127), which are never in
@ -107,6 +107,14 @@
#define N_DECIMAL_RATEVALUE_MM 0 // Rate or velocity value in mm/min
#define N_DECIMAL_SETTINGVALUE 3 // Decimals for floating point setting values
// If your machine has two limits switches wired in parallel to one axis, you will need to enable
// this feature. Since the two switches are sharing a single pin, there is no way for Grbl to tell
// which one is enabled. This option only effects homing, where if a limit is engaged, Grbl will
// alarm out and force the user to manually disengage the limit switch. Otherwise, if you have one
// limit switch for each axis, don't enable this option. By keeping it disabled, you can homing while
// on the limit switch and not have to move the machine off of it.
// #define LIMITS_TWO_SWITCHES_ON_AXES
// Allows GRBL to track and report gcode line numbers. Enabling this means that the planning buffer
// goes from 18 or 16 to make room for the additional line number data in the plan_block_t struct
// #define USE_LINE_NUMBERS // Disabled by default. Uncomment to enable.
@ -126,6 +134,15 @@
// NOTE: The M8 flood coolant control pin on analog pin 4 will still be functional regardless.
// #define ENABLE_M7 // Disabled by default. Uncomment to enable.
// Enable CoreXY kinematics. Use ONLY with CoreXY machines.
// IMPORTANT: If homing is enabled, you must reconfigure the homing cycle #defines above to
// #define HOMING_CYCLE_0 (1<<X_AXIS) and #define HOMING_CYCLE_1 (1<<Y_AXIS)
// NOTE: This configuration option alters the motion of the X and Y axes to principle of operation
// defined at (http://corexy.com/theory.html). Motors are assumed to positioned and wired exactly as
// described, if not, motions may move in strange directions. Grbl assumes the CoreXY A and B motors
// have the same steps per mm internally.
// #define COREXY // Default disabled. Uncomment to enable.
// ---------------------------------------------------------------------------------------
// ADVANCED CONFIGURATION OPTIONS:
@ -268,9 +285,7 @@
// ---------------------------------------------------------------------------------------
// COMPILE-TIME ERROR CHECKING OF DEFINE VALUES:
// #if (ISR_TICKS_PER_ACCELERATION_TICK > 255)
// #error Parameters ACCELERATION_TICKS / ISR_TICKS must be < 256 to prevent integer overflow.
// #endif
// ---------------------------------------------------------------------------------------

View File

@ -2,7 +2,7 @@
coolant_control.c - coolant control methods
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -43,12 +43,8 @@ void coolant_stop()
}
void coolant_run(uint8_t mode)
void coolant_set_state(uint8_t mode)
{
if (sys.state == STATE_CHECK_MODE) { return; }
protocol_auto_cycle_start(); //temp fix for M8 lockup
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
if (mode == COOLANT_FLOOD_ENABLE) {
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
@ -61,3 +57,11 @@ void coolant_run(uint8_t mode)
coolant_stop();
}
}
void coolant_run(uint8_t mode)
{
if (sys.state == STATE_CHECK_MODE) { return; }
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
coolant_set_state(mode);
}

View File

@ -2,7 +2,7 @@
coolant_control.h - spindle control methods
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -24,6 +24,7 @@
void coolant_init();
void coolant_stop();
void coolant_set_state(uint8_t mode);
void coolant_run(uint8_t mode);
#endif

174
cpu_map.h
View File

@ -2,7 +2,7 @@
cpu_map.h - CPU and pin mapping configuration file
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@
//----------------------------------------------------------------------------------------
#ifdef CPU_MAP_ATMEGA328P_TRADITIONAL // (Arduino Uno) Officially supported by Grbl.
#ifdef CPU_MAP_ATMEGA328P // (Arduino Uno) Officially supported by Grbl.
// Define serial port pins and interrupt vectors.
#define SERIAL_RX USART_RX_vect
@ -123,6 +123,7 @@
#ifdef VARIABLE_SPINDLE
// Advanced Configuration Below You should not need to touch these variables
#define PWM_MAX_VALUE 255.0
#define TCCRA_REGISTER TCCR2A
#define TCCRB_REGISTER TCCR2B
#define OCR_REGISTER OCR2A
@ -142,118 +143,6 @@
#endif
//----------------------------------------------------------------------------------------
#ifdef CPU_MAP_ATMEGA328P_NEW // (Arduino Uno) New test pinout configuration. Still subject to change. Not finalized!
// Define serial port pins and interrupt vectors.
#define SERIAL_RX USART_RX_vect
#define SERIAL_UDRE USART_UDRE_vect
// Define step pulse output pins. NOTE: All step bit pins must be on the same port.
#define STEP_DDR DDRD
#define STEP_PORT PORTD
#define X_STEP_BIT 2 // Uno Digital Pin 2
#define Y_STEP_BIT 3 // Uno Digital Pin 3
#define Z_STEP_BIT 4 // Uno Digital Pin 4
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
// Define step direction output pins. NOTE: All direction pins must be on the same port.
#define DIRECTION_DDR DDRD
#define DIRECTION_PORT PORTD
#define X_DIRECTION_BIT 5 // Uno Digital Pin 5
#define Y_DIRECTION_BIT 6 // Uno Digital Pin 6
#define Z_DIRECTION_BIT 7 // Uno Digital Pin 7
#define DIRECTION_MASK ((1<<X_DIRECTION_BIT)|(1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) // All direction bits
// Define stepper driver enable/disable output pin.
#define STEPPERS_DISABLE_DDR DDRB
#define STEPPERS_DISABLE_PORT PORTB
#define STEPPERS_DISABLE_BIT 0 // Uno Digital Pin 8
#define STEPPERS_DISABLE_MASK (1<<STEPPERS_DISABLE_BIT)
// Define homing/hard limit switch input pins and limit interrupt vectors.
// NOTE: All limit bit pins must be on the same port, but not on a port with other input pins (pinout).
#define LIMIT_DDR DDRB
#define LIMIT_PIN PINB
#define LIMIT_PORT PORTB
#define X_LIMIT_BIT 1 // Uno Digital Pin 9
#define Y_LIMIT_BIT 2 // Uno Digital Pin 10
#ifdef VARIABLE_SPINDLE // Z Limit pin and spindle enabled swapped to access hardware PWM on Pin 11.
#define Z_LIMIT_BIT 4 // Uno Digital Pin 12
#else
#define Z_LIMIT_BIT 3 // Uno Digital Pin 11
#endif
#define LIMIT_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT)) // All limit bits
#define LIMIT_INT PCIE0 // Pin change interrupt enable pin
#define LIMIT_INT_vect PCINT0_vect
#define LIMIT_PCMSK PCMSK0 // Pin change interrupt register
// Define spindle enable and spindle direction output pins.
#define SPINDLE_ENABLE_DDR DDRB
#define SPINDLE_ENABLE_PORT PORTB
#ifdef VARIABLE_SPINDLE // Z Limit pin and spindle enabled swapped to access hardware PWM on Pin 11.
#define SPINDLE_ENABLE_BIT 3 // Uno Digital Pin 11
#else
#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12
#endif
#define SPINDLE_DIRECTION_DDR DDRB
#define SPINDLE_DIRECTION_PORT PORTB
#define SPINDLE_DIRECTION_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
// Define flood and mist coolant enable output pins.
// NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at
// a later date if flash and memory space allows.
#define COOLANT_FLOOD_DDR DDRC
#define COOLANT_FLOOD_PORT PORTC
#define COOLANT_FLOOD_BIT 1 // Uno Analog Pin 1
#ifdef ENABLE_M7 // Mist coolant disabled by default. See config.h to enable/disable.
#define COOLANT_MIST_DDR DDRC
#define COOLANT_MIST_PORT PORTC
#define COOLANT_MIST_BIT 2 // Uno Analog Pin 2
#endif
// Define user-control pinouts (cycle start, reset, feed hold) input pins.
// NOTE: All pinouts pins must be on the same port and not on a port with other input pins (limits).
#define PINOUT_DDR DDRC
#define PINOUT_PIN PINC
#define PINOUT_PORT PORTC
#define PIN_RESET 3 // Uno Analog Pin 3
#define PIN_FEED_HOLD 4 // Uno Analog Pin 4
#define PIN_CYCLE_START 5 // Uno Analog Pin 5
#define PINOUT_INT PCIE1 // Pin change interrupt enable pin
#define PINOUT_INT_vect PCINT1_vect
#define PINOUT_PCMSK PCMSK1 // Pin change interrupt register
#define PINOUT_MASK ((1<<PIN_RESET)|(1<<PIN_FEED_HOLD)|(1<<PIN_CYCLE_START))
// Define probe switch input pin.
#define PROBE_DDR DDRC
#define PROBE_PIN PINC
#define PROBE_PORT PORTC
#define PROBE_BIT 0 // Uno Analog Pin 0
#define PROBE_MASK (1<<PROBE_BIT)
#ifdef VARIABLE_SPINDLE
// Advanced Configuration Below You should not need to touch these variables
#define TCCRA_REGISTER TCCR2A
#define TCCRB_REGISTER TCCR2B
#define OCR_REGISTER OCR2A
#define COMB_BIT COM2A1
#define WAVE0_REGISTER WGM20
#define WAVE1_REGISTER WGM21
#define WAVE2_REGISTER WGM22
#define WAVE3_REGISTER WGM23
// NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings.
#define SPINDLE_PWM_DDR SPINDLE_ENABLE_DDR
#define SPINDLE_PWM_PORT SPINDLE_ENABLE_PORT
#define SPINDLE_PWM_BIT SPINDLE_ENABLE_BIT // Shared with SPINDLE_ENABLE.
#endif // End of VARIABLE_SPINDLE
#endif
//----------------------------------------------------------------------------------------
#ifdef CPU_MAP_ATMEGA2560 // (Arduino Mega 2560) Working @EliteEng
@ -272,18 +161,18 @@
#define STEP_DDR DDRA
#define STEP_PORT PORTA
#define STEP_PIN PINA
#define X_STEP_BIT 2 // MEGA2560 Digital Pin 24
#define Y_STEP_BIT 3 // MEGA2560 Digital Pin 25
#define Z_STEP_BIT 4 // MEGA2560 Digital Pin 26
#define X_STEP_BIT 2 // MEGA2560 Digital Pin 24
#define Y_STEP_BIT 3 // MEGA2560 Digital Pin 25
#define Z_STEP_BIT 4 // MEGA2560 Digital Pin 26
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
// Define step direction output pins. NOTE: All direction pins must be on the same port.
#define DIRECTION_DDR DDRA
#define DIRECTION_PORT PORTA
#define DIRECTION_PIN PINA
#define X_DIRECTION_BIT 5 // MEGA2560 Digital Pin 27
#define Y_DIRECTION_BIT 6 // MEGA2560 Digital Pin 28
#define Z_DIRECTION_BIT 7 // MEGA2560 Digital Pin 29
#define DIRECTION_DDR DDRC
#define DIRECTION_PORT PORTC
#define DIRECTION_PIN PINC
#define X_DIRECTION_BIT 7 // MEGA2560 Digital Pin 30
#define Y_DIRECTION_BIT 6 // MEGA2560 Digital Pin 31
#define Z_DIRECTION_BIT 5 // MEGA2560 Digital Pin 32
#define DIRECTION_MASK ((1<<X_DIRECTION_BIT)|(1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) // All direction bits
// Define stepper driver enable/disable output pin.
@ -305,9 +194,9 @@
#define LIMIT_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT)) // All limit bits
// Define spindle enable and spindle direction output pins.
#define SPINDLE_ENABLE_DDR DDRH
#define SPINDLE_ENABLE_PORT PORTH
#define SPINDLE_ENABLE_BIT 3 // MEGA2560 Digital Pin 6
#define SPINDLE_ENABLE_DDR DDRH
#define SPINDLE_ENABLE_PORT PORTH
#define SPINDLE_ENABLE_BIT 3 // MEGA2560 Digital Pin 6
#define SPINDLE_DIRECTION_DDR DDRE
#define SPINDLE_DIRECTION_PORT PORTE
#define SPINDLE_DIRECTION_BIT 3 // MEGA2560 Digital Pin 5
@ -315,13 +204,13 @@
// Define flood and mist coolant enable output pins.
// NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at
// a later date if flash and memory space allows.
#define COOLANT_FLOOD_DDR DDRH
#define COOLANT_FLOOD_PORT PORTH
#define COOLANT_FLOOD_BIT 5 // MEGA2560 Digital Pin 8
#define COOLANT_FLOOD_DDR DDRH
#define COOLANT_FLOOD_PORT PORTH
#define COOLANT_FLOOD_BIT 5 // MEGA2560 Digital Pin 8
#ifdef ENABLE_M7 // Mist coolant disabled by default. See config.h to enable/disable.
#define COOLANT_MIST_DDR DDRH
#define COOLANT_MIST_PORT PORTH
#define COOLANT_MIST_BIT 6 // MEGA2560 Digital Pin 9
#define COOLANT_MIST_DDR DDRH
#define COOLANT_MIST_PORT PORTH
#define COOLANT_MIST_BIT 6 // MEGA2560 Digital Pin 9
#endif
// Define user-control pinouts (cycle start, reset, feed hold) input pins.
@ -347,20 +236,21 @@
// Start of PWM & Stepper Enabled Spindle
#ifdef VARIABLE_SPINDLE
// Advanced Configuration Below You should not need to touch these variables
// Set Timer up to use TIMER2B which is attached to Digital Pin 9
#define TCCRA_REGISTER TCCR2A
#define TCCRB_REGISTER TCCR2B
#define OCR_REGISTER OCR2B
// Set Timer up to use TIMER4B which is attached to Digital Pin 7
#define PWM_MAX_VALUE 65535.0
#define TCCRA_REGISTER TCCR4A
#define TCCRB_REGISTER TCCR4B
#define OCR_REGISTER OCR4B
#define COMB_BIT COM2B1
#define WAVE0_REGISTER WGM20
#define WAVE1_REGISTER WGM21
#define WAVE2_REGISTER WGM22
#define WAVE3_REGISTER WGM23
#define COMB_BIT COM4B1
#define WAVE0_REGISTER WGM40
#define WAVE1_REGISTER WGM41
#define WAVE2_REGISTER WGM42
#define WAVE3_REGISTER WGM43
#define SPINDLE_PWM_DDR DDRH
#define SPINDLE_PWM_PORT PORTH
#define SPINDLE_PWM_BIT 6 // MEGA2560 Digital Pin 9
#define SPINDLE_PWM_BIT 4 // MEGA2560 Digital Pin 97
#endif // End of VARIABLE_SPINDLE
#endif

View File

@ -2,7 +2,7 @@
defaults.h - defaults settings configuration file
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

34
gcode.c
View File

@ -2,7 +2,7 @@
gcode.c - rs274/ngc parser.
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -66,10 +66,7 @@ void gc_init()
// limit pull-off routines.
void gc_sync_position()
{
uint8_t i;
for (i=0; i<N_AXIS; i++) {
gc_state.position[i] = sys.position[i]/settings.steps_per_mm[i];
}
system_convert_array_steps_to_mpos(gc_state.position,sys.position);
}
@ -243,6 +240,12 @@ uint8_t gc_execute_line(char *line)
if (int_value == 20) { gc_block.modal.units = UNITS_MODE_INCHES; } // G20
else { gc_block.modal.units = UNITS_MODE_MM; } // G21
break;
case 40:
word_bit = MODAL_GROUP_G7;
// NOTE: Not required since cutter radius compensation is always disabled. Only here
// to support G40 commands that often appear in g-code program headers to setup defaults.
// gc_block.modal.cutter_comp = CUTTER_COMP_DISABLE; // G40
break;
case 43: case 49:
word_bit = MODAL_GROUP_G8;
// NOTE: The NIST g-code standard vaguely states that when a tool length offset is changed,
@ -306,7 +309,7 @@ uint8_t gc_execute_line(char *line)
}
break;
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported M command]
}
}
// Check for more than one command per modal group violations in the current block
// NOTE: Variable 'word_bit' is always assigned, if the command is valid.
@ -488,7 +491,10 @@ uint8_t gc_execute_line(char *line)
}
}
// [13. Cutter radius compensation ]: NOT SUPPORTED. Error, if G53 is active.
// [13. Cutter radius compensation ]: G41/42 NOT SUPPORTED. Error, if enabled while G53 is active.
// [G40 Errors]: G2/3 arc is programmed after a G40. The linear move after disabling is less than tool diameter.
// NOTE: Since cutter radius compensation is never enabled, these G40 errors don't apply. Grbl supports G40
// only for the purpose to not error when G40 is sent with a g-code program header to setup the default modes.
// [14. Cutter length compensation ]: G43 NOT SUPPORTED, but G43.1 and G49 are.
// [G43.1 Errors]: Motion command in same line.
@ -839,10 +845,9 @@ uint8_t gc_execute_line(char *line)
// [4. Set spindle speed ]:
if (gc_state.spindle_speed != gc_block.values.s) {
gc_state.spindle_speed = gc_block.values.s;
// Update running spindle only if not in check mode and not already enabled.
if (gc_state.modal.spindle != SPINDLE_DISABLE) { spindle_run(gc_state.modal.spindle, gc_state.spindle_speed); }
if (gc_state.modal.spindle != SPINDLE_DISABLE) { spindle_run(gc_state.modal.spindle, gc_block.values.s); }
gc_state.spindle_speed = gc_block.values.s;
}
// [5. Select tool ]: NOT SUPPORTED. Only tracks tool value.
@ -852,15 +857,15 @@ uint8_t gc_execute_line(char *line)
// [7. Spindle control ]:
if (gc_state.modal.spindle != gc_block.modal.spindle) {
gc_state.modal.spindle = gc_block.modal.spindle;
// Update spindle control and apply spindle speed when enabling it in this block.
spindle_run(gc_state.modal.spindle, gc_state.spindle_speed);
spindle_run(gc_block.modal.spindle, gc_state.spindle_speed);
gc_state.modal.spindle = gc_block.modal.spindle;
}
// [8. Coolant control ]:
if (gc_state.modal.coolant != gc_block.modal.coolant) {
coolant_run(gc_block.modal.coolant);
gc_state.modal.coolant = gc_block.modal.coolant;
coolant_run(gc_state.modal.coolant);
}
// [9. Enable/disable feed rate or spindle overrides ]: NOT SUPPORTED
@ -874,7 +879,8 @@ uint8_t gc_execute_line(char *line)
// [12. Set length units ]:
gc_state.modal.units = gc_block.modal.units;
// [13. Cutter radius compensation ]: NOT SUPPORTED
// [13. Cutter radius compensation ]: G41/42 NOT SUPPORTED
// gc_state.modal.cutter_comp = gc_block.modal.cutter_comp; // NOTE: Not needed since always disabled.
// [14. Cutter length compensation ]: G43.1 and G49 supported. G43 NOT SUPPORTED.
// NOTE: If G43 were supported, its operation wouldn't be any different from G43.1 in terms

43
gcode.h
View File

@ -2,7 +2,7 @@
gcode.h - rs274/ngc parser.
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -40,16 +40,17 @@
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
#define MODAL_GROUP_G5 4 // [G93,G94] Feed rate mode
#define MODAL_GROUP_G6 5 // [G20,G21] Units
#define MODAL_GROUP_G8 6 // [G43,G43.1,G49] Tool length offset
#define MODAL_GROUP_G12 7 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
#define MODAL_GROUP_G7 6 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED.
#define MODAL_GROUP_G8 7 // [G43,G43.1,G49] Tool length offset
#define MODAL_GROUP_G12 8 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
#define MODAL_GROUP_M4 8 // [M0,M1,M2,M30] Stopping
#define MODAL_GROUP_M7 9 // [M3,M4,M5] Spindle turning
#define MODAL_GROUP_M8 10 // [M7,M8,M9] Coolant control
#define MODAL_GROUP_M4 9 // [M0,M1,M2,M30] Stopping
#define MODAL_GROUP_M7 10 // [M3,M4,M5] Spindle turning
#define MODAL_GROUP_M8 11 // [M7,M8,M9] Coolant control
#define OTHER_INPUT_F 11
#define OTHER_INPUT_S 12
#define OTHER_INPUT_T 13
#define OTHER_INPUT_F 12
#define OTHER_INPUT_S 13
#define OTHER_INPUT_T 14
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
// internally by the parser to know which command to execute.
@ -99,6 +100,9 @@
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
#define UNITS_MODE_INCHES 1 // G20
// Modal Group G7: Cutter radius compensation mode
#define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero)
// Modal Group M7: Spindle control
#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero)
#define SPINDLE_ENABLE_CW 1 // M3
@ -135,16 +139,17 @@
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
typedef struct {
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
uint8_t feed_rate; // {G93,G94}
uint8_t units; // {G20,G21}
uint8_t distance; // {G90,G91}
uint8_t plane_select; // {G17,G18,G19}
uint8_t tool_length; // {G43.1,G49}
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
uint8_t program_flow; // {M0,M1,M2,M30}
uint8_t coolant; // {M7,M8,M9}
uint8_t spindle; // {M3,M4,M5}
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
uint8_t feed_rate; // {G93,G94}
uint8_t units; // {G20,G21}
uint8_t distance; // {G90,G91}
uint8_t plane_select; // {G17,G18,G19}
// uint8_t cutter_comp; // {G40} NOTE: Don't need to track since it's always disabled.
uint8_t tool_length; // {G43.1,G49}
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
uint8_t program_flow; // {M0,M1,M2,M30}
uint8_t coolant; // {M7,M8,M9}
uint8_t spindle; // {M3,M4,M5}
} gc_modal_t;
typedef struct {

49
grbl.h Normal file
View File

@ -0,0 +1,49 @@
/*
grbl.h - include file
Part of Grbl v0.9
Copyright (c) 2015 Sungeun K. Jeon
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/>.
*/
// NOTE: This is not used by the 'make' compiling method. This is currently only used for
// simplifying compiling through the Arduino IDE at the moment. However, it may eventually
// turn into a central include file for the overall system.
#ifndef grbl_h
#define grbl_h
// All of the Grbl system include files.
#include "config.h"
#include "coolant_control.h"
#include "cpu_map.h"
#include "defaults.h"
#include "eeprom.h"
#include "gcode.h"
#include "limits.h"
#include "motion_control.h"
#include "nuts_bolts.h"
#include "planner.h"
#include "print.h"
#include "probe.h"
#include "protocol.h"
#include "report.h"
#include "serial.h"
#include "settings.h"
#include "spindle_control.h"
#include "stepper.h"
#include "system.h"
#endif

139
limits.c
View File

@ -2,7 +2,7 @@
limits.c - code pertaining to limit-switches and performing the homing cycle
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -89,9 +89,9 @@ void limits_disable()
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
// limit setting if their limits are constantly triggering after a reset and move their axes.
if (sys.state != STATE_ALARM) {
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
if (!(sys.rt_exec_alarm)) {
mc_reset(); // Initiate system kill.
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate hard limit critical event
bit_true_atomic(sys.rt_exec_alarm, (EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
}
}
}
@ -102,13 +102,13 @@ void limits_disable()
{
WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
if (sys.state != STATE_ALARM) { // Ignore if already in alarm state.
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
if (!(sys.rt_exec_alarm)) {
uint8_t bits = LIMIT_PIN;
// Check limit pin state.
if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { bits ^= LIMIT_MASK; }
if (bits & LIMIT_MASK) {
mc_reset(); // Initiate system kill.
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate hard limit critical event
bit_true_atomic(sys.rt_exec_alarm, (EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate hard limit critical event
}
}
}
@ -121,7 +121,7 @@ void limits_disable()
// the trigger point of the limit switches. The rapid stops are handled by a system level axis lock
// mask, which prevents the stepper algorithm from executing step pulses. Homing motions typically
// circumvent the processes for executing motions in normal operation.
// NOTE: Only the abort runtime command can interrupt this process.
// NOTE: Only the abort realtime command can interrupt this process.
// TODO: Move limit pin-specific calls to a general function for portability.
void limits_go_home(uint8_t cycle_mask)
{
@ -140,7 +140,10 @@ void limits_go_home(uint8_t cycle_mask)
// Initialize limit and step pin masks
limit_pin[idx] = get_limit_pin_mask(idx);
step_pin[idx] = get_step_pin_mask(idx);
#ifdef COREXY
if ((idx==A_MOTOR)||(idx==B_MOTOR)) { step_pin[idx] = (get_step_pin_mask(X_AXIS)|get_step_pin_mask(Y_AXIS)); }
#endif
// Determine travel distance to the furthest homing switch based on user max travel settings.
// NOTE: settings.max_travel[] is stored as a negative value.
if (max_travel > settings.max_travel[idx]) { max_travel = settings.max_travel[idx]; }
@ -148,6 +151,7 @@ void limits_go_home(uint8_t cycle_mask)
max_travel *= -HOMING_AXIS_SEARCH_SCALAR; // Ensure homing switches engaged by over-estimating max travel.
plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions.
plan_sync_position(); // Sync planner position to current machine position.
do {
// Initialize invert_pin boolean based on approach and invert pin user setting.
@ -157,20 +161,23 @@ void limits_go_home(uint8_t cycle_mask)
// Initialize and declare variables needed for homing routine.
uint8_t n_active_axis = 0;
uint8_t axislock = 0;
system_convert_array_steps_to_mpos(target,sys.position);
for (idx=0; idx<N_AXIS; idx++) {
// Set target location for active axes and setup computation for homing rate.
if (bit_istrue(cycle_mask,bit(idx))) {
n_active_axis++;
if (!approach) { target[idx] = -max_travel; }
else { target[idx] = max_travel; }
} else {
target[idx] = 0.0;
if (!approach) {
// Set target direction based on cycle mask
if (bit_istrue(settings.homing_dir_mask,bit(idx))) { target[idx] += max_travel; }
else { target[idx] -= max_travel; }
} else {
// Set target direction based on cycle mask
if (bit_istrue(settings.homing_dir_mask,bit(idx))) { target[idx] -= max_travel; }
else { target[idx] += max_travel; }
}
}
// Set target direction based on cycle mask
if (bit_istrue(settings.homing_dir_mask,bit(idx))) { target[idx] = -target[idx]; }
// Apply axislock to the step port pins active in this cycle.
if (bit_istrue(cycle_mask,bit(idx))) { axislock |= step_pin[idx]; }
}
@ -199,12 +206,14 @@ void limits_go_home(uint8_t cycle_mask)
}
sys.homing_axis_lock = axislock;
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
// Check only for user reset. No time to run protocol_execute_runtime() in this loop.
if (sys.execute & EXEC_RESET) { protocol_execute_runtime(); return; }
// Check only for user reset. No time to run protocol_execute_realtime() in this loop.
if (sys.rt_exec_state & EXEC_RESET) { protocol_execute_realtime(); return; }
} while (STEP_MASK & axislock);
st_reset(); // Immediately force kill steppers and reset step segment buffer.
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure homing motion is cleared.
plan_sync_position(); // Sync planner position to current machine position
delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
@ -220,45 +229,73 @@ void limits_go_home(uint8_t cycle_mask)
// set up pull-off maneuver from axes limit switches that have been homed. This provides
// some initial clearance off the switches and should also help prevent them from falsely
// triggering when hard limits are enabled or when more than one axes shares a limit pin.
#ifdef COREXY
int32_t off_axis_position = 0;
#endif
int32_t set_axis_position;
// Set machine positions for homed limit switches. Don't update non-homed axes.
for (idx=0; idx<N_AXIS; idx++) {
// Set up pull off targets and machine positions for limit switches homed in the negative
// direction, rather than the traditional positive. Leave non-homed positions as zero and
// do not move them.
// NOTE: settings.max_travel[] is stored as a negative value.
if (cycle_mask & bit(idx)) {
#ifdef HOMING_FORCE_SET_ORIGIN
sys.position[idx] = 0; // Set axis homed location as axis origin
target[idx] = settings.homing_pulloff;
if ( bit_isfalse(settings.homing_dir_mask,bit(idx)) ) { target[idx] = -target[idx]; }
#else
set_axis_position = 0;
#ifndef HOMING_FORCE_SET_ORIGIN
if ( bit_istrue(settings.homing_dir_mask,bit(idx)) ) {
target[idx] = settings.homing_pulloff+settings.max_travel[idx];
sys.position[idx] = lround(settings.max_travel[idx]*settings.steps_per_mm[idx]);
} else {
target[idx] = -settings.homing_pulloff;
sys.position[idx] = 0;
set_axis_position = lround(settings.max_travel[idx]*settings.steps_per_mm[idx]);
}
#endif
} else { // Non-active cycle axis. Set target to not move during pull-off.
target[idx] = (float)sys.position[idx]/settings.steps_per_mm[idx];
#ifdef COREXY
if (idx==X_AXIS) {
off_axis_position = (sys.position[B_MOTOR] - sys.position[A_MOTOR])/2;
sys.position[A_MOTOR] = set_axis_position - off_axis_position;
sys.position[B_MOTOR] = set_axis_position + off_axis_position;
} else if (idx==Y_AXIS) {
off_axis_position = (sys.position[A_MOTOR] + sys.position[B_MOTOR])/2;
sys.position[A_MOTOR] = off_axis_position - set_axis_position;
sys.position[B_MOTOR] = off_axis_position + set_axis_position;
} else {
sys.position[idx] = set_axis_position;
}
#else
sys.position[idx] = set_axis_position;
#endif
}
}
plan_sync_position(); // Sync planner position to current machine position for pull-off move.
plan_sync_position(); // Sync planner position to homed machine position.
// Set pull-off motion target. Seperated from above loop if target is dependent on sys.position.
if (settings.homing_pulloff > 0.0) {
for (idx=0; idx<N_AXIS; idx++) {
if (cycle_mask & bit(idx)) {
#ifdef HOMING_FORCE_SET_ORIGIN
target[idx] = settings.homing_pulloff;
if ( bit_isfalse(settings.homing_dir_mask,bit(idx)) ) { target[idx] = -target[idx]; }
#else
if ( bit_istrue(settings.homing_dir_mask,bit(idx)) ) {
target[idx] = settings.homing_pulloff+settings.max_travel[idx];
} else {
target[idx] = -settings.homing_pulloff;
}
#endif
} else {
// Non-active cycle axis. Set target to not move during pull-off.
target[idx] = system_convert_axis_steps_to_mpos(sys.position, idx);
}
}
#ifdef USE_LINE_NUMBERS
plan_buffer_line(target, settings.homing_seek_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan motion.
#else
plan_buffer_line(target, settings.homing_seek_rate, false); // Bypass mc_line(). Directly plan motion.
#endif
#ifdef USE_LINE_NUMBERS
plan_buffer_line(target, settings.homing_seek_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan motion.
#else
plan_buffer_line(target, settings.homing_seek_rate, false); // Bypass mc_line(). Directly plan motion.
#endif
// Initiate pull-off using main motion control routines.
// TODO : Clean up state routines so that this motion still shows homing state.
sys.state = STATE_QUEUED;
bit_true_atomic(sys.execute, EXEC_CYCLE_START);
protocol_execute_runtime();
protocol_buffer_synchronize(); // Complete pull-off motion.
// Initiate pull-off using main motion control routines.
// TODO : Clean up state routines so that this motion still shows homing state.
sys.state = STATE_QUEUED;
bit_true_atomic(sys.rt_exec_state, EXEC_CYCLE_START);
protocol_execute_realtime();
protocol_buffer_synchronize(); // Complete pull-off motion.
}
// Set system state to homing before returning.
sys.state = STATE_HOMING;
@ -291,16 +328,16 @@ void limits_soft_check(float *target)
// workspace volume so just come to a controlled stop so position is not lost. When complete
// enter alarm mode.
if (sys.state == STATE_CYCLE) {
bit_true_atomic(sys.execute, EXEC_FEED_HOLD);
bit_true_atomic(sys.rt_exec_state, EXEC_FEED_HOLD);
do {
protocol_execute_runtime();
protocol_execute_realtime();
if (sys.abort) { return; }
} while ( sys.state != STATE_IDLE || sys.state != STATE_QUEUED);
}
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate soft limit critical event
protocol_execute_runtime(); // Execute to enter critical event loop and system abort
bit_true_atomic(sys.rt_exec_alarm, (EXEC_ALARM_SOFT_LIMIT|EXEC_CRITICAL_EVENT)); // Indicate soft limit critical event
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
return;
}
}

View File

@ -2,7 +2,7 @@
limits.h - code pertaining to limit-switches and performing the homing cycle
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

5
main.c
View File

@ -2,7 +2,7 @@
main.c - An embedded CNC Controller with rs274/ngc (g-code) support
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -89,7 +89,8 @@ int main(void)
// Reset system variables.
sys.abort = false;
sys.execute = 0;
sys.rt_exec_state = 0;
sys.rt_exec_alarm = 0;
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
else { sys.auto_start = false; }

View File

@ -2,7 +2,7 @@
motion_control.c - high level interface for issuing motion commands
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -76,12 +76,13 @@
// If the buffer is full: good! That means we are well ahead of the robot.
// Remain in this loop until there is room in the buffer.
do {
protocol_execute_runtime(); // Check for any run-time commands
protocol_execute_realtime(); // Check for any run-time commands
if (sys.abort) { return; } // Bail, if system abort.
if ( plan_check_full_buffer() ) { protocol_auto_cycle_start(); } // Auto-cycle start when buffer is full.
else { break; }
} while (1);
// Plan and queue motion into planner buffer
#ifdef USE_LINE_NUMBERS
plan_buffer_line(target, feed_rate, invert_feed_rate, line_number);
#else
@ -227,8 +228,8 @@ void mc_dwell(float seconds)
protocol_buffer_synchronize();
delay_ms(floor(1000*seconds-i*DWELL_TIME_STEP)); // Delay millisecond remainder.
while (i-- > 0) {
// NOTE: Check and execute runtime commands during dwell every <= DWELL_TIME_STEP milliseconds.
protocol_execute_runtime();
// NOTE: Check and execute realtime commands during dwell every <= DWELL_TIME_STEP milliseconds.
protocol_execute_realtime();
if (sys.abort) { return; }
_delay_ms(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
}
@ -243,15 +244,16 @@ void mc_homing_cycle()
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
// with machines with limits wired on both ends of travel to one limit pin.
// TODO: Move the pin-specific LIMIT_PIN call to limits.c as a function.
uint8_t limit_state = (LIMIT_PIN & LIMIT_MASK);
if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { limit_state ^= LIMIT_MASK; }
if (limit_state) {
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate homing limit critical event
return;
}
sys.state = STATE_HOMING; // Set system state variable
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
uint8_t limit_state = (LIMIT_PIN & LIMIT_MASK);
if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { limit_state ^= LIMIT_MASK; }
if (limit_state) {
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
bit_true_atomic(sys.rt_exec_alarm, (EXEC_ALARM_HARD_LIMIT|EXEC_CRITICAL_EVENT));
return;
}
#endif
limits_disable(); // Disable hard limits pin change register for cycle duration
// -------------------------------------------------------------------------------------
@ -266,7 +268,7 @@ void mc_homing_cycle()
limits_go_home(HOMING_CYCLE_2); // Homing cycle 2
#endif
protocol_execute_runtime(); // Check for reset and set system abort.
protocol_execute_realtime(); // Check for reset and set system abort.
if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
// Homing cycle complete! Setup system for normal operation.
@ -275,10 +277,6 @@ void mc_homing_cycle()
// Gcode parser position was circumvented by the limits_go_home() routine, so sync position now.
gc_sync_position();
// Set idle state after homing completes and before returning to main program.
sys.state = STATE_IDLE;
st_go_idle(); // Set idle state after homing completes
// If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
limits_init();
}
@ -308,8 +306,8 @@ void mc_homing_cycle()
// After syncing, check if probe is already triggered. If so, halt and issue alarm.
// NOTE: This probe initialization error applies to all probing cycles.
if ( probe_get_state() ) { // Check probe pin state.
bit_true_atomic(sys.execute, EXEC_CRIT_EVENT);
protocol_execute_runtime();
bit_true_atomic(sys.rt_exec_alarm, EXEC_ALARM_PROBE_FAIL);
protocol_execute_realtime();
}
if (sys.abort) { return; } // Return if system reset has been issued.
@ -324,9 +322,9 @@ void mc_homing_cycle()
sys.probe_state = PROBE_ACTIVE;
// Perform probing cycle. Wait here until probe is triggered or motion completes.
bit_true_atomic(sys.execute, EXEC_CYCLE_START);
bit_true_atomic(sys.rt_exec_state, EXEC_CYCLE_START);
do {
protocol_execute_runtime();
protocol_execute_realtime();
if (sys.abort) { return; } // Check for system abort
} while ((sys.state != STATE_IDLE) && (sys.state != STATE_QUEUED));
@ -335,12 +333,12 @@ void mc_homing_cycle()
// Set state variables and error out, if the probe failed and cycle with error is enabled.
if (sys.probe_state == PROBE_ACTIVE) {
if (is_no_error) { memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS); }
else { bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); }
else { bit_true_atomic(sys.rt_exec_alarm, EXEC_ALARM_PROBE_FAIL); }
} else {
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
}
sys.probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
protocol_execute_runtime(); // Check and execute run-time commands
protocol_execute_realtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
@ -349,13 +347,11 @@ void mc_homing_cycle()
plan_sync_position(); // Sync planner position to current machine position.
// TODO: Update the g-code parser code to not require this target calculation but uses a gc_sync_position() call.
uint8_t idx;
for(idx=0; idx<N_AXIS; idx++){
// NOTE: The target[] variable updated here will be sent back and synced with the g-code parser.
target[idx] = (float)sys.position[idx]/settings.steps_per_mm[idx];
}
// NOTE: The target[] variable updated here will be sent back and synced with the g-code parser.
system_convert_array_steps_to_mpos(target, sys.position);
sys.auto_start = auto_start_state; // Restore run state before returning
// Restore run state before returning
sys.auto_start = auto_start_state;
#ifdef MESSAGE_PROBE_COORDINATES
// All done! Output the probe position as message.
@ -364,16 +360,16 @@ void mc_homing_cycle()
}
// Method to ready the system to reset by setting the runtime reset command and killing any
// Method to ready the system to reset by setting the realtime reset command and killing any
// active processes in the system. This also checks if a system reset is issued while Grbl
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
// runtime abort command and hard limits. So, keep to a minimum.
// realtime abort command and hard limits. So, keep to a minimum.
void mc_reset()
{
// Only this function can set the system reset. Helps prevent multiple kill calls.
if (bit_isfalse(sys.execute, EXEC_RESET)) {
bit_true_atomic(sys.execute, EXEC_RESET);
if (bit_isfalse(sys.rt_exec_state, EXEC_RESET)) {
bit_true_atomic(sys.rt_exec_state, EXEC_RESET);
// Kill spindle and coolant.
spindle_stop();
@ -384,7 +380,7 @@ void mc_reset()
// the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
// violated, by which, all bets are off.
if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_HOMING)) {
bit_true_atomic(sys.execute, EXEC_ALARM); // Flag main program to execute alarm state.
bit_true_atomic(sys.rt_exec_alarm, EXEC_ALARM_ABORT_CYCLE);
st_go_idle(); // Force kill steppers. Position has likely been lost.
}
}

View File

@ -2,7 +2,7 @@
motion_control.h - high level interface for issuing motion commands
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
nuts_bolts.c - Shared functions
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
nuts_bolts.h - Header file for shared definitions, variables, and functions
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -30,15 +30,23 @@
#define false 0
#define true 1
// Axis array index values. Must start with 0 and be continuous.
#define N_AXIS 3 // Number of axes
#define X_AXIS 0 // Axis indexing value. Must start with 0 and be continuous.
#define X_AXIS 0 // Axis indexing value.
#define Y_AXIS 1
#define Z_AXIS 2
// #define A_AXIS 3
// CoreXY motor assignments. DO NOT ALTER.
// NOTE: If the A and B motor axis bindings are changed, this effects the CoreXY equations.
#ifdef COREXY
#define A_MOTOR X_AXIS // Must be X_AXIS
#define B_MOTOR Y_AXIS // Must be Y_AXIS
#endif
// Conversions
#define MM_PER_INCH (25.40)
#define INCH_PER_MM (0.0393701)
#define TICKS_PER_MICROSECOND (F_CPU/1000000)
// Useful macros

View File

@ -2,7 +2,7 @@
planner.c - buffers movement commands and manages the acceleration profile plan
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -284,17 +284,36 @@ uint8_t plan_check_full_buffer()
int32_t target_steps[N_AXIS];
float unit_vec[N_AXIS], delta_mm;
uint8_t idx;
#ifdef COREXY
target_steps[A_MOTOR] = lround(target[A_MOTOR]*settings.steps_per_mm[A_MOTOR]);
target_steps[B_MOTOR] = lround(target[B_MOTOR]*settings.steps_per_mm[B_MOTOR]);
block->steps[A_MOTOR] = labs((target_steps[X_AXIS]-pl.position[X_AXIS]) - (target_steps[Y_AXIS]-pl.position[Y_AXIS]));
block->steps[B_MOTOR] = labs((target_steps[X_AXIS]-pl.position[X_AXIS]) + (target_steps[Y_AXIS]-pl.position[Y_AXIS]));
#endif
for (idx=0; idx<N_AXIS; idx++) {
// Calculate target position in absolute steps. This conversion should be consistent throughout.
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
// Number of steps for each axis and determine max step events
block->steps[idx] = labs(target_steps[idx]-pl.position[idx]);
block->step_event_count = max(block->step_event_count, block->steps[idx]);
// Compute individual axes distance for move and prep unit vector calculations.
// Calculate target position in absolute steps, number of steps for each axis, and determine max step events.
// Also, compute individual axes distance for move and prep unit vector calculations.
// NOTE: Computes true distance from converted step values.
delta_mm = (target_steps[idx] - pl.position[idx])/settings.steps_per_mm[idx];
#ifdef COREXY
if ( !(idx == A_MOTOR) && !(idx == B_MOTOR) ) {
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
block->steps[idx] = labs(target_steps[idx]-pl.position[idx]);
}
block->step_event_count = max(block->step_event_count, block->steps[idx]);
if (idx == A_MOTOR) {
delta_mm = ((target_steps[X_AXIS]-pl.position[X_AXIS]) - (target_steps[Y_AXIS]-pl.position[Y_AXIS]))/settings.steps_per_mm[idx];
} else if (idx == B_MOTOR) {
delta_mm = ((target_steps[X_AXIS]-pl.position[X_AXIS]) + (target_steps[Y_AXIS]-pl.position[Y_AXIS]))/settings.steps_per_mm[idx];
} else {
delta_mm = (target_steps[idx] - pl.position[idx])/settings.steps_per_mm[idx];
}
#else
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
block->steps[idx] = labs(target_steps[idx]-pl.position[idx]);
block->step_event_count = max(block->step_event_count, block->steps[idx]);
delta_mm = (target_steps[idx] - pl.position[idx])/settings.steps_per_mm[idx];
#endif
unit_vec[idx] = delta_mm; // Store unit vector numerator. Denominator computed later.
// Set direction bits. Bit enabled always means direction is negative.
@ -403,9 +422,21 @@ uint8_t plan_check_full_buffer()
// Reset the planner position vectors. Called by the system abort/initialization routine.
void plan_sync_position()
{
// TODO: For motor configurations not in the same coordinate frame as the machine position,
// this function needs to be updated to accomodate the difference.
uint8_t idx;
for (idx=0; idx<N_AXIS; idx++) {
pl.position[idx] = sys.position[idx];
#ifdef COREXY
if (idx==A_MOTOR) {
pl.position[idx] = (sys.position[A_MOTOR] + sys.position[B_MOTOR])/2;
} else if (idx==B_MOTOR) {
pl.position[idx] = (sys.position[A_MOTOR] - sys.position[B_MOTOR])/2;
} else {
pl.position[idx] = sys.position[idx];
}
#else
pl.position[idx] = sys.position[idx];
#endif
}
}

View File

@ -2,7 +2,7 @@
planner.h - buffers movement commands and manages the acceleration profile plan
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
print.c - Functions for formatting output strings
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
print.h - Functions for formatting output strings
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
probe.c - code pertaining to probing methods
Part of Grbl v0.9
Copyright (c) 2014 Sungeun K. Jeon
Copyright (c) 2014-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -63,7 +63,7 @@ void probe_state_monitor()
if (probe_get_state()) {
sys.probe_state = PROBE_OFF;
memcpy(sys.probe_position, sys.position, sizeof(float)*N_AXIS);
bit_true(sys.execute, EXEC_FEED_HOLD);
bit_true(sys.rt_exec_state, EXEC_FEED_HOLD);
}
}
}

View File

@ -2,7 +2,7 @@
probe.h - code pertaining to probing methods
Part of Grbl v0.9
Copyright (c) 2014 Sungeun K. Jeon
Copyright (c) 2014-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
protocol.c - controls Grbl execution protocol and procedures
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -43,7 +43,7 @@ static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
// such as settings, initiating the homing cycle, and toggling switch states.
static void protocol_execute_line(char *line)
{
protocol_execute_runtime(); // Runtime command check point.
protocol_execute_realtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to calling function upon system abort
if (line[0] == 0) {
@ -160,7 +160,7 @@ void protocol_main_loop()
// completed. In either case, auto-cycle start, if enabled, any queued moves.
protocol_auto_cycle_start();
protocol_execute_runtime(); // Runtime command check point.
protocol_execute_realtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to main() program loop to reset system.
}
@ -172,50 +172,52 @@ void protocol_main_loop()
// Executes run-time commands, when required. This is called from various check points in the main
// program, primarily where there may be a while loop waiting for a buffer to clear space or any
// point where the execution time from the last check point may be more than a fraction of a second.
// This is a way to execute runtime commands asynchronously (aka multitasking) with grbl's g-code
// This is a way to execute realtime commands asynchronously (aka multitasking) with grbl's g-code
// parsing and planning functions. This function also serves as an interface for the interrupts to
// set the system runtime flags, where only the main program handles them, removing the need to
// set the system realtime flags, where only the main program handles them, removing the need to
// define more computationally-expensive volatile variables. This also provides a controlled way to
// execute certain tasks without having two or more instances of the same task, such as the planner
// recalculating the buffer upon a feedhold or override.
// NOTE: The sys.execute variable flags are set by any process, step or serial interrupts, pinouts,
// NOTE: The sys.rt_exec_state variable flags are set by any process, step or serial interrupts, pinouts,
// limit switches, or the main program.
void protocol_execute_runtime()
void protocol_execute_realtime()
{
uint8_t rt_exec = sys.execute; // Copy to avoid calling volatile multiple times
uint8_t rt_exec; // Temp variable to avoid calling volatile multiple times.
// Check and execute alarms.
rt_exec = sys.rt_exec_alarm; // Copy volatile sys.rt_exec_alarm.
if (rt_exec) { // Enter only if any bit flag is true
// System alarm. Everything has shutdown by something that has gone severely wrong. Report
// the source of the error to the user. If critical, Grbl disables by entering an infinite
// loop until system reset/abort.
if (rt_exec & (EXEC_ALARM | EXEC_CRIT_EVENT)) {
sys.state = STATE_ALARM; // Set system alarm state
// Critical events. Hard/soft limit events identified by both critical event and alarm exec
// flags. Probe fail is identified by the critical event exec flag only.
if (rt_exec & EXEC_CRIT_EVENT) {
if (rt_exec & EXEC_ALARM) { report_alarm_message(ALARM_LIMIT_ERROR); }
else { report_alarm_message(ALARM_PROBE_FAIL); }
report_feedback_message(MESSAGE_CRITICAL_EVENT);
bit_false_atomic(sys.execute,EXEC_RESET); // Disable any existing reset
do {
// Nothing. Block EVERYTHING until user issues reset or power cycles. Hard limits
// typically occur while unattended or not paying attention. Gives the user time
// to do what is needed before resetting, like killing the incoming stream. The
// same could be said about soft limits. While the position is not lost, the incoming
// stream could be still engaged and cause a serious crash if it continues afterwards.
} while (bit_isfalse(sys.execute,EXEC_RESET));
// Standard alarm event. Only abort during motion qualifies.
} else {
// Runtime abort command issued during a cycle, feed hold, or homing cycle. Message the
// user that position may have been lost and set alarm state to enable the alarm lockout
// to indicate the possible severity of the problem.
report_alarm_message(ALARM_ABORT_CYCLE);
}
bit_false_atomic(sys.execute,(EXEC_ALARM | EXEC_CRIT_EVENT));
}
sys.state = STATE_ALARM; // Set system alarm state
if (rt_exec & EXEC_ALARM_HARD_LIMIT) {
report_alarm_message(ALARM_HARD_LIMIT_ERROR);
} else if (rt_exec & EXEC_ALARM_SOFT_LIMIT) {
report_alarm_message(ALARM_SOFT_LIMIT_ERROR);
} else if (rt_exec & EXEC_ALARM_ABORT_CYCLE) {
report_alarm_message(ALARM_ABORT_CYCLE);
} else if (rt_exec & EXEC_ALARM_PROBE_FAIL) {
report_alarm_message(ALARM_PROBE_FAIL);
}
// Halt everything upon a critical event flag. Currently hard and soft limits flag this.
if (rt_exec & EXEC_CRITICAL_EVENT) {
report_feedback_message(MESSAGE_CRITICAL_EVENT);
bit_false_atomic(sys.rt_exec_state,EXEC_RESET); // Disable any existing reset
do {
// Nothing. Block EVERYTHING until user issues reset or power cycles. Hard limits
// typically occur while unattended or not paying attention. Gives the user time
// to do what is needed before resetting, like killing the incoming stream. The
// same could be said about soft limits. While the position is not lost, the incoming
// stream could be still engaged and cause a serious crash if it continues afterwards.
} while (bit_isfalse(sys.rt_exec_state,EXEC_RESET));
}
bit_false_atomic(sys.rt_exec_alarm,0xFF); // Clear all alarm flags
}
// Check amd execute realtime commands
rt_exec = sys.rt_exec_state; // Copy volatile sys.rt_exec_state.
if (rt_exec) { // Enter only if any bit flag is true
// Execute system abort.
if (rt_exec & EXEC_RESET) {
sys.abort = true; // Only place this is set true.
@ -225,7 +227,7 @@ void protocol_execute_runtime()
// Execute and serial print status
if (rt_exec & EXEC_STATUS_REPORT) {
report_realtime_status();
bit_false_atomic(sys.execute,EXEC_STATUS_REPORT);
bit_false_atomic(sys.rt_exec_state,EXEC_STATUS_REPORT);
}
// Execute a feed hold with deceleration, only during cycle.
@ -238,7 +240,7 @@ void protocol_execute_runtime()
st_prep_buffer();
sys.auto_start = false; // Disable planner auto start upon feed hold.
}
bit_false_atomic(sys.execute,EXEC_FEED_HOLD);
bit_false_atomic(sys.rt_exec_state,EXEC_FEED_HOLD);
}
// Execute a cycle start by starting the stepper interrupt begin executing the blocks in queue.
@ -253,24 +255,23 @@ void protocol_execute_runtime()
sys.auto_start = false; // Reset auto start per settings.
}
}
bit_false_atomic(sys.execute,EXEC_CYCLE_START);
bit_false_atomic(sys.rt_exec_state,EXEC_CYCLE_START);
}
// Reinitializes the cycle plan and stepper system after a feed hold for a resume. Called by
// runtime command execution in the main program, ensuring that the planner re-plans safely.
// realtime command execution in the main program, ensuring that the planner re-plans safely.
// NOTE: Bresenham algorithm variables are still maintained through both the planner and stepper
// cycle reinitializations. The stepper path should continue exactly as if nothing has happened.
// NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
if (rt_exec & EXEC_CYCLE_STOP) {
if ( plan_get_current_block() ) { sys.state = STATE_QUEUED; }
else { sys.state = STATE_IDLE; }
bit_false_atomic(sys.execute,EXEC_CYCLE_STOP);
bit_false_atomic(sys.rt_exec_state,EXEC_CYCLE_STOP);
}
}
// Overrides flag byte (sys.override) and execution should be installed here, since they
// are runtime and require a direct and controlled interface to the main stepper program.
// are realtime and require a direct and controlled interface to the main stepper program.
// Reload step segment buffer
if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_HOMING)) { st_prep_buffer(); }
@ -287,7 +288,7 @@ void protocol_buffer_synchronize()
// Check and set auto start to resume cycle after synchronize and caller completes.
if (sys.state == STATE_CYCLE) { sys.auto_start = true; }
while (plan_get_current_block() || (sys.state == STATE_CYCLE)) {
protocol_execute_runtime(); // Check and execute run-time commands
protocol_execute_realtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort
}
}
@ -303,4 +304,4 @@ void protocol_buffer_synchronize()
// NOTE: This function is called from the main loop and mc_line() only and executes when one of
// two conditions exist respectively: There are no more blocks sent (i.e. streaming is finished,
// single commands), or the planner buffer is full and ready to go.
void protocol_auto_cycle_start() { if (sys.auto_start) { bit_true_atomic(sys.execute, EXEC_CYCLE_START); } }
void protocol_auto_cycle_start() { if (sys.auto_start) { bit_true_atomic(sys.rt_exec_state, EXEC_CYCLE_START); } }

View File

@ -2,7 +2,7 @@
protocol.h - controls Grbl execution protocol and procedures
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -41,8 +41,8 @@
// them as they complete. It is also responsible for finishing the initialization procedures.
void protocol_main_loop();
// Checks and executes a runtime command at various stop points in main program
void protocol_execute_runtime();
// Checks and executes a realtime command at various stop points in main program
void protocol_execute_realtime();
// Notify the stepper subsystem to start executing the g-code program in buffer.
// void protocol_cycle_start();

View File

@ -2,7 +2,7 @@
report.c - reporting and messaging methods
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -97,8 +97,10 @@ void report_alarm_message(int8_t alarm_code)
{
printPgmString(PSTR("ALARM: "));
switch (alarm_code) {
case ALARM_LIMIT_ERROR:
printPgmString(PSTR("Hard/soft limit")); break;
case ALARM_HARD_LIMIT_ERROR:
printPgmString(PSTR("Hard limit")); break;
case ALARM_SOFT_LIMIT_ERROR:
printPgmString(PSTR("Soft limit")); break;
case ALARM_ABORT_CYCLE:
printPgmString(PSTR("Abort during cycle")); break;
case ALARM_PROBE_FAIL:
@ -230,9 +232,9 @@ void report_probe_parameters()
float print_position[N_AXIS];
// Report in terms of machine position.
printPgmString(PSTR("[PRB:"));
printPgmString(PSTR("[PRB:"));
for (i=0; i< N_AXIS; i++) {
print_position[i] = sys.probe_position[i]/settings.steps_per_mm[i];
print_position[i] = system_convert_axis_steps_to_mpos(sys.probe_position,i);
printFloat_CoordValue(print_position[i]);
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
}
@ -394,17 +396,12 @@ void report_realtime_status()
// If reporting a position, convert the current step count (current_position) to millimeters.
if (bit_istrue(settings.status_report_mask,(BITFLAG_RT_STATUS_MACHINE_POSITION | BITFLAG_RT_STATUS_WORK_POSITION))) {
for (i=0; i< N_AXIS; i++) { print_position[i] = current_position[i]/settings.steps_per_mm[i]; }
system_convert_array_steps_to_mpos(print_position,current_position);
}
// Report machine position
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_MACHINE_POSITION)) {
printPgmString(PSTR(",MPos:"));
// print_position[X_AXIS] = 0.5*current_position[X_AXIS]/settings.steps_per_mm[X_AXIS];
// print_position[Z_AXIS] = 0.5*current_position[Y_AXIS]/settings.steps_per_mm[Y_AXIS];
// print_position[Y_AXIS] = print_position[X_AXIS]-print_position[Z_AXIS]);
// print_position[X_AXIS] -= print_position[Z_AXIS];
// print_position[Z_AXIS] = current_position[Z_AXIS]/settings.steps_per_mm[Z_AXIS];
for (i=0; i< N_AXIS; i++) {
printFloat_CoordValue(print_position[i]);
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }

View File

@ -2,7 +2,7 @@
report.h - reporting and messaging methods
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -54,9 +54,10 @@
#define STATUS_GCODE_G43_DYNAMIC_AXIS_ERROR 37
// Define Grbl alarm codes. Less than zero to distinguish alarm error from status error.
#define ALARM_LIMIT_ERROR -1
#define ALARM_ABORT_CYCLE -2
#define ALARM_PROBE_FAIL -3
#define ALARM_HARD_LIMIT_ERROR -1
#define ALARM_SOFT_LIMIT_ERROR -2
#define ALARM_ABORT_CYCLE -3
#define ALARM_PROBE_FAIL -4
// Define Grbl feedback message codes.
#define MESSAGE_CRITICAL_EVENT 1

View File

@ -2,7 +2,7 @@
serial.c - Low level functions for sending and recieving bytes via the serial port
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -98,7 +98,7 @@ void serial_write(uint8_t data) {
// Wait until there is space in the buffer
while (next_head == serial_tx_buffer_tail) {
// TODO: Restructure st_prep_buffer() calls to be executed here during a long print.
if (sys.execute & EXEC_RESET) { return; } // Only check for abort to avoid an endless loop.
if (sys.rt_exec_state & EXEC_RESET) { return; } // Only check for abort to avoid an endless loop.
}
// Store data and advance head
@ -170,12 +170,12 @@ ISR(SERIAL_RX)
uint8_t data = UDR0;
uint8_t next_head;
// Pick off runtime command characters directly from the serial stream. These characters are
// not passed into the buffer, but these set system state flag bits for runtime execution.
// Pick off realtime command characters directly from the serial stream. These characters are
// not passed into the buffer, but these set system state flag bits for realtime execution.
switch (data) {
case CMD_STATUS_REPORT: bit_true_atomic(sys.execute, EXEC_STATUS_REPORT); break; // Set as true
case CMD_CYCLE_START: bit_true_atomic(sys.execute, EXEC_CYCLE_START); break; // Set as true
case CMD_FEED_HOLD: bit_true_atomic(sys.execute, EXEC_FEED_HOLD); break; // Set as true
case CMD_STATUS_REPORT: bit_true_atomic(sys.rt_exec_state, EXEC_STATUS_REPORT); break; // Set as true
case CMD_CYCLE_START: bit_true_atomic(sys.rt_exec_state, EXEC_CYCLE_START); break; // Set as true
case CMD_FEED_HOLD: bit_true_atomic(sys.rt_exec_state, EXEC_FEED_HOLD); break; // Set as true
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
default: // Write character to buffer
next_head = serial_rx_buffer_head + 1;

View File

@ -2,7 +2,7 @@
serial.c - Low level functions for sending and recieving bytes via the serial port
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
settings.c - eeprom configuration handling
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -110,7 +110,7 @@ void settings_restore_global_settings() {
// Helper function to clear the EEPROM space containing parameter data.
void settings_clear_parameters() {
uint8_t idx;
float coord_data[3];
float coord_data[N_AXIS];
memset(&coord_data, 0, sizeof(coord_data));
for (idx=0; idx < SETTING_INDEX_NCOORD; idx++) { settings_write_coord_data(idx, coord_data); }
}

View File

@ -2,7 +2,7 @@
settings.h - eeprom configuration handling
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -28,8 +28,8 @@
#define settings_h
#define GRBL_VERSION "0.9g"
#define GRBL_VERSION_BUILD "20140905"
#define GRBL_VERSION "0.9h"
#define GRBL_VERSION_BUILD "20150114"
// Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl
// when firmware is upgraded. Always stored in byte 0 of eeprom

View File

@ -2,7 +2,7 @@
spindle_control.c - spindle control methods
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -60,22 +60,16 @@ void spindle_stop()
}
void spindle_run(uint8_t direction, float rpm)
void spindle_set_state(uint8_t state, float rpm)
{
if (sys.state == STATE_CHECK_MODE) { return; }
// Empty planner buffer to ensure spindle is set when programmed.
protocol_auto_cycle_start(); //temp fix for M3 lockup
protocol_buffer_synchronize();
// Halt or set spindle direction and rpm.
if (direction == SPINDLE_DISABLE) {
if (state == SPINDLE_DISABLE) {
spindle_stop();
} else {
if (direction == SPINDLE_ENABLE_CW) {
if (state == SPINDLE_ENABLE_CW) {
SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
} else {
SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
@ -83,21 +77,30 @@ void spindle_run(uint8_t direction, float rpm)
#ifdef VARIABLE_SPINDLE
// TODO: Install the optional capability for frequency-based output for servos.
#ifdef CPU_MAP_ATMEGA2560
TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02 | (1<<WAVE2_REGISTER) | (1<<WAVE3_REGISTER); // set to 1/8 Prescaler
OCR4A = 0xFFFF; // set the top 16bit value
uint16_t current_pwm;
#else
TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler
uint8_t current_pwm;
#endif
#define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler
if ( rpm < SPINDLE_MIN_RPM ) { rpm = 0; }
else {
rpm -= SPINDLE_MIN_RPM;
if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent uint8 overflow
if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent integer overflow
}
uint8_t current_pwm = floor( rpm*(255.0/SPINDLE_RPM_RANGE) + 0.5);
current_pwm = floor( rpm*(PWM_MAX_VALUE/SPINDLE_RPM_RANGE) + 0.5);
#ifdef MINIMUM_SPINDLE_PWM
if (current_pwm < MINIMUM_SPINDLE_PWM) { current_pwm = MINIMUM_SPINDLE_PWM; }
#endif
OCR_REGISTER = current_pwm; // Set PWM pin output
#ifndef CPU_MAP_ATMEGA328P // On the Uno, spindle enable and PWM are shared.
#ifdef CPU_MAP_ATMEGA2560 // On the Uno, spindle enable and PWM are shared.
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif
#else
@ -106,3 +109,11 @@ void spindle_run(uint8_t direction, float rpm)
}
}
void spindle_run(uint8_t state, float rpm)
{
if (sys.state != STATE_CHECK_MODE) { return; }
protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
spindle_set_state(state, rpm);
}

View File

@ -2,7 +2,7 @@
spindle_control.h - spindle control methods
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -34,6 +34,8 @@ void spindle_init();
// Sets spindle direction and spindle rpm via PWM, if enabled.
void spindle_run(uint8_t direction, float rpm);
void spindle_set_state(uint8_t state, float rpm);
// Kills spindle.
void spindle_stop();

View File

@ -2,7 +2,7 @@
stepper.c - stepper motor driver: executes motion plans using stepper motors
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -228,7 +228,7 @@ void st_go_idle()
// Set stepper driver idle state, disabled or enabled, depending on settings and circumstances.
bool pin_state = false; // Keep enabled.
if (((settings.stepper_idle_lock_time != 0xff) || bit_istrue(sys.execute,EXEC_ALARM)) && sys.state != STATE_HOMING) {
if (((settings.stepper_idle_lock_time != 0xff) || sys.rt_exec_alarm) && sys.state != STATE_HOMING) {
// Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete
// stop and not drift from residual inertial forces at the end of the last movement.
delay_ms(settings.stepper_idle_lock_time);
@ -351,7 +351,7 @@ ISR(TIMER1_COMPA_vect)
} else {
// Segment buffer empty. Shutdown.
st_go_idle();
bit_true_atomic(sys.execute,EXEC_CYCLE_STOP); // Flag main program for cycle end
bit_true_atomic(sys.rt_exec_state,EXEC_CYCLE_STOP); // Flag main program for cycle end
return; // Nothing to do but exit.
}
}
@ -846,7 +846,7 @@ void st_prep_buffer()
}
// Called by runtime status reporting to fetch the current speed being executed. This value
// Called by realtime status reporting to fetch the current speed being executed. This value
// however is not exactly the current speed, but the speed computed in the last step segment
// in the segment buffer. It will always be behind by up to the number of segment blocks (-1)
// divided by the ACCELERATION TICKS PER SECOND in seconds.

View File

@ -2,7 +2,7 @@
stepper.h - stepper motor driver: executes motion plans of planner.c using the stepper motors
Part of Grbl v0.9
Copyright (c) 2012-2014 Sungeun K. Jeon
Copyright (c) 2012-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -34,7 +34,7 @@
// Initialize and setup the stepper motor subsystem
void stepper_init();
// Enable steppers, but cycle does not start unless called by motion control or runtime command.
// Enable steppers, but cycle does not start unless called by motion control or realtime command.
void st_wake_up();
// Immediately disables steppers
@ -46,13 +46,13 @@ void st_generate_step_dir_invert_masks();
// Reset the stepper subsystem variables
void st_reset();
// Reloads step segment buffer. Called continuously by runtime execution system.
// Reloads step segment buffer. Called continuously by realtime execution system.
void st_prep_buffer();
// Called by planner_recalculate() when the executing block is updated by the new plan.
void st_update_plan_block_parameters();
// Called by runtime status reporting if realtime rate reporting is enabled in config.h.
// Called by realtime status reporting if realtime rate reporting is enabled in config.h.
#ifdef REPORT_REALTIME_RATE
float st_get_realtime_rate();
#endif

View File

@ -2,7 +2,7 @@
system.c - Handles system level commands and real-time processes
Part of Grbl v0.9
Copyright (c) 2014 Sungeun K. Jeon
Copyright (c) 2014-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,8 +20,10 @@
#include "system.h"
#include "settings.h"
#include "protocol.h"
#include "gcode.h"
#include "motion_control.h"
#include "stepper.h"
#include "report.h"
#include "print.h"
@ -36,8 +38,8 @@ void system_init()
// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets
// only the runtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based runtime commands when picked off
// only the realtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based realtime commands when picked off
// directly from the incoming serial data stream.
ISR(PINOUT_INT_vect)
{
@ -46,9 +48,9 @@ ISR(PINOUT_INT_vect)
if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) {
mc_reset();
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) {
bit_true(sys.execute, EXEC_FEED_HOLD);
bit_true(sys.rt_exec_state, EXEC_FEED_HOLD);
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_CYCLE_START))) {
bit_true(sys.execute, EXEC_CYCLE_START);
bit_true(sys.rt_exec_state, EXEC_CYCLE_START);
}
}
}
@ -74,7 +76,7 @@ void system_execute_startup(char *line)
// Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
// settings, initiating the homing cycle, and toggling switch states. This differs from
// the runtime command module by being susceptible to when Grbl is ready to execute the
// the realtime command module by being susceptible to when Grbl is ready to execute the
// next line during a cycle, so for switches like block delete, the switch only effects
// the lines that are processed afterward, not necessarily real-time during a cycle,
// since there are motions already stored in the buffer. However, this 'lag' should not
@ -118,17 +120,17 @@ uint8_t system_execute_line(char *line)
} // Otherwise, no effect.
break;
// case 'J' : break; // Jogging methods
// TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be
// susceptible to other runtime commands except for e-stop. The jogging function is intended to
// be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// motion by repeatedly toggling to slow the motion to the desired location. Location data would
// need to be updated real-time and supplied to the user through status queries.
// More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are
// handled by the planner. It would be possible for the jog subprogram to insert blocks into the
// block buffer without having the planner plan them. It would need to manage de/ac-celerations
// on its own carefully. This approach could be effective and possibly size/memory efficient.
// TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be
// susceptible to other realtime commands except for e-stop. The jogging function is intended to
// be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// motion by repeatedly toggling to slow the motion to the desired location. Location data would
// need to be updated real-time and supplied to the user through status queries.
// More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are
// handled by the planner. It would be possible for the jog subprogram to insert blocks into the
// block buffer without having the planner plan them. It would need to manage de/ac-celerations
// on its own carefully. This approach could be effective and possibly size/memory efficient.
default :
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
@ -139,9 +141,14 @@ uint8_t system_execute_line(char *line)
break;
case 'H' : // Perform homing cycle [IDLE/ALARM]
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
sys.state = STATE_HOMING; // Set system state variable
// Only perform homing if Grbl is idle or lost.
mc_homing_cycle();
if (!sys.abort) { system_execute_startup(line); } // Execute startup scripts after successful homing.
if (!sys.abort) { // Execute startup scripts after successful homing.
sys.state = STATE_IDLE; // Set to IDLE when complete.
st_go_idle(); // Set steppers to the settings idle state before returning.
system_execute_startup(line);
}
} else { return(STATUS_SETTING_DISABLED); }
break;
case 'I' : // Print or store build info. [IDLE/ALARM]
@ -197,3 +204,27 @@ uint8_t system_execute_line(char *line)
}
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
}
float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx)
{
#ifdef COREXY
if (idx==A_MOTOR) {
return((0.5*(steps[A_MOTOR] + steps[B_MOTOR]))/settings.steps_per_mm[idx]);
} else if (idx==B_MOTOR) {
return((0.5*(steps[A_MOTOR] - steps[B_MOTOR]))/settings.steps_per_mm[idx]);
}
#else
return((float)steps[idx]/settings.steps_per_mm[idx]);
#endif
}
void system_convert_array_steps_to_mpos(float *position, int32_t *steps)
{
uint8_t idx;
for (idx=0; idx<N_AXIS; idx++) {
position[idx] = system_convert_axis_steps_to_mpos(steps, idx);
}
return;
}

View File

@ -2,7 +2,7 @@
system.h - Header for system level commands and real-time processes
Part of Grbl v0.9
Copyright (c) 2014 Sungeun K. Jeon
Copyright (c) 2014-2015 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -41,19 +41,26 @@
#include "nuts_bolts.h"
// Define system executor bit map. Used internally by runtime protocol as runtime command flags,
// which notifies the main program to execute the specified runtime command asynchronously.
// Define system executor bit map. Used internally by realtime protocol as realtime command flags,
// which notifies the main program to execute the specified realtime command asynchronously.
// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
// flags are always false, so the runtime protocol only needs to check for a non-zero value to
// know when there is a runtime command to execute.
// flags are always false, so the realtime protocol only needs to check for a non-zero value to
// know when there is a realtime command to execute.
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000
#define EXEC_CRIT_EVENT bit(6) // bitmask 01000000
// #define bit(7) // bitmask 10000000
// Alarm executor bit map.
// NOTE: EXEC_CRITICAL_EVENT is an optional flag that must be set with an alarm flag. When enabled,
// this halts Grbl into an infinite loop until the user aknowledges the problem and issues a soft-
// reset command. For example, a hard limit event needs this type of halt and aknowledgement.
#define EXEC_CRITICAL_EVENT bit(0) // bitmask 00000001 (SPECIAL FLAG. See NOTE:)
#define EXEC_ALARM_HARD_LIMIT bit(0) // bitmask 00000010
#define EXEC_ALARM_SOFT_LIMIT bit(1) // bitmask 00000100
#define EXEC_ALARM_ABORT_CYCLE bit(2) // bitmask 00001000
#define EXEC_ALARM_PROBE_FAIL bit(3) // bitmask 00010000
// Define system state bit map. The state variable primarily tracks the individual functions
// of Grbl to manage each without overlapping. It is also used as a messaging flag for
@ -72,7 +79,9 @@
typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
volatile uint8_t rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
volatile uint8_t rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
int32_t position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
// NOTE: This may need to be a volatile variable, if problems arise.
@ -92,10 +101,13 @@ void system_init();
// Executes an internal system command, defined as a string starting with a '$'
uint8_t system_execute_line(char *line);
// Checks and executes a runtime command at various stop points in main program
void system_execute_runtime();
// Execute the startup script lines stored in EEPROM upon initialization
void system_execute_startup(char *line);
// Returns machine position of axis 'idx'. Must be sent a 'step' array.
float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx);
// Updates a machine 'position' array based on the 'step' array sent.
void system_convert_array_steps_to_mpos(float *position, int32_t *steps);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,773 +0,0 @@
(ShapeOko2 "Hello World" test file)
(Set up sheet of paper landscape, long edge on X-axis)
(Starting location around the lower[-y] left[-x] corner)
(originally Generated by PartKam Version 0.05)
G20 G90 (remove G40)
(write the words)
G0 Z0.125
(remove x)
G17
G0 X0.435 Y0.4042
G1 Z-0.01 F10
G3 X0.4557 Y0.4046 I0 J0.4533 F40
G3 X0.4728 Y0.4059 I-0.0142 J0.3117
G3 X0.4898 Y0.4082 I-0.0257 J0.2542
G3 X0.5034 Y0.4111 I-0.028 J0.1653
G3 X0.5168 Y0.415 I-0.0472 J0.1844
G3 X0.5278 Y0.4192 I-0.0435 J0.1296
G3 X0.5383 Y0.4245 I-0.0462 J0.1062
G3 X0.5468 Y0.4299 I-0.0415 J0.0739
G3 X0.5545 Y0.4363 I-0.0474 J0.0649
G3 X0.5606 Y0.4429 I-0.0441 J0.0468
G3 X0.5656 Y0.4503 I-0.0464 J0.0371
G3 X0.5694 Y0.4582 I-0.0481 J0.0278
G3 X0.5721 Y0.4664 I-0.0805 J0.031
G3 X0.5741 Y0.4754 I-0.093 J0.0254
G3 X0.5753 Y0.4846 I-0.1022 J0.0176
G3 X0.5757 Y0.4946 I-0.1224 J0.01
G3 X0.5731 Y0.5153 I-0.083 J0
G3 X0.5656 Y0.5337 I-0.0731 J-0.0188
G3 X0.5537 Y0.5498 I-0.072 J-0.0408
G3 X0.5355 Y0.5656 I-0.0876 J-0.083
G3 X0.5146 Y0.5784 I-0.1178 J-0.1676
G3 X0.4808 Y0.5949 I-0.2293 J-0.4268
G3 X0.4459 Y0.6092 I-0.282 J-0.6397
G3 X0.3973 Y0.6265 I-0.4624 J-1.2235
G2 X0.376 Y0.6343 I0.3353 J0.9488
G2 X0.3546 Y0.6427 I0.3684 J0.9724
G2 X0.3333 Y0.6515 I0.3967 J0.9808
G2 X0.3119 Y0.661 I0.4333 J1.0077
G2 X0.2909 Y0.6715 I0.1396 J0.3066
G2 X0.2714 Y0.683 I0.1507 J0.2779
G2 X0.2527 Y0.6959 I0.1666 J0.2606
G2 X0.2353 Y0.71 I0.1811 J0.2422
G2 X0.2191 Y0.7255 I0.1487 J0.1708
G2 X0.2045 Y0.7427 I0.1668 J0.1572
G2 X0.1916 Y0.7611 I0.1861 J0.1436
G2 X0.18 Y0.7816 I0.2168 J0.1363
G2 X0.1709 Y0.8032 I0.1508 J0.0765
G2 X0.164 Y0.8282 I0.1965 J0.0675
G2 X0.1601 Y0.854 I0.2316 J0.0483
G2 X0.1587 Y0.884 I0.3133 J0.03
G2 X0.1601 Y0.914 I0.3058 J0
G2 X0.1643 Y0.9413 I0.2576 J-0.0254
G2 X0.1715 Y0.968 I0.2377 J-0.0494
G2 X0.1813 Y0.9926 I0.2132 J-0.0704
G2 X0.1938 Y1.016 I0.2171 J-0.1015
G2 X0.2086 Y1.0374 I0.1951 J-0.1191
G2 X0.2257 Y1.0569 I0.1807 J-0.1407
G2 X0.2453 Y1.0749 I0.1727 J-0.1691
G2 X0.2668 Y1.0906 I0.1588 J-0.1942
G2 X0.2912 Y1.1049 I0.1534 J-0.2346
G2 X0.3168 Y1.1167 I0.1391 J-0.2681
G2 X0.3458 Y1.127 I0.1352 J-0.3335
G2 X0.3756 Y1.1348 I0.1068 J-0.3459
G2 X0.4086 Y1.1407 I0.0911 J-0.4184
G2 X0.442 Y1.144 I0.0638 J-0.4657
G2 X0.4789 Y1.1452 I0.037 J-0.5706
G2 X0.5228 Y1.144 I0 J-0.7643
G2 X0.5609 Y1.1405 I-0.0333 J-0.5787
G2 X0.5986 Y1.1344 I-0.062 J-0.5001
G2 X0.6309 Y1.1264 I-0.0758 J-0.3755
G2 X0.6627 Y1.1163 I-0.2335 J-0.7931
G2 X0.6893 Y1.1066 I-0.191 J-0.5638
G2 X0.7154 Y1.0955 I-0.1827 J-0.4653
G2 X0.7364 Y1.0849 I-0.1447 J-0.3148
G1 X0.6799 Y0.9304
G3 X0.6615 Y0.9394 I-0.2077 J-0.4011
G3 X0.6414 Y0.9482 I-0.2158 J-0.4675
G3 X0.621 Y0.9561 I-0.2093 J-0.5093
G3 X0.5989 Y0.9637 I-0.2164 J-0.5924
G3 X0.5764 Y0.9698 I-0.0747 J-0.2309
G3 X0.5498 Y0.9745 I-0.0698 J-0.3171
G3 X0.5228 Y0.9772 I-0.0502 J-0.3738
G3 X0.4915 Y0.9782 I-0.0314 J-0.5063
G3 X0.4565 Y0.9767 I0 J-0.4369
G3 X0.4311 Y0.9733 I0.0187 J-0.2329
G3 X0.4065 Y0.9666 I0.0312 J-0.1619
G3 X0.3904 Y0.9587 I0.0277 J-0.0771
G3 X0.3767 Y0.9474 I0.0374 J-0.0591
G3 X0.3673 Y0.9341 I0.0432 J-0.0405
G3 X0.3618 Y0.9186 I0.0563 J-0.029
G3 X0.3596 Y0.899 I0.0892 J-0.0196
G3 X0.3604 Y0.8872 I0.093 J0
G3 X0.3625 Y0.8771 I0.0704 J0.009
G3 X0.366 Y0.8674 I0.0617 J0.0173
G3 X0.3709 Y0.8588 I0.0525 J0.0244
G3 X0.377 Y0.851 I0.0702 J0.0485
G3 X0.3846 Y0.8433 I0.0772 J0.0678
G3 X0.3929 Y0.8363 I0.0778 J0.0845
G3 X0.403 Y0.8293 I0.0886 J0.1165
G3 X0.4135 Y0.823 I0.1229 J0.1933
G3 X0.4253 Y0.8168 I0.1326 J0.2355
G3 X0.4373 Y0.8111 I0.1314 J0.2629
G3 X0.4507 Y0.8055 I0.1413 J0.3181
G3 X0.4642 Y0.8002 I0.4349 J1.1
G3 X0.4791 Y0.7946 I0.5053 J1.3254
G3 X0.4941 Y0.7892 I0.5351 J1.4522
G3 X0.5104 Y0.7835 I0.615 J1.7234
G2 X0.5441 Y0.7706 I-0.62 J-1.6745
G2 X0.5738 Y0.7585 I-0.5126 J-1.3027
G2 X0.6031 Y0.7457 I-0.4768 J-1.135
G2 X0.6284 Y0.7339 I-0.3858 J-0.8553
G2 X0.653 Y0.7208 I-0.1756 J-0.3603
G2 X0.6744 Y0.7073 I-0.164 J-0.2844
G2 X0.6946 Y0.6922 I-0.1689 J-0.2468
G2 X0.7119 Y0.6767 I-0.1605 J-0.1966
G2 X0.7276 Y0.6596 I-0.1493 J-0.1521
G2 X0.741 Y0.6412 I-0.1581 J-0.1293
G2 X0.7522 Y0.6215 I-0.172 J-0.1113
G2 X0.7615 Y0.6001 I-0.1936 J-0.0968
G2 X0.7685 Y0.5778 I-0.2008 J-0.0746
G2 X0.7738 Y0.5514 I-0.2755 J-0.0693
G2 X0.7768 Y0.5247 I-0.3264 J-0.0499
G2 X0.7779 Y0.4934 I-0.4455 J-0.0313
G2 X0.772 Y0.4337 I-0.3082 J0
G2 X0.7565 Y0.3852 I-0.2183 J0.0431
G2 X0.7301 Y0.3418 I-0.1887 J0.0852
G2 X0.6925 Y0.3043 I-0.1784 J0.1413
G2 X0.647 Y0.2762 I-0.146 J0.1856
G2 X0.5854 Y0.2539 I-0.1514 J0.3216
G2 X0.5204 Y0.2419 I-0.1159 J0.4443
G2 X0.435 Y0.2371 I-0.0854 J0.7648
G2 X0.4061 Y0.2376 I0 J0.919
G2 X0.38 Y0.2388 I0.0236 J0.75
G2 X0.354 Y0.2411 I0.0448 J0.6746
G2 X0.3307 Y0.244 I0.0572 J0.5433
G2 X0.3075 Y0.2478 I0.1319 J0.886
G2 X0.2869 Y0.2517 I0.1238 J0.7045
G2 X0.2664 Y0.2563 I0.1284 J0.6229
G2 X0.2485 Y0.261 I0.1166 J0.4841
G2 X0.2307 Y0.2663 I0.1781 J0.6347
G2 X0.2152 Y0.2714 I0.1505 J0.4834
G2 X0.1999 Y0.277 I0.1443 J0.4161
G2 X0.1869 Y0.2823 I0.1191 J0.3062
G2 X0.1741 Y0.2881 I0.2781 J0.6336
G2 X0.1632 Y0.2933 I0.2146 J0.4632
G2 X0.1524 Y0.2988 I0.1915 J0.3889
G2 X0.1436 Y0.3037 I0.1422 J0.2695
G1 X0.1988 Y0.4594
G3 X0.2186 Y0.4494 I0.1622 J0.2959
G3 X0.2423 Y0.4392 I0.1933 J0.4152
G3 X0.2666 Y0.4302 I0.1967 J0.4934
G3 X0.2949 Y0.4211 I0.2292 J0.6675
G3 X0.3238 Y0.414 I0.0929 J0.313
G3 X0.3585 Y0.4084 I0.0897 J0.4486
G3 X0.3936 Y0.4053 I0.065 J0.537
G3 X0.435 Y0.4042 I0.0414 J0.7464
G0 Z0.125
G0 X1.4536 Y1.1251
G1 Z-0.01 F10
G1 X1.6496 Y1.1251 F40
G1 X1.6496 Y0.2547
G1 X1.4536 Y0.2547
G1 X1.4536 Y0.624
G1 X1.1246 Y0.624
G1 X1.1246 Y0.2547
G1 X0.9286 Y0.2547
G1 X0.9286 Y1.1251
G1 X1.1246 Y1.1251
G1 X1.1246 Y0.7923
G1 X1.4536 Y0.7923
G1 X1.4536 Y1.1251
G0 Z0.125
G0 X2.4338 Y0.2547
G1 Z-0.01 F10
G1 X2.403 Y0.3477 F40
G1 X2.3698 Y0.4431
G1 X2.0306 Y0.4431
G1 X1.9973 Y0.3477
G1 X1.9666 Y0.2547
G1 X1.7631 Y0.2547
G2 X1.7877 Y0.325 I17.8599 J-6.2193
G2 X1.8108 Y0.39 I15.3154 J-5.401
G2 X1.8342 Y0.455 I14.1288 J-5.0502
G2 X1.856 Y0.5147 I11.9637 J-4.3385
G2 X1.8782 Y0.5743 I9.7422 J-3.588
G2 X1.8995 Y0.6306 I8.7097 J-3.2684
G2 X1.9212 Y0.6867 I8.2125 J-3.1426
G2 X1.9421 Y0.7395 I7.2956 J-2.8491
G2 X1.9633 Y0.7922 I8.4224 J-3.3598
G2 X1.9838 Y0.8424 I7.6529 J-3.1085
G2 X2.0047 Y0.8924 I7.277 J-3.0116
G2 X2.025 Y0.9399 I6.5821 J-2.7772
G2 X2.0457 Y0.9872 I4.2002 J-1.8081
G2 X2.0666 Y1.0336 I4.0692 J-1.8064
G2 X2.0881 Y1.0798 I3.9952 J-1.8286
G2 X2.1098 Y1.1251 I3.8717 J-1.8266
G1 X2.2969 Y1.1251
G2 X2.3181 Y1.0798 I-6.0675 J-2.8652
G2 X2.3393 Y1.0336 I-6.3027 J-2.919
G2 X2.3602 Y0.9872 I-6.4339 J-2.9227
G2 X2.381 Y0.9399 I-6.6806 J-2.977
G2 X2.4016 Y0.8924 I-5.4185 J-2.3686
G2 X2.4227 Y0.8424 I-5.9798 J-2.5519
G2 X2.4433 Y0.7922 I-6.2861 J-2.6208
G2 X2.4646 Y0.7395 I-6.9077 J-2.8155
G2 X2.4854 Y0.6867 I-7.3628 J-2.9356
G2 X2.5071 Y0.6306 I-8.2907 J-3.237
G2 X2.5284 Y0.5743 I-8.7947 J-3.3654
G2 X2.5506 Y0.5147 I-9.8397 J-3.6933
G2 X2.5724 Y0.455 I-11.8601 J-4.3698
G2 X2.5958 Y0.39 I-14.0105 J-5.0822
G2 X2.6189 Y0.325 I-15.1905 J-5.4307
G2 X2.6436 Y0.2547 I-17.7191 J-6.2494
G1 X2.4338 Y0.2547
G0 Z0.125
G0 X2.1989 Y0.9279
G1 Z-0.01 F10
G2 X2.1957 Y0.9185 I-0.5641 J0.1881 F40
G2 X2.1911 Y0.9056 I-1.0677 J0.3759
G2 X2.1863 Y0.8928 I-1.4028 J0.513
G2 X2.1801 Y0.8764 I-2.2751 J0.8558
G3 X2.1738 Y0.8601 I30.9994 J-11.916
G3 X2.1666 Y0.8413 I41.2401 J-15.8275
G3 X2.1594 Y0.8224 I47.1201 J-18.0595
G3 X2.1512 Y0.8011 I60.4881 J-23.1553
G3 X2.143 Y0.7797 I19.8859 J-7.6046
G3 X2.1341 Y0.7562 I24.1414 J-9.2022
G3 X2.1251 Y0.7326 I26.4832 J-10.0653
G3 X2.1154 Y0.7069 I31.5951 J-11.976
G3 X2.1057 Y0.6811 I4.794 J-1.8127
G3 X2.0958 Y0.6541 I5.244 J-1.9507
G3 X2.086 Y0.6271 I5.4846 J-2.0082
G3 X2.0758 Y0.5988 I5.9771 J-2.1552
G1 X2.3233 Y0.5988
G3 X2.3132 Y0.6271 I-12.9639 J-4.6057
G3 X2.3035 Y0.6541 I-11.8652 J-4.2445
G3 X2.2937 Y0.6811 I-11.3354 J-4.0841
G3 X2.2843 Y0.7069 I-10.3324 J-3.7506
G3 X2.2748 Y0.7326 I-4.3139 J-1.5783
G3 X2.266 Y0.7562 I-3.6331 J-1.3538
G3 X2.2569 Y0.7797 I-3.3175 J-1.2608
G3 X2.2485 Y0.8011 I-2.7503 J-1.0677
G2 X2.2401 Y0.8224 I9.4214 J3.7426
G2 X2.2327 Y0.8413 I7.3257 J2.8909
G2 X2.2253 Y0.8601 I6.4077 J2.5096
G2 X2.219 Y0.8764 I4.802 J1.8645
G3 X2.2127 Y0.8927 I-7.2811 J-2.7989
G3 X2.2077 Y0.9056 I-4.551 J-1.7612
G3 X2.2027 Y0.9185 I-3.4837 J-1.3595
G3 X2.1989 Y0.9279 I-1.8801 J-0.7417
G0 Z0.125
G0 X3.0175 Y1.1352
G1 Z-0.01 F10
G2 X3.1143 Y1.1304 I0 J-0.9783 F40
G2 X3.1895 Y1.118 I-0.06 J-0.603
G2 X3.2619 Y1.0953 I-0.1063 J-0.4642
G2 X3.3164 Y1.0667 I-0.1178 J-0.2911
G2 X3.362 Y1.0268 I-0.1208 J-0.184
G2 X3.3946 Y0.9764 I-0.1634 J-0.1415
G2 X3.4133 Y0.9188 I-0.2268 J-0.1055
G2 X3.4207 Y0.8425 I-0.3919 J-0.0763
G2 X3.4132 Y0.7656 I-0.4013 J0
G2 X3.3943 Y0.7073 I-0.2484 J0.0485
G2 X3.3613 Y0.6563 I-0.1992 J0.0927
G2 X3.3152 Y0.6158 I-0.1701 J0.147
G2 X3.26 Y0.5867 I-0.1755 J0.2656
G2 X3.187 Y0.5635 I-0.1806 J0.4426
G2 X3.1111 Y0.551 I-0.1365 J0.5905
G2 X3.0137 Y0.5461 I-0.0974 J0.969
G1 X2.9522 Y0.5461
G1 X2.9522 Y0.2547
G1 X2.7562 Y0.2547
G1 X2.7562 Y1.1126
G2 X2.7883 Y1.1183 I0.19 J-0.9718
G2 X2.8222 Y1.1232 I0.1732 J-1.0725
G2 X2.8561 Y1.1271 I0.1462 J-1.1296
G2 X2.8919 Y1.1301 I0.1235 J-1.2476
G2 X2.9277 Y1.1324 I0.1789 J-2.5504
G2 X2.9591 Y1.1339 I0.1097 J-1.9581
G2 X2.9905 Y1.1349 I0.068 J-1.701
G2 X3.0175 Y1.1352 I0.027 J-1.257
G0 Z0.125
G0 X3.03 Y0.9681
G1 Z-0.01 F10
G1 X2.988 Y0.9669 F40
G3 X2.9775 Y0.9662 I0.1375 J-2.2842
G3 X2.9686 Y0.9656 I0.1084 J-1.6742
G3 X2.9597 Y0.965 I0.0994 J-1.4177
G3 X2.9522 Y0.9644 I0.0758 J-0.9911
G1 X2.9522 Y0.7131
G1 X3.0137 Y0.7131
G3 X3.0644 Y0.7151 I0 J0.6562
G3 X3.1029 Y0.72 I-0.0297 J0.3827
G3 X3.1403 Y0.7294 I-0.051 J0.2826
G3 X3.1669 Y0.7408 I-0.0497 J0.1535
G3 X3.1895 Y0.7577 I-0.0439 J0.0818
G3 X3.2056 Y0.7803 I-0.0644 J0.0629
G3 X3.2147 Y0.807 I-0.0959 J0.048
G3 X3.2184 Y0.8438 I-0.1813 J0.0368
G3 X3.2175 Y0.8619 I-0.1838 J0
G3 X3.2151 Y0.877 I-0.1312 J-0.013
G3 X3.2109 Y0.8918 I-0.1104 J-0.0241
G3 X3.2052 Y0.9041 I-0.0828 J-0.0303
G3 X3.1979 Y0.9154 I-0.0877 J-0.0485
G3 X3.1892 Y0.9256 I-0.078 J-0.058
G3 X3.1793 Y0.9344 I-0.0709 J-0.0697
G3 X3.1676 Y0.9424 I-0.0682 J-0.088
G3 X3.155 Y0.9489 I-0.0659 J-0.1118
G3 X3.1404 Y0.9546 I-0.0654 J-0.1451
G3 X3.1253 Y0.959 I-0.0571 J-0.1695
G3 X3.1079 Y0.9625 I-0.0538 J-0.2228
G3 X3.0903 Y0.9649 I-0.0622 J-0.3868
G3 X3.0709 Y0.9667 I-0.0535 J-0.4675
G3 X3.0514 Y0.9677 I-0.0373 J-0.514
G3 X3.03 Y0.9681 I-0.0213 J-0.6163
G0 Z0.125
G0 X3.5657 Y0.2547
G1 Z-0.01 F10
G1 X3.5657 Y1.1251 F40
G1 X4.1536 Y1.1251
G1 X4.1536 Y0.9606
G1 X3.7617 Y0.9606
G1 X3.7617 Y0.7898
G1 X4.1096 Y0.7898
G1 X4.1096 Y0.629
G1 X3.7617 Y0.629
G1 X3.7617 Y0.4193
G1 X4.1825 Y0.4193
G1 X4.1825 Y0.2547
G1 X3.5657 Y0.2547
G0 Z0.125
G0 X4.4908 Y0.6905
G1 Z-0.01 F10
G3 X4.4918 Y0.6586 I0.4971 J0 F40
G3 X4.4947 Y0.6296 I0.4109 J0.0265
G3 X4.4997 Y0.601 I0.3733 J0.0507
G3 X4.5065 Y0.575 I0.3139 J0.0676
G3 X4.5154 Y0.5497 I0.3036 J0.0925
G3 X4.5256 Y0.5271 I0.2511 J0.1004
G3 X4.5379 Y0.5056 I0.2254 J0.1151
G3 X4.5517 Y0.4864 I0.1934 J0.124
G3 X4.5674 Y0.4689 I0.1636 J0.1303
G3 X4.5845 Y0.4536 I0.1398 J0.1398
G3 X4.6033 Y0.4405 I0.1224 J0.1548
G3 X4.6239 Y0.4293 I0.109 J0.1765
G3 X4.6457 Y0.4206 I0.0819 J0.174
G3 X4.6698 Y0.4142 I0.0674 J0.205
G3 X4.6944 Y0.4105 I0.0471 J0.2296
G3 X4.7219 Y0.4092 I0.0275 J0.2849
G3 X4.7487 Y0.4105 I0 J0.2758
G3 X4.7732 Y0.4142 I-0.0227 J0.2323
G3 X4.7971 Y0.4206 I-0.0443 J0.2143
G3 X4.8192 Y0.4293 I-0.0629 J0.192
G3 X4.8402 Y0.4405 I-0.0881 J0.1899
G3 X4.8591 Y0.4536 I-0.1024 J0.1678
G3 X4.8763 Y0.4689 I-0.1208 J0.154
G3 X4.8921 Y0.4864 I-0.1445 J0.1452
G3 X4.9058 Y0.5056 I-0.1798 J0.1433
G3 X4.9181 Y0.5271 I-0.2133 J0.1367
G3 X4.9284 Y0.5497 I-0.2412 J0.1232
G3 X4.9373 Y0.575 I-0.295 J0.1181
G3 X4.944 Y0.601 I-0.3069 J0.0937
G3 X4.9491 Y0.6296 I-0.3679 J0.0794
G3 X4.952 Y0.6586 I-0.4076 J0.0554
G3 X4.953 Y0.6905 I-0.4955 J0.032
G3 X4.952 Y0.7225 I-0.4983 J0
G3 X4.9491 Y0.7516 I-0.4161 J-0.0268
G3 X4.944 Y0.7804 I-0.3801 J-0.0514
G3 X4.9373 Y0.8067 I-0.3232 J-0.0691
G3 X4.9284 Y0.8324 I-0.3076 J-0.0928
G3 X4.9181 Y0.8551 I-0.252 J-0.0999
G3 X4.9058 Y0.8767 I-0.2249 J-0.1141
G3 X4.8921 Y0.8959 I-0.1909 J-0.1218
G3 X4.8763 Y0.9135 I-0.1602 J-0.1276
G3 X4.8591 Y0.9287 I-0.1379 J-0.1385
G3 X4.8402 Y0.9418 I-0.1212 J-0.1544
G3 X4.8192 Y0.9531 I-0.1088 J-0.1784
G3 X4.7971 Y0.9618 I-0.085 J-0.1835
G3 X4.7732 Y0.9681 I-0.0682 J-0.2081
G3 X4.7487 Y0.9718 I-0.0472 J-0.2288
G3 X4.7219 Y0.9731 I-0.0269 J-0.2747
G3 X4.6944 Y0.9718 I0 J-0.2778
G3 X4.6698 Y0.968 I0.0226 J-0.2269
G3 X4.6458 Y0.9614 I0.0436 J-0.206
G3 X4.6239 Y0.9524 I0.0608 J-0.1793
G3 X4.6033 Y0.941 I0.0938 J-0.1933
G3 X4.5845 Y0.9276 I0.1085 J-0.1725
G3 X4.5674 Y0.9123 I0.1271 J-0.159
G3 X4.5517 Y0.8947 I0.1514 J-0.1507
G3 X4.538 Y0.8755 I0.1766 J-0.1407
G3 X4.5256 Y0.8538 I0.2121 J-0.1354
G3 X4.5154 Y0.8311 I0.2413 J-0.1223
G3 X4.5065 Y0.8055 I0.2984 J-0.1182
G3 X4.4997 Y0.7792 I0.3216 J-0.0968
G3 X4.4947 Y0.7507 I0.3729 J-0.0801
G3 X4.4918 Y0.7219 I0.4066 J-0.0555
G3 X4.4908 Y0.6905 I0.4804 J-0.0313
G0 Z0.125
G0 X5.1552 Y0.6905
G1 Z-0.01 F10
G2 X5.153 Y0.6348 I-0.7056 J0 F40
G2 X5.1469 Y0.5855 I-0.5592 J0.0443
G2 X5.1362 Y0.537 I-0.4973 J0.0842
G2 X5.1219 Y0.494 I-0.4061 J0.1107
G2 X5.1034 Y0.4526 I-0.4475 J0.1756
G2 X5.0825 Y0.4161 I-0.3674 J0.1859
G2 X5.058 Y0.3821 I-0.3264 J0.2094
G2 X5.0309 Y0.3521 I-0.2803 J0.2261
G2 X5.0006 Y0.3252 I-0.2579 J0.2609
G2 X4.9676 Y0.302 I-0.2269 J0.2867
G2 X4.9322 Y0.2824 I-0.1983 J0.3171
G2 X4.8933 Y0.266 I-0.1783 J0.3683
G2 X4.8529 Y0.2534 I-0.1576 J0.4351
G2 X4.8106 Y0.2443 I-0.1231 J0.4701
G2 X4.7676 Y0.239 I-0.0841 J0.4988
G2 X4.7219 Y0.2371 I-0.0457 J0.5609
G2 X4.6774 Y0.239 I0 J0.5346
G2 X4.6352 Y0.2443 I0.0407 J0.4884
G2 X4.5936 Y0.2534 I0.0806 J0.4691
G2 X4.5536 Y0.266 I0.1189 J0.4479
G2 X4.5149 Y0.2824 I0.1418 J0.3881
G2 X4.4795 Y0.302 I0.1683 J0.3468
G2 X4.4463 Y0.3252 I0.2011 J0.3229
G2 X4.4154 Y0.3521 I0.2387 J0.3054
G2 X4.3877 Y0.3821 I0.2524 J0.2608
G2 X4.3627 Y0.4161 I0.2987 J0.246
G2 X4.3414 Y0.4526 I0.3422 J0.2241
G2 X4.3225 Y0.494 I0.4215 J0.2176
G2 X4.3079 Y0.537 I0.3858 J0.1543
G2 X4.297 Y0.5855 I0.4777 J0.1328
G2 X4.2908 Y0.6348 I0.5427 J0.0937
G2 X4.2885 Y0.6905 I0.6897 J0.0557
G2 X4.2909 Y0.7462 I0.6678 J0
G2 X4.2973 Y0.7956 I0.5306 J-0.0444
G2 X4.3086 Y0.844 I0.473 J-0.0846
G2 X4.3237 Y0.8871 I0.3899 J-0.1124
G2 X4.3432 Y0.9285 I0.4519 J-0.1874
G2 X4.365 Y0.9652 I0.376 J-0.199
G2 X4.3904 Y0.9993 I0.3361 J-0.2236
G2 X4.4185 Y1.0297 I0.2923 J-0.2425
G2 X4.4497 Y1.0569 I0.2779 J-0.287
G2 X4.4829 Y1.0802 I0.2379 J-0.303
G2 X4.5184 Y1.1 I0.2055 J-0.3276
G2 X4.5567 Y1.1163 I0.1789 J-0.3656
G2 X4.5964 Y1.129 I0.1604 J-0.4356
G2 X4.6372 Y1.138 I0.1212 J-0.4502
G2 X4.6787 Y1.1434 I0.0819 J-0.4678
G2 X4.7219 Y1.1452 I0.0432 J-0.5057
G2 X4.7663 Y1.1434 I0 J-0.535
G2 X4.8085 Y1.138 I-0.0407 J-0.4886
G2 X4.8501 Y1.1289 I-0.0806 J-0.4692
G2 X4.8902 Y1.1163 I-0.1189 J-0.4478
G2 X4.9288 Y1.0999 I-0.1394 J-0.3816
G2 X4.9643 Y1.0802 I-0.1667 J-0.3421
G2 X4.9975 Y1.0568 I-0.2001 J-0.3191
G2 X5.0284 Y1.0297 I-0.2393 J-0.3033
G2 X5.0561 Y0.9993 I-0.2595 J-0.2651
G2 X5.0811 Y0.9652 I-0.3049 J-0.2492
G2 X5.1024 Y0.9285 I-0.3477 J-0.2267
G2 X5.1213 Y0.8871 I-0.4252 J-0.219
G2 X5.1358 Y0.844 I-0.3859 J-0.1543
G2 X5.1467 Y0.7956 I-0.4781 J-0.1328
G2 X5.1529 Y0.7462 I-0.5432 J-0.0937
G2 X5.1552 Y0.6905 I-0.6906 J-0.0557
G0 Z0.125
G0 X5.831 Y0.2547
G1 Z-0.01 F10
G3 X5.8176 Y0.2759 I-1.044 J-0.6457 F40
G3 X5.8023 Y0.2991 I-1.2661 J-0.8193
G3 X5.7865 Y0.3221 I-1.3802 J-0.9298
G3 X5.7688 Y0.347 I-1.648 J-1.1507
G3 X5.7507 Y0.3716 I-1.2024 J-0.8671
G3 X5.7315 Y0.3966 I-1.2587 J-0.9478
G3 X5.7118 Y0.4213 I-1.2783 J-1.0032
G3 X5.691 Y0.4462 I-1.3393 J-1.0938
G3 X5.6697 Y0.4708 I-1.3401 J-1.1372
G3 X5.6481 Y0.4949 I-1.3041 J-1.1488
G3 X5.6261 Y0.5186 I-1.2762 J-1.1671
G3 X5.6037 Y0.5417 I-1.2437 J-1.1807
G3 X5.5807 Y0.5643 I-0.7609 J-0.7501
G3 X5.5585 Y0.5849 I-0.6558 J-0.6866
G3 X5.5355 Y0.6048 I-0.5973 J-0.6668
G3 X5.5132 Y0.6227 I-0.5113 J-0.6113
G1 X5.5132 Y0.2547
G1 X5.3173 Y0.2547
G1 X5.3173 Y1.1251
G1 X5.5132 Y1.1251
G1 X5.5132 Y0.796
G3 X5.5514 Y0.8364 I-4.1871 J3.9914
G3 X5.59 Y0.8782 I-4.4359 J4.1481
G3 X5.6283 Y0.9203 I-4.5842 J4.207
G3 X5.6671 Y0.9637 I-4.8507 J4.3705
G2 X5.7058 Y1.0073 I26.9704 J-23.868
G2 X5.7417 Y1.0477 I23.1463 J-20.5506
G2 X5.7777 Y1.088 I21.3614 J-19.0327
G2 X5.8109 Y1.1251 I18.1034 J-16.1914
G1 X6.0433 Y1.1251
G2 X5.9984 Y1.0726 I-5.3969 J4.5615
G2 X5.9539 Y1.0215 I-5.1497 J4.4395
G2 X5.9089 Y0.9709 I-5.0078 J4.405
G2 X5.8643 Y0.9217 I-4.7755 J4.2874
G2 X5.8191 Y0.8729 I-4.3297 J3.9689
G2 X5.7721 Y0.8234 I-4.526 J4.244
G2 X5.7246 Y0.7743 I-4.6029 J4.4123
G2 X5.6753 Y0.7244 I-4.8095 J4.7102
G2 X5.7262 Y0.6798 I-0.8185 J-0.9847
G2 X5.7778 Y0.6296 I-0.9824 J-1.0622
G2 X5.8269 Y0.577 I-1.1027 J-1.0792
G2 X5.8769 Y0.5185 I-1.3152 J-1.1722
G2 X5.9244 Y0.458 I-1.6952 J-1.3829
G2 X5.9722 Y0.3929 I-1.9177 J-1.4551
G2 X6.0177 Y0.3262 I-2.064 J-1.4598
G2 X6.0634 Y0.2547 I-2.3302 J-1.5388
G1 X5.831 Y0.2547
G0 Z0.125
G0 X6.3404 Y0.6905
G1 Z-0.01 F10
G3 X6.3415 Y0.6586 I0.4971 J0 F40
G3 X6.3444 Y0.6296 I0.4109 J0.0265
G3 X6.3494 Y0.601 I0.3733 J0.0507
G3 X6.3561 Y0.575 I0.3139 J0.0676
G3 X6.365 Y0.5497 I0.3036 J0.0925
G3 X6.3753 Y0.5271 I0.2511 J0.1004
G3 X6.3876 Y0.5056 I0.2254 J0.1151
G3 X6.4013 Y0.4864 I0.1934 J0.124
G3 X6.417 Y0.4689 I0.1636 J0.1303
G3 X6.4342 Y0.4536 I0.1398 J0.1398
G3 X6.4529 Y0.4405 I0.1224 J0.1548
G3 X6.4736 Y0.4293 I0.109 J0.1765
G3 X6.4954 Y0.4206 I0.0819 J0.174
G3 X6.5194 Y0.4142 I0.0674 J0.205
G3 X6.5441 Y0.4105 I0.0471 J0.2296
G3 X6.5715 Y0.4092 I0.0275 J0.2849
G3 X6.5984 Y0.4105 I0 J0.2758
G3 X6.6229 Y0.4142 I-0.0227 J0.2323
G3 X6.6468 Y0.4206 I-0.0443 J0.2143
G3 X6.6689 Y0.4293 I-0.0629 J0.192
G3 X6.6898 Y0.4405 I-0.0881 J0.1899
G3 X6.7088 Y0.4536 I-0.1024 J0.1678
G3 X6.726 Y0.4689 I-0.1208 J0.154
G3 X6.7417 Y0.4864 I-0.1445 J0.1452
G3 X6.7555 Y0.5056 I-0.1798 J0.1433
G3 X6.7678 Y0.5271 I-0.2133 J0.1367
G3 X6.778 Y0.5497 I-0.2412 J0.1232
G3 X6.787 Y0.575 I-0.295 J0.1181
G3 X6.7937 Y0.601 I-0.3069 J0.0937
G3 X6.7987 Y0.6296 I-0.3679 J0.0794
G3 X6.8016 Y0.6586 I-0.4076 J0.0554
G3 X6.8027 Y0.6905 I-0.4955 J0.032
G3 X6.8016 Y0.7225 I-0.4983 J0
G3 X6.7987 Y0.7516 I-0.4161 J-0.0268
G3 X6.7937 Y0.7804 I-0.3801 J-0.0514
G3 X6.787 Y0.8067 I-0.3232 J-0.0691
G3 X6.778 Y0.8324 I-0.3076 J-0.0928
G3 X6.7678 Y0.8551 I-0.252 J-0.0999
G3 X6.7554 Y0.8767 I-0.2249 J-0.1141
G3 X6.7417 Y0.8959 I-0.1909 J-0.1218
G3 X6.726 Y0.9135 I-0.1602 J-0.1276
G3 X6.7088 Y0.9287 I-0.1379 J-0.1385
G3 X6.6898 Y0.9418 I-0.1212 J-0.1544
G3 X6.6689 Y0.9531 I-0.1088 J-0.1784
G3 X6.6468 Y0.9618 I-0.085 J-0.1835
G3 X6.6229 Y0.9681 I-0.0682 J-0.2081
G3 X6.5984 Y0.9718 I-0.0472 J-0.2288
G3 X6.5715 Y0.9731 I-0.0269 J-0.2747
G3 X6.5441 Y0.9718 I0 J-0.2778
G3 X6.5194 Y0.968 I0.0226 J-0.2269
G3 X6.4954 Y0.9614 I0.0436 J-0.206
G3 X6.4736 Y0.9524 I0.0608 J-0.1793
G3 X6.4529 Y0.941 I0.0938 J-0.1933
G3 X6.4342 Y0.9276 I0.1085 J-0.1725
G3 X6.417 Y0.9123 I0.1271 J-0.159
G3 X6.4013 Y0.8947 I0.1514 J-0.1507
G3 X6.3876 Y0.8755 I0.1766 J-0.1407
G3 X6.3753 Y0.8538 I0.2121 J-0.1354
G3 X6.3651 Y0.8311 I0.2413 J-0.1223
G3 X6.3561 Y0.8055 I0.2984 J-0.1182
G3 X6.3494 Y0.7792 I0.3216 J-0.0968
G3 X6.3444 Y0.7507 I0.3729 J-0.0801
G3 X6.3415 Y0.7219 I0.4066 J-0.0555
G3 X6.3404 Y0.6905 I0.4804 J-0.0313
G0 Z0.125
G0 X7.0049 Y0.6905
G1 Z-0.01 F10
G2 X7.0027 Y0.6348 I-0.7056 J0 F40
G2 X6.9965 Y0.5855 I-0.5592 J0.0443
G2 X6.9859 Y0.537 I-0.4973 J0.0842
G2 X6.9716 Y0.494 I-0.4061 J0.1107
G2 X6.953 Y0.4526 I-0.4475 J0.1756
G2 X6.9322 Y0.4161 I-0.3674 J0.1859
G2 X6.9077 Y0.3821 I-0.3264 J0.2094
G2 X6.8805 Y0.3521 I-0.2803 J0.2261
G2 X6.8503 Y0.3252 I-0.2579 J0.2609
G2 X6.8173 Y0.302 I-0.2269 J0.2867
G2 X6.7819 Y0.2824 I-0.1983 J0.3171
G2 X6.743 Y0.266 I-0.1783 J0.3683
G2 X6.7026 Y0.2534 I-0.1576 J0.4351
G2 X6.6602 Y0.2443 I-0.1231 J0.4701
G2 X6.6172 Y0.239 I-0.0841 J0.4988
G2 X6.5715 Y0.2371 I-0.0457 J0.5609
G2 X6.5271 Y0.239 I0 J0.5346
G2 X6.4849 Y0.2443 I0.0407 J0.4884
G2 X6.4433 Y0.2534 I0.0806 J0.4691
G2 X6.4032 Y0.266 I0.1189 J0.4479
G2 X6.3646 Y0.2824 I0.1418 J0.3881
G2 X6.3291 Y0.302 I0.1683 J0.3468
G2 X6.2959 Y0.3252 I0.2011 J0.3229
G2 X6.2651 Y0.3521 I0.2387 J0.3054
G2 X6.2374 Y0.3821 I0.2524 J0.2608
G2 X6.2123 Y0.4161 I0.2987 J0.246
G2 X6.191 Y0.4526 I0.3422 J0.2241
G2 X6.1721 Y0.494 I0.4215 J0.2176
G2 X6.1576 Y0.537 I0.3858 J0.1544
G2 X6.1467 Y0.5855 I0.4777 J0.1328
G2 X6.1405 Y0.6348 I0.5427 J0.0937
G2 X6.1382 Y0.6905 I0.6897 J0.0557
G2 X6.1405 Y0.7462 I0.6678 J0
G2 X6.147 Y0.7956 I0.5306 J-0.0444
G2 X6.1583 Y0.844 I0.473 J-0.0846
G2 X6.1734 Y0.8871 I0.3899 J-0.1124
G2 X6.1929 Y0.9285 I0.4519 J-0.1874
G2 X6.2147 Y0.9652 I0.376 J-0.199
G2 X6.2401 Y0.9993 I0.3361 J-0.2236
G2 X6.2682 Y1.0297 I0.2923 J-0.2425
G2 X6.2994 Y1.0569 I0.2779 J-0.287
G2 X6.3326 Y1.0802 I0.2379 J-0.303
G2 X6.3681 Y1.1 I0.2055 J-0.3276
G2 X6.4064 Y1.1163 I0.1789 J-0.3656
G2 X6.4461 Y1.129 I0.1604 J-0.4356
G2 X6.4869 Y1.138 I0.1212 J-0.4502
G2 X6.5284 Y1.1434 I0.0819 J-0.4678
G2 X6.5715 Y1.1452 I0.0432 J-0.5057
G2 X6.616 Y1.1434 I0 J-0.535
G2 X6.6582 Y1.138 I-0.0407 J-0.4886
G2 X6.6998 Y1.1289 I-0.0806 J-0.4692
G2 X6.7399 Y1.1163 I-0.1189 J-0.4478
G2 X6.7785 Y1.0999 I-0.1394 J-0.3816
G2 X6.814 Y1.0802 I-0.1667 J-0.3421
G2 X6.8471 Y1.0568 I-0.2001 J-0.3191
G2 X6.878 Y1.0297 I-0.2393 J-0.3033
G2 X6.9058 Y0.9993 I-0.2595 J-0.2651
G2 X6.9308 Y0.9652 I-0.3049 J-0.2492
G2 X6.9521 Y0.9285 I-0.3477 J-0.2267
G2 X6.971 Y0.8871 I-0.4252 J-0.219
G2 X6.9855 Y0.844 I-0.3859 J-0.1543
G2 X6.9964 Y0.7956 I-0.4781 J-0.1328
G2 X7.0026 Y0.7462 I-0.5432 J-0.0937
G2 X7.0049 Y0.6905 I-0.6906 J-0.0557
G0 Z0.125
G0 X7.9912 Y0.8965
G1 Z-0.01 F10
G2 X7.99 Y0.8728 I-0.237 J0 F40
G2 X7.9865 Y0.8497 I-0.2267 J0.0228
G2 X7.9807 Y0.8272 I-0.2234 J0.0459
G2 X7.9724 Y0.8048 I-0.2271 J0.0715
G2 X7.9623 Y0.7832 I-0.3646 J0.1563
G2 X7.9507 Y0.7617 I-0.3716 J0.1865
G2 X7.9379 Y0.7409 I-0.371 J0.2144
G2 X7.9234 Y0.7201 I-0.3849 J0.2528
G2 X7.9079 Y0.7 I-0.5278 J0.3898
G2 X7.8914 Y0.68 I-0.5353 J0.4282
G2 X7.8741 Y0.6607 I-0.5316 J0.4593
G2 X7.8556 Y0.6416 I-0.5427 J0.505
G1 X7.7815 Y0.57
G3 X7.7721 Y0.5611 I0.8861 J-0.9498
G3 X7.7618 Y0.5513 I1.0881 J-1.1433
G3 X7.7517 Y0.5413 I1.2053 J-1.2439
G3 X7.7406 Y0.5304 I1.4521 J-1.4741
G1 X7.6986 Y0.4858
G3 X7.6886 Y0.4744 I1.1214 J-0.996
G3 X7.6796 Y0.464 I0.9432 J-0.8208
G3 X7.6707 Y0.4534 I0.8658 J-0.7369
G3 X7.6628 Y0.4437 I0.7169 J-0.5953
G3 X7.6552 Y0.4338 I0.1702 J-0.1375
G3 X7.65 Y0.426 I0.0998 J-0.0716
G3 X7.6456 Y0.4178 I0.0757 J-0.046
G3 X7.6433 Y0.4117 I0.0391 J-0.0185
G1 X8.0176 Y0.4117
G1 X8.0176 Y0.2547
G1 X7.4373 Y0.2547
G2 X7.4363 Y0.2616 I0.1145 J0.0207
G2 X7.4354 Y0.2704 I0.1829 J0.0218
G2 X7.435 Y0.2792 I0.2268 J0.0161
G2 X7.4348 Y0.2899 I0.3344 J0.0107
G1 X7.4348 Y0.2998
G1 X7.4348 Y0.3081
G1 X7.4348 Y0.3148
G1 X7.4348 Y0.32
G2 X7.4361 Y0.3501 I0.3578 J0
G2 X7.4397 Y0.3778 I0.3087 J-0.026
G2 X7.4458 Y0.4051 I0.2878 J-0.0507
G2 X7.4543 Y0.4306 I0.2595 J-0.0719
G2 X7.4648 Y0.4553 I0.3938 J-0.1527
G2 X7.4767 Y0.4791 I0.3744 J-0.1733
G2 X7.4902 Y0.502 I0.3612 J-0.1964
G2 X7.5052 Y0.5241 I0.3512 J-0.2214
G2 X7.5213 Y0.5454 I0.4675 J-0.3386
G2 X7.5386 Y0.566 I0.457 J-0.3645
G2 X7.5568 Y0.5859 I0.4444 J-0.3892
G2 X7.5761 Y0.6051 I0.4388 J-0.4211
G1 X7.6546 Y0.6805
G3 X7.6697 Y0.6949 I-6.5538 J6.8409
G3 X7.6838 Y0.7086 I-5.8415 J6.0705
G3 X7.6979 Y0.7223 I-5.5113 J5.7006
G3 X7.7111 Y0.7351 I-4.8745 J5.0171
G3 X7.7242 Y0.7482 I-0.5266 J0.5392
G3 X7.7359 Y0.7606 I-0.4648 J0.4531
G3 X7.7474 Y0.7733 I-0.4416 J0.4084
G3 X7.7576 Y0.7854 I-0.388 J0.3389
G3 X7.7673 Y0.7979 I-0.2179 J0.1789
G3 X7.7755 Y0.8099 I-0.1921 J0.1404
G3 X7.7829 Y0.8223 I-0.1846 J0.1184
G3 X7.789 Y0.8343 I-0.1653 J0.0911
G3 X7.794 Y0.8468 I-0.1205 J0.0556
G3 X7.7975 Y0.859 I-0.1118 J0.0384
G3 X7.7996 Y0.8715 I-0.111 J0.0253
G3 X7.8003 Y0.884 I-0.1104 J0.0125
G3 X7.798 Y0.9112 I-0.1655 J0
G3 X7.7924 Y0.9311 I-0.0937 J-0.0156
G3 X7.7824 Y0.9488 I-0.0702 J-0.0283
G3 X7.7689 Y0.9618 I-0.0509 J-0.0389
G3 X7.7525 Y0.9716 I-0.064 J-0.0889
G3 X7.7337 Y0.9788 I-0.0523 J-0.1085
G3 X7.714 Y0.9829 I-0.0372 J-0.1282
G3 X7.691 Y0.9844 I-0.023 J-0.1742
G3 X7.6741 Y0.9838 I0 J-0.2082
G3 X7.6582 Y0.9818 I0.0152 J-0.1867
G3 X7.6426 Y0.9784 I0.0299 J-0.1776
G3 X7.6276 Y0.9738 I0.0434 J-0.166
G3 X7.613 Y0.9681 I0.124 J-0.3427
G3 X7.5994 Y0.9621 I0.1248 J-0.3035
G3 X7.586 Y0.9556 I0.1317 J-0.2831
G3 X7.5736 Y0.9486 I0.1322 J-0.2521
G3 X7.5615 Y0.9412 I0.2233 J-0.3784
G3 X7.5508 Y0.9342 I0.1896 J-0.2988
G3 X7.5405 Y0.9268 I0.179 J-0.2609
G3 X7.5315 Y0.9198 I0.1505 J-0.2014
G3 X7.5228 Y0.9125 I0.4664 J-0.5685
G3 X7.5161 Y0.9067 I0.2834 J-0.3348
G3 X7.5096 Y0.9008 I0.2157 J-0.2447
G3 X7.5052 Y0.8965 I0.1113 J-0.1196
G1 X7.4122 Y1.0271
G2 X7.4408 Y1.0516 I0.3033 J-0.3254
G2 X7.472 Y1.0741 I0.2859 J-0.3642
G2 X7.505 Y1.0939 I0.2634 J-0.4
G2 X7.541 Y1.1119 I0.2525 J-0.4598
G2 X7.5784 Y1.1265 I0.1528 J-0.3372
G2 X7.6171 Y1.1369 I0.115 J-0.3507
G2 X7.6567 Y1.1431 I0.078 J-0.3692
G2 X7.6986 Y1.1452 I0.0419 J-0.4097
G2 X7.7368 Y1.1441 I0 J-0.6209
G2 X7.7698 Y1.1408 I-0.0288 J-0.4669
G2 X7.8025 Y1.1351 I-0.0537 J-0.4022
G2 X7.8304 Y1.1276 I-0.0656 J-0.3011
G2 X7.8576 Y1.1176 I-0.0975 J-0.3061
G2 X7.8808 Y1.1064 I-0.0996 J-0.2366
G2 X7.9028 Y1.0929 I-0.1113 J-0.2042
G2 X7.9215 Y1.078 I-0.1143 J-0.1635
G2 X7.9383 Y1.0611 I-0.1312 J-0.1467
G2 X7.9526 Y1.0425 I-0.1419 J-0.1243
G2 X7.9645 Y1.0224 I-0.1576 J-0.1068
G2 X7.9743 Y1.0002 I-0.1832 J-0.0937
G2 X7.9816 Y0.9769 I-0.2296 J-0.085
G2 X7.987 Y0.9513 I-0.2735 J-0.0712
G2 X7.9901 Y0.9253 I-0.3042 J-0.0498
G2 X7.9912 Y0.8965 I-0.3724 J-0.0288
G0 Z0.125
(remove M5 and M30)

File diff suppressed because it is too large Load Diff

View File

@ -1,437 +0,0 @@
% ----------------------------------------------------------------------------------------
% The MIT License (MIT)
%
% Copyright (c) 2014 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.
% ----------------------------------------------------------------------------------------
% This MATLAB script was written for the purpose of being a GRBL planner simulator. This
% simulator is a rough representation of the actual workings of Grbl on the Arduino, but
% was used to hone and proof the actual planner by providing quick visual feedback on its
% functionality when experimented on. This script should be considered for educational
% purposes only. This script requires and executes a pre-parsed g-code file from the
% matlab_convert.py script that is in a specific non-g-code format.
% There will be two figures plotted. The first is the line motion paths of the complete
% g-code program. The second is a representation of Grbl's planner buffer as new line
% motions are fed to it, plotting the velocity profiles the stepper motors will execute.
% Every time the user inputs an <Enter>, this feeds the simulator planner one line motion
% block. The left side is the first block in the buffer and the one that will be executed
% by the stepper module first. The right side is the end of the planner buffer, where the
% most recent streamed block is appended onto the planner buffer. Grbl's planner
% optimizes the velocity profiles between the beginning and end of the buffer based on
% the acceleration limits, intended velocity/feedrate, and line motion junction angles
% with their corresponding velocity limits (i.e. junctions with acute angles needs to come
% to a complete stop vs straight junctions can continue through at full speed.)
% ----------------------------------------------------------------------------------------
% Main function
% NOTE: This is just a way to keep all functions in one place, but all non-global variables
% are cleared as soon as this script completes.
function main()
% Load pre-parsed gcode moves.
close all;
warning off;
clearvars -global
fid = fopen('matlab.gcode','r');
gcode = textscan(fid,'%d8%f32%f32%f32%f32');
nblock = length(gcode{1});
% Plot all g-code moves.
figure
line(gcode{3},gcode{4},gcode{5});
axis equal;
% axis([min(gcode{3}) max(gcode{3}) min(gcode{4}) max(gcode{4}) min(gcode{5}) max(gcode{5})]);
title('G-code programming line motions');
view(3);
% Set up figure for planner queue
figure
% Print help.
disp('<NOTE: Press Enter to Advance One G-Code Line Motion>');
disp(' BLUE line indicates completed planner blocks that require no recalculation.');
disp(' RED line indicates planner blocks that have been recalculated.');
disp(' GREEN line indicates the location of the BPLANNED pointer. Always a recalculated block.');
disp(' BLACK dotted-line and ''x'' indicates block nominal speed and max junction velocity, respectively.');
disp(' CYAN ''.'' indicates block initial entry speed.');
% Define Grbl settings.
BUFFER_SIZE = 18; % Number of planner blocks in its ring buffer.
steps_per_mm = 200;
seekrate = 2500; % mm/min
acceleration = [100 100 100]; % mm/sec^2 [ X Y Z ] axes
junction_deviation = 0.1; % mm. See Grbl documentation on this parameter.
inch_2_mm = 25.4;
ACCELERATION_TICKS_PER_SECOND = 100;
gcode{2} = gcode{2};
gcode{2} = inch_2_mm*gcode{2};
gcode{3} = inch_2_mm*gcode{3};
gcode{4} = inch_2_mm*gcode{4};
gcode{5} = inch_2_mm*gcode{5};
% Initialize blocks
block.steps = [];
block.step_event_count = [];
block.delta_mm = [];
block.millimeters = [];
block.acceleration = [];
block.speed = [];
block.nominal_speed = [];
block.max_entry_speed = [];
block.entry_speed = [];
block.recalculate_flag = false;
for i = 2:BUFFER_SIZE
block(i) = block(1);
end
% Initialize planner
position = [0 0 0];
prev_unit_vec = [0 0 0];
previous_nominal_speed = 0;
pos = 0;
% BHEAD and BTAIL act as pointers to the block head and tail.
% BPLANNED acts as a pointer of the location of the end of a completed/optimized plan.
bhead = 1;
btail = 1;
bplanned = 1;
global block bhead btail bplanned nind acceleration BUFFER_SIZE pos ACCELERATION_TICKS_PER_SECOND
% Main loop. Simulates plan_buffer_line(). All of the precalculations for the newest incoming
% block occurs here. Anything independent of the planner changes.
for i = 1:nblock
target = round([gcode{3}(i) gcode{4}(i) gcode{5}(i)].*steps_per_mm);
if gcode{1}(i) == 1
feedrate = gcode{2}(i);
else
feedrate = seekrate;
end
nind = next_block_index(bhead);
if nind == btail
% Simulate a constantly full buffer. Move buffer tail.
bind = next_block_index(btail);
% Push planned pointer if encountered. Prevents it from looping back around the ring buffer.
if btail == bplanned; bplanned = bind; end
btail = bind;
end
block(bhead).steps = abs(target-position);
block(bhead).step_event_count = max(block(bhead).steps);
% Bail if this is a zero-length block
if block(bhead).step_event_count == 0
disp(['Zero-length block in line ',int2str(i)]);
else
% Compute path vector in terms of absolute step target and current positions
delta_mm = single((target-position)./steps_per_mm);
block(bhead).millimeters = single(norm(delta_mm));
inverse_millimeters = single(1/block(bhead).millimeters);
% Compute path unit vector
unit_vec = delta_mm/block(bhead).millimeters;
% Calculate speed in mm/minute for each axis
inverse_minute = single(feedrate * inverse_millimeters);
block(bhead).speed = delta_mm*inverse_minute;
block(bhead).nominal_speed = block(bhead).millimeters*inverse_minute;
% Calculate block acceleration. Operates on absolute value of unit vector.
[max_acc,ind] = max(abs(unit_vec)./acceleration); % Determine limiting acceleration
block(bhead).acceleration = acceleration(ind)/abs(unit_vec(ind));
% Compute maximum junction speed
block(bhead).max_entry_speed = 0.0;
if previous_nominal_speed > 0.0
cos_theta = dot(-previous_unit_vec,unit_vec);
if (cos_theta < 0.95)
block(bhead).max_entry_speed = min([block(bhead).nominal_speed,previous_nominal_speed]);
if (cos_theta > -0.95)
sin_theta_d2 = sqrt(0.5*(1.0-cos_theta));
block(bhead).max_entry_speed = min([block(bhead).max_entry_speed,sqrt(block(bhead).acceleration*3600*junction_deviation*sin_theta_d2/(1.0-sin_theta_d2))]);
end
end
end
block(bhead).entry_speed = 0; % Just initialize. Set accurately in the replanning function.
block(bhead).recalculate_flag = true; % Plotting flag to indicate this block has been updated.
previous_unit_vec = unit_vec;
previous_nominal_speed = block(bhead).nominal_speed;
position = target;
bhead = nind; % Block complete. Push buffer pointer.
planner_recalculate();
plot_buffer_velocities();
end
end
return
% Computes the next block index in the planner ring buffer
function block_index = next_block_index(block_index)
global BUFFER_SIZE
block_index = block_index + 1;
if block_index > BUFFER_SIZE
block_index = 1;
end
return
% Computes the previous block index in the planner ring buffer
function block_index = prev_block_index(block_index)
global BUFFER_SIZE
block_index = block_index-1;
if block_index < 1
block_index = BUFFER_SIZE;
end
return
% Planner recalculate function. The magic happens here.
function planner_recalculate(block)
global block bhead btail bplanned acceleration
bind = prev_block_index(bhead);
if bind == bplanned; return; end % Bail, if only one block in buffer. Can't be operated on.
% Reverse Pass: Coarsely maximize all possible deceleration curves back-planning from the last
% block in buffer. Cease planning when the last optimal planned or tail pointer is reached.
% NOTE: Forward pass will later refine and correct the reverse pass to create an optimal plan.
next = [];
curr = bind; % Last block in buffer.
% Calculate maximum entry speed for last block in buffer, where the exit speed is always zero.
block(curr).entry_speed = min([block(curr).max_entry_speed,sqrt(2*block(curr).acceleration*60*60*block(curr).millimeters)]);
bind = prev_block_index(bind); % Btail or second to last block
if (bind == bplanned)
% Only two plannable blocks in buffer. Reverse pass complete.
% Check if the first block is the tail. If so, notify stepper module to update its current parameters.
% if bind == btail; update_tail_block; end
else
% Three or more plannable blocks in buffer. Loop it.
while bind ~= bplanned % Loop until bplanned point hits. Replans to last plan point.
next = curr;
curr = bind;
bind = prev_block_index( bind ); % Previous block pointer.
% Check if the first block is the tail. If so, notify stepper module to update its current parameters.
% if bind == btail; update_tail_block; end
% Compute maximum entry speed decelerating over the current block from its exit speed.
if block(curr).entry_speed ~= block(curr).max_entry_speed
block(curr).recalculate_flag = true; % Plotting flag to indicate this block has been updated.
block(curr).entry_speed = min([ block(curr).max_entry_speed,...
sqrt(block(next).entry_speed^2 + 2*block(curr).acceleration*60*60*block(curr).millimeters)]);
end
end
end
% For two blocks, reverse pass is skipped, but forward pass plans second block entry speed
% onward. This prevents the first, or the potentially executing block, from being over-written.
% NOTE: Can never be bhead, since bsafe is always in active buffer.
next = bplanned;
bind = next_block_index(bplanned); % Start at bplanned
while bind ~= bhead
curr = next;
next = bind;
% An acceleration block is always an optimally planned block since it starts from the first
% block's current speed or a maximum junction speed. Compute accelerations from this block
% and update the next block's entry speed.
if (block(curr).entry_speed < block(next).entry_speed)
% Once speed is set by forward planner, the plan for this block is finished and optimal.
% Increment the planner pointer forward one block.
entry_speed = sqrt(block(curr).entry_speed^2 + 2*block(curr).acceleration*60*60*block(curr).millimeters);
if (block(next).entry_speed > entry_speed)
block(next).entry_speed = entry_speed;
bplanned = bind;
end
end
% Check if the next block entry speed is at max_entry_speed. If so, move the planned pointer, since
% this entry speed cannot be improved anymore and all prior blocks have been completed and optimally planned.
if block(next).entry_speed == block(next).max_entry_speed
bplanned = bind;
end
% Recalculate trapezoid can be installed here, since it scans through all of the plannable blocks.
% NOTE: Eventually this will only be computed when being executed.
bind = next_block_index( bind );
end
return
% ----------------------------------------------------------------------------------------
% PLOTTING FUNCTIONS
% Plots the entire buffer plan into a MATLAB figure to visual the plan.
% BLUE line indicates completed planner blocks that require no recalculation.
% RED line indicates planner blocks that have been recalculated.
% GREEN line indicates the location of the BPLANNED pointer. Always a recalculated block.
% BLACK dotted-line and 'x' indicates block nominal speed and max junction velocity, respectively.
% CYAN '.' indicates block initial entry speed.
function plot_buffer_velocities()
global block bhead btail bplanned acceleration pos ACCELERATION_TICKS_PER_SECOND
bind = btail;
curr = [];
next = [];
pos_initial = 0;
pos = 0;
while bind ~= bhead
curr = next;
next = bind;
hold on;
if ~isempty(curr)
accel_d = estimate_acceleration_distance(block(curr).entry_speed, block(curr).nominal_speed, block(curr).acceleration*60*60);
decel_d = estimate_acceleration_distance(block(curr).nominal_speed, block(next).entry_speed,-block(curr).acceleration*60*60);
plateau_d = block(curr).millimeters-accel_d-decel_d;
if plateau_d < 0
accel_d = intersection_distance(block(curr).entry_speed, block(next).entry_speed, block(curr).acceleration*60*60, block(curr).millimeters);
if accel_d < 0
accel_d = 0;
elseif accel_d > block(curr).millimeters
accel_d = block(curr).millimeters;
end
plateau_d = 0;
end
color = 'b';
if (block(curr).recalculate_flag || block(next).recalculate_flag)
block(curr).recalculate_flag = false;
color = 'r';
end
if bplanned == curr
color = 'g';
end
plot_trap(pos,block(curr).entry_speed,block(next).entry_speed,block(curr).nominal_speed,block(curr).acceleration,accel_d,plateau_d,block(curr).millimeters,color)
plot([pos pos+block(curr).millimeters],block(curr).nominal_speed*[1 1],'k:') % BLACK dotted indicates
plot(pos,block(curr).max_entry_speed,'kx')
pos = pos + block(curr).millimeters;
plot(pos,block(next).entry_speed,'c.');
end
bind = next_block_index( bind );
end
accel_d = estimate_acceleration_distance(block(next).entry_speed, block(next).nominal_speed, block(next).acceleration*60*60);
decel_d = estimate_acceleration_distance(block(next).nominal_speed, 0, -block(next).acceleration*60*60);
plateau_d = block(next).millimeters-accel_d-decel_d;
if plateau_d < 0
accel_d = intersection_distance(block(next).entry_speed, 0, block(next).acceleration*60*60, block(next).millimeters);
if accel_d < 0
accel_d = 0;
elseif accel_d > block(next).millimeters
accel_d = block(next).millimeters;
end
plateau_d = 0;
end
block(next).recalculate_flag = false;
color = 'r';
if bplanned == next
color= 'g';
end
plot_trap(pos,block(next).entry_speed,0,block(next).nominal_speed,block(next).acceleration,accel_d,plateau_d,block(next).millimeters,color)
plot([pos pos+block(next).millimeters],block(next).nominal_speed*[1 1],'k:')
plot(pos,block(next).max_entry_speed,'kx')
plot(pos,block(next).entry_speed,'.');
pos = pos + block(next).millimeters;
plot(pos,0,'rx');
xlabel('mm');
ylabel('mm/sec');
xlim([pos_initial pos])
title('Planner buffer optimized velocity profile');
pause();
hold off;
plot(pos,0)
return
function d_a = estimate_acceleration_distance(initial_rate, target_rate, acceleration,rate_delta)
d_a = (target_rate*target_rate-initial_rate*initial_rate)/(2*acceleration);
return
function d_i = intersection_distance(initial_rate, final_rate, acceleration, distance, rate_delta)
d_i = (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4*acceleration);
return
% Simply plots the ac/de-celeration curves and plateaus of a trapezoid.
function plot_trap(pos,initial_rate,final_rate,rate,accel,accel_d,plateau_d,millimeters,color)
dx = 1.0; % Line segment length
linex = [pos]; liney = [initial_rate];
% Acceleration
np = floor(accel_d/dx);
if np
v = initial_rate;
for i = 1:np
v = sqrt(v^2+2*accel*60*60*dx);
linex = [linex pos+i*dx];
liney = [liney v];
end
end
% Plateau
v = sqrt(initial_rate^2 + 2*accel*60*60*accel_d);
if v < rate
rate = v;
end
linex = [linex pos+[accel_d accel_d+plateau_d]];
liney = [liney [rate rate]];
% Deceleration
np = floor((millimeters-accel_d-plateau_d)/dx);
if np
v = rate;
for i = 1:np
v = sqrt(v^2-2*accel*60*60*dx);
linex = [linex pos+i*dx+accel_d+plateau_d];
liney = [liney v];
end
end
linex = [linex pos+millimeters];
liney = [ liney final_rate];
plot(linex,liney,color);
return

File diff suppressed because it is too large Load Diff

View File

@ -1,270 +0,0 @@
#!/usr/bin/env python
"""\
The MIT License (MIT)
Copyright (c) 2014 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.
----------------------------------------------------------------------------------------
"""
"""\
G-code preprocessor for the grbl_sim.m MATLAB script. Parses the g-code program to a
specific file format for the MATLAB script to use. Based on PreGrbl by @chamnit.
How to use: When running this python script, it will process the g-code program under
the filename "test.gcode" (may be changed below) and produces a file called "matlab.gcode"
that the grbl_sim.m MATLAB script will search for and execute.
"""
import re
from math import *
from copy import *
# -= SETTINGS =-
filein = 'test.gcode' # Input file name
fileout = 'matlab.gcode' # Output file name
ndigits_in = 4 # inch significant digits after '.'
ndigits_mm = 2 # mm significant digits after '.'
# mm_per_arc_segment = 0.38 # mm per arc segment
arc_tolerance = 0.00005*25.4
n_arc_correction = 20
inch2mm = 25.4 # inch to mm conversion scalar
verbose = False # Verbose flag to show all progress
remove_unsupported = True # Removal flag for all unsupported statements
# Initialize parser state
gc = { 'current_xyz' : [0,0,0],
'feed_rate' : 0, # F0
'motion_mode' : 'SEEK', # G00
'plane_axis' : [0,1,2], # G17
'inches_mode' : False, # G21
'inverse_feedrate_mode' : False, # G94
'absolute_mode' : True} # G90
def unit_conv(val) : # Converts value to mm
if gc['inches_mode'] : val *= inch2mm
return(val)
def fout_conv(val) : # Returns converted value as rounded string for output file.
if gc['inches_mode'] : return( str(round(val/inch2mm,ndigits_in)) )
else : return( str(round(val,ndigits_mm)) )
# Open g-code file
fin = open(filein,'r');
fout = open(fileout,'w');
# Iterate through g-code file
l_count = 0
for line in fin:
l_count += 1 # Iterate line counter
# Strip comments/spaces/tabs/new line and capitalize. Comment MSG not supported.
block = re.sub('\s|\(.*?\)','',line).upper()
block = re.sub('\\\\','',block) # Strip \ block delete character
block = re.sub('%','',block) # Strip % program start/stop character
if len(block) == 0 : # Ignore empty blocks
print "Skipping: " + line.strip()
else : # Process valid g-code clean block. Assumes no block delete characters or comments
g_cmd = re.findall(r'[^0-9\.\-]+',block) # Extract block command characters
g_num = re.findall(r'[0-9\.\-]+',block) # Extract block numbers
# G-code block error checks
# if len(g_cmd) != len(g_num) : print block; raise Exception('Invalid block. Unbalanced word and values.')
if 'N' in g_cmd :
if g_cmd[0]!='N': raise Exception('Line number must be first command in line.')
if g_cmd.count('N') > 1: raise Exception('More than one line number in block.')
g_cmd = g_cmd[1:] # Remove line number word
g_num = g_num[1:]
# Block item repeat checks? (0<=n'M'<5, G/M modal groups)
# Initialize block state
blk = { 'next_action' : 'DEFAULT',
'absolute_override' : False,
'target_xyz' : deepcopy(gc['current_xyz']),
'offset_ijk' : [0,0,0],
'radius_mode' : False,
'unsupported': [] }
# Pass 1
for cmd,num in zip(g_cmd,g_num) :
fnum = float(num)
inum = int(fnum)
if cmd is 'G' :
if inum is 0 : gc['motion_mode'] = 'SEEK'
elif inum is 1 : gc['motion_mode'] = 'LINEAR'
elif inum is 2 : gc['motion_mode'] = 'CW_ARC'
elif inum is 3 : gc['motion_mode'] = 'CCW_ARC'
elif inum is 4 : blk['next_action'] = 'DWELL'
elif inum is 17 : gc['plane_axis'] = [0,1,2] # Select XY Plane
elif inum is 18 : gc['plane_axis'] = [0,2,1] # Select XZ Plane
elif inum is 19 : gc['plane_axis'] = [1,2,0] # Select YZ Plane
elif inum is 20 : gc['inches_mode'] = True
elif inum is 21 : gc['inches_mode'] = False
elif inum in [28,30] : blk['next_action'] = 'GO_HOME'
elif inum is 53 : blk['absolute_override'] = True
elif inum is 54 : pass
elif inum is 80 : gc['motion_mode'] = 'MOTION_CANCEL'
elif inum is 90 : gc['absolute_mode'] = True
elif inum is 91 : gc['absolute_mode'] = False
elif inum is 92 : blk['next_action'] = 'SET_OFFSET'
elif inum is 93 : gc['inverse_feedrate_mode'] = True
elif inum is 94 : gc['inverse_feedrate_mode'] = False
else :
print 'Unsupported command ' + cmd + num + ' on line ' + str(l_count)
if remove_unsupported : blk['unsupported'].append(zip(g_cmd,g_num).index((cmd,num)))
elif cmd is 'M' :
if inum in [0,1] : pass # Program Pause
elif inum in [2,30,60] : pass # Program Completed
elif inum is 3 : pass # Spindle Direction 1
elif inum is 4 : pass # Spindle Direction -1
elif inum is 5 : pass # Spindle Direction 0
else :
print 'Unsupported command ' + cmd + num + ' on line ' + str(l_count)
if remove_unsupported : blk['unsupported'].append(zip(g_cmd,g_num).index((cmd,num)))
elif cmd is 'T' : pass # Tool Number
# Pass 2
for cmd,num in zip(g_cmd,g_num) :
fnum = float(num)
if cmd is 'F' : gc['feed_rate'] = unit_conv(fnum) # Feed Rate
elif cmd in ['I','J','K'] : blk['offset_ijk'][ord(cmd)-ord('I')] = unit_conv(fnum) # Arc Center Offset
elif cmd is 'N' : pass
elif cmd is 'P' : p = fnum # Misc value parameter
elif cmd is 'R' : r = unit_conv(fnum); blk['radius_mode'] = True # Arc Radius Mode
elif cmd is 'S' : pass # Spindle Speed
elif cmd in ['X','Y','Z'] : # Target Coordinates
if (gc['absolute_mode'] | blk['absolute_override']) :
blk['target_xyz'][ord(cmd)-ord('X')] = unit_conv(fnum)
else :
blk['target_xyz'][ord(cmd)-ord('X')] += unit_conv(fnum)
# Execute actions
if blk['next_action'] is 'GO_HOME' :
gc['current_xyz'] = deepcopy(blk['target_xyz']) # Update position
elif blk['next_action'] is 'SET_OFFSET' :
pass
elif blk['next_action'] is 'DWELL' :
if p < 0 : raise Exception('Dwell time negative.')
else : # 'DEFAULT'
if gc['motion_mode'] is 'SEEK' :
fout.write('0 '+fout_conv(gc['feed_rate']))
fout.write(' '+fout_conv(blk['target_xyz'][0]))
fout.write(' '+fout_conv(blk['target_xyz'][1]))
fout.write(' '+fout_conv(blk['target_xyz'][2]))
fout.write('\n')
gc['current_xyz'] = deepcopy(blk['target_xyz']) # Update position
elif gc['motion_mode'] is 'LINEAR' :
fout.write('1 '+fout_conv(gc['feed_rate']))
fout.write(' '+fout_conv(blk['target_xyz'][0]))
fout.write(' '+fout_conv(blk['target_xyz'][1]))
fout.write(' '+fout_conv(blk['target_xyz'][2]))
fout.write('\n')
gc['current_xyz'] = deepcopy(blk['target_xyz']) # Update position
elif gc['motion_mode'] in ['CW_ARC','CCW_ARC'] :
axis = gc['plane_axis']
# Convert radius mode to ijk mode
if blk['radius_mode'] :
x = blk['target_xyz'][axis[0]]-gc['current_xyz'][axis[0]]
y = blk['target_xyz'][axis[1]]-gc['current_xyz'][axis[1]]
if not (x==0 and y==0) : raise Exception('Same target and current XYZ not allowed in arc radius mode.')
h_x2_div_d = -sqrt(4 * r*r - x*x - y*y)/hypot(x,y)
if isnan(h_x2_div_d) : raise Exception('Floating point error in arc conversion')
if gc['motion_mode'] is 'CCW_ARC' : h_x2_div_d = -h_x2_div_d
if r < 0 : h_x2_div_d = -h_x2_div_d
blk['offset_ijk'][axis[0]] = (x-(y*h_x2_div_d))/2;
blk['offset_ijk'][axis[1]] = (y+(x*h_x2_div_d))/2;
else :
radius = sqrt(blk['offset_ijk'][axis[0]]**2+blk['offset_ijk'][axis[1]]**2)
center_axis0 = gc['current_xyz'][axis[0]]+blk['offset_ijk'][axis[0]]
center_axis1 = gc['current_xyz'][axis[1]]+blk['offset_ijk'][axis[1]]
linear_travel = blk['target_xyz'][axis[2]]-gc['current_xyz'][axis[2]]
r_axis0 = -blk['offset_ijk'][axis[0]]
r_axis1 = -blk['offset_ijk'][axis[1]]
rt_axis0 = blk['target_xyz'][axis[0]] - center_axis0;
rt_axis1 = blk['target_xyz'][axis[1]] - center_axis1;
clockwise_sign = 1
if gc['motion_mode'] is 'CW_ARC' : clockwise_sign = -1
angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1)
if gc['motion_mode'] is 'CW_ARC' :
if angular_travel >= 0 :
angular_travel -= 2*pi
else :
if angular_travel <= 0 :
angular_travel += 2*pi
millimeters_of_travel = sqrt((angular_travel*radius)**2 + abs(linear_travel)**2)
mm_per_arc_segment = sqrt(4*(2*radius*arc_tolerance-arc_tolerance**2))
segments = int(millimeters_of_travel/mm_per_arc_segment)
print segments
print l_count
theta_per_segment = angular_travel/segments
linear_per_segment = linear_travel/segments
cos_T = 1-0.5*theta_per_segment*theta_per_segment
sin_T = theta_per_segment-theta_per_segment**3/6
print(fout_conv(mm_per_arc_segment))
print theta_per_segment*180/pi
arc_target = [0,0,0]
arc_target[axis[2]] = gc['current_xyz'][axis[2]]
count = 0
for i in range(1,segments+1) :
if i < segments :
if count < n_arc_correction :
r_axisi = r_axis0*sin_T + r_axis1*cos_T
r_axis0 = r_axis0*cos_T - r_axis1*sin_T
r_axis1 = deepcopy(r_axisi)
count += 1
else :
cos_Ti = cos((i-1)*theta_per_segment)
sin_Ti = sin((i-1)*theta_per_segment)
print n_arc_correction*(r_axis0 -( -blk['offset_ijk'][axis[0]]*cos_Ti + blk['offset_ijk'][axis[1]]*sin_Ti))
print n_arc_correction*(r_axis1 -( -blk['offset_ijk'][axis[0]]*sin_Ti - blk['offset_ijk'][axis[1]]*cos_Ti))
cos_Ti = cos(i*theta_per_segment)
sin_Ti = sin(i*theta_per_segment)
r_axis0 = -blk['offset_ijk'][axis[0]]*cos_Ti + blk['offset_ijk'][axis[1]]*sin_Ti
r_axis1 = -blk['offset_ijk'][axis[0]]*sin_Ti - blk['offset_ijk'][axis[1]]*cos_Ti
count = 0
arc_target[axis[0]] = center_axis0 + r_axis0
arc_target[axis[1]] = center_axis1 + r_axis1
arc_target[axis[2]] += linear_per_segment
else :
arc_target = deepcopy(blk['target_xyz']) # Last segment at target_xyz
# Write only changed variables.
fout.write('1 '+fout_conv(gc['feed_rate']))
fout.write(' '+fout_conv(arc_target[0]))
fout.write(' '+fout_conv(arc_target[1]))
fout.write(' '+fout_conv(arc_target[2]))
fout.write('\n')
gc['current_xyz'] = deepcopy(arc_target) # Update position
print 'Done!'
# Close files
fin.close()
fout.close()

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +0,0 @@
(Machine settings provided by @kikigey89)
$0=87.489 (x, step/mm)
$1=87.489 (y, step/mm)
$2=1280.000 (z, step/mm)
$3=1000.000 (x max rate, mm/min)
$4=1000.000 (y max rate, mm/min)
$5=500.000 (z max rate, mm/min)
$6=10.000 (x accel, mm/sec^2)
$7=10.000 (y accel, mm/sec^2)
$8=10.000 (z accel, mm/sec^2)
$9=211.000 (x max travel, mm)
$10=335.000 (y max travel, mm)
$11=70.000 (z max travel, mm)
$12=20 (step pulse, usec)
$13=160 (step port invert mask:10100000)
$14=160 (dir port invert mask:10100000)
$15=50 (step idle delay, msec)
$16=0.010 (junction deviation, mm)
$17=0.002 (arc tolerance, mm)
$19=0 (report inches, bool)
$20=1 (auto start, bool)
$21=0 (invert step enable, bool)
$22=0 (invert limit pins, bool)
$23=0 (soft limits, bool)
$24=0 (hard limits, bool)
$25=0 (homing cycle, bool)
$26=0 (homing dir invert mask:00000000)
$27=50.000 (homing feed, mm/min)
$28=500.000 (homing seek, mm/min)
$29=10 (homing debounce, msec)
$30=3.000 (homing pull-off, mm)

View File

@ -1,25 +0,0 @@
import random
import serial
import time
ser = serial.Serial('/dev/tty.usbmodem24111', 115200, timeout=0.001)
time.sleep(1)
outstanding = 0
data = ''
while True:
time.sleep(0.1)
data += ser.read()
pos = data.find('\n')
if pos == -1:
line = ''
else:
line = data[0:pos + 1]
data = data[pos + 1:]
if line == '' and outstanding < 3:
while outstanding < 3:
ser.write("G0 Z%0.3f\n" % (0.01 * (random.random() - 0.5)))
#ser.write("M3\n")
outstanding += 1
continue
if line == 'ok\r\n':
outstanding -= 1
print outstanding, repr(line.rstrip())