Skip to content

Commit

Permalink
Fixed threading start position Z shift when changing RPM
Browse files Browse the repository at this point in the history
Fixed threading start position Z shift when changing RPM
Release 1.1g3.20211014
  • Loading branch information
HuubBuis committed Oct 14, 2021
1 parent 561cd77 commit 52802b8
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 162 deletions.
13 changes: 12 additions & 1 deletion MemorySizes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,15 @@ Global variables use 1592 bytes (77%) of dynamic memory, leaving 456 bytes for l

AFter enabling probe, implementing Lichuan servo STEP_ENABLE_DELAY and updated threading synchronisation:
Release 20211002 board version 1.6.23, IDE 1.8.15
Sketch uses 32148 bytes (99%) of program storage space. Maximum is 32256 bytes.Global variables use 1596 bytes (77%) of dynamic memory, leaving 452 bytes for local variables. Maximum is 2048 bytes.
Sketch uses 32148 bytes (99%) of program storage space. Maximum is 32256 bytes.Global variables use 1596 bytes (77%) of dynamic memory, leaving 452 bytes for local variables. Maximum is 2048 bytes.
AFter fixing spindle rpm fluctuations when a threading pass starts:
Release 20211012 board version 1.6.23, IDE 1.8.15
Sketch uses 32244 bytes (99%) of program storage space. Maximum is 32256 bytes.
Global variables use 1600 bytes (78%) of dynamic memory, leaving 448 bytes for local variables. Maximum is 2048 bytes.
Release 20211012 board version 1.8.3, IDE 1.8.16
Sketch uses 32112 bytes (99%) of program storage space. Maximum is 32256 bytes.
Global variables use 1600 bytes (78%) of dynamic memory, leaving 448 bytes for local variables. Maximum is 2048 bytes.
Release 20211014 board version 1.8.3, IDE 1.8.16
Sketch uses 32080 bytes (99%) of program storage space. Maximum is 32256 bytes.
Global variables use 1600 bytes (78%) of dynamic memory, leaving 448 bytes for local variables. Maximum is 2048 bytes.

Expand Down
113 changes: 41 additions & 72 deletions grbl/examples/SpindleSimulator/SpindleSimulator.ino
Original file line number Diff line number Diff line change
@@ -1,111 +1,80 @@
// Program to simulate a spindel for testing lathe G33 (threading)
// It generatates Low pulses as if NO NPN sensors where connected.
// When no sensors are connected, all should work
//
//

#define MinRPM 30UL // 30 RPM Speed slowest
#define MaxRPM 3000UL // 3000 RPM Speed fastest
#define MinRPM 30L // 30 RPM Speed slowest
#define MaxRPM 3000L // 3000 RPM Speed fastest

#define PotMeter A0 //Potmeter pin, must be analog, not A4 or A5 on arduino (SDA SCL)
#define MinAdc 50UL //add dead band on start
#define MaxAdc 975UL //add dead band on end
#define MinAdc 50L //add dead band on start
#define MaxAdc 975L //add dead band on end

#define PulsesPerRevolution 4UL
#define PulseLowMin 1UL
#define PulsesPerRevolution 4L
#define PulseLowMin 1L

#define IndexPin 13
#define SyncPin 12
#define PulseLevel LOW // Use LOW for Low level pulse (NO), HIGH for High level pulse (NC)

#if PulseLevel == LOW
#define NoPulseLevel HIGH
#else
#define NoPulseLevel LOW
#endif

#define IndexPin 0
#define SyncPin 2
#define LedPin 1

//#define DebugInfo
//define one of the fixed speed simulation setting or define none and use a potmeter connected to A0
//#define FixSpeed30RPM
//#define FixSpeed120RPM
//#define FixSpeed600RPM

int ReadPotmeter()
{
return analogRead(PotMeter);
}

unsigned long CalculateDelayTime(unsigned long RPM)
{
return 60000UL / (RPM * PulsesPerRevolution );
}

