MarlinFirmware / Marlin

Marlin is an optimized firmware for RepRap 3D printers based on the Arduino platform. Many commercial 3D printers come with Marlin installed. Check with your vendor if you need source code for your specific machine.
https://marlinfw.org
GNU General Public License v3.0
16.16k stars 19.21k forks source link

[FR] Delta dual-nozzle support #10047

Closed mshicom closed 6 years ago

mshicom commented 6 years ago

Description

I have a delta machine with dual static extruders (E3D Chimera like). When I have a nonzero hotend offset in the configuration, the tool change command will lead to strange movements and crash the hotend whenever I try to print with dual extrusion.

However, if the hotend 1 offset is set to zero (i.e. M218 T1 X0 Y0) then everything works fine, but then I have to use software offset with the slicer, which I would like to avoid.

This bug is related to #8496, but it doesn't seem to be fixed in Delta machine and it is reproducible on the newest bugfix-1.1.x branch (2018/03/10).

Steps to Reproduce

  1. Enable dual static extruders in Configuration.h:
    #define EXTRUDERS 2
    //#define SINGLENOZZLE
    //#define MK2_MULTIPLEXER
    //#define SWITCHING_EXTRUDER
    //#define SWITCHING_NOZZLE
    //#define PARKING_EXTRUDER
    //#define MIXING_EXTRUDER
  2. Run the following g-code:
    M218 T1 X0 Y18 ; set the hotend 1 offset to nonzero
    G28
    T0
    G0 X0 Y0 Z0 
    T1
    G0 X0 Y0 Z0 
    T0
    G0 X0 Y0 Z0 
    T1
    G0 X0 Y0 Z0 
    ... ; repeat many times to see the increasing drift

    Expected behavior: The print head will move back and forth, but its height should stay the same (i.e. 0).

Actual behavior: After each tool change command (no matter it is T0 or T1) the print head will move up a little bit (a +2mm Z movement in my case) and never come back, so you will see the print head is drifting upward. However, the Z-axis position in the LCD display is constantly 0.

Additional Information

My Configuration.h and Configuration_adv.h files Marlin.zip

thinkyhead commented 6 years ago

At this time a dual-nozzle is simply unsupportable for delta due to the way it's implemented (using a Cartesian "spoofing" technique). You'll have to use the slicer to manage it until proper support for offsets is added.

thinkyhead commented 6 years ago

I've made a first attempt to support hotend offsets on delta. Please test this Marlin branch and see if it works.

mshicom commented 6 years ago

Thanks for the reply! But your code won't compile if the delta setting is enabled, it shows:

sketch\Marlin_main.cpp: In function 'void inverse_kinematics(const float*)':

Marlin_main.cpp:12284: error: assignment of read-only location '* raw'

       raw[X_AXIS] -= hotend_offset[X_AXIS][active_extruder];

I have tried fixing this by simply removing the const keyword, but then the print head will run away and crash into something whenever I send the 'M218 T1 X0 Y18' command.

thinkyhead commented 6 years ago

by simply removing the const keyword

Sorry, this is still a work-in-progress. I've patched that function, so give it another go … once #10052 passes Travis CI.

mshicom commented 6 years ago

10052 tested, can compile now, but the runaway problem is still there, when I send the 'M218 T1 X0 Y18' command.

thinkyhead commented 6 years ago

Ah, ok. I was using the right motion function for T0/T1 tool change, but not for M218. That's now patched.

For the time being, don't try to change nozzles while the machine is homed at the top. That won't work yet, because when the machine is homed the effector can only be in the center. I'll need to add code to either reject impossible moves or to constrain them.

In the meantime, I'd be interested to know how M218, T0, and T1 behave when it's lower (10-20mm below the top), where the effector actually can move sideways. And, how M218, T0, and T1 behave when it's down in the "safe zone."

mshicom commented 6 years ago

First, the T0/T1/M218 seem to be well behaved:

Offset=0 (in EEPROM), G28:
    T0              -> no movement
    T1              -> no movement
    M218 T1 X10 Y0  -> no movement

Offset=X10 (in EEPROM), G28:
    T0              -> no movement
    T1              -> no movement

Offset=0 (in EEPROM), G28, Z=top-20:
    T0              -> no movement
    T0; T1          -> no movement

Offset=X10 (in EEPROM), G28, Z=top-20:
    T0              -> no movement
    T1              -> no movement
    M218 T1 X0 Y0   -> no movement

Z=top-20 means using G91; G0 Z-20; G90.

But there is something wrong after the tool change plus G0/G1, no matter the offset is zero or not:

Offset=0 (in EEPROM), G28:
    T0; G0 Z230;    -> success
    T0; G0 Z230; T1 -> runaway

Offset=X10 (in EEPROM), G28:
    T0; G0 Z230; T1 -> runaway

Offset=0 (in EEPROM), G28, Z=top-20:
    T0; G0 Z230; T1 -> runaway

