Files
OrcaSlicer/doc/developer-reference/Time_Estimation_Supplementary_Analysis.md
xiaoyeliu b43cfaaaf9 2.2.0 flutter & WCP & Network Test (#54)
* Add docs about time_estimate

* Fix: Problems with graceful program exit caused by Flutter refactoring

* Add: sw_OpenBrowser() & sw_OpenOrcaWebview

* Fix: NetworkTestDialog Crash & Add: Lan Device test \ cloud test
2025-12-09 10:39:27 +08:00

16 KiB
Raw Blame History

时间预估补充问题分析

文档版本: v1.0 创建日期: 2025-12-06 问题来源: M109/M190时间预估修复方案的补充问题


问题1挤出最大加速度 vs E最大加速度的区别

1.1 配置参数定义

位置: src/libslic3r/PrintConfig.cpp:3640-36823734-3744

machine_max_acceleration_eE轴最大加速度

// Line 3666: 通过循环自动生成 machine_max_acceleration_e
def = this->add("machine_max_acceleration_" + axis.name, coFloats);
// 对于E轴
// - 默认值:{ 5000., 5000. } mm/s²
// - 对应固件命令M201 E5000
// - 定义E轴电机的最大加速度

说明:

  • 物理含义: E轴挤出机电机的硬件物理限制
  • 固件命令: M201 E5000 - 设置E轴最大加速度
  • 作用范围: 限制E轴电机本身的加速度无论是打印、回抽还是其他动作
  • 默认值: 5000 mm/s²非常高因为E轴质量小电机响应快

machine_max_acceleration_extruding挤出时最大加速度

// Line 3734
def = this->add("machine_max_acceleration_extruding", coFloats);
def->full_label = L("Maximum acceleration for extruding");
def->tooltip = L("Maximum acceleration for extruding (M204 P)");
def->set_default_value(new ConfigOptionFloats{ 1500., 1250. });

说明:

  • 物理含义: 打印移动(挤出动作)时的最大加速度限制
  • 固件命令: M204 P1500 - 设置打印时最大加速度
  • 作用范围: 仅限于打印移动extrusion moves即XYZ+E同时移动的情况
  • 默认值: 1500 mm/s²比E轴最大加速度低很多

1.2 核心区别

特性 machine_max_acceleration_e machine_max_acceleration_extruding
固件命令 M201 E5000 M204 P1500
作用对象 E轴电机 打印移动XYZ+E
物理含义 电机硬件限制 打印质量限制
默认值 5000 mm/s² 1500 mm/s²
影响范围 E轴所有动作 仅打印时
限制原因 电机性能 打印质量、振动、层粘合

1.3 为什么extruding加速度更低

  1. 打印质量考虑

    • 高加速度会导致振动ringing/ghosting
    • 影响外壁质量和尺寸精度
    • 可能导致层间粘合问题
  2. 机械限制

    • XYZ轴移动的惯性更大
    • 打印头/打印床的质量较大
    • 需要考虑整机的刚性
  3. 挤出一致性

    • 高加速度会导致挤出量不均匀
    • 影响压力提前pressure advance效果
    • 可能产生过挤/欠挤

1.4 在时间预估中的使用

位置: src/libslic3r/GCode/GCodeProcessor.cpp

// Line 1002-1014: 加载配置
const ConfigOptionFloats* max_acceleration_extruding =
    config.option<ConfigOptionFloats>("machine_max_acceleration_extruding");
if (max_acceleration_extruding != nullptr)
    m_time_processor.machine_limits.machine_max_acceleration_extruding.values =
        max_acceleration_extruding->values;

// E轴加速度通过循环加载Line 1028-1042中的类似代码

使用场景:

  • machine_max_acceleration_e: 在jerk计算时限制E轴的加速度
  • machine_max_acceleration_extruding: 在打印移动时作为加速度上限

问题2Jerk如何影响预估时间的计算

2.1 Jerk的定义

Jerk加加速度: 加速度的变化率,单位 mm/s

在3D打印中jerk实际上被用作瞬时速度变化的限制,而不是严格意义上的加加速度。

2.2 Jerk配置参数

位置: src/libslic3r/PrintConfig.cpp:3684-3700

def = this->add("machine_max_jerk_" + axis.name, coFloats);
// 默认值:
// X轴10 mm/s
// Y轴10 mm/s
// Z轴0.2 mm/s很小因为Z轴移动慢
// E轴2.5 mm/s

对应固件命令: M205 X10 Y10 Z0.2 E2.5

2.3 Jerk在时间预估中的作用

位置: src/libslic3r/GCode/GCodeProcessor.cpp:2845-2929

作用1: 限制安全速度Safe Feedrate

// Line 2845-2849
for (unsigned char a = X; a <= E; ++a) {
    float axis_max_jerk = get_axis_max_jerk(..., static_cast<Axis>(a));
    if (curr.abs_axis_feedrate[a] > axis_max_jerk)
        curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
}

含义:

  • 每个轴的移动速度不能超过该轴的jerk限制
  • 如果某个轴的速度超过jerk降低整体移动的安全速度
  • 这是单轴独立限制

作用2: 计算连接速度Junction Velocity

// Line 2873-2884: 计算XYZ轴的jerk向量
Vec3f entry_v = block.feedrate_profile.cruise * (curr.enter_direction);
Vec3f exit_v = prev.feedrate * (prev.exit_direction);
Vec3f jerk_v = entry_v - exit_v;  // 速度变化向量
jerk_v = Vec3f(abs(jerk_v.x()), abs(jerk_v.y()), abs(jerk_v.z()));
Vec3f max_xyz_jerk_v = get_xyz_max_jerk(...);

// 检查是否超过jerk限制
for (size_t i = 0; i < 3; i++) {
    if (jerk_v[i] > max_xyz_jerk_v[i]) {
        v_factor *= max_xyz_jerk_v[i] / jerk_v[i];  // 计算降速系数
        limited = true;
    }
}

含义:

  • 计算从上一个移动到当前移动的速度变化
  • 如果速度变化超过jerk限制降低连接速度
  • 这是XYZ组合限制

作用3: E轴独立jerk计算

// Line 2901-2921: 计算E轴的jerk
float jerk = (v_exit > v_entry) ?
    (((v_entry > 0.0f) || (v_exit < 0.0f)) ?
        (v_exit - v_entry) :      // 同向减速
        std::max(v_exit, -v_entry)) :  // 反向
    (((v_entry < 0.0f) || (v_exit > 0.0f)) ?
        (v_entry - v_exit) :      // 同向加速
        std::max(-v_exit, v_entry));   // 反向

float axis_max_jerk = get_axis_max_jerk(..., static_cast<Axis>(a));
if (jerk > axis_max_jerk) {
    v_factor *= axis_max_jerk / jerk;  // 降速
    limited = true;
}

含义:

  • E轴的jerk单独计算
  • 区分同向运动coasting和反向运动reversal
  • 反向运动的jerk更严格

2.4 Jerk对时间的影响

影响机制:

  1. 降低连接速度 → 增加加速/减速时间

    示例:
    - 无jerk限制连接速度100 mm/s
    - 有jerk限制连接速度降至50 mm/s
    - 结果:需要更长的加速/减速时间
    
  2. 降低巡航速度 → 增加总移动时间

    示例:
    - 目标速度150 mm/s
    - jerk限制导致入口速度30 mm/s
    - 结果:加速段更长,可能无法达到目标速度
    
  3. 影响梯形速度曲线

    无jerk限制
    ┌─────────┐  (平顶梯形)
    │         │
    │         │
    └         └
    
    有jerk限制
      ┌───┐      (尖顶三角形或低平顶)
            ╲
    └       └
    

2.5 实际计算示例

场景: 直角转弯90度

前一移动X方向 100 mm/s
当前移动Y方向 100 mm/s
X轴jerk限制10 mm/s
Y轴jerk限制10 mm/s

计算:
- X轴速度变化100 mm/s → 0 mm/s = 100 mm/s
- Y轴速度变化0 mm/s → 100 mm/s = 100 mm/s
- 超过jerk限制需要降速

降速系数:
- X轴10 / 100 = 0.1
- Y轴10 / 100 = 0.1
- 最终连接速度100 * 0.1 = 10 mm/s

时间影响:
- 如果没有jerk限制可能以50 mm/s通过转角
- 有jerk限制只能以10 mm/s通过转角
- 需要从100减速到10再从10加速到100
- 增加的时间:约 (90/加速度) 秒

问题3换料gcode中的M109指令是否会被统计

3.1 换料gcode的处理流程

位置: src/libslic3r/GCode.cpp:903-918

if (line == "[change_filament_gcode]") {
    // BBS
    if (!m_single_extruder_multi_material) {
        extruder_offset = m_extruder_offsets[tcr.new_tool].cast<float>();

        // If the extruder offset changed, add an extra move
        if (extruder_offset != m_extruder_offsets[tcr.initial_tool].cast<float>()) {
            std::ostringstream oss;
            oss << std::fixed << std::setprecision(3)
                << "G1 X" << transformed_pos.x() - extruder_offset.x()
                << " Y" << transformed_pos.y() - extruder_offset.y()
                << "\n";
            gcode_out += oss.str();
        }
    }
}

说明:

  • [change_filament_gcode]是一个特殊标记
  • 在WipeTower中使用src/libslic3r/GCode/WipeTower.cpp:1013
  • 标记换料gcode的插入位置

3.2 换料gcode的生成

位置: src/libslic3r/GCode.cpp:6590-6597

// Process the custom change_filament_gcode.
const std::string& change_filament_gcode = m_config.change_filament_gcode.value;

//Orca: Ignore change_filament_gcode if is the first call for a tool change
//      and manual_filament_change is enabled
if (!change_filament_gcode.empty() &&
    !(m_config.manual_filament_change.value && m_toolchange_count == 1)) {

    toolchange_gcode_parsed = placeholder_parser_process(
        "change_filament_gcode", change_filament_gcode, extruder_id, &dyn_config);
}

说明:

  • change_filament_gcode是用户配置的自定义换料脚本
  • 通过placeholder_parser_process处理占位符如温度、喷头ID等
  • 生成的gcode会被插入到最终的G-code文件中

3.3 M109是否会被统计

答案:会被统计

原因:

  1. 换料gcode被完整插入到G-code文件中

    // Line 507-597
    toolchange_gcode_str = gcodegen.placeholder_parser_process(
        "change_filament_gcode", change_filament_gcode, new_extruder_id, ...);
    
  2. GCodeProcessor会解析所有G-code行

    // GCodeProcessor::process_gcode_line() 会处理所有行
    // 包括change_filament_gcode中的M109
    
  3. M109会触发process_M109()函数

    • 位置:GCodeProcessor.cpp:3640-3655(当前实现)
    • 如果应用修复方案,会计算等待时间并调用simulate_st_synchronize()

3.4 示例

用户的换料gcode配置:

M109 S{new_filament_temp[next_extruder]}  ; 等待新工具温度
G1 E10 F300                                ; 挤出少量材料

生成的实际gcode假设温度220°C:

M109 S220  ; 等待新工具温度 ⬅️ 这行会被GCodeProcessor处理
G1 E10 F300

时间统计:

  • 当前实现: M109不会添加等待时间bug
  • 修复后: M109会计算等待时间
    • 如果有M104预热计算剩余等待时间可能0-20秒
    • 如果无预热计算完整等待时间可能20-40秒

3.5 注意事项

⚠️ 重要: 如果用户的换料gcode中有M109修复方案会统计这个时间

建议:

  1. 检查U1的默认change_filament_gcode配置
  2. 确认是否包含M109
  3. 如果包含,修复后时间估算会更准确
  4. 如果不包含,需要确认换料过程是否在其他地方等待温度

问题4GCode.cpp中的M400是否会被统计到时间如何计算

4.1 U1的M400使用场景

位置: src/libslic3r/GCode.cpp:6377-6380

// Snapmaker U1
std::string printer_model = this->m_curr_print->m_config.printer_model.value;
if (printer_model == "Snapmaker U1" && toolchange) {
    gcode += "M400\n";  // ⬅️ 注意:没有参数
}

使用场景:

  • 工具切换时toolchange = true
  • 仅限Snapmaker U1机型
  • 添加一个无参数的M400命令

4.2 M400的含义

固件行为: M400表示"Finish all moves"(完成所有移动)

  • 阻塞等待,直到运动缓冲区清空
  • 确保所有G1/G0移动都已完成
  • 类似于固件的st_synchronize()调用

4.3 M400的时间计算

位置: src/libslic3r/GCode/GCodeProcessor.cpp:3883-3891

void GCodeProcessor::process_M400(const GCodeReader::GCodeLine& line)
{
    float value_s = 0.0;
    float value_p = 0.0;
    if (line.has_value('S', value_s) || line.has_value('P', value_p)) {
        value_s += value_p * 0.001;  // P参数单位是毫秒
        simulate_st_synchronize(value_s);
    }
    // ⚠️ 注意如果没有S或P参数不会调用simulate_st_synchronize()
}

关键点:

  1. 有参数的M400(如M400 S1M400 P100

    • 会调用simulate_st_synchronize(value_s)
    • 添加额外的等待时间
    • 示例:M400 P100 → 添加0.1秒等待时间
  2. 无参数的M400(如M400\n

    • 不会调用simulate_st_synchronize()
    • 不会添加额外的等待时间
    • 只会触发现有移动块的完成(但这部分时间已经在移动块计算中)

4.4 U1的M400时间统计

答案U1的M400不会添加额外等待时间

原因:

  1. U1添加的是M400\n(无参数)
  2. process_M400()检测到无S和P参数
  3. 不会调用simulate_st_synchronize()
  4. 只会同步现有移动,不会添加额外时间

4.5 M400的实际作用

虽然不添加额外时间但M400仍然有重要作用

在时间估算中:

void GCodeProcessor::process_M400(const GCodeReader::GCodeLine& line)
{
    // ... 检查参数 ...

    // 即使没有参数也会触发TimeMachine处理当前的移动块
    // 确保所有pending的移动都被计算完成
}

效果:

  • 确保M400之前的所有移动块都被处理完成
  • 刷新时间估算的缓冲区
  • 但不添加额外的等待时间

4.6 对比:有参数 vs 无参数的M400

M400命令 添加等待时间 代码位置 用途
M400\n (U1) GCode.cpp:6379 同步移动缓冲区
M400 S1 1秒 - 等待1秒
M400 P100 0.1秒 GCode.cpp扫描模型:行号未显示 等待0.1秒

4.7 GCode.cpp中其他M400的使用

扫描模型场景(搜索结果中发现):

gcode += "M976 S1 P1 ; scan model before printing 2nd layer\n";
gcode += "M400 P100\n";  // ⬅️ 有P参数会添加0.1秒等待

说明:

  • 这个M400有P参数
  • 会添加0.1秒的等待时间
  • 用于扫描模型后的延迟

总结

问题1答案挤出加速度 vs E加速度

参数 作用 默认值
machine_max_acceleration_e E轴电机的物理限制 5000 mm/s²
machine_max_acceleration_extruding 打印时的质量限制 1500 mm/s²

关键区别: e是硬件限制extruding是打印质量限制

问题2答案Jerk的影响

影响方式:

  1. 限制单轴的安全速度
  2. 限制相邻移动的连接速度
  3. 降低连接速度 → 增加加速/减速时间 → 增加总打印时间

典型影响: 直角转弯时jerk限制会将连接速度从50-100 mm/s降至10 mm/s

问题3答案换料gcode中的M109

会被统计

  • 换料gcode会被完整插入到G-code文件
  • GCodeProcessor会解析所有行包括M109
  • 修复方案会计算M109的等待时间考虑预热

问题4答案U1的M400时间计算

不会添加额外时间

  • U1添加的是M400\n(无参数)
  • process_M400()只在有S或P参数时添加时间
  • U1的M400只同步移动缓冲区不添加等待时间

但其他M400可能会:

  • M400 P100扫描模型会添加0.1秒

建议

对于M109修复方案的建议

  1. 确认U1的change_filament_gcode配置

    • 检查是否包含M109
    • 如果包含,修复后会更准确
  2. M400不影响修复方案

    • U1的M400不添加时间
    • 修复方案可以正常实施
  3. Jerk配置建议

    • 检查U1的jerk配置是否合理
    • 如果时间估算仍有偏差可能是jerk配置问题

测试建议

  1. 验证换料gcode中的M109

    # 检查生成的G-code中换料部分的M109
    grep -A10 "T1" output.gcode | grep M109
    
  2. 验证M400不影响时间

    # 检查M400是否有参数
    grep "M400" output.gcode
    
  3. 验证jerk影响

    # 对比不同jerk配置下的时间估算