FullControlXYZ / fullcontrol

Python version of FullControl for toolpath design (and more) - the readme below is best source of information
GNU General Public License v3.0
672 stars 78 forks source link

[FEATURE REQUEST] Device Support: Ultimaker S3 #87

Open ccoenen opened 6 months ago

ccoenen commented 6 months ago

I tried adding the Ultimaker S3 to the supported printers. Nothing fancy, just one of the two extruders. Sadly, I only produce files with this that the printer won't accept. I'll add my current state to this issue in case someone else wants to continue working on this.

# ultimakers3.py
from fullcontrol.gcode import Point, Printer, Extruder, ManualGcode, PrinterCommand, Buildplate, Hotend, Fan, StationaryExtrusion
import fullcontrol.gcode.printer_library.singletool.base_settings as base_settings

def set_up(user_overrides: dict):
    ''' DO THIS
    '''

    # overrides for this specific printer relative those defined in base_settings.py
    printer_overrides = {'e_units': 'mm3', 'dia_feed': 2.85}
    # update default initialization settings based on the printer-specific overrides and user-defined overrides
    initialization_data = {**base_settings.default_initial_settings, **printer_overrides}
    initialization_data = {**initialization_data, **user_overrides}

    starting_procedure_steps = []
    starting_procedure_steps.append(ManualGcode(text=';START_OF_HEADER'))
    starting_procedure_steps.append(ManualGcode(text=';HEADER_VERSION:0.1'))
    starting_procedure_steps.append(ManualGcode(text=';FLAVOR:Griffin'))
    starting_procedure_steps.append(ManualGcode(text=';GENERATOR.NAME:FullControlXYZ'))
    starting_procedure_steps.append(ManualGcode(text=';GENERATOR.VERSION:0.0')) # TODO how do I get this?
    starting_procedure_steps.append(ManualGcode(text=';GENERATOR.BUILD_DATE:2024-05-14')) # TODO how do I get this?
    starting_procedure_steps.append(ManualGcode(text=';TARGET_MACHINE.NAME:Ultimaker S3'))
    starting_procedure_steps.append(ManualGcode(text=';EXTRUDER_TRAIN.0.INITIAL_TEMPERATURE:{}'.format(initialization_data["nozzle_temp"])))
    starting_procedure_steps.append(ManualGcode(text=';EXTRUDER_TRAIN.0.MATERIAL.VOLUME_USED:0')) # unknowable but may be set to 0
    # starting_procedure_steps.append(ManualGcode(text=';EXTRUDER_TRAIN.0.MATERIAL.GUID:--guid here--')) # TODO supposedly optional
    starting_procedure_steps.append(ManualGcode(text=';EXTRUDER_TRAIN.0.NOZZLE.DIAMETER:0.4'))
    starting_procedure_steps.append(ManualGcode(text=';EXTRUDER_TRAIN.0.NOZZLE.NAME:AA 0.4'))
    starting_procedure_steps.append(ManualGcode(text=';BUILD_PLATE.INITIAL_TEMPERATURE:{}'.format(initialization_data["bed_temp"])))
    starting_procedure_steps.append(ManualGcode(text=';PRINT.TIME:0')) # unknowable, but may be set to 0
    starting_procedure_steps.append(ManualGcode(text=';PRINT.GROUPS:1'))
    starting_procedure_steps.append(ManualGcode(text=';PRINT.SIZE.MIN.X:0')) # TODO these could be analyzed perhaps, for now its just max dimensions for the printer
    starting_procedure_steps.append(ManualGcode(text=';PRINT.SIZE.MIN.Y:0'))
    starting_procedure_steps.append(ManualGcode(text=';PRINT.SIZE.MIN.Z:0'))
    starting_procedure_steps.append(ManualGcode(text=';PRINT.SIZE.MAX.X:230'))
    starting_procedure_steps.append(ManualGcode(text=';PRINT.SIZE.MAX.Y:190'))
    starting_procedure_steps.append(ManualGcode(text=';PRINT.SIZE.MAX.Z:200'))

    starting_procedure_steps.append(ManualGcode(text=';SLICE_UUID:-uuid-here-)) # unclear if necessary
    starting_procedure_steps.append(ManualGcode(text=';END_OF_HEADER'))

    starting_procedure_steps.append(ManualGcode(text=';Generated with FullControlXYZ')) # TODO can we get the version number?
    starting_procedure_steps.append(ManualGcode(text='T0')) # Select Tool 0
    starting_procedure_steps.append(ManualGcode(text='M82 ;absolute extrusion mode'))
    starting_procedure_steps.append(ManualGcode(text=''))
    starting_procedure_steps.append(ManualGcode(text='G92 E0'))
    #starting_procedure_steps.append(ManualGcode(text='M190 S60 ;Wait for print bed temperature\n'))
    starting_procedure_steps.append(Buildplate(temp=initialization_data["bed_temp"], wait=True))
    #starting_procedure_steps.append(ManualGcode(text='M109 S200 ;Wait for extruder to come up to temperature\n'))
    starting_procedure_steps.append(Hotend(temp=initialization_data["nozzle_temp"], wait=True))
    starting_procedure_steps.append(ManualGcode(text='G280 S1')) # unclear what this is.
    starting_procedure_steps.append(ManualGcode(text='G0 Z20.001'))
    starting_procedure_steps.append(ManualGcode(text='G1 F2700 E-6.5'))
    # starting_procedure_steps.append(ManualGcode(text=';LAYER_COUNT:33\n')) # TODO can we know this at this point?
    starting_procedure_steps.append(ManualGcode(text='G0 F9000 X180 Y180'))
    starting_procedure_steps.append(ManualGcode(text=';LAYER:0'))

    ending_procedure_steps = []
    ending_procedure_steps.append(ManualGcode(text='\n;-----\n; START OF ENDING PROCEDURE\n;-----'))
    ending_procedure_steps.append(ManualGcode(text='G1 F2700 E103.91916'))
    ending_procedure_steps.append(Buildplate(temp=0, wait=False))
    ending_procedure_steps.append(ManualGcode(text='M204 S3000'))
    ending_procedure_steps.append(ManualGcode(text='M205 X20 Y20'))
    ending_procedure_steps.append(Fan(speed_percent=0))
    ending_procedure_steps.append(ManualGcode(text='\n'))
    ending_procedure_steps.append(ManualGcode(text='M82 ;absolute extrusion mode'))
    ending_procedure_steps.append(Hotend(temp=0, wait=False))
    ending_procedure_steps.append(ManualGcode(text='M104 T1 S0')) # also cool down the other hotend.
    ending_procedure_steps.append(ManualGcode(text=';End of Gcode'))

    initialization_data['starting_procedure_steps'] = starting_procedure_steps
    initialization_data['ending_procedure_steps'] = ending_procedure_steps

    return initialization_data

With this current file, the printer will not accept the file (red exclamation mark on the device) and If I put a settings block at the end of the file, the printer will accept the file but will crash when printing.

That was the point when I gave up, if anyone else wants to take this up: feel free to take a look at this.

ccoenen commented 6 months ago

Here are a couple resources I used:

That code above is based on the file for the ultimaker 2 plus, because I had hoped that there might be similarities (Off-Screen Narrator: there were very few)

https://github.com/FullControlXYZ/fullcontrol/blob/528c85056023f1594bed52b52658a9e65d711fba/fullcontrol/gcode/printer_library/singletool/ultimaker2plus.py

fullcontrol-xyz commented 6 months ago

Thanks very much for sharing this! I've previously got an Ultimaker 3 to work, but not tried an S3. It took some trial and error to make sure the first few settings lines were set up correctly.

For anyone taking this forwards, or for you Claudius Coenen, I would copy the start gcode from a working GCode file exactly and put it as a single ManualGCode command with \n newline separators. If that works, I'd then gradually replace the hard-code text with variables and the potentially split it out from a single ManualGCode object to multiple single-line objects.

FYI, I am imminently going to add all of the printers from the Cura library to FullControl and will be asking people to test them. I'm not sure if the Cura S3 profile will work at all, but it will give an entirely new starting point for you to build from, if it's at least sensible to a degree.