# Recuperar impresión fallida en Klipper

No hay nada que duela más que ver una pieza al 80% y que, de repente, se produzca un atasco, se acabe el filamento o un gato decida que el cable de alimentación es un juguete.

Si no has movido la pieza de la cama, respira hondo. Aquí tienes posibles caminos de cómo resucitar tu impresión.

{% hint style="danger" %}
**Antes de hacer nada, asegúrate de que:**

1. **La pieza sigue pegada**: Si se ha despegado o la has movido, apaga y vámonos. No hay alineación que salve eso.
2. **No hagas Home (G28) completo**: Si haces un Home en Z con la pieza en la cama, el cabezal chocará. Haremos el homing con "trampas".
3. **Mantén la temperatura de la cama**: Si la cama se enfría, la pieza se contraerá y se despegará. Usa el panel web o el comando `SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=60` (ajusta el `TARGET` a la temperatura que usabas).
   {% endhint %}

## ¿Todavía tienes el homing?

Si la impresora se ha pausado o detenido pero **no ha perdido el posicionamiento** (los motores siguen activos), prueba primero lo más sencillo:

1. **Intenta hacer Resume** desde Mainsail/Fluidd. A veces es suficiente.
2. Si el Resume falla, comprueba que el `idle_timeout` no haya desactivado los motores. Añade esto a tu `printer.cfg` para evitarlo:

```ini
[idle_timeout]
timeout: 3600  ; 1 hora — ajusta según tus necesidades
```

O envía por consola mientras trabajas:

```
SET_IDLE_TIMEOUT TIMEOUT=4200
```

3. Si el resume sigue fallando, sigue leyendo.

***

## Preparación previa (hazlo ANTES de que falle una impresión)

Esta sección es para configurar Klipper correctamente antes de que ocurra un problema. Si ya tienes una impresión fallida, continúa al siguiente paso.

### Guardar la malla de cama (esencial con BLTouch/CRTouch/ABL)

Si usas nivelación automática, **guarda siempre tu malla con un nombre**, nunca uses el perfil `default`. Si Klipper se reinicia, el perfil `default` puede desaparecer:

```
BED_MESH_PROFILE SAVE=impresion_actual
```

O desde la UI de Klipper (Mainsail): ve a **HEIGHTMAP → CURRENT MESH**, haz clic en el nombre `default` y cámbialo.

### Macros de rescate (añade a `macros.cfg`)

Instala estas macros antes de que las necesites. Te ahorrarán tiempo y errores cuando estés en modo pánico:

```jinja
#=====================================================
# RESCUE_Z — Posicionar Z en altura conocida
#=====================================================
[gcode_macro RESCUE_Z]
description: "Establece la posición Z a la altura medida de la impresión fallida"
gcode:
    {% set z_height = params.Z|default(0)|float %}
    SET_KINEMATIC_POSITION Z={z_height}
    M117 Z establecido a {z_height}mm

#=====================================================
# SET_Z0 — Poner Z actual a 0
#=====================================================
[gcode_macro SET_Z0]
description: "Establece la posición Z actual como Z=0"
gcode:
    G92 Z0

#=====================================================
# IDLE_TO_70MIN — Ampliar timeout para trabajar sin prisas
#=====================================================
[gcode_macro IDLE_TO_70MIN]
description: "Establece idle timeout a 70 minutos"
gcode:
    SET_IDLE_TIMEOUT TIMEOUT=4200

#=====================================================
# FORCE_MOVE_Z — Mover Z por fuerza sin homing
#=====================================================
[force_move]
enable_force_move: True

[gcode_macro FORCE_MOVE_Z]
description: "Mueve Z por fuerza sin homing — usar con cuidado"
gcode:
    SET_FORCE_MOVE ENABLE=1
    {% set stepper = params.STEPPER|default("stepper_z")|string %}
    {% set distance = params.DISTANCE|default(-0.1)|float %}
    {% set velocity = params.VELOCITY|default(10)|float %}
    SET_KINEMATIC_POSITION Z=0
    FORCE_MOVE STEPPER={stepper} DISTANCE={distance} VELOCITY={velocity}
    SET_GCODE_OFFSET Z=0
    G92 Z={distance}
    SET_FORCE_MOVE ENABLE=0
```

{% hint style="warning" %}
`FORCE_MOVE_Z` mueve en **milímetros reales** sin límites de software. Empieza siempre con valores pequeños (0.1–1mm) y verifica visualmente antes de continuar. Un valor incorrecto puede dañar la pieza o la impresora.
{% endhint %}

### Macro de inicio para impresión rescatada (con BLTouch/ABL)

