KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Moderators: TomKerekes, dynomotion
-
griffinboyle
- Posts: 10
- Joined: Sun Apr 07, 2024 11:15 pm
- Location: Boston
KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
I am currently using a Kogna and Kstep together to operate a metal-additive 3D-printer which utilizes electric arc plasma for a drop-on-demand process. Suffice it to say, this produces a good deal of EMI.
Separate to this, I have noticed at least 4 or 5 times now - definitely on the Kogna, and I believe also near the end of using the KFLOP (before switching to the Kogna) - on occasion, a discrete shift in Y (thus far exclusively in the negative-Y direction, and on the order of 1mm) appears at a random point in the print. Using Wireshark to sniff the dedicated ethernet pot I do notice TCP duplicate ACK packets fairly often when arcing, I guess indicating packet retransmission (?), and also window resizing events occurring fairly often (should I reduce lookahead, socket buffer size, something in the NIC settings?). I know these are fairly normal and handled gracefully by TCP but is it possible that one of these is responsible for this strange and seemingly unrepeatable behavior? Machine coordinates and GCODE interpreter coordinates do not reflect this shift in any way. I assume it isn't hardware related since then I would expect to see a more gradual shift or at least a shift on all axes seeing as they are all carried along the same ethernet cable through the RJ45 connectors from Kogna to KSTEP (which are isolated from one another using the isolation jumpers) - though just in case I've swapped the X and Y axis to see if it persists on the Y axis or instead occurs on the X axis the next time it appears.
Do you have any ideas for the possible source of this issue, or at least some additional troubleshooting ideas? I'm kind of at a loss...
Thank you so much for any help you can provide - big fan of the Dynomotion products!
Best,
Griffin Boyle
Separate to this, I have noticed at least 4 or 5 times now - definitely on the Kogna, and I believe also near the end of using the KFLOP (before switching to the Kogna) - on occasion, a discrete shift in Y (thus far exclusively in the negative-Y direction, and on the order of 1mm) appears at a random point in the print. Using Wireshark to sniff the dedicated ethernet pot I do notice TCP duplicate ACK packets fairly often when arcing, I guess indicating packet retransmission (?), and also window resizing events occurring fairly often (should I reduce lookahead, socket buffer size, something in the NIC settings?). I know these are fairly normal and handled gracefully by TCP but is it possible that one of these is responsible for this strange and seemingly unrepeatable behavior? Machine coordinates and GCODE interpreter coordinates do not reflect this shift in any way. I assume it isn't hardware related since then I would expect to see a more gradual shift or at least a shift on all axes seeing as they are all carried along the same ethernet cable through the RJ45 connectors from Kogna to KSTEP (which are isolated from one another using the isolation jumpers) - though just in case I've swapped the X and Y axis to see if it persists on the Y axis or instead occurs on the X axis the next time it appears.
Do you have any ideas for the possible source of this issue, or at least some additional troubleshooting ideas? I'm kind of at a loss...
Thank you so much for any help you can provide - big fan of the Dynomotion products!
Best,
Griffin Boyle
Last edited by griffinboyle on Fri Oct 03, 2025 12:57 am, edited 1 time in total.
- TomKerekes
- Posts: 2868
- Joined: Mon Dec 04, 2017 1:49 am
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Griffin,
What type of motor drives do you have? Steppers? Servos? Do you have encoders?
What is the resolution of the axes? How many counts or steps would 1mm be?
What Version of software are you using?
Can you post your Initialization C Program?
I would expect a communication issue to result in a communication error and not a shift in position without other errors. The position commands sent over the communication link are absolute positions.
What type of motor drives do you have? Steppers? Servos? Do you have encoders?
What is the resolution of the axes? How many counts or steps would 1mm be?
What Version of software are you using?
Can you post your Initialization C Program?
I would expect a communication issue to result in a communication error and not a shift in position without other errors. The position commands sent over the communication link are absolute positions.
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
-
griffinboyle
- Posts: 10
- Joined: Sun Apr 07, 2024 11:15 pm
- Location: Boston
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Tom,
Thanks for the speedy response! I'm driving a total of four stepper motors from the KSTEP, three of which are responsible for operating an XYZ motion stage and are used to defined the coordinate system (the fourth stepper is used for separate independent motion not driven by GCODE). I currently do not have any encoders on the stage, though I'm in the process of designing a mounting bracket to use one for tuning and diagnostics (though I'm hoping to remain open loop if possible to reduce cost, also the stage is custom-milled and does not have the space for 3 encoders as is).
The resolution of all three of these axes is 3200 counts/mm, and all of the steppers are 400 steps/rev.
I am currently using the latest version of the software available KMotion5.4.0
I don't explicitly have an Initialization C program anymore, instead I use a single state-full multi-file program which runs continuously in thread 1. The code includes a light abstraction layer I wrote, is compiled externally from KMotion and then downloaded through KMotion, and relies on a combination python and Makefile build system I've been developing which converts custom JSON configuration files to pre-defined symbols passed to the compiler when building. Assuming that you're most interested in the initialization of the axes, here is an excerpt from my motion_stage.c file which contains the initialization of the channel structures:
And here is an excerpt from JSON file used to produce the defines, to give you an idea of the values used:
Please let me know if you'd like more information or insight into the C code - it's spread across many files so I figure excerpts are preferred. I appreciate all your help!
Thanks,
Griffin Boyle
Thanks for the speedy response! I'm driving a total of four stepper motors from the KSTEP, three of which are responsible for operating an XYZ motion stage and are used to defined the coordinate system (the fourth stepper is used for separate independent motion not driven by GCODE). I currently do not have any encoders on the stage, though I'm in the process of designing a mounting bracket to use one for tuning and diagnostics (though I'm hoping to remain open loop if possible to reduce cost, also the stage is custom-milled and does not have the space for 3 encoders as is).
The resolution of all three of these axes is 3200 counts/mm, and all of the steppers are 400 steps/rev.
I am currently using the latest version of the software available KMotion5.4.0
I don't explicitly have an Initialization C program anymore, instead I use a single state-full multi-file program which runs continuously in thread 1. The code includes a light abstraction layer I wrote, is compiled externally from KMotion and then downloaded through KMotion, and relies on a combination python and Makefile build system I've been developing which converts custom JSON configuration files to pre-defined symbols passed to the compiler when building. Assuming that you're most interested in the initialization of the axes, here is an excerpt from my motion_stage.c file which contains the initialization of the channel structures:
Code: Select all
/***********************/
/* Motion Stage X-Axis */
/***********************/
INST_IO(x_axis_negative_limit_pin, MOTION_STAGE_X_AXIS_LIMIT_SWITCH_NEGATIVE_LIMIT_BIT, IO_INPUT, MOTION_STAGE_X_AXIS_LIMIT_SWITCH_NEGATIVE_LIMIT_POLARITY, LOW);
INST_IO(x_axis_positive_limit_pin, MOTION_STAGE_X_AXIS_LIMIT_SWITCH_POSITIVE_LIMIT_BIT, IO_INPUT, MOTION_STAGE_X_AXIS_LIMIT_SWITCH_POSITIVE_LIMIT_POLARITY, LOW);
static const motion_stage_axis_config_t x_axis_config = {
.axis = AXIS_FROM_CHANNEL_NUM(X_AXIS_CHAN_NUM),
.max_velocity = MOTION_STAGE_X_AXIS_MAX_VELOCITY,
.max_acceleration = MOTION_STAGE_X_AXIS_MAX_ACCELERATION,
.max_jerk = MOTION_STAGE_X_AXIS_MAX_JERK,
.output_channel = MOTION_STAGE_X_AXIS_OUTPUT_CHANNEL,
.inverted = MOTION_STAGE_X_AXIS_INVERTED,
.negative_limit_bit = &x_axis_negative_limit_pin,
.positive_limit_bit = &x_axis_positive_limit_pin,
.soft_limit_neg = MOTION_STAGE_X_AXIS_SOFT_LIMIT_NEGATIVE * MOTION_STAGE_X_AXIS_COUNTS_PER_MM,
.soft_limit_pos = MOTION_STAGE_X_AXIS_SOFT_LIMIT_POSITIVE * MOTION_STAGE_X_AXIS_COUNTS_PER_MM,
.limit_switch_options = &x_axis_limit_switch_options,
.oversample = 4,
};
static motion_stage_axis_context_t x_axis_context = {0};
static motion_stage_axis_t x_axis = {
.config = &x_axis_config,
.context = &x_axis_context,
};
/***********************/
/* Motion Stage Y-Axis */
/***********************/
INST_IO(y_axis_negative_limit_pin, MOTION_STAGE_Y_AXIS_LIMIT_SWITCH_NEGATIVE_LIMIT_BIT, IO_INPUT, MOTION_STAGE_Y_AXIS_LIMIT_SWITCH_NEGATIVE_LIMIT_POLARITY, LOW);
INST_IO(y_axis_positive_limit_pin, MOTION_STAGE_Y_AXIS_LIMIT_SWITCH_POSITIVE_LIMIT_BIT, IO_INPUT, MOTION_STAGE_Y_AXIS_LIMIT_SWITCH_POSITIVE_LIMIT_POLARITY, LOW);
static const motion_stage_axis_config_t y_axis_config = {
.axis = AXIS_FROM_CHANNEL_NUM(Y_AXIS_CHAN_NUM),
.max_velocity = MOTION_STAGE_Y_AXIS_MAX_VELOCITY,
.max_acceleration = MOTION_STAGE_Y_AXIS_MAX_ACCELERATION,
.max_jerk = MOTION_STAGE_Y_AXIS_MAX_JERK,
.output_channel = MOTION_STAGE_Y_AXIS_OUTPUT_CHANNEL,
.inverted = MOTION_STAGE_Y_AXIS_INVERTED,
.negative_limit_bit = &y_axis_negative_limit_pin,
.positive_limit_bit = &y_axis_positive_limit_pin,
.soft_limit_neg = MOTION_STAGE_Y_AXIS_SOFT_LIMIT_NEGATIVE * MOTION_STAGE_Y_AXIS_COUNTS_PER_MM,
.soft_limit_pos = MOTION_STAGE_Y_AXIS_SOFT_LIMIT_POSITIVE * MOTION_STAGE_Y_AXIS_COUNTS_PER_MM,
.limit_switch_options = &y_axis_limit_switch_options,
.oversample = 4,
};
static motion_stage_axis_context_t y_axis_context = {0};
static motion_stage_axis_t y_axis = {
.config = &y_axis_config,
.context = &y_axis_context,
};
/***********************/
/* Motion Stage Z-Axis */
/***********************/
INST_IO(z_axis_negative_limit_pin, MOTION_STAGE_Z_AXIS_LIMIT_SWITCH_NEGATIVE_LIMIT_BIT, IO_INPUT, MOTION_STAGE_Z_AXIS_LIMIT_SWITCH_NEGATIVE_LIMIT_POLARITY, LOW);
INST_IO(z_axis_positive_limit_pin, MOTION_STAGE_Z_AXIS_LIMIT_SWITCH_POSITIVE_LIMIT_BIT, IO_INPUT, MOTION_STAGE_Z_AXIS_LIMIT_SWITCH_POSITIVE_LIMIT_POLARITY, LOW);
static const motion_stage_axis_config_t z_axis_config = {
.axis = AXIS_FROM_CHANNEL_NUM(Z_AXIS_CHAN_NUM),
.max_velocity = MOTION_STAGE_Z_AXIS_MAX_VELOCITY,
.max_acceleration = MOTION_STAGE_Z_AXIS_MAX_ACCELERATION,
.max_jerk = MOTION_STAGE_Z_AXIS_MAX_JERK,
.output_channel = MOTION_STAGE_Z_AXIS_OUTPUT_CHANNEL,
.inverted = MOTION_STAGE_Z_AXIS_INVERTED,
.negative_limit_bit = &z_axis_negative_limit_pin,
.positive_limit_bit = &z_axis_positive_limit_pin,
.soft_limit_neg = MOTION_STAGE_Z_AXIS_SOFT_LIMIT_NEGATIVE * MOTION_STAGE_Z_AXIS_COUNTS_PER_MM,
.soft_limit_pos = MOTION_STAGE_Z_AXIS_SOFT_LIMIT_POSITIVE * MOTION_STAGE_Z_AXIS_COUNTS_PER_MM,
.limit_switch_options = &z_axis_limit_switch_options,
.oversample = 4,
};
static motion_stage_axis_context_t z_axis_context = {0};
static motion_stage_axis_t z_axis = {
.config = &z_axis_config,
.context = &z_axis_context,
};
/****************/
/* Motion Stage */
/****************/
static const motion_stage_config_t motion_stage_config = {
.axis.x_axis = &x_axis,
.axis.y_axis = &y_axis,
.axis.z_axis = &z_axis,
};
static motion_stage_context_t motion_stage_context = {0};
static const motion_stage_t motion_stage_inst = {
.config = &motion_stage_config,
.context = &motion_stage_context,
};
const motion_stage_t *const motion_stage = &motion_stage_inst;
/** @addtogroup Motion_Stage_Initialization
* @{
*/
static void initialize_motion_stage_axis(motion_stage_axis_t *motion_stage_axis) {
const motion_stage_axis_config_t *config = motion_stage_axis->config;
motion_stage_axis_context_t *context = motion_stage_axis->context;
CHAN *const axis = config->axis;
BOOL use_negative_limit = FALSE;
BOOL use_positive_limit = FALSE;
int ret;
if (io_get_bit(config->negative_limit_bit) != -1) {
ret = io_initialize(config->negative_limit_bit);
if (ret != 0) {
LOG_ERR("Failed to initialize Motion Stage Axis - Error initializing negative limit: %s", io_error_to_str[ret]);
return;
}
use_negative_limit = TRUE;
}
if (io_get_bit(config->positive_limit_bit) != -1) {
ret = io_initialize(config->positive_limit_bit);
if (ret != 0) {
LOG_ERR("Failed to initialize Motion Stage Axis - Error initializing positive limit: %s", io_error_to_str[ret]);
return;
}
use_positive_limit = TRUE;
}
axis->InputMode = NO_INPUT_MODE;
axis->OutputMode = STEP_DIR_MODE;
axis->Vel = config->max_velocity;
axis->Accel = config->max_acceleration;
axis->Jerk = config->max_jerk;
axis->P = 0;
axis->I = 0;
axis->D = 0;
axis->FFAccel = 0;
axis->FFVel = 0;
axis->MaxI = 200;
axis->MaxErr = 1e+006;
axis->MaxOutput = 200;
axis->DeadBandGain = 1;
axis->DeadBandRange = 0;
axis->InputChan0 = 0;
axis->InputChan1 = 0;
axis->OutputChan0 = config->output_channel;
axis->OutputChan1 = 0;
axis->MasterAxis = -1;
if (use_negative_limit) {
axis->LimitSwitchNegBit = io_get_bit(config->negative_limit_bit);
} else {
axis->LimitSwitchNegBit = 0;
}
if (use_positive_limit) {
axis->LimitSwitchPosBit = io_get_bit(config->positive_limit_bit);
} else {
axis->LimitSwitchPosBit = 0;
}
axis->LimitSwitchOptions = config->limit_switch_options->as_int;
axis->SoftLimitPos = config->soft_limit_pos;
axis->SoftLimitNeg = config->soft_limit_neg;
axis->InputGain0 = 0;
axis->InputGain1 = 0;
axis->InputOffset0 = 0;
axis->InputOffset1 = 0;
axis->OutputGain = 1.0 - (2.0 * config->inverted);
axis->OutputOffset = 0;
axis->SlaveGain = 1;
axis->BacklashMode = BACKLASH_OFF;
axis->BacklashAmount = 0;
axis->BacklashRate = 0;
axis->invDistPerCycle = 1;
axis->Lead = 0;
axis->MaxFollowingError = 1000000000;
axis->StepperAmplitude = 255;
axis->iir[0].B0 = 0;
axis->iir[0].B1 = 0;
axis->iir[0].B2 = 0;
axis->iir[0].A1 = 0;
axis->iir[0].A2 = 0;
axis->iir[1].B0 = 0;
axis->iir[1].B1 = 0;
axis->iir[1].B2 = 0;
axis->iir[1].A1 = 0;
axis->iir[1].A2 = 0;
axis->iir[2].B0 = 0;
axis->iir[2].B1 = 0;
axis->iir[2].B2 = 0;
axis->iir[2].A1 = 0;
axis->iir[2].A2 = 0;
context->enabled = &axis->Enable;
context->position = &axis->Position;
context->destination = &axis->Dest;
context->oversample_idx = 0;
context->home_step = HOME_STEP_IDLE;
context->svc_prev_state = FALSE;
context->svc_state = FALSE;
context->svc_consec_on = 0;
context->svc_consec_off = 0;
context->initialized = TRUE;
}
void motion_stage_initialize(const motion_stage_t *const motion_stage) {
const motion_stage_config_t *config = motion_stage->config;
motion_stage_context_t *context = motion_stage->context;
/* Initialize each axis */
int i;
for (i = 0; i < (int)(sizeof(config->axes) / sizeof(motion_stage_axis_t *)); i++) {
motion_stage_axis_t *axis = config->axes[i];
initialize_motion_stage_axis(axis);
context->p.positions[i] = axis->context->position;
context->d.destinations[i] = axis->context->destination;
}
/* Define coordinate system based on axis channels */
DefineCoordSystem(X_AXIS_CHAN_NUM, Y_AXIS_CHAN_NUM, Z_AXIS_CHAN_NUM, -1);
context->initialized = TRUE;
context->enabled = FALSE;
#if MOTION_STAGE_DEBUG
// Initialize debug statistics on startup
motion_stage_debug_reset_stats();
#endif
}
Code: Select all
{
"Motion Stage": {
"Enabled": true,
"Debug": false,
"X Axis": {
"Enabled": true,
"Inverted": false,
"Output Channel": 13,
"Max Velocity": 9000,
"Max Acceleration": 7000,
"Max Jerk": 7e+6,
"Home Offset": 32.604,
"Counts per mm": 3200.0,
"Limit Switch": {
"Enabled": true,
"Negative Limit": {
"Enabled": true,
"Polarity": "LIMIT_SWITCH_ACTIVE_LOW",
"Bit": 5
},
"Positive Limit": {
"Enabled": false
},
"Action": "LIMIT_SWITCH_STOP_MOVEMENT"
},
"Soft Limit": {
"Positive": 20.620,
"Negative": -32.604
}
},
"Y Axis": {
"Enabled": true,
"Inverted": false,
"Output Channel": 14,
"Max Velocity": 9000,
"Max Acceleration": 7000,
"Max Jerk": 7e+6,
"Home Offset": 26.993,
"Counts per mm": 3200.0,
"Limit Switch": {
"Enabled": true,
"Negative Limit": {
"Enabled": true,
"Polarity": "LIMIT_SWITCH_ACTIVE_LOW",
"Bit": 8
},
"Positive Limit": {
"Enabled": false
},
"Action": "LIMIT_SWITCH_STOP_MOVEMENT"
},
"Soft Limit": {
"Positive": 29.075,
"Negative": -26.993
}
},
"Z Axis": {
"Enabled": true,
"Inverted": true,
"Output Channel": 15,
"Max Velocity": 9000,
"Max Acceleration": 7000,
"Max Jerk": 7e+6,
"Home Offset": 14.5,
"Counts per mm": 3200.0,
"Limit Switch": {
"Enabled": true,
"Negative Limit": {
"Enabled": true,
"Polarity": "LIMIT_SWITCH_ACTIVE_LOW",
"Bit": 13
},
"Positive Limit": {
"Enabled": false
},
"Action": "LIMIT_SWITCH_STOP_MOVEMENT"
},
"Soft Limit": {
"Positive": 39.533,
"Negative": -14.5
}
},
"Home": {
"Velocity": {
"Slow": 25,
"Fast": 1750
}
}
}
}
Thanks,
Griffin Boyle
- TomKerekes
- Posts: 2868
- Joined: Mon Dec 04, 2017 1:49 am
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Griffin,
3200 steps/mm seems very high is there a reason for such high resolution. Not that there is a problem just trying to understand the system.
The max Velocity is 9000. Is that steps/sec or mm/sec? One seems very slow the other very fast.
Not sure why you think a mechanical problem would be gradual. A common problem with steppers if their torque is exceeded or commanded to move too fast is they stall. They basically just vibrate instead of moving similar to a gear skipping cogs. After a stall the position will be off by a multiple of motor poles or 4 full motor steps or 1/100 of a revolution in your case.
To check for a software bug that is commanding the motor to move too fast or instantly you might run a monitor diagnostic program in a separate Thread to check for too large of a change in the Y axis Dest.
My understanding of the symptom is a 1mm instant shift in the -Y direction that occurs at random times? After the shift occurs the position is permanently off and commanding to some known machine position will be physically off. Re-homing would be required to correct it.
3200 steps/mm seems very high is there a reason for such high resolution. Not that there is a problem just trying to understand the system.
The max Velocity is 9000. Is that steps/sec or mm/sec? One seems very slow the other very fast.
Not sure why you think a mechanical problem would be gradual. A common problem with steppers if their torque is exceeded or commanded to move too fast is they stall. They basically just vibrate instead of moving similar to a gear skipping cogs. After a stall the position will be off by a multiple of motor poles or 4 full motor steps or 1/100 of a revolution in your case.
To check for a software bug that is commanding the motor to move too fast or instantly you might run a monitor diagnostic program in a separate Thread to check for too large of a change in the Y axis Dest.
My understanding of the symptom is a 1mm instant shift in the -Y direction that occurs at random times? After the shift occurs the position is permanently off and commanding to some known machine position will be physically off. Re-homing would be required to correct it.
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
-
griffinboyle
- Posts: 10
- Joined: Sun Apr 07, 2024 11:15 pm
- Location: Boston
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Tom,
We require high resolution for our motion stage because the molten metal droplets we are depositing are ~250um in diameter, and small subdivision of this allow us to achieve - among other things - precise overhang angles. The max velocity provided by the JSON file is currently still in steps/sec (planning to convert to SI units in the near future) - that being said these values are currently only used by my homing routine (which uses MoveXYZABC() to move to the center of the build plate after homing completes), as all of our GCODE currently uses G1 commands (and thus uses the trajectory planner values, which I've provided below for more context).
Trajectory Planner
Break Angle: 90 Degrees
Look ahead: 4 seconds
Collinear Tolerance: 0mm
Corner Tolerance: 0.0254mm
Arcs to Segments: False
Facet Angle: 1 Degrees
Axis Parameters (same for X, Y, and Z)
Counts/mm: 3200
Vel mm/sec: 50.8
Accel mm/sec^2: 254
What I had meant by a hardware-related issue resulting in gradual drift was not so much the mechanical side but the electrical size - I figured that if noise was coupling to the step/dir lines being carried from the Kogna to the KSTEP through the RJ45 connector causing extra or lost steps, it would more likely appear as gradual drift across all axes, not so much a large batch of lost or added steps that appear discretely and seemingly exclusive to one axis (unless it happened to be PCB layout quirk specific to the third KSTEP axis making it more susceptible to this particular range of RF - which, now that I've switched the X and Y axis output channels, would explain the behavior if I then see the shift occur on the X axis instead of the Y axis, but this remains to be seen).
I'm less inclined to expect this to be a mechanical issue since the X axis experience the largest load, followed by the Y axis, followed by the Z axis - were this a mechanical/kinematic issue I would think that it would manifest on the X axis not the Y axis, especially given that they are currently provided with identical axis parameters.
Do you think that I would expect to see this bug in the offending axis's Dest member, seeing as how the machine coordinates do not reflect this shift? I've been operating under the assumption that machine coordinates are derived from the status update's reported axis Dest member divided by Counts/mm, in which case I would assume that the shift would not be reflected there?
Your understanding is pretty much correct - though the actual shift wasn't exactly 1mm, it was more like 0.8mm. We are currently driving the stage a good bit below it's maximum performance in an attempt to ensure reliable open-loop operation, with the intention of tuning this with an encoder in the near future to improve print speed. Thus far this appears to be exclusive to the -Y direction and occurs at random times (in particular, it seems, during simultaneous GCODE and arcing), and the shift persists permanently such that commanding to some known machine position will be physically off.
On a slightly tangential note, I had a question about buffered IO with MCODEs between G1 commands. Our GCODE generally looks something like this:
I noticed that the Synchronous IO Commands Embedded in Coordinated Motion page in the Dynomotion manual says:
Will keep you updated with any additional findings. I would appreciate any additional troubleshooting ideas you might have for identifying the root cause. Please let me know if you need any additional information from me to give you a better understanding of the behavior.
Thanks again for all your help,
Griffin Boyle
We require high resolution for our motion stage because the molten metal droplets we are depositing are ~250um in diameter, and small subdivision of this allow us to achieve - among other things - precise overhang angles. The max velocity provided by the JSON file is currently still in steps/sec (planning to convert to SI units in the near future) - that being said these values are currently only used by my homing routine (which uses MoveXYZABC() to move to the center of the build plate after homing completes), as all of our GCODE currently uses G1 commands (and thus uses the trajectory planner values, which I've provided below for more context).
Trajectory Planner
Break Angle: 90 Degrees
Look ahead: 4 seconds
Collinear Tolerance: 0mm
Corner Tolerance: 0.0254mm
Arcs to Segments: False
Facet Angle: 1 Degrees
Axis Parameters (same for X, Y, and Z)
Counts/mm: 3200
Vel mm/sec: 50.8
Accel mm/sec^2: 254
What I had meant by a hardware-related issue resulting in gradual drift was not so much the mechanical side but the electrical size - I figured that if noise was coupling to the step/dir lines being carried from the Kogna to the KSTEP through the RJ45 connector causing extra or lost steps, it would more likely appear as gradual drift across all axes, not so much a large batch of lost or added steps that appear discretely and seemingly exclusive to one axis (unless it happened to be PCB layout quirk specific to the third KSTEP axis making it more susceptible to this particular range of RF - which, now that I've switched the X and Y axis output channels, would explain the behavior if I then see the shift occur on the X axis instead of the Y axis, but this remains to be seen).
I'm less inclined to expect this to be a mechanical issue since the X axis experience the largest load, followed by the Y axis, followed by the Z axis - were this a mechanical/kinematic issue I would think that it would manifest on the X axis not the Y axis, especially given that they are currently provided with identical axis parameters.
Do you think that I would expect to see this bug in the offending axis's Dest member, seeing as how the machine coordinates do not reflect this shift? I've been operating under the assumption that machine coordinates are derived from the status update's reported axis Dest member divided by Counts/mm, in which case I would assume that the shift would not be reflected there?
Your understanding is pretty much correct - though the actual shift wasn't exactly 1mm, it was more like 0.8mm. We are currently driving the stage a good bit below it's maximum performance in an attempt to ensure reliable open-loop operation, with the intention of tuning this with an encoder in the near future to improve print speed. Thus far this appears to be exclusive to the -Y direction and occurs at random times (in particular, it seems, during simultaneous GCODE and arcing), and the shift persists permanently such that commanding to some known machine position will be physically off.
On a slightly tangential note, I had a question about buffered IO with MCODEs between G1 commands. Our GCODE generally looks something like this:
Code: Select all
G21 (means units are mm)
M102 (Set bit <11> to <1> - Enables KSTEP)
G1 X-2.756 Y16.681 Z-0.001 F450 (Drop 1 Level 0) (New *** Level 0)
M107 (Set bit <1057> to <1> - Sets MAKE_DROPLET_BIT)
M106 (Wait bit <1057> till <0> - Waits for Kogna to indicate that droplet has been made by clearing MAKE_DROPLET_BIT)
M108 (Wait bit <1059> till <0> - Waits for INTERRUPTED_BIT to be set low if high, set high by a button press and used to pause GCODE operation to allow the operator to make minor adjustments when needed [usually already LOW])
G1 X-2.471 Y16.75 Z0.002 F450 (Drop 2 Level 0)
M107
M106 (comment)
M108
G1 X-2.179 Y16.916 Z0.001 F450 (Drop 3 Level 0)
M107
M106 (comment)
M108
G1 X-2.447 Y17.005 Z-0.001 F450 (Drop 4 Level 0)
M107
M106 (comment)
M108
G1 X-2.732 Y16.977 Z0 F450 (Drop 5 Level 0)
Does this mean that the steppers are not being accelerated/decelerated between GCODE segments? If so this definitely seems like an invitation for error to be introduced - is there something I can do to ensure that the interpreter tells the Kogna to gracefully accelerate and decelerate for each segment between the buffered IO commands?MCodes can be configure to insert these commands, Although Wait commands can be inserted anywhere in a motion path it normally is only useful to place them at locations where the motion stops. Such as the very beginning of a path or at a corner where motion comes to a stop. Otherwise an instantaneous stop will occur without any acceleration. Wait commands are useful when motion must proceed instantly on command. This is possible because the motion has already been Interpreted, planned, downloaded, and commanded to execute ahead of time.
Will keep you updated with any additional findings. I would appreciate any additional troubleshooting ideas you might have for identifying the root cause. Please let me know if you need any additional information from me to give you a better understanding of the behavior.
Thanks again for all your help,
Griffin Boyle
- TomKerekes
- Posts: 2868
- Joined: Mon Dec 04, 2017 1:49 am
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Griffin,
That monitor program I described might also monitor acceleration as a delta-delta Dest to detect an instance such as instant acceleration or deceleration (stop).
G4P0
That monitor program I described might also monitor acceleration as a delta-delta Dest to detect an instance such as instant acceleration or deceleration (stop).
Yes if the line segments are in-line (same direction) then the trajectory planner may combine them without a stop. Or even if they are in-line within the break angle it may insert a corner radius and not come to a complete stop. So an embedded wait could be a problem. To force a stop you may add a dwell of 0 seconds:Does this mean that the steppers are not being accelerated/decelerated between GCODE segments? If so this definitely seems like an invitation for error to be introduced - is there something I can do to ensure that the interpreter tells the Kogna to gracefully accelerate and decelerate for each segment between the buffered IO commands?
G4P0
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
-
griffinboyle
- Posts: 10
- Joined: Sun Apr 07, 2024 11:15 pm
- Location: Boston
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Tom,
Thanks for the info, I had a feeling that was what's happening just from listening to the steppers. Will definitely give that a try - I assume adding a single 0 second dwell command after each G1 move is sufficient, or would I need to place a 0 second dwell command on either side of the G1 command?
This will definitely be useful from a broader standpoint when operating in open-loop, but I'm still wary to place all of the blame for the discrete Y shift on this source of error. Again, if anything I would expect this to result in the greatest amount of error accumulating on the X axis, as it has the largest moving mass, instead of exclusively the Y axis.
I'll make this change and continue to operate the machine - will get back to you here with any additional information and/or the next time I observe the discrete shift, and whether it now appears on the X or Y axis.
Thanks for all your help,
Griffin Boyle
Thanks for the info, I had a feeling that was what's happening just from listening to the steppers. Will definitely give that a try - I assume adding a single 0 second dwell command after each G1 move is sufficient, or would I need to place a 0 second dwell command on either side of the G1 command?
This will definitely be useful from a broader standpoint when operating in open-loop, but I'm still wary to place all of the blame for the discrete Y shift on this source of error. Again, if anything I would expect this to result in the greatest amount of error accumulating on the X axis, as it has the largest moving mass, instead of exclusively the Y axis.
I'll make this change and continue to operate the machine - will get back to you here with any additional information and/or the next time I observe the discrete shift, and whether it now appears on the X or Y axis.
Thanks for all your help,
Griffin Boyle
- TomKerekes
- Posts: 2868
- Joined: Mon Dec 04, 2017 1:49 am
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Griffin,
One dwell after each G1 should be sufficient. Or one before each wait might be better if it would be beneficial to allow the trajectory planner to combine/smooth/blend other G1 motions together normally.
One dwell after each G1 should be sufficient. Or one before each wait might be better if it would be beneficial to allow the trajectory planner to combine/smooth/blend other G1 motions together normally.
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
-
griffinboyle
- Posts: 10
- Joined: Sun Apr 07, 2024 11:15 pm
- Location: Boston
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Tom,
Thanks for the tip regarding the use of 0 second dwell commands to ensure proper acceleration and deceleration of the stage steppers between buffer IO Wait commands, this has had the exact intended effect and removes a major source of potential error which I'm very happy about.
I'm reaching out in this thread again because I noticed this line in the "Release Changes KFLOP/Kogna Versions 5.4.0 -> 5.4.1" under the "Kogna" section:
Thanks for all your help,
Griffin Boyle
Thanks for the tip regarding the use of 0 second dwell commands to ensure proper acceleration and deceleration of the stage steppers between buffer IO Wait commands, this has had the exact intended effect and removes a major source of potential error which I'm very happy about.
I'm reaching out in this thread again because I noticed this line in the "Release Changes KFLOP/Kogna Versions 5.4.0 -> 5.4.1" under the "Kogna" section:
Am I understanding correctly that this means toggling the enable status of axes configured as step/dir outputs on the Kogna could occasionally produce non-deterministic step signals to be commanded without the firmware's knowledge or intention? Is it possible that this bug in version 5.4.0 was responsible for the behavior I've described previously in this thread?Fix Step/Direction output mode causing a random high frequency burst of steps when Axis was enabled
Thanks for all your help,
Griffin Boyle
- TomKerekes
- Posts: 2868
- Joined: Mon Dec 04, 2017 1:49 am
Re: KMotionCNC: Non-repeatable discrete shift on Y-Axis during GCODE operation
Hi Griffin,
I sort of doubt it. Normally the axes aren't enabled and disabled. Normally after being disabled the axes are re-zeroed anyway. Also the high frequency burst of pulses is usually ignored by the Drives. But yes, please update to 5.4.1 to eliminate this possibility.
I sort of doubt it. Normally the axes aren't enabled and disabled. Normally after being disabled the axes are re-zeroed anyway. Also the high frequency burst of pulses is usually ignored by the Drives. But yes, please update to 5.4.1 to eliminate this possibility.
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.