<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>物联网 &#8211; Tishonの小窝</title>
	<atom:link href="https://blog.tishon.top/tag/%e7%89%a9%e8%81%94%e7%bd%91/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.tishon.top</link>
	<description>~肘跟我进窝~</description>
	<lastBuildDate>Tue, 25 Aug 2026 18:04:54 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://blog.tishon.top/wp-content/uploads/2026/08/cropped-图层-1-拷贝-32x32.png</url>
	<title>物联网 &#8211; Tishonの小窝</title>
	<link>https://blog.tishon.top</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>基于ESP32与ADXL345的Marlin共振补偿(Input Shaping)全自动校准系统1.0.0</title>
		<link>https://blog.tishon.top/marlin-auto-inputshaper-esp32/</link>
					<comments>https://blog.tishon.top/marlin-auto-inputshaper-esp32/#respond</comments>
		
		<dc:creator><![CDATA[Tishon]]></dc:creator>
		<pubDate>Tue, 25 Aug 2026 18:04:20 +0000</pubDate>
				<category><![CDATA[3D打印]]></category>
		<category><![CDATA[嵌入式开发]]></category>
		<category><![CDATA[物联网项目]]></category>
		<category><![CDATA[3D打印机]]></category>
		<category><![CDATA[ADXL345]]></category>
		<category><![CDATA[c/c++]]></category>
		<category><![CDATA[ESP32]]></category>
		<category><![CDATA[marlin]]></category>
		<category><![CDATA[物联网]]></category>
		<category><![CDATA[调试]]></category>
		<guid isPermaLink="false">https://blog.tishon.top/?p=316</guid>

					<description><![CDATA[引言 3D打印机在高速打印时，运动部件的惯性激发的机械共振会严重影响打印质量——表面出现“涟漪纹”（VFA，即 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">引言</h1>



<p class="wp-block-paragraph">3D打印机在高速打印时，运动部件的惯性激发的机械共振会严重影响打印质量——表面出现“涟漪纹”（VFA，即垂直表面伪影），甚至导致层错位。Marlin固件从 2.0 版本开始引入&nbsp;<strong>M593</strong>&nbsp;命令，允许用户为 X/Y 轴设置共振频率，通过主动调整运动规划来抑制共振。但问题的关键在于：<strong>如何准确测得这组频率？</strong></p>



<p class="wp-block-paragraph">传统的做法是使用“共振补偿校准”插件（如 Klipper 的&nbsp;<code>shaper_calibrate</code>），但需要额外的硬件（如加速度计）和复杂接线。本文介绍一套基于&nbsp;<strong>ESP32</strong>&nbsp;的便携式共振检测装置，它通过 ADXL345 加速度计采集振动信号，自动执行扫频 G 代码，利用 FFT 分析找到共振峰，并将结果直接写入 Marlin 的 EEPROM 或发送 M593 指令。更重要的是，它自带 Web 界面，支持实时波形显示、参数调整、G 代码生成，甚至可以一键完成“扫描 → 分析 → 写入”的全流程。</p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots"/>



<h1 class="wp-block-heading">系统架构</h1>



<h2 class="wp-block-heading">硬件组成</h2>



<ul class="wp-block-list">
<li><strong>主控</strong>：ESP32 (支持 WiFi/蓝牙，双核，大容量 Flash)</li>



<li><strong>加速度计</strong>：ADXL345 (I2C 接口，可测 ±16g，采样率 400Hz)</li>



<li><strong>显示屏</strong>：0.96 寸 OLED (SSD1306, 128×64，可选)</li>



<li><strong>供电</strong>：通过 USB 或 3.3V 供电</li>



<li><strong>连接方式</strong>：WiFi STA 或 AP 模式，与打印机同网络通信（HTTP 协议）</li>
</ul>



<h2 class="wp-block-heading">软件框架</h2>



<p class="wp-block-paragraph"><strong>传感器驱动</strong>：ADXL345 的初始化与数据读取，通过 I²C 总线（GPIO21/22）与 ESP32 通信。</p>



<p class="wp-block-paragraph"><strong>FFT 分析</strong>：使用&nbsp;<code>arduinoFFT</code>&nbsp;库，对&nbsp;<strong>256 点</strong>&nbsp;采样（400Hz 采样率）做&nbsp;<strong>1024 点 FFT</strong>（零填充），频率分辨率约&nbsp;<strong>0.39Hz</strong>。峰值检测结合了 SNR（信噪比）、Q 因子和相对幅值的综合置信度评分，确保结果可靠。</p>



<p class="wp-block-paragraph"><strong>运动检测</strong>：计算加速度矢量的 RMS 偏差，判断打印机是否处于运动状态。阈值可通过 Web 界面调整，并支持自动校准。</p>



<p class="wp-block-paragraph"><strong>状态机</strong>：管理校准流程的三段式推进：</p>



<ul class="wp-block-list">
<li><code>INIT_WAITING</code>：等待 INIT.GCO 执行完毕，打印机归位并移动到起始位置</li>



<li><code>SWEEPING</code>：SWEEP.GCO 扫频执行中，持续采集 FFT 数据</li>



<li><code>FINISH_WAITING</code>：FINISH.GCO 归位完成后，计算共振频率</li>
</ul>



<p class="wp-block-paragraph"><strong>G 代码生成与上传</strong>：</p>



<ul class="wp-block-list">
<li><strong>INIT.GCO</strong>：归位 → 移动到热床中心 → 抬升 Z 轴 → 切换到相对坐标</li>



<li><strong>SWEEP.GCO</strong>：纯扫频运动（不含归位指令，避免与 INIT/FINISH 重复）</li>



<li><strong>FINISH.GCO</strong>：恢复绝对坐标 → 归位 → 关闭电机</li>
</ul>



<p class="wp-block-paragraph">三个文件通过 HTTP 分步上传至打印机 SD 卡，然后按顺序启动打印。</p>



<p class="wp-block-paragraph"><strong>Web 服务器</strong>：提供响应式控制面板（兼容手机/PC），使用 Chart.js 实时绘制加速度波形，支持一键校准、G 代码生成下载、噪声基底记录等完整功能。</p>



<p class="wp-block-paragraph"><strong>参数存储</strong>：</p>



<ul class="wp-block-list">
<li><strong>EEPROM</strong>：保存共振频率、WiFi 凭据、打印机 IP、运动阈值、热床尺寸、幅度阈值</li>



<li><strong>SPIFFS</strong>：保存 X/Y 轴的噪声基底数据（用于频谱抑制，提升信噪比）</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">核心原理</h1>



<h3 class="wp-block-heading">1. 扫频信号生成</h3>



<p class="wp-block-paragraph">为了激励打印机结构，我们让某个轴（X 或 Y）做正弦往复运动，等效频率由&nbsp;<strong>速度</strong>&nbsp;和&nbsp;<strong>移动距离</strong>&nbsp;决定：</p>



<pre class="wp-block-code"><code>f = v / (2 * travel * 60)</code></pre>



<p class="wp-block-paragraph">其中&nbsp;<code>v</code>&nbsp;是 G1 指令中的 F 参数（mm/min），<code>travel</code>&nbsp;是单次移动距离（mm）。通过从起始频率到结束频率逐步增加速度，生成一段扫频 G 代码。每个频率点执行若干完整周期，并在每个频率点后插入&nbsp;<code>G4 P800</code>&nbsp;暂停 800ms，等待机械运动彻底停止。</p>



<p class="wp-block-paragraph">我们通过改变运动速度来改变往复运动的频率。以下代码生成一段从&nbsp;<code>startFreq</code>&nbsp;到&nbsp;<code>endFreq</code>&nbsp;的扫频序列，每个频率点执行&nbsp;<code>CYCLES_PER_FREQ</code>&nbsp;个完整周期，并插入 800ms 暂停：</p>



<pre class="wp-block-code"><code>String generateSweepOnlyGCode(String axis, float &amp;startFreq, float &amp;endFreq, 
                              float stepFreq, float &amp;travel, float maxSpeed) {
    // 根据频率和行程计算速度 (mm/min)
    float v_min = 60 * travel * 2 * startFreq;
    float v_max = 60 * travel * 2 * endFreq;
    float v_step = 60 * travel * 2 * stepFreq;

    String gcode;
    gcode += "G91\n";   // 相对坐标

    for (float v = v_min; v &lt;= v_max; v += v_step) {
        float freq = v / (60 * travel * 2);
        for (int cycle = 0; cycle &lt; CYCLES_PER_FREQ; cycle++) {
            gcode += "G1 " + axis + String(travel) + " F" + String(v) + " ; ~" + String(freq, 2) + " Hz\n";
            gcode += "G1 " + axis + String(-travel) + " F" + String(v) + " ; ~" + String(freq, 2) + " Hz\n";
        }
        gcode += "G4 P800 ; pause for motion stop\n";   // 等待运动停止
    }
    return gcode;
}</code></pre>



<h3 class="wp-block-heading">2. 加速度信号采样与 FFT</h3>



<p class="wp-block-paragraph">在扫频过程中，ESP32 以 200Hz 采样率连续读取 ADXL345 的 X/Y 轴加速度。当检测到运动停止（RMS 低于阈值）且稳定 800ms 后，对最近的 128 个样本进行 FFT 分析。</p>



<pre class="wp-block-code"><code>void processFrequencySampling() {
    if (!freqSamplingActive) return;
    unsigned long now = micros();
    if (now - lastFreqSampleTime &lt; FREQ_SAMPLE_INTERVAL_US) return; // 5ms 间隔
    lastFreqSampleTime = now;

    sensors_event_t e;
    accel.getEvent(&amp;e);

    if (testAxis == "X") {
        freqDataX&#91;freqSampleCount] = e.acceleration.x;
        freqDataY&#91;freqSampleCount] = 0;
    } else if (testAxis == "Y") {
        freqDataX&#91;freqSampleCount] = 0;
        freqDataY&#91;freqSampleCount] = e.acceleration.y;
    } else { // XY
        freqDataX&#91;freqSampleCount] = e.acceleration.x;
        freqDataY&#91;freqSampleCount] = e.acceleration.y;
    }
    freqSampleCount++;

    if (freqSampleCount &gt;= FFT_SAMPLES) {  // FFT_SAMPLES = 128
        freqSamplingActive = false;
        // 接下来调用 analyzeFrequencyWithNoiseFloor 进行 FFT 分析
        // ...
    }
}</code></pre>



<h3 class="wp-block-heading">3. FFT 与峰值提取</h3>



<p class="wp-block-paragraph">对 128 个时域样本做零填充至 1024 点，加汉明窗，计算幅度谱。然后：</p>



<ul class="wp-block-list">
<li>抑制噪声基底（如有预记录的噪声基底，则从频谱中减去）</li>



<li>寻找前 10 个极大值点（避开直流分量），计算每个峰的置信度（综合考虑信噪比、Q 因子、相对幅值）</li>



<li>选取置信度最高的频率作为该频率点的共振频率</li>
</ul>



<pre class="wp-block-code"><code>float analyzeFrequencyWithNoiseFloor(float *data, int len, float samplingFreq, 
                                     float &amp;confidence, float &amp;altFreq, 
                                     const String&amp; axis, float &amp;peakAmplitude) {
    const int FFT_SIZE = 1024;
    const int HALF_FFT = FFT_SIZE / 2;

    // 去直流
    float mean = 0;
    for (int i = 0; i &lt; len; i++) mean += data&#91;i];
    mean /= len;
    for (int i = 0; i &lt; len; i++) {
        fftReal&#91;i] = data&#91;i] - mean;
        fftImag&#91;i] = 0.0;
    }
    for (int i = len; i &lt; FFT_SIZE; i++) {
        fftReal&#91;i] = 0.0;
        fftImag&#91;i] = 0.0;
    }

    // 加汉明窗 + FFT
    FFT.windowing(fftReal, FFT_SIZE, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.compute(fftReal, fftImag, FFT_SIZE, FFT_FORWARD);
    FFT.complexToMagnitude(fftReal, fftImag, FFT_SIZE);

    // 计算功率谱密度 (PSD)
    float psd&#91;HALF_FFT];
    float maxMag = 0;
    for (int i = 1; i &lt; HALF_FFT; i++) {
        psd&#91;i] = fftReal&#91;i] * fftReal&#91;i];
        if (psd&#91;i] &gt; maxMag) maxMag = psd&#91;i];
    }

    // 噪声基底抑制（如果有）
    if (noiseFloorEnabled) {
        float* floor = (axis == "X") ? noiseFloorX : noiseFloorY;
        bool valid = (axis == "X") ? noiseFloorValidX : noiseFloorValidY;
        if (valid) {
            for (int i = 1; i &lt; HALF_FFT &amp;&amp; i &lt; FFT_SAMPLES; i++) {
                psd&#91;i] = max(0.0f, psd&#91;i] - floor&#91;i]);
            }
        }
    }

    // 峰值检测（找极大值）
    struct Peak { int idx; float mag; };
    Peak peaks&#91;20];
    int peakCount = 0;
    for (int i = 3; i &lt; HALF_FFT - 3; i++) {
        if (psd&#91;i] &gt; psd&#91;i-1] &amp;&amp; psd&#91;i] &gt; psd&#91;i+1]) {
            // 合并邻近峰值
            // ...
        }
    }

    // 对每个峰值计算置信度（SNR、Q因子、相对幅值）
    float bestFreq = 0, bestConfidence = 0;
    for (int p = 0; p &lt; peakCount &amp;&amp; p &lt; 10; p++) {
        int idx = peaks&#91;p].idx;
        float freq = idx * samplingFreq / FFT_SIZE;
        if (freq &lt; 5.0 || freq &gt; 100.0) continue;

        float snr = calculateSNR(psd, HALF_FFT, idx, 5);
        float qFactor = calculateQFactor(psd, idx, samplingFreq, FFT_SIZE);
        float confidence_score = min(snr / 10.0f, 1.0f) * 0.5f +
                                 min(qFactor / 5.0f, 1.0f) * 0.3f +
                                 min(peaks&#91;p].mag / maxMag, 1.0f) * 0.2f;
        if (confidence_score &gt; bestConfidence) {
            bestFreq = freq;
            bestConfidence = confidence_score;
        }
    }
    confidence = bestConfidence;
    return (confidence &gt; 0.5f) ? bestFreq : 0;
}</code></pre>



<h3 class="wp-block-heading">4. 幅频曲线与最终共振频率</h3>



<p class="wp-block-paragraph">扫频过程产生一系列离散频率点及对应的振幅（FFT 峰值幅值）。最后，使用二次插值（抛物线拟合）在最大振幅点附近插值，得到更精确的共振频率。</p>



<h3 class="wp-block-heading">5. 写入打印机</h3>



<p class="wp-block-paragraph">得到频率后，自动发送&nbsp;<code>M593 X Fxx.x</code>（或 Y）命令给打印机，同时存入 EEPROM 以便断电记忆。</p>



<h1 class="wp-block-heading">运动检测与状态机</h1>



<h3 class="wp-block-heading">运动检测（非阻塞）</h3>



<p class="wp-block-paragraph">计算加速度矢量 RMS 偏差，判断是否运动：</p>



<pre class="wp-block-code"><code>void updateMotionState() {
    if (!resonanceTesting) { isMoving = false; return; }
    if (!motionDetectionEnabled) { isMoving = true; lastMotionTime = millis(); return; }

    const int samples = MOTION_SAMPLES_TOTAL;  // 20
    float diffs&#91;samples];
    float sum = 0;
    for (int i = 0; i &lt; samples; i++) {
        sensors_event_t e;
        accel.getEvent(&amp;e);
        float total = sqrt(e.acceleration.x*e.acceleration.x + 
                           e.acceleration.y*e.acceleration.y + 
                           e.acceleration.z*e.acceleration.z);
        diffs&#91;i] = total - GRAVITY;
        sum += diffs&#91;i];
        delayMicroseconds(100);  // 100us 间隔，总体约 2ms
    }
    float mean = sum / samples;
    float sqSum = 0;
    for (int i = 0; i &lt; samples; i++) {
        float dev = diffs&#91;i] - mean;
        sqSum += dev * dev;
    }
    float rms = sqrt(sqSum / samples);
    bool nowMoving = (rms &gt; motionThreshold);
    if (nowMoving) lastMotionTime = millis();
    isMoving = nowMoving;
}</code></pre>



<h3 class="wp-block-heading">校准状态机（三段式）</h3>



<p class="wp-block-paragraph">在&nbsp;<code>loop()</code>&nbsp;中，我们根据当前相位推进流程：</p>



<pre class="wp-block-code"><code>// 在 loop() 中
if (resonanceTesting &amp;&amp; calibrationMode) {
    switch (calibPhase) {
        case INIT_WAITING:
            if (!isMoving) {
                if (phaseStableStart == 0) phaseStableStart = millis();
                if (millis() - phaseStableStart &gt; STABLE_DELAY_MS) {
                    // 启动扫频文件
                    if (startPrint("SWEEP.GCO")) {
                        calibPhase = SWEEPING;
                        phaseStartTime = millis();
                        phaseStableStart = 0;
                    }
                }
            } else {
                phaseStableStart = 0;
            }
            break;

        case SWEEPING:
            if (!isMoving) {
                if (phaseStableStart == 0) phaseStableStart = millis();
                else {
                    unsigned long stableTime = millis() - phaseStableStart;
                    // 稳定时间达到频率间隔阈值，记录该频率点
                    if (stableTime &gt;= PER_FREQ_STABLE_DELAY &amp;&amp; !freqEndProcessed) {
                        // 记录 lastFx/lastFy 和 lastAmpX/lastAmpY 到 calib 数组
                        // 清空历史平均，准备下一频率
                        freqEndProcessed = true;
                    }
                    // 若稳定时间超过扫频结束超时，则启动结束文件
                    if (stableTime &gt;= SWEEP_END_TIMEOUT) {
                        if (startPrint("FINISH.GCO")) {
                            calibPhase = FINISH_WAITING;
                            phaseStartTime = millis();
                        }
                    }
                }
            } else {
                phaseStableStart = 0;
                freqEndProcessed = false;
            }
            break;

        case FINISH_WAITING:
            // 类似，等待归位完成
            break;

        case RESULT:
            // 计算共振频率并发送 M593
            break;
    }
}</code></pre>



<h2 class="wp-block-heading">噪声基底抑制（提升信噪比）</h2>



<p class="wp-block-paragraph">记录静态噪声时，我们多次做 FFT 并平均功率谱，保存到 SPIFFS：</p>



<pre class="wp-block-code"><code>void saveNoiseFloorToSPIFFS(const String&amp; axis) {
    File f = SPIFFS.open((axis == "X") ? "/noise_x.bin" : "/noise_y.bin", FILE_WRITE);
    if (!f) return;
    float* data = (axis == "X") ? noiseFloorX : noiseFloorY;
    f.write((uint8_t*)data, FFT_SAMPLES * sizeof(float));
    f.close();
}

void processNoiseCalibration() {
    // 采集 FFT_SAMPLES 个样本，做 FFT，累加功率谱到 accum
    // 当 noiseSampleCount 达到 NOISE_FFT_TOTAL 后，平均并保存
}</code></pre>



<h2 class="wp-block-heading">Web 接口与数据交互</h2>



<p class="wp-block-paragraph">后端暴露了多个 REST API，以下是数据返回格式（<code>/data</code>&nbsp;端点）：</p>



<pre class="wp-block-code"><code>void handleData() {
    StaticJsonDocument&lt;256&gt; doc;
    doc&#91;"freqX"] = currentFreqX;
    doc&#91;"freqY"] = currentFreqY;
    doc&#91;"moving"] = isMoving;
    doc&#91;"testing"] = resonanceTesting;
    doc&#91;"calibration"] = calibrationMode;
    doc&#91;"phaseProgress"] = phaseProgress;   // 0~100
    // 相位字符串
    switch (calibPhase) {
        case INIT_WAITING:   doc&#91;"calibPhase"] = "INIT_WAITING"; break;
        case SWEEPING:       doc&#91;"calibPhase"] = "SWEEPING"; break;
        // ...
    }
    sendJson(doc);
}</code></pre>



<h2 class="wp-block-heading">校准结果计算（幅频曲线插值）</h2>



<p class="wp-block-paragraph">在扫频结束后，我们从记录的所有&nbsp;<code>(频率, 幅值)</code>&nbsp;点中找出最大幅值，并做二次插值得到精确共振频率：</p>



<pre class="wp-block-code"><code>float calculateResonanceFreq(float* freqs, float* amps, int count) {
    if (count &lt; 3) return 0;
    int maxIdx = 0;
    for (int i = 1; i &lt; count; i++) {
        if (amps&#91;i] &gt; amps&#91;maxIdx]) maxIdx = i;
    }
    // 二次插值
    if (maxIdx &gt; 0 &amp;&amp; maxIdx &lt; count - 1) {
        float a = amps&#91;maxIdx-1], b = amps&#91;maxIdx], c = amps&#91;maxIdx+1];
        float denom = a - 2*b + c;
        if (fabs(denom) &gt; 1e-6) {
            float offset = (a - c) / (2 * denom);
            return freqs&#91;maxIdx] + offset * (freqs&#91;maxIdx+1] - freqs&#91;maxIdx]);
        }
    }
    return freqs&#91;maxIdx];
}</code></pre>



<h1 class="wp-block-heading">使用指南</h1>



<h2 class="wp-block-heading">硬件连接</h2>



<ul class="wp-block-list">
<li>ADXL345：VCC→3.3V，GND→GND，SDA→GPIO21，SCL→GPIO22。</li>



<li>OLED（可选）：SDA→GPIO21，SCL→GPIO22（与加速度计共享 I²C 总线）。</li>



<li>将 ESP32 靠近打印机，最好固定在热床上（或专用支架上）。</li>
</ul>



<h2 class="wp-block-heading">初次上电</h2>



<ul class="wp-block-list">
<li>ESP32 默认开启 AP 模式，SSID 为&nbsp;<code>ResonanceMeasurer</code>，密码&nbsp;<code>12345678</code>。</li>



<li>用手机/电脑连接该 WiFi，浏览器访问&nbsp;<code>192.168.4.1</code>。</li>



<li>在页面中设置打印机 IP（打印机需在同一局域网且已开启 WiFi 模块，端口 80）。</li>



<li>点击“连接”测试通信，自动读取固件信息（需支持&nbsp;<code>[ESP800]</code>&nbsp;命令）。</li>



<li>输入热床尺寸和安全 Z 高度（保存后生效）。</li>
</ul>



<h2 class="wp-block-heading">执行校准</h2>



<ul class="wp-block-list">
<li>选择测试轴（X 或 Y），设置扫频参数（建议起始 5~10Hz，结束 80~100Hz，步进 2Hz，移动距离 10~20mm，最大速度根据打印机能力）。</li>



<li>点击“一键校准”，系统自动完成全部流程。</li>



<li>校准过程中可观察实时频率和进度条，结束后自动发送 M593，频率结果会保存到 EEPROM。</li>
</ul>



<h2 class="wp-block-heading">其他功能</h2>



<ul class="wp-block-list">
<li><strong>测试传感器</strong>：只打开加速度计监测，不驱动打印机，适合手动检查振动。</li>



<li><strong>手动发送 G 代码</strong>：在文本框中输入任意 G 代码，可直接发送给打印机（用于调试）。</li>



<li><strong>噪声基底记录</strong>：在打印机完全静止时点击“记录噪声基底”，可提高后续分析的抗干扰能力。</li>



<li><strong>幅度阈值校准</strong>：自动设定信号有效的最小峰峰值，避免噪声被误判为共振。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots"/>



<h1 class="wp-block-heading">总结</h1>



<p class="wp-block-paragraph">这套 ESP32 共振补偿校准仪，将复杂的振动检测与 Marlin 校准流程封装成简便的一键操作。它不仅具备专业仪器的精度，还拥有友好的 Web 界面和丰富的辅助功能，让普通创客也能轻松完成高速打印的共振调校。代码全部开源，可根据自身打印机型号微调参数，是 3D 打印爱好者提升打印品质的得力工具。</p>



<div style="height:49px" aria-hidden="true" class="wp-block-spacer"></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><em>完整的项目代码可在 [<a href="https://github.com/TishonL/Marlin-Auto-InputShaper-ESP32">TishonL/Marlin-Auto-InputShaper-ESP32: 一键自动校准 3D 打印机共振频率，基于 Marlin + ESP32 + ADXL345 实现 Input Shaping 自动调谐</a>] 获取，欢迎 star 和 issue。</em></p>
</blockquote>
</blockquote>



<div class="wp-block-argon-github github-info-card card shadow-sm github-info-card-full" data-author="TishonL" data-project="Marlin-Auto-InputShaper-ESP32"><div class="github-info-card-header"><a href="https://github.com/" target="_blank" title="Github" rel="noopener"><span><i class="fa fa-github"></i> GitHub</span></a></div><div class="github-info-card-body"><div class="github-info-card-name-a"><a href="https://github.com/TishonL/Marlin-Auto-InputShaper-ESP32" target="_blank" rel="noopener"><span class="github-info-card-name">TishonL/Marlin-Auto-InputShaper-ESP32</span></a></div><div class="github-info-card-description"></div></div><div class="github-info-card-bottom"><span class="github-info-card-meta github-info-card-meta-stars"><i class="fa fa-star"></i> <span class="github-info-card-stars"></span></span><span class="github-info-card-meta github-info-card-meta-forks"><i class="fa fa-code-fork"></i> <span class="github-info-card-forks"></span></span></div></div>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tishon.top/marlin-auto-inputshaper-esp32/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