Esta macro sustituye a tu `START_PRINT` habitual: solo hace home en X/Y, carga la malla guardada y **no toca el eje Z**:

```jinja
[gcode_macro START_PRINT_RESCUE]
gcode:
    {% set BED_TEMP = params.BED_TEMP|default(60)|float %}
    {% set EXTRUDER_TEMP = params.EXTRUDER_TEMP|default(190)|float %}
    {% set MESH_PROFILE = params.MESH|default("impresion_actual")|string %}

    SET_IDLE_TIMEOUT TIMEOUT=600
    G90               ; coordenadas absolutas
    M83               ; extrusor en modo relativo

    M104 S{EXTRUDER_TEMP}   ; calentar extrusor
    M140 S{BED_TEMP}        ; calentar cama

    G28 X Y                             ; home solo X e Y — NUNCA Z
    BED_MESH_PROFILE LOAD={MESH_PROFILE} ; cargar malla guardada

    M109 S{EXTRUDER_TEMP}   ; esperar temperatura extrusor
    M190 S{BED_TEMP}        ; esperar temperatura cama

    G0 Z10 F240             ; subir a altura segura
    M106 S255               ; ventilador al máximo
```

***

## Proceso de recuperación

{% stepper %}
{% step %}

#### Paso 1 — Determinar la altura de fallo (Z)

Necesitamos saber exactamente en qué milímetro se quedó la impresora.

* **Método calibre (más preciso)**: Mide la altura de la pieza impresa con un calibre digital. Si mide 42.4 mm, esa es tu referencia.
* **Método visual**: Busca una geometría reconocible en la pieza (una ranura, un cambio de forma) y búscala en la previsualización del G-code del laminador para identificar la altura exacta.
* **Método Klipper**: Mueve el cabezal sobre una zona terminada de la pieza y baja el eje Z de 0.1 en 0.1 hasta que la boquilla casi toque la última capa. Lee el valor de Z en la consola.

{% hint style="info" %}
Es mejor quedarse 0.1–0.2 mm corto (que la boquilla imprima ligeramente en el aire al principio) que pasarse y que el cabezal choque y arranque la pieza de la cama.
{% endhint %}
{% endstep %}

{% step %}

#### Paso 2 — Establecer el home de Z sin mover la impresora

Aquí hay dos métodos dependiendo de si tienes BLTouch/ABL o no:

{% tabs %}
{% tab title="Con BLTouch / ABL — Método Z-Booking" %}
Este método usa el sensor ABL para hacer un home "falso" de Z sobre un objeto plano colocado encima de la pieza:

1. **Ten el botón de parada de emergencia a mano en todo momento**.
2. Coloca un objeto **rígido, plano y fino** (un libro de tapa dura, una lámina metálica) encima de tu impresión. El BLTouch necesita apoyarse en él.
3. Ejecuta `G28 X Y` para hacer home solo en X e Y.
4. Ejecuta `G28 Z` (o "Home Z" desde la UI). El sensor tocará el libro, no la cama. Klipper cree que ha hecho home en Z, pero en realidad está sobre tu pieza.
5. Retira el objeto con cuidado.
6. Amplía el timeout para trabajar sin prisa: `IDLE_TO_70MIN`
7. Mueve el cabezal cerca de la última capa usando `FORCE_MOVE_Z DISTANCE=-XX` (valores pequeños, verifica visualmente con un papel).
8. Cuando el papel roza la boquilla con algo de fricción, estás en la altura correcta.
9. Establece la altura real: `RESCUE_Z Z=42.4` (usa tu medida).
   {% endtab %}

{% tab title="Sin ABL — SET\_KINEMATIC\_POSITION directo" %}
Si no tienes sensor ABL o prefieres el método directo:

1. Haz home en X e Y: `G28 X Y` (nunca en Z).
2. Mueve el cabezal manualmente sobre la pieza y baja en pequeños incrementos hasta estar a \~0.2 mm de la última capa.
3. Engaña a Klipper sobre la posición Z:

```
SET_KINEMATIC_POSITION Z=42.4
```

*Sustituye 42.4 por tu altura medida.* Klipper "cree" que está en esa altura y ya puedes moverte con seguridad.

O usa la macro de rescate:

