From bd9d77842e31035c68446eac2257cfe4ffba0715 Mon Sep 17 00:00:00 2001 From: Ilya Gushchin Date: Fri, 8 Sep 2023 08:49:46 +0300 Subject: [PATCH] 1.4.0 (#168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * STEAPP-493: fixed bug for auto calibrate SPIRAL mode, doesn't any move before start calibrate. (#126) * Update main.yml * STEAPP-513: added park the axes A in auto calibrate after set template. (#130) * STEAPP-513: removed command PROBE_TEMPLATE_POINT because this command exist in another macro. * STEAPP-513: added park the axes A in auto calibrate after set template. * STEAPP-513: STEAPP-513: added park the axes A after set tool. * STEAPP-479: added statuses in filament_control_2. (#121) * STEAPP-479: added statuses. * STEAPP-479: added statuses. * STEAPP-479: added statuses. --------- Co-authored-by: Ilya Gushchin * STEAPP-487: added macro for checking fans. (#122) * STEAPP-453: added WARNING log for macros. (#123) * STEAPP-453-WIP:added new function for logging warning meassage. * STEAPP-453:added "WARNING" loging. * STEAPP-453: added WARNING loging for macros. --------- Co-authored-by: Ilya Gushchin * STEAPP-508: implementation of comments on the "fiber nozzle offset" manager. (#131) * STEAPP-495: added save radius tool. * STEAPP-508: changed sequence printing walls in model. * STEAPP-511: added move in home position. * STEAPP-506: changed default temperatures for heaters. * STEAPP-509: changed temperature for main extruder after print first layer. * STEAPP-508: removed SAVE_RADIUS_TOOL, because this code for other branch. * STEAPP-514: added calculate wcs_2_z and radius only whis baclash_y, added save raadius. (#132) * STEAPP: added calculate wcs_2_z, save radius, calculate radius only whis baclash_y. * STEAPP-514: WIP added calculate radius only whis baclash_y. * STEAPP-514: Added a condition that does not set wcs_2_z after an error. --------- Co-authored-by: Ilya Gushchin * Fix constrain not disabled by error Update print_macros.cfg * Create publish_changelog * Rename publish_changelog to publish_changelog.yml * Update probe_hybrid_printer.cfg * Update probe_fiber_printer.cfg * Update probe_fiber_printer.cfg * Update publish_changelog.yml * Update probe_fiber_printer.cfg * Update probe_hybrid_printer.cfg * Update probe.cfg * Update probe_2.cfg * fix probing error * Update homing.cfg * Update probe.cfg * fixed bug move out off the range for axis X. * bug fixed, in the "spiral" mode, the probe took measurements of the A axis, which is in the parked mode * removed unneeded probe move for 'SPIRAl' and 'SPIRAL-FULL' regimes. * bug fixed, Pause cmd did not work correctly. added checking in condition on the object-filament_sensor. * STEAPP-541: added load/save data about the sensor backlash. (#134) * STEAPP-541: added load/save the sensor backlash. Added calculate backlash in to main logic * STEAPP-541: added calculate backlash in to main logic * STEAPP-541: fixed bug in to apply radius for calculate wcs_2_z. * STEAPP-541: Removed unnecessary save radius and backlash sensor commands because SAVE_VARIABLES does that. * STEAPP-499: added move down on 5mm when change extruders. (#128) * STEAPP-499: added move down on 5mm when change extruders. * STEAPP-499: set Z param in G1 command after change extruder. * STEAPP-499: moved the macro MOVE_DOWN_Z_AXIS in print_macros.cfg, added condition for check the parking z axis. * STEAPP-432: added condition for check offset, needed for do not move outside coordinate system (#117) * STEAPP-432:added zeroing z_offset, when changing the module. * STEAPP-432:added condition for check offset, needed for do not move outside coordinate system. * STEAPP-432:added condition for check offset, needed for do not move outside coordinate system. --------- Co-authored-by: Ilya Gushchin * STEAPP-454: added status about trigered filament sensor. (#125) * STEAPP-454: added status abaut trigered filament sensor. * STEAPP-454: added status abaut trigered filament sensor. * STEAPP-454: added status abaut trigered filament sensor. * STEAPP-454: deleted the used module save_variable, and rename the variable. * STEAPP-489: added layer data the print stat. (#127) * STEAPP-489:WIP added raw code. * STEAPP-489: added layer data the print stat. * STEAPP-489: added in print stats info about layers. * STEAPP-489: changed naming variables. --------- Co-authored-by: Ilya Gushchin * STEAPP-512: added move for adjust nozzle offset. (#133) * STEAPP: added calculate wcs_2_z, save radius, calculate radius only whis baclash_y. * STEAPP-514: WIP added calculate radius only whis baclash_y. * STEAPP-512: added move for adjust nozzle offset. * STEAPP-512: removed code because this code from another branch. * STEAPP-512: added condition for checking the module used. * fix bug * STEAPP-490: added condition for do offset when triggered filament sensor, make offset only for first layer. (#129) * fixed bug if in PAUSE state user used CANCEL, will be reset offset from wcs0. * STEAPP-490: added condition for do offset, execute offset only for first layer. Added code from STEAPP-489 for suport changed. * Update filament_control_2.cfg --------- Co-authored-by: Ilya Gushchin * STEAPP-542:added a new algorithm for measuring the difference between two points for the A axis. (#135) * STEAPP-541: added load/save the sensor backlash. Added calculate backlash in to main logic * STEAPP-541: added calculate backlash in to main logic * STEAPP-541: fixed bug in to apply radius for calculate wcs_2_z. * STEAPP-541: Removed unnecessary save radius and backlash sensor commands because SAVE_VARIABLES does that. * STEAPP-542: added new algorithm for get difference meashuring between two points for axis A. * STEAPP-542: added new algorithm for get difference meashuring between two points for axis A. --------- Co-authored-by: Ilya Gushchin * STEAPP-547: added new algorithm for calculate wcs1/2. (#137) * STEAPP-547: added main algorithm for measuring wcs_1_x, wcs_1_y and check axis A. * STEAPP-547: added algorithm for measure wcs_1_x. * STEAPP-547: added measuring wcs_1_x/y to probe_2.cfg * STEAPP-547: refactoring the code. * STEAPP-547: refactoring the code. * STEAPP-547: Added main command with wcs measurement points by tool. * STEAPP-547: refactoring the code and dleted unneeded rows. * STEAPP-547: added new algorithm for calculate wcs1/2. * STEAPP-547: refactoring the code. * STEAPP-547: deleted the save unneeded brobe_baclash_x/y_2 * STEAPP-547: deleted unneeded checking. * STEAPP-547: added save/load baclash. * was comment out rows which checking gcode offset * Update filament_control_2.cfg * Update bed_mesh.py * STEAPP-521: Add virtual_sdcard dump to bug report. (#136) * STEAPP-521: A line has been added to the log that caused an error. * STEAPP-521: added to the log entry of commands that are unknown to klipper. * STEAPP-521: Added a dump of the data causing the exception and writing this data to a log file. * added dump data to loging file. * STEAPP-553: edited and checking config with use two mcu. (#140) Co-authored-by: frylock34 * STEAPP-588: fixed bug, status was overwritten by M109 command. (#147) * STEAPP-588: fixed bug, status was overwritten by M109 command. * Update extruder_macros.cfg --------- Co-authored-by: Ilya Gushchin * STEAPP-586: was find and set sensor type, based on spend tests. (#146) * STEAPP-585: cganged max_z_accel.Tests have been spend, and find optimal value. (#145) * STEAPP-574: added name extruder(fiber: bool). (#141) * STEAPP-554: Increased Z-axis movement speed before calibration. (#143) * STEAPP-460: added main configs file for Ender. (#148) * STEAPP-460: added main configs file. * STEAPP-460: added main configs for moving axes. * STEAPP-460: added config for printing. * STEAPP-460: adapted the command G28 and actions for vars.cfg. * STEAPP-460: Added boolean status to set Axis rotation to 45 degrees when moving home. --------- Co-authored-by: Ilya Gushchin * STEAPP-590: adapted the calibrate commands for Ender. (#150) * STEAPP-460: added main configs file. * STEAPP-460: added main configs for moving axes. * STEAPP-460: added config for printing. * STEAPP-460: adapted the command G28 and actions for vars.cfg. * STEAPP-590: adapted calibrate command. --------- Co-authored-by: Ilya Gushchin * STEAPP-601: added checking the state before used command PAUSE/RESUME. (#153) * STEAPP-601: added checking the state before used command PAUSE/RESUME. * Update print_macros.cfg --------- Co-authored-by: Ilya Gushchin * STEAPP-600: WIP: added new algorithm to calculate wcs for the SPIRAL mode. (#154) * STEAPP-555: added new comand and move for calculate skew beetwen two points the X axis. * STEAPP-556: added commands for set and apply the correct accentricity wcs_1_x/y. * STEAPP-556: added commands for set and apply the offset for correcting the eccentricity. * STEAPP-556: fixed bug, and added condition for checking length the tool before measure skew for the axis X(where use points only wcs_1). * STEAPP-581: added new logic for apply skew compensation * STEAPP-581: disabled skew compensation in the CANCEL_PRINT command. * STEAPP-581: Edited and tested new algorithm. * STEAPP-581: Edited and tested new algorithm. * STEAPP-581: Edited and tested new algorithm. * STEAPP-581: refactoring the code. * STEAPP-581: added save skew for quickly use this functionality. * STEAPP-581: added save skew for quickly use this functionality. * STEAPP-600: added mode calibrate to function for get rough radius. * STEAPP-600: added new algorithm to calculate wcs for the SPIRAL mode. * STEAPP-581: refactoring the code. * STEAPP-600: disabled skew compensation and apply eccentricity --------- Co-authored-by: Ilya Gushchin * STEAPP-455: added code for 'error' and 'warning' messages. (#155) Co-authored-by: Ilya Gushchin * Update publish_changelog.yml * STEAPP-598: added checking calibrate when used 5d module before print… (#152) * STEAPP-598: added checking calibrate when used 5d module before printing. * STEAPP-598: replacing the reaction to an uncalibrated printer, warning to error. * STEAPP-587: added macro for check accuracy set the 5d module. (#157) * STEAPP-587: added macro for check accuracy set the 5d module. * STEAPP-587: added macro for check accuracy set the 5d module. * STEAPP-587: added macro for check accuracy set the 5d module. * STEAPP-587: added macro for check accuracy set the 5d module. * STEAPP-587: added command for check accuracy set the module 5d. --------- Co-authored-by: Ilya Gushchin * STEAPP-611: modified and tested macros for printing and calibration (old template). (#156) * STEAPP-616: chenched macros for the manual calibrate for old teamplate. * STEAPP-616: changed and checked macros for the printing * STEAPP-611: added changes to main config Ender. * STEAPP-616: changed and checked macros for the load/eject material. * STEAPP-616: changed and checked macros for the load/eject material. * STEAPP-616: edited START command to avoid the clash * STEAPP-616: added comand for object 'bed_screws'. * STEAPP-616: checked and adaptived commands and params for the object 'bed_screws'. * STEAPP-616: added config bed_screws. --------- Co-authored-by: Ilya Gushchin * Update power_control.cfg * STEAPP-637 add HTE530-5-8-23 cfg * Add fiber config * Update fiber_extruder_3.cfg * STEAPP-626: HTE-630(step-1): added config for HTE-630, rename configs for the PRO-750 (#158) * STEAPP-626: renamed configs for the printer PRO-750. * STEAPP-626: added config for the printer HTE-630. * STEAPP-626: edited path to config * STEAPP-626: added raw kinematics for HTE-630 * STEAPP-625: HTE-630(step-2): adapted 'auto_calibrate' and 'set zero point', added kinematic. (#159) * STEAPP-626: renamed configs for the printer PRO-750. * STEAPP-626: added config for the printer HTE-630. * STEAPP-625: added raw config. * STEAPP-625: adapted auto calibrate for HTE-630. * STEAPP-625: added raw kinematics * STEAPP-625: added raw kinematics * STEAPP-626: edited path to config * STEAPP-626: added raw kinematics for HTE-630 * STEAPP-625: adapted for FULL mode 'set zero point'. * STEAPP-625: edited for HTE-630. --------- Co-authored-by: Ilya Gushchin * STEAPP-635: removed variables from save_variables, when calculate WCS whis DAC_v_2. (#162) * Update corexy_6axis.py * Update fiber_extruder_3.cfg * Update fiber_extruder_3.cfg * STEAPP-651: added new config for auto calibrate, change start point for axis X. (#164) * STEAPP-651: added new config for auto calibrate, change start point for axis X. * STEAPP-651: moved config to folder the v6 * STEAPP-613: deleted old configs filament_control and filament_control_second. (#161) * STEAPP-613: deleted old configs. * STEAPP-613: renamed configs. * STEAPP-613: new names have been added to configs. * STEAPP-613: changed naming config files for filament motion sensor --------- Co-authored-by: Ilya Gushchin * STEAPP-636: PROBE(step-2) Fixed a bug in the tool radius calculation algorithm for SPIRAL mode. And removed unnecessary functions for calculation radius for the FULL mode. (#163) * STEAPP-599: Moved the same macros to a separate configю * STEAPP-599: renamed configs, set logical names. * STEAPP-599: renamed configs, set logical names. * STEAPP-599: new names have been added to configs. * STEAPP-599: added .png image visual how as guide. * STEAPP-599: added descriptions. * STEAPP-636: error detected, incorrect radius calculation * STEAPP-636: Fixed a bug in the tool radius calculation algorithm. * STEAPP-636: Removed functions additional calculations radius for the full mode. * STEAPP-636: added new config files the autocalibrate --------- Co-authored-by: sokolovjek * Update kinematics_300_3.cfg * Update kinematics_300_2.cfg * Update module_3d_300.cfg * Update main.yml * fix bug, not applied the probe offset for Y axis... this leads to error "out off the range axis Y --------- Co-authored-by: Sokolov Evgenii <81033310+SokolovJek@users.noreply.github.com> Co-authored-by: Соколов Евгений --- .github/workflows/publish_changelog.yml | 19 + .vscode/launch.json | 24 +- ENDER-23.cfg | 27 + HTE530-5-4-22.cfg | 7 +- HTE750-0-0-23.cfg | 37 + .../calibrate/auto_calibrate_by_teamplate.png | Bin 0 -> 116419 bytes .../calibrate/auto_calibrate_by_tool.png | Bin 0 -> 216724 bytes .../calibrate/manual_calibrate_bed_level.txt | 10 + .../manual_calibrate_old_teamplate.txt | 42 + docs/stereotech/quide_error_list.txt | 270 +++ klippy/configfile.py | 32 +- klippy/extras/a_axis_offset.py | 9 +- klippy/extras/auto_wcs.py | 155 +- klippy/extras/b_axis_compensation.py | 2 +- klippy/extras/bed_mesh.py | 64 +- klippy/extras/bus.py | 8 +- klippy/extras/buttons.py | 4 +- klippy/extras/c_axis_align.py | 2 +- klippy/extras/canbus_ids.py | 4 +- klippy/extras/controller_fan.py | 2 +- klippy/extras/display/__init__.py | 4 +- klippy/extras/endstop_phase.py | 10 +- klippy/extras/force_move.py | 4 +- klippy/extras/gcode_macro.py | 10 +- klippy/extras/gcode_move.py | 20 +- klippy/extras/heaters.py | 16 +- klippy/extras/homing.py | 12 +- klippy/extras/homing_override.py | 11 +- klippy/extras/output_pin.py | 2 +- klippy/extras/pid_calibrate.py | 4 +- klippy/extras/print_stats.py | 46 +- klippy/extras/probe.py | 18 +- klippy/extras/safe_z_home.py | 4 +- klippy/extras/save_variables.py | 8 +- klippy/extras/skew_correction.py | 146 +- klippy/extras/stepper_enable.py | 2 +- klippy/extras/temperature_fan.py | 8 +- klippy/extras/temperature_host.py | 2 +- klippy/extras/temperature_mcu.py | 2 +- klippy/extras/tmc.py | 20 +- klippy/extras/tmc2130.py | 6 +- klippy/extras/tmc_uart.py | 14 +- klippy/extras/virtual_sdcard.py | 37 +- klippy/gcode.py | 39 +- klippy/kinematics/cartesian_6axis.py | 164 ++ klippy/kinematics/corexy_6axis.py | 4 +- klippy/kinematics/extruder.py | 25 +- klippy/klippy.py | 8 +- klippy/mathutil.py | 2 +- klippy/mcu.py | 28 +- klippy/msgproto.py | 6 +- klippy/pins.py | 22 +- klippy/serialhdl.py | 4 +- klippy/stepper.py | 20 +- klippy/toolhead.py | 2 +- klippy/webhooks.py | 30 +- stereotech_config/ENDER-23.cfg | 28 + stereotech_config/HFE530-5-3-23.cfg | 6 +- stereotech_config/HFE530-5-4-22.cfg | 5 +- stereotech_config/HFE530-5-8-23.cfg | 35 + stereotech_config/HFE530-5-C-22.cfg | 5 +- stereotech_config/HTE530-5-3-23.cfg | 7 +- stereotech_config/HTE530-5-4-22.cfg | 7 +- stereotech_config/HTE530-5-8-23.cfg | 36 + stereotech_config/HTE600-0-0-23.cfg | 38 - stereotech_config/HTE630-0-0-23.cfg | 35 + stereotech_config/HTE750-0-0-23.cfg | 38 + stereotech_config/diagnostics.cfg | 34 +- stereotech_config/ender/extruder_macros.cfg | 41 + stereotech_config/ender/homing.cfg | 95 + stereotech_config/ender/kinematics.cfg | 63 + stereotech_config/ender/kinematics_tmc.cfg | 13 + stereotech_config/ender/main_extruder.cfg | 32 + stereotech_config/ender/module_3d.cfg | 22 + stereotech_config/ender/module_3d_macros.cfg | 36 + stereotech_config/ender/module_5d.cfg | 92 + stereotech_config/ender/print_macros.cfg | 176 ++ stereotech_config/ender/printhead.cfg | 7 + stereotech_config/ender/probe.cfg | 526 +++++ stereotech_config/ender/variables.cfg | 26 + stereotech_config/extruder_macros.cfg | 17 +- stereotech_config/fiber_extruder.cfg | 6 +- stereotech_config/fiber_extruder_2.cfg | 6 +- stereotech_config/fiber_extruder_3.cfg | 65 + stereotech_config/fiber_nozzle_offset.cfg | 1853 +++++++++-------- stereotech_config/filament_control.cfg | 268 +-- stereotech_config/filament_control_2.cfg | 174 -- stereotech_config/filament_control_second.cfg | 13 +- .../filament_control_second_2.cfg | 14 - stereotech_config/homing.cfg | 5 +- stereotech_config/kinematics_300.cfg | 2 +- stereotech_config/kinematics_300_2.cfg | 4 +- stereotech_config/kinematics_300_3.cfg | 66 + stereotech_config/main_extruder.cfg | 6 +- stereotech_config/mcu/stm32f446.config | 10 +- stereotech_config/mcu/stm32g0b1.config | 36 +- stereotech_config/module_3d_300.cfg | 2 +- stereotech_config/nozzle_offset.cfg | 22 + stereotech_config/power_control.cfg | 5 +- stereotech_config/print_macros.cfg | 295 +-- stereotech_config/probe.cfg | 695 ------- stereotech_config/probe_DAC_v1.cfg | 215 ++ stereotech_config/probe_DAC_v2.cfg | 129 ++ stereotech_config/probe_fiber_printer.cfg | 16 +- stereotech_config/probe_fiber_printer_3.cfg | 229 ++ stereotech_config/probe_hybrid_printer.cfg | 16 +- .../{probe_2.cfg => probe_main.cfg} | 773 +++---- stereotech_config/second_extruder.cfg | 6 +- stereotech_config/v6/board_stm.cfg | 45 - stereotech_config/v6/chamber.cfg | 162 -- stereotech_config/v6/filament_control.cfg | 21 - .../v6/filament_control_second.cfg | 13 - stereotech_config/v6/kinematics.cfg | 36 +- stereotech_config/v6/module_3d.cfg | 17 - stereotech_config/v6/printhead.cfg | 9 - .../v6/probe_hybrid_printer_v6.cfg | 229 ++ stereotech_config/v7/board_stm32f4.cfg | 24 + stereotech_config/v7/board_stm32g1b0.cfg | 16 + stereotech_config/v7/chamber.cfg | 168 ++ .../{v6 => v7}/fiber_extruder.cfg | 25 +- stereotech_config/v7/filament_control.cfg | 21 + .../v7/filament_control_second.cfg | 13 + stereotech_config/v7/kinematics.cfg | 67 + stereotech_config/v7/kinematics_none.cfg | 66 + .../{v6 => v7}/kinematics_tmc.cfg | 25 +- .../{v6 => v7}/main_extruder.cfg | 33 +- stereotech_config/v7/module_3d.cfg | 17 + stereotech_config/v7/module_5d.cfg | 98 + stereotech_config/v7/printhead.cfg | 9 + .../{v6 => v7}/second_extruder.cfg | 33 +- stereotech_config/variables.cfg | 5 + 131 files changed, 5740 insertions(+), 3241 deletions(-) create mode 100644 .github/workflows/publish_changelog.yml create mode 100644 ENDER-23.cfg create mode 100644 HTE750-0-0-23.cfg create mode 100644 docs/stereotech/calibrate/auto_calibrate_by_teamplate.png create mode 100644 docs/stereotech/calibrate/auto_calibrate_by_tool.png create mode 100644 docs/stereotech/calibrate/manual_calibrate_bed_level.txt create mode 100644 docs/stereotech/calibrate/manual_calibrate_old_teamplate.txt create mode 100644 docs/stereotech/quide_error_list.txt create mode 100644 klippy/kinematics/cartesian_6axis.py create mode 100644 stereotech_config/ENDER-23.cfg create mode 100644 stereotech_config/HFE530-5-8-23.cfg create mode 100644 stereotech_config/HTE530-5-8-23.cfg delete mode 100644 stereotech_config/HTE600-0-0-23.cfg create mode 100644 stereotech_config/HTE630-0-0-23.cfg create mode 100644 stereotech_config/HTE750-0-0-23.cfg create mode 100644 stereotech_config/ender/extruder_macros.cfg create mode 100644 stereotech_config/ender/homing.cfg create mode 100644 stereotech_config/ender/kinematics.cfg create mode 100644 stereotech_config/ender/kinematics_tmc.cfg create mode 100644 stereotech_config/ender/main_extruder.cfg create mode 100644 stereotech_config/ender/module_3d.cfg create mode 100644 stereotech_config/ender/module_3d_macros.cfg create mode 100644 stereotech_config/ender/module_5d.cfg create mode 100644 stereotech_config/ender/print_macros.cfg create mode 100644 stereotech_config/ender/printhead.cfg create mode 100644 stereotech_config/ender/probe.cfg create mode 100644 stereotech_config/ender/variables.cfg create mode 100644 stereotech_config/fiber_extruder_3.cfg delete mode 100644 stereotech_config/filament_control_2.cfg delete mode 100644 stereotech_config/filament_control_second_2.cfg create mode 100644 stereotech_config/kinematics_300_3.cfg delete mode 100644 stereotech_config/probe.cfg create mode 100644 stereotech_config/probe_DAC_v1.cfg create mode 100644 stereotech_config/probe_DAC_v2.cfg create mode 100644 stereotech_config/probe_fiber_printer_3.cfg rename stereotech_config/{probe_2.cfg => probe_main.cfg} (55%) delete mode 100644 stereotech_config/v6/board_stm.cfg delete mode 100644 stereotech_config/v6/chamber.cfg delete mode 100644 stereotech_config/v6/filament_control.cfg delete mode 100644 stereotech_config/v6/filament_control_second.cfg delete mode 100644 stereotech_config/v6/module_3d.cfg delete mode 100644 stereotech_config/v6/printhead.cfg create mode 100644 stereotech_config/v6/probe_hybrid_printer_v6.cfg create mode 100644 stereotech_config/v7/board_stm32f4.cfg create mode 100644 stereotech_config/v7/board_stm32g1b0.cfg create mode 100644 stereotech_config/v7/chamber.cfg rename stereotech_config/{v6 => v7}/fiber_extruder.cfg (86%) create mode 100644 stereotech_config/v7/filament_control.cfg create mode 100644 stereotech_config/v7/filament_control_second.cfg create mode 100644 stereotech_config/v7/kinematics.cfg create mode 100644 stereotech_config/v7/kinematics_none.cfg rename stereotech_config/{v6 => v7}/kinematics_tmc.cfg (62%) rename stereotech_config/{v6 => v7}/main_extruder.cfg (65%) create mode 100644 stereotech_config/v7/module_3d.cfg create mode 100644 stereotech_config/v7/module_5d.cfg create mode 100644 stereotech_config/v7/printhead.cfg rename stereotech_config/{v6 => v7}/second_extruder.cfg (63%) diff --git a/.github/workflows/publish_changelog.yml b/.github/workflows/publish_changelog.yml new file mode 100644 index 000000000000..04a9e90be220 --- /dev/null +++ b/.github/workflows/publish_changelog.yml @@ -0,0 +1,19 @@ +# CI Code for generating and publishing beta assets + +name: publish_changelog +on: + release: + types: [published] +jobs: + generate_assets: + runs-on: ubuntu-latest + env: + WIKI_API_KEY: ${{ secrets.WIKI_API_KEY }} + RELEASE_VERSION: ${{ github.event.release.tag_name }} + RELEASE_DESCRIPTION: ${{ toJson(github.event.release.body) }} + steps: + - uses: actions/checkout@v2 + + - name: Update wiki + run: | + curl -XPOST --data '{"repo":"${{github.repository}}","version":"${{ env.RELEASE_VERSION }}", "description": ${{ env.RELEASE_DESCRIPTION }} }' "https://functions.yandexcloud.net/${{ secrets.FUNCTION_ID }}" diff --git a/.vscode/launch.json b/.vscode/launch.json index 871286be441b..12bab24e07b5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -28,7 +28,29 @@ "${workspaceFolder}/HTE530-5-4-22.cfg", "-v", "-a", - "/tmp/klipper_uds" + "/tmp/klipper_uds", + // "-l", + // "/tmp/dev_klipper_log.log" + ] + }, + { + "name": "Run klipper ender", + "type": "python", + "request": "launch", + "env": { + "PYTHONPATH": "${workspaceRoot}" + }, + "stopOnEntry": false, + "console": "integratedTerminal", + "cwd": "${workspaceRoot}", + "program": "${workspaceFolder}/klippy/klippy.py", + "args": [ + "${workspaceFolder}/ENDER-23.cfg", + "-v", + "-a", + "/tmp/klipper_uds", + // "-l", + // "/tmp/dev_klipper_log.log" ] } ] diff --git a/ENDER-23.cfg b/ENDER-23.cfg new file mode 100644 index 000000000000..54cf4e70be79 --- /dev/null +++ b/ENDER-23.cfg @@ -0,0 +1,27 @@ +[mcu] +serial: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 +restart_method: command + +[mcu second_mcu] +serial: /dev/serial/by-id/usb-Klipper_stm32g0b1xx_5800260019504B5735313920-if00 +restart_method: command + +[virtual_sdcard] +path: /home/ste/uploads + +[display_status] + +[include stereotech_config/ender/kinematics.cfg] +[include stereotech_config/ender/kinematics_tmc.cfg] +[include stereotech_config/ender/homing.cfg] + +[include stereotech_config/ender/main_extruder.cfg] +[include stereotech_config/ender/module_3d.cfg] +[include stereotech_config/ender/module_3d_macros.cfg] +[include stereotech_config/ender/module_5d.cfg] + +[include stereotech_config/ender/print_macros.cfg] +[include stereotech_config/ender/extruder_macros.cfg] +[include stereotech_config/ender/variables.cfg] + +# [include stereotech_config/ender/probe.cfg] diff --git a/HTE530-5-4-22.cfg b/HTE530-5-4-22.cfg index 61abee80fed7..e575c626664c 100644 --- a/HTE530-5-4-22.cfg +++ b/HTE530-5-4-22.cfg @@ -15,15 +15,16 @@ path: /home/ste/uploads [include stereotech_config/chamber_2.cfg] [include stereotech_config/printhead.cfg] -[include stereotech_config/probe.cfg] +[include stereotech_config/probe_main.cfg] +[include stereotech_config/probe_DAC_v1.cfg] [include stereotech_config/probe_hybrid_printer.cfg] [include stereotech_config/main_extruder.cfg] [include stereotech_config/second_extruder.cfg] [include stereotech_config/nozzle_offset.cfg] [include stereotech_config/extruder_macros.cfg] -[include stereotech_config/filament_control_2.cfg] -[include stereotech_config/filament_control_second_2.cfg] +[include stereotech_config/filament_control.cfg] +[include stereotech_config/filament_control_second.cfg] [include stereotech_config/power_control.cfg] [include stereotech_config/module_3d_300.cfg] diff --git a/HTE750-0-0-23.cfg b/HTE750-0-0-23.cfg new file mode 100644 index 000000000000..e48dd79550cc --- /dev/null +++ b/HTE750-0-0-23.cfg @@ -0,0 +1,37 @@ +[mcu] +serial: /dev/ttyACM1 +# serial: /dev/serial/by-id/usb-Klipper_stm32f446xx_410046000451303431333234-if00 + +[mcu second_mcu] +serial: /dev/ttyACM0 + +[virtual_sdcard] +path: /home/ste/uploads + +[display_status] + +[include stereotech_config/v7/kinematics_none.cfg] +# [include stereotech_config/v7/board_stm32f4.cfg] +# [include stereotech_config/v7/board_stm32g1b0.cfg] +# [include stereotech_config/v7/kinematics.cfg] +# [include stereotech_config/v7/kinematics_tmc.cfg] +# [include stereotech_config/v7/chamber.cfg] +# [include stereotech_config/v7/printhead.cfg] +# [include stereotech_config/v7/main_extruder.cfg] +# [include stereotech_config/v7/second_extruder.cfg] +# [include stereotech_config/v7/fiber_extruder.cfg] +# [include stereotech_config/v7/filament_control_2.cfg] +# [include stereotech_config/v7/filament_control_second_2.cfg] +# [include stereotech_config/v7/module_3d.cfg] +# [include stereotech_config/v7/module_5d.cfg] +# not defined +# [include stereotech_config/v7/homing.cfg] +# [include stereotech_config/v7/probe.cfg] +# [include stereotech_config/v7/probe_hybrid_printer.cfg] +# [include stereotech_config/v7/nozzle_offset.cfg] +# [include stereotech_config/v7/extruder_macros.cfg] +# [include stereotech_config/v7/power_control.cfg] +# [include stereotech_config/v7/module_3d_macros.cfg] +# [include stereotech_config/v7/print_macros.cfg] +# [include stereotech_config/v7/variables.cfg] +# [include stereotech_config/v7/diagnostics.cfg] diff --git a/docs/stereotech/calibrate/auto_calibrate_by_teamplate.png b/docs/stereotech/calibrate/auto_calibrate_by_teamplate.png new file mode 100644 index 0000000000000000000000000000000000000000..5936a263d331d4b500efde3f2c6accad1899bbbc GIT binary patch literal 116419 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�%(UYy%{raD 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 literal 0 HcmV?d00001 diff --git a/docs/stereotech/calibrate/auto_calibrate_by_tool.png b/docs/stereotech/calibrate/auto_calibrate_by_tool.png new file mode 100644 index 0000000000000000000000000000000000000000..ea4dc2e1b395bc81c6ba675f6a79ee2e8b28d61b GIT binary patch literal 216724 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%0DRYV_g;$|3pc$ZcUd!w!9e>p31Oi+u=wNmp| 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 literal 0 HcmV?d00001 diff --git a/docs/stereotech/calibrate/manual_calibrate_bed_level.txt b/docs/stereotech/calibrate/manual_calibrate_bed_level.txt new file mode 100644 index 000000000000..65a1602c8f0a --- /dev/null +++ b/docs/stereotech/calibrate/manual_calibrate_bed_level.txt @@ -0,0 +1,10 @@ +step1 +Z_ENDSTOP_CALIBRATE + +2 +ACCEPT_Z_ENDSTOP + +3 +ACCEPT_Z_ENDSTOP + +..... diff --git a/docs/stereotech/calibrate/manual_calibrate_old_teamplate.txt b/docs/stereotech/calibrate/manual_calibrate_old_teamplate.txt new file mode 100644 index 000000000000..cc852eec26d7 --- /dev/null +++ b/docs/stereotech/calibrate/manual_calibrate_old_teamplate.txt @@ -0,0 +1,42 @@ +"ручная калибровка 5д модуля" + #step5 + MOVE_SERVICE_POSITION + MOVE_CALIBRATION_POINT POINT=0 + #step6 + SET_A_AXIS_OFFSET_POINT POINT=0 + SAVE_A_AXIS_POINT POINT=0 COORDS=107.0,41.1,138.1 + #step7 + MOVE_CALIBRATION_POINT POINT=3 + SET_A_AXIS_OFFSET_POINT POINT=1 + SAVE_A_AXIS_POINT POINT=1 COORDS=106.3,90.9,139.5 + CALC_A_AXIS_OFFSET + MOVE_WCS_ZERO WCS=1 + #step8 + SET_WCS_OFFSET WCS=1 X=0 Y=0 Z=0 + SET_WCS_OFFSET WCS=3 X=0 Y=0 Z=0 + MOVE_WCS_ZERO WCS=2 + #step 9 + SET_WCS_OFFSET WCS=2 X=0 Y=0 Z=0.1 + SET_WCS_OFFSET WCS=4 X=0 Y=0 Z=0.1 + #step10 + HOME_POSITION ABORT=0 + +"ручная настройка точки старта печати FULL" + # step4 + MOVE_SERVICE_POSITION + # step7 + MOVE_WCS_ZERO WCS=1 + # step8 + SET_WCS_OFFSET WCS=1 ADJUST_WCS=2 X=0 Y=0 Z=0 + # step9 + HOME_POSITION ABORT=0 + +"ручная настройка точки старта печати SPIRAL" + # step4 + MOVE_SERVICE_POSITION + # step7 + MOVE_WCS_ZERO WCS=2 + # step8 + SET_WCS_OFFSET WCS=2 ADJUST_WCS=1 X=0 Y=0 Z=0 + # step9 + HOME_POSITION ABORT=0 diff --git a/docs/stereotech/quide_error_list.txt b/docs/stereotech/quide_error_list.txt new file mode 100644 index 000000000000..4d8a665541bb --- /dev/null +++ b/docs/stereotech/quide_error_list.txt @@ -0,0 +1,270 @@ +Код ошибки состоит из 3х частей, ABC: + A: к какой области относится ошибка, диапазон: 0-6 + B: статус ошибки error/warning, диапазон: 0-1 + C: индификатор ошибки + Пр: + 2020: 2-область калибровки; 0-error; 20-Mesh Leveling: Error splitting move + +config: + 001: Unable to open config file %s" % (filename,) + 002: Unable to parse option '%s' in section '%s' + 002: Option '%s' in section '%s' must have minimum of %s" + 002: Option '%s' in section '%s' must have maximum of %s" + 002: Option '%s' in section '%s' must be above %s + 002: Option '%s' in section '%s' must be below %s + 003: Choice '%s' for option '%s' in section '%s' is not a valid choice" + 004: Option '%s' in section '%s' must be specified" + 005: Include file '%s' does not exist" + 006: Recursive include of config file '%s'" % (filename) + 007: Section '%s' is not a valid config section" + 008: Option '%s' is not valid in section '%s'" + 009: Printer object skew_corection already created" + 0010: Unknown config object skew_corection_second." + 0011: Unable to load module math_2 + 0011: Unable to load module skew_corection_2 + 0012: gcode command %s already registered" % (cmd,) + 0013: mux command %s %s %s may have only one key (%s)" + 0014: mux command %s %s %s already registered (%s)" + 0015: Error loading kinematics ' + 0016: Error loading template '%s': %s + 0017: Error evaluating '%s': %s + 0018: A primary [display] section must be defined in printer.cfg to use auxilary displays + 0019: Section name [display display] is not valid. Please choose a different postfix. + 0020: Existing command '%s' not found in gcode_macro rename + +печать/кинематика/движение: + 101: Error loading kinematics + 102: G-Code move transform already specified + 103: Invalid speed in '%s' + 104: Unable to parse move '%s' + 105: Unknown g-code state: %s + 106: Printer not ready + 107: Invalid speed in '%s' + 108: Unable to parse move '%s' + 109: Must home X and Y axes first + 1010: homing_override and safe_z_homing cannot be used simultaneously + 1011: virtual_sdcard get_file_list + 1012: SD write not supported + 1013: SDCARD_RESET_FILE cannot be run from the sdcard + 1014: SD busy + 1015: SD busy + 1016: Unable to open file + 1017: SD busy + 1018: SD busy + 1019: Must home axis first + +калибровка: + 201: axis x=310 out of range (0 - 300) + 202: axis y=310 out of range (0 - 300) + 203: axis z=310 out of range (0 - 300) + 204: tool length not enough for calculate wcs_2_y! + 205: Error, tool length not enough! + 205: Error, tool length or radius not enough! + 206: auto_wcs: improperly formatted entry for point\n%s + 207: a_axis_offset: improperly formatted entry for point\n%s + 208: auto_wcs: improperly formatted entry for point\n%s + 209: b_axis_compensation: improperly formatted entry for point + #bed_mesh + 2010: bed_mesh: malformed '%s' value: %s" + 2011: Option '%s' in section bed_mesh must have a minimum of %s" + 2012: Option '%s' in section bed_mesh must have a maximum of %s + 2013: Unable to parse parameter '%s' + 2014: Unable to parse parameter ' + 2015: Parameter '%s + 2016: Parameter '%s' must have a maximum of + 2017: Unable to parse parameter '%s' + 2018: bed_mesh: ERROR, fade_target lies outside of mesh z range\nmin: %.4f, max: %.4f, fade_target: %.4f" + 2019: bed_mesh: Mesh extends outside of the fade range, please see the fade_start and fade_end options in example-extras.cfg. fade distance: %.2f mesh min: %.4f mesh max: %.4f" + 2020: Mesh Leveling: Error splitting move + 2021: bed_mesh: min/max points too close together + 2022: bed_mesh: Unable to generate coordinates for faulty region at index: %d + 2023: bed_mesh: probe_count must be odd for round beds + 2024: bed_mesh: invalid min/max points + 2025: bed_mesh: Existing faulty_region_%d %s overlaps added faulty_region_%d %s + 2026: bed_mesh: Added faulty_region_%d %s overlaps existing faulty_region_%d %s + 2027: bed_mesh: Unknown algorithm <%s> + 2028: bed_mesh: cannot exceed a probe_count of 6 when using lagrange interpolation. Configured Probe Count: %d, %d" + 2029: bed_mesh: invalid probe_count option when using bicubic interpolation. Combination of 3 points on one axis with more than 6 on another is not permitted. Configured Probe Count: %d, %d" + 2030: bed_mesh: bicubic interpolation with a probe_count of less than 4 points detected. Forcing lagrange interpolation. Configured Probe Count: %d, %d + 2031: Value for parameter 'PROFILE' must be specified + 2032: a_axis_offset: improperly formatted entry for point\n%s + # probe + 2033: Probe virtual endstop only useful as endstop pin + 2034: Can not pullup/invert probe virtual endstop + 2035: Must home before probe + 2036: Timeout during endstop homing + 2037: Probe samples exceed samples_tolerance + 2038: Toolhead moved during probe activate_gcode script + 2039: Toolhead moved during probe deactivate_gcode script + 2040: Need at least %d probe points for %s + 2041: horizontal_move_z can't be less than probe's z_offset + 2042: skew_corection: improperly formatted entry for point\n%s + 2043: Error! Factor name %s not in list factors['XY', 'XZ', 'YZ'] + 2044: skew_correction: improperly formatted entry for plane [%s]\n%s + +перефирия(mcu): + 301: Timeout on wait for '%s' response + 302: Error send cmd to mcu + 303: Multi-mcu homing not supported on multi-mcu shared axis" + 304: проблемы связанные с пинами + 305: Pin '%s' is not a valid pin name on mcu '%s' + 306: Stepper dir pin must be on same mcu as step pin + 307: Internal error in stepcompress + 308: Internal error in stepcompress + 309: Internal error in stepcompress + 3010: Internal error in stepcompress + 3011: full_steps_per_rotation invalid in section + 3012: PWM cycle time too large + 3013: MCU '%s' CRC does not match config" + 3014: MCU '%s' error during config: %s + 3015: Unable to configure MCU '%s'" + 3016: Failed automated reset of MCU '%s' + 3017: Too few moves available on MCU '%s' + 3018: проблемы с индификацией mcu(serialhdl) + 3020: Internal error in MCU stm22 stepcompress" + 3021: position_endstop in section '%s' must be between position_min and position_max + 3022: Unable to infer homing_positive_dir in section ' + 3023: Invalid homing_positive_dir / position_endstop in '%s' + 3024: Pinter rail %s shared endstop pin %s must specify the same pullup/invert settings + 3025: Must specify %s on mcu '%s'" + 3026: Unknown %s '%s'" + 3027: %s: spi pins must be on same mcu" + 3028: Pin %s must be on mcu %s + 3029: button pins must be on same mcu + 3030: %d steps per detent not supported + 3031: Duplicate canbus_uuid + 3032: Unknown canbus_uuid + 3033: One or more of these steppers are unknown: %s (valid steppers are: %s) + 3034: Stepper %s phase unknown + 3035: Invalid trigger_phase '%s' + 3036: Endstop for %s is not accurate enough for stepper phase adjustment + 3037: Endstop %s incorrect phase (got %d vs %d) + 3038: Stats not available for stepper %s + 3039: Requested temperature (%.1f) out of range (%.1f:%.1f) + 3040: Cannot load config '%s' + 3041: Heater %s already registered + 3042: Unknown heater + 3043: G-Code sensor id %s already registered + 3044: Unknown temperature sensor ' + 3045: Error on 'TEMPERATURE_WAIT': missing MINIMUM or MAXIMUM. + 3046: Unknown sensor '%s' + 3047: error homing_move_end + 3048: Endstop %s still triggered after retract + 3049: Homing failed due to printer shutdown + 3050: Probing failed due to printer shutdown + 3051: Probe triggered prior to movement + 3052: Homing failed due to printer shutdown + 3053: Invalid pin value + 3054: error pid_calibrate + 3055: pid_calibrate interrupted + 3056: Unknown stepper '%s' + 3057: Requested min speed (%.1f) is greater than max speed (%.1f) + 3058: Requested temperature (%.1f) out of range (%.1f:%.1f) + 3059: Requested min speed (%.1f) out of range (0.0 : 1.0) + 3060: Requested max speed (%.1f) out of range (0.0 : 1.0) + 3061: Unable to open temperature file '%s' + 3062: MCU temperature not supported on %s + # tmc UART + 3063: TMC mux pins must be on the same mcu + 3064: All TMC mux instances must use identical pins + 3065: Shared TMC uarts must use the same pins + 3066: Shared TMC uarts need unique address or select_pins polarity + 3067: TMC uart rx and tx pins must be on the same mcu + 3068: Unable to read tmc uart '%s' register %s + 3069: Unable to write tmc uart '%s' register %s + # tmc CAN + 3070: TMC '%s' reports error: %s + 3071: Unknown field name '%s' + 3072: VELOCITY parameter not supported by this driver + 3073: Specify either VALUE or VELOCITY + 3074: Unknown register name '%s' + 3075: tmc virtual endstop only useful as endstop + 3076: Can not pullup/invert tmc virtual pin + 3077: tmc virtual endstop requires diag pin config + 3078: Could not find config section '[%s]' required by tmc driver + 3079: TMC SPI chain must have same length + 3080: TMC SPI chain can not have duplicate position + 3081: Unable to write tmc spi '%s' register %s + +датчик филамента: + 401: Filament error on Extruder0 + 411: The filament has run out or there is a problem with its supply at the Extruder0. + 412: Recover extrusion by offset %s' % printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made + 413: Switch to second extruder and resume printing. + 414: All attempt to extrude failed. + 415: Recover extrusion after cooling and heating. + 416: Recover extrusion do extrude attempt %s' % printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made + 417: Extruding attempt completed successfully, resuming printing. + +диагностика: + 501: 3D module disabled, cannot set temperature for heater 'heater_bed + 502: Extruder extruder3 not connected. + +экструдер: + 601: '%s' is not a valid extruder. + 602: Active extruder does not have a stepper + 603: Unable to infer active extruder stepper + 604: Rotation distance can not be zero + 605: Extrude below minimum temp\n See the 'min_extrude_temp' config option for details + 606: Extrude only move too long (%.3fmm vs %.3fmm)\n See the 'max_extrude_only_distance' config option for details + 607: Move exceeds maximum extrusion (%.3fmm^2 vs %.3fmm^2)\n See the 'max_extrude_cross_section' config option for details + 608: Extruder not configured + 609: Extrude when no extruder present + 6010: Extruder not configured + 6011: Extruder not configured + 611: Extruder not hot enough. + +ethernet/client: + 701: Not a top-level dictionary + 702: Invalid request type + 703: Missing Argument [%s] + 704: Invalid Argument Type [%s] + 705: Multiple calls to send not allowed + 706: webhooks: Unable to delete socket file + 707: Path already registered to an endpoint + 708: mux endpoint %s %s %s may have only one key (%s) + 709: mux endpoint %s %s %s already registered (%s) + 7010: The value '%s' is not valid for %s" + 7011: webhooks: No registered callback for path '%s' + 7012: Remote method '%s' not registered" + 7013: No active connections for method '%s + 7014: Invalid argument + 7015: Invalid argument + +остальное: + 802: Error in coordinate descent: %s + # msgproto Protocol definitions for firmware communication + 806: Unable to extract params from: + 806: Unable to encode: + 806: Error during identify: + 806: Unknown value '%s' in enumeration + #Serial port management for firmware communication(serialhdl.py ) + 807: failure communication whis mcu + 808: Unable to obtain '%s' response + + 813: Printer not homed + 814: Printer not homed + 815: Printer not homed. + +gcode/gcode cmd: + 901: Internal error on command: + 902: Malformed command + 903: Error on '%s': unable to parse %s" + 903: Error on '%s': %s must have minimum of %s + 903: Error on '%s': %s must have maximum of %s" + 903: Error on '%s': %s must be above %s" + 903: Error on '%s': %s must be below %s" + 904: %s" % self.printer.get_state_message()[0] - printer is not ready for run this cmd + 905: The value '%s' is not valid for %s" + 906: Klipper state: Not ready + 907: SAVE_CONFIG section '%s' option '%s' conflicts with included value" + 908: Unable to parse existing config on SAVE_CONFIG + 909: Unable to write config file during SAVE_CONFIG + 9010: Unknown stepper %s + 9011: %s" % str(e) + 9012: Unable to parse existing variable file + 9013: Unable to parse '%s' as a literal + 9014: Unable to save variable + 9015: Internal error on command:"%s", origline"%s" + + 911: Unknown command: diff --git a/klippy/configfile.py b/klippy/configfile.py index dd32d47fd3c6..8d6c39681565 100644 --- a/klippy/configfile.py +++ b/klippy/configfile.py @@ -29,28 +29,28 @@ def _get_wrapper(self, parser, option, default, minval=None, maxval=None, acc_id = (self.section.lower(), option.lower()) self.access_tracking[acc_id] = default return default - raise error("Option '%s' in section '%s' must be specified" + raise error("001: Option '%s' in section '%s' must be specified" % (option, self.section)) try: v = parser(self.section, option) except self.error as e: raise except: - raise error("Unable to parse option '%s' in section '%s'" + raise error("002: Unable to parse option '%s' in section '%s'" % (option, self.section)) if note_valid: self.access_tracking[(self.section.lower(), option.lower())] = v if minval is not None and v < minval: - raise error("Option '%s' in section '%s' must have minimum of %s" + raise error("002: Option '%s' in section '%s' must have minimum of %s" % (option, self.section, minval)) if maxval is not None and v > maxval: - raise error("Option '%s' in section '%s' must have maximum of %s" + raise error("002: Option '%s' in section '%s' must have maximum of %s" % (option, self.section, maxval)) if above is not None and v <= above: - raise error("Option '%s' in section '%s' must be above %s" + raise error("002: Option '%s' in section '%s' must be above %s" % (option, self.section, above)) if below is not None and v >= below: - raise self.error("Option '%s' in section '%s' must be below %s" + raise self.error("002: Option '%s' in section '%s' must be below %s" % (option, self.section, below)) return v def get(self, option, default=sentinel, note_valid=True): @@ -74,7 +74,7 @@ def getchoice(self, option, choices, default=sentinel, note_valid=True): else: c = self.get(option, default, note_valid=note_valid) if c not in choices: - raise error("Choice '%s' for option '%s' in section '%s'" + raise error("003: Choice '%s' for option '%s' in section '%s'" " is not a valid choice" % (c, option, self.section)) return choices[c] def getlists(self, option, default=sentinel, seps=(',',), count=None, @@ -90,7 +90,7 @@ def lparser(value, pos): return tuple([lparser(p, pos - 1) for p in parts if p]) res = [parser(p) for p in parts] if count is not None and len(res) != count: - raise error("Option '%s' in section '%s' must have %d elements" + raise error("004: Option '%s' in section '%s' must have %d elements" % (option, self.section, count)) return tuple(res) def fcparser(section, option): @@ -159,7 +159,7 @@ def _read_config_file(self, filename): data = f.read() f.close() except: - msg = "Unable to open config file %s" % (filename,) + msg = "001: Unable to open config file %s" % (filename,) logging.exception(msg) raise error(msg) return data.replace('\r\n', '\n') @@ -226,7 +226,7 @@ def _resolve_include(self, source_filename, include_spec, fileconfig, include_filenames = glob.glob(include_glob) if not include_filenames and not glob.has_magic(include_glob): # Empty set is OK if wildcard but not for direct file reference - raise error("Include file '%s' does not exist" % (include_glob,)) + raise error("005: Include file '%s' does not exist" % (include_glob,)) include_filenames.sort() for include_filename in include_filenames: include_data = self._read_config_file(include_filename) @@ -236,7 +236,7 @@ def _resolve_include(self, source_filename, include_spec, fileconfig, def _parse_config(self, data, filename, fileconfig, visited): path = os.path.abspath(filename) if path in visited: - raise error("Recursive include of config file '%s'" % (filename)) + raise error("006: Recursive include of config file '%s'" % (filename)) visited.add(path) lines = data.split('\n') # Buffer lines between includes and parse as a unit so that overrides @@ -296,12 +296,12 @@ def check_unused_options(self, config): for section_name in fileconfig.sections(): section = section_name.lower() if section not in valid_sections and section not in objects: - raise error("Section '%s' is not a valid config section" + raise error("007: Section '%s' is not a valid config section" % (section,)) for option in fileconfig.options(section_name): option = option.lower() if (section, option) not in access_tracking: - raise error("Option '%s' is not valid in section '%s'" + raise error("008: Option '%s' is not valid in section '%s'" % (option, section)) # Setup get_status() self._build_status(config) @@ -371,7 +371,7 @@ def _disallow_include_conflicts(self, regular_data, cfgname, gcode): for section in self.autosave.fileconfig.sections(): for option in self.autosave.fileconfig.options(section): if config.fileconfig.has_option(section, option): - msg = ("SAVE_CONFIG section '%s' option '%s' conflicts " + msg = ("907: SAVE_CONFIG section '%s' option '%s' conflicts " "with included value" % (section, option)) raise gcode.error(msg) cmd_SAVE_CONFIG_help = "Overwrite config file and restart" @@ -393,7 +393,7 @@ def cmd_SAVE_CONFIG(self, gcmd): regular_data, old_autosave_data = self._find_autosave_data(data) config = self._build_config_wrapper(regular_data, cfgname) except error as e: - msg = "Unable to parse existing config on SAVE_CONFIG" + msg = "908: Unable to parse existing config on SAVE_CONFIG" logging.exception(msg) raise gcode.error(msg) regular_data = self._strip_duplicates(regular_data, self.autosave) @@ -416,7 +416,7 @@ def cmd_SAVE_CONFIG(self, gcmd): os.rename(cfgname, backup_name) os.rename(temp_name, cfgname) except: - msg = "Unable to write config file during SAVE_CONFIG" + msg = "909: Unable to write config file during SAVE_CONFIG" logging.exception(msg) raise gcode.error(msg) # Request a restart diff --git a/klippy/extras/a_axis_offset.py b/klippy/extras/a_axis_offset.py index 8e7de95032ab..ca8f5524fb7d 100644 --- a/klippy/extras/a_axis_offset.py +++ b/klippy/extras/a_axis_offset.py @@ -21,6 +21,7 @@ def __init__(self, config): 'SAVE_A_AXIS_POINT', self.cmd_SAVE_A_AXIS_POINT, desc=self.cmd_SAVE_A_AXIS_POINT_help) + cmd_SAVE_A_AXIS_POINT_help = "Save point for A axis offset" def cmd_SAVE_A_AXIS_POINT(self, gcmd): point_idx = gcmd.get_int('POINT', 0) coords = gcmd.get('COORDS', None) @@ -32,18 +33,17 @@ def cmd_SAVE_A_AXIS_POINT(self, gcmd): raise Exception except Exception: raise gcmd.error( - "a_axis_offset: improperly formatted entry for " + "207: a_axis_offset: improperly formatted entry for " "point\n%s" % (gcmd.get_commandline())) for axis, coord in enumerate(coords): self.point_coords[point_idx][axis] = coord - cmd_SAVE_A_AXIS_POINT_help = "Save point for A axis offset" - def _calc_a_axis_offset(self, point_0, point_1): offset = RAD_TO_DEG * math.asin((point_1[2] - point_0[2]) / math.hypot( point_1[1] - point_0[1], point_1[2] - point_0[2])) return offset + cmd_CALC_A_AXIS_OFFSET_help = "Calculate A axis offset" def cmd_CALC_A_AXIS_OFFSET(self, gcmd): offset = self._calc_a_axis_offset( self.point_coords[0], self.point_coords[1]) @@ -53,8 +53,7 @@ def cmd_CALC_A_AXIS_OFFSET(self, gcmd): offset_gcmd = self.gcode.create_gcode_command( 'SET_GCODE_OFFSET', 'SET_GCODE_OFFSET', {'A_ADJUST': offset}) self.gcode_move.cmd_SET_GCODE_OFFSET(offset_gcmd) - - cmd_CALC_A_AXIS_OFFSET_help = "Calculate A axis offset" + gcmd.respond_info("calculate offset for the axis A: %f." % offset) def load_config(config): diff --git a/klippy/extras/auto_wcs.py b/klippy/extras/auto_wcs.py index ba47e5b7412f..f34cd07db456 100644 --- a/klippy/extras/auto_wcs.py +++ b/klippy/extras/auto_wcs.py @@ -1,4 +1,5 @@ import math +import logging RAD_TO_DEG = 57.295779513 @@ -28,10 +29,8 @@ def __init__(self, config): self.probe_backlash_y = 0. self.probe_backlash_y_2 = 0. self.tooling_radius = 3. - self.tooling_radius_2 = 0. self.adjust_angle = 10 / RAD_TO_DEG self.gcode = self.printer.lookup_object('gcode') - self.printer.register_event_handler("klippy:ready", self._handle_ready) self.gcode.register_command( 'SAVE_WCS_CALC_POINT', self.cmd_SAVE_WCS_CALC_POINT, desc=self.cmd_SAVE_WCS_CALC_POINT_help) @@ -44,12 +43,12 @@ def __init__(self, config): self.gcode.register_command( 'GET_RADIUS_TOOLING', self.cmd_GET_RADIUS_TOOLING, desc=self.cmd_GET_RADIUS_TOOLING_help) - - def _handle_ready(self): - save_variables = self.printer.lookup_object('save_variables') - self.probe_backlash_x = save_variables.allVariables.get('probe_backlash_x', 0.) - self.probe_backlash_y = save_variables.allVariables.get('probe_backlash_y', 0.) - self.probe_backlash_y_2 = save_variables.allVariables.get('probe_backlash_y_2', 0.) + self.gcode.register_command( + 'SET_PROBE_BACKLASH', self.cmd_SET_PROBE_BACKLASH, + desc=self.cmd_SET_PROBE_BACKLASH_help) + self.gcode.register_command( + 'CALC_WCS_TOOL', self.cmd_CALC_WCS_TOOL, + desc=self.cmd_CALC_WCS_TOOL_help) def _calc_wcs_old_sensor(self, thickness, adj, gcmd): thickness = thickness / 2.0 @@ -83,64 +82,103 @@ def _calc_wcs_2_old_sensor(self, thickness, adj, gcmd): z = self.point_coords[0][2] - delta_z return x, y, z - def _calc_wcs_new_sensor(self, thickness, adj, gcmd): - thickness = thickness / 2. + def _calc_wcs_new_sensor(self): x = (self.point_coords[2][0] + self.point_coords[3][0]) / 2. y = (self.point_coords[1][1] + self.point_coords[7][1]) / 2. z = self.point_coords[0][2] return x, y, z - def _calc_wcs_2_new_sensor(self, thickness, adj, gcmd): - thickness = thickness / 2. + def _calc_wcs_2_new_sensor(self): len_thickness = 10. + thickness = len_thickness / 2. x = (self.point_coords[8][0] + self.point_coords[9][0]) / 2. - y = ((self.point_coords[5][1] + self.point_coords[6][1]) / 2.) - thickness - z = self.point_coords[4][2] - (len_thickness - adj) + y = (self.point_coords[5][1] + self.point_coords[6][1]) / 2. - thickness + z = self.point_coords[4][2] - len_thickness return x, y, z def calculate_probe_backlash(self, x1, y1, y2): self.probe_backlash_x = abs(self.point_coords[3][0] - (x1 + 55)) self.probe_backlash_y = abs(self.point_coords[5][1] - y2) self.probe_backlash_y_2 = abs(self.point_coords[1][1] - (y1 - 5)) + logging.info("""Probe backlash is set:\nprobe_backlash_x=%f, + probe_backlash_y=%f, probe_backlash_y_2=%f""" % (self.probe_backlash_x, + self.probe_backlash_y, + self.probe_backlash_y_2)) - def cmd_GET_RADIUS_TOOLING(self, gcmd): - x1, y1 = self.point_coords[1][0] + self.probe_backlash_x, self.point_coords[1][1] + def get_radius_full_mode(self, gcmd): + # calculate radius only whis probe_backlash_y for FULL mode + x1, y1 = self.point_coords[1][0] + self.probe_backlash_y, self.point_coords[1][1] x2, y2 = self.point_coords[0][0], self.point_coords[0][1] + self.probe_backlash_y - x3, y3 = self.point_coords[2][0] - self.probe_backlash_x, self.point_coords[2][1] + x3, y3 = self.point_coords[2][0] - self.probe_backlash_y, self.point_coords[2][1] c = (x1-x2)**2 + (y1-y2)**2 a = (x2-x3)**2 + (y2-y3)**2 b = (x3-x1)**2 + (y3-y1)**2 - s = 2*(a*b + b*c + c*a) - (a*a + b*b + c*c) - px = (a*(b+c-a)*x1 + b*(c+a-b)*x2 + c*(a+b-c)*x3) / s - py = (a*(b+c-a)*y1 + b*(c+a-b)*y2 + c*(a+b-c)*y3) / s + s= 2*(a*b + b*c + c*a) - (a*a + b*b + c*c) + centr_x = (a*(b+c-a)*x1 + b*(c+a-b)*x2 + c*(a+b-c)*x3) / s + centr_y = (a*(b+c-a)*y1 + b*(c+a-b)*y2 + c*(a+b-c)*y3) / s ar = a**0.5 br = b**0.5 cr = c**0.5 - r = ar*br*cr / ((ar+br+cr)*(-ar+br+cr)*(ar-br+cr)*(ar+br-cr))**0.5 - self.tooling_radius = r - gcmd.respond_info('radius_tooling_1= %s, centr_tool(%s;%s)' % (self.tooling_radius, px, py)) - self.get_radius_2(gcmd) - return px, py, r - cmd_GET_RADIUS_TOOLING_help = "command for get the tooling radius from measuring points." + radius = ar*br*cr / ((ar+br+cr)*(-ar+br+cr)*(ar-br+cr)*(ar+br-cr))**0.5 + gcmd.respond_info('radius_tooling= %s,(only backlash_y) centr_tool(%s;%s)' % ( + radius, centr_x, centr_y)) + return radius + + def get_radius_spiral_mode(self, gcmd): + # calculate radius for SPIARAL mode + x1, z1 = self.point_coords[1][0] + self.probe_backlash_x, self.point_coords[1][2] + # x2, z2 = self.point_coords[0][0], self.point_coords[0][2] + (self.tooling_radius - 5) + x2, z2 = self.point_coords[0][0], self.point_coords[0][2] - self.probe_backlash_x + x3, z3 = self.point_coords[2][0] - self.probe_backlash_x, self.point_coords[2][2] + c = (x1-x2)**2 + (z1-z2)**2 + a = (x2-x3)**2 + (z2-z3)**2 + b = (x3-x1)**2 + (z3-z1)**2 + s= 2*(a*b + b*c + c*a) - (a*a + b*b + c*c) + centr_x = (a*(b+c-a)*x1 + b*(c+a-b)*x2 + c*(a+b-c)*x3) / s + centr_y = (a*(b+c-a)*z1 + b*(c+a-b)*z2 + c*(a+b-c)*z3) / s + ar = a**0.5 + br = b**0.5 + cr = c**0.5 + radius = ar*br*cr / ((ar+br+cr)*(-ar+br+cr)*(ar-br+cr)*(ar+br-cr))**0.5 + gcmd.respond_info('radius_tooling= %s, centr_tool(%s;%s)' % ( + radius, centr_x, centr_y)) + return radius + + cmd_CALC_WCS_TOOL_help = "command for calculate wcs coordinate for SPIRALL-FULL." + def cmd_CALC_WCS_TOOL(self, gcmd): + wcs = gcmd.get_int('WCS') + ind_axis = gcmd.get_int('AXIS') + new_axis = (self.point_coords[0][ind_axis] + self.point_coords[1][ind_axis]) / 2. + gcode_move = self.printer.lookup_object('gcode_move') + old_axis = gcode_move.wcs_offsets[wcs][ind_axis] + diff_axis = new_axis - old_axis + self.wcs[wcs - 1][ind_axis] = new_axis + gcmd.respond_info("""calculated wcs_%d_%d=%f, + difference between tool and template=%f.""" % (wcs, ind_axis, new_axis, diff_axis)) + return new_axis - def get_radius_2(self, gcmd): - x1, y1 = self.point_coords[1][0] + self.probe_backlash_x, self.point_coords[1][1] - x2, y2 = self.point_coords[0][0], self.point_coords[0][1] + self.probe_backlash_y_2 - x3, y3 = self.point_coords[2][0] - self.probe_backlash_x, self.point_coords[2][1] - c = (x1-x2)**2 + (y1-y2)**2 - a = (x2-x3)**2 + (y2-y3)**2 - b = (x3-x1)**2 + (y3-y1)**2 - s = 2*(a*b + b*c + c*a) - (a*a + b*b + c*c) - px = (a*(b+c-a)*x1 + b*(c+a-b)*x2 + c*(a+b-c)*x3) / s - py = (a*(b+c-a)*y1 + b*(c+a-b)*y2 + c*(a+b-c)*y3) / s - ar = a**0.5 - br = b**0.5 - cr = c**0.5 - r = ar*br*cr / ((ar+br+cr)*(-ar+br+cr)*(ar-br+cr)*(ar+br-cr))**0.5 - self.tooling_radius_2 = r - gcmd.respond_info('radius_tooling_2= %s, centr_tool(%s;%s)' % (self.tooling_radius_2, px, py)) - return px, py, r + cmd_GET_RADIUS_TOOLING_help = "command for get the tooling radius from measuring points." + def cmd_GET_RADIUS_TOOLING(self, gcmd): + rough = gcmd.get_int('ROUGH', 0) + mode = gcmd.get('MODE', 'full') + if not rough: + if mode == 'full': + self.tooling_radius = self.get_radius_full_mode(gcmd) + elif mode == 'spiral': + self.tooling_radius = self.get_radius_spiral_mode(gcmd) + else: + # if needed calculate rough radius + gcode_move = self.printer.lookup_object('gcode_move') + if mode == 'full': + y = self.point_coords[0][1] + self.probe_backlash_y + self.tooling_radius = gcode_move.wcs_offsets[3][1] - y + elif mode == 'spiral': + z = self.point_coords[0][2] + self.tooling_radius = z - gcode_move.wcs_offsets[4][2] + gcmd.respond_info('rough radius_tooling= %s' % self.tooling_radius) + return self.tooling_radius + cmd_SAVE_WCS_CALC_POINT_help = "Save point for WCS calculation" def cmd_SAVE_WCS_CALC_POINT(self, gcmd): point_idx = gcmd.get_int('POINT', 0) coords = gcmd.get('COORDS', None) @@ -152,27 +190,26 @@ def cmd_SAVE_WCS_CALC_POINT(self, gcmd): raise Exception except Exception: raise gcmd.error( - "auto_wcs: improperly formatted entry for " + "206: auto_wcs: improperly formatted entry for " "point\n%s" % (gcmd.get_commandline())) for axis, coord in enumerate(coords): self.point_coords[point_idx][axis] = coord - cmd_SAVE_WCS_CALC_POINT_help = "Save point for WCS calculation" - + cmd_CALC_WCS_PARAMS_help = "Perform WCS calculation" def cmd_CALC_WCS_PARAMS(self, gcmd): #todo: get thickness default 10 - thickness = gcmd.get_float('THICKNESS', 10.) - adjustment_coeff = gcmd.get_float('ADJUSTMENT', .3) sensor_version = gcmd.get_int('SENSOR_VERSION', 0) if sensor_version: - x, y, z = self._calc_wcs_new_sensor(thickness, adjustment_coeff, gcmd) - x2, y2, z2 = self._calc_wcs_2_new_sensor(thickness, adjustment_coeff, gcmd) + x, y, z = self._calc_wcs_new_sensor() + x2, y2, z2 = self._calc_wcs_2_new_sensor() self.calculate_probe_backlash(x, y, y2) delta_y = y - y2 delta_z = z - z2 avg_delta = (delta_y + delta_z) / 2.0 gcmd.respond_info("D_Y: %.3f, D_Z: %.3f, Avg_D: %.3f" % (delta_y, delta_z, avg_delta)) else: + thickness = gcmd.get_float('THICKNESS', 10.) + adjustment_coeff = gcmd.get_float('ADJUSTMENT', .3) x, y, z = self._calc_wcs_old_sensor(thickness, adjustment_coeff, gcmd) x2, y2, z2 = self._calc_wcs_2_old_sensor(thickness, adjustment_coeff, gcmd) out = "Calculated WCS 1 center: X:%.6f, Y:%.6f, Z:%.6f\n" % ( @@ -183,8 +220,6 @@ def cmd_CALC_WCS_PARAMS(self, gcmd): self.wcs[1] = [x2, y2, z2] gcmd.respond_info(out) - cmd_CALC_WCS_PARAMS_help = "Perform WCS calculation" - def cmd_SET_AUTO_WCS(self, gcmd): point_idx = gcmd.get_int('WCS', 0) coords = gcmd.get('COORDS', None) @@ -196,12 +231,20 @@ def cmd_SET_AUTO_WCS(self, gcmd): raise Exception except Exception: raise gcmd.error( - "auto_wcs: improperly formatted entry for " + "208: auto_wcs: improperly formatted entry for " "point\n%s" % (gcmd.get_commandline())) for axis, coord in enumerate(coords): self.wcs[point_idx][axis] = coord - cmd_CALC_WCS_PARAMS_help = "Perform WCS calculation" + cmd_SET_PROBE_BACKLASH_help = "Set the sensor backlash for the current sensor." + def cmd_SET_PROBE_BACKLASH(self, gcmd): + self.probe_backlash_x = gcmd.get_float('BACKLASH_X', self.probe_backlash_x) + self.probe_backlash_y = gcmd.get_float('BACKLASH_Y', self.probe_backlash_y) + self.probe_backlash_y_2 = gcmd.get_float('BACKLASH_Y_2', self.probe_backlash_y_2) + gcmd.respond_info( + 'Probe backlash is set:\nprobe_backlash_x=%f, probe_backlash_y=%f, probe_backlash_y_2=%f' % ( + self.probe_backlash_x, self.probe_backlash_y, self.probe_backlash_y_2) + ) def get_status(self, eventtime=None): return { @@ -209,9 +252,9 @@ def get_status(self, eventtime=None): "probe_backlash_x": self.probe_backlash_x, "probe_backlash_y": self.probe_backlash_y, "probe_backlash_y_2": self.probe_backlash_y_2, - 'tooling_radius': self.tooling_radius, - 'tooling_radius_2': self.tooling_radius_2 + 'tooling_radius': self.tooling_radius } + def load_config(config): return AutoWcs(config) diff --git a/klippy/extras/b_axis_compensation.py b/klippy/extras/b_axis_compensation.py index 69c0ffa20dfc..f7721506449e 100644 --- a/klippy/extras/b_axis_compensation.py +++ b/klippy/extras/b_axis_compensation.py @@ -126,7 +126,7 @@ def cmd_SAVE_B_AXIS_POINT(self, gcmd): raise Exception except Exception: raise gcmd.error( - "b_axis_compensation: improperly formatted entry for " + "209: b_axis_compensation: improperly formatted entry for " "point\n%s" % (gcmd.get_commandline())) for axis, coord in enumerate(coords): self.point_coords[point_idx][axis] = coord diff --git a/klippy/extras/bed_mesh.py b/klippy/extras/bed_mesh.py index ad01e9a4b848..d6c1e8118724 100644 --- a/klippy/extras/bed_mesh.py +++ b/klippy/extras/bed_mesh.py @@ -54,18 +54,18 @@ def parse_config_pair(config, option, default, minval=None, maxval=None): pair = config.getintlist(option, (default, default)) if len(pair) != 2: if len(pair) != 1: - raise config.error("bed_mesh: malformed '%s' value: %s" + raise config.error("2010: bed_mesh: malformed '%s' value: %s" % (option, config.get(option))) pair = (pair[0], pair[0]) if minval is not None: if pair[0] < minval or pair[1] < minval: raise config.error( - "Option '%s' in section bed_mesh must have a minimum of %s" + "2011: Option '%s' in section bed_mesh must have a minimum of %s" % (option, str(minval))) if maxval is not None: if pair[0] > maxval or pair[1] > maxval: raise config.error( - "Option '%s' in section bed_mesh must have a maximum of %s" + "2012: Option '%s' in section bed_mesh must have a maximum of %s" % (option, str(maxval))) return pair @@ -76,18 +76,18 @@ def parse_gcmd_pair(gcmd, name, minval=None, maxval=None): try: pair = [int(v.strip()) for v in gcmd.get(name).split(',')] except: - raise gcmd.error("Unable to parse parameter '%s'" % (name,)) + raise gcmd.error("2013: Unable to parse parameter '%s'" % (name,)) if len(pair) != 2: if len(pair) != 1: - raise gcmd.error("Unable to parse parameter '%s'" % (name,)) + raise gcmd.error("2014: Unable to parse parameter '%s'" % (name,)) pair = (pair[0], pair[0]) if minval is not None: if pair[0] < minval or pair[1] < minval: - raise gcmd.error("Parameter '%s' must have a minimum of %d" + raise gcmd.error("2015: Parameter '%s' must have a minimum of %d" % (name, minval)) if maxval is not None: if pair[0] > maxval or pair[1] > maxval: - raise gcmd.error("Parameter '%s' must have a maximum of %d" + raise gcmd.error("2016: Parameter '%s' must have a maximum of %d" % (name, maxval)) return pair @@ -98,7 +98,7 @@ def parse_gcmd_coord(gcmd, name): try: v1, v2 = [float(v.strip()) for v in gcmd.get(name).split(',')] except: - raise gcmd.error("Unable to parse parameter '%s'" % (name,)) + raise gcmd.error("2017: Unable to parse parameter '%s'" % (name,)) return v1, v2 @@ -167,7 +167,7 @@ def set_mesh(self, mesh): self.z_mesh = None self.fade_target = 0. raise self.gcode.error( - "bed_mesh: ERROR, fade_target lies outside of mesh z " + "2018: bed_mesh: ERROR, fade_target lies outside of mesh z " "range\nmin: %.4f, max: %.4f, fade_target: %.4f" % (min_z, max_z, err_target)) min_z, max_z = mesh.get_z_range() @@ -175,7 +175,7 @@ def set_mesh(self, mesh): self.z_mesh = None self.fade_target = 0. raise self.gcode.error( - "bed_mesh: Mesh extends outside of the fade range, " + "2019: bed_mesh: Mesh extends outside of the fade range, " "please see the fade_start and fade_end options in" "example-extras.cfg. fade distance: %.2f mesh min: %.4f" "mesh max: %.4f" % (self.fade_dist, min_z, max_z)) @@ -240,7 +240,7 @@ def move(self, newpos, speed): self.next_transform.move(split_move, speed) else: raise self.gcode.error( - "Mesh Leveling: Error splitting move ") + "2020: Mesh Leveling: Error splitting move ") self.last_position[:] = newpos def get_status(self, eventtime=None): @@ -348,7 +348,7 @@ def _generate_points(self, error): x_dist = math.floor(x_dist * 100) / 100 y_dist = math.floor(y_dist * 100) / 100 if x_dist < 1. or y_dist < 1.: - raise error("bed_mesh: min/max points too close together") + raise error("2021: bed_mesh: min/max points too close together") if self.radius is not None: # round bed, min/max needs to be recalculated @@ -416,7 +416,7 @@ def _generate_points(self, error): if dist_from_origin <= self.radius: valid_coords.append(ac) if not valid_coords: - raise error("bed_mesh: Unable to generate coordinates" + raise error("2022: bed_mesh: Unable to generate coordinates" " for faulty region at index: %d" % (i)) self.substituted_indices[i] = valid_coords @@ -454,7 +454,7 @@ def _init_mesh_config(self, config): # round beds must have an odd number of points along each axis if not x_cnt & 1: raise config.error( - "bed_mesh: probe_count must be odd for round beds") + "2023: bed_mesh: probe_count must be odd for round beds") # radius may have precision to .1mm self.radius = math.floor(self.radius * 10) / 10 orig_cfg['radius'] = self.radius @@ -468,7 +468,7 @@ def _init_mesh_config(self, config): min_x, min_y = config.getfloatlist('mesh_min', count=2) max_x, max_y = config.getfloatlist('mesh_max', count=2) if max_x <= min_x or max_y <= min_y: - raise config.error('bed_mesh: invalid min/max points') + raise config.error('2024: bed_mesh: invalid min/max points') orig_cfg['x_count'] = mesh_cfg['x_count'] = x_cnt orig_cfg['y_count'] = mesh_cfg['y_count'] = y_cnt orig_cfg['mesh_min'] = self.mesh_min = (min_x, min_y) @@ -504,7 +504,7 @@ def _init_mesh_config(self, config): for coord in [prev_c1, prev_c2, prev_c3, prev_c4]: if within(coord, c1, c3): raise config.error( - "bed_mesh: Existing faulty_region_%d %s overlaps " + "2025: bed_mesh: Existing faulty_region_%d %s overlaps " "added faulty_region_%d %s" % (j+1, repr([prev_c1, prev_c3]), i, repr([c1, c3]))) @@ -512,7 +512,7 @@ def _init_mesh_config(self, config): for coord in [c1, c2, c3, c4]: if within(coord, prev_c1, prev_c3): raise config.error( - "bed_mesh: Added faulty_region_%d %s overlaps " + "2026: bed_mesh: Added faulty_region_%d %s overlaps " "existing faulty_region_%d %s" % (i, repr([c1, c3]), j+1, repr([prev_c1, prev_c3]))) @@ -525,7 +525,7 @@ def _verify_algorithm(self, error): y_pps = params['mesh_y_pps'] if params['algo'] not in self.ALGOS: raise error( - "bed_mesh: Unknown algorithm <%s>" + "2027: bed_mesh: Unknown algorithm <%s>" % (self.mesh_config['algo'])) # Check the algorithm against the current configuration max_probe_cnt = max(params['x_count'], params['y_count']) @@ -537,20 +537,20 @@ def _verify_algorithm(self, error): # Lagrange interpolation tends to oscillate when using more # than 6 samples raise error( - "bed_mesh: cannot exceed a probe_count of 6 when using " + "2028: bed_mesh: cannot exceed a probe_count of 6 when using " "lagrange interpolation. Configured Probe Count: %d, %d" % (self.mesh_config['x_count'], self.mesh_config['y_count'])) elif params['algo'] == 'bicubic' and min_probe_cnt < 4: if max_probe_cnt > 6: raise error( - "bed_mesh: invalid probe_count option when using bicubic " + "2029: bed_mesh: invalid probe_count option when using bicubic " "interpolation. Combination of 3 points on one axis with " "more than 6 on another is not permitted. " "Configured Probe Count: %d, %d" % (self.mesh_config['x_count'], self.mesh_config['y_count'])) else: logging.info( - "bed_mesh: bicubic interpolation with a probe_count of " + "2030: bed_mesh: bicubic interpolation with a probe_count of " "less than 4 points detected. Forcing lagrange " "interpolation. Configured Probe Count: %d, %d" % (self.mesh_config['x_count'], self.mesh_config['y_count'])) @@ -641,7 +641,7 @@ def _get_adjusted_points(self): def cmd_BED_MESH_CALIBRATE(self, gcmd): self._profile_name = gcmd.get('PROFILE', "default") if not self._profile_name.strip(): - raise gcmd.error("Value for parameter 'PROFILE' must be specified") + raise gcmd.error("2031: Value for parameter 'PROFILE' must be specified") self.bedmesh.set_mesh(None) self.update_config(gcmd) self.probe_helper.start_probe(gcmd) @@ -686,7 +686,7 @@ def probe_finalize(self, offsets, positions): if len(self.points) != len(corrected_pts): self._dump_points(positions, corrected_pts, offsets) raise self.gcode.error( - "bed_mesh: invalid position list size, " + "2024: bed_mesh: invalid position list size, " "generated count: %d, probed count: %d" % (len(self.points), len(corrected_pts))) for gen_pt, probed in zip(self.points, corrected_pts): @@ -695,7 +695,7 @@ def probe_finalize(self, offsets, positions): not isclose(off_pt[1], probed[1], abs_tol=.1): self._dump_points(positions, corrected_pts, offsets) raise self.gcode.error( - "bed_mesh: point mismatch, orig = (%.2f, %.2f)" + "2024: bed_mesh: point mismatch, orig = (%.2f, %.2f)" ", probed = (%.2f, %.2f)" % (off_pt[0], off_pt[1], probed[0], probed[1])) positions = corrected_pts @@ -726,7 +726,7 @@ def probe_finalize(self, offsets, positions): # make sure the y-axis is the correct length if len(probed_matrix) != y_cnt: raise self.gcode.error( - ("bed_mesh: Invalid y-axis table length\n" + ("2024: bed_mesh: Invalid y-axis table length\n" "Probed table length: %d Probed Table:\n%s") % (len(probed_matrix), str(probed_matrix))) @@ -736,7 +736,7 @@ def probe_finalize(self, offsets, positions): row_size = len(row) if not row_size & 1: # an even number of points in a row shouldn't be possible - msg = "bed_mesh: incorrect number of points sampled on X\n" + msg = "2024: bed_mesh: incorrect number of points sampled on X\n" msg += "Probed Table:\n" msg += str(probed_matrix) raise self.gcode.error(msg) @@ -752,7 +752,7 @@ def probe_finalize(self, offsets, positions): for row in probed_matrix: if len(row) != x_cnt: raise self.gcode.error( - ("bed_mesh: invalid x-axis table length\n" + ("2024: bed_mesh: invalid x-axis table length\n" "Probed table length: %d Probed Table:\n%s") % (len(probed_matrix), str(probed_matrix))) @@ -760,7 +760,7 @@ def probe_finalize(self, offsets, positions): try: z_mesh.build_mesh(probed_matrix) except BedMeshError as e: - raise self.gcode.error(str(e)) + raise self.gcode.error("2024: %s" % str(e)) self.bedmesh.set_mesh(z_mesh) self.gcode.respond_info("Mesh Bed Leveling Complete") self.bedmesh.save_profile(self._profile_name) @@ -820,7 +820,7 @@ def _set_next_move(self, distance_from_prev): t = distance_from_prev / self.total_move_length if t > 1. or t < 0.: raise self.gcode.error( - "bed_mesh: Slice distance is negative " + "2024: bed_mesh: Slice distance is negative " "or greater than entire move length") for i in range(6): if self.axis_move[i]: @@ -1267,14 +1267,14 @@ def load_profile(self, prof_name): profile = self.profiles.get(prof_name, None) if profile is None: raise self.gcode.error( - "bed_mesh: Unknown profile [%s]" % prof_name) + "2024: bed_mesh: Unknown profile [%s]" % prof_name) probed_matrix = profile['points'] mesh_params = profile['mesh_params'] z_mesh = ZMesh(mesh_params) try: z_mesh.build_mesh(probed_matrix) except BedMeshError as e: - raise self.gcode.error(str(e)) + raise self.gcode.error("2024: %s" % str(e)) self.current_profile = prof_name self.bedmesh.set_mesh(z_mesh) @@ -1282,7 +1282,7 @@ def add_profile(self, prof_name, gcmd): profile = self.profiles.get(prof_name, None) if profile is None: raise self.gcode.error( - "bed_mesh: Unknown profile [%s]" % prof_name) + "2024: bed_mesh: Unknown profile [%s]" % prof_name) else: mesh_params = profile['mesh_params'] probed_matrix = list(list(line) for line in profile['points']) diff --git a/klippy/extras/bus.py b/klippy/extras/bus.py index f37897d83114..5021b6d712f5 100644 --- a/klippy/extras/bus.py +++ b/klippy/extras/bus.py @@ -19,10 +19,10 @@ def resolve_bus_name(mcu, param, bus): if bus is None: rev_enums = {v: k for k, v in enums.items()} if 0 not in rev_enums: - raise ppins.error("Must specify %s on mcu '%s'" % (param, mcu_name)) + raise ppins.error("3025: Must specify %s on mcu '%s'" % (param, mcu_name)) bus = rev_enums[0] if bus not in enums: - raise ppins.error("Unknown %s '%s'" % (param, bus)) + raise ppins.error("3026: Unknown %s '%s'" % (param, bus)) # Check for reserved bus pins constants = mcu.get_constants() reserve_pins = constants.get('BUS_PINS_%s' % (bus,), None) @@ -125,7 +125,7 @@ def MCU_SPI_from_config(config, mode, pin_option="cs_pin", for name in sw_pin_names] for pin_params in sw_pin_params: if pin_params['chip'] != mcu: - raise ppins.error("%s: spi pins must be on same mcu" % ( + raise ppins.error("3027: %s: spi pins must be on same mcu" % ( config.get_name(),)) sw_pins = tuple([pin_params['pin'] for pin_params in sw_pin_params]) bus = None @@ -223,7 +223,7 @@ def __init__(self, mcu, pin_desc, cmd_queue=None, value=0): ppins = mcu.get_printer().lookup_object('pins') pin_params = ppins.lookup_pin(pin_desc) if pin_params['chip'] is not mcu: - raise ppins.error("Pin %s must be on mcu %s" % ( + raise ppins.error("3028: Pin %s must be on mcu %s" % ( pin_desc, mcu.get_name())) mcu.add_config_cmd("config_digital_out oid=%d pin=%s value=%d" " default_value=%d max_duration=%d" diff --git a/klippy/extras/buttons.py b/klippy/extras/buttons.py index 1a6147d1df28..b33b2d0a1a9d 100644 --- a/klippy/extras/buttons.py +++ b/klippy/extras/buttons.py @@ -275,7 +275,7 @@ def register_buttons(self, pins, callback): for pin in pins: pin_params = ppins.lookup_pin(pin, can_invert=True, can_pullup=True) if mcu is not None and pin_params['chip'] != mcu: - raise ppins.error("button pins must be on same mcu") + raise ppins.error("3029: button pins must be on same mcu") mcu = pin_params['chip'] mcu_name = pin_params['chip_name'] pin_params_list.append(pin_params) @@ -294,7 +294,7 @@ def register_rotary_encoder(self, pin1, pin2, cw_callback, ccw_callback, re = FullStepRotaryEncoder(cw_callback, ccw_callback) else: raise self.printer.config_error( - "%d steps per detent not supported" % steps_per_detent) + "3030: %d steps per detent not supported" % steps_per_detent) self.register_buttons([pin1, pin2], re.encoder_callback) def register_button_push(self, pin, callback): def helper(eventtime, state, callback=callback): diff --git a/klippy/extras/c_axis_align.py b/klippy/extras/c_axis_align.py index 2adf74231889..a00b720f289b 100644 --- a/klippy/extras/c_axis_align.py +++ b/klippy/extras/c_axis_align.py @@ -32,7 +32,7 @@ def cmd_SAVE_C_AXIS_POINT(self, gcmd): raise Exception except Exception: raise gcmd.error( - "a_axis_offset: improperly formatted entry for " + "2032: a_axis_offset: improperly formatted entry for " "point\n%s" % (gcmd.get_commandline())) for axis, coord in enumerate(coords): self.point_coords[point_idx][axis] = coord diff --git a/klippy/extras/canbus_ids.py b/klippy/extras/canbus_ids.py index f96510fadfa5..5a8a3c66a956 100644 --- a/klippy/extras/canbus_ids.py +++ b/klippy/extras/canbus_ids.py @@ -12,13 +12,13 @@ def __init__(self, config): self.ids = {} def add_uuid(self, config, canbus_uuid, canbus_iface): if canbus_uuid in self.ids: - raise config.error("Duplicate canbus_uuid") + raise config.error("3031: Duplicate canbus_uuid") new_id = len(self.ids) + NODEID_FIRST self.ids[canbus_uuid] = new_id return new_id def get_nodeid(self, canbus_uuid): if canbus_uuid not in self.ids: - raise self.printer.config_error("Unknown canbus_uuid %s" + raise self.printer.config_error("3032: Unknown canbus_uuid %s" % (canbus_uuid,)) return self.ids[canbus_uuid] diff --git a/klippy/extras/controller_fan.py b/klippy/extras/controller_fan.py index df141e7eb7d1..333560f76da1 100644 --- a/klippy/extras/controller_fan.py +++ b/klippy/extras/controller_fan.py @@ -37,7 +37,7 @@ def handle_connect(self): return if not all(x in all_steppers for x in self.stepper_names): raise self.printer.config_error( - "One or more of these steppers are unknown: " + "3033: One or more of these steppers are unknown: " "%s (valid steppers are: %s)" % (self.stepper_names, ", ".join(all_steppers))) def handle_ready(self): diff --git a/klippy/extras/display/__init__.py b/klippy/extras/display/__init__.py index 1cea00e02297..53e42d6eb0bf 100644 --- a/klippy/extras/display/__init__.py +++ b/klippy/extras/display/__init__.py @@ -11,11 +11,11 @@ def load_config(config): def load_config_prefix(config): if not config.has_section('display'): raise config.error( - "A primary [display] section must be defined in printer.cfg " + "0018: A primary [display] section must be defined in printer.cfg " "to use auxilary displays") name = config.get_name().split()[-1] if name == "display": raise config.error( - "Section name [display display] is not valid. " + "0019: Section name [display display] is not valid. " "Please choose a different postfix.") return display.load_config(config) diff --git a/klippy/extras/endstop_phase.py b/klippy/extras/endstop_phase.py index feb9e8b8b082..4ffaaae75a19 100644 --- a/klippy/extras/endstop_phase.py +++ b/klippy/extras/endstop_phase.py @@ -39,7 +39,7 @@ def calc_phase(self, stepper, trig_mcu_pos): mcu_phase_offset, phases = self.tmc_module.get_phase_offset() if mcu_phase_offset is None: if self.printer.get_start_args().get('debugoutput') is None: - raise self.printer.command_error("Stepper %s phase unknown" + raise self.printer.command_error("3034: Stepper %s phase unknown" % (self.name,)) mcu_phase_offset = 0 phase = (trig_mcu_pos + mcu_phase_offset) % self.phases @@ -71,7 +71,7 @@ def __init__(self, config): if trigger_phase is not None: p, ps = config.getintlist('trigger_phase', sep='/', count=2) if p >= ps: - raise config.error("Invalid trigger_phase '%s'" + raise config.error("3035: Invalid trigger_phase '%s'" % (trigger_phase,)) self.endstop_phase = self.phase_calc.convert_phase(p, ps) self.endstop_align_zero = config.getboolean('endstop_align_zero', False) @@ -87,7 +87,7 @@ def __init__(self, config): self.endstop_phase_accuracy = int( math.ceil(self.endstop_accuracy / self.step_dist)) if self.endstop_phase_accuracy >= self.phases // 2: - raise config.error("Endstop for %s is not accurate enough for" + raise config.error("3036: Endstop for %s is not accurate enough for" " stepper phase adjustment" % (self.name,)) if self.printer.get_start_args().get('debugoutput') is not None: self.endstop_phase_accuracy = self.phases @@ -113,7 +113,7 @@ def get_homed_offset(self, stepper, trig_mcu_pos): delta -= self.phases elif delta > self.endstop_phase_accuracy: raise self.printer.command_error( - "Endstop %s incorrect phase (got %d vs %d)" % ( + "3037: Endstop %s incorrect phase (got %d vs %d)" % ( self.name, phase, self.endstop_phase)) return delta * self.step_dist def handle_home_rails_end(self, homing_state, rails): @@ -175,7 +175,7 @@ def cmd_ENDSTOP_PHASE_CALIBRATE(self, gcmd): return phase_calc = self.tracking.get(stepper_name) if phase_calc is None or phase_calc.phase_history is None: - raise gcmd.error("Stats not available for stepper %s" + raise gcmd.error("3037: Stats not available for stepper %s" % (stepper_name,)) endstop_phase, phases = self.generate_stats(stepper_name, phase_calc) if not phase_calc.is_primary: diff --git a/klippy/extras/force_move.py b/klippy/extras/force_move.py index 2ba4d5de5df1..c49694aa5318 100644 --- a/klippy/extras/force_move.py +++ b/klippy/extras/force_move.py @@ -59,7 +59,7 @@ def register_stepper(self, config, mcu_stepper): def lookup_stepper(self, name): if name not in self.steppers: - raise self.printer.config_error("Unknown stepper %s" % (name,)) + raise self.printer.config_error("9011: Unknown stepper %s" % (name,)) return self.steppers[name] def _force_enable(self, stepper): @@ -106,7 +106,7 @@ def manual_move(self, stepper, dist, speed, accel=0.): def _lookup_stepper(self, gcmd): name = gcmd.get('STEPPER') if name not in self.steppers: - raise gcmd.error("Unknown stepper %s" % (name,)) + raise gcmd.error("9010: Unknown stepper %s" % (name,)) return self.steppers[name] cmd_STEPPER_BUZZ_help = "Oscillate a given stepper to help id it" diff --git a/klippy/extras/gcode_macro.py b/klippy/extras/gcode_macro.py index 52ee745d46a7..b7985fb983e1 100644 --- a/klippy/extras/gcode_macro.py +++ b/klippy/extras/gcode_macro.py @@ -50,7 +50,7 @@ def __init__(self, printer, env, name, script): try: self.template = env.from_string(script) except Exception as e: - msg = "Error loading template '%s': %s" % ( + msg = "0016: Error loading template '%s': %s" % ( name, traceback.format_exception_only(type(e), e)[-1]) logging.exception(msg) raise printer.config_error(msg) @@ -60,7 +60,7 @@ def render(self, context=None): try: return str(self.template.render(context)) except Exception as e: - msg = "Error evaluating '%s': %s" % ( + msg = "0017: Error evaluating '%s': %s" % ( self.name, traceback.format_exception_only(type(e), e)[-1]) logging.exception(msg) raise self.gcode.error(msg) @@ -101,6 +101,9 @@ def _action_stop_for_power_off(self, msg="action_stop_for_power_off"): def _action_respond_info(self, msg): self.printer.lookup_object('gcode').respond_info(msg) return "" + def _action_respond_warning(self, msg): + self.printer.lookup_object('gcode').respond_warning(msg) + return "" def _action_raise_error(self, msg): raise self.printer.command_error(msg) def _action_call_remote_method(self, method, **kwargs): @@ -115,6 +118,7 @@ def create_template_context(self, eventtime=None): 'printer': GetStatusWrapper(self.printer, eventtime), 'action_emergency_stop': self._action_emergency_stop, 'action_respond_info': self._action_respond_info, + 'action_respond_warning': self._action_respond_warning, 'action_raise_error': self._action_raise_error, 'action_call_remote_method': self._action_call_remote_method, 'action_stop_for_power_off': self._action_stop_for_power_off @@ -171,7 +175,7 @@ def handle_connect(self): prev_cmd = self.gcode.register_command(self.alias, None) if prev_cmd is None: raise self.printer.config_error( - "Existing command '%s' not found in gcode_macro rename" + "0020: Existing command '%s' not found in gcode_macro rename" % (self.alias,)) pdesc = "Renamed builtin of '%s'" % (self.alias,) self.gcode.register_command(self.rename_existing, prev_cmd, desc=pdesc) diff --git a/klippy/extras/gcode_move.py b/klippy/extras/gcode_move.py index 9d2de20a02bd..e889afb51496 100644 --- a/klippy/extras/gcode_move.py +++ b/klippy/extras/gcode_move.py @@ -128,7 +128,7 @@ def _handle_home_rails_end(self, homing_state, rails): def set_move_transform(self, transform, force=False): if self.move_transform is not None and not force: raise self.printer.config_error( - "G-Code move transform already specified") + "102: G-Code move transform already specified") old_transform = self.move_transform if old_transform is None: old_transform = self.printer.lookup_object('toolhead', None) @@ -218,7 +218,7 @@ def cmd_G1(self, gcmd): if 'F' in params: gcode_speed = float(params['F']) if gcode_speed <= 0.: - raise gcmd.error("Invalid speed in '%s'" + raise gcmd.error("103: Invalid speed in '%s'" % (gcmd.get_commandline(),)) self.speed = gcode_speed * self.speed_factor if with_rotation and self.radius > 0. and self.radial_speed_compensation_enabled: @@ -229,7 +229,7 @@ def cmd_G1(self, gcmd): if self.rotary_speed < self.square_corner_velocity: self.rotary_speed = self.square_corner_velocity except ValueError as e: - raise gcmd.error("Unable to parse move '%s'" + raise gcmd.error("104: Unable to parse move '%s'" % (gcmd.get_commandline(),)) self.move_with_transform(self.last_position, \ self.rotary_speed if with_rotation and self.radius > 0. \ @@ -301,6 +301,12 @@ def cmd_SET_GCODE_OFFSET(self, gcmd): if offset is None: continue offset += self.homing_position[pos] + # if offset > 0.0: + # msg = """Offset %f for the %s axis will cause movement + # outside the coordinate system.""" % (offset, axis) + # gcmd.respond_info(msg) + # logging.warning(msg) + # continue delta = offset - self.homing_position[pos] move_delta[pos] = delta self.base_position[pos] += delta @@ -335,7 +341,7 @@ def cmd_RESTORE_GCODE_STATE(self, gcmd): state_name = gcmd.get('NAME', 'default') state = self.saved_states.get(state_name) if state is None: - raise gcmd.error("Unknown g-code state: %s" % (state_name,)) + raise gcmd.error("105: Unknown g-code state: %s" % (state_name,)) # Restore state self.absolute_coord = state['absolute_coord'] self.absolute_extrude = state['absolute_extrude'] @@ -411,7 +417,7 @@ def cmd_LOAD_GCODE_STATE(self, gcmd): def cmd_GET_POSITION(self, gcmd): toolhead = self.printer.lookup_object('toolhead', None) if toolhead is None: - raise gcmd.error("Printer not ready") + raise gcmd.error("106: Printer not ready") kin = toolhead.get_kinematics() steppers = kin.get_steppers() mcu_pos = " ".join(["%s:%d" % (s.get_name(), s.get_mcu_position()) @@ -689,11 +695,11 @@ def process_move_with_compensation(self, gcmd): if 'F' in params: gcode_speed = float(params['F']) if gcode_speed <= 0.: - raise gcmd.error("Invalid speed in '%s'" + raise gcmd.error("107: Invalid speed in '%s'" % (gcmd.get_commandline(),)) self.speed = gcode_speed * self.speed_factor except ValueError as e: - raise gcmd.error("Unable to parse move '%s'" + raise gcmd.error("108: Unable to parse move '%s'" % (gcmd.get_commandline(),)) positions = self._calc_compensation(new_position) for position in positions: diff --git a/klippy/extras/heaters.py b/klippy/extras/heaters.py index b0b2c16df6af..a0c5975992de 100644 --- a/klippy/extras/heaters.py +++ b/klippy/extras/heaters.py @@ -96,7 +96,7 @@ def get_smooth_time(self): def set_temp(self, degrees): if degrees and (degrees < self.min_temp or degrees > self.max_temp): raise self.printer.command_error( - "Requested temperature (%.1f) out of range (%.1f:%.1f)" + "3039: Requested temperature (%.1f) out of range (%.1f:%.1f)" % (degrees, self.min_temp, self.max_temp)) with self.lock: self.target_temp = degrees @@ -250,7 +250,7 @@ def load_config(self, config): try: dconfig = pconfig.read_config(filename) except Exception: - raise config.config_error("Cannot load config '%s'" % (filename,)) + raise config.config_error("3040: Cannot load config '%s'" % (filename,)) for c in dconfig.get_prefix_sections(''): self.printer.load_object(dconfig, c.get_name()) def add_sensor_factory(self, sensor_type, sensor_factory): @@ -258,7 +258,7 @@ def add_sensor_factory(self, sensor_type, sensor_factory): def setup_heater(self, config, gcode_id=None): heater_name = config.get_name().split()[-1] if heater_name in self.heaters: - raise config.error("Heater %s already registered" % (heater_name,)) + raise config.error("3041: Heater %s already registered" % (heater_name,)) # Setup sensor sensor = self.setup_sensor(config) # Create heater @@ -271,7 +271,7 @@ def get_all_heaters(self): def lookup_heater(self, heater_name): if heater_name not in self.heaters: raise self.printer.config_error( - "Unknown heater '%s'" % (heater_name,)) + "3042: Unknown heater '%s'" % (heater_name,)) return self.heaters[heater_name] def setup_sensor(self, config): if not self.have_load_sensors: @@ -279,7 +279,7 @@ def setup_sensor(self, config): sensor_type = config.get('sensor_type') if sensor_type not in self.sensor_factories: raise self.printer.config_error( - "Unknown temperature sensor '%s'" % (sensor_type,)) + "3044: Unknown temperature sensor '%s'" % (sensor_type,)) if sensor_type == 'NTC 100K beta 3950': config.deprecate('sensor_type', 'NTC 100K beta 3950') return self.sensor_factories[sensor_type](config) @@ -291,7 +291,7 @@ def register_sensor(self, config, psensor, gcode_id=None): return if gcode_id in self.gcode_id_to_sensor: raise self.printer.config_error( - "G-Code sensor id %s already registered" % (gcode_id,)) + "3043: G-Code sensor id %s already registered" % (gcode_id,)) self.gcode_id_to_sensor[gcode_id] = psensor def get_status(self, eventtime): return {'available_heaters': self.available_heaters, @@ -344,12 +344,12 @@ def set_temperature(self, heater, temp, wait=False): def cmd_TEMPERATURE_WAIT(self, gcmd): sensor_name = gcmd.get('SENSOR') if sensor_name not in self.available_sensors: - raise gcmd.error("Unknown sensor '%s'" % (sensor_name,)) + raise gcmd.error("3046: Unknown sensor '%s'" % (sensor_name,)) min_temp = gcmd.get_float('MINIMUM', float('-inf')) max_temp = gcmd.get_float('MAXIMUM', float('inf'), above=min_temp) if min_temp == float('-inf') and max_temp == float('inf'): raise gcmd.error( - "Error on 'TEMPERATURE_WAIT': missing MINIMUM or MAXIMUM.") + "3045: Error on 'TEMPERATURE_WAIT': missing MINIMUM or MAXIMUM.") if self.printer.get_start_args().get('debugoutput') is not None: return if sensor_name in self.heaters: diff --git a/klippy/extras/homing.py b/klippy/extras/homing.py index 877f2f9bfad7..eb859bafc4e0 100644 --- a/klippy/extras/homing.py +++ b/klippy/extras/homing.py @@ -149,7 +149,7 @@ def homing_move(self, movepos, speed, probe_pos=False, if error is None: error = str(e) if error is not None: - raise self.printer.command_error(error) + raise self.printer.command_error("3047: %s" % error) return trigpos def check_no_movement(self): @@ -235,7 +235,7 @@ def home_rails(self, rails, forcepos, movepos): hmove.homing_move(homepos, hi.second_homing_speed) if hmove.check_no_movement() is not None: raise self.printer.command_error( - "Endstop %s still triggered after retract" + "3048: Endstop %s still triggered after retract" % (hmove.check_no_movement(),)) # Signal home operation complete self.toolhead.flush_step_generation() @@ -272,7 +272,7 @@ def manual_home(self, toolhead, endstops, pos, speed, except self.printer.command_error: if self.printer.is_shutdown(): raise self.printer.command_error( - "Homing failed due to printer shutdown") + "3049: Homing failed due to printer shutdown") raise def probing_move(self, mcu_probe, pos, speed): @@ -283,11 +283,11 @@ def probing_move(self, mcu_probe, pos, speed): except self.printer.command_error: if self.printer.is_shutdown(): raise self.printer.command_error( - "Probing failed due to printer shutdown") + "3050: Probing failed due to printer shutdown") raise if hmove.check_no_movement() is not None: raise self.printer.command_error( - "Probe triggered prior to movement") + "3051: Probe triggered prior to movement") return epos def cmd_G28(self, gcmd): @@ -307,7 +307,7 @@ def cmd_G28(self, gcmd): except self.printer.command_error: if self.printer.is_shutdown(): raise self.printer.command_error( - "Homing failed due to printer shutdown") + "3052: Homing failed due to printer shutdown") self.printer.lookup_object('stepper_enable').motor_off() raise diff --git a/klippy/extras/homing_override.py b/klippy/extras/homing_override.py index 6bfc335e86ec..f61a23e581d5 100644 --- a/klippy/extras/homing_override.py +++ b/klippy/extras/homing_override.py @@ -10,6 +10,8 @@ def __init__(self, config): self.start_pos = [config.getfloat('set_position_' + a, None) for a in 'xyzac'] self.axes = config.get('axes', 'XYZAC').upper() + # rotate axis A on 45 degrees + self.rotate_a = config.getboolean('rotate_a', False) gcode_macro = self.printer.load_object(config, 'gcode_macro') self.template = gcode_macro.load_template(config, 'gcode') self.in_script = False @@ -51,18 +53,17 @@ def check_axes_for_homing(self, gcmd): def cmd_G28(self, gcmd): if self.in_script: + if self.rotate_a: + self.check_axes_for_homing(gcmd) # Was called recursively - invoke the real G28 command - self.check_axes_for_homing(gcmd) self.prev_G28(gcmd) return - # if no axis is given as parameter we assume the override no_axis = True for axis in 'XYZAC': if gcmd.get(axis, None) is not None: no_axis = False break - if no_axis: override = True else: @@ -71,9 +72,9 @@ def cmd_G28(self, gcmd): for axis in self.axes: if gcmd.get(axis, None) is not None: override = True - if not override: - self.check_axes_for_homing(gcmd) + if self.rotate_a: + self.check_axes_for_homing(gcmd) self.prev_G28(gcmd) return diff --git a/klippy/extras/output_pin.py b/klippy/extras/output_pin.py index 8b41aca7a454..1f00510c44ad 100644 --- a/klippy/extras/output_pin.py +++ b/klippy/extras/output_pin.py @@ -78,7 +78,7 @@ def cmd_SET_PIN(self, gcmd): cycle_time = gcmd.get_float('CYCLE_TIME', self.default_cycle_time, above=0., maxval=MAX_SCHEDULE_TIME) if not self.is_pwm and value not in [0., 1.]: - raise gcmd.error("Invalid pin value") + raise gcmd.error("3053: Invalid pin value") toolhead = self.printer.lookup_object('toolhead') toolhead.register_lookahead_callback( lambda print_time: self._set_pin(print_time, value, cycle_time)) diff --git a/klippy/extras/pid_calibrate.py b/klippy/extras/pid_calibrate.py index f32f1be79856..7c5f64cfa43c 100644 --- a/klippy/extras/pid_calibrate.py +++ b/klippy/extras/pid_calibrate.py @@ -21,7 +21,7 @@ def cmd_PID_CALIBRATE(self, gcmd): try: heater = pheaters.lookup_heater(heater_name) except self.printer.config_error as e: - raise gcmd.error(str(e)) + raise gcmd.error("3054: %s" % str(e)) self.printer.lookup_object('toolhead').get_last_move_time() calibrate = ControlAutoTune(heater, target) old_control = heater.set_control(calibrate) @@ -34,7 +34,7 @@ def cmd_PID_CALIBRATE(self, gcmd): if write_file: calibrate.write_file('/tmp/heattest.txt') if calibrate.check_busy(0., 0., 0.): - raise gcmd.error("pid_calibrate interrupted") + raise gcmd.error("3054: pid_calibrate interrupted") # Log and report results Kp, Ki, Kd = calibrate.calc_final_pid() logging.info("Autotune: final: Kp=%f Ki=%f Kd=%f", Kp, Ki, Kd) diff --git a/klippy/extras/print_stats.py b/klippy/extras/print_stats.py index 668cd7d0c860..6a031149cf1f 100644 --- a/klippy/extras/print_stats.py +++ b/klippy/extras/print_stats.py @@ -3,15 +3,17 @@ # Copyright (C) 2020 Eric Callahan # # This file may be distributed under the terms of the GNU GPLv3 license. +import logging + class PrintStats: def __init__(self, config): - printer = config.get_printer() - self.gcode_move = printer.load_object(config, 'gcode_move') - self.reactor = printer.get_reactor() + self.printer = config.get_printer() + self.gcode_move = self.printer.load_object(config, 'gcode_move') + self.reactor = self.printer.get_reactor() self.reset() + self.gcode = self.printer.lookup_object('gcode') # Register commands - self.gcode = printer.lookup_object('gcode') self.gcode.register_command( "SET_PRINT_STATS_INFO", self.cmd_SET_PRINT_STATS_INFO, desc=self.cmd_SET_PRINT_STATS_INFO_help) @@ -64,24 +66,36 @@ def _note_finish(self, state, error_message = ""): self.init_duration = self.total_duration - \ self.prev_pause_duration self.print_start_time = None - cmd_SET_PRINT_STATS_INFO_help = "Pass slicer info like layer act and " \ - "total to klipper" + cmd_SET_PRINT_STATS_INFO_help = "Set info about current file." def cmd_SET_PRINT_STATS_INFO(self, gcmd): - total_layer = gcmd.get_int("TOTAL_LAYER", self.info_total_layer, \ - minval=0) - current_layer = gcmd.get_int("CURRENT_LAYER", self.info_current_layer, \ - minval=0) - if total_layer == 0: - self.info_total_layer = None - self.info_current_layer = None - elif total_layer != self.info_total_layer: + total_layer = gcmd.get_int("TOTAL_LAYER", 0) + current_layer = gcmd.get_int("CURRENT_LAYER", 0) + count_trigered_sensor = gcmd.get_int("COUNT_TRIGERED_SENSOR", 0) + if total_layer: self.info_total_layer = total_layer self.info_current_layer = 0 - if self.info_total_layer is not None and \ current_layer is not None and \ current_layer != self.info_current_layer: self.info_current_layer = min(current_layer, self.info_total_layer) + if count_trigered_sensor: + self.count_trigered_sensor = count_trigered_sensor + + def set_layer(self, total_layer=None, current_layer=None): + if total_layer: + try: + total_layer = int(total_layer) + self.info_total_layer = total_layer + except Exception as e: + logging.warning('Do not get total_layer\n %s' % e) + self.info_total_layer = 0 + if current_layer: + try: + current_layer = int(current_layer) + self.info_current_layer = current_layer + except Exception as e: + logging.warning('Do not get current_layer\n %s' % e) + def reset(self): self.filename = self.error_message = "" self.state = "standby" @@ -89,6 +103,7 @@ def reset(self): self.filament_used = self.total_duration = 0. self.print_start_time = self.last_pause_time = None self.init_duration = 0. + self.count_trigered_sensor = 0 self.info_total_layer = None self.info_current_layer = None def get_status(self, eventtime): @@ -112,6 +127,7 @@ def get_status(self, eventtime): 'filament_used': self.filament_used, 'state': self.state, 'message': self.error_message, + 'count_trigered_sensor': self.count_trigered_sensor, 'info': {'total_layer': self.info_total_layer, 'current_layer': self.info_current_layer} } diff --git a/klippy/extras/probe.py b/klippy/extras/probe.py index 1b182b1ca3e8..33e93c6677fd 100644 --- a/klippy/extras/probe.py +++ b/klippy/extras/probe.py @@ -106,9 +106,9 @@ def multi_probe_end(self): self.mcu_probe.multi_probe_end() def setup_pin(self, pin_type, pin_params): if pin_type != 'endstop' or pin_params['pin'] != 'z_virtual_endstop': - raise pins.error("Probe virtual endstop only useful as endstop pin") + raise pins.error("2033: Probe virtual endstop only useful as endstop pin") if pin_params['invert'] or pin_params['pullup']: - raise pins.error("Can not pullup/invert probe virtual endstop") + raise pins.error("2034: Can not pullup/invert probe virtual endstop") return self.mcu_probe def get_lift_speed(self, gcmd=None): if gcmd is not None: @@ -120,7 +120,7 @@ def _probe(self, speed, axis='z', positive_direction=0): toolhead = self.printer.lookup_object('toolhead') curtime = self.printer.get_reactor().monotonic() if axis not in toolhead.get_status(curtime)['homed_axes']: - raise self.printer.command_error("Must home before probe") + raise self.printer.command_error("2035: Must home before probe") axis_index = 'xyz'.index(axis) phoming = self.printer.lookup_object('homing') pos = toolhead.get_position() @@ -131,7 +131,7 @@ def _probe(self, speed, axis='z', positive_direction=0): reason = str(e) if "Timeout during endstop homing" in reason: reason += HINT_TIMEOUT - raise self.printer.command_error(reason) + raise self.printer.command_error("2036: %s" % reason) self.gcode.respond_info("probe at x=%.3f y=%.3f z=%.6f" % (epos[0], epos[1], epos[2])) return epos[:3] @@ -184,7 +184,7 @@ def run_probe(self, gcmd): axis_positions = [p[axis_index] for p in positions] if max(axis_positions) - min(axis_positions) > samples_tolerance: if retries >= samples_retries: - raise gcmd.error("Probe samples exceed samples_tolerance") + raise gcmd.error("2037: Probe samples exceed samples_tolerance") gcmd.respond_info("Probe samples exceed tolerance. Retrying...") retries += 1 positions = [] @@ -358,14 +358,14 @@ def raise_probe(self): self.deactivate_gcode.run_gcode_from_command() if toolhead.get_position()[:3] != start_pos[:3]: raise self.printer.command_error( - "Toolhead moved during probe activate_gcode script") + "2038: Toolhead moved during probe activate_gcode script") def lower_probe(self): toolhead = self.printer.lookup_object('toolhead') start_pos = toolhead.get_position() self.activate_gcode.run_gcode_from_command() if toolhead.get_position()[:3] != start_pos[:3]: raise self.printer.command_error( - "Toolhead moved during probe deactivate_gcode script") + "2039: Toolhead moved during probe deactivate_gcode script") def multi_probe_begin(self): if self.stow_on_each_sample: return @@ -410,7 +410,7 @@ def __init__(self, config, finalize_callback, default_points=None): def minimum_points(self,n): if len(self.probe_points) < n: raise self.printer.config_error( - "Need at least %d probe points for %s" % (n, self.name)) + "2040: Need at least %d probe points for %s" % (n, self.name)) def update_probe_points(self, points, min_points): self.probe_points = points self.minimum_points(min_points) @@ -459,7 +459,7 @@ def start_probe(self, gcmd): self.lift_speed = probe.get_lift_speed(gcmd) self.probe_offsets = probe.get_offsets() if self.horizontal_move_z < self.probe_offsets[2]: - raise gcmd.error("horizontal_move_z can't be less than" + raise gcmd.error("2041: horizontal_move_z can't be less than" " probe's z_offset") probe.multi_probe_begin() while 1: diff --git a/klippy/extras/safe_z_home.py b/klippy/extras/safe_z_home.py index ca9b8eb59ea3..eeacfea85d53 100644 --- a/klippy/extras/safe_z_home.py +++ b/klippy/extras/safe_z_home.py @@ -21,7 +21,7 @@ def __init__(self, config): self.gcode.register_command("G28", self.cmd_G28) if config.has_section("homing_override"): - raise config.error("homing_override and safe_z_homing cannot" + raise config.error("1010: homing_override and safe_z_homing cannot" +" be used simultaneously") def cmd_G28(self, gcmd): @@ -70,7 +70,7 @@ def cmd_G28(self, gcmd): kin_status = toolhead.get_kinematics().get_status(curtime) if ('x' not in kin_status['homed_axes'] or 'y' not in kin_status['homed_axes']): - raise gcmd.error("Must home X and Y axes first") + raise gcmd.error("109: Must home X and Y axes first") # Move to safe XY homing position prevpos = toolhead.get_position() toolhead.manual_move([self.home_x_pos, self.home_y_pos], self.speed) diff --git a/klippy/extras/save_variables.py b/klippy/extras/save_variables.py index fb6ce1b824d6..d3bbee954caa 100644 --- a/klippy/extras/save_variables.py +++ b/klippy/extras/save_variables.py @@ -17,7 +17,7 @@ def __init__(self, config): # open(self.filename, "w").close() self.loadVariables() except self.printer.command_error as e: - raise config.error(str(e)) + raise config.error("9011: %s" % str(e)) gcode = self.printer.lookup_object('gcode') gcode.register_command('SAVE_VARIABLE', self.cmd_SAVE_VARIABLE, desc=self.cmd_SAVE_VARIABLE_help) @@ -30,7 +30,7 @@ def loadVariables(self): for name, val in varfile.items('Variables'): allvars[name] = ast.literal_eval(val) except: - msg = "Unable to parse existing variable file" + msg = "9012: Unable to parse existing variable file" logging.exception(msg) raise self.printer.command_error(msg) self.allVariables = allvars @@ -43,7 +43,7 @@ def cmd_SAVE_VARIABLE(self, gcmd): try: value = ast.literal_eval(value) except ValueError as e: - raise gcmd.error("Unable to parse '%s' as a literal" % (value,)) + raise gcmd.error("9013: Unable to parse '%s' as a literal" % (value,)) newvars = dict(self.allVariables) newvars[varname] = value # Write file @@ -56,7 +56,7 @@ def cmd_SAVE_VARIABLE(self, gcmd): varfile.write(f) f.close() except: - msg = "Unable to save variable" + msg = "9014: Unable to save variable" logging.exception(msg) raise gcmd.error(msg) self.loadVariables() diff --git a/klippy/extras/skew_correction.py b/klippy/extras/skew_correction.py index 0918c64731f1..1e0e53ca07ab 100644 --- a/klippy/extras/skew_correction.py +++ b/klippy/extras/skew_correction.py @@ -43,12 +43,13 @@ def __init__(self, config): self.xy_factor = 0. self.xz_factor = 0. self.yz_factor = 0. + self.apply_skew = False self.current_profile = None self.skew_profiles = {} # Fetch stored profiles from Config self._load_storage(config) - self.printer.register_event_handler("klippy:connect", - self._handle_connect) + self.printer.register_event_handler("klippy:ready", + self._handle_ready) self.printer.register_event_handler("gcode_move:change_wcs_lists", self._change_wcs_lists) # self.printer.register_event_handler("gcode_move:change_current_wcs", @@ -69,6 +70,12 @@ def __init__(self, config): gcode.register_command('CALC_SKEW_COMPENSATION', self.cmd_CALC_SKEW_COMPENSATION, desc=self.cmd_CALC_SKEW_COMPENSATION_help) + gcode.register_command( + 'CHECK_ACCURACY_SET_MODULE_FIVE_D', self.cmd_CHECK_ACCURACY_SET_MODULE_FIVE_D, + desc=self.cmd_CHECK_ACCURACY_SET_MODULE_FIVE_D_help) + gcode.register_command('CALC_SKEW_COMPENSATION_WCS', + self.cmd_CALC_SKEW_COMPENSATION_WCS, + desc=self.cmd_CALC_SKEW_COMPENSATION_WCS_help) self.point_coords = [ [0., 0., 0.], [0., 0., 0.], @@ -83,9 +90,9 @@ def __init__(self, config): [0., 0., 0.] ] self.next_transform = None - self.start_z_point = 0. - def _handle_connect(self): + + def _handle_ready(self): kin = self.printer.lookup_object('toolhead').get_kinematics() self.axes_min = kin.axes_min self.axes_max = kin.axes_max @@ -112,12 +119,19 @@ def cmd_SAVE_SKEW_POINT(self, gcmd): raise Exception except Exception: raise gcmd.error( - "skew_corection: improperly formatted entry for " + "2042: skew_corection: improperly formatted entry for " "point\n%s" % (gcmd.get_commandline())) for axis, coord in enumerate(coords): self.point_coords[point_idx][axis] = coord cmd_SAVE_SKEW_POINT_help = "Save point for align skew" + cmd_CHECK_ACCURACY_SET_MODULE_FIVE_D_help = "command for checked accuracy set the module 5d." + def cmd_CHECK_ACCURACY_SET_MODULE_FIVE_D(self, gcmd): + diferent_z = self.point_coords[0][2] - self.point_coords[1][2] + diferent_y = self.point_coords[2][1] - self.point_coords[3][1] + gcmd.respond_info("difference between Z: %f\ndifference between Y: %f" + % (diferent_z, diferent_y)) + def cmd_CALC_MEASURED_SKEW(self, gcmd): ac = gcmd.get_float("AC", above=0.) bd = gcmd.get_float("BD", above=0.) @@ -135,6 +149,7 @@ def cmd_CALC_SKEW_COMPENSATION(self, gcmd): """ factors = ['XY', 'XZ', 'YZ'] factor_name = gcmd.get('FACTOR').upper() + msg = gcmd.get('MSG', '') if factor_name in factors: if factor_name == factors[0]: # xy_factor @@ -144,6 +159,7 @@ def cmd_CALC_SKEW_COMPENSATION(self, gcmd): b_point = get_point(self.point_coords[0], self.point_coords[1]) c_point = list(b_point) c_point[0] = c_point[0] + 50. + diff_points = b_point[0] - a_point[0] bc = length_side(b_point[0], b_point[1], c_point[0], c_point[1]) bd = length_side(b_point[0], b_point[1], d_point[0], d_point[1]) ac = length_side(a_point[0], a_point[1], c_point[0], c_point[1]) @@ -155,6 +171,7 @@ def cmd_CALC_SKEW_COMPENSATION(self, gcmd): b_point = get_point(self.point_coords[0], self.point_coords[1]) c_point = list(b_point) c_point[0] = c_point[0] + 50 + diff_points = b_point[0] - a_point[0] bc = length_side(b_point[0], b_point[2], c_point[0], c_point[2]) bd = length_side(b_point[0], b_point[2], d_point[0], d_point[2]) ac = length_side(a_point[0], a_point[2], c_point[0], c_point[2]) @@ -166,20 +183,70 @@ def cmd_CALC_SKEW_COMPENSATION(self, gcmd): b_point = get_point(self.point_coords[1], self.point_coords[2]) c_point = list(b_point) c_point[1] = c_point[1] - 50 + diff_points = b_point[1] - a_point[1] bc = length_side(b_point[1], b_point[2], c_point[1], c_point[2]) bd = length_side(b_point[1], b_point[2], d_point[1], d_point[2]) ac = length_side(a_point[1], a_point[2], c_point[1], c_point[2]) factor_value = float("%.4f" % calc_skew_factor(ac, bd, bc)) factor_name = factor_name.lower() + '_factor' setattr(self, factor_name, factor_value) - out = "Calculated skew compensation %s: %.6f radians, %.2f degrees\n" % ( - factor_name, factor_value, math.degrees(factor_value)) + out = "Calculated %s skew compensation %s: %.6f radians, %.2f degrees, difference beetwen points=%f" % ( + msg, factor_name, factor_value, math.degrees(factor_value), diff_points) gcmd.respond_info(out) else: raise gcmd.error( - "Error! Factor name %s not in list factors['XY', 'XZ', 'YZ']" % (factor_name)) + "2043: Error! Factor name %s not in list factors['XY', 'XZ', 'YZ']" % (factor_name)) cmd_CALC_SKEW_COMPENSATION_help = "Calculate skew compensation." + cmd_CALC_SKEW_COMPENSATION_WCS_help = "Calculate skew compensation by wcs." + def cmd_CALC_SKEW_COMPENSATION_WCS(self, gcmd): + factors = ['XY', 'XZ', 'YZ'] + factor_name = gcmd.get('FACTOR').upper() + factor_name = factor_name + wcs_list = self.gcode_move.wcs_offsets + if factor_name in factors: + if factor_name == factors[0]: + # xy_factor + a_point = wcs_list[2] + d_point = list(a_point) + d_point[0] = d_point[0] + 50 + b_point = wcs_list[4] + c_point = list(b_point) + c_point[0] = c_point[0] + 50 + # diff_points = b_point[0] - a_point[0] + bc = length_side(b_point[0], b_point[1], c_point[0], c_point[1]) + bd = length_side(b_point[0], b_point[1], d_point[0], d_point[1]) + ac = length_side(a_point[0], a_point[1], c_point[0], c_point[1]) + elif factor_name == factors[1]: + # xz_factor + a_point = wcs_list[3] + d_point = list(a_point) + d_point[0] = d_point[0] + 50. + b_point = wcs_list[1] + c_point = list(b_point) + c_point[0] = c_point[0] + 50. + # diff_points = b_point[0] - a_point[0] + bc = length_side(b_point[0], b_point[2], c_point[0], c_point[2]) + bd = length_side(b_point[0], b_point[2], d_point[0], d_point[2]) + ac = length_side(a_point[0], a_point[2], c_point[0], c_point[2]) + else: + # yz_factor + a_point = wcs_list[1] + d_point = list(a_point) + d_point[1] = d_point[1] + 50 + b_point = wcs_list[3] + c_point = list(b_point) + c_point[1] = c_point[1] + 50 + bc = length_side(b_point[1], b_point[2], c_point[1], c_point[2]) + bd = length_side(b_point[1], b_point[2], d_point[1], d_point[2]) + ac = length_side(a_point[1], a_point[2], c_point[1], c_point[2]) + factor_value = float("%.4f" % calc_skew_factor(ac, bd, bc)) + factor_name = factor_name.lower() + '_factor' + setattr(self, factor_name, factor_value) + out = "Calculated skew compensation %s: %.6f radians, %.2f degrees" % ( + factor_name, factor_value, math.degrees(factor_value)) + gcmd.respond_info(out) + def _load_storage(self, config): stored_profs = config.get_prefix_sections(self.name) # Remove primary skew_correction section, as it is not a stored profile @@ -195,30 +262,33 @@ def _load_storage(self, config): def calc_skew(self, pos): newpos = list(pos) - # pos_z = pos[2] - self.wcs_list[self.current_wcs + 2][2] - # used middle point, an alternative to getting the actual z coordinate in wcs. - pos_z = pos[2] - self.start_z_point - # newpos[0] = pos[0] - pos[1] * self.xy_factor \ - # - pos[2] * (self.xz_factor - (self.xy_factor * self.yz_factor)) - # removed self.xy_factor from the formula for a cleaner and easier compensation application. - newpos[0] = pos[0] - pos_z * self.xz_factor - newpos[1] = pos[1] - pos_z * (self.yz_factor * -1) - return newpos + if self.gcode_move.current_wcs == 2: + newpos[0] = pos[0] + ((self.wcs_list[2][1] - pos[1]) * (self.xy_factor * -1 )) + return newpos + elif self.gcode_move.current_wcs == 1: + newpos[0] = pos[0] + ((self.wcs_list[1][2] - pos[2]) * (self.xz_factor * -1 )) + newpos[1] = pos[1] + ((self.wcs_list[1][2] - pos[2]) * (self.yz_factor)) + return newpos + else: + return pos def calc_unskew(self, pos): newpos = list(pos) - # pos_z = pos[2] - self.wcs_list[self.current_wcs + 2][2] - pos_z = pos[2] - self.start_z_point - # newpos[0] = pos[0] + pos[1] * self.xy_factor \ - # + pos[2] * self.xz_factor - newpos[0] = pos[0] + pos_z * self.xz_factor - newpos[1] = pos[1] + pos_z * (self.yz_factor * -1) - return newpos + if self.gcode_move.current_wcs == 2: + newpos[0] = pos[0] - ((self.wcs_list[2][1] - pos[1]) * (self.xy_factor * -1 )) + return newpos + elif self.gcode_move.current_wcs == 1: + newpos[0] = pos[0] - ((self.wcs_list[1][2] - pos[2]) * (self.xz_factor * -1 )) + newpos[1] = pos[1] - ((self.wcs_list[1][2] - pos[2]) * (self.yz_factor)) + return newpos + else: + return pos def get_position(self): - if not self.enabled: + if self.apply_skew and self.enabled: + return self.calc_unskew(self.next_transform.get_position()) + else: return self.next_transform.get_position() - return self.calc_unskew(self.next_transform.get_position()) def move(self, newpos, speed): old_pos = self.next_transform.get_position() @@ -226,8 +296,10 @@ def move(self, newpos, speed): (0, 1, 2, 3, 4, 5)] move_d = math.sqrt(sum([d * d for d in axes_d[:5]])) if not self.enabled or move_d < .000000001: + self.apply_skew = False self.next_transform.move(newpos, speed) return + self.apply_skew = True corrected_pos = self.calc_skew(newpos) self.next_transform.move(corrected_pos, speed) @@ -271,7 +343,7 @@ def cmd_SET_SKEW(self, gcmd): gcmd.respond_info(out) except Exception: raise gcmd.error( - "skew_correction: improperly formatted entry for " + "2044: skew_correction: improperly formatted entry for " "plane [%s]\n%s" % (plane, gcmd.get_commandline())) cmd_SET_SKEW_help = "Set skews(XY=0.1, ...), delete skews(CLEAR=1) \ or include skew correction(ENABLE=1) its." @@ -299,16 +371,11 @@ def cmd_SKEW_PROFILE(self, gcmd): def load_profile(self, prof_name): """ - load profile and set neaded start point Z. + load profile """ - self.current_profile = prof_name - if prof_name == 'module_3d': - self.start_z_point = self.wcs_list[0] - else: - # get middle point, an alternative to getting the actual wcs index. - self.start_z_point = (self.wcs_list[3][2] + self.wcs_list[4][2]) / 2. profile = self.skew_profiles.get(prof_name) if profile is not None: + self.current_profile = prof_name self._update_skew(profile['xy_skew'], profile['xz_skew'], profile['yz_skew']) def save_profile(self, prof_name): @@ -331,14 +398,17 @@ def change_profile(self, prof_name, gcmd): """ change profile factors but don't change config """ - xy_factor = gcmd.get_float('XY', 0.) - xz_factor = gcmd.get_float('XZ', 0.) - yz_factor = gcmd.get_float('YZ', 0.) + xy_factor = gcmd.get_float('XY', self.skew_profiles[prof_name]['xy_skew']) + xz_factor = gcmd.get_float('XZ', self.skew_profiles[prof_name]['xz_skew']) + yz_factor = gcmd.get_float('YZ', self.skew_profiles[prof_name]['yz_skew']) self.skew_profiles[prof_name] = { 'xy_skew': xy_factor, 'xz_skew': xz_factor, 'yz_skew': yz_factor } + gcmd.respond_info( + "Changed skew_profile=%s: xy_skew=%s; xz_skew=%s; yz_skew=%s." % ( + prof_name, xy_factor, xz_factor, yz_factor)) def remove_profile(self, prof_name): configfile = self.printer.lookup_object('configfile') @@ -358,7 +428,7 @@ def get_status(self, eventtime=None): 'skew_profiles': self.skew_profiles, 'wcs_list': self.wcs_list, 'current_skew_profile': self.current_profile, - 'start_z_point': self.start_z_point + 'self.point_coords': self.point_coords } def load_config(config): diff --git a/klippy/extras/stepper_enable.py b/klippy/extras/stepper_enable.py index 621ff700e2ac..8998861411f0 100644 --- a/klippy/extras/stepper_enable.py +++ b/klippy/extras/stepper_enable.py @@ -128,7 +128,7 @@ def cmd_SET_STEPPER_ENABLE(self, gcmd): self.motor_debug_enable(stepper_name, stepper_enable) def lookup_enable(self, name): if name not in self.enable_lines: - raise self.printer.config_error("Unknown stepper '%s'" % (name,)) + raise self.printer.config_error("3056: Unknown stepper '%s'" % (name,)) return self.enable_lines[name] def get_steppers(self): return list(self.enable_lines.keys()) diff --git a/klippy/extras/temperature_fan.py b/klippy/extras/temperature_fan.py index aee94f281594..af88d019a589 100644 --- a/klippy/extras/temperature_fan.py +++ b/klippy/extras/temperature_fan.py @@ -84,7 +84,7 @@ def cmd_SET_TEMPERATURE_FAN_TARGET(self, gcmd): max_speed = gcmd.get_float('MAX_SPEED', self.max_speed) if min_speed > max_speed: raise self.printer.command_error( - "Requested min speed (%.1f) is greater than max speed (%.1f)" + "3057: Requested min speed (%.1f) is greater than max speed (%.1f)" % (min_speed, max_speed)) self.set_min_speed(min_speed) self.set_max_speed(max_speed) @@ -92,21 +92,21 @@ def cmd_SET_TEMPERATURE_FAN_TARGET(self, gcmd): def set_temp(self, degrees): if degrees and (degrees < self.min_temp or degrees > self.max_temp): raise self.printer.command_error( - "Requested temperature (%.1f) out of range (%.1f:%.1f)" + "3058: Requested temperature (%.1f) out of range (%.1f:%.1f)" % (degrees, self.min_temp, self.max_temp)) self.target_temp = degrees def set_min_speed(self, speed): if speed and (speed < 0. or speed > 1.): raise self.printer.command_error( - "Requested min speed (%.1f) out of range (0.0 : 1.0)" + "3059: Requested min speed (%.1f) out of range (0.0 : 1.0)" % (speed)) self.min_speed = speed def set_max_speed(self, speed): if speed and (speed < 0. or speed > 1.): raise self.printer.command_error( - "Requested max speed (%.1f) out of range (0.0 : 1.0)" + "3060: Requested max speed (%.1f) out of range (0.0 : 1.0)" % (speed)) self.max_speed = speed diff --git a/klippy/extras/temperature_host.py b/klippy/extras/temperature_host.py index 94a736033d19..8c25132b5466 100644 --- a/klippy/extras/temperature_host.py +++ b/klippy/extras/temperature_host.py @@ -26,7 +26,7 @@ def __init__(self, config): try: self.file_handle = open(self.path, "r") except: - raise config.error("Unable to open temperature file '%s'" + raise config.error("3061: Unable to open temperature file '%s'" % (self.path,)) self.printer.register_event_handler("klippy:connect", diff --git a/klippy/extras/temperature_mcu.py b/klippy/extras/temperature_mcu.py index 585ec4c1d20d..5717ff03de92 100644 --- a/klippy/extras/temperature_mcu.py +++ b/klippy/extras/temperature_mcu.py @@ -94,7 +94,7 @@ def _mcu_identify(self): minval=min(adc_range), maxval=max(adc_range), range_check_count=RANGE_CHECK_COUNT) def config_unknown(self): - raise self.printer.config_error("MCU temperature not supported on %s" + raise self.printer.config_error("3062: MCU temperature not supported on %s" % (self.mcu_type,)) def config_rp2040(self): self.slope = 3.3 / -0.001721 diff --git a/klippy/extras/tmc.py b/klippy/extras/tmc.py index 28f7be6fc01f..109665188b14 100644 --- a/klippy/extras/tmc.py +++ b/klippy/extras/tmc.py @@ -157,7 +157,9 @@ def _query_register(self, reg_info, try_clear=False): count += 1 if count >= 3: fmt = self.fields.pretty_format(reg_name, val) - raise self.printer.command_error("TMC '%s' reports error: %s" + logging.error("3070: TMC '%s' reports error: %s" + % (self.stepper_name, fmt)) + raise self.printer.command_error("3070: TMC '%s' reports error: %s" % (self.stepper_name, fmt)) if try_clear and val & err_mask: try_clear = False @@ -271,14 +273,14 @@ def cmd_SET_TMC_FIELD(self, gcmd): field_name = gcmd.get('FIELD').lower() reg_name = self.fields.lookup_register(field_name, None) if reg_name is None: - raise gcmd.error("Unknown field name '%s'" % (field_name,)) + raise gcmd.error("3071: Unknown field name '%s'" % (field_name,)) value = gcmd.get_int('VALUE', None) velocity = gcmd.get_float('VELOCITY', None, minval=0.) tmc_frequency = self.mcu_tmc.get_tmc_frequency() if tmc_frequency is None and velocity is not None: - raise gcmd.error("VELOCITY parameter not supported by this driver") + raise gcmd.error("3072: VELOCITY parameter not supported by this driver") if (value is None) == (velocity is None): - raise gcmd.error("Specify either VALUE or VELOCITY") + raise gcmd.error("3073: Specify either VALUE or VELOCITY") if velocity is not None: step_dist = self.stepper.get_step_dist() mres = self.fields.get_field("mres") @@ -441,7 +443,7 @@ def cmd_DUMP_TMC(self, gcmd): reg_name, val = self.read_translate(reg_name, val) gcmd.respond_info(self.fields.pretty_format(reg_name, val)) else: - raise gcmd.error("Unknown register name '%s'" % (reg_name)) + raise gcmd.error("3074: Unknown register name '%s'" % (reg_name)) else: gcmd.respond_info("========== Write-only registers ==========") for reg_name, val in self.fields.registers.items(): @@ -486,11 +488,11 @@ def setup_pin(self, pin_type, pin_params): # Validate pin ppins = self.printer.lookup_object('pins') if pin_type != 'endstop' or pin_params['pin'] != 'virtual_endstop': - raise ppins.error("tmc virtual endstop only useful as endstop") + raise ppins.error("3075: tmc virtual endstop only useful as endstop") if pin_params['invert'] or pin_params['pullup']: - raise ppins.error("Can not pullup/invert tmc virtual pin") + raise ppins.error("3076: Can not pullup/invert tmc virtual pin") if self.diag_pin is None: - raise ppins.error("tmc virtual endstop requires diag pin config") + raise ppins.error("3077: tmc virtual endstop requires diag pin config") # Setup for sensorless homing self.printer.register_event_handler("homing:homing_move_begin", self.handle_homing_move_begin) @@ -566,7 +568,7 @@ def TMCMicrostepHelper(config, mcu_tmc): stepper_name = " ".join(config.get_name().split()[1:]) if not config.has_section(stepper_name): raise config.error( - "Could not find config section '[%s]' required by tmc driver" + "3078: Could not find config section '[%s]' required by tmc driver" % (stepper_name,)) stepper_config = ms_config = config.getsection(stepper_name) if (stepper_config.get('microsteps', None, note_valid=False) is None diff --git a/klippy/extras/tmc2130.py b/klippy/extras/tmc2130.py index 62a9abbfe56b..d157c302aac3 100644 --- a/klippy/extras/tmc2130.py +++ b/klippy/extras/tmc2130.py @@ -239,10 +239,10 @@ def lookup_tmc_spi_chain(config): if tmc_spi is None: tmc_spi = cs_pin_params['class'] = MCU_TMC_SPI_chain(config, chain_len) if chain_len != tmc_spi.chain_len: - raise config.error("TMC SPI chain must have same length") + raise config.error("3079: TMC SPI chain must have same length") chain_pos = config.getint('chain_position', minval=1, maxval=chain_len) if chain_pos in tmc_spi.taken_chain_positions: - raise config.error("TMC SPI chain can not have duplicate position") + raise config.error("3080: TMC SPI chain can not have duplicate position") tmc_spi.taken_chain_positions.append(chain_pos) return tmc_spi, chain_pos @@ -271,7 +271,7 @@ def set_register(self, reg_name, val, print_time=None): if v == val: return raise self.printer.command_error( - "Unable to write tmc spi '%s' register %s" % (self.name, reg_name)) + "3081: Unable to write tmc spi '%s' register %s" % (self.name, reg_name)) def get_tmc_frequency(self): return self.tmc_frequency diff --git a/klippy/extras/tmc_uart.py b/klippy/extras/tmc_uart.py index 4d5ec1d5a257..09dbf36a06ca 100644 --- a/klippy/extras/tmc_uart.py +++ b/klippy/extras/tmc_uart.py @@ -36,11 +36,11 @@ def get_instance_id(self, select_pins_desc): for pin_params in select_pin_params: if pin_params['chip'] != self.mcu: raise self.mcu.get_printer().config_error( - "TMC mux pins must be on the same mcu") + "3063: TMC mux pins must be on the same mcu") pins = [pp['pin'] for pp in select_pin_params] if pins != self.pins: raise self.mcu.get_printer().config_error( - "All TMC mux instances must use identical pins") + "3064: All TMC mux instances must use identical pins") return tuple([not pp['invert'] for pp in select_pin_params]) def activate(self, instance_id): for oid, old, new in zip(self.oids, self.pin_values, instance_id): @@ -109,13 +109,13 @@ def register_instance(self, rx_pin_params, tx_pin_params, or tx_pin_params['pin'] != self.tx_pin or (select_pins_desc is None) != (self.analog_mux is None)): raise self.mcu.get_printer().config_error( - "Shared TMC uarts must use the same pins") + "3065: Shared TMC uarts must use the same pins") instance_id = None if self.analog_mux is not None: instance_id = self.analog_mux.get_instance_id(select_pins_desc) if (instance_id, addr) in self.instances: raise self.mcu.get_printer().config_error( - "Shared TMC uarts need unique address or select_pins polarity") + "3066: Shared TMC uarts need unique address or select_pins polarity") self.instances[(instance_id, addr)] = True return instance_id def _calc_crc8(self, data): @@ -196,7 +196,7 @@ def lookup_tmc_uart_bitbang(config, max_addr): else: tx_pin_params = ppins.lookup_pin(tx_pin_desc, share_type="tmc_uart_tx") if rx_pin_params['chip'] is not tx_pin_params['chip']: - raise ppins.error("TMC uart rx and tx pins must be on the same mcu") + raise ppins.error("3067: TMC uart rx and tx pins must be on the same mcu") select_pins_desc = config.getlist('select_pins', None) addr = config.getint('uart_address', 0, minval=0, maxval=max_addr) mcu_uart = rx_pin_params.get('class') @@ -231,7 +231,7 @@ def _do_get_register(self, reg_name): if val is not None: return val raise self.printer.command_error( - "Unable to read tmc uart '%s' register %s" % (self.name, reg_name)) + "3068: Unable to read tmc uart '%s' register %s" % (self.name, reg_name)) def get_register(self, reg_name): with self.mutex: return self._do_get_register(reg_name) @@ -250,6 +250,6 @@ def set_register(self, reg_name, val, print_time=None): if self.ifcnt == (ifcnt + 1) & 0xff: return raise self.printer.command_error( - "Unable to write tmc uart '%s' register %s" % (self.name, reg_name)) + "3069: Unable to write tmc uart '%s' register %s" % (self.name, reg_name)) def get_tmc_frequency(self): return self.tmc_frequency diff --git a/klippy/extras/virtual_sdcard.py b/klippy/extras/virtual_sdcard.py index 8f56dfbb4a6e..a3b5c9e7af59 100644 --- a/klippy/extras/virtual_sdcard.py +++ b/klippy/extras/virtual_sdcard.py @@ -19,6 +19,8 @@ def __init__(self, config): self.file_position = self.file_size = 0 # Print Stat Tracking self.print_stats = self.printer.load_object(config, 'print_stats') + # variable + self.get_layer_count = True # Work timer self.reactor = self.printer.get_reactor() self.must_pause_work = self.cmd_from_sd = False @@ -81,8 +83,8 @@ def get_file_list(self, check_subdirs=False): if not fname.startswith('.') and os.path.isfile((os.path.join(dname, fname)))] except: - logging.exception("virtual_sdcard get_file_list") - raise self.gcode.error("Unable to get file list") + logging.exception("1011: virtual_sdcard get_file_list") + raise self.gcode.error("1011: Unable to get file list") def get_status(self, eventtime): return { 'file_path': self.file_path(), @@ -111,7 +113,7 @@ def do_pause(self): self.reactor.pause(self.reactor.monotonic() + .001) def do_resume(self): if self.work_timer is not None: - raise self.gcode.error("SD busy") + raise self.gcode.error("1017: SD busy") self.must_pause_work = False self.work_timer = self.reactor.register_timer( self.work_handler, self.reactor.NOW) @@ -124,7 +126,7 @@ def do_cancel(self): self.file_position = self.file_size = 0. # G-Code commands def cmd_error(self, gcmd): - raise gcmd.error("SD write not supported") + raise gcmd.error("1012: SD write not supported") def _reset_file(self): if self.current_file is not None: self.do_pause() @@ -138,13 +140,13 @@ def _reset_file(self): def cmd_SDCARD_RESET_FILE(self, gcmd): if self.cmd_from_sd: raise gcmd.error( - "SDCARD_RESET_FILE cannot be run from the sdcard") + "1013: SDCARD_RESET_FILE cannot be run from the sdcard") self._reset_file() cmd_SDCARD_PRINT_FILE_help = "Loads a SD file and starts the print. May "\ "include files in subdirectories." def cmd_SDCARD_PRINT_FILE(self, gcmd): if self.work_timer is not None: - raise gcmd.error("SD busy") + raise gcmd.error("1014: SD busy") self._reset_file() filename = gcmd.get("FILENAME") file_position = gcmd.get_int('POSITION', 0) @@ -165,7 +167,7 @@ def cmd_M21(self, gcmd): def cmd_M23(self, gcmd): # Select SD file if self.work_timer is not None: - raise gcmd.error("SD busy") + raise gcmd.error("1015: SD busy") self._reset_file() filename = gcmd.get_raw_command_parameters().strip() if filename.startswith('/'): @@ -185,8 +187,8 @@ def _load_file(self, gcmd, filename, file_position=0, check_subdirs=False): fsize = f.tell() f.seek(0) except: - logging.exception("virtual_sdcard file open") - raise gcmd.error("Unable to open file") + logging.exception("1016: virtual_sdcard file open") + raise gcmd.error("1016: Unable to open file") gcmd.respond_raw("File opened:%s Size:%d" % (filename, fsize)) gcmd.respond_raw("File selected") self.current_file = f @@ -202,7 +204,7 @@ def cmd_M25(self, gcmd): def cmd_M26(self, gcmd): # Set SD position if self.work_timer is not None: - raise gcmd.error("SD busy") + raise gcmd.error("1018: SD busy") pos = gcmd.get_int('S', minval=0) self.file_position = pos def cmd_M27(self, gcmd): @@ -232,6 +234,7 @@ def work_handler(self, eventtime): gcode_mutex = self.gcode.get_mutex() partial_input = "" lines = [] + data = '' error_message = None while not self.must_pause_work: if not lines: @@ -264,16 +267,23 @@ def work_handler(self, eventtime): next_file_position = self.file_position + len(line) + 1 self.next_file_position = next_file_position try: + if self.get_layer_count and line.find(';LAYER_COUNT:') >= 0: + self.get_layer_count = False + total_layers = line[13:] + self.print_stats.set_layer(total_layer=total_layers) + if line.find(';LAYER:') >= 0: + layer_number = line[7:] + self.print_stats.set_layer(current_layer=layer_number) self.gcode.run_script(line) except self.gcode.error as e: - error_message = str(e) + error_message = str('Error: %s,\nLine: %s\nData caused the error: %s.' % (e, line, str(data))) try: self.gcode.run_script(self.on_error_gcode.render()) except: logging.exception("virtual_sdcard on_error") break except: - logging.exception("virtual_sdcard dispatch") + logging.exception("virtual_sdcard dispatch. %s" % str(data)) break self.cmd_from_sd = False self.file_position = self.next_file_position @@ -291,10 +301,13 @@ def work_handler(self, eventtime): self.work_timer = None self.cmd_from_sd = False if error_message is not None: + self.get_layer_count = True self.print_stats.note_error(error_message) + logging.error(error_message) elif self.current_file is not None: self.print_stats.note_pause() else: + self.get_layer_count = True self.print_stats.note_complete() return self.reactor.NEVER diff --git a/klippy/gcode.py b/klippy/gcode.py index 0355bbc866ea..93492a710921 100644 --- a/klippy/gcode.py +++ b/klippy/gcode.py @@ -19,6 +19,7 @@ def __init__(self, gcode, command, commandline, params, need_ack): self._need_ack = need_ack # Method wrappers self.respond_info = gcode.respond_info + self.respond_warning = gcode.respond_warning self.respond_raw = gcode.respond_raw def get_command(self): return self._command @@ -63,19 +64,19 @@ def get(self, name, default=sentinel, parser=str, minval=None, maxval=None, try: value = parser(value) except: - raise self.error("Error on '%s': unable to parse %s" + raise self.error("903: Error on '%s': unable to parse %s" % (self._commandline, value)) if minval is not None and value < minval: - raise self.error("Error on '%s': %s must have minimum of %s" + raise self.error("903: Error on '%s': %s must have minimum of %s" % (self._commandline, name, minval)) if maxval is not None and value > maxval: - raise self.error("Error on '%s': %s must have maximum of %s" + raise self.error("903: Error on '%s': %s must have maximum of %s" % (self._commandline, name, maxval)) if above is not None and value <= above: - raise self.error("Error on '%s': %s must be above %s" + raise self.error("903: Error on '%s': %s must be above %s" % (self._commandline, name, above)) if below is not None and value >= below: - raise self.error("Error on '%s': %s must be below %s" + raise self.error("903: Error on '%s': %s must be below %s" % (self._commandline, name, below)) return value def get_int(self, name, default=sentinel, minval=None, maxval=None): @@ -129,7 +130,7 @@ def register_command(self, cmd, func, when_not_ready=False, desc=None): return old_cmd if cmd in self.ready_gcode_handlers: raise self.printer.config_error( - "gcode command %s already registered" % (cmd,)) + "0012: gcode command %s already registered" % (cmd,)) if not self.is_traditional_gcode(cmd): origfunc = func func = lambda params: origfunc(self._get_extended_params(params)) @@ -147,11 +148,11 @@ def register_mux_command(self, cmd, key, value, func, desc=None): prev_key, prev_values = prev if prev_key != key: raise self.printer.config_error( - "mux command %s %s %s may have only one key (%s)" % ( + "0013: mux command %s %s %s may have only one key (%s)" % ( cmd, key, value, prev_key)) if value in prev_values: raise self.printer.config_error( - "mux command %s %s %s already registered (%s)" % ( + "0014: mux command %s %s %s already registered (%s)" % ( cmd, key, value, prev_values)) prev_values[value] = func def get_command_help(self): @@ -199,12 +200,14 @@ def _process_commands(self, commands, need_ack=True): try: handler(gcmd) except self.error as e: - self._respond_error(str(e)) + self._respond_error('901: Internal error on command: "%s", error: "%s\n"' % ( + origline, str(e))) self.printer.send_event("gcode:command_error") if not need_ack: raise except: - msg = 'Internal error on command:"%s"' % (cmd,) + msg = '9015: Internal error on command:"%s", origline"%s"' % ( + cmd, origline) logging.exception(msg) self.printer.invoke_shutdown(msg) self._respond_error(msg) @@ -229,6 +232,10 @@ def respond_info(self, msg, log=True): logging.info(msg) lines = [l.strip() for l in msg.strip().split('\n')] self.respond_raw("// " + "\n// ".join(lines)) + def respond_warning(self, msg): + logging.warning(msg) + lines = msg.strip().split('\n') + self.respond_info("\n".join(lines), log=False) def _respond_error(self, msg): logging.warning(msg) lines = msg.strip().split('\n') @@ -248,7 +255,7 @@ def _respond_state(self, state): def _get_extended_params(self, gcmd): m = self.extended_r.match(gcmd.get_commandline()) if m is None: - raise self.error("Malformed command '%s'" + raise self.error("902: Malformed command '%s'" % (gcmd.get_commandline(),)) eargs = m.group('args') try: @@ -258,7 +265,7 @@ def _get_extended_params(self, gcmd): gcmd._params.update(eparams) return gcmd except ValueError as e: - raise self.error("Malformed command '%s'" + raise self.error("902: Malformed command '%s'" % (gcmd.get_commandline(),)) # G-Code special command handlers def cmd_default(self, gcmd): @@ -271,7 +278,7 @@ def cmd_default(self, gcmd): # Don't warn about sd card init when not ready return if not self.is_printer_ready: - raise gcmd.error(self.printer.get_state_message()[0]) + raise gcmd.error("904: %s" % self.printer.get_state_message()[0]) return if not cmd: cmdline = gcmd.get_commandline() @@ -291,7 +298,7 @@ def cmd_default(self, gcmd): not gcmd.get_float('S', 1.) or self.is_fileinput)): # Don't warn about requests to turn off fan when fan not present return - gcmd.respond_info('Unknown command:"%s"' % (cmd,)) + gcmd.respond_warning('911: Unknown command:"%s"' % (cmd,)) def _cmd_mux(self, command, gcmd): key, values = self.mux_commands[command] if None in values: @@ -299,7 +306,7 @@ def _cmd_mux(self, command, gcmd): else: key_param = gcmd.get(key) if key_param not in values: - raise gcmd.error("The value '%s' is not valid for %s" + raise gcmd.error("905: The value '%s' is not valid for %s" % (key_param, key)) values[key_param](gcmd) # Low-level G-Code commands that are needed before the config file is loaded @@ -340,7 +347,7 @@ def cmd_STATUS(self, gcmd): if self.is_printer_ready: self._respond_state("Ready") return - msg = self.printer.get_state_message()[0] + msg = "906: %s" % self.printer.get_state_message()[0] msg = msg.rstrip() + "\nKlipper state: Not ready" raise gcmd.error(msg) cmd_HELP_help = "Report the list of available extended G-Code commands" diff --git a/klippy/kinematics/cartesian_6axis.py b/klippy/kinematics/cartesian_6axis.py new file mode 100644 index 000000000000..daabed846cbd --- /dev/null +++ b/klippy/kinematics/cartesian_6axis.py @@ -0,0 +1,164 @@ +# Code for handling the kinematics of cartesian robots +# +# Copyright (C) 2016-2021 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import logging +import stepper + + +class CartKinematics: + def __init__(self, toolhead, config): + self.printer = config.get_printer() + # Setup axis rails + self.dual_carriage_axis = None + self.dual_carriage_rails = [] + self.rails = [stepper.LookupMultiRail(config.getsection('stepper_' + n)) + for n in 'xyzac'] + for rail, axis in zip(self.rails, 'xyzac'): + rail.setup_itersolve('cartesian_stepper_alloc', axis.encode()) + for s in self.get_steppers(): + s.set_trapq(toolhead.get_trapq()) + toolhead.register_step_generator(s.generate_steps) + self.printer.register_event_handler("stepper_enable:motor_off", + self._motor_off) + # Setup boundary checks + max_velocity, max_accel = toolhead.get_max_velocity() + self.max_z_velocity = config.getfloat('max_z_velocity', max_velocity, + above=0., maxval=max_velocity) + self.max_z_accel = config.getfloat('max_z_accel', max_accel, + above=0., maxval=max_accel) + self.limits = [(1.0, -1.0)] * 5 + ranges = [r.get_range() for r in self.rails] + self.axes_min = toolhead.Coord( + *[r[0] for r in ranges], e=0.) + self.axes_max = toolhead.Coord( + *[r[1] for r in ranges], e=0.) + # Check for dual carriage support + if config.has_section('dual_carriage'): + dc_config = config.getsection('dual_carriage') + dc_axis = dc_config.getchoice('axis', {'x': 'x', 'y': 'y'}) + self.dual_carriage_axis = {'x': 0, 'y': 1}[dc_axis] + dc_rail = stepper.LookupMultiRail(dc_config) + dc_rail.setup_itersolve( + 'cartesian_stepper_alloc', dc_axis.encode()) + for s in dc_rail.get_steppers(): + toolhead.register_step_generator(s.generate_steps) + self.dual_carriage_rails = [ + self.rails[self.dual_carriage_axis], dc_rail] + self.printer.lookup_object('gcode').register_command( + 'SET_DUAL_CARRIAGE', self.cmd_SET_DUAL_CARRIAGE, + desc=self.cmd_SET_DUAL_CARRIAGE_help) + + def get_steppers(self): + rails = self.rails + if self.dual_carriage_axis is not None: + dca = self.dual_carriage_axis + rails = rails[:dca] + self.dual_carriage_rails + rails[dca+1:] + return [s for rail in rails for s in rail.get_steppers()] + + def calc_position(self, stepper_positions): + return [stepper_positions[rail.get_name()] for rail in self.rails] + + def set_position(self, newpos, homing_axes): + for i, rail in enumerate(self.rails): + rail.set_position(newpos) + if i in homing_axes: + self.limits[i] = rail.get_range() + + def note_z_not_homed(self): + # Helper for Safe Z Home + self.limits[2] = (1.0, -1.0) + + def _home_axis(self, homing_state, axis, rail): + # Determine movement + position_min, position_max = rail.get_range() + hi = rail.get_homing_info() + homepos = [None, None, None, None, None, None] + if hi.position_endstop: + homepos[axis] = hi.position_endstop + else: + homepos[axis] = 0. + forcepos = list(homepos) + if hi.positive_dir: + forcepos[axis] -= 1.5 * (homepos[axis] - position_min) + else: + forcepos[axis] += 1.5 * (position_max - homepos[axis]) + # Perform homing + homing_state.home_rails([rail], forcepos, homepos) + + def home(self, homing_state): + # Each axis is homed independently and in order + for axis in homing_state.get_axes(): + if axis == self.dual_carriage_axis: + dc1, dc2 = self.dual_carriage_rails + altc = self.rails[axis] == dc2 + self._activate_carriage(0) + self._home_axis(homing_state, axis, dc1) + self._activate_carriage(1) + self._home_axis(homing_state, axis, dc2) + self._activate_carriage(altc) + else: + self._home_axis(homing_state, axis, self.rails[axis]) + + def _motor_off(self, print_time): + self.limits = [(1.0, -1.0)] * 5 + + def _check_endstops(self, move): + end_pos = move.end_pos + for i in (0, 1, 2, 3): + if (move.axes_d[i] + and (end_pos[i] < self.limits[i][0] + or end_pos[i] > self.limits[i][1])): + if self.limits[i][0] > self.limits[i][1]: + raise move.move_error("1019: Must home axis first") + raise move.move_error("1019: ") + + def check_move(self, move): + limits = self.limits + xpos, ypos = move.end_pos[:2] + if (xpos < limits[0][0] or xpos > limits[0][1] + or ypos < limits[1][0] or ypos > limits[1][1]): + self._check_endstops(move) + if not move.axes_d[2] and not move.axes_d[3] and not move.axes_d[ + 4] and not move.axes_d[5]: + # Normal XY move - use defaults + return + # Move with Z - update velocity and accel for slower Z axis + self._check_endstops(move) + if move.axes_d[2]: + z_ratio = move.move_d / abs(move.axes_d[2]) + move.limit_speed( + self.max_z_velocity * z_ratio, self.max_z_accel * z_ratio) + + def get_status(self, eventtime): + axes = [a for a, (l, h) in zip("xyzac", self.limits) if l <= h] + return { + 'homed_axes': "".join(axes), + 'axis_minimum': self.axes_min, + 'axis_maximum': self.axes_max, + } + # Dual carriage support + + def _activate_carriage(self, carriage): + toolhead = self.printer.lookup_object('toolhead') + toolhead.flush_step_generation() + dc_rail = self.dual_carriage_rails[carriage] + dc_axis = self.dual_carriage_axis + self.rails[dc_axis].set_trapq(None) + dc_rail.set_trapq(toolhead.get_trapq()) + self.rails[dc_axis] = dc_rail + pos = toolhead.get_position() + pos[dc_axis] = dc_rail.get_commanded_position() + toolhead.set_position(pos) + if self.limits[dc_axis][0] <= self.limits[dc_axis][1]: + self.limits[dc_axis] = dc_rail.get_range() + cmd_SET_DUAL_CARRIAGE_help = "Set which carriage is active" + + def cmd_SET_DUAL_CARRIAGE(self, gcmd): + carriage = gcmd.get_int('CARRIAGE', minval=0, maxval=1) + self._activate_carriage(carriage) + + +def load_kinematics(toolhead, config): + return CartKinematics(toolhead, config) diff --git a/klippy/kinematics/corexy_6axis.py b/klippy/kinematics/corexy_6axis.py index 7df655d054ee..be87356adcb9 100644 --- a/klippy/kinematics/corexy_6axis.py +++ b/klippy/kinematics/corexy_6axis.py @@ -92,8 +92,8 @@ def _check_endstops(self, move): and (end_pos[i] < self.limits[i][0] or end_pos[i] > self.limits[i][1])): if self.limits[i][0] > self.limits[i][1]: - raise move.move_error("Must home axis first") - raise move.move_error() + raise move.move_error("1019: Must home axis first") + raise move.move_error("1019: Must home axis first") def check_move(self, move): limits = self.limits diff --git a/klippy/kinematics/extruder.py b/klippy/kinematics/extruder.py index ecd42d80d8ad..3c789847ce7b 100644 --- a/klippy/kinematics/extruder.py +++ b/klippy/kinematics/extruder.py @@ -67,7 +67,7 @@ def sync_to_extruder(self, extruder_name): return extruder = self.printer.lookup_object(extruder_name, None) if extruder is None or not isinstance(extruder, PrinterExtruder): - raise self.printer.command_error("'%s' is not a valid extruder." + raise self.printer.command_error("601: '%s' is not a valid extruder." % (extruder_name,)) self.stepper.set_position([extruder.last_position, 0., 0., 0., 0.]) self.stepper.set_trapq(extruder.get_trapq()) @@ -91,10 +91,10 @@ def _set_pressure_advance(self, pressure_advance, smooth_time): def cmd_default_SET_PRESSURE_ADVANCE(self, gcmd): extruder = self.printer.lookup_object('toolhead').get_extruder() if extruder.extruder_stepper is None: - raise gcmd.error("Active extruder does not have a stepper") + raise gcmd.error("602: Active extruder does not have a stepper") strapq = extruder.extruder_stepper.stepper.get_trapq() if strapq is not extruder.get_trapq(): - raise gcmd.error("Unable to infer active extruder stepper") + raise gcmd.error("603: Unable to infer active extruder stepper") extruder.extruder_stepper.cmd_SET_PRESSURE_ADVANCE(gcmd) def cmd_SET_PRESSURE_ADVANCE(self, gcmd): pressure_advance = gcmd.get_float('ADVANCE', self.pressure_advance, @@ -113,7 +113,7 @@ def cmd_SET_E_ROTATION_DISTANCE(self, gcmd): rotation_dist = gcmd.get_float('DISTANCE', None) if rotation_dist is not None: if not rotation_dist: - raise gcmd.error("Rotation distance can not be zero") + raise gcmd.error("604: Rotation distance can not be zero") invert_dir, orig_invert_dir = self.stepper.get_dir_inverted() next_invert_dir = orig_invert_dir if rotation_dist < 0.: @@ -205,6 +205,8 @@ def __init__(self, config, extruder_num): or config.get('rotation_distance', None) is not None): self.extruder_stepper = ExtruderStepper(config) self.extruder_stepper.stepper.set_trapq(self.trapq) + # check extruder name is fiber + self.is_fiber = config.getboolean('fiber', False) # Register commands gcode = self.printer.lookup_object('gcode') if self.name == 'extruder': @@ -219,6 +221,7 @@ def update_move_time(self, flush_time): def get_status(self, eventtime): sts = self.heater.get_status(eventtime) sts['can_extrude'] = self.heater.can_extrude + sts['fiber'] = self.is_fiber if self.extruder_stepper is not None: sts.update(self.extruder_stepper.get_status(eventtime)) return sts @@ -237,14 +240,14 @@ def check_move(self, move): axis_r = move.axes_r[5] if not self.heater.can_extrude: raise self.printer.command_error( - "Extrude below minimum temp\n" + "605: Extrude below minimum temp\n" "See the 'min_extrude_temp' config option for details") if (not move.axes_d[0] and not move.axes_d[1] and not move.axes_d[2] and not move.axes_d[3] and not move.axes_d[4]) or axis_r < 0.: # Extrude only move (or retraction move) - limit accel and velocity if abs(move.axes_d[5]) > self.max_e_dist: raise self.printer.command_error( - "Extrude only move too long (%.3fmm vs %.3fmm)\n" + "606: Extrude only move too long (%.3fmm vs %.3fmm)\n" "See the 'max_extrude_only_distance' config" " option for details" % (move.axes_d[5], self.max_e_dist)) inv_extrude_r = 1. / abs(axis_r) @@ -258,7 +261,7 @@ def check_move(self, move): logging.debug("Overextrude: %s vs %s (area=%.3f dist=%.3f)", axis_r, self.max_extrude_ratio, area, move.move_d) raise self.printer.command_error( - "Move exceeds maximum extrusion (%.3fmm^2 vs %.3fmm^2)\n" + "607: Move exceeds maximum extrusion (%.3fmm^2 vs %.3fmm^2)\n" "See the 'max_extrude_cross_section' config option for details" % (area, self.max_extrude_ratio * self.filament_area)) @@ -301,7 +304,7 @@ def cmd_M104(self, gcmd, wait=False): if extruder is None: if temp <= 0.: return - raise gcmd.error("Extruder not configured") + raise gcmd.error("608: Extruder not configured") else: extruder = self.printer.lookup_object('toolhead').get_extruder() pheaters = self.printer.lookup_object('heaters') @@ -332,7 +335,7 @@ def update_move_time(self, flush_time): pass def check_move(self, move): - raise move.move_error("Extrude when no extruder present") + raise move.move_error("609: Extrude when no extruder present") def find_past_position(self, print_time): return 0. @@ -344,10 +347,10 @@ def get_name(self): return "" def get_heater(self): - raise self.printer.command_error("Extruder not configured") + raise self.printer.command_error("6010: Extruder not configured") def get_trapq(self): - raise self.printer.command_error("Extruder not configured") + raise self.printer.command_error("6011: Extruder not configured") def add_printer_objects(config): diff --git a/klippy/klippy.py b/klippy/klippy.py index 8f2caf3b5222..cbf8579789e2 100644 --- a/klippy/klippy.py +++ b/klippy/klippy.py @@ -88,13 +88,13 @@ def _set_state(self, msg): def add_object(self, name, obj): if name in self.objects: raise self.config_error( - "Printer object '%s' already created" % (name,)) + "009: Printer object '%s' already created" % (name,)) self.objects[name] = obj def lookup_object(self, name, default=configfile.sentinel): if name in self.objects: return self.objects[name] if default is configfile.sentinel: - raise self.config_error("Unknown config object '%s'" % (name,)) + raise self.config_error("0010: Unknown config object '%s'" % (name,)) return default def lookup_objects(self, module=None): if module is None: @@ -117,7 +117,7 @@ def load_object(self, config, section, default=configfile.sentinel): if not os.path.exists(py_name) and not os.path.exists(py_dirname): if default is not configfile.sentinel: return default - raise self.config_error("Unable to load module '%s'" % (section,)) + raise self.config_error("0011: Unable to load module '%s'" % (section,)) mod = importlib.import_module('extras.' + module_name) init_func = 'load_config' if len(module_parts) > 1: @@ -126,7 +126,7 @@ def load_object(self, config, section, default=configfile.sentinel): if init_func is None: if default is not configfile.sentinel: return default - raise self.config_error("Unable to load module '%s'" % (section,)) + raise self.config_error("0011: Unable to load module '%s'" % (section,)) self.objects[section] = init_func(config.getsection(section)) return self.objects[section] def _read_config(self): diff --git a/klippy/mathutil.py b/klippy/mathutil.py index 9e20e7ab10cf..875b751d0bed 100644 --- a/klippy/mathutil.py +++ b/klippy/mathutil.py @@ -83,7 +83,7 @@ def wrapper(): # Return results is_err, res = parent_conn.recv() if is_err: - raise Exception("Error in coordinate descent: %s" % (res,)) + raise Exception("802: Error in coordinate descent: %s" % (res,)) calc_proc.join() parent_conn.close() return res diff --git a/klippy/mcu.py b/klippy/mcu.py index 76c70506ba4a..b4535d596e28 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -42,7 +42,7 @@ def get_response(self, cmds, cmd_queue, minclock=0, reqclock=0): query_time = self.reactor.monotonic() if query_time > first_query_time + self.TIMEOUT_TIME: self.serial.register_response(None, self.name, self.oid) - raise serialhdl.error("Timeout on wait for '%s' response" + raise serialhdl.error("301: Timeout on wait for '%s' response" % (self.name,)) self.serial.raw_send(cmd, minclock, minclock, cmd_queue) @@ -68,7 +68,7 @@ def _do_send(self, cmds, minclock, reqclock): try: return xh.get_response(cmds, self._cmd_queue, minclock, reqclock) except serialhdl.error as e: - raise self._error(str(e)) + raise self._error("302: %s" % str(e)) def send(self, data=(), minclock=0, reqclock=0): return self._do_send([self._cmd.encode(data)], minclock, reqclock) def send_with_preface(self, preface_cmd, preface_data=(), data=(), @@ -249,7 +249,7 @@ def add_stepper(self, stepper): for s in ot.get_steppers(): if ot is not trsync and s.get_name().startswith(sname[:9]): cerror = self._mcu.get_printer().config_error - raise cerror("Multi-mcu homing not supported on" + raise cerror("303: Multi-mcu homing not supported on" " multi-mcu shared axis") def get_steppers(self): return [s for trsync in self._trsyncs for s in trsync.get_steppers()] @@ -480,7 +480,7 @@ def set_pwm(self, print_time, value, cycle_time=None): if cycle_ticks != self._last_cycle_ticks: if cycle_ticks >= 1<<31: raise self._mcu.get_printer().command_error( - "PWM cycle time too large") + "3012: PWM cycle time too large") self._set_cycle_ticks.send([self._oid, cycle_ticks], minclock=minclock, reqclock=clock) self._last_cycle_ticks = cycle_ticks @@ -656,7 +656,7 @@ def _check_restart(self, reason): self._name, reason) self._printer.request_exit('firmware_restart') self._reactor.pause(self._reactor.monotonic() + 2.000) - raise error("Attempt MCU '%s' restart failed" % (self._name,)) + raise error("3013: Attempt MCU '%s' restart failed" % (self._name,)) def _connect_file(self, pace=False): # In a debugging mode. Open debug output file and read data dictionary start_args = self._printer.get_start_args() @@ -696,7 +696,7 @@ def _send_config(self, prev_crc): self.add_config_cmd("finalize_config crc=%d" % (config_crc,)) if prev_crc is not None and config_crc != prev_crc: self._check_restart("CRC mismatch") - raise error("MCU '%s' CRC does not match config" % (self._name,)) + raise error("3013: MCU '%s' CRC does not match config" % (self._name,)) # Transmit config messages (if needed) self.register_response(self._handle_starting, 'starting') try: @@ -716,7 +716,7 @@ def _send_config(self, prev_crc): if enum_name == 'pin': # Raise pin name errors as a config error (not a protocol error) raise self._printer.config_error( - "Pin '%s' is not a valid pin name on mcu '%s'" + "305: Pin '%s' is not a valid pin name on mcu '%s'" % (enum_value, self._name)) raise def _send_get_config(self): @@ -727,10 +727,10 @@ def _send_get_config(self): return { 'is_config': 0, 'move_count': 500, 'crc': 0 } config_params = get_config_cmd.send() if self._is_shutdown: - raise error("MCU '%s' error during config: %s" % ( + raise error("3014: MCU '%s' error during config: %s" % ( self._name, self._shutdown_msg)) if config_params['is_shutdown']: - raise error("Can not update MCU '%s' config as it is shutdown" % ( + raise error("3013: Can not update MCU '%s' config as it is shutdown" % ( self._name,)) return config_params def _log_info(self): @@ -753,18 +753,18 @@ def _connect(self): self._send_config(None) config_params = self._send_get_config() if not config_params['is_config'] and not self.is_fileoutput(): - raise error("Unable to configure MCU '%s'" % (self._name,)) + raise error("3015: Unable to configure MCU '%s'" % (self._name,)) else: start_reason = self._printer.get_start_args().get("start_reason") if start_reason == 'firmware_restart': - raise error("Failed automated reset of MCU '%s'" + raise error("3016: Failed automated reset of MCU '%s'" % (self._name,)) # Already configured - send init commands self._send_config(config_params['crc']) # Setup steppersync with the move_count returned by get_config move_count = config_params['move_count'] if move_count < self._reserved_move_slots: - raise error("Too few moves available on MCU '%s'" % (self._name,)) + raise error("3017: Too few moves available on MCU '%s'" % (self._name,)) ffi_main, ffi_lib = chelper.get_ffi() self._steppersync = ffi_main.gc( ffi_lib.steppersync_alloc(self._serial.get_serialqueue(), @@ -800,7 +800,7 @@ def _mcu_identify(self): self._serial.connect_pipe(self._serialport) self._clocksync.connect(self._serial) except serialhdl.error as e: - raise error(str(e)) + raise error("3018: %s" % str(e)) logging.info(self._log_info()) ppins = self._printer.lookup_object('pins') pin_resolver = ppins.get_pin_resolver(self._name) @@ -964,7 +964,7 @@ def flush_moves(self, print_time): return ret = self._ffi_lib.steppersync_flush(self._steppersync, clock) if ret: - raise error("Internal error in MCU '%s' stepcompress" + raise error("3020: Internal error in MCU '%s' stepcompress" % (self._name,)) def check_active(self, print_time, eventtime): if self._steppersync is None: diff --git a/klippy/msgproto.py b/klippy/msgproto.py index f8a12530e67e..c4d927cc38c7 100644 --- a/klippy/msgproto.py +++ b/klippy/msgproto.py @@ -88,7 +88,7 @@ class enumeration_error(error): def __init__(self, enum_name, value): self.enum_name = enum_name self.value = value - error.__init__(self, "Unknown value '%s' in enumeration '%s'" + error.__init__(self, "806: Unknown value '%s' in enumeration '%s'" % (value, enum_name)) def get_enum_params(self): return self.enum_name, self.value @@ -149,7 +149,7 @@ def lookup_output_params(msgformat): param_types.append(t) break else: - raise error("Invalid output format for '%s'" % (msgformat,)) + raise error("806: Invalid output format for '%s'" % (msgformat,)) args = args[pos+1:] return param_types @@ -227,7 +227,7 @@ def format_params(self, params): class MessageParser: error = error - def __init__(self, warn_prefix=""): + def __init__(self, warn_prefix="806: "): self.warn_prefix = warn_prefix self.unknown = UnknownFormat() self.enumerations = {} diff --git a/klippy/pins.py b/klippy/pins.py index 35fc58a255a3..c9179aad0b26 100644 --- a/klippy/pins.py +++ b/klippy/pins.py @@ -23,15 +23,15 @@ def __init__(self, validate_aliases=True): self.active_pins = {} def reserve_pin(self, pin, reserve_name): if pin in self.reserved and self.reserved[pin] != reserve_name: - raise error("Pin %s reserved for %s - can't reserve for %s" % ( + raise error("304: Pin %s reserved for %s - can't reserve for %s" % ( pin, self.reserved[pin], reserve_name)) self.reserved[pin] = reserve_name def alias_pin(self, alias, pin): if alias in self.aliases and self.aliases[alias] != pin: - raise error("Alias %s mapped to %s - can't alias to %s" % ( + raise error("304: Alias %s mapped to %s - can't alias to %s" % ( alias, self.aliases[alias], pin)) if [c for c in '^~!:' if c in pin] or ''.join(pin.split()) != pin: - raise error("Invalid pin alias '%s'\n" % (pin,)) + raise error("304: Invalid pin alias '%s'\n" % (pin,)) if pin in self.aliases: pin = self.aliases[pin] self.aliases[alias] = pin @@ -44,10 +44,10 @@ def pin_fixup(m): pin_id = self.aliases.get(name, name) if (name != self.active_pins.setdefault(pin_id, name) and self.validate_aliases): - raise error("pin %s is an alias for %s" % ( + raise error("304: pin %s is an alias for %s" % ( name, self.active_pins[pin_id])) if pin_id in self.reserved: - raise error("pin %s is reserved for %s" % ( + raise error("304: pin %s is reserved for %s" % ( name, self.reserved[pin_id])) return m.group('prefix') + str(pin_id) return re_pin.sub(pin_fixup, cmd) @@ -80,14 +80,14 @@ def parse_pin(self, pin_desc, can_invert=False, can_pullup=False): else: chip_name, pin = [s.strip() for s in desc.split(':', 1)] if chip_name not in self.chips: - raise error("Unknown pin chip name '%s'" % (chip_name,)) + raise error("304: Unknown pin chip name '%s'" % (chip_name,)) if [c for c in '^~!:' if c in pin] or ''.join(pin.split()) != pin: format = "" if can_pullup: format += "[^~] " if can_invert: format += "[!] " - raise error("Invalid pin description '%s'\n" + raise error("304: Invalid pin description '%s'\n" "Format is: %s[chip_name:] pin_name" % ( pin_desc, format)) pin_params = {'chip': self.chips[chip_name], 'chip_name': chip_name, @@ -103,10 +103,10 @@ def lookup_pin(self, pin_desc, can_invert=False, can_pullup=False, if share_name in self.allow_multi_use_pins: pass elif share_type is None or share_type != share_params['share_type']: - raise error("pin %s used multiple times in config" % (pin,)) + raise error("304: pin %s used multiple times in config" % (pin,)) elif (pin_params['invert'] != share_params['invert'] or pin_params['pullup'] != share_params['pullup']): - raise error("Shared pin %s must have same polarity" % (pin,)) + raise error("304: Shared pin %s must have same polarity" % (pin,)) return share_params pin_params['share_type'] = share_type self.active_pins[share_name] = pin_params @@ -121,12 +121,12 @@ def reset_pin_sharing(self, pin_params): del self.active_pins[share_name] def get_pin_resolver(self, chip_name): if chip_name not in self.pin_resolvers: - raise error("Unknown chip name '%s'" % (chip_name,)) + raise error("304: Unknown chip name '%s'" % (chip_name,)) return self.pin_resolvers[chip_name] def register_chip(self, chip_name, chip): chip_name = chip_name.strip() if chip_name in self.chips: - raise error("Duplicate chip name '%s'" % (chip_name,)) + raise error("304: Duplicate chip name '%s'" % (chip_name,)) self.chips[chip_name] = chip self.pin_resolvers[chip_name] = PinResolver() def allow_multi_use_pin(self, pin_desc): diff --git a/klippy/serialhdl.py b/klippy/serialhdl.py index 0285799385fb..d22d000b8bb6 100644 --- a/klippy/serialhdl.py +++ b/klippy/serialhdl.py @@ -12,7 +12,7 @@ class error(Exception): pass class SerialReader: - def __init__(self, reactor, warn_prefix=""): + def __init__(self, reactor, warn_prefix="807: "): self.reactor = reactor self.warn_prefix = warn_prefix # Serial port @@ -323,7 +323,7 @@ def get_response(self, cmds, cmd_queue, minclock=0, reqclock=0): return params if retries <= 0: self.serial.register_response(None, self.name, self.oid) - raise error("Unable to obtain '%s' response" % (self.name,)) + raise error("808: Unable to obtain '%s' response" % (self.name,)) reactor = self.serial.reactor reactor.pause(reactor.monotonic() + retry_delay) retries -= 1 diff --git a/klippy/stepper.py b/klippy/stepper.py index e4d3db8e0c07..3769e2870fe5 100644 --- a/klippy/stepper.py +++ b/klippy/stepper.py @@ -38,7 +38,7 @@ def __init__(self, name, step_pin_params, dir_pin_params, self._invert_step = step_pin_params['invert'] if dir_pin_params['chip'] is not self._mcu: raise self._mcu.get_printer().config_error( - "Stepper dir pin must be on same mcu as step pin") + "306: Stepper dir pin must be on same mcu as step pin") self._dir_pin = dir_pin_params['pin'] self._invert_dir = self._orig_invert_dir = dir_pin_params['invert'] self._step_both_edge = self._req_step_both_edge = False @@ -203,11 +203,11 @@ def note_homing_end(self): ffi_main, ffi_lib = chelper.get_ffi() ret = ffi_lib.stepcompress_reset(self._stepqueue, 0) if ret: - raise error("Internal error in stepcompress") + raise error("307: Internal error in stepcompress") data = (self._reset_cmd_tag, self._oid, 0) ret = ffi_lib.stepcompress_queue_msg(self._stepqueue, data, len(data)) if ret: - raise error("Internal error in stepcompress") + raise error("308: Internal error in stepcompress") self._query_mcu_position() def _query_mcu_position(self): @@ -223,7 +223,7 @@ def _query_mcu_position(self): ret = ffi_lib.stepcompress_set_last_position(self._stepqueue, clock, last_pos) if ret: - raise error("Internal error in stepcompress") + raise error("309: Internal error in stepcompress") self._set_mcu_position(last_pos) self._mcu.get_printer().send_event("stepper:sync_mcu_position", self) def get_trapq(self): @@ -254,7 +254,7 @@ def generate_steps(self, flush_time): sk = self._stepper_kinematics ret = self._itersolve_generate_steps(sk, flush_time) if ret: - raise error("Internal error in stepcompress") + raise error("3010: Internal error in stepcompress") def is_active_axis(self, axis): ffi_main, ffi_lib = chelper.get_ffi() @@ -314,7 +314,7 @@ def parse_step_distance(config, units_in_radians=None, note_valid=False): full_steps = config.getint('full_steps_per_rotation', 200, minval=1, note_valid=note_valid) if full_steps % 4: - raise config.error("full_steps_per_rotation invalid in section '%s'" + raise config.error("3011: full_steps_per_rotation invalid in section '%s'" % (config.get_name(),)) gearing = parse_gear_ratio(config, note_valid) return rotation_dist, full_steps * microsteps * gearing @@ -364,7 +364,7 @@ def __init__(self, config, need_position_minmax=True, if (self.position_endstop < self.position_min or self.position_endstop > self.position_max): raise config.error( - "position_endstop in section '%s' must be between" + "3021: position_endstop in section '%s' must be between" " position_min and position_max" % config.get_name()) else: self.position_min = -sys.float_info.max # float('-inf') @@ -389,7 +389,7 @@ def __init__(self, config, need_position_minmax=True, self.homing_positive_dir = True else: raise config.error( - "Unable to infer homing_positive_dir in section '%s'" + "3022: Unable to infer homing_positive_dir in section '%s'" % (config.get_name(),)) config.getboolean('homing_positive_dir', self.homing_positive_dir) elif ((self.homing_positive_dir @@ -397,7 +397,7 @@ def __init__(self, config, need_position_minmax=True, or (not self.homing_positive_dir and self.position_endstop == self.position_max)): raise config.error( - "Invalid homing_positive_dir / position_endstop in '%s'" + "3023: Invalid homing_positive_dir / position_endstop in '%s'" % (config.get_name(),)) def get_range(self): @@ -449,7 +449,7 @@ def add_extra_stepper(self, config): changed_invert = pin_params['invert'] != endstop['invert'] changed_pullup = pin_params['pullup'] != endstop['pullup'] if changed_invert or changed_pullup: - raise error("Pinter rail %s shared endstop pin %s " + raise error("3023: Pinter rail %s shared endstop pin %s " "must specify the same pullup/invert settings" % (self.get_name(), pin_name)) mcu_endstop.add_stepper(stepper) diff --git a/klippy/toolhead.py b/klippy/toolhead.py index b9a51219e7d8..cf572804d6a2 100644 --- a/klippy/toolhead.py +++ b/klippy/toolhead.py @@ -290,7 +290,7 @@ def __init__(self, config): except self.printer.lookup_object('pins').error as e: raise except: - msg = "Error loading kinematics '%s'" % (kin_name,) + msg = "0015: Error loading kinematics '%s'" % (kin_name,) logging.exception(msg) raise config.error(msg) # Register commands diff --git a/klippy/webhooks.py b/klippy/webhooks.py index 43ff9a914e62..36c9a4782c76 100644 --- a/klippy/webhooks.py +++ b/klippy/webhooks.py @@ -44,12 +44,12 @@ def __init__(self, client_conn, request): self.client_conn = client_conn base_request = json.loads(request, object_hook=json_loads_byteify) if type(base_request) != dict: - raise ValueError("Not a top-level dictionary") + raise ValueError("701: Not a top-level dictionary") self.id = base_request.get('id', None) self.method = base_request.get('method') self.params = base_request.get('params', {}) if type(self.method) != str or type(self.params) != dict: - raise ValueError("Invalid request type") + raise ValueError("702: Invalid request type") self.response = None self.is_error = False @@ -59,10 +59,10 @@ def get_client_connection(self): def get(self, item, default=Sentinel, types=None): value = self.params.get(item, default) if value is Sentinel: - raise WebRequestError("Missing Argument [%s]" % (item,)) + raise WebRequestError("703: Missing Argument [%s]" % (item,)) if (types is not None and type(value) not in types and item in self.params): - raise WebRequestError("Invalid Argument Type [%s]" % (item,)) + raise WebRequestError("704: Invalid Argument Type [%s]" % (item,)) return value def get_str(self, item, default=Sentinel): @@ -86,7 +86,7 @@ def set_error(self, error): def send(self, data): if self.response is not None: - raise WebRequestError("Multiple calls to send not allowed") + raise WebRequestError("705: Multiple calls to send not allowed") self.response = data def finish(self): @@ -155,7 +155,7 @@ def _remove_socket_file(self, file_path): except OSError: if os.path.exists(file_path): logging.exception( - "webhooks: Unable to delete socket file '%s'" + "706: webhooks: Unable to delete socket file '%s'" % (file_path)) raise @@ -308,7 +308,7 @@ def __init__(self, printer): def register_endpoint(self, path, callback): if path in self._endpoints: - raise WebRequestError("Path already registered to an endpoint") + raise WebRequestError("707: Path already registered to an endpoint") self._endpoints[path] = callback def register_mux_endpoint(self, path, key, value, callback): @@ -319,11 +319,11 @@ def register_mux_endpoint(self, path, key, value, callback): prev_key, prev_values = prev if prev_key != key: raise self.printer.config_error( - "mux endpoint %s %s %s may have only one key (%s)" + "708: mux endpoint %s %s %s may have only one key (%s)" % (path, key, value, prev_key)) if value in prev_values: raise self.printer.config_error( - "mux endpoint %s %s %s already registered (%s)" + "709: mux endpoint %s %s %s already registered (%s)" % (path, key, value, prev_values)) prev_values[value] = callback @@ -334,7 +334,7 @@ def _handle_mux(self, web_request): else: key_param = web_request.get(key) if key_param not in values: - raise web_request.error("The value '%s' is not valid for %s" + raise web_request.error("7010: The value '%s' is not valid for %s" % (key_param, key)) values[key_param](web_request) @@ -373,7 +373,7 @@ def get_connection(self): def get_callback(self, path): cb = self._endpoints.get(path, None) if cb is None: - msg = "webhooks: No registered callback for path '%s'" % (path) + msg = "7011: webhooks: No registered callback for path '%s'" % (path) logging.info(msg) raise WebRequestError(msg) return cb @@ -388,7 +388,7 @@ def stats(self, eventtime): def call_remote_method(self, method, **kwargs): if method not in self._remote_methods: raise self.printer.command_error( - "Remote method '%s' not registered" % (method)) + "7012: Remote method '%s' not registered" % (method)) conn_map = self._remote_methods[method] valid_conns = {} for conn, template in conn_map.items(): @@ -400,7 +400,7 @@ def call_remote_method(self, method, **kwargs): if not valid_conns: del self._remote_methods[method] raise self.printer.command_error( - "No active connections for method '%s'" % (method)) + "7013: No active connections for method '%s'" % (method)) self._remote_methods[method] = valid_conns class GCodeHelper: @@ -512,11 +512,11 @@ def _handle_query(self, web_request, is_subscribe=False): # Validate subscription format for k, v in objects.items(): if type(k) != str or (v is not None and type(v) != list): - raise web_request.error("Invalid argument") + raise web_request.error("7014: Invalid argument") if v is not None: for ri in v: if type(ri) != str: - raise web_request.error("Invalid argument") + raise web_request.error("7015: Invalid argument") # Add to pending queries cconn = web_request.get_client_connection() template = web_request.get_dict('response_template', {}) diff --git a/stereotech_config/ENDER-23.cfg b/stereotech_config/ENDER-23.cfg new file mode 100644 index 000000000000..7ac00fdcf0e4 --- /dev/null +++ b/stereotech_config/ENDER-23.cfg @@ -0,0 +1,28 @@ +[mcu] +serial: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 +restart_method: command + +[mcu second_mcu] +serial: /dev/serial/by-id/usb-Klipper_stm32g0b1xx_5800260019504B5735313920-if00 +restart_method: command + +[virtual_sdcard] +path: /home/ste/uploads + +[display_status] + +[include config/ender/kinematics.cfg] +[include config/ender/kinematics_tmc.cfg] +[include config/ender/homing.cfg] + + +[include config/ender/main_extruder.cfg] +[include config/ender/module_3d.cfg] +[include config/ender/module_3d_macros.cfg] +[include config/ender/module_5d.cfg] + +[include config/ender/print_macros.cfg] +[include config/ender/extruder_macros.cfg] +[include config/ender/variables.cfg] + +# [include config/ender/probe.cfg] diff --git a/stereotech_config/HFE530-5-3-23.cfg b/stereotech_config/HFE530-5-3-23.cfg index b73611bef3af..722c63002412 100644 --- a/stereotech_config/HFE530-5-3-23.cfg +++ b/stereotech_config/HFE530-5-3-23.cfg @@ -15,14 +15,15 @@ path: /home/ste/uploads [include config/chamber_2.cfg] [include config/printhead.cfg] -[include config/probe_2.cfg] +[include config/probe_main.cfg] +[include config/probe_DAC_v2.cfg] [include config/probe_fiber_printer.cfg] [include config/main_extruder.cfg] [include config/fiber_extruder_2.cfg] [include config/fiber_nozzle_offset.cfg] [include config/extruder_macros.cfg] -[include config/filament_control_2.cfg] +[include config/filament_control.cfg] [include config/power_control.cfg] [include config/module_3d_300.cfg] @@ -31,3 +32,4 @@ path: /home/ste/uploads [include config/print_macros.cfg] [include config/variables.cfg] +[include config/diagnostics.cfg] diff --git a/stereotech_config/HFE530-5-4-22.cfg b/stereotech_config/HFE530-5-4-22.cfg index f7142c9314b9..09c48041fad7 100644 --- a/stereotech_config/HFE530-5-4-22.cfg +++ b/stereotech_config/HFE530-5-4-22.cfg @@ -15,14 +15,15 @@ path: /home/ste/uploads [include config/chamber_2.cfg] [include config/printhead.cfg] -[include config/probe.cfg] +[include config/probe_main.cfg] +[include config/probe_DAC_v1.cfg] [include config/probe_hybrid_printer.cfg] [include config/main_extruder.cfg] [include config/fiber_extruder_2.cfg] [include config/fiber_nozzle_offset.cfg] [include config/extruder_macros.cfg] -[include config/filament_control_2.cfg] +[include config/filament_control.cfg] [include config/power_control.cfg] [include config/module_3d_300.cfg] diff --git a/stereotech_config/HFE530-5-8-23.cfg b/stereotech_config/HFE530-5-8-23.cfg new file mode 100644 index 000000000000..43096b7b08a5 --- /dev/null +++ b/stereotech_config/HFE530-5-8-23.cfg @@ -0,0 +1,35 @@ +[mcu] +serial: /dev/ttyACM0 + +[virtual_sdcard] +path: /home/ste/uploads + +[display_status] + +[include config/board_stm32f4.cfg] + +[include config/kinematics_300_3.cfg] +[include config/kinematics_tmc.cfg] +[include config/homing.cfg] + +[include config/chamber_2.cfg] + +[include config/printhead.cfg] +[include config/probe_main.cfg] +[include config/probe_DAC_v2.cfg] +[include config/probe_fiber_printer_3.cfg] + +[include config/main_extruder.cfg] +[include config/fiber_extruder_3.cfg] +[include config/fiber_nozzle_offset.cfg] +[include config/extruder_macros.cfg] +[include config/filament_control.cfg] +[include config/power_control.cfg] + +[include config/module_3d_300.cfg] +[include config/module_3d_macros.cfg] +[include config/module_5d.cfg] + +[include config/print_macros.cfg] +[include config/variables.cfg] +[include config/diagnostics.cfg] diff --git a/stereotech_config/HFE530-5-C-22.cfg b/stereotech_config/HFE530-5-C-22.cfg index cb8d69fd182e..6a5352ba60fd 100644 --- a/stereotech_config/HFE530-5-C-22.cfg +++ b/stereotech_config/HFE530-5-C-22.cfg @@ -15,14 +15,15 @@ path: /home/ste/uploads [include config/chamber_2.cfg] [include config/printhead.cfg] -[include config/probe.cfg] +[include config/probe_main.cfg] +[include config/probe_DAC_v1.cfg] [include config/probe_fiber_printer.cfg] [include config/main_extruder.cfg] [include config/fiber_extruder_2.cfg] [include config/fiber_nozzle_offset.cfg] [include config/extruder_macros.cfg] -[include config/filament_control_2.cfg] +[include config/filament_control.cfg] [include config/power_control.cfg] [include config/module_3d_300.cfg] diff --git a/stereotech_config/HTE530-5-3-23.cfg b/stereotech_config/HTE530-5-3-23.cfg index 5039dbbbea45..7957b8ac1f3d 100644 --- a/stereotech_config/HTE530-5-3-23.cfg +++ b/stereotech_config/HTE530-5-3-23.cfg @@ -15,15 +15,16 @@ path: /home/ste/uploads [include config/chamber_2.cfg] [include config/printhead.cfg] -[include config/probe_2.cfg] +[include config/probe_main.cfg] +[include config/probe_DAC_v2.cfg] [include config/probe_hybrid_printer.cfg] [include config/main_extruder.cfg] [include config/second_extruder.cfg] [include config/nozzle_offset.cfg] [include config/extruder_macros.cfg] -[include config/filament_control_2.cfg] -[include config/filament_control_second_2.cfg] +[include config/filament_control.cfg] +[include config/filament_control_second.cfg] [include config/power_control.cfg] [include config/module_3d_300.cfg] diff --git a/stereotech_config/HTE530-5-4-22.cfg b/stereotech_config/HTE530-5-4-22.cfg index 742e9b54cab8..52fde7b51823 100644 --- a/stereotech_config/HTE530-5-4-22.cfg +++ b/stereotech_config/HTE530-5-4-22.cfg @@ -15,15 +15,16 @@ path: /home/ste/uploads [include config/chamber_2.cfg] [include config/printhead.cfg] -[include config/probe.cfg] +[include config/probe_main.cfg] +[include config/probe_DAC_v1.cfg] [include config/probe_hybrid_printer.cfg] [include config/main_extruder.cfg] [include config/second_extruder.cfg] [include config/nozzle_offset.cfg] [include config/extruder_macros.cfg] -[include config/filament_control_2.cfg] -[include config/filament_control_second_2.cfg] +[include config/filament_control.cfg] +[include config/filament_control_second.cfg] [include config/power_control.cfg] [include config/module_3d_300.cfg] diff --git a/stereotech_config/HTE530-5-8-23.cfg b/stereotech_config/HTE530-5-8-23.cfg new file mode 100644 index 000000000000..092163850b38 --- /dev/null +++ b/stereotech_config/HTE530-5-8-23.cfg @@ -0,0 +1,36 @@ +[mcu] +serial: /dev/ttyACM0 + +[virtual_sdcard] +path: /home/ste/uploads + +[display_status] + +[include config/board_stm32f4.cfg] + +[include config/kinematics_300_3.cfg] +[include config/kinematics_tmc.cfg] +[include config/homing.cfg] + +[include config/chamber_2.cfg] + +[include config/printhead.cfg] +[include config/probe_main.cfg] +[include config/probe_DAC_v2.cfg] +[include config/probe_hybrid_printer.cfg] + +[include config/main_extruder.cfg] +[include config/second_extruder.cfg] +[include config/nozzle_offset.cfg] +[include config/extruder_macros.cfg] +[include config/filament_control.cfg] +[include config/filament_control_second.cfg] +[include config/power_control.cfg] + +[include config/module_3d_300.cfg] +[include config/module_3d_macros.cfg] +[include config/module_5d.cfg] + +[include config/print_macros.cfg] +[include config/variables.cfg] +[include config/diagnostics.cfg] diff --git a/stereotech_config/HTE600-0-0-23.cfg b/stereotech_config/HTE600-0-0-23.cfg deleted file mode 100644 index 18d376b5c4d8..000000000000 --- a/stereotech_config/HTE600-0-0-23.cfg +++ /dev/null @@ -1,38 +0,0 @@ -[mcu] -serial: /dev/ttyACM0 - -[mcu second_mcu] -serial: /dev/ttyACM1 # ls /dev/serial/by-id/* - -[virtual_sdcard] -path: /home/ste/uploads - -[display_status] - -[include config/v6/board_stm.cfg] -[include config/v6/kinematics.cfg] -[include config/v6/kinematics_tmc.cfg] -# [include config/v6/homing.cfg] - -[include config/v6/chamber.cfg] - -[include config/v6/printhead.cfg] -# [include config/v6/probe.cfg] -# [include config/v6/probe_hybrid_printer.cfg] - -[include config/v6/main_extruder.cfg] -[include config/v6/second_extruder.cfg] -[include config/v6/fiber_extruder.cfg] -# [include config/v6/nozzle_offset.cfg] -# [include config/v6/extruder_macros.cfg] -[include config/v6/filament_control_2.cfg] -[include config/v6/filament_control_second_2.cfg] -# [include config/v6/power_control.cfg] - -[include config/v6/module_3d.cfg] -# [include config/v6/module_3d_macros.cfg] -# [include config/v6/module_5d.cfg] - -# [include config/v6/print_macros.cfg] -# [include config/v6/variables.cfg] -# [include config/v6/diagnostics.cfg] diff --git a/stereotech_config/HTE630-0-0-23.cfg b/stereotech_config/HTE630-0-0-23.cfg new file mode 100644 index 000000000000..635e47ad1cf8 --- /dev/null +++ b/stereotech_config/HTE630-0-0-23.cfg @@ -0,0 +1,35 @@ +[mcu] +serial: /dev/ttyACM0 + +[virtual_sdcard] +path: /home/ste/uploads + +[display_status] + +[include config/board_stm32f4.cfg] + +[include config/v6/kinematics.cfg] +[include config/kinematics_tmc.cfg] +[include config/homing.cfg] + +[include config/chamber_2.cfg] + +[include config/printhead.cfg] +[include config/probe.cfg] +[include config/probe_hybrid_printer.cfg] + +[include config/main_extruder.cfg] +[include config/second_extruder.cfg] +[include config/nozzle_offset.cfg] +[include config/extruder_macros.cfg] +[include config/filament_control_2.cfg] +[include config/filament_control_second_2.cfg] +[include config/power_control.cfg] + +[include config/module_3d_300.cfg] +[include config/module_3d_macros.cfg] +[include config/module_5d.cfg] + +[include config/print_macros.cfg] +[include config/variables.cfg] +[include config/diagnostics.cfg] diff --git a/stereotech_config/HTE750-0-0-23.cfg b/stereotech_config/HTE750-0-0-23.cfg new file mode 100644 index 000000000000..9aece6f3b69e --- /dev/null +++ b/stereotech_config/HTE750-0-0-23.cfg @@ -0,0 +1,38 @@ +[mcu] +serial: /dev/ttyACM1 + +[mcu second_mcu] +serial: /dev/ttyACM0 + +[virtual_sdcard] +path: /home/ste/uploads + +[display_status] + +# [include config/v7/kinematics_none.cfg] + +[include config/v7/board_stm32f4.cfg] +[include config/v7/board_stm32g1b0.cfg] + +[include config/v7/kinematics.cfg] +[include config/v7/kinematics_tmc.cfg] + +# [include config/v7/chamber.cfg] +# [include config/v7/printhead.cfg] +# [include config/v7/main_extruder.cfg] +# [include config/v7/second_extruder.cfg] +# [include config/v7/fiber_extruder.cfg] +# [include config/v7/filament_control_2.cfg] +# [include config/v7/filament_control_second_2.cfg] +# [include config/v7/module_3d.cfg] +# [include config/v7/module_5d.cfg] +# [include config/v7/homing.cfg] +# [include config/v7/probe.cfg] +# [include config/v7/probe_hybrid_printer.cfg] +# [include config/v7/nozzle_offset.cfg] +# [include config/v7/extruder_macros.cfg] +# [include config/v7/power_control.cfg] +# [include config/v7/module_3d_macros.cfg] +# [include config/v7/print_macros.cfg] +# [include config/v7/variables.cfg] +# [include config/v7/diagnostics.cfg] diff --git a/stereotech_config/diagnostics.cfg b/stereotech_config/diagnostics.cfg index 1fa57ce13478..42ffdf918818 100644 --- a/stereotech_config/diagnostics.cfg +++ b/stereotech_config/diagnostics.cfg @@ -75,17 +75,23 @@ description: Checking heater for in move. gcode: {% set heater = params.HEATER|default('extruder')|lower %} {% set temp = params.TEMP|default(100)|float %} + {% set axis_min_x = printer.toolhead.axis_minimum[0] * 0 %} + {% set axis_min_y = printer.toolhead.axis_minimum[1] %} + {% set axis_min_z = printer.toolhead.axis_minimum[2] * 0 + 10 %} + {% set axis_max_x = printer.toolhead.axis_maximum[0] %} + {% set axis_max_y = printer.toolhead.axis_maximum[1] - 1 %} + {% set axis_max_z = printer.toolhead.axis_maximum[2] %} G28 SET_TEMP_HEATER HEATER={heater} TEMP={temp} - G1 X{printer.toolhead.axis_minimum[0]} Y{printer.toolhead.axis_minimum[1]} Z{printer.toolhead.axis_minimum[2] * 0} F3600 + G1 X{axis_min_x} Y{axis_min_y} Z{axis_min_z} F3600 SET_TEMP_HEATER HEATER={heater} TEMP={temp} - G1 X{printer.toolhead.axis_minimum[0]} Y{printer.toolhead.axis_maximum[1]} Z{printer.toolhead.axis_maximum[2]} F3600 + G1 X{axis_min_x} Y{axis_max_y} Z{axis_max_z} F3600 SET_TEMP_HEATER HEATER={heater} TEMP={temp} - G1 X{printer.toolhead.axis_maximum[0]} Y{printer.toolhead.axis_minimum[1]} Z{printer.toolhead.axis_minimum[2] * 0} F3600 + G1 X{axis_max_x} Y{axis_min_y} Z{axis_min_z} F3600 SET_TEMP_HEATER HEATER={heater} TEMP={temp} - G1 X{printer.toolhead.axis_maximum[0]} Y{printer.toolhead.axis_maximum[1]} Z{printer.toolhead.axis_maximum[2]} F3600 + G1 X{axis_max_x} Y{axis_max_y} Z{axis_max_z} F3600 SET_TEMP_HEATER HEATER={heater} TEMP={temp} - G1 X{printer.toolhead.axis_minimum[0]} Y{printer.toolhead.axis_minimum[1]} Z{printer.toolhead.axis_minimum[2] * 0} F3600 + G1 X{axis_min_x} Y{axis_min_y} Z{axis_min_z} F3600 SET_TEMP_HEATER HEATER={heater} TEMP={temp} G28 M84 @@ -96,7 +102,7 @@ gcode: {% set heater = params.HEATER|default('extruder')|lower %} {% set temp = params.TEMP|default(100)|float %} {% if printer["gcode_button five_axis_module"].state == "PRESSED" and heater == "heater_bed" %} - {action_raise_error("3D module disabled, cannot set temperature for heater 'heater_bed'.")} + {action_raise_error("501: 3D module disabled, cannot set temperature for heater 'heater_bed'.")} {% else %} SET_HEATER_TEMPERATURE HEATER={heater} TARGET={temp} TEMPERATURE_WAIT SENSOR={heater} MINIMUM={temp} MAXIMUM={temp + 2} @@ -144,5 +150,19 @@ gcode: {% endif %} T0 # return to main state {% else %} - {action_raise_error("Extruder '%s' not connected." % extruder)} + {action_raise_error("502: Extruder '%s' not connected." % extruder)} + {% endif %} + +[gcode_macro CHECK_FAN] +description: Checking fans. +gcode: + {% set fan = params.FAN|default('fan') %} + {% if fan == 'fan' %} + M106 S255 + G4 P5000 + M107 + {% elif fan == 'chamber_fan' %} + SET_FAN_SPEED FAN=chamber_fan SPEED=1.0 + G4 P5000 + SET_FAN_SPEED FAN=chamber_fan SPEED=0.0 {% endif %} diff --git a/stereotech_config/ender/extruder_macros.cfg b/stereotech_config/ender/extruder_macros.cfg new file mode 100644 index 000000000000..9bdd58af4103 --- /dev/null +++ b/stereotech_config/ender/extruder_macros.cfg @@ -0,0 +1,41 @@ +[gcode_macro INSERT_MATERIAL] +gcode: + G91 + {% set active_extruder = printer.toolhead.extruder %} + G1 E100 F300 + G90 + +[gcode_macro EJECT_MATERIAL] +gcode: + LOAD_MATERIAL + G91 + {% set active_extruder = printer.toolhead.extruder %} + G1 E-100 F300 + G90 + +[gcode_macro LOAD_MATERIAL] +gcode: + G91 + G1 E20 F300 + G90 + +[gcode_macro RETRACT_MATERIAL] +gcode: + G91 + G1 E-20 F300 + G90 + +[gcode_macro M109] +rename_existing: M1091 +gcode: + M117 extruder_heating + M1091 S{params.S} + M117 + +[gcode_macro TURN_OFF_EXTRUDERS] +gcode: + M104 T0 S0 + +[delayed_gcode TURN_OFF_EXTRUDERS_DELAYED] +gcode: + TURN_OFF_EXTRUDERS diff --git a/stereotech_config/ender/homing.cfg b/stereotech_config/ender/homing.cfg new file mode 100644 index 000000000000..d71e731dc50f --- /dev/null +++ b/stereotech_config/ender/homing.cfg @@ -0,0 +1,95 @@ +[homing_override] +axes: +gcode: + {% set axis_max = printer.toolhead.axis_maximum %} + G28 Z + G1 Z{axis_max[2] - 50} F3600 + G28 X + G28 Y + {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} + G28 A + G28 C + {% endif %} + +[gcode_macro MOVE_SERVICE_POSITION] +gcode: + G54 + TURN_OFF_HEATERS + G28 + G92 E0 + {% set max_x = printer.toolhead.axis_maximum[0] %} + G1 Z200 F3600 + G0 X{max_x / 2.0} Y50 F3600 + SET_IDLE_TIMEOUT TIMEOUT=7200 + +[gcode_macro MOVE_SERVICE_POSITION_HEAD] +gcode: + {% set max_x = printer.toolhead.axis_maximum[0] %} + G54 + TURN_OFF_HEATERS + G28 + G92 E0 + G90 + G0 X{max_x / 2.0} Y50 Z200 F3600 + SET_IDLE_TIMEOUT TIMEOUT=7200 + +[gcode_macro HOME_POSITION] +gcode: + {% set axis_max = printer.toolhead.axis_maximum %} + G54 + TURN_OFF_HEATERS + G1 C0 + G1 Z{axis_max[2] - 50} + G1 Y0 + G28 + G92 E0 + G90 + {% if params.ABORT|default(0)|float == 0 %} + SAVE_VARIABLES + SAVE_STATE_MODULE + {% else %} + ABORT + {% endif %} + {% if printer.probe %} + CANCEL_TEST_PROBE + {% endif %} + SET_IDLE_TIMEOUT TIMEOUT=600 + +# [gcode_macro MOVE_TO_SERVICE_POSITION] +# description: move in position for service +# gcode: +# {% if printer.toolhead.axis_maximum[0] > 250 %} +# {% set x = params.X|default(300) %} +# {% set y = params.Y|default(10) %} +# {% else %} +# {% set x = params.X|default(200) %} +# {% set y = params.Y|default(10) %} +# {% endif %} +# {% set z = params.Z|default(50)|float %} +# {% set e = params.E|default(3) %} +# {% set max_z = printer.toolhead.axis_maximum.z|float %} +# {% set act_z = printer.toolhead.position.z|float %} +# {% set lift_z = z|abs %} +# {% set fan_speed = printer.fan.speed * 255 | int %} +# {% if act_z < (max_z - lift_z) %} +# {% set z_safe = lift_z %} +# {% else %} +# {% set z_safe = max_z - act_z %} +# {% endif %} +# {% if z_safe < 0 %} +# {% set z_safe = 0 %} +# {% endif %} +# G54 +# G91 +# {% if printer[printer.toolhead.extruder].can_extrude|lower == 'true' %} +# G1 E-{e} F1200 +# {% else %} +# {action_respond_warning("611: Extruder not hot enough")} +# {% endif %} +# {% if "xyz" in printer.toolhead.homed_axes %} +# G1 Z{z_safe} F3600 +# G90 +# G1 X{x} Y{y} F3600 +# {% else %} +# {action_respond_warning("813: Printer not homed")} +# {% endif %} diff --git a/stereotech_config/ender/kinematics.cfg b/stereotech_config/ender/kinematics.cfg new file mode 100644 index 000000000000..e31758e0d1fe --- /dev/null +++ b/stereotech_config/ender/kinematics.cfg @@ -0,0 +1,63 @@ +[printer] +kinematics: cartesian_6axis +max_velocity: 300 +max_accel: 3000 +max_z_velocity: 20 +max_z_accel: 100 +square_corner_velocity: 2.50 + +[stepper_x] +step_pin: PC2 +dir_pin: PB9 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA5 +position_endstop: 0 +position_max: 235 +homing_speed: 70 + +[stepper_y] +step_pin: PB8 +dir_pin: PB7 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA6 +position_endstop: 0 +position_max: 230 +homing_speed: 20 + +[stepper_z] +step_pin: PB6 +dir_pin: !PB5 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 8 +endstop_pin: ^PA7 +position_endstop: 0.0 +position_max: 250 +homing_speed: 20 + +[stepper_a] +step_pin: second_mcu: PB13 +dir_pin: !second_mcu:PB12 +enable_pin: !second_mcu:PB14 +microsteps: 16 +rotation_distance: 360 +gear_ratio: 80:20 +endstop_pin: second_mcu:PC0 +position_endstop: 0 +position_min: -10 +position_max: 90 +homing_speed: 10 + +[stepper_c] +step_pin: second_mcu:PB10 +dir_pin: second_mcu:PB2 +enable_pin: !second_mcu:PB11 +microsteps: 16 +rotation_distance: 120 +gear_ratio: 80:20 +can_home: false +homing_speed: 10 diff --git a/stereotech_config/ender/kinematics_tmc.cfg b/stereotech_config/ender/kinematics_tmc.cfg new file mode 100644 index 000000000000..ed90f3c5306c --- /dev/null +++ b/stereotech_config/ender/kinematics_tmc.cfg @@ -0,0 +1,13 @@ +[tmc2209 stepper_a] +uart_pin: second_mcu:PC11 +tx_pin: second_mcu:PC10 +uart_address: 0 +run_current: 0.580 +stealthchop_threshold: 999999 + +[tmc2209 stepper_c] +uart_pin: second_mcu:PC11 +tx_pin: second_mcu:PC10 +uart_address: 2 +run_current: 0.580 +stealthchop_threshold: 999999 diff --git a/stereotech_config/ender/main_extruder.cfg b/stereotech_config/ender/main_extruder.cfg new file mode 100644 index 000000000000..04605fb7d7e0 --- /dev/null +++ b/stereotech_config/ender/main_extruder.cfg @@ -0,0 +1,32 @@ +[extruder] +max_extrude_only_distance: 100.0 +step_pin: PB4 +dir_pin: PB3 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 34.406 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +heater_pin: PA1 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC5 +control: pid +# tuned for stock hardware with 200 degree Celsius target +pid_Kp: 21.527 +pid_Ki: 1.063 +pid_Kd: 108.982 +min_temp: 0 +max_temp: 250 + +[gcode_macro T0] +gcode: + M117 set_extruder + {% set current_wcs = printer.gcode_move.current_wcs %} + {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and "z" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder' %} + G54 + MOVE_UP_Z_AXIS Z=5 + G0 X10 Y2 F3600 + {% endif %} + ACTIVATE_EXTRUDER extruder=extruder + SET_WCS WCS={current_wcs} + M117 diff --git a/stereotech_config/ender/module_3d.cfg b/stereotech_config/ender/module_3d.cfg new file mode 100644 index 000000000000..1208aa2f2195 --- /dev/null +++ b/stereotech_config/ender/module_3d.cfg @@ -0,0 +1,22 @@ +[heater_bed] +heater_pin: PA2 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC4 +control: pid +# tuned for stock hardware with 50 degree Celsius target +pid_Kp: 54.027 +pid_Ki: 0.770 +pid_Kd: 948.182 +min_temp: 0 +max_temp: 130 + +[bed_screws] +horizontal_move_z: 10.0 +screw1: 20,210 +screw2: 220,210 +screw1_fine_adjust: 159,0 +screw3: 20,10 +screw4: 220,10 + +[fan] +pin: PA0 diff --git a/stereotech_config/ender/module_3d_macros.cfg b/stereotech_config/ender/module_3d_macros.cfg new file mode 100644 index 000000000000..de54a24282f5 --- /dev/null +++ b/stereotech_config/ender/module_3d_macros.cfg @@ -0,0 +1,36 @@ +[gcode_macro M140] +rename_existing: M141 +gcode: + {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} + M141 S{ params.S } + {% endif %} + +[gcode_macro M190] +rename_existing: M191 +gcode: + {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} + M117 platform_heating + M191 S{ params.S } + M117 + {% endif %} + +[gcode_macro Z_ENDSTOP_CALIBRATE] +rename_existing: Z_ENDSTOP_CALIBRATE_OLD +gcode: + G54 + TURN_OFF_HEATERS + SET_GCODE_OFFSET Z=0 + G28 + G92 E0 + G0 X117 Y115 Z10 F3600 + SET_IDLE_TIMEOUT TIMEOUT=7200 + Z_ENDSTOP_CALIBRATE_OLD + +[gcode_macro ACCEPT_Z_ENDSTOP] +gcode: + ACCEPT + G28 Z + {% set probe = params.PROBE|default(0)|int %} + {% if probe < 1 %} + BED_SCREWS_ADJUST + {% endif %} diff --git a/stereotech_config/ender/module_5d.cfg b/stereotech_config/ender/module_5d.cfg new file mode 100644 index 000000000000..bc4de0372ec5 --- /dev/null +++ b/stereotech_config/ender/module_5d.cfg @@ -0,0 +1,92 @@ +[gcode_button five_axis_module] +pin: !second_mcu:PC4 +press_gcode: QUERY_BUTTON BUTTON=five_axis_module + +[a_axis_offset] + +[gcode_macro MOVE_WCS_ZERO] +gcode: + G54 + G0 Z200 F3600 + {% set current_wcs = params.WCS|default(1)|int %} + {% set offsets = printer.gcode_move.wcs_offsets[current_wcs] %} + {% if offsets[0] == 0 and offsets[1] == 0 %} + G0 X120 Y50 F3600 + {% else %} + G0 X{offsets[0]} Y{offsets[1]} F3600 + {% endif %} + {% if current_wcs == 1 %} + G0 A0 + {% elif current_wcs == 2 %} + G0 Y110 A90 F3600 C-30 + {% endif %} + +[gcode_macro SET_WCS_OFFSET] +description: macro for set the wcs for: manual calibrate FULL and SPIRALL and manual calibrate 5d module above old template +gcode: + G54 + G90 + {% set current_wcs = params.WCS|default(1)|int %} + {% set adjust_wcs = params.ADJUST_WCS|default(0)|int %} + SET_WCS WCS={current_wcs} + {% if (current_wcs == 2 or current_wcs == 4) and adjust_wcs == 0 %} + # for manual calibrate 5d module by old template + G10 L20 X{params.X} Y{params.Y} Z{params.Z|float + 50.0} + {% else %} + G10 L20 X{params.X} Y{params.Y} Z{params.Z} + {% endif %} + G54 + {% if adjust_wcs > 0 and adjust_wcs != current_wcs %} + ADJUST_WCS_OFFSET WCS={current_wcs} ADJUST_WCS={adjust_wcs} X={params.X} Y={params.Y} Z={params.Z} + {% endif %} + +[gcode_macro ADJUST_WCS_OFFSET] +gcode: + {% set current_wcs = params.WCS|default(1)|int %} + {% set adjust_wcs = params.ADJUST_WCS|default(0)|int %} + {% set source_wcs = current_wcs + 2 %} + {% set source_wcs_2 = adjust_wcs + 2 %} + {% set offsets = printer.gcode_move.wcs_offsets[source_wcs] %} + {% set offsets_2 = printer.gcode_move.wcs_offsets[source_wcs_2] %} + {% set delta_x = printer.gcode_move.wcs_offsets[current_wcs][0] - offsets[0] %} + {% set delta_y = printer.gcode_move.wcs_offsets[current_wcs][1] - offsets[1] %} + {% set delta_z = printer.gcode_move.wcs_offsets[current_wcs][2] - offsets[2] %} + # G10 L2 P{adjust_wcs + 1} X{offsets_2[0] + delta_x + params.X|float} Y{offsets_2[1] - delta_z + params.Z|float} Z{offsets_2[2] + delta_y + params.Y|float} + G10 L2 P{adjust_wcs + 1} X{offsets_2[0] + delta_x + params.X|float} Y{offsets_2[1] - delta_z + params.Z|float} Z{offsets_2[2] + params.Y|float} + +[gcode_macro MOVE_CALIBRATION_POINT] +gcode: + G54 + {% set point = params.POINT|default(0)|int %} + {% set x = 118 %} + {% set y = 174 %} + {% if point == 3 or point == 4 %} + {% set y = 123 %} + {% endif %} + {% if point == 1 %} + {% set x = 118 %} + {% endif %} + {% if point == 2 %} + {% set x = 158 %} + {% endif %} + G0 A0 + G0 X{x} Y{y} Z150 F600 + {% if point > 3 %} + G0 Z150 A90 F600 + {% endif %} + +[gcode_macro SET_A_AXIS_OFFSET_POINT] +gcode: + {% set point = params.POINT|default(0)|int %} + {% set coord_x = printer.gcode_move.position.x %} + {% set coord_y = printer.gcode_move.position.y %} + {% set coord_z = printer.gcode_move.position.z %} + SAVE_A_AXIS_POINT POINT={point} COORDS={coord_x},{coord_y},{coord_z} + +[gcode_macro SAVE_STATE_MODULE] +gcode: + {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} + SAVE_VARIABLE VARIABLE=5d_module_enabled VALUE=0 + {% else %} + SAVE_VARIABLE VARIABLE=5d_module_enabled VALUE=1 + {% endif %} diff --git a/stereotech_config/ender/print_macros.cfg b/stereotech_config/ender/print_macros.cfg new file mode 100644 index 000000000000..814683cc1938 --- /dev/null +++ b/stereotech_config/ender/print_macros.cfg @@ -0,0 +1,176 @@ +[pause_resume] + +[gcode_macro PAUSE] +description: Pause the actual running print +rename_existing: PAUSE_BASE +variable_extruder_temp: 0 +variable_extruder1_temp: 0 +variable_current_extruder: 0 +variable_fan_speed: 0 +gcode: + ENABLE_CONSTRAIN ENABLE=0 + {% if printer.toolhead.axis_maximum[0] > 250 %} + {% set x = params.X|default(300) %} + {% set y = params.Y|default(10) %} + {% else %} + {% set x = params.X|default(200) %} + {% set y = params.Y|default(10) %} + {% endif %} + {% set z = params.Z|default(50)|float %} + {% set e = params.E|default(3) %} + {% set turn_off_extruders = params.TURN_OFF_EXTRUDERS|default(1)|int %} + {% set max_z = printer.toolhead.axis_maximum.z|float %} + {% set act_z = printer.toolhead.position.z|float %} + {% set lift_z = z|abs %} + {% set fan_speed = printer.fan.speed * 255 | int %} + {% if act_z < (max_z - lift_z) %} + {% set z_safe = lift_z %} + {% else %} + {% set z_safe = max_z - act_z %} + {% endif %} + {% if z_safe < 0 %} + {% set z_safe = 0 %} + {% endif %} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE={printer.extruder.target} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=fan_speed VALUE={fan_speed} + SET_IDLE_TIMEOUT TIMEOUT=360000 + PAUSE_BASE + G54 + G91 + {% if printer[printer.toolhead.extruder].can_extrude|lower == 'true' %} + G1 E-{e} F1200 + {% else %} + {action_respond_warning("611: Extruder not hot enough")} + {% endif %} + {% if "xyz" in printer.toolhead.homed_axes %} + G1 Z{z_safe} F3600 + G90 + G1 X{x} Y{y} F3600 + {% else %} + {action_respond_warning("814: Printer not homed")} + {% endif %} + M106 S0 + +[gcode_macro RESUME] +description: Resume the actual running print +rename_existing: RESUME_BASE +gcode: + ENABLE_CONSTRAIN ENABLE=0 + M109 T0 S{printer["gcode_macro PAUSE"].extruder_temp} + M106 S{printer["gcode_macro PAUSE"].fan_speed} + T{printer["gcode_macro PAUSE"].current_extruder} + {% set e = params.E|default(8) %} + {% set velocity = params.VELOCITY|default(30) %} + G91 + {% if printer[printer.toolhead.extruder].can_extrude|lower == 'true' %} + G1 E{e} F1800 + {% else %} + {action_respond_warning("611: Extruder not hot enough")} + {% endif %} + G90 + SET_IDLE_TIMEOUT TIMEOUT=600 + RESUME_BASE VELOCITY={velocity} + M117 + ENABLE_CONSTRAIN ENABLE=1 + +[gcode_macro CANCEL_PRINT] +description: Cancel the actual running print +rename_existing: CANCEL_PRINT_BASE +gcode: + ENABLE_CONSTRAIN ENABLE=0 + {% set e = params.E|default(3) %} + {% set z = params.Z|default(50)|float %} + G40 + G54 + {% if printer.extruder.can_extrude|lower == 'true' %} + G91 + G1 E-{e} F2100 + G90 + {% endif %} + TURN_OFF_HEATERS + M107 + SET_FAN_SPEED FAN=chamber_fan SPEED=0.0 + MOVE_UP_Z_AXIS Z={z} + G28 X0 Y0 + T0 + CANCEL_PRINT_BASE + + +[gcode_macro START] +description: Start Gcode +gcode: + ENABLE_CONSTRAIN ENABLE=0 + G21 + G90 + M82 + M107 + G28 + {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} + G0 Y20 Z30 F2100 + {% else %} + G0 Y0 C1 A90 F3600 + {% endif %} + G92 E0 C0 + ENABLE_CONSTRAIN ENABLE=1 + +[delayed_gcode CHECK_TEMP] +gcode: + {% set temp_e = printer.extruder.temperature|float %} + {% set temp_e1 = printer.extruder1.temperature|float %} + {% if temp_e < 50 and temp_e1 < 50 %} + UPDATE_DELAYED_GCODE ID=CHECK_TEMP DURATION=0 + POWER_OFF + {% else %} + UPDATE_DELAYED_GCODE ID=CHECK_TEMP DURATION=10 + {% endif %} + +[gcode_macro END] +description: End Gcode +variable_power_off: 0 +gcode: + ENABLE_CONSTRAIN ENABLE=0 + { action_respond_info('Printjob ended') } + {% set z = params.Z|default(50)|float %} + {% set e = params.E|default(3) %} + G40 + G54 + {% if printer.extruder.can_extrude|lower == 'true' %} + G91 + G1 E-{e} F2100 + G90 + {% endif %} + TURN_OFF_HEATERS + M107 + SET_FAN_SPEED FAN=chamber_fan SPEED=0.0 + MOVE_UP_Z_AXIS Z={z} + G28 X0 Y0 + T0 + {% if printer['gcode_macro END'].power_off %} + UPDATE_DELAYED_GCODE ID=CHECK_TEMP DURATION=1 + {% endif %} + +[gcode_macro MOVE_UP_Z_AXIS] +description: macro to move down z axis. +gcode: + {% set max_z = printer.toolhead.axis_maximum.z|float %} + {% set act_z = printer.toolhead.position.z|float %} + {% set z = params.Z|default(50)|float %} + {% set lift_z = z|abs %} + {% if act_z < (max_z - lift_z) %} + {% set z_safe = lift_z %} + {% else %} + {% set z_safe = max_z - act_z - 0.1 %} + {% endif %} + {% if z_safe < 0 %} + {% set z_safe = 0 %} + {% endif %} + {% set result_move = act_z + z_safe %} + {% if result_move >= max_z - 0.1 %} + {% set z_safe = 0 %} + {% endif %} + G54 + G91 + {% if "z" in printer.toolhead.homed_axes %} + G1 Z{z_safe} F1600 + {% endif %} + G90 diff --git a/stereotech_config/ender/printhead.cfg b/stereotech_config/ender/printhead.cfg new file mode 100644 index 000000000000..0ff89b663aeb --- /dev/null +++ b/stereotech_config/ender/printhead.cfg @@ -0,0 +1,7 @@ +[fan] +pin: PA0 + +# [heater_fan heatsink_fan] +# pin: heatsink_fan_pin +# heater: extruder, extruder1 +# heater_temp: 50.0 diff --git a/stereotech_config/ender/probe.cfg b/stereotech_config/ender/probe.cfg new file mode 100644 index 000000000000..4ced317536ac --- /dev/null +++ b/stereotech_config/ender/probe.cfg @@ -0,0 +1,526 @@ +[probe] +pin: !PG13 +samples: 4 +samples_tolerance_retries: 1 +samples_result: median +lift_speed: 10.0 +x_offset: -42.3 +y_offset: -48.14 +z_offset: 0.0 + +[auto_wcs] +# [skew_correction] +# [b_axis_compensation] + +# [bed_mesh] +# speed: 120 +# horizontal_move_z: 50 +# mesh_min: 20, 20 +# mesh_max: 261, 245 +# probe_count: 5, 5 +# fade_start: 1 +# fade_end: 10 +# fade_target: 0 + +# [bed_mesh module_3d] +# version = 1 +# points = +# 0.0, 0.0, 0.0, 0.0, 0.0 +# 0.0, 0.0, 0.0, 0.0, 0.0 +# 0.0, 0.0, 0.0, 0.0, 0.0 +# 0.0, 0.0, 0.0, 0.0, 0.0 +# 0.0, 0.0, 0.0, 0.0, 0.0 +# x_count = 5 +# y_count = 5 +# mesh_x_pps = 2 +# mesh_y_pps = 2 +# algo = lagrange +# tension = 0.2 +# min_x = 10.0 +# max_x = 261.0 +# min_y = 10.0 +# max_y = 253.0 + +# [gcode_macro SET_PROBE_SENSOR] +# description: Set offsets for new sensor and set sensor version. +# gcode: +# {% set probe_sensor_version = params.PROBE_VERSION|default(0)|int %} +# {% if probe_sensor_version > 0 %} +# {% set x_offset = -40.0 %} +# {% set y_offset = -34.0 %} +# {% set z_offset = 0.0 %} +# {% else %} +# {% set x_offset = -42.3 %} +# {% set y_offset = -48.14 %} +# {% set z_offset = 0.0 %} +# {% endif %} +# Z_OFFSET_APPLY_PROBE X={x_offset} Y={y_offset} Z={z_offset} +# SAVE_VARIABLE VARIABLE=probe_sensor_version VALUE={probe_sensor_version} +# SAVE_VARIABLE VARIABLE=probe_offset_x VALUE={x_offset} +# SAVE_VARIABLE VARIABLE=probe_offset_y VALUE={y_offset} +# SAVE_VARIABLE VARIABLE=probe_offset_z VALUE={z_offset} +# {action_respond_info("Apply offset for new sensor: x_offset= %s, y_offset= %s, z_offset= %s" % (x_offset, y_offset, z_offset))} + +# [gcode_macro TEST_PROBE] +# gcode: +# QUERY_PROBE +# UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=1.0 + +# [gcode_macro CANCEL_TEST_PROBE] +# gcode: +# UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=0.0 +# {action_respond_info('Abort check loop')} + +# [delayed_gcode test_probe_loop] +# gcode: +# {% if printer["probe"].last_query %} +# UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=0.0 +# {action_respond_info('Probe pressed, abort check loop')} +# {% else %} +# {action_respond_info('Probe not pressed')} +# QUERY_PROBE +# UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=1.0 +# {% endif %} + +# [gcode_macro CALIBRATE_MODULE_THREE_D] +# description: 3D module calibration +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} +# G0 X197 Y195 F6000 +# PROBE +# G91 +# G0 Z30 F600 +# G90 +# MODULE_THREE_D_MESH_CALIBRATE +# G91 +# G0 Z30 F600 +# G90 +# G0 X150 Y50 F3600 +# {% endif %} + +# [gcode_macro MODULE_THREE_D_MESH_CALIBRATE] +# description: 3D module calibration +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} +# Z_OFFSET_APPLY_PROBE Z={printer.probe.last_result[2]} +# BED_MESH_CALIBRATE PROFILE=module_3d +# BED_MESH_CLEAR +# {% endif %} + +# [gcode_macro CALIBRATE_MODULE_FIVE_D] +# description: 5D module calibration +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} +# G28 A +# M204 S500 +# G0 C0.1 +# G0 C0 +# {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} +# ADJUST_TEMPLATE_HEIGHT +# PROBE_TEMPLATE_POINT POINT=AY +# SET_C_ALIGN_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=BY +# SET_C_ALIGN_POINT POINT=1 +# CALC_C_AXIS_ALIGN +# PROBE_TEMPLATE_POINT POINT=AY +# SET_C_ALIGN_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=BY +# SET_C_ALIGN_POINT POINT=1 +# CALC_C_AXIS_ALIGN + +# PROBE_TEMPLATE_POINT POINT=O +# SET_A_OFFSET_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=CZ +# SET_A_OFFSET_POINT POINT=1 +# CALC_A_AXIS_OFFSET +# PROBE_TEMPLATE_POINT POINT=O +# SET_A_OFFSET_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=CZ +# SET_A_OFFSET_POINT POINT=1 +# CALC_A_AXIS_OFFSET + +# ; PROBE_TEMPLATE_POINT POINT=CZ +# ; SET_B_COMPENSATION_POINT POINT=0 +# ; PROBE_TEMPLATE_POINT POINT=CZ1 +# ; SET_B_COMPENSATION_POINT POINT=1 +# ; PROBE_TEMPLATE_POINT POINT=AZ +# ; SET_B_COMPENSATION_POINT POINT=2 +# ; PROBE_TEMPLATE_POINT POINT=BZ +# ; SET_B_COMPENSATION_POINT POINT=3 +# ; PROBE_TEMPLATE_POINT POINT=AX +# ; SET_B_COMPENSATION_POINT POINT=4 +# ; PROBE_TEMPLATE_POINT POINT=BX +# ; SET_B_COMPENSATION_POINT POINT=5 +# ; CALC_B_AXIS_COMPENSATION ENABLE=0 + +# ; skew corection +# ; xy skew +# ;PROBE_TEMPLATE_POINT POINT=AX +# ;SET_SKEW_COMPENSATION_POINT POINT=0 +# ;PROBE_TEMPLATE_POINT POINT=BX +# ;SET_SKEW_COMPENSATION_POINT POINT=1 +# ;PROBE_TEMPLATE_POINT POINT=XY1 +# ;SET_SKEW_COMPENSATION_POINT POINT=2 +# ;PROBE_TEMPLATE_POINT POINT=XY2 +# ;SET_SKEW_COMPENSATION_POINT POINT=3 +# ;CALC_SKEW_COMPENSATION FACTOR=XY +# ; xz skew +# ;PROBE_TEMPLATE_POINT POINT=BX +# ;SET_SKEW_COMPENSATION_POINT POINT=0 +# ;PROBE_TEMPLATE_POINT POINT=AX +# ;SET_SKEW_COMPENSATION_POINT POINT=1 +# ;PROBE_TEMPLATE_POINT POINT=XZ3 +# ;SET_SKEW_COMPENSATION_POINT POINT=2 +# ;PROBE_TEMPLATE_POINT POINT=XZ4 +# ;SET_SKEW_COMPENSATION_POINT POINT=3 +# ;CALC_SKEW_COMPENSATION FACTOR=XZ +# ; yz skew +# ;PROBE_TEMPLATE_POINT POINT=YZ1 +# ;SET_SKEW_COMPENSATION_POINT POINT=0 +# ;PROBE_TEMPLATE_POINT POINT=YZ2 +# ;SET_SKEW_COMPENSATION_POINT POINT=1 +# ;PROBE_TEMPLATE_POINT POINT=YZ3 +# ;SET_SKEW_COMPENSATION_POINT POINT=2 +# ;CALC_SKEW_COMPENSATION FACTOR=YZ +# ; save profile 5d +# ;SKEW_PROFILE SAVE=module_5d + + +# {% if probe_sensor_version > 0 %} +# AUTO_WCS_OFFSET_NEW_SENSOR +# {% else %} +# AUTO_WCS_OFFSET_OLD_SERNSOR +# {% endif %} +# M204 S1500 +# {% endif %} + +# [gcode_macro SET_C_ALIGN_POINT] +# gcode: +# {% set point = printer.probe.last_result %} +# {% set offsets = printer.probe.offsets %} +# {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} +# {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} +# {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} +# {% set index = params.POINT|default(0) %} +# SAVE_C_AXIS_POINT POINT={index} COORDS='{x},{y},{z}' + +# [gcode_macro SET_A_OFFSET_POINT] +# gcode: +# {% set point = printer.probe.last_result %} +# {% set offsets = printer.probe.offsets %} +# {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} +# {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} +# {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} +# {% set index = params.POINT|default(0) %} +# SAVE_A_AXIS_POINT POINT={index} COORDS='{x},{y},{z}' + +# [gcode_macro SET_B_COMPENSATION_POINT] +# gcode: +# {% set point = printer.probe.last_result %} +# {% set offsets = printer.probe.offsets %} +# {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} +# {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} +# {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} +# {% set index = params.POINT|default(0) %} +# SAVE_B_AXIS_POINT POINT={index} COORDS='{x},{y},{z}' + +# [gcode_macro SET_SKEW_COMPENSATION_POINT] +# description: saved value about probe for align skew +# gcode: +# {% set point = printer.probe.last_result %} +# {% set offsets = printer.probe.offsets %} +# {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} +# {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} +# {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} +# {% set index = params.POINT|default(0) %} +# SAVE_SKEW_POINT POINT={index} COORDS='{x},{y},{z}' + +# [gcode_macro ADJUST_TEMPLATE_HEIGHT] +# gcode: +# PROBE_TEMPLATE_POINT +# SET_TEMPLATE_HEIGHT + +# [gcode_macro SET_TEMPLATE_HEIGHT] +# gcode: +# SET_GCODE_VARIABLE MACRO=PROBE_TEMPLATE_POINT VARIABLE=probe_z VALUE={printer.probe.last_result[2] - printer.gcode_move.homing_origin.z} + +# [c_axis_align] + + +# [skew_correction module_3d] +# xy_skew = 0.0 +# xz_skew = 0.0 +# yz_skew = 0.0 + +# [skew_correction module_5d] +# xy_skew = 0.0 +# xz_skew = 0.0 +# yz_skew = 0.0 + +# [gcode_macro SET_AUTO_WCS_POINT] +# gcode: +# {% set point = printer.probe.last_result %} +# {% set offsets = printer.probe.offsets %} +# {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} +# {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} +# {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} +# # checking the axes that they are within the allowable range +# {% set home_min = printer.toolhead.axis_minimum %} +# {% set home_max = printer.toolhead.axis_maximum %} +# {% if x < home_min[0] or x > home_max[0] %} +# {action_raise_error('201: axis x=%f out of range (%f - %f)' % (x, home_min[0], home_max[0]))} +# {% elif y < home_min[1] or y > home_max[1] %} +# {action_raise_error('202: axis y=%f out of range (%f - %f)' % (y, home_min[1], home_max[1]))} +# {% elif z < home_min[2] or z > home_max[2] %} +# {action_raise_error('203: axis z=%f out of range (%f - %f)' % (z, home_min[2], home_max[2]))} +# {% endif %} +# {% set index = params.POINT|default(0) %} +# SAVE_WCS_CALC_POINT POINT={index} COORDS='{x},{y},{z}' + +# [gcode_macro AUTO_WCS_OFFSET_OLD_SERNSOR] +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} +# {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} +# G0 C0.1 +# G0 C0 +# ADJUST_TEMPLATE_HEIGHT +# PROBE_TEMPLATE_POINT POINT=AY +# SET_C_ALIGN_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=BY +# SET_C_ALIGN_POINT POINT=1 +# CALC_C_AXIS_ALIGN +# ADJUST_TEMPLATE_HEIGHT +# SET_AUTO_WCS_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=AY1 +# SET_AUTO_WCS_POINT POINT=1 +# PROBE_TEMPLATE_POINT POINT=AY2 +# SET_AUTO_WCS_POINT POINT=7 +# PROBE_TEMPLATE_POINT POINT=AX +# SET_AUTO_WCS_POINT POINT=2 +# PROBE_TEMPLATE_POINT POINT=BX +# SET_AUTO_WCS_POINT POINT=3 +# PROBE_TEMPLATE_POINT POINT=DZ +# SET_AUTO_WCS_POINT POINT=4 +# PROBE_TEMPLATE_POINT POINT=DY +# SET_AUTO_WCS_POINT POINT=5 +# PROBE_TEMPLATE_POINT POINT=EY +# SET_AUTO_WCS_POINT POINT=6 +# {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} +# {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.25)|float %} +# CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION={probe_sensor_version} +# PROBE_TEMPLATE_POINT POINT=AY +# SET_C_ALIGN_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=BY +# SET_C_ALIGN_POINT POINT=1 +# CALC_C_AXIS_ALIGN +# MOVE_TO_AUTO_WCS +# {% endif %} + +# [gcode_macro AUTO_WCS_OFFSET_NEW_SENSOR] +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} +# {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} +# G0 C0.1 +# G0 C0 +# ADJUST_TEMPLATE_HEIGHT +# PROBE_TEMPLATE_POINT POINT=AY +# SET_C_ALIGN_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=BY +# SET_C_ALIGN_POINT POINT=1 +# CALC_C_AXIS_ALIGN +# ADJUST_TEMPLATE_HEIGHT +# SET_AUTO_WCS_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=AY2_2 +# SET_AUTO_WCS_POINT POINT=7 +# PROBE_TEMPLATE_POINT POINT=AY1_2 +# SET_AUTO_WCS_POINT POINT=1 +# PROBE_TEMPLATE_POINT POINT=BX +# SET_AUTO_WCS_POINT POINT=3 +# PROBE_TEMPLATE_POINT POINT=AX +# SET_AUTO_WCS_POINT POINT=2 +# PROBE_TEMPLATE_POINT POINT=DZ_2 +# SET_AUTO_WCS_POINT POINT=4 +# PROBE_TEMPLATE_POINT POINT=EY_2 +# SET_AUTO_WCS_POINT POINT=6 +# PROBE_TEMPLATE_POINT POINT=DY_2 +# SET_AUTO_WCS_POINT POINT=5 +# PROBE_TEMPLATE_POINT POINT=CX1 +# SET_AUTO_WCS_POINT POINT=8 +# PROBE_TEMPLATE_POINT POINT=CX2 +# SET_AUTO_WCS_POINT POINT=9 +# {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} +# {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.3)|float %} +# CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION={probe_sensor_version} +# PROBE_TEMPLATE_POINT POINT=AY +# SET_C_ALIGN_POINT POINT=0 +# PROBE_TEMPLATE_POINT POINT=BY +# SET_C_ALIGN_POINT POINT=1 +# CALC_C_AXIS_ALIGN +# MOVE_TO_AUTO_WCS +# {% endif %} + +# [gcode_macro MOVE_TO_AUTO_WCS] +# gcode: +# {% set set_xy = params.XY|default(0) %} +# {% set y_shift = 50 if set_xy else 7 %} +# {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} +# G0 X{printer.auto_wcs.wcs[0][0]} Y{printer.auto_wcs.wcs[0][1] - y_shift} Z{printer.auto_wcs.wcs[0][2] + 10} F3600 +# {% endif %} + +# [gcode_macro ADJUST_PROBE_OFFSET_Z] +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} +# {% set wcs_0 = printer.auto_wcs.wcs[0] %} +# {% set wcs_1 = printer.auto_wcs.wcs[1] %} +# {% set offsets = printer.probe.offsets %} +# {% set coord_z = printer.gcode_move.position.z - printer.gcode_move.homing_origin.z %} +# {% set delta_z = wcs_0[2] - coord_z %} +# Z_OFFSET_APPLY_PROBE Z={(offsets[2] + delta_z)|abs} +# {% if params.ADJUST_CALIBRATION|default(0) %} +# {% set b_axis_params = printer.b_axis_compensation %} +# B_AXIS_COMPENSATION_VARS Z={b_axis_params.rot_center_z - delta_z} +# {% endif %} +# {% if params.ADJUST_WCS|default(0) %} +# {% set auto_wcs_params = printer.auto_wcs.wcs %} +# {% set x0 = auto_wcs_params[0][0] %} +# {% set y0 = auto_wcs_params[0][1] %} +# {% set z0 = auto_wcs_params[0][2] - delta_z %} +# SET_AUTO_WCS WCS=0 COORDS='{x0},{y0},{z0}' +# {% set x1 = auto_wcs_params[1][0] %} +# {% set y1 = auto_wcs_params[1][1] %} +# {% set z1 = auto_wcs_params[1][2] - delta_z %} +# SET_AUTO_WCS WCS=1 COORDS='{x1},{y1},{z1}' +# {% endif %} +# {% endif %} + + +# [gcode_macro ADJUST_PROBE_OFFSET_XY] +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} +# {% set y_shift = 50 %} +# {% set wcs_0 = printer.auto_wcs.wcs[0] %} +# {% set wcs_1 = printer.auto_wcs.wcs[1] %} +# {% set offsets = printer.probe.offsets %} +# {% set coord_x = printer.gcode_move.position.x - printer.gcode_move.homing_origin.x %} +# {% set coord_y = printer.gcode_move.position.y + y_shift - printer.gcode_move.homing_origin.y %} +# {% set delta_x = wcs_0[0] - coord_x %} +# {% set delta_y = wcs_0[1] - coord_y %} +# Z_OFFSET_APPLY_PROBE X={offsets[0] - delta_x} Y={offsets[1] - delta_y} +# {% if params.ADJUST_CALIBRATION|default(0) %} +# {% set b_axis_params = printer.b_axis_compensation %} +# B_AXIS_COMPENSATION_VARS X={b_axis_params.rot_center_x - delta_x} +# {% endif %} +# {% if params.ADJUST_WCS|default(0) %} +# {% set auto_wcs_params = printer.auto_wcs.wcs %} +# {% set x0 = auto_wcs_params[0][0] - delta_x %} +# {% set y0 = auto_wcs_params[0][1] - delta_y %} +# {% set z0 = auto_wcs_params[0][2] %} +# SET_AUTO_WCS WCS=0 COORDS='{x0},{y0},{z0}' +# {% set x1 = auto_wcs_params[1][0] - delta_x %} +# {% set y1 = auto_wcs_params[1][1] - delta_y %} +# {% set z1 = auto_wcs_params[1][2] %} +# SET_AUTO_WCS WCS=1 COORDS='{x1},{y1},{z1}' +# {% endif %} +# {% endif %} + +[gcode_macro SET_WCS_FROM_AUTO_WCS] +gcode: + {% set auto_wcs_params = printer.auto_wcs.wcs %} + {% set max_x = printer.toolhead.axis_maximum[0] %} + G10 L2 P2 X{auto_wcs_params[0][0]} Y{auto_wcs_params[0][1]} Z{auto_wcs_params[0][2]} + G10 L2 P4 X{auto_wcs_params[0][0]} Y{auto_wcs_params[0][1]} Z{auto_wcs_params[0][2]} + G10 L2 P3 X{auto_wcs_params[1][0]} Y{auto_wcs_params[1][1]} Z{auto_wcs_params[1][2]} + G10 L2 P5 X{auto_wcs_params[1][0]} Y{auto_wcs_params[1][1]} Z{auto_wcs_params[1][2]} + G90 + G0 Z245 F1500 + G54 + G0 X{max_x / 2.0} Y50 F3600 + +# [gcode_macro AUTO_BASEMENT_WCS] +# description: This macro performs move based on the required measuring(wcs1_z, wcs2_y, wcs2_z), and takes measurements. +# gcode: +# {% set wcs = params.WCS|default(0)|int %} +# {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} +# {% if wcs == 0 %} +# ; move for measuring wcs_1_z +# AUTO_BASEMENT_WCS_MOVE +# PROBE +# {% else %} +# PROBE +# {% endif %} +# G0 Z245 F3600 + +# [gcode_macro AUTO_BASEMENT_WCS_MOVE] +# description: This macro does a move for measuring wcs_1_z and wcs_2_y-raw or wcs_2_y and wcs_1_z-raw. +# gcode: +# {% set wcs = params.WCS|default(0)|int %} +# {% set offsets = printer.probe.offsets %} +# {% set wcs_offsets = printer.gcode_move.wcs_offsets[wcs + 3] %} +# {% set x = wcs_offsets[0] - offsets[0] %} +# {% set y = wcs_offsets[1] - offsets[1] %} +# {% set z = wcs_offsets[2] + offsets[2] %} +# {% set a = '0' if wcs == 0 else '90' %} +# G28 A +# G0 A{a} F3600 +# G0 Z150 F3600 +# G0 X{x} Y{y} F3600 + +# [gcode_macro CHECK_AXIS_A] +# description: This macro moves, measures the a-axis, and gets the difference between the two measuring points and apply offset. +# gcode: +# PROBE_TOOL_POINT POINT=Z_2_0 WCS=2 +# SET_A_OFFSET_POINT POINT=1 +# PROBE_TOOL_POINT POINT=Z_2_1 WCS=2 +# SET_A_OFFSET_POINT POINT=0 +# ; calculate and apply offset for axis A +# CALC_A_AXIS_OFFSET + +# [gcode_macro GET_TOOL_LENGTH] +# description: This macro calculate length tool. +# variable_length_is_enough: 0 +# gcode: +# {% set old_y = printer.gcode_move.wcs_offsets[4][1] %} +# {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} +# {% set wcs_2_y = printer.gcode_move.wcs_offsets[2][1] %} +# {% set tool_length = old_y + template_thickness - wcs_2_y %} +# {% if tool_length > 35.0 %} +# SET_GCODE_VARIABLE MACRO=GET_TOOL_LENGTH VARIABLE=length_is_enough VALUE=1 +# {action_respond_info('tool length=%s' % tool_length)} +# {% endif %} + +# [gcode_macro TOOL_RADIUS] +# description: moved to measure tool radius and calculate it. +# gcode: +# PROBE_TOOL_POINT POINT=Y_1 WCS=1 +# SET_AUTO_WCS_POINT POINT=0 +# GET_RADIUS_TOOLING ADVANCE=1 +# PROBE_TOOL_POINT POINT=X_1_0 WCS=1 +# SET_AUTO_WCS_POINT POINT=1 +# PROBE_TOOL_POINT POINT=X_1_1 WCS=1 +# SET_AUTO_WCS_POINT POINT=2 +# GET_RADIUS_TOOLING + +[gcode_macro ADJUST_BASEMENT_WCS] +description: macro needed for set wcs based selected mode the manager calibrate. +gcode: + {% set wcs = params.WCS|default(0)|int %} + {% set point = printer.probe.last_result %} + {% set offsets = printer.probe.offsets %} + {% set wcs_0 = printer.gcode_move.wcs_offsets[3] %} + {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} + {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} + {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} + {% set wcs_1 = printer.gcode_move.wcs_offsets[4] %} + {% set old_z = wcs_0[2] %} + {% set old_y = wcs_1[1] %} + {% if wcs == 0 %} + ; Mode SPIRAL-FULL + ; apply measuring for the set wcs_1_z and wcs_2_y. + G10 L2 P2 Z{z} + G10 L2 P3 Y{old_y - (z - old_z)} + {% elif wcs == 1 %} + ; Mode SPIRAL + ; apply measuring for the set wcs_2_y and wcs_1_z(raw). + G10 L2 P3 Y{y} + G10 L2 P2 Z{old_z - (y - old_y)} + {% endif %} diff --git a/stereotech_config/ender/variables.cfg b/stereotech_config/ender/variables.cfg new file mode 100644 index 000000000000..8418c9b94653 --- /dev/null +++ b/stereotech_config/ender/variables.cfg @@ -0,0 +1,26 @@ +[save_variables] +filename: ~/klipper/vars.cfg + +[delayed_gcode LOAD_VARIABLES] +initial_duration: 1.0 +gcode: + {% set svv = printer.save_variables.variables %} + {% set z_offset = svv.z_offset|default(0.0) %} + {% set a_offset = svv.a_offset|default(0.0) %} + SET_GCODE_OFFSET Z={z_offset} A={a_offset} + {% for wcs in range(1, 6) %} + {% set wcs_x = "wcs_x" %} + {% set wcs_y = "wcs_y" %} + {% set wcs_z = "wcs_z" %} + G10 L2 P{wcs+1} X{svv["wcs" ~ wcs ~ "_x"]|default(0.0)} Y{svv["wcs" ~ wcs ~ "_y"]|default(0.0)} Z{svv["wcs" ~ wcs ~ "_z"]|default(0.0)} + {% endfor %} + +[gcode_macro SAVE_VARIABLES] +gcode: + SAVE_VARIABLE VARIABLE=z_offset VALUE={printer.gcode_move.homing_origin.z} + SAVE_VARIABLE VARIABLE=a_offset VALUE={printer.gcode_move.homing_origin.a} + {% for wcs in range(6) %} + SAVE_VARIABLE VARIABLE=wcs{wcs}_x VALUE={printer.gcode_move.wcs_offsets[wcs][0]} + SAVE_VARIABLE VARIABLE=wcs{wcs}_y VALUE={printer.gcode_move.wcs_offsets[wcs][1]} + SAVE_VARIABLE VARIABLE=wcs{wcs}_z VALUE={printer.gcode_move.wcs_offsets[wcs][2]} + {% endfor %} diff --git a/stereotech_config/extruder_macros.cfg b/stereotech_config/extruder_macros.cfg index f0d6d9f574e7..780c84eb1242 100644 --- a/stereotech_config/extruder_macros.cfg +++ b/stereotech_config/extruder_macros.cfg @@ -57,20 +57,15 @@ rename_existing: M1091 gcode: STATUS_LED STATUS=started {% set extruder = params.T|default(-1)|int %} - {% set current_extruder = printer.toolhead.extruder %} + {% set extruder_name = printer.toolhead.extruder %} + {% set heat_phase = "_heating" if params.S|int > 50 else "_cooling" %} + {% if extruder >= 0 %} + {% set extruder_name = "extruder" if extruder == 0 else "extruder1" %} + {% endif %} + M117 {extruder_name ~ heat_phase} {% if extruder >= 0 %} - {% if extruder == 0 %} - M117 extruder_heating - {% elif extruder == 1 %} - M117 extruder1_heating - {% endif %} M1091 T{params.T} S{params.S} {% else %} - {% if current_extruder == 'extruder' %} - M117 extruder_heating - {% elif current_extruder == 'extruder1' %} - M117 extruder1_heating - {% endif %} M1091 S{params.S} {% endif %} STATUS_LED STATUS=printing diff --git a/stereotech_config/fiber_extruder.cfg b/stereotech_config/fiber_extruder.cfg index f0a7179bafc5..b5697423673f 100644 --- a/stereotech_config/fiber_extruder.cfg +++ b/stereotech_config/fiber_extruder.cfg @@ -7,7 +7,7 @@ rotation_distance: 40 nozzle_diameter: 0.6 filament_diameter: 0.6 heater_pin: P2.4 -sensor_type: EPCOS 100K B57560G104F +sensor_type: NTC 100K MGB18-104F39050L32 sensor_pin: P0.25 control: pid pid_Kp: 13.509 @@ -17,6 +17,7 @@ min_temp: -150 max_temp: 320 max_extrude_only_distance: 300.0 min_extrude_temp: 0 +fiber: true [gcode_macro T1] variable_t1_offset_enabled: 0.0 @@ -25,8 +26,9 @@ gcode: SET_GCODE_VARIABLE MACRO=T1 VARIABLE=t1_offset_enabled VALUE=1 SET_GCODE_OFFSET X_ADJUST={printer["gcode_macro SET_NOZZLE_OFFSET"].offset_x|default(0.0)} Y_ADJUST={printer["gcode_macro SET_NOZZLE_OFFSET"].offset_y|default(0.0)} {% set current_wcs = printer.gcode_move.current_wcs %} - {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder1' %} + {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and "z" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder1' %} G54 + MOVE_DOWN_Z_AXIS Z=5 G0 X10 Y2 F3600 {% endif %} ACTIVATE_EXTRUDER extruder=extruder1 diff --git a/stereotech_config/fiber_extruder_2.cfg b/stereotech_config/fiber_extruder_2.cfg index c9d3d42a7fe5..e5bbeea71b64 100644 --- a/stereotech_config/fiber_extruder_2.cfg +++ b/stereotech_config/fiber_extruder_2.cfg @@ -7,7 +7,7 @@ rotation_distance: 40 nozzle_diameter: 0.6 filament_diameter: 0.6 heater_pin: second_extruder_heater_pin -sensor_type: EPCOS 100K B57560G104F +sensor_type: NTC 100K MGB18-104F39050L32 sensor_pin: second_extruder_sensor_pin control: pid pid_Kp: 6.185 @@ -18,6 +18,7 @@ max_temp: 320 max_extrude_only_distance: 300.0 min_extrude_temp: 0 max_power: 0.7 +fiber: true [gcode_macro T1] variable_t1_offset_enabled: 0.0 @@ -26,8 +27,9 @@ gcode: SET_GCODE_VARIABLE MACRO=T1 VARIABLE=t1_offset_enabled VALUE=1 SET_GCODE_OFFSET X_ADJUST={printer["gcode_macro SET_NOZZLE_OFFSET"].offset_x|default(0.0)} Y_ADJUST={printer["gcode_macro SET_NOZZLE_OFFSET"].offset_y|default(0.0)} {% set current_wcs = printer.gcode_move.current_wcs %} - {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder1' %} + {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and "z" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder1' %} G54 + MOVE_DOWN_Z_AXIS Z=5 G0 X10 Y2 F3600 {% endif %} ACTIVATE_EXTRUDER extruder=extruder1 diff --git a/stereotech_config/fiber_extruder_3.cfg b/stereotech_config/fiber_extruder_3.cfg new file mode 100644 index 000000000000..accc58a62231 --- /dev/null +++ b/stereotech_config/fiber_extruder_3.cfg @@ -0,0 +1,65 @@ +[extruder1] +step_pin: second_extruder_step_pin +dir_pin: !second_extruder_dir_pin +enable_pin: !second_extruder_enable_pin +microsteps: 16 +rotation_distance: 40 +nozzle_diameter: 0.6 +filament_diameter: 0.6 +heater_pin: second_extruder_heater_pin +sensor_type: NTC 100K MGB18-104F39050L32 +sensor_pin: second_extruder_sensor_pin +control: pid +pid_Kp: 6.185 +pid_Ki: 0.191 +pid_Kd: 50.04 +min_temp: -150 +max_temp: 320 +max_extrude_only_distance: 300.0 +min_extrude_temp: 0 +max_power: 0.7 +fiber: true + +[gcode_macro T1] +variable_t1_offset_enabled: 0.0 +gcode: + M117 set_extruder1 + SET_GCODE_VARIABLE MACRO=T1 VARIABLE=t1_offset_enabled VALUE=1 + SET_GCODE_OFFSET X_ADJUST={printer["gcode_macro SET_NOZZLE_OFFSET"].offset_x|default(0.0)} Y_ADJUST={printer["gcode_macro SET_NOZZLE_OFFSET"].offset_y|default(0.0)} + {% set current_wcs = printer.gcode_move.current_wcs %} + {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and "z" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder1' %} + G54 + MOVE_DOWN_Z_AXIS Z=5 + G0 X10 Y2 F3600 + {% endif %} + ACTIVATE_EXTRUDER extruder=extruder1 + SET_WCS WCS={current_wcs} + M117 + +[servo cutter_servo] +pin: PB6 +initial_angle: 180 + +[gcode_macro CUT_FIBER] +gcode: + {% if printer.toolhead.extruder == 'extruder1' %} + M400 + SET_SERVO SERVO=cutter_servo ANGLE=0 + G4 P1000 + M400 + SET_SERVO SERVO=cutter_servo ANGLE=180 + M400 + {% endif %} + +[gcode_macro PRIME_FIBER] +gcode: + {% if printer.toolhead.extruder == 'extruder1' %} + M400 + SAVE_GCODE_STATE NAME=prime_fiber_state + {% set e = params.E|default(16) %} + G91 + G0 E{e} F1800 + G90 + RESTORE_GCODE_STATE NAME=prime_fiber_state + M400 + {% endif %} diff --git a/stereotech_config/fiber_nozzle_offset.cfg b/stereotech_config/fiber_nozzle_offset.cfg index 73dab8557da7..dc0b368df37f 100644 --- a/stereotech_config/fiber_nozzle_offset.cfg +++ b/stereotech_config/fiber_nozzle_offset.cfg @@ -4,12 +4,12 @@ gcode: SET_GCODE_VARIABLE MACRO=SET_NOZZLE_OFFSET VARIABLE=offset_x VALUE=0.0 SET_GCODE_VARIABLE MACRO=SET_NOZZLE_OFFSET VARIABLE=offset_y VALUE=0.0 T0 - M140 S{params.BED|default(100)} + M140 S{params.BED|default(70)} M105 - M190 S{params.BED|default(100)} - M104 S{params.MAIN_E|default(230)} + M190 S{params.BED|default(70)} + M104 S{params.MAIN_E|default(220)} M105 - M109 S{params.MAIN_E|default(230)} + M109 S{params.MAIN_E|default(220)} M104 T1 S175 M82 ;absolute extrusion mode ;STE Slicer 5D Gcode @@ -21,903 +21,92 @@ gcode: G92 E0 M73 P1 G1 F1500 E-3 - ;LAYER_COUNT:9 ;LAYER:0 M107 M107 P3 - - G0 F1800 X59.498 Y73.319 Z0.3 - ;TYPE:WALL-INNER - G1 F1500 E0 - G1 F1800 X59.498 Y79.519 E0.30932 - G1 X63.698 Y79.519 E0.51886 - G1 X63.698 Y73.319 E0.82818 - G1 X59.498 Y73.319 E1.03772 - G0 X59.428 Y73.249 - G0 X59.528 Y83.249 - G0 X59.598 Y83.319 - G1 X59.598 Y89.519 E1.34704 - G1 X63.798 Y89.519 E1.55657 - G1 X63.798 Y83.319 E1.86589 - G1 X59.598 Y83.319 E2.07543 + ;TYPE:SKIN + G92 E132.86503 + G0 X60.508 Y212.929 F1800 Z0.3 + G1 X60.508 Y219.909 E133.21326 + G1 X65.488 Y219.909 E133.46171 + G1 X65.488 Y212.929 E133.80995 + M73 P2 + G1 X60.508 Y212.929 E134.0584 + G0 X60.408 Y209.909 + G1 X65.388 Y209.909 E134.30685 + G1 X65.388 Y202.929 E134.65509 M73 P3 - G0 X59.528 Y83.249 - G0 X59.628 Y93.249 - G0 X59.698 Y93.319 - G1 X59.698 Y99.519 E2.38475 - G1 X63.898 Y99.519 E2.59429 - G1 X63.898 Y93.319 E2.90361 - G1 X59.698 Y93.319 E3.11315 - G0 X59.628 Y93.249 - G0 X59.728 Y103.249 - G0 X59.798 Y103.319 - G1 X59.798 Y109.519 E3.42247 - G1 X63.998 Y109.519 E3.63201 - G1 X63.998 Y103.319 E3.94133 - G1 X59.798 Y103.319 E4.15086 - G0 X59.728 Y103.249 - G0 X59.828 Y113.249 - G0 X59.898 Y113.319 + G1 X60.408 Y202.929 E134.90354 + G1 X60.408 Y209.909 E135.25177 + G0 X60.308 Y199.909 + G1 X65.288 Y199.909 E135.50023 + G1 X65.288 Y192.929 E135.84846 + G1 X60.308 Y192.929 E136.09691 + G1 X60.308 Y199.909 E136.44515 + G0 X60.208 Y189.909 + G1 X65.188 Y189.909 E136.6936 + G1 X65.188 Y182.929 E137.04183 + G1 X60.208 Y182.929 E137.29029 + G1 X60.208 Y189.909 E137.63852 + G0 X60.108 Y179.909 + G1 X65.088 Y179.909 E137.88697 + G1 X65.088 Y172.929 E138.23521 + G1 X60.108 Y172.929 E138.48366 + G1 X60.108 Y179.909 E138.83189 + G0 X60.008 Y169.909 + G1 X64.988 Y169.909 E139.08035 + G1 X64.988 Y162.929 E139.42858 M73 P4 - G1 X59.898 Y119.519 E4.46018 - G1 X64.098 Y119.519 E4.66972 - G1 X64.098 Y113.319 E4.97904 - G1 X59.898 Y113.319 E5.18858 - G0 X59.828 Y113.249 - G0 X59.928 Y123.249 - G0 X59.998 Y123.319 - G1 X59.998 Y129.519 E5.4979 - G1 X64.198 Y129.519 E5.70744 - G1 X64.198 Y123.319 E6.01676 - G1 X59.998 Y123.319 E6.2263 - G0 X59.928 Y123.249 - G0 X60.028 Y133.249 - G0 X60.098 Y133.319 - G1 X60.098 Y139.519 E6.53562 - G1 X64.298 Y139.519 E6.74516 - G1 X64.298 Y133.319 E7.05447 + G1 X60.008 Y162.929 E139.67703 + G1 X60.008 Y169.909 E140.02527 + G0 X59.908 Y159.909 + G1 X64.888 Y159.909 E140.27372 M73 P5 - G1 X60.098 Y133.319 E7.26401 - G0 X60.028 Y133.249 - G0 X60.128 Y143.249 - G0 X60.198 Y143.319 - G1 X60.198 Y149.519 E7.57333 - G1 X64.398 Y149.519 E7.78287 - G1 X64.398 Y143.319 E8.09219 - G1 X60.198 Y143.319 E8.30173 - G0 X60.128 Y143.249 - G0 X60.228 Y153.249 - G0 X60.298 Y153.319 - G1 X60.298 Y159.519 E8.61105 - G1 X64.498 Y159.519 E8.82059 - G1 X64.498 Y153.319 E9.12991 - G1 X60.298 Y153.319 E9.33945 - G0 X60.228 Y153.249 - G0 X60.328 Y163.249 - G0 X60.398 Y163.319 - G1 X60.398 Y169.519 E9.64877 - G1 X64.598 Y169.519 E9.8583 - G1 X64.598 Y163.319 E10.16762 - G1 X60.398 Y163.319 E10.37716 - G0 X60.328 Y163.249 - G0 X60.428 Y173.249 - G0 X60.498 Y173.319 - G1 X60.498 Y179.519 E10.68648 - G1 X64.698 Y179.519 E10.89602 - M73 P10 - G1 X64.698 Y173.319 E11.20534 - G1 X60.498 Y173.319 E11.41488 - G0 X60.428 Y173.249 - G0 X60.528 Y183.249 - G0 X60.598 Y183.319 - G1 X60.598 Y189.519 E11.7242 - G1 X64.798 Y189.519 E11.93374 - G1 X64.798 Y183.319 E12.24306 - G1 X60.598 Y183.319 E12.45259 - G0 X60.528 Y183.249 - G0 X60.628 Y193.249 - G0 X60.698 Y193.319 - G1 X60.698 Y199.519 E12.76191 - G1 X64.898 Y199.519 E12.97145 - G1 X64.898 Y193.319 E13.28077 - G1 X60.698 Y193.319 E13.49031 - G0 X60.628 Y193.249 - G0 X60.728 Y203.249 - G0 X60.798 Y203.319 - G1 X60.798 Y209.519 E13.79963 - G1 X64.998 Y209.519 E14.00917 - G1 X64.998 Y203.319 E14.31849 - G1 X60.798 Y203.319 E14.52803 - G0 X60.728 Y203.249 - G0 X60.828 Y213.249 - G0 X60.898 Y213.319 - G1 X60.898 Y219.519 E14.83735 - G1 X65.098 Y219.519 E15.04689 - G1 X65.098 Y213.319 E15.3562 - G1 X60.898 Y213.319 E15.56574 - G0 X60.828 Y213.249 - G0 X60.77 Y209.547 - G0 X60.77 Y203.291 - G0 X64.926 Y199.547 - G0 X71.714 Y65.634 - G0 X71.998 Y64.491 - G0 X72.516 Y63.43 - G0 X84.128 Y48.549 - G0 X84.198 Y48.619 - G1 X84.198 Y52.819 E15.77528 - G1 X90.398 Y52.819 E16.0846 - G1 X90.398 Y48.619 E16.29414 - G1 X84.198 Y48.619 E16.60346 - G0 X84.128 Y48.549 - G0 X94.128 Y48.649 - G0 X94.198 Y48.719 - G1 X94.198 Y52.919 E16.813 - G1 X100.398 Y52.919 E17.12232 - G1 X100.398 Y48.719 E17.33186 - G1 X94.198 Y48.719 E17.64118 - G0 X94.128 Y48.649 - G0 X104.128 Y48.749 - G0 X104.198 Y48.819 - G1 X104.198 Y53.019 E17.85071 - G1 X110.398 Y53.019 E18.16003 - G1 X110.398 Y48.819 E18.36957 - G1 X104.198 Y48.819 E18.67889 - G0 X104.128 Y48.749 - G0 X114.128 Y48.849 - G0 X114.198 Y48.919 - G1 X114.198 Y53.119 E18.88843 - G1 X120.398 Y53.119 E19.19775 - G1 X120.398 Y48.919 E19.40729 - G1 X114.198 Y48.919 E19.71661 - G0 X114.128 Y48.849 - G0 X124.128 Y48.949 - G0 X124.198 Y49.019 - G1 X124.198 Y53.219 E19.92615 - G1 X130.398 Y53.219 E20.23547 - G1 X130.398 Y49.019 E20.44501 - G1 X124.198 Y49.019 E20.75432 - G0 X124.128 Y48.949 - G0 X134.128 Y49.049 - G0 X134.198 Y49.119 - G1 X134.198 Y53.319 E20.96386 - G1 X140.398 Y53.319 E21.27318 - G1 X140.398 Y49.119 E21.48272 - G1 X134.198 Y49.119 E21.79204 - G0 X134.128 Y49.049 - G0 X144.128 Y49.149 - G0 X144.198 Y49.219 - G1 X144.198 Y53.419 E22.00158 - G1 X150.398 Y53.419 E22.3109 - G1 X150.398 Y49.219 E22.52044 - G1 X144.198 Y49.219 E22.82976 - G0 X144.128 Y49.149 - G0 X154.128 Y49.249 - G0 X154.198 Y49.319 - G1 X154.198 Y53.519 E23.0393 - G1 X160.398 Y53.519 E23.34861 - G1 X160.398 Y49.319 E23.55815 - G1 X154.198 Y49.319 E23.86747 - G0 X154.128 Y49.249 - G0 X164.128 Y49.349 - G0 X164.198 Y49.419 - G1 X164.198 Y53.619 E24.07701 - G1 X170.398 Y53.619 E24.38633 - G1 X170.398 Y49.419 E24.59587 - G1 X164.198 Y49.419 E24.90519 - G0 X164.128 Y49.349 - G0 X174.128 Y49.449 - M73 P15 - G0 X174.198 Y49.519 - G1 X174.198 Y53.719 E25.11473 - G1 X180.398 Y53.719 E25.42405 - G1 X180.398 Y49.519 E25.63359 - G1 X174.198 Y49.519 E25.94291 - G0 X174.128 Y49.449 - G0 X184.128 Y49.549 - G0 X184.198 Y49.619 - G1 X184.198 Y53.819 E26.15244 - G1 X190.398 Y53.819 E26.46176 - G1 X190.398 Y49.619 E26.6713 - G1 X184.198 Y49.619 E26.98062 - G0 X184.128 Y49.549 - G0 X194.128 Y49.649 - G0 X194.198 Y49.719 - G1 X194.198 Y53.919 E27.19016 - G1 X200.398 Y53.919 E27.49948 - G1 X200.398 Y49.719 E27.70902 - G1 X194.198 Y49.719 E28.01834 - G0 X194.128 Y49.649 - G0 X204.128 Y49.749 - G0 X204.198 Y49.819 - G1 X204.198 Y54.019 E28.22788 - G1 X210.398 Y54.019 E28.5372 - G1 X210.398 Y49.819 E28.74673 - G1 X204.198 Y49.819 E29.05605 - G0 X204.128 Y49.749 - G0 X214.128 Y49.849 - G0 X214.198 Y49.919 - G1 X214.198 Y54.119 E29.26559 - G1 X220.398 Y54.119 E29.57491 - G1 X220.398 Y49.919 E29.78445 - G1 X214.198 Y49.919 E30.09377 - G0 X214.128 Y49.849 - G0 X224.128 Y49.949 - G0 X224.198 Y50.019 - G1 X224.198 Y54.219 E30.30331 - G1 X230.398 Y54.219 E30.61263 - G1 X230.398 Y50.019 E30.82217 - G1 X224.198 Y50.019 E31.13149 - G0 X224.128 Y49.949 - G0 X230.426 Y49.991 - G0 X238.151 Y51.419 - G0 X238.251 Y51.419 - G1 X238.484 Y51.582 E31.14567 - G1 X241.698 Y53.831 E31.34138 - G1 X241.695 Y56.565 E31.47778 - G1 X241.673 Y56.886 E31.49383 - G1 X241.632 Y57.175 E31.50839 - G1 X241.565 Y57.486 E31.52427 - G1 X241.484 Y57.772 E31.5391 - G1 X241.378 Y58.066 E31.55469 - G1 X241.25 Y58.352 E31.57032 - G1 X241.11 Y58.616 E31.58523 - G1 X240.951 Y58.871 E31.60022 - G1 X240.765 Y59.126 E31.61597 - G1 X240.56 Y59.371 E31.6319 - G1 X240.354 Y59.583 E31.64665 - G1 X240.134 Y59.782 E31.66145 - G1 X239.875 Y59.985 E31.67787 - G1 X239.628 Y60.151 E31.69272 - G1 X239.371 Y60.299 E31.70751 - G1 X239.086 Y60.438 E31.72333 - G1 X238.8 Y60.554 E31.73873 - G1 X238.51 Y60.649 E31.75395 - G1 X238.223 Y60.72 E31.76871 - G1 X237.91 Y60.776 E31.78457 - G1 X237.608 Y60.806 E31.79971 - G1 X237.276 Y60.819 E31.81629 - G1 X160.546 Y60.819 E35.64436 - G1 X157.439 Y57.711 E35.86361 - G1 X157.298 Y57.57 E35.87356 - G1 X157.157 Y57.711 E35.87998 - G1 X154.05 Y60.819 E36.09924 - G1 X77.102 Y60.822 E39.93819 - G1 X76.713 Y60.849 E39.95764 - G1 X76.325 Y60.903 E39.97718 - G1 X75.943 Y60.985 E39.99668 - G1 X75.567 Y61.092 E40.01618 - G1 X75.2 Y61.227 E40.03569 - G1 X74.843 Y61.385 E40.05517 - G1 X74.498 Y61.568 E40.07465 - G1 X74.166 Y61.775 E40.09417 - G1 X73.851 Y62.005 E40.11363 - G1 X73.55 Y62.257 E40.13321 - G1 X73.269 Y62.529 E40.15272 - G1 X73.008 Y62.82 E40.17223 - G1 X72.768 Y63.126 E40.19163 - G1 X72.549 Y63.451 E40.21118 - G1 X72.353 Y63.789 E40.23067 - G1 X72.181 Y64.141 E40.25022 - G1 X72.035 Y64.504 E40.26974 - G1 X71.915 Y64.875 E40.28919 - G1 X71.819 Y65.254 E40.3087 - G1 X71.753 Y65.639 E40.32819 - G1 X71.711 Y66.028 E40.34771 - G1 X71.698 Y66.409 E40.36673 - G1 X71.698 Y143.171 E44.1964 - G1 X68.59 Y146.278 E44.41565 - G1 X68.449 Y146.419 E44.4256 - G1 X68.59 Y146.56 E44.43202 - G1 X71.698 Y149.667 E44.65127 - G1 X71.695 Y226.564 E48.48768 - G1 X71.674 Y226.877 E48.50333 - G1 X71.637 Y227.147 E48.51692 - G1 X71.573 Y227.46 E48.53286 - G1 X71.491 Y227.753 E48.54804 - G1 X71.395 Y228.023 E48.56234 - G1 X71.27 Y228.309 E48.57791 - G1 X71.134 Y228.573 E48.59273 - G1 X70.969 Y228.844 E48.60856 - G1 X70.811 Y229.068 E48.62223 - G1 X70.621 Y229.301 E48.63723 - G1 X70.408 Y229.529 E48.6528 - G1 X70.18 Y229.742 E48.66836 - G1 X69.958 Y229.923 E48.68265 - G1 X69.711 Y230.097 E48.69773 - G1 X69.455 Y230.253 E48.71268 - G1 X69.183 Y230.394 E48.72797 - G1 X68.916 Y230.51 E48.74249 - G1 X68.628 Y230.611 E48.75772 - G1 X68.346 Y230.691 E48.77234 - G1 X68.026 Y230.758 E48.78866 - G1 X67.761 Y230.793 E48.80199 - G1 X67.441 Y230.816 E48.818 - G1 X65.546 Y230.819 E48.91254 - M73 P20 - G1 X62.439 Y227.711 E49.13179 - G1 X62.298 Y227.57 E49.14174 - G1 X62.157 Y227.711 E49.14816 - G1 X59.05 Y230.819 E49.36741 - G1 X57.174 Y230.817 E49.46101 - G1 X56.865 Y230.797 E49.47646 - G1 X56.562 Y230.756 E49.49171 - G1 X56.253 Y230.693 E49.50744 - G1 X55.952 Y230.608 E49.52305 - G1 X55.677 Y230.508 E49.53765 - G1 X55.388 Y230.382 E49.55338 - G1 X55.115 Y230.239 E49.56875 - G1 X54.867 Y230.085 E49.58331 - G1 X54.602 Y229.895 E49.59958 - G1 X54.371 Y229.703 E49.61457 - G1 X54.156 Y229.497 E49.62942 - G1 X53.935 Y229.255 E49.64577 - G1 X53.756 Y229.027 E49.66024 - G1 X53.58 Y228.769 E49.67582 - G1 X53.426 Y228.505 E49.69107 - G1 X53.288 Y228.227 E49.70655 - G1 X53.167 Y227.933 E49.72241 - G1 X53.079 Y227.662 E49.73663 - G1 X53.002 Y227.361 E49.75213 - G1 X52.946 Y227.049 E49.76794 - G1 X52.911 Y226.74 E49.78346 - G1 X52.899 Y226.43 E49.79893 - G1 X52.9 Y46.293 E58.786 - G1 X52.92 Y45.972 E58.80205 - G1 X52.957 Y45.697 E58.81589 - G1 X53.024 Y45.37 E58.83255 - G1 X53.102 Y45.093 E58.8469 - G1 X53.212 Y44.786 E58.86317 - G1 X53.335 Y44.507 E58.87839 - G1 X53.477 Y44.238 E58.89356 - G1 X53.634 Y43.984 E58.90846 - G1 X53.814 Y43.731 E58.92395 - G1 X54.015 Y43.489 E58.93964 - G1 X54.216 Y43.279 E58.95415 - G1 X54.461 Y43.055 E58.97071 - G1 X54.687 Y42.878 E58.98503 - G1 X54.945 Y42.701 E59.00064 - G1 X55.218 Y42.543 E59.01638 - G1 X55.482 Y42.412 E59.03108 - G1 X55.768 Y42.295 E59.0465 - G1 X56.058 Y42.199 E59.06174 - G1 X56.371 Y42.119 E59.07785 - G1 X56.652 Y42.068 E59.0921 - G1 X56.968 Y42.033 E59.10796 - G1 X57.295 Y42.02 E59.12429 - G1 X237.423 Y42.021 E68.11091 - G1 X237.731 Y42.04 E68.12631 - G1 X238.034 Y42.081 E68.14156 - G1 X238.342 Y42.144 E68.15725 - G1 X238.641 Y42.228 E68.17274 - G1 X238.926 Y42.331 E68.18786 - G1 X239.206 Y42.454 E68.20312 - G1 X239.473 Y42.593 E68.21814 - G1 X239.732 Y42.754 E68.23335 - G1 X239.994 Y42.942 E68.24944 - G1 X240.225 Y43.135 E68.26446 - G1 X240.437 Y43.337 E68.27907 - G1 X240.661 Y43.582 E68.29563 - G1 X240.842 Y43.813 E68.31027 - G1 X241.013 Y44.063 E68.32538 - G1 X241.171 Y44.333 E68.34099 - G1 X241.303 Y44.598 E68.35576 - G1 X241.42 Y44.884 E68.37117 - G1 X241.521 Y45.189 E68.3872 - G1 X241.594 Y45.474 E68.40188 - G1 X241.65 Y45.788 E68.41779 - G1 X241.685 Y46.097 E68.43331 - G1 X241.697 Y46.408 E68.44884 - G1 X241.698 Y49.007 E68.5785 - G1 X238.484 Y51.256 E68.77421 - G1 X238.251 Y51.419 E68.78257 - G0 X238.949 Y51.419 - ;TYPE:WALL-OUTER - G1 X239.182 Y51.582 E68.79676 - G1 X242.098 Y53.623 E68.97434 - G1 X242.095 Y56.579 E69.12181 - G1 X242.071 Y56.927 E69.13921 - G1 X242.026 Y57.245 E69.15524 - G1 X241.953 Y57.586 E69.17263 - G1 X241.865 Y57.896 E69.18871 - G1 X241.751 Y58.21 E69.20538 - G1 X241.611 Y58.524 E69.22253 - G1 X241.454 Y58.82 E69.23925 - G1 X241.281 Y59.097 E69.25554 - G1 X241.077 Y59.377 E69.27282 - G1 X240.865 Y59.63 E69.28929 - G1 X240.627 Y59.876 E69.30637 - G1 X240.389 Y60.091 E69.32237 - G1 X240.12 Y60.302 E69.33943 - G1 X239.836 Y60.492 E69.35647 - G1 X239.557 Y60.653 E69.37254 - G1 X239.244 Y60.806 E69.38992 - G1 X238.943 Y60.928 E69.40613 - G1 X238.621 Y61.033 E69.42303 - G1 X238.299 Y61.113 E69.43958 - G1 X237.966 Y61.172 E69.45645 - G1 X237.633 Y61.206 E69.47315 - G1 X237.291 Y61.219 E69.49023 - G1 X160.38 Y61.219 E73.32733 - G1 X157.439 Y58.277 E73.53487 - G1 X157.298 Y58.136 E73.54482 - G1 X157.157 Y58.277 E73.55124 - G1 X154.216 Y61.219 E73.75878 - G1 X77.116 Y61.222 E77.60532 - G1 X76.754 Y61.247 E77.62342 - G1 X76.395 Y61.297 E77.6415 - G1 X76.04 Y61.373 E77.65961 - G1 X75.691 Y61.473 E77.67773 - G1 X75.35 Y61.598 E77.69585 - G1 X75.018 Y61.745 E77.71396 - G1 X74.698 Y61.915 E77.73204 - G1 X74.39 Y62.107 E77.75015 - G1 X74.097 Y62.32 E77.76822 - G1 X73.818 Y62.554 E77.78638 - G1 X73.557 Y62.806 E77.80449 - G1 X73.315 Y63.077 E77.82261 - G1 X73.091 Y63.362 E77.8407 - G1 X72.888 Y63.663 E77.85881 - G1 X72.706 Y63.977 E77.87692 - G1 X72.547 Y64.304 E77.89506 - G1 X72.411 Y64.64 E77.91314 - G1 X72.3 Y64.985 E77.93122 - G1 X72.211 Y65.337 E77.94934 - G1 X72.149 Y65.695 E77.96746 - G1 X72.11 Y66.056 E77.98558 - G1 X72.098 Y66.416 E78.00355 - G1 X72.098 Y143.337 E81.84115 - G1 X69.156 Y146.278 E82.04869 - G1 X69.015 Y146.419 E82.05864 - G1 X69.156 Y146.56 E82.06506 - G1 X72.098 Y149.501 E82.2726 - G1 X72.095 Y226.576 E86.11789 - G1 X72.072 Y226.916 E86.13489 - G1 X72.029 Y227.228 E86.1506 - G1 X71.963 Y227.548 E86.1669 - G1 X71.871 Y227.877 E86.18395 - G1 X71.766 Y228.173 E86.19962 - G1 X71.635 Y228.474 E86.21599 - G1 X71.48 Y228.774 E86.23284 - G1 X71.308 Y229.057 E86.24936 - G1 X71.127 Y229.314 E86.26505 - G1 X70.92 Y229.568 E86.28139 - G1 X70.691 Y229.812 E86.29809 - G1 X70.447 Y230.041 E86.31478 - G1 X70.204 Y230.239 E86.33042 - G1 X69.928 Y230.433 E86.34725 - G1 X69.653 Y230.601 E86.36333 - G1 X69.353 Y230.756 E86.38018 - G1 X69.065 Y230.881 E86.39584 - G1 X68.748 Y230.993 E86.41261 - G1 X68.432 Y231.082 E86.42899 - G1 X68.107 Y231.15 E86.44556 - G1 X67.795 Y231.192 E86.46126 - G1 X67.455 Y231.216 E86.47827 - G1 X65.38 Y231.219 E86.58179 - G1 X62.439 Y228.277 E86.78933 - G1 X62.298 Y228.136 E86.79928 - G1 X62.157 Y228.277 E86.8057 - G1 X59.216 Y231.219 E87.01324 - G1 X57.163 Y231.217 E87.11566 - G1 X56.815 Y231.194 E87.13306 - G1 X56.498 Y231.152 E87.14902 - G1 X56.164 Y231.083 E87.16603 - G1 X55.833 Y230.99 E87.18319 - G1 X55.521 Y230.877 E87.19974 - G1 X55.22 Y230.746 E87.21612 - G1 X54.92 Y230.588 E87.23303 - G1 X54.642 Y230.416 E87.24934 - G1 X54.359 Y230.213 E87.26672 - G1 X54.106 Y230.002 E87.28316 - G1 X53.866 Y229.773 E87.29971 - G1 X53.634 Y229.518 E87.3169 - G1 X53.427 Y229.255 E87.3336 - G1 X53.245 Y228.988 E87.34972 - G1 X53.07 Y228.689 E87.36701 - G1 X52.925 Y228.396 E87.38332 - G1 X52.794 Y228.078 E87.40048 - G1 X52.695 Y227.773 E87.41647 - G1 X52.608 Y227.434 E87.43394 - G1 X52.549 Y227.105 E87.45061 - G1 X52.512 Y226.772 E87.46733 - G1 X52.499 Y226.446 E87.4836 - G1 X52.5 Y46.284 E96.47192 - G1 X52.522 Y45.936 E96.48932 - G1 X52.565 Y45.617 E96.50538 - G1 X52.635 Y45.275 E96.52279 - G1 X52.722 Y44.967 E96.53876 - G1 X52.835 Y44.651 E96.5555 - G1 X52.975 Y44.333 E96.57284 - G1 X53.131 Y44.036 E96.58958 - G1 X53.301 Y43.762 E96.60566 - G1 X53.495 Y43.49 E96.62233 - G1 X53.714 Y43.226 E96.63944 - G1 X53.94 Y42.989 E96.65578 - G1 X54.198 Y42.754 E96.67319 - G1 X54.456 Y42.551 E96.68957 - G1 X54.734 Y42.361 E96.70637 - G1 X55.024 Y42.193 E96.72309 - G1 X55.32 Y42.046 E96.73958 - G1 X55.63 Y41.919 E96.75629 - G1 X55.951 Y41.813 E96.77316 - G1 X56.272 Y41.731 E96.78969 - G1 X56.605 Y41.67 E96.80658 - G1 X56.938 Y41.634 E96.82329 - G1 X57.279 Y41.62 E96.84031 - G1 X237.432 Y41.621 E105.82818 - G1 X237.781 Y41.643 E105.84563 - G1 X238.098 Y41.685 E105.86158 - G1 X238.431 Y41.754 E105.87855 - G1 X238.763 Y41.847 E105.89575 - G1 X239.075 Y41.96 E105.91231 - G1 X239.385 Y42.096 E105.9292 - G1 X239.669 Y42.244 E105.94517 - G1 X239.954 Y42.421 E105.96191 - G1 X240.237 Y42.624 E105.97929 - G1 X240.49 Y42.835 E105.99572 - G1 X240.727 Y43.061 E106.01206 - G1 X240.962 Y43.319 E106.02947 - G1 X241.169 Y43.582 E106.04617 - G1 X241.35 Y43.847 E106.06218 - G1 X241.526 Y44.148 E106.07957 - G1 X241.669 Y44.436 E106.09562 - G1 X241.796 Y44.746 E106.11233 - G1 X241.901 Y45.064 E106.12904 - G1 X241.988 Y45.403 E106.1465 - G1 X242.047 Y45.732 E106.16317 - G1 X242.084 Y46.065 E106.17989 - G1 X242.097 Y46.392 E106.19622 - G1 X242.098 Y49.215 E106.33706 - G1 X239.182 Y51.256 E106.51463 - G1 X238.949 Y51.419 E106.523 - G0 X239.113 Y51.533 - G0 X238.825 Y51.942 - G0 X230.426 Y49.991 - G0 X224.598 Y49.919 - G0 X224.598 Y50.419 - G1 X224.598 Y53.819 E106.69263 - G1 X229.998 Y53.819 E106.96203 - G1 X229.998 Y50.419 E107.13166 - G1 X224.598 Y50.419 E107.40107 - G0 X224.598 Y50.619 - G0 X224.098 Y50.619 - G0 X220.426 Y49.891 - G0 X214.598 Y49.819 - G0 X214.598 Y50.319 - G1 X214.598 Y53.719 E107.57069 - G1 X219.998 Y53.719 E107.8401 - G1 X219.998 Y50.319 E108.00973 - G1 X214.598 Y50.319 E108.27913 - G0 X214.598 Y50.519 - G0 X214.098 Y50.519 - G0 X210.426 Y49.791 - G0 X204.598 Y49.719 - G0 X204.598 Y50.219 - G1 X204.598 Y53.619 E108.44876 - G1 X209.998 Y53.619 E108.71817 - G1 X209.998 Y50.219 E108.88779 - G1 X204.598 Y50.219 E109.1572 - G0 X204.598 Y50.419 - G0 X204.098 Y50.419 - G0 X200.426 Y49.691 - G0 X194.598 Y49.619 - G0 X194.598 Y50.119 - G1 X194.598 Y53.519 E109.32683 - G1 X199.998 Y53.519 E109.59624 - G1 X199.998 Y50.119 E109.76586 - G1 X194.598 Y50.119 E110.03527 - G0 X194.598 Y50.319 - G0 X194.098 Y50.319 - G0 X190.426 Y49.591 - G0 X184.598 Y49.519 - G0 X184.598 Y50.019 - G1 X184.598 Y53.419 E110.2049 - G1 X189.998 Y53.419 E110.4743 - G1 X189.998 Y50.019 E110.64393 - G1 X184.598 Y50.019 E110.91334 - G0 X184.598 Y50.219 - G0 X184.098 Y50.219 - G0 X180.426 Y49.491 - G0 X174.598 Y49.419 - G0 X174.598 Y49.919 - G1 X174.598 Y53.319 E111.08296 - G1 X179.998 Y53.319 E111.35237 - G1 X179.998 Y49.919 E111.522 - G1 X174.598 Y49.919 E111.7914 - G0 X174.598 Y50.119 - G0 X174.098 Y50.119 - G0 X170.426 Y49.391 - G0 X164.598 Y49.319 - G0 X164.598 Y49.819 - G1 X164.598 Y53.219 E111.96103 - G1 X169.998 Y53.219 E112.23044 - G1 X169.998 Y49.819 E112.40007 - G1 X164.598 Y49.819 E112.66947 - G0 X164.598 Y50.019 - G0 X164.098 Y50.019 - G0 X160.426 Y49.291 - G0 X154.598 Y49.219 - G0 X154.598 Y49.719 - G1 X154.598 Y53.119 E112.8391 - G1 X159.998 Y53.119 E113.10851 - G1 X159.998 Y49.719 E113.27813 - G1 X154.598 Y49.719 E113.54754 - G0 X154.598 Y49.919 - G0 X154.098 Y49.919 - G0 X150.426 Y49.191 - G0 X144.598 Y49.119 - G0 X144.598 Y49.619 - G1 X144.598 Y53.019 E113.71717 - G1 X149.998 Y53.019 E113.98657 - G1 X149.998 Y49.619 E114.1562 - G1 X144.598 Y49.619 E114.42561 - G0 X144.598 Y49.819 - G0 X144.098 Y49.819 - G0 X140.426 Y49.091 - G0 X134.598 Y49.019 - G0 X134.598 Y49.519 - G1 X134.598 Y52.919 E114.59523 - G1 X139.998 Y52.919 E114.86464 - G1 X139.998 Y49.519 E115.03427 - G1 X134.598 Y49.519 E115.30368 - G0 X134.598 Y49.719 - G0 X134.098 Y49.719 - G0 X130.426 Y48.991 - G0 X124.598 Y48.919 - G0 X124.598 Y49.419 - G1 X124.598 Y52.819 E115.4733 - G1 X129.998 Y52.819 E115.74271 - G1 X129.998 Y49.419 E115.91234 - G1 X124.598 Y49.419 E116.18174 - G0 X124.598 Y49.619 - G0 X124.098 Y49.619 - G0 X120.426 Y48.891 - G0 X114.598 Y48.819 - G0 X114.598 Y49.319 - G1 X114.598 Y52.719 E116.35137 - G1 X119.998 Y52.719 E116.62078 - G1 X119.998 Y49.319 E116.7904 - G1 X114.598 Y49.319 E117.05981 - G0 X114.598 Y49.519 - G0 X114.098 Y49.519 - G0 X110.426 Y48.791 - G0 X104.598 Y48.719 - G0 X104.598 Y49.219 - G1 X104.598 Y52.619 E117.22944 - G1 X109.998 Y52.619 E117.49884 - G1 X109.998 Y49.219 E117.66847 - G1 X104.598 Y49.219 E117.93788 - G0 X104.598 Y49.419 - G0 X104.098 Y49.419 - G0 X100.426 Y48.691 - G0 X94.598 Y48.619 - G0 X94.598 Y49.119 - G1 X94.598 Y52.519 E118.1075 - G1 X99.998 Y52.519 E118.37691 - G1 X99.998 Y49.119 E118.54654 - G1 X94.598 Y49.119 E118.81595 - G0 X94.598 Y49.319 - G0 X94.098 Y49.319 - G0 X90.426 Y48.591 - G0 X84.598 Y48.519 - G0 X84.598 Y49.019 - G1 X84.598 Y52.419 E118.98557 - G1 X89.998 Y52.419 E119.25498 - G1 X89.998 Y49.019 E119.42461 - G1 X84.598 Y49.019 E119.69401 - G0 X84.598 Y49.219 - G0 X84.098 Y49.219 - G0 X59.898 Y73.219 - G0 X59.898 Y73.719 - G1 X59.898 Y79.119 E119.96342 - G1 X63.298 Y79.119 E120.13305 - G1 X63.298 Y73.719 E120.40245 - G1 X59.898 Y73.719 E120.57208 - G0 X59.898 Y73.919 - G0 X59.398 Y73.919 - G0 X59.47 Y79.547 - G0 X59.998 Y83.219 - G0 X59.998 Y83.719 - G1 X59.998 Y89.119 E120.84149 - G1 X63.398 Y89.119 E121.01111 - G1 X63.398 Y83.719 E121.28052 - G1 X59.998 Y83.719 E121.45015 - G0 X59.998 Y83.919 - G0 X59.498 Y83.919 - G0 X59.57 Y89.547 - G0 X60.098 Y93.219 - G0 X60.098 Y93.719 - G1 X60.098 Y99.119 E121.71956 - G1 X63.498 Y99.119 E121.88918 - G1 X63.498 Y93.719 E122.15859 - G1 X60.098 Y93.719 E122.32822 - G0 X60.098 Y93.919 - G0 X59.598 Y93.919 - G0 X59.67 Y99.547 - G0 X60.198 Y103.219 - G0 X60.198 Y103.719 - G1 X60.198 Y109.119 E122.59762 - G1 X63.598 Y109.119 E122.76725 - G1 X63.598 Y103.719 E123.03666 - G1 X60.198 Y103.719 E123.20628 - G0 X60.198 Y103.919 - G0 X59.698 Y103.919 - G0 X59.77 Y109.547 - G0 X60.298 Y113.219 - G0 X60.298 Y113.719 - G1 X60.298 Y119.119 E123.47569 - G1 X63.698 Y119.119 E123.64532 - G1 X63.698 Y113.719 E123.91472 - G1 X60.298 Y113.719 E124.08435 - G0 X60.298 Y113.919 - G0 X59.798 Y113.919 - G0 X59.87 Y119.547 - G0 X60.398 Y123.219 - G0 X60.398 Y123.719 - G1 X60.398 Y129.119 E124.35376 - G1 X63.798 Y129.119 E124.52338 - G1 X63.798 Y123.719 E124.79279 - G1 X60.398 Y123.719 E124.96242 - G0 X60.398 Y123.919 - G0 X59.898 Y123.919 - G0 X59.97 Y129.547 - G0 X60.498 Y133.219 - G0 X60.498 Y133.719 - G1 X60.498 Y139.119 E125.23183 - G1 X63.898 Y139.119 E125.40145 - G1 X63.898 Y133.719 E125.67086 - G1 X60.498 Y133.719 E125.84049 - G0 X60.498 Y133.919 - G0 X59.998 Y133.919 - G0 X60.07 Y139.547 - G0 X60.598 Y143.219 - G0 X60.598 Y143.719 - G1 X60.598 Y149.119 E126.10989 - G1 X63.998 Y149.119 E126.27952 - G1 X63.998 Y143.719 E126.54893 - G1 X60.598 Y143.719 E126.71855 - G0 X60.598 Y143.919 - G0 X60.098 Y143.919 - G0 X60.17 Y149.547 - G0 X60.698 Y153.219 - G0 X60.698 Y153.719 - G1 X60.698 Y159.119 E126.98796 - G1 X64.098 Y159.119 E127.15759 - G1 X64.098 Y153.719 E127.42699 - G1 X60.698 Y153.719 E127.59662 - G0 X60.698 Y153.919 - G0 X60.198 Y153.919 - G0 X60.27 Y159.547 - G0 X60.798 Y163.219 - G0 X60.798 Y163.719 - G1 X60.798 Y169.119 E127.86603 - G1 X64.198 Y169.119 E128.03565 - G1 X64.198 Y163.719 E128.30506 - G1 X60.798 Y163.719 E128.47469 - G0 X60.798 Y163.919 - G0 X60.298 Y163.919 - G0 X60.37 Y169.547 - G0 X60.898 Y173.219 - G0 X60.898 Y173.719 - G1 X60.898 Y179.119 E128.7441 - G1 X64.298 Y179.119 E128.91372 - G1 X64.298 Y173.719 E129.18313 - G1 X60.898 Y173.719 E129.35276 - G0 X60.898 Y173.919 - G0 X60.398 Y173.919 - G0 X60.47 Y179.547 - G0 X60.998 Y183.219 - G0 X60.998 Y183.719 - G1 X60.998 Y189.119 E129.62216 - G1 X64.398 Y189.119 E129.79179 - G1 X64.398 Y183.719 E130.0612 - G1 X60.998 Y183.719 E130.23082 - G0 X60.998 Y183.919 - G0 X60.498 Y183.919 - G0 X60.57 Y189.547 - G0 X61.098 Y193.219 - G0 X61.098 Y193.719 - G1 X61.098 Y199.119 E130.50023 - G1 X64.498 Y199.119 E130.66986 - G1 X64.498 Y193.719 E130.93926 - G1 X61.098 Y193.719 E131.10889 - G0 X61.098 Y193.919 - G0 X60.598 Y193.919 - G0 X60.67 Y199.547 - G0 X61.198 Y203.219 - G0 X61.198 Y203.719 - G1 X61.198 Y209.119 E131.3783 - G1 X64.598 Y209.119 E131.54792 - G1 X64.598 Y203.719 E131.81733 - G1 X61.198 Y203.719 E131.98696 - G0 X61.198 Y203.919 - G0 X60.698 Y203.919 - G0 X60.77 Y209.547 - G0 X61.298 Y213.219 - G0 X61.298 Y213.719 - G1 X61.298 Y219.119 E132.25637 - G1 X64.698 Y219.119 E132.42599 - G1 X64.698 Y213.719 E132.6954 - G1 X61.298 Y213.719 E132.86503 - G0 X61.298 Y213.919 - G0 X60.798 Y213.919 - G0 X60.508 Y212.929 - ;TYPE:SKIN - G1 X60.508 Y219.909 E133.21326 - G1 X65.488 Y219.909 E133.46171 - G1 X65.488 Y212.929 E133.80995 - G1 X60.508 Y212.929 E134.0584 - G0 X60.408 Y209.909 - G1 X65.388 Y209.909 E134.30685 - G1 X65.388 Y202.929 E134.65509 - G1 X60.408 Y202.929 E134.90354 - G1 X60.408 Y209.909 E135.25177 - G0 X60.308 Y199.909 - G1 X65.288 Y199.909 E135.50023 - G1 X65.288 Y192.929 E135.84846 - G1 X60.308 Y192.929 E136.09691 - G1 X60.308 Y199.909 E136.44515 - G0 X60.208 Y189.909 - G1 X65.188 Y189.909 E136.6936 - G1 X65.188 Y182.929 E137.04183 - G1 X60.208 Y182.929 E137.29029 - G1 X60.208 Y189.909 E137.63852 - G0 X60.108 Y179.909 - G1 X65.088 Y179.909 E137.88697 - G1 X65.088 Y172.929 E138.23521 - G1 X60.108 Y172.929 E138.48366 - G1 X60.108 Y179.909 E138.83189 - G0 X60.008 Y169.909 - G1 X64.988 Y169.909 E139.08035 - G1 X64.988 Y162.929 E139.42858 - G1 X60.008 Y162.929 E139.67703 - G1 X60.008 Y169.909 E140.02527 - G0 X59.908 Y159.909 - G1 X64.888 Y159.909 E140.27372 - G1 X64.888 Y152.929 E140.62196 - G1 X59.908 Y152.929 E140.87041 - G1 X59.908 Y159.909 E141.21864 - G0 X59.808 Y149.909 - G1 X64.788 Y149.909 E141.4671 - G1 X64.788 Y142.929 E141.81533 - G1 X59.808 Y142.929 E142.06378 - G1 X59.808 Y149.909 E142.41202 - G0 X59.708 Y139.909 - G1 X64.688 Y139.909 E142.66047 - G1 X64.688 Y132.929 E143.0087 - G1 X59.708 Y132.929 E143.25716 - G1 X59.708 Y139.909 E143.60539 - G0 X59.608 Y129.909 - G1 X64.588 Y129.909 E143.85384 - G1 X64.588 Y122.929 E144.20208 - G1 X59.608 Y122.929 E144.45053 - G1 X59.608 Y129.909 E144.79876 - G0 X59.508 Y119.909 - G1 X64.488 Y119.909 E145.04722 - G1 X64.488 Y112.929 E145.39545 - G1 X59.508 Y112.929 E145.6439 - G1 X59.508 Y119.909 E145.99214 - G0 X59.408 Y109.909 - G1 X64.388 Y109.909 E146.24059 - G1 X64.388 Y102.929 E146.58882 - G1 X59.408 Y102.929 E146.83728 - G1 X59.408 Y109.909 E147.18551 - G0 X59.308 Y99.909 - G1 X64.288 Y99.909 E147.43396 - G1 X64.288 Y92.929 E147.7822 - G1 X59.308 Y92.929 E148.03065 - G1 X59.308 Y99.909 E148.37888 - G0 X59.208 Y89.909 - G1 X64.188 Y89.909 E148.62734 - G1 X64.188 Y82.929 E148.97557 - G1 X59.208 Y82.929 E149.22402 - G1 X59.208 Y89.909 E149.57226 - G0 X59.108 Y79.909 - G1 X64.088 Y79.909 E149.82071 - G1 X64.088 Y72.929 E150.16894 - G1 X59.108 Y72.929 E150.4174 - G1 X59.108 Y79.909 E150.76563 - G0 X63.726 Y79.547 + G1 X64.888 Y152.929 E140.62196 + G1 X59.908 Y152.929 E140.87041 + G1 X59.908 Y159.909 E141.21864 + G0 X59.808 Y149.909 + G1 X64.788 Y149.909 E141.4671 + G1 X64.788 Y142.929 E141.81533 + G1 X59.808 Y142.929 E142.06378 + G1 X59.808 Y149.909 E142.41202 + G0 X59.708 Y139.909 + G1 X64.688 Y139.909 E142.66047 + G1 X64.688 Y132.929 E143.0087 + G1 X59.708 Y132.929 E143.25716 + G1 X59.708 Y139.909 E143.60539 + G0 X59.608 Y129.909 + G1 X64.588 Y129.909 E143.85384 + G1 X64.588 Y122.929 E144.20208 + G1 X59.608 Y122.929 E144.45053 + G1 X59.608 Y129.909 E144.79876 + G0 X59.508 Y119.909 + G1 X64.488 Y119.909 E145.04722 + G1 X64.488 Y112.929 E145.39545 + G1 X59.508 Y112.929 E145.6439 + G1 X59.508 Y119.909 E145.99214 + G0 X59.408 Y109.909 + G1 X64.388 Y109.909 E146.24059 + G1 X64.388 Y102.929 E146.58882 + G1 X59.408 Y102.929 E146.83728 + G1 X59.408 Y109.909 E147.18551 + M73 P8 + G0 X59.308 Y99.909 + G1 X64.288 Y99.909 E147.43396 + G1 X64.288 Y92.929 E147.7822 + G1 X59.308 Y92.929 E148.03065 + G1 X59.308 Y99.909 E148.37888 + G0 X59.208 Y89.909 + G1 X64.188 Y89.909 E148.62734 + G1 X64.188 Y82.929 E148.97557 + G1 X59.208 Y82.929 E149.22402 + G1 X59.208 Y89.909 E149.57226 + G0 X59.108 Y79.909 + G1 X64.088 Y79.909 E149.82071 + G1 X64.088 Y72.929 E150.16894 + G1 X59.108 Y72.929 E150.4174 + G1 X59.108 Y79.909 E150.76563 + G0 X63.726 Y79.547 G0 X72.516 Y63.43 G0 X73.241 Y62.502 G0 X83.808 Y53.209 @@ -938,6 +127,7 @@ gcode: G0 X113.808 Y53.509 G1 X120.788 Y53.509 E154.69399 G1 X120.788 Y48.529 E154.94244 + M73 P10 G1 X113.808 Y48.529 E155.29067 G1 X113.808 Y53.509 E155.53913 G0 X123.808 Y53.609 @@ -978,6 +168,7 @@ gcode: G0 X193.808 Y54.309 G1 X200.788 Y54.309 E164.24097 G1 X200.788 Y49.329 E164.48943 + M73 P17 G1 X193.808 Y49.329 E164.83766 G1 X193.808 Y54.309 E165.08611 G0 X203.808 Y54.409 @@ -1058,7 +249,7 @@ gcode: G1 X237.964 Y42.465 E187.6083 G1 X238.244 Y42.522 E187.62255 G1 X238.522 Y42.6 E187.63696 - M73 P30 + M73 P22 G1 X238.79 Y42.697 E187.65118 G1 X239.047 Y42.81 E187.66518 G1 X239.274 Y42.929 E187.67797 @@ -1465,7 +656,7 @@ gcode: G0 X63.004 Y213.284 G0 X71.126 Y198.405 G1 X62.809 Y190.088 E276.52677 - M73 P40 + M73 P27 G0 X63.375 Y190.088 G1 X71.126 Y197.839 E277.07365 G0 X71.126 Y197.274 @@ -2020,7 +1211,7 @@ gcode: G1 X64.567 Y109.256 E389.47789 G0 X64.567 Y108.69 G1 X71.127 Y115.251 E389.94077 - M73 P50 + M73 P32 G0 X71.127 Y114.685 G1 X64.567 Y108.125 E390.40362 G0 X64.567 Y107.559 @@ -2419,7 +1610,7 @@ gcode: G0 X59.87 Y119.547 G0 X59.128 Y99.291 G1 X53.469 Y93.632 E475.77452 - M73 P60 + M73 P38 G0 X53.469 Y93.067 G1 X59.128 Y98.726 E476.17379 G0 X59.128 Y98.16 @@ -2676,7 +1867,7 @@ gcode: G1 X83.627 Y51.949 E585.68565 G0 X83.627 Y52.514 G1 X73.703 Y42.59 E586.38585 - M73 P70 + M73 P45 G1 X73.633 Y42.52 G0 X85.582 Y42.59 G1 X93.627 Y50.635 E586.95346 @@ -2875,6 +2066,7 @@ gcode: G0 X123.684 Y48.448 G1 X117.826 Y42.59 E628.33445 G0 X117.26 Y42.59 + M73 P50 G1 X123.627 Y48.956 E628.78365 G0 X123.627 Y49.522 G1 X116.695 Y42.59 E629.27274 @@ -3139,7 +2331,7 @@ gcode: G1 X165.379 Y48.848 E682.82302 G0 X165.945 Y48.848 G1 X159.688 Y42.591 E683.26448 - M73 P80 + M73 P50 G0 X160.253 Y42.591 G1 X166.51 Y48.848 E683.70595 G0 X167.076 Y48.848 @@ -3377,6 +2569,7 @@ gcode: G0 X193.063 Y42.591 G1 X199.621 Y49.148 E732.62652 G0 X199.055 Y49.148 + M73 P55 G1 X192.497 Y42.591 E733.08919 G0 X191.932 Y42.591 G1 X198.489 Y49.148 E733.55182 @@ -3540,7 +2733,7 @@ gcode: G1 X156.527 Y57.533 E765.10409 G0 X156.245 Y57.815 G1 X150.967 Y52.538 E765.47645 - M73 P90 + M73 P60 G0 X150.967 Y53.103 G1 X155.963 Y58.099 E765.82894 G0 X155.68 Y58.382 @@ -3641,6 +2834,7 @@ gcode: G0 X176.476 Y54.288 G1 X182.437 Y60.249 E782.98939 G0 X183.002 Y60.249 + M73 P65 G1 X177.042 Y54.288 E783.40993 G0 X177.608 Y54.288 G1 X183.568 Y60.249 E783.83048 @@ -3727,6 +2921,7 @@ gcode: G0 X219.085 Y42.591 G1 X225.942 Y49.448 E802.04079 G0 X226.508 Y49.448 + M73 P70 G1 X219.65 Y42.591 E802.52463 G0 X220.216 Y42.591 G1 X227.073 Y49.448 E803.00843 @@ -3900,6 +3095,828 @@ gcode: G0 X73.938 Y61.926 G0 X59.428 Y73.249 G0 X59.498 Y73.319 + ;TYPE:WALL-INNER + G92 E0 + G0 F1800 X59.498 Y73.319 Z0.3 + G1 F1800 X59.498 Y79.519 E0.30932 + G1 X63.698 Y79.519 E0.51886 + G1 X63.698 Y73.319 E0.82818 + G1 X59.498 Y73.319 E1.03772 + G0 X59.428 Y73.249 + G0 X59.528 Y83.249 + G0 X59.598 Y83.319 + G1 X59.598 Y89.519 E1.34704 + G1 X63.798 Y89.519 E1.55657 + G1 X63.798 Y83.319 E1.86589 + G1 X59.598 Y83.319 E2.07543 + M73 P75 + G0 X59.528 Y83.249 + G0 X59.628 Y93.249 + G0 X59.698 Y93.319 + G1 X59.698 Y99.519 E2.38475 + G1 X63.898 Y99.519 E2.59429 + G1 X63.898 Y93.319 E2.90361 + G1 X59.698 Y93.319 E3.11315 + G0 X59.628 Y93.249 + G0 X59.728 Y103.249 + G0 X59.798 Y103.319 + G1 X59.798 Y109.519 E3.42247 + G1 X63.998 Y109.519 E3.63201 + G1 X63.998 Y103.319 E3.94133 + G1 X59.798 Y103.319 E4.15086 + G0 X59.728 Y103.249 + G0 X59.828 Y113.249 + G0 X59.898 Y113.319 + M73 P80 + G1 X59.898 Y119.519 E4.46018 + G1 X64.098 Y119.519 E4.66972 + G1 X64.098 Y113.319 E4.97904 + G1 X59.898 Y113.319 E5.18858 + G0 X59.828 Y113.249 + G0 X59.928 Y123.249 + G0 X59.998 Y123.319 + G1 X59.998 Y129.519 E5.4979 + G1 X64.198 Y129.519 E5.70744 + G1 X64.198 Y123.319 E6.01676 + G1 X59.998 Y123.319 E6.2263 + G0 X59.928 Y123.249 + G0 X60.028 Y133.249 + G0 X60.098 Y133.319 + G1 X60.098 Y139.519 E6.53562 + G1 X64.298 Y139.519 E6.74516 + G1 X64.298 Y133.319 E7.05447 + M73 P83 + G1 X60.098 Y133.319 E7.26401 + G0 X60.028 Y133.249 + G0 X60.128 Y143.249 + G0 X60.198 Y143.319 + G1 X60.198 Y149.519 E7.57333 + G1 X64.398 Y149.519 E7.78287 + G1 X64.398 Y143.319 E8.09219 + G1 X60.198 Y143.319 E8.30173 + G0 X60.128 Y143.249 + G0 X60.228 Y153.249 + G0 X60.298 Y153.319 + G1 X60.298 Y159.519 E8.61105 + G1 X64.498 Y159.519 E8.82059 + G1 X64.498 Y153.319 E9.12991 + G1 X60.298 Y153.319 E9.33945 + G0 X60.228 Y153.249 + G0 X60.328 Y163.249 + G0 X60.398 Y163.319 + G1 X60.398 Y169.519 E9.64877 + G1 X64.598 Y169.519 E9.8583 + G1 X64.598 Y163.319 E10.16762 + G1 X60.398 Y163.319 E10.37716 + G0 X60.328 Y163.249 + G0 X60.428 Y173.249 + G0 X60.498 Y173.319 + G1 X60.498 Y179.519 E10.68648 + G1 X64.698 Y179.519 E10.89602 + M73 P87 + G1 X64.698 Y173.319 E11.20534 + G1 X60.498 Y173.319 E11.41488 + G0 X60.428 Y173.249 + G0 X60.528 Y183.249 + G0 X60.598 Y183.319 + G1 X60.598 Y189.519 E11.7242 + G1 X64.798 Y189.519 E11.93374 + G1 X64.798 Y183.319 E12.24306 + G1 X60.598 Y183.319 E12.45259 + G0 X60.528 Y183.249 + G0 X60.628 Y193.249 + G0 X60.698 Y193.319 + G1 X60.698 Y199.519 E12.76191 + G1 X64.898 Y199.519 E12.97145 + G1 X64.898 Y193.319 E13.28077 + G1 X60.698 Y193.319 E13.49031 + G0 X60.628 Y193.249 + G0 X60.728 Y203.249 + G0 X60.798 Y203.319 + G1 X60.798 Y209.519 E13.79963 + G1 X64.998 Y209.519 E14.00917 + G1 X64.998 Y203.319 E14.31849 + G1 X60.798 Y203.319 E14.52803 + G0 X60.728 Y203.249 + G0 X60.828 Y213.249 + G0 X60.898 Y213.319 + G1 X60.898 Y219.519 E14.83735 + G1 X65.098 Y219.519 E15.04689 + G1 X65.098 Y213.319 E15.3562 + G1 X60.898 Y213.319 E15.56574 + G0 X60.828 Y213.249 + G0 X60.77 Y209.547 + G0 X60.77 Y203.291 + G0 X64.926 Y199.547 + G0 X71.714 Y65.634 + G0 X71.998 Y64.491 + G0 X72.516 Y63.43 + G0 X84.128 Y48.549 + G0 X84.198 Y48.619 + G1 X84.198 Y52.819 E15.77528 + G1 X90.398 Y52.819 E16.0846 + G1 X90.398 Y48.619 E16.29414 + G1 X84.198 Y48.619 E16.60346 + G0 X84.128 Y48.549 + G0 X94.128 Y48.649 + G0 X94.198 Y48.719 + G1 X94.198 Y52.919 E16.813 + G1 X100.398 Y52.919 E17.12232 + G1 X100.398 Y48.719 E17.33186 + G1 X94.198 Y48.719 E17.64118 + G0 X94.128 Y48.649 + G0 X104.128 Y48.749 + G0 X104.198 Y48.819 + G1 X104.198 Y53.019 E17.85071 + G1 X110.398 Y53.019 E18.16003 + G1 X110.398 Y48.819 E18.36957 + G1 X104.198 Y48.819 E18.67889 + G0 X104.128 Y48.749 + G0 X114.128 Y48.849 + G0 X114.198 Y48.919 + G1 X114.198 Y53.119 E18.88843 + G1 X120.398 Y53.119 E19.19775 + G1 X120.398 Y48.919 E19.40729 + G1 X114.198 Y48.919 E19.71661 + G0 X114.128 Y48.849 + G0 X124.128 Y48.949 + G0 X124.198 Y49.019 + G1 X124.198 Y53.219 E19.92615 + G1 X130.398 Y53.219 E20.23547 + G1 X130.398 Y49.019 E20.44501 + G1 X124.198 Y49.019 E20.75432 + G0 X124.128 Y48.949 + G0 X134.128 Y49.049 + G0 X134.198 Y49.119 + G1 X134.198 Y53.319 E20.96386 + G1 X140.398 Y53.319 E21.27318 + G1 X140.398 Y49.119 E21.48272 + G1 X134.198 Y49.119 E21.79204 + G0 X134.128 Y49.049 + G0 X144.128 Y49.149 + G0 X144.198 Y49.219 + G1 X144.198 Y53.419 E22.00158 + G1 X150.398 Y53.419 E22.3109 + G1 X150.398 Y49.219 E22.52044 + G1 X144.198 Y49.219 E22.82976 + G0 X144.128 Y49.149 + G0 X154.128 Y49.249 + G0 X154.198 Y49.319 + G1 X154.198 Y53.519 E23.0393 + G1 X160.398 Y53.519 E23.34861 + G1 X160.398 Y49.319 E23.55815 + G1 X154.198 Y49.319 E23.86747 + G0 X154.128 Y49.249 + G0 X164.128 Y49.349 + G0 X164.198 Y49.419 + G1 X164.198 Y53.619 E24.07701 + G1 X170.398 Y53.619 E24.38633 + G1 X170.398 Y49.419 E24.59587 + G1 X164.198 Y49.419 E24.90519 + G0 X164.128 Y49.349 + G0 X174.128 Y49.449 + M73 P90 + G0 X174.198 Y49.519 + G1 X174.198 Y53.719 E25.11473 + G1 X180.398 Y53.719 E25.42405 + G1 X180.398 Y49.519 E25.63359 + G1 X174.198 Y49.519 E25.94291 + G0 X174.128 Y49.449 + G0 X184.128 Y49.549 + G0 X184.198 Y49.619 + G1 X184.198 Y53.819 E26.15244 + G1 X190.398 Y53.819 E26.46176 + G1 X190.398 Y49.619 E26.6713 + G1 X184.198 Y49.619 E26.98062 + G0 X184.128 Y49.549 + G0 X194.128 Y49.649 + G0 X194.198 Y49.719 + G1 X194.198 Y53.919 E27.19016 + G1 X200.398 Y53.919 E27.49948 + G1 X200.398 Y49.719 E27.70902 + G1 X194.198 Y49.719 E28.01834 + G0 X194.128 Y49.649 + G0 X204.128 Y49.749 + G0 X204.198 Y49.819 + G1 X204.198 Y54.019 E28.22788 + G1 X210.398 Y54.019 E28.5372 + G1 X210.398 Y49.819 E28.74673 + G1 X204.198 Y49.819 E29.05605 + G0 X204.128 Y49.749 + G0 X214.128 Y49.849 + G0 X214.198 Y49.919 + G1 X214.198 Y54.119 E29.26559 + G1 X220.398 Y54.119 E29.57491 + G1 X220.398 Y49.919 E29.78445 + G1 X214.198 Y49.919 E30.09377 + G0 X214.128 Y49.849 + G0 X224.128 Y49.949 + G0 X224.198 Y50.019 + G1 X224.198 Y54.219 E30.30331 + G1 X230.398 Y54.219 E30.61263 + G1 X230.398 Y50.019 E30.82217 + G1 X224.198 Y50.019 E31.13149 + G0 X224.128 Y49.949 + G0 X230.426 Y49.991 + G0 X238.151 Y51.419 + G0 X238.251 Y51.419 + G1 X238.484 Y51.582 E31.14567 + G1 X241.698 Y53.831 E31.34138 + G1 X241.695 Y56.565 E31.47778 + G1 X241.673 Y56.886 E31.49383 + G1 X241.632 Y57.175 E31.50839 + G1 X241.565 Y57.486 E31.52427 + G1 X241.484 Y57.772 E31.5391 + G1 X241.378 Y58.066 E31.55469 + G1 X241.25 Y58.352 E31.57032 + G1 X241.11 Y58.616 E31.58523 + G1 X240.951 Y58.871 E31.60022 + G1 X240.765 Y59.126 E31.61597 + G1 X240.56 Y59.371 E31.6319 + G1 X240.354 Y59.583 E31.64665 + G1 X240.134 Y59.782 E31.66145 + G1 X239.875 Y59.985 E31.67787 + G1 X239.628 Y60.151 E31.69272 + G1 X239.371 Y60.299 E31.70751 + G1 X239.086 Y60.438 E31.72333 + G1 X238.8 Y60.554 E31.73873 + G1 X238.51 Y60.649 E31.75395 + G1 X238.223 Y60.72 E31.76871 + G1 X237.91 Y60.776 E31.78457 + G1 X237.608 Y60.806 E31.79971 + G1 X237.276 Y60.819 E31.81629 + G1 X160.546 Y60.819 E35.64436 + G1 X157.439 Y57.711 E35.86361 + G1 X157.298 Y57.57 E35.87356 + G1 X157.157 Y57.711 E35.87998 + G1 X154.05 Y60.819 E36.09924 + G1 X77.102 Y60.822 E39.93819 + G1 X76.713 Y60.849 E39.95764 + G1 X76.325 Y60.903 E39.97718 + G1 X75.943 Y60.985 E39.99668 + G1 X75.567 Y61.092 E40.01618 + G1 X75.2 Y61.227 E40.03569 + G1 X74.843 Y61.385 E40.05517 + G1 X74.498 Y61.568 E40.07465 + G1 X74.166 Y61.775 E40.09417 + G1 X73.851 Y62.005 E40.11363 + G1 X73.55 Y62.257 E40.13321 + G1 X73.269 Y62.529 E40.15272 + G1 X73.008 Y62.82 E40.17223 + G1 X72.768 Y63.126 E40.19163 + G1 X72.549 Y63.451 E40.21118 + G1 X72.353 Y63.789 E40.23067 + G1 X72.181 Y64.141 E40.25022 + G1 X72.035 Y64.504 E40.26974 + G1 X71.915 Y64.875 E40.28919 + G1 X71.819 Y65.254 E40.3087 + G1 X71.753 Y65.639 E40.32819 + G1 X71.711 Y66.028 E40.34771 + G1 X71.698 Y66.409 E40.36673 + G1 X71.698 Y143.171 E44.1964 + G1 X68.59 Y146.278 E44.41565 + G1 X68.449 Y146.419 E44.4256 + G1 X68.59 Y146.56 E44.43202 + G1 X71.698 Y149.667 E44.65127 + G1 X71.695 Y226.564 E48.48768 + G1 X71.674 Y226.877 E48.50333 + G1 X71.637 Y227.147 E48.51692 + G1 X71.573 Y227.46 E48.53286 + G1 X71.491 Y227.753 E48.54804 + G1 X71.395 Y228.023 E48.56234 + G1 X71.27 Y228.309 E48.57791 + G1 X71.134 Y228.573 E48.59273 + G1 X70.969 Y228.844 E48.60856 + G1 X70.811 Y229.068 E48.62223 + G1 X70.621 Y229.301 E48.63723 + G1 X70.408 Y229.529 E48.6528 + G1 X70.18 Y229.742 E48.66836 + G1 X69.958 Y229.923 E48.68265 + G1 X69.711 Y230.097 E48.69773 + G1 X69.455 Y230.253 E48.71268 + G1 X69.183 Y230.394 E48.72797 + G1 X68.916 Y230.51 E48.74249 + G1 X68.628 Y230.611 E48.75772 + G1 X68.346 Y230.691 E48.77234 + G1 X68.026 Y230.758 E48.78866 + G1 X67.761 Y230.793 E48.80199 + G1 X67.441 Y230.816 E48.818 + G1 X65.546 Y230.819 E48.91254 + M73 P92 + G1 X62.439 Y227.711 E49.13179 + G1 X62.298 Y227.57 E49.14174 + G1 X62.157 Y227.711 E49.14816 + G1 X59.05 Y230.819 E49.36741 + G1 X57.174 Y230.817 E49.46101 + G1 X56.865 Y230.797 E49.47646 + G1 X56.562 Y230.756 E49.49171 + G1 X56.253 Y230.693 E49.50744 + G1 X55.952 Y230.608 E49.52305 + G1 X55.677 Y230.508 E49.53765 + G1 X55.388 Y230.382 E49.55338 + G1 X55.115 Y230.239 E49.56875 + G1 X54.867 Y230.085 E49.58331 + G1 X54.602 Y229.895 E49.59958 + G1 X54.371 Y229.703 E49.61457 + G1 X54.156 Y229.497 E49.62942 + G1 X53.935 Y229.255 E49.64577 + G1 X53.756 Y229.027 E49.66024 + G1 X53.58 Y228.769 E49.67582 + G1 X53.426 Y228.505 E49.69107 + G1 X53.288 Y228.227 E49.70655 + G1 X53.167 Y227.933 E49.72241 + G1 X53.079 Y227.662 E49.73663 + G1 X53.002 Y227.361 E49.75213 + G1 X52.946 Y227.049 E49.76794 + G1 X52.911 Y226.74 E49.78346 + G1 X52.899 Y226.43 E49.79893 + G1 X52.9 Y46.293 E58.786 + G1 X52.92 Y45.972 E58.80205 + G1 X52.957 Y45.697 E58.81589 + G1 X53.024 Y45.37 E58.83255 + G1 X53.102 Y45.093 E58.8469 + G1 X53.212 Y44.786 E58.86317 + G1 X53.335 Y44.507 E58.87839 + G1 X53.477 Y44.238 E58.89356 + G1 X53.634 Y43.984 E58.90846 + G1 X53.814 Y43.731 E58.92395 + G1 X54.015 Y43.489 E58.93964 + G1 X54.216 Y43.279 E58.95415 + G1 X54.461 Y43.055 E58.97071 + G1 X54.687 Y42.878 E58.98503 + G1 X54.945 Y42.701 E59.00064 + G1 X55.218 Y42.543 E59.01638 + G1 X55.482 Y42.412 E59.03108 + G1 X55.768 Y42.295 E59.0465 + G1 X56.058 Y42.199 E59.06174 + G1 X56.371 Y42.119 E59.07785 + G1 X56.652 Y42.068 E59.0921 + G1 X56.968 Y42.033 E59.10796 + G1 X57.295 Y42.02 E59.12429 + G1 X237.423 Y42.021 E68.11091 + G1 X237.731 Y42.04 E68.12631 + G1 X238.034 Y42.081 E68.14156 + G1 X238.342 Y42.144 E68.15725 + G1 X238.641 Y42.228 E68.17274 + G1 X238.926 Y42.331 E68.18786 + G1 X239.206 Y42.454 E68.20312 + G1 X239.473 Y42.593 E68.21814 + G1 X239.732 Y42.754 E68.23335 + G1 X239.994 Y42.942 E68.24944 + G1 X240.225 Y43.135 E68.26446 + G1 X240.437 Y43.337 E68.27907 + G1 X240.661 Y43.582 E68.29563 + G1 X240.842 Y43.813 E68.31027 + G1 X241.013 Y44.063 E68.32538 + G1 X241.171 Y44.333 E68.34099 + G1 X241.303 Y44.598 E68.35576 + M73 P93 + G1 X241.42 Y44.884 E68.37117 + G1 X241.521 Y45.189 E68.3872 + G1 X241.594 Y45.474 E68.40188 + G1 X241.65 Y45.788 E68.41779 + G1 X241.685 Y46.097 E68.43331 + G1 X241.697 Y46.408 E68.44884 + G1 X241.698 Y49.007 E68.5785 + G1 X238.484 Y51.256 E68.77421 + G1 X238.251 Y51.419 E68.78257 + G0 X238.949 Y51.419 + ;TYPE:WALL-OUTER + G1 X239.182 Y51.582 E68.79676 + G1 X242.098 Y53.623 E68.97434 + G1 X242.095 Y56.579 E69.12181 + G1 X242.071 Y56.927 E69.13921 + G1 X242.026 Y57.245 E69.15524 + G1 X241.953 Y57.586 E69.17263 + G1 X241.865 Y57.896 E69.18871 + G1 X241.751 Y58.21 E69.20538 + G1 X241.611 Y58.524 E69.22253 + G1 X241.454 Y58.82 E69.23925 + G1 X241.281 Y59.097 E69.25554 + G1 X241.077 Y59.377 E69.27282 + G1 X240.865 Y59.63 E69.28929 + G1 X240.627 Y59.876 E69.30637 + G1 X240.389 Y60.091 E69.32237 + G1 X240.12 Y60.302 E69.33943 + G1 X239.836 Y60.492 E69.35647 + G1 X239.557 Y60.653 E69.37254 + G1 X239.244 Y60.806 E69.38992 + G1 X238.943 Y60.928 E69.40613 + G1 X238.621 Y61.033 E69.42303 + G1 X238.299 Y61.113 E69.43958 + G1 X237.966 Y61.172 E69.45645 + G1 X237.633 Y61.206 E69.47315 + G1 X237.291 Y61.219 E69.49023 + G1 X160.38 Y61.219 E73.32733 + G1 X157.439 Y58.277 E73.53487 + G1 X157.298 Y58.136 E73.54482 + G1 X157.157 Y58.277 E73.55124 + G1 X154.216 Y61.219 E73.75878 + G1 X77.116 Y61.222 E77.60532 + G1 X76.754 Y61.247 E77.62342 + G1 X76.395 Y61.297 E77.6415 + G1 X76.04 Y61.373 E77.65961 + G1 X75.691 Y61.473 E77.67773 + G1 X75.35 Y61.598 E77.69585 + G1 X75.018 Y61.745 E77.71396 + M73 P94 + G1 X74.698 Y61.915 E77.73204 + G1 X74.39 Y62.107 E77.75015 + G1 X74.097 Y62.32 E77.76822 + G1 X73.818 Y62.554 E77.78638 + G1 X73.557 Y62.806 E77.80449 + G1 X73.315 Y63.077 E77.82261 + G1 X73.091 Y63.362 E77.8407 + G1 X72.888 Y63.663 E77.85881 + G1 X72.706 Y63.977 E77.87692 + G1 X72.547 Y64.304 E77.89506 + G1 X72.411 Y64.64 E77.91314 + G1 X72.3 Y64.985 E77.93122 + G1 X72.211 Y65.337 E77.94934 + G1 X72.149 Y65.695 E77.96746 + G1 X72.11 Y66.056 E77.98558 + G1 X72.098 Y66.416 E78.00355 + G1 X72.098 Y143.337 E81.84115 + G1 X69.156 Y146.278 E82.04869 + G1 X69.015 Y146.419 E82.05864 + G1 X69.156 Y146.56 E82.06506 + G1 X72.098 Y149.501 E82.2726 + G1 X72.095 Y226.576 E86.11789 + G1 X72.072 Y226.916 E86.13489 + G1 X72.029 Y227.228 E86.1506 + G1 X71.963 Y227.548 E86.1669 + G1 X71.871 Y227.877 E86.18395 + G1 X71.766 Y228.173 E86.19962 + G1 X71.635 Y228.474 E86.21599 + G1 X71.48 Y228.774 E86.23284 + G1 X71.308 Y229.057 E86.24936 + G1 X71.127 Y229.314 E86.26505 + G1 X70.92 Y229.568 E86.28139 + G1 X70.691 Y229.812 E86.29809 + G1 X70.447 Y230.041 E86.31478 + G1 X70.204 Y230.239 E86.33042 + G1 X69.928 Y230.433 E86.34725 + G1 X69.653 Y230.601 E86.36333 + G1 X69.353 Y230.756 E86.38018 + G1 X69.065 Y230.881 E86.39584 + G1 X68.748 Y230.993 E86.41261 + G1 X68.432 Y231.082 E86.42899 + G1 X68.107 Y231.15 E86.44556 + G1 X67.795 Y231.192 E86.46126 + G1 X67.455 Y231.216 E86.47827 + G1 X65.38 Y231.219 E86.58179 + G1 X62.439 Y228.277 E86.78933 + G1 X62.298 Y228.136 E86.79928 + G1 X62.157 Y228.277 E86.8057 + G1 X59.216 Y231.219 E87.01324 + G1 X57.163 Y231.217 E87.11566 + G1 X56.815 Y231.194 E87.13306 + G1 X56.498 Y231.152 E87.14902 + G1 X56.164 Y231.083 E87.16603 + G1 X55.833 Y230.99 E87.18319 + G1 X55.521 Y230.877 E87.19974 + G1 X55.22 Y230.746 E87.21612 + G1 X54.92 Y230.588 E87.23303 + G1 X54.642 Y230.416 E87.24934 + G1 X54.359 Y230.213 E87.26672 + G1 X54.106 Y230.002 E87.28316 + G1 X53.866 Y229.773 E87.29971 + G1 X53.634 Y229.518 E87.3169 + G1 X53.427 Y229.255 E87.3336 + G1 X53.245 Y228.988 E87.34972 + G1 X53.07 Y228.689 E87.36701 + G1 X52.925 Y228.396 E87.38332 + G1 X52.794 Y228.078 E87.40048 + G1 X52.695 Y227.773 E87.41647 + G1 X52.608 Y227.434 E87.43394 + G1 X52.549 Y227.105 E87.45061 + G1 X52.512 Y226.772 E87.46733 + G1 X52.499 Y226.446 E87.4836 + G1 X52.5 Y46.284 E96.47192 + G1 X52.522 Y45.936 E96.48932 + G1 X52.565 Y45.617 E96.50538 + G1 X52.635 Y45.275 E96.52279 + G1 X52.722 Y44.967 E96.53876 + G1 X52.835 Y44.651 E96.5555 + G1 X52.975 Y44.333 E96.57284 + G1 X53.131 Y44.036 E96.58958 + G1 X53.301 Y43.762 E96.60566 + G1 X53.495 Y43.49 E96.62233 + G1 X53.714 Y43.226 E96.63944 + G1 X53.94 Y42.989 E96.65578 + G1 X54.198 Y42.754 E96.67319 + G1 X54.456 Y42.551 E96.68957 + G1 X54.734 Y42.361 E96.70637 + G1 X55.024 Y42.193 E96.72309 + G1 X55.32 Y42.046 E96.73958 + G1 X55.63 Y41.919 E96.75629 + G1 X55.951 Y41.813 E96.77316 + G1 X56.272 Y41.731 E96.78969 + G1 X56.605 Y41.67 E96.80658 + G1 X56.938 Y41.634 E96.82329 + G1 X57.279 Y41.62 E96.84031 + G1 X237.432 Y41.621 E105.82818 + G1 X237.781 Y41.643 E105.84563 + G1 X238.098 Y41.685 E105.86158 + G1 X238.431 Y41.754 E105.87855 + G1 X238.763 Y41.847 E105.89575 + G1 X239.075 Y41.96 E105.91231 + G1 X239.385 Y42.096 E105.9292 + G1 X239.669 Y42.244 E105.94517 + G1 X239.954 Y42.421 E105.96191 + G1 X240.237 Y42.624 E105.97929 + G1 X240.49 Y42.835 E105.99572 + G1 X240.727 Y43.061 E106.01206 + G1 X240.962 Y43.319 E106.02947 + G1 X241.169 Y43.582 E106.04617 + G1 X241.35 Y43.847 E106.06218 + G1 X241.526 Y44.148 E106.07957 + G1 X241.669 Y44.436 E106.09562 + G1 X241.796 Y44.746 E106.11233 + G1 X241.901 Y45.064 E106.12904 + G1 X241.988 Y45.403 E106.1465 + G1 X242.047 Y45.732 E106.16317 + G1 X242.084 Y46.065 E106.17989 + G1 X242.097 Y46.392 E106.19622 + G1 X242.098 Y49.215 E106.33706 + G1 X239.182 Y51.256 E106.51463 + G1 X238.949 Y51.419 E106.523 + G0 X239.113 Y51.533 + G0 X238.825 Y51.942 + G0 X230.426 Y49.991 + G0 X224.598 Y49.919 + G0 X224.598 Y50.419 + G1 X224.598 Y53.819 E106.69263 + G1 X229.998 Y53.819 E106.96203 + G1 X229.998 Y50.419 E107.13166 + G1 X224.598 Y50.419 E107.40107 + G0 X224.598 Y50.619 + G0 X224.098 Y50.619 + G0 X220.426 Y49.891 + G0 X214.598 Y49.819 + G0 X214.598 Y50.319 + G1 X214.598 Y53.719 E107.57069 + G1 X219.998 Y53.719 E107.8401 + G1 X219.998 Y50.319 E108.00973 + G1 X214.598 Y50.319 E108.27913 + G0 X214.598 Y50.519 + G0 X214.098 Y50.519 + G0 X210.426 Y49.791 + G0 X204.598 Y49.719 + G0 X204.598 Y50.219 + G1 X204.598 Y53.619 E108.44876 + G1 X209.998 Y53.619 E108.71817 + G1 X209.998 Y50.219 E108.88779 + G1 X204.598 Y50.219 E109.1572 + G0 X204.598 Y50.419 + G0 X204.098 Y50.419 + G0 X200.426 Y49.691 + G0 X194.598 Y49.619 + G0 X194.598 Y50.119 + G1 X194.598 Y53.519 E109.32683 + G1 X199.998 Y53.519 E109.59624 + G1 X199.998 Y50.119 E109.76586 + G1 X194.598 Y50.119 E110.03527 + G0 X194.598 Y50.319 + G0 X194.098 Y50.319 + G0 X190.426 Y49.591 + G0 X184.598 Y49.519 + G0 X184.598 Y50.019 + G1 X184.598 Y53.419 E110.2049 + G1 X189.998 Y53.419 E110.4743 + G1 X189.998 Y50.019 E110.64393 + G1 X184.598 Y50.019 E110.91334 + G0 X184.598 Y50.219 + G0 X184.098 Y50.219 + G0 X180.426 Y49.491 + G0 X174.598 Y49.419 + G0 X174.598 Y49.919 + G1 X174.598 Y53.319 E111.08296 + G1 X179.998 Y53.319 E111.35237 + G1 X179.998 Y49.919 E111.522 + G1 X174.598 Y49.919 E111.7914 + G0 X174.598 Y50.119 + G0 X174.098 Y50.119 + G0 X170.426 Y49.391 + G0 X164.598 Y49.319 + G0 X164.598 Y49.819 + G1 X164.598 Y53.219 E111.96103 + G1 X169.998 Y53.219 E112.23044 + G1 X169.998 Y49.819 E112.40007 + G1 X164.598 Y49.819 E112.66947 + G0 X164.598 Y50.019 + G0 X164.098 Y50.019 + G0 X160.426 Y49.291 + G0 X154.598 Y49.219 + G0 X154.598 Y49.719 + G1 X154.598 Y53.119 E112.8391 + G1 X159.998 Y53.119 E113.10851 + G1 X159.998 Y49.719 E113.27813 + G1 X154.598 Y49.719 E113.54754 + G0 X154.598 Y49.919 + G0 X154.098 Y49.919 + G0 X150.426 Y49.191 + G0 X144.598 Y49.119 + G0 X144.598 Y49.619 + G1 X144.598 Y53.019 E113.71717 + G1 X149.998 Y53.019 E113.98657 + G1 X149.998 Y49.619 E114.1562 + G1 X144.598 Y49.619 E114.42561 + G0 X144.598 Y49.819 + G0 X144.098 Y49.819 + G0 X140.426 Y49.091 + G0 X134.598 Y49.019 + G0 X134.598 Y49.519 + G1 X134.598 Y52.919 E114.59523 + G1 X139.998 Y52.919 E114.86464 + G1 X139.998 Y49.519 E115.03427 + G1 X134.598 Y49.519 E115.30368 + G0 X134.598 Y49.719 + G0 X134.098 Y49.719 + G0 X130.426 Y48.991 + G0 X124.598 Y48.919 + G0 X124.598 Y49.419 + G1 X124.598 Y52.819 E115.4733 + G1 X129.998 Y52.819 E115.74271 + G1 X129.998 Y49.419 E115.91234 + G1 X124.598 Y49.419 E116.18174 + G0 X124.598 Y49.619 + G0 X124.098 Y49.619 + G0 X120.426 Y48.891 + G0 X114.598 Y48.819 + G0 X114.598 Y49.319 + G1 X114.598 Y52.719 E116.35137 + G1 X119.998 Y52.719 E116.62078 + G1 X119.998 Y49.319 E116.7904 + G1 X114.598 Y49.319 E117.05981 + G0 X114.598 Y49.519 + G0 X114.098 Y49.519 + G0 X110.426 Y48.791 + G0 X104.598 Y48.719 + G0 X104.598 Y49.219 + G1 X104.598 Y52.619 E117.22944 + G1 X109.998 Y52.619 E117.49884 + G1 X109.998 Y49.219 E117.66847 + G1 X104.598 Y49.219 E117.93788 + G0 X104.598 Y49.419 + G0 X104.098 Y49.419 + G0 X100.426 Y48.691 + G0 X94.598 Y48.619 + G0 X94.598 Y49.119 + G1 X94.598 Y52.519 E118.1075 + G1 X99.998 Y52.519 E118.37691 + G1 X99.998 Y49.119 E118.54654 + G1 X94.598 Y49.119 E118.81595 + G0 X94.598 Y49.319 + G0 X94.098 Y49.319 + G0 X90.426 Y48.591 + G0 X84.598 Y48.519 + G0 X84.598 Y49.019 + G1 X84.598 Y52.419 E118.98557 + G1 X89.998 Y52.419 E119.25498 + G1 X89.998 Y49.019 E119.42461 + G1 X84.598 Y49.019 E119.69401 + G0 X84.598 Y49.219 + G0 X84.098 Y49.219 + G0 X59.898 Y73.219 + G0 X59.898 Y73.719 + G1 X59.898 Y79.119 E119.96342 + G1 X63.298 Y79.119 E120.13305 + G1 X63.298 Y73.719 E120.40245 + G1 X59.898 Y73.719 E120.57208 + G0 X59.898 Y73.919 + G0 X59.398 Y73.919 + G0 X59.47 Y79.547 + G0 X59.998 Y83.219 + G0 X59.998 Y83.719 + G1 X59.998 Y89.119 E120.84149 + G1 X63.398 Y89.119 E121.01111 + G1 X63.398 Y83.719 E121.28052 + G1 X59.998 Y83.719 E121.45015 + G0 X59.998 Y83.919 + G0 X59.498 Y83.919 + G0 X59.57 Y89.547 + G0 X60.098 Y93.219 + G0 X60.098 Y93.719 + G1 X60.098 Y99.119 E121.71956 + G1 X63.498 Y99.119 E121.88918 + G1 X63.498 Y93.719 E122.15859 + G1 X60.098 Y93.719 E122.32822 + G0 X60.098 Y93.919 + G0 X59.598 Y93.919 + G0 X59.67 Y99.547 + G0 X60.198 Y103.219 + G0 X60.198 Y103.719 + G1 X60.198 Y109.119 E122.59762 + G1 X63.598 Y109.119 E122.76725 + G1 X63.598 Y103.719 E123.03666 + G1 X60.198 Y103.719 E123.20628 + G0 X60.198 Y103.919 + G0 X59.698 Y103.919 + G0 X59.77 Y109.547 + G0 X60.298 Y113.219 + G0 X60.298 Y113.719 + G1 X60.298 Y119.119 E123.47569 + G1 X63.698 Y119.119 E123.64532 + G1 X63.698 Y113.719 E123.91472 + G1 X60.298 Y113.719 E124.08435 + G0 X60.298 Y113.919 + G0 X59.798 Y113.919 + G0 X59.87 Y119.547 + G0 X60.398 Y123.219 + G0 X60.398 Y123.719 + G1 X60.398 Y129.119 E124.35376 + G1 X63.798 Y129.119 E124.52338 + G1 X63.798 Y123.719 E124.79279 + G1 X60.398 Y123.719 E124.96242 + G0 X60.398 Y123.919 + G0 X59.898 Y123.919 + G0 X59.97 Y129.547 + G0 X60.498 Y133.219 + G0 X60.498 Y133.719 + G1 X60.498 Y139.119 E125.23183 + G1 X63.898 Y139.119 E125.40145 + G1 X63.898 Y133.719 E125.67086 + G1 X60.498 Y133.719 E125.84049 + G0 X60.498 Y133.919 + G0 X59.998 Y133.919 + G0 X60.07 Y139.547 + G0 X60.598 Y143.219 + G0 X60.598 Y143.719 + G1 X60.598 Y149.119 E126.10989 + G1 X63.998 Y149.119 E126.27952 + G1 X63.998 Y143.719 E126.54893 + G1 X60.598 Y143.719 E126.71855 + G0 X60.598 Y143.919 + G0 X60.098 Y143.919 + G0 X60.17 Y149.547 + G0 X60.698 Y153.219 + G0 X60.698 Y153.719 + G1 X60.698 Y159.119 E126.98796 + G1 X64.098 Y159.119 E127.15759 + G1 X64.098 Y153.719 E127.42699 + G1 X60.698 Y153.719 E127.59662 + G0 X60.698 Y153.919 + G0 X60.198 Y153.919 + G0 X60.27 Y159.547 + M73 P96 + G0 X60.798 Y163.219 + G0 X60.798 Y163.719 + G1 X60.798 Y169.119 E127.86603 + G1 X64.198 Y169.119 E128.03565 + G1 X64.198 Y163.719 E128.30506 + G1 X60.798 Y163.719 E128.47469 + G0 X60.798 Y163.919 + G0 X60.298 Y163.919 + G0 X60.37 Y169.547 + G0 X60.898 Y173.219 + G0 X60.898 Y173.719 + G1 X60.898 Y179.119 E128.7441 + G1 X64.298 Y179.119 E128.91372 + G1 X64.298 Y173.719 E129.18313 + G1 X60.898 Y173.719 E129.35276 + G0 X60.898 Y173.919 + G0 X60.398 Y173.919 + G0 X60.47 Y179.547 + G0 X60.998 Y183.219 + G0 X60.998 Y183.719 + G1 X60.998 Y189.119 E129.62216 + G1 X64.398 Y189.119 E129.79179 + G1 X64.398 Y183.719 E130.0612 + G1 X60.998 Y183.719 E130.23082 + G0 X60.998 Y183.919 + G0 X60.498 Y183.919 + G0 X60.57 Y189.547 + M73 P97 + G0 X61.098 Y193.219 + G0 X61.098 Y193.719 + G1 X61.098 Y199.119 E130.50023 + G1 X64.498 Y199.119 E130.66986 + G1 X64.498 Y193.719 E130.93926 + G1 X61.098 Y193.719 E131.10889 + G0 X61.098 Y193.919 + G0 X60.598 Y193.919 + G0 X60.67 Y199.547 + G0 X61.198 Y203.219 + G0 X61.198 Y203.719 + G1 X61.198 Y209.119 E131.3783 + G1 X64.598 Y209.119 E131.54792 + G1 X64.598 Y203.719 E131.81733 + G1 X61.198 Y203.719 E131.98696 + G0 X61.198 Y203.919 + G0 X60.698 Y203.919 + G0 X60.77 Y209.547 + G0 X61.298 Y213.219 + G0 X61.298 Y213.719 + M73 P98 + G1 X61.298 Y219.119 E132.25637 + G1 X64.698 Y219.119 E132.42599 + G1 X64.698 Y213.719 E132.6954 + G1 X61.298 Y213.719 E132.86503 + G0 X61.298 Y213.919 + G0 X60.798 Y213.919 + G0 X60.508 Y212.929 + M73 P99 ;my G0 Z0.5 @@ -3910,12 +3927,13 @@ gcode: G90 T1 G92 E0 - M104 T0 S0 - M104 S{params.SECOND_E|default(230)} - M109 S{params.SECOND_E|default(230)} + M104 T0 S150 + M109 T0 S150 + M104 S{params.SECOND_E|default(250)} + M109 S{params.SECOND_E|default(250)} ;left-> rigth G92 E0 ;zero the extruded length again - G0 F1800 X211.298 Y51.419 + G0 F1800 X211.298 Y51.419 Z0.5 G0 F200 X31.298 Y51.419 E180 ; down -> up G1 F200 X31.298 Y216.419 E345 @@ -3927,6 +3945,7 @@ gcode: M73 P100 M82 ;absolute extrusion mode M104 S0 + G28 ;End of Gcode [gcode_macro SET_NOZZLE_OFFSET] @@ -3937,3 +3956,25 @@ gcode: {% set value = params.VALUE|default(8)|int %} {% set offset = 0.7 + 0.1 * (value - 1) * -1 %} SET_GCODE_VARIABLE MACRO=SET_NOZZLE_OFFSET VARIABLE=offset_{axis} VALUE={offset} + +[gcode_macro ADJUST_NOZZLE_OFFSET_Z] +gcode: + {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} + G28 A + M204 S500 + G0 C0.1 + G0 C0 + PROBE_TEMPLATE_POINT + MOVE_NOZZLE_OFFSET_Z + {% endif %} + +[gcode_macro MOVE_NOZZLE_OFFSET_Z] +gcode: + {% set point = printer.probe.last_result %} + {% set offsets = printer.probe.offsets %} + {% set x = 145 %} + {% set y = 240 %} + {% set z = point[2] - offsets[2] + 10 %} + G1 A0 + G1 X{x} Y{y} + G1 Z{z} diff --git a/stereotech_config/filament_control.cfg b/stereotech_config/filament_control.cfg index a03ead5f5671..6bc81265888a 100644 --- a/stereotech_config/filament_control.cfg +++ b/stereotech_config/filament_control.cfg @@ -1,45 +1,24 @@ [filament_motion_sensor extruder_sensor] extruder: extruder detection_length: 10.5 -event_delay: 60.0 +event_delay: 15.0 switch_pin: PG14 pause_on_runout: False runout_gcode: {% if printer.virtual_sdcard.is_active %} M117 trigered_filament_sensor0 - {action_respond_info('The filament has run out or there is a problem with its supply at the Extruder0.')} - PAUSE TURN_OFF_EXTRUDERS=0 E=0 - M400 - SET_STATE_TRY_EXTRUDE_FILAMENT SENSOR='extruder_sensor' ENABLE=1 - UPDATE_STATE_FILAMENT_RUNOUT_POSITION SENSOR='extruder_sensor' - G4 P1000 - TRY_DO_EXTRUDE SENSOR='extruder_sensor' - SET_STATE_TRY_EXTRUDE_FILAMENT SENSOR='extruder_sensor' ENABLE=0 - CHECK_FILAMENT_MOTION_SENSOR SENSOR='extruder_sensor' + {action_respond_warning('411: The filament has run out or there is a problem with its supply at the Extruder0.')} + RECOVER_EXTRUSION SENSOR='extruder_sensor' {% else %} FILAMENT_ERROR EXTRUDER=extruder {% endif %} -[gcode_macro TRY_DO_EXTRUDE] -variable_retries_count: 1 -gcode: - {% set sensor = params.SENSOR %} - {% if printer[printer.toolhead.extruder].can_extrude %} - M400 - M117 try_do_extrude - EXTRUDE_WITH_CURRENT_TEMP - M400 - EXTRUDE_WITH_COOLING_AND_HEATING SENSOR={sensor} - {% else %} - {action_respond_info('Extruder not heat enough!')} - {% endif %} - [gcode_macro FILAMENT_ERROR] gcode: {% if params.EXTRUDER == 'extruder' %} - {action_raise_error('Filament error on Extruder 1')} + {action_raise_error('401: Filament error on Extruder0')} {% else %} - {action_raise_error('Filament error on Extruder 2')} + {action_raise_error('402: Filament error on Extruder1')} {% endif %} [gcode_macro SET_FILAMENT_SENSOR] @@ -48,127 +27,162 @@ gcode: SET_FILAMENT_SENSOR_OLD SENSOR={params.SENSOR} ENABLE={params.ENABLE} SAVE_VARIABLE VARIABLE={params.SENSOR} VALUE={params.ENABLE} -[gcode_macro CHECK_FILAMENT_MOTION_SENSOR] +[gcode_macro RECOVER_EXTRUSION] +variable_enable_offset: 1 +variable_enable_prime: 1 +variable_enable_second_extruder: 0 +variable_count_trigered_sensor: 0 gcode: {% set sensor = params.SENSOR %} - {% set filament_detected = printer['filament_motion_sensor ' ~ sensor].filament_detected %} - {% if filament_detected %} - {action_respond_info('Extruding attempt completed successfully, resuming printing.')} - M117 resume_after_trigered_sensor - RESUME + {% if params.RESET %} + RECOVER_EXTRUSION_BY_OFFSET RESET=1 + RECOVER_EXTRUSION_BY_PRIME SENSOR={sensor} RESET=1 + {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_second_extruder %} + RECOVER_EXTRUSION_BY_SECOND_EXTRUDER RESET=1 + {% endif %} + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_offset VALUE=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_prime VALUE=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_second_extruder VALUE=0 + SET_PRINT_STATS_INFO COUNT_TRIGERED_SENSOR={printer["gcode_macro RECOVER_EXTRUSION"].count_trigered_sensor} + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=count_trigered_sensor VALUE=0 {% else %} - M117 failed_try_do_extrude - {action_respond_info('All extruding attempt completed failed.')} - {% if sensor == 'extruder_sensor' %} - SET_GCODE_VARIABLE MACRO=CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=triggered_extruder VALUE=0 - {% elif sensor == 'extruder1_sensor' %} - SET_GCODE_VARIABLE MACRO=CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=triggered_extruder VALUE=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=count_trigered_sensor VALUE={printer["gcode_macro RECOVER_EXTRUSION"].count_trigered_sensor + 1} + {% if printer.print_stats.info.current_layer == 0 and printer["gcode_macro RECOVER_EXTRUSION"].enable_offset and printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made < printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_count %} + {action_respond_warning('412: Recover extrusion by offset %s' % printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made)} + RECOVER_EXTRUSION_BY_OFFSET SENSOR={sensor} + {% else %} + {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_offset %} + RECOVER_EXTRUSION_BY_OFFSET RESET=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_offset VALUE=0 + {% endif %} + {% if not printer.pause_resume.is_paused %} + PAUSE TURN_OFF_EXTRUDERS=0 E=0 + {% endif %} + {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_prime and (printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made < printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].check_count or printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].use_cooldown) %} + RECOVER_EXTRUSION_BY_PRIME SENSOR={sensor} + {% else %} + {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_prime %} + RECOVER_EXTRUSION_BY_PRIME SENSOR={sensor} RESET=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_prime VALUE=0 + {% endif %} + {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_second_extruder and sensor == 'extruder_sensor' and printer["filament_motion_sensor extruder1_sensor"] and not printer["gcode_macro RECOVER_EXTRUSION_BY_SECOND_EXTRUDER"].enabled %} + RECOVER_EXTRUSION_BY_SECOND_EXTRUDER + {% else %} + {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_second_extruder and sensor == 'extruder_sensor' %} + {action_respond_warning('413: Switch to second extruder and resume printing.')} + RECOVER_EXTRUSION_BY_SECOND_EXTRUDER RESET=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_second_extruder VALUE=0 + {% endif %} + #Set timeout and wait for user + {action_respond_warning('414: All attempt to extrude failed.')} + M117 all_attempt_extrude_failed + UPDATE_DELAYED_GCODE ID=TURN_OFF_EXTRUDERS_DELAYED DURATION=300 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_offset VALUE=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_prime VALUE=1 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_second_extruder VALUE=0 + {% endif %} + {% endif %} {% endif %} - UPDATE_DELAYED_GCODE ID=CHECK_PRINT_CONTINUE_DELAYED DURATION=300 {% endif %} -[delayed_gcode CHECK_PRINT_CONTINUE_DELAYED] +[delayed_gcode RECOVER_EXTRUSION_DELAY] gcode: - ; checking the printer state is pause, maybe user resumed printing - {% if printer.pause_resume.is_paused %} - {% if printer["gcode_macro CONTINUE_PRINT_WITH_EXTRUDER"].enabled|int > 0 %} - {action_respond_info('Function "continue printing with another extruder" is enabled')} - CONTINUE_PRINT_WITH_EXTRUDER + RECOVER_EXTRUSION SENSOR='extruder_sensor' + +[gcode_macro RECOVER_EXTRUSION_BY_OFFSET] +variable_check_count: 3 +variable_checks_made: 0 +variable_check_value: 0.1 +gcode: + {% set sensor = params.SENSOR %} + {% if params.RESET %} + {% set reset_value = printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_value * printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made %} + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_OFFSET VARIABLE=checks_made VALUE=0 + {% if printer.gcode_move.current_wcs == 0 %} + SET_GCODE_OFFSET Z_ADJUST=-{reset_value} MOVE=1 + {% else %} + G10 L2 P0 R1 Z-{reset_value} + {% endif %} + {% else %} + M117 recover_extrusion_by_offset_attempt_{printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made + 1} + {% if printer.gcode_move.current_wcs == 0 %} + SET_GCODE_OFFSET Z_ADJUST={printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_value} MOVE=1 {% else %} - {action_respond_info('Function "continue printing with another extruder" is disabled. Turn off all extruder')} - TURN_OFF_EXTRUDERS + G10 L2 P0 R1 Z{printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_value} {% endif %} + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_OFFSET VARIABLE=checks_made VALUE={printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made + 1} + UPDATE_STATE_FILAMENT_RUNOUT_POSITION SENSOR={sensor} {% endif %} -[gcode_macro CONTINUE_PRINT_WITH_EXTRUDER] -variable_enabled: 0 -variable_triggered_extruder: -1 +[gcode_macro RECOVER_EXTRUSION_BY_PRIME] +variable_check_count: 3 +variable_checks_made: 0 +variable_use_cooldown: 1 gcode: - ; checked what the printer name is hybrid(get objekt extruder1_sensor). - {% if printer.pause_resume.is_paused and printer["filament_motion_sensor extruder1_sensor"] %} - {% set triggered_extruder = printer["gcode_macro CONTINUE_PRINT_WITH_EXTRUDER"].triggered_extruder|int %} - {% if triggered_extruder == 0 %} - {action_respond_info('Printing continued with extruder 2.')} - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=current_extruder VALUE=1 - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder1_temp VALUE={printer["gcode_macro PAUSE"].extruder_temp} - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE=0 - SET_GCODE_VARIABLE MACRO=SET_CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=needed_set VALUE=1 - RESUME - {% elif triggered_extruder == 1 %} - {action_respond_info('Continue printing with extruder0 fails because this function is not available.')} - {action_respond_info('Turn off all extruder')} - TURN_OFF_EXTRUDERS - SET_GCODE_VARIABLE MACRO=CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=triggered_extruder VALUE=-1 + {% set sensor = params.SENSOR %} + {% set extruder = 'extruder' if sensor == 'extruder_sensor' else 'extruder1' %} + {% if params.RESET %} + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=checks_made VALUE=0 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=use_cooldown VALUE=1 + {% else %} + {% if printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].use_cooldown and printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made >= printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].check_count %} + {% set extruder_temp = printer["gcode_macro PAUSE"].extruder_temp if extruder == 'extruder' else printer["gcode_macro PAUSE"].extruder1_temp %} + {action_respond_warning('415: Recover extrusion after cooling and heating.')} + M106 S255 + M109 S50 + M107 + M109 S{extruder_temp} + M400 + G4 P3000 + LOAD_MATERIAL + LOAD_MATERIAL + M400 + G4 P3000 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=use_cooldown VALUE=0 + CHECK_FILAMENT_MOTION_SENSOR SENSOR={sensor} {% else %} - {action_respond_info('Turn off all extruder')} - TURN_OFF_EXTRUDERS + {action_respond_warning('416: Recover extrusion do extrude attempt %s' % printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made)} + M117 try_do_extrude_{printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made + 1} + M400 + G4 P3000 + LOAD_MATERIAL + LOAD_MATERIAL + M400 + G4 P3000 + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=checks_made VALUE={printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made + 1} + CHECK_FILAMENT_MOTION_SENSOR SENSOR={sensor} {% endif %} {% endif %} -[gcode_macro RESET_CONTINUE_PRINT_WITH_EXTRUDER] -variable_needed_reset: 0 +[gcode_macro CHECK_FILAMENT_MOTION_SENSOR] gcode: - {% if printer["gcode_macro RESET_CONTINUE_PRINT_WITH_EXTRUDER"].needed_reset > 0 %} - {action_respond_info('Reset offset.')} - SET_GCODE_OFFSET X_ADJUST=25.0 MOVE=1 - ENABLE_CONSTRAIN ENABLE=0 - SET_GCODE_VARIABLE MACRO=SET_CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=needed_set VALUE=1 - SET_GCODE_VARIABLE MACRO=RESET_CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=needed_reset VALUE=0 - {% endif %} - {% if params.RESET_VARIABLES|default(0) > 0 %} - {action_respond_info('Reset variable.')} - SET_GCODE_VARIABLE MACRO=CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=enabled VALUE=0 - SET_GCODE_VARIABLE MACRO=CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=triggered_extruder VALUE=-1 - SET_GCODE_VARIABLE MACRO=SET_CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=needed_set VALUE=0 - SET_GCODE_VARIABLE MACRO=RESET_CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=needed_reset VALUE=0 + {% set sensor = params.SENSOR %} + {% set filament_detected = printer['filament_motion_sensor ' ~ sensor].filament_detected %} + {% if filament_detected %} + {action_respond_warning('417: Extruding attempt completed successfully, resuming printing.')} + M117 resume_after_trigered_sensor + RESUME + {% else %} + UPDATE_DELAYED_GCODE ID=RECOVER_EXTRUSION_DELAY DURATION=1 {% endif %} -[gcode_macro SET_CONTINUE_PRINT_WITH_EXTRUDER] -variable_needed_set: 0 +[gcode_macro RECOVER_EXTRUSION_BY_SECOND_EXTRUDER] +variable_enabled: 0 gcode: - {% if printer["gcode_macro SET_CONTINUE_PRINT_WITH_EXTRUDER"].needed_set|int > 0 %} - {action_respond_info('An offset is set to continue printing on another extruder.')} + {% if params.RESET and printer["gcode_macro RECOVER_EXTRUSION_BY_SECOND_EXTRUDER"].enabled %} + SET_GCODE_OFFSET X_ADJUST=25.0 MOVE=1 + ENABLE_CONSTRAIN ENABLE=0 + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=current_extruder VALUE=0 + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder1_temp VALUE=0 + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE={printer["gcode_macro PAUSE"].extruder_temp} + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_SECOND_EXTRUDER VARIABLE=enabled VALUE=0 + {% else %} + M117 resume_print_another_extruder + SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_SECOND_EXTRUDER VARIABLE=enabled VALUE=1 SET_GCODE_OFFSET X_ADJUST=-25.0 MOVE=1 - ;if an offset is added, movement beyond coord_min is possible, you need to enable the coordinate limit for movement in the tolhead module ENABLE_CONSTRAIN ENABLE=1 - SET_GCODE_VARIABLE MACRO=RESET_CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=needed_reset VALUE=1 - SET_GCODE_VARIABLE MACRO=SET_CONTINUE_PRINT_WITH_EXTRUDER VARIABLE=needed_set VALUE=0 - {% endif %} - -[gcode_macro EXTRUDE_WITH_CURRENT_TEMP] -description: Trying to extrude the filament. -gcode: - {% for attempt in range(printer["gcode_macro TRY_DO_EXTRUDE"].retries_count|int) %} - {action_respond_info('Attempt to extrude the filament.')} - G91 - G0 E25 F600 - G90 - {% endfor %} - -[gcode_macro EXTRUDE_WITH_COOLING_AND_HEATING] -description: Trying to extrude the filament after the extruder has cooled down. -gcode: - {% set sensor = params.SENSOR %} - {% set filament_detected = printer['filament_motion_sensor ' ~ sensor].filament_detected %} - {% if not filament_detected %} - {action_respond_info('Attempt to extrude the filament is failed.')} - {% if sensor == 'extruder_sensor' %} - {action_respond_info('Cooling and heat extruder0.')} - {% set temp_extruder = printer["gcode_macro PAUSE"].extruder_temp|int %} - M117 cooling_extruder - M109 T0 S50 - M117 heat_extruder - M109 T0 S{temp_extruder} - {% elif sensor == 'extruder1_sensor' %} - {action_respond_info('Cooling and heat extruder1.')} - {% set temp_extruder = printer["gcode_macro PAUSE"].extruder1_temp|int %} - M117 cooling_extruder - M109 T1 S50 - M117 heat_extruder - M109 T1 S{temp_extruder} - {% endif %} - UPDATE_STATE_FILAMENT_RUNOUT_POSITION SENSOR={sensor} - EXTRUDE_WITH_CURRENT_TEMP - M400 + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=current_extruder VALUE=1 + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder1_temp VALUE={printer["gcode_macro PAUSE"].extruder_temp} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE=0 + RESUME {% endif %} - G4 P2000 diff --git a/stereotech_config/filament_control_2.cfg b/stereotech_config/filament_control_2.cfg deleted file mode 100644 index c4c573239422..000000000000 --- a/stereotech_config/filament_control_2.cfg +++ /dev/null @@ -1,174 +0,0 @@ -[filament_motion_sensor extruder_sensor] -extruder: extruder -detection_length: 10.5 -event_delay: 15.0 -switch_pin: PG14 -pause_on_runout: False -runout_gcode: - {% if printer.virtual_sdcard.is_active %} - M117 trigered_filament_sensor0 - {action_respond_info('The filament has run out or there is a problem with its supply at the Extruder0.')} - RECOVER_EXTRUSION SENSOR='extruder_sensor' - {% else %} - FILAMENT_ERROR EXTRUDER=extruder - {% endif %} - -[gcode_macro FILAMENT_ERROR] -gcode: - {% if params.EXTRUDER == 'extruder' %} - {action_raise_error('Filament error on Extruder 1')} - {% else %} - {action_raise_error('Filament error on Extruder 2')} - {% endif %} - -[gcode_macro SET_FILAMENT_SENSOR] -rename_existing: SET_FILAMENT_SENSOR_OLD -gcode: - SET_FILAMENT_SENSOR_OLD SENSOR={params.SENSOR} ENABLE={params.ENABLE} - SAVE_VARIABLE VARIABLE={params.SENSOR} VALUE={params.ENABLE} - -[gcode_macro RECOVER_EXTRUSION] -variable_enable_offset: 1 -variable_enable_prime: 1 -variable_enable_second_extruder: 0 -gcode: - {% set sensor = params.SENSOR %} - {% if params.RESET %} - RECOVER_EXTRUSION_BY_OFFSET RESET=1 - RECOVER_EXTRUSION_BY_PRIME SENSOR={sensor} RESET=1 - {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_second_extruder %} - RECOVER_EXTRUSION_BY_SECOND_EXTRUDER RESET=1 - {% endif %} - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_offset VALUE=1 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_prime VALUE=1 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_second_extruder VALUE=0 - {% else %} - {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_offset and printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made < printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_count %} - RECOVER_EXTRUSION_BY_OFFSET - {% else %} - {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_offset %} - RECOVER_EXTRUSION_BY_OFFSET RESET=1 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_offset VALUE=0 - {% endif %} - {% if not printer.pause_resume.is_paused %} - PAUSE TURN_OFF_EXTRUDERS=0 E=0 - {% endif %} - {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_prime and (printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made < printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].check_count or printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].use_cooldown) %} - RECOVER_EXTRUSION_BY_PRIME SENSOR={sensor} - {% else %} - {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_prime %} - RECOVER_EXTRUSION_BY_PRIME SENSOR={sensor} RESET=1 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_prime VALUE=0 - {% endif %} - {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_second_extruder and sensor == 'extruder_sensor' and printer["filament_motion_sensor extruder1_sensor"] and not printer["gcode_macro RECOVER_EXTRUSION_BY_SECOND_EXTRUDER"].enabled %} - RECOVER_EXTRUSION_BY_SECOND_EXTRUDER - {% else %} - {% if printer["gcode_macro RECOVER_EXTRUSION"].enable_second_extruder and sensor == 'extruder_sensor' %} - RECOVER_EXTRUSION_BY_SECOND_EXTRUDER RESET=1 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_second_extruder VALUE=0 - {% endif %} - #Set timeout and wait for user - UPDATE_DELAYED_GCODE ID=TURN_OFF_EXTRUDERS_DELAYED DURATION=300 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_offset VALUE=1 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_prime VALUE=1 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION VARIABLE=enable_second_extruder VALUE=0 - {% endif %} - {% endif %} - {% endif %} - {% endif %} - -[delayed_gcode RECOVER_EXTRUSION_DELAY] -gcode: - RECOVER_EXTRUSION SENSOR='extruder_sensor' - -[gcode_macro RECOVER_EXTRUSION_BY_OFFSET] -variable_check_count: 3 -variable_checks_made: 0 -variable_check_value: 0.1 -gcode: - {% if params.RESET %} - {% set reset_value = printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_value * printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made %} - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_OFFSET VARIABLE=checks_made VALUE=0 - {% if printer.gcode_move.current_wcs == 0 %} - SET_GCODE_OFFSET Z_ADJUST=-{reset_value} MOVE=1 - {% else %} - G10 L2 P0 R1 Z-{reset_value} - {% endif %} - {% else %} - {% if printer.gcode_move.current_wcs == 0 %} - SET_GCODE_OFFSET Z_ADJUST={printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_value} MOVE=1 - {% else %} - G10 L2 P0 R1 Z{printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].check_value} - {% endif %} - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_OFFSET VARIABLE=checks_made VALUE={printer["gcode_macro RECOVER_EXTRUSION_BY_OFFSET"].checks_made + 1} - {% endif %} - -[gcode_macro RECOVER_EXTRUSION_BY_PRIME] -variable_check_count: 3 -variable_checks_made: 0 -variable_use_cooldown: 1 -gcode: - {% set sensor = params.SENSOR %} - {% set extruder = 'extruder' if sensor == 'extruder_sensor' else 'extruder1' %} - {% if params.RESET %} - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=checks_made VALUE=0 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=use_cooldown VALUE=1 - {% else %} - {% if printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].use_cooldown and printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made >= printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].check_count %} - {% set extruder_temp = printer["gcode_macro PAUSE"].extruder_temp if extruder == 'extruder' else printer["gcode_macro PAUSE"].extruder1_temp %} - M117 cooling_extruder - M106 S255 - M109 S50 - M107 - M117 heat_extruder - M109 S{extruder_temp} - M400 - G4 P3000 - LOAD_MATERIAL - LOAD_MATERIAL - M400 - G4 P3000 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=use_cooldown VALUE=0 - CHECK_FILAMENT_MOTION_SENSOR SENSOR={sensor} - {% else %} - M400 - G4 P3000 - LOAD_MATERIAL - LOAD_MATERIAL - M400 - G4 P3000 - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_PRIME VARIABLE=checks_made VALUE={printer["gcode_macro RECOVER_EXTRUSION_BY_PRIME"].checks_made + 1} - CHECK_FILAMENT_MOTION_SENSOR SENSOR={sensor} - {% endif %} - {% endif %} - -[gcode_macro CHECK_FILAMENT_MOTION_SENSOR] -gcode: - {% set sensor = params.SENSOR %} - {% set filament_detected = printer['filament_motion_sensor ' ~ sensor].filament_detected %} - {% if filament_detected %} - {action_respond_info('Extruding attempt completed successfully, resuming printing.')} - RESUME - {% else %} - UPDATE_DELAYED_GCODE ID=RECOVER_EXTRUSION_DELAY DURATION=1 - {% endif %} - -[gcode_macro RECOVER_EXTRUSION_BY_SECOND_EXTRUDER] -variable_enabled: 0 -gcode: - {% if params.RESET and printer["gcode_macro RECOVER_EXTRUSION_BY_SECOND_EXTRUDER"].enabled %} - SET_GCODE_OFFSET X_ADJUST=25.0 MOVE=1 - ENABLE_CONSTRAIN ENABLE=0 - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=current_extruder VALUE=0 - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder1_temp VALUE=0 - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE={printer["gcode_macro PAUSE"].extruder_temp} - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_SECOND_EXTRUDER VARIABLE=enabled VALUE=0 - {% else %} - SET_GCODE_VARIABLE MACRO=RECOVER_EXTRUSION_BY_SECOND_EXTRUDER VARIABLE=enabled VALUE=1 - SET_GCODE_OFFSET X_ADJUST=-25.0 MOVE=1 - ENABLE_CONSTRAIN ENABLE=1 - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=current_extruder VALUE=1 - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder1_temp VALUE={printer["gcode_macro PAUSE"].extruder_temp} - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE=0 - RESUME - {% endif %} diff --git a/stereotech_config/filament_control_second.cfg b/stereotech_config/filament_control_second.cfg index 1d10d7245244..8b4115062902 100644 --- a/stereotech_config/filament_control_second.cfg +++ b/stereotech_config/filament_control_second.cfg @@ -1,21 +1,14 @@ [filament_motion_sensor extruder1_sensor] extruder: extruder1 detection_length: 10.5 -event_delay: 60.0 +event_delay: 15.0 switch_pin: PG15 pause_on_runout: False runout_gcode: {% if printer.virtual_sdcard.is_active %} M117 trigered_filament_sensor1 - {action_respond_info('The filament has run out or there is a problem with its supply at the Extruder2.')} - PAUSE TURN_OFF_EXTRUDERS=0 E=0 - M400 - SET_STATE_TRY_EXTRUDE_FILAMENT SENSOR='extruder1_sensor' ENABLE=1 - UPDATE_STATE_FILAMENT_RUNOUT_POSITION SENSOR='extruder1_sensor' - G4 P1000 - TRY_DO_EXTRUDE SENSOR='extruder1_sensor' - SET_STATE_TRY_EXTRUDE_FILAMENT SENSOR='extruder1_sensor' ENABLE=0 - CHECK_FILAMENT_MOTION_SENSOR SENSOR='extruder1_sensor' + {action_respond_warning('411: The filament has run out or there is a problem with its supply at the Extruder2.')} + RECOVER_EXTRUSION SENSOR='extruder1_sensor' {% else %} FILAMENT_ERROR EXTRUDER=extruder1 {% endif %} diff --git a/stereotech_config/filament_control_second_2.cfg b/stereotech_config/filament_control_second_2.cfg deleted file mode 100644 index 02c06d683567..000000000000 --- a/stereotech_config/filament_control_second_2.cfg +++ /dev/null @@ -1,14 +0,0 @@ -[filament_motion_sensor extruder1_sensor] -extruder: extruder1 -detection_length: 10.5 -event_delay: 15.0 -switch_pin: PG15 -pause_on_runout: False -runout_gcode: - {% if printer.virtual_sdcard.is_active %} - M117 trigered_filament_sensor1 - {action_respond_info('The filament has run out or there is a problem with its supply at the Extruder2.')} - RECOVER_EXTRUSION SENSOR='extruder1_sensor' - {% else %} - FILAMENT_ERROR EXTRUDER=extruder1 - {% endif %} diff --git a/stereotech_config/homing.cfg b/stereotech_config/homing.cfg index 5f1d765b2773..33e0dbf163d6 100644 --- a/stereotech_config/homing.cfg +++ b/stereotech_config/homing.cfg @@ -1,4 +1,5 @@ [homing_override] +rotate_a: true axes: gcode: G28 Z @@ -98,12 +99,12 @@ gcode: CUT_FIBER G1 E-{e} F1200 {% else %} - {action_respond_info("Extruder not hot enough")} + {action_respond_warning("611: Extruder not hot enough.")} {% endif %} {% if "xyz" in printer.toolhead.homed_axes %} G1 Z{z_safe} F3600 G90 G1 X{x} Y{y} F3600 {% else %} - {action_respond_info("Printer not homed")} + {action_respond_warning("815: Printer not homed.")} {% endif %} diff --git a/stereotech_config/kinematics_300.cfg b/stereotech_config/kinematics_300.cfg index 27bdafd9f489..406241975bf8 100644 --- a/stereotech_config/kinematics_300.cfg +++ b/stereotech_config/kinematics_300.cfg @@ -3,7 +3,7 @@ kinematics: corexy_6axis max_velocity: 200 max_accel: 1500 max_z_velocity: 20 -max_z_accel: 200 +max_z_accel: 100 [stepper_x] step_pin: x_step_pin diff --git a/stereotech_config/kinematics_300_2.cfg b/stereotech_config/kinematics_300_2.cfg index d28651051e1e..117540f0ee0b 100644 --- a/stereotech_config/kinematics_300_2.cfg +++ b/stereotech_config/kinematics_300_2.cfg @@ -2,8 +2,8 @@ kinematics: corexy_6axis max_velocity: 200 max_accel: 1500 -max_z_velocity: 40 -max_z_accel: 500 +max_z_velocity: 30 +max_z_accel: 100 square_corner_velocity: 2.5 [stepper_x] diff --git a/stereotech_config/kinematics_300_3.cfg b/stereotech_config/kinematics_300_3.cfg new file mode 100644 index 000000000000..f8dd7a78c15a --- /dev/null +++ b/stereotech_config/kinematics_300_3.cfg @@ -0,0 +1,66 @@ +[printer] +kinematics: corexy_6axis +max_velocity: 200 +max_accel: 1500 +max_z_velocity: 30 +max_z_accel: 100 +square_corner_velocity: 2.5 + +[stepper_x] +step_pin: x_step_pin +dir_pin: !x_dir_pin +enable_pin: !x_en_pin +microsteps: 128 +rotation_distance: 40 +endstop_pin: x_endstop_pin +position_endstop: 309 +position_max: 309 +position_min: -1 +homing_speed: 70 + +[stepper_y] +step_pin: y_step_pin +dir_pin: !y_dir_pin +enable_pin: !y_en_pin +microsteps: 128 +rotation_distance: 40 +endstop_pin: y_endstop_pin +position_endstop: 300.3 +position_max: 300.3 +position_min: 0 +homing_speed: 70 + +[stepper_z] +step_pin: z_step_pin +dir_pin: !z_dir_pin +enable_pin: !z_en_pin +microsteps: 128 +rotation_distance: 2 +endstop_pin: z_endstop_pin +position_endstop: 300 +position_max: 300 +position_min: -10 +homing_speed: 20 + +[stepper_a] +step_pin: a_step_pin +dir_pin: a_dir_pin +enable_pin: !a_en_pin +microsteps: 128 +rotation_distance: 360 +gear_ratio: 80:20 +endstop_pin: a_endstop_pin +position_endstop: 90 +position_min: -10 +position_max: 90 +homing_speed: 20 + +[stepper_c] +step_pin: c_step_pin +dir_pin: c_dir_pin +enable_pin: !c_en_pin +microsteps: 128 +rotation_distance: 120 +gear_ratio: 80:20 +can_home: false +homing_speed: 20 diff --git a/stereotech_config/main_extruder.cfg b/stereotech_config/main_extruder.cfg index 96bdf1b54b51..03f2f943fbf0 100644 --- a/stereotech_config/main_extruder.cfg +++ b/stereotech_config/main_extruder.cfg @@ -7,7 +7,7 @@ rotation_distance: 7.777 nozzle_diameter: 0.4 filament_diameter: 1.75 heater_pin: main_extruder_heater_pin -sensor_type: EPCOS 100K B57560G104F +sensor_type: NTC 100K MGB18-104F39050L32 sensor_pin: main_extruder_sensor_pin control: pid pid_Kp: 13.509 @@ -18,6 +18,7 @@ max_temp: 320 min_extrude_temp: 100 max_extrude_only_distance: 300.0 max_extrude_cross_section: 2.56 +fiber: false [gcode_macro T0] gcode: @@ -27,8 +28,9 @@ gcode: SET_GCODE_VARIABLE MACRO=T1 VARIABLE=t1_offset_enabled VALUE=0 {% endif %} {% set current_wcs = printer.gcode_move.current_wcs %} - {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder' %} + {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and "z" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder' %} G54 + MOVE_DOWN_Z_AXIS Z=5 G0 X10 Y2 F3600 {% endif %} ACTIVATE_EXTRUDER extruder=extruder diff --git a/stereotech_config/mcu/stm32f446.config b/stereotech_config/mcu/stm32f446.config index cb6d9ec58bea..eff7ca988d25 100644 --- a/stereotech_config/mcu/stm32f446.config +++ b/stereotech_config/mcu/stm32f446.config @@ -28,6 +28,7 @@ CONFIG_STM32_SELECT=y # CONFIG_MACH_STM32F407 is not set # CONFIG_MACH_STM32F429 is not set CONFIG_MACH_STM32F446=y +# CONFIG_MACH_STM32F765 is not set # CONFIG_MACH_STM32F031 is not set # CONFIG_MACH_STM32F042 is not set # CONFIG_MACH_STM32F070 is not set @@ -55,6 +56,7 @@ CONFIG_STM32_FLASH_START_8000=y CONFIG_STM32_CLOCK_REF_12M=y # CONFIG_STM32_CLOCK_REF_16M is not set # CONFIG_STM32_CLOCK_REF_20M is not set +# CONFIG_STM32_CLOCK_REF_24M is not set # CONFIG_STM32_CLOCK_REF_25M is not set # CONFIG_STM32_CLOCK_REF_INTERNAL is not set CONFIG_CLOCK_REF_FREQ=12000000 @@ -85,7 +87,12 @@ CONFIG_USB_SERIAL_NUMBER="12345" # # end of USB ids -CONFIG_CANBUS_FREQUENCY=500000 +CONFIG_WANT_GPIO_BITBANGING=y +CONFIG_WANT_DISPLAYS=y +CONFIG_WANT_SENSORS=y +CONFIG_WANT_SOFTWARE_I2C=y +CONFIG_WANT_SOFTWARE_SPI=y +CONFIG_CANBUS_FREQUENCY=1000000 CONFIG_INITIAL_PINS="" CONFIG_HAVE_GPIO=y CONFIG_HAVE_GPIO_ADC=y @@ -93,7 +100,6 @@ CONFIG_HAVE_GPIO_SPI=y CONFIG_HAVE_GPIO_SDIO=y CONFIG_HAVE_GPIO_I2C=y CONFIG_HAVE_GPIO_HARD_PWM=y -CONFIG_HAVE_GPIO_BITBANGING=y CONFIG_HAVE_STRICT_TIMING=y CONFIG_HAVE_CHIPID=y CONFIG_HAVE_STEPPER_BOTH_EDGE=y diff --git a/stereotech_config/mcu/stm32g0b1.config b/stereotech_config/mcu/stm32g0b1.config index 3047da0942d0..16800d568efd 100644 --- a/stereotech_config/mcu/stm32g0b1.config +++ b/stereotech_config/mcu/stm32g0b1.config @@ -1,4 +1,4 @@ -# CONFIG_LOW_LEVEL_OPTIONS is not set +CONFIG_LOW_LEVEL_OPTIONS=y # CONFIG_MACH_AVR is not set # CONFIG_MACH_ATSAM is not set # CONFIG_MACH_ATSAMD is not set @@ -28,6 +28,7 @@ CONFIG_STM32_SELECT=y # CONFIG_MACH_STM32F407 is not set # CONFIG_MACH_STM32F429 is not set # CONFIG_MACH_STM32F446 is not set +# CONFIG_MACH_STM32F765 is not set # CONFIG_MACH_STM32F031 is not set # CONFIG_MACH_STM32F042 is not set # CONFIG_MACH_STM32F070 is not set @@ -41,6 +42,8 @@ CONFIG_MACH_STM32G0B1=y # CONFIG_MACH_STM32H743 is not set # CONFIG_MACH_STM32H750 is not set # CONFIG_MACH_STM32L412 is not set +# CONFIG_MACH_N32G452 is not set +# CONFIG_MACH_N32G455 is not set CONFIG_MACH_STM32G0=y CONFIG_MACH_STM32G0Bx=y CONFIG_HAVE_STM32_USBFS=y @@ -49,12 +52,28 @@ CONFIG_HAVE_STM32_USBCANBUS=y CONFIG_STM32_DFU_ROM_ADDRESS=0x1fff0000 CONFIG_STM32_FLASH_START_2000=y # CONFIG_STM32_FLASH_START_0000 is not set +CONFIG_STM32_CLOCK_REF_8M=y +# CONFIG_STM32_CLOCK_REF_12M is not set +# CONFIG_STM32_CLOCK_REF_16M is not set +# CONFIG_STM32_CLOCK_REF_20M is not set +# CONFIG_STM32_CLOCK_REF_24M is not set +# CONFIG_STM32_CLOCK_REF_25M is not set +# CONFIG_STM32_CLOCK_REF_INTERNAL is not set CONFIG_CLOCK_REF_FREQ=8000000 CONFIG_STM32F0_TRIM=16 CONFIG_STM32_USB_PA11_PA12=y # CONFIG_STM32_SERIAL_USART1 is not set +# CONFIG_STM32_SERIAL_USART1_ALT_PB7_PB6 is not set +# CONFIG_STM32_SERIAL_USART2 is not set +# CONFIG_STM32_SERIAL_USART2_ALT_PD6_PD5 is not set +# CONFIG_STM32_SERIAL_USART3 is not set +# CONFIG_STM32_SERIAL_USART3_ALT_PD9_PD8 is not set +# CONFIG_STM32_SERIAL_USART5 is not set # CONFIG_STM32_CANBUS_PA11_PA12 is not set # CONFIG_STM32_CANBUS_PA11_PB9 is not set +# CONFIG_STM32_MMENU_CANBUS_PB8_PB9 is not set +# CONFIG_STM32_MMENU_CANBUS_PB12_PB13 is not set +# CONFIG_STM32_MMENU_CANBUS_PD0_PD1 is not set # CONFIG_STM32_MMENU_CANBUS_PB0_PB1 is not set # CONFIG_STM32_MMENU_CANBUS_PD12_PD13 is not set # CONFIG_STM32_MMENU_CANBUS_PC2_PC3 is not set @@ -64,13 +83,24 @@ CONFIG_USB_VENDOR_ID=0x1d50 CONFIG_USB_DEVICE_ID=0x614e CONFIG_USB_SERIAL_NUMBER_CHIPID=y CONFIG_USB_SERIAL_NUMBER="12345" -CONFIG_CANBUS_FREQUENCY=500000 + +# +# USB ids +# +# end of USB ids + +CONFIG_WANT_GPIO_BITBANGING=y +CONFIG_WANT_DISPLAYS=y +CONFIG_WANT_SENSORS=y +CONFIG_WANT_SOFTWARE_I2C=y +CONFIG_WANT_SOFTWARE_SPI=y +CONFIG_CANBUS_FREQUENCY=1000000 +CONFIG_INITIAL_PINS="" CONFIG_HAVE_GPIO=y CONFIG_HAVE_GPIO_ADC=y CONFIG_HAVE_GPIO_SPI=y CONFIG_HAVE_GPIO_I2C=y CONFIG_HAVE_GPIO_HARD_PWM=y -CONFIG_HAVE_GPIO_BITBANGING=y CONFIG_HAVE_STRICT_TIMING=y CONFIG_HAVE_CHIPID=y CONFIG_HAVE_STEPPER_BOTH_EDGE=y diff --git a/stereotech_config/module_3d_300.cfg b/stereotech_config/module_3d_300.cfg index b4054d106604..5d9012d5feb9 100644 --- a/stereotech_config/module_3d_300.cfg +++ b/stereotech_config/module_3d_300.cfg @@ -14,4 +14,4 @@ horizontal_move_z: 10.0 screw1: 159,275 screw1_fine_adjust: 159,0 screw2: 20,0 -screw3: 282,0 +screw3: 269,0 diff --git a/stereotech_config/nozzle_offset.cfg b/stereotech_config/nozzle_offset.cfg index 0985abdc1c4d..3ede205298ec 100644 --- a/stereotech_config/nozzle_offset.cfg +++ b/stereotech_config/nozzle_offset.cfg @@ -208,3 +208,25 @@ gcode: {% set value = params.VALUE|default(8)|int %} {% set offset = -0.7 + 0.1 * (value - 1) %} SET_GCODE_VARIABLE MACRO=SET_NOZZLE_OFFSET VARIABLE=offset_{axis} VALUE={offset} + +[gcode_macro ADJUST_NOZZLE_OFFSET_Z] +gcode: + {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} + G28 A + M204 S500 + G0 C0.1 + G0 C0 + PROBE_TEMPLATE_POINT + MOVE_NOZZLE_OFFSET_Z + {% endif %} + +[gcode_macro MOVE_NOZZLE_OFFSET_Z] +gcode: + {% set point = printer.probe.last_result %} + {% set offsets = printer.probe.offsets %} + {% set x = 145 %} + {% set y = 240 %} + {% set z = point[2] - offsets[2] + 10 %} + G1 A0 + G1 X{x} Y{y} + G1 Z{z} diff --git a/stereotech_config/power_control.cfg b/stereotech_config/power_control.cfg index e377cc47bea4..5e6359cdb44e 100644 --- a/stereotech_config/power_control.cfg +++ b/stereotech_config/power_control.cfg @@ -11,10 +11,9 @@ press_gcode: extruder_temp=printer.extruder.target, extruder=printer.toolhead.extruder )} - {% else %} - POWER_OFF {% endif %} - + POWER_OFF + [output_pin power_pin] pin: !PE11 diff --git a/stereotech_config/print_macros.cfg b/stereotech_config/print_macros.cfg index d092f1f9333a..de5e81c3f8f1 100644 --- a/stereotech_config/print_macros.cfg +++ b/stereotech_config/print_macros.cfg @@ -8,110 +8,118 @@ variable_extruder1_temp: 0 variable_current_extruder: 0 variable_fan_speed: 0 gcode: - ENABLE_CONSTRAIN ENABLE=0 - {% if printer.toolhead.axis_maximum[0] > 250 %} - {% set x = params.X|default(300) %} - {% set y = params.Y|default(10) %} - {% else %} - {% set x = params.X|default(200) %} - {% set y = params.Y|default(10) %} - {% endif %} - {% set z = params.Z|default(50)|float %} - {% set e = params.E|default(3) %} - {% set turn_off_extruders = params.TURN_OFF_EXTRUDERS|default(1)|int %} - {% set max_z = printer.toolhead.axis_maximum.z|float %} - {% set act_z = printer.toolhead.position.z|float %} - {% set lift_z = z|abs %} - {% set fan_speed = printer.fan.speed * 255 | int %} - {% if act_z < (max_z - lift_z) %} - {% set z_safe = lift_z %} - {% else %} - {% set z_safe = max_z - act_z %} - {% endif %} - {% if z_safe < 0 %} - {% set z_safe = 0 %} - {% endif %} - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE={printer.extruder.target} - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder1_temp VALUE={printer.extruder1.target} - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=fan_speed VALUE={fan_speed} - {% set current_extruder = 0 %} - {% if printer.toolhead.extruder == 'extruder1' %} - {% set current_extruder = 1 %} - {% endif %} - SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=current_extruder VALUE={current_extruder} - {% if turn_off_extruders > 0 and printer["filament_motion_sensor extruder_sensor"] %} - UPDATE_DELAYED_GCODE ID=TURN_OFF_EXTRUDERS_DELAYED DURATION=300 - {% endif %} - SET_IDLE_TIMEOUT TIMEOUT=360000 - PAUSE_BASE - STATUS_LED STATUS=paused - {% if printer.probe %} - {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} - BED_MESH_CLEAR - ;SET_SKEW ENABLE=0 + {% if not printer.pause_resume.is_paused %} + ENABLE_CONSTRAIN ENABLE=0 + {% if printer.toolhead.axis_maximum[0] > 250 %} + {% set x = params.X|default(300) %} + {% set y = params.Y|default(10) %} {% else %} - ;FIVE AXIS COMPENSATION OFF - ;B_AXIS_COMPENSATION_VARS ENABLE=0 - ;SET_SKEW ENABLE=0 - RADIAL_SPEED_COMPENSATION ENABLE=0 + {% set x = params.X|default(200) %} + {% set y = params.Y|default(10) %} {% endif %} - {% endif %} - G54 - G91 - {% if printer[printer.toolhead.extruder].can_extrude|lower == 'true' %} - CUT_FIBER - G1 E-{e} F1200 - {% else %} - {action_respond_info("Extruder not hot enough")} - {% endif %} - {% if "xyz" in printer.toolhead.homed_axes %} - G1 Z{z_safe} F3600 - G90 - G1 X{x} Y{y} F3600 + {% set z = params.Z|default(50)|float %} + {% set e = params.E|default(3) %} + {% set turn_off_extruders = params.TURN_OFF_EXTRUDERS|default(1)|int %} + {% set max_z = printer.toolhead.axis_maximum.z|float %} + {% set act_z = printer.toolhead.position.z|float %} + {% set lift_z = z|abs %} + {% set fan_speed = printer.fan.speed * 255 | int %} + {% if act_z < (max_z - lift_z) %} + {% set z_safe = lift_z %} + {% else %} + {% set z_safe = max_z - act_z %} + {% endif %} + {% if z_safe < 0 %} + {% set z_safe = 0 %} + {% endif %} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder_temp VALUE={printer.extruder.target} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=extruder1_temp VALUE={printer.extruder1.target} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=fan_speed VALUE={fan_speed} + {% set current_extruder = 0 %} + {% if printer.toolhead.extruder == 'extruder1' %} + {% set current_extruder = 1 %} + {% endif %} + SET_GCODE_VARIABLE MACRO=PAUSE VARIABLE=current_extruder VALUE={current_extruder} + {% if turn_off_extruders > 0 and printer["filament_motion_sensor extruder_sensor"] %} + UPDATE_DELAYED_GCODE ID=TURN_OFF_EXTRUDERS_DELAYED DURATION=300 + {% endif %} + SET_IDLE_TIMEOUT TIMEOUT=360000 + PAUSE_BASE + STATUS_LED STATUS=paused + {% if printer.probe %} + {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} + BED_MESH_CLEAR + ;SET_SKEW ENABLE=0 + {% else %} + ;FIVE AXIS COMPENSATION OFF + ;B_AXIS_COMPENSATION_VARS ENABLE=0 + SET_SKEW ENABLE=0 + RADIAL_SPEED_COMPENSATION ENABLE=0 + {% endif %} + {% endif %} + G54 + G91 + {% if printer[printer.toolhead.extruder].can_extrude|lower == 'true' %} + CUT_FIBER + G1 E-{e} F1200 + {% else %} + {action_respond_warning("611: Extruder not hot enough")} + {% endif %} + {% if "xyz" in printer.toolhead.homed_axes %} + G1 Z{z_safe} F3600 + G90 + G1 X{x} Y{y} F3600 + {% else %} + {action_respond_warning("813: Printer not homed")} + {% endif %} + M106 S0 {% else %} - {action_respond_info("Printer not homed")} + {action_respond_warning("PAUSE command can't be used because the printer is in PAUSE state.")} {% endif %} - M106 S0 [gcode_macro RESUME] description: Resume the actual running print rename_existing: RESUME_BASE gcode: - ENABLE_CONSTRAIN ENABLE=0 - M109 T0 S{printer["gcode_macro PAUSE"].extruder_temp} - M109 T1 S{printer["gcode_macro PAUSE"].extruder1_temp} - M106 S{printer["gcode_macro PAUSE"].fan_speed} - T{printer["gcode_macro PAUSE"].current_extruder} - {% set e = params.E|default(8) %} - {% set velocity = params.VELOCITY|default(30) %} - G91 - {% if printer[printer.toolhead.extruder].can_extrude|lower == 'true' %} - G1 E{e} F1800 - PRIME_FIBER - {% else %} - {action_respond_info("Extruder not hot enough")} - {% endif %} - G90 - SET_IDLE_TIMEOUT TIMEOUT=600 - {% if printer["filament_motion_sensor extruder_sensor"] %} - UPDATE_DELAYED_GCODE ID=TURN_OFF_EXTRUDERS_DELAYED DURATION=0 - {% endif %} - {% if printer.probe %} - {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} - BED_MESH_PROFILE LOAD=module_3d - ;SET_SKEW ENABLE=1 - ;SKEW_PROFILE LOAD=module_3d + {% if printer.pause_resume.is_paused %} + ENABLE_CONSTRAIN ENABLE=0 + M109 T0 S{printer["gcode_macro PAUSE"].extruder_temp} + M109 T1 S{printer["gcode_macro PAUSE"].extruder1_temp} + M106 S{printer["gcode_macro PAUSE"].fan_speed} + T{printer["gcode_macro PAUSE"].current_extruder} + {% set e = params.E|default(8) %} + {% set velocity = params.VELOCITY|default(30) %} + G91 + {% if printer[printer.toolhead.extruder].can_extrude|lower == 'true' %} + G1 E{e} F1800 + PRIME_FIBER {% else %} - ;FIVE AXIS COMPENSATION - ;SET_SKEW ENABLE=1 - ;SKEW_PROFILE LOAD=module_5d - ;B_AXIS_COMPENSATION_VARS ENABLE=1 - RADIAL_SPEED_COMPENSATION ENABLE=1 + {action_respond_warning("611: Extruder not hot enough")} + {% endif %} + G90 + SET_IDLE_TIMEOUT TIMEOUT=600 + {% if printer["filament_motion_sensor extruder_sensor"] %} + UPDATE_DELAYED_GCODE ID=TURN_OFF_EXTRUDERS_DELAYED DURATION=0 {% endif %} + {% if printer.probe %} + {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} + BED_MESH_PROFILE LOAD=module_3d + ;SET_SKEW ENABLE=1 + ;SKEW_PROFILE LOAD=module_3d + {% else %} + ;FIVE AXIS COMPENSATION + ;SET_SKEW ENABLE=1 + ;SKEW_PROFILE LOAD=module_5d + ;B_AXIS_COMPENSATION_VARS ENABLE=1 + RADIAL_SPEED_COMPENSATION ENABLE=1 + {% endif %} + {% endif %} + RESUME_BASE VELOCITY={velocity} + M117 + ENABLE_CONSTRAIN ENABLE=1 + {% else %} + {action_respond_warning("RESUME command can't be used because the printer is not in PAUSE state.")} {% endif %} - RESUME_BASE VELOCITY={velocity} - M117 - ENABLE_CONSTRAIN ENABLE=1 [gcode_macro CANCEL_PRINT] description: Cancel the actual running print @@ -124,32 +132,19 @@ gcode: {% endif %} {% set e = params.E|default(3) %} {% set z = params.Z|default(50)|float %} - {% set max_z = printer.toolhead.axis_maximum.z|float %} - {% set act_z = printer.toolhead.position.z|float %} - {% set lift_z = z|abs %} - {% if act_z < (max_z - lift_z) %} - {% set z_safe = lift_z %} - {% else %} - {% set z_safe = max_z - act_z %} - {% endif %} - {% if z_safe < 0 %} - {% set z_safe = 0 %} - {% endif %} G40 G54 - G91 {% if printer.extruder.can_extrude|lower == 'true' %} + G91 CUT_FIBER PRIME_FIBER G1 E-{e} F2100 + G90 {% endif %} TURN_OFF_HEATERS M107 SET_FAN_SPEED FAN=chamber_fan SPEED=0.0 - {% if "z" in printer.toolhead.homed_axes %} - G1 Z{z_safe} F6000 - {% endif %} - G90 + MOVE_DOWN_Z_AXIS Z={z} G28 X0 Y0 T0 {% if printer.probe %} @@ -159,7 +154,7 @@ gcode: {% else %} ;FIVE AXIS COMPENSATION OFF ;B_AXIS_COMPENSATION_VARS ENABLE=0 - ;SET_SKEW ENABLE=0 + SET_SKEW ENABLE=0 RADIAL_SPEED_COMPENSATION ENABLE=0 {% endif %} {% endif %} @@ -169,20 +164,26 @@ gcode: [gcode_macro SDCARD_PRINT_FILE] rename_existing: SDCARD_PRINT_FILE_BASE gcode: - {% if params.DICT_STATE %} - {action_respond_info("Realise gcode_macro SDCARD_PRINT_FILE-continued printing. File start with: %s position." % params.FILE_POSITION)} - ACTIVATE_EXTRUDER EXTRUDER={params.EXTRUDER} - M140 S{params.HEATER_BED_TEMP|default(75, true)} - M190 S{params.HEATER_BED_TEMP|default(75, true)} - M104 S{params.EXTRUDER_TEMP|default(255, true)} - M109 S{params.EXTRUDER_TEMP|default(255, true)} - M82 - START - LOAD_GCODE_STATE NAME=power_off PARAMS="{params.DICT_STATE}" - RESTORE_GCODE_STATE NAME=power_off MOVE=1 MOVE_SPEED=30 - SDCARD_PRINT_FILE_BASE FILENAME={params.FILENAME} POSITION={params.FILE_POSITION} + {% set wcs_1 = printer.gcode_move.wcs_offsets[1] %} + ; checking printer is calibrate when used 5d module before printing + {% if wcs_1[0] != 0.0 or printer["gcode_button five_axis_module"].state == "RELEASED"%} + {% if params.DICT_STATE %} + {action_respond_info("Realise gcode_macro SDCARD_PRINT_FILE-continued printing. File start with: %s position." % params.FILE_POSITION)} + ACTIVATE_EXTRUDER EXTRUDER={params.EXTRUDER} + M140 S{params.HEATER_BED_TEMP|default(75, true)} + M190 S{params.HEATER_BED_TEMP|default(75, true)} + M104 S{params.EXTRUDER_TEMP|default(255, true)} + M109 S{params.EXTRUDER_TEMP|default(255, true)} + M82 + START + LOAD_GCODE_STATE NAME=power_off PARAMS="{params.DICT_STATE}" + RESTORE_GCODE_STATE NAME=power_off MOVE=1 MOVE_SPEED=30 + SDCARD_PRINT_FILE_BASE FILENAME={params.FILENAME} POSITION={params.FILE_POSITION} + {% else %} + SDCARD_PRINT_FILE_BASE FILENAME={params.FILENAME} + {% endif %} {% else %} - SDCARD_PRINT_FILE_BASE FILENAME={params.FILENAME} + {action_raise_error("Can't start printing beacose the printer not is calibrated. Please calibrate printer.")} {% endif %} [gcode_macro START] @@ -241,29 +242,19 @@ gcode: { action_respond_info('Printjob ended') } {% set z = params.Z|default(50)|float %} {% set e = params.E|default(3) %} - {% set max_z = printer.toolhead.axis_maximum.z|float %} - {% set act_z = printer.toolhead.position.z|float %} - {% set lift_z = z|abs %} - {% if act_z < (max_z - lift_z) %} - {% set z_safe = lift_z %} - {% else %} - {% set z_safe = max_z - act_z - 0.1 %} - {% endif %} - {% if z_safe < 0 %} - {% set z_safe = 0 %} - {% endif %} + G40 G54 - G91 {% if printer.extruder.can_extrude|lower == 'true' %} + G91 + CUT_FIBER + PRIME_FIBER G1 E-{e} F2100 + G90 {% endif %} TURN_OFF_HEATERS M107 SET_FAN_SPEED FAN=chamber_fan SPEED=0.0 - {% if "z" in printer.toolhead.homed_axes %} - G1 Z{z_safe} F6000 - {% endif %} - G90 + MOVE_DOWN_Z_AXIS Z={z} G28 X0 Y0 T0 {% if printer.probe %} @@ -272,7 +263,7 @@ gcode: ;SET_SKEW ENABLE=0 {% else %} ;FIVE AXIS COMPENSATION OFF - ;SET_SKEW ENABLE=0 + SET_SKEW ENABLE=0 ;B_AXIS_COMPENSATION_VARS ENABLE=0 RADIAL_SPEED_COMPENSATION ENABLE=0 {% endif %} @@ -281,3 +272,29 @@ gcode: {% if printer['gcode_macro END'].power_off %} UPDATE_DELAYED_GCODE ID=CHECK_TEMP DURATION=1 {% endif %} + +[gcode_macro MOVE_DOWN_Z_AXIS] +description: macro to move down z axis. +gcode: + {% set max_z = printer.toolhead.axis_maximum.z|float %} + {% set act_z = printer.toolhead.position.z|float %} + {% set z = params.Z|default(50)|float %} + {% set lift_z = z|abs %} + {% if act_z < (max_z - lift_z) %} + {% set z_safe = lift_z %} + {% else %} + {% set z_safe = max_z - act_z - 0.1 %} + {% endif %} + {% if z_safe < 0 %} + {% set z_safe = 0 %} + {% endif %} + {% set result_move = act_z + z_safe %} + {% if result_move >= max_z - 0.1 %} + {% set z_safe = 0 %} + {% endif %} + G54 + G91 + {% if "z" in printer.toolhead.homed_axes %} + G1 Z{z_safe} F1600 + {% endif %} + G90 diff --git a/stereotech_config/probe.cfg b/stereotech_config/probe.cfg deleted file mode 100644 index 82e03ef3cee2..000000000000 --- a/stereotech_config/probe.cfg +++ /dev/null @@ -1,695 +0,0 @@ -[probe] -pin: !PG13 -samples: 4 -samples_tolerance_retries: 1 -samples_result: median -lift_speed: 10.0 -x_offset: -42.3 -y_offset: -48.14 -z_offset: 0.0 - -[skew_correction] -[b_axis_compensation] - -[bed_mesh] -speed: 120 -horizontal_move_z: 50 -mesh_min: 20, 20 -mesh_max: 261, 245 -probe_count: 5, 5 -fade_start: 1 -fade_end: 10 -fade_target: 0 - -[bed_mesh module_3d] -version = 1 -points = - 0.0, 0.0, 0.0, 0.0, 0.0 - 0.0, 0.0, 0.0, 0.0, 0.0 - 0.0, 0.0, 0.0, 0.0, 0.0 - 0.0, 0.0, 0.0, 0.0, 0.0 - 0.0, 0.0, 0.0, 0.0, 0.0 -x_count = 5 -y_count = 5 -mesh_x_pps = 2 -mesh_y_pps = 2 -algo = lagrange -tension = 0.2 -min_x = 10.0 -max_x = 261.0 -min_y = 10.0 -max_y = 253.0 - -[gcode_macro SET_PROBE_SENSOR] -description: Set offsets for new sensor and set sensor version. -gcode: - {% set probe_sensor_version = params.PROBE_VERSION|default(0)|int %} - {% if probe_sensor_version > 0 %} - {% set x_offset = -40.0 %} - {% set y_offset = -34.0 %} - {% set z_offset = 0.0 %} - {% else %} - {% set x_offset = -42.3 %} - {% set y_offset = -48.14 %} - {% set z_offset = 0.0 %} - {% endif %} - Z_OFFSET_APPLY_PROBE X={x_offset} Y={y_offset} Z={z_offset} - SAVE_VARIABLE VARIABLE=probe_sensor_version VALUE={probe_sensor_version} - SAVE_VARIABLE VARIABLE=probe_offset_x VALUE={x_offset} - SAVE_VARIABLE VARIABLE=probe_offset_y VALUE={y_offset} - SAVE_VARIABLE VARIABLE=probe_offset_z VALUE={z_offset} - {action_respond_info("Apply offset for new sensor: x_offset= %s, y_offset= %s, z_offset= %s" % (x_offset, y_offset, z_offset))} - -[gcode_macro TEST_PROBE] -gcode: - QUERY_PROBE - UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=1.0 - -[gcode_macro CANCEL_TEST_PROBE] -gcode: - UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=0.0 - {action_respond_info('Abort check loop')} - -[delayed_gcode test_probe_loop] -gcode: - {% if printer["probe"].last_query %} - UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=0.0 - {action_respond_info('Probe pressed, abort check loop')} - {% else %} - {action_respond_info('Probe not pressed')} - QUERY_PROBE - UPDATE_DELAYED_GCODE ID=test_probe_loop DURATION=1.0 - {% endif %} - -[gcode_macro CALIBRATE_MODULE_THREE_D] -description: 3D module calibration -gcode: - {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} - G0 X197 Y195 F6000 - PROBE - G91 - G0 Z30 F600 - G90 - MODULE_THREE_D_MESH_CALIBRATE - G91 - G0 Z30 F600 - G90 - G0 X150 Y50 F3600 - {% endif %} - -[gcode_macro MODULE_THREE_D_MESH_CALIBRATE] -description: 3D module calibration -gcode: - {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} - Z_OFFSET_APPLY_PROBE Z={printer.probe.last_result[2]} - BED_MESH_CALIBRATE PROFILE=module_3d - BED_MESH_CLEAR - {% endif %} - -[gcode_macro CALIBRATE_MODULE_FIVE_D] -description: 5D module calibration -gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - M204 S500 - G0 C0.1 - G0 C0 - {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} - ADJUST_TEMPLATE_HEIGHT - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - - PROBE_TEMPLATE_POINT POINT=O - SET_A_OFFSET_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=CZ - SET_A_OFFSET_POINT POINT=1 - CALC_A_AXIS_OFFSET - PROBE_TEMPLATE_POINT POINT=O - SET_A_OFFSET_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=CZ - SET_A_OFFSET_POINT POINT=1 - CALC_A_AXIS_OFFSET - - ;PROBE_TEMPLATE_POINT POINT=CZ - ;SET_B_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=CZ1 - ;SET_B_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=AZ - ;SET_B_COMPENSATION_POINT POINT=2 - ;PROBE_TEMPLATE_POINT POINT=BZ - ;SET_B_COMPENSATION_POINT POINT=3 - ;PROBE_TEMPLATE_POINT POINT=AX - ;SET_B_COMPENSATION_POINT POINT=4 - ;PROBE_TEMPLATE_POINT POINT=BX - ;SET_B_COMPENSATION_POINT POINT=5 - ;CALC_B_AXIS_COMPENSATION ENABLE=0 - - ; skew corection - ; xy skew - ;PROBE_TEMPLATE_POINT POINT=AX - ;SET_SKEW_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=BX - ;SET_SKEW_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=XY1 - ;SET_SKEW_COMPENSATION_POINT POINT=2 - ;PROBE_TEMPLATE_POINT POINT=XY2 - ;SET_SKEW_COMPENSATION_POINT POINT=3 - ;CALC_SKEW_COMPENSATION FACTOR=XY - ; xz skew - ;PROBE_TEMPLATE_POINT POINT=BX - ;SET_SKEW_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=AX - ;SET_SKEW_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=XZ3 - ;SET_SKEW_COMPENSATION_POINT POINT=2 - ;PROBE_TEMPLATE_POINT POINT=XZ4 - ;SET_SKEW_COMPENSATION_POINT POINT=3 - ;CALC_SKEW_COMPENSATION FACTOR=XZ - ; yz skew - ;PROBE_TEMPLATE_POINT POINT=YZ1 - ;SET_SKEW_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=YZ2 - ;SET_SKEW_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=YZ3 - ;SET_SKEW_COMPENSATION_POINT POINT=2 - ;CALC_SKEW_COMPENSATION FACTOR=YZ - ; save profile 5d - ;SKEW_PROFILE SAVE=module_5d - - - {% if probe_sensor_version > 0 %} - AUTO_WCS_OFFSET_NEW_SENSOR - {% else %} - AUTO_WCS_OFFSET_OLD_SERNSOR - {% endif %} - M204 S1500 - {% endif %} - -[gcode_macro SET_C_ALIGN_POINT] -gcode: - {% set point = printer.probe.last_result %} - {% set offsets = printer.probe.offsets %} - {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} - {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} - {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} - {% set index = params.POINT|default(0) %} - SAVE_C_AXIS_POINT POINT={index} COORDS='{x},{y},{z}' - -[gcode_macro SET_A_OFFSET_POINT] -gcode: - {% set point = printer.probe.last_result %} - {% set offsets = printer.probe.offsets %} - {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} - {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} - {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} - {% set index = params.POINT|default(0) %} - SAVE_A_AXIS_POINT POINT={index} COORDS='{x},{y},{z}' - -[gcode_macro SET_B_COMPENSATION_POINT] -gcode: - {% set point = printer.probe.last_result %} - {% set offsets = printer.probe.offsets %} - {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} - {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} - {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} - {% set index = params.POINT|default(0) %} - SAVE_B_AXIS_POINT POINT={index} COORDS='{x},{y},{z}' - -[gcode_macro SET_SKEW_COMPENSATION_POINT] -description: saved value about probe for align skew -gcode: - {% set point = printer.probe.last_result %} - {% set offsets = printer.probe.offsets %} - {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} - {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} - {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} - {% set index = params.POINT|default(0) %} - SAVE_SKEW_POINT POINT={index} COORDS='{x},{y},{z}' - -[gcode_macro ADJUST_TEMPLATE_HEIGHT] -gcode: - PROBE_TEMPLATE_POINT - SET_TEMPLATE_HEIGHT - -[gcode_macro SET_TEMPLATE_HEIGHT] -gcode: - SET_GCODE_VARIABLE MACRO=PROBE_TEMPLATE_POINT VARIABLE=probe_z VALUE={printer.probe.last_result[2] - printer.gcode_move.homing_origin.z} - -[c_axis_align] -[auto_wcs] - -[skew_correction module_3d] -xy_skew = 0.0 -xz_skew = 0.0 -yz_skew = 0.0 - -[skew_correction module_5d] -xy_skew = 0.0 -xz_skew = 0.0 -yz_skew = 0.0 - -[gcode_macro SET_AUTO_WCS_POINT] -gcode: - {% set point = printer.probe.last_result %} - {% set offsets = printer.probe.offsets %} - {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} - {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} - {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} - # checking the axes that they are within the allowable range - {% set home_min = printer.toolhead.axis_minimum %} - {% set home_max = printer.toolhead.axis_maximum %} - {% if x < home_min[0] or x > home_max[0] %} - {action_raise_error('axis x=%f out of range (%f - %f)' % (x, home_min[0], home_max[0]))} - {% elif y < home_min[1] or y > home_max[1] %} - {action_raise_error('axis y=%f out of range (%f - %f)' % (y, home_min[1], home_max[1]))} - {% elif z < home_min[2] or z > home_max[2] %} - {action_raise_error('axis z=%f out of range (%f - %f)' % (z, home_min[2], home_max[2]))} - {% endif %} - {% set index = params.POINT|default(0) %} - SAVE_WCS_CALC_POINT POINT={index} COORDS='{x},{y},{z}' - -[gcode_macro AUTO_WCS_OFFSET_OLD_SERNSOR] -gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} - G0 C0.1 - G0 C0 - ADJUST_TEMPLATE_HEIGHT - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - ADJUST_TEMPLATE_HEIGHT - SET_AUTO_WCS_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=AY1 - SET_AUTO_WCS_POINT POINT=1 - PROBE_TEMPLATE_POINT POINT=AY2 - SET_AUTO_WCS_POINT POINT=7 - PROBE_TEMPLATE_POINT POINT=AX - SET_AUTO_WCS_POINT POINT=2 - PROBE_TEMPLATE_POINT POINT=BX - SET_AUTO_WCS_POINT POINT=3 - PROBE_TEMPLATE_POINT POINT=DZ - SET_AUTO_WCS_POINT POINT=4 - PROBE_TEMPLATE_POINT POINT=DY - SET_AUTO_WCS_POINT POINT=5 - PROBE_TEMPLATE_POINT POINT=EY - SET_AUTO_WCS_POINT POINT=6 - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} - {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.25)|float %} - CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION={probe_sensor_version} - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - MOVE_TO_AUTO_WCS - {% endif %} - -[gcode_macro AUTO_WCS_OFFSET_NEW_SENSOR] -gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} - G0 C0.1 - G0 C0 - ADJUST_TEMPLATE_HEIGHT - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - ADJUST_TEMPLATE_HEIGHT - SET_AUTO_WCS_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=AY2_2 - SET_AUTO_WCS_POINT POINT=7 - PROBE_TEMPLATE_POINT POINT=AY1_2 - SET_AUTO_WCS_POINT POINT=1 - PROBE_TEMPLATE_POINT POINT=BX - SET_AUTO_WCS_POINT POINT=3 - PROBE_TEMPLATE_POINT POINT=AX - SET_AUTO_WCS_POINT POINT=2 - PROBE_TEMPLATE_POINT POINT=DZ_2 - SET_AUTO_WCS_POINT POINT=4 - PROBE_TEMPLATE_POINT POINT=EY_2 - SET_AUTO_WCS_POINT POINT=6 - PROBE_TEMPLATE_POINT POINT=DY_2 - SET_AUTO_WCS_POINT POINT=5 - PROBE_TEMPLATE_POINT POINT=CX1 - SET_AUTO_WCS_POINT POINT=8 - PROBE_TEMPLATE_POINT POINT=CX2 - SET_AUTO_WCS_POINT POINT=9 - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} - {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.3)|float %} - CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION={probe_sensor_version} - SAVE_PROBE_BACKLASH - - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - MOVE_TO_AUTO_WCS - {% endif %} - -[gcode_macro SAVE_PROBE_BACKLASH] -description: this macros save the sensor backlash. -gcode: - {% set probe_backlash_x = printer.auto_wcs.probe_backlash_x %} - {% set probe_backlash_y = printer.auto_wcs.probe_backlash_y %} - {% set probe_backlash_y_2 = printer.auto_wcs.probe_backlash_y_2 %} - SAVE_VARIABLE VARIABLE=probe_backlash_x VALUE={probe_backlash_x} - SAVE_VARIABLE VARIABLE=probe_backlash_y VALUE={probe_backlash_y} - SAVE_VARIABLE VARIABLE=probe_backlash_y_2 VALUE={probe_backlash_y_2} - {action_respond_info('save probe_backlash_x=%s' % probe_backlash_x)} - {action_respond_info('save probe_backlash_y=%s' % probe_backlash_y)} - {action_respond_info('save probe_backlash_y_2=%s' % probe_backlash_y_2)} - -[gcode_macro MOVE_TO_AUTO_WCS] -gcode: - {% set set_xy = params.XY|default(0) %} - {% set y_shift = 50 if set_xy else 7 %} - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - G0 X{printer.auto_wcs.wcs[0][0]} Y{printer.auto_wcs.wcs[0][1] - y_shift} Z{printer.auto_wcs.wcs[0][2] + 10} F3600 - {% endif %} - -[gcode_macro ADJUST_PROBE_OFFSET_Z] -gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - {% set wcs_0 = printer.auto_wcs.wcs[0] %} - {% set wcs_1 = printer.auto_wcs.wcs[1] %} - {% set offsets = printer.probe.offsets %} - {% set coord_z = printer.gcode_move.position.z - printer.gcode_move.homing_origin.z %} - {% set delta_z = wcs_0[2] - coord_z %} - Z_OFFSET_APPLY_PROBE Z={(offsets[2] + delta_z)|abs} - {% if params.ADJUST_CALIBRATION|default(0) %} - {% set b_axis_params = printer.b_axis_compensation %} - B_AXIS_COMPENSATION_VARS Z={b_axis_params.rot_center_z - delta_z} - {% endif %} - {% if params.ADJUST_WCS|default(0) %} - {% set auto_wcs_params = printer.auto_wcs.wcs %} - {% set x0 = auto_wcs_params[0][0] %} - {% set y0 = auto_wcs_params[0][1] %} - {% set z0 = auto_wcs_params[0][2] - delta_z %} - SET_AUTO_WCS WCS=0 COORDS='{x0},{y0},{z0}' - {% set x1 = auto_wcs_params[1][0] %} - {% set y1 = auto_wcs_params[1][1] %} - {% set z1 = auto_wcs_params[1][2] - delta_z %} - SET_AUTO_WCS WCS=1 COORDS='{x1},{y1},{z1}' - {% endif %} - {% endif %} - -[gcode_macro ADJUST_PROBE_OFFSET_XY] -gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - {% set y_shift = 50 %} - {% set wcs_0 = printer.auto_wcs.wcs[0] %} - {% set wcs_1 = printer.auto_wcs.wcs[1] %} - {% set offsets = printer.probe.offsets %} - {% set coord_x = printer.gcode_move.position.x - printer.gcode_move.homing_origin.x %} - {% set coord_y = printer.gcode_move.position.y + y_shift - printer.gcode_move.homing_origin.y %} - {% set delta_x = wcs_0[0] - coord_x %} - {% set delta_y = wcs_0[1] - coord_y %} - Z_OFFSET_APPLY_PROBE X={offsets[0] - delta_x} Y={offsets[1] - delta_y} - {% if params.ADJUST_CALIBRATION|default(0) %} - {% set b_axis_params = printer.b_axis_compensation %} - B_AXIS_COMPENSATION_VARS X={b_axis_params.rot_center_x - delta_x} - {% endif %} - {% if params.ADJUST_WCS|default(0) %} - {% set auto_wcs_params = printer.auto_wcs.wcs %} - {% set x0 = auto_wcs_params[0][0] - delta_x %} - {% set y0 = auto_wcs_params[0][1] - delta_y %} - {% set z0 = auto_wcs_params[0][2] %} - SET_AUTO_WCS WCS=0 COORDS='{x0},{y0},{z0}' - {% set x1 = auto_wcs_params[1][0] - delta_x %} - {% set y1 = auto_wcs_params[1][1] - delta_y %} - {% set z1 = auto_wcs_params[1][2] %} - SET_AUTO_WCS WCS=1 COORDS='{x1},{y1},{z1}' - {% endif %} - {% endif %} - -[gcode_macro SET_WCS_FROM_AUTO_WCS] -gcode: - {% set auto_wcs_params = printer.auto_wcs.wcs %} - G10 L2 P2 X{auto_wcs_params[0][0]} Y{auto_wcs_params[0][1]} Z{auto_wcs_params[0][2]} - G10 L2 P4 X{auto_wcs_params[0][0]} Y{auto_wcs_params[0][1]} Z{auto_wcs_params[0][2]} - G10 L2 P3 X{auto_wcs_params[1][0]} Y{auto_wcs_params[1][1]} Z{auto_wcs_params[1][2]} - G10 L2 P5 X{auto_wcs_params[1][0]} Y{auto_wcs_params[1][1]} Z{auto_wcs_params[1][2]} - G90 - G0 Z150 F1500 - G54 - {% if printer.toolhead.axis_maximum[0] > 250 %} - G0 X150 Y50 F3600 - {% else %} - G0 X100 Y50 F3600 - {% endif %} - -[gcode_macro AUTO_BASEMENT_WCS] -description: This macro performs move based on the required measuring(wcs1_z, wcs2_y, wcs2_z), and takes measurements. -gcode: - {% set wcs = params.WCS|default(0)|int %} - {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} - {% if wcs == 0 %} - {% if probe_sensor_version %} - ; move for measuring wcs_1_z - AUTO_BASEMENT_WCS_MOVE - PROBE - ; set wcs_1_z, wcs_2_y(raw) - ADJUST_BASEMENT_WCS WCS=2 - G0 Z150 F3600 - ; get tool length - GET_TOOL_LENGTH - ; moving for measure radius the tool - TOOL_RADIUS - G0 Z150 F3600 - ; checking axis A - CHECK_AXIS_A - ; move and probing for measuring the wcs_2_y - AUTO_BASEMENT_WCS_TWO_Y_MOVE - {% else %} - ; move for measuring wcs_1_z - AUTO_BASEMENT_WCS_MOVE - PROBE - {% endif %} - {% else %} - PROBE - {% endif %} - G0 Z150 F3600 - -[gcode_macro CHECK_AXIS_A] -description: This macro moves, measures the a-axis, and gets the difference between the two measuring points and apply offset. -gcode: - PROBE_TOOL_POINT POINT=Z_2_0 WCS=2 - SET_A_OFFSET_POINT POINT=1 - PROBE_TOOL_POINT POINT=Z_2_1 WCS=2 - SET_A_OFFSET_POINT POINT=0 - ; calculate and apply offset for axis A - CALC_A_AXIS_OFFSET - -[gcode_macro GET_TOOL_LENGTH] -description: This macro calculate length tool. -variable_length_is_enough: 0 -gcode: - {% set old_y = printer.gcode_move.wcs_offsets[4][1] %} - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} - {% set wcs_2_y = printer.gcode_move.wcs_offsets[2][1] %} - {% set tool_length = old_y + template_thickness - wcs_2_y %} - {% if tool_length > 35.0 %} - SET_GCODE_VARIABLE MACRO=GET_TOOL_LENGTH VARIABLE=length_is_enough VALUE=1 - {action_respond_info('Tool length=%s' % tool_length)} - {% else %} - {action_respond_info("Warning tool length less 35mm!")} - {% endif %} - -[gcode_macro AUTO_BASEMENT_WCS_MOVE] -description: This macro does a move for measuring wcs_1_z and wcs_2_y-raw or wcs_2_y and wcs_1_z-raw. -gcode: - {% set wcs = params.WCS|default(0)|int %} - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[wcs + 3] %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - {% set a = '0' if wcs == 0 else '90' %} - G0 A{a} F3600 - G0 Z150 F3600 - G0 X{x} Y{y} F3600 - -[gcode_macro AUTO_BASEMENT_WCS_TWO_Y_MOVE] -description: This macro does a move for measuring wcs_2_y. -variable_length_is_enough: 1 -gcode: - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[2] %} - {% set radius = printer.auto_wcs.tooling_radius|float %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - {% set old_y = printer.gcode_move.wcs_offsets[4][1] %} - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} - {% set wcs_2_y = printer.gcode_move.wcs_offsets[2][1] %} - {% set tool_length = old_y + template_thickness - wcs_2_y %} - {action_respond_info('tool_length=%s' % tool_length)} - {% if tool_length > 35.0 %} - SET_GCODE_VARIABLE MACRO=AUTO_BASEMENT_WCS_TWO_Y_MOVE VARIABLE=length_is_enough VALUE=1 - G0 A90 F3600 - G0 X{x} Y{y - 20} F3600 - G0 Z{z + (radius - 4) } F3600 - PROBE AXIS=y POSITIVE_DIR=1 - G0 X{x} Y{y - 20} F3600 - {% else %} - SET_GCODE_VARIABLE MACRO=AUTO_BASEMENT_WCS_TWO_Y_MOVE VARIABLE=length_is_enough VALUE=0 - {action_raise_error("Tool length not enough for calculate wcs_2_y!")} - {% endif %} - -[gcode_macro TOOL_RADIUS] -description: moved to measure tool radius and calculate it. -gcode: - {% for i in range(3) %} - AUTO_BASEMENT_MOVE_MEASURE_RADIUS PROBE={i} - SET_AUTO_WCS_POINT_RADIUS POINT={i} - {% endfor %} - GET_RADIUS_TOOLING - -[gcode_macro AUTO_BASEMENT_MOVE_MEASURE_RADIUS] -description: measuring radius for geting wcs_2_z. -gcode: - {% set probe = params.PROBE|default(0)|int %} - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[1] %} - {% set point = printer.probe.last_result %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - G0 A0 F3600 - {% if probe == 0 %} - G0 X{x} Y{y - 60} F3600 - G0 Z{z - 5} F3600 - PROBE AXIS=y POSITIVE_DIR=1 - G0 X{x} Y{y - 60} F3600 - {% elif probe == 1 %} - {% set advance_radius = y - point[1] %} - G0 X{x - (advance_radius + 10)} Y{y} F3600 - G0 Z{z - 5} F3600 - PROBE AXIS=x POSITIVE_DIR=1 - G0 X{x - (advance_radius + 10)} Y{y} F3600 - {% elif probe == 2 %} - {% set advance_radius = x - point[0] %} - G0 X{x + (advance_radius + 10)} Y{y} F3600 - G0 Z{z - 5} F3600 - PROBE AXIS=x POSITIVE_DIR=0 - G0 X{x + (advance_radius + 10)} Y{y} F3600 - {% endif %} - G0 Z{z + 10} F3600 - -[gcode_macro SET_AUTO_WCS_POINT_RADIUS] -description: This macro is for saving the points required for calculating the radius. -gcode: - {% set point = printer.probe.last_result %} - {% set index = params.POINT|default(0) %} - {% set x = point[0] %} - {% set y = point[1] %} - {% set z = point[2] %} - SAVE_WCS_CALC_POINT POINT={index} COORDS='{x},{y},{z}' - -[gcode_macro AUTO_BASEMENT_WCS_TWO_Z_MOVE] -description: This macro does a move for measuring wcs_2_z. -gcode: - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[2] %} - {% set radius = printer.auto_wcs.tooling_radius %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - G0 A90 F3600 - G0 X{x} Y{y + 5} F3600 - G0 Z{z + (radius + 10)} F3600 - PROBE - G0 Z150 F3600 - -[gcode_macro ADJUST_BASEMENT_WCS] -description: macro needed for set wcs based selected mode the manager calibrate. -gcode: - {% set wcs = params.WCS|default(0)|int %} - {% set point = printer.probe.last_result %} - {% set offsets = printer.probe.offsets %} - {% set wcs_0 = printer.gcode_move.wcs_offsets[3] %} - {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} - {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} - {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} - {% set wcs_1 = printer.gcode_move.wcs_offsets[4] %} - {% set old_z = wcs_0[2] %} - {% set old_y = wcs_1[1] %} - {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} - {% set probe_backlash_y = printer.save_variables.variables.probe_backlash_y|default(0.0)|float %} - {% if wcs == 0 %} - ; Mode SPIRAL-FULL - {% if probe_sensor_version %} - ; apply measuring for the set wcs_2_y - G10 L2 P3 Y{y + probe_backlash_y} - {% else %} - ; apply measuring for the set wcs_1_z and wcs_2_y. - G10 L2 P2 Z{z} - G10 L2 P3 Y{old_y - (z - old_z)} - {% endif %} - {% elif wcs == 1 %} - ; Mode SPIRAL - ; apply measuring for the set wcs_2_y and wcs_1_z(raw). - G10 L2 P3 Y{y} - G10 L2 P2 Z{old_z - (y - old_y)} - {% elif wcs == 2 %} - ; crutch! for the support different version sensor - ; set wcs_1_z and wcs_2_y(raw). - G10 L2 P2 Z{z} - G10 L2 P3 Y{old_y - (z - old_z)} - {% elif wcs == 3 %} - ; {% set radius = printer.auto_wcs.tooling_radius %} - ; apply measuring for the set wcs_2_z radius. - ; G10 L2 P3 Z{z - radius} - {% endif %} - -[gcode_macro PROBE_TOOL_POINT] -Description: This macro does movement and measurement relative to the tool. -gcode: - {% set point = params.POINT %} - {% set wcs = params.WCS|int %} - {% set positiv_dir = 0 %} - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[wcs] %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - {% set radius = printer.auto_wcs.tooling_radius|float %} - {% set tool_length = printer['gcode_macro GET_TOOL_LENGTH'].length_is_enough|int %} - {% set a = '0' if wcs == 1 else '90' %} - {% set checking = 'true' %} - {% if point == 'Z_2_0' %} - {% set axis_name = 'Z' %} - {% set y = y + 3 %} - {% set z = z + (radius + 10) %} - {% set checking = 'true' if tool_length > 0 else 'false' %} - {% set msg = 'Error, tool length not enough!' %} - {% elif point == 'Z_2_1' %} - {% set axis_name = 'Z' %} - {% set y = y + 25 %} - {% set z = z + (radius + 10) %} - {% set checking = 'true' if tool_length > 0 else 'false' %} - {% set msg = 'Error, tool length not enough!' %} - {% endif %} - {% if checking == 'true' %} - G0 A{a} C0 F3600 - G0 X{x} Y{y} F3600 - G0 Z{z} F3600 - PROBE AXIS={axis_name} POSITIVE_DIR={positiv_dir} - G0 X{x} Y{y} F3600 - G0 Z{z + radius + 10} F3600 - {% else %} - {action_raise_error('%s' % msg)} - {% endif %} diff --git a/stereotech_config/probe_DAC_v1.cfg b/stereotech_config/probe_DAC_v1.cfg new file mode 100644 index 000000000000..16ac92df9711 --- /dev/null +++ b/stereotech_config/probe_DAC_v1.cfg @@ -0,0 +1,215 @@ +[probe] +pin: !PG13 +samples: 4 +samples_tolerance_retries: 1 +samples_result: median +lift_speed: 10.0 +x_offset: -42.3 +y_offset: -48.14 +z_offset: 0.0 + +[gcode_macro SET_PROBE_SENSOR] +description: Set offsets for new sensor and set sensor version. +gcode: + {% set probe_sensor_version = params.PROBE_VERSION|default(0)|int %} + {% if probe_sensor_version > 0 %} + {% set x_offset = -40.0 %} + {% set y_offset = -34.0 %} + {% set z_offset = 0.0 %} + {% else %} + {% set x_offset = -42.3 %} + {% set y_offset = -48.14 %} + {% set z_offset = 0.0 %} + {% endif %} + Z_OFFSET_APPLY_PROBE X={x_offset} Y={y_offset} Z={z_offset} FROM_VARS=1 + SAVE_VARIABLE VARIABLE=probe_sensor_version VALUE={probe_sensor_version} + SAVE_VARIABLE VARIABLE=probe_offset_x VALUE={x_offset} + SAVE_VARIABLE VARIABLE=probe_offset_y VALUE={y_offset} + SAVE_VARIABLE VARIABLE=probe_offset_z VALUE={z_offset} + {action_respond_info("Apply offset for new sensor: x_offset= %s, y_offset= %s, z_offset= %s" % (x_offset, y_offset, z_offset))} + +[gcode_macro CHECK_SENSOR_VERSION_AND_START_AUTOCALIBRATE] +description: macro to continue automatic calibration depending on the version of the sensor +gcode: + {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} + {% if probe_sensor_version > 0 %} + AUTO_WCS_OFFSET_NEW_SENSOR + {% else %} + AUTO_WCS_OFFSET_OLD_SERNSOR + {% endif %} + +[gcode_macro AUTO_WCS_OFFSET_OLD_SERNSOR] +description: macro do move for measuring and calculated WCS. Sensor DAC_v_1 +gcode: + {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} + {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} + G0 C0.1 + G0 C0 + ADJUST_TEMPLATE_HEIGHT + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + ADJUST_TEMPLATE_HEIGHT + SET_AUTO_WCS_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=AY1 + SET_AUTO_WCS_POINT POINT=1 + PROBE_TEMPLATE_POINT POINT=AY2 + SET_AUTO_WCS_POINT POINT=7 + PROBE_TEMPLATE_POINT POINT=AX + SET_AUTO_WCS_POINT POINT=2 + PROBE_TEMPLATE_POINT POINT=BX + SET_AUTO_WCS_POINT POINT=3 + PROBE_TEMPLATE_POINT POINT=DZ + SET_AUTO_WCS_POINT POINT=4 + PROBE_TEMPLATE_POINT POINT=DY + SET_AUTO_WCS_POINT POINT=5 + PROBE_TEMPLATE_POINT POINT=EY + SET_AUTO_WCS_POINT POINT=6 + {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} + {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.25)|float %} + CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION={probe_sensor_version} + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + MOVE_TO_AUTO_WCS + {% endif %} + +[gcode_macro AUTO_WCS_OFFSET_NEW_SENSOR] +description: macro do move for measuring and calculated WCS. Sensor DAC_v_2 +gcode: + {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} + {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} + G0 C0.1 + G0 C0 + ADJUST_TEMPLATE_HEIGHT + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + ADJUST_TEMPLATE_HEIGHT + SET_AUTO_WCS_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=AY2_2 + SET_AUTO_WCS_POINT POINT=7 + PROBE_TEMPLATE_POINT POINT=AY1_2 + SET_AUTO_WCS_POINT POINT=1 + PROBE_TEMPLATE_POINT POINT=BX + SET_AUTO_WCS_POINT POINT=3 + PROBE_TEMPLATE_POINT POINT=AX + SET_AUTO_WCS_POINT POINT=2 + PROBE_TEMPLATE_POINT POINT=DZ_2 + SET_AUTO_WCS_POINT POINT=4 + PROBE_TEMPLATE_POINT POINT=EY_2 + SET_AUTO_WCS_POINT POINT=6 + PROBE_TEMPLATE_POINT POINT=DY_2 + SET_AUTO_WCS_POINT POINT=5 + PROBE_TEMPLATE_POINT POINT=CX1 + SET_AUTO_WCS_POINT POINT=8 + PROBE_TEMPLATE_POINT POINT=CX2 + SET_AUTO_WCS_POINT POINT=9 + {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} + {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.3)|float %} + CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION={probe_sensor_version} + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + MOVE_TO_AUTO_WCS + {% endif %} + +[gcode_macro AUTO_BASEMENT_WCS] +description: macro do main moves for get wcs for SPIRAL and FULL modes. +gcode: + {% set wcs = params.WCS|default(0)|int %} + {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} + {% if wcs == 0 %} + ; meachuring for mode the FULL + {% if probe_sensor_version %} + ; move for measuring all points for wcs_1 and wcs_2 + MOVE_AUTOCALIBRATE_FULL_V_2 + {% else %} + ; move for measuring wcs_1_z + AUTO_BASEMENT_WCS_MOVE + PROBE + G0 Z150 F3600 + {% endif %} + {% else %} + ; meachuring for mode the SPIRAL + {% if probe_sensor_version %} + ; move for measuring all points for wcs_2 + MOVE_AUTOCALIBRATE_SPIRAL_V_2 + {% else %} + ; move for measuring wcs_2_y + PROBE + G0 Z150 F3600 + {% endif %} + {% endif %} + +[gcode_macro ADJUST_BASEMENT_WCS] +gcode: + {% set wcs = params.WCS|default(0)|int %} + {% set point = printer.probe.last_result %} + {% set offsets = printer.probe.offsets %} + {% set wcs_0 = printer.gcode_move.wcs_offsets[3] %} + {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} + {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} + {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} + {% set wcs_1 = printer.gcode_move.wcs_offsets[4] %} + {% set old_z = wcs_0[2] %} + {% set old_y = wcs_1[1] %} + {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} + {% set probe_backlash_y = printer.auto_wcs.probe_backlash_y|default(0.0)|float %} + {% set tool_length = printer['gcode_macro GET_TOOL_LENGTH'].tool_length|float %} + {% set radius = printer.auto_wcs.tooling_radius %} + {% if wcs == 0 %} + ; Mode SPIRAL-FULL + {% if probe_sensor_version %} + ; apply measuring for the set wcs_2_z radius. + {% if tool_length > 35.0 %} + G10 L2 P3 Z{z - radius} + {% else %} + {action_raise_error('204: Error, tool length not enough for calculate wcs_2_y!')} + {% endif %} + {% else %} + ; apply measuring for the set wcs_1_z and wcs_2_y(raw). + G10 L2 P2 Z{z} + G10 L2 P3 Y{old_y - (z - old_z)} + {% endif %} + {% elif wcs == 1 %} + ; Mode SPIRAL + {% if probe_sensor_version and radius < 5.0 and tool_length > 35.0 %} + G10 L2 P3 Z{z - radius} + {% else %} + ; apply measuring for the set wcs_2_y and wcs_1_z(raw). + G10 L2 P3 Y{y} + G10 L2 P2 Z{old_z - (y - old_y)} + {% endif %} + {% elif wcs == 2 %} + ; set wcs_1_z and wcs_2_y(raw). + G10 L2 P2 Z{z} + G10 L2 P3 Y{old_y - (z - old_z)} + {% elif wcs == 3 %} + ; apply measuring for the set wcs_2_y + G10 L2 P3 Y{y + probe_backlash_y} + {% elif wcs == 4 %} + {% set x = printer.auto_wcs.wcs[0][0]|float %} + ; set wcs_1_x + G10 L2 P2 X{x} + {% elif wcs == 5 %} + {% set y = printer.auto_wcs.wcs[0][1]|float %} + ; set wcs_1_y + G10 L2 P2 Y{y} + {% elif wcs == 6 %} + {% set x = printer.auto_wcs.wcs[1][0]|float %} + ; set the wcs_2_x + G10 L2 P3 X{x} + {% elif wcs == 7 %} + ; apply measuring for the set wcs_2_y and wcs_1_z(raw). + G10 L2 P3 Y{y} + G10 L2 P2 Z{old_z - (y - old_y)} + {% endif %} diff --git a/stereotech_config/probe_DAC_v2.cfg b/stereotech_config/probe_DAC_v2.cfg new file mode 100644 index 000000000000..c21508c5aa54 --- /dev/null +++ b/stereotech_config/probe_DAC_v2.cfg @@ -0,0 +1,129 @@ +[probe] +pin: !PG13 +samples: 4 +samples_tolerance_retries: 1 +samples_result: median +lift_speed: 10.0 +x_offset: -40.0 +y_offset: -34.0 +z_offset: 0.0 + +[gcode_macro CHECK_SENSOR_VERSION_AND_START_AUTOCALIBRATE] +gcode: + {% set probe_sensor_version = 1 %} + {% if probe_sensor_version > 0 %} + AUTO_WCS_OFFSET_NEW_SENSOR + {% else %} + AUTO_WCS_OFFSET_OLD_SERNSOR + {% endif %} + +[gcode_macro AUTO_WCS_OFFSET_NEW_SENSOR] +description: macro do move for measuring and calculated WCS. Sensor DAC_v_2 +gcode: + {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} + G0 C0.1 + G0 C0 + ADJUST_TEMPLATE_HEIGHT + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + ADJUST_TEMPLATE_HEIGHT + SET_AUTO_WCS_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=AY2_2 + SET_AUTO_WCS_POINT POINT=7 + PROBE_TEMPLATE_POINT POINT=AY1_2 + SET_AUTO_WCS_POINT POINT=1 + PROBE_TEMPLATE_POINT POINT=BX + SET_AUTO_WCS_POINT POINT=3 + PROBE_TEMPLATE_POINT POINT=AX + SET_AUTO_WCS_POINT POINT=2 + PROBE_TEMPLATE_POINT POINT=DZ_2 + SET_AUTO_WCS_POINT POINT=4 + PROBE_TEMPLATE_POINT POINT=EY_2 + SET_AUTO_WCS_POINT POINT=6 + PROBE_TEMPLATE_POINT POINT=DY_2 + SET_AUTO_WCS_POINT POINT=5 + PROBE_TEMPLATE_POINT POINT=CX1 + SET_AUTO_WCS_POINT POINT=8 + PROBE_TEMPLATE_POINT POINT=CX2 + SET_AUTO_WCS_POINT POINT=9 + {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} + {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.3)|float %} + CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION=1 + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + MOVE_TO_AUTO_WCS + {% endif %} + +[gcode_macro AUTO_BASEMENT_WCS] +description: macro do main moves for get wcs for SPIRAL and FULL modes. +gcode: + {% set wcs = params.WCS|default(0)|int %} + {% if wcs == 0 %} + MOVE_AUTOCALIBRATE_FULL_V_2 + {% else %} + ; meachuring for mode the SPIRAL + MOVE_AUTOCALIBRATE_SPIRAL_V_2 + {% endif %} + +[gcode_macro ADJUST_BASEMENT_WCS] +gcode: + {% set wcs = params.WCS|default(0)|int %} + {% set point = printer.probe.last_result %} + {% set offsets = printer.probe.offsets %} + {% set wcs_0 = printer.gcode_move.wcs_offsets[3] %} + {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} + {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} + {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} + {% set wcs_1 = printer.gcode_move.wcs_offsets[4] %} + {% set old_z = wcs_0[2] %} + {% set old_y = wcs_1[1] %} + {% set probe_backlash_y = printer.auto_wcs.probe_backlash_y|default(0.0)|float %} + {% set tool_length = printer['gcode_macro GET_TOOL_LENGTH'].tool_length|float %} + {% set radius = printer.auto_wcs.tooling_radius %} + {% if wcs == 0 %} + ; Mode SPIRAL-FULL + ; apply measuring for the set wcs_2_z radius. + {% if tool_length > 35.0 %} + G10 L2 P3 Z{z - radius} + {% else %} + {action_raise_error('204: tool length not enough for calculate wcs_2_y!')} + {% endif %} + {% elif wcs == 1 %} + ; Mode SPIRAL + {% if radius < 5.0 and tool_length > 35.0 %} + G10 L2 P3 Z{z - radius} + {% else %} + ; apply measuring for the set wcs_2_y and wcs_1_z(raw). + G10 L2 P3 Y{y} + G10 L2 P2 Z{old_z - (y - old_y)} + {% endif %} + {% elif wcs == 2 %} + ; set wcs_1_z and wcs_2_y(raw). + G10 L2 P2 Z{z} + G10 L2 P3 Y{old_y - (z - old_z)} + {% elif wcs == 3 %} + ; apply measuring for the set wcs_2_y + G10 L2 P3 Y{y + probe_backlash_y} + {% elif wcs == 4 %} + {% set x = printer.auto_wcs.wcs[0][0]|float %} + ; set wcs_1_x + G10 L2 P2 X{x} + {% elif wcs == 5 %} + {% set y = printer.auto_wcs.wcs[0][1]|float %} + ; set wcs_1_y + G10 L2 P2 Y{y} + {% elif wcs == 6 %} + {% set x = printer.auto_wcs.wcs[1][0]|float %} + ; set the wcs_2_x + G10 L2 P3 X{x} + {% elif wcs == 7 %} + ; apply measuring for the set wcs_2_y and wcs_1_z(raw). + G10 L2 P3 Y{y} + G10 L2 P2 Z{old_z - (y - old_y)} + {% endif %} diff --git a/stereotech_config/probe_fiber_printer.cfg b/stereotech_config/probe_fiber_printer.cfg index da35c19b8fce..d40a98932666 100644 --- a/stereotech_config/probe_fiber_printer.cfg +++ b/stereotech_config/probe_fiber_printer.cfg @@ -6,7 +6,7 @@ gcode: {% set offsets = printer['probe'].offsets %} {% set O = [168 - offsets[0], 243 - offsets[1], 120] %} {% if O[1] > 294.0 %} - O[1] = 294.0 + {% set O = [168 - offsets[0], 294, 120] %} {% endif %} G0 Z120 F3600 G0 A0 C0 F3600 @@ -21,6 +21,12 @@ gcode: {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} {% set axis = 'Y' %} {% set positive = 1 %} + {% elif point=='CHECK_MODULE_Z1' %} + {% set target_x = O[0] - 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} + {% elif point=='CHECK_MODULE_Z2' %} + {% set target_x = O[0] + 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} {% elif point=='AY1' %} {% set target_x = O[0] - 32 %} {% set target_y = O[1] - 83 %} @@ -188,15 +194,15 @@ gcode: G0 A90 C60 F3600 {% elif point=='YZ2' %} {% set target_x = O[0] - 45 %} - {% set target_y = O[1] - 60 %} - {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 2 %} {% set axis = 'Y' %} {% set positive = 1 %} G0 A90 C5 F3600 {% elif point=='YZ3' %} {% set target_x = O[0] + 45 %} - {% set target_y = O[1] - 60 %} - {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 2 %} {% set axis = 'Y' %} {% set positive = 1 %} G0 A90 C-5 F3600 diff --git a/stereotech_config/probe_fiber_printer_3.cfg b/stereotech_config/probe_fiber_printer_3.cfg new file mode 100644 index 000000000000..3068f520377f --- /dev/null +++ b/stereotech_config/probe_fiber_printer_3.cfg @@ -0,0 +1,229 @@ +[gcode_macro PROBE_TEMPLATE_POINT] +description: Macro for calibration template probing +variable_probe_z: 120.0 +gcode: + {% set point = params.POINT|default('O') %} + {% set offsets = printer['probe'].offsets %} + {% set O = [160 - offsets[0], 243 - offsets[1], 120] %} + {% if O[1] > 294.0 %} + {% set O = [160 - offsets[0], 294, 120] %} + {% endif %} + G0 Z120 F3600 + G0 A0 C0 F3600 + {% set target_x = O[0] %} + {% set target_y = O[1] %} + {% set target_z = O[2] %} + {% set axis = 'Z' %} + {% set positive = 0 %} + {% if point=='AY' %} + {% set target_x = O[0] - 45 %} + {% set target_y = O[1] - 35 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + {% elif point=='CHECK_MODULE_Z1' %} + {% set target_x = O[0] - 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} + {% elif point=='CHECK_MODULE_Z2' %} + {% set target_x = O[0] + 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} + {% elif point=='AY1' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] - 83 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 C15 F3600 + {% elif point=='AY1_2' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] - 15 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 C30 + {% elif point=='AY2' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] - 6 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + G0 C15 F3600 + {% elif point=='AY2_2' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] + 16 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + G0 C30 F3600 + {% elif point=='BY' %} + {% set target_x = O[0] + 45 %} + {% set target_y = O[1] - 35 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + {% elif point=='CY' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 90 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + {% elif point=='DY' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 30 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C30 F3600 + {% elif point=='DY_2' %} + {% set target_x = O[0] + 2 %} + {% set target_y = O[1] - 40 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 28.5 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C90 F3600 + {% elif point=='EY' %} + {% set target_x = O[0] %} + {% set target_y = O[1] + 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 30 %} + {% set axis = 'Y' %} + G0 A90 C30 F3600 + {% elif point=='EY_2' %} + {% set target_x = O[0] + 2 %} + {% set target_y = O[1] + 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 28.5 %} + {% set axis = 'Y' %} + G0 A90 C90 F3600 + {% elif point=='AZ' %} + {% set target_x = O[0] - 45 %} + {% elif point=='BZ' %} + {% set target_x = O[0] + 45%} + {% elif point=='CZ' %} + {% set target_y = O[1] - 45 %} + {% elif point=='CZ1' %} + {% set target_y = O[1] - 45 %} + G0 A10 F3600 + {% elif point=='DZ' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 8 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 57 %} + G0 A90 C30 F3600 + {% elif point=='DZ_2' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 10 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 57 %} + G0 A90 F3600 + {% elif point=='EZ' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 57 %} + G0 A90 F3600 + {% elif point=='AX' %} + {% set target_x = O[0] - 80 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='AX1' %} + {% set target_x = O[0] - 40 %} + {% set target_y = O[1] - 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='AX2' %} + {% set target_x = O[0] - 80 %} + {% set target_y = O[1] + 2 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='BX' %} + {% set target_x = O[0] + 80 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='BX1' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] - 2 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='BX2' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] + 2 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + ; skew_correction + ; xy skew + {% elif point=='XY1' %} + {% set target_x = O[0] + 15 %} + {% set target_y = O[1] - 50 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='XY2' %} + {% set target_x = O[0] - 15 %} + {% set target_y = O[1] - 50 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + ; xz skew + {% elif point=='XZ1' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='XZ2' %} + {% set target_x = O[0] - 80 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='XZ3' %} + {% set target_x = O[0] + 15 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 36 %} + {% set axis = 'X' %} + G0 A90 C60 + {% elif point=='XZ4' %} + {% set target_x = O[0] - 15 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 36 %} + {% set axis = 'X' %} + {% set positive = 1 %} + G0 A90 C60 F3600 + ; yz skew + {% elif point=='YZ1' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 60 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 36 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C60 F3600 + {% elif point=='YZ2' %} + {% set target_x = O[0] - 45 %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 2 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C5 F3600 + {% elif point=='YZ3' %} + {% set target_x = O[0] + 45 %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 2 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C-5 F3600 + {% elif point=='CX1' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] - 11 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 17.5 %} + {% set axis = 'X' %} + G0 A90 + {% elif point=='CX2' %} + {% set target_x = O[0] - 80 %} + {% set target_y = O[1] - 11 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 17.5 %} + {% set axis = 'X' %} + {% set positive = 1 %} + G0 A90 + {% endif %} + G0 X{target_x} Y{target_y} F3600 + G0 Z{target_z} F3600 + PROBE AXIS={axis} POSITIVE_DIR={positive} + G0 X{target_x} Y{target_y} F3600 + G0 Z{target_z} F3600 + G0 Z120 F3600 + G0 A0 C0 F3600 diff --git a/stereotech_config/probe_hybrid_printer.cfg b/stereotech_config/probe_hybrid_printer.cfg index 3cc896dfd28e..3c908e294fa8 100644 --- a/stereotech_config/probe_hybrid_printer.cfg +++ b/stereotech_config/probe_hybrid_printer.cfg @@ -6,7 +6,7 @@ gcode: {% set offsets = printer['probe'].offsets %} {% set O = [161 - offsets[0], 243 - offsets[1], 120] %} {% if O[1] > 294.0 %} - O[1] = 294.0 + {% set O = [161 - offsets[0], 294, 120] %} {% endif %} G0 Z120 F3600 G0 A0 C0 F3600 @@ -21,6 +21,12 @@ gcode: {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} {% set axis = 'Y' %} {% set positive = 1 %} + {% elif point=='CHECK_MODULE_Z1' %} + {% set target_x = O[0] - 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} + {% elif point=='CHECK_MODULE_Z2' %} + {% set target_x = O[0] + 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} {% elif point=='AY1' %} {% set target_x = O[0] - 32 %} {% set target_y = O[1] - 83 %} @@ -188,15 +194,15 @@ gcode: G0 A90 C60 F3600 {% elif point=='YZ2' %} {% set target_x = O[0] - 45 %} - {% set target_y = O[1] - 60 %} - {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 2 %} {% set axis = 'Y' %} {% set positive = 1 %} G0 A90 C5 F3600 {% elif point=='YZ3' %} {% set target_x = O[0] + 45 %} - {% set target_y = O[1] - 60 %} - {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 2 %} {% set axis = 'Y' %} {% set positive = 1 %} G0 A90 C-5 F3600 diff --git a/stereotech_config/probe_2.cfg b/stereotech_config/probe_main.cfg similarity index 55% rename from stereotech_config/probe_2.cfg rename to stereotech_config/probe_main.cfg index 5deaff940264..c72a78eb0401 100644 --- a/stereotech_config/probe_2.cfg +++ b/stereotech_config/probe_main.cfg @@ -1,16 +1,3 @@ -[probe] -pin: !PG13 -samples: 4 -samples_tolerance_retries: 1 -samples_result: median -lift_speed: 10.0 -x_offset: -40.0 -y_offset: -34.0 -z_offset: 0.0 - -[skew_correction] -[b_axis_compensation] - [bed_mesh] speed: 120 horizontal_move_z: 50 @@ -40,6 +27,24 @@ max_x = 261.0 min_y = 10.0 max_y = 253.0 +[skew_correction] + +[b_axis_compensation] + +[c_axis_align] + +[auto_wcs] + +[skew_correction module_3d] +xy_skew = 0.0 +xz_skew = 0.0 +yz_skew = 0.0 + +[skew_correction module_5d] +xy_skew = 0.0 +xz_skew = 0.0 +yz_skew = 0.0 + [gcode_macro TEST_PROBE] gcode: QUERY_PROBE @@ -66,15 +71,16 @@ description: 3D module calibration gcode: {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} G0 X197 Y195 F6000 + G0 Z40 F3600 PROBE G91 - G0 Z30 F600 + G0 Z30 F3600 G90 MODULE_THREE_D_MESH_CALIBRATE - G91 - G0 Z30 F600 + G91 + G0 Z30 F3600 G90 - G0 X150 Y50 F3600 + G0 X150 Y50 F3600 {% endif %} [gcode_macro MODULE_THREE_D_MESH_CALIBRATE] @@ -86,87 +92,6 @@ gcode: BED_MESH_CLEAR {% endif %} -[gcode_macro CALIBRATE_MODULE_FIVE_D] -description: 5D module calibration -gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - M204 S500 - G0 C0.1 - G0 C0 - ADJUST_TEMPLATE_HEIGHT - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - - PROBE_TEMPLATE_POINT POINT=O - SET_A_OFFSET_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=CZ - SET_A_OFFSET_POINT POINT=1 - CALC_A_AXIS_OFFSET - PROBE_TEMPLATE_POINT POINT=O - SET_A_OFFSET_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=CZ - SET_A_OFFSET_POINT POINT=1 - CALC_A_AXIS_OFFSET - - ;PROBE_TEMPLATE_POINT POINT=CZ - ;SET_B_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=CZ1 - ;SET_B_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=AZ - ;SET_B_COMPENSATION_POINT POINT=2 - ;PROBE_TEMPLATE_POINT POINT=BZ - ;SET_B_COMPENSATION_POINT POINT=3 - ;PROBE_TEMPLATE_POINT POINT=AX - ;SET_B_COMPENSATION_POINT POINT=4 - ;PROBE_TEMPLATE_POINT POINT=BX - ;SET_B_COMPENSATION_POINT POINT=5 - ;CALC_B_AXIS_COMPENSATION ENABLE=0 - - ; skew corection - ; xy skew - ;PROBE_TEMPLATE_POINT POINT=AX - ;SET_SKEW_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=BX - ;SET_SKEW_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=XY1 - ;SET_SKEW_COMPENSATION_POINT POINT=2 - ;PROBE_TEMPLATE_POINT POINT=XY2 - ;SET_SKEW_COMPENSATION_POINT POINT=3 - ;CALC_SKEW_COMPENSATION FACTOR=XY - ; xz skew - ;PROBE_TEMPLATE_POINT POINT=BX - ;SET_SKEW_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=AX - ;SET_SKEW_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=XZ3 - ;SET_SKEW_COMPENSATION_POINT POINT=2 - ;PROBE_TEMPLATE_POINT POINT=XZ4 - ;SET_SKEW_COMPENSATION_POINT POINT=3 - ;CALC_SKEW_COMPENSATION FACTOR=XZ - ; yz skew - ;PROBE_TEMPLATE_POINT POINT=YZ1 - ;SET_SKEW_COMPENSATION_POINT POINT=0 - ;PROBE_TEMPLATE_POINT POINT=YZ2 - ;SET_SKEW_COMPENSATION_POINT POINT=1 - ;PROBE_TEMPLATE_POINT POINT=YZ3 - ;SET_SKEW_COMPENSATION_POINT POINT=2 - ;CALC_SKEW_COMPENSATION FACTOR=YZ - ; save profile 5d - ;SKEW_PROFILE SAVE=module_5d - - - AUTO_WCS_OFFSET_NEW_SENSOR - M204 S1500 - {% endif %} - [gcode_macro SET_C_ALIGN_POINT] gcode: {% set point = printer.probe.last_result %} @@ -208,28 +133,6 @@ gcode: {% set index = params.POINT|default(0) %} SAVE_SKEW_POINT POINT={index} COORDS='{x},{y},{z}' -[gcode_macro ADJUST_TEMPLATE_HEIGHT] -gcode: - PROBE_TEMPLATE_POINT - SET_TEMPLATE_HEIGHT - -[gcode_macro SET_TEMPLATE_HEIGHT] -gcode: - SET_GCODE_VARIABLE MACRO=PROBE_TEMPLATE_POINT VARIABLE=probe_z VALUE={printer.probe.last_result[2] - printer.gcode_move.homing_origin.z} - -[c_axis_align] -[auto_wcs] - -[skew_correction module_3d] -xy_skew = 0.0 -xz_skew = 0.0 -yz_skew = 0.0 - -[skew_correction module_5d] -xy_skew = 0.0 -xz_skew = 0.0 -yz_skew = 0.0 - [gcode_macro SET_AUTO_WCS_POINT] gcode: {% set point = printer.probe.last_result %} @@ -241,108 +144,23 @@ gcode: {% set home_min = printer.toolhead.axis_minimum %} {% set home_max = printer.toolhead.axis_maximum %} {% if x < home_min[0] or x > home_max[0] %} - {action_raise_error('axis x=%f out of range (%f - %f)' % (x, home_min[0], home_max[0]))} + {action_raise_error('201: axis x=%f out of range (%f - %f)' % (x, home_min[0], home_max[0]))} {% elif y < home_min[1] or y > home_max[1] %} - {action_raise_error('axis y=%f out of range (%f - %f)' % (y, home_min[1], home_max[1]))} + {action_raise_error('202: axis y=%f out of range (%f - %f)' % (y, home_min[1], home_max[1]))} {% elif z < home_min[2] or z > home_max[2] %} - {action_raise_error('axis z=%f out of range (%f - %f)' % (z, home_min[2], home_max[2]))} + {action_raise_error('203: axis z=%f out of range (%f - %f)' % (z, home_min[2], home_max[2]))} {% endif %} {% set index = params.POINT|default(0) %} SAVE_WCS_CALC_POINT POINT={index} COORDS='{x},{y},{z}' -[gcode_macro AUTO_WCS_OFFSET_OLD_SERNSOR] -gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - G0 C0.1 - G0 C0 - ADJUST_TEMPLATE_HEIGHT - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - ADJUST_TEMPLATE_HEIGHT - SET_AUTO_WCS_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=AY1 - SET_AUTO_WCS_POINT POINT=1 - PROBE_TEMPLATE_POINT POINT=AY2 - SET_AUTO_WCS_POINT POINT=7 - PROBE_TEMPLATE_POINT POINT=AX - SET_AUTO_WCS_POINT POINT=2 - PROBE_TEMPLATE_POINT POINT=BX - SET_AUTO_WCS_POINT POINT=3 - PROBE_TEMPLATE_POINT POINT=DZ - SET_AUTO_WCS_POINT POINT=4 - PROBE_TEMPLATE_POINT POINT=DY - SET_AUTO_WCS_POINT POINT=5 - PROBE_TEMPLATE_POINT POINT=EY - SET_AUTO_WCS_POINT POINT=6 - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} - {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.25)|float %} - CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION=1 - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - MOVE_TO_AUTO_WCS - {% endif %} - -[gcode_macro AUTO_WCS_OFFSET_NEW_SENSOR] +[gcode_macro ADJUST_TEMPLATE_HEIGHT] gcode: - {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} - G0 C0.1 - G0 C0 - ADJUST_TEMPLATE_HEIGHT - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - ADJUST_TEMPLATE_HEIGHT - SET_AUTO_WCS_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=AY2_2 - SET_AUTO_WCS_POINT POINT=7 - PROBE_TEMPLATE_POINT POINT=AY1_2 - SET_AUTO_WCS_POINT POINT=1 - PROBE_TEMPLATE_POINT POINT=BX - SET_AUTO_WCS_POINT POINT=3 - PROBE_TEMPLATE_POINT POINT=AX - SET_AUTO_WCS_POINT POINT=2 - PROBE_TEMPLATE_POINT POINT=DZ_2 - SET_AUTO_WCS_POINT POINT=4 - PROBE_TEMPLATE_POINT POINT=EY_2 - SET_AUTO_WCS_POINT POINT=6 - PROBE_TEMPLATE_POINT POINT=DY_2 - SET_AUTO_WCS_POINT POINT=5 - PROBE_TEMPLATE_POINT POINT=CX1 - SET_AUTO_WCS_POINT POINT=8 - PROBE_TEMPLATE_POINT POINT=CX2 - SET_AUTO_WCS_POINT POINT=9 - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} - {% set auto_wcs_adj = printer.save_variables.variables.auto_wcs_adj|default(0.3)|float %} - CALC_WCS_PARAMS THICKNESS={ template_thickness } ADJUSTMENT={ auto_wcs_adj } SENSOR_VERSION=1 - SAVE_PROBE_BACKLASH - PROBE_TEMPLATE_POINT POINT=AY - SET_C_ALIGN_POINT POINT=0 - PROBE_TEMPLATE_POINT POINT=BY - SET_C_ALIGN_POINT POINT=1 - CALC_C_AXIS_ALIGN - MOVE_TO_AUTO_WCS - {% endif %} + PROBE_TEMPLATE_POINT + SET_TEMPLATE_HEIGHT -[gcode_macro SAVE_PROBE_BACKLASH] -description: this macros save the sensor backlash. +[gcode_macro SET_TEMPLATE_HEIGHT] gcode: - {% set probe_backlash_x = printer.auto_wcs.probe_backlash_x %} - {% set probe_backlash_y = printer.auto_wcs.probe_backlash_y %} - {% set probe_backlash_y_2 = printer.auto_wcs.probe_backlash_y_2 %} - SAVE_VARIABLE VARIABLE=probe_backlash_x VALUE={probe_backlash_x} - SAVE_VARIABLE VARIABLE=probe_backlash_y VALUE={probe_backlash_y} - SAVE_VARIABLE VARIABLE=probe_backlash_y_2 VALUE={probe_backlash_y_2} - {action_respond_info('probe_backlash_x=%s' % probe_backlash_x)} - {action_respond_info('probe_backlash_y=%s' % probe_backlash_y)} - {action_respond_info('probe_backlash_y_2=%s' % probe_backlash_y_2)} + SET_GCODE_VARIABLE MACRO=PROBE_TEMPLATE_POINT VARIABLE=probe_z VALUE={printer.probe.last_result[2] - printer.gcode_move.homing_origin.z} [gcode_macro MOVE_TO_AUTO_WCS] gcode: @@ -378,7 +196,6 @@ gcode: {% endif %} {% endif %} - [gcode_macro ADJUST_PROBE_OFFSET_XY] gcode: {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} @@ -424,31 +241,20 @@ gcode: G0 X100 Y50 F3600 {% endif %} -[gcode_macro AUTO_BASEMENT_WCS] -description: This macro performs move based on the required measuring(wcs1_z, wcs2_y, wcs2_z), and takes measurements. +[gcode_macro AUTO_BASEMENT_WCS_MOVE] +description: This macro does a move for measuring wcs_1_z and wcs_2_y-raw mode FULL wcs_2_y and wcs_1_z-raw mode SPIRAL. gcode: {% set wcs = params.WCS|default(0)|int %} - {% set probe_sensor_version = printer.save_variables.variables.probe_sensor_version|default(0)|int %} - {% if wcs == 0 %} - ; move for measuring wcs_1_z - AUTO_BASEMENT_WCS_MOVE - PROBE - ; set wcs_1_z, wcs_2_y(raw) - ADJUST_BASEMENT_WCS WCS=2 - G0 Z150 F3600 - ; get tool length - GET_TOOL_LENGTH - ; moving for measure radius the tool - TOOL_RADIUS - G0 Z150 F3600 - ; checking axis A - CHECK_AXIS_A - ; move and probing for measuring the wcs_2_y - AUTO_BASEMENT_WCS_TWO_Y_MOVE - {% else %} - PROBE - {% endif %} + {% set offsets = printer.probe.offsets %} + {% set wcs_offsets = printer.gcode_move.wcs_offsets[wcs + 3] %} + {% set x = wcs_offsets[0] - offsets[0] %} + {% set y = wcs_offsets[1] - offsets[1] %} + {% set z = wcs_offsets[2] + offsets[2] %} + {% set a = '0' if wcs == 0 else '90' %} + G28 A + G0 A{a} F3600 G0 Z150 F3600 + G0 X{x} Y{y} F3600 [gcode_macro CHECK_AXIS_A] description: This macro moves, measures the a-axis, and gets the difference between the two measuring points and apply offset. @@ -462,159 +268,119 @@ gcode: [gcode_macro GET_TOOL_LENGTH] description: This macro calculate length tool. -variable_length_is_enough: 0 +variable_tool_length: 0.0 gcode: {% set old_y = printer.gcode_move.wcs_offsets[4][1] %} - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} + {% set template_thickness = 10.0 %} {% set wcs_2_y = printer.gcode_move.wcs_offsets[2][1] %} {% set tool_length = old_y + template_thickness - wcs_2_y %} - {% if tool_length > 35.0 %} - SET_GCODE_VARIABLE MACRO=GET_TOOL_LENGTH VARIABLE=length_is_enough VALUE=1 - {action_respond_info('Tool length=%s' % tool_length)} - {% else %} - {action_respond_info("Warning tool length less 35mm!")} - {% endif %} - -[gcode_macro AUTO_BASEMENT_WCS_MOVE] -description: This macro does a move for measuring wcs_1_z and wcs_2_y-raw or wcs_2_y and wcs_1_z-raw. -gcode: - {% set wcs = params.WCS|default(0)|int %} - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[wcs + 3] %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - {% set a = '0' if wcs == 0 else '90' %} - G0 A{a} F3600 - G0 Z150 F3600 - G0 X{x} Y{y} F3600 - -[gcode_macro AUTO_BASEMENT_WCS_TWO_Y_MOVE] -description: This macro does a move for measuring wcs_2_y. -variable_length_is_enough: 1 -gcode: - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[2] %} - {% set radius = printer.auto_wcs.tooling_radius|float %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - {% set old_y = printer.gcode_move.wcs_offsets[4][1] %} - {% set template_thickness = printer.save_variables.variables.template_thickness|default(10.0)|float %} - {% set wcs_2_y = printer.gcode_move.wcs_offsets[2][1] %} - {% set tool_length = old_y + template_thickness - wcs_2_y %} - {action_respond_info('tool_length=%s' % tool_length)} - {% if tool_length > 35.0 %} - SET_GCODE_VARIABLE MACRO=AUTO_BASEMENT_WCS_TWO_Y_MOVE VARIABLE=length_is_enough VALUE=1 - G0 A90 F3600 - G0 X{x} Y{y - 20} F3600 - G0 Z{z + (radius - 4) } F3600 - PROBE AXIS=y POSITIVE_DIR=1 - G0 X{x} Y{y - 20} F3600 - {% else %} - SET_GCODE_VARIABLE MACRO=AUTO_BASEMENT_WCS_TWO_Y_MOVE VARIABLE=length_is_enough VALUE=0 - {action_raise_error("Tool length not enough for calculate wcs_2_y!")} - {% endif %} + SET_GCODE_VARIABLE MACRO=GET_TOOL_LENGTH VARIABLE=tool_length VALUE={tool_length} + {action_respond_info('tool length=%s' % tool_length)} [gcode_macro TOOL_RADIUS] description: moved to measure tool radius and calculate it. gcode: - {% for i in range(3) %} - AUTO_BASEMENT_MOVE_MEASURE_RADIUS PROBE={i} - SET_AUTO_WCS_POINT_RADIUS POINT={i} - {% endfor %} - GET_RADIUS_TOOLING - -[gcode_macro AUTO_BASEMENT_MOVE_MEASURE_RADIUS] -description: measuring radius for geting wcs_2_z. -gcode: - {% set probe = params.PROBE|default(0)|int %} - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[1] %} - {% set point = printer.probe.last_result %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - G0 A0 F3600 - {% if probe == 0 %} - G0 X{x} Y{y - 60} F3600 - G0 Z{z - 5} F3600 - PROBE AXIS=y POSITIVE_DIR=1 - G0 X{x} Y{y - 60} F3600 - {% elif probe == 1 %} - {% set advance_radius = y - point[1] %} - G0 X{x - (advance_radius + 10)} Y{y} F3600 - G0 Z{z - 5} F3600 - PROBE AXIS=x POSITIVE_DIR=1 - G0 X{x - (advance_radius + 10)} Y{y} F3600 - {% elif probe == 2 %} - {% set advance_radius = x - point[0] %} - G0 X{x + (advance_radius + 10)} Y{y} F3600 - G0 Z{z - 5} F3600 - PROBE AXIS=x POSITIVE_DIR=0 - G0 X{x + (advance_radius + 10)} Y{y} F3600 + {% set mode = params.MODE %} + {% if mode == 'full' %} + PROBE_TOOL_POINT POINT=Y_1 WCS=1 + SET_AUTO_WCS_POINT POINT=0 + GET_RADIUS_TOOLING ROUGH=1 MODE={mode} + PROBE_TOOL_POINT POINT=X_1_0 WCS=1 + SET_AUTO_WCS_POINT POINT=1 + PROBE_TOOL_POINT POINT=X_1_1 WCS=1 + SET_AUTO_WCS_POINT POINT=2 + GET_RADIUS_TOOLING MODE={mode} + {% elif mode == 'spiral' %} + PROBE_TOOL_POINT POINT=Z_2_0 WCS=2 + SET_AUTO_WCS_POINT POINT=0 + PROBE_TOOL_POINT POINT=X_2_0 WCS=2 + SET_AUTO_WCS_POINT POINT=1 + PROBE_TOOL_POINT POINT=X_2_1 WCS=2 + SET_AUTO_WCS_POINT POINT=2 + GET_RADIUS_TOOLING MODE={mode} {% endif %} - G0 Z{z + 10} F3600 -[gcode_macro SET_AUTO_WCS_POINT_RADIUS] -description: This macro is for saving the points required for calculating the radius. +[gcode_macro MOVE_ACCURACY_SET_MODULE_FIVE_D] +Description: This macro do moved for accuracy set the module 5d. gcode: - {% set point = printer.probe.last_result %} - {% set index = params.POINT|default(0) %} - {% set x = point[0] %} - {% set y = point[1] %} - {% set z = point[2] %} - SAVE_WCS_CALC_POINT POINT={index} COORDS='{x},{y},{z}' + G28 A + M204 S500 + G0 C0.1 + G0 C0 + ADJUST_TEMPLATE_HEIGHT + + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + + PROBE_TEMPLATE_POINT POINT=O + SET_A_OFFSET_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=CZ + SET_A_OFFSET_POINT POINT=1 + CALC_A_AXIS_OFFSET -[gcode_macro AUTO_BASEMENT_WCS_TWO_Z_MOVE] -description: This macro does a move for measuring wcs_2_z. + PROBE_TEMPLATE_POINT POINT=CHECK_MODULE_Z1 + SET_SKEW_COMPENSATION_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=CHECK_MODULE_Z2 + SET_SKEW_COMPENSATION_POINT POINT=1 + PROBE_TEMPLATE_POINT POINT=YZ2 + SET_SKEW_COMPENSATION_POINT POINT=2 + PROBE_TEMPLATE_POINT POINT=YZ3 + SET_SKEW_COMPENSATION_POINT POINT=3 + CHECK_ACCURACY_SET_MODULE_FIVE_D + +[gcode_macro CHECK_SKEW_TOOL] +description: This macro check skew axis X beetwen two X point. gcode: - {% set offsets = printer.probe.offsets %} - {% set wcs_offsets = printer.gcode_move.wcs_offsets[2] %} - {% set radius = printer.auto_wcs.tooling_radius %} - {% set x = wcs_offsets[0] - offsets[0] %} - {% set y = wcs_offsets[1] - offsets[1] %} - {% set z = wcs_offsets[2] + offsets[2] %} - G0 A90 F3600 - G0 X{x} Y{y + 5} F3600 - G0 Z{z + (radius + 10)} F3600 - PROBE - G0 Z150 F3600 + {% set tool_length = printer['gcode_macro GET_TOOL_LENGTH'].tool_length|float %} + CALC_SKEW_COMPENSATION_WCS FACTOR=XY + CALC_SKEW_COMPENSATION_WCS FACTOR=XZ + CALC_SKEW_COMPENSATION_WCS FACTOR=YZ + SKEW_PROFILE SAVE=module_5d + {% if tool_length > 50.0 %} + G0 Z150 F3600 + PROBE_TOOL_POINT POINT=X_2_0 WCS=2 + SET_SKEW_COMPENSATION_POINT POINT=2 + PROBE_TOOL_POINT POINT=X_2_1 WCS=2 + SET_SKEW_COMPENSATION_POINT POINT=3 + PROBE_TOOL_POINT POINT=X_2_3 WCS=2 + SET_SKEW_COMPENSATION_POINT POINT=0 + PROBE_TOOL_POINT POINT=X_2_2 WCS=2 + SET_SKEW_COMPENSATION_POINT POINT=1 + CALC_SKEW_COMPENSATION FACTOR=XY MSG=skew_calculate_by_tool + SKEW_PROFILE SAVE=module_5d + {% else %} + {action_respond_info('Warning, tool length less 50mm for calculate skew for the axis X, where use only wcs_2 points!')} + {% endif %} -[gcode_macro ADJUST_BASEMENT_WCS] -description: macro needed for set wcs based selected mode the manager calibrate. +[gcode_macro SET_ECCENTRICITY] +Description: This macro save eccentricity for wcs_1. gcode: - {% set wcs = params.WCS|default(0)|int %} - {% set point = printer.probe.last_result %} - {% set offsets = printer.probe.offsets %} - {% set wcs_0 = printer.gcode_move.wcs_offsets[3] %} - {% set x = point[0] + offsets[0] - printer.gcode_move.homing_origin.x %} - {% set y = point[1] + offsets[1] - printer.gcode_move.homing_origin.y %} - {% set z = point[2] - offsets[2] - printer.gcode_move.homing_origin.z %} - {% set wcs_1 = printer.gcode_move.wcs_offsets[4] %} - {% set old_z = wcs_0[2] %} - {% set old_y = wcs_1[1] %} - {% set probe_backlash_y = printer.save_variables.variables.probe_backlash_y|default(0.0)|float %} - {% if wcs == 0 %} - ; Mode SPIRAL-FULL - ; apply measuring for the set wcs_2_y. - G10 L2 P3 Y{y + probe_backlash_y} - {% elif wcs == 1 %} - ; Mode SPIRAL - ; apply measuring for the set wcs_2_y and wcs_1_z(raw). - G10 L2 P3 Y{y} - G10 L2 P2 Z{old_z - (y - old_y)} - {% elif wcs == 2 %} - ; Mode SPIRAL-FULL - ; crutch! for the support different version sensor - ; set wcs_1_z and wcs_2_y(raw). - G10 L2 P2 Z{z} - G10 L2 P3 Y{old_y - (z - old_z)} - {% elif wcs == 3 %} - ; {% set radius = printer.auto_wcs.tooling_radius %} - ; apply measuring for the set wcs_2_z radius. - ; G10 L2 P3 Z{z - radius} - {% endif %} + {% set x1 = params.X1|default(0.0)|float %} + {% set x2 = params.X2|default(0.0)|float %} + {% set y1 = params.Y1|default(0.0)|float %} + {% set y2 = params.Y2|default(0.0)|float %} + {% set offset_x = (x2 - x1) / 2 %} + {% set offset_y = (y1 - y2) / 2 %} + SAVE_VARIABLE VARIABLE=eccentricity_offset_x VALUE={offset_x} + SAVE_VARIABLE VARIABLE=eccentricity_offset_y VALUE={offset_y} + {action_respond_info('offset_x=%.3f; offset_y=%.3f for correcting ECCENTRICITY saved! Please use calibrate mode "auto calibrate the start point" for apply this params.' % (offset_x, offset_y))} + +[gcode_macro APPLY_ECCENTRICITY] +Description: This macro apply eccentricity correction for wcs_1. +gcode: + {% set svv = printer.save_variables.variables %} + {% set offset_x = svv.eccentricity_offset_x|default(0.0)|float %} + {% set offset_y = svv.eccentricity_offset_y|default(0.0)|float %} + {% set old_x = printer.gcode_move.wcs_offsets[1][0] %} + {% set old_y = printer.gcode_move.wcs_offsets[1][1] %} + {% set new_x = old_x + offset_x %} + {% set new_y = old_y + offset_y %} + G10 L2 P2 R1 X{offset_x} + G10 L2 P2 R1 Y{offset_y} + {action_respond_info('Applied offset for corrective eccentricity.\noffset_x=%.3f; offset_y=%.3f. Old wcs_1_x=%.3f, wcs_1_y=%.3f. New wcs_1_x=%.3f, wcs_1_y=%.3f' % (offset_x, offset_y, old_x, old_y, new_x, new_y))} [gcode_macro PROBE_TOOL_POINT] Description: This macro does movement and measurement relative to the tool. @@ -628,20 +394,90 @@ gcode: {% set y = wcs_offsets[1] - offsets[1] %} {% set z = wcs_offsets[2] + offsets[2] %} {% set radius = printer.auto_wcs.tooling_radius|float %} - {% set tool_length = printer['gcode_macro GET_TOOL_LENGTH'].length_is_enough|int %} + {% set tool_length = printer['gcode_macro GET_TOOL_LENGTH'].tool_length|float %} {% set a = '0' if wcs == 1 else '90' %} {% set checking = 'true' %} - {% if point == 'Z_2_0' %} + {% if point == 'X_1_0' %} + {% set x = x - (radius + 10) %} + {% set z = z - 5 %} + {% set axis_name = 'X' %} + {% set positiv_dir = 1 %} + {% elif point == 'X_1_1' %} + {% set axis_name = 'X' %} + {% set x = x + 10 + radius %} + {% set z = z - 5 %} + {% elif point == 'Y_1_0' %} + {% set axis_name = 'Y' %} + {% set positiv_dir = 1 %} + {% set y = y - (radius + 10) %} + {% set z = z - 5 %} + {% set checking = 'true' if radius < 10.0 else 'false' %} + {% set msg = 'Error, radius not enough!' %} + {% elif point == 'Y_1_1' %} + {% set axis_name = 'Y' %} + {% set z = z - 5 %} + {% set y = printer.toolhead.axis_maximum[1] - 1 %} + {% set checking = 'true' if radius < 10.0 else 'false' %} + {% set msg = 'Error, radius not enough!' %} + {% elif point == 'Y_1' %} + ; move for get advance radius + {% set axis_name = 'Y' %} + {% set positiv_dir = 1 %} + {% set y = y - 60 %} + {% set z = z - 5 %} + {% elif point == 'Z_1' %} + {% set axis_name = 'Z' %} + {% set z = 150 %} + {% set a = 0 %} + G28 A + {% elif point == 'X_2_0' %} + {% set axis_name = 'X' %} + {% set positiv_dir = 1 %} + {% set x = x - 15 %} + {% set y = y + 1 %} + {% set z = z + (radius - 5) %} + {% set checking = 'true' if tool_length > 35.0 else 'false' %} + {% set msg = 'Error, tool length not enough!' %} + {% elif point == 'X_2_1' %} + {% set axis_name = 'X' %} + {% set x = x + 15 %} + {% set y = y + 1 %} + {% set z = z + (radius - 5) %} + {% set checking = 'true' if tool_length > 35.0 else 'false' %} + {% set msg = 'Error, tool length not enough!' %} + {% elif point == 'X_2_2' %} + {% set axis_name = 'X' %} + {% set positiv_dir = 1 %} + {% set x = x - 15 %} + {% set y = y + 16 %} + {% set z = z + (radius - 5) %} + {% set checking = 'true' if tool_length > 50.0 else 'false' %} + {% set msg = 'Error, tool length lees 50mm!' %} + {% elif point == 'X_2_3' %} + {% set axis_name = 'X' %} + {% set x = x + 15 %} + {% set y = y + 16 %} + {% set z = z + (radius - 5) %} + {% set checking = 'true' if tool_length > 50.0 else 'false' %} + {% set msg = 'Error, tool length lees 50mm!' %} + {% elif point == 'Y_2' %} + {% set axis_name = 'Y' %} + {% set positiv_dir = 1 %} + {% set y = y - 20 %} + {% set z = z + (radius - 4) %} + {% set checking = 'true' if tool_length > 35.0 else 'false' %} + {% set msg = 'Error, tool length not enough for calculate wcs_2_y!' %} + {% elif point == 'Z_2_0' %} {% set axis_name = 'Z' %} - {% set y = y + 3 %} + {% set y = y + 1 %} {% set z = z + (radius + 10) %} - {% set checking = 'true' if tool_length > 0 else 'false' %} + {% set checking = 'true' if tool_length > 35.0 else 'false' %} {% set msg = 'Error, tool length not enough!' %} {% elif point == 'Z_2_1' %} {% set axis_name = 'Z' %} {% set y = y + 25 %} {% set z = z + (radius + 10) %} - {% set checking = 'true' if tool_length > 0 else 'false' %} + {% set checking = 'true' if tool_length > 35.0 else 'false' %} {% set msg = 'Error, tool length not enough!' %} {% endif %} {% if checking == 'true' %} @@ -652,5 +488,182 @@ gcode: G0 X{x} Y{y} F3600 G0 Z{z + radius + 10} F3600 {% else %} - {action_raise_error('%s' % msg)} + {action_raise_error('205: %s' % msg)} + {% endif %} + +[gcode_macro CALIBRATE_MODULE_FIVE_D] +description: macro for get first point to auto calibrate 5d and align teamplate +gcode: + {% if printer["gcode_button five_axis_module"].state == "PRESSED" %} + G28 A + M204 S500 + G0 C0.1 + G0 C0 + ADJUST_TEMPLATE_HEIGHT + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + PROBE_TEMPLATE_POINT POINT=AY + SET_C_ALIGN_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=BY + SET_C_ALIGN_POINT POINT=1 + CALC_C_AXIS_ALIGN + + PROBE_TEMPLATE_POINT POINT=O + SET_A_OFFSET_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=CZ + SET_A_OFFSET_POINT POINT=1 + CALC_A_AXIS_OFFSET + PROBE_TEMPLATE_POINT POINT=O + SET_A_OFFSET_POINT POINT=0 + PROBE_TEMPLATE_POINT POINT=CZ + SET_A_OFFSET_POINT POINT=1 + CALC_A_AXIS_OFFSET + + ; checked accuracy set the module 5d. + ;MOVE_ACCURACY_SET_MODULE_FIVE_D + + ; calculate b compensation + ; PROBE_TEMPLATE_POINT POINT=CZ + ; SET_B_COMPENSATION_POINT POINT=0 + ; PROBE_TEMPLATE_POINT POINT=CZ1 + ; SET_B_COMPENSATION_POINT POINT=1 + ; PROBE_TEMPLATE_POINT POINT=AZ + ; SET_B_COMPENSATION_POINT POINT=2 + ; PROBE_TEMPLATE_POINT POINT=BZ + ; SET_B_COMPENSATION_POINT POINT=3 + ; PROBE_TEMPLATE_POINT POINT=AX + ; SET_B_COMPENSATION_POINT POINT=4 + ; PROBE_TEMPLATE_POINT POINT=BX + ; SET_B_COMPENSATION_POINT POINT=5 + ; CALC_B_AXIS_COMPENSATION ENABLE=0 + + ; skew corection + ; xy skew + ;PROBE_TEMPLATE_POINT POINT=AX + ;SET_SKEW_COMPENSATION_POINT POINT=0 + ;PROBE_TEMPLATE_POINT POINT=BX + ;SET_SKEW_COMPENSATION_POINT POINT=1 + ;PROBE_TEMPLATE_POINT POINT=XY1 + ;SET_SKEW_COMPENSATION_POINT POINT=2 + ;PROBE_TEMPLATE_POINT POINT=XY2 + ;SET_SKEW_COMPENSATION_POINT POINT=3 + ;CALC_SKEW_COMPENSATION FACTOR=XY + ;; xz skew + ;PROBE_TEMPLATE_POINT POINT=BX + ;SET_SKEW_COMPENSATION_POINT POINT=0 + ;PROBE_TEMPLATE_POINT POINT=AX + ;SET_SKEW_COMPENSATION_POINT POINT=1 + ;PROBE_TEMPLATE_POINT POINT=XZ3 + ;SET_SKEW_COMPENSATION_POINT POINT=2 + ;PROBE_TEMPLATE_POINT POINT=XZ4 + ;SET_SKEW_COMPENSATION_POINT POINT=3 + ;CALC_SKEW_COMPENSATION FACTOR=XZ + ;; yz skew + ;PROBE_TEMPLATE_POINT POINT=YZ1 + ;SET_SKEW_COMPENSATION_POINT POINT=0 + ;PROBE_TEMPLATE_POINT POINT=YZ2 + ;SET_SKEW_COMPENSATION_POINT POINT=1 + ;PROBE_TEMPLATE_POINT POINT=YZ3 + ;SET_SKEW_COMPENSATION_POINT POINT=2 + ;CALC_SKEW_COMPENSATION FACTOR=YZ + ;; save profile 5d + ;SKEW_PROFILE SAVE=module_5d + + CHECK_SENSOR_VERSION_AND_START_AUTOCALIBRATE + M204 S1500 + {% endif %} + +[gcode_macro MOVE_AUTOCALIBRATE_FULL_V_2] +description: macro do move for measuring and calculated WCS for FULL-SPIRALL mode. Sensor DAC_v_2 +gcode: + ; move for measuring wcs_1_z + PROBE_TOOL_POINT POINT=Z_1 WCS=3 + ; set wcs_1_z, wcs_2_y(raw) + ADJUST_BASEMENT_WCS WCS=2 + ; get tool length + GET_TOOL_LENGTH + ; moving for measure radius the tool + TOOL_RADIUS MODE=full + ; checking and apply offset for axis A + CHECK_AXIS_A + G0 Z150 F3600 + ; move for measuring the wcs_1_x + PROBE_TOOL_POINT POINT=X_1_0 WCS=1 + SET_AUTO_WCS_POINT POINT=0 + PROBE_TOOL_POINT POINT=X_1_1 WCS=1 + SET_AUTO_WCS_POINT POINT=1 + CALC_WCS_TOOL WCS=1 AXIS=0 + ; set wcs_1_x + ADJUST_BASEMENT_WCS WCS=4 + ; move for measuring the wcs_1_y + PROBE_TOOL_POINT POINT=Y_1_0 WCS=1 + SET_AUTO_WCS_POINT POINT=0 + PROBE_TOOL_POINT POINT=Y_1_1 WCS=1 + SET_AUTO_WCS_POINT POINT=1 + CALC_WCS_TOOL WCS=1 AXIS=1 + ; set wcs_1_y + ADJUST_BASEMENT_WCS WCS=5 + ; move for measuring the wcs_2_y + PROBE_TOOL_POINT POINT=Y_2 WCS=2 + ; set wcs_2_y + ADJUST_BASEMENT_WCS WCS=3 + ; move for measuring the wcs_2_x + PROBE_TOOL_POINT POINT=X_2_0 WCS=2 + SET_AUTO_WCS_POINT POINT=0 + PROBE_TOOL_POINT POINT=X_2_1 WCS=2 + SET_AUTO_WCS_POINT POINT=1 + CALC_WCS_TOOL WCS=2 AXIS=0 + ; set wcs_2_x + ADJUST_BASEMENT_WCS WCS=6 + ; eccentricity correction + ;APPLY_ECCENTRICITY + ; check skew axis X + CHECK_SKEW_TOOL + ; move for measuring the wcs_2_z + PROBE_TOOL_POINT POINT=Z_2_0 WCS=2 + +[gcode_macro MOVE_AUTOCALIBRATE_SPIRAL_V_2] +description: macro do move for measuring and calculated WCS for SPIRALL mode. Sensor DAC_v_2 +gcode: + ; move for measuring wcs_2_y + PROBE + G0 Z150 F3600 + ; set wcs_2_y and wcs_1_z(row) + ADJUST_BASEMENT_WCS WCS=7 + ; calculate rough radius + SET_AUTO_WCS_POINT POINT=0 + GET_RADIUS_TOOLING ROUGH=1 MODE=spiral + ; get tool length + GET_TOOL_LENGTH + ; move to calculate wcs by tool + MOVE_MEASHURING_SPIRAL + +[gcode_macro MOVE_MEASHURING_SPIRAL] +description: This macro do move and calculate wcs for SPIRAL mode. +gcode: + {% set wcs = params.WCS %} + {% set radius = printer.auto_wcs.tooling_radius %} + {% set tool_length = printer['gcode_macro GET_TOOL_LENGTH'].tool_length|float %} + {% if radius < 5.0 and tool_length > 35.0 %} + ; checking and apply offset for axis A + CHECK_AXIS_A + ; moving for measure radius the tool + TOOL_RADIUS MODE=spiral + ; move for measuring the wcs_2_x + PROBE_TOOL_POINT POINT=X_2_0 WCS=2 + SET_AUTO_WCS_POINT POINT=0 + PROBE_TOOL_POINT POINT=X_2_1 WCS=2 + SET_AUTO_WCS_POINT POINT=1 + CALC_WCS_TOOL WCS=2 AXIS=0 + ; set wcs_2_x + ADJUST_BASEMENT_WCS WCS=6 + ; check skew axes + CHECK_SKEW_TOOL + ; move for measuring the wcs_2_z + PROBE_TOOL_POINT POINT=Z_2_0 WCS=2 + {% else %} + {action_respond_info("Radius greater than 5 mm or tool length less 35mm, movement to calculate wcs by tool is not available. Wcs will be calculated from the template.")} {% endif %} diff --git a/stereotech_config/second_extruder.cfg b/stereotech_config/second_extruder.cfg index 6e4091d6711c..4f49cafd823c 100644 --- a/stereotech_config/second_extruder.cfg +++ b/stereotech_config/second_extruder.cfg @@ -7,7 +7,7 @@ rotation_distance: 7.777 nozzle_diameter: 0.4 filament_diameter: 1.75 heater_pin: second_extruder_heater_pin -sensor_type: EPCOS 100K B57560G104F +sensor_type: NTC 100K MGB18-104F39050L32 sensor_pin: second_extruder_sensor_pin control: pid pid_Kp: 13.509 @@ -18,6 +18,7 @@ max_temp: 320 min_extrude_temp: 100 max_extrude_only_distance: 300.0 max_extrude_cross_section: 2.56 +fiber: false [gcode_macro T1] variable_t1_offset_enabled: 0 @@ -28,8 +29,9 @@ gcode: SET_GCODE_VARIABLE MACRO=T1 VARIABLE=t1_offset_enabled VALUE=1 {% endif %} {% set current_wcs = printer.gcode_move.current_wcs %} - {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder1' %} + {% if "x" in printer.toolhead.homed_axes and "y" in printer.toolhead.homed_axes and "z" in printer.toolhead.homed_axes and printer.toolhead.extruder != 'extruder1' %} G54 + MOVE_DOWN_Z_AXIS Z=5 G0 X10 Y2 F3600 {% endif %} ACTIVATE_EXTRUDER extruder=extruder1 diff --git a/stereotech_config/v6/board_stm.cfg b/stereotech_config/v6/board_stm.cfg deleted file mode 100644 index 481ec8f5af48..000000000000 --- a/stereotech_config/v6/board_stm.cfg +++ /dev/null @@ -1,45 +0,0 @@ -[board_pins] -mcu: - mcu, second_mcu -aliases: - ; mcu_bigtreetech_octopus_pro - x_step_pin=PF13, x_dir_pin=PF12, x_en_pin=PF14, x_endstop_pin=PG6, - y_step_pin=PG0, y_dir_pin=PG1, y_en_pin=PF15, y_endstop_pin=PG9, - z_step_pin=PF11, z_dir_pin=PG3, z_en_pin=PG5, z_endstop_pin=PG10, - a_step_pin=PG4, a_dir_pin=PC1, a_en_pin=PA0, a_endstop_pin=PG11, - c_step_pin=PF9, c_dir_pin=PF10, c_en_pin=PG2, c_endstop_pin=PG12, - door_endswitch=PG13, filament_control_1=PG14, filament_control_2=PG15, - - led_pin=PB0, - - bed_heater=PA1, bed_sensor=PF5, - - - - main_nozzle_blower_heater=PA2, main_nozzle_blower_sensor=PF6, - second_nozzle_blower_heater=PA3, second_nozzle_blower_sensor=PF7, - - ; air_compressor=PB10, blower_air_compressor=PD15, ????? - - cooling_fan_heat=PA8, turbine_5d=PE5, fan_5d=PD12, pump=PD13, - fan_pump_cooling=PD14, - - ; mcu_bigtreetech_octopus_pro - main_extruder_step_pin=second_mcu:PE2, main_extruder_dir_pin=second_mcu:PB8, - main_extruder_enable_pin=second_mcu:PC11, main_extruder_heater_pin=second_mcu:PE3, - main_extruder_sensor_pin=second_mcu:PA2, - - second_extruder_step_pin=second_mcu:PF12, second_extruder_dir_pin=second_mcu:PF11, - second_extruder_enable_pin=second_mcu:PB3, second_extruder_heater_pin=second_mcu:PB5, - second_extruder_sensor_pin=second_mcu:PA3, - - fiber_extruder_step_pin=second_mcu:PD7, fiber_extruder_dir_pin=second_mcu:PD6, - fiber_extruder_enable_pin=second_mcu:PF10, fiber_extruder_heater_pin=second_mcu:PB6, - fiber_extruder_sensor_pin=second_mcu:PA4, - - heater_fire_bar=second_mcu:PB7, temp_chamber=second_mcu:PA1, - - fiber_cut_pin=second_mcu:PA9, switching_extruder=second_mcu:PA15, - - - diff --git a/stereotech_config/v6/chamber.cfg b/stereotech_config/v6/chamber.cfg deleted file mode 100644 index 10be1bf5bfaa..000000000000 --- a/stereotech_config/v6/chamber.cfg +++ /dev/null @@ -1,162 +0,0 @@ -[heater_generic chamber_heater] -gcode_id: CHAM_HEATE -heater_pin: heater_fire_bar -sensor_type: ATC Semitec 104GT-2 -sensor_pin: temp_chamber -control: pid -pid_Kp: 13.509 -pid_Ki: 0.566 -pid_Kd: 80.549 -min_temp: -150 -max_temp: 320 - -[gcode_button endswitch_door] -pin: !door_endswitch -press_gcode: QUERY_BUTTON BUTTON=endswitch_door - -# cooling axis C -[heater_fan fan_axis_c] -pin: turbine_5d -heater: chamber_heater -heater_temp: 40.0 - -# cooling axis A and module 5D -[heater_fan fan_cooling_5d] -pin: fan_5d -heater: chamber_heater -heater_temp: 40.0 - -# [temperature_fan bottom_fan] -# pin: PD13 -# sensor_type: temperature_host -# control: pid -# pid_Kp: 15 -# pid_Ki: 0.5 -# pid_Kd: 25 -# min_temp: 0 -# max_temp: 90 -# target_temp: 45.0 -# min_speed: 0.0 -# gcode_id: E - -# LED Light controls - -[neopixel case_led] -pin: led_pin -chain_count: 1 -color_order: GRB -initial_RED: 0.0 -initial_GREEN: 0.0 -initial_BLUE: 0.0 - -[display_template led_white] -text: 0.0, 0.0, 0.0 - -[display_template led_red] -text: 1.0, 0.0, 0.0 - -[display_template led_green] -text: 0.0, 1.0, 0.0 - -[display_template led_blue] -text: 0.0, 0.0, 1.0 - -[display_template led_color] -param_red: 0.0 -param_green: 0.0 -param_blue: 0.0 -text: {param_red}, {param_green}, {param_blue} - -[display_template led_heatup] -text: {printer[printer.toolhead.extruder].temperature / 320}, 0.0, 1.0, 0.0 - -[gcode_macro M150] -description: Change color macro -variable_current_red_value: 0.0 -variable_current_green_value: 0.0 -variable_current_blue_value: 0.0 -gcode: - SET_GCODE_VARIABLE MACRO=M150 VARIABLE=current_red_value VALUE={printer["neopixel case_led"].color_data[0][0]} - SET_GCODE_VARIABLE MACRO=M150 VARIABLE=current_green_value VALUE={printer["neopixel case_led"].color_data[0][1]} - SET_GCODE_VARIABLE MACRO=M150 VARIABLE=current_blue_value VALUE={printer["neopixel case_led"].color_data[0][2]} - {% set duration = params.D|default(0)|float %} - {% set red_input = params.R|default(0)|float %} - {% set green_input = params.G|default(0)|float %} - {% set blue_input = params.B|default(0)|float %} - {% set red_value = red_input %} - {% set green_value = green_input%} - {% set blue_value = blue_input%} - M400 - SET_LED_TEMPLATE LED=case_led TEMPLATE=led_color param_red={red_value / 255} param_green={green_value / 255} param_blue={blue_value / 255} - ;SET_LED LED=case_led RED={red_value / 255} GREEN={green_value / 255} BLUE={blue_value / 255} - {% if duration > 0 %} - UPDATE_DELAYED_GCODE ID=return_color DURATION={duration} - {% endif %} - -[delayed_gcode return_color] -gcode: - M400 - SET_LED_TEMPLATE LED=case_led TEMPLATE=led_color param_red={printer["gcode_macro M150"].current_red_value} param_green={printer["gcode_macro M150"].current_green_value} param_blue={printer["gcode_macro M150"].current_blue_value} - ;SET_LED LED=case_led RED={printer["gcode_macro M150"].current_red_value} GREEN={printer["gcode_macro M150"].current_green_value} BLUE={printer["gcode_macro M150"].current_blue_value} - -[gcode_macro TOGGLE_LIGHT] -variable_light: 1 -gcode: - {% set red_value = printer["neopixel case_led"].color_data[0][0] %} - {% set green_value = printer["neopixel case_led"].color_data[0][1] %} - {% set blue_value = printer["neopixel case_led"].color_data[0][2] %} - {% set light_is_on = [white_value, red_value, green_value, blue_value]|max %} - {% if light_is_on > 0 %} - M150 R0 G0 B0 - SET_GCODE_VARIABLE MACRO=TOGGLE_LIGHT VARIABLE=light VALUE=0 - {% else %} - M150 R255 G255 B255 - SET_GCODE_VARIABLE MACRO=TOGGLE_LIGHT VARIABLE=light VALUE=1 - {% endif %} - -[gcode_macro STATUS_LED] -gcode: - {% set status = params.STATUS|default(printing) %} - {% if status == "started" %} - SET_LED_TEMPLATE LED=case_led TEMPLATE=led_heatup - {% elif status == "paused" %} - M150 R255 G255 B0 D5 - {% elif status == "completed" %} - M150 R0 G255 B0 D5 - {% elif status == "cancelled" %} - M150 R255 G0 B0 D3 - {% elif status == "printing" %} - {% if printer["gcode_macro TOGGLE_LIGHT"].light > 0 %} - M150 R255 G255 B255 - {% else %} - M150 R0 G0 B0 - {% endif %} - {% else %} - UPDATE_DELAYED_GCODE ID=return_color DURATION=0.1 - {% endif %} - -# [gcode_macro M106] -# rename_existing: M106.1 -# gcode: -# {% set p = params.P|default(0)|int %} -# {% set s = params.S|default(0)|int %} -# {% if p > 0 %} -# {% if p == 3 %} -# SET_FAN_SPEED FAN=chamber_fan SPEED={params.S|default(0)|int / 255} -# {% endif %} -# {% else %} -# M106.1 S{s} -# {% endif %} - -# [gcode_macro M107] -# rename_existing: M107.1 -# gcode: -# {% set p = params.P|default(0)|int %} -# {% if p > 0 %} -# {% if p == 3 %} -# SET_FAN_SPEED FAN=chamber_fan SPEED=0.0 -# {% endif %} -# {% else %} -# M107.1 -# {% endif %} - diff --git a/stereotech_config/v6/filament_control.cfg b/stereotech_config/v6/filament_control.cfg deleted file mode 100644 index 1458f6f843f2..000000000000 --- a/stereotech_config/v6/filament_control.cfg +++ /dev/null @@ -1,21 +0,0 @@ -[filament_motion_sensor extruder_sensor] -extruder: extruder -detection_length: 10.5 -event_delay: 60.0 -switch_pin: filament_control_1 -pause_on_runout: False -runout_gcode: - {% if printer.virtual_sdcard.is_active %} - {action_respond_info('The filament has run out or there is a problem with its supply at the Extruder 1.')} - # PAUSE TURN_OFF_EXTRUDERS=0 E=0 - {% else %} - FILAMENT_ERROR EXTRUDER=extruder - {% endif %} - -[gcode_macro FILAMENT_ERROR] -gcode: - {% if params.EXTRUDER == 'extruder' %} - {action_raise_error('Filament error on Extruder 1')} - {% else %} - {action_raise_error('Filament error on Extruder 2')} - {% endif %} diff --git a/stereotech_config/v6/filament_control_second.cfg b/stereotech_config/v6/filament_control_second.cfg deleted file mode 100644 index d27767a3e741..000000000000 --- a/stereotech_config/v6/filament_control_second.cfg +++ /dev/null @@ -1,13 +0,0 @@ -[filament_motion_sensor extruder1_sensor] -extruder: extruder1 -detection_length: 10.5 -event_delay: 60.0 -switch_pin: filament_control_2 -pause_on_runout: False -runout_gcode: - {% if printer.virtual_sdcard.is_active %} - {action_respond_info('The filament has run out or there is a problem with its supply at the Extruder 2.')} - # PAUSE TURN_OFF_EXTRUDERS=0 E=0 - {% else %} - FILAMENT_ERROR EXTRUDER=extruder1 - {% endif %} diff --git a/stereotech_config/v6/kinematics.cfg b/stereotech_config/v6/kinematics.cfg index 5b8f9bd2acf3..a46b07a4100c 100644 --- a/stereotech_config/v6/kinematics.cfg +++ b/stereotech_config/v6/kinematics.cfg @@ -2,8 +2,8 @@ kinematics: corexy_6axis max_velocity: 200 max_accel: 1500 -max_z_velocity: 20 -max_z_accel: 200 +max_z_velocity: 40 +max_z_accel: 100 square_corner_velocity: 2.5 [stepper_x] @@ -13,9 +13,10 @@ enable_pin: !x_en_pin microsteps: 128 rotation_distance: 40 endstop_pin: x_endstop_pin -position_endstop: 310 -position_max: 310 -homing_speed: 50 +position_endstop: 309 +position_max: 309 +position_min: -1 +homing_speed: 70 [stepper_y] step_pin: y_step_pin @@ -26,19 +27,20 @@ rotation_distance: 40 endstop_pin: y_endstop_pin position_endstop: 300.3 position_max: 300.3 -homing_speed: 50 +position_min: 0 +homing_speed: 70 [stepper_z] step_pin: z_step_pin dir_pin: !z_dir_pin enable_pin: !z_en_pin microsteps: 128 -rotation_distance: 4 +rotation_distance: 2 endstop_pin: z_endstop_pin position_endstop: 300 position_max: 300 position_min: -10 -homing_speed: 10 +homing_speed: 20 [stepper_a] step_pin: a_step_pin @@ -46,12 +48,12 @@ dir_pin: a_dir_pin enable_pin: !a_en_pin microsteps: 128 rotation_distance: 360 -gear_ratio: 80:20 -endstop_pin: a_endstop_pin +gear_ratio: 10:1 +endstop_pin: !a_endstop_pin position_endstop: 90 position_min: -10 position_max: 90 -homing_speed: 10 +homing_speed: 20 [stepper_c] step_pin: c_step_pin @@ -59,10 +61,10 @@ dir_pin: c_dir_pin enable_pin: !c_en_pin microsteps: 128 rotation_distance: 120 -gear_ratio: 80:20 +gear_ratio: 10:1 +# endstop_pin: !c_endstop_pin +# position_endstop: 0 +# position_min: 0 +# position_max: 120 can_home: false -endstop_pin: a_endstop_pin -;position_endstop: 90 -;position_min: -10 -;position_max: 90 -homing_speed: 10 +homing_speed: 20 diff --git a/stereotech_config/v6/module_3d.cfg b/stereotech_config/v6/module_3d.cfg deleted file mode 100644 index fae9d3b97bf9..000000000000 --- a/stereotech_config/v6/module_3d.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[heater_bed] -heater_pin: bed_heater -sensor_type: ATC Semitec 104GT-2 -sensor_pin: bed_sensor -control: pid -pid_Kp: 63.164 -pid_Ki: 2.379 -pid_Kd: 419.254 -min_temp: -100 -max_temp: 130 - -;[bed_screws] -;horizontal_move_z: 10.0 -;screw1: 159,275 -;screw1_fine_adjust: 159,0 -;screw2: 20,0 -;screw3: 282,0 diff --git a/stereotech_config/v6/printhead.cfg b/stereotech_config/v6/printhead.cfg deleted file mode 100644 index 891d361bb7e3..000000000000 --- a/stereotech_config/v6/printhead.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[heater_fan printhead_fan] -pin: cooling_fan_heat -heater: extruder, extruder1, extruder2 -heater_temp: 50.0 - -[heater_fan heatsink_fan] -pin: fan_pump_cooling, pump -heater: extruder, extruder1, extruder2 -heater_temp: 50.0 diff --git a/stereotech_config/v6/probe_hybrid_printer_v6.cfg b/stereotech_config/v6/probe_hybrid_printer_v6.cfg new file mode 100644 index 000000000000..abe51a480f09 --- /dev/null +++ b/stereotech_config/v6/probe_hybrid_printer_v6.cfg @@ -0,0 +1,229 @@ +[gcode_macro PROBE_TEMPLATE_POINT] +description: Macro for calibration template probing +variable_probe_z: 120.0 +gcode: + {% set point = params.POINT|default('O') %} + {% set offsets = printer['probe'].offsets %} + {% set O = [161 - offsets[0], 243 - offsets[1], 120] %} + {% if O[1] > 294.0 %} + O[1] = 294.0 + {% endif %} + G0 Z150 F3600 + G0 A0 C0 F3600 + {% set target_x = O[0] %} + {% set target_y = O[1] %} + {% set target_z = O[2] %} + {% set axis = 'Z' %} + {% set positive = 0 %} + {% if point=='AY' %} + {% set target_x = O[0] - 45 %} + {% set target_y = O[1] - 35 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + {% elif point=='CHECK_MODULE_Z1' %} + {% set target_x = O[0] - 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} + {% elif point=='CHECK_MODULE_Z2' %} + {% set target_x = O[0] + 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 5 %} + {% elif point=='AY1' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] - 83 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 C15 F3600 + {% elif point=='AY1_2' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] - 15 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 C30 + {% elif point=='AY2' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] - 6 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + G0 C15 F3600 + {% elif point=='AY2_2' %} + {% set target_x = O[0] - 32 %} + {% set target_y = O[1] + 17 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + G0 C30 F3600 + {% elif point=='BY' %} + {% set target_x = O[0] + 45 %} + {% set target_y = O[1] - 35 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + {% elif point=='CY' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 90 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + {% elif point=='DY' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 30 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 30 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C30 F3600 + {% elif point=='DY_2' %} + {% set target_x = O[0] + 2 %} + {% set target_y = O[1] - 80 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 12 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C90 F3600 + {% elif point=='EY' %} + {% set target_x = O[0] %} + {% set target_y = O[1] + 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 30 %} + {% set axis = 'Y' %} + G0 A90 C30 F3600 + {% elif point=='EY_2' %} + {% set target_x = O[0] + 2 %} + {% set target_y = O[1] + 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 12 %} + {% set axis = 'Y' %} + G0 A90 C90 F3600 + {% elif point=='AZ' %} + {% set target_x = O[0] - 45 %} + {% elif point=='BZ' %} + {% set target_x = O[0] + 45%} + {% elif point=='CZ' %} + {% set target_y = O[1] - 45 %} + {% elif point=='CZ1' %} + {% set target_y = O[1] - 45 %} + G0 A10 F3600 + {% elif point=='DZ' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 8 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 57 %} + G0 A90 C30 F3600 + {% elif point=='DZ_2' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 50 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 57 %} + G0 A90 F3600 + {% elif point=='EZ' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 57 %} + G0 A90 F3600 + {% elif point=='AX' %} + {% set target_x = O[0] - 80 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='AX1' %} + {% set target_x = O[0] - 40 %} + {% set target_y = O[1] - 45 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='AX2' %} + {% set target_x = O[0] - 80 %} + {% set target_y = O[1] + 2 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='BX' %} + {% set target_x = O[0] + 80 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='BX1' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] - 2 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='BX2' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] + 2 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + ; skew_correction + ; xy skew + {% elif point=='XY1' %} + {% set target_x = O[0] + 15 %} + {% set target_y = O[1] - 50 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='XY2' %} + {% set target_x = O[0] - 15 %} + {% set target_y = O[1] - 50 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + ; xz skew + {% elif point=='XZ1' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% elif point=='XZ2' %} + {% set target_x = O[0] - 80 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 6 %} + {% set axis = 'X' %} + {% set positive = 1 %} + {% elif point=='XZ3' %} + {% set target_x = O[0] + 15 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 36 %} + {% set axis = 'X' %} + G0 A90 C60 + {% elif point=='XZ4' %} + {% set target_x = O[0] - 15 %} + {% set target_y = O[1] - 5 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 36 %} + {% set axis = 'X' %} + {% set positive = 1 %} + G0 A90 C60 F3600 + ; yz skew + {% elif point=='YZ1' %} + {% set target_x = O[0] %} + {% set target_y = O[1] - 60 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z + 36 %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C60 F3600 + {% elif point=='YZ2' %} + {% set target_x = O[0] - 45 %} + {% set target_y = O[1] - 60 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C5 F3600 + {% elif point=='YZ3' %} + {% set target_x = O[0] + 45 %} + {% set target_y = O[1] - 60 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z %} + {% set axis = 'Y' %} + {% set positive = 1 %} + G0 A90 C-5 F3600 + {% elif point=='CX1' %} + {% set target_x = O[0] + 80 %} + {% set target_y = O[1] - 50 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 45 %} + {% set axis = 'X' %} + G0 A90 C-4 + {% elif point=='CX2' %} + {% set target_x = O[0] - 80 %} + {% set target_y = O[1] - 50 %} + {% set target_z = printer['gcode_macro PROBE_TEMPLATE_POINT'].probe_z - 45 %} + {% set axis = 'X' %} + {% set positive = 1 %} + G0 A90 C4 + {% endif %} + G0 X{target_x} Y{target_y} F1500 + G0 Z{target_z} F1500 + PROBE AXIS={axis} POSITIVE_DIR={positive} + G0 X{target_x} Y{target_y} F3600 + G0 Z{target_z} F3600 + G0 Z150 F3600 + G0 A0 C0 F3600 diff --git a/stereotech_config/v7/board_stm32f4.cfg b/stereotech_config/v7/board_stm32f4.cfg new file mode 100644 index 000000000000..3552f16e5e79 --- /dev/null +++ b/stereotech_config/v7/board_stm32f4.cfg @@ -0,0 +1,24 @@ +[board_pins] +mcu: + mcu +aliases: + x_step_pin=PF13, x_dir_pin=PF12, x_en_pin=PF14, x_endstop_pin=PG6, + y_step_pin=PG0, y_dir_pin=PG1, y_en_pin=PF15, y_endstop_pin=PG9, + z_step_pin=PF11, z_dir_pin=PG3, z_en_pin=PG5, z_endstop_pin=PG10, + a_step_pin=PG4, a_dir_pin=PC1, a_en_pin=PA0, a_endstop_pin=PG11, + c_step_pin=PF9, c_dir_pin=PF10, c_en_pin=PG2, c_endstop_pin=PG12, + door_endswitch=PG13, filament_control_1=PG14, filament_control_2=PG15, + + led_pin=PB0, + + bed_heater=PA1, bed_sensor=PF5, + + five_axis_pin=PG12, + + main_nozzle_blower_heater=PA2, main_nozzle_blower_sensor=PF6, + second_nozzle_blower_heater=PA3, second_nozzle_blower_sensor=PF7, + + ; air_compressor=PB10, blower_air_compressor=PD15, ????? + + cooling_fan_heat=PA8, turbine_5d=PE5, fan_5d=PD12, pump=PD13, + fan_pump_cooling=PD14, diff --git a/stereotech_config/v7/board_stm32g1b0.cfg b/stereotech_config/v7/board_stm32g1b0.cfg new file mode 100644 index 000000000000..5c4b5e2104c3 --- /dev/null +++ b/stereotech_config/v7/board_stm32g1b0.cfg @@ -0,0 +1,16 @@ +[board_pins second_mcu] +mcu: + second_mcu +aliases: + main_extruder_step_pin=PE2, main_extruder_dir_pin=PB4, main_extruder_enable_pin=PC11, main_extruder_cs_pin=PC10, + main_extruder_heater_pin=PE3, main_extruder_sensor_pin=PA2, + + second_extruder_step_pin=PF12, second_extruder_dir_pin=PF11, second_extruder_enable_pin=PB3, second_extruder_cs_pin=PF13, + second_extruder_heater_pin=PB5, second_extruder_sensor_pin=PA3, + + fiber_extruder_step_pin=PD7, fiber_extruder_dir_pin=PD6, fiber_extruder_enable_pin=PF10, fiber_extruder_cs_pin=PF9, + fiber_extruder_heater_pin=PB6, fiber_extruder_sensor_pin=PA4, + + heater_fire_bar=PB7, temp_chamber=PA1, + + fiber_cut_pin=PA9, switching_extruder=PB15, diff --git a/stereotech_config/v7/chamber.cfg b/stereotech_config/v7/chamber.cfg new file mode 100644 index 000000000000..e32c445df143 --- /dev/null +++ b/stereotech_config/v7/chamber.cfg @@ -0,0 +1,168 @@ +[fan_generic chamber_fan] +pin: PE6 + +# [fan_generic chamber_fan] +# pin: second_mcu: cooling_fan_heat + +# [heater_generic chamber_heater] +# gcode_id: CHAM_HEATE +# heater_pin: heater_fire_bar +# sensor_type: ATC Semitec 104GT-2 +# sensor_pin: temp_chamber +# control: pid +# pid_Kp: 13.509 +# pid_Ki: 0.566 +# pid_Kd: 80.549 +# min_temp: -150 +# max_temp: 320 + +# [gcode_button endswitch_door] +# pin: !door_endswitch +# press_gcode: QUERY_BUTTON BUTTON=endswitch_door + +# # cooling axis C +# [heater_fan fan_axis_c] +# pin: turbine_5d +# heater: chamber_heater +# heater_temp: 40.0 + +# # cooling axis A and module 5D +# [heater_fan fan_cooling_5d] +# pin: fan_5d +# heater: chamber_heater +# heater_temp: 40.0 + +# [temperature_fan bottom_fan] # ???????? +# pin: PD13 # ???????? +# sensor_type: temperature_host +# control: pid +# pid_Kp: 15 +# pid_Ki: 0.5 +# pid_Kd: 25 +# min_temp: 0 +# max_temp: 90 +# target_temp: 45.0 +# min_speed: 0.0 +# gcode_id: E + +# LED Light controls + +# [neopixel case_led] +# pin: led_pin +# chain_count: 1 +# color_order: GRB +# initial_RED: 0.0 +# initial_GREEN: 0.0 +# initial_BLUE: 0.0 + +# [display_template led_white] +# text: 0.0, 0.0, 0.0 + +# [display_template led_red] +# text: 1.0, 0.0, 0.0 + +# [display_template led_green] +# text: 0.0, 1.0, 0.0 + +# [display_template led_blue] +# text: 0.0, 0.0, 1.0 + +# [display_template led_color] +# param_red: 0.0 +# param_green: 0.0 +# param_blue: 0.0 +# text: {param_red}, {param_green}, {param_blue} + +# [display_template led_heatup] +# text: {printer[printer.toolhead.extruder].temperature / 320}, 0.0, 1.0, 0.0 + +# [gcode_macro M150] +# description: Change color macro +# variable_current_red_value: 0.0 +# variable_current_green_value: 0.0 +# variable_current_blue_value: 0.0 +# gcode: +# SET_GCODE_VARIABLE MACRO=M150 VARIABLE=current_red_value VALUE={printer["neopixel case_led"].color_data[0][0]} +# SET_GCODE_VARIABLE MACRO=M150 VARIABLE=current_green_value VALUE={printer["neopixel case_led"].color_data[0][1]} +# SET_GCODE_VARIABLE MACRO=M150 VARIABLE=current_blue_value VALUE={printer["neopixel case_led"].color_data[0][2]} +# {% set duration = params.D|default(0)|float %} +# {% set red_input = params.R|default(0)|float %} +# {% set green_input = params.G|default(0)|float %} +# {% set blue_input = params.B|default(0)|float %} +# {% set red_value = red_input %} +# {% set green_value = green_input%} +# {% set blue_value = blue_input%} +# M400 +# SET_LED_TEMPLATE LED=case_led TEMPLATE=led_color param_red={red_value / 255} param_green={green_value / 255} param_blue={blue_value / 255} +# ;SET_LED LED=case_led RED={red_value / 255} GREEN={green_value / 255} BLUE={blue_value / 255} +# {% if duration > 0 %} +# UPDATE_DELAYED_GCODE ID=return_color DURATION={duration} +# {% endif %} + +# [delayed_gcode return_color] +# gcode: +# M400 +# SET_LED_TEMPLATE LED=case_led TEMPLATE=led_color param_red={printer["gcode_macro M150"].current_red_value} param_green={printer["gcode_macro M150"].current_green_value} param_blue={printer["gcode_macro M150"].current_blue_value} +# ;SET_LED LED=case_led RED={printer["gcode_macro M150"].current_red_value} GREEN={printer["gcode_macro M150"].current_green_value} BLUE={printer["gcode_macro M150"].current_blue_value} + +# [gcode_macro TOGGLE_LIGHT] +# variable_light: 1 +# gcode: +# {% set red_value = printer["neopixel case_led"].color_data[0][0] %} +# {% set green_value = printer["neopixel case_led"].color_data[0][1] %} +# {% set blue_value = printer["neopixel case_led"].color_data[0][2] %} +# {% set light_is_on = [white_value, red_value, green_value, blue_value]|max %} +# {% if light_is_on > 0 %} +# M150 R0 G0 B0 +# SET_GCODE_VARIABLE MACRO=TOGGLE_LIGHT VARIABLE=light VALUE=0 +# {% else %} +# M150 R255 G255 B255 +# SET_GCODE_VARIABLE MACRO=TOGGLE_LIGHT VARIABLE=light VALUE=1 +# {% endif %} + +# [gcode_macro STATUS_LED] +# gcode: +# {% set status = params.STATUS|default(printing) %} +# {% if status == "started" %} +# SET_LED_TEMPLATE LED=case_led TEMPLATE=led_heatup +# {% elif status == "paused" %} +# M150 R255 G255 B0 D5 +# {% elif status == "completed" %} +# M150 R0 G255 B0 D5 +# {% elif status == "cancelled" %} +# M150 R255 G0 B0 D3 +# {% elif status == "printing" %} +# {% if printer["gcode_macro TOGGLE_LIGHT"].light > 0 %} +# M150 R255 G255 B255 +# {% else %} +# M150 R0 G0 B0 +# {% endif %} +# {% else %} +# UPDATE_DELAYED_GCODE ID=return_color DURATION=0.1 +# {% endif %} + +# # [gcode_macro M106] +# # rename_existing: M106.1 +# # gcode: +# # {% set p = params.P|default(0)|int %} +# # {% set s = params.S|default(0)|int %} +# # {% if p > 0 %} +# # {% if p == 3 %} +# # SET_FAN_SPEED FAN=chamber_fan SPEED={params.S|default(0)|int / 255} +# # {% endif %} +# # {% else %} +# # M106.1 S{s} +# # {% endif %} + +# # [gcode_macro M107] +# # rename_existing: M107.1 +# # gcode: +# # {% set p = params.P|default(0)|int %} +# # {% if p > 0 %} +# # {% if p == 3 %} +# # SET_FAN_SPEED FAN=chamber_fan SPEED=0.0 +# # {% endif %} +# # {% else %} +# # M107.1 +# # {% endif %} + diff --git a/stereotech_config/v6/fiber_extruder.cfg b/stereotech_config/v7/fiber_extruder.cfg similarity index 86% rename from stereotech_config/v6/fiber_extruder.cfg rename to stereotech_config/v7/fiber_extruder.cfg index a1697e4224bf..597a795e59ae 100644 --- a/stereotech_config/v6/fiber_extruder.cfg +++ b/stereotech_config/v7/fiber_extruder.cfg @@ -1,14 +1,14 @@ [extruder2] -step_pin: fiber_extruder_step_pin -dir_pin: fiber_extruder_dir_pin -enable_pin: !fiber_extruder_enable_pin +step_pin: second_mcu:fiber_extruder_step_pin +dir_pin: second_mcu:fiber_extruder_dir_pin +enable_pin: !second_mcu:fiber_extruder_enable_pin microsteps: 16 rotation_distance: 40 nozzle_diameter: 0.6 filament_diameter: 0.6 -heater_pin: fiber_extruder_heater_pin +heater_pin: second_mcu:fiber_extruder_heater_pin sensor_type: Trianglelab T-D500 -sensor_pin: fiber_extruder_sensor_pin +sensor_pin: second_mcu:fiber_extruder_sensor_pin control: pid pid_Kp: 13.509 pid_Ki: 0.566 @@ -17,6 +17,14 @@ min_temp: -150 max_temp: 320 max_extrude_only_distance: 300.0 min_extrude_temp: 0 +fiber: true + +# [manual_stepper cutter_stepper] +# step_pin: P2.8 +# dir_pin: P2.13 +# enable_pin: !P4.29 +# microsteps: 16 +# rotation_distance: 1 # [gcode_macro T1] # variable_t1_offset_enabled: 0.0 @@ -31,12 +39,7 @@ min_extrude_temp: 0 # ACTIVATE_EXTRUDER extruder=extruder1 # SET_WCS WCS={current_wcs} -# [manual_stepper cutter_stepper] -# step_pin: P2.8 -# dir_pin: P2.13 -# enable_pin: !P4.29 -# microsteps: 16 -# rotation_distance: 1 + # [gcode_macro CUT_FIBER] diff --git a/stereotech_config/v7/filament_control.cfg b/stereotech_config/v7/filament_control.cfg new file mode 100644 index 000000000000..53f8f8570c0c --- /dev/null +++ b/stereotech_config/v7/filament_control.cfg @@ -0,0 +1,21 @@ +# [filament_motion_sensor extruder_sensor] +# extruder: extruder +# detection_length: 10.5 +# event_delay: 60.0 +# switch_pin: filament_control_1 +# pause_on_runout: False +# runout_gcode: +# {% if printer.virtual_sdcard.is_active %} +# {action_respond_warning('411: The filament has run out or there is a problem with its supply at the Extruder 1.')} +# # PAUSE TURN_OFF_EXTRUDERS=0 E=0 +# {% else %} +# FILAMENT_ERROR EXTRUDER=extruder +# {% endif %} + +# [gcode_macro FILAMENT_ERROR] +# gcode: +# {% if params.EXTRUDER == 'extruder' %} +# {action_raise_error('401: Filament error on Extruder0')} +# {% else %} +# {action_raise_error('402: Filament error on Extruder1')} +# {% endif %} diff --git a/stereotech_config/v7/filament_control_second.cfg b/stereotech_config/v7/filament_control_second.cfg new file mode 100644 index 000000000000..28bd1ed84255 --- /dev/null +++ b/stereotech_config/v7/filament_control_second.cfg @@ -0,0 +1,13 @@ +# [filament_motion_sensor extruder1_sensor] +# extruder: extruder1 +# detection_length: 10.5 +# event_delay: 60.0 +# switch_pin: filament_control_2 +# pause_on_runout: False +# runout_gcode: +# {% if printer.virtual_sdcard.is_active %} +# {action_respond_warning('411: The filament has run out or there is a problem with its supply at the Extruder 2.')} +# # PAUSE TURN_OFF_EXTRUDERS=0 E=0 +# {% else %} +# FILAMENT_ERROR EXTRUDER=extruder1 +# {% endif %} diff --git a/stereotech_config/v7/kinematics.cfg b/stereotech_config/v7/kinematics.cfg new file mode 100644 index 000000000000..b5097b5566e3 --- /dev/null +++ b/stereotech_config/v7/kinematics.cfg @@ -0,0 +1,67 @@ +[printer] +kinematics: corexy_6axis +max_velocity: 200 +max_accel: 1500 +max_z_velocity: 40 +max_z_accel: 500 +square_corner_velocity: 2.5 + +[stepper_x] +step_pin: x_step_pin +dir_pin: !x_dir_pin +enable_pin: !x_en_pin +microsteps: 128 +rotation_distance: 40 +endstop_pin: x_endstop_pin +position_endstop: 309 +position_max: 309 +position_min: -1 +homing_speed: 70 + +[stepper_y] +step_pin: y_step_pin +dir_pin: !y_dir_pin +enable_pin: !y_en_pin +microsteps: 128 +rotation_distance: 40 +endstop_pin: y_endstop_pin +position_endstop: 300.3 +position_max: 300.3 +position_min: 0 +homing_speed: 70 + +[stepper_z] +step_pin: z_step_pin +dir_pin: !z_dir_pin +enable_pin: !z_en_pin +microsteps: 128 +rotation_distance: 4 +endstop_pin: z_endstop_pin +position_endstop: 300 +position_max: 300 +position_min: -10 +homing_speed: 20 + +[stepper_a] +step_pin: a_step_pin +dir_pin: a_dir_pin +enable_pin: !a_en_pin +microsteps: 128 +rotation_distance: 360 +gear_ratio: 80:20 +endstop_pin: a_endstop_pin +position_endstop: 90 +position_min: -10 +position_max: 90 +homing_speed: 20 + +[stepper_c] +step_pin: c_step_pin +dir_pin: c_dir_pin +enable_pin: !c_en_pin +microsteps: 128 +rotation_distance: 120 +gear_ratio: 80:20 +can_home: false +homing_speed: 20 + diff --git a/stereotech_config/v7/kinematics_none.cfg b/stereotech_config/v7/kinematics_none.cfg new file mode 100644 index 000000000000..e454ce5adbbd --- /dev/null +++ b/stereotech_config/v7/kinematics_none.cfg @@ -0,0 +1,66 @@ +[printer] +kinematics: none +max_velocity: 200 +max_accel: 1500 + +# MANUAL_STEPPER STEPPER=cutter_stepper_1 ENABLE=1 SET_POSITION=0 MOVE=30 SPEED=5 + +[manual_stepper cutter_stepper_1] +step_pin: c_step_pin +dir_pin: c_dir_pin +enable_pin: !c_en_pin +microsteps: 16 +rotation_distance: 40 + +[tmc2130 manual_stepper cutter_stepper_1] +cs_pin: c_cs_pin +spi_bus: spi1 +run_current: 0.15 +interpolate: False + +# [manual_stepper cutter_stepper_2] +# step_pin: second_mcu:x_step_pin +# dir_pin: second_mcu:x_dir_pin +# enable_pin: !second_mcu:x_en_pin +# microsteps: 16 +# rotation_distance: 40 + +# [tmc2130 manual_stepper cutter_stepper_2] +# cs_pin: second_mcu:x_cs_pin +# spi_software_sclk_pin: second_mcu:PA5 +# spi_software_mosi_pin: second_mcu:PA7 +# spi_software_miso_pin: second_mcu:PA6 +# run_current: 0.15 +# interpolate: False + +[manual_stepper cutter_stepper_3] +step_pin: second_mcu:y_step_pin +dir_pin: second_mcu:y_dir_pin +enable_pin: !second_mcu:y_en_pin +microsteps: 16 +rotation_distance: 40 + +[tmc2130 manual_stepper cutter_stepper_3] +cs_pin: second_mcu:y_cs_pin +spi_software_sclk_pin: second_mcu:PA5 +spi_software_mosi_pin: second_mcu:PA7 +spi_software_miso_pin: second_mcu:PA6 +run_current: 0.15 +interpolate: False + +[board_pins] +mcu: + mcu +aliases: + x_step_pin=PF13, x_dir_pin=PF12, x_en_pin=PF14, x_endstop_pin=PG6, + y_step_pin=PG0, y_dir_pin=PG1, y_en_pin=PF15, y_endstop_pin=PG9, + z_step_pin=PF11, z_dir_pin=PG3, z_en_pin=PG5, z_endstop_pin=PG10, + a_step_pin=PG4, a_dir_pin=PC1, a_en_pin=PA0, a_endstop_pin=PG11, + c_step_pin=PF9, c_dir_pin=PF10, c_en_pin=PG2, c_cs_pin=PF2, + +[board_pins second_mcu] +mcu: + second_mcu +aliases: + x_step_pin=PE2, x_dir_pin=PB4, x_en_pin=PC11, x_cs_pin=PC10, + y_step_pin=PF12, y_dir_pin=PF11, y_en_pin=PB3, y_cs_pin=PF13, diff --git a/stereotech_config/v6/kinematics_tmc.cfg b/stereotech_config/v7/kinematics_tmc.cfg similarity index 62% rename from stereotech_config/v6/kinematics_tmc.cfg rename to stereotech_config/v7/kinematics_tmc.cfg index b6617bf1f903..1a0a75d763a5 100644 --- a/stereotech_config/v6/kinematics_tmc.cfg +++ b/stereotech_config/v7/kinematics_tmc.cfg @@ -39,25 +39,34 @@ interpolate: False #stealthchop_threshold: 999999 [tmc2130 extruder] -cs_pin: second_mcu:PC10 -spi_bus: spi1 +cs_pin: second_mcu:main_extruder_cs_pin +spi_software_sclk_pin: second_mcu:PA5 +spi_software_mosi_pin: second_mcu:PA7 +spi_software_miso_pin: second_mcu:PA6 +# spi_bus: spi1 #diag1_pin: PG11 run_current: 0.700 interpolate: False #stealthchop_threshold: 999999 [tmc2130 extruder1] -cs_pin: second_mcu:PF13 -spi_bus: spi1 +cs_pin: second_mcu:second_extruder_cs_pin +spi_software_sclk_pin: second_mcu:PA5 +spi_software_mosi_pin: second_mcu:PA7 +spi_software_miso_pin: second_mcu:PA6 +# spi_bus: spi1 #diag1_pin: PG11 run_current: 0.700 interpolate: False #stealthchop_threshold: 999999 -[tmc2130 fiber_extruder] -cs_pin: second_mcu:PF9 -spi_bus: spi1 +[tmc2130 extruder2] +cs_pin: second_mcu:fiber_extruder_cs_pin +spi_software_sclk_pin: second_mcu:PA5 +spi_software_mosi_pin: second_mcu:PA7 +spi_software_miso_pin: second_mcu:PA6 +# spi_bus: spi1 #diag1_pin: PG11 run_current: 0.700 interpolate: False -#stealthchop_threshold: 999999 \ No newline at end of file +#stealthchop_threshold: 999999 diff --git a/stereotech_config/v6/main_extruder.cfg b/stereotech_config/v7/main_extruder.cfg similarity index 65% rename from stereotech_config/v6/main_extruder.cfg rename to stereotech_config/v7/main_extruder.cfg index b94e8f62cbb0..933abd761831 100644 --- a/stereotech_config/v6/main_extruder.cfg +++ b/stereotech_config/v7/main_extruder.cfg @@ -1,14 +1,14 @@ [extruder] -step_pin: main_extruder_step_pin -dir_pin: main_extruder_dir_pin -enable_pin: !main_extruder_enable_pin +step_pin: second_mcu:main_extruder_step_pin +dir_pin: second_mcu:main_extruder_dir_pin +enable_pin: !second_mcu:main_extruder_enable_pin microsteps: 16 rotation_distance: 7.777 nozzle_diameter: 0.4 filament_diameter: 1.75 -heater_pin: main_extruder_heater_pin +heater_pin: second_mcu:main_extruder_heater_pin sensor_type: Trianglelab T-D500 -sensor_pin: main_extruder_sensor_pin +sensor_pin: second_mcu:main_extruder_sensor_pin control: pid pid_Kp: 13.509 pid_Ki: 0.566 @@ -18,18 +18,19 @@ max_temp: 320 min_extrude_temp: 100 max_extrude_only_distance: 300.0 max_extrude_cross_section: 2.56 +fiber: false -[heater_generic main_nozzle_blower_heater] -gcode_id: E0 -heater_pin: main_nozzle_blower_heater -sensor_type: ATC Semitec 104GT-2 -sensor_pin: main_nozzle_blower_sensor -control: pid -pid_Kp: 13.509 -pid_Ki: 0.566 -pid_Kd: 80.549 -min_temp: -150 -max_temp: 320 +# [heater_generic main_nozzle_blower_heater] +# gcode_id: E0 +# heater_pin: main_nozzle_blower_heater +# sensor_type: ATC Semitec 104GT-2 +# sensor_pin: main_nozzle_blower_sensor +# control: pid +# pid_Kp: 13.509 +# pid_Ki: 0.566 +# pid_Kd: 80.549 +# min_temp: -150 +# max_temp: 320 # [gcode_macro T0] # gcode: diff --git a/stereotech_config/v7/module_3d.cfg b/stereotech_config/v7/module_3d.cfg new file mode 100644 index 000000000000..88f29d10e074 --- /dev/null +++ b/stereotech_config/v7/module_3d.cfg @@ -0,0 +1,17 @@ +# [heater_bed] +# heater_pin: bed_heater +# sensor_type: ATC Semitec 104GT-2 +# sensor_pin: bed_sensor +# control: pid +# pid_Kp: 63.164 +# pid_Ki: 2.379 +# pid_Kd: 419.254 +# min_temp: -100 +# max_temp: 130 + +;[bed_screws] +;horizontal_move_z: 10.0 +;screw1: 159,275 +;screw1_fine_adjust: 159,0 +;screw2: 20,0 +;screw3: 282,0 diff --git a/stereotech_config/v7/module_5d.cfg b/stereotech_config/v7/module_5d.cfg new file mode 100644 index 000000000000..831e91f43e0e --- /dev/null +++ b/stereotech_config/v7/module_5d.cfg @@ -0,0 +1,98 @@ +# [gcode_button five_axis_module] +# pin: !five_axis_pin +# press_gcode: QUERY_BUTTON BUTTON=five_axis_module + +# # [a_axis_offset] + +# [gcode_macro MOVE_WCS_ZERO] +# gcode: +# G54 +# {% if printer.toolhead.axis_maximum[0] > 250 %} +# G0 Z150 F6000 +# {% else %} +# G0 Z100 F6000 +# {% endif %} +# {% set current_wcs = params.WCS|default(1)|int %} +# {% set offsets = printer.gcode_move.wcs_offsets[current_wcs] %} +# {% if offsets[0] == 0 and offsets[1] == 0 %} +# {% if printer.toolhead.axis_maximum[0] > 250 %} +# G0 X162 Y242 F6000 +# {% else %} +# G0 X107 Y137 F6000 +# {% endif %} +# {% else %} +# G0 X{offsets[0]} Y{offsets[1]} F6000 +# {% endif %} +# {% if current_wcs == 1 %} +# G0 A0 +# {% elif current_wcs == 2 %} +# {% if printer.toolhead.axis_maximum[0] > 250 %} +# G0 Y192 A90 F6000 +# {% else %} +# G0 Y87 A90 F6000 +# {% endif %} +# {% endif %} + +# [gcode_macro SET_WCS_OFFSET] +# gcode: +# G54 +# G90 +# {% set current_wcs = params.WCS|default(1)|int %} +# SET_WCS WCS={current_wcs} +# G10 L20 X{params.X} Y{params.Y} Z{params.Z} +# G54 +# {% set adjust_wcs = params.ADJUST_WCS|default(0)|int %} +# {% if adjust_wcs > 0 and adjust_wcs != current_wcs %} +# ADJUST_WCS_OFFSET WCS={current_wcs} ADJUST_WCS={adjust_wcs} X={params.X} Y={params.Y} Z={params.Z} +# {% endif %} + +# [gcode_macro ADJUST_WCS_OFFSET] +# gcode: +# {% set current_wcs = params.WCS|default(1)|int %} +# {% set adjust_wcs = params.ADJUST_WCS|default(0)|int %} +# {% set source_wcs = current_wcs + 2 %} +# {% set source_wcs_2 = adjust_wcs + 2 %} +# {% set offsets = printer.gcode_move.wcs_offsets[source_wcs] %} +# {% set offsets_2 = printer.gcode_move.wcs_offsets[source_wcs_2] %} +# {% set delta_x = printer.gcode_move.wcs_offsets[current_wcs][0] - offsets[0] %} +# {% set delta_y = printer.gcode_move.wcs_offsets[current_wcs][1] - offsets[1] %} +# {% set delta_z = printer.gcode_move.wcs_offsets[current_wcs][2] - offsets[2] %} +# G10 L2 P{adjust_wcs + 1} X{offsets_2[0] + delta_x + params.X|float} Y{offsets_2[1] - delta_z + params.Z|float} Z{offsets_2[2] + delta_y + params.Y|float} + +# [gcode_macro MOVE_CALIBRATION_POINT] +# gcode: +# G54 +# {% set point = params.POINT|default(0)|int %} +# {% set x = 162 if printer.toolhead.axis_maximum[0] > 250 else 108 %} +# {% set y = 242 if printer.toolhead.axis_maximum[0] > 250 else 137 %} +# {% if point == 3 or point == 4 %} +# {% set y = 192 if printer.toolhead.axis_maximum[0] > 250 else 87 %} +# {% endif %} +# {% if point == 1 %} +# {% set x = 112 if printer.toolhead.axis_maximum[0] > 250 else 58 %} +# {% endif %} +# {% if point == 2 %} +# {% set x = 212 if printer.toolhead.axis_maximum[0] > 250 else 158 %} +# {% endif %} +# G0 A0 +# G0 X{x} Y{y} Z110 F3600 +# {% if point > 3 %} +# G0 Z70 A90 F3600 +# {% endif %} + + +# [gcode_macro SET_A_AXIS_OFFSET_POINT] +# gcode: +# {% set point = params.POINT|default(0)|int %} +# {% set coord_x = printer.gcode_move.position.x %} +# {% set coord_y = printer.gcode_move.position.y %} +# {% set coord_z = printer.gcode_move.position.z %} +# SAVE_A_AXIS_POINT POINT={point} COORDS={coord_x},{coord_y},{coord_z} + +# [gcode_macro SAVE_STATE_MODULE] +# gcode: +# {% if printer["gcode_button five_axis_module"].state == "RELEASED" %} +# SAVE_VARIABLE VARIABLE=5d_module_enabled VALUE=0 +# {% else %} +# SAVE_VARIABLE VARIABLE=5d_module_enabled VALUE=1 +# {% endif %} diff --git a/stereotech_config/v7/printhead.cfg b/stereotech_config/v7/printhead.cfg new file mode 100644 index 000000000000..609bdc72f536 --- /dev/null +++ b/stereotech_config/v7/printhead.cfg @@ -0,0 +1,9 @@ +# [heater_fan printhead_fan] +# pin: cooling_fan_heat +# heater: extruder, extruder1, extruder2 +# heater_temp: 50.0 + +# [heater_fan heatsink_fan] +# pin: fan_pump_cooling, pump +# heater: extruder, extruder1, extruder2 +# heater_temp: 50.0 diff --git a/stereotech_config/v6/second_extruder.cfg b/stereotech_config/v7/second_extruder.cfg similarity index 63% rename from stereotech_config/v6/second_extruder.cfg rename to stereotech_config/v7/second_extruder.cfg index 03fa06c3b3b8..be79a92541f7 100644 --- a/stereotech_config/v6/second_extruder.cfg +++ b/stereotech_config/v7/second_extruder.cfg @@ -1,14 +1,14 @@ [extruder1] -step_pin: second_extruder_step_pin -dir_pin: second_extruder_dir_pin -enable_pin: !second_extruder_enable_pin +step_pin: second_mcu:second_extruder_step_pin +dir_pin: second_mcu:second_extruder_dir_pin +enable_pin: !second_mcu:second_extruder_enable_pin microsteps: 16 rotation_distance: 7.777 nozzle_diameter: 0.4 filament_diameter: 1.75 -heater_pin: second_extruder_heater_pin +heater_pin: second_mcu:second_extruder_heater_pin sensor_type: Trianglelab T-D500 -sensor_pin: second_extruder_sensor_pin +sensor_pin: second_mcu:second_extruder_sensor_pin control: pid pid_Kp: 13.509 pid_Ki: 0.566 @@ -18,18 +18,19 @@ max_temp: 320 min_extrude_temp: 100 max_extrude_only_distance: 300.0 max_extrude_cross_section: 2.56 +fiber: false -[heater_generic second_nozzle_blower_heater] -gcode_id: E1 -heater_pin: second_nozzle_blower_heater -sensor_type: ATC Semitec 104GT-2 -sensor_pin: second_nozzle_blower_sensor -control: pid -pid_Kp: 13.509 -pid_Ki: 0.566 -pid_Kd: 80.549 -min_temp: -150 -max_temp: 320 +# [heater_generic second_nozzle_blower_heater] +# gcode_id: E1 +# heater_pin: second_nozzle_blower_heater +# sensor_type: ATC Semitec 104GT-2 +# sensor_pin: second_nozzle_blower_sensor +# control: pid +# pid_Kp: 13.509 +# pid_Ki: 0.566 +# pid_Kd: 80.549 +# min_temp: -150 +# max_temp: 320 # [gcode_macro T1] # variable_t1_offset_enabled: 0.0 diff --git a/stereotech_config/variables.cfg b/stereotech_config/variables.cfg index d4d659f8b28a..b8b705e8b889 100644 --- a/stereotech_config/variables.cfg +++ b/stereotech_config/variables.cfg @@ -31,6 +31,7 @@ gcode: SKEW_PROFILE CHANGE={key} XY={svv[key ~ '_xy_skew']} XZ={svv[key ~ '_xz_skew']} YZ={svv[key ~ '_yz_skew']} {% endif %} {% endfor %} + SET_PROBE_BACKLASH BACKLASH_X={svv.probe_backlash_x|default(0.0)|float} BACKLASH_Y={svv.probe_backlash_y|default(0.0)|float} BACKLASH_Y_2={svv.probe_backlash_y_2|default(0.0)|float} {% endif %} {% if printer["filament_motion_sensor extruder_sensor"] %} SET_FILAMENT_SENSOR SENSOR=extruder_sensor ENABLE={svv['extruder_sensor']|default(1)} @@ -72,4 +73,8 @@ gcode: SAVE_VARIABLE VARIABLE=probe_offset_x VALUE={printer.probe.offsets[0]} SAVE_VARIABLE VARIABLE=probe_offset_y VALUE={printer.probe.offsets[1]} SAVE_VARIABLE VARIABLE=probe_offset_z VALUE={printer.probe.offsets[2]} + + SAVE_VARIABLE VARIABLE=probe_backlash_x VALUE={printer.auto_wcs.probe_backlash_x} + SAVE_VARIABLE VARIABLE=probe_backlash_y VALUE={printer.auto_wcs.probe_backlash_y} + SAVE_VARIABLE VARIABLE=probe_backlash_y_2 VALUE={printer.auto_wcs.probe_backlash_y_2} {% endif %}