Showing preview only (756K chars total). Download the full file or copy to clipboard to get everything.
Repository: Phil1988/FreeDi
Branch: master
Commit: 4a6b6b2774e7
Files: 59
Total size: 15.9 MB
Directory structure:
gitextract_3uvhfo04/
├── .github/
│ ├── FUNDING.yml
│ └── ISSUE_TEMPLATE/
│ ├── bug-report.md
│ ├── feature_request.md
│ └── getting-help.md
├── FreeDiLCD/
│ ├── LICENSE
│ ├── freedi_update.sh
│ └── start.py
├── LICENSE
├── README.md
├── config_section/
│ ├── Plus4/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── Q1_Pro/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── X-Max3/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── X-Plus3/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── X-Smart3/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── generic/
│ │ ├── crowsnest.conf
│ │ ├── freedi.cfg
│ │ └── moonraker.conf
│ └── template/
│ ├── macros.cfg
│ └── printer.cfg
├── helpers/
│ ├── AutoFlasher.service
│ ├── FreeDi.service
│ ├── dtbo/
│ │ └── rockchip-mkspi-uart1.dtbo
│ ├── flashtool.py
│ ├── freedi-prerequisites-1.0-all.deb
│ ├── hid-flash
│ ├── klipper_auto_flasher.sh
│ ├── usbmounter.sh
│ └── wifi/
│ └── aic8800-dkms.deb
├── install/
│ ├── freedi_install.conf
│ ├── packages.sh
│ └── wifi.sh
├── install.sh
├── klipper_module/
│ ├── freedi.py
│ └── qidi_auto_z_offset/
│ ├── LICENSE
│ ├── README.md
│ └── auto_z_offset.py
├── mainboard_and_toolhead_firmwares/
│ └── v0.13.0-154/
│ ├── Toolhead_Q1_katapult.uf2
│ ├── Toolhead_X3.uf2
│ └── flash_nuke.uf2
├── old_mainboard_and_toolhead_firmwares/
│ └── v0.10.0-530_old_stock/
│ └── Toolhead_RP2040.uf2
├── presliced_z-offset_calibration_files/
│ ├── Plus4/
│ │ └── z-offset_calibration_Plus4_PLA_4m4s.gcode
│ ├── Q1_Pro/
│ │ └── z-offset_calibration_Q1_Pro_PLA_4m6s.gcode
│ ├── X-Max3/
│ │ └── z-offset_calibration_X-Max3_PLA_8m46s.gcode
│ ├── X-Plus3/
│ │ └── z-offset_calibration_X-Plus3_PLA_4m4s.gcode
│ └── X-Smart3/
│ └── z-offset_calibration_X-Smart3_PLA_8m38s.gcode
├── requirements.txt
├── screen_firmwares/
│ ├── q1_pro_stable_v2.08.tft
│ ├── x-plus3_x-max3_plus4_stable_v2.08.tft
│ └── x-smart3_stable_v2.08.tft
└── themes/
├── Plus4/
│ └── .theme/
│ └── custom.css
├── Q1_Pro/
│ └── .theme/
│ └── custom.css
├── X-Max3/
│ └── .theme/
│ └── custom.css
├── X-Plus3/
│ └── .theme/
│ └── custom.css
└── X-Smart3/
└── .theme/
└── custom.css
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: coco33 # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom:
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug report
about: Create a report to help me improve
title: "[Bug]"
labels: ''
assignees: Phil1988
---
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
If not self self-explanatory, add a clear and concise description of what you expected to happen.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Screenshots or picture**
If applicable, add screenshots to help explain your problem.
**Console output**
If applicable, add the debug console output here (here is a [how to](https://github.com/Phil1988/FreeDi/wiki/Bugs!))
**Base (please complete the following information):**
- Printer model: [eg. X-Plus 3]
- X3seriesLCD firmware version: [e.g. v1.00 stable]
- Source: [eg. self configured or FreeDi image]
- Mainboard: [eg. stock Mainboard X-4 / other]
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: "[Feature request]"
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is.
**Describe the feature you'd like**
A clear and concise description of what you want to happen.
================================================
FILE: .github/ISSUE_TEMPLATE/getting-help.md
================================================
---
name: Getting help
about: Describe this issue template's purpose here.
title: "[Help]"
labels: ''
assignees: ''
---
If you are facing issues (especially during the first installation), please share important information to let me understand your current status.
This may include...
**How did you install it?** (Did you use the full image? Did it on your own? ...)
**What have you done?** (describe exactly please. step by step)
**What kind of messages/responses/feedback did you get?** (command line responses, error messages in the Screen/on Mainsail etc.)
And sometimes a **printer.cfg** is handy, which can be included here as renamed to *.txt or zipped.
In general:
**Anything you think is helpful for me to understand your problem and how you got there :)**
================================================
FILE: FreeDiLCD/LICENSE
================================================
Copyright (c) 2024,
https://github.com/Phil1988 [C0co].
All rights reserved.
Custom License Agreement
Version 1.0, September 2024
1. Permission and Usage
You are hereby granted permission to use, copy, and distribute unmodified
copies of this software, subject to the following conditions:
- Commercial use of the software is prohibited without prior written
permission from the original author. To request permission, please
contact the author via their GitHub profile.
- For the purpose of this license, "commercial use" refers to any use
of the software in a manner that is intended for or directed toward
commercial advantage or monetary compensation.
- You may not modify, merge, or publish derivative works based on this
software without prior written permission from the original author.
- Any redistribution of this software, with or without modification,
must include a clear and visible acknowledgment of the original author
in the documentation and/or other materials provided with the distribution.
- Redistribution of this software under different licensing terms is not
permitted without prior written permission from the original author.
- If you modify the source code, you must notify the original author of
the changes made and provide feedback through GitHub.
2. Attribution
When redistributing the software, you must retain the following:
- The original author's name and copyright notice must be included in all
copies or substantial portions of the software.
- Clear acknowledgment must be given to the original author(s) in any
documentation or software release notes.
3. No Warranty
This software is provided "as-is," without any express or implied warranties.
In no event shall the author be held liable for any damages arising from the
use of the software, including but not limited to direct, indirect,
incidental, special, exemplary, or consequential damages.
4. No Patent Rights
No patent rights are granted under this license. You may not use this software
to apply for any patent or related intellectual property rights.
5. Limitation of Liability
In no event shall the author be liable for any claims, damages, or other
liabilities, whether in an action of contract, tort, or otherwise, arising
from, out of, or in connection with the software or the use or other
dealings in the software.
6. Indemnification
You agree to indemnify and hold the author harmless from and against any and
all claims, losses, damages, liabilities, costs, and expenses, including
attorneys' fees, arising out of or related to your use or distribution of
the software.
7. Reverse Engineering and Decompilation
You may not reverse engineer, decompile, or disassemble the software, except
to the extent that such activity is expressly permitted by applicable law.
8. Security Vulnerabilities
Users are encouraged to report any security vulnerabilities or issues found
in the software to the author via GitHub for assessment and remediation.
9. Termination
Any violation of the terms of this license will result in the immediate
termination of the rights granted herein.
10. Global Applicability
This license is intended to be globally applicable, subject to the laws and
regulations of the relevant jurisdictions.
11. Severability
If any provision of this License is held to be unenforceable or invalid,
such provision will be modified to the extent necessary to make it enforceable
and valid, and the remaining provisions will remain in effect.
12. Governing Law
This License shall be governed by and construed in accordance with the laws
of germany, without regard to its conflict of law principles.
By using, modifying, or distributing the software, you acknowledge that you have
read, understood, and agreed to be bound by these terms.
Author: https://github.com/Phil1988 [C0co]
Date: September 1, 2024
================================================
FILE: FreeDiLCD/freedi_update.sh
================================================
#!/bin/bash
# to delete '\r' signs use
# sed -i 's/\r$//' freedi_update.sh
# Set variables
echo "Starting the FreeDi update process..."
SERVICE="FreeDi.service"
# ── Directory layout ─────────────────────────────────────────────────────────────
SCRIPT_DIR="$( cd -- "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd -P )" # /home/<user>/FreeDi/FreeDiLCD
FREEDI_DIR="$( dirname "${SCRIPT_DIR}" )" # /home/<user>/FreeDi
USER_HOME_DIR="$( dirname "${FREEDI_DIR}" )" # /home/<user>
USER_NAME="$( basename "${USER_HOME_DIR}" )" # The last path component is the user name -> <user>
USER_GROUP="$( id -gn "${USER_NAME}" )" # The group name of the user
FREEDI_LCD_DIR="${FREEDI_DIR}/FreeDiLCD"
REPO_MODULE_DIR="${FREEDI_DIR}/klipper_module"
LCD_FIRMWARE_DIR="${FREEDI_DIR}/screen_firmwares"
KLIPPER_DIR="${USER_HOME_DIR}/klipper"
KLIPPER_EXTRAS_DIR="${KLIPPER_DIR}/klippy/extras"
# Set python path to klipper env
KLIPPER_ENV="${USER_HOME_DIR}/klippy-env" # klipper virtual environment
KLIPPER_VENV_PYTHON_BIN="$KLIPPER_ENV/bin/python" # klipper python binary
# -------- FreeDi repository ( $FREEDI_DIR ) ---------------------------
PULLABLE_FILES_FREEDI=(
# example: "FreeDiLCD/always_pull_from_remote.py"
"FreeDiLCD/freedi_update.sh"
)
BLOCKED_FILES_FREEDI=(
# example: "FreeDiLCD/never_pull_from_remote.py"
)
# -------- Klipper repository ( $KLIPPER_DIR ) ------------------------------
# Basically files that doesnt exist in upstream klipper (thus not in $KLIPPER_EXTRAS_DIR)
PULLABLE_FILES_KLIPPER=(
# example: "klippy/extras/freedi_custom_modified_file.py"
"klippy/extras/freedi.py"
"klippy/extras/auto_z_offset.py"
)
BLOCKED_FILES_KLIPPER=(
# example: "klippy/extras/freedi_custom_modified_file.py"
#"klippy/extras/hall_filament_width_sensor.py"
# test showed this error/issue when trying to update klipper:
# Updating 08a1c9f12..61c0c8d2e
# From https://github.com/Klipper3d/klipper
# * branch 61c0c8d2ef40340781835dd53fb04cc7a454e37a -> FETCH_HEAD
# error: Your local changes to the following files would be overwritten by merge:
# klippy/extras/hall_filament_width_sensor.py
# Please commit your changes or stash them before you merge.
)
# ----- colour definitions -----
YLW='\033[1;33m' # bold yellow
RED='\033[1;31m' # bold red
RST='\033[0m' # reset
############ legacyFreeDi 1.XX -> 2.00 Update ############
PRINTER_DATA_DIR="${USER_HOME_DIR}/printer_data"
PRINTER_CONFIG_DIR="${PRINTER_DATA_DIR}/config"
PRINTER_CFG="${PRINTER_CONFIG_DIR}/printer.cfg"
FREEDI_CFG_SRC="${FREEDI_DIR}/config_section/generic/freedi.cfg"
FREEDI_CFG_DST="${PRINTER_CONFIG_DIR}/freedi.cfg"
### Make sure the repo is complete
# 1) Detect and fix a partial clone ( --filter=blob:none )
if [ "$(git config --get remote.origin.partialclonefilter)" = "blob:none" ]; then
echo "Partial clone detected – fetching all blobs ..."
# switch the repo to a normal clone
git config --unset-all remote.origin.partialclonefilter
git config --unset-all remote.origin.promisor
# fetch (download) everything that is still missing
git fetch --no-filter --prune --tags --progress
fi
# 2) Detect and disable sparse-checkout
if git config --bool core.sparseCheckout | grep -q true; then
echo "Sparse-checkout is active – disabling ..."
git sparse-checkout disable
fi
### Installing and update the new introduced freedi.cfg
# 1. Copy freedi.cfg into the Klipper config directory
if install -m 644 -T "${FREEDI_CFG_SRC}" "${FREEDI_CFG_DST}"; then
# Ensure proper ownership in case the script is executed as root
chown "${USER_NAME}:${USER_GROUP}" "${FREEDI_CFG_DST}"
echo "freedi.cfg copied and ownership set to ${USER_NAME}:${USER_GROUP}."
else
echo "Error: failed to copy freedi.cfg." >&2
fi
# 2. Comment out the legacy [freedi] section in printer.cfg
if grep -q '^\[freedi\]$' "${PRINTER_CFG}"; then
sed -i '
/^\[freedi\]$/,/^\[/{ # range: from [freedi] up to next "[" line
/^\[freedi\]$/ s/^/#/ # comment the [freedi] header
/^\[/ b # if line starts with [, skip further cmds
s/^/#/ # otherwise: comment the line
}
' "${PRINTER_CFG}"
echo "Legacy [freedi] section commented out."
fi
# 3. Insert include statement where the former [freedi] section started
if ! grep -q "^\[include freedi.cfg\]" "${PRINTER_CFG}"; then
# Find the line number of the (now commented) [freedi] header
FREEDI_LINE=$(grep -n -m1 '^[#]*\[freedi\]' "${PRINTER_CFG}" | cut -d':' -f1)
if [[ -n "${FREEDI_LINE}" ]]; then
# Insert the include line directly above that header
sed -i "${FREEDI_LINE}i [include freedi.cfg]\n" "${PRINTER_CFG}"
echo "Include statement inserted near the original [freedi] section."
else
echo "Warning: could not locate the commented [freedi] section; include line not added." >&2
fi
else
echo "Include statement already present in printer.cfg."
fi
# Activate the Klipper virtual environment and install required Python packages
echo "Activating Klipper virtual environment and installing Python packages..."
if [ ! -d "$KLIPPER_ENV" ]; then
echo "Klippy env doesn't exist so I can't continue installation..."
exit 1
fi
PYTHON_V=$($KLIPPER_VENV_PYTHON_BIN -c 'import sys; print(".".join(map(str, sys.version_info[:3])))')
echo "Klipper environment python version: $PYTHON_V"
# Arrange Python requirements from requirements.txt
echo "Arranging Python requirements..."
"${KLIPPER_ENV}/bin/pip" install --upgrade pip
"${KLIPPER_ENV}/bin/pip" install -r "${FREEDI_DIR}/requirements.txt"
if [ $? -ne 0 ]; then
echo "Failed to install Python requirements."
exit 1
fi
echo "Python requirements installed from requirements.txt."
###### Installing klipper modules ######
# Create a symbolic links for needed modules to the Klipper extras directory
FREEDI_MODULES=(
"freedi.py"
"qidi_auto_z_offset/auto_z_offset.py"
#"reverse_homing.py"
#"hall_filament_width_sensor.py"
)
for MODULE_PATH in "${FREEDI_MODULES[@]}"; do
MODULE_NAME=$(basename "${MODULE_PATH}")
echo "Creating a symbolic link for ${MODULE_NAME} from ${REPO_MODULE_DIR}/${MODULE_PATH} to ${KLIPPER_EXTRAS_DIR} …"
if ln -sf "${REPO_MODULE_DIR}/${MODULE_PATH}" "${KLIPPER_EXTRAS_DIR}/${MODULE_NAME}"; then
# Ensure the symlink belongs to the regular user, not root
chown -h "${USER_NAME}:${USER_GROUP}" "${KLIPPER_EXTRAS_DIR}/${MODULE_NAME}"
echo "Successfully installed ${MODULE_NAME} to ${KLIPPER_EXTRAS_DIR}."
else
echo "Error: failed to create a symbolic link for ${MODULE_NAME}." >&2
exit 1
fi
done
############ Git housekeeping to prevent dirty repos and setting the correct logic (updateable or not) ############
# Check if the script is run inside a Git repository
if [ ! -d "${FREEDI_DIR}/.git" ]; then
echo "Error: Not a git repository. Please initialize the repository first."
fi
# Ensure if the Klipper extras directory exists
if [ ! -d "$KLIPPER_EXTRAS_DIR" ]; then
echo "Error: Klipper extras directory not found at $KLIPPER_EXTRAS_DIR."
echo "Make sure Klipper is installed correctly."
fi
# Wrapper to execute commands as the target user when running as root
# Especially useful for Git operations
run_as_user() {
if [ "$(id -u)" -eq 0 ]; then
sudo -u "$USER_NAME" -- "$@"
else
"$@"
fi
}
# Helper: keep repo clean for a given list of files
# • pullable → assume-unchanged
# • blocked → skip-worktree
# • detects & clears an already recorded change (typechange, content, …)
# • runs Git as $USER_NAME even when script is executed as root
clean_repo() {
local repo="$1"
local mode="$2"
shift 2
local files=("$@")
# Determine the .git directory and build absolute path to info/exclude
local git_dir
git_dir="$(run_as_user git -C "$repo" rev-parse --git-dir)"
# <-- changed: use absolute path for exclude file
local exclude_file="${repo}/${git_dir}/info/exclude"
echo "Exclude file resolved to: $exclude_file"
# Ensure the exclude file exists
run_as_user mkdir -p "$(dirname "$exclude_file")"
run_as_user touch "$exclude_file"
for f in "${files[@]}"; do
local full_path="${repo}/${f}"
local st
st="$(run_as_user git -C "$repo" status --porcelain -- "$f")"
# Warn if file/symlink is missing in working tree
if [ ! -e "$full_path" ]; then
echo -e "${YLW}Notice: ${f} does not exist in working tree – index/ignore rules are still applied.${RST}"
fi
# ------------------------------------------------------------------
# CASE 1 : tracked file or type-change
# ------------------------------------------------------------------
if run_as_user git -C "$repo" ls-files --error-unmatch "$f" >/dev/null 2>&1 \
|| [[ $st =~ ^.?T ]]; then
# Check if this file has changes already
local dirty_pre=false
if [ -n "$st" ]; then
echo -e "${YLW}Detected changes for ${f} in index / working tree (causes dirty repo).${RST}"
dirty_pre=true
fi
if [[ "$mode" == "pullable" ]]; then
if run_as_user git -C "$repo" update-index --assume-unchanged -- "$f"; then
echo -e "Git will now ignore local changes to ${f} (assume-unchanged)."
else
echo -e "${RED}Warning: git update-index failed for ${f} – file NOT marked.${RST}"
fi
else
if run_as_user git -C "$repo" update-index --skip-worktree -- "$f"; then
echo -e "Git will keep your local version of ${f} (skip-worktree)."
else
echo -e "${RED}Warning: git update-index failed for ${f} – file NOT marked.${RST}"
fi
fi
# If it was dirty, refresh index to clear existing change
if [ "$dirty_pre" = true ]; then
echo -e "${YLW}Cleaning index / working tree for ${f}...${RST}"
run_as_user git -C "$repo" update-index --really-refresh -q -- "$f"
if run_as_user git -C "$repo" status --porcelain -- "$f" | grep -q .; then
echo -e "${RED}Index still reports changes for ${f}!${RST}"
else
echo -e "${YLW}Index cleaned for ${f}.${RST}"
fi
fi
# ------------------------------------------------------------------
# CASE 2 : untracked file → add to info/exclude
# ------------------------------------------------------------------
else
if ! grep -Fxq "$f" "$exclude_file"; then
if printf '%s\n' "$f" | run_as_user tee -a "$exclude_file" >/dev/null; then
echo -e "Added ${f} to $(basename "$exclude_file") (untracked→exclude)."
else
echo -e "${RED}Warning: failed to write ${f} to $(basename "$exclude_file").${RST}"
fi
else
echo -e "${f} already listed in $(basename "$exclude_file") – skipping."
fi
fi
done
}
# Run git cleaning - Apply the definitions above
clean_repo "$FREEDI_DIR" pullable "${PULLABLE_FILES_FREEDI[@]}"
clean_repo "$FREEDI_DIR" blocked "${BLOCKED_FILES_FREEDI[@]}"
clean_repo "$KLIPPER_DIR" pullable "${PULLABLE_FILES_KLIPPER[@]}"
clean_repo "$KLIPPER_DIR" blocked "${BLOCKED_FILES_KLIPPER[@]}"
############ Update finished: Restart klipper and FreeDi.service ############
# Restart Klipper to load the new modules
echo "Restarting Klipper service..."
sudo systemctl restart klipper
================================================
FILE: FreeDiLCD/start.py
================================================
import os
import sys
import subprocess
def run_and_delete_bash_script(file_name):
file_name = os.path.join(os.path.dirname(__file__), file_name)
if not os.path.exists(file_name):
return
try:
result = subprocess.run(["bash", file_name], capture_output=True, text=True, check=True)
print("Script Output:\n", result.stdout)
os.remove(file_name)
print(f"File '{file_name}' has been deleted.")
except subprocess.CalledProcessError as e:
print("Error occurred:\n", e.stderr)
except FileNotFoundError:
print(f"File '{file_name}' not found. Nothing to delete.")
# Run the update script
file_name = "freedi_update.sh"
run_and_delete_bash_script(file_name)
import psutil
# Import the main function from main.py
from main import main as main_function
def is_instance_running(script_name):
"""Check if another instance of the script is running."""
current_pid = os.getpid()
script_name = os.path.abspath(script_name) # Ensure absolute path for comparison
matching_processes = []
for proc in psutil.process_iter(['pid', 'cmdline']):
try:
cmdline = proc.info['cmdline']
if cmdline:
# Check if the script name matches and it's not the current process
if proc.info['pid'] != current_pid and script_name in cmdline:
matching_processes.append(proc.info)
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return len(matching_processes) > 0
if __name__ == "__main__":
# Ensure the script name matches explicitly
script_name = os.path.abspath(__file__)
if is_instance_running(script_name):
print(f"Another instance of {script_name} is already running.")
sys.exit(1)
main_function() # Call the main function from main.py
================================================
FILE: LICENSE
================================================
Copyright (c) 2024,
https://github.com/Phil1988 [C0co].
All rights reserved.
Custom License Agreement
Version 1.0, September 2024
1. Permission and Usage
You are hereby granted permission to use, copy, and distribute unmodified
copies of this software, subject to the following conditions:
- Commercial use of the software is prohibited without prior written
permission from the original author. To request permission, please
contact the author via their GitHub profile.
- For the purpose of this license, "commercial use" refers to any use
of the software in a manner that is intended for or directed toward
commercial advantage or monetary compensation.
- You may not modify, merge, or publish derivative works based on this
software without prior written permission from the original author.
- Any redistribution of this software, with or without modification,
must include a clear and visible acknowledgment of the original author
in the documentation and/or other materials provided with the distribution.
- Redistribution of this software under different licensing terms is not
permitted without prior written permission from the original author.
- If you modify the source code, you must notify the original author of
the changes made and provide feedback through GitHub.
2. Attribution
When redistributing the software, you must retain the following:
- The original author's name and copyright notice must be included in all
copies or substantial portions of the software.
- Clear acknowledgment must be given to the original author(s) in any
documentation or software release notes.
3. No Warranty
This software is provided "as-is," without any express or implied warranties.
In no event shall the author be held liable for any damages arising from the
use of the software, including but not limited to direct, indirect,
incidental, special, exemplary, or consequential damages.
4. No Patent Rights
No patent rights are granted under this license. You may not use this software
to apply for any patent or related intellectual property rights.
5. Limitation of Liability
In no event shall the author be liable for any claims, damages, or other
liabilities, whether in an action of contract, tort, or otherwise, arising
from, out of, or in connection with the software or the use or other
dealings in the software.
6. Indemnification
You agree to indemnify and hold the author harmless from and against any and
all claims, losses, damages, liabilities, costs, and expenses, including
attorneys' fees, arising out of or related to your use or distribution of
the software.
7. Reverse Engineering and Decompilation
You may not reverse engineer, decompile, or disassemble the software, except
to the extent that such activity is expressly permitted by applicable law.
8. Security Vulnerabilities
Users are encouraged to report any security vulnerabilities or issues found
in the software to the author via GitHub for assessment and remediation.
9. Termination
Any violation of the terms of this license will result in the immediate
termination of the rights granted herein.
10. Global Applicability
This license is intended to be globally applicable, subject to the laws and
regulations of the relevant jurisdictions.
11. Severability
If any provision of this License is held to be unenforceable or invalid,
such provision will be modified to the extent necessary to make it enforceable
and valid, and the remaining provisions will remain in effect.
12. Governing Law
This License shall be governed by and construed in accordance with the laws
of germany, without regard to its conflict of law principles.
By using, modifying, or distributing the software, you acknowledge that you have
read, understood, and agreed to be bound by these terms.
Author: https://github.com/Phil1988 [C0co]
Date: September 1, 2024
================================================
FILE: README.md
================================================
# FreeDi
**Open Mainline Klipper for QIDI Printers**
Transform your QIDI printer with FreeDi - built on open Armbian OS, official Klipper, custom display firmware, and cutting-edge features. Stay current, stay secure, unlock your printer's full potential.
<p align="center">
<img src="https://github.com/user-attachments/assets/745a7b53-ab59-433f-a441-291efb53926c" alt="unlock">
</p>
---
## 🚀 Quick Start
Ready to upgrade? Head to the 📖 **[Installation Guide](https://github.com/Phil1988/FreeDi/wiki/Introduction)** and follow the step-by-step instructions.
**Version 2.xx** → [Installation Guide](https://github.com/Phil1988/FreeDi/wiki/Introduction)
**Version 1.xx** → [Legacy Installation Guide](https://github.com/Phil1988/FreeDi/wiki/Installation-guide) | [Video Tutorial](https://www.youtube.com/watch?v=_ZmSTJBWUus)
---
## 💡 What Is FreeDi?
FreeDi is a complete firmware ecosystem for QIDI printers that replaces the outdated stock system with modern, open-source components:
- **Open Foundation**: Armbian OS + official mainline Klipper (unmodified)
- **Custom Display**: Lightning-fast LCD firmware built for production use
- **Seamless Integration**: Optimized communication layer between Klipper and display
- **Latest Software**: Klipper 0.13.0+, Moonraker 0.9.3+, Mainsail 2.14+, KIAUH support
- **OTA Updates**: Update everything in ~4 minutes - no USB drives, no hassle
### Why Users Switch to FreeDi
- **Full Klipper Ecosystem Access**: Use modern plugins like Cartographer, Beacon, Shake&Tune, Spoolman without compatibility issues
- **More Storage**: ~2.6GB free space vs. stock's ~500MB - never run out of room for gcode files
- **Security Compliant**: Passes security tests that stock firmware fails - critical for professional environments
- **Actually Updated**: Stock systems run OS and Klipper versions up to 4 years old with no update path
- **No More Stock Bugs**: Eliminate nozzle crashes, bed slamming, missing thumbnails, and "SYSTEM STARTS ABNORMALLY" errors
<p align="center">
<img src="https://github.com/user-attachments/assets/a98c5b18-c3e9-48b0-a21b-7799c58e283e" alt="animated_menu" width="45%">
<img src="https://github.com/Phil1988/FreeDi/blob/master/animation.gif" alt="animated_menu" width="45%">
</p>
<p align="center">
<img src="https://github.com/user-attachments/assets/ede5aa17-d846-4368-9d28-f3c54d67b8fa" alt="thumbnails" width="45%">
<img src="https://github.com/user-attachments/assets/e8a632de-2093-47ba-9bf1-003bb99845d6" alt="thumbnails" width="45%">
</p>
---
## 🖨️ Supported Printers
- QIDI X-Max 3
- QIDI X-Plus 3
- QIDI X-Smart 3
- QIDI Q1 Pro
- QIDI Plus 4
---
## ❤️ Support This Project
If FreeDi has improved your printing experience, consider supporting development:
[](https://ko-fi.com/B0B4V3TJ6)
You can also help by giving this repo a ⭐, sharing it with other QIDI users, providing feedback, or contributing improvements!
---
## 🛠️ Contributing
FreeDi thrives on community input. Have ideas, feature requests, or improvements? Open an issue or submit a pull request. Help spread the word so every QIDI user can make an informed choice about their firmware.
---
## ⚠️ Important Information
**This is a hobby project - use at your own risk.** I've tested extensively (1,000+ LCD flashes), but I can't cover every scenario. Please report issues on GitHub, not to QIDI support - modifications may void your warranty. You can always revert to stock using QIDI's recovery image and official .tft firmware.
**Regarding Sharing & Attribution**: Please don't copy or redistribute parts of this project without permission. In the past, modified/incorrect versions of my guides caused confusion and extra support work. Feel free to **share the project with proper credit** - the more users benefit, the better! I welcome contributions submitted directly here so we can maintain accuracy and make this the go-to resource for QIDI improvements. Thank you for respecting this and building a supportive community.
---
**Together, let's unlock the full potential of your printer!** 🎉
For complete documentation, visit the [FreeDi Wiki](https://github.com/Phil1988/FreeDi/wiki).
================================================
FILE: config_section/Plus4/macros.cfg
================================================
#####################################################################
# Specific Plus4 macros
#####################################################################
#Danger Zone Y 318 -323
[gcode_macro SET_PRINT_STATS_INFO]
rename_existing: BASE_SET_PRINT_STATS_INFO_BASE
gcode:
# To prevent the chamber heater to blow hot air directly onto the left side of the print bed
{% if (printer.toolhead.position.z) > 260 %}
M141 S0
{% endif %}
#TIMELAPSE_TAKE_FRAME
BASE_SET_PRINT_STATS_INFO_BASE {rawparams}
CHAMBER_TEMP_CONTROLLER
# Safety macro that gets frequently called by SET_PRINT_STATS_INFO to prevent too high chamber temperatures
[gcode_macro CHAMBER_TEMP_CONTROLLER]
gcode:
{% set chamber_target_temp = printer['heater_generic chamber'].target %}
{% set chamber_temp = printer['heater_generic chamber'].temperature %}
{% if chamber_temp > printer.configfile.settings['heater_generic chamber'].max_temp %}
M106 P3 S255
{% else %}
{% if chamber_target_temp > 0 %}
# Allow for 3C of "grace" before we start ramping the exhaust fan speed
# This prevents the macro from fighting with the chamber heater PID algorithm
{% set difference = chamber_temp - (chamber_target_temp + 3) %}
{% if difference > 0 %}
{% set filterfan_speed = ([(difference * 50), 255] | min) | int %}
M106 P3 S{filterfan_speed}
{% else %}
M106 P3 S0
{% endif %}
{% endif %}
{% endif %}
[gcode_macro ENABLE_ALL_SENSOR]
gcode:
ENABLE_FILAMENT_WIDTH_SENSOR
RESET_FILAMENT_WIDTH_SENSOR
query_filament_width
SET_FILAMENT_SENSOR SENSOR=filament_tangle_sensor ENABLE=1
[gcode_macro DISABLE_ALL_SENSOR]
gcode:
SET_FILAMENT_SENSOR SENSOR=filament_tangle_sensor ENABLE=0
DISABLE_FILAMENT_WIDTH_SENSOR
[gcode_macro SCREWS_TILT_CALCULATE]
rename_existing: BASE_SCREWS_TILT_CALCULATE_BASE
gcode:
{ action_respond_info("starting screw rotation calculation...") }
M141 S0 # disable chamber heater (see https://github.com/qidi-community/Plus4-Wiki/tree/main/content/chamber-heater-issue)
BASE_SCREWS_TILT_CALCULATE_BASE
[gcode_macro HOME_IF_NEEDED]
description: Homes X and Y if needed
gcode:
{% if "y" not in printer.toolhead.homed_axes %}
G28 Y
{% endif %}
{% if "x" not in printer.toolhead.homed_axes %}
G28 X
{% endif %}
{% if "z" not in printer.toolhead.homed_axes %}
G28 Z
{% endif %}
[gcode_macro CUT_FILAMENT]
description: Cuts the filament
gcode:
HOME_IF_NEEDED
{% if printer.gcode_move.position.y < 20 %}
G1 Y40 F9000
{% endif %}
{% if printer.gcode_move.position.y > 300 %}
G1 Y300 F9000
{% endif %}
G1 X305 Y40 F9000
G1 Y20 F9000
G1 Y5 F3000
G4 P500
G1 Y20 F9000
G1 Y5 F3000
G4 P500
G1 Y20 F9000
[gcode_macro GO_TO_POOP_SHOOT]
description: Move toolhead to poop shoot
gcode:
HOME_IF_NEEDED
G90
{% if printer.gcode_move.position.y > 300 %}
G1 Y300 F9000
{% endif %}
G1 X95 Y312 F12000
G1 Y316 F600
G1 Y320 F9000
G1 Y324 F600
[gcode_macro LEAVE_POOP_SHOOT]
description: Primes the nozzle with fresh filament before load/unload/print start
gcode:
HOME_IF_NEEDED
{% if printer.gcode_move.position.y > 323 %}
G1 X95 F1200
G1 Y300 F1200
{% else %}
{% if printer.gcode_move.position.y < 318 %}
G1 X95 Y300 F1200
{% else %}
{% if (printer.gcode_move.position.x < 83 or printer.gcode_move.position.x > 106 or
(printer.gcode_move.position.x >= 93 and printer.gcode_move.position.x <= 97)) %}
G1 Y300 F1200
G1 X95
{% else %}
M118 Warning: Nozzle in dangerous position!
{% endif %}
{% endif %}
{% endif %}
[gcode_macro _SILICON_WIPE]
description: Wipe on the silicon pad with custom min and max coordinates and margin
gcode:
G90
{% if (printer.gcode_move.position.y) > 300 %}
G1 Y300 F600
{% endif %}
G1 X95 F12000
G1 Y314 F9000
G1 Y324 F600
; Wipe movements in X direction
G1 X58 F12000
G1 X78 F12000
G1 Y324
G1 X58 F12000
G1 X78 F12000
G1 Y323.5
G1 X58 F12000
G1 X78 F12000
G1 Y323
G1 X58 F12000
G1 X78 F12000
G1 Y322.5
G1 X58 F12000
G1 X78 F12000
G1 Y322
G1 X58 F12000
G1 X75 F12000
G1 Y321.5
; Wipe movements in circles
G2 I0.8 J0.8 F600
G2 I0.8 J0.8 F600
G2 I0.8 J0.8 F600
G1 Y324 F600
G1 X95 F12000
[gcode_macro _PEI_WIPE]
description: Wipe on the PEI pad
gcode:
# Input values for the minimum and maximum coordinates of the pad
{% set pad_min_coordinate_x = 111 %}
{% set pad_max_coordinate_x = 136 %}
{% set pad_min_coordinate_y = 317 %}
{% set pad_max_coordinate_y = 325 %}
{% set margin = 1.0 %} # margin from the edge of the pad
{% set repetitions = 3 %}
# Arc parameters and radius to keep full arc inside limits
{% set arc_i = 0.5 %}
{% set arc_j = 0.5 %}
{% set arc_r = ((arc_i|float)**2 + (arc_j|float)**2) ** 0.5 %}
G90 # absolute positioning
{% if (printer.gcode_move.position.y) < 300 %}
G1 Y300 F9000
{% endif %}
G1 X108 F9000
# Compute safe max/min positions (account for margin and arc radius)
{% set X_max_position = pad_max_coordinate_x - margin - arc_r %}
{% set Y_max_position = pad_max_coordinate_y - margin - arc_r %}
{% set X_min_position = pad_min_coordinate_x + margin + arc_r %}
{% set Y_min_position = pad_min_coordinate_y + margin + arc_r %}
# Calculate random end positions within the defined safe boundaries (0.05 mm steps)
{% set random_x_steps = ((X_max_position - X_min_position) * 20) | int %}
{% if random_x_steps < 1 %}{% set random_x_steps = 1 %}{% endif %}
{% set random_x = (range(0, random_x_steps) | random) / 20.0 %}
{% set X_move_position = X_min_position + random_x %}
{% set random_y_steps = ((Y_max_position - Y_min_position) * 20) | int %}
{% if random_y_steps < 1 %}{% set random_y_steps = 1 %}{% endif %}
{% set random_y = (range(0, random_y_steps) | random) / 20.0 %}
{% set Y_move_position = Y_min_position + random_y %}
# Calculate a random starting Y position within the safe range (0.1 mm steps)
{% set random_start_y_steps = ((Y_max_position - Y_min_position) * 10) | int %}
{% if random_start_y_steps < 1 %}{% set random_start_y_steps = 1 %}{% endif %}
{% set random_start_y = (range(0, random_start_y_steps) | random) / 10.0 + Y_min_position %}
# Move the print head to the random starting Y position
G1 Y{random_start_y} F500
# Wiping movements in X direction
{% for move in range(repetitions|int) %}
G1 X{X_max_position} F400
G1 X{X_move_position} F400
{% endfor %}
# Wiping movements in Y direction
{% for move in range(repetitions|int) %}
G1 Y{Y_move_position} F400
G1 Y{Y_max_position} F400
{% endfor %}
G1 X{X_move_position} Y{Y_move_position} F300
# Circular wiping movements (kept inside safe area by arc radius)
{% for move in range(repetitions|int) %}
G2 I{arc_i} J{arc_j} F500
{% endfor %}
# Rectangular wiping movements
{% for move in range(repetitions|int) %}
G1 Y{Y_max_position} F400
G1 X{X_max_position} F400
G1 Y{Y_move_position} F400
G1 X{X_move_position} F400
{% endfor %}
[gcode_macro PRIME_NOZZLE]
description: Primes the nozzle with fresh filament before load/unload/print start
gcode:
{% set hotend_target_temp = params.HOTEND_TARGET_TEMP|default(220)|int %}
M106 S0
M104 S{hotend_target_temp}
HOME_IF_NEEDED
TEMPERATURE_WAIT SENSOR=extruder MINIMUM={hotend_target_temp-50}
GO_TO_POOP_SHOOT
M109 S{hotend_target_temp}
G92 E0
G1 E5 F50
G1 E50 F200
G92 E0
G1 E-0.8 F200
G4 P300
M104 S{([hotend_target_temp-80, 150]|min)}
M106 S255
G4 P4000
_PEI_WIPE
TEMPERATURE_WAIT SENSOR=extruder MAXIMUM={([hotend_target_temp-80, 150]|min)}
_SILICON_WIPE
GO_TO_POOP_SHOOT
M106 S0
LEAVE_POOP_SHOOT
[gcode_macro M603]
description: Unload filament with cutting filament
gcode:
{% set hotend_target_temp = params.S|default(220)|int %}
{% set accel = printer.toolhead.max_accel|int %}
M104 S{hotend_target_temp}
HOME_IF_NEEDED
M204 S10000
CUT_FILAMENT
M106 S0
M400
M204 S{accel}
M118 Unload finished
[gcode_macro M604]
description: Load filament with priming nozzle
gcode:
{% set hotend_target_temp = params.S|default(250)|int %}
{% set accel = printer.toolhead.max_accel|int %}
M104 S{hotend_target_temp}
HOME_IF_NEEDED
M204 S10000
PRIME_NOZZLE hotend_target_temp={hotend_target_temp}
M106 S0
M400
M204 S{accel}
M118 Load finished
#####################################################################
# Homing modification
#####################################################################
[gcode_macro G28]
rename_existing: G28.1
gcode:
{% set reduced_current_x = 0.55 %}
{% set reduced_current_y = 0.45 %}
{% set home_all = ('X' in rawparams.upper() and 'Y' in rawparams.upper() and 'Z' in rawparams.upper()) or
('X' not in rawparams.upper() and 'Y' not in rawparams.upper() and 'Z' not in rawparams.upper()) %}
{% set home_current_x = printer.configfile.settings['tmc2240 stepper_x'].run_current * reduced_current_x %}
{% set home_current_y = printer.configfile.settings['tmc2240 stepper_y'].run_current * reduced_current_y %}
{% set init_XY_move = 30 %}
#{% set y_init_move = 5 %}
{% set z_clearance = 2 %}
{% set home_all_final_position_x = printer.toolhead.axis_maximum.x / 2 %}
{% set home_all_final_position_y = printer.toolhead.axis_maximum.y - 40 %}
{% set home_all_final_position_z = 20 %}
{% if 'x' not in printer.toolhead.homed_axes %}
{% set X_axis_was_homed = false %} ; Set Z_axis_was_homed to false if Z is not homed
{% endif %}
{% if 'y' not in printer.toolhead.homed_axes %}
{% set Y_axis_was_homed = false %} ; Set Z_axis_was_homed to false if Z is not homed
{% endif %}
# If homing should at least move X or Y axis
{% if home_all or 'X' in rawparams.upper() or 'Y' in rawparams.upper() %}
# Check if Z is homed
{% if 'z' in printer.toolhead.homed_axes %}
{% set Z_axis_was_homed = true %} ; Set Z_axis_was_homed to true if Z is already homed
G91 ; Use relative positioning
G1 Z2 F600 ; Move bed down
G90 ; Use absolute positioning
{% else %}
{% set Z_axis_was_homed = false %} ; Set Z_axis_was_homed to false if Z is not homed
G90
SET_KINEMATIC_POSITION Z=0 ; To allow bed move down
G1 Z{z_clearance} ; Move bed down
{% if X_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=X ; Set X to be unhomed
{% endif %}
{% if Y_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=Y ; Set Y to be unhomed
{% endif %}
{% endif %}
{% endif %}
{% if home_all or 'X' in rawparams.upper() or 'Y' in rawparams.upper() %}
FORCE_MOVE STEPPER=stepper_x DISTANCE={init_XY_move} VELOCITY=40 ; Move X a little before homing
SET_KINEMATIC_POSITION X={printer.toolhead.position.x + (init_XY_move/2)} ; Compensate the FORCE_MOVE position
SET_KINEMATIC_POSITION Y={printer.toolhead.position.y + (init_XY_move/2)} ; Compensate the FORCE_MOVE position
{% if X_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=X ; Set X to be unhomed
{% endif %}
{% if Y_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=Y ; Set Y to be unhomed
{% endif %}
{% endif %}
# Home Y
{% if home_all or 'Y' in rawparams.upper() %}
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={home_current_x} ; Lower motor current
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={home_current_y} ; Lower motor current
G28.1 Y ; Home Y
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.settings['tmc2240 stepper_x'].run_current} ; Set motor current to the previous value
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.settings['tmc2240 stepper_y'].run_current} ; Set motor current to the previous value
G1 Y10 F1200 ; Move Y-axis slightly
{% endif %}
# Home X
{% if home_all or 'X' in rawparams.upper() %}
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={home_current_x} ; Lower motor current
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={home_current_x} ; Lower motor current
G28.1 X ; Home X
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.settings['tmc2240 stepper_x'].run_current} ; Set motor current to the previous value
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.settings['tmc2240 stepper_y'].run_current} ; Set motor current to the previous value
G1 X10 F1200 ; Move X-axis slightly
{% endif %}
# Raise the bed again if only X or only Y axes were homed
{% if not (home_all or 'Z' in rawparams.upper()) %}
{% if Z_axis_was_homed %}
G91 ; Use relative positioning
G1 Z-2 F600 ; Raise the bed back again
G90 ; Use absolute positioning
{% else %}
G1 Z0.1 ; Raise the bed back again
SET_STEPPER_ENABLE STEPPER=stepper_z enable=0 ; Disable Z to prevent collisions
SET_STEPPER_ENABLE STEPPER=stepper_z1 enable=0 ; Disable Z to prevent collisions
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=Z ; Set Z to be unhomed
{% endif %}
{% endif %}
# Home Z
{% if home_all or 'Z' in rawparams.upper() %}
G1 X{printer.toolhead.axis_maximum.x / 2} Y{printer.toolhead.axis_maximum.x / 2} F12000
G28.1 Z ; Home Z
G90 ; Set absolute positioning
G1 Z{home_all_final_position_z} F600 ; Move bed down
{% endif %}
# Move to the final position if all axes were homed
{% if home_all %}
G90 ; Set absolute positioning
G1 X{home_all_final_position_x} Y{home_all_final_position_y} Z{home_all_final_position_z} F7800 ; Move to the rear center
{% endif %}
# Unconditional stop
[gcode_macro M0]
gcode:
PAUSE
# Pause SD print
[gcode_macro M25]
rename_existing: M9925
gcode:
PAUSE
########################################
# Basic Macros
########################################
# Flag macro to use STATIC_MESH usage instead of KAMP (needed make this function work from printjob selection on the LCD)
[gcode_macro NEXT_PRINT_STATIC_MESH]
description: Forces the NEXT print to use 'STATIC_MESH' instead of KAMP.
gcode:
{% if "STATIC_MESH" in printer.bed_mesh.profiles %}
SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=force_static_mesh VALUE=True
{action_respond_info("The NEXT print will use 'STATIC_MESH'.")}
M118 The NEXT print will use the STATIC_MESH.
{% else %}
{action_respond_info("WARNING: No mesh named 'STATIC_MESH' found. Please save one first (BED_MESH_PROFILE SAVE=STATIC_MESH).")}
M118 WARNING: No mesh named STATIC_MESH found. Please save one first (BED_MESH_PROFILE SAVE=STATIC_MESH).
{% endif %}
[gcode_macro PRINT_START]
# Use PRINT_START for the slicer starting script
description: Start printing
variable_force_static_mesh: False ; Set to True to force a static mesh instead of KAMP
gcode:
{% set bed_target_temp = params.BED|int %}
{% set hotend_target_temp = params.HOTEND|int %}
{% set chamber_target_temp = params.CHAMBER|default(0)|int %}
{% set bed_center_x = printer.configfile.config["stepper_x"]["position_max"]|float / 2 %}
{% set bed_center_y = printer.configfile.config["stepper_y"]["position_max"]|float / 2 %}
{% set start_position_x = printer.toolhead.axis_maximum.x / 2 %}
{% set start_position_y = printer.toolhead.axis_maximum.y - 40 %}
{% set start_position_z = 10 %}
CLEAR_PAUSE ; Clear existing pause states
BED_MESH_CLEAR ; Clear previous adaptive mesh
{% set KAMP_deactivated = printer["gcode_macro PRINT_START"].force_static_mesh %} ; Check if KAMP is deactivated for this print
SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=force_static_mesh VALUE=False ; Auto-reset the variable immediately for the next print after this one
SET_TEMPERATURE_FAN_TARGET TEMPERATURE_FAN=Mainboard_fan TARGET=1 ; Decrease the mainboard target temp to fully turn the fan on
M140 S{bed_target_temp}
M141 S{chamber_target_temp}
G28
{% if chamber_target_temp > 0 %} ; Accelerate chamber heating by using the bed as additional heater
G0 X{bed_center_x} Y{bed_center_y} Z3 F780 ; Move print bed to perfect postion to help chamber heating
M106 P2 S185 ; Turn sidefan on to use bed heat and mix air
M106 P0 S128 ; Turn part cooling fan on to help air mixing
TEMPERATURE_WAIT SENSOR="heater_generic chamber" MINIMUM={chamber_target_temp - 5} ; Wait for chamber to heat up
M106 P2 S0 ; Turn off sidefan
M106 P0 S0 ; Turn off part cooling fan
{% endif %}
{% if bed_target_temp !=0 %}
TEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={bed_target_temp * 0.95} MAXIMUM={bed_target_temp * 1.05}
{% endif %}
M191 S{chamber_target_temp} ; Set and wait for chamber temperature
M190 S{bed_target_temp} ; Set and wait for bed temperature
G90 ; Set absolute positioning
G1 X{start_position_x} Y{start_position_y} Z{start_position_z} F7800 ; Move to start position
G28 Z ; Home Z again for to compensate bed expansion
{% if KAMP_deactivated %}
{% if "STATIC_MESH" in printer.bed_mesh.profiles %} ; Check if the spicific STATIC_MESH exists
M118 Loading 'STATIC_MESH' instead of KAMP.
BED_MESH_PROFILE LOAD=STATIC_MESH
{% else %} ; Fallback to KAMP if STATIC_MESH not found
M118 ERROR: 'STATIC_MESH' not found! Using fallback: KAMP Adaptive Mesh.
BED_MESH_CLEAR ; Clear previous adaptive mesh
BED_MESH_CALIBRATE PROFILE=adaptive ADAPTIVE=1 ; Start adaptive meshing
{% endif %}
{% else %} ; Standard operation
{% if printer.toolhead.homed_axes|length < 3 %}
G28
{% endif %}
BED_MESH_CLEAR ; Clear previous adaptive mesh
BED_MESH_CALIBRATE PROFILE=adaptive ADAPTIVE=1 ; Start adaptive meshing
{% endif %}
PRIME_NOZZLE hotend_target_temp={hotend_target_temp}
M109 S{hotend_target_temp} ; Set and wait for hotend temperature
[gcode_macro PRINT_END]
gcode:
{% set max_x = printer.configfile.config["stepper_x"]["position_max"]|float %}
{% set max_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
{% set max_z = printer.configfile.config["stepper_z"]["position_max"]|float %}
{% set current_extruder_temp = printer.extruder.temperature|float %}
{% set min_extrusion_temp = printer.configfile.config["extruder"]["min_extrude_temp"]|float %}
{% set z_clearance = 50 %}
{% if (printer.toolhead.position.z + z_clearance) < max_z %}
{% set z_hop = 2 %}
{% else %}
{% set z_hop = 0 %}
{% endif %}
M106 P0 S0 ; Turn off part cooling fan
M106 P2 S0 ; Turn off side fan
M106 P3 S0 ; Turn off activated charcoal fan
M104 S0 ; Turn off hotend
M140 S0 ; Turn off heated bed
M141 S0 ; Turn off heated chamber
G91 ; Relative positioning
{% if current_extruder_temp >= min_extrusion_temp + 5 %} ; Check if the hotend is hot enough to perform a retraction (with a small gap)
G0 E-4.0 F300 ; Retract filament
{% endif %}
G0 Z{z_hop} F3600 ; Move bed down a bit
G90 ; Absolute positioning
G0 X{max_x/2} Y{max_y-40} F20000 ; Move nozzle to remove stringing
_Z_CLEARANCE DISTANCE={z_clearance} ; Lower bed
M400 ; Wait for buffer to clear
G92 E0 ; Zero the extruder
M220 S100 ; Set feedrate (speed percentage) back to 100%
M221 S100 ; Set flow percentage back to 100%
SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; Set timeout back to configured value
CLEAR_PAUSE ; Ensure pause state is cleared if applicable
M84 ; Disable steppers
SET_TEMPERATURE_FAN_TARGET TEMPERATURE_FAN=Mainboard_fan TARGET=45 ; Reset the mainboard fan temp
BEEP I=2 DUR=500 ; Alert at the end of the print (if sound is enabled)
[gcode_macro PAUSE]
rename_existing: BASE_PAUSE
gcode:
{% set z_hop = params.Z|default(30)|int %} ; Z hop amount
{% if printer['pause_resume'].is_paused|int == 0 %}
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=zhop VALUE={z_hop} ; Set Z hop variable for reference in resume macro
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=etemp VALUE={printer['extruder'].target} ; Set hotend temperature variable for reference in resume macro
SAVE_GCODE_STATE NAME=PAUSE ; Save current position for resume
BASE_PAUSE ; Pause print
{% if (printer.gcode_move.position.z + z_hop) < printer.toolhead.axis_maximum.z %} ; Check that Z hop doesn't exceed Z max
G91 ; Use Relative positioning
G1 Z{z_hop} F600 ; Raise Z up by Z hop amount
{% else %}
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=zhop VALUE=0 ; Set Z hop to 0 if exceeds max
{% endif %}
SAVE_GCODE_STATE NAME=PAUSEPARK2
G90 ; Absolute positioning
G1 X{printer.toolhead.axis_maximum.x/2} Y{printer.toolhead.axis_maximum.y-40} F6000 ; Park toolhead at rear center
SAVE_GCODE_STATE NAME=PAUSEPARK ; Save parked position in case toolhead is moved during the pause (otherwise the return zhop can error)
M104 S0 ; Turn off hotend
SET_IDLE_TIMEOUT TIMEOUT=43200 ; Set timeout to 12 hours
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=0 ; Disable extruder stepper
{% endif %}
[gcode_macro RESUME]
rename_existing: BASE_RESUME
variable_zhop: 0
variable_etemp: 0
gcode:
{% set extrusion_length = params.E|default(2.5)|int %} ; Hotend prime amount (in mm)
{% if printer['pause_resume'].is_paused|int == 1 %}
{% if "z" not in printer.toolhead.homed_axes %} ; check if z position is lost
{action_raise_error("ERROR: Z-axixs lost its position (Idle-Timeout)! Resume not possible - Print should be aborted.")}
{% endif %}
SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; Set idle timeout back to configured value
# If X/Y position lost: Give Z-clearance for homing X/Y that will be done by PRIME_NOZZLE
{% if "x" not in printer.toolhead.homed_axes or "y" not in printer.toolhead.homed_axes %} ; If X/Y position is lost, but z is still OK
G91 ; Relative positioning
G1 Z5 F600 ; 5mm clearance for safe X/Y-Homing
G90 ; Absolute positioning
{% endif %}
PRIME_NOZZLE HOTEND_TARGET_TEMP={etemp} ; Prime nozzle with last used hotend temperature
M109 S{etemp} ; Wait for hotend to heat up
RESTORE_GCODE_STATE NAME=PAUSEPARK2 MOVE=1 MOVE_SPEED=150 ; Return to position after Z-hop (safely above the part)
RESTORE_GCODE_STATE NAME=PAUSE MOVE=1 MOVE_SPEED=10 ; Restore position
BASE_RESUME ; Absolute positioning
{% endif %}
[gcode_macro CANCEL_PRINT]
rename_existing: BASE_CANCEL_PRINT
gcode:
{% set max_z = printer.configfile.config["stepper_z"]["position_max"]|float %}
{% if (printer.toolhead.position.z + 12) < max_z %}
{% set z_hop = 2 %}
{% else %}
{% set z_hop = 0 %}
{% endif %}
G91 ; Relative positioning
G1 Z{z_hop} F600 ; Do a tiny z-hop
G90 ; Absolute positioning
G1 X{printer.toolhead.axis_maximum.x/2} Y{printer.toolhead.axis_maximum.y-40} F12000
CLEAR_PAUSE
SDCARD_RESET_FILE
PRINT_END
BASE_CANCEL_PRINT
[gcode_macro _Z_CLEARANCE]
description: Lower the bed to give some clearance
variable_default_distance: 40.0
gcode:
{% set current_z_height = printer.toolhead.position.z %}
{% set max_z_height = printer.toolhead.axis_maximum.z %}
{% set distance = params.DISTANCE|default(variable_default_distance)|float %}
{% set target_z_height = current_z_height + distance %}
{% set min_z_param = params.MIN_Z|default(None) %}
{% if min_z_param is not none %}
{% set min_z = min_z_param|float %}
{% if target_z_height < min_z %}
{% set target_z_height = min_z %}
{% endif %}
{% endif %}
G90 ; Absolute positioning
G1 Z{ [target_z_height, max_z_height]|min }
########################################
# Filament Macros
########################################
[gcode_macro UNLOAD_FILAMENT]
description: Unloads filament from toolhead
gcode:
{% set EXTRUDER_TEMP = params.TEMP|default(230)|int %}
{% set CURRENT_TEMP = printer.extruder.temperature|int %}
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M104 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
GO_TO_POOP_SHOOT ; go to poop shoot
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M109 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=1 ; enable extruder stepper
M83 ; set extruder to relative mode
G1 E5 F150 ; extrude a small amount to elimate soften the filament
G1 E-8 F1800 ; quickly retract a small amount to elimate stringing
G4 P200 ; pause for a short amount of time
G1 E-50 F300 ; retract slowly the rest of the way
M104 S0 ; turn off hotend
LEAVE_POOP_SHOOT ; leave poop shoot
M400 ; wait for moves to finish
M118 Unload Complete!
[gcode_macro LOAD_FILAMENT]
description: Loads filament to toolhead
gcode:
{% set EXTRUDER_TEMP = params.TEMP|default(230)|int %}
{% set CURRENT_TEMP = printer.extruder.temperature|int %}
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M104 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
GO_TO_POOP_SHOOT ; go to poop shoot
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M109 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=1 ; enable extruder stepper
M83 ; set extruder to relative mode
G1 E5 F120 ; feed filament
G1 E5 F300 ; feed filament
G1 E40 F600 ; feed filament
G1 E15 F300 ; feed filament
G1 E15 F120 ; feed filament
G4 P200 ; pause for a short amount of time
G1 E10 F90 ; feed filament
M104 S0 ; turn off hotend
LEAVE_POOP_SHOOT ; leave poop shoot
M400 ; wait for moves to finish
M118 Load Complete!
# Filament runout sensor enable/disable
[gcode_macro M8029]
gcode:
{% if params.D is defined %}
{% if (params.D|int)==1 %}
SET_FILAMENT_SENSOR SENSOR=filament_tangle_sensor ENABLE=1
{% endif %}
{% if (params.D|int)==0 %}
SET_FILAMENT_SENSOR SENSOR=filament_tangle_sensor ENABLE=0
{% endif %}
{% endif %}
########################################
# Fan Macros
########################################
# Set Fan Speed macro
# Mainly name castings for nicer web interface names and display functionality
[gcode_macro M106]
rename_existing: M106.1
gcode:
{% if params.P is defined %}
{% if params.S is defined %}
{% set speed = 0.003921*params.S|int %}
{% if (params.P|int) == 0 %}
M106.1 S{params.S|int}
{% elif (params.P|int) == 2 %}
SET_FAN_SPEED FAN=sidefan SPEED={speed}
{% elif (params.P|int) == 3 %}
SET_FAN_SPEED FAN=filterfan SPEED={speed}
{% else %}
SET_FAN_SPEED FAN=fan{params.P|int} SPEED={speed}
{% endif %}
{% else %}
{% if (params.P|int) == 0 %}
M106.1 S255
{% elif (params.P|int) == 2 %}
SET_FAN_SPEED FAN=sidefan SPEED=1
{% elif (params.P|int) == 3 %}
SET_FAN_SPEED FAN=filterfan SPEED=1
{% else %}
SET_FAN_SPEED FAN=fan{params.P|int} SPEED=1
{% endif %}
{% endif %}
{% endif %}
{% if params.T is defined %}
{% if (params.T|int) == -2 %}
{% if params.S is defined %}
{% set speed = 0.003921*params.S|int %}
SET_FAN_SPEED FAN=filterfan SPEED={speed}
{% else %}
SET_FAN_SPEED FAN=filterfan SPEED=1
{% endif %}
{% endif %}
{% endif %}
{% if params.P is undefined %}
{% if params.T is undefined %}
{% if params.S is defined %}
M106.1 S{params.S|int}
{% else %}
M106.1 S255
{% endif %}
{% endif %}
{% endif %}
[gcode_macro M107]
rename_existing: M107.1
gcode:
M106.1 S0
########################################
# Temperature Macros
########################################
# Wait for Hotend Temperature
[gcode_macro M109]
rename_existing: M109.1
gcode:
#Parameters
{% set s = params.S|float %}
M104 {% for p in params %}{'%s%s' % (p, params[p])}{% endfor %} ; Set hotend temp
{% if s != 0 %}
TEMPERATURE_WAIT SENSOR=extruder MINIMUM={s} MAXIMUM={s+1} ; Wait for hotend temp (within 1 degree)
{% endif %}
# PID autotune
[gcode_macro M303]
gcode:
{% if params.E is defined %}
{% if params.S is defined %}
{% if (params.E|int)==-1 %}
PID_CALIBRATE HEATER=heater_bed TARGET={params.S|int}
{% endif %}
{% if (params.E|int)==0 %}
PID_CALIBRATE HEATER=extruder TARGET={params.S|int}
{% endif %}
{% endif %}
{% endif %}
# Set chamber temperature
[gcode_macro M141]
gcode:
{% if printer["heater_generic chamber"] is defined %}
{% set chamber_target_temp = params.S|float %}
SET_HEATER_TEMPERATURE HEATER=chamber TARGET={([chamber_target_temp, 65]|min)}
{% endif %}
# Set wait chamber temperature
[gcode_macro M191]
gcode:
#Parameters
{% set chamber_target_temp = params.S|float %}
{% if chamber_target_temp == 0 %}
M118 Chamber heater off
{% else %}
M141 S{chamber_target_temp}
TEMPERATURE_WAIT SENSOR="heater_generic chamber" MINIMUM={([chamber_target_temp, 65]|min)-2} MAXIMUM={chamber_target_temp + 5}
M118 Chamber at target temperature
{% endif %}
########################################
# Sound Macros
########################################
[gcode_macro BEEP]
gcode:
# Parameters
{% set i = params.I|default(1)|int %} ; Iterations (number of times to beep).
{% set dur = params.DUR|default(100)|int %} ; Duration/wait of each beep in ms. Default 100ms.
{% if printer["output_pin sound"].value|int == 1 %}
{% for iteration in range(i|int) %}
SET_PIN PIN=buzzer VALUE=1
G4 P{dur}
SET_PIN PIN=buzzer VALUE=0
G4 P{dur}
{% endfor %}
{% endif %}
[gcode_macro beep_on]
gcode:
SET_PIN PIN=buzzer VALUE=1
[gcode_macro beep_off]
gcode:
SET_PIN PIN=buzzer VALUE=0
########################################
# Z-height Macros
########################################
# Bed Leveling (Unified)
[gcode_macro G29]
variable_k:1
gcode:
{% set temp = printer["heater_generic chamber"].target %}
M141 S0
{% if temp > 0 %}
G4 P15000
{% endif %}
{% if k|int==1 %}
BED_MESH_CLEAR ; Clear levelling data
BED_MESH_CALIBRATE ADAPTIVE=1 ADAPTIVE_MARGIN=5 ; Start adaptive meshing
{% endif %}
M141 S{temp}
# Babystep
[gcode_macro M290]
gcode:
SET_GCODE_OFFSET Z_ADJUST={params.Z}
########################################
# Tuning Macros
########################################
[gcode_macro SHAPER_CALIBRATE]
rename_existing: RESHAPER_CALIBRATE
gcode:
RESHAPER_CALIBRATE FREQ_START=30 FREQ_END=130
# Linear Advance Factor
[gcode_macro M900]
gcode:
{% if params.K is defined %}
SET_PRESSURE_ADVANCE ADVANCE={params.K}
{% endif %}
{% if params.T is defined %}
SET_PRESSURE_ADVANCE SMOOTH_TIME={params.T}
{% endif %}
# Set Starting Acceleration
[gcode_macro M204]
rename_existing: M99204
gcode:
{% if params.S is defined %}
{% set s = params.S|float %}
{% endif %}
{% if params.P is defined %}
{% if params.T is defined %}
{% set s = [params.P|float ,params.T|float] | min %}
{% endif %}
{% endif %}
SET_VELOCITY_LIMIT ACCEL={s}
SET_VELOCITY_LIMIT ACCEL_TO_DECEL={s/2}
# Bed leveling
# For more information, see https://www.klipper3d.org/Manual_Level.html#adjusting-bed-leveling-screws-using-the-bed-probe
[gcode_macro LEVEL_BED]
description: "Measure bed and calculate screw adjustments for manual bed leveling"
gcode:
G28 ; Home all
SCREWS_TILT_CALCULATE ; Perform measurements and output screw adjustments
# Automatic rough Bed Leveling by ramming the bed to the bottom
[gcode_macro AUTO_LEVEL_BED]
gcode:
{% set Z_max = printer.toolhead.axis_maximum.z %}
G28
G1 Z{Z_max-30} F600
SET_TMC_CURRENT STEPPER=stepper_z CURRENT={printer.configfile.settings['tmc2209 stepper_z'].run_current * 0.5 }
SET_TMC_CURRENT STEPPER=stepper_z1 CURRENT={printer.configfile.settings['tmc2209 stepper_z1'].run_current * 0.5 }
G1 Z{Z_max} F600
SET_KINEMATIC_POSITION Z=0
G1 Z10 F600
G1 Z0 F600
G1 Z15 F600
SET_TMC_CURRENT STEPPER=stepper_z CURRENT={printer.configfile.settings['tmc2209 stepper_z'].run_current}
SET_TMC_CURRENT STEPPER=stepper_z1 CURRENT={printer.configfile.settings['tmc2209 stepper_z1'].run_current}
G28
# Probe Calibration
# For more information, see https://www.klipper3d.org/Probe_Calibrate.html
[gcode_macro CALIBRATE_Z_OFFSET]
description: "Calibrate the Z offset using the probe"
gcode:
{% set max_x = printer.configfile.config["stepper_x"]["position_max"]|float %}
{% set max_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
G28 ; Home all
G0 Z10 ; Increase z clearance
G0 X{max_x/2} Y{max_y-40} F6000 ; Move to bed center
PROBE_CALIBRATE ; Perform a probe calibration
# Nozzle PID tuning
# For more information, see https://www.klipper3d.org/Config_checks.html#calibrate-pid-settings
[gcode_macro NOZZLE_PID_TUNE]
description: "Perform PID tuning for the nozzle heater"
gcode:
PID_CALIBRATE HEATER=extruder TARGET=220 ; PID tune the nozzle
# Bed PID tuning
# For more information, see https://www.klipper3d.org/Config_checks.html#calibrate-pid-settings
[gcode_macro BED_PID_TUNE]
description: "Perform PID tuning for the bed heater"
gcode:
PID_CALIBRATE HEATER=heater_bed TARGET=80 ; PID tune the bed
########################################
# Macros for display functionallity
########################################
[gcode_macro INPUT_SHAPING_CALIBRATE]
description: "Perform Input Shaping calibration and save the results to printer.cfg"
gcode:
SHAPER_CALIBRATE ; Step 1: Perform the Input Shaping calibration
PAUSE ; Step 2: Pause to allow the calibration to complete
SAVE_CONFIG ; Step 3: Save the configuration to printer.cfg
RESTART ; Step 4: Restart the firmware to apply the new settings
================================================
FILE: config_section/Plus4/printer.cfg
================================================
# Plus4 config created by Phil1988(github)/coco.33(discord) on 04.05.2025
# For more information check out my wiki: https://github.com/Phil1988/FreeDi/wiki
#####################################################################
# Kinematics
#####################################################################
[printer]
kinematics:corexy
max_velocity: 600
max_accel: 20000
max_z_velocity: 20
max_z_accel: 500
square_corner_velocity: 8
#####################################################################
# Motherboard and periphery
#####################################################################
[temperature_sensor Mainboard_RK3328]
sensor_type: temperature_host
min_temp: 10
max_temp: 100
[mcu]
serial: /dev/ttyS0
restart_method: command
baud: 500000
[temperature_sensor Mainboard_STM32F402]
sensor_type: temperature_mcu
sensor_mcu: mcu
[mcu Toolhead]
serial: /dev/ttyS2
restart_method: command
baud: 500000
[temperature_sensor Toolhead_STM32F103XE]
sensor_type: temperature_mcu
sensor_mcu: Toolhead
min_temp: 0
max_temp: 100
#####################################################################
# Features
#####################################################################
# For saving GCODE files
[virtual_sdcard]
path: ~/printer_data/gcodes
on_error_gcode: CANCEL_PRINT
# For enabling pause/resume
[pause_resume]
# Activating exclude objects feature
[display_status]
[exclude_object]
# Expanding idle timeout
[idle_timeout]
timeout: 5400 ; 90min timeout
# Activating GCODE arc feature
[gcode_arcs]
resolution: 1.0
# Allowing free move (can be dangerous!)
[force_move]
enable_force_move: True
# Activating responses
[respond]
default_type: echo
#####################################################################
# FreeDi
#####################################################################
[include freedi.cfg]
#####################################################################
# Macros
#####################################################################
[include macros.cfg]
#####################################################################
# Input shaping
#####################################################################
[resonance_tester]
accel_chip: adxl345
probe_points:
150, 150, 10
accel_per_hz: 75
sweeping_period: 0
max_smoothing: 0.5
[adxl345]
cs_pin: Toolhead:PA4
spi_software_sclk_pin: Toolhead:PA5
spi_software_mosi_pin: Toolhead:PA7
spi_software_miso_pin: Toolhead:PA6
axes_map: -x, z, -y
[input_shaper]
shaper_type_x: mzv
shaper_freq_x: 57.6
shaper_type_y: mzv
shaper_freq_y: 46.6
#####################################################################
# Hotend
#####################################################################
[extruder]
step_pin: Toolhead:PB9
dir_pin: Toolhead:PB8
enable_pin: !Toolhead:PC15
rotation_distance: 53.7
gear_ratio: 1517:170
microsteps: 16
full_steps_per_rotation: 200
nozzle_diameter: 0.400
filament_diameter: 1.75
min_temp: 0
max_temp: 360
min_extrude_temp: 170
smooth_time: 0.000001
step_pulse_duration: 0.000002
heater_pin: Toolhead:PB3
sensor_type: MAX6675
sensor_pin: Toolhead:PB12
max_power: 1.0
control: pid
pid_Kp: 33.879
pid_Ki: 6.453
pid_Kd: 44.467
spi_speed: 100000
spi_software_sclk_pin: Toolhead:PB13
spi_software_mosi_pin: Toolhead:PA11
spi_software_miso_pin: Toolhead:PB14
pressure_advance: 0.032
pressure_advance_smooth_time: 0.03
max_extrude_cross_section:500
instantaneous_corner_velocity: 10.000
max_extrude_only_distance: 1000.0
max_extrude_only_velocity: 5000
max_extrude_only_accel: 5000
[verify_heater extruder]
max_error: 120
check_gain_time:20
hysteresis: 5
heating_gain: 1
#####################################################################
# Heated bed
#####################################################################
[heater_bed]
heater_pin: PB10
sensor_type: NTC 100K MGB18-104F39050L32
sensor_pin: PA0
max_power: 1.0
control: pid
pid_kp: 70.638
pid_ki: 0.671
pid_kd: 1859.554
min_temp: -50
max_temp: 125
pwm_cycle_time: 0.02 # for 50Hz line power
#pwm_cycle_time: 0.016 # for 60Hz line power
[verify_heater heater_bed]
max_error: 200
check_gain_time: 360
hysteresis: 5
heating_gain: 1
#####################################################################
# Bed mesh
#####################################################################
[bed_mesh]
speed: 150
horizontal_move_z: 2.6
mesh_min: 25,10
mesh_max: 295,295
probe_count: 9,9
algorithm: bicubic
bicubic_tension: 0.3
mesh_pps: 4, 4
#####################################################################
# Probe
#####################################################################
#!# Pay attention to this section and compare it with your stock backup config
[probe]
pin: ^!Toolhead:PA10
x_offset: 25
y_offset: 1.3
z_offset: 1.00 #!# change this to 0 if you get a "Probe triggered prior to movement" - Error
speed: 5
samples: 2
samples_result: average
sample_retract_dist: 0.7
samples_tolerance: 0.08
samples_tolerance_retries: 3
# Check this for documentation https://github.com/frap129/qidi_auto_z_offset
# Add AUTO_Z_LOAD_OFFSET to your PRINT_START macro to load the value every time you start a print.
# If you make adujstments to the offset by micro-stepping durring a print, you can save that with AUTO_Z_SAVE_GCODE_OFFSET and SAVE_CONFIG
[auto_z_offset]
pin: PC1
# Adjust this z_offset value for a good first layer:
# decrease if lines are squished (eg -0.2 -> -0.25)
# increase if lines are thin/not sticking (-0.2 -> -0.15)
z_offset: -0.2
calibrated_z_offset: -1.00
speed: 13
probe_accel: 50
samples: 5
samples_result: median
samples_tolerance: 0.013
samples_tolerance_retries: 5
offset_samples: 3
prepare_gcode:
G90
G0 Z3
G91
SET_PIN PIN=bed_sensor VALUE=0
M204 S10000
{% set i = 6 %}
{% for iteration in range(i|int) %}
G1 Z5 F1200
G1 Z-5 F1200
{% endfor %}
G1 Z3
G90
SET_PIN PIN=bed_sensor VALUE=1
[output_pin bed_sensor]
pin: !PA14
pwm: false
shutdown_value:0
value:0
#####################################################################
# Heated chamber
#####################################################################
[temperature_sensor chamber_sensor]
sensor_type: NTC 100K MGB18-104F39050L32
sensor_pin: PA1
[heater_generic chamber]
heater_pin: PC8
#!# Caution!
#set max_power to 0.4 for 110V
#set max_power to 0.7 for 220V
#set max_power to 1.0 if you are using a quality aftermarket SSR with a heat sink
max_power: 0.4 #!# Pay attention to this value and compare it with your stock backup config and with caution (read the comments)
#sensor_type: NTC 100K MGB18-104F39050L32
#sensor_pin: PA1
sensor_type: temperature_combined
sensor_list: temperature_sensor Toolhead_STM32F103XE, temperature_sensor Toolhead_STM32F103XE, temperature_sensor Toolhead_STM32F103XE, temperature_sensor chamber_sensor
combination_method: mean
maximum_deviation: 70
control: pid
pid_Kp: 63.418
pid_Ki: 1.342
pid_Kd: 749.125
min_temp: -100
max_temp: 75
[verify_heater chamber]
max_error: 400
check_gain_time: 600
hysteresis: 5
heating_gain: 2
[temperature_sensor Chamber_Heater]
sensor_type: NTC 100K MGB18-104F39050L32
sensor_pin: PC2
min_temp: -100
max_temp: 140
########################################
# Filament sensors
########################################
[filament_switch_sensor filament_tangle_sensor]
switch_pin: PC3
pause_on_runout: True
runout_gcode:
M118 Filament tangled!
event_delay: 3.0
pause_delay: 0.5
[hall_filament_width_sensor]
adc1: Toolhead:PA2
adc2: Toolhead:PA3
cal_dia1: 1.50
cal_dia2: 2.0
raw_dia1: 14206
raw_dia2: 15278
default_nominal_filament_diameter: 1.75
max_difference: 0.00
measurement_delay: 50
enable: True
enable_flow_compensation: False
measurement_interval: 3
logging: False
min_diameter: 1.00
use_current_dia_while_delay: False
pause_on_runout: True
runout_gcode:
M118 Filament run out!
event_delay: 3.0
pause_delay: 0.5
#####################################################################
# Fans
#####################################################################
## Part cooling fan
# [fan_generic partfan]
# pin: Toolhead:PA8
# max_power: 1.0
# cycle_time: 0.0100
# hardware_pwm: false
# kick_start_time: 0.200
# off_below: 0.08
# shutdown_speed: 0
[fan]
pin: Toolhead:PA8
max_power: 1.0
cycle_time: 0.0100
hardware_pwm: false
kick_start_time: 0.200
off_below: 0.08
shutdown_speed: 0.0
## Big side radial turbo fan
[fan_generic sidefan]
pin: PA8
max_power: 1.0
cycle_time: 0.0100
hardware_pwm: false
kick_start_time: 0.250
off_below: 0.3
shutdown_speed: 0
## Activated charcoal blowing fan
[fan_generic filterfan]
pin: PC9
max_power: 1.0
cycle_time: 0.0100
hardware_pwm: false
kick_start_time: 0.200
off_below: 0.3
shutdown_speed: 0
## Chamber heater fan
[heater_fan chamber_heater_fan]
pin: PA4
max_power: 1.0
shutdown_speed: 0
kick_start_time: 0.5
heater: chamber
fan_speed: 1.0
off_below: 0
heater_temp: 40
## Cold end and toolhead housing fans
[heater_fan hotend_fan]
pin: Toolhead:PB5
max_power: 1.0
shutdown_speed: 1.0
kick_start_time: 0.5
heater: extruder
heater_temp: 50.0
fan_speed: 1.0
off_below: 0
# Toolhead cooling fan
[heater_fan hotend_fan2]
pin:Toolhead: PB4
max_power: 1.0
shutdown_speed: 1.0
kick_start_time: 0.5
heater: extruder
heater_temp: 50.0
fan_speed: 1.0
off_below: 0
# Toolhead cooling fan
[heater_fan hotend_fan3]
pin:Toolhead: PB10
max_power: 1.0
shutdown_speed: 1.0
kick_start_time: 0.5
heater: extruder
heater_temp: 50.0
fan_speed: 1.0
off_below: 0
#!# Delete the next section if your stock backup config doesnt have it
## Controllable Mainboard cooling fan
[temperature_fan Mainboard_fan]
sensor_type: temperature_host
pin: PC4
max_power: 1.0
cycle_time: 0.01
sensor_type: temperature_combined
sensor_list: temperature_sensor Mainboard_RK3328, temperature_sensor Mainboard_STM32F402
combination_method: max # use the maximum reading of the sensors
maximum_deviation: 999.9 # we don't care about the difference in temperature
shutdown_speed: 0.0
kick_start_time: 0.4
off_below: 0.19
min_temp: 0
max_temp: 85.0
target_temp: 42.0
min_speed: 0
max_speed: 1.0
control: pid
pid_deriv_time: 2.0
pid_Kp: 5.0
pid_Ki: 2.5
pid_Kd: 3.5
#####################################################################
# Light
#####################################################################
## caselight LEDs
[output_pin caselight]
pin: PC7
pwm: true
cycle_time: 0.0100
shutdown_value:0
value:1
#####################################################################
# Buzzer
#####################################################################
## Buzzer
[output_pin buzzer]
pin: PA2
pwm: false
shutdown_value:0
value:0
[output_pin sound]
pin: Toolhead:PA1
value:0
#####################################################################
# Power outage shutdown
#####################################################################
[output_pin pwc]
pin: PA3
pwm: False
value: 1
shutdown_value: 1
#####################################################################
# Drives
#####################################################################
[stepper_x]
step_pin: PB4
dir_pin: !PB3
enable_pin: !PB5
microsteps: 32
rotation_distance: 38.82
full_steps_per_rotation: 200
endstop_pin: tmc2240_stepper_x:virtual_endstop
position_min: -1.5
position_endstop: -1.5
position_max: 307
homing_speed: 55
homing_retract_dist:0
homing_positive_dir:False
step_pulse_duration:0.0000001
[stepper_y]
step_pin: PC14
dir_pin: !PC13
enable_pin: !PC15
microsteps: 32
rotation_distance: 38.82
full_steps_per_rotation:200
endstop_pin: tmc2240_stepper_y:virtual_endstop
position_min: -2
position_endstop: -2
position_max: 325
homing_speed: 55
homing_retract_dist: 0
homing_positive_dir: False
step_pulse_duration: 0.0000001
[stepper_z]
step_pin: PB1
dir_pin: PB6
enable_pin: !PB0
microsteps: 16
rotation_distance: 4
full_steps_per_rotation: 200
endstop_pin: probe:z_virtual_endstop
position_max:285
position_min: -4
homing_speed: 13
homing_retract_dist: 8.0
second_homing_speed: 5
homing_positive_dir: False
step_pulse_duration: 0.000002
[stepper_z1]
step_pin: PC10
dir_pin: PA15
enable_pin: !PC11
microsteps: 16
rotation_distance: 4
full_steps_per_rotation: 200
step_pulse_duration: 0.000002
#####################################################################
# Steppers configuration
#####################################################################
[tmc2209 extruder]
uart_pin: Toolhead:PC13
interpolate: False
run_current: 0.714 #!# Pay attention to this value and compare it with your stock backup config
stealthchop_threshold: 0
sense_resistor: 0.075
[tmc2240 stepper_x]
cs_pin: PD2
spi_software_sclk_pin: PA5
spi_software_mosi_pin: PA7
spi_software_miso_pin: PA6
spi_speed: 200000
run_current: 1.07 #!# Pay attention to this value and compare it with your stock backup config
interpolate: False
stealthchop_threshold: 0
diag0_pin: !PB8
driver_SGT: 1
rref: 12000
[tmc2240 stepper_y]
cs_pin: PB9
spi_software_sclk_pin: PA5
spi_software_mosi_pin: PA7
spi_software_miso_pin: PA6
spi_speed: 200000
run_current: 1.07 #!# Pay attention to this value and compare it with your stock backup config
interpolate: False
stealthchop_threshold: 0
diag0_pin: !PC0
driver_SGT:1
rref: 12000
[tmc2209 stepper_z]
uart_pin: PB7
run_current: 1.07 #!# Pay attention to this value and compare it with your stock backup config
interpolate: False
stealthchop_threshold: 9999999999
diag_pin: ^PA13
sense_resistor: 0.075
[tmc2209 stepper_z1]
uart_pin: PC5
run_current: 1.07 #!# Pay attention to this value and compare it with your stock backup config
interpolate: False
stealthchop_threshold: 9999999999
diag_pin: ^PC12
sense_resistor: 0.075
#####################################################################
# Bed tilt adjust
#####################################################################
[z_tilt]
z_positions:
-17.5,138.5
335.7,138.5
points:
0,138.5
255,138.5
speed: 150
horizontal_move_z: 10
retries: 5
retry_tolerance: 0.013
#####################################################################
# Screws tilt adjust
#####################################################################
[screws_tilt_adjust]
horizontal_move_z: 5
screw_thread: CW-M4
speed: 300
screw1:0,20
screw1_name: Front left
screw2: 260,20
screw2_name: Front right
screw3: 260,280
screw3_name: Back right
screw4: 0,280
screw4_name: Back left
================================================
FILE: config_section/Q1_Pro/macros.cfg
================================================
#####################################################################
# Specific Q1 Pro macros
#####################################################################
[gcode_macro SET_PRINT_STATS_INFO]
rename_existing: BASE_SET_PRINT_STATS_INFO_BASE
gcode:
TIMELAPSE_TAKE_FRAME
BASE_SET_PRINT_STATS_INFO_BASE {rawparams}
CHAMBER_TEMP_CONTROLLER
# Safety macro that gets frequently called by SET_PRINT_STATS_INFO to prevent too high chamber temperatures
[gcode_macro CHAMBER_TEMP_CONTROLLER]
gcode:
{% set chamber_target_temp = printer['heater_generic chamber'].target %}
{% set chamber_temp = printer['heater_generic chamber'].temperature %}
{% if chamber_temp > printer.configfile.settings['heater_generic chamber'].max_temp %}
M106 P3 S255
{% else %}
{% if chamber_target_temp > 0 %}
# Allow for 3C of "grace" before we start ramping the exhaust fan speed
# This prevents the macro from fighting with the chamber heater PID algorithm
{% set difference = chamber_temp - (chamber_target_temp + 3) %}
{% if difference > 0 %}
{% set filterfan_speed = ([(difference * 50), 255] | min) | int %}
M106 P3 S{filterfan_speed}
{% else %}
M106 P3 S0
{% endif %}
{% endif %}
{% endif %}
[gcode_macro CHAMBER_TEMP_CONTROLLER]
gcode:
{% set chamber_cfg = printer.configfile.settings['heater_generic chamber'] %}
{% set chamber_target_temp = printer['heater_generic chamber'].target %}
{% set chamber_temp = printer['heater_generic chamber'].temperature %}
{% set min_filterfan = (255 * 0.40) | int %} # ~35 % Mindestdrehzahl
{% if chamber_temp > chamber_cfg.max_temp %}
M106 P3 S255
{% elif chamber_target_temp > 0 %}
{% set difference = chamber_temp - (chamber_target_temp + 3) %}
{% set raw_speed = ([(difference * 50), 255] | min) | int %}
{% set filterfan_speed = [raw_speed, min_filterfan] | max %}
M106 P3 S{filterfan_speed}
{% else %}
M106 P3 S0
{% endif %}
[gcode_macro HOME_IF_NEEDED]
description: Homes X and Y if needed
gcode:
{% if "y" not in printer.toolhead.homed_axes %}
G28 Y
{% endif %}
{% if "x" not in printer.toolhead.homed_axes %}
G28 X
{% endif %}
{% if "z" not in printer.toolhead.homed_axes %}
G28 Z
{% endif %}
[gcode_macro _SET_ACCEL]
gcode:
{% set printer_config = printer.configfile.settings['printer'] %}
{% set set_acceleration = params.ACCEL|default(printer_config.max_accel)|float %}
SET_VELOCITY_LIMIT ACCEL={set_acceleration}
[gcode_macro _FELT_WIPE]
description: Wipe on the felt pad
gcode:
G90 ; Absolute positioning
; Input values for the minimum and maximum coordinates of the pad
{% set pad_min_coordinate_x = 60 %}
{% set pad_max_coordinate_x = 88 %}
{% set pad_min_coordinate_y = 250 %}
{% set pad_max_coordinate_y = 254 %}
{% set margin = 1 %} ; margin from the edge of the pad
{% set repetitions = 3 %}
; Calculate wipe area (with margin)
{% set x_start = pad_min_coordinate_x + margin %}
{% set x_end = pad_max_coordinate_x - margin %}
{% set y_start = pad_min_coordinate_y + margin %}
{% set y_end = pad_max_coordinate_y - margin %}
; First X wiping (Y stays constant, X moves back and forth)
{% set random_y_start = (range(0, (y_end - y_start) * 20) | random) / 20 + y_start %} ; Calculate a random starting Y position within the allowed range
G1 Y{random_y_start} F1500 ; Move to random Y position
G1 X{x_start} F1500 ; Move to X start position
{% for move in range(repetitions|int) %}
G1 X{x_end} F500
G1 X{x_start} F500
{% endfor %}
; Y wiping (X stays constant, Y moves back and forth)
{% set random_x_start = (range(0, (x_end - x_start) * 20) | random) / 20 + x_start %} ; Calculate a random starting X position within the allowed range
G1 X{random_x_start} F1500 ; Move to random X position
G1 Y{y_start} F1500 ; Move to Y start position
{% for move in range(repetitions|int) %}
G1 Y{y_end} F500
G1 Y{y_start} F500
{% endfor %}
; Additional X wiping (Y stays constant, X moves back and forth)
{% set random_y_start_2 = (range(0, (y_end - y_start) * 20) | random) / 20 + y_start %} ; Calculate a random starting Y position within the allowed range
G1 Y{random_y_start_2} F1500 ; Move to random Y position again
G1 X{x_start} F1500 ; Move to X start position
{% for move in range(repetitions|int) %}
G1 X{x_end} F500
G1 X{x_start} F500
{% endfor %}
[gcode_macro GO_TO_POOP_BUCKET]
description: Move toolhead to poop bucket
gcode:
{% set curr_x = printer.toolhead.position.x %}
{% set curr_y = printer.toolhead.position.y %}
{% if (curr_y != 240) or (curr_x != 97) %}
_Z_CLEARANCE DISTANCE=0 MIN_Z=40 ; Make sure to have enough clearance
G90 ; Absolute positioning
{% if printer.gcode_move.position.y > 240 %}
G1 Y240 F9000
{% endif %}
G1 X97 Y240 F9000
_SET_ACCEL ACCEL=100 ; Reduce acceleration to 100mm/s^2
G1 Y254 F1500 ; gently press against wiper arm
_SET_ACCEL ; Reset acceleration
{% endif %}
[gcode_macro LEAVE_POOP_BUCKET]
description: Leaving the poop bucket
gcode:
{% set curr_x = printer.toolhead.position.x %}
{% set curr_y = printer.toolhead.position.y %}
{% if (curr_y >= 240) and (curr_x >= 59) and (curr_x <= 98) %}
G90 ; Absolute positioning
_SET_ACCEL ACCEL=500
G1 Y254 F2000
G1 X70 F5000
_SET_ACCEL ACCEL=100
G1 Y240 F1500 ; gently leave the wiper arm
_SET_ACCEL ; reset accel
{% endif %}
[gcode_macro _BUCKET_CUT]
description: Cut off the extruded filament on the nozzle
gcode:
{% set i = 6 %}
{% for iteration in range(i|int) %}
G1 X85 F2000
G1 X97 F2000
{% endfor %}
[gcode_macro PRIME_NOZZLE]
description: Primes the nozzle with fresh filament before load/unload/print start
gcode:
{% set hotend_target_temp = params.HOTEND_TARGET_TEMP|default(220)|int %}
M106 S0
M104 S{hotend_target_temp}
HOME_IF_NEEDED
TEMPERATURE_WAIT SENSOR=extruder MINIMUM={hotend_target_temp-50}
GO_TO_POOP_BUCKET
M109 S{hotend_target_temp}
G92 E0
G1 E5 F50
G1 E50 F200
G92 E0
G1 E-0.8 F200
G4 P300
M104 S{([hotend_target_temp-80, 150]|min)}
M106 S255
G4 P5000
_FELT_WIPE
TEMPERATURE_WAIT SENSOR=extruder MAXIMUM={([hotend_target_temp-80, 150]|min)}
M106 S0
_BUCKET_CUT
LEAVE_POOP_BUCKET
#####################################################################
# Homing modification
#####################################################################
[gcode_macro G28]
rename_existing: G28.1
gcode:
{% set reduced_current_x = 0.55 %}
{% set reduced_current_y = 0.45 %}
{% set home_all = ('X' in rawparams.upper() and 'Y' in rawparams.upper() and 'Z' in rawparams.upper()) or
('X' not in rawparams.upper() and 'Y' not in rawparams.upper() and 'Z' not in rawparams.upper()) %}
{% set home_current_x = printer.configfile.settings['tmc2240 stepper_x'].run_current * reduced_current_x %}
{% set home_current_y = printer.configfile.settings['tmc2240 stepper_y'].run_current * reduced_current_y %}
{% set init_XY_move = 30 %}
#{% set y_init_move = 5 %}
{% set z_clearance = 2 %}
{% set home_all_final_position_x = printer.toolhead.axis_maximum.x / 2 %}
{% set home_all_final_position_y = printer.toolhead.axis_maximum.y - 40 %}
{% set home_all_final_position_z = 20 %}
{% if 'x' not in printer.toolhead.homed_axes %}
{% set X_axis_was_homed = false %} ; Set Z_axis_was_homed to false if Z is not homed
{% endif %}
{% if 'y' not in printer.toolhead.homed_axes %}
{% set Y_axis_was_homed = false %} ; Set Z_axis_was_homed to false if Z is not homed
{% endif %}
# If homing should at least move X or Y axis
{% if home_all or 'X' in rawparams.upper() or 'Y' in rawparams.upper() %}
# Check if Z is homed
{% if 'z' in printer.toolhead.homed_axes %}
{% set Z_axis_was_homed = true %} ; Set Z_axis_was_homed to true if Z is already homed
G91 ; Use relative positioning
G1 Z2 F600 ; Move bed down
G90 ; Use absolute positioning
{% else %}
{% set Z_axis_was_homed = false %} ; Set Z_axis_was_homed to false if Z is not homed
G90
SET_KINEMATIC_POSITION Z=0 ; To allow bed move down
G1 Z{z_clearance} ; Move bed down
{% if X_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=X ; Set X to be unhomed
{% endif %}
{% if Y_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=Y ; Set Y to be unhomed
{% endif %}
{% endif %}
{% endif %}
{% if home_all or 'X' in rawparams.upper() or 'Y' in rawparams.upper() %}
FORCE_MOVE STEPPER=stepper_x DISTANCE={init_XY_move} VELOCITY=40 ; Move X a little before homing
SET_KINEMATIC_POSITION X={printer.toolhead.position.x + (init_XY_move/2)} ; Compensate the FORCE_MOVE position
SET_KINEMATIC_POSITION Y={printer.toolhead.position.y + (init_XY_move/2)} ; Compensate the FORCE_MOVE position
{% if X_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=X ; Set X to be unhomed
{% endif %}
{% if Y_axis_was_homed == false %}
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=Y ; Set Y to be unhomed
{% endif %}
{% endif %}
# Home Y
{% if home_all or 'Y' in rawparams.upper() %}
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={home_current_x} ; Lower motor current
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={home_current_y} ; Lower motor current
G28.1 Y ; Home Y
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.settings['tmc2240 stepper_x'].run_current} ; Set motor current to the previous value
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.settings['tmc2240 stepper_y'].run_current} ; Set motor current to the previous value
G1 Y10 F1200 ; Move Y-axis slightly
{% endif %}
# Home X
{% if home_all or 'X' in rawparams.upper() %}
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={home_current_x} ; Lower motor current
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={home_current_x} ; Lower motor current
G28.1 X ; Home X
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.settings['tmc2240 stepper_x'].run_current} ; Set motor current to the previous value
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.settings['tmc2240 stepper_y'].run_current} ; Set motor current to the previous value
G1 X10 F1200 ; Move X-axis slightly
{% endif %}
# Raise the bed again if only X or only Y axes were homed
{% if not (home_all or 'Z' in rawparams.upper()) %}
{% if Z_axis_was_homed %}
G91 ; Use relative positioning
G1 Z-2 F600 ; Raise the bed back again
G90 ; Use absolute positioning
{% else %}
G1 Z0.1 ; Raise the bed back again
SET_STEPPER_ENABLE STEPPER=stepper_z enable=0 ; Disable Z to prevent collisions
SET_STEPPER_ENABLE STEPPER=stepper_z1 enable=0 ; Disable Z to prevent collisions
SET_KINEMATIC_POSITION SET_HOMED= CLEAR_HOMED=Z ; Set Z to be unhomed
{% endif %}
{% endif %}
# Home Z
{% if home_all or 'Z' in rawparams.upper() %}
G1 X{printer.toolhead.axis_maximum.x / 2} Y{printer.toolhead.axis_maximum.x / 2} F12000
G28.1 Z ; Home Z
G90 ; Set absolute positioning
G1 Z{home_all_final_position_z} F600 ; Move bed down
{% endif %}
# Move to the final position if all axes were homed
{% if home_all %}
G90 ; Set absolute positioning
G1 X{home_all_final_position_x} Y{home_all_final_position_y} Z{home_all_final_position_z} F7800 ; Move to the rear center
{% endif %}
# Unconditional stop
[gcode_macro M0]
gcode:
PAUSE
# Pause SD print
[gcode_macro M25]
rename_existing: M9925
gcode:
PAUSE
########################################
# Basic Macros
########################################
# Flag macro to use STATIC_MESH usage instead of KAMP (needed make this function work from printjob selection on the LCD)
[gcode_macro NEXT_PRINT_STATIC_MESH]
description: Forces the NEXT print to use 'STATIC_MESH' instead of KAMP.
gcode:
{% if "STATIC_MESH" in printer.bed_mesh.profiles %}
SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=force_static_mesh VALUE=True
{action_respond_info("The NEXT print will use 'STATIC_MESH'.")}
M118 The NEXT print will use the STATIC_MESH.
{% else %}
{action_respond_info("WARNING: No mesh named 'STATIC_MESH' found. Please save one first (BED_MESH_PROFILE SAVE=STATIC_MESH).")}
M118 WARNING: No mesh named STATIC_MESH found. Please save one first (BED_MESH_PROFILE SAVE=STATIC_MESH).
{% endif %}
[gcode_macro PRINT_START]
# Use PRINT_START for the slicer starting script
description: Start printing
variable_force_static_mesh: False ; Set to True to force a static mesh instead of KAMP
gcode:
{% set bed_target_temp = params.BED|int %}
{% set hotend_target_temp = params.HOTEND|int %}
{% set chamber_target_temp = params.CHAMBER|default(0)|int %}
{% set bed_center_x = printer.configfile.config["stepper_x"]["position_max"]|float / 2 %}
{% set bed_center_y = printer.configfile.config["stepper_y"]["position_max"]|float / 2 %}
{% set start_position_x = printer.toolhead.axis_maximum.x / 2 %}
{% set start_position_y = printer.toolhead.axis_maximum.y - 40 %}
{% set start_position_z = 10 %}
CLEAR_PAUSE ; Clear existing pause states
BED_MESH_CLEAR ; Clear previous adaptive mesh
{% set KAMP_deactivated = printer["gcode_macro PRINT_START"].force_static_mesh %} ; Check if KAMP is deactivated for this print
SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=force_static_mesh VALUE=False ; Auto-reset the variable immediately for the next print after this one
SET_TEMPERATURE_FAN_TARGET TEMPERATURE_FAN=Mainboard_fan TARGET=1 ; Decrease the mainboard target temp to fully turn the fan on
M140 S{bed_target_temp}
M141 S{chamber_target_temp}
G28
{% if chamber_target_temp > 0 %} ; Accelerate chamber heating by using the bed as additional heater
G0 X{bed_center_x} Y{bed_center_y} Z3 F780 ; Move print bed to perfect postion to help chamber heating
M106 P2 S185 ; Turn sidefan on to use bed heat and mix air
M106 P0 S128 ; Turn part cooling fan on to help air mixing
TEMPERATURE_WAIT SENSOR="heater_generic chamber" MINIMUM={chamber_target_temp - 5} ; Wait for chamber to heat up
M106 P2 S0 ; Turn off sidefan
M106 P0 S0 ; Turn off part cooling fan
{% endif %}
{% if bed_target_temp !=0 %}
TEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={bed_target_temp * 0.95} MAXIMUM={bed_target_temp * 1.05}
{% endif %}
M191 S{chamber_target_temp} ; Set and wait for chamber temperature
M190 S{bed_target_temp} ; Set and wait for bed temperature
G90 ; Set absolute positioning
G1 X{start_position_x} Y{start_position_y} Z{start_position_z} F7800 ; Move to start position
G28 Z ; Home Z again for to compensate bed expansion
{% if KAMP_deactivated %}
{% if "STATIC_MESH" in printer.bed_mesh.profiles %} ; Check if the spicific STATIC_MESH exists
M118 Loading 'STATIC_MESH' instead of KAMP.
BED_MESH_PROFILE LOAD=STATIC_MESH
{% else %} ; Fallback to KAMP if STATIC_MESH not found
M118 ERROR: 'STATIC_MESH' not found! Using fallback: KAMP Adaptive Mesh.
BED_MESH_CLEAR ; Clear previous adaptive mesh
BED_MESH_CALIBRATE PROFILE=adaptive ADAPTIVE=1 ; Start adaptive meshing
{% endif %}
{% else %} ; Standard operation
{% if printer.toolhead.homed_axes|length < 3 %}
G28
{% endif %}
BED_MESH_CLEAR ; Clear previous adaptive mesh
BED_MESH_CALIBRATE PROFILE=adaptive ADAPTIVE=1 ; Start adaptive meshing
{% endif %}
PRIME_NOZZLE hotend_target_temp={hotend_target_temp}
M109 S{hotend_target_temp} ; Set and wait for hotend temperature
[gcode_macro PRINT_END]
gcode:
{% set max_x = printer.configfile.config["stepper_x"]["position_max"]|float %}
{% set max_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
{% set max_z = printer.configfile.config["stepper_z"]["position_max"]|float %}
{% set current_extruder_temp = printer.extruder.temperature|float %}
{% set min_extrusion_temp = printer.configfile.config["extruder"]["min_extrude_temp"]|float %}
{% set z_clearance = 50 %}
{% if (printer.toolhead.position.z + z_clearance) < max_z %}
{% set z_hop = 2 %}
{% else %}
{% set z_hop = 0 %}
{% endif %}
M106 P0 S0 ; Turn off part cooling fan
M106 P2 S0 ; Turn off side fan
M106 P3 S0 ; Turn off activated charcoal fan
M104 S0 ; Turn off hotend
M140 S0 ; Turn off heated bed
M141 S0 ; Turn off heated chamber
G91 ; Relative positioning
{% if current_extruder_temp >= min_extrusion_temp + 5 %} ; Check if the hotend is hot enough to perform a retraction (with a small gap)
G0 E-4.0 F300 ; Retract filament
{% endif %}
G0 Z{z_hop} F3600 ; Move bed down a bit
G90 ; Absolute positioning
G0 X{max_x/2} Y{max_y-40} F20000 ; Move nozzle to remove stringing
_Z_CLEARANCE DISTANCE={z_clearance} ; Lower bed
M400 ; Wait for buffer to clear
G92 E0 ; Zero the extruder
M220 S100 ; Set feedrate (speed percentage) back to 100%
M221 S100 ; Set flow percentage back to 100%
SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; Set timeout back to configured value
CLEAR_PAUSE ; Ensure pause state is cleared if applicable
M84 ; Disable steppers
SET_TEMPERATURE_FAN_TARGET TEMPERATURE_FAN=Mainboard_fan TARGET=45 ; Disable steppers
BEEP I=2 DUR=500 ; Alert at the end of the print (if sound is enabled)
[gcode_macro PAUSE]
rename_existing: BASE_PAUSE
gcode:
{% set z_hop = params.Z|default(30)|int %} ; Z hop amount
{% if printer['pause_resume'].is_paused|int == 0 %}
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=zhop VALUE={z_hop} ; Set Z hop variable for reference in resume macro
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=etemp VALUE={printer['extruder'].target} ; Set hotend temperature variable for reference in resume macro
SAVE_GCODE_STATE NAME=PAUSE ; Save current position for resume
BASE_PAUSE ; Pause print
{% if (printer.gcode_move.position.z + z_hop) < printer.toolhead.axis_maximum.z %} ; Check that Z hop doesn't exceed Z max
G91 ; Use Relative positioning
G1 Z{z_hop} F600 ; Raise Z up by Z hop amount
{% else %}
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=zhop VALUE=0 ; Set Z hop to 0 if exceeds max
{% endif %}
SAVE_GCODE_STATE NAME=PAUSEPARK2
G90 ; Absolute positioning
GO_TO_POOP_BUCKET ; Move toolhead to poop bucket
SAVE_GCODE_STATE NAME=PAUSEPARK ; Save parked position in case toolhead is moved during the pause (otherwise the return zhop can error)
M104 S0 ; Turn off hotend
SET_IDLE_TIMEOUT TIMEOUT=43200 ; Set timeout to 12 hours
SET_STEPPER_ENABLE STEPPER=extruder enable=0 ; Disable extruder stepper
{% endif %}
[gcode_macro RESUME]
rename_existing: BASE_RESUME
variable_zhop: 0
variable_etemp: 0
gcode:
{% if printer['pause_resume'].is_paused|int == 1 %}
{% if "z" not in printer.toolhead.homed_axes %} ; check if z position is lost
{action_raise_error("ERROR: Z-axixs lost its position (Idle-Timeout)! Resume not possible - Print should be aborted.")}
{% endif %}
SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; Set idle timeout back to configured value
# If X/Y position lost: Give Z-clearance for homing X/Y that will be done by PRIME_NOZZLE
{% if "x" not in printer.toolhead.homed_axes or "y" not in printer.toolhead.homed_axes %} ; If X/Y position is lost, but z is still OK
G91 ; Relative positioning
G1 Z5 F600 ; 5mm clearance for safe X/Y-Homing
G90 ; Absolute positioning
{% endif %}
PRIME_NOZZLE HOTEND_TARGET_TEMP={etemp} ; Prime nozzle with last used hotend temperature
M109 S{etemp} ; Wait for hotend to heat up
RESTORE_GCODE_STATE NAME=PAUSEPARK2 MOVE=1 MOVE_SPEED=150 ; Return to position after Z-hop (safely above the part)
RESTORE_GCODE_STATE NAME=PAUSE MOVE=1 MOVE_SPEED=10 ; Restore position
BASE_RESUME ; Resume print ; Resume print
{% endif %}
[gcode_macro CANCEL_PRINT]
rename_existing: BASE_CANCEL_PRINT
gcode:
{% set max_z = printer.configfile.config["stepper_z"]["position_max"]|float %}
{% if (printer.toolhead.position.z + 12) < max_z %}
{% set z_hop = 2 %}
{% else %}
{% set z_hop = 0 %}
{% endif %}
G91 ; Relative positioning
G1 Z{z_hop} F600 ; Do a tiny z-hop
G90 ; Absolute positioning
G1 X{printer.toolhead.axis_maximum.x/2} Y{printer.toolhead.axis_maximum.y-40} F12000
CLEAR_PAUSE
SDCARD_RESET_FILE
PRINT_END
BASE_CANCEL_PRINT
[gcode_macro _Z_CLEARANCE]
description: Lower the bed to give some clearance
variable_default_distance: 40.0
gcode:
{% set current_z_height = printer.toolhead.position.z %}
{% set max_z_height = printer.toolhead.axis_maximum.z %}
{% set distance = params.DISTANCE|default(variable_default_distance)|float %}
{% set target_z_height = current_z_height + distance %}
{% set min_z_param = params.MIN_Z|default(None) %}
{% if min_z_param is not none %}
{% set min_z = min_z_param|float %}
{% if target_z_height < min_z %}
{% set target_z_height = min_z %}
{% endif %}
{% endif %}
G90 ; Absolute positioning
G1 Z{ [target_z_height, max_z_height]|min }
########################################
# Filament Macros
########################################
[gcode_macro UNLOAD_FILAMENT]
description: Unloads filament from toolhead
gcode:
{% set EXTRUDER_TEMP = params.TEMP|default(230)|int %}
{% set CURRENT_TEMP = printer.extruder.temperature|int %}
GO_TO_POOP_BUCKET ; go to poop bucket
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M104 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M109 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=1 ; enable extruder stepper
M83 ; set extruder to relative mode
G1 E5 F150 ; extrude a small amount to elimate soften the filament
G1 E-8 F1800 ; quickly retract a small amount to elimate stringing
G4 P200 ; pause for a short amount of time
G1 E-50 F300 ; retract slowly the rest of the way
M104 S0 ; turn off hotend and wait for cooldown before leaving
LEAVE_POOP_BUCKET ; leave poop bucket
M400 ; wait for moves to finish
M118 Unload Complete!
[gcode_macro LOAD_FILAMENT]
description: Loads filament to toolhead
gcode:
{% set EXTRUDER_TEMP = params.TEMP|default(230)|int %}
{% set CURRENT_TEMP = printer.extruder.temperature|int %}
GO_TO_POOP_BUCKET ; go to poop bucket
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M104 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M109 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=1 ; enable extruder stepper
M107 ; turn off fan
M83 ; set extruder to relative mode
G1 E5 F120 ; feed filament
G1 E5 F300 ; feed filament
G1 E40 F600 ; feed filament
G1 E15 F500 ; feed filament
G1 E15 F120 ; feed filament
G4 P200 ; pause for a short amount of time
G1 E10 F90 ; feed filament
G4 P3000 ; wait a bit to finish oozing
{% if printer.pause_resume.is_paused %}
LEAVE_POOP_BUCKET ; leave poop bucket
M118 Filament Loaded - Resuming Print... ; print message
RESUME ; resume print
{% else %}
M104 S0 ; turn off hotend
M106 S255 ; turn on fan
TEMPERATURE_WAIT SENSOR=extruder MAXIMUM=80 ; wait for hotend to cool
LEAVE_POOP_BUCKET ; leave poop bucket
M400 ; wait for moves to finish
M107 ; turn off fan
M118 Load Complete! ; print message
{% endif %}
# Filament runout sensor enable/disable
[gcode_macro M8029]
gcode:
{% if params.D is defined %}
{% if (params.D|int)==1 %}
SET_FILAMENT_SENSOR SENSOR=filament_tangle_sensor ENABLE=1
{% endif %}
{% if (params.D|int)==0 %}
SET_FILAMENT_SENSOR SENSOR=filament_tangle_sensor ENABLE=0
{% endif %}
{% endif %}
########################################
# Fan Macros
########################################
# Set Fan Speed macro
# Mainly name castings for nicer web interface names and display functionality
[gcode_macro M106]
rename_existing: M106.1
gcode:
{% if params.P is defined %}
{% if params.S is defined %}
{% set speed = 0.003921*params.S|int %}
{% if (params.P|int) == 0 %}
M106.1 S{params.S|int}
{% elif (params.P|int) == 2 %}
SET_FAN_SPEED FAN=sidefan SPEED={speed}
{% elif (params.P|int) == 3 %}
SET_FAN_SPEED FAN=filterfan SPEED={speed}
{% else %}
SET_FAN_SPEED FAN=fan{params.P|int} SPEED={speed}
{% endif %}
{% else %}
{% if (params.P|int) == 0 %}
M106.1 S255
{% elif (params.P|int) == 2 %}
SET_FAN_SPEED FAN=sidefan SPEED=1
{% elif (params.P|int) == 3 %}
SET_FAN_SPEED FAN=filterfan SPEED=1
{% else %}
SET_FAN_SPEED FAN=fan{params.P|int} SPEED=1
{% endif %}
{% endif %}
{% endif %}
{% if params.T is defined %}
{% if (params.T|int) == -2 %}
{% if params.S is defined %}
{% set speed = 0.003921*params.S|int %}
SET_FAN_SPEED FAN=filterfan SPEED={speed}
{% else %}
SET_FAN_SPEED FAN=filterfan SPEED=1
{% endif %}
{% endif %}
{% endif %}
{% if params.P is undefined %}
{% if params.T is undefined %}
{% if params.S is defined %}
M106.1 S{params.S|int}
{% else %}
M106.1 S255
{% endif %}
{% endif %}
{% endif %}
[gcode_macro M107]
rename_existing: M107.1
gcode:
M106.1 S0
########################################
# Temperature Macros
########################################
# Wait for Hotend Temperature
[gcode_macro M109]
rename_existing: M109.1
gcode:
#Parameters
{% set s = params.S|float %}
M104 {% for p in params %}{'%s%s' % (p, params[p])}{% endfor %} ; Set hotend temp
{% if s != 0 %}
TEMPERATURE_WAIT SENSOR=extruder MINIMUM={s} MAXIMUM={s+1} ; Wait for hotend temp (within 1 degree)
{% endif %}
# PID autotune
[gcode_macro M303]
gcode:
{% if params.E is defined %}
{% if params.S is defined %}
{% if (params.E|int)==-1 %}
PID_CALIBRATE HEATER=heater_bed TARGET={params.S|int}
{% endif %}
{% if (params.E|int)==0 %}
PID_CALIBRATE HEATER=extruder TARGET={params.S|int}
{% endif %}
{% endif %}
{% endif %}
# Set chamber temperature
[gcode_macro M141]
gcode:
{% if printer["heater_generic chamber"] is defined %}
{% set chamber_target_temp = params.S|float %}
SET_HEATER_TEMPERATURE HEATER=chamber TARGET={([chamber_target_temp, 65]|min)}
{% endif %}
# Set wait chamber temperature
[gcode_macro M191]
gcode:
{% set chamber_target_temp = params.S|float %}
{% if chamber_target_temp == 0 %}
M118 Chamber heater off
{% else %}
M141 S{chamber_target_temp}
TEMPERATURE_WAIT SENSOR="heater_generic chamber" MINIMUM={([chamber_target_temp, 65]|min)-2} MAXIMUM={chamber_target_temp + 5}
M118 Chamber at target temperature
{% endif %}
########################################
# Sound Macros
########################################
[gcode_macro BEEP]
gcode:
# Parameters
{% set i = params.I|default(1)|int %} ; Iterations (number of times to beep).
{% set dur = params.DUR|default(100)|int %} ; Duration/wait of each beep in ms. Default 100ms.
{% if printer["output_pin sound"].value|int == 1 %}
{% for iteration in range(i|int) %}
SET_PIN PIN=buzzer VALUE=1
G4 P{dur}
SET_PIN PIN=buzzer VALUE=0
G4 P{dur}
{% endfor %}
{% endif %}
[gcode_macro beep_on]
gcode:
SET_PIN PIN=buzzer VALUE=1
[gcode_macro beep_off]
gcode:
SET_PIN PIN=buzzer VALUE=0
########################################
# Z-height Macros
########################################
# Bed Leveling (Unified)
[gcode_macro G29]
variable_k:1
gcode:
{% set temp = printer["heater_generic chamber"].target %}
M141 S0
{% if temp > 0 %}
G4 P15000
{% endif %}
{% if k|int==1 %}
BED_MESH_CLEAR ; Clear levelling data
BED_MESH_CALIBRATE ADAPTIVE=1 ADAPTIVE_MARGIN=5 ; Start adaptive meshing
{% endif %}
M141 S{temp}
# Babystep
[gcode_macro M290]
gcode:
SET_GCODE_OFFSET Z_ADJUST={params.Z}
########################################
# Tuning Macros
########################################
[gcode_macro SHAPER_CALIBRATE]
rename_existing: RESHAPER_CALIBRATE
gcode:
RESHAPER_CALIBRATE FREQ_START=30 FREQ_END=130
# Linear Advance Factor
[gcode_macro M900]
gcode:
{% if params.K is defined %}
SET_PRESSURE_ADVANCE ADVANCE={params.K}
{% endif %}
{% if params.T is defined %}
SET_PRESSURE_ADVANCE SMOOTH_TIME={params.T}
{% endif %}
# Set Starting Acceleration
[gcode_macro M204]
rename_existing: M99204
gcode:
{% if params.S is defined %}
{% set s = params.S|float %}
{% endif %}
{% if params.P is defined %}
{% if params.T is defined %}
{% set s = [params.P|float ,params.T|float] | min %}
{% endif %}
{% endif %}
SET_VELOCITY_LIMIT ACCEL={s}
SET_VELOCITY_LIMIT ACCEL_TO_DECEL={s/2}
# Bed leveling
# For more information, see https://www.klipper3d.org/Manual_Level.html#adjusting-bed-leveling-screws-using-the-bed-probe
[gcode_macro LEVEL_BED]
description: "Measure bed and calculate screw adjustments for manual bed leveling"
gcode:
G28 ; Home all
SCREWS_TILT_CALCULATE ; Perform measurements and output screw adjustments
# Automatic rough Bed Leveling by ramming the bed to the bottom
[gcode_macro AUTO_LEVEL_BED]
gcode:
{% set Z_max = printer.toolhead.axis_maximum.z %}
G28
G1 Z{Z_max-30} F600
SET_TMC_CURRENT STEPPER=stepper_z CURRENT={printer.configfile.settings['tmc2209 stepper_z'].run_current * 0.5 }
SET_TMC_CURRENT STEPPER=stepper_z1 CURRENT={printer.configfile.settings['tmc2209 stepper_z1'].run_current * 0.5 }
G1 Z{Z_max} F600
SET_KINEMATIC_POSITION Z=0
G1 Z10 F600
G1 Z0 F600
G1 Z15 F600
SET_TMC_CURRENT STEPPER=stepper_z CURRENT={printer.configfile.settings['tmc2209 stepper_z'].run_current}
SET_TMC_CURRENT STEPPER=stepper_z1 CURRENT={printer.configfile.settings['tmc2209 stepper_z1'].run_current}
G28
# Probe Calibration
# For more information, see https://www.klipper3d.org/Probe_Calibrate.html
[gcode_macro CALIBRATE_Z_OFFSET]
description: "Calibrate the Z offset using the probe"
gcode:
{% set max_x = printer.configfile.config["stepper_x"]["position_max"]|float %}
{% set max_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
G28 ; Home all
G0 Z10 ; Increase z clearance
G0 X{max_x/2} Y{max_y-40} F6000 ; Move to bed center
PROBE_CALIBRATE ; Perform a probe calibration
# Nozzle PID tuning
# For more information, see https://www.klipper3d.org/Config_checks.html#calibrate-pid-settings
[gcode_macro NOZZLE_PID_TUNE]
description: "Perform PID tuning for the nozzle heater"
gcode:
PID_CALIBRATE HEATER=extruder TARGET=220 ; PID tune the nozzle
# Bed PID tuning
# For more information, see https://www.klipper3d.org/Config_checks.html#calibrate-pid-settings
[gcode_macro BED_PID_TUNE]
description: "Perform PID tuning for the bed heater"
gcode:
PID_CALIBRATE HEATER=heater_bed TARGET=80 ; PID tune the bed
########################################
# Macros for display functionallity
########################################
[gcode_macro INPUT_SHAPING_CALIBRATE]
description: "Perform Input Shaping calibration and save the results to printer.cfg"
gcode:
SHAPER_CALIBRATE ; Step 1: Perform the Input Shaping calibration
PAUSE ; Step 2: Pause to allow the calibration to complete
SAVE_CONFIG ; Step 3: Save the configuration to printer.cfg
RESTART ; Step 4: Restart the firmware to apply the new settings
================================================
FILE: config_section/Q1_Pro/printer.cfg
================================================
# Q1 Pro config created by Phil1988(github)/coco.33(discord) on 11.05.2025
# For more information check out my wiki: https://github.com/Phil1988/FreeDi/wiki
#####################################################################
# Kinematics
#####################################################################
[printer]
kinematics:corexy
max_velocity: 600
max_accel: 20000
max_z_velocity: 10
max_z_accel: 500
square_corner_velocity: 8
#####################################################################
# Motherboard and periphery
#####################################################################
[temperature_sensor Mainboard_RK3328]
sensor_type: temperature_host
min_temp: 10
max_temp: 100
[mcu]
serial: /dev/ttyS0
restart_method: command
baud: 500000
[temperature_sensor Mainboard_STM32F402]
sensor_type: temperature_mcu
sensor_mcu: mcu
[mcu Toolhead]
serial: /dev/ttyS2
restart_method: command
baud: 500000
[temperature_sensor Toolhead_RP2040]
sensor_type: temperature_mcu
sensor_mcu: Toolhead
min_temp: 0
max_temp: 100
#####################################################################
# Features
#####################################################################
# For saving GCODE files
[virtual_sdcard]
path: ~/printer_data/gcodes
on_error_gcode: CANCEL_PRINT
# For enabling pause/resume
[pause_resume]
# Activating exclude objects feature
[display_status]
[exclude_object]
# Expanding idle timeout
[idle_timeout]
timeout: 5400 ; 90min timeout
# Activating GCODE arc feature
[gcode_arcs]
resolution: 1.0
# Allowing free move (can be dangerous!)
[force_move]
enable_force_move: True
# Activating responses
[respond]
default_type: echo
#####################################################################
# FreeDi
#####################################################################
[include freedi.cfg]
#####################################################################
# Macros
#####################################################################
[include macros.cfg]
#####################################################################
# Input shaping
#####################################################################
[resonance_tester]
accel_chip: adxl345
probe_points:
120, 120, 10
accel_per_hz: 75
sweeping_period: 0
max_smoothing: 0.5
[adxl345]
cs_pin: Toolhead:gpio13
spi_software_sclk_pin: Toolhead:gpio14
spi_software_mosi_pin: Toolhead:gpio15
spi_software_miso_pin: Toolhead:gpio12
axes_map: -x, z, -y
[input_shaper]
shaper_type_x: mzv
shaper_freq_x: 53.6
shaper_type_y: mzv
shaper_freq_y: 50.8
#####################################################################
# Hotend
#####################################################################
[extruder]
step_pin: Toolhead:gpio5
dir_pin: Toolhead:gpio4
enable_pin: !Toolhead:gpio10
rotation_distance: 53.7
gear_ratio: 1517:170
microsteps: 16
full_steps_per_rotation: 200
nozzle_diameter: 0.400
filament_diameter: 1.75
min_temp: 0
max_temp: 360
min_extrude_temp: 170
smooth_time: 0.000001
step_pulse_duration:0.000002
heater_pin: Toolhead:gpio24
sensor_type:MAX6675
sensor_pin: Toolhead:gpio17
max_power: 1.0
control: pid
pid_Kp: 24.737
pid_Ki: 10.994
pid_Kd: 13.915
spi_speed: 100000
spi_software_sclk_pin: Toolhead:gpio18
spi_software_mosi_pin: Toolhead:gpio19
spi_software_miso_pin: Toolhead:gpio16
pressure_advance: 0.032
pressure_advance_smooth_time: 0.03
max_extrude_cross_section:500
instantaneous_corner_velocity: 10.000
max_extrude_only_distance: 500.0
max_extrude_only_velocity: 5000
max_extrude_only_accel: 2000
[verify_heater extruder]
max_error: 120
check_gain_time: 20
hysteresis: 5
heating_gain: 1
#####################################################################
# Heated bed
#####################################################################
[heater_bed]
heater_pin: PB10
sensor_type: NTC 100K MGB18-104F39050L32
sensor_pin: PA0
max_power: 1.0
control: pid
pid_kp: 64.431
pid_ki: 2.845
pid_kd: 364.839
min_temp: -50
max_temp: 125
pwm_cycle_time: 0.02 # for 50Hz line power
#pwm_cycle_time: 0.016 # for 60Hz line power
[verify_heater heater_bed]
max_error: 200
check_gain_time: 360
hysteresis: 5
heating_gain: 1
#####################################################################
# Bed mesh
#####################################################################
[bed_mesh]
speed: 150
horizontal_move_z: 3.5
mesh_min: 20,15
mesh_max: 230,230
probe_count: 8,8
algorithm:bicubic
bicubic_tension:0.2
mesh_pps: 4, 4
#####################################################################
# Probe
#####################################################################
#!# Pay attention to this section and compare it with your stock backup config
[probe]
pin: !Toolhead:gpio21
x_offset: 17.6
y_offset: 4.4
z_offset: 1.0 #!# change this to 0 if you get a "Probe triggered prior to movement" - Error
speed: 5
samples: 2
samples_result: average
sample_retract_dist: 0.7
samples_tolerance: 0.08
samples_tolerance_retries: 3
# Check this for documentation https://github.com/frap129/qidi_auto_z_offset
# Add AUTO_Z_LOAD_OFFSET to your PRINT_START macro to load the value every time you start a print.
# If you make adujstments to the offset by micro-stepping durring a print, you can save that with AUTO_Z_SAVE_GCODE_OFFSET and SAVE_CONFIG
[auto_z_offset]
pin: PC1
# Adjust this z_offset value for a good first layer:
# decrease if lines are squished (eg -0.2 -> -0.25)
# increase if lines are thin/not sticking (-0.2 -> -0.15)
z_offset: -0.07
calibrated_z_offset: -1.00
speed: 13
probe_accel: 50
samples: 5
samples_result: median
samples_tolerance: 0.013
samples_tolerance_retries: 5
offset_samples: 3
prepare_gcode:
G90
G0 Z3
G91
SET_PIN PIN=bed_sensor VALUE=0
M204 S10000
{% set i = 6 %}
{% for iteration in range(i|int) %}
G1 Z5 F1200
G1 Z-5 F1200
{% endfor %}
G1 Z3
G90
SET_PIN PIN=bed_sensor VALUE=1
[output_pin bed_sensor]
pin: !PA14
pwm: false
shutdown_value:0
value:0
#####################################################################
# Heated chamber
#####################################################################
[heater_generic chamber]
heater_pin: PC8
max_power:1.0
sensor_type: NTC 100K MGB18-104F39050L32
sensor_pin: PA1
control: pid
pid_Kp: 63.418
pid_Ki: 1.342
pid_Kd: 749.125
min_temp: -100
max_temp: 62
[verify_heater chamber]
max_error: 400
check_gain_time: 600
hysteresis: 5
heating_gain: 1
########################################
# Filament sensors
########################################
[filament_switch_sensor filament_tangle_sensor]
switch_pin: PC3
pause_on_runout: True
runout_gcode:
M118 Filament tangled!
event_delay: 3.0
pause_delay: 0.5
[hall_filament_width_sensor]
adc1: Toolhead:gpio27
adc2: Toolhead:gpio28
cal_dia1: 1.50
cal_dia2: 2.0
raw_dia1: 14206
raw_dia2: 15278
default_nominal_filament_diameter: 1.75
max_difference: 0.00
measurement_delay: 50
enable: True
enable_flow_compensation: False
measurement_interval: 3
logging: False
min_diameter: 1.00
use_current_dia_while_delay: False
pause_on_runout: True
runout_gcode:
M118 Filament run out
event_delay: 3.0
pause_delay: 0.5
#####################################################################
# Fans
#####################################################################
## Part cooling fan
# [fan_generic partfan]
# pin: Toolhead:gpio2
# max_power: 1.0
# cycle_time: 0.0100
# hardware_pwm: false
# kick_start_time: 0.200
# off_below: 0.08
# shutdown_speed: 0
[fan]
pin: Toolhead:gpio2
max_power: 1.0
cycle_time: 0.0100
hardware_pwm: false
kick_start_time: 0.200
off_below: 0.08
shutdown_speed: 0.0
## Big side radial turbo fan
[fan_generic sidefan]
pin: PA8
max_power: 1.0
cycle_time: 0.0100
hardware_pwm: false
kick_start_time: 0.250
off_below: 0.3
shutdown_speed: 0
## Activated charcoal blowing fan
[fan_generic filterfan]
pin: PC9
max_power: 1.0
cycle_time: 0.0100
hardware_pwm: false
kick_start_time: 0.200
off_below: 0.3
shutdown_speed: 0
## Chamber heater fan
[heater_fan chamber_heater_fan]
pin: PA4
max_power: 1.0
shutdown_speed: 0
kick_start_time: 0.5
heater: chamber
fan_speed: 1.0
off_below: 0
heater_temp: 35
## Cold end and toolhead housing fans
[heater_fan hotend_fan]
pin: Toolhead:gpio25
max_power: 1.0
shutdown_speed: 1.0
kick_start_time: 0.5
heater: extruder
heater_temp: 50.0
fan_speed: 1.0
off_below: 0
#!# Delete the next section if your stock backup config doesnt have it
# Toolhead cooling fan
[heater_fan hotend_fan2]
pin: Toolhead:gpio11
max_power: 1.0
shutdown_speed: 1.0
kick_start_time: 0.5
heater: extruder
heater_temp: 50.0
fan_speed: 1.0
off_below: 0
#!# Delete the next section if your stock backup config doesnt have it
## Controllable Mainboard cooling fan
[temperature_fan Mainboard_fan]
sensor_type: temperature_host
pin: PC4
max_power: 1.0
cycle_time: 0.01
sensor_type: temperature_combined
sensor_list: temperature_sensor Mainboard_RK3328, temperature_sensor Mainboard_STM32F402
combination_method: max # use the maximum reading of the sensors
maximum_deviation: 999.9 # we don't care about the difference in temperature
shutdown_speed: 0.0
kick_start_time: 0.4
off_below: 0.19
min_temp: 0
max_temp: 85.0
target_temp: 42.0
min_speed: 0
max_speed: 1.0
control: pid
pid_deriv_time: 2.0
pid_Kp: 2.0
pid_Ki: 5.0
pid_Kd: 0.5
#####################################################################
# Light
#####################################################################
## caselight LEDs
[output_pin caselight]
pin: PC7
pwm: true
cycle_time: 0.0100
shutdown_value:0
value:1
#####################################################################
# Buzzer
#####################################################################
## Buzzer
[output_pin buzzer]
pin: PA2
pwm: false
shutdown_value:0
value:0
[output_pin sound]
pin: PA13
value:0
#####################################################################
# Power outage shutdown
#####################################################################
[output_pin pwc]
pin: PA3
pwm: False
value: 1
shutdown_value: 1
#####################################################################
# Drives
#####################################################################
[stepper_x]
step_pin: PB4
dir_pin: !PB3
enable_pin: !PB5
microsteps: 32
rotation_distance: 39.88
full_steps_per_rotation: 200
endstop_pin: tmc2240_stepper_x:virtual_endstop
position_min: -5.5
position_endstop: -5.5
position_max: 245
homing_speed: 50
homing_retract_dist:0
homing_positive_dir: False
step_pulse_duration:0.0000001
[stepper_y]
step_pin: PC14
dir_pin: !PC13
enable_pin: !PC15
microsteps: 32
rotation_distance: 39.88
full_steps_per_rotation:200
endstop_pin: tmc2240_stepper_y:virtual_endstop
position_min: -4.5
position_endstop: -4.5
position_max: 258
homing_speed: 50
homing_retract_dist:0
homing_positive_dir: False
step_pulse_duration:0.0000001
[stepper_z]
step_pin: PC10
dir_pin: PA15
enable_pin: !PC11
microsteps: 16
rotation_distance: 4
full_steps_per_rotation: 200
endstop_pin: probe:z_virtual_endstop
position_max: 248
position_min: -4
homing_speed: 8
homing_retract_dist: 8.0
second_homing_speed: 5
homing_positive_dir: False
step_pulse_duration: 0.0000001
[stepper_z1]
step_pin: PB1
dir_pin: PB6
enable_pin: !PB0
microsteps: 16
rotation_distance: 4
full_steps_per_rotation: 200
step_pulse_duration: 0.0000001
#####################################################################
# Steppers configuration
#####################################################################
[tmc2209 extruder]
uart_pin: Toolhead:gpio6
interpolate: False
run_current: 0.714 #!# Pay attention to this value and compare it with your stock backup config
stealthchop_threshold: 0
sense_resistor: 0.075
[tmc2240 stepper_x]
cs_pin: PD2
spi_software_sclk_pin: PA5
spi_software_mosi_pin: PA7
spi_software_miso_pin: PA6
spi_speed: 200000
run_current: 1.07 #!# Pay attention to this value and compare it with your stock backup config
interpolate: True
stealthchop_threshold: 0
diag0_pin: !PB8
driver_SGT: 1
rref: 12000
[tmc2240 stepper_y]
cs_pin: PB9
spi_software_sclk_pin: PA5
spi_software_mosi_pin: PA7
spi_software_miso_pin: PA6
spi_speed: 200000
run_current: 1.07 #!# Pay attention to this value and compare it with your stock backup config
interpolate: True
stealthchop_threshold: 0
diag0_pin: !PC0
driver_SGT: 1
rref: 12000
[tmc2209 stepper_z]
uart_pin: PC5
run_current: 0.6 #!# Pay attention to this value and compare it with your stock backup config
interpolate: False
stealthchop_threshold: 9999999999
[tmc2209 stepper_z1]
uart_pin: PB7
run_current: 0.6 #!# Pay attention to this value and compare it with your stock backup config
interpolate: False
stealthchop_threshold: 9999999999
#####################################################################
# Bed tilt adjust
#####################################################################
[z_tilt]
z_positions:
-59,125
307.5,125
points:
0,125
215,125
speed: 150
horizontal_move_z: 5
retries: 2
retry_tolerance: 0.05
#####################################################################
# Screws tilt adjust
#####################################################################
[screws_tilt_adjust]
horizontal_move_z: 5
screw_thread: CW-M4
speed: 300
screw1:10,10
screw1_name: Front left
screw2: 220,10
screw2_name: Front right
screw3: 125,230
screw3_name: Back center
================================================
FILE: config_section/X-Max3/macros.cfg
================================================
#####################################################################
# Advanced CHAMBER_TEMP_CONTROLLER
#####################################################################
[gcode_macro SET_PRINT_STATS_INFO]
rename_existing: BASE_SET_PRINT_STATS_INFO_BASE
gcode:
#TIMELAPSE_TAKE_FRAME
BASE_SET_PRINT_STATS_INFO_BASE {rawparams}
CHAMBER_TEMP_CONTROLLER
# Safety macro that gets frequently called by SET_PRINT_STATS_INFO to prevent too high chamber temperatures
[gcode_macro CHAMBER_TEMP_CONTROLLER]
gcode:
{% set chamber_target_temp = printer['heater_generic chamber'].target %}
{% set chamber_temp = printer['heater_generic chamber'].temperature %}
{% if chamber_temp > printer.configfile.settings['heater_generic chamber'].max_temp %}
M106 P3 S255
{% else %}
{% if chamber_target_temp > 0 %}
# Allow for 3C of "grace" before we start ramping the exhaust fan speed
# This prevents the macro from fighting with the chamber heater PID algorithm
{% set difference = chamber_temp - (chamber_target_temp + 3) %}
{% if difference > 0 %}
{% set filterfan_speed = ([(difference * 50), 255] | min) | int %}
M106 P3 S{filterfan_speed}
{% else %}
M106 P3 S0
{% endif %}
{% endif %}
{% endif %}
#####################################################################
# Homing modification
#####################################################################
[gcode_macro G28]
rename_existing: G28.1
gcode:
{% set reduced_current_x = 0.6 %}
{% set reduced_current_y = 0.7 %}
{% set home_all = ('X' in rawparams.upper() and 'Y' in rawparams.upper() and 'Z' in rawparams.upper()) or
('X' not in rawparams.upper() and 'Y' not in rawparams.upper() and 'Z' not in rawparams.upper()) %}
{% set home_current_x = printer.configfile.settings['tmc2209 stepper_x'].run_current * reduced_current_x %}
{% set home_current_y = printer.configfile.settings['tmc2209 stepper_y'].run_current * reduced_current_y %}
{% set init_XY_move = 30 %}
#{% set y_init_move = 5 %}
{% set z_clearance = 2 %}
{% set home_all_final_position_x = printer.toolhead.axis_maximum.x / 2 %}
{% set home_all_final_position_y = printer.toolhead.axis_maximum.y - 40 %}
{% set home_all_final_position_z = 10 %}
# If homing should at least move X or Y axis
{% if home_all or 'X' in rawparams.upper() or 'Y' in rawparams.upper() %}
# Check if Z is homed
{% if 'z' in printer.toolhead.homed_axes %}
{% set Z_axis_was_homed = true %} ; Set Z_axis_was_homed to true if Z is already homed
G91 ; Use relative positioning
G1 Z2 F600 ; Move bed down
G90 ; Use absolute positioning
{% else %}
{% set Z_axis_was_homed = false %} ; Set Z_axis_was_homed to false if Z is not homed
FORCE_MOVE STEPPER=stepper_z DISTANCE={z_clearance} VELOCITY=10 ; Move bed down
{% endif %}
{% endif %}
{% if home_all or 'X' in rawparams.upper() or 'Y' in rawparams.upper() %}
G91 ; Use relative positioning
FORCE_MOVE STEPPER=stepper_x DISTANCE={init_XY_move} VELOCITY=40 ; Move X a little before homing
SET_KINEMATIC_POSITION X={printer.toolhead.position.x + (init_XY_move/2)} ; Compensate the FORCE_MOVE position
SET_KINEMATIC_POSITION Y={printer.toolhead.position.y + (init_XY_move/2)} ; Compensate the FORCE_MOVE position
G90 ; Use absolute positioning
{% endif %}
# Home Y
{% if home_all or 'Y' in rawparams.upper() %}
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={home_current_y} ; Lower motor current
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={home_current_y} ; Lower motor current
G28.1 Y ; Home Y
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.settings['tmc2209 stepper_x'].run_current} ; Set motor current to the previous value
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.settings['tmc2209 stepper_y'].run_current} ; Set motor current to the previous value
G1 Y10 F1200 ; Move Y-axis slightly
{% endif %}
# Home X
{% if home_all or 'X' in rawparams.upper() %}
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={home_current_x} ; Lower motor current
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={home_current_x} ; Lower motor current
G28.1 X ; Home X
SET_TMC_CURRENT STEPPER=stepper_x CURRENT={printer.configfile.settings['tmc2209 stepper_x'].run_current} ; Set motor current to the previous value
SET_TMC_CURRENT STEPPER=stepper_y CURRENT={printer.configfile.settings['tmc2209 stepper_y'].run_current} ; Set motor current to the previous value
G1 X10 F1200 ; Move X-axis slightly
{% endif %}
# Raise the bed again if only X or only Y axes were homed
{% if not (home_all or 'Z' in rawparams.upper()) %}
{% if Z_axis_was_homed %}
G91 ; Use relative positioning
G1 Z-2 F600 ; Raise the bed back again
G90 ; Use absolute positioning
{% else %}
FORCE_MOVE STEPPER=stepper_z DISTANCE=-{z_clearance} VELOCITY=10 ; Raise the bed back again
{% endif %}
{% endif %}
# Home Z
{% if home_all or 'Z' in rawparams.upper() %}
G28.1 Z ; Home Z
G90 ; Set absolute positioning
G1 Z{home_all_final_position_z} ; Move bed down
{% endif %}
# Move to the final position if all axes were homed
{% if home_all %}
G90 ; Set absolute positioning
G1 X{home_all_final_position_x} Y{home_all_final_position_y} Z{home_all_final_position_z} F7800 ; Move to the rear center
{% endif %}
# Unconditional stop
[gcode_macro M0]
gcode:
PAUSE
# Pause SD print
[gcode_macro M25]
rename_existing: M9925
gcode:
PAUSE
########################################
# Basic Macros
########################################
# Flag macro to use STATIC_MESH usage instead of KAMP (needed make this function work from printjob selection on the LCD)
[gcode_macro NEXT_PRINT_STATIC_MESH]
description: Forces the NEXT print to use 'STATIC_MESH' instead of KAMP.
gcode:
{% if "STATIC_MESH" in printer.bed_mesh.profiles %}
SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=force_static_mesh VALUE=True
{action_respond_info("The NEXT print will use 'STATIC_MESH'.")}
M118 The NEXT print will use the STATIC_MESH.
{% else %}
{action_respond_info("WARNING: No mesh named 'STATIC_MESH' found. Please save one first (BED_MESH_PROFILE SAVE=STATIC_MESH).")}
M118 WARNING: No mesh named STATIC_MESH found. Please save one first (BED_MESH_PROFILE SAVE=STATIC_MESH).
{% endif %}
# PRINT_START Macro for use in Slicer start G-code
[gcode_macro PRINT_START]
# Use PRINT_START for the slicer starting script
description: Start printing
variable_force_static_mesh: False ; Set to True to force a static mesh instead of KAMP
gcode:
{% set bed_target_temp = params.BED|default(0)|int %}
{% set hotend_target_temp = params.HOTEND|default(0)|int %}
{% set chamber_target_temp = params.CHAMBER|default(0)|int %}
{% set in_advanced_mode = (bed_target_temp > 0) or (hotend_target_temp > 0) or (chamber_target_temp > 0) %}
CLEAR_PAUSE ; Clear existing pause states
BED_MESH_CLEAR ; Clear previous adaptive mesh
SET_TEMPERATURE_FAN_TARGET TEMPERATURE_FAN=Mainboard_fan TARGET=1 ; Decrease the mainboard target temp to fully turn the fan on
{% set KAMP_deactivated = printer["gcode_macro PRINT_START"].force_static_mesh %} ; Check if KAMP is deactivated for this print
SET_GCODE_VARIABLE MACRO=PRINT_START VARIABLE=force_static_mesh VALUE=False ; Auto-reset the variable immediately for the next print after this one
{% if in_advanced_mode %}
{% set bed_center_x = printer.configfile.config["stepper_x"]["position_max"]|float / 2 %}
{% set bed_center_y = printer.configfile.config["stepper_y"]["position_max"]|float / 2 %}
{% set start_position_x = printer.toolhead.axis_maximum.x / 2 %}
{% set start_position_y = printer.toolhead.axis_maximum.y - 40 %}
{% set start_position_z = 10 %}
M140 S{bed_target_temp} ; Set bed temperature
M141 S{chamber_target_temp} ; Set chamber temperature
G28 ; Home all axes
{% if chamber_target_temp > 0 %} ; Accelerate chamber heating by using the bed as additional heater
G0 X{bed_center_x} Y{bed_center_y} Z3 F780 ; Move print bed to perfect postion to help chamber heating
M106 P2 S185 ; Turn sidefan on to use bed heat and mix air
M106 P0 S128 ; Turn part cooling fan on to help air mixing
TEMPERATURE_WAIT SENSOR="heater_generic chamber" MINIMUM={chamber_target_temp - 5} ; Wait for chamber to heat up
M106 P2 S0 ; Turn off sidefan
M106 P0 S0 ; Turn off part cooling fan
{% endif %}
M191 S{chamber_target_temp} ; Set and wait for chamber temperature
M190 S{bed_target_temp} ; Set and wait for bed temperature
G90 ; Set absolute positioning
G1 X{start_position_x} Y{start_position_y} Z{start_position_z} F7800 ; Move to start position
G28 Z ; Home Z again for to compensate bed expansion
{% if KAMP_deactivated %}
{% if "STATIC_MESH" in printer.bed_mesh.profiles %} ; Check if the spicific STATIC_MESH exists
M118 Loading 'STATIC_MESH' instead of KAMP.
BED_MESH_PROFILE LOAD=STATIC_MESH
{% else %} ; Fallback to KAMP if STATIC_MESH not found
M118 ERROR: 'STATIC_MESH' not found! Using fallback: KAMP Adaptive Mesh.
BED_MESH_CLEAR ; Clear previous adaptive mesh
BED_MESH_CALIBRATE PROFILE=adaptive ADAPTIVE=1 ; Start adaptive meshing
{% endif %}
{% else %} ; Standard operation
{% if printer.toolhead.homed_axes|length < 3 %}
G28
{% endif %}
BED_MESH_CLEAR ; Clear previous adaptive mesh
BED_MESH_CALIBRATE PROFILE=adaptive ADAPTIVE=1 ; Start adaptive meshing
{% endif %}
M109 S{hotend_target_temp} ; Set and wait for hotend temperature
{% endif %}
[gcode_macro PRINT_END]
gcode:
{% set max_x = printer.configfile.config["stepper_x"]["position_max"]|float %}
{% set max_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
{% set max_z = printer.configfile.config["stepper_z"]["position_max"]|float %}
{% set current_extruder_temp = printer.extruder.temperature|float %}
{% set min_extrusion_temp = printer.configfile.config["extruder"]["min_extrude_temp"]|float %}
{% set z_clearance = 50 %}
{% set z_hop = 2 %}
{% if (printer.toolhead.position.z + z_clearance) < max_z %}
{% set z_hop = 2 %}
{% else %}
{% set z_hop = 0 %}
{% endif %}
M106 P0 S0 ; Turn off part cooling fan
M106 P2 S0 ; Turn off side fan
M106 P3 S0 ; Turn off activated charcoal fan
M104 S0 ; Turn off hotend
M140 S0 ; Turn off heated bed
M141 S0 ; Turn off heated chamber
G91 ; Relative positioning
{% if current_extruder_temp >= min_extrusion_temp + 5 %} ; Check if the hotend is hot enough to perform a retraction (with a small gap)
G0 E-4.0 F300 ; Retract filament
{% endif %}
G0 Z{z_hop} F3600 ; Move bed down a bit
G90 ; Absolute positioning
G0 X{max_x/2} Y{max_y-40} F20000 ; Move nozzle to remove stringing
_Z_CLEARANCE DISTANCE={z_clearance} ; Lower bed
M400 ; Wait for buffer to clear
G92 E0 ; Zero the extruder
M220 S100 ; Set feedrate (speed percentage) back to 100%
M221 S100 ; Set flow percentage back to 100%
SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; Set timeout back to configured value
CLEAR_PAUSE ; Ensure pause state is cleared if applicable
M84 ; Disable steppers
SET_TEMPERATURE_FAN_TARGET TEMPERATURE_FAN=Mainboard_fan TARGET=45 ; Reset the mainboard fan temp
BEEP I=2 DUR=500 ; Alert at the end of the print (if sound is enabled)
[gcode_macro PAUSE]
rename_existing: BASE_PAUSE
gcode:
{% set z_hop = params.Z|default(30)|int %} ; Z hop amount
{% if printer['pause_resume'].is_paused|int == 0 %}
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=zhop VALUE={z_hop} ; Set Z hop variable for reference in resume macro
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=etemp VALUE={printer['extruder'].target} ; Set hotend temperature variable for reference in resume macro
SAVE_GCODE_STATE NAME=PAUSE ; Save current position for resume
BASE_PAUSE ; Pause print
{% if (printer.gcode_move.position.z + z_hop) < printer.toolhead.axis_maximum.z %} ; Check that Z hop doesn't exceed Z max
G91 ; Use Relative positioning
G1 Z{z_hop} F600 ; Raise Z up by Z hop amount
{% else %}
SET_GCODE_VARIABLE MACRO=RESUME VARIABLE=zhop VALUE=0 ; Set Z hop to 0 if exceeds max
{% endif %}
SAVE_GCODE_STATE NAME=PAUSEPARK2
G90 ; Absolute positioning
G1 X{printer.toolhead.axis_maximum.x/2} Y{printer.toolhead.axis_maximum.y-40} F6000 ; Park toolhead at rear center
SAVE_GCODE_STATE NAME=PAUSEPARK ; Save parked position in case toolhead is moved during the pause (otherwise the return zhop can error)
M104 S0 ; Turn off hotend
SET_IDLE_TIMEOUT TIMEOUT=43200 ; Set timeout to 12 hours
SET_STEPPER_ENABLE STEPPER=extruder enable=0 ; Disable extruder stepper
{% endif %}
[gcode_macro RESUME]
rename_existing: BASE_RESUME
variable_zhop: 0
variable_etemp: 0
gcode:
{% set extrusion_length = params.E|default(2.5)|int %} ; Hotend prime amount (in mm)
{% if printer['pause_resume'].is_paused|int == 1 %}
{% if "z" not in printer.toolhead.homed_axes %} ; check if z position is lost
{action_raise_error("ERROR: Z-axixs lost its position (Idle-Timeout)! Resume not possible - Print should be aborted.")}
{% endif %}
SET_IDLE_TIMEOUT TIMEOUT={printer.configfile.settings.idle_timeout.timeout} ; Set idle timeout back to configured value
# If X/Y position lost: Give Z-clearance for homing X/Y that will be done by PRIME_NOZZLE
{% if "x" not in printer.toolhead.homed_axes or "y" not in printer.toolhead.homed_axes %} ; If X/Y position is lost, but z is still OK
G91 ; Relative positioning
G1 Z5 F600 ; 5mm clearance for safe X/Y-Homing
G90 ; Absolute positioning
{% endif %}
{% if etemp > 0 %}
M109 S{etemp|int} ; Wait for hotend to heat up
{% endif %}
RESTORE_GCODE_STATE NAME=PAUSEPARK MOVE=1 MOVE_SPEED=150 ; Restore back to parked position in case toolhead was moved during pause (otherwise the return zhop can error)
G91 ; Relative positioning
M83 ; Relative extruder positioning
{% if printer[printer.toolhead.extruder].temperature >= printer.configfile.settings.extruder.min_extrude_temp %}
G1 E{extrusion_length} F900 ; Prime nozzle
{% endif %}
RESTORE_GCODE_STATE NAME=PAUSEPARK2 MOVE=1 MOVE_SPEED=150
RESTORE_GCODE_STATE NAME=PAUSE MOVE=1 MOVE_SPEED=10 ; Restore position
BASE_RESUME ; Resume print
G90 ; Absolute positioning
{% endif %}
[gcode_macro CANCEL_PRINT]
rename_existing: BASE_CANCEL_PRINT
gcode:
{% set max_z = printer.configfile.config["stepper_z"]["position_max"]|float %}
{% if (printer.toolhead.position.z + 12) < max_z %}
{% set z_hop = 2 %}
{% else %}
{% set z_hop = 0 %}
{% endif %}
G91 ; Relative positioning
G1 Z{z_hop} F600 ; Do a tiny z-hop
G90 ; Absolute positioning
G1 X{printer.toolhead.axis_maximum.x/2} Y{printer.toolhead.axis_maximum.y-40} F12000
CLEAR_PAUSE
SDCARD_RESET_FILE
PRINT_END
BASE_CANCEL_PRINT
[gcode_macro _Z_CLEARANCE]
description: Lower the bed to give some clearance
variable_default_distance: 40.0
gcode:
{% set current_z_height = printer.toolhead.position.z %}
{% set max_z_height = printer.toolhead.axis_maximum.z %}
{% set distance = params.DISTANCE|default(variable_default_distance)|float %}
{% set target_z_height = current_z_height + distance %}
{% set min_z_param = params.MIN_Z|default(None) %}
{% if min_z_param is not none %}
{% set min_z = min_z_param|float %}
{% if target_z_height < min_z %}
{% set target_z_height = min_z %}
{% endif %}
{% endif %}
G90 ; Absolute positioning
G1 Z{ [target_z_height, max_z_height]|min }
########################################
# Filament Macros
########################################
[gcode_macro UNLOAD_FILAMENT]
description: Unloads filament from toolhead
gcode:
{% set EXTRUDER_TEMP = params.TEMP|default(230)|int %}
{% set CURRENT_TEMP = printer.extruder.temperature|int %}
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M109 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=1 ; enable extruder stepper
M83 ; set extruder to relative mode
G1 E5 F150 ; extrude a small amount to elimate soften the filament
G1 E-8 F1800 ; quickly retract a small amount to elimate stringing
G4 P200 ; pause for a short amount of time
G1 E-50 F300 ; retract slowly the rest of the way
M104 S0 ; turn off hotend
M400 ; wait for moves to finish
M118 Unload Complete!
[gcode_macro LOAD_FILAMENT]
description: Loads filament to toolhead
gcode:
{% set EXTRUDER_TEMP = params.TEMP|default(230)|int %}
{% set CURRENT_TEMP = printer.extruder.temperature|int %}
{% if CURRENT_TEMP < EXTRUDER_TEMP %}
M109 S{EXTRUDER_TEMP} ; heat up the hotend
{% endif %}
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=1 ; enable extruder stepper
M83 ; set extruder to relative mode
G1 E5 F120 ; feed filament
G1 E5 F300 ; feed filament
G1 E40 F600 ; feed filament
G1 E15 F300 ; feed filament
G1 E15 F120 ; feed filament
G4 P200 ; pause for a short amount of time
G1 E10 F90 ; feed filament
M104 S0 ; turn off hotend
M400 ; wait for moves to finish
M118 Load Complete!
# Filament runout sensor enable/disable
[gcode_macro M8029]
gcode:
{% if params.D is defined %}
{% if (params.D|int)==1 %}
SET_FILAMENT_SENSOR SENSOR=filament ENABLE=1
{% endif %}
{% if (params.D|int)==0 %}
SET_FILAMENT_SENSOR SENSOR=filament ENABLE=0
{% endif %}
{% endif %}
########################################
# Fan Macros
########################################
# Set Fan Speed macro
# Mainly name castings for nicer web interface names and display functionality
[gcode_macro M106]
rename_existing: M106.1
gcode:
{% if params.P is defined %}
{% if params.S is defined %}
{% set speed = 0.003921*params.S|int %}
{% if (params.P|int) == 0 %}
M106.1 S{params.S|int}
{% elif (params.P|int) == 2 %}
SET_FAN_SPEED FAN=sidefan SPEED={speed}
{% elif (params.P|int) == 3 %}
SET_FAN_SPEED FAN=filterfan SPEED={speed}
{% else %}
SET_FAN_SPEED FAN=fan{params.P|int} SPEED={speed}
{% endif %}
{% else %}
{% if (params.P|int) == 0 %}
M106.1 S255
{% elif (params.P|int) == 2 %}
SET_FAN_SPEED FAN=sidefan SPEED=1
{% elif (params.P|int) == 3 %}
SET_FAN_SPEED FAN=filterfan SPEED=1
{% else %}
SET_FAN_SPEED FAN=fan{params.P|int} SPEED=1
{% endif %}
{% endif %}
{% endif %}
{% if params.T is defined %}
{% if (params.T|int) == -2 %}
{% if params.S is defined %}
{% set speed = 0.003921*params.S|int %}
SET_FAN_SPEED FAN=filterfan SPEED={speed}
{% else %}
SET_FAN_SPEED FAN=filterfan SPEED=1
{% endif %}
{% endif %}
{% endif %}
{% if params.P is undefined %}
{% if params.T is undefined %}
{% if params.S is defined %}
M106.1 S{params.S|int}
{% else %}
M106.1 S255
{% endif %}
{% endif %}
{% endif %}
[gcode_macro M107]
rename_existing: M107.1
gcode:
M106.1 S0
########################################
# Temperature Macros
########################################
# Wait for Hotend Temperature
[gcode_macro M109]
rename_existing: M109.1
gcode:
#Parameters
{% set s = params.S|float %}
M104 {% for p in params %}{'%s%s' % (p, params[p])}{% endfor %} ; Set hotend temp
{% if s != 0 %}
TEMPERATURE_WAIT SENSOR=extruder MINIMUM={s} MAXIMUM={s+1} ; Wait for hotend temp (within 1 degree)
{% endif %}
# PID autotune
[gcode_macro M303]
gcode:
{% if params.E is defined %}
{% if params.S is defined %}
{% if (params.E|int)==-1 %}
PID_CALIBRATE HEATER=heater_bed TARGET={params.S|int}
{% endif %}
{% if (params.E|int)==0 %}
PID_CALIBRATE HEATER=extruder TARGET={params.S|int}
{% endif %}
{% endif %}
{% endif %}
# Set chamber temperature
[gcode_macro M141]
gcode:
{% if printer["heater_generic chamber"] is defined %}
{% set chamber_target_temp = params.S|float %}
SET_HEATER_TEMPERATURE HEATER=chamber TARGET={([chamber_target_temp, 65]|min)}
{% endif %}
# Set wait chamber temperature
[gcode_macro M191]
gcode:
#Parameters
{% set chamber_target_temp = params.S|float %}
{% if chamber_target_temp == 0 %}
M118 Chamber heater off
{% else %}
M141 S{chamber_target_temp}
TEMPERATURE_WAIT SENSOR="heater_generic chamber" MINIMUM={([chamber_target_temp, 60]|min)-2} MAXIMUM={chamber_target_temp + 5}
M118 Chamber at target temperature
{% endif %}
########################################
# Sound Macros
########################################
[gcode_macro BEEP]
gcode:
{% set i = params.I|default(1)|int %} ; Iterations (number of times to beep).
{% set dur = params.DUR|default(100)|int %} ; Duration/wait of each beep in ms. Default 100ms.
{% if printer["output_pin sound"].value|int == 1 %}
{% for iteration in range(i|int) %}
SET_PIN PIN=buzzer VALUE=1
G4 P{dur}
SET_PIN PIN=buzzer VALUE=0
G4 P{dur}
{% endfor %}
{% endif %}
[gcode_macro beep_on]
gcode:
SET_PIN PIN=buzzer VALUE=1
[gcode_macro beep_off]
gcode:
SET_PIN PIN=buzzer VALUE=0
########################################
# Z-height Macros
########################################
# Bed Leveling (Unified)
[gcode_macro G29]
variable_k:1
gcode:
{% if k|int==1 %}
BED_MESH_CLEAR ; Clear levelling data
BED_MESH_CALIBRATE ADAPTIVE=1 ADAPTIVE_MARGIN=5 ; Start adaptive meshing
{% endif %}
# Babystep
[gcode_macro M290]
gcode:
SET_GCODE_OFFSET Z_ADJUST={params.Z}
########################################
# Tuning Macros
########################################
[gcode_macro SHAPER_CALIBRATE]
rename_existing: RESHAPER_CALIBRATE
gcode:
RESHAPER_CALIBRATE FREQ_START=30 FREQ_END=130
# Linear Advance Factor
[gcode_macro M900]
gcode:
{% if params.K is defined %}
SET_PRESSURE_ADVANCE ADVANCE={params.K}
{% endif %}
{% if params.T is defined %}
SET_PRESSURE_ADVANCE SMOOTH_TIME={params.T}
{% endif %}
# Set Starting Acceleration
[gcode_macro M204]
rename_existing: M99204
gcode:
{% if params.S is defined %}
{% set s = params.S|float %}
{% endif %}
{% if params.P is defined %}
{% if params.T is defined %}
{% set s = [params.P|float ,params.T|float] | min %}
{% endif %}
{% endif %}
SET_VELOCITY_LIMIT ACCEL={s}
SET_VELOCITY_LIMIT ACCEL_TO_DECEL={s/2}
# Bed leveling
# For more information, see https://www.klipper3d.org/Manual_Level.html#adjusting-bed-leveling-screws-using-the-bed-probe
[gcode_macro LEVEL_BED]
description: "Measure bed and calculate screw adjustments for manual bed leveling"
gcode:
G28 ; Home all
SCREWS_TILT_CALCULATE ; Perform measurements and output screw adjustments
# Probe Calibration
# For more information, see https://www.klipper3d.org/Probe_Calibrate.html
[gcode_macro CALIBRATE_Z_OFFSET]
description: "Calibrate the Z offset using the probe"
gcode:
{% set max_x = printer.configfile.config["stepper_x"]["position_max"]|float %}
{% set max_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
G28 ; Home all
G0 Z10 ; Increase z clearance
G0 X{max_x/2} Y{max_y-40} F6000 ; Move to bed center
PROBE_CALIBRATE ; Perform a probe calibration
# Nozzle PID tuning
# For more information, see https://www.klipper3d.org/Config_checks.html#calibrate-pid-settings
[gcode_macro NOZZLE_PID_TUNE]
description: "Perform PID tuning for the nozzle heater"
gcode:
PID_CALIBRATE HEATER=extruder TARGET=220 ; PID tune the nozzle
# Bed PID tuning
# For more information, see https://www.klipper3d.org/Config_checks.html#calibrate-pid-settings
[gcode_macro BED_PID_TUNE]
description: "Perform PID tuning for the bed heater"
gcode:
PID_CALIBRATE HEATER=heater_bed TARGET=80 ; PID tune the bed
########################################
# Macros for display functionallity
########################################
[gcode_macro INPUT_SHAPING_CALIBRATE]
description: "Perform Input Shaping calibration and save the results to printer.cfg"
gcode:
SHAPER_CALIBRATE ; Step 1: Perform the Input Shaping calibration
PAUSE ; Step 2: Pause to allow the calibration to complete
SAVE_CONFIG ; Step 3: Save the configuration to printer.cfg
RESTART ; Step 4: Restart the firmware to apply the new settings
================================================
FILE: config_section/X-Max3/printer.cfg
================================================
# X-Max3 config created by Phil1988(github)/coco.33(discord) on 20.12.2024
# For more information check out my wiki: https://github.com/Phil1988/FreeDi/wiki
#####################################################################
# Kinematics
#####################################################################
[printer]
kinematics:corexy
max_velocity: 600
max_accel: 20000
max_z_velocity: 20
max_z_accel: 500
square_corner_velocity: 8
#####################################################################
# Motherboard and periphery
#####################################################################
[temperature_sensor Mainboard_RK3328]
sensor_type: temperature_host
min_temp: 10
max_temp: 100
[mcu]
serial: /dev/ttyS0
restart_method: command
baud: 500000
[temperature_sensor Mainboard_STM32F402]
sensor_type: temperature_mcu
sensor_mcu: mcu
[mcu Toolhead]
serial: /dev/serial/by-id/usb-Klipper_rp2040_C5DA4D951E145858-if00
[temperature_sensor Toolhead_RP2040]
sensor_type: temperature_mcu
sensor_mcu: Toolhead
min_temp: 0
max_temp: 100
#####################################################################
# Features
#####################################################################
# For saving GCODE files
[virtual_sdcard]
path: ~/printer_data/gcodes
on_error_gcode: CANCEL_PRINT
# For enabling pause/resume
[pause_resume]
# Activating exclude objects feature
[display_status]
[exclude_object]
# Expanding idle timeout
[idle_timeout]
timeout: 5400 ; 90min timeout
# Activating GCODE arc feature
[gcode_arcs]
resolution: 1.0
# Allowing free move (can be dangerous!)
[force_move]
enable_force_move: True
# Activating responses
[respond]
default_type: echo
#####################################################################
# FreeDi
#####################################################################
[include freedi.cfg]
#####################################################################
# Macros
#####################################################################
[include macros.cfg]
#####################################################################
# Input shaping
#####################################################################
[resonance_tester]
accel_chip:adxl345
probe_points:
160, 160, 10
accel_per_hz: 75
sweeping_period: 0
max_smoothing: 0.5
[adxl345]
cs_pin: Toolhead:gpio13
spi_software_sclk_pin: Toolhead:gpio14
spi_software_mosi_pin: Toolhead:gpio15
spi_software_miso_pin: Toolhead:gpio12
axes_map: -x, z, -y
[input_shaper]
shaper_type_x: mzv
shaper_freq_x: 57.6
shaper_type_y: mzv
shaper_freq_y: 46.6
#####################################################################
# Hotend
#####################################################################
[extruder]
step_pin: Toolhead:gpio5
dir_pin: Toolhead:gpio4
enable_pin: !Toolhead:gpio10
rotation_distance: 53.5
gear_ratio: 1628:170
microsteps: 16
full_steps_per_rotation: 200
nozzle_diameter: 0.400
filament_diameter: 1.75
min_temp: 0
max_temp: 360
min_extrude_temp: 170
smooth_time: 0.000001
step_pulse_duration:0.000002
heater_pin: Toolhead:gpio0
sensor_type:MAX6675
sensor_pin: Toolhead:gpio17
max_power: 1.0
control: pid
pid_Kp: 24.737
pid_Ki: 10.994
pid_Kd: 13.915
spi_speed: 100000
spi_software_sclk_pin: Toolhead:gpio18
spi_software_mosi_pin: Toolhead:gpio19
spi_software_miso_pin: Toolhead:gpio16
pressure_advance: 0.032
pressure_advance_smooth_time: 0.03
max_extrude_cross_section:500
instantaneous_corner_velocity: 10.000
max_extrude_only_distance: 500.0
max_extrude_only_velocity: 5000
max_extrude_only_accel: 2000
[verify_heater extruder]
max_error: 120
check_gain_time: 20
hysteresis: 5
heating_gain: 1
#####################################################################
# Heated bed
#####################################################################
[heater_bed]
heater_pin: PC8
sensor_type: NTC 100K MGB18-104F39050L32
sensor_pin: PA0
max_power: 1.0
control: pid
pid_kp: 64.431
pid_ki: 2.845
pid_kd: 364.839
min_temp: -50
max_temp: 125
pwm_cycle_time: 0.02 # for 50Hz line power
#pwm_cycle_time: 0.016 # for 60Hz line power
[verify_heater heater_bed]
max_error: 200
check_gain_time: 360
hysteresis: 5
heating_gain: 1
#####################################################################
# Bed mesh
#####################################################################
[bed_mesh]
speed: 150
horizontal_move_z: 3.0
mesh_min: 28,8
mesh_max: 315,310
probe_count: 9,9
algorithm: bicubic
bicubic_tension: 0.2
mesh_pps: 4, 4
#####################################################################
# Probe
#####################################################################
#!# Pay attention to this section and compare it with your stock backup config
[probe]
pin: ^!Toolhead:gpio21
x_offset: 2
gitextract_3uvhfo04/
├── .github/
│ ├── FUNDING.yml
│ └── ISSUE_TEMPLATE/
│ ├── bug-report.md
│ ├── feature_request.md
│ └── getting-help.md
├── FreeDiLCD/
│ ├── LICENSE
│ ├── freedi_update.sh
│ └── start.py
├── LICENSE
├── README.md
├── config_section/
│ ├── Plus4/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── Q1_Pro/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── X-Max3/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── X-Plus3/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── X-Smart3/
│ │ ├── macros.cfg
│ │ └── printer.cfg
│ ├── generic/
│ │ ├── crowsnest.conf
│ │ ├── freedi.cfg
│ │ └── moonraker.conf
│ └── template/
│ ├── macros.cfg
│ └── printer.cfg
├── helpers/
│ ├── AutoFlasher.service
│ ├── FreeDi.service
│ ├── dtbo/
│ │ └── rockchip-mkspi-uart1.dtbo
│ ├── flashtool.py
│ ├── freedi-prerequisites-1.0-all.deb
│ ├── hid-flash
│ ├── klipper_auto_flasher.sh
│ ├── usbmounter.sh
│ └── wifi/
│ └── aic8800-dkms.deb
├── install/
│ ├── freedi_install.conf
│ ├── packages.sh
│ └── wifi.sh
├── install.sh
├── klipper_module/
│ ├── freedi.py
│ └── qidi_auto_z_offset/
│ ├── LICENSE
│ ├── README.md
│ └── auto_z_offset.py
├── mainboard_and_toolhead_firmwares/
│ └── v0.13.0-154/
│ ├── Toolhead_Q1_katapult.uf2
│ ├── Toolhead_X3.uf2
│ └── flash_nuke.uf2
├── old_mainboard_and_toolhead_firmwares/
│ └── v0.10.0-530_old_stock/
│ └── Toolhead_RP2040.uf2
├── presliced_z-offset_calibration_files/
│ ├── Plus4/
│ │ └── z-offset_calibration_Plus4_PLA_4m4s.gcode
│ ├── Q1_Pro/
│ │ └── z-offset_calibration_Q1_Pro_PLA_4m6s.gcode
│ ├── X-Max3/
│ │ └── z-offset_calibration_X-Max3_PLA_8m46s.gcode
│ ├── X-Plus3/
│ │ └── z-offset_calibration_X-Plus3_PLA_4m4s.gcode
│ └── X-Smart3/
│ └── z-offset_calibration_X-Smart3_PLA_8m38s.gcode
├── requirements.txt
├── screen_firmwares/
│ ├── q1_pro_stable_v2.08.tft
│ ├── x-plus3_x-max3_plus4_stable_v2.08.tft
│ └── x-smart3_stable_v2.08.tft
└── themes/
├── Plus4/
│ └── .theme/
│ └── custom.css
├── Q1_Pro/
│ └── .theme/
│ └── custom.css
├── X-Max3/
│ └── .theme/
│ └── custom.css
├── X-Plus3/
│ └── .theme/
│ └── custom.css
└── X-Smart3/
└── .theme/
└── custom.css
SYMBOL INDEX (110 symbols across 4 files)
FILE: FreeDiLCD/start.py
function run_and_delete_bash_script (line 5) | def run_and_delete_bash_script(file_name):
function is_instance_running (line 29) | def is_instance_running(script_name):
FILE: helpers/flashtool.py
function output_line (line 33) | def output_line(msg: str) -> None:
function output (line 37) | def output(msg: str) -> None:
function crc16_ccitt (line 42) | def crc16_ccitt(buf: Union[bytes, bytearray]) -> int:
class FlashError (line 92) | class FlashError(Exception):
function get_usb_info (line 95) | def get_usb_info(usb_path: pathlib.Path) -> Dict[str, Any]:
function get_usb_path (line 118) | def get_usb_path(device: pathlib.Path) -> Optional[pathlib.Path]:
function get_stable_usb_symlink (line 133) | def get_stable_usb_symlink(device: pathlib.Path) -> pathlib.Path:
function mix (line 174) | def mix(val: int) -> int:
function fasthash64 (line 180) | def fasthash64(buffer: bytes, seed: int) -> int:
function convert_usbsn_to_uuid (line 201) | def convert_usbsn_to_uuid(serial_number: str) -> int:
class CanFlasher (line 211) | class CanFlasher:
method __init__ (line 212) | def __init__(
method _check_binary (line 228) | def _check_binary(self) -> None:
method _build_command (line 253) | def _build_command(self, cmd: int, payload: bytes) -> bytearray:
method prime (line 265) | def prime(self) -> None:
method connect_btl (line 273) | async def connect_btl(self) -> None:
method verify_canbus_uuid (line 314) | async def verify_canbus_uuid(self, uuid):
method send_command (line 321) | async def send_command(
method send_file (line 408) | async def send_file(self):
method verify_file (line 451) | async def verify_file(self):
method finish (line 484) | async def finish(self):
class CanNode (line 488) | class CanNode:
method __init__ (line 489) | def __init__(self, node_id: int, cansocket: CanSocket | SerialSocket) ...
method read (line 494) | async def read(
method readexactly (line 499) | async def readexactly(
method readuntil (line 504) | async def readuntil(
method write (line 509) | def write(self, payload: Union[bytes, bytearray]) -> None:
method write_with_response (line 514) | async def write_with_response(
method feed_data (line 523) | def feed_data(self, data: bytes) -> None:
method close (line 526) | def close(self) -> None:
class BaseSocket (line 529) | class BaseSocket:
method __init__ (line 530) | def __init__(self, args: argparse.Namespace) -> None:
method is_flash_req (line 536) | def is_flash_req(self) -> bool:
method is_bootloader_req (line 542) | def is_bootloader_req(self) -> bool:
method is_status_req (line 546) | def is_status_req(self) -> bool:
method is_query (line 550) | def is_query(self) -> bool:
method is_usb_can_bridge (line 554) | def is_usb_can_bridge(self) -> bool:
method usb_serial_path (line 558) | def usb_serial_path(self) -> pathlib.Path:
method _check_firmware (line 561) | def _check_firmware(self) -> None:
method run (line 565) | async def run(self) -> None:
method close (line 568) | def close(self) -> None:
class CanSocket (line 571) | class CanSocket(BaseSocket):
method __init__ (line 572) | def __init__(self, args: argparse.Namespace) -> None:
method is_usb_can_bridge (line 602) | def is_usb_can_bridge(self) -> bool:
method usb_serial_path (line 606) | def usb_serial_path(self) -> pathlib.Path:
method _handle_can_response (line 621) | def _handle_can_response(self) -> None:
method _process_packet (line 646) | def _process_packet(self, packet: bytes) -> None:
method send (line 654) | def send(self, can_id: int, payload: bytes = b"") -> None:
method _do_can_send (line 673) | async def _do_can_send(self):
method _jump_to_bootloader (line 684) | def _jump_to_bootloader(self, uuid: int):
method _query_uuids (line 690) | async def _query_uuids(self) -> List[int]:
method _reset_nodes (line 721) | def _reset_nodes(self) -> None:
method _set_node_id (line 726) | def _set_node_id(self, uuid: int) -> CanNode:
method _search_canbus_bridge (line 739) | def _search_canbus_bridge(self) -> None:
method _wait_canbridge_reset (line 778) | async def _wait_canbridge_reset(self) -> None:
method run (line 804) | async def run(self) -> None:
method close (line 844) | def close(self):
class SerialSocket (line 853) | class SerialSocket(BaseSocket):
method __init__ (line 854) | def __init__(self, args: argparse.Namespace) -> None:
method is_query (line 876) | def is_query(self) -> bool:
method usb_serial_path (line 880) | def usb_serial_path(self) -> pathlib.Path:
method _handle_response (line 883) | def _handle_response(self) -> None:
method send (line 893) | def send(self, can_id: int, payload: bytes = b"") -> None:
method _lookup_proc_name (line 901) | async def _lookup_proc_name(self, process_id: str) -> str:
method validate_device (line 925) | async def validate_device(self, dev_strpath: str) -> None:
method _request_usb_bootloader (line 954) | async def _request_usb_bootloader(self, device: pathlib.Path) -> pathl...
method _request_serial_bootloader (line 1005) | async def _request_serial_bootloader(self, device: str, baud: int) -> ...
method _open_device (line 1013) | def _open_device(self, device: str, baud: int) -> Serial:
method _has_double_buffering (line 1024) | def _has_double_buffering(self, product: str) -> bool:
method run (line 1030) | async def run(self) -> None:
method close (line 1079) | def close(self):
function main (line 1086) | async def main(args: argparse.Namespace) -> int:
FILE: klipper_module/freedi.py
class FreeDi (line 7) | class FreeDi:
method __init__ (line 8) | def __init__(self, config):
method log_info (line 60) | def log_info(self, message):
function load_config (line 67) | def load_config(config):
FILE: klipper_module/qidi_auto_z_offset/auto_z_offset.py
class AutoZOffsetCommandHelper (line 14) | class AutoZOffsetCommandHelper(probe.ProbeCommandHelper):
method __init__ (line 15) | def __init__(self, config, mcu_probe, query_endstop=None):
method _move_to_center (line 62) | def _move_to_center(self, gcmd):
method lift_probe (line 72) | def lift_probe(self, gcmd):
method cmd_AUTO_Z_PROBE (line 83) | def cmd_AUTO_Z_PROBE(self, gcmd):
method cmd_AUTO_Z_HOME_Z (line 91) | def cmd_AUTO_Z_HOME_Z(self, gcmd):
method cmd_AUTO_Z_MEASURE_OFFSET (line 106) | def cmd_AUTO_Z_MEASURE_OFFSET(self, gcmd):
method cmd_AUTO_Z_CALIBRATE (line 132) | def cmd_AUTO_Z_CALIBRATE(self, gcmd):
method cmd_AUTO_Z_LOAD_OFFSET (line 158) | def cmd_AUTO_Z_LOAD_OFFSET(self, gcmd):
method cmd_AUTO_Z_SAVE_GCODE_OFFSET (line 170) | def cmd_AUTO_Z_SAVE_GCODE_OFFSET(self, gcmd):
class HomingViaAutoZHelper (line 186) | class HomingViaAutoZHelper(probe.HomingViaProbeHelper):
method __init__ (line 187) | def __init__(self, config, mcu_probe, param_helper):
class AutoZOffsetEndstopWrapper (line 214) | class AutoZOffsetEndstopWrapper:
method __init__ (line 215) | def __init__(self, config):
method multi_probe_begin (line 232) | def multi_probe_begin(self):
method probe_prepare (line 236) | def probe_prepare(self, hmove):
method probe_finish (line 245) | def probe_finish(self, hmove):
class AutoZOffsetParameterHelper (line 251) | class AutoZOffsetParameterHelper(probe.ProbeParameterHelper):
method __init__ (line 252) | def __init__(self, config):
class AutoZOffsetSessionHelper (line 269) | class AutoZOffsetSessionHelper(probe.ProbeSessionHelper):
method __init__ (line 270) | def __init__(self, config, param_helper, start_session_cb):
method run_probe (line 282) | def run_probe(self, gcmd):
class AutoZOffsetOffsetsHelper (line 317) | class AutoZOffsetOffsetsHelper:
method __init__ (line 318) | def __init__(self, config):
method get_offsets (line 323) | def get_offsets(self):
class AutoZOffsetProbe (line 327) | class AutoZOffsetProbe:
method __init__ (line 328) | def __init__(self, config):
method get_probe_params (line 343) | def get_probe_params(self, gcmd=None):
method get_offsets (line 346) | def get_offsets(self):
method get_status (line 349) | def get_status(self, eventtime):
method start_probe_session (line 352) | def start_probe_session(self, gcmd):
function load_config (line 356) | def load_config(config):
Condensed preview — 59 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (773K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 856,
"preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.md",
"chars": 896,
"preview": "---\nname: Bug report\nabout: Create a report to help me improve\ntitle: \"[Bug]\"\nlabels: ''\nassignees: Phil1988\n\n---\n\n**Des"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 344,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[Feature request]\"\nlabels: ''\nassignees: ''\n\n-"
},
{
"path": ".github/ISSUE_TEMPLATE/getting-help.md",
"chars": 773,
"preview": "---\nname: Getting help\nabout: Describe this issue template's purpose here.\ntitle: \"[Help]\"\nlabels: ''\nassignees: ''\n\n---"
},
{
"path": "FreeDiLCD/LICENSE",
"chars": 4190,
"preview": " Copyright (c) 2024, \n https://github.com/Phil1988 [C0co]. \n "
},
{
"path": "FreeDiLCD/freedi_update.sh",
"chars": 12076,
"preview": "#!/bin/bash\n\n# to delete '\\r' signs use\n# sed -i 's/\\r$//' freedi_update.sh\n# Set variables\n\necho \"Starting the FreeDi u"
},
{
"path": "FreeDiLCD/start.py",
"chars": 1862,
"preview": "import os\nimport sys\nimport subprocess\n\ndef run_and_delete_bash_script(file_name):\n file_name = os.path.join(os.path."
},
{
"path": "LICENSE",
"chars": 4190,
"preview": " Copyright (c) 2024, \n https://github.com/Phil1988 [C0co]. \n "
},
{
"path": "README.md",
"chars": 4221,
"preview": "# FreeDi\n**Open Mainline Klipper for QIDI Printers**\n\nTransform your QIDI printer with FreeDi - built on open Armbian OS"
},
{
"path": "config_section/Plus4/macros.cfg",
"chars": 48661,
"preview": "#####################################################################\n# Specific Plus4 macros\n##########################"
},
{
"path": "config_section/Plus4/printer.cfg",
"chars": 14519,
"preview": "# Plus4 config created by Phil1988(github)/coco.33(discord) on 04.05.2025\n# For more information check out my wiki: http"
},
{
"path": "config_section/Q1_Pro/macros.cfg",
"chars": 48432,
"preview": "#####################################################################\n# Specific Q1 Pro macros\n#########################"
},
{
"path": "config_section/Q1_Pro/printer.cfg",
"chars": 13562,
"preview": "# Q1 Pro config created by Phil1988(github)/coco.33(discord) on 11.05.2025\n# For more information check out my wiki: htt"
},
{
"path": "config_section/X-Max3/macros.cfg",
"chars": 38624,
"preview": "#####################################################################\n# Advanced CHAMBER_TEMP_CONTROLLER\n###############"
},
{
"path": "config_section/X-Max3/printer.cfg",
"chars": 11494,
"preview": "# X-Max3 config created by Phil1988(github)/coco.33(discord) on 20.12.2024\n# For more information check out my wiki: htt"
},
{
"path": "config_section/X-Plus3/macros.cfg",
"chars": 38671,
"preview": "#####################################################################\n# Advanced CHAMBER_TEMP_CONTROLLER\n###############"
},
{
"path": "config_section/X-Plus3/printer.cfg",
"chars": 11533,
"preview": "# X-Plus3 config created by Phil1988(github)/coco.33(discord) on 20.12.2024\n# For more information check out my wiki: ht"
},
{
"path": "config_section/X-Smart3/macros.cfg",
"chars": 34913,
"preview": "#####################################################################\n# Advanced CHAMBER_TEMP_CONTROLLER\n###############"
},
{
"path": "config_section/X-Smart3/printer.cfg",
"chars": 10951,
"preview": "# X-Smart3 config created by Phil1988(github)/coco.33(discord) on 20.12.2024\n# For more information check out my wiki: h"
},
{
"path": "config_section/generic/crowsnest.conf",
"chars": 3158,
"preview": "#### crowsnest.conf\n#### This is the default config after installation.\n#### It is also used as the default config in Ma"
},
{
"path": "config_section/generic/freedi.cfg",
"chars": 4850,
"preview": "#####################################################################\n# FreeDi config\n##################################"
},
{
"path": "config_section/generic/moonraker.conf",
"chars": 1635,
"preview": "#####################################################################\n# Basics\n#########################################"
},
{
"path": "config_section/template/macros.cfg",
"chars": 48190,
"preview": "#####################################################################\n# Specific Plus4 macros\n##########################"
},
{
"path": "config_section/template/printer.cfg",
"chars": 14519,
"preview": "# Plus4 config created by Phil1988(github)/coco.33(discord) on 04.05.2025\n# For more information check out my wiki: http"
},
{
"path": "helpers/AutoFlasher.service",
"chars": 216,
"preview": "[Unit]\nDescription=Toolhead & MCU Flash Service\nAfter=klipper.service\n\n[Service]\nType=oneshot\nExecStart=/home/{{USER}}/F"
},
{
"path": "helpers/FreeDi.service",
"chars": 659,
"preview": "[Unit]\nDescription=Starting the FreeDi service\nAfter=moonraker.service\n\n[Service]\nType=simple\n#User={{USER}}\nWorkingDire"
},
{
"path": "helpers/flashtool.py",
"chars": 43323,
"preview": "#!/usr/bin/env python3\n# Script to upload software via Katapult\n#\n# Copyright (C) 2022 Eric Callahan <arksine.code@gmail"
},
{
"path": "helpers/klipper_auto_flasher.sh",
"chars": 3076,
"preview": "#!/bin/bash\n\n## muss ausführbar gemacht werden mit\n## chmod +x /home/mks/FreeDi/mainboard_and_toolhead_firmwares/hid"
},
{
"path": "helpers/usbmounter.sh",
"chars": 4604,
"preview": "#!/bin/bash\n\nUSER=\"$1\"\nTARGET_DIR=\"/home/$USER/printer_data/gcodes\"\nARG=\"$2\"\nACTION=$(echo \"$ARG\" | cut -d'-' -f1)\nDEVIC"
},
{
"path": "install/freedi_install.conf",
"chars": 3655,
"preview": "################################################################################\n# FreeDi Installation Configuration\n#\n#"
},
{
"path": "install/packages.sh",
"chars": 2106,
"preview": "#!/bin/bash\n# Installs all required apt packages for FreeDi.\n# Sourced by install.sh — expects IS_FREEDI_IMAGE, OS_CODEN"
},
{
"path": "install/wifi.sh",
"chars": 5238,
"preview": "#!/bin/bash\n\n################################################################################\n# CONFIGURE WIFI\n#########"
},
{
"path": "install.sh",
"chars": 38563,
"preview": "#!/usr/bin/env bash\n#\n# FreeDi Installation Script\n# Installs FreeDi modules, configures services, and sets up hardware "
},
{
"path": "klipper_module/freedi.py",
"chars": 3723,
"preview": "# FreeDi Module for Klipper\n# This module registers a custom [FreeDi] section in the printer.cfg file\n# and loads the as"
},
{
"path": "klipper_module/qidi_auto_z_offset/LICENSE",
"chars": 35149,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "klipper_module/qidi_auto_z_offset/README.md",
"chars": 4322,
"preview": "# Auto Z-Offset Calibration for the QIDI Q1 Pro\n\nThis is a plugin for Klipper that makes use of the QIDI Q1 Pro's bed se"
},
{
"path": "klipper_module/qidi_auto_z_offset/auto_z_offset.py",
"chars": 14170,
"preview": "# QIDI Auto Z-Offset support\n#\n# Copyright (C) 2024 Joe Maples <joe@maples.dev>\n# Copyright (C) 2021 Dmitry Butyugin <"
},
{
"path": "presliced_z-offset_calibration_files/Plus4/z-offset_calibration_Plus4_PLA_4m4s.gcode",
"chars": 43311,
"preview": "; HEADER_BLOCK_START\n; generated by OrcaSlicer 2.2.0 on 2025-06-04 at 11:43:40\n; total layer number: 1\n; filament_densit"
},
{
"path": "presliced_z-offset_calibration_files/Q1_Pro/z-offset_calibration_Q1_Pro_PLA_4m6s.gcode",
"chars": 41405,
"preview": "; HEADER_BLOCK_START\n; generated by OrcaSlicer 2.2.0 on 2025-06-04 at 11:47:33\n; total layer number: 1\n; filament_densit"
},
{
"path": "presliced_z-offset_calibration_files/X-Max3/z-offset_calibration_X-Max3_PLA_8m46s.gcode",
"chars": 42003,
"preview": "; HEADER_BLOCK_START\n; generated by OrcaSlicer 2.2.0 on 2025-06-04 at 11:46:17\n; total layer number: 1\n; filament_densit"
},
{
"path": "presliced_z-offset_calibration_files/X-Plus3/z-offset_calibration_X-Plus3_PLA_4m4s.gcode",
"chars": 43311,
"preview": "; HEADER_BLOCK_START\n; generated by OrcaSlicer 2.2.0 on 2025-06-04 at 11:44:41\n; total layer number: 1\n; filament_densit"
},
{
"path": "presliced_z-offset_calibration_files/X-Smart3/z-offset_calibration_X-Smart3_PLA_8m38s.gcode",
"chars": 40029,
"preview": "; HEADER_BLOCK_START\n; generated by OrcaSlicer 2.2.0 on 2025-06-04 at 11:42:33\n; total layer number: 1\n; filament_densit"
},
{
"path": "requirements.txt",
"chars": 83,
"preview": "configparser\nrequests\npyserial>=3.5\nPillow\nnumpy\nmatplotlib\npsutil\nwebsocket-client"
},
{
"path": "themes/Plus4/.theme/custom.css",
"chars": 689,
"preview": ".theme--dark.v-list-item:not(.v-list-item--active):not(.v-list-item--disabled) {\n color: #51b0ff;\n}\n\n.v-progress-circ"
},
{
"path": "themes/Q1_Pro/.theme/custom.css",
"chars": 689,
"preview": ".theme--dark.v-list-item:not(.v-list-item--active):not(.v-list-item--disabled) {\n color: #51b0ff;\n}\n\n.v-progress-circ"
},
{
"path": "themes/X-Max3/.theme/custom.css",
"chars": 689,
"preview": ".theme--dark.v-list-item:not(.v-list-item--active):not(.v-list-item--disabled) {\n color: #51b0ff;\n}\n\n.v-progress-circ"
},
{
"path": "themes/X-Plus3/.theme/custom.css",
"chars": 689,
"preview": ".theme--dark.v-list-item:not(.v-list-item--active):not(.v-list-item--disabled) {\n color: #51b0ff;\n}\n\n.v-progress-circ"
},
{
"path": "themes/X-Smart3/.theme/custom.css",
"chars": 689,
"preview": ".theme--dark.v-list-item:not(.v-list-item--active):not(.v-list-item--disabled) {\n color: #51b0ff;\n}\n\n.v-progress-circ"
}
]
// ... and 11 more files (download for full content)
About this extraction
This page contains the full source code of the Phil1988/FreeDi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 59 files (15.9 MB), approximately 217.9k tokens, and a symbol index with 110 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.