```
RESCUE_Z Z=42.4
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

#### Paso 3 — Editar el G-Code

Aquí ocurre la "magia". Descarga el archivo `.gcode` desde Mainsail (sección **G-CODE FILES**) y ábrelo con un editor de texto (VS Code, Notepad++):

**3.1 — Encontrar la altura**

Usa `Ctrl+F` para buscar el valor de Z donde falló la impresión. Si la altura es 42.4 mm, busca `Z42.4`, `Z42.39`, etc., hasta encontrar la línea exacta o la más cercana por debajo.

**3.2 — Eliminar el G-code ya impreso**

Borra todo desde el inicio hasta justo antes de la capa donde se quedó. **Mantén** únicamente:

* La llamada al macro de inicio (la cambiarás en el siguiente punto)
* El G-code desde la última capa hacia el final

**3.3 — Sustituir el macro de inicio**

Cambia la llamada a `START_PRINT` por `START_PRINT_RESCUE`:

```
; Antes:
START_PRINT BED_TEMP=60 EXTRUDER_TEMP=210

; Después:
START_PRINT_RESCUE BED_TEMP=60 EXTRUDER_TEMP=210 MESH=impresion_actual
```

**3.4 — Corregir el contador de extrusión**

{% hint style="warning" %}
**Crítico si tu laminador usa extrusión absoluta (la mayoría: Cura, OrcaSlicer, etc.)**

Si empiezas en mitad del archivo, el G-code tendrá algo como `G1 E1500.5`. Si tu impresora cree que está en `E0`, intentará empujar 1.5 metros de filamento de golpe.

**Solución**: Justo antes de la primera línea de impresión, añade:

```
G92 E1500.5 ; Sustituye 1500.5 por el valor E de la línea donde empiezas
```

{% endhint %}

**3.5 — Restaurar el ventilador**

Busca el último `M106 S...` antes del punto de reinicio e insértalo después del `G92 E` anterior. Alternativamente, ajústalo manualmente desde la UI antes de imprimir.

**3.6 — Limpiar la malla activa**

Para evitar conflictos con cualquier malla cargada previamente, añade al inicio del G-code editado:

```
BED_MESH_CLEAR
```

**3.7 — Bloque de seguridad para el movimiento inicial**

Esto evita que el cabezal se mueva en línea recta desde su posición actual hasta el primer punto de la capa (riesgo de colisión lateral):

```gcode
G91             ; coordenadas relativas
G1 Z5 F600      ; sube 5 mm por seguridad
G90             ; coordenadas absolutas
G1 X... Y...    ; mueve a la posición XY de inicio de la capa (mira el G-Code)
G1 Z...         ; baja a la altura de la capa de rescate
```

{% endstep %}

{% step %}

#### Paso 4 — Reinicio de impresión seguro

1. Calienta el nozzle a temperatura de impresión.
2. Limpia bien la punta de cualquier resto de filamento.
3. Carga el archivo G-code modificado e inicia la impresión.
4. **Vigila los primeros minutos** para asegurarte de que la nueva capa se adhiere correctamente a la impresión existente y no hay desplazamiento.
   {% endstep %}
   {% endstepper %}

***

## Método alternativo — Reslicear con 0 capas inferiores

Si conservas el proyecto de tu laminador (archivo de Cura, OrcaSlicer, etc.), este método puede ser más limpio que editar el G-code:

1. En el laminador, baja el objeto en el eje Z hasta que el inicio de la pieza quede en la altura exacta donde falló. Ejemplo: si falló a 36.95 mm, el objeto debe estar 36.95 mm por debajo de la cama (Z negativo).
2. **Elimina las capas inferiores** (Bottom Layers = 0 en Cura: sección Top/Bottom → Bottom Thickness).
3. Lamina normalmente.
4. En el G-code generado, sustituye `START_PRINT` por `START_PRINT_RESCUE` (como en el paso 3.3).
5. En la impresora, sigue el proceso de los pasos 1 y 2 para establecer la posición Z.
6. En el paso final, usa `SET_Z0` en lugar de `RESCUE_Z` (porque el nuevo G-code empieza en Z=0 relativo).

{% hint style="info" %}
Este método puede dar problemas si el infill o los perímetros no se alinean exactamente con la impresión existente. Para piezas funcionales o con geometría compleja, el método de edición de G-code suele dar mejores resultados.
{% endhint %}

***

## Referencias y recursos

{% embed url="<https://www.youtube.com/watch?v=-wjE8eDiKWg>" %}
CNC Kitchen — HOW TO: Resume a failed 3D print
{% endembed %}

{% embed url="<https://www.youtube.com/watch?v=kwywIc7wUn4>" %}
Emily The Engineer — How to Resume an Unfinished/Failed 3D Print
{% endembed %}

* [Documentación Klipper — SET\_KINEMATIC\_POSITION](https://www.klipper3d.org/G-Codes.html#set_kinematic_position)
* [Documentación Klipper — idle\_timeout](https://www.klipper3d.org/Config_Reference.html#idle_timeout)
* [Documentación Klipper — force\_move](https://www.klipper3d.org/Config_Reference.html#force_move)