Offset=X10 (in EEPROM), G28, Z=top-20:
    T0; G0 Z230; T1 -> runaway
thinkyhead commented 6 years ago

Ok, I've made some additional changes that should prevent tool-change from being stupid. For additional logging, be sure to enable DEBUG_LEVELING_FEATURE and before testing the moves send M111 247 to enable maximum logging. That will give additional output during the tool-change commands. In addition to tests just below the top, if you move down closer to the bed and do M218 and tool-change that should also prove interesting.

mshicom commented 6 years ago

No runaway now, but each time I send T0/T1 the print head will lift a little bit and drift away if no G0 is sent:

Offset=X10 (in EEPROM), G28, G0 Z1:

Using tool 1.
>>> gcode_T(1)
  current_position=(0.00, 0.00, 1.00) : BEFORE
Offset Tool XY by { 10.00, 0.00 }
  current_position=(10.00, 0.00, 1.00) : Sync After Toolchange
  current_position=(10.00, 0.00, 1.00) : sync_plan_position_kinematic
  destination=(0.00, 0.00, 1.00) : Move back
>>> do_blocking_move_to(0.00, 0.00, 1.00)
  destination=(10.00, 0.00, 2.00) : set_destination_from_current
  current_position=(10.00, 0.00, 2.00) : xy move
<<< do_blocking_move_to
echo:Active Extruder: 1
  current_position=(10.00, 0.00, 2.00) : AFTER
<<< gcode_T

Using tool 0.
>>> gcode_T(0)
  current_position=(10.00, 0.00, 2.00) : BEFORE
Offset Tool XY by { -10.00, 0.00 }
  current_position=(0.00, 0.00, 2.00) : Sync After Toolchange
  current_position=(0.00, 0.00, 2.00) : sync_plan_position_kinematic
  destination=(10.00, 0.00, 2.00) : Move back
>>> do_blocking_move_to(10.00, 0.00, 2.00)
  destination=(0.00, 0.00, 3.00) : set_destination_from_current
  current_position=(0.00, 0.00, 3.00) : xy move
<<< do_blocking_move_to
echo:Active Extruder: 0
  current_position=(0.00, 0.00, 3.00) : AFTER
<<< gcode_T

Using tool 1.
>>> gcode_T(1)
  current_position=(0.00, 0.00, 3.00) : BEFORE
Offset Tool XY by { 10.00, 0.00 }
  current_position=(10.00, 0.00, 3.00) : Sync After Toolchange
  current_position=(10.00, 0.00, 3.00) : sync_plan_position_kinematic
  destination=(0.00, 0.00, 3.00) : Move back
>>> do_blocking_move_to(0.00, 0.00, 3.00)
  destination=(10.00, 0.00, 4.00) : set_destination_from_current
  current_position=(10.00, 0.00, 4.00) : xy move
<<< do_blocking_move_to
echo:Active Extruder: 1
  current_position=(10.00, 0.00, 4.00) : AFTER
<<< gcode_T

Using tool 0.
>>> gcode_T(0)
  current_position=(10.00, 0.00, 4.00) : BEFORE
Offset Tool XY by { -10.00, 0.00 }
  current_position=(0.00, 0.00, 4.00) : Sync After Toolchange
  current_position=(0.00, 0.00, 4.00) : sync_plan_position_kinematic
  destination=(10.00, 0.00, 4.00) : Move back
>>> do_blocking_move_to(10.00, 0.00, 4.00)
  destination=(0.00, 0.00, 5.00) : set_destination_from_current
  current_position=(0.00, 0.00, 5.00) : xy move
<<< do_blocking_move_to
echo:Active Extruder: 0
  current_position=(0.00, 0.00, 5.00) : AFTER
<<< gcode_T

Using tool 1.
>>> gcode_T(1)
  current_position=(0.00, 0.00, 5.00) : BEFORE
Offset Tool XY by { 10.00, 0.00 }
  current_position=(10.00, 0.00, 5.00) : Sync After Toolchange
  current_position=(10.00, 0.00, 5.00) : sync_plan_position_kinematic
  destination=(0.00, 0.00, 5.00) : Move back
>>> do_blocking_move_to(0.00, 0.00, 5.00)
  destination=(10.00, 0.00, 6.00) : set_destination_from_current
  current_position=(10.00, 0.00, 6.00) : xy move
<<< do_blocking_move_to
echo:Active Extruder: 1

But luckily a G0 command will bring the print head back to where it should be:

SENDING: G0 X0 Y0 Z1 F3000
SENDING: T1
>>> gcode_T(1)
  current_position=(0.00, 0.00, 1.00) : BEFORE
Offset Tool XY by { 10.00, 0.00 }
  current_position=(10.00, 0.00, 1.00) : Sync After Toolchange
  current_position=(10.00, 0.00, 1.00) : sync_plan_position_kinematic
  destination=(0.00, 0.00, 1.00) : Move back