unsigned long MapPotToRPM(unsigned long Pot)
{
unsigned long RPM = map(Pot, MinAdc, MaxAdc, MinRPM, MaxRPM);
if (RPM < MinRPM) return MinRPM;
if (RPM > MaxRPM) return MaxRPM;
return RPM;
}

unsigned long MapRPMtoDelay(unsigned long RPM)
{
if (RPM < MinRPM) RPM = MinRPM;
if (RPM > MaxRPM) RPM = MaxRPM;
return CalculateDelayTime(RPM);
}

unsigned long MapPotToDelay(unsigned long Pot)
long ReadPotmeter()
{
if (Pot < MinAdc) Pot = MinAdc;
if (Pot > MaxAdc) Pot = MaxAdc;
return MapRPMtoDelay(MapPotToRPM(Pot));
return (long) analogRead(PotMeter);
}

void ShowInfo()
long MapPotToDelay( long Pot)
{
#ifdef DebugInfo
unsigned long ADC;
ADC = (unsigned long) ReadPotmeter();
Serial.print("ADC: "); Serial.print(ADC);
Serial.print(" RPM: "); Serial.print(MapPotToRPM(ADC));
Serial.print(" Sync Pulse Delay: "); Serial.print(MapPotToDelay(ADC));
Serial.println();
#endif
unsigned long Delay = map(Pot, 0, 1024, 499.0, 11.5); // 10 bit adc, 30 RPM to 1200 RPM, 4 index pulses
if (Delay < 11) Delay = 11; // 30 RPM
if (Delay>499) Delay=249; // 1200 RPM
return Delay;
}

void setup()
{
#ifdef DebugInfo
Serial.begin(115200);
#endif
pinMode(IndexPin, OUTPUT); // Initialize the pin as an output
pinMode(SyncPin, OUTPUT); // Initialize the pin as aput
pinMode(IndexPin, OUTPUT); // Initialize the pin as an output
pinMode(SyncPin, OUTPUT); // Initialize the pin as aput
pinMode(LedPin, OUTPUT); // Initialize the pin as aput
}

int GetPulseTime()
{
#if defined FixSpeed30RPM
return MapRPMtoDelay(30);
#elif defined FixSpeed120RPM
return MapRPMtoDelay(120);
#elif defined FixSpeed600RPM
return MapRPMToDelay(600);
#else
return MapPotToDelay(ReadPotmeter());
#endif
}

void loop()
{
int PulseTime;
int PulseLow;
int PulseHigh;
long PulseTime;
for (;;)
{
PulseTime = GetPulseTime();
for (int i = 0; i < PulsesPerRevolution; i++)
{
PulseTime = GetPulseTime();
PulseTime -= PulseLowMin;
if (i == 0) digitalWrite(IndexPin, LOW); // Turn the index pin high on the first sync pulse
else digitalWrite(IndexPin, HIGH); // Turn the index pin low on all other sync pulses
digitalWrite(SyncPin, LOW); // Turn the sync pin high
delay(PulseLowMin); // Wait for the pulse high time
digitalWrite(SyncPin, HIGH); // Turn the sync pin Low
digitalWrite(IndexPin, HIGH); // Turn the index pin Low
delay(PulseTime); // Wait for the pulse low time
if (i == 0)
{
digitalWrite(IndexPin, PulseLevel); // Set pulse level on the first sync pulse
digitalWrite(LedPin, HIGH); // Set the led pin high
}
digitalWrite(SyncPin, PulseLevel); // Turn the sync pin high
delay(PulseLowMin); // Wait for the pulse high time
digitalWrite(SyncPin, NoPulseLevel); // Turn the sync pin Low
digitalWrite(IndexPin, NoPulseLevel); // Turn the index pin Low
digitalWrite(LedPin, LOW); // Turn the index pin Low
delay(PulseTime); // Wait for the pulse low time
}
#ifdef DebugInfo
ShowInfo();
Expand Down
29 changes: 15 additions & 14 deletions grbl/gcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,6 @@ uint8_t gc_execute_line(char *line)
system_flag_wco_change();
break;
}

// [20. Motion modes ]:
// NOTE: Commands G10,G28,G30,G92 lock out and prevent axis words from use in motion modes.
// Enter motion modes only if there are axis words or a motion mode command word in the block.
Expand All @@ -1064,28 +1063,30 @@ uint8_t gc_execute_line(char *line)
threading_init(gc_block.values.ijk[Z_AXIS]); //initialize a threading pass, all counters are cleared, check on index pulses timeout can be done
pl_data->condition |= (PL_COND_FLAG_FEED_PER_REV | PL_COND_FLAG_NO_FEED_OVERRIDE); //During threading (G33) no feed override. Set condition to allow updating the feed rate at every sync pulse
while (threading_index_pulse_count<SPINDLE_INDEX_PULSES_BEFORE_START_G33){
if (get_timer_ticks()>(uint32_t)((TIMER_TICS_PER_MINUTE*SPINDLE_INDEX_PULSES_BEFORE_START_G33)/MINIMAL_SPINDLE_SPEED_G33)){ // Check if the spindle pulses are fast enough
if (get_timer_ticks_passed()>(uint32_t)((TIMER_TICS_PER_MINUTE*SPINDLE_INDEX_PULSES_BEFORE_START_G33)/MINIMAL_SPINDLE_SPEED_G33)){ // Check if the spindle pulses are fast enough
FAIL(STATUS_INDEX_PULSE_TIMEOUT);
}
protocol_exec_rt_system(); //process real time commands until the spindle has made enough revolutions or a timeout occurs
}
if (settings.sync_pulses_per_revolution>1) { //There are synchronization pulses so also waiting for the next synchronization pulse
threading_sync_pulse_count=0;
while (threading_sync_pulse_count==0){
if (get_timer_ticks()>((TIMER_TICS_PER_MINUTE*(SPINDLE_INDEX_PULSES_BEFORE_START_G33+1L))/MINIMAL_SPINDLE_SPEED_G33)) //Check if the sync pulses are fast enough
FAIL(STATUS_SYNCHRONIZATION_PULSE_TIMEOUT);
protocol_exec_rt_system(); //process real time commands until the spindle has made enough revolutions or a timeout occurs
}
threading_sync_pulse_count=0;
while (threading_sync_pulse_count==0){
if (get_timer_ticks_passed()>((TIMER_TICS_PER_MINUTE*(SPINDLE_INDEX_PULSES_BEFORE_START_G33+1L))/MINIMAL_SPINDLE_SPEED_G33)) //Check if the sync pulses are fast enough
FAIL(STATUS_SYNCHRONIZATION_PULSE_TIMEOUT);
protocol_exec_rt_system(); //process real time commands until the spindle has made enough revolutions or a timeout occurs
}
}
pl_data->feed_rate=gc_block.values.ijk[Z_AXIS] * threading_index_spindle_speed; //set the start feed rate
mc_line(gc_block.values.xyz, pl_data); //execute the motion
} else if (gc_state.modal.motion == MOTION_MODE_SEEK) {
pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag.
threading_sync_pulse_count=0; // This is the start C position for spindle synchronization, even if threading is not started yet. The next line will add the threading distance to this target
threading_step_pulse_count=0; // This is the start Z position
pl_data->feed_rate=gc_block.values.ijk[Z_AXIS] * spindle_rpm; // Set the start feed rate
mc_line(gc_block.values.xyz, pl_data); // Execute the motion
} else if (gc_state.modal.motion == MOTION_MODE_SEEK) {
pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag.
mc_line(gc_block.values.xyz, pl_data);
} else if ((gc_state.modal.motion == MOTION_MODE_CW_ARC) || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
} else if ((gc_state.modal.motion == MOTION_MODE_CW_ARC) || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
mc_arc(gc_block.values.xyz, pl_data, gc_state.position, gc_block.values.ijk, gc_block.values.r,
axis_0, axis_1, axis_linear, bit_istrue(gc_parser_flags,GC_PARSER_ARC_IS_CLOCKWISE));
} else {
} else {
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
// upon a successful probing cycle, the machine position and the returned value should be the same.
#ifndef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
Expand Down
2 changes: 1 addition & 1 deletion grbl/grbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

// Grbl versioning system
#define GRBL_VERSION "1.1g3"
#define GRBL_VERSION_BUILD "20211002"
#define GRBL_VERSION_BUILD "20211014"

// Define standard libraries used by Grbl.
#include <util/atomic.h>
Expand Down
2 changes: 1 addition & 1 deletion grbl/limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void process_limit_pin_change_event()
if (sys.state != STATE_ALARM) {
if (!(sys_rt_exec_alarm)) {
if (index_pulse_active()) { // This is the lathe version, Y-axis limit pin hits are spindle index pulses so handle them and do not reset controller
system_set_threading_exec_flag(EXEC_SPINDLE_INDEX_PULSE); // pin is index pulse
process_spindle_index_pulse();
}
else
if (limits_get_state(LIMIT_MASK_ALL_EXCEPT_Y_AXIS)) { // handle all axis except the y-axis
Expand Down
27 changes: 15 additions & 12 deletions grbl/planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,20 @@ float plan_compute_profile_nominal_speed(plan_block_t *block)
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { nominal_speed *= (0.01*sys.r_override); }
else
if (block->condition & PL_COND_FLAG_FEED_PER_REV) { // SPINDLE_SYNC
if bit_istrue(threading_exec_flags, EXEC_PLANNER_SYNC_PULSE) { // there was a synchronization pulse so calculate the feed rate to be at the right position at the next spindle pulse
system_clear_threading_exec_flag(EXEC_PLANNER_SYNC_PULSE); // clear the bit to avoid processing again.
threading_millimeters_target-=threading_mm_per_synchronization_pulse; // calculate the new target
synchronization_millimeters_error=threading_millimeters_target-block->millimeters; // calculate the position error. Note that block->millimeters counts down This has to be compensated at the next spindle pulse
block->programmed_rate=(threading_mm_per_index_pulse-synchronization_millimeters_error) / (((float) threading_sync_timer_tics_passed ) / threading_feed_rate_calculation_factor); //calculate the new feed rate to reduce the error.
if (block->programmed_rate>block->rapid_rate) // limit speed to max-rate set for this block
block->programmed_rate=block->rapid_rate;
if bit_istrue(threading_exec_flags, EXEC_PLANNER_SYNC_PULSE) { // there was a synchronization pulse so calculate the feed rate to be at the right position at the next spindle pulse
system_clear_threading_exec_flag(EXEC_PLANNER_SYNC_PULSE); // clear the bit to avoid processing again.

float spindle_position=((float) threading_sync_pulse_count)*threading_mm_per_synchronization_pulse; // The actual position of the spindle expressed as z position.

int32_t step_count;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE){step_count=threading_step_pulse_count;} // Block updating the counter by the stepper interrupt while reading
float z_position=((float)step_count)/settings.steps_per_mm[Z_AXIS];// Calculate the actual position based on the step pulses done and the total feed for this thread pass

threading_synchronization_millimeters_error=z_position-spindle_position; // calculate the position error.

block->programmed_rate=(threading_mm_per_index_pulse-threading_synchronization_millimeters_error) / (((float) threading_sync_timer_tics_passed ) / threading_feed_rate_calculation_factor); //calculate the new feed rate to reduce the error.
if (block->programmed_rate>block->rapid_rate) // limit speed to max-rate set for this block
block->programmed_rate=block->rapid_rate;
}
} else {
if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) { nominal_speed *= (0.01*sys.f_override); }
Expand Down Expand Up @@ -397,7 +404,7 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
block->millimeters = convert_delta_vector_to_unit_vector(unit_vec);
block->acceleration = limit_value_by_axis_maximum(settings.acceleration, unit_vec);
block->rapid_rate = limit_value_by_axis_maximum(settings.max_rate, unit_vec);

// Store programmed rate.
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { block->programmed_rate = block->rapid_rate; }
else {
Expand Down Expand Up @@ -478,10 +485,6 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
// Finish up by recalculating the plan with the new block.
planner_recalculate();
}
//In feed per revolution mode set the global threading mm value. This value is defined global to save memory
if ((block->condition & PL_COND_FLAG_FEED_PER_REV)) {
threading_millimeters_target=block->millimeters;
}
return(PLAN_OK);
}

Expand Down
23 changes: 10 additions & 13 deletions grbl/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,30 +245,27 @@ void protocol_exec_rt_system()
//processing spindle index and synchronization pulses. Is done immediately after processing of the alarm to be as accurate as possible
//depending on settings, reports are triggered.
if (bit_istrue(threading_exec_flags, EXEC_SPINDLE_INDEX_PULSE)) { //process the detection of a spindle index pulse;
if (settings.sync_pulses_per_revolution>0) { // If index pulses are enabled.
if (index_pulse_active()){ // Check again to filter out some high frequentie false triggers
process_spindle_index_pulse(); // Process the pulse so the RPM will be updated in the real time status report
if (spindle_synchronization_active()) { // if spindle synchronization is active
if bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_SYNC_STATE){ // if setting report mask is set for reporting the synchronization status in the real time status report
system_set_threading_exec_flag((EXEC_SYNCHRONIZATION_STATE_REPORT)); // set the reporting flags to report the synchronization status now and once when finished
if (settings.sync_pulses_per_revolution>0) { // If index pulses are enabled.
if (index_pulse_active()){ // Check again to filter out some high frequentie false triggers
calculate_spindle_rpm(); // Calculate the spindle RPM, the rest is done in irq time
if (spindle_synchronization_active()) { // if spindle synchronization is active
if bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_SYNC_STATE){ // if setting report mask is set for reporting the synchronization status in the real time status report
system_set_threading_exec_flag((EXEC_SYNCHRONIZATION_STATE_REPORT)); // set the reporting flags to report the synchronization status now and once when finished
}
if bit_istrue(settings.status_report_mask,BITFLAG_FEED_BACK_SYNC_STATUS){ // if setting report mask is set for synchronization error feedback
system_set_threading_exec_flag((EXEC_SYNCHRONIZATION_STATE_FEEDBACK_ERROR)); // set the reporting flags to feedback the synchronization error
if bit_istrue(settings.status_report_mask,BITFLAG_FEED_BACK_SYNC_STATUS){ // if setting report mask is set for synchronization error feedback
system_set_threading_exec_flag((EXEC_SYNCHRONIZATION_STATE_FEEDBACK_ERROR)); // set the reporting flags to feedback the synchronization error
}
}
if (settings.sync_pulses_per_revolution==1) { // Just an index pulse, emulate the receive of a sync pulse.
system_set_threading_exec_flag(EXEC_PLANNER_SYNC_PULSE); // emulate the receive of a synchronization pulse if there is only an index pulse, eliminates wiring if the is just a index pulse
process_spindle_synchronization_pulse(); // emulate the receive of a synchronization pulse if there is only an index pulse, eliminates wiring if the is just a index pulse
}
}
}
system_clear_threading_exec_flag(EXEC_SPINDLE_INDEX_PULSE); // Bit is cleared at the end of processing to reduce false triggers,
}
if (bit_istrue(threading_exec_flags, EXEC_PLANNER_SYNC_PULSE)) { // if a sync pulse was detected;
if (sync_pulse_active()){ // if the sync pulse is still active, filter out some high frequency noise
process_spindle_synchronization_pulse(); // Synchronization pulse has to be counted before G33 becomes active
if (spindle_synchronization_active()) {update_planner_feed_rate();} // if spindle synchronization is active, update the planner to synchronize spindle
system_clear_threading_exec_flag(EXEC_PLANNER_SYNC_PULSE);
}
system_clear_threading_exec_flag(EXEC_PLANNER_SYNC_PULSE);
}
if (bit_istrue(threading_exec_flags,EXEC_SYNCHRONIZATION_STATE_FEEDBACK_ERROR)){
report_synchronization_error_feedback();
Expand Down
Loading

0 comments on commit 52802b8

Please sign in to comment.