3dSynth

Tutorials / Custom G-code

Open in the interactive tutorials reader

---
title: Tutorial 40 Feedback Loops (Closed Loop Printing)
description: Making the printer smart enough to fix itself.
---

Tutorial 40 Feedback Loops (Closed Loop Printing)

1. Lesson Header

2. Concept Introduction

Open Loop vs Closed Loop.
Standard G-code is Open Loop: "Move X100" -> The printer assumes it moved 100mm.
If it hits a clamp or skips a step, it doesn't know.
Closed Loop adds sensors: "Move X100" -> Encoder says "Moved 99mm" -> "Move X1 more".

3. Machine State Explanation

The Feedback Signal.
- Encoders: Measure motor rotation.
- Filament Sensor: Measures diameter/movement.
- Probe (BLTouch): Measures Z height.
- Camera: Measures print failure (Spaghetti Detective).

4. Command Breakdown

5. Minimal Working Example

The Dynamic Z-Offset.
Probe the bed at (X, Y).
If Z < 0 (Bed is high), adjust G92 Z... or use M290 (Babystep).

6. Visual Representation

Interactive preview is available in the interactive reader.

7. Build Exercise

Task: Simulate a "Filament Width Compensator".
Imagine you have a sensor that reads filament diameter (1.75mm +/- 0.05).
Write a Python script that streams G-code but adjusts the E value based on a mock sensor reading.
Volume = Area * Length.
Area = PI * (Diameter/2)^2.
If Diameter drops to 1.70, Area decreases, so Length (E) must increase to maintain Volume.

Formula:
Factor = (1.75 / Measured_Diameter)^2.
New_E = Original_E * Factor.

8. Deep Insight Section

PID Tuning.
Temperature control (M301) is the most common closed loop.
Error = Target - Current.
Output = P*Error + I*Sum(Error) + D*Delta(Error).
You can implement PID for anything!
Example: Chamber Heater Control using a fan and a spare thermistor.

9. Common Failure Modes

  1. Oscillation: If your feedback loop is too aggressive (High P-term), the printer will shake violently trying to correct tiny errors.
  2. Sensor Noise: If your filament sensor reads "1.75, 1.60, 1.75" due to noise, your extruder will stutter. You need a Moving Average Filter.

10. Real-World Application

Non-Planar Ironing with Load Cells.
Some high-end machines measure the force on the nozzle.
If the force is too high (scratching), they lift Z.
If too low (air gap), they lower Z.
This allows perfect ironing on uneven surfaces.

11. Final Clean Version

The Compensator Script:

import random

nominal_d = 1.75
current_e = 0

def read_sensor():
    # Simulate noisy sensor
    return nominal_d + random.uniform(-0.05, 0.05)

def process_gcode_line(line):
    global current_e
    if "E" in line:
        # Parse E value
        parts = line.split()
        new_parts = []
        for p in parts:
            if p.startswith("E"):
                val = float(p[1:])
                # Calculate compensation
                d = read_sensor()
                factor = (nominal_d / d) ** 2
                
                # Assume relative E for simplicity
                compensated_e = val * factor
                new_parts.append(f"E{compensated_e:.5f}")
                print(f"Compensating: D={d:.2f}mm -> Factor={factor:.2f}")
            else:
                new_parts.append(p)
        return " ".join(new_parts)
    return line

# Test
gcode = ["G1 X10 E1", "G1 X20 E1", "G1 X30 E1"]
for l in gcode:
    print(process_gcode_line(l))

12. Stretch Challenge

Challenge: Implement Spaghetti Detection.
Write a script that takes a camera image (mock function get_image_darkness()).
If the image is too dark (print detached and covering lens?) or too static (not moving?), trigger M600 (Pause).
Hint: This usually requires Computer Vision (OpenCV), but you can simulate the logic.