>>> do_blocking_move_to(0.00, 0.00, 1.00)
  destination=(10.00, 0.00, 2.00) : set_destination_from_current
  current_position=(10.00, 0.00, 2.00) : xy move
<<< do_blocking_move_to
echo:Active Extruder: 1
  current_position=(10.00, 0.00, 2.00) : AFTER
<<< gcode_T
SENDING:G0 X0 Y0 Z1 F3000
SENDING: T0
>>> gcode_T(0)
  current_position=(0.00, 0.00, 1.00) : BEFORE
Offset Tool XY by { -10.00, 0.00 }
  current_position=(-10.00, 0.00, 1.00) : Sync After Toolchange
  current_position=(-10.00, 0.00, 1.00) : sync_plan_position_kinematic
  destination=(0.00, 0.00, 1.00) : Move back
>>> do_blocking_move_to(0.00, 0.00, 1.00)
  destination=(-10.00, 0.00, 2.00) : set_destination_from_current
  current_position=(-10.00, 0.00, 2.00) : xy move
<<< do_blocking_move_to
echo:Active Extruder: 0
  current_position=(-10.00, 0.00, 2.00) : AFTER
<<< gcode_T
SENDING:G0 X0 Y0 Z1 F3000

Also, sending M218 near the bed (Z=1) is OK and shows no movement.

mshicom commented 6 years ago

Sending T0/T1 right after G28 homing looks good:

<<< gcode_G28
Using tool 1.
>>> gcode_T(1)
  current_position=(0.00, 0.00, 297.57) : BEFORE
Offset Tool XY by { 10.00, 0.00 }
  current_position=(10.00, 0.00, 297.57) : Sync After Toolchange
  current_position=(10.00, 0.00, 297.57) : sync_plan_position_kinematic
  destination=(0.00, 0.00, 297.57) : Move back
>>> do_blocking_move_to(0.00, 0.00, 297.57)
  destination=(10.00, 0.00, 297.57) : set_destination_from_current
  destination=(10.00, 0.00, 297.57) : prepare_uninterpolated_move_to_destination
  current_position=(10.00, 0.00, 297.57) : danger zone move
echo:Active Extruder: 1
  current_position=(10.00, 0.00, 297.57) : AFTER
<<< gcode_T
Using tool 0.
>>> gcode_T(0)
  current_position=(10.00, 0.00, 297.57) : BEFORE
Offset Tool XY by { -10.00, 0.00 }
  current_position=(0.00, 0.00, 297.57) : Sync After Toolchange
  current_position=(0.00, 0.00, 297.57) : sync_plan_position_kinematic
  destination=(10.00, 0.00, 297.57) : Move back
>>> do_blocking_move_to(10.00, 0.00, 297.57)
  destination=(0.00, 0.00, 297.57) : set_destination_from_current
  destination=(0.00, 0.00, 297.57) : prepare_uninterpolated_move_to_destination
  current_position=(0.00, 0.00, 297.57) : danger zone move
echo:Active Extruder: 0
  current_position=(0.00, 0.00, 297.57) : AFTER
<<< gcode_T

similary for M218:

<<< gcode_G28
>>> M218 T1 X10.00 Y0.00
SENDING:M218 T1 X10.00 Y0.00
>>> do_blocking_move_to(10.00, 0.00, 297.57)
  destination=(10.00, 0.00, 297.57) : set_destination_from_current
  destination=(10.00, 0.00, 297.57) : prepare_uninterpolated_move_to_destination
  current_position=(10.00, 0.00, 297.57) : danger zone move
>>> M218 T1 X0.00 Y0.00
SENDING:M218 T1 X0.00 Y0.00
>>> do_blocking_move_to(10.00, 0.00, 297.57)
  destination=(10.00, 0.00, 297.57) : set_destination_from_current
  destination=(10.00, 0.00, 297.57) : prepare_uninterpolated_move_to_destination
  current_position=(10.00, 0.00, 297.57) : danger zone move
thinkyhead commented 6 years ago

Getting closer. When switching nozzles I wanted to add a small lift before moving the nozzle over and down again, to help prevent it from colliding with the printed object. Sounds like the lift happens, but not the move back down. There's a line in there I expected to do this. Obviously I are mistaken.

thinkyhead commented 6 years ago

The failure to "Move Back" during T0/T1 was caused by an obscure issue so it took some time to track down. But I think it should now do the correct movement. Some small points still need to be settled before this can be merged:

mshicom commented 6 years ago

Cool! It works. Had a successful dual materials print. Thanks for all the effort!

thinkyhead commented 6 years ago

I'm gratified to hear that my solution is working! If you've peeked at the changes, they are surprisingly few and pretty simple. I'll spend some time on the loose ends over the next few days and aim to get this into Marlin just ahead of the 1.1.9 release. Thanks for bringing up the issue and for the excellent feedback!

github-actions[bot] commented 3 years ago

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.