-
-
Notifications
You must be signed in to change notification settings - Fork 19.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[2.0.x] Dual printing, losing position on toolhead switch? #10949
Comments
Able to confirm that by changing "tool_change" to the bare essentials we need, the problem goes away: void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
#if defined(LULZBOT_TOOLHEAD_CHANGE_WORKAROUND)
if(tmp_extruder != active_extruder) {
active_extruder = tmp_extruder;
#if ENABLED(SWITCHING_NOZZLE)
move_nozzle_servo(active_extruder);
#endif
}
return;
#endif
...
} So, something in this function is broken. |
I use dual nozzle single extruder (Dondolo) but in my case x, y, z shifting is normal behavior but I have SWITCHING_NOZZLE & SWITCHING_EXTRUDER activated) |
We'd love to have a patch from someone who (a) knows how to code and (b) has a printer of this kind to test with. |
@thinkyhead for sure a little bit more info will be helpful. I still have a "maybe similar" printer but with no "cnf" attached I'm not sure. I reported "part" of my configuration and I hope @marcio-ao will give its cnf. If they match maybe I will be able to help, maybe not and then some other "matching point 'a'" may comes to help. |
@thinkyhead: If I have more time, I'll try to selectively enable parts of @GMagician : I are using SWITCHING_NOZZLE, but not SWITCHING_EXTRUDER. However, my Marlin code is a bit modified since we have two servos that need to be commanded in opposite directions. I had to modify something in Marlin to support that. |
@marcio-ao are you sure your shiftings have nothing to do with HOTEND_OFFSET_X, HOTEND_OFFSET_Y or HOTEND_OFFSET_Z? |
@GMagician: I left those commented out. Perhaps this means the values are undefined and they don't default to zero? I'm not sure if that's the case though, I'm pretty sure I checked with M218 to make sure they were zero. |
As I remember C uninitialized array get 0 as value. But this is enforced by firmware EDIT: but they are also stored in eeprom...sure M502 M500? |
Just peeking at your example code, I see it doesn't do anything to update the current position so that it corresponds to the newly-selected nozzle. How does that work? |
@thinkyhead: We've always done the nozzle offsets in the slicer. The only thing we really need the |
Okay, here is what my void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
const float old_feedrate_mm_s = fr_mm_s > 0.0 ? fr_mm_s : feedrate_mm_s;
feedrate_mm_s = fr_mm_s > 0.0 ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
if (tmp_extruder != active_extruder) {
#if defined(LULZBOT_NO_MOVE_ON_TOOLHEAD_CHANGE)
no_move = true;
#endif
if (!no_move && axis_unhomed_error()) {
no_move = true;
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("No move on toolchange");
#endif
}
// Save current position to destination, for use later
set_destination_from_current();
DEBUG_POS("", current_position);
DEBUG_POS("", destination);
#if HAS_LEVELING
// Set current position to the physical position
const bool leveling_was_active = planner.leveling_active;
set_bed_leveling_enabled(false);
#endif
#if ENABLED(SWITCHING_NOZZLE)
// Always raise by at least 1 to avoid workpiece
const float zdiff = hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
current_position[Z_AXIS] += (zdiff > 0.0 ? zdiff : 0.0) + 1;
planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
move_nozzle_servo(tmp_extruder);
#endif
const float xdiff = hotend_offset[X_AXIS][tmp_extruder] - hotend_offset[X_AXIS][active_extruder],
ydiff = hotend_offset[Y_AXIS][tmp_extruder] - hotend_offset[Y_AXIS][active_extruder];
SERIAL_ECHOPAIR("Offset Tool XY by { ", xdiff);
SERIAL_ECHOPAIR(", ", ydiff);
SERIAL_ECHOLNPGM(" }");
// The newly-selected extruder XY is actually at...
current_position[X_AXIS] += xdiff;
current_position[Y_AXIS] += ydiff;
// Set the new active extruder
active_extruder = tmp_extruder;
#if HAS_LEVELING
// Restore leveling to re-establish the logical position
set_bed_leveling_enabled(leveling_was_active);
#endif
#if ENABLED(SWITCHING_NOZZLE)
// The newly-selected extruder Z is actually at...
current_position[Z_AXIS] -= zdiff;
#endif
// Tell the planner the new "current position"
SYNC_PLAN_POSITION_KINEMATIC();
DEBUG_POS("S1", current_position);
constexpr bool safe_to_move = true;
// Raise, move, and lower again
if (safe_to_move && !no_move && IsRunning()) {
DEBUG_POS("Move back", destination);
// Move back to the original (or tweaked) position
do_blocking_move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
}
#if ENABLED(SWITCHING_NOZZLE)
else {
// Move back down. (Including when the new tool is higher.)
do_blocking_move_to_z(destination[Z_AXIS], planner.max_feedrate_mm_s[Z_AXIS]);
}
#endif
} // (tmp_extruder != active_extruder)
DEBUG_POS("S2", current_position);
planner.synchronize();
feedrate_mm_s = old_feedrate_mm_s;
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(MSG_ACTIVE_EXTRUDER, (int)active_extruder);
} Now, look at the output:
So what seems to be happening is two-fold. There is in fact a bug in the code, but it only appears when As you can see from the lines "S1" and "S2" in the log, something -- I do not know what -- is causing the |
So a possible fix to the code is to always restore the |
Okay, I added more debugging statements: void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
const float old_feedrate_mm_s = fr_mm_s > 0.0 ? fr_mm_s : feedrate_mm_s;
feedrate_mm_s = fr_mm_s > 0.0 ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
if (tmp_extruder != active_extruder) {
#if defined(LULZBOT_NO_MOVE_ON_TOOLHEAD_CHANGE)
no_move = true;
#endif
if (!no_move && axis_unhomed_error()) {
no_move = true;
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("No move on toolchange");
#endif
}
// Save current position to destination, for use later
set_destination_from_current();
DEBUG_POS("", current_position);
DEBUG_POS("", destination);
#if HAS_LEVELING
// Set current position to the physical position
const bool leveling_was_active = planner.leveling_active;
set_bed_leveling_enabled(false);
#endif
DEBUG_POS("S1", current_position);
#if ENABLED(SWITCHING_NOZZLE)
// Always raise by at least 1 to avoid workpiece
const float zdiff = hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
current_position[Z_AXIS] += (zdiff > 0.0 ? zdiff : 0.0) + 1;
planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
move_nozzle_servo(tmp_extruder);
#endif
DEBUG_POS("S2", current_position);
const float xdiff = hotend_offset[X_AXIS][tmp_extruder] - hotend_offset[X_AXIS][active_extruder],
ydiff = hotend_offset[Y_AXIS][tmp_extruder] - hotend_offset[Y_AXIS][active_extruder];
//#if ENABLED(DEBUG_LEVELING_FEATURE)
// if (DEBUGGING(LEVELING)) {
SERIAL_ECHOPAIR("Offset Tool XY by { ", xdiff);
SERIAL_ECHOPAIR(", ", ydiff);
SERIAL_ECHOLNPGM(" }");
// }
//#endif
// The newly-selected extruder XY is actually at...
current_position[X_AXIS] += xdiff;
current_position[Y_AXIS] += ydiff;
DEBUG_POS("S3", current_position);
// Set the new active extruder
active_extruder = tmp_extruder;
DEBUG_POS("S4", current_position);
#if HAS_LEVELING
// Restore leveling to re-establish the logical position
set_bed_leveling_enabled(leveling_was_active);
#endif
DEBUG_POS("S5", current_position);
#if ENABLED(SWITCHING_NOZZLE)
// The newly-selected extruder Z is actually at...
current_position[Z_AXIS] -= zdiff;
#endif
DEBUG_POS("S6", current_position);
// Tell the planner the new "current position"
SYNC_PLAN_POSITION_KINEMATIC();
DEBUG_POS("S7", current_position);
constexpr bool safe_to_move = true;
// Raise, move, and lower again
if (safe_to_move && !no_move && IsRunning()) {
DEBUG_POS("Move back", destination);
// Move back to the original (or tweaked) position
do_blocking_move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
}
#if ENABLED(SWITCHING_NOZZLE)
else {
// Move back down. (Including when the new tool is higher.)
do_blocking_move_to_z(destination[Z_AXIS], planner.max_feedrate_mm_s[Z_AXIS]);
}
#endif
} // (tmp_extruder != active_extruder)
DEBUG_POS("S8", current_position);
DEBUG_POS("S9", destination);
planner.synchronize();
feedrate_mm_s = old_feedrate_mm_s;
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(MSG_ACTIVE_EXTRUDER, (int)active_extruder);
} And here are the results:
So the |
This of course |
When the tool is changed (with If the The
Bed leveling moves Z up and down as the XY position changes. The active nozzle is the one that's being adjusted. Its physical position over the bed is meant to remain constant. The other tool on the same carriage is essentially ignored, and the inactive nozzle's height over the bed is not considered. So, imagine a bed that is tilted at a pronounced angle, for example, such that the T1 nozzle's distance to the bed is always 1mm closer than the T0 nozzle. Imagine that the T0 nozzle is 10mm from the bed, and the T1 nozzle is 9mm from the bed, and the tool is changed from T0 to T1. Even though its physical distance from the bed is 9mm, its logical position would be Z=10 at this point. We have to apply a correction one way or another. The old code would look up the Z leveling offset being applied to the previous tool and subtract the Z leveling offset for the new tool and apply a correction. But this required the
So you can now see why that is not sensible. |
@thinkyhead: Your explanations make sense when the nozzle offsets are something other than zero. But you still haven't given an explanation for why the position is changing when the nozzle offsets are set to zero, as they are in my case. |
Which kind of bed leveling are you using? Only when ABL_PLANAR seems may alterate XY |
@GMagician : AUTO_BED_LEVELING_LINEAR |
@GMagician: It looks like AUTO_BED_LEVELING_LINEAR is ABL_PLANAR. So does this mean that the bug is actually in the code for ABL_PLANAR? That would explain why only we are seeing it. I think most printers have moved away from planar leveling. |
Not sure.. I read something like: void set_bed_leveling_enabled(const bool enable/*=true*/) {
[CUT]
#else // OLDSCHOOL_ABL
[CUT]
if (!enable)
// When disabling just get the current position from the steppers.
// This will yield the smallest error when first converted back to steps.
set_current_from_steppers_for_axis(
#if ABL_PLANAR
ALL_AXES
#else
Z_AXIS
#endif
); but I have to investigate |
set_current_from_steppers_for_axis should copy all axis curposition from stepcounter value. Don't know exactly logic behind. |
@GMagician: I think this explains the offset. Often when |
But are there two nozzles, spaced apart from each other? |
I'm pretty sure |
I don't see it... That code is the only part I saw that may change X & Y |
@thinkhead: I explained earlier in this thread that the nozzle offsets are handled by our slicer. So as far as Marlin is concerned, the nozzles are in the same location. |
You may try to add a |
Ah right, I forgot you were doing a hack. Ok, so Marlin is not currently coded for that. The firmware currently assumes that it will know the hard-coded XY nozzle offset so it can manage the movement limits, adjust the current position on tool-change, etc. You'll need to add a new option to the configuration which specifies that nozzle offsets are always handled externally, then have Marlin leave out all its nozzle offset handling when that option is enabled. |
@thinkyhead what if offsets are all 0? it could be handled and Marlin should think nozzles are in the same position even if are not. Then slicer will handle the offset moving head in another "physical" position |
@GMagician — It's not possible at the pre-compiler level to check if the nozzle XY offsets are 0, but we could add a Or, someone with coding skills and a vested interest in this customization could add code throughout Marlin to account for this special case and modify behavior wherever it's needed. |
@thinkyhead: It's not an error to have both nozzles in the same place, for example there are hotends out there, such as the Cyclops from E3D, that have no offsets. Besides, you are missing the point. The bug isn't that Marlin cannot support a XY_OFFSET of zero (it certainly can, because once I bypass the code in |
No, don't do this. Marlin already supports an offset of zero -- I made successful prints with it. The only bug is the bug in AUTO_BED_LEVELING_LINEAR which has nothing to do with nozzle offsets. |
That's what |
As this is an open source project, it is most helpful for contributors who have the equipment that exhibits the issue to figure out how to fix it and contribute a PR. Those of us who don't have the equipment will have a much harder time developing a solution. |
@marcio-ao, thinkyhead is right about
I can suggest you to analyze |
@thinkyhead, @GMagician: The flip side of this is that those of us with the equipment don't necessarily have the understanding of Marlin internals to come up with a correct fix, nor does a fix that works for me necessary work for everyone else -- case in point, the easiest fix for me is to bypass all the leveling and positioning code in Anyhow, one of the take-away from this discussion is that I should probably modify our FW to let Marlin handle the nozzle offsets -- the reason we have always done this in the slicer is historical and is probably something we should move away from. I'll experiment with that. For one thing, it seems like what is exposing the bug is the fact that I am forcing -- Marcio |
@marcio-ao I agree with you about knowledge and that with offset 0 on both extruders Marlin should works as expected since is slicer that will change "destination" according to its new offsets. |
I'm about to give it a try, although I guess I don't really understand the rationale for it. Isn't the ISR still moving the steppers while the toolhead change is taking place? |
@marcio-ao I checked code to see differences with |
@GMagician: You are exactly correct, this is what causes the bug. What is happening is that the position before the call to
So if I guess the thought is that if a |
@GMagician, @thinkyhead: Sorry for the delay in testing the suggested fix. It looks like putting a
|
Also, rather than doing what I was doing above, I also tried specifying the nozzle offset in Marlin. This works fine, except that the tool-head crashes into the min endstop when switching to the rightmost nozzle. I thought Marlin was supposed to automatically take travel limits into account when using nozzle offsets? This does not seem to be happening. |
Sounds like some extra logic will be needed to (1) make sure not to move outside of the configured boundaries and (2) make sure the final nozzle position is correctly set as |
The |
This has been fixed. |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Has anyone here done dual nozzle printing on Marlin bugfix-2.0.x? We are seeing a strange coordinate shift after toolhead changes and we don't know whether this problem has anything to do with changes we might have made to our FW.
The text was updated successfully, but these errors were encountered: