From e9d6c91c6b19ef0a4c8b1e3503f6d35560c58481 Mon Sep 17 00:00:00 2001 From: boetti-dev Date: Fri, 17 Apr 2026 13:38:26 +0200 Subject: [PATCH 1/5] Add Happy Hare MMU integration and Docker build tools - Happy Hare MMU configuration and hardware files - Kalico firmware MMU build recipes - Docker-based local build environment with bindgen sysroot fix - HH-Full and HH-Minimal image recipes - Mainsail docker setup for local development - README documentation for Happy Hare images Note: Release publishing configuration intentionally not included (decision left to project maintainers) --- README-happy-hare.md | 178 ++++ .../images/files/sw-description-hh-full | 180 ++++ .../images/files/sw-description-hh-minimal | 180 ++++ .../images/opencentauri-image-hh-full-mmc.bb | 21 + .../images/opencentauri-image-hh-full.bb | 31 + .../opencentauri-image-hh-minimal-mmc.bb | 21 + .../images/opencentauri-image-hh-minimal.bb | 104 ++ .../images/opencentauri-image-mmu.bb | 95 ++ .../images/opencentauri-upgrade-hh-full.bb | 40 + .../images/opencentauri-upgrade-hh-minimal.bb | 40 + .../happy-hare/files/happy-hare-init | 40 + .../happy-hare/files/mmu.cfg.erb-v2 | 86 ++ .../happy-hare/files/mmu/addons/blobifier.cfg | 914 ++++++++++++++++++ .../files/mmu/addons/blobifier_hw.cfg | 28 + .../files/mmu/addons/dc_espooler.cfg | 202 ++++ .../files/mmu/addons/dc_espooler_hw.cfg | 75 ++ .../files/mmu/addons/mmu_centauri.cfg | 239 +++++ .../files/mmu/addons/mmu_erec_cutter.cfg | 91 ++ .../files/mmu/addons/mmu_erec_cutter_hw.cfg | 10 + .../happy-hare/files/mmu/base/mmu.cfg | 100 ++ .../happy-hare/files/mmu/base/mmu_cut_tip.cfg | 296 ++++++ .../files/mmu/base/mmu_form_tip.cfg | 178 ++++ .../files/mmu/base/mmu_hardware.cfg | 340 +++++++ .../happy-hare/files/mmu/base/mmu_leds.cfg | 89 ++ .../files/mmu/base/mmu_macro_vars.cfg | 507 ++++++++++ .../files/mmu/base/mmu_parameters.cfg | 823 ++++++++++++++++ .../files/mmu/base/mmu_sequence.cfg | 665 +++++++++++++ .../files/mmu/base/mmu_software.cfg | 567 +++++++++++ .../happy-hare/files/mmu/base/mmu_state.cfg | 124 +++ .../happy-hare/files/mmu/mmu_vars.cfg | 8 + .../files/mmu/optional/client_macros.cfg | 132 +++ .../files/mmu/optional/mmu_menu.cfg | 146 +++ .../happy-hare/files/mmu_hardware.cfg.erb-v2 | 136 +++ .../files/mmu_parameters.cfg.erb-v2 | 150 +++ .../recipes-apps/happy-hare/happy-hare_git.bb | 124 +++ .../recipes-apps/klipper/files-hh/macros.cfg | 545 +++++++++++ .../recipes-apps/klipper/files-hh/shell.cfg | 10 + .../recipes-apps/klipper/files/config.mmu | 109 +++ .../klipper/kalico-firmware-mmu_2026.02.00.bb | 34 + .../klipper/kalico_2026.02.00.bbappend | 14 + .../mainsail/mainsail_2.17.0.bbappend | 16 + tools/README.md | 26 + tools/local-build/.dockerignore | 25 + tools/local-build/Dockerfile | 37 + tools/local-build/README.md | 53 + tools/local-build/build.sh | 88 ++ tools/local-mainsail/README.md | 64 ++ tools/local-mainsail/config.json | 8 + tools/local-mainsail/docker-compose.yml | 10 + tools/local-mainsail/nginx.conf | 65 ++ tools/local-mainsail/start.sh | 13 + 51 files changed, 8077 insertions(+) create mode 100644 README-happy-hare.md create mode 100644 meta-opencentauri/images/files/sw-description-hh-full create mode 100644 meta-opencentauri/images/files/sw-description-hh-minimal create mode 100644 meta-opencentauri/images/opencentauri-image-hh-full-mmc.bb create mode 100644 meta-opencentauri/images/opencentauri-image-hh-full.bb create mode 100644 meta-opencentauri/images/opencentauri-image-hh-minimal-mmc.bb create mode 100644 meta-opencentauri/images/opencentauri-image-hh-minimal.bb create mode 100644 meta-opencentauri/images/opencentauri-image-mmu.bb create mode 100644 meta-opencentauri/images/opencentauri-upgrade-hh-full.bb create mode 100644 meta-opencentauri/images/opencentauri-upgrade-hh-minimal.bb create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/happy-hare-init create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier_hw.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler_hw.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_centauri.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter_hw.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_cut_tip.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_form_tip.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_leds.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_parameters.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_sequence.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_software.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_state.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/mmu_vars.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/client_macros.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/mmu_menu.cfg create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 create mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 create mode 100644 meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb create mode 100644 meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg create mode 100644 meta-opencentauri/recipes-apps/klipper/files-hh/shell.cfg create mode 100644 meta-opencentauri/recipes-apps/klipper/files/config.mmu create mode 100644 meta-opencentauri/recipes-apps/klipper/kalico-firmware-mmu_2026.02.00.bb create mode 100644 meta-opencentauri/recipes-apps/klipper/kalico_2026.02.00.bbappend create mode 100644 meta-opencentauri/recipes-apps/mainsail/mainsail_2.17.0.bbappend create mode 100644 tools/README.md create mode 100644 tools/local-build/.dockerignore create mode 100644 tools/local-build/Dockerfile create mode 100644 tools/local-build/README.md create mode 100755 tools/local-build/build.sh create mode 100644 tools/local-mainsail/README.md create mode 100644 tools/local-mainsail/config.json create mode 100644 tools/local-mainsail/docker-compose.yml create mode 100644 tools/local-mainsail/nginx.conf create mode 100755 tools/local-mainsail/start.sh diff --git a/README-happy-hare.md b/README-happy-hare.md new file mode 100644 index 00000000..b993c4a9 --- /dev/null +++ b/README-happy-hare.md @@ -0,0 +1,178 @@ +# OpenCentauri HH Images + +This repository extends the standard OpenCentauri firmware with Happy Hare (MMU) enabled images for the Elegoo Centauri Carbon. + +## Available Images + +| Image | Description | +|-------|-------------| +| `opencentauri-upgrade` | Standard image (as defined in origin/main) | +| `opencentauri-upgrade-hh-full` | Standard + Happy Hare + Mainsail | +| `opencentauri-upgrade-hh-minimal` | Happy Hare without web frontend | + +--- + +## HH-Full Image + +> ⚠️ **WARNING: UNTESTED - USE AT YOUR OWN RISK** +> +> The `opencentauri-upgrade-hh-full` image is provided for completeness only. +> It has **NEVER been tested** and is **likely NOT WORKING**. +> +> The Centauri Carbon mainboard has only 128MB RAM. Running Happy Hare + Mainsail + Fluidd + multiple screens simultaneously will likely exceed available resources. +> +> **For a working MMU setup, use `opencentauri-upgrade-hh-minimal` instead.** + +--- + +## HH-Minimal Image (Recommended) + +The HH-Minimal image is designed for stable MMU operation on the resource-limited Centauri Carbon (128MB RAM). It includes: + +- **Happy Hare** - Full MMU software support +- **Kalico + Moonraker** - Klipper firmware with API backend +- **No Web Frontend** - Mainsail/Fluidd removed to save memory + +Use `tools/local-mainsail/` to run Mainsail on your PC and connect to the printer's moonraker API. + +### Network Setup Required + +> ⚠️ **Important: No Touchscreen Interface Available** +> +> The HH-Minimal image removes all touchscreen interfaces (atomscreen, guppyscreen, grumpyscreen). You must configure network access to connect to Moonraker (port 80). +> +> **Test network connectivity on the base image first!** Before flashing HH-Minimal, verify your network setup works on the standard OpenCentauri image. + +#### Option 1: USB Ethernet Adapter + +Connect a USB Ethernet adapter to the printer's USB port. Most adapters are auto-detected. + +#### Option 2: WiFi via USB Stick (wpa_supplicant) + +The printer automatically reads `wpa_supplicant.conf` from a USB stick when inserted. + +Create `wpa_supplicant.conf` on a USB stick: + +```conf +ctrl_interface=/var/run/wpa_supplicant +network={ + ssid="YOUR_WIFI_SSID" + psk="YOUR_WIFI_PASSWORD" +} +``` + +Insert the USB stick - the file is automatically copied to `/etc/wpa_supplicant.conf` and WiFi connects. + +Once connected, access Moonraker at `http://:80`. + +### Removed Packages + +#### fluidd & mainsail (frontend) +Web frontends removed - no browser interface available on printer. +**Note:** Use `tools/local-mainsail/` to run Mainsail on your PC and connect to the printer's moonraker API (port 80). + +#### atomscreen, guppyscreen & grumpyscreen +Touchscreen interfaces removed. +**Note:** The built-in touchscreen will not show any printer interface. Control via local Mainsail only. + +#### ustreamer +Webcam streaming server removed. +**Note:** Webcam streaming will not be available via moonraker. Consider external webcam hosting if needed. + +#### fbdoom +DOOM game removed. +**Note:** Removed because all screen interfaces are removed - no way to display the game. + +#### v4l-utils +Video4Linux utilities removed. +**Note:** Webcam configuration tools not available. If you need webcam tuning, install externally. + +### Added Packages + +#### happy-hare +MMU software suite installed. +**Note:** Full Happy Hare installation with MMU configs in `/etc/klipper/config/mmu/`. + +**Important:** Happy Hare's `install.sh` must be run on an external machine to generate MMU-specific config files for your hardware. The generated configs must either: +- Be added to the build (replace files in `recipes-apps/happy-hare/files/mmu/` before building) +- Or manually copied to the printer after installation (`/etc/klipper/config/mmu/`) + +#### kalico-firmware-mmu +MMU-specific Klipper firmware for the MMU MCU board. +**Note:** Required if your MMU uses a separate MCU (e.g., ERB board). This firmware must be flashed to the MMU MCU after installation. + +### Known Issues + +#### Chamber Lighting +The camera-related shell commands were removed from the HH-Minimal image. This causes the following error on startup: + +``` +Error running command {CAMERA_LIGHT_ON} +``` + +**Note:** Chamber lighting will not work because `v4l2-ctl` is not available (removed with v4l-utils package). Without `v4l2-ctl`, there is no way to control the camera backlight compensation which is used for chamber lighting. + +### PACKAGECONFIG Options + +#### opencentauri-hh-full (Kalico) +Enables modified macros.cfg for HH-Full image: +- `SILENT` parameter - suppress prompts during filament loading (for automated MMU operation) +- `LENGTH` parameter - custom purge length for `_LOAD_FILAMENT_STEP_PUSH` +- `SET_DISPLAY_TEXT_COSMOS` macro - wrapper with `rename_existing` to avoid conflict with Happy Hare's `SET_DISPLAY_TEXT` + +#### opencentauri-hh-minimal (Kalico) +Enables modified macros.cfg and minimal shell.cfg for HH-Minimal image: +- Same macros as `opencentauri-hh-full` +- Minimal `shell.cfg` overrides original - camera light and DOOM shell commands removed + +#### config-only (Mainsail) +Removes frontend files but keeps Mainsail config macros. +**Note:** Used by HH-Minimal to save memory. The config provides essential macros needed by Mainsail to communicate with moonraker. The moonraker API is still available - use `tools/local-mainsail/` for web interface. + +### Editable Configuration Files + +#### mmu_vars.cfg (Happy Hare) +Added as `CONFFILES` - user edits are preserved during firmware upgrades. +**Note:** Happy Hare calibration variables at `/etc/klipper/config/mmu/mmu_vars.cfg`. Contains servo positions, gate offsets, bowden lengths, and other MMU-specific settings that change during calibration. Template is empty - will be populated by Happy Hare after calibration. + +### Path Adjustments for OpenCentauri + +Happy Hare config paths are adapted for OpenCentauri's directory structure: + +| File | Setting | Original Happy Hare | OpenCentauri | +|------|---------|---------------------|--------------| +| mmu_macro_vars.cfg | `filename` (save_variables) | varies | `/etc/klipper/config/mmu/mmu_vars.cfg` | +| mmu_macro_vars.cfg | `path` (virtual_sdcard) | `~/printer_data/gcodes` | `/etc/klipper/gcodes` | + +**Note:** If you run Happy Hare's `install.sh` to generate new configs, you must adjust these paths to match OpenCentauri's structure. + +--- + +## Build & Testing Tools + +See the `tools/` directory for build and testing utilities: + +- **`tools/local-build/`** - Docker-based Yocto build environment for creating SWU images +- **`tools/local-mainsail/`** - Local Mainsail frontend for HH-Minimal (no frontend installed on printer) + +### Quick Build + +```bash +cd tools/local-build +./build.sh +``` + +### Testing HH-Minimal Locally + +The HH-Minimal image has no web frontend. Use `tools/local-mainsail/` to run Mainsail on your PC: + +```bash +cd tools/local-mainsail +# Edit config.json to set your printer's IP address +./start.sh +# Access at http://localhost:8080 +``` + +--- + +> **Note:** Release publishing configuration was intentionally not included in the build script. This decision is left to the project maintainers. \ No newline at end of file diff --git a/meta-opencentauri/images/files/sw-description-hh-full b/meta-opencentauri/images/files/sw-description-hh-full new file mode 100644 index 00000000..7b6c697c --- /dev/null +++ b/meta-opencentauri/images/files/sw-description-hh-full @@ -0,0 +1,180 @@ +software = +{ + version = "@@DISTRO_VERSION@@"; + description = "Firmware update for OpenCentauri"; + + hardware-compatibility: [ "1.0" ]; + + stable = { + + /* now in systemA, we need to upgrade systemB(bootB, rootfsB) */ + now_A_next_B = { + images: ( + { + filename = "bootA.img"; + device = "/dev/mmcblk0p7"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootA.img)" + }, + { + filename = "opencentauri-image-hh-full-mmc-elegoo-centauri-carbon1.rootfs.squashfs"; + device = "/dev/mmcblk0p8"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(opencentauri-image-hh-full-mmc-elegoo-centauri-carbon1.rootfs.squashfs)" + }, + { + filename = "u-boot-sunxi-with-spl.bin"; + device = "/dev/mmcblk0"; + type = "raw"; + offset = "8K"; + sha256 = "$swupdate_get_sha256(u-boot-sunxi-with-spl.bin)" + }, + { + filename = "bootlogos.img"; + device = "/dev/mmcblk0p1"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootlogos.img)" + } + ); + bootenv: ( + { + name = "boot_part"; + value = "7"; + }, + { + name = "mmc_root"; + value = "/dev/mmcblk0p8"; + }, + { + name = "systemAB_next"; + value = "B"; + }, + { + name = "swu_version"; + value = "@@DISTRO_VERSION@@"; + }, + { + name = "swu_mode"; + value = "mainline"; + }, + { + name = "setargs_mainline"; + value = "setenv bootargs console=ttyS0,115200 earlycon=uart8250,mmio32,0x02500000 root=${mmc_root} rootwait consoleblank=0"; + }, + { + name = "bootcmd_"; + value = "run setargs_mmc boot_dsp0 boot_normal"; + }, + { + name = "bootcmd_mainline"; + value = "run setargs_mainline; fatload mmc 0:${boot_part} 43000000 zImage; fatload mmc 0:${boot_part} 43800000 elegoo-centauri-carbon1.dtb; bootz 43000000 - 43800000"; + }, + { + name = "bootcmd"; + value = "run bootcmd_${swu_mode}"; + }, + { + name = "preboot"; + value = "load mmc 0:1 0x43000000 bootlogo.bmp; bmp display 0x43000000; usb start"; + }, + { + name = "stdin"; + value = "serial"; + }, + { + name = "stdout"; + value = "serial"; + }, + { + name = "stderror"; + value = "serial"; + } + ); + }; + + /* now in systemB, we need to upgrade systemA(bootA, rootfsA) */ + now_B_next_A = { + images: ( + { + filename = "bootA.img"; + device = "/dev/mmcblk0p4"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootA.img)" + }, + { + filename = "opencentauri-image-hh-full-mmc-elegoo-centauri-carbon1.rootfs.squashfs"; + device = "/dev/mmcblk0p5"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(opencentauri-image-hh-full-mmc-elegoo-centauri-carbon1.rootfs.squashfs)" + }, + { + filename = "u-boot-sunxi-with-spl.bin"; + device = "/dev/mmcblk0"; + type = "raw"; + offset = "8K"; + sha256 = "$swupdate_get_sha256(u-boot-sunxi-with-spl.bin)" + }, + { + filename = "bootlogos.img"; + device = "/dev/mmcblk0p1"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootlogos.img)" + } + ); + bootenv: ( + { + name = "boot_part"; + value = "4"; + }, + { + name = "mmc_root"; + value = "/dev/mmcblk0p5"; + }, + { + name = "systemAB_next"; + value = "A"; + }, + { + name = "swu_version"; + value = "@@DISTRO_VERSION@@"; + }, + { + name = "swu_mode"; + value = "mainline"; + }, + { + name = "setargs_mainline"; + value = "setenv bootargs console=ttyS0,115200 earlycon=uart8250,mmio32,0x02500000 root=${mmc_root} rootwait consoleblank=0"; + }, + { + name = "bootcmd_"; + value = "run setargs_mmc boot_dsp0 boot_normal"; + }, + { + name = "bootcmd_mainline"; + value = "run setargs_mainline; fatload mmc 0:${boot_part} 43000000 zImage; fatload mmc 0:${boot_part} 43800000 elegoo-centauri-carbon1.dtb; bootz 43000000 - 43800000"; + }, + { + name = "bootcmd"; + value = "run bootcmd_${swu_mode}"; + }, + { + name = "preboot"; + value = "load mmc 0:1 0x43000000 bootlogo.bmp; bmp display 0x43000000; usb start"; + }, + { + name = "stdin"; + value = "serial"; + }, + { + name = "stdout"; + value = "serial"; + }, + { + name = "stderror"; + value = "serial"; + } + ); + }; + }; +} diff --git a/meta-opencentauri/images/files/sw-description-hh-minimal b/meta-opencentauri/images/files/sw-description-hh-minimal new file mode 100644 index 00000000..f9f9eea5 --- /dev/null +++ b/meta-opencentauri/images/files/sw-description-hh-minimal @@ -0,0 +1,180 @@ +software = +{ + version = "@@DISTRO_VERSION@@"; + description = "Firmware update for OpenCentauri Minimal (Happy Hare ohne Web-Interface)"; + + hardware-compatibility: [ "1.0" ]; + + stable = { + + /* now in systemA, we need to upgrade systemB(bootB, rootfsB) */ + now_A_next_B = { + images: ( + { + filename = "bootA.img"; + device = "/dev/mmcblk0p7"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootA.img)" + }, + { + filename = "opencentauri-image-hh-minimal-mmc-elegoo-centauri-carbon1.rootfs.squashfs"; + device = "/dev/mmcblk0p8"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(opencentauri-image-hh-minimal-mmc-elegoo-centauri-carbon1.rootfs.squashfs)" + }, + { + filename = "u-boot-sunxi-with-spl.bin"; + device = "/dev/mmcblk0"; + type = "raw"; + offset = "8K"; + sha256 = "$swupdate_get_sha256(u-boot-sunxi-with-spl.bin)" + }, + { + filename = "bootlogos.img"; + device = "/dev/mmcblk0p1"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootlogos.img)" + } + ); + bootenv: ( + { + name = "boot_part"; + value = "7"; + }, + { + name = "mmc_root"; + value = "/dev/mmcblk0p8"; + }, + { + name = "systemAB_next"; + value = "B"; + }, + { + name = "swu_version"; + value = "@@DISTRO_VERSION@@"; + }, + { + name = "swu_mode"; + value = "mainline"; + }, + { + name = "setargs_mainline"; + value = "setenv bootargs console=ttyS0,115200 earlycon=uart8250,mmio32,0x02500000 root=${mmc_root} rootwait consoleblank=0"; + }, + { + name = "bootcmd_"; + value = "run setargs_mmc boot_dsp0 boot_normal"; + }, + { + name = "bootcmd_mainline"; + value = "run setargs_mainline; fatload mmc 0:${boot_part} 43000000 zImage; fatload mmc 0:${boot_part} 43800000 elegoo-centauri-carbon1.dtb; bootz 43000000 - 43800000"; + }, + { + name = "bootcmd"; + value = "run bootcmd_${swu_mode}"; + }, + { + name = "preboot"; + value = "load mmc 0:1 0x43000000 bootlogo.bmp; bmp display 0x43000000; usb start"; + }, + { + name = "stdin"; + value = "serial"; + }, + { + name = "stdout"; + value = "serial"; + }, + { + name = "stderror"; + value = "serial"; + } + ); + }; + + /* now in systemB, we need to upgrade systemA(bootA, rootfsA) */ + now_B_next_A = { + images: ( + { + filename = "bootA.img"; + device = "/dev/mmcblk0p4"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootA.img)" + }, + { + filename = "opencentauri-image-hh-minimal-mmc-elegoo-centauri-carbon1.rootfs.squashfs"; + device = "/dev/mmcblk0p5"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(opencentauri-image-hh-minimal-mmc-elegoo-centauri-carbon1.rootfs.squashfs)" + }, + { + filename = "u-boot-sunxi-with-spl.bin"; + device = "/dev/mmcblk0"; + type = "raw"; + offset = "8K"; + sha256 = "$swupdate_get_sha256(u-boot-sunxi-with-spl.bin)" + }, + { + filename = "bootlogos.img"; + device = "/dev/mmcblk0p1"; + installed-directly = true; + sha256 = "$swupdate_get_sha256(bootlogos.img)" + } + ); + bootenv: ( + { + name = "boot_part"; + value = "4"; + }, + { + name = "mmc_root"; + value = "/dev/mmcblk0p5"; + }, + { + name = "systemAB_next"; + value = "A"; + }, + { + name = "swu_version"; + value = "@@DISTRO_VERSION@@"; + }, + { + name = "swu_mode"; + value = "mainline"; + }, + { + name = "setargs_mainline"; + value = "setenv bootargs console=ttyS0,115200 earlycon=uart8250,mmio32,0x02500000 root=${mmc_root} rootwait consoleblank=0"; + }, + { + name = "bootcmd_"; + value = "run setargs_mmc boot_dsp0 boot_normal"; + }, + { + name = "bootcmd_mainline"; + value = "run setargs_mainline; fatload mmc 0:${boot_part} 43000000 zImage; fatload mmc 0:${boot_part} 43800000 elegoo-centauri-carbon1.dtb; bootz 43000000 - 43800000"; + }, + { + name = "bootcmd"; + value = "run bootcmd_${swu_mode}"; + }, + { + name = "preboot"; + value = "load mmc 0:1 0x43000000 bootlogo.bmp; bmp display 0x43000000; usb start"; + }, + { + name = "stdin"; + value = "serial"; + }, + { + name = "stdout"; + value = "serial"; + }, + { + name = "stderror"; + value = "serial"; + } + ); + }; + }; +} diff --git a/meta-opencentauri/images/opencentauri-image-hh-full-mmc.bb b/meta-opencentauri/images/opencentauri-image-hh-full-mmc.bb new file mode 100644 index 00000000..ff803e4a --- /dev/null +++ b/meta-opencentauri/images/opencentauri-image-hh-full-mmc.bb @@ -0,0 +1,21 @@ +require opencentauri-image-hh-full.bb +inherit extract-partition + +DESCRIPTION = "OpenCentauri HH-Full eMMC Image (Standard + Happy Hare)" +LICENSE = "GPL-3.0-only" + +IMAGE_FSTYPES += "wic squashfs" +EXTRA_IMAGECMD:squashfs = "-comp lz4" + +IMAGE_FEATURES += "read-only-rootfs overlayfs-etc" + +WKS_FILES = "opencentauri-mmc-image.wks.in" +WKS_FILE_DEPENDS += "squashfs-tools-native" + +EXTRACT_PARTITION_LABELS = "bootA bootlogos" + +OVERLAYFS_ETC_MOUNT_POINT = "/data" +OVERLAYFS_ETC_DEVICE = "/dev/mmcblk0p10" +OVERLAYFS_ETC_FSTYPE ?= "ext4" +OVERLAYFS_ETC_CREATE_MOUNT_DIRS = "0" +OVERLAYFS_ETC_INIT_TEMPLATE = "${FILE_DIRNAME}/files/overlayfs-etc-preinit.sh.in" \ No newline at end of file diff --git a/meta-opencentauri/images/opencentauri-image-hh-full.bb b/meta-opencentauri/images/opencentauri-image-hh-full.bb new file mode 100644 index 00000000..539b493f --- /dev/null +++ b/meta-opencentauri/images/opencentauri-image-hh-full.bb @@ -0,0 +1,31 @@ +require opencentauri-image-base.bb + +DESCRIPTION = "OpenCentauri HH-Full Image (Standard + Happy Hare)" +LICENSE = "GPL-3.0-only" + +# Enable MMU/COSMOS macros for this image +PACKAGECONFIG:pn-kalico = "opencentauri-hh-full" + +# Happy Hare und MMU-Optimierungen hinzufügen +CORE_IMAGE_EXTRA_INSTALL += "\ + happy-hare \ + kalico-firmware-mmu \ + zram-emmc-swap \ + gui-switcher \ +" + +# zram-Konfiguration für MMU-Betrieb vorbereiten (200% Faktor für 128MB RAM = 256MB Swap) +ROOTFS_POSTPROCESS_COMMAND:append = " \ + install_zram_config ; \ +" + +install_zram_config() { + install -d ${IMAGE_ROOTFS}/etc/default + echo "FACTOR=200" > ${IMAGE_ROOTFS}/etc/default/zram + + # Swappiness und Memory-Parameter für MMU optimieren (ausgewogen) + install -d ${IMAGE_ROOTFS}/etc/sysctl.d + echo 'vm.swappiness=100' > ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.vfs_cache_pressure=150' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.watermark_boost_factor=0' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf +} \ No newline at end of file diff --git a/meta-opencentauri/images/opencentauri-image-hh-minimal-mmc.bb b/meta-opencentauri/images/opencentauri-image-hh-minimal-mmc.bb new file mode 100644 index 00000000..1f6d4c75 --- /dev/null +++ b/meta-opencentauri/images/opencentauri-image-hh-minimal-mmc.bb @@ -0,0 +1,21 @@ +require opencentauri-image-hh-minimal.bb +inherit extract-partition + +DESCRIPTION = "OpenCentauri Minimal eMMC Image (ohne Web-Interface)" +LICENSE = "GPL-3.0-only" + +IMAGE_FSTYPES += "wic squashfs" +EXTRA_IMAGECMD:squashfs = "-comp lz4" + +IMAGE_FEATURES += "read-only-rootfs overlayfs-etc" + +WKS_FILES = "opencentauri-mmc-image.wks.in" +WKS_FILE_DEPENDS += "squashfs-tools-native" + +EXTRACT_PARTITION_LABELS = "bootA bootlogos" + +OVERLAYFS_ETC_MOUNT_POINT = "/data" +OVERLAYFS_ETC_DEVICE = "/dev/mmcblk0p10" +OVERLAYFS_ETC_FSTYPE ?= "ext4" +OVERLAYFS_ETC_CREATE_MOUNT_DIRS = "0" +OVERLAYFS_ETC_INIT_TEMPLATE = "${FILE_DIRNAME}/files/overlayfs-etc-preinit.sh.in" diff --git a/meta-opencentauri/images/opencentauri-image-hh-minimal.bb b/meta-opencentauri/images/opencentauri-image-hh-minimal.bb new file mode 100644 index 00000000..fbe7fbd7 --- /dev/null +++ b/meta-opencentauri/images/opencentauri-image-hh-minimal.bb @@ -0,0 +1,104 @@ +#@TYPE: Image +#@NAME: OpenCentauri Minimal Image +#@DESCRIPTION: OpenCentauri Minimal Image mit Happy Hare aber ohne Web-Interface (nur Klipper zum Drucken) + +DESCRIPTION = "OpenCentauri Minimal Image mit Happy Hare (kein Web-Interface)" +LICENSE = "GPL-3.0-only" + +IMAGE_INSTALL = "packagegroup-core-boot ${CORE_IMAGE_EXTRA_INSTALL}" + +IMAGE_LINGUAS = " " + +inherit core-image + +# Enable MMU/COSMOS macros for this image +PACKAGECONFIG:pn-kalico = "opencentauri-hh-minimal" +# Mainsail config only (no frontend) - macros needed for Klipper +PACKAGECONFIG:pn-mainsail = "config-only" + +IMAGE_FEATURES += "ssh-server-dropbear" + +CORE_IMAGE_EXTRA_INSTALL += "\ + usbutils \ + libgpiod \ + libgpiod-tools \ + kernel-modules \ + rtw88 \ + wpa-supplicant \ + iw \ + kalico \ + kalico-firmware-mmu \ + moonraker \ + htop \ + i2c-tools \ + nano \ + devmem2 \ + swupdate \ + u-boot-fw-utils \ + zram \ + zram-emmc-swap \ + usb-automount \ + dev-by-id \ + psplash \ + opencentauri-bootlogos \ + swu-flasher \ + update-scripts \ + logrotate \ + happy-hare \ + mainsail \ +" + +# zram auf 200% für MMU-Betrieb (ausgewogen für 128MB RAM = 256MB Swap) +ROOTFS_POSTPROCESS_COMMAND:append = " \ + install_zram_config ; \ +" + +install_zram_config() { + install -d ${IMAGE_ROOTFS}/etc/default + echo "FACTOR=200" > ${IMAGE_ROOTFS}/etc/default/zram + + # Swappiness und Memory-Parameter für MMU optimieren (ausgewogen) + install -d ${IMAGE_ROOTFS}/etc/sysctl.d + echo 'vm.swappiness=100' > ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.vfs_cache_pressure=150' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.watermark_boost_factor=0' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.page-cluster=0' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + + # OOM-Score Anpassung für Klipper vorbereiten + install -d ${IMAGE_ROOTFS}/etc/init.d + cat > ${IMAGE_ROOTFS}/etc/init.d/mmuprotect <<'EOF' +#!/bin/sh +### BEGIN INIT INFO +# Provides: mmuprotect +# Required-Start: klipper moonraker +# Default-Start: 2 3 4 5 +# Short-Description: Protect Klipper and MMU from OOM killer +### END INIT INFO + +case "$1" in + start) + # Klipper OOM-Score senken (weniger likely to be killed) + if [ -f /var/run/klipper.pid ]; then + echo -500 > /proc/$(cat /var/run/klipper.pid)/oom_score_adj 2>/dev/null || true + fi + ;; +esac +exit 0 +EOF + chmod +x ${IMAGE_ROOTFS}/etc/init.d/mmuprotect +} + +# Memory-Optimierungen +IMAGE_FEATURES:remove = "splash" +IMAGE_FEATURES:remove = "tools-debug" + +# Explizit entfernte Pakete für Minimal-Image +IMAGE_INSTALL:remove = "grumpyscreen" +BAD_PACKAGES =+ "grumpyscreen" + +INITRAMFS_IMAGE = "core-image-tiny-initramfs" +INITRAMFS_FSTYPES = "cpio.gz" +INITRAMFS_IMAGE_BUNDLE = "1" + +# Nur für Centauri Carbon 1 (128MB RAM) +COMPATIBLE_MACHINE = "elegoo-centauri-carbon1" \ No newline at end of file diff --git a/meta-opencentauri/images/opencentauri-image-mmu.bb b/meta-opencentauri/images/opencentauri-image-mmu.bb new file mode 100644 index 00000000..6ed0c0ae --- /dev/null +++ b/meta-opencentauri/images/opencentauri-image-mmu.bb @@ -0,0 +1,95 @@ +#@TYPE: Image +#@NAME: OpenCentauri MMU Image +#@DESCRIPTION: OpenCentauri Image optimized for MMU operation with Happy Hare. +# Removes all native UIs and uses external web interface for maximum RAM availability. + +DESCRIPTION = "OpenCentauri Image optimized for MMU operation (Happy Hare)" +LICENSE = "GPL-3.0-only" + +IMAGE_INSTALL = "packagegroup-core-boot ${CORE_IMAGE_EXTRA_INSTALL}" + +IMAGE_LINGUAS = " " + +inherit core-image + +IMAGE_FEATURES += "ssh-server-dropbear" + +CORE_IMAGE_EXTRA_INSTALL += "\ + usbutils \ + libgpiod \ + libgpiod-tools \ + kernel-modules \ + rtw88 \ + wpa-supplicant \ + iw \ + kalico \ + moonraker \ + htop \ + i2c-tools \ + nano \ + devmem2 \ + swupdate \ + u-boot-fw-utils \ + zram \ + zram-emmc-swap \ + usb-automount \ + dev-by-id \ + psplash \ + opencentauri-bootlogos \ + swu-flasher \ + update-scripts \ + camera-led-bridge \ + logrotate \ + happy-hare \ +" + +# zram auf 200% für MMU-Betrieb (ausgewogen für 128MB RAM = 256MB Swap) +ROOTFS_POSTPROCESS_COMMAND:append = " \ + install_zram_config ; \ +" + +install_zram_config() { + install -d ${IMAGE_ROOTFS}/etc/default + echo "FACTOR=200" > ${IMAGE_ROOTFS}/etc/default/zram + + # Swappiness und Memory-Parameter für MMU optimieren (ausgewogen) + install -d ${IMAGE_ROOTFS}/etc/sysctl.d + echo 'vm.swappiness=100' > ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.vfs_cache_pressure=150' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.watermark_boost_factor=0' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + echo 'vm.page-cluster=0' >> ${IMAGE_ROOTFS}/etc/sysctl.d/99-mmu-memory.conf + + # OOM-Score Anpassung für Klipper vorbereiten + install -d ${IMAGE_ROOTFS}/etc/init.d + cat > ${IMAGE_ROOTFS}/etc/init.d/mmuprotect <<'EOF' +#!/bin/sh +### BEGIN INIT INFO +# Provides: mmuprotect +# Required-Start: klipper moonraker +# Default-Start: 2 3 4 5 +# Short-Description: Protect Klipper and MMU from OOM killer +### END INIT INFO + +case "$1" in + start) + # Klipper OOM-Score senken (weniger likely to be killed) + if [ -f /var/run/klipper.pid ]; then + echo -500 > /proc/$(cat /var/run/klipper.pid)/oom_score_adj 2>/dev/null || true + fi + ;; +esac +exit 0 +EOF + chmod +x ${IMAGE_ROOTFS}/etc/init.d/mmuprotect +} + +# Memory-Optimierungen +IMAGE_FEATURES:remove = "splash" +IMAGE_FEATURES:remove = "tools-debug" + +INITRAMFS_IMAGE = "core-image-tiny-initramfs" +INITRAMFS_FSTYPES = "cpio.gz" +INITRAMFS_IMAGE_BUNDLE = "1" + +# Nur für Centauri Carbon 1 (128MB RAM) +COMPATIBLE_MACHINE = "elegoo-centauri-carbon1" diff --git a/meta-opencentauri/images/opencentauri-upgrade-hh-full.bb b/meta-opencentauri/images/opencentauri-upgrade-hh-full.bb new file mode 100644 index 00000000..9967594f --- /dev/null +++ b/meta-opencentauri/images/opencentauri-upgrade-hh-full.bb @@ -0,0 +1,40 @@ +DESCRIPTION = "OpenCentauri HH-Full Upgrade Image (Standard + Happy Hare + Mainsail)" +LICENSE = "GPL-3.0-only" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-3.0-only;md5=c79ff39f19dfec6d293b95dea7b07891" + +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +SRC_URI = "file://sw-description-hh-full" + +do_copy_swu_description() { + cp ${WORKDIR}/sw-description-hh-full ${WORKDIR}/sw-description +} +addtask do_copy_swu_description before do_swuimage after do_unpack + +S = "${WORKDIR}" + +IMAGE_DEPENDS = "opencentauri-image-hh-full-mmc virtual/kernel u-boot" + +SWUPDATE_IMAGES = " \ + opencentauri-image-hh-full-mmc-elegoo-centauri-carbon1.rootfs \ + bootA \ + bootlogos \ + u-boot-sunxi-with-spl \ +" + +SWUPDATE_IMAGES_FSTYPES[opencentauri-image-hh-full-mmc-elegoo-centauri-carbon1.rootfs] = ".squashfs" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[opencentauri-image-hh-full-mmc-elegoo-centauri-carbon1.rootfs] = "1" + +SWUPDATE_IMAGES_FSTYPES[bootA] = ".img" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[bootA] = "1" + +SWUPDATE_IMAGES_FSTYPES[bootlogos] = ".img" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[bootlogos] = "1" + +SWUPDATE_IMAGES_FSTYPES[u-boot-sunxi-with-spl] = ".bin" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[u-boot-sunxi-with-spl] = "1" + +SWUPDATE_SIGNING = "RSA" +SWUPDATE_PRIVATE_KEY = "${TOPDIR}/../meta-opencentauri/images/files/swupdate_private.pem" + +inherit swupdate diff --git a/meta-opencentauri/images/opencentauri-upgrade-hh-minimal.bb b/meta-opencentauri/images/opencentauri-upgrade-hh-minimal.bb new file mode 100644 index 00000000..b37d8836 --- /dev/null +++ b/meta-opencentauri/images/opencentauri-upgrade-hh-minimal.bb @@ -0,0 +1,40 @@ +DESCRIPTION = "OpenCentauri HH-Minimal Upgrade Image (Happy Hare without Web-Interface)" +LICENSE = "GPL-3.0-only" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-3.0-only;md5=c79ff39f19dfec6d293b95dea7b07891" + +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +SRC_URI = "file://sw-description-hh-minimal" + +do_copy_swu_description() { + cp ${WORKDIR}/sw-description-hh-minimal ${WORKDIR}/sw-description +} +addtask do_copy_swu_description before do_swuimage after do_unpack + +S = "${WORKDIR}" + +IMAGE_DEPENDS = "opencentauri-image-hh-minimal-mmc virtual/kernel u-boot" + +SWUPDATE_IMAGES = " \ + opencentauri-image-hh-minimal-mmc-elegoo-centauri-carbon1.rootfs \ + bootA \ + bootlogos \ + u-boot-sunxi-with-spl \ +" + +SWUPDATE_IMAGES_FSTYPES[opencentauri-image-hh-minimal-mmc-elegoo-centauri-carbon1.rootfs] = ".squashfs" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[opencentauri-image-hh-minimal-mmc-elegoo-centauri-carbon1.rootfs] = "1" + +SWUPDATE_IMAGES_FSTYPES[bootA] = ".img" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[bootA] = "1" + +SWUPDATE_IMAGES_FSTYPES[bootlogos] = ".img" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[bootlogos] = "1" + +SWUPDATE_IMAGES_FSTYPES[u-boot-sunxi-with-spl] = ".bin" +SWUPDATE_IMAGES_NOAPPEND_MACHINE[u-boot-sunxi-with-spl] = "1" + +SWUPDATE_SIGNING = "RSA" +SWUPDATE_PRIVATE_KEY = "${TOPDIR}/../meta-opencentauri/images/files/swupdate_private.pem" + +inherit swupdate diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/happy-hare-init b/meta-opencentauri/recipes-apps/happy-hare/files/happy-hare-init new file mode 100644 index 00000000..3286b049 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/happy-hare-init @@ -0,0 +1,40 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: happy-hare-setup +# Required-Start: $local_fs $network +# Required-Stop: $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Happy Hare MMU Setup +# Description: Sets up Happy Hare MMU configuration on first boot +### END INIT INFO + +case "$1" in + start) + # Check if MMU config needs setup + if [ ! -f /etc/klipper/config/mmu/mmu.cfg ]; then + echo "Setting up Happy Hare MMU configuration..." + + # Copy default config if exists + if [ -d /usr/share/happy-hare/config ]; then + cp -r /usr/share/happy-hare/config/*.cfg /etc/klipper/config/mmu/ 2>/dev/null || true + fi + + # Setup symlinks for Moonraker update manager + if [ -d /home/mainsail ]; then + ln -sf /usr/share/happy-hare /home/mainsail/Happy-Hare 2>/dev/null || true + fi + fi + ;; + stop) + ;; + restart) + $0 start + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 b/meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 new file mode 100644 index 00000000..232fbbe3 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 @@ -0,0 +1,86 @@ +# Happy Hare MMU Konfiguration für FYSETC ERB V2.0 +# Elegoo Centauri Carbon 1 (128MB RAM optimiert) +# +# Diese Datei definiert die MCU und Pin-Zuordnungen für das ERB V2.0 Board +# + +# MCU-Definition für FYSETC ERB V2.0 (RP2040) +[mcu mmu] +serial: /dev/serial/by-id/usb-Klipper_RP2040_* + +# Board-Pin-Aliase für FYSETC ERB V2.0 +# Alle Pins verwenden die RP2040 GPIO-Nummern +[board_pins erb] +mcu: mmu + +# Gear Stepper Pins (Antriebsmotor für Filament) +[stepper_mmu_gear] +step_pin: mmu:gpio10 +dir_pin: !mmu:gpio9 +enable_pin: !mmu:gpio8 +uart_pin: mmu:gpio11 +uart_address: 0 + +# Selector Stepper Pins (Gate-Auswahl) +[stepper_mmu_selector] +step_pin: mmu:gpio16 +dir_pin: !mmu:gpio15 +enable_pin: !mmu:gpio14 +uart_pin: mmu:gpio17 +uart_address: 1 +endstop_pin: ^mmu:gpio24 + +# Selector Servo (PWM für Gate-Verriegelung) +[mmu_servo selector_servo] +pin: mmu:gpio23 +minimum_pulse_width: 0.001000 +maximum_pulse_width: 0.002000 +maximum_servo_angle: 180 + +# Encoder (Filamentbewegungsmessung) +[mmu_encoder mmu_encoder] +encoder_pin: ^mmu:gpio22 +# RAM-Optimierung: Reduzierte Auflösung für weniger Memory +encoder_resolution: 1.0 + +# Neopixel LEDs (Status-Anzeige pro Gate) +[neopixel mmu_leds] +pin: mmu:gpio21 +chain_count: 12 +color_order: GRB +initial_RED: 0.0 +initial_GREEN: 0.5 +initial_BLUE: 0.0 + +# Gate Sensor (Hall-Effekt Sensor für Filament-Erkennung) +[mmu_sensors] +gate_switch_pin: ^mmu:gpio25 + +# Pre-Gate Sensoren (Filamentpräsenz an jedem Gate) +# GPIO-Pins für 12 Gates (ERCF v2 Standard) +pre_gate_switch_pin_0: ^mmu:gpio12 +pre_gate_switch_pin_1: ^mmu:gpio18 +pre_gate_switch_pin_2: ^mmu:gpio2 +pre_gate_switch_pin_3: ^mmu:gpio3 +pre_gate_switch_pin_4: ^mmu:gpio4 +pre_gate_switch_pin_5: ^mmu:gpio5 +pre_gate_switch_pin_6: ^mmu:gpio6 +pre_gate_switch_pin_7: ^mmu:gpio7 +pre_gate_switch_pin_8: ^mmu:gpio26 +pre_gate_switch_pin_9: ^mmu:gpio27 +pre_gate_switch_pin_10: ^mmu:gpio28 +pre_gate_switch_pin_11: ^mmu:gpio29 + +# RAM-Optimierung: Deaktiviere nicht genutzte Gates +# Wenn du weniger als 12 Gates verwendest, kommentiere die nicht benötigten Pins aus +# Beispiel für 6-Gate-System: +#pre_gate_switch_pin_6: +#pre_gate_switch_pin_7: +#pre_gate_switch_pin_8: +#pre_gate_switch_pin_9: +#pre_gate_switch_pin_10: +#pre_gate_switch_pin_11: + +# Toolhead und Extruder Sensoren (optional) +#extruder_switch_pin: ^mmu:gpio1 +#toolhead_switch_pin: ^mmu:gpio0 diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier.cfg new file mode 100644 index 00000000..71899567 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier.cfg @@ -0,0 +1,914 @@ +# Include servo hardware definition separately to allow for automatic upgrade +[include blobifier_hw.cfg] + +########################################################################################## + +# Sample config to be used in conjunction with Blobifier Purge Tray, Bucket & Nozzle +# Scrubber mod. Created by Dendrowen (dendrowen on Discord). The Macro is based on a +# version, and Nozzle Scrubber is made by Hernsl (hernsl#8860 on Discord). The device is +# designed around a Voron V2.4 300mm, but should work for 250mm and 350mm too. This +# version only supports the assembly on the rear-left of the bed. If you decide to change +# that, please consider contributing to the project by creating a pull request with the +# needed changes. + +# IMPORTANT: The rear-left part of your bed becomes unusable by this mod because the +# toolhead needs to lower down to 0. Be sure not to use the left-rear 130x35mm. + +# The goals of this combination of devices is to dispose of purged filament during a +# multicolored print without the need of a purge block and without the flurries of +# filament poops consuming your entire 3D printer room. The Blobifier achieves that by +# purging onto a retractable tray which causes the filament to turn into a tiny blob +# rather then a large spiral. This keeps the waste relatively small. The bucket should be +# able to account for up to 200 filament swaps (for the 300mm V2). + +# The Blobifier uses some room at the back-left side of your printer, depending on your +# printer limits and positions. (usually max_pos.y - toolhead_y and brush_start + +# brush_width + toolhead_x). If you do place objects within this region, Blobifier will +# skip purging automatically. It does this by extending the EXCLUDE_OBJECT_* macro's, so +# make sure you have exclude objects enabled in your slicer. + +# If your using Blobifier in conjunction with the filament cutter on the stealthburner +# toolhead, you can place the pin at max_pos.y - 7 (e.g., max pos y is 307, place it at +# 300). The pin will then poke through the cavity in your toolhead. (Be careful with +# manually moving the toolhead. I have broken many filament cutter pins) + +# It is advised to use the start_gcode from Happy Hare. Then you will be able to fully +# and efficiently use this mod. Check the Happy Hare document at gcode_preprocessing.md +# in the Happy Hare github for more details. + +###################################### DISCLAIMER ######################################## + +# You, and you alone, are responsible for the correct execution of these macros and +# gcodes. Any damage that may occur to your machine remains your responsibility. +# Especially when executing this macro for the first few times, keep an eye on your +# printer and the +# emergency stop. + +########################################################################################## + +########################################################################################## +# Main macro. Usually you should only need to call this one or place it in the Happy Hare +# _MMU_POST_LOAD macro using the variable_user_post_load_extension: +# +# variable_user_post_load_extension : `BLOBIFIER` +# +# Notes on parameters: +# PURGE_LENGTH=[float] (optional) The length to purge. If omitted (default) it will check +# the purge_volumes matrix or variable_purge_length. This can be used +# to override and for testing. +# +[gcode_macro BLOBIFIER] +# These parameters define your filament purging. +# Note that the control of retraction is set in 'mmu_macro_vars.cfg' which can be increased +# if you experience excessive oozing. +variable_purge_spd: 400 # Speed, in mm/min, of the purge. +variable_purge_temp_min: 200 # Minimum nozzle purge temperature. +variable_toolhead_x: 70 # From the nozzle to the left of your toolhead +variable_toolhead_y: 50 # From the nozzle to the front of your toolhead + +# This macro will prevent a gcode movement downward while 'blobbing' if there might be a +# print in the way (e.g. You print something large and need the area where Blobifier does +# its... 'business'). However, at low heights (or at print start) this might not be +# desireable. You can force a 'safe descend' with this variable. Keep in mind that the +# height of the print is an estimation based on previous heights and certain assumptions +# so it might be wise to include a safety margin of 0.2mm +variable_force_safe_descend_height_until: 1.0 + +# Adjust this so that your nozzle scrubs within the brush. Be careful not to go too low! +# Start out with a high value (like, 6) and go +# down from there. +variable_brush_top: 6 + +# These parameters define your scrubbing, travel speeds, safe z clearance and how many +# times you want to wipe. Update as necessary. +variable_clearance_z: 2 # When traveling, but not cleaning, the + # clearance along the z-axis between nozzle + # and brush. +variable_wipe_qty: 2 # Number of complete (A complete wipe: left, + # right, left OR right, left, right) wipes. +variable_travel_spd_xy: 10000 # Travel (not cleaning) speed along x and + # y-axis in mm/min. +variable_travel_spd_z: 1000 # Travel (not cleaning) speed along z axis + # in mm/min. +variable_wipe_spd_xy: 10000 # Nozzle wipe speed in mm/min. + +# The acceleration to use when using the brush action. If set to 0, it uses the already +# set acceleration. However, in some cases this is not desirable for the last motion +# could be an 'outer contour' acceleration which is usually lower. +variable_brush_accel: 0 + +# Blobifier sends the toolhead to the maximum y position during purge operations and +# minimum x position during shake operations. This can cause issues when skew correction +# is set up. If you have skew correction enabled and get 'move out of range' errors +# regarding blobifier while skew is enabled, try increasing this value. Keep the +# adjustments small though! (0.1mm - 0.5mm) and increase it until it works. +variable_skew_correction: 0.1 + +# These parameters define the size of the brush. Update as necessary. A visual reference +# is provided below. +# +# ← brush_width → +# _________________ +# | | ↑ Y position is acquired from your +# brush_start (x) | | brush_depth stepper_y position_max. Adjust +# |_________________| ↓ your brush physically in Y so +# (y) that the nozzle scrubs within the +# brush_front brush. +# __________________________________________________________ +# PRINTER FRONT +# +# +# Start location of the brush. Defaults for 250, 300 and 350mm are provided below. +# Uncomment as necessary +#variable_brush_start: 34 # For 250mm build +variable_brush_start: 67 # For 300mm build +#variable_brush_start: 84 # for 350mm build + +# width of the brush +variable_brush_width: 35 + +# Location of where to purge. The tray is 15mm in length, so if you assemble it against +# the side of the bed (default), 10mm is a good location +variable_purge_x: 10 + +# Height of the tray. If it's below your bed, give this a negative number equal to the +# difference. If it's above your bed, give it a positive number. You can find this number +# by homing, optional QGL or equivalent, and moving you toolhead above the tray, and +# lowering it with the paper method. +variable_tray_top: 0.7 + +# Servo angles for tray positions +variable_tray_angle_out: 0 +variable_tray_angle_in: 180 + +# ======================================================================================== +# ==================== BLOB TUNING ======================================================= +# ======================================================================================== + +# The following section defines how the purging sequence is executed. This is where you +# tune the purging to create pretty blobs. Refer to the visual reference for a better +# understanding. The visual is populated with example values. Below are some guides +# provided to help with tuning. +# +# \_____________/ +# |___|___| +# \_/ ______________ < End of third iteration. +# / \ HEIGHT: 3 x iteration_z_raise - (2 + 1) x iteration_z_change (3 x 5 - 2 x 1.2 = 11.4) +# | | EXTRUDED: 3 x max_iteration_length (3 x 50 = 150) +# / \ ______________ < End of second iteration. +# | \ HEIGHT: 2 x iteration_z_raise - 1 x iteration_z_change (2 x 5 - 1 x 1.2 = 8.8) +# / | EXTRUDED: 2 x max_iteration_length (2 x 50 = 100) +# | \ ______________ < End of first iteration. +# / \ HEIGHT: 1 x iteration_z_raise (1 x 5 = 5) +# | | EXTRUDED: 1 x max_iteration_length (1 x 50 = 50) +#___________ \ / ______________ < Start height of the nozzle. default value: 1.5mm +# |_______________\___________/_ ______________ < Bottom of the tray +# |_____________________________| +# | +# +########################### BLOB TUNING ############################## +# +-------------------------------------+----------------------------+ +# | Filament sticks to the nozzle at | Incr. purge start | +# | initial purge (first few mm) | | +# +-------------------------------------+----------------------------+ +# | Filament scoots out from under | Incr. temperature | +# | the nozzle at the first iteration | Decr. z_raise | +# | | Incr. purge_length_maximum | +# +-------------------------------------+----------------------------+ +# | Filament scoots out from under the | Decr. purge_spd | +# | the nozzle at later iterations | Decr. z_raise_exp | +# | | Decr. z_raise | +# | | Incr. purge_length_maximum | +# +-------------------------------------+----------------------------+ +# | Filament sticks to the nozzle at | Incr. z_raise_exp | +# | later iterations | (Not above 1) | +# +-------------------------------------+----------------------------+ +# + +# The height to raise the nozzle above the tray before purging. This allows any built up +# pressure to escape before the purge. +variable_purge_start: 0.2 + +# The amount to raise Z +variable_z_raise: 12 + +# As the nozzle gets higher and the blob wider, the Z raise needs to be reduced, this +# follows the following formula: +# (extruded_amount/max_purge_length)^z_raise_exp * z_raise +# 1 is linear, below 1 will cause z to raise less quickly over time, above 1 will make it +# raise quicker over time. 0.85 is a good starting point and you should not have it above 1 +variable_z_raise_exp: 0.85 + +# Lift the nozzle slightly after creating the blob te release pressure on the tray. +variable_eject_hop: 1.0 + +# Dwell time (ms) after purging and before cleaning to relieve pressure from the nozzle. +variable_pressure_release_time: 1000 + +# Set the part cooling fan speed. Disabling can help prevent the nozzle from cooling down +# and stimulate flow, Enabling it can prevent blobs from sticking together. Values range +# from 0 .. 1, or -1 if you don't want it changed. +#variable_part_cooling_fan: -1 # Leave it unchanged +#variable_part_cooling_fan: 0 # Disable the fan +variable_part_cooling_fan: 1 # Run it at full speed + + +# ======================================================================================== +# ==================== PURGE LENGTH TUNING =============================================== +# ======================================================================================== + +# The absolute minimum to purge, even if you don't changed tools. This is to prime the +# nozzle before printing +variable_purge_length_minimum: 30 + +# The maximum amount of filament (in mm¹) to purge in a single blob. Blobifier will +# automatically purge multiple blobs if the purge amount exceeds this. +variable_purge_length_maximum: 150 + +# Default purge length to fall back on when neither the tool map purge_volumes or +# parameter PURGE_LENGTH is set. +variable_purge_length: 150 + +# The slicer values often are a bit too wasteful. Tune it here to get optimal values. +# 0.6 (60%) is a good starting point. +variable_purge_length_modifier: 0.6 + +# Fixed length of filament to add after the purge volume calculation. Happy Hare already +# shares info on the extra amount of filament to purge based on known residual filament, +# tip cutting fragment and initial retraction setting. However this setting can add a fixed +# amount on top on that if necessary although it is recommended to start with 0 and tune +# slicer purge matrix first. +# When should you alter this value: +# INCREASE: When the dark to light swaps are good, but light to dark aren't. +# DECREASE: When the light to dark swaps are good, but dark to light aren't. Don't +# forget to increase the purge_length_modifier +variable_purge_length_addition: 0 + +# ======================================================================================== +# ==================== BUCKET ============================================================ +# ======================================================================================== + +# Maximum number of blobs that fit in the bucket. Pauses the print if it exceeds this +# number. +variable_max_blobs: 400 +# Enable the bucket shaker. You need to have the shaker.stl installed +variable_enable_shaker: 1 +# The number of back-and-forth motions of one shake +variable_bucket_shakes: 10 +# During shaking acceleration can often be higher because you don't need to keep print +# quality in mind. Higher acceleration helps better with dispersing the blobs. +variable_shake_accel: 10000 + +# The frequency at which to shake the bucket. A decimal value ranging from 0 to 1, where 0 +# is never, and 1 is every time. This way the shaking occurs more often as the bucket +# fills up. Sensible values range from 0.75 to 0.95 +variable_bucket_shake_frequency: 0.95 + +# Height of the shaker arm. If your hotend hits your tray during shaking, increase. +variable_shaker_arm_z: 2 + +gcode: + + # ====================================================================================== + # ==================== RECORD STATE (INCL. FANS, SPEEDS, ETC...) ======================= + # ====================================================================================== + + # General state + SAVE_GCODE_STATE NAME=BLOBIFIER_state + + + # ====================================================================================== + # ==================== CHECK HOMING STATUS ============================================= + # ====================================================================================== + + {% if "xyz" not in printer.toolhead.homed_axes %} + RESPOND MSG="BLOBIFIER: Not homed! Home xyz before blobbing" + {% elif printer.quad_gantry_level and printer.quad_gantry_level.applied == False %} + RESPOND MSG="BLOBIFIER: QGL not applied! run quad_gantry_level before blobbing" + {% else %} + + # Part cooling fan + {% if part_cooling_fan >= 0 %} + # Save the part cooling fan speed to be enabled again later + {% set backup_fan_speed = printer.fan.speed %} + # Set part cooling fan speed + M106 S{part_cooling_fan * 255} + {% endif %} + + # Set feedrate to 100% for correct speed purging + {% set backup_feedrate = printer.gcode_move.speed_factor %} + M220 S100 + + # ====================================================================================== + # ==================== DEFINE BASIC VARIABLES ========================================== + # ====================================================================================== + + {% set sequence_vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set filament_diameter = printer.configfile.config.extruder.filament_diameter|float %} + {% set filament_cross_section = (filament_diameter/2) ** 2 * 3.1415 %} + {% set from_tool = printer.mmu.last_tool %} + {% set to_tool = printer.mmu.tool %} + {% set bl_count = printer['gcode_macro _BLOBIFIER_COUNT'] %} + {% set pos = printer.gcode_move.gcode_position %} + {% set safe = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'] %} + {% set ignore_safe = safe.print_height < force_safe_descend_height_until %} + {% set restore_z = [printer['gcode_macro BLOBIFIER_PARK'].restore_z,pos.z]|max %} + {% set pos_max = printer.toolhead.axis_maximum %} + {% set position_y = pos_max.y - skew_correction %} + + # Get purge volumes from the slicer (if set up right. see + # https://github.com/moggieuk/Happy-Hare/wiki/Gcode-Preprocessing) + {% set pv = printer.mmu.slicer_tool_map.purge_volumes %} + + # ====================================================================================== + # ==================== DETERMINE PURGE LENGTH ========================================== + # ====================================================================================== + + {% if params.PURGE_LENGTH %} # =============== PARAM PURGE LENGTH ====================== + {action_respond_info("BLOBIFIER: param PURGE_LENGTH provided")} + {% set purge_len = params.PURGE_LENGTH|float %} + {% elif from_tool == to_tool and to_tool >= 0 %} # ==== TOOL DIDN'T CHANGE ============= + {action_respond_info("BLOBIFIER: Tool didn't change (T%s > T%s), %s" % (from_tool, to_tool, "priming" if purge_length_minimum else "skipping"))} + {% set purge_len = 0 %} + + {% elif pv %} # ============== FETCH FROM HAPPY HARE (LIKELY FROM SLICER) ============== + {% if from_tool < 0 and to_tool >= 0%} + {action_respond_info("BLOBIFIER: from tool unknown. Finding largest value for T? > T%d" % to_tool)} + {% set purge_vol = pv|map(attribute=to_tool)|max %} + {% elif to_tool < 0 %} + {action_respond_info("BLOBIFIER: tool(s) unknown. Finding largest value")} + {% set purge_vol = pv|map('max')|max %} + {% else %} + {% set purge_vol = pv[from_tool][to_tool]|float * purge_length_modifier %} + {action_respond_info("BLOBIFIER: Swapped T%s > T%s" % (from_tool, to_tool))} + {% endif %} + {% set purge_len = purge_vol / filament_cross_section %} + + {% set purge_len = purge_len + printer.mmu.extruder_filament_remaining + park_vars.retracted_length + purge_length_addition %} + + {% else %} # ========================= USE CONFIG VARIABLE ============================= + {action_respond_info("BLOBIFIER: No toolmap or PURGE_LENGTH. Using default")} + {% set purge_len = purge_length|float + printer.mmu.extruder_filament_remaining + park_vars.retracted_length %} + {% endif %} + + # ==================================== APPLY PURGE MINIMUM ============================= + {% set purge_len = [purge_len,purge_length_minimum]|max|round(0, 'ceil')|int %} + {action_respond_info("BLOBIFIER: Purging %dmm of filament" % (purge_len))} + + # ====================================================================================== + # ==================== PURGING SEQUENCE ================================================ + # ====================================================================================== + + # Set to absolute positioning. + G90 + + # Check for purge length and purge if necessary. + {% if purge_len|float > 0 %} + + # ==================================================================================== + # ==================== POSITIONING =================================================== + # ==================================================================================== + + # Retract the tray so it is not in the way + BLOBIFIER_SERVO POS=in + + # Move to the assembly, first a bit more to the right (brush_start) to avoid a + # potential filametrix pin if it's not already on the same Y coordinate. + {% if printer.toolhead.position.y != position_y %} + G1 X{[brush_start - 20, 30]|max} Y{position_y} F{travel_spd_xy} + {% endif %} + + # ==================================================================================== + # ==================== BUCKET SHAKE ================================================== + # ==================================================================================== + + {% if enable_shaker and (safe.shake or ignore_safe) %} + {% if (bl_count.current_blobs + 1) >= bl_count.next_shake %} + BLOBIFIER_SHAKE_BUCKET SHAKES={bucket_shakes} + _BLOBIFIER_CALCULATE_NEXT_SHAKE + {% endif %} + {% endif %} + + # ==================================================================================== + # ==================== POSITIONING ON TRAY =========================================== + # ==================================================================================== + {% if safe.tray or ignore_safe %} + G1 Z{tray_top + purge_start} F{travel_spd_z} + {% endif %} + + # Move over to the tray after z change (For cases when the tool is lower than the tray) + G1 X{purge_x} F{travel_spd_xy} + + # Extend the tray + BLOBIFIER_SERVO POS=out + + # ==================================================================================== + # ==================== HEAT HOTEND =================================================== + # ==================================================================================== + + {% if printer.extruder.temperature < purge_temp_min %} + {% if printer.extruder.target < purge_temp_min %} + M109 S{purge_temp_min} + {% else %} + TEMPERATURE_WAIT SENSOR=extruder MINIMUM={purge_temp_min} + {% endif %} + {% endif %} + + # ==================================================================================== + # ==================== START ITERATING =============================================== + # ==================================================================================== + + # Calculate total number of iterations based on the purge length and the max_iteration + # length. + {% set blobs = (purge_len / purge_length_maximum)|round(0, 'ceil')|int %} + {% set purge_per_blob = purge_len|float / blobs %} + {% set retracts_per_blob = (purge_per_blob / 40)|round(0, 'ceil')|int %} + {% set purge_per_retract = (purge_per_blob / retracts_per_blob)|int %} + {% set pulses_per_retract = (purge_per_blob / retracts_per_blob / 5)|round(0, 'ceil')|int %} + {% set pulses_per_blob = (purge_per_blob / 5)|round(0, 'ceil')|int %} + {% set purge_per_pulse = purge_per_blob / pulses_per_blob %} + {% set pulse_time_constant = purge_per_pulse * 0.95 / purge_spd / (purge_per_pulse * 0.95 / purge_spd + purge_per_pulse * 0.05 / 50) %} + {% set pulse_duration = purge_per_pulse / purge_spd %} + + # Repeat the process until purge_len is reached + {% for blob in range(blobs) %} + RESPOND MSG={"'BLOBIFIER: Blob %d of %d (%.1fmm)'" % (blob + 1, blobs, purge_per_blob)} + + {% if safe.tray or ignore_safe %} + G1 Z{tray_top + purge_start} F{travel_spd_z} + {% endif %} + + # relative positioning + G91 + # relative extrusion + M83 + + # Purge filament in a pulsating motion to purge the filament quicker and better + {% for pulse in range(pulses_per_blob) %} + # Calculations to determine z-speed + {% set purged_this_blob = pulse * purge_per_pulse %} + {% set z_last_pos = purge_start + ((purged_this_blob)/purge_length_maximum)**z_raise_exp * z_raise %} + {% set z_pos = purge_start + ((purged_this_blob + purge_per_pulse)/purge_length_maximum)**z_raise_exp * z_raise %} + {% set z_up = z_pos - z_last_pos %} + {% set speed = z_up / pulse_duration %} + + # Purge quickly + G1 Z{z_up * pulse_time_constant} E{purge_per_pulse * 0.95} F{speed} + # Purge a tiny bit slowly + G1 Z{z_up * (1 - pulse_time_constant)} E{purge_per_pulse * 0.05} F{speed} + + # retract and unretract filament every now and then for thorough cleaning + {% if pulse % pulses_per_retract == 0 and pulse > 0 %} + G1 E-2 F1800 + G1 E2 F800 + {% endif %} + + {% endfor %} + + # Retract to match what Happy Hare is expecting + G1 E-{park_vars.retracted_length} F{sequence_vars.retract_speed * 60} + + # ================================================================================== + # ==================== DEPOSIT BLOB ================================================ + # ================================================================================== + {% if safe.tray or ignore_safe %} + # Raise z a bit to relieve pressure on the blob preventing it to go sideways + G1 Z{eject_hop} F{travel_spd_z} + # Retract the tray + BLOBIFIER_SERVO POS=in + # Move the toolhead down to purge_start height lowering the blob below the tray + G90 # absolute positioning + G1 Z{tray_top} F{travel_spd_z} + # Extend the tray to 'cut off' the blob and prepare for the next blob + BLOBIFIER_SERVO POS=out + BLOBIFIER_SERVO POS=in + BLOBIFIER_SERVO POS=out + # Keep track of the # of blobs + _BLOBIFIER_COUNT + {% endif %} + {% endfor %} + {% endif %} + {% if safe.tray or ignore_safe %} + G1 Z{tray_top + 1} F{travel_spd_z} + G4 P{pressure_release_time} + {% endif %} + {% if safe.brush or ignore_safe %} + BLOBIFIER_CLEAN + {% else %} + G1 X{brush_start} F{travel_spd_xy} + {% endif %} + + # ====================================================================================== + # ==================== RESTORE STATE =================================================== + # ====================================================================================== + G90 # absolute positioning + G1 Z{restore_z} F{travel_spd_z} + + {% if part_cooling_fan >= 0 %} + # Reset part cooling fan if it was changed + M106 S{(backup_fan_speed * 255)|int} + {% endif %} + + M220 S{(backup_feedrate * 100)|int} + {% endif %} + + # Retract the tray + BLOBIFIER_SERVO POS=in + + RESTORE_GCODE_STATE NAME=BLOBIFIER_state + + +########################################################################################## +# Wipes the nozzle on the brass brush +# +[gcode_macro BLOBIFIER_CLEAN] +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + {% set pos_max = printer.toolhead.axis_maximum %} + {% set position_y = pos_max.y - bl.skew_correction %} + {% set original_accel = printer.toolhead.max_accel %} + {% set original_minimum_cruise_ratio = printer.toolhead.minimum_cruise_ratio %} + {% set pos = printer.gcode_move.gcode_position %} + + SAVE_GCODE_STATE NAME=BLOBIFIER_CLEAN_state + + G90 + + {% if bl.brush_accel > 0 %} + SET_VELOCITY_LIMIT ACCEL={bl.brush_accel} MINIMUM_CRUISE_RATIO=0.1 + {% endif %} + + {% if pos.z < bl.brush_top + bl.clearance_z %} + G1 Z{bl.brush_top + bl.clearance_z} F{bl.travel_spd_z} + {% endif %} + G1 X{bl.brush_start} F{bl.travel_spd_xy} + G1 Y{position_y} + G1 Z{bl.brush_top + bl.clearance_z} F{bl.travel_spd_z} + + # Move nozzle down into brush. + G1 Z{bl.brush_top} F{bl.travel_spd_z} + + SET_VELOCITY_LIMIT ACCEL={original_accel} MINIMUM_CRUISE_RATIO={original_minimum_cruise_ratio} + + # Perform wipe. Wipe direction based off bucket_pos for cool random scrubby routine. + {% for wipes in range(1, (bl.wipe_qty + 1)) %} + G1 X{bl.brush_start + bl.brush_width} F{bl.wipe_spd_xy} + G1 X{bl.brush_start} F{bl.wipe_spd_xy} + {% endfor %} + + # Move away from the brush, but not onto the tray or in front of the filametrix cutter pin + G1 X{[bl.brush_start - 20, 30]|max} F{bl.travel_spd_xy} + + RESTORE_GCODE_STATE NAME=BLOBIFIER_CLEAN_state + + + +########################################################################################## +# Park the nozzle on the tray to prevent oozing during filament swaps. Place this +# extension in the post_form_tip extension in mmu_macro_vars.cfg: +# variable_user_post_form_tip_extension: "BLOBIFIER_PARK" +# +[gcode_macro BLOBIFIER_PARK] +variable_restore_z: 0 +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + {% set pos = printer.gcode_move.gcode_position %} + {% set safe = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'] %} + {% set pos_max = printer.toolhead.axis_maximum %} + {% set position_y = pos_max.y - bl.skew_correction %} + + SET_GCODE_VARIABLE MACRO=BLOBIFIER_PARK VARIABLE=restore_z VALUE={pos.z} + + SAVE_GCODE_STATE NAME=blobifier_park_state + + {% if "xyz" in printer.toolhead.homed_axes and printer.quad_gantry_level and printer.quad_gantry_level.applied %} + G90 + + # Retract the tray + BLOBIFIER_SERVO POS=in + + G1 X{[bl.brush_start - 20, 30]|max} Y{position_y} F{bl.travel_spd_xy} + {% if safe.tray or ignore_safe %} + G1 Z{bl.tray_top} F{bl.travel_spd_z} + {% endif %} + G1 X{bl.purge_x} F{bl.travel_spd_xy} + + # Extend the tray + BLOBIFIER_SERVO POS=out + + {% else %} + RESPOND MSG="Please home (and QGL) before parking" + {% endif %} + + RESTORE_GCODE_STATE NAME=blobifier_park_state + +########################################################################################## +# Retract or extend the tray +# POS=[in|out] Retractor extend the tray +# +[gcode_macro BLOBIFIER_SERVO] +# Increase this value if the servo doesn't have enough time to fully retract or extend +variable_dwell_time: 200 +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + {% set pos = params.POS %} + {% if pos == "in" %} + SET_SERVO SERVO=blobifier ANGLE={bl.tray_angle_in} + G4 P{dwell_time} + {% elif pos == "out" %} + SET_SERVO SERVO=blobifier ANGLE={bl.tray_angle_out} + G4 P{dwell_time} + {% else %} + {action_respond_info("BLOBIFIER: provide POS=[in|out]")} + {% endif %} + SET_SERVO SERVO=blobifier WIDTH=0 + +########################################################################################## +# Define exclude objects for those who haven't already +# +[exclude_object] + +########################################################################################## +# Overwrite the existing EXCLUDE_OBJECT_DEFINE to also check for safe descend. +# +[gcode_macro EXCLUDE_OBJECT_DEFINE] +rename_existing: _EXCLUDE_OBJECT_DEFINE +gcode: + # only reset on the first object at the beginning of a print + {% if printer.exclude_object.objects|length < 1 %} + _BLOBIFIER_RESET_SAFE_DESCEND + {% endif %} + _EXCLUDE_OBJECT_DEFINE {rawparams} + _BLOBIFIER_SAFE_DESCEND + UPDATE_DELAYED_GCODE ID=BLOBIFIER_SHOW_SAFE_DESCEND DURATION=1 + +[delayed_gcode BLOBIFIER_SHOW_SAFE_DESCEND] +gcode: + {% set safe = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'] %} + {action_respond_info( + "BLOBIFIER: Safe descend possible:\n - tray: %s\n - brush: %s\n - shake: %s" % + ( + "yes" if safe.tray else "no", + "yes" if safe.brush else "no", + "yes" if safe.shake else "no" + ) + )} + +########################################################################################## +# Use the EXCLUDE_OBJECT_START gcode macro to record the current height +# +[gcode_macro EXCLUDE_OBJECT_START] +rename_existing: _EXCLUDE_OBJECT_START +gcode: + _EXCLUDE_OBJECT_START {rawparams} + {% if printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'].first_layer %} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=first_layer VALUE=False + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_height VALUE={printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'].print_layer_height} + {% else %} + {% set pos = printer.gcode_move.gcode_position %} + {% set last_height = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'].print_previous_height|float %} + {% if pos.z > last_height %} + {% set last_layer = (pos.z - last_height)|round(2) %} + {% set print_height = (pos.z + last_layer)|round(2) %} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_previous_height VALUE={pos.z} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_height VALUE={print_height} + {% endif %} + {% endif %} + +########################################################################################## +# Reset the safe descend variables. +# +[gcode_macro _BLOBIFIER_RESET_SAFE_DESCEND] +gcode: + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=tray VALUE=True + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=brush VALUE=True + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=shake VALUE=True + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=first_layer VALUE=True + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_height VALUE=0 + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_previous_height VALUE=0 + +########################################################################################## +# Determine if it is safe to drop the toolhead (e.g. not hit a print) +# +[gcode_macro _BLOBIFIER_SAFE_DESCEND] +variable_tray: True # Assume it is safe +variable_brush: True +variable_shake: True +variable_first_layer: True +variable_print_height: 0 +variable_print_previous_height: 0 +variable_print_layer_height: 0.3 +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + {% set pos_max = printer.toolhead.axis_maximum %} + {% set position_y = pos_max.y - bl.skew_correction %} + {% set tray = [bl.purge_x + bl.toolhead_x, position_y - bl.toolhead_y] %} + {% set brush = [bl.brush_start + bl.brush_width + bl.toolhead_x, position_y - bl.toolhead_y] %} + {% set shake = [bl.purge_x + bl.toolhead_x, position_y - bl.toolhead_y - 4] %} + {% set objects = printer.exclude_object.objects | map(attribute='polygon') %} + + {% for polygon in objects %} + {% for point in polygon %} + {% if point[0] < tray[0] and point[1] > tray[1] %} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=tray VALUE=False + {% endif %} + {% if point[0] < brush[0] and point[1] > brush[1] %} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=brush VALUE=False + {% endif %} + {% if point[0] < shake[0] and point[1] > shake[1] %} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=shake VALUE=False + {% endif %} + {% endfor %} + {% endfor %} + +########################################################################################## +# Increment the blob count with 1 and check if the bucket is full. Pause +# the printer if it is. +# +[gcode_macro _BLOBIFIER_COUNT] +# Don't change these variables +variable_current_blobs: 0 +variable_last_shake: 0 +variable_next_shake: 0 +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + {% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %} + {% if current_blobs >= bl.max_blobs %} + {action_respond_info("BLOBIFIER: Empty purge bucket!")} + M117 Empty purge bucket! + PAUSE + {% else %} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=current_blobs VALUE={current_blobs + 1} + _BLOBIFIER_SAVE_STATE + {action_respond_info( + "BLOBIFIER: Blobs in bucket: %s/%s. Next shake @ %s" + % (current_blobs + 1, bl.max_blobs, next_shake) + )} + {% endif %} + +########################################################################################## +# Reset the blob count to 0 +# +[gcode_macro _BLOBIFIER_COUNT_RESET] +gcode: + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=current_blobs VALUE=0 + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=last_shake VALUE=0 + _BLOBIFIER_SAVE_STATE + + _BLOBIFIER_CALCULATE_NEXT_SHAKE + +########################################################################################## +# Shake the blob bucket to disperse the blobs +# +[gcode_macro BLOBIFIER_SHAKE_BUCKET] +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + {% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %} + {% set original_accel = printer.toolhead.max_accel %} + {% set original_minimum_cruise_ratio = printer.toolhead.minimum_cruise_ratio %} + {% set position_x = bl.skew_correction %} + + {% if "xyz" not in printer.toolhead.homed_axes %} + {action_raise_error("BLOBIFIER: Not homed. Home xyz first")} + {% endif %} + + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=last_shake VALUE={count.current_blobs} + _BLOBIFIER_SAVE_STATE + SAVE_GCODE_STATE NAME=shake_bucket + + M400 + M117 (^_^) + + G90 + {% set shakes = params.SHAKES|default(10)|int %} + {% set pos_max = printer.toolhead.axis_maximum %} + {% set position_y = pos_max.y - bl.skew_correction %} + + # move to save y if not already there + {% if printer.toolhead.position.y != position_y %} + G1 X{bl.brush_start} Y{position_y} F{bl.travel_spd_xy} + {% endif %} + + # Retract the tray + BLOBIFIER_SERVO POS=in + + # move up a bit to prevent oozing on base + G1 Z{bl.shaker_arm_z} F{bl.travel_spd_z} + # slide into the slot + G1 X{position_x} F{bl.travel_spd_xy} + + M400 + M117 (+(+_+)+) + + SET_VELOCITY_LIMIT ACCEL={bl.shake_accel} MINIMUM_CRUISE_RATIO=0.1 + + # Shake away! + {% for shake in range(1, shakes) %} + G1 Y{position_y - 4} + G1 Y{position_y} + {% endfor %} + + SET_VELOCITY_LIMIT ACCEL={original_accel} MINIMUM_CRUISE_RATIO={original_minimum_cruise_ratio} + # move out of slot + G1 X{bl.purge_x} + + M400 + M117 (X_x) + + RESTORE_GCODE_STATE NAME=shake_bucket + +########################################################################################## +# Calculate when the bucket should be shaken. +# +[gcode_macro _BLOBIFIER_CALCULATE_NEXT_SHAKE] +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + {% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %} + + {% set remaining_blobs = bl.max_blobs - count.last_shake %} + {% set next_shake = (1 - bl.bucket_shake_frequency) * remaining_blobs + count.last_shake %} + _BLOBIFIER_SAVE_STATE + _BLOBIFIER_SET_NEXT_SHAKE VALUE={next_shake|int} + +########################################################################################## +# Set when the bucket should be shaken next +# VALUE=[int] At what amount of blobs should it be shaken +# +[gcode_macro _BLOBIFIER_SET_NEXT_SHAKE] +gcode: + {% if params.VALUE %} + {% set next_shake = params.VALUE %} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=next_shake VALUE={next_shake} + _BLOBIFIER_SAVE_STATE + {% else %} + {action_respond_info("BLOBIFIER: Provide parameter VALUE=")} + {% endif %} + +########################################################################################## +# Some sanity checks +# +[delayed_gcode BLOBIFIER_INIT] +initial_duration: 5.0 +gcode: + _BLOBIFIER_INIT + # Extend and retract the tray to test + BLOBIFIER_SERVO POS=out + BLOBIFIER_SERVO POS=in + +[gcode_macro _BLOBIFIER_INIT] +gcode: + {% set bl = printer['gcode_macro BLOBIFIER'] %} + + # Valid part cooling fan setting + {% if bl.part_cooling_fan != -1 and (bl.part_cooling_fan < 0 or bl.part_cooling_fan > 1) %} + {action_emergency_stop("BLOBIFIER: Value %f is invalid for variable part_cooling_fan. Either -1 or a value from 0 .. 1 is valid." % (bl.part_cooling_fan))} + {% endif %} + + # Valid bucket shake frequency + {% if bl.bucket_shake_frequency < 0 or bl.bucket_shake_frequency > 1 %} + {action_emergency_stop("BLOBIFIER: Value %f is invalid for variable bucket_shake_frequency. Change it to a value between 0 .. 1" % (bl.bucket_shake_frequency))} + {% endif %} + + # Check if position is on 'next' + {% if printer.mmu %} + {% if printer['gcode_macro _MMU_SEQUENCE_VARS'].restore_xy_pos != 'next' %} + {action_respond_info("BLOBIFIER: If not using a wipe tower, consider setting restore_xy_pos: 'next' in mmu_macro_vars.cfg")} + {% endif %} + {% endif %} + + # Check the z_raise variable for normal values + {% if bl.z_raise < 3 %} + {action_respond_info("BLOBIFIER: variable_z_raise: %f is very low. This is the value z raises in total on a single blob. Make sure the value is correct before continuing." % (bl.z_raise))} + {% endif %} + + # Z raise exponent + {% if bl.z_raise_exp > 1 or bl.z_raise_exp < 0.5 %} + {action_respond_info("BLOBIFIER: variable_z_raise_exp has value: %f. This value is out of spec (0.5 ... 1.0)." % (bl.z_raise))} + {% endif %} + + # cap user defined accels at printer max_accel if greater + {% if bl.shake_accel > printer.configfile.config.printer.max_accel|int %} + {action_respond_info("BLOBIFIER: variable_shake_accel has value: %d which is higher than your printer limit of %d. Reduce this if your printer skips steps." % (bl.shake_accel,printer.configfile.config.printer.max_accel|int))} + {% endif %} + {% if bl.brush_accel > printer.configfile.config.printer.max_accel|int %} + {action_respond_info("BLOBIFIER: variable_brush_accel has value: %d which is higher than your printer limit of %d. Reduce this if your printer skips steps." % (bl.brush_accel,printer.configfile.config.printer.max_accel|int))} + {% endif %} + +[delayed_gcode BLOBIFIER_LOAD_STATE] +initial_duration: 2.0 # Give it some time to boot up +gcode: + {% set sv = printer.save_variables.variables.blobifier %} + + {% if sv %} + # Restore state + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=last_shake VALUE={sv.last_shake} + SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=current_blobs VALUE={sv.current_blobs} + {% endif %} + _BLOBIFIER_CALCULATE_NEXT_SHAKE + +[gcode_macro _BLOBIFIER_SAVE_STATE] +gcode: + {% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %} + {% set sv = {'current_blobs': count.current_blobs, 'last_shake': count.last_shake} %} + SAVE_VARIABLE VARIABLE=blobifier VALUE="{sv}" diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier_hw.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier_hw.cfg new file mode 100644 index 00000000..5f76ae8c --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/blobifier_hw.cfg @@ -0,0 +1,28 @@ + +########################################################################################## +# The servo hardware configuration. Change the values to your needs. +# +[mmu_servo blobifier] +# Pin for the servo. +pin: PG14 +# Adjust this value until a 'BLOBIFIER_SERVO POS=out' extends the tray fully without a +# buzzing sound +minimum_pulse_width: 0.00053 +# Adjust this value until a 'BLOBIFIER_SERVO POS=in' retracts the tray fully without a +# buzzing sound +maximum_pulse_width: 0.0023 +# Leave this value at 180 +maximum_servo_angle: 180 + + +########################################################################################## +# The bucket hardware configuration. Change the pin to whatever pin you've connected the +# switch to. +# +[gcode_button bucket] +pin: ^PG15 # The pullup ( ^ ) is important here. +press_gcode: + M117 bucket installed +release_gcode: + M117 bucket removed + _BLOBIFIER_COUNT_RESET diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler.cfg new file mode 100644 index 00000000..6cb0defc --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler.cfg @@ -0,0 +1,202 @@ +#################################### +# Variables for the eSpooler macros +# +# Configure these for your setup. +# +[gcode_macro _MMU_ESPOOLER_VARS] +# Prefix of name of the `output_pin` for the eSpooler. +# The `output_pin` name must follow the pattern {prefix}_rwd_{gate} +# and {prefix}_en_{gate}. By default we prefix it with an underscore +# to prevent them from being shown in UI applications (like mainsail). +# +variable_pin_prefix: '_mmu_dc_espooler' + +# Default max number of seconds for eSpooler to run +# Note: Each time any eSpooler **starts** it will restart the timeout +# +variable_default_timeout: 60 + +# The step speed where you want to max out the eSpooler to run at full speed. +# +variable_max_step_speed: 200 + +# Minimum distance of a move required to activate the eSpooler +# The lowest valid value for this is 50 because eSpooler macros +# will not even be considered if the distance is less than 50. +# +variable_min_distance: 200 + +# Adjusts the speed conversion ratio +# For the following examples, let's assume max_step_speed = 50. +# And remember actual eSpooler speed values are between 0.0 (off) and 1.0 (full speed) (inclusive) +# +# The formula looks like this: +# ({step_speed} / {max_step_speed}) ^ {step_speed_exponent} +# +# With step_speed_exponent of 1 would have a linear ratio: +# If I am running with a step speed of 50mm/s, the eSpooler would run at full speed (1.0) +# Calculated via (50/50)^1 +# If I am running with a step speed of 25mm/s, the eSpooler would run at half speed (0.5) +# Calculated via (25/50)^1 +# +# With step_speed_exponent of 0.2 would have a linear ratio: +# If I am running with a step speed of 50mm/s, the eSpooler would run at full speed (1.0) +# Calculated via (50/50)^0.2 +# If I am running with a step speed of 25mm/s, the eSpooler would run at half speed (0.87) +# Calculated via (25/50)^0.2 +# +variable_step_speed_exponent: 0.5 + +# Internal variable for tracking the gates with eSpoolers +variable_espooler_gates: '' +gcode: # Leave empty + +########################################################################### +# Include DC motor pin definitions +# +# This should be after the eSpooler vars macro to ensure the users +# custom vars override our default ones. +# +[include dc_espooler_hw.cfg] + +########################################################################### +# Macro to actuate the correct DC motor for the gate being unloaded +# +# Easiest integration is to set this in mmu_parameters.cfg: +# +# eSpooler_start_macro: MMU_ESPOOLER_START +# +[gcode_macro MMU_ESPOOLER_START] +gcode: + _MMU_ESPOOLER_CTL {rawparams} + + # Param hints UI + {% set dummy = None if True else " + {% set d = params.GATE|default(current_gate)|int %} + {% set d = params.SCALE|default(cfg_scale)|float %} + {% set d = params.TIMEOUT|default(default_timeout)|float %} + " %} # End param hints for UI + + +########################################################################### +# Macro to stop the DC eSpooler motor +# +# Easiest integration is to set this in mmu_macro_vars.cfg: +# +# eSpooler_stop_macro: MMU_ESPOOLER_STOP +# +[gcode_macro MMU_ESPOOLER_STOP] +gcode: + _MMU_ESPOOLER_CTL {rawparams} SPEED={0} + + # Param hints UI + {% set dummy = None if True else " + {% set d = params.GATE|default(current_gate)|int %} + " %} # End param hints for UI + +########################################################################### +# Macro to control the DC eSpooler motor +# +# Used by both the start and stop eSpooler macros +# +[gcode_macro _MMU_ESPOOLER_CTL] +gcode: + {% set vars = printer["gcode_macro _MMU_ESPOOLER_VARS"] %} + {% set current_gate = printer['mmu'].gate %} + {% set gate = params.GATE|default(current_gate)|int %} + {% set step_speed = params.STEP_SPEED|default(-1)|float %} + {% set expected_distance = params.MAX_DISTANCE|default(-1)|float %} + {% set homing_move = params.HOMING_MOVE|default(0)|int %} + {% set speed = params.SPEED|default(-1)|float %} + {% set pin_prefix = vars.pin_prefix %} + {% set pin = ('%s_rwd_%d' % (pin_prefix, gate)) if printer['output_pin %s_rwd_%d' % (pin_prefix, gate)] else None %} + {% set en_pin = ('%s_en_%d' % (pin_prefix, gate)) if printer['output_pin %s_en_%d' % (pin_prefix, gate)] else None %} + {% set pin_cfg = ('output_pin %s' % pin) if pin else None %} + {% set pwm = (printer.configfile.settings[pin_cfg].scale) if pin_cfg else False %} + {% set default_timeout = vars.default_timeout %} + {% set timeout = params.TIMEOUT|default(default_timeout)|float %} + + # Convert speed + {% if speed < 0 and step_speed >= 0 %} + # determine speed from step speed + {% if not pwm %} + # TODO: something special for long slow (tbd) moves? + # delayed start so it runs after the stepper has run for a little bit? + # or just don't run on long slow moves? + {% set speed = 1 %} + {% elif step_speed > vars.max_step_speed %} + {% set speed = 1 %} + {% else %} + {% set speed = (step_speed / vars.max_step_speed) ** vars.step_speed_exponent %} + {% endif %} + {% elif speed < 0 %} + {% set speed = 1 %} + {% endif %} + + {% if gate < 0 %} + RESPOND TYPE=error MSG="No active gate. Cannot start espooler." + {% elif not pin %} + RESPOND TYPE=error MSG="{pin_cfg} does not exist. Cannot start espooler." + {% elif expected_distance >= 0 and expected_distance < vars.min_distance %} + MMU_LOG DEBUG=1 MSG="Travel distance ({expected_distance}) is shorter than the configured min distance ({vars.min_distance}). Ignoring espooler activation." + {% else %} + MMU_LOG DEBUG=1 MSG="Setting espooler {pin} to {speed}" + {% set cfg_scale = printer.configfile.settings[pin_cfg].scale|default(1)|float %} + {% set scale = params.SCALE|default(cfg_scale)|float %} + {% if en_pin and speed > 0 %} + SET_PIN PIN="{en_pin}" value="{1}" + {% endif %} + + SET_PIN PIN="{pin}" value="{speed * cfg_scale * scale}" + + {% if timeout > 0 and speed > 0 and printer[pin_cfg].value == 0 %} + UPDATE_DELAYED_GCODE ID=mmu_espooler_timeout DURATION={timeout} + {% elif speed == 0 %} + # Cancel delayed gcode...if all are turned off + {% set values = [] %} + {% for igate in (vars.espooler_gates) %} + {% set value = printer['output_pin %s_rwd_%d' % (pin_prefix, igate)].value %} + {% set value = 0 if (igate == gate or value == 0) else value %} + {% set d = values.append(value) %} + {% endfor %} + {% if values|sum == 0 %} + UPDATE_DELAYED_GCODE ID=mmu_espooler_timeout DURATION=0 + {% endif %} + {% endif %} + + {% if en_pin and speed == 0 %} + SET_PIN PIN="{en_pin}" value="{0}" + {% endif %} + {% endif %} + +########################################################################### +# Delayed gcode to run on startup to identify all the eSpoolers which +# will be used after espooler timeout to ensure all eSpoolers have +# stopped. +# +[delayed_gcode mmu_espooler_startup] +initial_duration: 1. +gcode: + {% set vars = printer["gcode_macro _MMU_ESPOOLER_VARS"] %} + {% set pin_prefix = vars.pin_prefix %} + {% set pin_cfg_prefix = 'output_pin %s_rwd_' % pin_prefix %} + {% set espooler_gates = [] %} + {% for key in printer %} + {% if key.startswith(pin_cfg_prefix) %} + {% set gate = key | replace(pin_cfg_prefix, '') | int %} + {% set d = espooler_gates.append(gate | string) %} + {% endif %} + {% endfor %} + SET_GCODE_VARIABLE MACRO=_MMU_ESPOOLER_VARS VARIABLE=espooler_gates VALUE={espooler_gates|join(',')} + +########################################################################### +# Delayed gcode to stop all eSpooler after timeout. This is used as a +# failsafe (unless explicitly disabled by setting a timeout of 0) to ensure +# the eSpoolers do not run indefinitely. +# +[delayed_gcode mmu_espooler_timeout] +gcode: + {% set vars = printer["gcode_macro _MMU_ESPOOLER_VARS"] %} + {% for gate in (vars.espooler_gates) %} + MMU_ESPOOLER_STOP GATE={gate} + {% endfor %} diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler_hw.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler_hw.cfg new file mode 100644 index 00000000..be7029de --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/dc_espooler_hw.cfg @@ -0,0 +1,75 @@ +########################################################################################### +# Define the pins for DC motor based eSpooler. Create a section for each gate of your MMU. +# +# With pwm enabled, setting the scale parameter (between 0.0 and 1.0) to adjust the top +# speed of the eSpooler. +# +# Some setups may require an "enable" pin to activate the motor driver. Uncomment those +# pins as needed for each gate. +# +# See https://www.klipper3d.org/Config_Reference.html#output_pin +# + +################## +# Gate 0 eSpooler +# + +# Rewind pin +[output_pin _mmu_dc_espooler_rwd_0] +pin: mmu:MMU_DC_MOT_1_A +value: 0 +pwm: True +scale: 1 + +# Enable pin +# [output_pin _mmu_dc_espooler_en_0] +# pin: mmu:MMU_DC_MOT_1_EN +# value: 0 + +################## +# Gate 1 eSpooler +# + +# Rewind pin +[output_pin _mmu_dc_espooler_rwd_1] +pin: mmu:MMU_DC_MOT_2_A +value: 0 +pwm: True +scale: 1 + +# Enable pin +# [output_pin _mmu_dc_espooler_en_1] +# pin: mmu:MMU_DC_MOT_2_EN +# value: 0 + +################## +# Gate 2 eSpooler +# + +# Rewind pin +[output_pin _mmu_dc_espooler_rwd_2] +pin: mmu:MMU_DC_MOT_3_A +value: 0 +pwm: True +scale: 1 + +# Enable pin +# [output_pin _mmu_dc_espooler_en_2] +# pin: mmu:MMU_DC_MOT_3_EN +# value: 0 + +################## +# Gate 3 eSpooler +# + +# Rewind pin +[output_pin _mmu_dc_espooler_rwd_3] +pin: mmu:MMU_DC_MOT_4_A +value: 0 +pwm: True +scale: 1 + +# Enable pin +# [output_pin _mmu_dc_espooler_en_3] +# pin: mmu:MMU_DC_MOT_4_EN +# value: 0 diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_centauri.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_centauri.cfg new file mode 100644 index 00000000..46e37e43 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_centauri.cfg @@ -0,0 +1,239 @@ +######################################################################################################################## +# Happy Hare MMU - Centauri Carbon 1 Integration +# +# Combines MMU load/unload with Centauri's cutter and wiper +# +# SETUP: +# 1. Include this file in printer.cfg: [include mmu/addons/mmu_centauri.cfg] +# 2. In mmu_parameters.cfg set: +# form_tip_macro: _MMU_CUT_TIP (already set - this file overrides the default) +# force_form_tip_standalone: 1 +# 3. In mmu_macro_vars.cfg set: +# variable_user_post_load_extension: _MMU_CENTAURI_POST_LOAD +# variable_user_pre_unload_extension: _MMU_CENTAURI_PRE_UNLOAD +# +######################################################################################################################## + +# ============================================================================ +# CUT TIP - Uses Centauri's cutter at X255, Y3 +# Overrides Happy Hare's default _MMU_CUT_TIP +# ============================================================================ +[gcode_macro _MMU_CUT_TIP_VARS] +description: Variables for Centauri cutter integration +gcode: # Leave empty - this is a variable storage macro +# Cutter position (from original UNLOAD_FILAMENT) +variable_pin_loc_xy: (255, 3) ; X255, Y3 - cutting position +variable_cutting_axis: "y" ; Cut by moving Y +variable_pin_park_dist: 30 ; Distance to park before cut (Y30) +variable_pin_loc_compressed: 3 ; Y position when cutter is engaged +variable_retract_length: 15 ; Retract before cut +variable_blade_pos: 37.5 ; Distance from nozzle to blade +variable_rip_length: 1.0 ; Retract after cut +variable_pushback_length: 0 ; No pushback (filament is ejected) +variable_travel_speed: 150 ; mm/s +variable_cut_fast_move_speed: 32 ; mm/s +variable_cut_slow_move_speed: 8 ; mm/s +variable_extruder_move_speed: 25 ; mm/s +variable_simple_tip_forming: False ; No tip forming - we cut! +variable_restore_position: False ; Don't restore position (MMU handles it) +variable_gantry_servo_enabled: False ; No gantry servo +# CRITICAL: Z-hop for bed-moving printers (Centauri CoreXY) +# This is RELATIVE to current Z - bed will move DOWN when Z increases +variable_z_hop_clearance: 15 ; mm to ADD to current Z for clearance (bed moves DOWN) +# Post-load clearance position (move away from tray to prevent blobs) +variable_post_load_retract: 2 ; mm retract after purge to prevent ooze +variable_clearance_y: 250 ; Y position to move away from tray (264.5 -> 250) + +[gcode_macro _MMU_CUT_TIP] +description: Cut filament using Centauri's cutter mechanism (overrides Happy Hare default) +variable_output_park_pos: 0 + +gcode: + {% set final_eject = params.FINAL_EJECT|default(0)|int %} + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set z_hop = vars.z_hop_clearance|default(15)|float %} + {% set current_z = printer.gcode_move.gcode_position.z %} + {% set safe_z = current_z + z_hop %} + + MMU_LOG MSG="Centauri Cutter: Starting cut sequence" + + # Ensure XYZ homed (from original UNLOAD_FILAMENT) + {% if "xyz" not in printer.toolhead.homed_axes %} + G28 + {% endif %} + + SAVE_GCODE_STATE NAME=_MMU_CUT_TIP_state + G90 ; Absolute positioning + M83 ; Relative extrusion + G92 E0 + + # Step 1: Retract filament before cut (if needed) + {% set retract_length = 15 %} + {% set effective_retract = retract_length - printer.mmu.extruder_filament_remaining|default(0)|float %} + {% if effective_retract > 0 %} + MMU_LOG MSG="Retracting {effective_retract|round(1)}mm before cut" + G1 E-{effective_retract} F1500 + {% endif %} + + # Step 2: Move to cutting position with RELATIVE Z-hop (bed moves DOWN) + # CRITICAL: For bed-moving Z printers, increasing Z moves bed DOWN (clearance) + MMU_LOG MSG="Z-hop: current Z={current_z|round(1)}, safe Z={safe_z|round(1)} (bed moves DOWN {z_hop}mm)" + G0 Z{safe_z} F600 ; Move bed DOWN for clearance + G0 Y30 F15000 ; Get some clearance for Y + G0 X255 F8000 ; Move to cutting position + + # Step 3: Perform the cut (from original UNLOAD_FILAMENT) + G0 Y3 F1200 ; Cut + G0 Y30 F8000 ; Retract from cutting + M400 ; Wait for movements to complete + + # Step 4: Move to tray so cut piece falls into chute + MOVE_TO_TRAY ; Move to the tray + M400 ; Wait for movements to complete + + # Set park position for MMU (filament is at blade position from nozzle) + # MMU will handle eject with Gear Motor - Encoder will sense the movement + SET_GCODE_VARIABLE MACRO=_MMU_CUT_TIP VARIABLE=output_park_pos VALUE=37.5 + + MMU_LOG MSG="Centauri Cutter: Cut complete, at tray position, park_pos=37.5mm" + + _MMU_EVENT EVENT="filament_cut" + + +# ============================================================================ +# PRE LOAD - Move to chute BEFORE MMU inserts filament +# ============================================================================ +[gcode_macro _MMU_CENTAURI_PRE_LOAD] +description: Move to chute before MMU loads filament +gcode: + MMU_LOG MSG="Centauri: Pre-load - moving to chute first" + + {% if "xyz" not in printer.toolhead.homed_axes %} + G28 X Y + {% endif %} + + # Move to tray/chute FIRST (before filament insert) + G90 ; Absolute positioning + G0 Y250 F12000 ; Move Y near tray first + G0 X202 F12000 ; Move X to tray position + G0 Y264.5 F1200 ; Move slowly to tray position + M400 ; Wait for moves + + MMU_LOG MSG="Centauri: Pre-load complete - at chute, ready for filament" + + +# ============================================================================ +# POST LOAD - Purge and wipe AFTER MMU delivers filament (chute already positioned) +# ============================================================================ +[gcode_macro _MMU_CENTAURI_POST_LOAD_VARS] +description: Variables for post-load sequence +gcode: # Leave empty +variable_post_load_retract: 2.0 ; mm to retract after purge/wipe to prevent ooze +variable_post_load_clearance_y: 240 ; Y position to move away from tray (prevent blobs) +variable_post_load_clearance_x: 128 ; X position after post-load (center-ish) +variable_post_load_travel_speed: 12000 ; mm/min travel speed + +[gcode_macro _MMU_CENTAURI_POST_LOAD] +description: Purge and wipe after MMU delivers filament (uses LOAD_FILAMENT logic) +gcode: + {% set vars = printer['gcode_macro _MMU_CENTAURI_POST_LOAD_VARS'] %} + {% set extruder_temp = printer['gcode_macro _MMU_SEQUENCE_VARS'].extruder_temp|default(220)|float %} + {% set purge_length = params.LENGTH|default(50)|float %} + {% set retract = vars.post_load_retract|default(2.0)|float %} + {% set clearance_y = vars.post_load_clearance_y|default(240)|float %} + {% set clearance_x = vars.post_load_clearance_x|default(128)|float %} + {% set travel_speed = vars.post_load_travel_speed|default(12000)|int %} + + MMU_LOG MSG="Centauri: Post-load - purging and wiping" + + # Ensure temperature + {% if printer[printer.toolhead.extruder].temperature < extruder_temp - 10 %} + M109 S{extruder_temp} + {% endif %} + + # Turn on part cooling fan to prevent blobbing (same as LOAD_FILAMENT) + M106 S255 ; Turn on part cooling fan (full speed) + SET_FAN_SPEED FAN=model_helper_fan SPEED=1 ; Turn on auxiliary fan (full speed) + + # Use existing LOAD_FILAMENT purge/wipe logic (SILENT=1 suppresses prompt) + _LOAD_FILAMENT_STEP_PUSH SILENT=1 LENGTH={purge_length} + + # Turn off fans after purge/wipe + M106 S0 ; Turn off part cooling fan + SET_FAN_SPEED FAN=model_helper_fan SPEED=0 ; Turn off auxiliary fan + + # CRITICAL: Retract and move AWAY from tray to prevent blobs/hanging + {% if retract > 0 %} + MMU_LOG MSG="Retracting {retract}mm to prevent ooze" + G1 E-{retract} F1800 ; Quick retract + {% endif %} + + # Move away from tray to clearance position + MMU_LOG MSG="Moving to clearance position (X:{clearance_x}, Y:{clearance_y})" + G90 ; Absolute positioning + G0 Y{clearance_y} F{travel_speed} ; Move Y away from tray first + G0 X{clearance_x} F{travel_speed} ; Move X to center position + M400 ; Wait for movements + + MMU_LOG MSG="Centauri: Post-load complete - clear of tray" + + +# ============================================================================ +# PRE UNLOAD - Position for cutting before MMU unload +# ============================================================================ +[gcode_macro _MMU_CENTAURI_PRE_UNLOAD] +description: Prepare for unload by positioning for cut +gcode: + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set z_hop = vars.z_hop_clearance|default(15)|float %} + {% set current_z = printer.gcode_move.gcode_position.z %} + {% set safe_z = current_z + z_hop %} + + MMU_LOG MSG="Centauri: Pre-unload - preparing cutter position" + + {% if "xyz" not in printer.toolhead.homed_axes %} + G28 X Y + {% endif %} + + # Z clearance for cutting - RELATIVE Z-hop (bed moves DOWN) + # CRITICAL: For bed-moving Z printers, increasing Z moves bed DOWN (clearance) + MMU_LOG MSG="Z-hop: current Z={current_z|round(1)}, safe Z={safe_z|round(1)} (bed moves DOWN {z_hop}mm)" + G0 Z{safe_z} F600 + + MMU_LOG MSG="Centauri: Pre-unload ready" + + +# ============================================================================ +# WIPE ONLY - For manual wipe without load +# ============================================================================ +[gcode_macro MMU_WIPE_NOZZLE] +description: Wipe nozzle using Centauri's wiper +gcode: + M729 + + +# ============================================================================ +# PURGE - Purge filament at tray position +# ============================================================================ +[gcode_macro _MMU_PURGE_CENTAURI] +description: Purge filament at tray position +gcode: + {% set purge_length = params.LENGTH|default(50)|float %} + {% set extruder_temp = params.TEMP|default(220)|float %} + + # Move to tray + G0 X202 F6000 + G0 Y264.5 F1200 + + # Heat if needed + {% if printer[printer.toolhead.extruder].temperature < extruder_temp - 10 %} + M109 S{extruder_temp} + {% endif %} + + # Purge + M83 + G92 E0 + G1 E{purge_length} F240 + + # Wipe + M729 \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter.cfg new file mode 100644 index 00000000..12e1d53f --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter.cfg @@ -0,0 +1,91 @@ +# Include servo hardware definition separately to allow for automatic upgrade +[include mmu_erec_cutter_hw.cfg] + +########################################################################### +# Optional EREC Filament Cutter Support +# +# https://github.com/kevinakasam/ERCF_Filament_Cutter +# +# This is the supplementary macro to support filament cutting at the MMU +# on a ERCF design. +# +# To configure: +# 1. Add this to your printer.cfg: +# +# [include mmu/addons/mmu_erec_cutter.cfg] +# +# 2. In mmu_macro_vars.cfg, change this line: +# +# variable_user_post_unload_extension : "EREC_CUTTER_ACTION" +# +# 3. Tune the servo configuration and macro "variables" below +# + +# EREC CUTTER CONFIGURATION ----------------------------------------------- +# (addons/mmu_erec_cutter.cfg) +# +[gcode_macro _EREC_VARS] +description: Empty macro to store the variables +gcode: # Leave empty + +# These variables control the servo movement +variable_servo_closed_angle : 70 ; Servo angle for closed position with bowden aligned MMU +variable_servo_open_angle : 10 ; Servo angle to open up the cutter and move bowden away from MMU +variable_servo_duration : 1.5 ; Time (s) of PWM pulse train to activate servo +variable_servo_idle_time : 1.8 ; Time (s) to let the servo to reach it's position + +# Controls for feed and cut lengths +variable_feed_length : 48 ; Distance in mm from gate parking position to blade (ERCFv1.1: 58, v2/other: 48) +variable_cut_length : 10 ; Amount in mm of filament to cut +variable_cut_attempts : 1 ; Number of times the cutter tries to cut the filament + + +########################################################################### +# Macro to perform the cutting step. Designed to be included to the +# _MMU_POST_UNLOAD step +# +[gcode_macro EREC_CUTTER_ACTION] +description: Cut off the filament tip at the MMU after the unload sequence is complete +gcode: + {% set vars = printer["gcode_macro _EREC_VARS"] %} + + MMU_LOG MSG="Cutting filament tip..." + + _CUTTER_OPEN + _MMU_STEP_MOVE MOVE={vars.feed_length + vars.cut_length} + {% for i in range(vars.cut_attempts - 1) %} + _CUTTER_CLOSE + _CUTTER_OPEN + {% endfor %} + _MMU_STEP_MOVE MOVE=-1 + _CUTTER_CLOSE + _MMU_EVENT EVENT="filament_cut" # Count as one cut for consumption counter + + _MMU_STEP_SET_FILAMENT STATE=2 # FILAMENT_POS_START_BOWDEN + _MMU_STEP_UNLOAD_GATE # Repeat gate parking move + _MMU_M400 # Wait on both move queues + +[gcode_macro _CUTTER_ANGLE] +description: Helper macro to set cutter servo angle +gcode: + {% set angle = params.ANGLE|default(0)|int %} + SET_SERVO SERVO=cut_servo ANGLE={angle} + +[gcode_macro _CUTTER_CLOSE] +description: Helper macro to set cutting servo the closed position +gcode: + {% set vars = printer["gcode_macro _EREC_VARS"] %} + SET_SERVO SERVO=cut_servo ANGLE={vars.servo_closed_angle} DURATION={vars.servo_duration} + G4 P{vars.servo_idle_time * 1000} + RESPOND MSG="EREC Cutter closed" + M400 + +[gcode_macro _CUTTER_OPEN] +description: Helper macro to set cutting servo the open position +gcode: + {% set vars = printer["gcode_macro _EREC_VARS"] %} + SET_SERVO SERVO=cut_servo ANGLE={vars.servo_open_angle} DURATION={vars.servo_duration} + G4 P{vars.servo_idle_time * 1000} + RESPOND MSG="EREC Cutter open" + M400 + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter_hw.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter_hw.cfg new file mode 100644 index 00000000..4fec0c18 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/addons/mmu_erec_cutter_hw.cfg @@ -0,0 +1,10 @@ + +########################################################################################## +# The servo hardware configuration. Change the values to your needs. +# +[mmu_servo cut_servo] +pin: mmu:PA7 # Extra Pin on the ERCF easy Board +maximum_servo_angle: 180 # Set this to 60 for a 60° Servo +minimum_pulse_width: 0.0005 # Adapt these for your servo +maximum_pulse_width: 0.0025 # Adapt these for your servo + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu.cfg new file mode 100644 index 00000000..208b09af --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu.cfg @@ -0,0 +1,100 @@ +######################################################################################################################## +# Happy Hare MMU Software +# +# EDIT THIS FILE BASED ON YOUR SETUP +# +# Copyright (C) 2022 moggieuk#6538 (discord) moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Happy Hare MMU hardware pin config +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +# This contains aliases for pins for MCU type ERBv2 +# +[mcu mmu] +serial: /dev/serial/by-id/usb-Klipper_rp2040_E6609CB2D3905424-if00 # Change to `canbus_uuid: 1234567890` for CANbus setups + + +# PIN ALIASES FOR MMU MCU BOARD ---------------------------------------------------------------------------------------- +# ██████╗ ██╗███╗ ██╗ █████╗ ██╗ ██╗ █████╗ ███████╗ +# ██╔══██╗██║████╗ ██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝ +# ██████╔╝██║██╔██╗ ██║ ███████║██║ ██║███████║███████╗ +# ██╔═══╝ ██║██║╚██╗██║ ██╔══██║██║ ██║██╔══██║╚════██║ +# ██║ ██║██║ ╚████║ ██║ ██║███████╗██║██║ ██║███████║ +# ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝╚══════╝ +# Section to create alias for pins used by MMU for easier integration into Klippain and RatOS. The names match those +# referenced in the mmu_hardware.cfg file. If you get into difficulty you can also comment out this aliases definition +# completely and configure the pin names directly into mmu_hardware.cfg. However, use of aliases is encouraged. + +# Note: that aliases are not created for TOOLHEAD_SENSOR, EXTRUDER_SENSOR or SYNC_FEEDBACK_SENSORS because those are +# most likely on the printer's main mcu. These should be set directly in mmu_hardware.cfg +# +[board_pins mmu] +mcu: mmu # Assumes using an external / extra mcu dedicated to MMU +aliases: + MMU_GEAR_UART=gpio11, + MMU_GEAR_STEP=gpio10, + MMU_GEAR_DIR=gpio9, + MMU_GEAR_ENABLE=gpio8, + MMU_GEAR_DIAG=gpio13, + + MMU_GEAR_UART_1=, + MMU_GEAR_STEP_1=, + MMU_GEAR_DIR_1=, + MMU_GEAR_ENABLE_1=, + MMU_GEAR_DIAG_1=, + + MMU_GEAR_UART_2=, + MMU_GEAR_STEP_2=, + MMU_GEAR_DIR_2=, + MMU_GEAR_ENABLE_2=, + MMU_GEAR_DIAG_2=, + + MMU_GEAR_UART_3=, + MMU_GEAR_STEP_3=, + MMU_GEAR_DIR_3=, + MMU_GEAR_ENABLE_3=, + MMU_GEAR_DIAG_3=, + + MMU_SEL_UART=gpio17, + MMU_SEL_STEP=gpio16, + MMU_SEL_DIR=gpio15, + MMU_SEL_ENABLE=gpio14, + MMU_SEL_DIAG=gpio19, + MMU_SEL_ENDSTOP=gpio24, + MMU_SEL_SERVO=gpio23, + + MMU_ENCODER=gpio22, + MMU_GATE_SENSOR=, + MMU_NEOPIXEL=gpio21, + + MMU_PRE_GATE_0=gpio12, + MMU_PRE_GATE_1=gpio18, + MMU_PRE_GATE_2=gpio2, + MMU_PRE_GATE_3=gpio3, + MMU_PRE_GATE_4=gpio4, + MMU_PRE_GATE_5=gpio5, + MMU_PRE_GATE_6=gpio6, + MMU_PRE_GATE_7=gpio7, + MMU_PRE_GATE_8=gpio26, + MMU_PRE_GATE_9=gpio27, + MMU_PRE_GATE_10=gpio28, + MMU_PRE_GATE_11=gpio29, + + MMU_POST_GEAR_0=, + MMU_POST_GEAR_1=, + MMU_POST_GEAR_2=, + MMU_POST_GEAR_3=, + MMU_POST_GEAR_4=, + MMU_POST_GEAR_5=, + MMU_POST_GEAR_6=, + MMU_POST_GEAR_7=, + MMU_POST_GEAR_8=, + MMU_POST_GEAR_9=, + MMU_POST_GEAR_10=, + MMU_POST_GEAR_11=, + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_cut_tip.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_cut_tip.cfg new file mode 100644 index 00000000..4201a6aa --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_cut_tip.cfg @@ -0,0 +1,296 @@ +######################################################################################################################## +# Happy Hare MMU Software +# Supporting macros +# +# THIS FILE IS READ ONLY +# +# Copyright (C) 2022-2026 moggieuk#6538 (discord) +# moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Standalone Tip Cutting for "Filametrix" style toolhead cutters +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +# When using this macro it is important to turn off tip forming in your slicer +# (read the wiki: Slicer Setup & Toolchange-Movement pages) +# Then set the following parameters in mmu_parameters.cfg: +# +# form_tip_macro: _MMU_CUT_TIP +# force_form_tip_standalone: 1 +# +# This will ensure this macro is always called either in out of a print +# +# NOTE: +# The park position of the filament is relative to the nozzle and +# represents where the end of the filament is after cutting. The park position +# is important and used by Happy Hare both to finish unloading the extruder +# as well as to calculate how far to advance the filament on the subsequent load. +# It is set dynamically in gcode with this construct: +# SET_GCODE_VARIABLE MACRO=_MMU_CUT_TIP VARIABLE=output_park_pos VALUE=.. +# +[gcode_macro _MMU_CUT_TIP] +description: Cut filament by pressing the cutter on a pin with a horizontal movement + +# -------------------------- Internal Don't Touch ------------------------- +variable_output_park_pos: 0 # Dynamically set in this macro + +gcode: + {% set final_eject = params.FINAL_EJECT|default(0)|int %} + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set pin_loc_x, pin_loc_y = vars.pin_loc_xy|map('float') %} + {% set pin_park_dist = vars['pin_park_dist']|float %} + {% set retract_length = vars['retract_length']|float %} + {% set simple_tip_forming = vars['simple_tip_forming']|default(true)|lower == 'true' %} + {% set blade_pos = vars['blade_pos']|float %} + {% set rip_length = vars['rip_length']|float %} + {% set pushback_length = vars['pushback_length']|float %} + {% set pushback_dwell_time = vars['pushback_dwell_time']|int %} + {% set extruder_move_speed = vars['extruder_move_speed']|float %} + {% set travel_speed = vars['travel_speed']|float %} + {% set restore_position = vars['restore_position']|default(true)|lower == 'true' %} + {% set extruder_park_pos = blade_pos + rip_length %} + {% set cutting_axis = vars['cutting_axis'] %} + + {% if cutting_axis == "x" %} + {% set pin_park_x_loc = pin_loc_x + pin_park_dist %} + {% set pin_park_y_loc = pin_loc_y %} + {% else %} + {% set pin_park_y_loc = pin_loc_y + pin_park_dist %} + {% set pin_park_x_loc = pin_loc_x %} + {% endif %} + + {% if "xy" not in printer.toolhead.homed_axes %} + MMU_LOG MSG="Automatically homing XY" + G28 X Y + _CUT_TIP_MOVE_IN_BOUNDS + {% endif %} + + SAVE_GCODE_STATE NAME=_MMU_CUT_TIP_state # Save after possible homing operation to prevent 0,0 being recorded + + G90 # Absolute positioning + M83 # Relative extrusion + G92 E0 + + # Step 1 - Calculate initial retract to save filament waste, repeat to allow some cooling + {% set effective_retract_length = retract_length - printer.mmu.extruder_filament_remaining - park_vars.retracted_length %} + {% if effective_retract_length > 0 %} + MMU_LOG MSG="Retracting filament {effective_retract_length|round(1)}mm prior to cut" + G1 E-{effective_retract_length} F{extruder_move_speed * 60} + {% if simple_tip_forming %} + G1 E{effective_retract_length / 2} F{extruder_move_speed * 60} + G1 E-{effective_retract_length / 2} F{extruder_move_speed * 60} + {% endif %} + {% endif %} + + # Step 2 - Perform the cut + _CUT_TIP_ADJUST_CURRENT + _CUT_TIP_MOVE_TO_CUTTER_PIN PIN_PARK_X_LOC={pin_park_x_loc} PIN_PARK_Y_LOC={pin_park_y_loc} + _CUT_TIP_GANTRY_SERVO_DOWN + _CUT_TIP_DO_CUT_MOTION PIN_PARK_X_LOC={pin_park_x_loc} PIN_PARK_Y_LOC={pin_park_y_loc} RIP_LENGTH={rip_length} + _CUT_TIP_GANTRY_SERVO_UP + _CUT_TIP_RESTORE_CURRENT + _MMU_EVENT EVENT="filament_cut" + + # Step 3 - Pushback of the tip residual into the hotend to avoid future catching (ideally past the PTFE/metal boundary) + {% set effective_pushback_length = [pushback_length, retract_length - printer.mmu.extruder_filament_remaining - park_vars.retracted_length]|min %} + {% if effective_pushback_length > 0 %} + MMU_LOG MSG="Pushing filament fragment back {effective_pushback_length|round(1)}mm after cut" + G1 E{effective_pushback_length} F{extruder_move_speed * 60} + G4 P{pushback_dwell_time} + G1 E-{effective_pushback_length} F{extruder_move_speed * 60} + {% endif %} + + # Final eject is for testing + {% if final_eject %} + G92 E0 + G1 E-80 F{extruder_move_speed * 60} + {% endif %} + + # Dynamically set the required output variables for Happy Hare + SET_GCODE_VARIABLE MACRO=_MMU_CUT_TIP VARIABLE=output_park_pos VALUE={extruder_park_pos} + + # Restore state and optionally position (usually on wipetower) + RESTORE_GCODE_STATE NAME=_MMU_CUT_TIP_state MOVE={1 if restore_position else 0} MOVE_SPEED={travel_speed} + +########################################################################### +# Helper macro to alter X/Y stepper current during cut operation +# +[gcode_macro _CUT_TIP_ADJUST_CURRENT] +description: Helper to optionally increase X/Y stepper current prior to cut +variable_current_map: {} # Internal, don't set +gcode: + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set cut_axis_steppers = (vars['cut_axis_steppers'] | default('')).split(',') | map('trim') | list %} + {% set cut_stepper_current = vars['cut_stepper_current'] | default(100) | int %} + {% set tmc_types = ["tmc2209", "tmc2130", "tmc2208", "tmc2660", "tmc5160", "tmc2240"] %} + + {% if not current_map %} + {% set ns = namespace(run_current={}) %} + {% if cut_stepper_current != 100 %} + {% for stepper in cut_axis_steppers %} + {% for tmc in tmc_types %} + {% set fullname = tmc ~ ' ' ~ stepper %} + {% if printer[fullname] is defined %} + # Save original run_current and reset to new value + {% set cur_rc = printer[fullname].run_current %} + {% if ns.run_current.update({stepper: cur_rc}) %}{% endif %} + {% set new_rc = cur_rc * cut_stepper_current | float / 100 %} + MMU_LOG MSG="Adjusting {stepper} current" + SET_TMC_CURRENT STEPPER={stepper} CURRENT={new_rc} + {% endif %} + {% endfor %} + {% endfor %} + {% endif %} + + SET_GCODE_VARIABLE MACRO=_CUT_TIP_ADJUST_CURRENT VARIABLE=current_map VALUE="{ns.run_current}" + {% endif %} + +########################################################################### +# Helper macro to restore X/Y stepper current after cutting action +# +[gcode_macro _CUT_TIP_RESTORE_CURRENT] +description: Helper to restore X/Y stepper current after cutting action +gcode: + {% set current_vars = printer['gcode_macro _CUT_TIP_ADJUST_CURRENT'] %} + {% set current_map = current_vars['current_map'] %} + + {% if current_map %} + {% for stepper, current in current_map.items() %} + MMU_LOG MSG="Restoring {stepper} current" + SET_TMC_CURRENT STEPPER={stepper} CURRENT={current} + {% endfor %} + {% endif %} + + SET_GCODE_VARIABLE MACRO=_CUT_TIP_ADJUST_CURRENT VARIABLE=current_map VALUE="{{}}" + + +########################################################################### +# Helper macro to ensure toolhead is in bounds after home in case it is +# used as a restore position point +# +[gcode_macro _CUT_TIP_MOVE_IN_BOUNDS] +description: Helper to move the toolhead to a legal position after homing +gcode: + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set travel_speed = vars['travel_speed']|float %} + + {% set pos = printer.gcode_move.gcode_position %} + {% set axis_minimum = printer.toolhead.axis_minimum %} + {% set axis_maximum = printer.toolhead.axis_maximum %} + {% set x = [axis_minimum.x, [axis_maximum.x, pos.x]|min]|max %} + {% set y = [axis_minimum.y, [axis_maximum.y, pos.y]|min]|max %} + + MMU_LOG MSG="Warning: Klipper reported out of range gcode position (x:{pos.x}, y:{pos.y})! Adjusted to (x:{x}, y:{y}) to prevent move failure" ERROR=1 + G1 X{x} Y{y} F{travel_speed * 60} + + +########################################################################### +# Helper macro for tip cutting +# +[gcode_macro _CUT_TIP_MOVE_TO_CUTTER_PIN] +description: Helper to move the toolhead to the target pin in either safe or faster way, depending on toolhead clearance +gcode: + {% set pin_park_x_loc = params.PIN_PARK_X_LOC|float %} + {% set pin_park_y_loc = params.PIN_PARK_Y_LOC|float %} + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + + {% set safe_margin_x, safe_margin_y = vars.safe_margin_xy|map('float') %} + {% set travel_speed = vars['travel_speed']|float %} + {% set cutting_axis = vars['cutting_axis'] %} + + {% if ((printer.gcode_move.gcode_position.x - pin_park_x_loc)|abs < safe_margin_x) or ((printer.gcode_move.gcode_position.y - pin_park_y_loc)|abs < safe_margin_y) %} + # Make a safe but slower travel move + {% if cutting_axis == "x" %} + G1 X{pin_park_x_loc} F{travel_speed * 60} + G1 Y{pin_park_y_loc} F{travel_speed * 60} + {% else %} + G1 Y{pin_park_y_loc} F{travel_speed * 60} + G1 X{pin_park_x_loc} F{travel_speed * 60} + {% endif %} + {% else %} + G1 X{pin_park_x_loc} Y{pin_park_y_loc} F{travel_speed * 60} + {% endif %} + + +########################################################################### +# Helper macro for tip cutting +# +[gcode_macro _CUT_TIP_DO_CUT_MOTION] +description: Helper to do a single cut movement +gcode: + {% set pin_park_x_loc = params.PIN_PARK_X_LOC | float %} + {% set pin_park_y_loc = params.PIN_PARK_Y_LOC | float %} + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set cutting_axis = vars['cutting_axis'] %} + + {% set pin_loc = vars['pin_loc_compressed']|default(-999)|float %} + {% if pin_loc != -999 %} + # Old one-dimensional pin_loc_compressed config + {% if cutting_axis == "x" %} + {% set pin_loc_compressed_x = pin_loc %} + {% set pin_loc_compressed_y = pin_park_y_loc %} + {% else %} + {% set pin_loc_compressed_x = pin_park_x_loc %} + {% set pin_loc_compressed_y = pin_loc %} + {% endif %} + {% else %} + # New config + {% set pin_loc_compressed_x, pin_loc_compressed_y = vars.pin_loc_compressed_xy|map('float') %} + {% endif %} + + {% set cut_fast_move_fraction = vars['cut_fast_move_fraction']|float %} + {% set cut_fast_move_speed = vars['cut_fast_move_speed']|float %} + {% set cut_slow_move_speed = vars['cut_slow_move_speed']|float %} + {% set cut_dwell_time = vars['cut_dwell_time']|float %} + {% set evacuate_speed = vars['evacuate_speed']|float %} + {% set rip_length = vars['rip_length']|float %} + {% set rip_speed = vars['rip_speed']|float %} + + + {% set fast_slow_transition_loc_x = (pin_loc_compressed_x - pin_park_x_loc) * cut_fast_move_fraction + pin_park_x_loc|float %} + {% set fast_slow_transition_loc_y = (pin_loc_compressed_y - pin_park_y_loc) * cut_fast_move_fraction + pin_park_y_loc|float %} + G1 X{fast_slow_transition_loc_x} Y{fast_slow_transition_loc_y} F{cut_fast_move_speed * 60} # Fast move to initiate contact of the blade with filament + G1 X{pin_loc_compressed_x} Y{pin_loc_compressed_y} F{cut_slow_move_speed * 60} # Do the cut in slow move + + G4 P{cut_dwell_time} + {% if rip_length > 0 %} + G1 E-{rip_length} F{rip_speed * 60} + {% endif %} + + G1 X{pin_park_x_loc} Y{pin_park_y_loc} F{evacuate_speed * 60} # Evacuate + + +########################################################################### +# Helper macro for tip cutting +# +[gcode_macro _CUT_TIP_GANTRY_SERVO_DOWN] +description: Operate optional gantry servo operated pin +gcode: + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set gantry_servo_enabled = vars['gantry_servo_enabled']|default(true)|lower == 'true' %} + {% set angle = vars['gantry_servo_down_angle']|float %} + + {% if gantry_servo_enabled %} + SET_SERVO SERVO=mmu_gantry_servo ANGLE={angle} + G4 P500 # Pause to ensure servo is fully down before movement + {% endif %} + + +########################################################################### +# Helper macro for tip cutting +# +[gcode_macro _CUT_TIP_GANTRY_SERVO_UP] +description: Operate optional gantry servo operated pin +gcode: + {% set vars = printer['gcode_macro _MMU_CUT_TIP_VARS'] %} + {% set gantry_servo_enabled = vars['gantry_servo_enabled']|default(true)|lower == 'true' %} + {% set angle = vars['gantry_servo_up_angle']|float %} + + {% if gantry_servo_enabled %} + SET_SERVO SERVO=mmu_gantry_servo ANGLE={angle} DURATION=0.5 + {% endif %} diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_form_tip.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_form_tip.cfg new file mode 100644 index 00000000..090c3721 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_form_tip.cfg @@ -0,0 +1,178 @@ +######################################################################################################################## +# Happy Hare MMU Software +# Supporting macros +# +# THIS FILE IS READ ONLY +# +# Copyright (C) 2022-2026 moggieuk#6538 (discord) +# moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Standalone Tip Forming roughly based on Superslicer +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +# To configure, set +# 'form_tip_macro: _MMU_FORM_TIP' in 'mmu_parameters.cfg' +# +# This macro is, by default, called by Happy Hare to form filament tip +# prior to unloading. This will need to be tuned for your particular +# setup. Although the slicer can also perform similarly you must also +# tune tips here. The slicer will be used when printing, this logic will be +# used when not in print. Because of the need to setup twice, it is recommended +# that you turn off slicer tip forming and to use this routine in all circumstances. +# +# To force Happy Hare to always run this when loading filament add: +# 'force_form_tip_standalone: 1' in 'mmu_parameters.cfg' +# +# Also decide on whether you want toolhead to remain over wipetower while tool +# changing or move to park location (see 'enable_park' in mmu_sequence.cfg) +# +[gcode_macro _MMU_FORM_TIP] +description: Standalone macro that mimics Superslicer process + +gcode: + {% set final_eject = params.FINAL_EJECT|default(0)|int %} + {% set vars = printer['gcode_macro _MMU_FORM_TIP_VARS'] %} + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set unloading_speed_start = vars['unloading_speed_start']|int %} + {% set unloading_speed = vars['unloading_speed']|int %} + {% set ramming_volume = vars['ramming_volume']|float %} + {% set ramming_volume_standalone = vars['ramming_volume_standalone']|float %} + {% set cooling_tube_length = vars['cooling_tube_length']|float %} + {% set cooling_tube_position = vars['cooling_tube_position']|float %} + {% set initial_cooling_speed = vars['initial_cooling_speed']|int %} + {% set final_cooling_speed = vars['final_cooling_speed']|int %} + {% set cooling_moves = vars['cooling_moves']|int %} + {% set toolchange_temp = vars['toolchange_temp']|default(0)|int %} + {% set use_skinnydip = vars['use_skinnydip']|default(false)|lower == 'true' %} + {% set use_fast_skinnydip = vars['use_fast_skinnydip']|default(false)|lower == 'true' %} + {% set skinnydip_distance = vars['skinnydip_distance']|float %} + {% set dip_insertion_speed = vars['dip_insertion_speed']|int %} + {% set dip_extraction_speed = vars['dip_extraction_speed']|int %} + {% set melt_zone_pause = vars['melt_zone_pause']|default(0)|int %} + {% set cooling_zone_pause = vars['cooling_zone_pause']|default(0)|int %} + {% set extruder_eject_speed = vars['extruder_eject_speed']|int %} + {% set parking_distance = vars['parking_distance']|default(0)|float %} + {% set orig_temp = printer.extruder.target %} + {% set next_temp = params.NEXT_TEMP|default(orig_temp)|int %} + + # Useful state for customizing operations depending on mode + {% set runout = printer.mmu.runout %} + {% set printing = printer.mmu.print_state == 'printing' %} + + SAVE_GCODE_STATE NAME=MMU_FORM_TIP_state + + G91 # Relative positioning + M83 # Relative extrusion + G92 E0 + + # Step 1 - Ramming + # This is very generic and unlike slicer does not incorporate moves on the wipetower + {% set ramming_volume = ramming_volume_standalone if not printing else ramming_volume %} + {% if ramming_volume > 0 %} # Standalone Ramming + {% set ratio = ramming_volume / 23.0 %} + G1 E{0.5784 * ratio} F299 #7 + G1 E{0.5834 * ratio} F302 #3 + G1 E{0.5918 * ratio} F306 #6 + G1 E{0.6169 * ratio} F319 #6 + G1 E{0.3393 * ratio} F350 #0 + G1 E{0.3363 * ratio} F350 #0 + G1 E{0.7577 * ratio} F392 #6 + G1 E{0.8382 * ratio} F434 #3 + G1 E{0.7776 * ratio} F469 #9 + G1 E{0.1293 * ratio} F469 #9 + G1 E{0.9673 * ratio} F501 #2 + G1 E{1.0176 * ratio} F527 #2 + G1 E{0.5956 * ratio} F544 #6 + G1 E{0.4555 * ratio} F544 #6 + G1 E{1.0662 * ratio} F552 #4 + {% endif %} + + # Step 2 - Retraction / Nozzle Separation + # This is where the tip spear shape comes from. Faster=longer/pointer/higher stringing + {% set total_retraction_distance = cooling_tube_position - printer.mmu.extruder_filament_remaining - park_vars.retracted_length + cooling_tube_length - 15 %} + G1 E-15 F{1.0 * unloading_speed_start * 60} # Fixed default value from SS + {% if total_retraction_distance > 0 %} + G1 E-{(0.7 * total_retraction_distance)|round(2)} F{1.0 * unloading_speed * 60} + G1 E-{(0.2 * total_retraction_distance)|round(2)} F{0.5 * unloading_speed * 60} + G1 E-{(0.1 * total_retraction_distance)|round(2)} F{0.3 * unloading_speed * 60} + {% endif %} + + # Set toolchange temperature just prior to cooling moves (not fast skinnydip mode) + {% if toolchange_temp > 0 %} + M104 S{toolchange_temp} + {% if not use_fast_skinnydip %} + _WAIT_FOR_TEMP + {% endif %} + {% endif %} + + # Step 3 - Cooling Moves + # Solidifies tip shape and helps break strings if formed + {% set speed_inc = (final_cooling_speed - initial_cooling_speed) / (2 * cooling_moves - 1) %} + {% for move in range(cooling_moves) %} + {% set speed = initial_cooling_speed + speed_inc * move * 2 %} + G1 E{cooling_tube_length} F{speed * 60} + G1 E-{cooling_tube_length} F{(speed + speed_inc) * 60} + {% endfor %} + + # Wait for extruder to reach toolchange temperature after cooling moves complete (fast skinnydip only) + {% if toolchange_temp > 0 and use_skinnydip and use_fast_skinnydip %} + _WAIT_FOR_TEMP + {% endif %} + + # Step 4 - Skinnydip + # Burns off very fine hairs (Good for PLA) + {% if use_skinnydip %} + G1 E{skinnydip_distance} F{dip_insertion_speed * 60} + G4 P{melt_zone_pause} + G1 E-{skinnydip_distance} F{dip_extraction_speed * 60} + G4 P{cooling_zone_pause} + {% endif %} + + # Set temperature target to next filament temp or starting temp. Note that we don't + # wait because the temp will settle during the rest of the toolchange + M104 S{next_temp} + + # Step 5 - Parking + # Optional park filament at fixed location or eject completely (testing) + {% if final_eject %} + G92 E0 + G1 E-80 F{extruder_eject_speed * 60} + {% elif parking_distance > 0 %} + G90 # Absolute positioning + M82 # Absolute extrusion + G1 E-{parking_distance} F{extruder_eject_speed * 60} + {% endif %} + + # Restore state + RESTORE_GCODE_STATE NAME=MMU_FORM_TIP_state + + +[gcode_macro _WAIT_FOR_TEMP] +description: Helper function for fan assisted extruder temp reduction +gcode: + {% set vars = printer['gcode_macro _MMU_FORM_TIP_VARS'] %} + {% set toolchange_temp = vars['toolchange_temp']|default(0)|int %} + {% set toolchange_use_fan = vars['toolchange_fan_assist']|default(false)|lower == 'true' %} + {% set toolchange_fan_speed = vars['toolchange_fan_speed']|default(50)|int %} + {% set toolchange_fan = vars['toolchange_fan_name']|default('')|string %} + + MMU_LOG MSG='{"Waiting for extruder temp %d\u00B0C..." % toolchange_temp}' + {% if toolchange_use_fan %} + {% if printer.fan is defined or printer[toolchange_fan] is defined %} + {% set orig_fan_speed = printer[toolchange_fan].speed if printer[toolchange_fan] is defined else printer.fan.speed %} + M106 S{(toolchange_fan_speed / 100 * 255)|int} + M109 S{toolchange_temp} + M106 S{(orig_fan_speed * 255)|int} + {% else %} + MMU_LOG MSG="Warning: Printer part fan is not defined. Ignoring 'toolchange_use_fan' option" ERROR=1 + M109 S{toolchange_temp} + {% endif %} + {% else %} + M109 S{toolchange_temp} + {% endif %} + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg new file mode 100644 index 00000000..4d6b2c64 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg @@ -0,0 +1,340 @@ +######################################################################################################################## +# Happy Hare MMU Software +# +# EDIT THIS FILE BASED ON YOUR SETUP +# +# Copyright (C) 2022 moggieuk#6538 (discord) moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Happy Hare MMU hardware config file with config for ERBv2 MCU board +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +# Notes about setup of common external MCUs can be found here: +# https://github.com/moggieuk/Happy-Hare/blob/main/doc/mcu_notes.md +# +# Note about "touch" endstops: Happy Hare provides extremely flexible homing options using both single steppers or +# synced steppers. The "touch" option leverages stallguard and thus requires the appropriate 'diag_pin' and stallguard +# parameters set on the TMC driver section. If you have the diag_pin exposed, it is harmless to define this because +# they will only be used when explicitly needed and configured. +# +# Touch option for each stepper provides these benefits / possibilities (experimental): +# - on extruder stepper allows for the automatic detection of the nozzle! +# - on selector stepper allows for the automatic detection of filament stuck in the gate and subsequent recovery +# - on gear stepper allows for the automatic detection of the extruder entrance +# +# These sound wonderful right? They are, but there are caveats: +# - Some external MCUs are terrible at detecting stallguard and often result in an "undervoltage error" +# It is generally possible to get selector touch (TMC2209) tuned especially if you set 'stealthchop_threshold' +# to a value greater than homing speeds and less than move speed. I.e. the stepper runs in stealthchop mode when +# homing. [klipper experts will know that it switches the chip mode automatically to stealthchop and then back for +# Stallguard2 support, however the automatic switching back to spreadcycle at the end homing move seems to provoke +# the error condition and setting 'stealthchop_threshold' appropriately avoids this condition. More than you wanted +# to know I'm sure! +# - I have not had much luck with touch (stallguard) on the gear stepper with EASY-BRD and ERB MCUs and you really +# want the extra torque of spreadcycle so adjusting 'stealthchop_threshold' is not really an option +# - Enabling on the extruder stepper is viable but you will likely have to change jumpers on your main mcu to expose +# the DIAG pin for whichever driver the extruder stepper is connected to. +# +# In summary, "touch" homing with your MMU is an advanced option that requires patience and careful tuning. Everything +# works with regular endstops and there are workaround options for certain homing points (like extruder entry) in +# the absence of any endstop. I'm really interested in creative setups. Ping me on Discord (moggieuk#6538) +# +# See 'mmu.cfg' for serial definition and pins aliases +# +# HOMING CAPABLE EXTRUDER (VERY ADVANCED) ----------------------------------------------------------------------------- +# With Happy Hare installed even the extruder can be homed. You will find the usual 'endstop' parameters can be added +# to your '[extruder]' section. Useless you have some clever load cell attached to your nozzle it only really makes +# sense to configure stallguard style "touch" homing. To do this add lines similar to this to your existing +# '[extruder]' definition in printer.cfg. +# +# [extruder] +# endstop_pin: tmc2209_extruder:virtual_endstop +# +# Also be sure to add the appropriate stallguard config to the TMC section, e.g. +# +# [tmc2209 extruder] +# diag_pin: E_DIAG # Set to MCU pin connected to TMC DIAG pin for extruder +# driver_SGTHRS: 100 # 255 is most sensitive value, 0 is least sensitive +# +# Happy Hare will take care of the rest and add a 'mmu_ext_touch' endstop automatically +# + + +# MMU MACHINE / TYPE --------------------------------------------------------------------------------------------------- +# ███╗ ███╗███╗ ███╗██╗ ██╗ ███╗ ███╗ █████╗ ██████╗██╗ ██╗██╗███╗ ██╗███████╗ +# ████╗ ████║████╗ ████║██║ ██║ ████╗ ████║██╔══██╗██╔════╝██║ ██║██║████╗ ██║██╔════╝ +# ██╔████╔██║██╔████╔██║██║ ██║ ██╔████╔██║███████║██║ ███████║██║██╔██╗ ██║█████╗ +# ██║╚██╔╝██║██║╚██╔╝██║██║ ██║ ██║╚██╔╝██║██╔══██║██║ ██╔══██║██║██║╚██╗██║██╔══╝ +# ██║ ╚═╝ ██║██║ ╚═╝ ██║╚██████╔╝ ██║ ╚═╝ ██║██║ ██║╚██████╗██║ ██║██║██║ ╚████║███████╗ +# ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚══════╝ +[mmu_machine] +num_gates: 12 # Number of selectable gates on MMU + +# MMU Vendor & Version is used to automatically configure some parameters and validate configuration +# If custom set to "Other" and uncomment the additional parameters below +# +# ERCF 1.1 add "s" suffix for Springy, "b" for Binky, "t" for Triple-Decky +# e.g. "1.1sb" for v1.1 with Springy mod and Binky encoder +# ERCF 2.0 community edition ERCFv2 +# Tradrack 1.0 add "e" if encoder is fitted (assumed to be Binky) +# AngryBeaver 1.0 +# BoxTurtle 1.0 +# NightOwl 1.0 +# 3MS 1.0 +# 3D Chameleon 1.0 +# Prusa 3.0 NOT YET SUPPORTED - COMING SOON +# Other Generic setup that may require further customization of 'cad' parameters. See doc in mmu_parameters.cfg +# +mmu_vendor: ERCF # MMU family +mmu_version: 2.0 # MMU hardware version number (add mod suffix documented above) + +# These are set automatically from vendor/version above. Only uncomment and set for custom designs ("Other") +#selector_type: LinearSelector # LinearSelector (type-A) or VirtualSelector (type-B) +#variable_bowden_lengths: 0 # 1 = If MMU design has different bowden lengths per gate, 0 = bowden length is the same +#variable_rotation_distances: 1 # 1 = If MMU design has dissimilar drive/BMG gears, thus rotation distance, 0 = One drive gear (e.g. Tradrack) +#require_bowden_move: 1 # 1 = If MMU design has bowden move that is included in load/unload, 0 = zero length bowden (skip bowden move) +#filament_always_gripped: 0 # 1 = Filament is always trapped by MMU (most type-B designs), 0 = MMU can release filament +#has_bypass: {has_bypass} # 1 = Bypass gate available, 0 = No filament bypass possible + + +# FILAMENT DRIVE GEAR STEPPER(S) -------------------------------------------------------------------------------------- +# ██████╗ ███████╗ █████╗ ██████╗ +# ██╔════╝ ██╔════╝██╔══██╗██╔══██╗ +# ██║ ███╗█████╗ ███████║██████╔╝ +# ██║ ██║██╔══╝ ██╔══██║██╔══██╗ +# ╚██████╔╝███████╗██║ ██║██║ ██║ +# ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ +# Note that 'toolhead' & 'mmu_gear' endstops will automatically be added if a toolhead sensor or gate sensor is defined +# +# The default values are tested with the ERCF BOM NEMA14 motor. Please adapt these values to the motor you are using +# Example : for NEMA17 motors, you'll usually use higher current +# +[tmc2209 stepper_mmu_gear] +uart_pin: mmu:MMU_GEAR_UART +run_current: 0.5 # ERCF BOM NEMA14 motor +hold_current: 0.1 # Recommend to be small if not using "touch" or move (TMC stallguard) +interpolate: True +sense_resistor: 0.110 # Usually 0.11, 0.15 for BTT TMC2226 +stealthchop_threshold: 0 # Spreadcycle has more torque and better at speed +# +# Uncomment two lines below if you have TMC and want the ability to use filament "touch" homing with gear stepper +#diag_pin: ^mmu:MMU_GEAR_DIAG # Set to MCU pin connected to TMC DIAG pin for gear stepper +#driver_SGTHRS: 60 # 255 is most sensitive value, 0 is least sensitive + +[stepper_mmu_gear] +step_pin: mmu:MMU_GEAR_STEP +dir_pin: mmu:MMU_GEAR_DIR +enable_pin: !mmu:MMU_GEAR_ENABLE +rotation_distance: 22.7316868 # Bondtech 5mm Drive Gears. Overridden by 'mmu_gear_rotation_distance' in mmu_vars.cfg +gear_ratio: 80:20 # E.g. ERCF 80:20, Tradrack 50:17 +microsteps: 16 # Recommend 16. Increase only if you "step compress" issues when syncing +full_steps_per_rotation: 200 # 200 for 1.8 degree, 400 for 0.9 degree +# +# Uncomment the two lines below to enable filament "touch" homing option with gear motor +#extra_endstop_pins: tmc2209_stepper_mmu_gear:virtual_endstop +#extra_endstop_names: mmu_gear_touch + + + +# SELECTOR STEPPER ---------------------------------------------------------------------------------------------------- +# ███████╗███████╗██╗ ███████╗ ██████╗████████╗ ██████╗ ██████╗ +# ██╔════╝██╔════╝██║ ██╔════╝██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗ +# ███████╗█████╗ ██║ █████╗ ██║ ██║ ██║ ██║██████╔╝ +# ╚════██║██╔══╝ ██║ ██╔══╝ ██║ ██║ ██║ ██║██╔══██╗ +# ███████║███████╗███████╗███████╗╚██████╗ ██║ ╚██████╔╝██║ ██║ +# ╚══════╝╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ +# Consult doc if you want to setup selector for "touch" homing instead or physical endstop +# +[tmc2209 stepper_mmu_selector] +uart_pin: mmu:MMU_SEL_UART +run_current: 0.4 # ERCF BOM NEMA17 motor +hold_current: 0.2 # Can be small if not using "touch" movement (TMC stallguard) +interpolate: True +sense_resistor: 0.110 +stealthchop_threshold: 100 # Stallguard "touch" movement (slower speeds) best done with stealthchop +# +# Uncomment two lines below if you have TMC and want to use selector "touch" movement +#diag_pin: ^mmu:MMU_SEL_DIAG # Set to MCU pin connected to TMC DIAG pin for selector stepper +#driver_SGTHRS: 75 # 255 is most sensitive value, 0 is least sensitive + +[stepper_mmu_selector] +step_pin: mmu:MMU_SEL_STEP +dir_pin: !mmu:MMU_SEL_DIR +enable_pin: !mmu:MMU_SEL_ENABLE +rotation_distance: 40 +microsteps: 16 # Don't need high fidelity +full_steps_per_rotation: 200 # 200 for 1.8 degree, 400 for 0.9 degree +endstop_pin: ^mmu:MMU_SEL_ENDSTOP # Selector microswitch +endstop_name: mmu_sel_home +# Uncomment this line only if default endstop above is using stallguard +#homing_retract_dist: 0 +# +# Uncomment two lines below to give option of selector "touch" movement +#extra_endstop_pins: tmc2209_stepper_mmu_selector:virtual_endstop +#extra_endstop_names: mmu_sel_touch + + +# SERVOS --------------------------------------------------------------------------------------------------------------- +# ███████╗███████╗██████╗ ██╗ ██╗ ██████╗ ███████╗ +# ██╔════╝██╔════╝██╔══██╗██║ ██║██╔═══██╗██╔════╝ +# ███████╗█████╗ ██████╔╝██║ ██║██║ ██║███████╗ +# ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║ ██║╚════██║ +# ███████║███████╗██║ ██║ ╚████╔╝ ╚██████╔╝███████║ +# ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ +# Basic servo PWM setup. If these values are changed then the angles defined for different positions will also change +# +# SELECTOR SERVO ------------------------------------------------------------------------------------------------------- +# +[mmu_servo selector_servo] +pin: mmu:MMU_SEL_SERVO +maximum_servo_angle: 180 +minimum_pulse_width: 0.00085 +maximum_pulse_width: 0.00215 +# +# OPTIONAL GANTRY SERVO FOR TOOLHEAD FILAMENT CUTTER ------------------------------------------------------------------ +# +# (uncomment this section if you have a gantry servo for toolhead cutter pin) +#[mmu_servo mmu_gantry_servo] +#pin: +#maximum_servo_angle:180 +#minimum_pulse_width: 0.00075 +#maximum_pulse_width: 0.00225 +#initial_angle: 180 + + +# ENCODER ------------------------------------------------------------------------------------------------------------- +# ███████╗███╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗██████╗ +# ██╔════╝████╗ ██║██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗ +# █████╗ ██╔██╗ ██║██║ ██║ ██║██║ ██║█████╗ ██████╔╝ +# ██╔══╝ ██║╚██╗██║██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗ +# ███████╗██║ ╚████║╚██████╗╚██████╔╝██████╔╝███████╗██║ ██║ +# ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ +# Encoder measures distance, monitors for runout and clogging and constantly calculates % flow rate +# Note that the encoder_resolution set here is purely a default to get started. It will be correctly set after calibration +# with the value stored in mmu_vars.cfg +# +# The encoder resolution will be calibrated but it needs a default approximation +# If BMG gear based: +# resolution = bmg_circumference / (2 * teeth) +# 24 / (2 * 17) = 0.7059 for TRCT5000 based sensor +# 24 / (2 * 12) = 1.0 for Binky with 12 tooth disc +# +[mmu_encoder mmu_encoder] +encoder_pin: ^mmu:MMU_ENCODER # EASY-BRD: ^PA6, Flytech ERB: ^gpio22 +encoder_resolution: 1.0 # This is just a starter value. Overridden by 'mmu_encoder_resolution' in mmm_vars.cfg +desired_headroom: 5.0 # The clog/runout headroom that MMU attempts to maintain (closest point to triggering runout) +average_samples: 4 # The "damping" effect of last measurement (higher value means slower clog_length reduction) +flowrate_samples: 20 # How many extruder "movements" on the encoder to measure over for flowrate calc + + +# FILAMENT SENSORS ----------------------------------------------------------------------------------------------------- +# ███████╗███████╗███╗ ██╗███████╗ ██████╗ ██████╗ ███████╗ +# ██╔════╝██╔════╝████╗ ██║██╔════╝██╔═══██╗██╔══██╗██╔════╝ +# ███████╗█████╗ ██╔██╗ ██║███████╗██║ ██║██████╔╝███████╗ +# ╚════██║██╔══╝ ██║╚██╗██║╚════██║██║ ██║██╔══██╗╚════██║ +# ███████║███████╗██║ ╚████║███████║╚██████╔╝██║ ██║███████║ +# ╚══════╝╚══════╝╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ +# Define the pins for optional sensors in the filament path. All but the pre-gate sensors will be automatically setup as +# both endstops (for homing) and sensors for visibility purposes. +# +# 'pre_gate_switch_pin_X' .. 'mmu_pre_gate_X' sensor detects filament at entry to MMU. X=gate number (0..N) +# 'gate_switch_pin' .. 'mmu_gate' shared sensor detects filament past the gate of the MMU +# or +# 'post_gear_switch_pin_X' .. 'mmu_gear_X' post gear sensor for each filament +# 'extruder_switch_pin' .. 'extruder' sensor detects filament just before the extruder entry +# 'toolhead_switch_pin' .. 'toolhead' sensor detects filament after extruder entry +# +# Sync motor feedback will typically have a tension switch (more important) or both tension and compression +# 'sync_feedback_tension_pin' .. pin for switch activated when filament is under tension +# 'sync_feedback_compression_pin' .. pin for switch activated when filament is under compression +# +# Configuration is flexible: Simply define pins for any sensor you want to enable, if pin is not set (or the alias is empty) +# it will be ignored. You can also just comment out what you are not using. +# +[mmu_sensors] +pre_gate_switch_pin_0: ^mmu:MMU_PRE_GATE_0 +pre_gate_switch_pin_1: ^mmu:MMU_PRE_GATE_1 +pre_gate_switch_pin_2: ^mmu:MMU_PRE_GATE_2 +pre_gate_switch_pin_3: ^mmu:MMU_PRE_GATE_3 +pre_gate_switch_pin_4: ^mmu:MMU_PRE_GATE_4 +pre_gate_switch_pin_5: ^mmu:MMU_PRE_GATE_5 +pre_gate_switch_pin_6: ^mmu:MMU_PRE_GATE_6 +pre_gate_switch_pin_7: ^mmu:MMU_PRE_GATE_7 +pre_gate_switch_pin_8: ^mmu:MMU_PRE_GATE_8 +pre_gate_switch_pin_9: ^mmu:MMU_PRE_GATE_9 +pre_gate_switch_pin_10: ^mmu:MMU_PRE_GATE_10 +pre_gate_switch_pin_11: ^mmu:MMU_PRE_GATE_11 + +post_gear_switch_pin_0: ^mmu:MMU_POST_GEAR_0 +post_gear_switch_pin_1: ^mmu:MMU_POST_GEAR_1 +post_gear_switch_pin_2: ^mmu:MMU_POST_GEAR_2 +post_gear_switch_pin_3: ^mmu:MMU_POST_GEAR_3 +post_gear_switch_pin_4: ^mmu:MMU_POST_GEAR_4 +post_gear_switch_pin_5: ^mmu:MMU_POST_GEAR_5 +post_gear_switch_pin_6: ^mmu:MMU_POST_GEAR_6 +post_gear_switch_pin_7: ^mmu:MMU_POST_GEAR_7 +post_gear_switch_pin_8: ^mmu:MMU_POST_GEAR_8 +post_gear_switch_pin_9: ^mmu:MMU_POST_GEAR_9 +post_gear_switch_pin_10: ^mmu:MMU_POST_GEAR_10 +post_gear_switch_pin_11: ^mmu:MMU_POST_GEAR_11 + +gate_switch_pin: ^mmu:MMU_GATE_SENSOR + +extruder_switch_pin: +toolhead_switch_pin: + +sync_feedback_tension_pin: +sync_feedback_compression_pin: + + +# MMU OPTIONAL NEOPIXEL LED SUPPORT ------------------------------------------------------------------------------------ +# ██╗ ███████╗██████╗ ███████╗ +# ██║ ██╔════╝██╔══██╗██╔════╝ +# ██║ █████╗ ██║ ██║███████╗ +# ██║ ██╔══╝ ██║ ██║╚════██║ +# ███████╗███████╗██████╔╝███████║ +# ╚══════╝╚══════╝╚═════╝ ╚══════╝ +# Define the led connection, type and length +# +# (comment out this section if you don't have leds) +[neopixel mmu_leds] +pin: mmu:MMU_NEOPIXEL +chain_count: 25 # Number gates x1 or x2 + 1 (if you want status) +color_order: GRBW # Set based on your particular neopixel specification + +# MMU LED EFFECT SEGMENTS ---------------------------------------------------------------------------------------------- +# Define neopixel LEDs for your MMU. The chain_count must be large enough for your desired ranges: +# exit .. this set of LEDs, one for every gate, usually would be mounted at the exit point of the gate +# entry .. this set of LEDs, one for every gate, could be mounted at the entry point of filament into the MMU/buffer +# status .. this single LED represents the status of the currently selected filament +# +# Note that all sets are optional. You can opt simple to have just the 'exit' set for example. The advantage to having +# both entry and exit LEDs is, for example, so that 'entry' can display gate status while 'exit' displays the color +# +# The animation effects requires the installation of Julian Schill's awesome LED effect module otherwise the LEDs +# will be static: +# https://github.com/julianschill/klipper-led_effect +# LED's are indexed in the chain from 1..N. Thus to set up LED's on 'exit' and a single 'status' LED on a 4 gate MMU: +# exit_range: 1-4 +# status_index: 5 +# In this example no 'entry' set is configured. +# +# Note the range order is important and depends on your wiring. Thus 1-4 and 4-1 both represent the same LED range +# but mapped to increasing or decreasing gates respectively +# +# Note that Happy Hare provides a convenience wrapper [mmu_led_effect] that not only creates an effect on each of the +# [mmu_leds] specified segments but also each individual LED for atomic control. See mmu_leds.cfg for examples +# +# (this section is harmless and ignored if the 'led_strip' above doesn't exist - LED support will simply be disabled) +# v3.4: Section name required for multiple MMU units support +[mmu_leds primary] +led_strip: neopixel:mmu_leds +exit_range: 1-12 +entry_range: 24-13 +status_index: 25 +frame_rate: 24 + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_leds.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_leds.cfg new file mode 100644 index 00000000..d85b9b90 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_leds.cfg @@ -0,0 +1,89 @@ +# +# NOTE: This is a temporary pre-inclusion of Happy Hare v4 functionality for the v3.4.0 release +# + +# LED EFFECTS --------------------------------------------------------------------------------------------------------- +# ██╗ ███████╗██████╗ ███████╗███████╗███████╗███████╗ ██████╗████████╗███████╗ +# ██║ ██╔════╝██╔══██╗ ██╔════╝██╔════╝██╔════╝██╔════╝██╔════╝╚══██╔══╝██╔════╝ +# ██║ █████╗ ██║ ██║ █████╗ █████╗ █████╗ █████╗ ██║ ██║ ███████╗ +# ██║ ██╔══╝ ██║ ██║ ██╔══╝ ██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ╚════██║ +# ███████╗███████╗██████╔╝ ███████╗██║ ██║ ███████╗╚██████╗ ██║ ███████║ +# ╚══════╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝ +# +# These are the default effects that may be assigned to actions in the [mmu_leds] section. Note that 'define_on' +# is optional and if sepcified can be used to restrict effect creation to the desired segments +# +[mmu_led_effect mmu_breathing_red] +layers: breathing 4 0 top (1,0,0) + +[mmu_led_effect mmu_white_slow] +define_on: exit, status +layers: breathing 1.0 0 top (0.8,0.8,0.8) + +[mmu_led_effect mmu_white_fast] +define_on: exit, status +layers: breathing 0.6 0 top (0.2,0.2,0.2) + +[mmu_led_effect mmu_blue_clockwise_slow] +define_on: gates, status +layers: chase .5 .5 top (0,0,1), (0,0,.4) + +[mmu_led_effect mmu_blue_clockwise_fast] +define_on: gates, status +layers: chase 1 .5 top (0,0,1), (0,0,.4) + +[mmu_led_effect mmu_blue_anticlock_slow] +define_on: gates, status +layers: chase -.5 .5 top (0,0,1), (0,0,.4) + +[mmu_led_effect mmu_blue_anticlock_fast] +define_on: gates, status +layers: chase -1 .5 top (0,0,1), (0,0,.4) + +[mmu_led_effect mmu_strobe] +layers: strobe 1 1.5 add (1,1,1) + breathing 2 0 difference (0.95,0,0) + static 0 0 top (1,0,0) + +[mmu_led_effect mmu_static_green] +define_on: gates +layers: static 0 0 top (0,0.5,0) + +[mmu_led_effect mmu_ready_green] +define_on: gates +layers: breathing 2 0 subtract (0,0.35,0) + static 0 0 top (0,0.5,0) + +[mmu_led_effect mmu_static_orange] +define_on: gates +layers: static 0 0 top (0.5,0.2,0) + +[mmu_led_effect mmu_ready_orange] +define_on: gates +layers: breathing 2 0 subtract (0.35,0.14,0) + static 0 0 top (0.5,0.2,0) + +[mmu_led_effect mmu_ready_orange2] +define_on: gates +layers: breathing 2 0 top (0.175,0.07,0) + +[mmu_led_effect mmu_static_blue] +define_on: gates +layers: static 0 0 top (0,0,1) + +[mmu_led_effect mmu_ready_blue] +define_on: gates +layers: breathing 2 0 add (0,0,0.5) + static 0 0 top (0,0,0) + +[mmu_led_effect mmu_static_black] +define_on: gates +layers: static 0 0 top (0,0,0) + +[mmu_led_effect mmu_rainbow] +define_on: entry, exit, status +layers: gradient 0.8 0.5 add (0.3, 0.0, 0.0), (0.0, 0.3, 0.0), (0.0, 0.0, 0.3) + +[mmu_led_effect mmu_sparkle] +define_on: exit +layers: twinkle 8 0.15 top (0.3,0.3,0.3), (0.4,0,0.25) diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg new file mode 100644 index 00000000..8fdb0d77 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg @@ -0,0 +1,507 @@ +######################################################################################################################## +# Happy Hare MMU Software +# +# EDIT THIS FILE BASED ON YOUR SETUP +# +# Copyright (C) 2022 moggieuk#6538 (discord) moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Happy Hare supporting MACRO configuration +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +# Supporting set of macros supplied with Happy Hare can be customized by editing the macro "variables" declared here. +# +# This configuration will automatically retained and upgraded between releases (a backup of previous config files will +# always be made for your reference). If you want to customize macros beyond what is possible through these variables +# it is highly recommended you copy the macro to a new name and change the callback macro name in 'mmu_parameters.cfg' +# That way the default macros can still be upgraded but your customization will be left intact +# + + +# PERSISTED STATE --------------------------------------------------------- +# Happy Hare stores configuration and state in the klipper variables file. +# Since klipper can only be a single 'save_variables' file, if you already +# have one you will need to merge the two and point this appropriately. +# +[save_variables] +filename: /etc/klipper/config/mmu/mmu_vars.cfg + + +# NECESSARY KLIPPER OVERRIDES --------------------------------------------- +# ██╗ ██╗██╗ ██╗██████╗ ██████╗ ███████╗██████╗ +# ██║ ██╔╝██║ ██║██╔══██╗██╔══██╗██╔════╝██╔══██╗ +# █████╔╝ ██║ ██║██████╔╝██████╔╝█████╗ ██████╔╝ +# ██╔═██╗ ██║ ██║██╔═══╝ ██╔═══╝ ██╔══╝ ██╔══██╗ +# ██║ ██╗███████╗██║██║ ██║ ███████╗██║ ██║ +# ╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ +# +# These supplemental settings essentially disable klipper's built in +# extrusion limits and is necessary when using an MMU +[extruder] +max_extrude_only_distance: 200 +max_extrude_cross_section: 50 + +# For dialog prompts and progress in Mainsail. Requires Mainsail version >= v2.9.0 +[respond] + +# Other Happy Hare prerequisites. Harmless if already defined elsewhere in user config +[display_status] +[pause_resume] +[virtual_sdcard] +path: /etc/klipper/gcodes +#on_error_gcode: CANCEL_PRINT + + +# PRINT START/END --------------------------------------------------------- +# ██████╗ ██████╗ ██╗███╗ ██╗████████╗ ███████╗████████╗ █████╗ ██████╗ ████████╗ +# ██╔══██╗██╔══██╗██║████╗ ██║╚══██╔══╝ ██╔════╝╚══██╔══╝██╔══██╗██╔══██╗╚══██╔══╝ +# ██████╔╝██████╔╝██║██╔██╗ ██║ ██║ ███████╗ ██║ ███████║██████╔╝ ██║ +# ██╔═══╝ ██╔══██╗██║██║╚██╗██║ ██║ ╚════██║ ██║ ██╔══██║██╔══██╗ ██║ +# ██║ ██║ ██║██║██║ ╚████║ ██║ ███████║ ██║ ██║ ██║██║ ██║ ██║ +# ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ +# (base/mmu_software.cfg) +# +[gcode_macro _MMU_SOFTWARE_VARS] +description: Happy Hare optional configuration for print start/end checks +gcode: # Leave empty + +# These variables control the behavior of the MMU_START_SETUP and MMU_START_LOAD_INITIAL_TOOL macros +variable_user_pre_initialize_extension : '' ; Executed at start of MMU_START_SETUP. Commonly G28 to home +variable_home_mmu : False ; True/False, Whether to home mmu before print starts +variable_check_gates : True ; True/False, Whether to check filament is loaded in all gates used +variable_load_initial_tool : True ; True/False, Whether to automatically load initial tool +# +# Automapping strategy to apply slicer tool map to find matching MMU gate (will adjust tool-to-gate map). Options are: +# 'none' - don't automap (i.e. don't update tool-to-gate map) +# 'filament_name' - exactly match on case insensitive filament name +# 'material' - exactly match on material +# 'color' - exactly match on color (with same material) +# 'closest_color' - match to closest available filament color (with same material) +# 'spool_id' - exactly match on spool_id [FUTURE] +variable_automap_strategy : "none" ; none|filament_name|material|color|closest_color|spool_id + +# These variables control the behavior of the MMU_END macro +variable_user_print_end_extension : '' ; Executed at start of MMU_END. Good place to move off print +variable_unload_tool : True ; True/False, Whether to unload the tool at the end of the print +variable_reset_ttg : False ; True/False, Whether reset TTG map at end of print +variable_dump_stats : True ; True/False, Whether to display print stats at end of print + + +# STATE MACHINE CHANGES --------------------------------------------------- +# ███████╗████████╗ █████╗ ████████╗███████╗ ██████╗██╗ ██╗ █████╗ ███╗ ██╗ ██████╗ ███████╗ +# ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██╔════╝ ██╔════╝██║ ██║██╔══██╗████╗ ██║██╔════╝ ██╔════╝ +# ███████╗ ██║ ███████║ ██║ █████╗ ██║ ███████║███████║██╔██╗ ██║██║ ███╗█████╗ +# ╚════██║ ██║ ██╔══██║ ██║ ██╔══╝ ██║ ██╔══██║██╔══██║██║╚██╗██║██║ ██║██╔══╝ +# ███████║ ██║ ██║ ██║ ██║ ███████╗ ╚██████╗██║ ██║██║ ██║██║ ╚████║╚██████╔╝███████╗ +# ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝ +# (base/mmu_state.cfg) +# +[gcode_macro _MMU_STATE_VARS] +description: Happy Hare configuration for state change hooks +gcode: # Leave empty + +# You can extend functionality to all Happy Hare state change or event +# macros by adding a command (or call to your gcode macro). +# E.g for additional LED logic or consumption counters +variable_user_action_changed_extension : '' ; Executed after default logic with duplicate params +variable_user_print_state_changed_extension : '' ; Executed after default logic with duplicate params +variable_user_mmu_event_extension : '' ; Executed after default logic with duplicate params + +# Maintenance warning limits (consumption counters) +variable_servo_down_limit : 5000 ; Set to -1 for no limit / disable warning +variable_cutter_blade_limit : 3000 ; Set to -1 for no limit / disable warning + + +# LED CONTROL ------------------------------------------------------------- +# ██╗ ███████╗██████╗ ███████╗ +# ██║ ██╔════╝██╔══██╗██╔════╝ +# ██║ █████╗ ██║ ██║███████╗ +# ██║ ██╔══╝ ██║ ██║╚════██║ +# ███████╗███████╗██████╔╝███████║ +# ╚══════╝╚══════╝╚═════╝ ╚══════╝ +# Only configure if you have LEDs installed. The led_effects option is +# automatically ignored if led-effects klipper module is not installed +# (base/mmu_led.cfg) +# +[gcode_macro _MMU_LED_VARS] +description: Happy Hare led macro configuration variables +gcode: # Leave empty + +# Default effects for LED segments when not providing action status +# This can be any effect name, 'r,g,b' color, or built-in functional effects: +# 'off' - LED's off +# 'on' - LED's white +# 'gate_status' - indicate gate availability +# 'filament_color' - indicate filament color +# 'slicer_color' - display slicer defined set color for each gate (printer.mmu.slicer_color_rgb) +variable_led_enable : True ; True = LEDs are enabled at startup (MMU_LED can control), False = Disabled +variable_led_animation : True ; True = Use led-animation-effects, False = Static LEDs +variable_default_exit_effect : "gate_status" ; off|gate_status|filament_color|slicer_color +variable_default_entry_effect : "filament_color" ; off|gate_status|filament_color|slicer_color +variable_default_status_effect : "filament_color" ; on|off|gate_status|filament_color|slicer_color +variable_white_light : (1, 1, 1) ; RGB color for static white light +variable_black_light : (.01, 0, .02) ; RGB color used to represent "black" (filament) +variable_empty_light : (0, 0, 0) ; RGB color used to represent empty gate + + +# SEQUENCE MACRO - PARKING MOVEMENT AND TOOLCHANGE CONTROL ---------------- +# ███╗ ███╗ ██████╗ ██╗ ██╗███████╗███╗ ███╗███████╗███╗ ██╗████████╗ +# ████╗ ████║██╔═══██╗██║ ██║██╔════╝████╗ ████║██╔════╝████╗ ██║╚══██╔══╝ +# ██╔████╔██║██║ ██║██║ ██║█████╗ ██╔████╔██║█████╗ ██╔██╗ ██║ ██║ +# ██║╚██╔╝██║██║ ██║╚██╗ ██╔╝██╔══╝ ██║╚██╔╝██║██╔══╝ ██║╚██╗██║ ██║ +# ██║ ╚═╝ ██║╚██████╔╝ ╚████╔╝ ███████╗██║ ╚═╝ ██║███████╗██║ ╚████║ ██║ +# ╚═╝ ╚═╝ ╚═════╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝ +# Configure carefully if you 'enable_park: True' +# (base/mmu_sequence.cfg) +# +[gcode_macro _MMU_SEQUENCE_VARS] +description: Happy Hare sequence macro configuration variables +gcode: # Leave empty + +# Parking and movement controls: +# Happy Hare defines 7 operations that may require parking. You can specify +# whether to park for each of those operations both during a print and +# standalone (not printing) with Happy Hare or when HH is disabled: +# +# enable_park_printing +# This is a list of the operations that should result in toolhead parking +# while in a print. There are really two main starting points from which +# you can customize. If using the slicer to form tips (and toolchange is +# over the wipetower) you don't want to park on "toolchange" but you would +# want to on "runout" which is a forced toolchange unknown by the slicer. +# Typically you would also want to park at least on pause, cancel and +# complete if not done elsewhere +# +# enabled_park_standalone +# List of the operations that should result in toolhead parking when not +# printing, for example, just manipulating the MMU manually or via +# Klipperscreen. Really it is up to you to choose based on personal +# workflow preferences but this defaults to just 'pause,cancel' +# (i.e. disabled for toolchange) +# +# enabled_park_disabled +# List of the operations that should result in toolhead parking when MMU is +# disabled (MMU ENABLE=0) and using Happy Hare client macros. Note that only +# pause and cancel can occur in this mode and would typically be enabled +# +# The operations are as follows: +# toolchange - normal toolchange initiated with Tx or MMU_CHANGE_TOOL command +# runout - when a forced toolchange occurs as a result of runout +# load - individual MMU_LOAD operation +# unload - individual MMU_UNLOAD/MMU_EJECT operation +# complete - when print is complete (Happy Hare enabled) +# pause - a regular klipper PAUSE +# cancel - a regular klipper CANCEL_PRINT +# +# It is possible to call the parking macro manually in this form should you wish +# to include in your macros. +# +# _MMU_PARK FORCE_PARK=1 X=10 Y=10 Z_HOP=5 +# +# restore_xy_pos +# Controls where the toolhead (x,y) is returned to after an operation that +# invokes a parking move: +# last - return to original position before park (frequently the default) +# next - return to next print position if possible else last logic will be applied. +# In print this reduces dwell time at the last position reducing blobbing +# and unnecessary movement. Only applied to "toolchange" operation +# none - the toolhead is left wherever it ends up after change. In a print the +# next gcode command will restore toolhead x,y position +# +# Notes: +# - The starting z-height will always be restored, thus the different between 'next' +# and 'none' is the z-height at which the (x,y) move occurs and the location of +# of any un-retract +# - The default parking logic is a straight line move to the 'park_*' position. +# To implement fancy movement and control you can specify your own +# 'user_park_move_macro' to use instead of default straight line move +# +# Retraction can be used to optimize stringing and blobs that can occur when +# changing tools and are active only during a print. +# IMPORTANT: For toolchanging the config order would be: +# 1. In mmu_parameters.cfg configure extruder dimensions like +# 'toolhead_extruder_to_nozzle',etc. These are based on geometry. +# 2. In mmu_parameters.cfg tweak 'toolhead_ooze_reduction' only if necessary +# so that filament _just_ appears at the nozzle on load +# 3. Only then, adjust retraction to control stringing and blobs when +# changing tool in a print +variable_enable_park_printing : 'toolchange,runout,load,unload,complete,pause,cancel' ; Empty '' to disable parking +variable_enable_park_standalone : 'toolchange,load,unload,pause,cancel' ; Empty '' to disable parking +variable_enable_park_disabled : 'pause,cancel' ; Empty '' to disable parking + +variable_min_toolchange_z : 1.0 ; The absolute minimum safety floor (z-height) for ALL parking moves + +# These specify the parking location, z_hop and retraction for all enabled operation +# types. Each must be 5 values: +# x_coord, y_coord, z_hop(delta), z_hop_ramp, retraction length +# Use -1,-1 for no x,y move (you can just have z_hop). Use 0 for no z_hop +# The z_hop ramp is the horizontal distance in mm to travel during the lift. The +# direction is automatic any only applied if lifting the first time from print. +# This move is useful to help break the filament "string" +variable_park_toolchange : -1, -1, 1, 5, 2 ; x,y,z-hop,z_hop_ramp,retract for "toolchange" operations (toolchange,load,unload) +variable_park_runout : -1, -1, 1, 5, 2 ; x,y,z-hop,z_hop_ramp,retract +variable_park_pause : 50, 50, 5, 0, 2 ; x,y,z-hop,z_hop_ramp,retract (park position when mmu error occurs) +variable_park_cancel : -1, -1, 10, 0, 5 ; x,y,z-hop,z_hop_ramp,retract +variable_park_complete : 50, 50, 10, 0, 5 ; x,y,z-hop,z_hop_ramp,retract + +# For toolchange operations, this allows to you to specify additional parking moves +# at various stages of the toolchange. Each must have 3 values: +# x_coord, y_coord, z_hop(delta) +# Use -1,-1,0 for no movement at that stage (no-op). +# All movement will be at the established movement plane (z-height) +variable_pre_unload_position : -1, -1, 0 ; x,y,z-hop position before unloading starts +variable_post_form_tip_position : -1, -1, 0 ; x,y,z-hop position after form/cut tip on unload +variable_pre_load_position : -1, -1, 0 ; x,y,z-hop position before loading starts + +variable_restore_xy_pos : "last" ; last|next|none - What x,y position the toolhead should travel to after a "toolchange" + +variable_park_travel_speed : 200 ; Speed for any travel movement XY(Z) in mm/s +variable_park_lift_speed : 15 ; Z-only travel speed in mm/s +variable_retract_speed : 30 ; Speed of the retract move in mm/s +variable_unretract_speed : 30 ; Speed of the unretract move in mm/s + +# ADVANCED: Normally x,y moves default to 'G1 X Y' to park position. This allows +# you to create exotic movements. Macro will be provided the following parameters: +# YOUR_MOVE_MACRO X= Y= F= +variable_user_park_move_macro : '' ; Executed instead of default 'G1 X Y move' to park position + +variable_auto_home : True ; True = automatically home if necessary, False = disable +variable_timelapse : False ; True = take frame snapshot after load, False = disable + +# Instead of completely defining your your own macros you can can extend functionality +# of default sequence macros by adding a command (or call to your gcode macro) +variable_user_mmu_error_extension : '' ; Executed after default logic when mmu error condition occurs +variable_user_pre_unload_extension : '' ; Executed after default logic +variable_user_post_form_tip_extension : '' ; Executed after default logic +variable_user_post_unload_extension : '' ; Executed after default logic +variable_user_pre_load_extension : '' ; Executed after default logic +variable_user_post_load_extension : '' ; Executed after default logic but before restoring toolhead position + + +# CUT_TIP ----------------------------------------------------------------- +# ██████╗██╗ ██╗████████╗ ████████╗██╗██████╗ +# ██╔════╝██║ ██║╚══██╔══╝ ╚══██╔══╝██║██╔══██╗ +# ██║ ██║ ██║ ██║ ██║ ██║██████╔╝ +# ██║ ██║ ██║ ██║ ██║ ██║██╔═══╝ +# ╚██████╗╚██████╔╝ ██║ ██║ ██║██║ +# ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ +# Don't need to configure if using tip forming +# (base/mmu_cut_tip.cfg) +# +[gcode_macro _MMU_CUT_TIP_VARS] +description: Happy Hare toolhead tip cutting macro configuration variables +gcode: # Leave empty + +# Whether the toolhead tip cutting macro will return toolhead to initial position +# after the cut is complete. If using parking logic it is better to disable this +variable_restore_position : False ; True = return to initial position, False = don't return + +# Distance from the internal nozzle tip to the cutting blade. This dimension +# is based on your toolhead and should not be used for tuning +# Note: If you have a toolhead sensor this variable can be automatically determined! +# Read https://github.com/moggieuk/Happy-Hare/wiki/Blobing-and-Stringing +variable_blade_pos : 37.5 ; TUNE ME: Distance in mm from internal nozzle tip + +# Distance to retract prior to making the cut, measured from the internal nozzle +# tip. This reduces wasted filament (left behind in extruder) but might cause a +# clog if set too large. This must be less than 'blade_pos' +# Note: the residual filament left in nozzle ('toolhead_ooze_reduction') is +# subtracted from this value so make sure toolhead is calibrated +variable_retract_length : 32.5 ; TUNE ME: 5mm less than 'blade_pos' is a good starting point + +# Whether to perform a simple tip forming move after the initial retraction +# Enabling this adds gives some additional cooling time of molten filament and +# may help avoid potential clogging on some hotends +variable_simple_tip_forming : True ; True = Perform simple tip forming, False = skip + +# This should be the position of the toolhead where the cutter arm just +# lightly touches the depressor pin +variable_cutting_axis : "x" ; "x" or "y". Determines cut direction (axis) during cut motion +variable_pin_loc_xy : 14, 250 ; x,y coordinates of depressor pin + +# This distance is added to "pin_loc_x" or "pin_loc_y" depending on the 'cutting_axis' +# to determine the starting position and to create a small safety distance that aids +# in generating momentum +variable_pin_park_dist : 5.0 ; Distance in mm + +# Position of the toolhead when the cutter is fully compressed. This value is on the x or y axis depending on the value of +# 'cutting_axis'. Should leave a small headroom (should be a bit larger than 0, or whatever xmin is) to +# avoid banging the toolhead or gantry +variable_pin_loc_compressed : 0.5 ; Distance. Coordinate in x or y direction depending on 'cutting_axis' + +# Retract length and speed after the cut so that the cutter blade doesn't +# get stuck on return to origin position +variable_rip_length : 1.0 ; Distance in mm to retract to aid lever decompression (>= 0) +variable_rip_speed : 3 ; Speed mm/s + +# Pushback of the remaining tip from the cold end into the hotend. This does +# not have to push back all the way, just sufficient to ensure filament fragment +# stays in hot end and the "nail head" of the cut is pushed back past the +# PTFE/metal junction so it cannot cause clogging problems on future loads. +# Cannot be larger than 'retract_length' - `toolhead_ooze_reduction` +variable_pushback_length : 15.0 ; TUNE ME: PTFE tube length + 3mm is good starting point +variable_pushback_dwell_time : 0 ; Time in ms to dwell after the pushback + +# Speed related settings for tip cutting +# Note that if the cut speed is too fast, the steppers can lose steps. +# Therefore, for a cut: +# - We first make a fast move to accumulate some momentum and get the cut +# blade to the initial contact with the filament +# - We then make a slow move for the actual cut to happen +variable_travel_speed : 150 ; Speed mm/s +variable_cut_fast_move_speed : 32 ; Speed mm/s +variable_cut_slow_move_speed : 8 ; Speed mm/s +variable_evacuate_speed : 150 ; Speed mm/s +variable_cut_dwell_time : 50 ; Time in ms to dwell at the cut point +variable_cut_fast_move_fraction : 1.0 ; Fraction of the move that uses fast move +variable_extruder_move_speed : 25 ; Speed mm/s for all extruder movement + +# Safety margin for fast vs slow travel. When traveling to the pin location +# we make a safer but longer move if we are closer to the pin than this +# specified margin. Usually setting these to the size of the toolhead +# (plus a small margin) should be good enough +variable_safe_margin_xy : 30, 30 ; Approx toolhead width +5mm, height +5mm) + +# If gantry servo option is installed, enable the servo and set up and down +# angle positions +variable_gantry_servo_enabled : False ; True = enabled, False = disabled +variable_gantry_servo_down_angle: 55 ; Angle for when pin is deployed +variable_gantry_servo_up_angle : 180 ; Angle for when pin is retracted + + +# FORM_TIP ---------------------------------------------------------------- +# ███████╗ ██████╗ ██████╗ ███╗ ███╗ ████████╗██╗██████╗ +# ██╔════╝██╔═══██╗██╔══██╗████╗ ████║ ╚══██╔══╝██║██╔══██╗ +# █████╗ ██║ ██║██████╔╝██╔████╔██║ ██║ ██║██████╔╝ +# ██╔══╝ ██║ ██║██╔══██╗██║╚██╔╝██║ ██║ ██║██╔═══╝ +# ██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║ ██║ ██║██║ +# ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ +# Don't need to configure if using tip cutting +# (base/mmu_form_tip.cfg) +# +[gcode_macro _MMU_FORM_TIP_VARS] +description: Happy Hare tip forming macro configuration variables +gcode: # Leave empty + +# Step 1 - Ramming +# Ramming is the initial squeeze of filament prior to cooling moves and is +# described in terms of total volume and progression of squeeze intensity +# printing/standalone. This can be separately controlled when printing or +# standalone +variable_ramming_volume : 0 ; Volume in mm^3, 0 = disabled (optionally let slicer do it) +variable_ramming_volume_standalone : 0 ; Volume in mm^3, 0 = disabled + +# Optionally set for temperature change (reduction). The wait will occur +# before nozzle separation if 'use_fast_skinnydip: False' else after cooling +# moves. Temperature will be restored after tip creation is complete +variable_toolchange_temp : 0 ; 0 = don't change temp, else temp to set +variable_toolchange_fan_assist : False ; Whether to use part cooling fan for quicker temp change +variable_toolchange_fan_speed : 50 ; Fan speed % if using fan_assist enabled + +# Step 2 - Nozzle Separation +# The filament is then quickly separated from the meltzone by a fast movement +# before then slowing to travel the remaining distance to cooling tube. The +# initial fast movement should be as fast as extruder can comfortably perform. +# A good starting point# for slower move is unloading_speed_start/cooling_moves. +# Too fast a slower movement can lead to excessively long tips or hairs +variable_unloading_speed_start : 80 ; Speed in mm/s for initial fast movement +variable_unloading_speed : 18 ; Speed in mm/s for slow move to cooling zone + +# Step 3 - Cooling Moves +# The cooling move allows the filament to harden while constantly moving back +# and forth in the cooling tube portion of the extruder to prevent a bulbous +# tip forming. The cooling tube position is measured from the internal nozzle +# to just past the top of the heater block (often it is beneficial to add a +# couple of mm to ensure the tip is in the cooling section. The cooling tube +# length is then the distance from here to top of heatsink (this is the length +# length of the cooling moves). The final cooling move is a fast movement to +# break the string formed. +variable_cooling_tube_position : 35 ; Start of cooling tube. DragonST:35, DragonHF:30, Mosquito:30, Revo:35, RapidoHF:27 +variable_cooling_tube_length : 10 ; Movement length. DragonST:15, DragonHF:10, Mosquito:20, Revo:10, RapidoHF:10 +variable_initial_cooling_speed : 10 ; Initial slow movement (mm/s) to solidify tip and cool string if formed +variable_final_cooling_speed : 50 ; Fast movement (mm/s) Too fast: tip deformation on eject, Too Slow: long string/no separation +variable_cooling_moves : 4 ; Number of back and forth cooling moves to make (2-4 is a good start) + +# Step 4 - Skinnydip +# Skinnydip is an advanced final move that may have benefit with some +# material like PLA to burn off persistent very fine hairs. To work the +# depth of insertion is critical (start with it disabled and tune last) +# For reference the internal nozzle would be at a distance of +# cooling_tube_position + cooling_tube_length, the top of the heater +# block would be cooling_tube_length away. +variable_use_skinnydip : False ; True = enable skinnydip, False = skinnydip move disabled +variable_skinnydip_distance : 30 ; Distance to reinsert filament into hotend starting from end of cooling tube +variable_dip_insertion_speed : 30 ; Medium/Slow insertion speed mm/s - Just long enough to melt the fine hairs, too slow will pull up molten filament +variable_dip_extraction_speed : 70 ; Speed mm/s - Around 2x Insertion speed to prevents forming new hairs +variable_melt_zone_pause : 0 ; Pause if melt zone in ms. Default 0 +variable_cooling_zone_pause : 0 ; Pause if cooling zone after dip in ms. Default 0 +variable_use_fast_skinnydip : False ; False = Skip the toolhead temp change wait during skinnydip move + +# Step 5 - Parking +# Park filament ready to eject +variable_parking_distance : 0 ; Position mm to park the filament at end of tip forming, 0 = leave where filament ends up after tip forming +variable_extruder_eject_speed : 25 ; Speed mm/s used for parking_distance (and final_eject when testing) + + +# CLIENT MACROS ----------------------------------------------------------- +# ██████╗ █████╗ ██╗ ██╗███████╗███████╗ ██████╗ ███████╗███████╗██╗ ██╗███╗ ███╗███████╗ +# ██╔══██╗██╔══██╗██║ ██║██╔════╝██╔════╝ ██╔══██╗██╔════╝██╔════╝██║ ██║████╗ ████║██╔════╝ +# ██████╔╝███████║██║ ██║███████╗█████╗ ██████╔╝█████╗ ███████╗██║ ██║██╔████╔██║█████╗ +# ██╔═══╝ ██╔══██║██║ ██║╚════██║██╔══╝ ██╔══██╗██╔══╝ ╚════██║██║ ██║██║╚██╔╝██║██╔══╝ +# ██║ ██║ ██║╚██████╔╝███████║███████╗ ██║ ██║███████╗███████║╚██████╔╝██║ ╚═╝ ██║███████╗ +# ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ +# If using the recommended PAUSE/RESUME/CANCEL_PRINT macros shipped with +# Happy Hare these variables allow for customization and basic extension +# Note that most parameters are pulled from the "movement" (sequence) +# macro above and thus these are supplemental a +# (optional/client_macros.cfg) +# +[gcode_macro _MMU_CLIENT_VARS] +description: Happy Hare client macro configuration variables +gcode: # Leave empty + +variable_reset_ttg_on_cancel : False ; True/False, Whether reset TTG map if print is canceled +variable_unload_tool_on_cancel : False ; True/False, Whether to unload the tool on cancel + +# You can extend functionality by adding a command (or call to your gcode macro) +variable_user_pause_extension : '' ; Executed after the klipper base pause +variable_user_resume_extension : '' ; Executed before the klipper base resume +variable_user_cancel_extension : '' ; Executed before the klipper base cancel_print + + +########################################################################### +# Tool change macros +# This is automatically created on installation but you can increase or +# reduce this list to match your number of tools in operation +# Note: it is annoying to have to do this but interfaces like Mainsail rely +# on real macro definitions for tools to be visible in the UI +# +[gcode_macro T0] +gcode: MMU_CHANGE_TOOL TOOL=0 +[gcode_macro T1] +gcode: MMU_CHANGE_TOOL TOOL=1 +[gcode_macro T2] +gcode: MMU_CHANGE_TOOL TOOL=2 +[gcode_macro T3] +gcode: MMU_CHANGE_TOOL TOOL=3 +[gcode_macro T4] +gcode: MMU_CHANGE_TOOL TOOL=4 +[gcode_macro T5] +gcode: MMU_CHANGE_TOOL TOOL=5 +[gcode_macro T6] +gcode: MMU_CHANGE_TOOL TOOL=6 +[gcode_macro T7] +gcode: MMU_CHANGE_TOOL TOOL=7 +[gcode_macro T8] +gcode: MMU_CHANGE_TOOL TOOL=8 +[gcode_macro T9] +gcode: MMU_CHANGE_TOOL TOOL=9 +[gcode_macro T10] +gcode: MMU_CHANGE_TOOL TOOL=10 +[gcode_macro T11] +gcode: MMU_CHANGE_TOOL TOOL=11 + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_parameters.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_parameters.cfg new file mode 100644 index 00000000..aa0a9e1b --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_parameters.cfg @@ -0,0 +1,823 @@ +######################################################################################################################## +# Happy Hare MMU Software +# +# EDIT THIS FILE BASED ON YOUR SETUP +# +# Copyright (C) 2022-2026 moggieuk#6538 (discord) +# moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Main configuration parameters for the klipper module +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# Notes: +# Macro configuration is specified separately in 'mmu_macro_vars.cfg'. +# Full details in https://github.com/moggieuk/Happy-Hare/tree/main/doc/configuration.md +# +[mmu] +happy_hare_version: 3.42 # Don't mess, used for upgrade detection + +# MMU Hardware Limits -------------------------------------------------------------------------------------------------- +# ██╗ ██╗███╗ ███╗██╗████████╗███████╗ +# ██║ ██║████╗ ████║██║╚══██╔══╝██╔════╝ +# ██║ ██║██╔████╔██║██║ ██║ ███████╗ +# ██║ ██║██║╚██╔╝██║██║ ██║ ╚════██║ +# ███████╗██║██║ ╚═╝ ██║██║ ██║ ███████║ +# ╚══════╝╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝ +# +# Define the physical limits of your MMU. These settings will be respected regardless of individual speed settings. +# +gear_max_velocity: 300 # Never to be exceeded gear velocity regardless of specific parameters +gear_max_accel: 1500 # Never to be exceeded gear acceleration regardless of specific parameters +selector_max_velocity: 250 # Never to be exceeded selector velocity regardless of specific parameters +selector_max_accel: 1200 # Never to be exceeded selector acceleration regardless of specific parameters + + +# Servo configuration ------------------------------------------------------------------------------------------------- +# ███████╗███████╗██████╗ ██╗ ██╗ ██████╗ +# ██╔════╝██╔════╝██╔══██╗██║ ██║██╔═══██╗ +# ███████╗█████╗ ██████╔╝██║ ██║██║ ██║ +# ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║ ██║ +# ███████║███████╗██║ ██║ ╚████╔╝ ╚██████╔╝ +# ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═════╝ +# +# Angle of the servo in three named positions +# up = tool is selected and filament is allowed to freely move through gate +# down = to grip filament +# move = ready the servo for selector move (optional - defaults to up) +# V2.4.0 on: These positions are only for initial config they are replaced with calibrated servo positions in 'mmu_vars.cfg' +# +# Note that leaving the servo active when down can stress the electronics and is not recommended with EASY-BRD or ERB board +# unless the 5v power supply has been improved and it is not necessary with standard ERCF builds +# Make sure your hardware is suitable for the job! +# +servo_up_angle: 40 # ERCF: MG90S: 30 ; SAVOX SH0255MG: 140 ; Tradrack: 145 +servo_down_angle: 113 # ERCF: MG90S: 140 ; SAVOX SH0255MG: 30 ; Tradrack: 1 +servo_move_angle: 60 # Optional angle used when selector is moved (defaults to up position) +servo_duration: 0.4 # Duration of PWM burst sent to servo (default non-active mode, automatically turns off) +servo_dwell: 0.5 # Minimum time given to servo to complete movement prior to next move +servo_always_active: 0 # CAUTION - WILL DAMAGE COMMON SERVOS, PLEASE USE AT YOUR OWN RISK: 1=Force servo to always stay active, 0=Release after movement +servo_active_down: 0 # CAUTION - WILL DAMAGE COMMON SERVOS, PLEASE USE AT YOUR OWN RISK: 1=Force servo to stay active when down only, 0=Release after movement +servo_buzz_gear_on_down: 1 # Whether to "buzz" the gear stepper on down to aid engagement + + +# Logging -------------------------------------------------------------------------------------------------------------- +# ██╗ ██████╗ ██████╗ ██████╗ ██╗███╗ ██╗ ██████╗ +# ██║ ██╔═══██╗██╔════╝ ██╔════╝ ██║████╗ ██║██╔════╝ +# ██║ ██║ ██║██║ ███╗██║ ███╗██║██╔██╗ ██║██║ ███╗ +# ██║ ██║ ██║██║ ██║██║ ██║██║██║╚██╗██║██║ ██║ +# ███████╗╚██████╔╝╚██████╔╝╚██████╔╝██║██║ ╚████║╚██████╔╝ +# ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ +# +# log_level & logfile_level can be set to one of (0 = essential, 1 = info, 2 = debug, 3 = trace, 4 = developer + stepper moves) +# Generally you can keep console logging to a minimal whilst still sending debug output to the mmu.log file +# Increasing the console log level is only really useful during initial setup to save having to constantly open the log file +# Note: that it is not recommended to keep logging at level greater that 2 (debug) if not debugging an issue because +# of the additional overhead +# +log_level: 1 +log_file_level: 2 # Can also be set to -1 to disable log file completely +log_statistics: 1 # 1 to log statistics on every toolchange (default), 0 to disable (but still recorded) +log_visual: 1 # 1 log visual representation of filament, 0 = disable +log_startup_status: 1 # Whether to log tool to gate status on startup, 1 = summary (default), 0 = disable +log_m117_messages: 1 # Whether send toolchange message via M117 to screen + + +# Movement speeds ------------------------------------------------------------------------------------------------------ +# ███████╗██████╗ ███████╗███████╗██████╗ ███████╗ +# ██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗██╔════╝ +# ███████╗██████╔╝█████╗ █████╗ ██║ ██║███████╗ +# ╚════██║██╔═══╝ ██╔══╝ ██╔══╝ ██║ ██║╚════██║ +# ███████║██║ ███████╗███████╗██████╔╝███████║ +# ╚══════╝╚═╝ ╚══════╝╚══════╝╚═════╝ ╚══════╝ +# +# Long moves are faster than the small ones and used for the bulk of the bowden movement. You can set two fast load speeds +# depending on whether pulling from the spool or filament buffer (if fitted and not the first time load). This can be helpful +# in allowing faster loading from buffer and slower when pulling from the spool because of the additional friction (prevents +# loosing steps). Unloading speed can be tuning if you have a rewinder system that imposes additional limits. +# NOTE: Encoder cannot keep up much above 450mm/s so make sure 'bowden_apply_correction' is off at very high speeds! +# +gear_from_spool_speed: 80 # mm/s Speed when loading from the spool (for the first time if has_filament_buffer: 1) +gear_from_spool_accel: 100 # Acceleration when loading from spool +gear_from_buffer_speed: 150 # mm/s Speed when loading filament from buffer. Conservative is 100mm/s, Max around 400mm/s +gear_from_buffer_accel: 400 # Normal acceleration when loading filament +gear_unload_speed: 80 # mm/s Use (lower) speed when unloading filament (defaults to "from spool" speed) +gear_unload_accel: 100 # Acceleration when unloading filament (defaults to "from spool" accel) +# +gear_short_move_speed: 80 # mm/s Speed when making short moves (like incremental retracts with encoder) +gear_short_move_accel: 600 # Usually the same as gear_from_buffer_accel (for short movements) +gear_short_move_threshold: 70 # Move distance that controls application of 'short_move' speed/accel +gear_homing_speed: 50 # mm/s Speed of gear stepper only homing moves (e.g. homing to gate or extruder) + +# Speeds of extruder movement. The 'sync' speeds will be used when gear and extruder steppers are moving in sync +# +extruder_load_speed: 16 # mm/s speed of load move inside extruder from homing position to meltzone +extruder_unload_speed: 16 # mm/s speed of unload moves inside of extruder (very initial move from meltzone is 50% of this) +extruder_sync_load_speed: 18 # mm/s speed of synchronized extruder load moves +extruder_sync_unload_speed: 18 # mm/s speed of synchronized extruder unload moves +extruder_homing_speed: 18 # mm/s speed of extruder only homing moves (e.g. to toolhead sensor) + +# Selector movement speeds. (Acceleration is defined by physical MMU limits set above and passed to selector stepper driver) +# +selector_move_speed: 200 # mm/s speed of selector movement (not touch) +selector_homing_speed: 60 # mm/s speed of initial selector homing move (not touch) +selector_touch_speed: 80 # mm/s speed of all touch selector moves (if stallguard configured) + +# Selector touch (stallguard) operation. If stallguard is configured, then this can be used to switch on touch movement which +# can detect blocked filament path and try to recover automatically but it is more difficult to set up +# +selector_touch_enabled: 0 # If selector touch operation configured this can be used to disable it 1=enabled, 0=disabled + +# When Happy Hare calls out to a macro for user customization and for parking moves these settings are applied and the previous +# values automatically restored afterwards. This allows for deterministic movement speed regardless of the starting state. +# +macro_toolhead_max_accel: 0 # Default printer toolhead acceleration applied when macros are run. 0 = use printer max +macro_toolhead_min_cruise_ratio: 0.5 # Default printer cruise ratio applied when macros are run + + +# Gate loading/unloading ----------------------------------------------------------------------------------------------- +# ██████╗ █████╗ ████████╗███████╗ ██╗ ██████╗ █████╗ ██████╗ +# ██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝ ██║ ██╔═══██╗██╔══██╗██╔══██╗ +# ██║ ███╗███████║ ██║ █████╗ ██║ ██║ ██║███████║██║ ██║ +# ██║ ██║██╔══██║ ██║ ██╔══╝ ██║ ██║ ██║██╔══██║██║ ██║ +# ╚██████╔╝██║ ██║ ██║ ███████╗ ███████╗╚██████╔╝██║ ██║██████╔╝ +# ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ +# +# These settings control the loading and unloading filament at the gate which is the parking position inside the MMU. +# Typically this would be switch sensor but you can also use an encoder. Even with encoder the endstop can be a switch +# and the encoder used for move verifcation (see advanced 'gate_endstop_to_encoder' option). Note that the `encoder` +# method, due to the nature of its operation will overshoot a little. This is not a problem in practice because the +# overshoot will simply be compensated for in the subsequent move. A +ve parking distance moves towards the MMU, -ve +# moves back through the endstop towards the toolhead. If the MMU has multiple bowden tubes then it is possible to home +# at the extruder sensor and avoid long bowden moves! +# +# Possible gate_homing_endstop names: +# encoder - Detect filament position using movement of the encoder +# mmu_gate - Use gate endstop +# mmu_gear - Use individual per-gate endstop (type-B MMU's) +# extruder - Use extruder entry sensor (Only for some type-B designs, see [mmu_machine] require_bowden_move setting) +# +gate_homing_endstop: encoder # Name of gate endstop, "encoder" forces use of encoder for parking +gate_homing_max: 70 # Maximum move distance to home (or actual move distance if encoder endstop) +gate_parking_distance: 13 # Parking position relative to homing endstop (-ve value means move forward) +gate_preload_homing_max: 70 # Maximum homing distance to the mmu_gear endstop (if MMU is fitted with one) +gate_preload_parking_distance: -10 # Parking position relative to mmu_gear endstop (-ve value means move forward) +gate_endstop_to_encoder: 10 # Distance between gate endstop and encoder (IF both fitted. +ve if encoder after endstop) +gate_unload_buffer: 50 # Amount to reduce the fast unload so that filament doesn't overshoot when parking +gate_load_retries: 2 # Number of times MMU will attempt to grab the filament on initial load (type-A designs) +gate_autoload: 1 # If pre-gate sensor fitted this controls the automatic loading of the gate +gate_final_eject_distance: 0 # Additional distance to eject filament on MMU_EJECT to clear MMU grip + + +# Bowden tube loading/unloading ---------------------------------------------------------------------------------------- +# ██████╗ ██████╗ ██╗ ██╗██████╗ ███████╗███╗ ██╗ ██╗ ██████╗ █████╗ ██████╗ +# ██╔══██╗██╔═══██╗██║ ██║██╔══██╗██╔════╝████╗ ██║ ██║ ██╔═══██╗██╔══██╗██╔══██╗ +# ██████╔╝██║ ██║██║ █╗ ██║██║ ██║█████╗ ██╔██╗ ██║ ██║ ██║ ██║███████║██║ ██║ +# ██╔══██╗██║ ██║██║███╗██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║ ██║██╔══██║██║ ██║ +# ██████╔╝╚██████╔╝╚███╔███╔╝██████╔╝███████╗██║ ╚████║ ███████╗╚██████╔╝██║ ██║██████╔╝ +# ╚═════╝ ╚═════╝ ╚══╝╚══╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ +# +bowden_homing_max: 2000 # Maximum attempted bowden move (for calibration). Should be larger than your actual bowden! + +# If you MMU is equiped with an encoder the following options are available: +# +# In addition to different bowden loading speeds for buffer and non-buffered filament it is possible to detect missed +# steps caused by "jerking" on a heavy spool. If bowden correction is enabled Happy Hare will "believe" the encoder +# reading and make correction moves to bring the filament to within the 'bowden_allowable_load_delta' of the end of +# bowden position (this does require a reliable encoder and is not recommended for very high speed loading >350mm/s) +# +bowden_apply_correction: 1 # 1 to enable, 0 disabled +bowden_allowable_load_delta: 25.0 # How close in mm the correction moves will attempt to get to target +# +# This saftey check uses the encoder to verify the filament is free of extruder before the fast bowden movement to +# reduce possibility of grinding filament. If enabled the trigger can be tuned by setting the "error tolerance" which +# represents the fraction of allowable mismatch between actual movement and that seen by encoder. Setting to 50% tolerance +# usually works well. Increasing will make test more tolerant. Value of 100% essentially disables error detection +# +bowden_pre_unload_test: 1 # 1 to check for bowden movement before full pull (slower), 0 don't check (faster) +bowden_pre_unload_error_tolerance: 50 # ADVANCED: tune pre_unload_test + + +# Extruder homing ----------------------------------------------------------------------------------------------------- +# ███████╗██╗ ██╗████████╗ ██╗ ██╗ ██████╗ ███╗ ███╗██╗███╗ ██╗ ██████╗ +# ██╔════╝╚██╗██╔╝╚══██╔══╝ ██║ ██║██╔═══██╗████╗ ████║██║████╗ ██║██╔════╝ +# █████╗ ╚███╔╝ ██║ ███████║██║ ██║██╔████╔██║██║██╔██╗ ██║██║ ███╗ +# ██╔══╝ ██╔██╗ ██║ ██╔══██║██║ ██║██║╚██╔╝██║██║██║╚██╗██║██║ ██║ +# ███████╗██╔╝ ██╗ ██║██╗ ██║ ██║╚██████╔╝██║ ╚═╝ ██║██║██║ ╚████║╚██████╔╝ +# ╚══════╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝ +# +# Happy Hare needs a reference "homing point" close to the extruder from which to accurately complete the loading of +# the toolhead. This homing operation takes place after the fast bowden load and it is anticipated that that load +# operation will leave the filament just shy of the homing point. If using a toolhead sensor this initial extruder +# homing is unnecessary (but can be forced) because the homing will occur inside the extruder for the optimum in accuracy. +# You still should set this homing method because it is also used for the determination and calibration of bowden length. +# +# In addition to an entry sensor "extruder" it is possible for Happy Hare to "feel" for the extruder gear entry +# by colliding with it. This can be done with encoder based collision detection, the compression of the sync-feedback +# (aka buffer) sensor or using "touch" (stallguard) on the gear stepper. Note that encoder collision detection is not +# completely deterministic and you will have to find the sweetspot for your setup by adjusting the TMC current reduction. +# Note that reduced current during collision detection can also prevent unecessary filament griding. +# +# Possible extruder_homing_endtop names: +# filament_compression - If you have a "sync-feedback" sensor with compression switch configured +# Fast bowden load will move to extruder_homing_buffer distance before extruder gear, then home +# extruder - If you have a "filament entry" endstop configured (Requires 'extruder' endstop) +# Fast bowden load will move to extruder_homing_buffer distance before sensor, then home +# collision - Detect the collision with the extruder gear by monitoring encoder movement (Requires encoder) +# Fast bowden load will move to the extruder gears +# mmu_gear_touch - Use touch detection when the gear stepper hits the extruder (Requires stallguard) +# Fast bowden load will move to extruder_homing_buffer distance before extruder gear, then home +# none - Don't attempt to home. Only possibiliy if lacking all sensor options +# Fast bowden load will move to the extruder gears. Option is fine if using toolhead sensor +# Note: The homing_endstop will be ignored ("none") if a toolhead sensor is available unless "extruder_force_homing: 1" +# +extruder_homing_max: 80 # Maximum distance to advance in order to attempt to home the extruder +extruder_homing_endstop: collision # Filament homing method/endstop name (fallback if toolhead sensor not available) +extruder_homing_buffer: 25 # Amount to reduce the fast bowden load so filament doesn't overshoot the extruder homing point +extruder_collision_homing_current: 30 # % gear_stepper current (10%-100%) to use when homing to extruder homing (100 to disable) + +# If you have a toolhead sensor it will always be used as a homing point making the homing outside of the extruder +# potentially unnecessary. However you can still force this initial homing step by setting this option in which case +# the filament will home to the extruder and then home to the toolhead sensor in two steps +# +extruder_force_homing: 0 + + +# Toolhead loading and unloading -------------------------------------------------------------------------------------- +# ████████╗ ██████╗ ██████╗ ██╗ ██╗ ██╗███████╗ █████╗ ██████╗ ██╗ ██████╗ █████╗ ██████╗ +# ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██║ ██║██╔════╝██╔══██╗██╔══██╗ ██║ ██╔═══██╗██╔══██╗██╔══██╗ +# ██║ ██║ ██║██║ ██║██║ ███████║█████╗ ███████║██║ ██║ ██║ ██║ ██║███████║██║ ██║ +# ██║ ██║ ██║██║ ██║██║ ██╔══██║██╔══╝ ██╔══██║██║ ██║ ██║ ██║ ██║██╔══██║██║ ██║ +# ██║ ╚██████╔╝╚██████╔╝███████╗██║ ██║███████╗██║ ██║██████╔╝ ███████╗╚██████╔╝██║ ██║██████╔╝ +# ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ +# +# It is possible to define highly customized loading and unloading sequences, however, unless you have a specialized +# setup it is probably easier to opt for the built-in toolhead loading and unloading sequence which already offers a +# high degree of customization. If you need even more control then edit the _MMU_LOAD_SEQUENCE and _MMU_UNLOAD_SEQUENCE +# macros in mmu_sequence.cfg - but be careful! +# +# An MMU must have a known point at the end of the bowden from which it can precisely load the extruder. Generally this +# will either be the extruder entrance (which is controlled with settings above) or by homing to toolhead sensor. If +# you have toolhead sensor it is past the extruder gear and the driver needs to know the max distance (from end of +# bowden move) to attempt homing +# +toolhead_homing_max: 40 # Maximum distance to advance in order to attempt to home to defined homing endstop + +# IMPORTANT: These next three settings are based on the physical dimensions of your toolhead +# Once a homing position is determined, Happy Hare needs to know the final move distance to the nozzle. There is only +# one correct value for your setup - use 'toolhead_ooze_reduction' (which corresponds to the residual filament left in +# your nozzle) to control excessive oozing on load. See doc for table of proposed values for common configurations. +# +# NOTE: If you have a toolhead sensor you can automate the calculation of these parameters! Read about the +# `MMU_CALIBRATE_TOOLHEAD` command (https://github.com/moggieuk/Happy-Hare/wiki/Blobbing-and-Stringing#---calibrating-toolhead) +# +toolhead_extruder_to_nozzle: 72 # Distance from extruder gears (entrance) to nozzle +toolhead_sensor_to_nozzle: 62 # Distance from toolhead sensor to nozzle (ignored if not fitted) +toolhead_entry_to_extruder: 8 # Distance from extruder "entry" sensor to extruder gears (ignored if not fitted) + +# This setting represents how much residual filament is left behind in the nozzle when filament is removed, it is thus +# used to reduce the extruder loading length and prevent excessive blobbing but also in the calculation of purge volume. +# Note that this value can also be measured with the `MMU_CALIBRATE_TOOLHEAD` procedure +# +toolhead_residual_filament: 0 # Reduction in extruder loading length because of residual filament left behind + +# TUNING: Finally, this is the last resort tuning value to fix blobbing. It is expected that this value is NEAR ZERO as +# it represents a further reduction in extruder load length to fix blobbing. If using a wipetower and you experience blobs +# on it, increase this value (reduce the quantity of filament loaded). If you experience gaps, decrease this value. If gaps +# and already at 0 then perhaps the 'toolhead_extruder_to_nozzle' or 'toolhead_residual_filament' settings are incorrect. +# Similarly a value >+5mm also suggests the four settings above are not correct. Also see 'retract' setting in +# 'mmu_macro_vars.cfg' for final in-print ooze tuning. +# +toolhead_ooze_reduction: 0 # Reduction in extruder loading length to prevent ooze (represents filament remaining) + +# Distance added to the extruder unload movement to ensure filament is free of extruder. This adds some degree of tolerance +# to slightly incorrect configuration or extruder slippage. However don't use as an excuse for incorrect toolhead settings +# +toolhead_unload_safety_margin: 10 # Extra movement safety margin (default: 10mm) + +# If not synchronizing gear and extruder and you experience a "false" encoder clog detection immediately after the tool +# change it might be because of a long bowden and/or large internal diameter that causes slack in the filament. This optional +# move will tighten the filament after a load by % of current clog detection length. Gear stepper will run at 50% current +# +toolhead_post_load_tighten: 60 # % of clog detection length, 0 to disable. Ignored if 'sync_to_extruder: 1' + +# If synchronizing gear and extruder and you have a sync-feedback "buffer" (switch based or proportional) this setting +# determines whether to use it to create neutral tension after loading +toolhead_post_load_tension_adjust: 1 # 1 to enable (recommended), 0 to disable + +# If sync-feedback compression sensor is available this test will ensure the filament passes the extruder entry by checking +# for neutral tension when moving filament with just the extruder. Recommended with sprung loaded sync-feedback buffers. +# This is ignored if toolhead sensor is available. +toolhead_entry_tension_test: 1 # 1 to enable (recommended), 0 to disable + +# ADVANCED: Controls the detection of successful extruder load/unload movement and represents the fraction of allowable +# mismatch between actual movement and that seen by encoder. Setting to 100% tolerance effectively turns off checking. +# Some designs of extruder have a short move distance that may not be picked up by encoder and cause false errors. This +# allows masking of those errors. However the error often indicates that your extruder load speed is too high or the +# friction is too high on the filament and in that case masking the error is not a good idea. Try reducing friction +# and lowering speed first! +# +toolhead_move_error_tolerance: 60 + + +# Tip forming --------------------------------------------------------------------------------------------------------- +# ████████╗██╗██████╗ ███████╗ ██████╗ ██████╗ ███╗ ███╗██╗███╗ ██╗ ██████╗ +# ╚══██╔══╝██║██╔══██╗ ██╔════╝██╔═══██╗██╔══██╗████╗ ████║██║████╗ ██║██╔════╝ +# ██║ ██║██████╔╝ █████╗ ██║ ██║██████╔╝██╔████╔██║██║██╔██╗ ██║██║ ███╗ +# ██║ ██║██╔═══╝ ██╔══╝ ██║ ██║██╔══██╗██║╚██╔╝██║██║██║╚██╗██║██║ ██║ +# ██║ ██║██║ ██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║██║██║ ╚████║╚██████╔╝ +# ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝ +# +# Tip forming responsibility can be split between slicer (in-print) and standalone macro (not in-print) or forced to always +# be done by Happy Hare's standalone macro. Since you always need the option to form tips without the slicer so it is +# generally easier to completely turn off the slicer, force "standalone" tip forming and tune only in Happy Hare. +# +# When Happy Hare is asked to form a tip it will run the referenced macro. Two are reference examples are provided but +# you can implement your own: +# _MMU_FORM_TIP .. default tip forming similar to popular slicers like Superslicer and Prusaslicer +# _MMU_CUT_TIP .. for Filametrix (originally ERCFv2) or similar style toolhead filament cutting system +# +# NOTE: For MMU located cutting like the optional EREC cutter you should set still this to _MMU_FORM_TIP to build a decent +# tip prior to extraction and cutting after the unload. +# +# Often it is useful to increase the extruder current for the rapid movement to ensure high torque and no skipped steps +# +# If opting for slicer tip forming you MUST configure where the slicer leaves the filament in the extruder since +# there is no way to determine this. This can be ignored if all tip forming is performed by Happy Hare +# +force_form_tip_standalone: 1 # 0 = Slicer in print else standalone, 1 = Always standalone tip forming (TURN SLICER OFF!) +form_tip_macro: _MMU_CUT_TIP # Name of macro to call to perform the tip forming (or cutting) operation (Centauri override) +extruder_form_tip_current: 100 # % of extruder current (100%-150%) to use when forming tip (100 to disable) +slicer_tip_park_pos: 0 # This specifies the position of filament in extruder after slicer completes tip forming + + +# Purging ------------------------------------------------------------------------------------------------------------- +# ██████╗ ██╗ ██╗██████╗ ██████╗ ██╗███╗ ██╗ ██████╗ +# ██╔══██╗██║ ██║██╔══██╗██╔════╝ ██║████╗ ██║██╔════╝ +# ██████╔╝██║ ██║██████╔╝██║ ███╗██║██╔██╗ ██║██║ ███╗ +# ██╔═══╝ ██║ ██║██╔══██╗██║ ██║██║██║╚██╗██║██║ ██║ +# ██║ ╚██████╔╝██║ ██║╚██████╔╝██║██║ ╚████║╚██████╔╝ +# ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ +# +# After a toolchange it is necessary to purge the old filament. Similar to tip forming this can be done by the slicer and/or +# by Happy Hare using an extension like Blobifer. If a purge_macro is defined it will be called when not printing or whenever +# the slicer isn't going to purge (like initial tool load). You can force it to always be called in a print by setting +# force_purge_standalone, but remember to turn off the slicer wipetower +# +# The default is for no (empty) macro so purging will not be done out of a print and thus wipetower. Two options are shipped with +# Happy Hare but you can also build your own custom one: +# _MMU_PURGE .. default purging that just dumps the desired amount of filament (setup correct parking before enabling this!) +# BLOBIFIER .. for excellent Blobifer addon (https://github.com/Dendrowen/Blobifier) +# +# Often it is useful to increase the extruder current for the often rapid puring movement to ensure high torque and no skipped steps +# +force_purge_standalone: 0 # 0 = Slicer wipetower in print else standalone, 1 = Always standalone purging (TURN WIPETOWER OFF!) +purge_macro: '' # Name of macro to call to perform the standalone purging operation. E.g. BLOBIFIER, _MMU_PURGE +extruder_purge_current: 100 # % of extruder current (100%-150%) to use when purging (100 to disable) + + +# Synchronized gear/extruder movement ---------------------------------------------------------------------------------- +# ███╗ ███╗ ██████╗ ████████╗ ██████╗ ██████╗ ███████╗██╗ ██╗███╗ ██╗ ██████╗ +# ████╗ ████║██╔═══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ██╔════╝╚██╗ ██╔╝████╗ ██║██╔════╝ +# ██╔████╔██║██║ ██║ ██║ ██║ ██║██████╔╝ ███████╗ ╚████╔╝ ██╔██╗ ██║██║ +# ██║╚██╔╝██║██║ ██║ ██║ ██║ ██║██╔══██╗ ╚════██║ ╚██╔╝ ██║╚██╗██║██║ +# ██║ ╚═╝ ██║╚██████╔╝ ██║ ╚██████╔╝██║ ██║ ███████║ ██║ ██║ ╚████║╚██████╗ +# ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ +# +# This controls whether the extruder and gear steppers are synchronized during printing operations +# If you normally run with maxed out gear stepper current consider reducing it with 'sync_gear_current' +# If equipped with TMC drivers the current of the gear and extruder motors can be controlled to optimize performance. +# This can be useful to control gear stepper temperature when printing with synchronized motor +# +sync_to_extruder: 0 # Gear motor is synchronized to extruder during print +sync_gear_current: 70 # % of gear_stepper current (10%-100%) to use when syncing with extruder during print +sync_form_tip: 0 # Synchronize during standalone tip formation (initial part of unload) +sync_purge: 0 # Synchronize during standalone purging (last part of load) + +# Optionally it is possible to leverage feedback from a "compression/expansion" sensor (aka "buffer") in the bowden +# path from MMU to extruder to ensure that the two motors are kept in sync as viewed by the filament (the signal feedback +# state can be binary supplied by one or two switches: -1 (expanded) and 1 (compressed) of proportional value between +# -1.0 and 1.0. +# +# If only "one half" of the sync-feedback is available (either compression-only or tension-only) then the rotation +# distance is always shifted based on the high/low multipliers, however if both tension and compression are available +# then the rotation distance will autotune to correct setting (recommend you also enable 'autotune_rotation_distance: 1' +# so that values are saved) +# +# Possible buffer setups, forth option for type where neutral is when both sensors are active: +# +# <------maxrange------> <------maxrange------> <------maxrange------> <------maxrange------> +# <--range---> <----range-----> <----range-----> <> range=0 +# |====================| |====================| |====================| |====================| +# ^ ^ ^ ^ ^^ +# compression tension compression-only tension-only +# +sync_feedback_enabled: 0 # Turn off even if sensor is installed and active +sync_feedback_buffer_range: 6 # Travel in "buffer" between compression/tension or one sensor and end (see above) +sync_feedback_buffer_maxrange: 12 # Absolute maximum end-to-end travel (mm) provided by buffer (see above) +sync_feedback_speed_multiplier: 5 # % "twolevel" gear speed delta to keep filament neutral in buffer (recommend 5%) +sync_feedback_boost_multiplier: 3 # % "twolevel" extra gear speed boost for finding initial neutral position (recommend 3%) +sync_feedback_extrude_threshold: 5 # Extruder movement (mm) for updates (keep small but set > retract distance) + +# If defined this forces debugging to a telemetry log file "sync_.jsonl". This is great if trying to tune clog/tangle +# detection or for getting help on the Happy Hare forum. To plot graph of sync-feedback operation, run: +# ~/Happy-Hare/utils/plot_sync_feedback.sh +# +sync_feedback_debug_log: 0 # 0 = disable (normal operation), 1 = enable telemetry log (for debugging) + + +# ESpooler control ----------------------------------------------------------------------------------------------------- +# ███████╗███████╗██████╗ ██████╗ ██████╗ ██╗ ███████╗██████╗ +# ██╔════╝██╔════╝██╔══██╗██╔═══██╗██╔═══██╗██║ ██╔════╝██╔══██╗ +# █████╗ ███████╗██████╔╝██║ ██║██║ ██║██║ █████╗ ██████╔╝ +# ██╔══╝ ╚════██║██╔═══╝ ██║ ██║██║ ██║██║ ██╔══╝ ██╔══██╗ +# ███████╗███████║██║ ╚██████╔╝╚██████╔╝███████╗███████╗██║ ██║ +# ╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝ +# +# If your MMU has a dc motor (often N20) controlled respooler/assist then how it operates can be controlled with these +# settings. Typically the espooler will be controlled with PWM signal. This will be at the maximum at speeds equal or +# above 'espooler.max_stepper_speed'. The PWM signal will scale downwards towards 0 for slower speeds. The falloff being +# controlled by the 'espooler_speed_exponent' setting according to this formula and allows for non-linear characteristics +# the DC motor (0.5 is a good starting value). +# +# espooler_pwm = (stepper_speed / espooler_max_stepper_speed) ^ {espooler_speed_exponent} +# +# Regardless of h/w configuration you can enable/disable actions with the 'espooler_operations' list. E.g. remove 'play' to +# turn off operation while printing. Options are: +# +# rewind - when filament is being unloaded under MMU control (aka respool) +# assist - when filament is being loaded under MMU control (% of "rewind" speed but with minimum of "print" power) +# print - while printing. Generally set 'espooler_printing_power' to a low percentage just to allow motor to be turned +# freely or set to 0 to enable/allow "burst" assist movements +# +# If using a digitally controlled espooler motor (not PWM) then you should turn off the "print" mode and set +# 'espooler_min_stepper_speed' to prevent "over movement" +# +espooler_min_distance: 200 # Individual stepper movements less than this distance will not active espooler +espooler_max_stepper_speed: 200 # Gear stepper speed at which espooler will be at maximum power +espooler_min_stepper_speed: 0 # Gear stepper speed at which espooler will become inactive (useful for non PWM control) +espooler_speed_exponent: 0.5 # Controls non-linear espooler power relative to stepper speed (see notes) +espooler_assist_reduced_speed: 50 # Control the % of the rewind speed that is applied to assisting load (want rewind to be faster) +espooler_printing_power: 0 # If >0, fixes the % of PWM power while printing. 0=allows burst movement +espooler_operations: rewind, assist, print # List of operational modes (allows disabling even if h/w is configured) +# +# The following burst configuration is used to control the small rotation in the ASSIST direction optionally used +# when in 'print' operation is enabled, 'espooler_printing_power: 0' and is triggered (tension switch or extruder movement). +# It can also be used to loosen filament with 'MMU_ESPOOLER COMMAND=assist BURST=1' +# +espooler_assist_extruder_move_length: 100 # Distance (mm) extruder needs to move between each assist burst +espooler_assist_burst_power: 100 # The % power of the burst move +espooler_assist_burst_duration: 0.4 # The duration of the burst move is seconds +espooler_assist_burst_trigger: 0 # If trigger assist switch is fitted 0=disable, 1=enable +espooler_assist_burst_trigger_max: 3 # If trigger assist switch is fitted this limits the max number of back-to-back advances +# +# The following burst configuration is used to control the small rotation in the REWIND direction optionally used +# when running running the filament drying cycle. The goal is to rotate the spool 60-90 degrees. It can also be +# used to tighten the filament with 'MMU_ESPOOLER COMMAND=rewind BURST=1' +# +espooler_rewind_burst_power: 100 # The % power of the rewind burst move +espooler_rewind_burst_duration: 0.4 # The duration of the rewind burst move is seconds + + +# Heater / Environment Management ------------------------------------------------------------------------------------ +# ██╗ ██╗███████╗ █████╗ ████████╗███████╗██████╗ +# ██║ ██║██╔════╝██╔══██╗╚══██╔══╝██╔════╝██╔══██╗ +# ███████║█████╗ ███████║ ██║ █████╗ ██████╔╝ +# ██╔══██║██╔══╝ ██╔══██║ ██║ ██╔══╝ ██╔══██╗ +# ██║ ██║███████╗██║ ██║ ██║ ███████╗██║ ██║ +# ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ +# +heater_max_temp: 70 # Absolute max heater setting to protect the MMU enclosure construction (adjust to match material) +heater_default_dry_temp: 45 # Default drying temperature if filament type is not matched in drying_data +heater_default_dry_time: 300 # Default drying cycle time in minutes +heater_default_humidity: 25 # Default humidity % goal. Drying will terminate if this value is reached +heater_vent_macro: _MMU_VENT # Name of macro to periodicaly call during drying cycle +heater_vent_interval: 0 # Interval in minutes to call heater_vent_macro during drying cycle, 0=disable venting +heater_rotate_interval: 5 # Interval in minutes to rotate filament (requires eSpooler and filament end attached to spool) + +# Drying data for MMU_HEATER DRY=1 command in form (material type is case insensitive): +# 'filament_type': (temp, drying_time_mins) +# +# (Careful with formatting of this line - reformatting will break upgrade logic) +# +drying_data: { 'pla': (45, 300), 'pla+': (55, 300), 'petg': (60, 300), 'tpu': (55, 300), 'abs': (70, 300), 'abs+': (75, 300), 'asa': (65, 300), 'nylon': (75, 600), 'pc': (75, 600), 'pva': (75, 600), 'hips': (75, 600) } + + +# FlowGuard Clog and Tangle Detection -------------------------------------------------------------------------------- +# ███████╗██╗ ██████╗ ██╗ ██╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗ +# ██╔════╝██║ ██╔═══██╗██║ ██║██╔════╝ ██║ ██║██╔══██╗██╔══██╗██╔══██╗ +# █████╗ ██║ ██║ ██║██║ █╗ ██║██║ ███╗██║ ██║███████║██████╔╝██║ ██║ +# ██╔══╝ ██║ ██║ ██║██║███╗██║██║ ██║██║ ██║██╔══██║██╔══██╗██║ ██║ +# ██║ ███████╗╚██████╔╝╚███╔███╔╝╚██████╔╝╚██████╔╝██║ ██║██║ ██║██████╔╝ +# ╚═╝ ╚══════╝ ╚═════╝ ╚══╝╚══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ +# +# Options are available to automatically detects extruder clogs and MMU tangles. Each option works independently and +# can be combined. Flowguard can even discern the difference between an extruder clog and a spool tangle! +# +# Flowguard: This intelligently measures filament tension (only available if sync-feedback buffer is fitted) +# +# Encoder detection: This monitors encoder movement and compares to extruder (only available if encoder is fitted) +# +flowguard_enabled: 1 # 0 = Flowguard protection disabled, 1 = Enabled + +# The flowguard_max_relief is the amount of relief movement (effective mm change in filament length between MMU and extruder) +# that Happy Hare will wait until triggering a clog or runout. A smaller value is more sensitive to triggering. Since the +# relief movement is hightly dependent on filament "spring" in the bowden tube, filament friction, and +# 'sync_feedback_buffer_range', it is generally good to start high and then decrease if a more sensitive trigger is desired. +# Analog proportional (type P) sensors can generally have a much lower value. Increase if you have false triggers. +flowguard_max_relief: 40 + +# Encoder runout/clog/tangle detection watches for movement over either a static or automatically adjusted distance - if +# no encoder movement is seen when the extruder moves this distance runout/ clog/tangle event will be generated. Allowing +# the distance to be adjusted automatically (mode=2) will generally allow for a quicker trigger but use a static length +# (mode=1, set encoder_max_motion) if you get false triggers (see flowguard guide on wiki for more details). +# Note that this feature cannot disinguish between clog or tangle. +flowguard_encoder_mode: 2 # 0 = Disable, 1 = Static length clog detection, 2 = Automatic length clog detection + +# The encoder_max_motion is the absolute max permitted extruder movement without the encoder seeing movement when using +# status mode (mode=1). Smaller values are more sensitive but beware of going too small - slack and friction in the +# bowden may cause gaps in encoder movement. Increase if you have false triggers. +# Note that this value is overriden by any calibrated value stored in 'mmu_vars.cfg' if in automatic mode (mode=2). +flowguard_encoder_max_motion: 20 + + +# Filament Management Options ---------------------------------------------------------------------------------------- +# ███████╗██╗██╗ ███╗ ███╗ ██████╗ ███╗ ███╗████████╗ +# ██╔════╝██║██║ ████╗ ████║██╔════╝ ████╗ ████║╚══██╔══╝ +# █████╗ ██║██║ ██╔████╔██║██║ ███╗██╔████╔██║ ██║ +# ██╔══╝ ██║██║ ██║╚██╔╝██║██║ ██║██║╚██╔╝██║ ██║ +# ██║ ██║███████╗██╗ ██║ ╚═╝ ██║╚██████╔╝██║ ╚═╝ ██║ ██║ +# ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ +# +# - EndlessSpool feature allows detection of runout on one spool and the automatic mapping of tool to an alternative +# gate (spool). Set to '1', this feature requires clog detection or gate sensor or pre-gate sensors. EndlessSpool +# functionality can optionally be extended to attempt to load an empty gate with 'endless_spool_on_load'. On some MMU +# designs (with linear selector) it can also be configured to eject filament remains to a designated gate rather than +# defaulting to current gate. A custom gate will disable pre-gate runout detection for EndlessSpool because filament +# end must completely pass through the gate for selector to move +# +endless_spool_enabled: 1 # 0 = disable, 1 = enable endless spool +endless_spool_on_load: 0 # 0 = don't apply endless spool on load, 1 = run endless spool if gate is empty +endless_spool_eject_gate: -1 # Which gate to eject the filament remains. -1 = current gate +#endless_spool_groups: # Default EndlessSpool groups (see later in file) +# +# Spoolman support requires you to correctly enable spoolman with moonraker first. If enabled, the gate SpoolId will +# be used to load filament details and color from the spoolman database and Happy Hare will activate/deactivate +# spools as they are used. The enabled variation allows for either the local map or the spoolman map to be the +# source of truth as well as just fetching filament attributes. See this table for explanation: +# +# | Activate/ | Fetch filament attributes | Filament gate | Filament gate | +# spoolman_support | Deactivate | attributes from spoolman | assignment shown | assignment pulled | +# | spool? | based on spool_id? | in spoolman db? | from spoolman db? | +# -----------------+------------+---------------------------+------------------+-------------------+ +# off | no | no | no | no | +# readonly | yes | yes | no | no | +# push | yes | yes | yes | no | +# pull | yes | yes | yes | yes | +# +spoolman_support: off # off = disabled, readonly = enabled, push = local gate map, pull = remote gate map +pending_spool_id_timeout: 20 # Seconds after which this pending spool_id (set with rfid) is voided +# +# Mainsail/Fluid UI can visualize the color of filaments next to the extruder/tool chooser. The color is dynamic and +# can be customized to your choice: +# +# slicer - Color from slicer tool map (what the slicer expects) +# allgates - Color from all the tools in the gate map after running through the TTG map +# gatemap - As per gatemap but hide empty tools +# off - Turns off support +# +# Note: Happy Hare will also add the 'spool_id' variable to the Tx macro if spoolman is enabled +# +t_macro_color: slicer # 'slicer' = default | 'allgates' = mmu | 'gatemap' = mmu without empty gates | 'off' + + +# Print Statistics --------------------------------------------------------------------------------------------------- +# ███████╗████████╗ █████╗ ████████╗███████╗ +# ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██╔════╝ +# ███████╗ ██║ ███████║ ██║ ███████╗ +# ╚════██║ ██║ ██╔══██║ ██║ ╚════██║ +# ███████║ ██║ ██║ ██║ ██║ ███████║ +# ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ +# +# These parameters determine how print statistic data is shown in the console. This table can show a lot of data, +# probably more than you'd want to see. Below you can enable/disable options to your needs. +# +# +-----------+---------------------+----------------------+----------+ +# | 114(46) | unloading | loading | complete | +# | swaps | pre | - | post | pre | - | post | swap | +# +-----------+------+-------+------+------+-------+-------+----------+ +# | all time | 0:07 | 47:19 | 0:00 | 0:01 | 37:11 | 33:39 | 2:00:38 | +# | - avg | 0:00 | 0:24 | 0:00 | 0:00 | 0:19 | 0:17 | 1:03 | +# | this job | 0:00 | 10:27 | 0:00 | 0:00 | 8:29 | 8:30 | 28:02 | +# | - avg | 0:00 | 0:13 | 0:00 | 0:00 | 0:11 | 0:11 | 0:36 | +# | last | 0:00 | 0:12 | 0:00 | 0:00 | 0:10 | 0:14 | 0:39 | +# +-----------+------+-------+------+------+-------+-------+----------+ +# Note: Only formats correctly on Python3 +# +# Comma separated list of desired columns +# Options: pre_unload, form_tip, unload, post_unload, pre_load, load, purge, post_load, total +console_stat_columns: unload, load, post_load, total + +# Comma separated list of rows. The order determines the order in which they're shown. +# Options: total, total_average, job, job_average, last +console_stat_rows: total, total_average, job, job_average, last + +# How you'd want to see the state of the gates and how they're performing +# string - poor, good, perfect, etc.. +# percentage - rate of success +# emoticon - fun sad to happy faces (python3 only) +console_gate_stat: emoticon + +# Always display the full statistics table +console_always_output_full: 1 # 1 = Show full table, 0 = Only show totals out of print + + +# Calibration and autotune ------------------------------------------------------------------------------------------- +# ██████╗ █████╗ ██╗ ██╗██████╗ ██████╗ █████╗ ████████╗██╗ ██████╗ ███╗ ██╗ +# ██╔════╝██╔══██╗██║ ██║██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██║██╔═══██╗████╗ ██║ +# ██║ ███████║██║ ██║██████╔╝██████╔╝███████║ ██║ ██║██║ ██║██╔██╗ ██║ +# ██║ ██╔══██║██║ ██║██╔══██╗██╔══██╗██╔══██║ ██║ ██║██║ ██║██║╚██╗██║ +# ╚██████╗██║ ██║███████╗██║██████╔╝██║ ██║██║ ██║ ██║ ██║╚██████╔╝██║ ╚████║ +# ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ +# +# These are auto calibration/tuning settings that can be used to ease initial setup and/or to tune calibration over +# time based on measured telemetry. Whether these auto-tuning features are available depends on MMU design and +# configured sensors (explained below). The setting will be ignored if the required sensors are not available but if +# they can operate they will suppress the normal calibration warnings (MMU_STATUS can still be used to view them). +# Note that these are initially set by the installer to recommended values +# +# autocal_bowden_length - the calibrated bowden length will be established on first load. It can also be set +# manually or reset with MMU_CALIBRATE_BOWDEN. Best results require the use of +# sync-feedback-compression or extruder sensor but gear-touch or encoder will also work. +# 'extruder_homing_endstop' cannot be 'none' +# autotune_bowden_length - Once calibrated this setting will tune the bowden distance over time. Works best with +# toolhead sensor +# skip_cal_rotation_distance - This will rely on installed default value (although it can still be calibrated). Usually +# a good choice if autotune is enabled +# autotune_rotation_distance - Requires sync-feedback sensor (aka "buffer") or calibrated encoder. If set then either the +# "autotuner" (sync-feedback buffer) or encoder telemetry will be used to adjust the +# persisted gear rotation distance. +# skip_cal_encoder - Will rely on installed default value (although it can still be calibrated). +# Not recommended but allows for easier initial setup especially when 'autotune_encoder' +# is enabled. +# autotune_encoder - NOT IMPLEMENTED YET. Soon! +# +autocal_bowden_length: 1 # Automated bowden length calibration. 1=automatic, 0=manual/off +autotune_bowden_length: 0 # Automated bowden length tuning. 1=on, 0=off +skip_cal_rotation_distance: 0 # Skip rotation distance calibration (MMU_CALIBRATE_GEAR), 1=skip, 0=require +autotune_rotation_distance: 0 # Automated gate calibration/tuning. 1=automatic, 0=manual/off +skip_cal_encoder: 0 # Skip encoder calibration (MMU_CALIBRATE_ENCODER), 1=skip, 0=require +autotune_encoder: 0 # Automated encoder tuning. 1=automatic, 0=manual/off + + +# Miscellaneous, but you should review ------------------------------------------------------------------------------- +# ███╗ ███╗██╗███████╗ ██████╗ +# ████╗ ████║██║██╔════╝██╔════╝ +# ██╔████╔██║██║███████╗██║ +# ██║╚██╔╝██║██║╚════██║██║ +# ██║ ╚═╝ ██║██║███████║╚██████╗ +# ╚═╝ ╚═╝╚═╝╚══════╝ ╚═════╝ +# +# Important you verify these work for you setup/workflow. Temperature and timeouts +# +timeout_pause: 72000 # Idle time out (printer shuts down) in seconds used when in MMU pause state +disable_heater: 600 # Delay in seconds after which the hotend heater is disabled in the MMU_PAUSE state +default_extruder_temp: 200 # Default temperature for performing swaps and forming tips when not in print (overridden by gate map) +extruder_temp_variance: 2 # When waiting for extruder temperature this is the +/- permissible variance in degrees (>= 1) +# +# Other workflow options +# +startup_home_if_unloaded: 0 # 1 = force mmu homing on startup if unloaded, 0 = do nothing +startup_reset_ttg_map: 0 # 1 = reset TTG map on startup, 0 = do nothing +show_error_dialog: 0 # 1 = show pop-up dialog in addition to console message, 0 = show error in console +preload_attempts: 5 # How many "grabbing" attempts are made to pick up the filament with preload feature +strict_filament_recovery: 0 # If enabled with MMU with toolhead sensor, this will cause filament position recovery to + # perform extra moves to look for filament trapped in the space after extruder but before sensor +filament_recovery_on_pause: 1 # 1 = Run a quick check to determine current filament position on pause/error, 0 = disable +retry_tool_change_on_error: 0 # Whether to automatically retry a failed tool change. If enabled Happy Hare will perform + # the equivalent of 'MMU_RECOVER' + 'Tx' commands which usually is all that is necessary + # to recover. Note that enabling this can mask problems with your MMU +bypass_autoload: 1 # If extruder sensor fitted this controls the automatic loading of extruder for bypass operation +has_filament_buffer: 1 # Whether the MMU has a filament buffer. Set to 0 if using Filamentalist or DC eSpooler, etc +# +# Advanced options. Don't mess unless you fully understand. Read documentation. +# +encoder_move_validation: 1 # ADVANCED: 1 = Normally Encoder validates move distances are within given tolerance + # 0 = Validation is disabled (eliminates slight pause between moves but less safe) +print_start_detection: 1 # ADVANCED: Enabled for Happy Hare to automatically detect start and end of print and call + # ADVANCED: MMU_PRINT_START and MMU_PRINT_END automatically. Harmless to leave enabled but can disable + # if you think it is causing problems and known START/END is covered in your macros +extruder: extruder # ADVANCED: Name of the toolhead extruder that MMU is using +gcode_load_sequence: 0 # VERY ADVANCED: Gcode loading sequence 1=enabled, 0=internal logic (default) +gcode_unload_sequence: 0 # VERY ADVANCED: Gcode unloading sequence, 1=enabled, 0=internal logic (default) + + +# ADVANCED: Klipper tuning ------------------------------------------------------------------------------------------- +# ██╗ ██╗██╗ ██╗██████╗ ██████╗ ███████╗██████╗ +# ██║ ██╔╝██║ ██║██╔══██╗██╔══██╗██╔════╝██╔══██╗ +# █████╔╝ ██║ ██║██████╔╝██████╔╝█████╗ ██████╔╝ +# ██╔═██╗ ██║ ██║██╔═══╝ ██╔═══╝ ██╔══╝ ██╔══██╗ +# ██║ ██╗███████╗██║██║ ██║ ███████╗██║ ██║ +# ╚═╝ ╚═╝╚══════╝╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ +# +# Timer too close is a catch all error, however it has been found to occur on some systems during homing and probing +# operations especially so with CANbus connected MCUs. Happy Hare uses many homing moves for reliable extruder loading +# and unloading and enabling this option affords klipper more tolerance and avoids this dreaded error +# +update_trsync: 0 # 1 = Increase TRSYNC_TIMEOUT, 0 = Leave the klipper default +# +# Some CANbus boards are prone to this but it have been seen on regular USB boards where a comms timeout will kill +# the print. Since it seems to occur only on homing moves they can be safely retried to workaround. This has been +# working well in practice +canbus_comms_retries: 3 # Number of retries. Recommend the default of 3. +# +# Older neopixels have very finicky timing and can generate lots of "Unable to obtain 'neopixel_result' response" +# errors in klippy.log. An often cited workaround is to increase BIT_MAX_TIME in neopixel.py. This option does that +# automatically for you to save dirtying klipper +update_bit_max_time: 1 # 1 = Increase BIT_MAX_TIME, 0 = Leave the klipper default +# +# BTT ViViD used a AHT30 sensor. If you are using an older klipper you may not have this sensor available. If so, use +# AHT10 and set this to 1 to convert AHT30 commands to AHT10 +update_aht10_commands: 0 # 1 = Config AHT10 for BTT ViViD heater sensor on older klipper, 0 = Leave the klipper default + + +# ADVANCED: MMU macro overrides --- ONLY SET IF YOU'RE COMFORTABLE WITH KLIPPER MACROS ------------------------------- +# ███╗ ███╗ █████╗ ██████╗██████╗ ██████╗ ███████╗ +# ████╗ ████║██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔════╝ +# ██╔████╔██║███████║██║ ██████╔╝██║ ██║███████╗ +# ██║╚██╔╝██║██╔══██║██║ ██╔══██╗██║ ██║╚════██║ +# ██║ ╚═╝ ██║██║ ██║╚██████╗██║ ██║╚██████╔╝███████║ +# ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ +# +# 'pause_macro' defines what macro to call on MMU error (must put printer in paused state) +# Other macros are detailed in 'mmu_sequence.cfg' +# Also see form_tip_macro in Tip Forming section and purge_macro in Purging section +# +pause_macro: PAUSE # What macro to call to pause the print +action_changed_macro: _MMU_ACTION_CHANGED # Called when action (printer.mmu.action) changes +print_state_changed_macro: _MMU_PRINT_STATE_CHANGED # Called when print state (printer.mmu.print_state) changes +mmu_event_macro: _MMU_EVENT # Called on useful MMU events +pre_unload_macro: _MMU_PRE_UNLOAD # Called before starting the unload +post_form_tip_macro: _MMU_POST_FORM_TIP # Called immediately after tip forming +post_unload_macro: _MMU_POST_UNLOAD # Called after unload completes +pre_load_macro: _MMU_PRE_LOAD # Called before starting the load +post_load_macro: _MMU_POST_LOAD # Called after the load is complete +unload_sequence_macro: _MMU_UNLOAD_SEQUENCE # VERY ADVANCED: Optionally called based on 'gcode_unload_sequence' +load_sequence_macro: _MMU_LOAD_SEQUENCE # VERY ADVANCED: Optionally called based on 'gcode_load_sequence' + + +# ADVANCED: See documentation for use of these ----------------------------------------------------------------------- +# ██████╗ ███████╗███████╗███████╗████████╗ ██████╗ ███████╗███████╗███████╗ +# ██╔══██╗██╔════╝██╔════╝██╔════╝╚══██╔══╝ ██╔══██╗██╔════╝██╔════╝██╔════╝ +# ██████╔╝█████╗ ███████╗█████╗ ██║ ██║ ██║█████╗ █████╗ ███████╗ +# ██╔══██╗██╔══╝ ╚════██║██╔══╝ ██║ ██║ ██║██╔══╝ ██╔══╝ ╚════██║ +# ██║ ██║███████╗███████║███████╗ ██║ ██████╔╝███████╗██║ ███████║ +# ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚══════╝ +# +# These are the values that the various "RESET" commands will reset too rather than the built-in defaults. The lenght +# of the lists must match the number of gates on your MMU +# +# e.g. MMU_GATE_MAP RESET=1 - will use all the 'gate_XXX' values +# MMU_TTG_MAP RESET=1 - will use the 'tool_to_gate_map' +# MMU_ENDLESS_SPOOL_GROUPS RESET=1 - will use the 'endless_spool_groups' +# +# Gate: #0 #1 #2 #3 #4 #5 #6 #7 #8 +#gate_status: 1, 0, 1, 2, 2, -1, -1, 0, 1 +#gate_filament_name: one, two, three, four, five, six, seven, eight, nine +#gate_material: PLA, ABS, ABS, ABS+, PLA, PLA, PETG, TPU, ABS +#gate_color: red, black, yellow, green, blue, indigo, ffffff, grey, black +#gate_temperature: 210, 240, 235, 245, 210, 200, 215, 240, 240 +#gate_spool_id: 3, 2, 1, 4, 5, 6, 7, -1, 9 +#gate_speed_override: 100, 100, 100, 100, 100, 100, 100, 50, 100 +#endless_spool_groups: 0, 1, 2, 1, 0, 0, 3, 4, 1 +# +# Tool: T0 T1 T2 T3 T4 T5 T6 T7 T8 +#tool_to_gate_map: 0, 1, 2, 3, 4, 5, 6, 7, 8 + + +# ADVANCED/CUSTOM MMU: See documentation for use of these ------------------------------------------------------------ +# ██████╗██╗ ██╗███████╗████████╗ ██████╗ ███╗ ███╗ ███╗ ███╗███╗ ███╗██╗ ██╗ +# ██╔════╝██║ ██║██╔════╝╚══██╔══╝██╔═══██╗████╗ ████║ ████╗ ████║████╗ ████║██║ ██║ +# ██║ ██║ ██║███████╗ ██║ ██║ ██║██╔████╔██║ ██╔████╔██║██╔████╔██║██║ ██║ +# ██║ ██║ ██║╚════██║ ██║ ██║ ██║██║╚██╔╝██║ ██║╚██╔╝██║██║╚██╔╝██║██║ ██║ +# ╚██████╗╚██████╔╝███████║ ██║ ╚██████╔╝██║ ╚═╝ ██║ ██║ ╚═╝ ██║██║ ╚═╝ ██║╚██████╔╝ +# ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ +# +# Normally all these settings are set based on your choice of 'mmu_vendor' and 'mmu_version' in mmu_hardware.cfg, but they +# can be overridden. If you have selected a vendor of "Other" and your MMU has a selector you must set these CAD based +# dimensions else you will get arbitrary defaults. You may also need to set additional attributes in '[mmu_machine]' +# section of mmu_hardware.cfg. +# +#cad_gate0_pos: 4.2 # Approximate distance from endstop to first gate. Used for rough calibration only +#cad_gate_width: 21.0 # Width of each gate +#cad_bypass_offset: 0 # Distance from limit of travel back to the bypass (e.g. ERCF v2.0) +#cad_last_gate_offset: 2.0 # Distance from limit of travel back to last gate +#cad_selector_tolerance: 10.0 # How much extra selector movement to allow for calibration +#cad_gate_directions = [1, 1, 0, 0] # Directions of gear depending on gate (3DChameleon) +#cad_release_gates = [2, 3, 0, 1] # Gate to move to when releasing filament (3DChameleon) + +# SUPPLEMENTAL USER CONFIG retained after upgrade -------------------------------------------------------------------- +# diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_sequence.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_sequence.cfg new file mode 100644 index 00000000..9f3ce822 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_sequence.cfg @@ -0,0 +1,665 @@ +######################################################################################################################## +# Happy Hare MMU Software +# Supporting macros +# +# THIS FILE IS READ ONLY +# +# Copyright (C) 2022-2026 moggieuk#6538 (discord) +# moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Control of parking and loading and unload sequences +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +# These skeleton macros define all the callbacks made during filament loading or unloading. They can be extended with +# the user command additions (see 'mmu_macro_vars.cfg') or can be used as templates for completely custom macros. Note +# the SAVE/RESTORE_GCODE_STATE wrapper pattern is precautionary +# +# The ordering of these macros is as follows (if any are not defined they are skipped): +# +# Unloading sequence... +# _MMU_PRE_UNLOAD Called before starting the unload +# 'form_tip_macro' User defined macro for tip forming +# _MMU_POST_FORM_TIP Called immediately after tip forming +# (_MMU_UNLOAD_SEQUENCE) Advanced: Optionally called based on 'gcode_unload_sequence' +# _MMU_POST_UNLOAD Called after unload completes +# +# Loading sequence... +# _MMU_PRE_LOAD Called before starting the load +# (_MMU_LOAD_SEQUENCE) Advanced: Optionally called based on 'gcode_load_sequence' +# _MMU_POST_LOAD Called after the load is complete +# +# If changing a tool the unload sequence will be immediately followed by the load sequence +# +# Notes: +# 1. When the MMU is enabled Happy Hare implement z-hop and retraction portion of the moves on toolchange, runout, +# pauses and mmu errors (while in print) as well as the un-retraction and return to print positioning. The reason +# for this is print quality, speed and safety. However the configuration is still defined in mmu_macro_vars. +# 2. Pressure advance will automatically be cleared prior and restored after tip forming +# 3. M220 & M221 overrides will be retained after a toolchange +# 4. If configured, Spoolman will be notified of toolchange +# 5. Should an error occur causing a pause, the extruder temp will be saved and restored on MMU_UNLOCK or resume +# +# When the MMU is disabled, the supplied client_macros.cfg will take over retraction and z-hop moves using the +# same configuration which is why they are recommended rather than using alternatives +# +# Leveraging the user defined macro callbacks is usually sufficient for customization, however if you really want to +# do something unusual you can enable the gcode loading/unloading sequences by setting the following in 'mmu_parameters.cfg' +# +# 'gcode_load_sequence: 1' +# 'gcode_unload_sequence: 1' +# +# This is quite advanced and you will need to understand the Happy Hare state machine before embarking on changes. +# Reading the doc is essential +# + + +########################################################################### +# Shared toolhead parking macro designed to position toolhead at a suitable +# parking position, manage z-hops and retraction +# +# Standalone use, typically: _MMU_PARK FORCE_PARK=1 X= Y= Z_HOP= +# +# FORCE_PARK=1 - force parking move +# X | float - x coordinate of forced parking location +# Y | float - y coordinate of forced parking location +# Z_HOP | float - z-hop for forced parking move +# +# OPERATION | string - define operation being performed for built-in parking +# +[gcode_macro _MMU_PARK] +description: Park toolhead safely away from print + +# -------------------------- Internal Don't Touch ------------------------- +variable_saved_xyz: 0, 0, 0 +variable_saved_pos: False # Saved pos valid? +variable_park_operation: '' # If parked, what operation was responsible +variable_next_xy: 0, 0 # Next x,y pos if next_pos is True +variable_next_pos: False # Restore to next_pos? +variable_min_lifted_z: 0 # Supports rising "z-lifted floor" for sequential printing +variable_toolchange_z: -1 # Current calculated toolchange/movement plane +variable_retracted_length: 0 # Amount of current retraction + +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set operation = params.OPERATION|default(printer.mmu.operation)|string|lower %} + {% set is_printing = printer.mmu.print_state in ["started", "printing"] and not printer.pause_resume.is_paused %} + {% set force_park = params.FORCE_PARK|default(0)|int == 1 %} + {% set force_park_x = params.X|default(-999)|float %} + {% set force_park_y = params.Y|default(-999)|float %} + {% set enable_park_printing = (vars.enable_park_printing|default("toolchange,runout,pause,cancel")|string|lower).split(",") %} + {% set enable_park_standalone = (vars.enable_park_standalone|default("toolchange,load,unload,pause,cancel")|string|lower).split(",") %} + {% set enable_park_disabled = (vars.enable_park_disabled|default("pause,cancel")|string|lower).split(",") %} + {% set nx,ny = next_xy|map('float') %} + {% set pos = printer.gcode_move.gcode_position %} + {% if force_park %} + {% set operation = 'force_park' %} + {% set x = force_park_x %} + {% set y = force_park_y %} + {% set park_z_hop = params.Z_HOP|default(0)|float %} + {% set z_hop_ramp = params.RAMP|default(0)|float %} + {% set retract = 0 %} + {% elif operation in ['toolchange','load','unload'] %} + {% set x, y, park_z_hop, z_hop_ramp, retract = vars.park_toolchange|default([-999,-999,0,0,0])|map('float') %} + {% elif operation in ['runout'] %} + {% set x, y, park_z_hop, z_hop_ramp, retract = vars.park_runout|default([-999,-999,0,0,0])|map('float') %} + {% elif operation in ['pause'] %} + {% set x, y, park_z_hop, z_hop_ramp, retract = vars.park_pause|default([-999,-999,0,0,0])|map('float') %} + {% elif operation in ['cancel'] %} + {% set x, y, park_z_hop, z_hop_ramp, retract = vars.park_cancel|default([-999,-999,0,0,0])|map('float') %} + {% elif operation in ['complete'] %} + {% set x, y, park_z_hop, z_hop_ramp, retract = vars.park_complete|default([-999,-999,0,0,0])|map('float') %} + {% else %} + {% set x = -999 %} + {% set y = -999 %} + {% set park_z_hop = 0 %} + {% set z_hop_ramp = 0 %} + {% set retract = 0 %} + {% endif %} + {% set park_z_hop = park_z_hop|abs %} + {% set z_hop_ramp = z_hop_ramp|abs %} + {% set min_toolchange_z = vars.min_toolchange_z|default(1)|float|abs %} + {% if x == -999 and y == -999 and park_z_hop == 0 %} + {% set min_toolchange_z = 0 %} + {% endif %} + {% set park_travel_speed = vars.park_travel_speed|default(200)|float * 60 %} + {% set park_lift_speed = vars.park_lift_speed|default(15)|float * 60 %} + {% set pos = printer.gcode_move.gcode_position %} + {% set origin = printer.gcode_move.homing_origin %} + {% set max = printer.toolhead.axis_maximum %} + + # Z-hop ramp position calcs + {% set orig_x = pos.x %} + {% set orig_y = pos.y %} + {% set cx = (max.x - origin.x) / 2.0 %} + {% set cy = (max.y - origin.y) / 2.0 %} + {% if pos.x == cx and pos.y == cy %} + {% set target_x = 0 %} + {% set target_y = 0 %} + {% else %} + {% set target_x = cx %} + {% set target_y = cy %} + {% endif %} + {% set dx = target_x - pos.x %} + {% set dy = target_y - pos.y %} + {% set length = (dx * dx + dy * dy) ** 0.5 %} + {% set z_hop_x = pos.x + z_hop_ramp * dx / length %} + {% set z_hop_y = pos.y + z_hop_ramp * dy / length %} + + {% set starting_z = saved_xyz[2] if saved_pos else pos.z %} + {% set z_hop_floor = [starting_z, min_lifted_z]|max %} + {% set toolchange_z = [[z_hop_floor + park_z_hop, max.z - origin.z]|min, min_toolchange_z, toolchange_z]|max %} + + {% set should_park = force_park or ( + operation in ( + enable_park_disabled if not printer.mmu.enabled else + (enable_park_printing if is_printing else enable_park_standalone) + ) and operation != park_operation + ) %} + {% set should_ramp = ( + should_park and pos.z == starting_z and + park_z_hop > 0 and z_hop_ramp > 0 and + operation not in ['load'] and is_printing + ) %} + {% set should_retract = ( + should_park and + retracted_length == 0 and retract > 0 and + operation not in ['load'] + ) %} + + {% if should_park %} + {% if should_retract %} + _MMU_RETRACT LENGTH={retract} + {% endif %} + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=toolchange_z VALUE={toolchange_z} + {% set lift=" with ramping lift" if should_ramp else "" %} + MMU_LOG MSG="Parking toolhead at (x:{x|round(1) if x != -999 else "n/a"}, y:{y|round(1) if y != -999 else "n/a"}, z:{toolchange_z|round(1)}){lift} for {operation} operation" + {% if 'xy' not in printer.toolhead.homed_axes %} + MMU_LOG MSG="Cannot park because XY not homed" + {% else %} + G90 # Absolute + {% if 'z' not in printer.toolhead.homed_axes %} + MMU_LOG MSG="Skipping z_hop move because Z not homed" + {% else %} + {% if should_ramp %} + G1 X{z_hop_x} Y{z_hop_y} Z{toolchange_z} F{park_travel_speed} # Ramping Z lift + G1 X{orig_x} Y{orig_y} Z{toolchange_z} F{park_travel_speed} # Restore starting X,Y + {% else %} + G1 Z{toolchange_z} F{park_lift_speed} # Z lift to toolchange plane + {% endif %} + {% endif %} + {% if vars.user_park_move_macro %} + {vars.user_park_move_macro} X={x} Y={y} F={park_travel_speed} + {% elif x != -999 and y != -999 %} + G1 X{x} Y{y} F{park_travel_speed} # Move to park position + {% elif x != -999 and y == -999 %} + G1 X{x} F{park_travel_speed} # X move only + {% elif x == -999 and y != -999 %} + G1 Y{y} F{park_travel_speed} # Y move only + {% endif %} + {% endif %} + {% if not force_park %} + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=park_operation VALUE=\"{operation}\" + {% endif %} + {% endif %} + + +########################################################################### +# Helper macro: save current toolhead position +# This macro is idempotent recording only the first position until cleared +# This is often called directly by Happy Hare +# +[gcode_macro _MMU_SAVE_POSITION] +description: Record to toolhead position for return later +gcode: + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set pos = printer.gcode_move.gcode_position %} + {% set axis_minimum = printer.toolhead.axis_minimum %} + {% set axis_maximum = printer.toolhead.axis_maximum %} + {% set x = [axis_minimum.x, [axis_maximum.x, pos.x]|min]|max %} + {% set y = [axis_minimum.y, [axis_maximum.y, pos.y]|min]|max %} + + {% if not park_vars.saved_pos and 'xyz' in printer.toolhead.homed_axes %} + {% if x != pos.x or y != pos.y %} + MMU_LOG MSG="Warning: Klipper reported out of range gcode position (x:{pos.x}, y:{pos.y})! Adjusted to (x:{x}, y:{y}) to prevent move failure" ERROR=1 + {% endif %} + MMU_LOG MSG="Saving toolhead position (x:{x|round(1)}, y:{y|round(1)}, z:{pos.z|round(1)})" + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=saved_xyz VALUE="{x}, {y}, {pos.z}" + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=saved_pos VALUE={True} + {% endif %} + + +########################################################################### +# Helper macro: restore previously saved position and reset +# This is often called directly by Happy Hare +# +[gcode_macro _MMU_RESTORE_POSITION] +description: Restore saved toolhead position +gcode: + {% set restore = params.RESTORE|default(1)|int %} + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set x,y,z = park_vars.saved_xyz|map('float') %} + {% set nx,ny = park_vars.next_xy|map('float') %} + {% set park_travel_speed = vars.park_travel_speed|default(200)|float * 60 %} + {% set park_lift_speed = vars.park_lift_speed|default(15)|float * 60 %} + {% set restore_xy_pos = vars.restore_xy_pos|default('last') %} + {% set is_printing = printer.mmu.print_state in ["started", "printing"] and not printer.pause_resume.is_paused %} + + {% set should_unretract = ( + park_vars.retracted_length and + park_vars.park_operation not in ['unload', 'cancel', 'complete'] + ) %} + {% set should_restore_nextxy = ( + park_vars.next_pos and + restore_xy_pos == 'next' and + park_vars.park_operation == 'toolchange' + ) %} + {% set should_restore_xy = ( + park_vars.saved_pos and + (restore_xy_pos != 'none' or park_vars.park_operation != 'toolchange') + ) %} + + {% if restore %} # Allows override for initial tool load and final unload + G90 # Absolute + {% if park_vars.toolchange_z > 0 and park_vars.saved_pos and 'z' in printer.toolhead.homed_axes %} + G1 Z{park_vars.toolchange_z} F{park_lift_speed} # Ensure at toolchange height for collision avoidance before move + {% endif %} + {% if should_restore_nextxy %} + {% if vars.user_park_move_macro %} + MMU_LOG MSG="Restoring toolhead position to next pos using {vars.user_park_move_macro} RESTORE=1 (x:{nx|round(1)}, y:{ny|round(1)})" + {vars.user_park_move_macro} RESTORE=1 X={nx} Y={ny} F={park_travel_speed} + {% else %} + MMU_LOG MSG="Restoring toolhead position to next pos: (x:{nx|round(1)}, y:{ny|round(1)}, z:{z|round(1)})" + G1 X{nx} Y{ny} F{park_travel_speed} # Restore X,Y to next print position + {% endif %} + {% elif should_restore_xy %} + {% if vars.user_park_move_macro %} + MMU_LOG MSG="Restoring toolhead position to last pos using {vars.user_park_move_macro} RESTORE=1 (x:{x|round(1)}, y:{y|round(1)})" + {vars.user_park_move_macro} RESTORE=1 X={x} Y={y} F={park_travel_speed} + {% else %} + MMU_LOG MSG="Restoring toolhead position to last pos: (x:{x|round(1)}, y:{y|round(1)}, z:{z|round(1)})" + G1 X{x} Y{y} F{park_travel_speed} # Restore X,Y to last (starting) position + {% endif %} + {% elif park_vars.saved_pos %} + MMU_LOG MSG="Restoring toolhead position to: (z:{z|round(1)})" + {% endif %} + {% if park_vars.saved_pos and 'z' in printer.toolhead.homed_axes %} + G1 Z{z} F{park_lift_speed} # Restore original Z height + {% endif %} + {% else %} + MMU_LOG MSG="Skipping restore of toolhead XYZ position" + {% endif %} + + {% if should_unretract %} + _MMU_UNRETRACT + {% endif %} + + _MMU_CLEAR_POSITION + + +########################################################################### +# Helper macro: Retract filament +# +[gcode_macro _MMU_RETRACT] +description: Helper to retract filament +gcode: + {% set sequence_vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set retracted_length = park_vars.retracted_length %} + {% set length = params.LENGTH|default(0)|float|abs %} + {% set speed = sequence_vars.retract_speed|int %} + {% set length = [length - retracted_length, 0] | max %} + + {% if printer.extruder.can_extrude %} + {% if length > 0 %} + MMU_LOG MSG="Retracting {length}mm" + M83 ; Extruder relative + G1 E-{length} F{speed|abs * 60} + {% endif %} + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=retracted_length VALUE={length} + {% else %} + MMU_LOG MSG="Extruder is not hot enough to retract" DEBUG=1 + {% endif %} + + +########################################################################### +# Helper macro: Undo retract filament move +# +[gcode_macro _MMU_UNRETRACT] +description: Helper to extruder filament to undo retract +gcode: + {% set sequence_vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set length = park_vars.retracted_length %} + {% set speed = sequence_vars.unretract_speed|int %} + + {% if printer.extruder.can_extrude %} + {% if length > 0 %} + MMU_LOG MSG="Un-retracting {length}mm" + M83 ; Extruder relative + G1 E{length} F{speed|abs * 60} + {% endif %} + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=retracted_length VALUE=0 + {% else %} + MMU_LOG MSG="Extruder is not hot enough to un-retract" DEBUG=1 + {% endif %} + + +########################################################################### +# Helper macro: clear previously saved position +# +[gcode_macro _MMU_CLEAR_POSITION] +description: Clear previously recorded toolhead position +gcode: + {% set reset = params.RESET|default(0)|int %} + + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=saved_pos VALUE={False} + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=next_pos VALUE={False} + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=toolchange_z VALUE=-1 + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=retracted_length VALUE=0 + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=park_operation VALUE=\"\" + {% if reset %} + # Reset rising floor used in sequential printing + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=min_lifted_z VALUE=0 + {% endif %} + MMU_LOG MSG="Clearing saved toolhead position{' and rising toolchange floor' if reset else ''}" DEBUG=1 + + +########################################################################### +# Helper macro: option to auto home toolhead +# +[gcode_macro _MMU_AUTO_HOME] +description: Convenience auto homing primarily for testing +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set auto_home = vars.auto_home|default(true)|lower == 'true' %} + + {% if auto_home and 'xyz' not in printer.toolhead.homed_axes %} + MMU_LOG MSG="Automatically homing XYZ before parking toolhead" + G28 + {% endif %} + + +########################################################################### +# Helper macro: record maximum toolhead height +# Designed to be called from slicer layer changed logic +# +[gcode_macro MMU_UPDATE_HEIGHT] +description: Record maximum toolhead height for z-hop base (call on layer change for sequential printing) +gcode: + {% set height = params.HEIGHT|default(0)|float %} + {% set park_vars = printer['gcode_macro _MMU_PARK'] %} + {% set max_z = [park_vars.min_lifted_z, printer.gcode_move.gcode_position.z, height]|max %} + + {% if max_z > park_vars.min_lifted_z %} + MMU_LOG MSG="Setting rising toolchange floor to {max_z}" DEBUG=1 + {% endif %} + SET_GCODE_VARIABLE MACRO=_MMU_PARK VARIABLE=min_lifted_z VALUE={max_z} + + +########################################################################### +# This occurs prior to unloading filament on a toolchange +# +[gcode_macro _MMU_PRE_UNLOAD] +description: Optional pre unload routine for filament change +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set x, y, z_hop = vars.pre_unload_position|default([-999,-999,0])|map('float') %} + + {% if x != -999 or y != -999 or z_hop > 0 %} + _MMU_PARK FORCE_PARK=1 X={x} Y={y} Z_HOP={z_hop} + {% endif %} + {vars.user_pre_unload_extension|default("")} + + +########################################################################### +# This occurs immediately after the tip forming or cutting procedure +# +[gcode_macro _MMU_POST_FORM_TIP] +description: Optional post tip forming/cutting routing +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set x, y, z_hop = vars.post_form_tip_position|default([-999,-999,0])|map('float') %} + + {% if x != -999 or y != -999 or z_hop > 0 %} + _MMU_PARK FORCE_PARK=1 X={x} Y={y} Z_HOP={z_hop} + {% endif %} + {vars.user_post_form_tip_extension|default("")} + + +########################################################################### +# This occurs immediately after unloading filament on a toolchange +# +[gcode_macro _MMU_POST_UNLOAD] +description: Optional post unload routine for filament change +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + + # This is a good place to inject logic to, for example, perform tip + # cutting when cutter is located at the MMU, thus prepping the unloaded + # filament for next use (e.g. EREC) + {vars.user_post_unload_extension|default("")} + + +########################################################################### +# This occurs prior to starting the load sequence on a toolchange +# +[gcode_macro _MMU_PRE_LOAD] +description: Optional pre load routine for filament change +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set x, y, z_hop = vars.pre_load_position|default([-999,-999,0])|map('float') %} + + {% if x != -999 or y != -999 or z_hop > 0 %} + _MMU_PARK FORCE_PARK=1 X={x} Y={y} Z_HOP={z_hop} + {% endif %} + {vars.user_pre_load_extension|default("")} + + +########################################################################### +# This occurs after loading new filament on a toolchange +# +[gcode_macro _MMU_POST_LOAD] +description: Optional post load routine for filament change +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {% set timelapse = vars.timelapse|default(false)|lower == 'true' %} + + {% if timelapse %} + TIMELAPSE_TAKE_FRAME + {% endif %} + + # A good place to implement custom purging logic and/or nozzle cleaning + # prior to returning to print/wipetower (e.g. Blobifier) + {vars.user_post_load_extension|default("")} + + +########################################################################### +# This is called when a MMU error occurs +# +[gcode_macro _MMU_ERROR] +description: Called when an MMU error occurs +gcode: + {% set vars = printer['gcode_macro _MMU_SEQUENCE_VARS'] %} + {vars.user_mmu_error_extension|default("")} + + +########################################################################### +# ADVANCED ADVANCED ADVANCED ADVANCED ADVANCED ADVANCED +# User modifiable loading and unloading sequences +# +# By default Happy Hare will call internal logic to handle loading and unloading +# sequences. To enable the calling of user defined sequences you must add the +# following to your mmu_parameters.cfg +# +# gcode_load_sequence: 1 # Gcode loading sequence 1=enabled, 0=internal logic (default) +# gcode_unload_sequence: 1 # Gcode unloading sequence, 1=enabled, 0=internal logic (default) +# +# This reference example load sequence mimicks the internal ones exactly. It uses the +# high level "modular" movements that are all controlled by parameters defined in +# mmu_parameters.cfg and automatically keep the internal filament position state up-to-date. +# Switching to these macros should not change behavior and can serve as a starting point for +# your customizations +# +# State Machine: +# If you experiment beyond the basic example shown here you will need to understand +# the possible states for filament position. This is the same state that is exposed +# as the `printer.mmu.filament_pos` printer variable. This internal state must be +# kept up-to-date and will need to be set directly as you progress through your +# custom move sequence. At this time the state machine is non-extensible. +# +# FILAMENT_POS_UNKNOWN = -1 +# L ^ FILAMENT_POS_UNLOADED = 0 +# O | FILAMENT_POS_HOMED_GATE = 1 # If gate sensor fitted +# A | FILAMENT_POS_START_BOWDEN = 2 +# D | FILAMENT_POS_IN_BOWDEN = 3 +# FILAMENT_POS_END_BOWDEN = 4 +# | U FILAMENT_POS_HOMED_ENTRY = 5 # If extruder (entry) sensor fitted +# | N FILAMENT_POS_HOMED_EXTRUDER = 6 +# | L FILAMENT_POS_PAST_EXTRUDER = 7 +# | O FILAMENT_POS_HOMED_TS = 8 # If toolhead sensor fitted +# | A FILAMENT_POS_IN_EXTRUDER = 9 # AKA Filament is past the Toolhead Sensor +# v D FILAMENT_POS_LOADED = 10 # AKA Filament is homed to the nozzle +# +# Final notes: +# 1) You need to respect the context being passed into the macro such as the +# desired 'length' to move because this can be called for test loading +# 2) The unload macro can be called with the filament in any position (states) +# You are required to handle any starting point. The default reference +# serves as a good guide +# +[gcode_macro _MMU_LOAD_SEQUENCE] +description: Called when MMU is asked to load filament +gcode: + {% set filament_pos = params.FILAMENT_POS|float %} + {% set length = params.LENGTH|float %} + {% set full = params.FULL|int %} + {% set home_extruder = params.HOME_EXTRUDER|int %} + {% set skip_extruder = params.SKIP_EXTRUDER|int %} + {% set extruder_only = params.EXTRUDER_ONLY|int %} + + {% if extruder_only %} + _MMU_STEP_LOAD_TOOLHEAD EXTRUDER_ONLY=1 + + {% elif filament_pos >= 7 %} # FILAMENT_POS_PAST_EXTRUDER + {action_raise_error("Can't load - already in extruder!")} + + {% else %} + {% if filament_pos <= 0 %} # FILAMENT_POS_UNLOADED + _MMU_STEP_LOAD_GATE + {% endif %} + + {% if filament_pos < 4 %} # FILAMENT_POS_END_BOWDEN + _MMU_STEP_LOAD_BOWDEN LENGTH={length} + {% endif %} + + {% if filament_pos < 6 and home_extruder %} # FILAMENT_POS_HOMED_EXTRUDER + _MMU_STEP_HOME_EXTRUDER + {% endif %} + + {% if not skip_extruder %} # FILAMENT_POS_PAST_EXTRUDER + _MMU_STEP_LOAD_TOOLHEAD + {% endif %} + + {% endif %} + +[gcode_macro _MMU_UNLOAD_SEQUENCE] +description: Called when MMU is asked to unload filament +gcode: + {% set filament_pos = params.FILAMENT_POS|float %} + {% set length = params.LENGTH|float %} + {% set extruder_only = params.EXTRUDER_ONLY|int %} + {% set park_pos = params.PARK_POS|float %} + + {% if extruder_only %} + {% if filament_pos >= 7 %} # FILAMENT_POS_PAST_EXTRUDER + _MMU_STEP_UNLOAD_TOOLHEAD EXTRUDER_ONLY=1 PARK_POS={park_pos} + {% else %} + {action_raise_error("Can't unload extruder - already unloaded!")} + {% endif %} + + {% elif filament_pos == 0 %} + {action_raise_error("Can't unload - already unloaded!")} + + {% else %} + {% if filament_pos >= 7 %} # FILAMENT_POS_PAST_EXTRUDER + # Exit extruder, fast unload of bowden, then slow unload encoder + _MMU_STEP_UNLOAD_TOOLHEAD PARK_POS={park_pos} + {% endif %} + + {% if filament_pos >= 4 %} # FILAMENT_POS_END_BOWDEN + # Fast unload of bowden, then slow unload encoder + _MMU_STEP_UNLOAD_BOWDEN FULL=1 + _MMU_STEP_UNLOAD_GATE + + {% elif filament_pos >= 2 %} # FILAMENT_POS_START_BOWDEN + # Have to do slow unload because we don't know exactly where in the bowden we are + _MMU_STEP_UNLOAD_GATE FULL=1 + {% endif %} + + {% endif %} + +# +# Some examples of alternative macros follow +# +# 1. This loading example leverages the built-in modules to load filament to the end +# of the bowden tube. Then homes the filament to the toolhead sensor (toolhead) +# using synchronized gear and extruder movement. The state is updated to reflect this +# new position. It then performs a synchronized stepper move of 62mm to advance the +# filament to the nozzle +# +#[gcode_macro _MMU_LOAD_SEQUENCE] +#description: Called when MMU is asked to load filament +#gcode: +# {% set filament_pos = params.FILAMENT_POS|float %} +# {% set length = params.LENGTH|float %} +# {% set skip_extruder = params.SKIP_EXTRUDER|int %} +# {% set extruder_only = params.EXTRUDER_ONLY|int %} +# +# {% if extruder_only %} +# _MMU_STEP_HOMING_MOVE ENDSTOP=toolhead MOVE=50 MOTOR=extruder +# _MMU_STEP_SET_FILAMENT STATE=8 # FILAMENT_POS_HOMED_TS +# _MMU_STEP_MOVE MOVE=62 MOTOR=extruder +# _MMU_STEP_SET_FILAMENT STATE=10 # FILAMENT_POS_LOADED +# {% else %} +# _MMU_STEP_LOAD_GATE +# _MMU_STEP_LOAD_BOWDEN LENGTH={length} +# {% if full and not skip_extruder %} +# _MMU_STEP_HOMING_MOVE ENDSTOP=toolhead MOVE=50 MOTOR=gear+extruder +# _MMU_STEP_SET_FILAMENT STATE=8 # FILAMENT_POS_HOMED_TS +# _MMU_STEP_MOVE MOVE=62 MOTOR=gear+extruder +# _MMU_STEP_SET_FILAMENT STATE=10 # FILAMENT_POS_LOADED +# {% endif %} +# {% endif %} +# +# +# 2. This very streamlined loading example starts off similarly loading to the end of the +# calibrated bowden. It then simply homes to the nozzle (using TMC stallguard on the extruder +# stepper!) with synchronized extruder+gear steppers. This requires the `mmu_ext_touch` +# endstop to be defined for the EXTRUDER stepper (this is possible with Happy Hare extension) +# +#[gcode_macro _MMU_LOAD_SEQUENCE] +#description: Called when MMU is asked to load filament +#gcode: +# {% set length = params.LENGTH|float %} +# {% set full = params.FULL|int %} +# {% set skip_extruder = params.SKIP_EXTRUDER|int %} +# {% set extruder_only = params.EXTRUDER_ONLY|int %} +# +# {% if extruder_only %} +# _MMU_STEP_HOMING_MOVE ENDSTOP=mmu_ext_touch MOVE=100 MOTOR=extruder +# _MMU_STEP_SET_FILAMENT STATE=10 # FILAMENT_POS_LOADED +# {% else %} +# _MMU_STEP_LOAD_GATE +# _MMU_STEP_LOAD_BOWDEN LENGTH={length} +# {% if full and not skip_extruder %} +# _MMU_STEP_HOMING_MOVE ENDSTOP=mmu_ext_touch MOVE=100 MOTOR=extruder+gear +# _MMU_STEP_SET_FILAMENT STATE=10 # FILAMENT_POS_LOADED +# {% endif %} +# {% endif %} + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_software.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_software.cfg new file mode 100644 index 00000000..98ecf345 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_software.cfg @@ -0,0 +1,567 @@ +######################################################################################################################## +# Happy Hare MMU Software +# Supporting macros +# +# THIS FILE IS READ ONLY +# +# Copyright (C) 2022-2026 moggieuk#6538 (discord) +# moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Miscellaneous supporting macros +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# + + +########################################################################### +# Convenience print start marco that users can call directly from their +# slicer's custom "start g-code" or call from existing start marco +# +# To call from slicer (recommended), add these lines to your custom start +# g-code (before and after the call to your regular print start macro). +# It is recommended to separate the filament purge portion of the start +# sequence until after the initial tool is loaded. +# +# Slicer: Custom Start g-code +# +----------------------------------------------------------+ +# | ; Initialize MMU and save info from gcode file | +# | MMU_START_SETUP INITIAL_TOOL={initial_tool} | +# | REFERENCED_TOOLS=!referenced_tools! | +# | TOOL_COLORS=!colors! | +# | TOOL_TEMPS=!temperatures! | +# | TOOL_MATERIALS=!materials! | +# | FILAMENT_NAMES=!filament_names! | +# | PURGE_VOLUMES=!purge_volumes! | +# | | +# | ; Check MMU is setup for the slicer defined print | +# | MMU_START_CHECK | +# | | +# | ; Bed leveling, heating logic, etc for print start | +# | ; (Nothing that requires filament in extruder) | +# | PRINT_START ; call you existing macro here.. | +# | | +# | ; Load slicer defined initial tool into MMU | +# | MMU_START_LOAD_INITIAL_TOOL | +# | | +# | ; Final purge logic before starting to print | +# | ..optionally call you purge logic start macro.. | +# +----------------------------------------------------------+ +# +# NOTE: The reason that it is recommended to add these 4 or 5 lines to your +# slicer is to keep them as separate gcode macros to enable the print to +# pause in the case of an error. If you bundle everything into a single +# print start macro then the first opportunity to pause will be at the end +# of that, potentially long running, macro! +# +# Alternatively you can pass in the params to your existing print start +# macro and then insert these calls in that macro (but not recommended +# because of pause warning above) +# +# MMU_START_SETUP {rawparams} +# MMU_START_CHECK +# MMU_START_LOAD_INITIAL_TOOL +# +[gcode_macro MMU_START_SETUP] +description: Called when starting print to setup MMU +gcode: + {% set initial_tool = params.INITIAL_TOOL|default(0)|int %} + {% set total_toolchanges = params.TOTAL_TOOLCHANGES|default(0)|int %} + {% set ttg_map = printer.mmu.ttg_map %} + {% set gate_fil_names = printer.mmu.gate_filament_name %} + {% set gate_colors = printer.mmu.gate_color %} + {% set num_gates = ttg_map|length %} + {% set referenced_tools = (params.REFERENCED_TOOLS|default("!referenced_tools!")|string).split(",") + if (params.REFERENCED_TOOLS and params.REFERENCED_TOOLS != "") + else [] %} + {% set tool_colors = (params.TOOL_COLORS|default("")|string).split(",") + if (params.TOOL_COLORS and params.TOOL_COLORS != "!colors!" and params.TOOL_COLORS != "") + else ['000000'] * num_gates %} + {% set tool_temps = (params.TOOL_TEMPS|default("")|string).split(",") + if (params.TOOL_TEMPS and params.TOOL_TEMPS != "!temperatures!" and params.TOOL_TEMPS != "") + else ['0'] * num_gates %} + {% set tool_materials = (params.TOOL_MATERIALS|default("")|string).split(",") + if (params.TOOL_MATERIALS and params.TOOL_MATERIALS != "!materials!" and params.TOOL_MATERIALS != "") + else ['unknown'] * num_gates %} + {% set filament_names = (params.FILAMENT_NAMES|default("")|string).split(",") + if (params.FILAMENT_NAMES and params.FILAMENT_NAMES != "!filament_names!" and params.FILAMENT_NAMES != "") + else [''] * num_gates %} + {% set purge_volumes = (params.PURGE_VOLUMES|default("")|string) + if (params.PURGE_VOLUMES and params.PURGE_VOLUMES != "!purge_volumes!" and params.PURGE_VOLUMES != "") + else "" %} + + {% set vars = printer['gcode_macro _MMU_SOFTWARE_VARS'] %} + {% set home_mmu = vars.home_mmu|lower == 'true' %} + + {% set filament_loaded = printer.mmu.filament_pos == 10 %} + {% set using_bypass = printer.mmu.tool == -2 %} + {% set num_colors = referenced_tools|length %} + + {% if printer.mmu.enabled %} + # Bookend for start of MMU print job. Initializes MMU print state + # Necessary when printing from Octoprint (but harmless if printing from virtual SD card) + MMU_PRINT_START + + # Typically this would be something like a G28 to ensure homing in case of pause + {% if not vars.user_pre_initialize_extension == "" %} + {vars.user_pre_initialize_extension} + {% endif %} + + # Establish number of colors in print and tools being used + {% if referenced_tools == ['!referenced_tools!'] %} + MMU_LOG MSG="Happy Hare gcode pre-processor is probably disabled or not setup correctly" + {% set referenced_tools = [] %} + {% set num_colors = -1 %} + {% elif referenced_tools == [] %} + {% set num_colors = 1 %} + {% endif %} + + # Sanity check the parsed information + {% set num_slicer_tools = tool_colors|length %} + {% if not using_bypass %} + {% if tool_colors|length != tool_temps|length or tool_colors|length != tool_materials|length or tool_colors|length != filament_names|length %} + MMU_LOG MSG="Warning: Slicer defined extruder attributes have different lengths. Possibly an issue with parsing slicer information or missing parameters to MMU_START_SETUP" + MMU_LOG MSG=" TOOL_COLORS={tool_colors}" + MMU_LOG MSG=" TOOL_TEMPS={tool_temps}" + MMU_LOG MSG=" TOOL_MATERIALS={tool_materials}" + MMU_LOG MSG=" FILAMENT_NAMES={filament_names}" + {% endif %} + {% if tool_colors|length != num_gates or tool_temps|length != num_gates or tool_materials|length != num_gates or filament_names|length != num_gates %} + {% if vars.automap_strategy != 'none' %} + MMU_LOG MSG="Warning: Looks like slicer is setup with {num_slicer_tools} extruders but your MMU has {num_gates} gates! Probably using auto-map feature." + {% else %} + MMU_LOG MSG="Warning: Looks like slicer is setup with {num_slicer_tools} extruders but your MMU has {num_gates} gates! These should match but will attempt to continue" + {% endif %} + {% endif %} + {% endif %} + + # Setup slicer tool map + MMU_SLICER_TOOL_MAP RESET=1 PURGE_VOLUMES={purge_volumes} NUM_SLICER_TOOLS={num_slicer_tools} INITIAL_TOOL={initial_tool} TOTAL_TOOLCHANGES={total_toolchanges} + {% if using_bypass %} + MMU_SLICER_TOOL_MAP SKIP_AUTOMAP=1 + {% endif %} + {% for t in range(num_slicer_tools) %} + MMU_SLICER_TOOL_MAP TOOL={t} TEMP={tool_temps[t]} MATERIAL='{tool_materials[t]}' COLOR={tool_colors[t]} NAME='{filament_names[t]}' {"USED=0" if t|string not in referenced_tools and t != initial_tool else ""} QUIET=1 AUTOMAP={vars.automap_strategy} + {% endfor %} + + # Build message in case of error + {% set custom_msg = [] %} + {% set m = [] %} + {% for tool in referenced_tools %} + {% set _ = m.append("T" + tool|string + " (Gate" + ttg_map[tool|int]|string + ")") %} + {% endfor %} + {% set line = "Initial Tool: T%s" % initial_tool %} + {% set _ = m.append(line) %} + {% set _ = custom_msg.append("Print requires tools: %s" % ", ".join(m)) %} + {% set _ = custom_msg.append("Manually ensure that T" + initial_tool|string + " is loaded and all other tools available before resuming print") %} + + # Display map summary + {% if num_colors > 1 %} + MMU_SLICER_TOOL_MAP SPARSE_PURGE_MAP=1 NUM_SLICER_TOOLS={num_slicer_tools} + {% else %} + MMU_SLICER_TOOL_MAP + {% endif %} + + SET_GCODE_VARIABLE MACRO=_MMU_ERROR_DIALOG VARIABLE=show_abort VALUE={True} # Show abort option during startup + {% if using_bypass and filament_loaded %} + MMU_LOG MSG="MMU Bypass selected and loaded" + {% if num_colors > 1 %} + SET_GCODE_VARIABLE MACRO=_MMU_ERROR_DIALOG VARIABLE=custom_msg VALUE="{custom_msg}" + MMU_PAUSE MSG="Bypass selected for multi-color print" + {% endif %} + {% else %} + # Preemptively set verbose dialog message in case of additional mmu error during start + SET_GCODE_VARIABLE MACRO=_MMU_ERROR_DIALOG VARIABLE=custom_msg VALUE="{custom_msg}" + {% if home_mmu %} + {% if not filament_loaded %} + MMU_HOME TOOL={initial_tool} + {% else %} + MMU_LOG MSG="Skipping homing MMU because filament is already loaded" + {% endif %} + {% endif %} + {% endif %} + {% endif %} + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_start_setup_run VALUE={True} + + +########################################################################### +# Helper macro to check required gates have filament. This is separated out +# from main setup macro to allow for pausing on previous error first +# +[gcode_macro MMU_START_CHECK] +description: Helper macro. Can be called to perform pre-start checks on MMU based on slicer requirements +gcode: + {% set vars = printer['gcode_macro _MMU_SOFTWARE_VARS'] %} + {% set check_gates = vars.check_gates|lower == 'true' %} + {% set using_bypass = printer.mmu.tool == -2 %} + + {% if printer.mmu.enabled %} + {% set slicer_tool_map = printer.mmu.slicer_tool_map %} + {% set initial_tool = slicer_tool_map.initial_tool %} + {% set tools = slicer_tool_map.referenced_tools %} + {% if not using_bypass %} + # Future: Could do extra checks like filament material type/color checking here + # to ensure what's loaded on MMU matches the slicer expectations + {% if check_gates and tools|length > 0 %} + # Pre-check gates option if multi-color print. Will pause if tools missing + MMU_LOG MSG="Checking all required gates have filament loaded..." + {% if not printer.mmu.is_homed %} + MMU_HOME + {% endif %} + MMU_CHECK_GATE TOOLS={tools|join(",")} + {% endif %} + {% endif %} + {% endif %} + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_start_check_run VALUE={True} + + +########################################################################### +# Helper macro to load the initial tool. This is separated out from main +# setup macro to allow for pausing on previous error first +# +[gcode_macro MMU_START_LOAD_INITIAL_TOOL] +description: Helper to load initial tool if not paused +gcode: + {% set vars = printer['gcode_macro _MMU_SOFTWARE_VARS'] %} + {% set load_initial_tool = vars.load_initial_tool|lower == 'true' %} + {% set using_bypass = printer.mmu.tool == -2 %} + {% set filament_loaded = printer.mmu.filament_pos == 10 %} + {% set slicer_tool_map = printer.mmu.slicer_tool_map %} + {% set initial_tool = slicer_tool_map.initial_tool %} + {% set tools = slicer_tool_map.referenced_tools %} + + {% if printer.mmu.enabled %} + {% if not using_bypass and tools|length > 0 %} + {% if load_initial_tool and (initial_tool is not none and initial_tool >= 0) %} + MMU_LOG MSG="Loading initial tool T{initial_tool}..." + MMU_CHANGE_TOOL STANDALONE=1 RESTORE=0 TOOL={initial_tool} + {% endif %} + {% elif not filament_loaded %} + MMU_PAUSE MSG="Load bypass or initial tool before resuming print" + {% else %} + MMU_LOG MSG="Using bypass" + {% endif %} + {% endif %} + + # Important: Clear preemptive error message and remove abort option from pause dialog + SET_GCODE_VARIABLE MACRO=_MMU_ERROR_DIALOG VARIABLE=custom_msg VALUE='""' + SET_GCODE_VARIABLE MACRO=_MMU_ERROR_DIALOG VARIABLE=show_abort VALUE={False} + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_start_load_initial_tool_run VALUE={True} + + +########################################################################### +# Convenience print end marco that users can call directly from their +# slicer's custom "end g-code" or call from existing end marco +# +# To call from slicer, add this to custom end g-code (possibly as one line +# just after the call to your regular print end macro) or call directly from +# without your existing print end macro: +# +# Slicer: Custom End g-code +# +----------------------------------------------------------+ +# | ; Finalize MMU and optionally park and unload filament | +# | MMU_END | +# | | +# | ; Your existing print end macro | +# | PRINT_END | +# +----------------------------------------------------------+ +# +[gcode_macro MMU_END] +description: Called when ending print to finalize MMU +gcode: + {% set unload = params.UNLOAD|default(0)|int %} + {% set vars = printer['gcode_macro _MMU_SOFTWARE_VARS'] %} + {% set unload_tool = vars.unload_tool|lower == 'true' %} + {% set reset_ttg = vars.reset_ttg|lower == 'true' %} + {% set dump_stats = vars.dump_stats|lower == 'true' %} + {% set slicer_tool_map = printer.mmu.slicer_tool_map %} + {% set tools = slicer_tool_map.referenced_tools %} + {% set using_bypass = printer.mmu.tool == -2 %} + + {% if printer.mmu.enabled %} + {% if not vars.user_print_end_extension == "" %} + {vars.user_print_end_extension} + {% endif %} + + {% if unload or unload_tool %} + MMU_LOG MSG="Unloading filament on print end" + MMU_UNLOAD RESTORE=0 + {% endif %} + + {% if reset_ttg %} + MMU_TTG_MAP RESET=1 QUIET=1 + {% endif %} + + {% if dump_stats and not using_bypass and tools|length > 0 %} + MMU_STATS + {% endif %} + + # Bookend for end of MMU print job. Finalizes MMU state + MMU_PRINT_END STATE=complete + {% endif %} + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_end_run VALUE={True} + + +########################################################################### +# Helper macro that will walk the user through a cold-pull +# +# Assumes the bowden tube is removed from the toolhead and the extruder +# is loaded with about a 300mm piece of filament. The user should have access +# to the filament to assist pull when asked +# +# Params: +# MATERIAL=nylon|pla|abs|petg Starting temp defaults +# HOT_TEMP Initial high temp +# COLD_TEMP Temp to cool too to help release filament +# MIN_EXTRUDE_TEMP Temp to which the extruder will keep nozzle pressurized +# PULL_TEMP Temp to perform the cold pull +# PULL_SPEED Speed in mm/s of extruder movement to help manual pull +# CLEAN_LENGTH Amount of filament to extrude to prime extruder/nozzle +# EXTRUDE_SPEED Speed in mm/s to perform extrude operations +# +[gcode_macro MMU_COLD_PULL] +description: Guide you through the process of cleaning your extruder with a cold pull +gcode: + {% set material = params.MATERIAL|default("pla")|string|upper %} + {% set materials = { + 'NYLON': {'hot_temp': 260, 'cold_temp': 50, 'pull_temp': 120, 'min_extrude_temp': 190}, + 'PLA': {'hot_temp': 250, 'cold_temp': 45, 'pull_temp': 100, 'min_extrude_temp': 160}, + 'ABS': {'hot_temp': 255, 'cold_temp': 50, 'pull_temp': 120, 'min_extrude_temp': 190}, + 'PETG': {'hot_temp': 250, 'cold_temp': 45, 'pull_temp': 100, 'min_extrude_temp': 180} + } %} + {% if material not in materials %} + {action_raise_error("Unknown material. Valid types are: Nylon, ABS, PLA, PETG")} + {% endif %} + + # Allow individual temperature overrides. Coded like this so Mainsail can parse options + {% set hot_temp = params.HOT_TEMP|default('')|int %} + {% set cold_temp = params.COLD_TEMP|default('')|int %} + {% set pull_temp = params.PULL_TEMP|default('')|int %} + {% set min_extrude_temp = params.MIN_EXTRUDE_TEMP|default('')|int %} + {% set hot_temp = (hot_temp if hot_temp > 0 else materials.get(material).hot_temp)|int %} + {% set cold_temp = (cold_temp if cold_temp > 0 else materials.get(material).cold_temp)|int %} + {% set pull_temp = (pull_temp if pull_temp > 0 else materials.get(material).pull_temp)|int %} + {% set min_extrude_temp = (min_extrude_temp if min_extrude_temp > 0 else materials.get(material).min_extrude_temp)|int %} + + {% set pull_speed = params.PULL_SPEED|default(10)|int %} + {% set clean_length = params.CLEAN_LENGTH|default(25)|int %} + {% set extrude_speed = params.EXTRUDE_SPEED|default(1.5)|float %} + + {% set ns = namespace(stuff_points=[], cool_points=[]) %} + + {% for temp in range(hot_temp + 1, cold_temp - 1, -1) %} + {% if temp % 10 == 0 %} + {% if temp > min_extrude_temp %} + {% set ns.stuff_points = ns.stuff_points + [temp] %} + {% elif temp < min_extrude_temp %} + {% set ns.cool_points = ns.cool_points + [temp] %} + {% endif %} + {% endif %} + {% endfor %} + + MMU_LOG MSG='{"Cold Pull based on %s profile (use MATERIAL= to adjust):" % material}' + MMU_LOG MSG='{"pull_temp=%d\u00B0C, hot_temp=%d\u00B0C, min_extruder=%d\u00B0C, cold_temp=%d\u00B0C" % (pull_temp, hot_temp, min_extrude_temp, cold_temp)}' + + MMU_LOG MSG='{"Heating extruder to %d\u00B0C..." % hot_temp}' + SET_HEATER_TEMPERATURE HEATER="extruder" TARGET={hot_temp} + TEMPERATURE_WAIT SENSOR="extruder" MINIMUM={hot_temp - 2} MAXIMUM={hot_temp + 2} + + # Ensure the nozzle id completely full + MMU_LOG MSG="Cleaning nozzle tip with {clean_length}mm of filament" + _MMU_STEP_MOVE MOTOR="extruder" MOVE={clean_length} SPEED={extrude_speed} ALLOW_BYPASS=1 + + # Begin the cooling ramp + MMU_LOG MSG="Allowing extruder to cool..." + SET_HEATER_TEMPERATURE HEATER="extruder" TARGET={cold_temp} + M106 S255 # 100% part fan to cool faster + + # While filament can still extrude keep the nozzle completely full + {% for temp in ns.stuff_points %} + TEMPERATURE_WAIT SENSOR="extruder" MAXIMUM={temp} + MMU_LOG MSG='{"> Stuffing nozzle at %d\u00B0C" % temp}' + _MMU_STEP_MOVE MOTOR="extruder" MOVE=1 SPEED={extrude_speed} ALLOW_BYPASS=1 + {% endfor %} + + # Give some feedback on cooling process + MMU_LOG MSG='{"Waiting for extruder to completely cool to %d\u00B0C..." % cold_temp}' + {% for temp in ns.cool_points %} + TEMPERATURE_WAIT SENSOR="extruder" MAXIMUM={temp} + MMU_LOG MSG='{"> Nozzle at %d\u00B0C" % temp}' + {% endfor %} + TEMPERATURE_WAIT SENSOR="extruder" MAXIMUM={cold_temp} + + # Re-warm + M107 # Part fan off + MMU_LOG MSG='{"Re-warming extruder to %d\u00B0C" % pull_temp}' + SET_HEATER_TEMPERATURE HEATER="extruder" TARGET={pull_temp} + + # The manual cold-pull + TEMPERATURE_WAIT SENSOR="extruder" MINIMUM={pull_temp - 10} + MMU_LOG MSG="Get ready to pull..." + TEMPERATURE_WAIT SENSOR="extruder" MINIMUM={pull_temp} + MMU_LOG MSG=">>>>> PULL NOW <<<<<" + + # Retract 150 mm at moderate speed (user should assist pull too, especially in bypass)) + _MMU_STEP_MOVE MOTOR="extruder" MOVE=-150 SPEED={pull_speed} ALLOW_BYPASS=1 + + MMU_LOG MSG="Cold pull is successful if you can see the shape of the nozzle at the filament end" + MMU_LOG MSG="If not, try again, perhaps with tweaked temperatures" + + # Heater completely off + SET_HEATER_TEMPERATURE HEATER="extruder" + + +########################################################################### +# Helper macros to display dialog in supporting UIs when MMU pauses +# +[gcode_macro _MMU_ERROR_DIALOG] +description: Helper to display pause dialog +variable_custom_msg: '' # List of additional custom message lines to append in dialog +variable_show_abort: False +gcode: + {% set message = params.MSG|string %} + {% set reason = params.REASON|string %} + RESPOND TYPE=command MSG="action:prompt_begin Happy Hare Error Notice" + RESPOND TYPE=command MSG='{"action:prompt_text %s" % message}' + RESPOND TYPE=command MSG='{"action:prompt_text Reason: %s" % reason}' + {% if not custom_msg == "" %} + {% for line in custom_msg %} + RESPOND TYPE=command MSG='{"action:prompt_text %s" % line}' + {% endfor %} + {% else %} + RESPOND TYPE=command MSG="action:prompt_text After fixing, call RESUME to continue printing (MMU_UNLOCK to restore temperature)" + {% endif %} + RESPOND TYPE=command MSG="action:prompt_button_group_start" + {% if show_abort %} + RESPOND TYPE=command MSG="action:prompt_button ABORT|CANCEL_PRINT|error" + {% endif %} + RESPOND TYPE=command MSG="action:prompt_button UNLOCK|MMU_UNLOCK|secondary" + RESPOND TYPE=command MSG="action:prompt_button RESUME|RESUME|warning" + RESPOND TYPE=command MSG="action:prompt_button_group_end" + RESPOND TYPE=command MSG="action:prompt_show" + {% set custom_msg = "" %} + + +########################################################################### +# Helper for Klippain to reset start/end step "run" trackers +# +[gcode_macro _MMU_RUN_MARKERS] +variable_mmu_start_setup_run: False +variable_mmu_start_check_run: False +variable_mmu_start_load_initial_tool_run: False +variable_mmu_end_run: False +gcode: + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_start_setup_run VALUE=False + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_start_check_run VALUE=False + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_start_load_initial_tool_run VALUE=False + SET_GCODE_VARIABLE MACRO=_MMU_RUN_MARKERS VARIABLE=mmu_end_run VALUE=False + + +########################################################################### +# Simplified subset of commands just for macro visibility in +# Mainsail/Fluidd UI (until custom HH panel is complete!) +# The __ is a trick because it is not displayed by the UI but allows for +# similar names to the real commands defined by the klipper module +# +[gcode_macro MMU__UNLOAD] +gcode: MMU_UNLOAD + +[gcode_macro MMU__EJECT] +gcode: MMU_EJECT + +[gcode_macro MMU__HOME] +gcode: + {% set tool = params.TOOL|default(0)|int %} + {% set force_unload = params.FORCE_UNLOAD|default(0)|int %} + MMU_HOME TOOL={tool} FORCE_UNLOAD={force_unload} + +[gcode_macro MMU__STATUS] +gcode: MMU_STATUS + +[gcode_macro MMU__MOTORS_OFF] +gcode: MMU_MOTORS_OFF + +[gcode_macro MMU__SERVO] +gcode: + {% set pos = params.POS|default("up")|string %} + MMU_SERVO POS={pos} + +[gcode_macro MMU__SELECT_TOOL] +gcode: + {% set tool = params.TOOL|default(0)|int %} + MMU_SELECT TOOL={tool} + +[gcode_macro MMU__SELECT_BYPASS] +gcode: MMU_SELECT_BYPASS + +[gcode_macro MMU__LOAD_BYPASS] +gcode: MMU_LOAD + +[gcode_macro MMU__RECOVER] +gcode: MMU_RECOVER + +[gcode_macro MMU__PRELOAD] +gcode: + MMU_PRELOAD {rawparams} + +[gcode_macro MMU__CHECK_GATE] +gcode: + {% set gate = params.GATE|default(-1)|int %} + {% set tool = params.GATE|default(-1)|int %} + {% set gates = params.GATE|default('!')|string %} + {% set tools = params.GATE|default('!')|string %} + MMU_CHECK_GATE GATE={gate} TOOL={tool} GATES={gates} TOOLS={tools} + + +########################################################################### +# Macro to query filament pressure sensor (proportional sync sensor) state +# +[gcode_macro MMU_QUERY_PSENSOR] +description: "Show raw and scaled readings for proportional (sync_feedback_analog_*) sensor" +variable_sensor: "filament_proportional" +gcode: + {% set name = params.SENSOR|default(sensor) %} + {% set obj = printer[name] %} + M118 PSENSOR Enabled: {obj.enabled} Value: {obj.value|float|round(3)} Raw Value: {obj.value_raw|float|round(3)} + + +########################################################################### +# Aliases (for backward compatibility) of previously well used commands... +# +[gcode_macro MMU_CHANGE_TOOL_STANDALONE] +description: Convenience macro for inclusion in print_start for initial tool load +gcode: + MMU_CHANGE_TOOL {rawparams} STANDALONE=1 + +[gcode_macro MMU_CHECK_GATES] +description: Alias for updated macro name of MMU_CHECK_GATE +gcode: + MMU_CHECK_GATE ALL=1 + +[gcode_macro MMU_REMAP_TTG] +description: Alias for updated macro name of MMU_TTG_MAP +gcode: + MMU_TTG_MAP {rawparams} + +[gcode_macro MMU_FORM_TIP] +description: Alias for updated macro name of MMU_TEST_FORM_TIP +gcode: + MMU_TEST_FORM_TIP {rawparams} + +# Underscore was removed from these to indicate user can call +[gcode_macro _MMU_PRINT_START] +description: Alias for updated macro name of MMU_PRINT_START +gcode: + MMU_PRINT_START {rawparams} + +[gcode_macro _MMU_PRINT_END] +description: Alias for updated macro name of MMU_PRINT_END +gcode: + MMU_PRINT_END {rawparams} + +[gcode_macro _MMU_UPDATE_HEIGHT] +description: Alias for updated macro name of MMU_UPDATE_HEIGHT +gcode: + MMU_UPDATE_HEIGHT {rawparams} diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_state.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_state.cfg new file mode 100644 index 00000000..902192d1 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_state.cfg @@ -0,0 +1,124 @@ +######################################################################################################################## +# Happy Hare MMU Software +# Supporting macros +# +# THIS FILE IS READ ONLY +# +# Copyright (C) 2022-2026 moggieuk#6538 (discord) +# moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Callouts for Happy Hare state changes +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# + + +########################################################################### +# Called when when the MMU action status changes +# +# The `ACTION` parameter will contain the current action string +# (also available in `printer.mmu.action` printer variable). +# Also the previous action is available in `OLD_ACTION`. +# +# See Happy Hare README for full list of action strings, but a quick ref is: +# +# Idle|Loading|Unloading|Loading Ext|Exiting Ext|Heating|Checking|Homing|Selecting +# Forming Tip|Cutting Tip|Cutting Filament|Purging +# +[gcode_macro _MMU_ACTION_CHANGED] +description: Called when an action has changed +gcode: + {% set vars = printer['gcode_macro _MMU_STATE_VARS'] %} + {% set action = params.ACTION|string %} + {% set old_action = params.OLD_ACTION|string %} + + {% if not vars.user_action_changed_extension == "" %} + {vars.user_action_changed_extension} {rawparams} + {% endif %} + + +########################################################################### +# Called when the MMU print state changes +# +# The `STATE` parameter will contain the current state string +# (also available in `printer.mmu.print_state` printer variable) +# Also the previous action is available in `OLD_STATE`. +# +# See Happy Hare README for full list of state strings and the state transition +# diagram, but a quick ref is: +# +# initialized|ready|started|printing|complete|cancelled|error|pause_locked|paused|standby +# +[gcode_macro _MMU_PRINT_STATE_CHANGED] +description: Called when print state changes +gcode: + {% set vars = printer['gcode_macro _MMU_STATE_VARS'] %} + {% set state = params.STATE|string %} + {% set old_state = params.OLD_STATE|string %} + + {% if not vars.user_print_state_changed_extension == "" %} + {vars.user_print_state_changed_extension} {rawparams} + {% endif %} + + +########################################################################### +# Called when an atomic event occurs. Different from ACTION_CHANGE because +# these are not necessarily part of any important state change but rather +# informational +# +# The `EVENT` parameter will contain the event name. Other parameters +# depend on the event type +# +# See Happy Hare README for full list of event strings, but a quick ref is: +# +# Events: +# "restart" Called when Happy Hare starts / restarts +# Parameters: None +# +# "gate_map_changed" Called when the MMU gate_map (containing information +# about the filament type, color, availability and +# spoolId) is updated +# Parameters: GATE The gate that is updated or -1 if all updated +# +# "filament_gripped" Called when MMU servo (if fitted) grips filament +# Parameters: None +# +# "filament_cut" Called when filament is cut +# Parameters: None +# +[gcode_macro _MMU_EVENT] +description: Called when certain MMU actions occur +gcode: + {% set vars = printer['gcode_macro _MMU_STATE_VARS'] %} + {% set servo_down_limit = vars.servo_down_limit|default(-1)|int %} + {% set cutter_blade_limit = vars.cutter_blade_limit|default(-1)|int %} + {% set event = params.EVENT|string %} + + {% if event == "restart" %} + MMU_STATS COUNTER=mmu_restarts INCR=1 + + {% set vendor = printer.configfile.config.mmu_machine.mmu_vendor|string|lower %} + {% set version = printer.configfile.config.mmu_machine.mmu_version|string|lower %} + {% if vendor == "ercf" %} + MMU_STATS COUNTER=servo_down LIMIT={servo_down_limit} WARNING="Inspect servo arm for wear/damage" + MMU_STATS COUNTER=cutter_blade LIMIT={cutter_blade_limit} WARNING="Inspect/replace filament cutting blade" + {% elif vendor == "tradrack" %} + MMU_STATS COUNTER=servo_down LIMIT={servo_down_limit} WARNING="Inspect servo mechanism for wear/damage" + MMU_STATS COUNTER=cutter_blade LIMIT={cutter_blade_limit} WARNING="Inspect/replace filament cutting blade" + {% endif %} + + {% elif event == "gate_map_changed" %} + ; + {% elif event == "filament_gripped" %} + MMU_STATS COUNTER=servo_down INCR=1 + {% elif event == "filament_cut" %} + MMU_STATS COUNTER=cutter_blade INCR=1 + {% endif %} + + {% if not vars.user_mmu_event_extension == "" %} + {vars.user_mmu_event_extension} {rawparams} + {% endif %} + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/mmu_vars.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/mmu_vars.cfg new file mode 100644 index 00000000..0bd436a1 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/mmu_vars.cfg @@ -0,0 +1,8 @@ +# This is the template file for storing Happy Hare state and calibration variables. It is pointed to +# with the [save_variables] block in 'mmu_macro_vars.cfg' +# +# If you want to use an existing "variables" file, then that is fine but make sure you copy the +# "mmu__revision" line to it because Happy Hare will look for this to validate correct setup +# +[Variables] +mmu__revision = 0 diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/client_macros.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/client_macros.cfg new file mode 100644 index 00000000..909a4641 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/client_macros.cfg @@ -0,0 +1,132 @@ +######################################################################################################################## +# Happy Hare MMU Software +# Supporting macros +# +# THIS FILE IS READ ONLY +# +# Copyright (C) 2022-2026 moggieuk#6538 (discord) +# moggieuk@hotmail.com +# +# Portions integrated from mainsail.cfg +# Copyright (C) 2022 Alex Zellner +# +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Complimentary and functional "client" macros that work with MMU enabled or disabled +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +# These are the recommended PAUSE/RESUME/CANCEL_PRINT macros for use with +# Happy Hare that use the parking logic defined in 'mmu_sequence.cfg' and are +# centrally configured in 'mmu_macro_vars.cfg' +# +# (Technically you can also use your own set but you will likely need to +# modify configuration to avoid double retraction, etc) +# +[gcode_macro PAUSE] +rename_existing: BASE_PAUSE +description: Pause the print and park +gcode: + {% set vars = printer['gcode_macro _MMU_CLIENT_VARS'] %} + + {% if printer.pause_resume.is_paused %} + MMU_LOG MSG="Print is already paused" + {% else %} + _MMU_SAVE_POSITION + BASE_PAUSE + {% if not printer.mmu.enabled %} + _MMU_PARK OPERATION="pause" + {% endif %} + {vars.user_pause_extension|default("")} + {% endif %} + +[gcode_macro RESUME] +rename_existing: BASE_RESUME +description: Resume the print +gcode: + {% set vars = printer['gcode_macro _MMU_CLIENT_VARS'] %} + + {% if not printer.pause_resume.is_paused %} + MMU_LOG MSG="Print is not paused. Resume ignored" + {% else %} + {vars.user_resume_extension|default("")} + {% if not printer.mmu.enabled %} + _MMU_RESTORE_POSITION # This will take the correct "over and down" movement path and unretract + {% endif %} + BASE_RESUME + {% endif %} + +[gcode_macro CANCEL_PRINT] +rename_existing: BASE_CANCEL_PRINT +description: Cancel print +gcode: + {% set vars = printer['gcode_macro _MMU_CLIENT_VARS'] %} + {% set reset_ttg_on_cancel = vars.reset_ttg_on_cancel|default('true')|lower == 'true' %} + {% set unload_tool_on_cancel = vars.unload_tool_on_cancel|default('false')|lower == 'true' %} + + MMU_LOG MSG="Print cancelled!" + {% if not printer.mmu.enabled %} + _MMU_PARK OPERATION="cancel" + {% else %} + {% if unload_tool_on_cancel %} + MMU_LOG MSG="Ejecting filament on print cancel" + MMU_UNLOAD RESTORE=0 + {% endif %} + {% if reset_ttg_on_cancel %} + MMU_TTG_MAP RESET=1 QUIET=1 + {% endif %} + {% endif %} + _MMU_CLEAR_POSITION + TURN_OFF_HEATERS + M107 ; Fan off + SET_PAUSE_NEXT_LAYER ENABLE=0 + SET_PAUSE_AT_LAYER ENABLE=0 LAYER=0 + {vars.user_cancel_extension|default("")} + BASE_CANCEL_PRINT + + +# The following macros are copied from the Mainsail client macros (mainsail.cfg) +# They are integrated here to add the extra functionality into the Happy Hare +# client_macros whilst still retaining centralized and consistent parking logic +# +# Copyright (C) 2022 Alex Zellner + +# Usage: SET_PAUSE_NEXT_LAYER [ENABLE=[0|1]] [MACRO=] +[gcode_macro SET_PAUSE_NEXT_LAYER] +description: Enable a pause if the next layer is reached +gcode: + {% set pause_next_layer = printer['gcode_macro SET_PRINT_STATS_INFO'].pause_next_layer %} + {% set ENABLE = params.ENABLE|default(1)|int != 0 %} + {% set MACRO = params.MACRO|default(pause_next_layer.call, True) %} + SET_GCODE_VARIABLE MACRO=SET_PRINT_STATS_INFO VARIABLE=pause_next_layer VALUE="{{ 'enable': ENABLE, 'call': MACRO }}" + +# Usage: SET_PAUSE_AT_LAYER [ENABLE=[0|1]] [LAYER=] [MACRO=] +[gcode_macro SET_PAUSE_AT_LAYER] +description: Enable/disable a pause if a given layer number is reached +gcode: + {% set pause_at_layer = printer['gcode_macro SET_PRINT_STATS_INFO'].pause_at_layer %} + {% set ENABLE = params.ENABLE|int != 0 if params.ENABLE is defined else params.LAYER is defined %} + {% set LAYER = params.LAYER|default(pause_at_layer.layer)|int %} + {% set MACRO = params.MACRO|default(pause_at_layer.call, True) %} + SET_GCODE_VARIABLE MACRO=SET_PRINT_STATS_INFO VARIABLE=pause_at_layer VALUE="{{ 'enable': ENABLE, 'layer': LAYER, 'call': MACRO }}" + +# Usage: SET_PRINT_STATS_INFO [TOTAL_LAYER=] [CURRENT_LAYER=] +[gcode_macro SET_PRINT_STATS_INFO] +rename_existing: SET_PRINT_STATS_INFO_BASE +description: Overwrite, to get pause_next_layer and pause_at_layer feature +variable_pause_next_layer: { 'enable': False, 'call': "PAUSE" } +variable_pause_at_layer : { 'enable': False, 'layer': 0, 'call': "PAUSE" } +gcode: + {% if pause_next_layer.enable %} + MMU_LOG MSG='{"%s, forced by pause_next_layer" % pause_next_layer.call}' + {pause_next_layer.call} ; execute the given gcode to pause, should be either M600 or PAUSE + SET_PAUSE_NEXT_LAYER ENABLE=0 + {% elif pause_at_layer.enable and params.CURRENT_LAYER is defined and params.CURRENT_LAYER|int == pause_at_layer.layer %} + MMU_LOG MSG='{"%s, forced by pause_at_layer [%d]" % (pause_at_layer.call, pause_at_layer.layer)}' + {pause_at_layer.call} ; execute the given gcode to pause, should be either M600 or PAUSE + SET_PAUSE_AT_LAYER ENABLE=0 + {% endif %} + SET_PRINT_STATS_INFO_BASE {rawparams} diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/mmu_menu.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/mmu_menu.cfg new file mode 100644 index 00000000..2c97f54a --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/optional/mmu_menu.cfg @@ -0,0 +1,146 @@ +######################################################################################################################## +# Happy Hare MMU Software +# Supporting macros +# +# THIS FILE IS READ ONLY +# +# Copyright (C) 2022 moggieuk#6538 (discord) moggieuk@hotmail.com +# This file may be distributed under the terms of the GNU GPLv3 license. +# +# Goal: Happy Hare MMU MENU designed for LCD Mini12864 screen +# +# (\_/) +# ( *,*) +# (")_(") Happy Hare Ready +# +# +[menu __main __MMU] +enable: {printer.mmu.enabled} +type: list +name: MMU +index: 6 + +[menu __main __MMU __HOME] +type: command +name: Home MMU +index: 1 +gcode: MMU_HOME + +[menu __main __MMU __SERVO_UP] +type: command +name: Servo up +index: 2 +gcode: MMU_SERVO POS=up + +[menu __main __MMU __SERVO_MOVE] +type: command +name: Servo move +index: 3 +gcode: MMU_SERVO POS=move + +[menu __main __MMU __SERVO_DOWN] +type: command +name: Servo down +index: 4 +gcode: MMU_SERVO POS=down + +[menu __main __MMU __CHANGE_TOOL] +type: input +name: Change Tool: {'%2d' % (menu.input|int)} +input: 0 +input_min: 0 +input_max: 8 +input_step: 1 +index: 5 +gcode: + MMU_CHANGE_TOOL STANDALONE=1 TOOL={menu.input|int} + +[menu __main __MMU __SELECT_TOOL] +type: input +name: Select Tool: {'%2d' % (menu.input|int)} +input: 0 +input_min: 0 +input_max: 8 +input_step: 1 +index: 6 +gcode: + MMU_SELECT TOOL={menu.input|int} + +[menu __main __MMU __PRELOAD_TOOL] +type: input +name: Preload Tool: {'%1d' % (menu.input|int)} +input: 0 +input_min: 0 +input_max: 8 +input_step: 1 +index: 7 +gcode: + MMU_PRELOAD GATE={menu.input|int} + +[menu __main __MMU __EJECT] +type: command +name: Eject +index: 8 +gcode: MMU_EJECT + +[menu __main __MMU __RECOVER] +type: command +name: Recover +index: 9 +gcode: MMU_RECOVER + +[menu __main __MMU __SELECT_BYPASS] +enable: {not printer.idle_timeout.state == "Printing"} +type: command +name: Select bypass +index: 10 +gcode: MMU_SELECT_BYPASS + +[menu __main __MMU __LOAD_BYPASS] +enable: {not printer.idle_timeout.state == "Printing" and printer.mmu.gate == -2} +type: command +name: Load bypass +index: 11 +gcode: MMU_LOAD + +[menu __main __MMU __UNLOAD_BYPASS] +enable: {not printer.idle_timeout.state == "Printing" and printer.mmu.gate == -2} +type: command +name: Unload bypass +index: 13 +gcode: MMU_EJECT + +[menu __main __MMU __clogdetection] +type: input +name: Clog detect: {'%2d' % (menu.input|int)} +input: 0 +input_min: 0 +input_max: 2 +input_step: 1 +index: 14 +gcode: + MMU_TEST_CONFIG enable_clog_detection={menu.input|int} + +[menu __main __MMU __endlessspool] +type: input +name: Endl. spool: {'%2d' % (menu.input|int)} +input: 0 +input_min: 0 +input_max: 1 +input_step: 1 +index: 15 +gcode: + MMU_TEST_CONFIG enable_endless_spool={menu.input|int} + +[menu __main __MMU __STATUS] +type: command +name: Show Status +index: 16 +gcode: MMU_STATUS + +[menu __main __MMU __MOTORS_OFF] +type: command +name: Motors off +index: 17 +gcode: MMU_MOTORS_OFF + diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 b/meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 new file mode 100644 index 00000000..5ae525d4 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 @@ -0,0 +1,136 @@ +# Happy Hare Hardware Konfiguration für FYSETC ERB V2.0 +# Elegoo Centauri Carbon 1 (128MB RAM optimiert) +# +# Diese Datei enthält die Motor-Treiber und mechanischen Einstellungen +# + +# ============================================================================= +# TMC2209 Treiber-Konfiguration +# ============================================================================= + +# Gear Stepper (TMC2209 onboard) +[tmc2209 stepper_mmu_gear] +uart_pin: mmu:gpio11 +uart_address: 0 +interpolate: false # RAM-Optimierung: Weniger Interpolation +run_current: 0.8 # Anpassen an Motor (NEMA14 typisch: 0.6-1.0A) +hold_current: 0.4 # 50% von run_current +sense_resistor: 0.110 +stealthchop_threshold: 0 # Force SpreadCycle für bessere Kontrolle +# Optional für Touch Homing (StallGuard): +#diag_pin: ^mmu:gpio13 +#driver_SGTHRS: 60 + +# Selector Stepper (TMC2209 onboard) +[tmc2209 stepper_mmu_selector] +uart_pin: mmu:gpio17 +uart_address: 1 +interpolate: false # RAM-Optimierung +run_current: 0.6 # NEMA17 typisch: 0.5-0.8A +hold_current: 0.3 # 50% von run_current +sense_resistor: 0.110 +stealthchop_threshold: 100 # StealthChop im Home für leisere Operation +# Optional für Touch Homing: +#diag_pin: ^mmu:gpio19 +#driver_SGTHRS: 55 + +# ============================================================================= +# Mechanische Konfiguration +# ============================================================================= + +# Gear Stepper Mechanik +[stepper_mmu_gear] +rotation_distance: 22.7316868 # Bondtech 5mm Drive Gears +# Alternative für andere Getriebe: +#rotation_distance: 6.283185307179586 # Direktantrieb +microsteps: 16 +full_steps_per_rotation: 200 +# Gear Ratio für ERCF v2: +# 80:1 für Selector, 52:10 für Gear (abhängig vom Build) + +# Selector Stepper Mechanik +[stepper_mmu_selector] +rotation_distance: 40 # Anpassen an tatsächliche Distanz pro Rotation +microsteps: 16 +full_steps_per_rotation: 200 +# Endstop für Selector Homing +endstop_pin: ^mmu:gpio24 +endstop_name: mmu_selector_endstop + +# ============================================================================= +# Servo-Konfiguration +# ============================================================================= + +# Selector Servo (Gate-Verriegelung) +[mmu_servo selector_servo] +pin: mmu:gpio23 +minimum_pulse_width: 0.001000 +maximum_pulse_width: 0.002000 +maximum_servo_angle: 180 +# Servo-Positionen (werden in mmu_parameters.cfg überschrieben) +#up_angle: 90 +#down_angle: 0 + +# ============================================================================= +# Encoder-Konfiguration +# ============================================================================= + +# Encoder für Filamentbewegungsmessung +[mmu_encoder mmu_encoder] +encoder_pin: ^mmu:gpio22 +encoder_resolution: 1.0 # mm pro Count (wird kalibriert) +# RAM-Optimierung: Weniger Samples für weniger Memory +#sample_time: 0.1 + +# ============================================================================= +# LED-Konfiguration +# ============================================================================= + +# Neopixel LEDs für Status-Anzeige +[neopixel mmu_leds] +pin: mmu:gpio21 +chain_count: 12 # Anzahl Gates (anpassen: 6 oder 12) +color_order: GRB +initial_RED: 0.0 +initial_GREEN: 0.5 +initial_BLUE: 0.0 + +# ============================================================================= +# Sensor-Konfiguration +# ============================================================================= + +# Alle Filament-Sensoren +[mmu_sensors] +# Gate Sensor (Hall-Effekt, gemeinsamer Sensor) +gate_switch_pin: ^mmu:gpio25 + +# Pre-Gate Sensoren (individuell pro Gate) +pre_gate_switch_pin_0: ^mmu:gpio12 +pre_gate_switch_pin_1: ^mmu:gpio18 +pre_gate_switch_pin_2: ^mmu:gpio2 +pre_gate_switch_pin_3: ^mmu:gpio3 +pre_gate_switch_pin_4: ^mmu:gpio4 +pre_gate_switch_pin_5: ^mmu:gpio5 +pre_gate_switch_pin_6: ^mmu:gpio6 +pre_gate_switch_pin_7: ^mmu:gpio7 +pre_gate_switch_pin_8: ^mmu:gpio26 +pre_gate_switch_pin_9: ^mmu:gpio27 +pre_gate_switch_pin_10: ^mmu:gpio28 +pre_gate_switch_pin_11: ^mmu:gpio29 + +# Post-Gear Sensoren (optional, nach dem Getriebe) +#post_gear_switch_pin_0: +#post_gear_switch_pin_1: +#post_gear_switch_pin_2: +#post_gear_switch_pin_3: +#post_gear_switch_pin_4: +#post_gear_switch_pin_5: + +# Toolhead/Extruder Sensoren (optional) +#extruder_switch_pin: +#toolhead_switch_pin: + +# Sync Feedback (optional für Spannungs-/Druckmessung) +#sync_feedback_tension_pin: +#sync_feedback_compression_pin: +#sync_feedback_analog_pin: diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 b/meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 new file mode 100644 index 00000000..444f9b22 --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 @@ -0,0 +1,150 @@ +# Happy Hare Parameter-Konfiguration für FYSETC ERB V2.0 +# Elegoo Centauri Carbon 1 (128MB RAM optimiert) +# +# Diese Datei enthält Happy Hare-spezifische Parameter +# RAM-optimierte Einstellungen für 128MB Systeme +# + +[mmu_parameters] +# ============================================================================= +# Grundlegende Einstellungen +# ============================================================================= + +# Firmware-Modus (1 = Full MMU, 2 = Gate Selector nur) +mmu_mode: 1 + +# Anzahl der Gates (anpassen an Build: 6 oder 12) +gate_total: 12 + +# Standard-Gate für Tests +gate_default: 0 + +# ============================================================================= +# RAM-Optimierungen (KRITISCH für 128MB Systeme) +# ============================================================================= + +# Reduziere Cache-Größe für Gate-Map (6 statt 12 für 6-Gate-System) +gate_map_cache_size: 6 + +# Sensor-Update-Rate reduzieren (50 Hz statt 100 Hz) +sensor_update_rate: 50 + +# Bewegungspuffer reduzieren +movement_buffer_size: 50 + +# Encoder-Sample-Zeit reduzieren +encoder_sample_time: 0.1 + +# ============================================================================= +# Motor-Einstellungen +# ============================================================================= + +# Gear Motor Geschwindigkeit (mm/s) +gear_speed: 50 + +# Gear Motor Beschleunigung (mm/s²) +gear_accel: 200 + +# Selector Motor Geschwindigkeit (mm/s) +selector_speed: 80 + +# Selector Motor Beschleunigung (mm/s²) +selector_accel: 400 + +# ============================================================================= +# Filament-Einstellungen +# ============================================================================= + +# Filament-Durchmesser (mm) +filament_diameter: 1.75 + +# Maximale Filament-Länge (mm) +filament_max_length: 1000 + +# Minimale Filament-Länge für Loading (mm) +filament_min_load_length: 50 + +# ============================================================================= +# Sensor-Einstellungen +# ============================================================================= + +# Gate Sensor Timeout (ms) +gate_sensor_timeout: 500 + +# Encoder Timeout für Bewegung (ms) +encoder_timeout: 2000 + +# Pre-Gate Sensor aktiviert (true/false) +pre_gate_sensors_enabled: true + +# ============================================================================= +# Servo-Einstellungen +# ============================================================================= + +# Servo Up-Position (Gate offen) +servo_up_angle: 90 + +# Servo Down-Position (Gate geschlossen) +servo_down_angle: 0 + +# Servo Bewgungsgeschwindigkeit (ms) +servo_move_time: 200 + +# ============================================================================= +# LED-Einstellungen +# ============================================================================= + +# LED Helligkeit (0.0 - 1.0) +led_brightness: 0.5 + +# LED Animation aktivieren +led_animation_enabled: true + +# LED Animation Geschwindigkeit (ms) +led_animation_speed: 100 + +# ============================================================================= +# Homing-Einstellungen +# ============================================================================= + +# Homing Methode (endstop, current, stallguard) +homing_method: endstop + +# Homing Geschwindigkeit (mm/s) +homing_speed: 30 + +# Homing Retract Distanz (mm) +homing_retract_dist: 5 + +# ============================================================================= +# Error-Handling +# ============================================================================= + +# Maximale Fehler vor Stop +max_errors_before_stop: 3 + +# Error-Reset nach (Sekunden) +error_reset_time: 60 + +# ============================================================================= +# Logging (RAM-optimiert) +# ============================================================================= + +# Log-Level (0 = minimal, 1 = normal, 2 = debug) +log_level: 1 + +# Log-File aktivieren (false für weniger I/O) +log_file_enabled: false + +# ============================================================================= +# Advanced (nicht ändern außer bei Problemen) +# ============================================================================= + +# MMU Timeout für Operationen (ms) +mmu_operation_timeout: 10000 + +# Retry-Versuche bei Fehlern +retry_attempts: 2 + +# Retry-Verzögerung (ms) +retry_delay: 500 diff --git a/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb b/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb new file mode 100644 index 00000000..50601ecb --- /dev/null +++ b/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb @@ -0,0 +1,124 @@ +SUMMARY = "Happy Hare MMU Firmware for Klipper (ERCF v2)" +DESCRIPTION = "Multi-Material-Unit firmware extension for Klipper. \ + Supports ERCF v2 with FYSETC ERB V2.0 board. \ + Optimized for low-memory systems (128MB RAM)." +HOMEPAGE = "https://github.com/moggieuk/Happy-Hare" +LICENSE = "CLOSED" + +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +SRC_URI = "git://github.com/moggieuk/Happy-Hare.git;protocol=https;branch=main \ + file://mmu \ + file://mmu.cfg.erb-v2 \ + file://mmu_hardware.cfg.erb-v2 \ + file://mmu_parameters.cfg.erb-v2 \ + file://happy-hare-init \ +" + +SRCREV = "${AUTOREV}" + +S = "${WORKDIR}/git" + +inherit update-rc.d python3-dir + +DEPENDS = " \ + python3-native \ + klipper \ +" + +RDEPENDS:${PN} = " \ + python3 \ + python3-pyserial \ + python3-jinja2 \ + python3-msgspec \ + klipper \ + moonraker \ + zram \ + bash \ +" + +INITSCRIPT_NAME = "happy-hare-setup" +INITSCRIPT_PARAMS = "defaults 94 6" + +do_configure() { + : +} + +do_compile() { + : +} + +do_install() { + # Install Happy Hare Python-Module + install -d ${D}${datadir}/happy-hare + + # Kopiere alle vorhandenen Dateien aus dem Git-Repo + cp -r ${S}/* ${D}${datadir}/happy-hare/ 2>/dev/null || true + + # Install Klipper-Erweiterung (mmu.py nach klippy/extras) + install -d ${D}${datadir}/klipper/klippy/extras + if [ -f ${S}/extras/mmu/mmu.py ]; then + install -m 0644 ${S}/extras/mmu/mmu.py ${D}${datadir}/klipper/klippy/extras/mmu.py + fi + # Install additional Happy Hare extras + if [ -d ${S}/extras ]; then + cp -r ${S}/extras/* ${D}${datadir}/klipper/klippy/extras/ 2>/dev/null || true + fi + + # Install Konfigurations-Vorlagen für FYSETC ERB V2.0 + install -d ${D}${sysconfdir}/klipper/config/happy-hare + install -m 0644 ${WORKDIR}/mmu.cfg.erb-v2 ${D}${sysconfdir}/klipper/config/happy-hare/mmu.cfg + install -m 0644 ${WORKDIR}/mmu_hardware.cfg.erb-v2 ${D}${sysconfdir}/klipper/config/happy-hare/mmu_hardware.cfg + install -m 0644 ${WORKDIR}/mmu_parameters.cfg.erb-v2 ${D}${sysconfdir}/klipper/config/happy-hare/mmu_parameters.cfg + + # Install MMU config from local mmu folder + install -d ${D}${sysconfdir}/klipper/config/mmu/base + install -d ${D}${sysconfdir}/klipper/config/mmu/addons + install -d ${D}${sysconfdir}/klipper/config/mmu/optional + if [ -d "${WORKDIR}/mmu/base" ]; then + cp -r ${WORKDIR}/mmu/base/*.cfg ${D}${sysconfdir}/klipper/config/mmu/base/ 2>/dev/null || true + fi + if [ -d "${WORKDIR}/mmu/addons" ]; then + cp -r ${WORKDIR}/mmu/addons/*.cfg ${D}${sysconfdir}/klipper/config/mmu/addons/ 2>/dev/null || true + fi + if [ -d "${WORKDIR}/mmu/optional" ]; then + cp -r ${WORKDIR}/mmu/optional/*.cfg ${D}${sysconfdir}/klipper/config/mmu/optional/ 2>/dev/null || true + fi + if [ -f "${WORKDIR}/mmu/mmu_vars.cfg" ]; then + install -m 0644 ${WORKDIR}/mmu/mmu_vars.cfg ${D}${sysconfdir}/klipper/config/mmu/mmu_vars.cfg + fi + + # Install Init-Skript für Setup + install -d ${D}${sysconfdir}/init.d + install -m 0755 ${WORKDIR}/happy-hare-init ${D}${sysconfdir}/init.d/happy-hare-setup + + # Symlink für Moonraker Update-Manager (optional) + install -d ${D}/home/mainsail + ln -sf ${datadir}/happy-hare ${D}/home/mainsail/Happy-Hare +} + +FILES:${PN} = " \ + ${datadir}/happy-hare \ + ${datadir}/klipper/klippy/extras/mmu.py \ + ${sysconfdir}/klipper/config/happy-hare \ + ${sysconfdir}/klipper/config/mmu \ + ${sysconfdir}/init.d/happy-hare-setup \ + /home/mainsail/Happy-Hare \ +" + +# Allow Klipper files in non-standard location +FILES:${PN} += "${datadir}/klipper" + +# Config files that should be editable (like printer.cfg) +CONFFILES:${PN} = " \ + ${sysconfdir}/klipper/config/mmu/mmu_vars.cfg \ +" + +# Memory-Optimierung: Strip Python-Bytecode +do_install:append() { + find ${D} -name '*.pyc' -delete || true + find ${D} -name '__pycache__' -type d -exec rm -rf {} + || true +} + +# Nur auf Centauri Carbon 1 bauen (128MB RAM) +COMPATIBLE_MACHINE = "elegoo-centauri-carbon1" \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg b/meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg new file mode 100644 index 00000000..049d7fa2 --- /dev/null +++ b/meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg @@ -0,0 +1,545 @@ +# ----- +# PLEASE DO NOT EDIT THIS FILE. EDIT printer.cfg INSTEAD. +# EDITING THIS FILE WILL EXCLUDE YOUR CHANGES FROM FUTURE UPDATES. +# ----- + +[gcode_macro _COSMOS_SETTINGS] +variable_sync_camera_led_to_chamber_led: False +variable_camera_led_default_on: True +gcode: + +[gcode_macro _GLOBAL_VARS] +variable_extruder_target: 230 +gcode: + +[gcode_macro PRINT_START] +gcode: + SET_GCODE_VARIABLE MACRO=_GLOBAL_VARS VARIABLE=extruder_target VALUE={params.EXTRUDER_TEMP} + +# Home Z with Strain Gauge, ends up with the nozzle 2mm above bed +[gcode_macro STRAINGAUGE_Z_HOME] +gcode: + SAVE_GCODE_STATE NAME=straingauge_z_home_state + + # TODO: Clear bed mesh + + # Move down a Z to get some clearance + G91 ; Relative positioning + G1 Z2 F600 ; Move up 2mm + G90 + + PROBE ; Probe with strain gauge + + M400 ; Wait for moves to finish + + # Store the end position as new Z=0 + SET_KINEMATIC_POSITION Z=0 SET_HOMED=Z ; Set current Z as 0 + + # Move up 2mm from the probed position + G91 ; Relative positioning + G1 Z2 F600 ; Move up 2mm + M400 ; Wait for moves to finish + G90 ; Absolute positioning + + # TODO: Restore bed mesh + + RESTORE_GCODE_STATE NAME=straingauge_z_home_state + +# Wipe Nozzle, see auto_leveling.cpp:443 +[gcode_macro M729] +gcode: + SAVE_GCODE_STATE NAME=m729_saved_state + + G90 + + # Move to tray + G1 X202 F6000 + G1 Y264.5 F6000 + + # Wipe + G1 X173 F8000 + G1 X187 + G1 X173 + G1 X187 + G1 X173 + + # Move a 2mm on Y + G1 Y262.5 + + # Wipe + G1 X187 F8000 + G1 X173 + G1 X187 + G1 X173 + G1 X187 + G1 X173 + + # Add some clearance + G1 Y250 + + # Move back to tray + G1 X202 + G1 Y264.5 F1200 + + # Clear command queue + M400 + + RESTORE_GCODE_STATE NAME=m729_saved_state + +[gcode_macro WIPE_NOZZLE] +gcode: + {% set bed_temp = params.BED_TEMP|default(60)|float %} + + G28 ; Home + M204 S5000 ; Set acceleration to 5000 mm/s + M400 ; Wait for moves to finish + G90 ; Absolute positioning + M106 S0 ; Turn off part cooling fan + SET_FAN_SPEED FAN=model_helper_fan SPEED=0 ; Turn off auxiliary fan + M83 ; Relative extrusion mode + + # Move to purge position + G1 X202 Y250 F20000 ; Rapid move to purge area + G1 Y264.5 F1200 ; Move to exact purge Y position + M109 S250 ; Heat nozzle to 250°C and wait + + # Purge filament (8 cycles) + G92 E0 ; Reset extruder position + M106 S255 ; Turn on part cooling fan (full speed) + SET_FAN_SPEED FAN=model_helper_fan SPEED=1 ; Turn on auxiliary fan (full speed) + G1 E13 F523 ; Extrude 13mm at medium speed + G1 E2 F150 ; Extrude 2mm slowly (ensure flow) + M400 ; Wait for completion + G1 E13 F523 ; Repeat purge cycle 2 + G1 E2 F150 + M400 + G1 E13 F523 ; Repeat purge cycle 3 + G1 E2 F150 + M400 + G1 E13 F523 ; Repeat purge cycle 4 + G1 E2 F150 + M400 + G1 E13 F523 ; Repeat purge cycle 5 + G1 E2 F150 + M400 + G1 E13 F523 ; Repeat purge cycle 6 + G1 E2 F150 + M400 + G1 E13 F523 ; Repeat purge cycle 7 + G1 E2 F150 + M400 + G1 E13 F523 ; Repeat purge cycle 8 + G1 E2 F150 + M400 + G1 E-2 F1800 ; Retract 2mm to prevent oozing + + # Cool nozzle for cleaning + M109 S180 ; Cool to 180°C and wait + M400 ; Wait for moves + M104 S140 ; Start cooling to final temp (140°C) + G4 S4 ; Dwell 4 seconds + + # Wipe nozzle using M729 pattern + M204 S15000 ; Set high acceleration for wipe + M729 ; Execute wipe pattern (moves across wiper) + M204 S5000 ; Restore normal acceleration + + # --- ADDITIONAL NOZZLE CLEANING --- + G1 X128 Y254 F3000 ; Move to cleaning brush area + M140 S{bed_temp} ; Keep bed at target temp + + STRAINGAUGE_Z_HOME ; Home Z using strain gauge + + M400 ; Wait for completion + #G91 ; Relative positioning + #G1 Z2 F600 ; Lift Z by 2mm + #G90 ; Absolute positioning + G1 Z2 F600 ; Ensure Z is 2mm above bed + + G1 Y261.5 F9000 ; Move to brush position + G91 ; Relative positioning + G1 Z-2.5 F600 ; Lower into brush + M400 ; Wait for position + + # Scrub nozzle back and forth (4 passes) + G90 ; Absolute positioning + G1 X140 F2000 ; Scrub right + G1 X110 ; Scrub left + G1 X140 F2000 ; Scrub right + G1 X110 ; Scrub left + G1 X140 F2000 ; Scrub right + G1 X110 ; Scrub left + G1 X140 F2000 ; Scrub right + G1 X110 ; Scrub left + G1 X140 F2000 ; Final scrub right + G1 X128 ; Return to center + M400 ; Wait for completion + + # Lift and move away from brush + G91 ; Relative positioning + G1 Z3 F600 ; Lift Z by 3mm + M400 ; Wait + G90 ; Absolute positioning + G1 Y254 F9000 ; Move away from brush + G1 X128 F9000 ; Center X position + + # --- CALIBRATION PREPARATION --- + M140 S{bed_temp} ; Keep bed at target temp + STRAINGAUGE_Z_HOME ; Home Z with strain gauge again + #G91 ; Relative positioning + #G1 Z-2.5 F600 ; Lower slightly + #G90 ; Absolute positioning + M400 ; Wait for completion + + # Heat to calibration temperatures + M140 S{bed_temp} ; Heat bed to target temp + M109 S140 ; Heat nozzle to 140°C and wait + M400 ; Wait for stability + M106 S0 ; Turn off part cooling fan + SET_FAN_SPEED FAN=model_helper_fan SPEED=0 ; Turn off auxiliary fan + + # Final positioning before probe calibration + G91 ; Relative positioning + G1 Z2 F600 ; Lift Z by 2mm + G90 ; Absolute positioning + +# Bed Mesh Calibration Macro with temperature and wipe +[gcode_macro BED_MESH_CALIBRATE_WITH_WIPE] +gcode: + {% set bed_temp = params.BED_TEMP|default(60)|float %} + + M104 S140 ; Set nozzle temp to 140°C + M140 S{bed_temp} ; Set bed temp + M106 S0 ; Turn off part cooling fan + SET_FAN_SPEED FAN=model_helper_fan SPEED=0 ; Turn off auxiliary fan + SET_FAN_SPEED FAN=box_fan SPEED=0 ; Turn off box fan + + WIPE_NOZZLE BED_TEMP={bed_temp} ; Clean nozzle before probing + + M140 S{bed_temp} ; Set bed temp + M104 S140 ; Set nozzle temp to 140°C + + SET_GCODE_OFFSET Z=0 MOVE=0 ; Reset Z offset + + G28 Z0 ; Home Z only using photoelectric sensor + + M109 S140 ; Ensure nozzle at 140°C + M190 S{bed_temp} ; Ensure bed temp + + BED_MESH_CALIBRATE ; Start bed mesh calibration + + MOVE_TO_TRAY ; Move to tray after calibration + M106 S0 ; Turn off part cooling fan + SET_FAN_SPEED FAN=model_helper_fan SPEED=0 ; Turn off auxiliary fan + M104 S0 ; Turn off nozzle heater + M140 S0 ; Turn off bed heater + +# Move the toolhead to the tray +[gcode_macro MOVE_TO_TRAY] +gcode: + {% if "xyz" not in printer.toolhead.homed_axes %} + G28 ; Home if necessary + {% endif %} + + G90 ; Absolute positioning + G0 X202 Y250 F12000 ; Move near to the try + G0 Y264.5 F1200 ; Move slowly back to the tray + + M400 ; Wait for movements to complete + +[gcode_macro _LOAD_FILAMENT_STEP_PUSH] +gcode: + {% set silent = params.SILENT|default(0)|int %} + {% set purge_length = params.LENGTH|default(120)|float %} + _CLOSE_PROMPT ; Close any existing prompt + M83 ; Relative extrusion mode + G92 E0 ; Reset extruder position + G1 E{purge_length} F240 ; Move filament into the extruder (120mm at 4mm/s) + M729 ; Wipe nozzle after loading + + {% if not silent %} + RESPOND TYPE=command MSG="action:prompt_begin Loading Filament" + RESPOND TYPE=command MSG="action:prompt_text Load completed. Do you want to purge more?" + RESPOND TYPE=command MSG="action:prompt_footer_button Purge more|_LOAD_FILAMENT_STEP_PUSH" + RESPOND TYPE=command MSG="action:prompt_footer_button Done|_LOAD_FILAMENT_STEP_DONE" + RESPOND TYPE=command MSG="action:prompt_show" + {% endif %} + +[gcode_macro _LOAD_FILAMENT_STEP_DONE] +gcode: + M729 ; Wipe nozzle after loading + M104 S0 ; Turn off nozzle heater + M106 S0 ; Turn off part cooling fan + _CLOSE_PROMPT ; Close the loading prompt + +[gcode_macro LOAD_FILAMENT] +gcode: + {% set extruder_temp = params.EXTRUDER_TEMP|default(250)|float %} + + M104 S{extruder_temp} ; Start heating the nozzle + + MOVE_TO_TRAY ; Move to the tray + M109 S{extruder_temp} ; Wait for nozzle to reach temp + M106 S255 ; Turn on part cooling fan (full speed) + _LOAD_FILAMENT_STEP_PUSH ; Push filament into extruder and wipe + +# Cuts the tip of the filament and ejects it from the extruder +[gcode_macro UNLOAD_FILAMENT] +gcode: + {% if "xyz" not in printer.toolhead.homed_axes %} + G28 ; Home if necessary + {% endif %} + + G90 ; Absolute positioning + G0 Z14.5 F600 ; Ensure we have some Z clearance + G0 Y30 F15000 ; Get some clearance for Y + G0 X255 F8000 ; Move to cutting position + G0 Y3 F1200 ; Cut + G0 Y30 F8000 ; Retract from cutting + M400 ; Wait for movements to complete + + MOVE_TO_TRAY ; Move to the tray + FORCE_MOVE STEPPER=extruder DISTANCE=-30 VELOCITY=4 ; Move the filament out of the extruder + + M400 ; Wait for movements to complete + +[gcode_macro _HOME_X] +gcode: + # Home X + G28 X + M400 + + # Move away + G91 + G1 X-20 F4800 + G90 + +[gcode_macro _HOME_Y] +gcode: + # Home Y + G28 Y + M400 + + # Move away + G91 + G1 Y30 F4800 + G90 + +[delayed_gcode startup] +initial_duration: 1 +gcode: + {% set settings = printer["gcode_macro _COSMOS_SETTINGS"]|default({}) %} + {% set camera_led_on = settings.camera_led_default_on|default(false)|lower == 'true' %} + + {% if camera_led_on %} + RUN_SHELL_COMMAND CMD=CAMERA_LIGHT_ON + {% endif %} + + _CHECK_INITIAL_CALIBRATION + + BED_MESH_PROFILE LOAD=default + +[homing_override] +axes: yxz +gcode: + {% set bed_mesh = printer.bed_mesh.profile_name %} + {% set home_all = 'X' not in params and 'Y' not in params and 'Z' not in params %} + # On the Centauri Carbon 1, 8mm is the requested minimum Z clearance before XY homing. + {% set safe_z = 8.0 %} + {% set safe_z_feedrate = 1500 %} + {% set RUN_CURRENT_X = printer.configfile.settings['tmc2209 stepper_x'].run_current|float %} + {% set RUN_CURRENT_Y = printer.configfile.settings['tmc2209 stepper_y'].run_current|float %} + {% set HOME_CURRENT_X = printer.configfile.settings['tmc2209 stepper_x'].home_current|float %} + {% set HOME_CURRENT_Y = printer.configfile.settings['tmc2209 stepper_y'].home_current|float %} + + BED_MESH_CLEAR + + # Set lower current for homing + SET_TMC_CURRENT STEPPER=stepper_x CURRENT={HOME_CURRENT_X} + SET_TMC_CURRENT STEPPER=stepper_y CURRENT={HOME_CURRENT_Y} + + # Pause to ensure driver stall flag is clear + G4 P500 + + # Ensure Z clearance before XY homing when Z homing is requested + {% if home_all or 'Z' in params %} + {% if 'z' in printer.toolhead.homed_axes %} + {% if printer.gcode_move.gcode_position.z|float < safe_z %} + G90 + G0 Z{safe_z} F{safe_z_feedrate} + {% endif %} + {% else %} + # When Z is unhomed, normal G0/G1 moves are unavailable, so use a short + # positive force move to create the requested minimum clearance first. + # WARNING: This intentionally assumes the printer is in a state where a + # +8mm Z move is safe and that Z is not already at its positive travel limit + # before continuing with the requested Z homing sequence. + FORCE_MOVE STEPPER=stepper_z DISTANCE={safe_z} VELOCITY={safe_z_feedrate / 60} + {% endif %} + # Wait for the Z clearance move to finish before starting XY homing moves. + M400 + {% endif %} + + # First X home. Note this may crash into the back steppers. + {% if home_all or 'X' in params %} + _HOME_X + {% endif %} + + # First Y Home. + {% if home_all or 'Y' in params %} + _HOME_Y + {% endif %} + + # Second X home (if homing both X and Y) to home x at a known good position for sensorless homing + {% if home_all or ('X' in params and 'Y' in params) %} + _HOME_X + {% endif %} + + # Second Y home just in case the X home caused a jump in Y + {% if home_all or ('X' in params and 'Y' in params) %} + _HOME_Y + {% endif %} + + # Restore running current after homing + SET_TMC_CURRENT STEPPER=stepper_x CURRENT={RUN_CURRENT_X} + SET_TMC_CURRENT STEPPER=stepper_y CURRENT={RUN_CURRENT_Y} + + {% if home_all or 'Z' in params %} + G90 # Absolute positioning + G1 X125 Y125 F15000 # Move to center of the bed for Z homing + G28 Z # Home Z + G0 Z10 F1500 # Move down after homing + {% endif %} + + {% if bed_mesh != "" %} + BED_MESH_PROFILE LOAD="{bed_mesh}" + {% endif %} + +[gcode_macro _SHOW_PROMPT] +gcode: + {% set title = params.TITLE|default('Please wait') %} + {% set message = params.MESSAGE %} + {% set esc_title = title|replace('"','\\"') %} + {% set esc_message = message|replace('"','\\"') %} + + RESPOND TYPE=command MSG="action:prompt_begin {esc_title}" + RESPOND TYPE=command MSG="action:prompt_text {esc_message}" + RESPOND TYPE=command MSG="action:prompt_footer_button Dismiss|RESPOND TYPE=command MSG=action:prompt_end" + + RESPOND TYPE=command MSG="action:prompt_show" + +[gcode_macro _CLOSE_PROMPT] +gcode: + RESPOND TYPE=command MSG="action:prompt_end" + +[gcode_macro SET_DISPLAY_TEXT_COSMOS] +rename_existing: SET_DISPLAY_TEXT_BASE +gcode: + {% set message = params.MSG|default('') %} + + {% if message %} + {action_respond_info(message)} + {% endif %} + + SET_DISPLAY_TEXT_BASE MSG="{message}" + +[gcode_macro SAVE_CONFIG] +rename_existing: SAVE_CONFIG_BASE +gcode: + _CLOSE_PROMPT + G4 P1000 ; Wait 1 second to ensure prompt is closed + SAVE_CONFIG_BASE + +[gcode_macro _SAVE_CONFIG_PROMPT] +description: Save the current configuration with a user prompt +gcode: + RESPOND TYPE=command MSG="action:prompt_begin Save Configuration" + RESPOND TYPE=command MSG="action:prompt_text Do you want to save the current configuration? This will save all current settings and will overwrite previous configurations." + RESPOND TYPE=command MSG="action:prompt_text If you'd like to check the current settings before saving, please dismiss this prompt. You can save the current configuration by running the SAVE_CONFIG command directly." + RESPOND TYPE=command MSG="action:prompt_footer_button Dismiss, Save later|_CLOSE_PROMPT" + RESPOND TYPE=command MSG="action:prompt_footer_button Save|SAVE_CONFIG|warning" + RESPOND TYPE=command MSG="action:prompt_show" + +[gcode_macro _FULL_CALIBRATION] +gcode: + {% set extruder_temp = params.EXTRUDER_TEMP|default(220)|float %} + {% set bed_temp = params.BED_TEMP|default(60)|float %} + + _CLOSE_PROMPT + + SET_DISPLAY_TEXT_COSMOS MSG="Performing extruder PID calibration (1/4)" + MOVE_TO_TRAY + PID_CALIBRATE HEATER=extruder TARGET={extruder_temp} + M729 + + SET_DISPLAY_TEXT_COSMOS MSG="Calibrating load cells (2/4)" + G28 + M400 + LOAD_CELL_SAVE_TARE + G4 P2000 + + SET_DISPLAY_TEXT_COSMOS MSG="Performing probe z-offset & bed mesh calibration (3/4)" + BED_MESH_CALIBRATE_WITH_WIPE BED_TEMP={bed_temp} + + SET_DISPLAY_TEXT_COSMOS MSG="Performing shaper calibration (4/4)" + G28 + M400 + SHAPER_CALIBRATE AXIS=X + SHAPER_CALIBRATE AXIS=Y + + SET_DISPLAY_TEXT_COSMOS ; Clear screen message + _SAVE_CONFIG_PROMPT + +[gcode_macro FULL_CALIBRATION] +gcode: + {% set extruder_temp = params.EXTRUDER_TEMP|default(220)|float %} + {% set bed_temp = params.BED_TEMP|default(60)|float %} + + RESPOND TYPE=command MSG="action:prompt_begin Preparation: Full Calibration" + RESPOND TYPE=command MSG="action:prompt_text Please clear the bed and toolhead of any foreign objects. Make sure the build plate is on top of the bed." + RESPOND TYPE=command MSG="action:prompt_text The calibration process will take approximately 30 minutes to complete. Do you want to start the full calibration process now?" + RESPOND TYPE=command MSG="action:prompt_footer_button Cancel|_CLOSE_PROMPT" + RESPOND TYPE=command MSG="action:prompt_footer_button Start Calibration|_FULL_CALIBRATION EXTRUDER_TEMP={extruder_temp} BED_TEMP={bed_temp}|primary" + RESPOND TYPE=command MSG="action:prompt_show" + +[gcode_macro _CLIENT_VARIABLE] +variable_use_custom_pos: True +variable_custom_park_x: 202 +variable_custom_park_y: 264.5 +gcode: + +[gcode_macro Bed_Level_Screws_Tune] +gcode: + {% set bed_temp = params.BED_TEMP|default(60)|float %} + BED_MESH_CLEAR + M104 S140 + M400 + G28 + M109 S140 + M729 + SCREWS_TILT_CALCULATE + +[gcode_macro _INITIAL_CALIBRATION_ACTION_LATER] +gcode: + RESPOND TYPE=command MSG="action:prompt_begin Welcome to COSMOS!" + RESPOND TYPE=command MSG="action:prompt_text You can calibrate anytime by running the FULL_CALIBRATION gcode command." + RESPOND TYPE=command MSG="action:prompt_text Initial calibration is required before printing!" + RESPOND TYPE=command MSG="action:prompt_text You can bypass automatic calibration, but if you do not run calibration manually you may damage your build plate or hotend." + RESPOND TYPE=command MSG="action:prompt_footer_button Bypass Calibration|_CLOSE_PROMPT|error" + RESPOND TYPE=command MSG="action:prompt_footer_button Calibrate Printer|FULL_CALIBRATION|primary" + RESPOND TYPE=command MSG="action:prompt_show" + +[gcode_macro _CHECK_INITIAL_CALIBRATION] +gcode: + {% set shaper_freq_x = printer.configfile.settings.input_shaper.shaper_freq_x|default(0)|float %} + {% set shaper_freq_y = printer.configfile.settings.input_shaper.shaper_freq_y|default(0)|float %} + {% set shaper_calibrated = shaper_freq_x > 0 and shaper_freq_y > 0 %} + {% set bed_mesh_default_exists = 'bed_mesh default' in printer.configfile.settings %} + + {% if not shaper_calibrated and not bed_mesh_default_exists %} + RESPOND TYPE=command MSG="action:prompt_begin Welcome to COSMOS!" + RESPOND TYPE=command MSG="action:prompt_text It looks like you haven't ran the initial calibration yet. Would you like to run it now? This will perform all necessary calibrations to get your printer ready for use, including input shaper and bed mesh calibration." + RESPOND TYPE=command MSG="action:prompt_footer_button Bypass Calibration|_INITIAL_CALIBRATION_ACTION_LATER|warning" + RESPOND TYPE=command MSG="action:prompt_footer_button Calibrate Printer|FULL_CALIBRATION|primary" + RESPOND TYPE=command MSG="action:prompt_show" + {% endif %} \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/klipper/files-hh/shell.cfg b/meta-opencentauri/recipes-apps/klipper/files-hh/shell.cfg new file mode 100644 index 00000000..c2208264 --- /dev/null +++ b/meta-opencentauri/recipes-apps/klipper/files-hh/shell.cfg @@ -0,0 +1,10 @@ +# ----- +# PLEASE DO NOT EDIT THIS FILE. EDIT printer.cfg INSTEAD. +# EDITING THIS FILE WILL EXCLUDE YOUR CHANGES FROM FUTURE UPDATES. +# ----- + +# Minimal shell.cfg for HH-Minimal image +# Removed: CAMERA_LIGHT_ON, CAMERA_LIGHT_OFF, SYNC_CAMERA_LED, sync_camera_led_loop, START_DOOM, DOOM +# Reason: v4l2-ctl and fbdoom removed, no camera/light support + +# (empty - no shell commands in minimal image) \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/klipper/files/config.mmu b/meta-opencentauri/recipes-apps/klipper/files/config.mmu new file mode 100644 index 00000000..c1f696d2 --- /dev/null +++ b/meta-opencentauri/recipes-apps/klipper/files/config.mmu @@ -0,0 +1,109 @@ +CONFIG_LOW_LEVEL_OPTIONS=y +# CONFIG_MACH_AVR is not set +# CONFIG_MACH_ATSAM is not set +# CONFIG_MACH_ATSAMD is not set +# CONFIG_MACH_LPC176X is not set +# CONFIG_MACH_STM32 is not set +# CONFIG_MACH_HC32F460 is not set +CONFIG_MACH_RPXXXX=y +# CONFIG_MACH_PRU is not set +# CONFIG_MACH_AR100 is not set +# CONFIG_MACH_HIFI4 is not set +# CONFIG_MACH_LINUX is not set +# CONFIG_MACH_SIMU is not set +CONFIG_BOARD_DIRECTORY="rp2040" +CONFIG_MCU="rp2040" +CONFIG_CLOCK_FREQ=125000000 +CONFIG_RP2040_SELECT=y +CONFIG_USBSERIAL=y +CONFIG_FLASH_SIZE=0x80000 +CONFIG_FLASH_BOOT_ADDRESS=0x10000000 +CONFIG_RAM_START=0x20000000 +CONFIG_RAM_SIZE=0x40000 +CONFIG_STACK_SIZE=512 +CONFIG_FLASH_APPLICATION_ADDRESS=0x10000100 +# CONFIG_RP2040_USB_BOOTROM is not set +# CONFIG_RP2040_FLASH_SKIP is not set +CONFIG_USB=y +CONFIG_USB_VENDOR_ID=0x1d50 +CONFIG_USB_DEVICE_ID=0x614e +CONFIG_USB_SERIAL_NUMBER_CHIPID=y +CONFIG_USB_SERIAL_NUMBER="12345" +CONFIG_USB_MANUFACTURER="Klipper" + +# +# USB ids +# +# end of USB ids + +CONFIG_CAN_UUID_CUSTOM="abc1234" +CONFIG_WANT_ADC=y +CONFIG_WANT_SPI=y +CONFIG_WANT_SOFTWARE_SPI=y +CONFIG_WANT_I2C=y +CONFIG_WANT_SOFTWARE_I2C=y +CONFIG_WANT_HARD_PWM=y +CONFIG_WANT_BUTTONS=y +CONFIG_WANT_TMCUART=y +CONFIG_WANT_NEOPIXEL=y +CONFIG_WANT_PULSE_COUNTER=y +# CONFIG_WANT_ST7920 is not set +# CONFIG_WANT_HD44780 is not set +# CONFIG_WANT_ADXL345 is not set +# CONFIG_WANT_LIS2DW is not set +# CONFIG_WANT_MPU9250 is not set +# CONFIG_WANT_ICM20948 is not set +# CONFIG_WANT_THERMOCOUPLE is not set +CONFIG_WANT_HX71X=y +# CONFIG_WANT_ADS1220 is not set +# CONFIG_WANT_LDC1612 is not set +# CONFIG_WANT_SENSOR_ANGLE is not set +CONFIG_WANT_GPIO_SPI=y +CONFIG_WANT_GPIO_ADC=y +CONFIG_WANT_GPIO_I2C=y +CONFIG_NEED_SENSOR_BULK=y +# CONFIG_WANT_OPTIMIZE_SIZE is not set + +# +# Feature Configuration +# + +# +# Microcontroller interfaces +# +# CONFIG_WANT_GPIO_BUTTONS is not set + +# +# ---- +# + +# +# LCD chips +# + +# +# Accelerometer chips +# + +# +# External ADC type chips +# + +# +# Compiler options +# +# end of Feature Configuration + +CONFIG_CANBUS_FREQUENCY=1000000 +CONFIG_INLINE_STEPPER_HACK=y +CONFIG_HAVE_STEPPER_OPTIMIZED_BOTH_EDGE=y +CONFIG_WANT_STEPPER_OPTIMIZED_BOTH_EDGE=y +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_STRICT_TIMING=y +CONFIG_HAVE_CHIPID=y +CONFIG_HAVE_BOOTLOADER_REQUEST=y \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/klipper/kalico-firmware-mmu_2026.02.00.bb b/meta-opencentauri/recipes-apps/klipper/kalico-firmware-mmu_2026.02.00.bb new file mode 100644 index 00000000..3801a347 --- /dev/null +++ b/meta-opencentauri/recipes-apps/klipper/kalico-firmware-mmu_2026.02.00.bb @@ -0,0 +1,34 @@ +require kalico_${PV}.inc + +SUMMARY = "Kalico MMU Firmware for RP2040 (Pico)" +DESCRIPTION = "Klipper/Kalico firmware for MMU secondary MCU on RP2040 (FYSETC ERB v2)" + +SRC_URI += " \ + file://config.mmu \ +" + +DEPENDS += "gcc-arm-none-eabi-native" + +RPROVIDES:${PN} += "klipper-firmware-mmu" + +EXTRA_OEMAKE += "KCONFIG_CONFIG=../config.mmu" + +# No init script needed - MMU firmware is flashed manually via USB/UF2 + +INSANE_SKIP:${PN} = "arch" + +do_install() { + install -d ${D}/lib/firmware + + # Copy uf2 file for RP2040 (auto-generated by Klipper build) + cp ${S}/out/klipper.uf2 ${D}/lib/firmware/klipper-mmu.uf2 + + echo "${SRCREV}" > ${D}/lib/firmware/klipper-mmu.uf2.ver +} + +FILES:${PN} = " \ + /lib/firmware/klipper-mmu.uf2 \ + /lib/firmware/klipper-mmu.uf2.ver \ +" + +PACKAGES = "${PN}" \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/klipper/kalico_2026.02.00.bbappend b/meta-opencentauri/recipes-apps/klipper/kalico_2026.02.00.bbappend new file mode 100644 index 00000000..0051d791 --- /dev/null +++ b/meta-opencentauri/recipes-apps/klipper/kalico_2026.02.00.bbappend @@ -0,0 +1,14 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/files-hh:" + +# PACKAGECONFIG for OpenCentauri HH images +# opencentauri-hh-full: macros.cfg only (original shell.cfg from files/ used) +# opencentauri-hh-minimal: macros.cfg + minimal shell.cfg (camera/doom removed) +PACKAGECONFIG ??= "" +PACKAGECONFIG[opencentauri-hh-full] = ",,," +PACKAGECONFIG[opencentauri-hh-minimal] = ",,," + +# Use modified macros.cfg for both HH images +SRC_URI:append = "${@bb.utils.contains_any('PACKAGECONFIG', 'opencentauri-hh-full opencentauri-hh-minimal', ' file://macros.cfg', '', d)}" + +# Use minimal shell.cfg only for HH-Minimal (removes camera/doom commands) +SRC_URI:append = "${@bb.utils.contains('PACKAGECONFIG', 'opencentauri-hh-minimal', ' file://shell.cfg', '', d)}" \ No newline at end of file diff --git a/meta-opencentauri/recipes-apps/mainsail/mainsail_2.17.0.bbappend b/meta-opencentauri/recipes-apps/mainsail/mainsail_2.17.0.bbappend new file mode 100644 index 00000000..283e49c7 --- /dev/null +++ b/meta-opencentauri/recipes-apps/mainsail/mainsail_2.17.0.bbappend @@ -0,0 +1,16 @@ +# bbappend for mainsail - allows installing only config without frontend +# Used by minimal image which needs mainsail.cfg macros but no web interface + +PACKAGECONFIG ??= "" +PACKAGECONFIG[config-only] = ",,," + +# When config-only is enabled, skip frontend installation +do_install:append() { + if ${@bb.utils.contains('PACKAGECONFIG', 'config-only', 'true', 'false', d)}; then + # Remove frontend files, keep only config + rm -rf ${D}/var/www/mainsail + fi +} + +# Adjust FILES when config-only is enabled +FILES:${PN}:remove = "${@bb.utils.contains('PACKAGECONFIG', 'config-only', '/var/www/mainsail', '', d)}" \ No newline at end of file diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 00000000..eab7d893 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,26 @@ +# OpenCentauri Build Tools + +This directory contains tools for building and testing OpenCentauri firmware images. + +## Directory Structure + +| Directory | Description | +|-----------|-------------| +| `local-build/` | Docker-based Yocto build environment for creating SWU update images | +| `local-mainsail/` | Mainsail web interface for HH-Minimal (required - no frontend on printer) | + +## Quick Start + +### Build SWU Images +```bash +cd local-build +./build.sh +``` + +### Run Local Mainsail for Minimal Image Testing +```bash +cd local-mainsail +./start.sh +``` + +See the README in each subdirectory for detailed instructions. \ No newline at end of file diff --git a/tools/local-build/.dockerignore b/tools/local-build/.dockerignore new file mode 100644 index 00000000..6ef76371 --- /dev/null +++ b/tools/local-build/.dockerignore @@ -0,0 +1,25 @@ +# Yocto Build-Verzeichnis (riesig, wird im Container neu gebaut) +build/ + +# Git +.git/ +.gitmodules + +# Cache (kann im Container neu erstellt werden) +cache/ + +# Logs (lokal, nicht im Container benötigt) +*.log +build-log.txt +build-docker-log.txt + +# IDE/Editor +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Temporäre Dateien +*.tmp +*.bak diff --git a/tools/local-build/Dockerfile b/tools/local-build/Dockerfile new file mode 100644 index 00000000..062d4d48 --- /dev/null +++ b/tools/local-build/Dockerfile @@ -0,0 +1,37 @@ +# OpenCentauri Yocto Build Environment +FROM ubuntu:22.04 + +ENV DEBIAN_FRONTEND=noninteractive + +# Install required packages +RUN apt-get update && apt-get install -y \ + gawk wget git diffstat unzip texinfo gcc build-essential \ + chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils \ + iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \ + pylint xterm python3-subunit mesa-common-dev zstd liblz4-tool file locales \ + bmap-tools sunxi-tools \ + clang libclang-dev \ + sudo vim nano curl \ + && rm -rf /var/lib/apt/lists/* + +# Generate required locales +RUN sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \ + locale-gen en_US.UTF-8 +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 + +# Create build user +RUN useradd -m -s /bin/bash builder && \ + echo "builder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +WORKDIR /home/builder + +# Set up environment +USER builder + +# Clone repository (will be overwritten by volume mount) +RUN git config --global user.email "builder@localhost" && \ + git config --global user.name "Builder" + +# Default command +CMD ["/bin/bash"] diff --git a/tools/local-build/README.md b/tools/local-build/README.md new file mode 100644 index 00000000..aac9ef80 --- /dev/null +++ b/tools/local-build/README.md @@ -0,0 +1,53 @@ +# Local Yocto Build Environment + +Docker-based build environment for creating OpenCentauri SWU update images. + +## Prerequisites + +- Docker installed and running +- Sufficient disk space (~50GB for full build) +- Internet connection for downloading sources + +## Usage + +### Build All SWU Images +```bash +./build.sh +``` + +This builds 3 SWU files: +- `opencentauri-upgrade-*.swu` - Standard (as defined in main, no Happy Hare) +- `opencentauri-upgrade-hh-full-*.swu` - Standard + Happy Hare + Mainsail +- `opencentauri-upgrade-hh-minimal-*.swu` - Happy Hare without web interface + +### Build Specific Image +```bash +./build.sh opencentauri-upgrade-hh-full +``` + +## Output Location + +Built images are located in: +``` +../../build/tmp/deploy/images/elegoo-centauri-carbon1/*.swu +``` + +## Cache + +Build cache is stored in `../../cache/` to speed up subsequent builds. + +## Clean Build + +To start a fresh build: +```bash +rm -rf ../../build ../../cache +./build.sh +``` + +## Files + +| File | Description | +|------|-------------| +| `Dockerfile` | Ubuntu 22.04 with Yocto build dependencies | +| `build.sh` | Main build script | +| `.dockerignore` | Excludes unnecessary files from Docker context | \ No newline at end of file diff --git a/tools/local-build/build.sh b/tools/local-build/build.sh new file mode 100755 index 00000000..8039c721 --- /dev/null +++ b/tools/local-build/build.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# OpenCentauri Docker Build Script + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +BUILD_DIR="$REPO_DIR/build" +CACHE_DIR="$REPO_DIR/cache" + +# Create directories +mkdir -p "$BUILD_DIR" "$CACHE_DIR" + +echo "========================================" +echo "OpenCentauri Docker Build" +echo "========================================" +echo "" + +# Build Docker image +echo "Building Docker image..." +docker build -t opencentauri-build "$SCRIPT_DIR" + +echo "" +echo "Starting Docker container..." +echo "" + +# Run Docker container with volume mounts +docker run --rm -i \ + -v "$REPO_DIR:/home/builder/opencentauri-repo" \ + -v "$CACHE_DIR:/home/builder/cache" \ + -w /home/builder/opencentauri-repo \ + opencentauri-build \ + /bin/bash -c ' + set -e + echo "" + echo "========================================" + echo "Initializing Yocto Build Environment" + echo "========================================" + + # Initialize submodules if not already done + if [ ! -d "poky" ]; then + echo "Initializing git submodules..." + git submodule update --init --recursive + fi + + # Source Yocto environment + source poky/oe-init-build-env build + + # Create site.conf for bindgen cross-compilation (not in repo, auto-included by bitbake) + cat > /home/builder/opencentauri-repo/build/conf/site.conf << 'SITECONF' +# Site-specific configuration (generated by Docker build.sh) +# This file is not in the repo and will not be committed. + +# Bindgen cross-compilation support +# clang needs ARM sysroot for cross-compilation (asm/types.h) +export BINDGEN_EXTRA_CLANG_ARGS = "--sysroot=\${RECIPE_SYSROOT}" +SITECONF + + echo "" + echo "========================================" + echo "Starting BitBake Build" + echo "========================================" + echo "" + + # Build SWUpdate images (pass any arguments or build all) + if [ -n "$1" ]; then + bitbake "$@" + else + bitbake \ + opencentauri-upgrade \ + opencentauri-upgrade-hh-full \ + opencentauri-upgrade-hh-minimal + fi + + echo "" + echo "========================================" + echo "Build Complete!" + echo "========================================" + echo "" + echo "Images location: /home/builder/opencentauri-repo/build/tmp/deploy/images/elegoo-centauri-carbon1/" + echo "" + echo "SWUpdate Images:" + ls -la /home/builder/opencentauri-repo/build/tmp/deploy/images/elegoo-centauri-carbon1/*.swu 2>/dev/null || true + + # Cleanup: remove site.conf + rm -f /home/builder/opencentauri-repo/build/conf/site.conf + echo "Cleaned up site.conf" + ' -- "$@" diff --git a/tools/local-mainsail/README.md b/tools/local-mainsail/README.md new file mode 100644 index 00000000..b62ab7b5 --- /dev/null +++ b/tools/local-mainsail/README.md @@ -0,0 +1,64 @@ +# Mainsail Frontend for HH-Minimal Image + +**Required** - Provides the web interface for HH-Minimal, which has no frontend installed on the printer. + +## Purpose + +The HH-Minimal image includes: +- Kalico + Happy Hare + Moonraker (API backend on port 80) +- **No web frontend** (Mainsail/Fluidd removed to save RAM) + +This container runs Mainsail locally on your PC and connects to the printer's moonraker API. + +## Prerequisites + +- Docker and docker-compose installed +- Printer running minimal image with moonraker accessible +- Network connection to printer + +## Configuration + +**IMPORTANT:** Edit `config.json` to set your printer's moonraker IP address before starting! + +Default config (adjust IP to your printer): +```json +{ + "instances": [ + { + "hostname": "192.168.1.100", + "port": 7125 + } + ] +} +``` + +## Usage + +### Start Mainsail +```bash +./start.sh +``` + +### Access Web Interface +Open browser: http://localhost:8080 + +### Stop Container +```bash +docker-compose down +``` + +## Files + +| File | Description | +|------|-------------| +| `docker-compose.yml` | Container configuration | +| `nginx.conf` | Nginx reverse proxy config | +| `config.json` | Moonraker host connection settings | +| `start.sh` | Startup script | + +## Benefits + +- Minimal image saves storage/RAM (no frontend) +- Full Mainsail interface available locally +- Can run on PC/laptop instead of printer +- Multiple printers can be configured \ No newline at end of file diff --git a/tools/local-mainsail/config.json b/tools/local-mainsail/config.json new file mode 100644 index 00000000..ad266884 --- /dev/null +++ b/tools/local-mainsail/config.json @@ -0,0 +1,8 @@ +{ + "instances": [ + { + "hostname": "192.168.1.100", + "port": 80 + } + ] +} \ No newline at end of file diff --git a/tools/local-mainsail/docker-compose.yml b/tools/local-mainsail/docker-compose.yml new file mode 100644 index 00000000..abb3a9be --- /dev/null +++ b/tools/local-mainsail/docker-compose.yml @@ -0,0 +1,10 @@ +services: + mainsail: + image: ghcr.io/mainsail-crew/mainsail:latest + container_name: mainsail + restart: unless-stopped + ports: + - "8080:80" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + - ./config.json:/usr/share/nginx/html/config.json:ro \ No newline at end of file diff --git a/tools/local-mainsail/nginx.conf b/tools/local-mainsail/nginx.conf new file mode 100644 index 00000000..5a5533b6 --- /dev/null +++ b/tools/local-mainsail/nginx.conf @@ -0,0 +1,65 @@ +worker_processes 1; +error_log /dev/stderr info; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log /dev/stdout; + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + upstream moonraker { + server 192.168.178.117:7125; + } + + server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + # Mainsail frontend + location / { + try_files $uri $uri/ /index.html; + } + + # Moonraker WebSocket + location /websocket { + proxy_pass http://moonraker/websocket; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 86400; + } + + # Moonraker API + location ~ ^/(printer|api|machine|server|access) { + proxy_pass http://moonraker; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Webcam stream + location /webcam/ { + proxy_pass http://moonraker/webcam/; + } + + # Webcam snapshot + location /webcam { + proxy_pass http://moonraker/webcam?action=stream; + } + } +} \ No newline at end of file diff --git a/tools/local-mainsail/start.sh b/tools/local-mainsail/start.sh new file mode 100755 index 00000000..cb2c2a08 --- /dev/null +++ b/tools/local-mainsail/start.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Start Mainsail container for minimal image frontend + +cd "$(dirname "$0")" + +echo "Starting Mainsail container..." +docker-compose up -d + +echo "" +echo "Mainsail is available at: http://localhost:8080" +echo "" +echo "Configure your printer's moonraker address in config.json" \ No newline at end of file From 070701a3c6ab3ae9609c539ba15de873d2e00009 Mon Sep 17 00:00:00 2001 From: boetti-dev Date: Fri, 17 Apr 2026 16:12:45 +0200 Subject: [PATCH 2/5] Add backlight-off init script for HH-Minimal - Turns off display backlight and blanks framebuffer after boot - Optimized for headless MMU operation without touchscreen - Added to opencentauri-image-hh-minimal.bb --- .../images/opencentauri-image-hh-minimal.bb | 1 + .../backlight-off/backlight-off.bb | 15 ++++++ .../backlight-off/files/backlight-off.init | 47 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 meta-opencentauri/recipes-core/backlight-off/backlight-off.bb create mode 100644 meta-opencentauri/recipes-core/backlight-off/files/backlight-off.init diff --git a/meta-opencentauri/images/opencentauri-image-hh-minimal.bb b/meta-opencentauri/images/opencentauri-image-hh-minimal.bb index fbe7fbd7..3d150226 100644 --- a/meta-opencentauri/images/opencentauri-image-hh-minimal.bb +++ b/meta-opencentauri/images/opencentauri-image-hh-minimal.bb @@ -46,6 +46,7 @@ CORE_IMAGE_EXTRA_INSTALL += "\ logrotate \ happy-hare \ mainsail \ + backlight-off \ " # zram auf 200% für MMU-Betrieb (ausgewogen für 128MB RAM = 256MB Swap) diff --git a/meta-opencentauri/recipes-core/backlight-off/backlight-off.bb b/meta-opencentauri/recipes-core/backlight-off/backlight-off.bb new file mode 100644 index 00000000..150caa72 --- /dev/null +++ b/meta-opencentauri/recipes-core/backlight-off/backlight-off.bb @@ -0,0 +1,15 @@ +SUMMARY = "Turn off display for headless operation" +DESCRIPTION = "Init script to disable display backlight and blank framebuffer \ + after boot for headless MMU setups without touchscreen interface." + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" + +SRC_URI = "file://backlight-off.init" + +inherit update-rc.d + +INITSCRIPT_NAME = "backlight-off" +INITSCRIPT_PARAMS = "start 99 S . stop 10 0 ." + +RDEPENDS:${PN} = "" \ No newline at end of file diff --git a/meta-opencentauri/recipes-core/backlight-off/files/backlight-off.init b/meta-opencentauri/recipes-core/backlight-off/files/backlight-off.init new file mode 100644 index 00000000..a1525c5c --- /dev/null +++ b/meta-opencentauri/recipes-core/backlight-off/files/backlight-off.init @@ -0,0 +1,47 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: backlight-off +# Required-Start: $local_fs +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Turn off display for headless operation +# Description: Turns off display backlight and blanks framebuffer +# after boot for headless MMU setups. +### END INIT INFO + +case "$1" in + start) + # Wait for system to settle + sleep 2 + + # Blank framebuffer (stops display controller) + if [ -e /sys/class/graphics/fb0/blank ]; then + echo 1 > /sys/class/graphics/fb0/blank + fi + + # Turn off backlight + if [ -d /sys/class/backlight/backlight ]; then + echo 0 > /sys/class/backlight/backlight/brightness + fi + ;; + stop) + # Restore display for clean shutdown + if [ -e /sys/class/graphics/fb0/blank ]; then + echo 0 > /sys/class/graphics/fb0/blank + fi + if [ -d /sys/class/backlight/backlight ]; then + echo 1 > /sys/class/backlight/backlight/brightness + fi + ;; + restart|force-reload) + $0 stop + $0 start + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 + ;; +esac + +exit 0 \ No newline at end of file From 967d57e627d396a24a5f64c3d7958cfcff76ad14 Mon Sep 17 00:00:00 2001 From: boetti-dev Date: Fri, 17 Apr 2026 18:38:10 +0200 Subject: [PATCH 3/5] Fix backlight-off package: add do_install and clean before build - Add do_install task to properly install init script - Clean backlight-off before build to ensure IPK is created - Package now correctly includes /etc/init.d/backlight-off --- .../recipes-core/backlight-off/backlight-off.bb | 9 +++++++++ tools/local-build/build.sh | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/meta-opencentauri/recipes-core/backlight-off/backlight-off.bb b/meta-opencentauri/recipes-core/backlight-off/backlight-off.bb index 150caa72..5c877a41 100644 --- a/meta-opencentauri/recipes-core/backlight-off/backlight-off.bb +++ b/meta-opencentauri/recipes-core/backlight-off/backlight-off.bb @@ -7,9 +7,18 @@ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda SRC_URI = "file://backlight-off.init" +S = "${WORKDIR}" + +do_install() { + install -d ${D}${sysconfdir}/init.d + install -m 0755 ${WORKDIR}/backlight-off.init ${D}${sysconfdir}/init.d/backlight-off +} + inherit update-rc.d INITSCRIPT_NAME = "backlight-off" INITSCRIPT_PARAMS = "start 99 S . stop 10 0 ." +FILES:${PN} = "${sysconfdir}/init.d/backlight-off" + RDEPENDS:${PN} = "" \ No newline at end of file diff --git a/tools/local-build/build.sh b/tools/local-build/build.sh index 8039c721..ba0bc4f6 100755 --- a/tools/local-build/build.sh +++ b/tools/local-build/build.sh @@ -62,6 +62,10 @@ SITECONF echo "========================================" echo "" + # Clean and rebuild backlight-off to ensure IPK is available + bitbake backlight-off -c clean + bitbake backlight-off + # Build SWUpdate images (pass any arguments or build all) if [ -n "$1" ]; then bitbake "$@" From fc1c0d37a669fbf34780c449a0277b5df35324f2 Mon Sep 17 00:00:00 2001 From: boetti-dev Date: Fri, 17 Apr 2026 22:23:40 +0200 Subject: [PATCH 4/5] Update MMU config files and nginx config --- .../happy-hare/files/mmu.cfg.erb-v2 | 86 ---------- .../files/mmu/base/mmu_hardware.cfg | 16 +- .../happy-hare/files/mmu_hardware.cfg.erb-v2 | 136 ---------------- .../files/mmu_parameters.cfg.erb-v2 | 150 ------------------ .../recipes-apps/happy-hare/happy-hare_git.bb | 5 +- .../recipes-apps/klipper/files-hh/macros.cfg | 3 +- tools/local-mainsail/nginx.conf | 4 +- 7 files changed, 11 insertions(+), 389 deletions(-) delete mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 delete mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 delete mode 100644 meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 b/meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 deleted file mode 100644 index 232fbbe3..00000000 --- a/meta-opencentauri/recipes-apps/happy-hare/files/mmu.cfg.erb-v2 +++ /dev/null @@ -1,86 +0,0 @@ -# Happy Hare MMU Konfiguration für FYSETC ERB V2.0 -# Elegoo Centauri Carbon 1 (128MB RAM optimiert) -# -# Diese Datei definiert die MCU und Pin-Zuordnungen für das ERB V2.0 Board -# - -# MCU-Definition für FYSETC ERB V2.0 (RP2040) -[mcu mmu] -serial: /dev/serial/by-id/usb-Klipper_RP2040_* - -# Board-Pin-Aliase für FYSETC ERB V2.0 -# Alle Pins verwenden die RP2040 GPIO-Nummern -[board_pins erb] -mcu: mmu - -# Gear Stepper Pins (Antriebsmotor für Filament) -[stepper_mmu_gear] -step_pin: mmu:gpio10 -dir_pin: !mmu:gpio9 -enable_pin: !mmu:gpio8 -uart_pin: mmu:gpio11 -uart_address: 0 - -# Selector Stepper Pins (Gate-Auswahl) -[stepper_mmu_selector] -step_pin: mmu:gpio16 -dir_pin: !mmu:gpio15 -enable_pin: !mmu:gpio14 -uart_pin: mmu:gpio17 -uart_address: 1 -endstop_pin: ^mmu:gpio24 - -# Selector Servo (PWM für Gate-Verriegelung) -[mmu_servo selector_servo] -pin: mmu:gpio23 -minimum_pulse_width: 0.001000 -maximum_pulse_width: 0.002000 -maximum_servo_angle: 180 - -# Encoder (Filamentbewegungsmessung) -[mmu_encoder mmu_encoder] -encoder_pin: ^mmu:gpio22 -# RAM-Optimierung: Reduzierte Auflösung für weniger Memory -encoder_resolution: 1.0 - -# Neopixel LEDs (Status-Anzeige pro Gate) -[neopixel mmu_leds] -pin: mmu:gpio21 -chain_count: 12 -color_order: GRB -initial_RED: 0.0 -initial_GREEN: 0.5 -initial_BLUE: 0.0 - -# Gate Sensor (Hall-Effekt Sensor für Filament-Erkennung) -[mmu_sensors] -gate_switch_pin: ^mmu:gpio25 - -# Pre-Gate Sensoren (Filamentpräsenz an jedem Gate) -# GPIO-Pins für 12 Gates (ERCF v2 Standard) -pre_gate_switch_pin_0: ^mmu:gpio12 -pre_gate_switch_pin_1: ^mmu:gpio18 -pre_gate_switch_pin_2: ^mmu:gpio2 -pre_gate_switch_pin_3: ^mmu:gpio3 -pre_gate_switch_pin_4: ^mmu:gpio4 -pre_gate_switch_pin_5: ^mmu:gpio5 -pre_gate_switch_pin_6: ^mmu:gpio6 -pre_gate_switch_pin_7: ^mmu:gpio7 -pre_gate_switch_pin_8: ^mmu:gpio26 -pre_gate_switch_pin_9: ^mmu:gpio27 -pre_gate_switch_pin_10: ^mmu:gpio28 -pre_gate_switch_pin_11: ^mmu:gpio29 - -# RAM-Optimierung: Deaktiviere nicht genutzte Gates -# Wenn du weniger als 12 Gates verwendest, kommentiere die nicht benötigten Pins aus -# Beispiel für 6-Gate-System: -#pre_gate_switch_pin_6: -#pre_gate_switch_pin_7: -#pre_gate_switch_pin_8: -#pre_gate_switch_pin_9: -#pre_gate_switch_pin_10: -#pre_gate_switch_pin_11: - -# Toolhead und Extruder Sensoren (optional) -#extruder_switch_pin: ^mmu:gpio1 -#toolhead_switch_pin: ^mmu:gpio0 diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg index 4d6b2c64..f02651b3 100644 --- a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_hardware.cfg @@ -303,8 +303,8 @@ sync_feedback_compression_pin: # (comment out this section if you don't have leds) [neopixel mmu_leds] pin: mmu:MMU_NEOPIXEL -chain_count: 25 # Number gates x1 or x2 + 1 (if you want status) -color_order: GRBW # Set based on your particular neopixel specification +chain_count: 24 # Number gates x1 or x2 + 1 (if you want status) +color_order: GRB # Set based on your particular neopixel specification # MMU LED EFFECT SEGMENTS ---------------------------------------------------------------------------------------------- # Define neopixel LEDs for your MMU. The chain_count must be large enough for your desired ranges: @@ -327,14 +327,12 @@ color_order: GRBW # Set based on your particular neopixel specification # but mapped to increasing or decreasing gates respectively # # Note that Happy Hare provides a convenience wrapper [mmu_led_effect] that not only creates an effect on each of the -# [mmu_leds] specified segments but also each individual LED for atomic control. See mmu_leds.cfg for examples +# [mmu_leds unit0] specified segments but also each individual LED for atomic control. See mmu_leds.cfg for examples # # (this section is harmless and ignored if the 'led_strip' above doesn't exist - LED support will simply be disabled) -# v3.4: Section name required for multiple MMU units support -[mmu_leds primary] -led_strip: neopixel:mmu_leds -exit_range: 1-12 -entry_range: 24-13 -status_index: 25 +[mmu_leds unit0] +exit_leds: neopixel:mmu_leds (12-1) +entry_leds: neopixel:mmu_leds (13-24) +status_leds: frame_rate: 24 diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 b/meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 deleted file mode 100644 index 5ae525d4..00000000 --- a/meta-opencentauri/recipes-apps/happy-hare/files/mmu_hardware.cfg.erb-v2 +++ /dev/null @@ -1,136 +0,0 @@ -# Happy Hare Hardware Konfiguration für FYSETC ERB V2.0 -# Elegoo Centauri Carbon 1 (128MB RAM optimiert) -# -# Diese Datei enthält die Motor-Treiber und mechanischen Einstellungen -# - -# ============================================================================= -# TMC2209 Treiber-Konfiguration -# ============================================================================= - -# Gear Stepper (TMC2209 onboard) -[tmc2209 stepper_mmu_gear] -uart_pin: mmu:gpio11 -uart_address: 0 -interpolate: false # RAM-Optimierung: Weniger Interpolation -run_current: 0.8 # Anpassen an Motor (NEMA14 typisch: 0.6-1.0A) -hold_current: 0.4 # 50% von run_current -sense_resistor: 0.110 -stealthchop_threshold: 0 # Force SpreadCycle für bessere Kontrolle -# Optional für Touch Homing (StallGuard): -#diag_pin: ^mmu:gpio13 -#driver_SGTHRS: 60 - -# Selector Stepper (TMC2209 onboard) -[tmc2209 stepper_mmu_selector] -uart_pin: mmu:gpio17 -uart_address: 1 -interpolate: false # RAM-Optimierung -run_current: 0.6 # NEMA17 typisch: 0.5-0.8A -hold_current: 0.3 # 50% von run_current -sense_resistor: 0.110 -stealthchop_threshold: 100 # StealthChop im Home für leisere Operation -# Optional für Touch Homing: -#diag_pin: ^mmu:gpio19 -#driver_SGTHRS: 55 - -# ============================================================================= -# Mechanische Konfiguration -# ============================================================================= - -# Gear Stepper Mechanik -[stepper_mmu_gear] -rotation_distance: 22.7316868 # Bondtech 5mm Drive Gears -# Alternative für andere Getriebe: -#rotation_distance: 6.283185307179586 # Direktantrieb -microsteps: 16 -full_steps_per_rotation: 200 -# Gear Ratio für ERCF v2: -# 80:1 für Selector, 52:10 für Gear (abhängig vom Build) - -# Selector Stepper Mechanik -[stepper_mmu_selector] -rotation_distance: 40 # Anpassen an tatsächliche Distanz pro Rotation -microsteps: 16 -full_steps_per_rotation: 200 -# Endstop für Selector Homing -endstop_pin: ^mmu:gpio24 -endstop_name: mmu_selector_endstop - -# ============================================================================= -# Servo-Konfiguration -# ============================================================================= - -# Selector Servo (Gate-Verriegelung) -[mmu_servo selector_servo] -pin: mmu:gpio23 -minimum_pulse_width: 0.001000 -maximum_pulse_width: 0.002000 -maximum_servo_angle: 180 -# Servo-Positionen (werden in mmu_parameters.cfg überschrieben) -#up_angle: 90 -#down_angle: 0 - -# ============================================================================= -# Encoder-Konfiguration -# ============================================================================= - -# Encoder für Filamentbewegungsmessung -[mmu_encoder mmu_encoder] -encoder_pin: ^mmu:gpio22 -encoder_resolution: 1.0 # mm pro Count (wird kalibriert) -# RAM-Optimierung: Weniger Samples für weniger Memory -#sample_time: 0.1 - -# ============================================================================= -# LED-Konfiguration -# ============================================================================= - -# Neopixel LEDs für Status-Anzeige -[neopixel mmu_leds] -pin: mmu:gpio21 -chain_count: 12 # Anzahl Gates (anpassen: 6 oder 12) -color_order: GRB -initial_RED: 0.0 -initial_GREEN: 0.5 -initial_BLUE: 0.0 - -# ============================================================================= -# Sensor-Konfiguration -# ============================================================================= - -# Alle Filament-Sensoren -[mmu_sensors] -# Gate Sensor (Hall-Effekt, gemeinsamer Sensor) -gate_switch_pin: ^mmu:gpio25 - -# Pre-Gate Sensoren (individuell pro Gate) -pre_gate_switch_pin_0: ^mmu:gpio12 -pre_gate_switch_pin_1: ^mmu:gpio18 -pre_gate_switch_pin_2: ^mmu:gpio2 -pre_gate_switch_pin_3: ^mmu:gpio3 -pre_gate_switch_pin_4: ^mmu:gpio4 -pre_gate_switch_pin_5: ^mmu:gpio5 -pre_gate_switch_pin_6: ^mmu:gpio6 -pre_gate_switch_pin_7: ^mmu:gpio7 -pre_gate_switch_pin_8: ^mmu:gpio26 -pre_gate_switch_pin_9: ^mmu:gpio27 -pre_gate_switch_pin_10: ^mmu:gpio28 -pre_gate_switch_pin_11: ^mmu:gpio29 - -# Post-Gear Sensoren (optional, nach dem Getriebe) -#post_gear_switch_pin_0: -#post_gear_switch_pin_1: -#post_gear_switch_pin_2: -#post_gear_switch_pin_3: -#post_gear_switch_pin_4: -#post_gear_switch_pin_5: - -# Toolhead/Extruder Sensoren (optional) -#extruder_switch_pin: -#toolhead_switch_pin: - -# Sync Feedback (optional für Spannungs-/Druckmessung) -#sync_feedback_tension_pin: -#sync_feedback_compression_pin: -#sync_feedback_analog_pin: diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 b/meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 deleted file mode 100644 index 444f9b22..00000000 --- a/meta-opencentauri/recipes-apps/happy-hare/files/mmu_parameters.cfg.erb-v2 +++ /dev/null @@ -1,150 +0,0 @@ -# Happy Hare Parameter-Konfiguration für FYSETC ERB V2.0 -# Elegoo Centauri Carbon 1 (128MB RAM optimiert) -# -# Diese Datei enthält Happy Hare-spezifische Parameter -# RAM-optimierte Einstellungen für 128MB Systeme -# - -[mmu_parameters] -# ============================================================================= -# Grundlegende Einstellungen -# ============================================================================= - -# Firmware-Modus (1 = Full MMU, 2 = Gate Selector nur) -mmu_mode: 1 - -# Anzahl der Gates (anpassen an Build: 6 oder 12) -gate_total: 12 - -# Standard-Gate für Tests -gate_default: 0 - -# ============================================================================= -# RAM-Optimierungen (KRITISCH für 128MB Systeme) -# ============================================================================= - -# Reduziere Cache-Größe für Gate-Map (6 statt 12 für 6-Gate-System) -gate_map_cache_size: 6 - -# Sensor-Update-Rate reduzieren (50 Hz statt 100 Hz) -sensor_update_rate: 50 - -# Bewegungspuffer reduzieren -movement_buffer_size: 50 - -# Encoder-Sample-Zeit reduzieren -encoder_sample_time: 0.1 - -# ============================================================================= -# Motor-Einstellungen -# ============================================================================= - -# Gear Motor Geschwindigkeit (mm/s) -gear_speed: 50 - -# Gear Motor Beschleunigung (mm/s²) -gear_accel: 200 - -# Selector Motor Geschwindigkeit (mm/s) -selector_speed: 80 - -# Selector Motor Beschleunigung (mm/s²) -selector_accel: 400 - -# ============================================================================= -# Filament-Einstellungen -# ============================================================================= - -# Filament-Durchmesser (mm) -filament_diameter: 1.75 - -# Maximale Filament-Länge (mm) -filament_max_length: 1000 - -# Minimale Filament-Länge für Loading (mm) -filament_min_load_length: 50 - -# ============================================================================= -# Sensor-Einstellungen -# ============================================================================= - -# Gate Sensor Timeout (ms) -gate_sensor_timeout: 500 - -# Encoder Timeout für Bewegung (ms) -encoder_timeout: 2000 - -# Pre-Gate Sensor aktiviert (true/false) -pre_gate_sensors_enabled: true - -# ============================================================================= -# Servo-Einstellungen -# ============================================================================= - -# Servo Up-Position (Gate offen) -servo_up_angle: 90 - -# Servo Down-Position (Gate geschlossen) -servo_down_angle: 0 - -# Servo Bewgungsgeschwindigkeit (ms) -servo_move_time: 200 - -# ============================================================================= -# LED-Einstellungen -# ============================================================================= - -# LED Helligkeit (0.0 - 1.0) -led_brightness: 0.5 - -# LED Animation aktivieren -led_animation_enabled: true - -# LED Animation Geschwindigkeit (ms) -led_animation_speed: 100 - -# ============================================================================= -# Homing-Einstellungen -# ============================================================================= - -# Homing Methode (endstop, current, stallguard) -homing_method: endstop - -# Homing Geschwindigkeit (mm/s) -homing_speed: 30 - -# Homing Retract Distanz (mm) -homing_retract_dist: 5 - -# ============================================================================= -# Error-Handling -# ============================================================================= - -# Maximale Fehler vor Stop -max_errors_before_stop: 3 - -# Error-Reset nach (Sekunden) -error_reset_time: 60 - -# ============================================================================= -# Logging (RAM-optimiert) -# ============================================================================= - -# Log-Level (0 = minimal, 1 = normal, 2 = debug) -log_level: 1 - -# Log-File aktivieren (false für weniger I/O) -log_file_enabled: false - -# ============================================================================= -# Advanced (nicht ändern außer bei Problemen) -# ============================================================================= - -# MMU Timeout für Operationen (ms) -mmu_operation_timeout: 10000 - -# Retry-Versuche bei Fehlern -retry_attempts: 2 - -# Retry-Verzögerung (ms) -retry_delay: 500 diff --git a/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb b/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb index 50601ecb..c4150115 100644 --- a/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb +++ b/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb @@ -9,9 +9,6 @@ FILESEXTRAPATHS:prepend := "${THISDIR}/files:" SRC_URI = "git://github.com/moggieuk/Happy-Hare.git;protocol=https;branch=main \ file://mmu \ - file://mmu.cfg.erb-v2 \ - file://mmu_hardware.cfg.erb-v2 \ - file://mmu_parameters.cfg.erb-v2 \ file://happy-hare-init \ " @@ -121,4 +118,4 @@ do_install:append() { } # Nur auf Centauri Carbon 1 bauen (128MB RAM) -COMPATIBLE_MACHINE = "elegoo-centauri-carbon1" \ No newline at end of file +COMPATIBLE_MACHINE = "elegoo-centauri-carbon1" diff --git a/meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg b/meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg index 049d7fa2..9b6ccb34 100644 --- a/meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg +++ b/meta-opencentauri/recipes-apps/klipper/files-hh/macros.cfg @@ -433,7 +433,6 @@ gcode: RESPOND TYPE=command MSG="action:prompt_end" [gcode_macro SET_DISPLAY_TEXT_COSMOS] -rename_existing: SET_DISPLAY_TEXT_BASE gcode: {% set message = params.MSG|default('') %} @@ -542,4 +541,4 @@ gcode: RESPOND TYPE=command MSG="action:prompt_footer_button Bypass Calibration|_INITIAL_CALIBRATION_ACTION_LATER|warning" RESPOND TYPE=command MSG="action:prompt_footer_button Calibrate Printer|FULL_CALIBRATION|primary" RESPOND TYPE=command MSG="action:prompt_show" - {% endif %} \ No newline at end of file + {% endif %} diff --git a/tools/local-mainsail/nginx.conf b/tools/local-mainsail/nginx.conf index 5a5533b6..6faacfb7 100644 --- a/tools/local-mainsail/nginx.conf +++ b/tools/local-mainsail/nginx.conf @@ -16,7 +16,7 @@ http { } upstream moonraker { - server 192.168.178.117:7125; + server 192.168.178.117:80; } server { @@ -62,4 +62,4 @@ http { proxy_pass http://moonraker/webcam?action=stream; } } -} \ No newline at end of file +} From ba7fd1b98f5d419009f618e4b4b9c867b546344c Mon Sep 17 00:00:00 2001 From: boetti-dev Date: Sat, 18 Apr 2026 09:29:46 +0200 Subject: [PATCH 5/5] Replace mainsail with mainsail-config and move mmu_vars.cfg - Create mainsail-config package (only macros, no frontend) - Remove mainsail frontend from HH-Minimal (re-remove after accidental add) - Move mmu_vars.cfg from mmu/ subdir to config/ to prevent overwrite by updates - Update save_variables path in mmu_macro_vars.cfg --- .../images/opencentauri-image-hh-minimal.bb | 4 +--- .../files/mmu/base/mmu_macro_vars.cfg | 2 +- .../recipes-apps/happy-hare/happy-hare_git.bb | 5 +++-- .../recipes-apps/mainsail/mainsail-config.bb | 21 +++++++++++++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 meta-opencentauri/recipes-apps/mainsail/mainsail-config.bb diff --git a/meta-opencentauri/images/opencentauri-image-hh-minimal.bb b/meta-opencentauri/images/opencentauri-image-hh-minimal.bb index 3d150226..6bcdab5d 100644 --- a/meta-opencentauri/images/opencentauri-image-hh-minimal.bb +++ b/meta-opencentauri/images/opencentauri-image-hh-minimal.bb @@ -13,8 +13,6 @@ inherit core-image # Enable MMU/COSMOS macros for this image PACKAGECONFIG:pn-kalico = "opencentauri-hh-minimal" -# Mainsail config only (no frontend) - macros needed for Klipper -PACKAGECONFIG:pn-mainsail = "config-only" IMAGE_FEATURES += "ssh-server-dropbear" @@ -45,7 +43,7 @@ CORE_IMAGE_EXTRA_INSTALL += "\ update-scripts \ logrotate \ happy-hare \ - mainsail \ + mainsail-config \ backlight-off \ " diff --git a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg index 8fdb0d77..815ef354 100644 --- a/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg +++ b/meta-opencentauri/recipes-apps/happy-hare/files/mmu/base/mmu_macro_vars.cfg @@ -28,7 +28,7 @@ # have one you will need to merge the two and point this appropriately. # [save_variables] -filename: /etc/klipper/config/mmu/mmu_vars.cfg +filename: /etc/klipper/config/mmu_vars.cfg # NECESSARY KLIPPER OVERRIDES --------------------------------------------- diff --git a/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb b/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb index c4150115..b9177981 100644 --- a/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb +++ b/meta-opencentauri/recipes-apps/happy-hare/happy-hare_git.bb @@ -82,7 +82,7 @@ do_install() { cp -r ${WORKDIR}/mmu/optional/*.cfg ${D}${sysconfdir}/klipper/config/mmu/optional/ 2>/dev/null || true fi if [ -f "${WORKDIR}/mmu/mmu_vars.cfg" ]; then - install -m 0644 ${WORKDIR}/mmu/mmu_vars.cfg ${D}${sysconfdir}/klipper/config/mmu/mmu_vars.cfg + install -m 0644 ${WORKDIR}/mmu/mmu_vars.cfg ${D}${sysconfdir}/klipper/config/mmu_vars.cfg fi # Install Init-Skript für Setup @@ -99,6 +99,7 @@ FILES:${PN} = " \ ${datadir}/klipper/klippy/extras/mmu.py \ ${sysconfdir}/klipper/config/happy-hare \ ${sysconfdir}/klipper/config/mmu \ + ${sysconfdir}/klipper/config/mmu_vars.cfg \ ${sysconfdir}/init.d/happy-hare-setup \ /home/mainsail/Happy-Hare \ " @@ -108,7 +109,7 @@ FILES:${PN} += "${datadir}/klipper" # Config files that should be editable (like printer.cfg) CONFFILES:${PN} = " \ - ${sysconfdir}/klipper/config/mmu/mmu_vars.cfg \ + ${sysconfdir}/klipper/config/mmu_vars.cfg \ " # Memory-Optimierung: Strip Python-Bytecode diff --git a/meta-opencentauri/recipes-apps/mainsail/mainsail-config.bb b/meta-opencentauri/recipes-apps/mainsail/mainsail-config.bb new file mode 100644 index 00000000..da1f012e --- /dev/null +++ b/meta-opencentauri/recipes-apps/mainsail/mainsail-config.bb @@ -0,0 +1,21 @@ +SUMMARY = "Mainsail config macros for Klipper" +DESCRIPTION = "Provides mainsail.cfg macros (PAUSE, RESUME, CANCEL_PRINT) \ + without the web frontend for headless operation." + +LICENSE = "GPL-3.0-only" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-3.0-only;md5=c79ff39f19dfec6d293b95dea7b07891" + +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +SRC_URI = "file://mainsail.cfg" + +S = "${WORKDIR}" + +do_install() { + install -d ${D}${sysconfdir}/klipper/config/klipper-readonly + install -m 0644 ${WORKDIR}/mainsail.cfg ${D}${sysconfdir}/klipper/config/klipper-readonly/ +} + +FILES:${PN} = "${sysconfdir}/klipper/config/klipper-readonly/mainsail.cfg" + +RDEPENDS:${PN} = "kalico" \ No newline at end of file