Files
OrcaSlicer/doc/developer-reference/Time_Estimation_Detailed_Answers.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

475 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 补充问题的详细答案
> **日期**: 2025-12-06
> **问题来源**: 时间预估分析的进一步确认
---
## 问题1E最大加速度5000 vs 挤出最大加速度20000实际使用哪个
### 快速答案
**会使用5000**(取最小值)
### 详细分析
#### 配置场景
```
machine_max_acceleration_e = 5000 mm/s² (E轴电机硬件限制)
machine_max_acceleration_extruding = 20000 mm/s² (打印时加速度限制)
```
#### 代码执行流程
**位置**: `src/libslic3r/GCode/GCodeProcessor.cpp`
##### 步骤1: 初始化Line 770-773
```cpp
// Line 771: 读取machine_max_acceleration_extruding配置
float max_acceleration = get_option_value(
m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
// max_acceleration = 20000
// Line 772-773: 设置到machines[i]
m_time_processor.machines[i].max_acceleration = max_acceleration; // 20000
m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ?
max_acceleration : DEFAULT_ACCELERATION; // 20000
```
此时:`machines[i].acceleration = 20000`
##### 步骤2: 计算移动块加速度Line 2827-2838
```cpp
// Line 2827-2831: 获取基础加速度
float acceleration = get_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i));
// acceleration = 20000 (从machines[i].acceleration读取)
// 🔥 关键步骤Line 2834-2838
// 检查每个轴的最大加速度限制
for (unsigned char a = X; a <= E; ++a) {
float axis_max_acceleration = get_axis_max_acceleration(..., static_cast<Axis>(a));
// 对于E轴axis_max_acceleration = 5000
// 计算这个轴的实际加速度分量
// acceleration * |delta_pos[a]| / distance
if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration)
acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance);
// acceleration被降低以满足E轴限制
}
// Line 2840
block.acceleration = acceleration; // 最终加速度
```
##### 步骤3: get_axis_max_acceleration函数
**位置**: Line 4850-4862
```cpp
float GCodeProcessor::get_axis_max_acceleration(
PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
{
switch (axis)
{
case X: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, ...); }
case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, ...); }
case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, ...); }
case E: {
// 🔥 关键E轴返回machine_max_acceleration_e
return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, ...);
// 返回 5000
}
default: { return 0.0f; }
}
}
```
### 实际计算示例
**场景**打印移动XYZ+E同时运动
```
初始配置:
- machine_max_acceleration_extruding = 20000 mm/s²
- machine_max_acceleration_e = 5000 mm/s²
移动参数:
- 距离: 100mm
- XY移动: 99mm
- E挤出: 5mm
- inv_distance = 1/100 = 0.01
计算过程:
1. acceleration = 20000 (从extruding配置)
2. 检查E轴限制
- E轴分量加速度 = 20000 * 5 * 0.01 = 1000 mm/s²
- E轴最大 = 5000 mm/s²
- 1000 < 5000满足 ✓
3. 但如果E挤出量更大如30mm
- E轴分量加速度 = 20000 * 30 * 0.01 = 6000 mm/s²
- E轴最大 = 5000 mm/s²
- 6000 > 5000超限
- 调整acceleration = 5000 / (30 * 0.01) = 16666.7 mm/s²
4. 最终使用: 16666.7 mm/s² (被E轴限制降低)
```
### 结论
**多重限制机制**:
1. **初始限制**: `machine_max_acceleration_extruding`20000
2. **轴向限制**: 每个轴的`machine_max_acceleration_*`E轴5000
3. **最终结果**: 取决于移动的轴向分量
**简化规则**:
- 对于**纯E轴移动**(回抽/回退直接受E轴5000限制
- 对于**XYZ+E移动**(打印):
- 如果E分量小可能接近20000
- 如果E分量大会被降低以满足5000限制
- **实际加速度 ≤ min(20000, 5000/E轴比例)**
---
## 问题2Jerk怎么参与计算的
### 完整计算流程
#### 阶段1: 计算安全速度Safe Feedrate - Line 2842-2849
```cpp
// 初始化为巡航速度
curr.safe_feedrate = block.feedrate_profile.cruise; // 假设150 mm/s
// 🔥 检查每个轴的jerk限制
for (unsigned char a = X; a <= E; ++a) {
float axis_max_jerk = get_axis_max_jerk(..., static_cast<Axis>(a));
// X: 10 mm/s, Y: 10 mm/s, Z: 0.2 mm/s, E: 2.5 mm/s
if (curr.abs_axis_feedrate[a] > axis_max_jerk)
// 如果当前轴速度超过jerk降低安全速度
curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
}
// 示例:
// X轴速度: 120 mm/s > jerk 10 → safe_feedrate = 10 mm/s
// 最终: curr.safe_feedrate = 10 mm/s
```
**目的**: 限制当前块能够安全达到的最大速度
#### 阶段2: 设置出口速度 - Line 2851
```cpp
block.feedrate_profile.exit = curr.safe_feedrate; // 10 mm/s
```
**目的**: 确保当前块的出口速度不超过安全速度
#### 阶段3: 计算连接速度Junction Velocity - Line 2856-2929
这是**最复杂的部分**,涉及三个步骤:
##### 步骤3.1: XYZ向量jerk检查Line 2868-2884
```cpp
// 前一块的出口速度向量
Vec3f exit_v = prev.feedrate * prev.exit_direction;
// 假设: 100 mm/s 向X方向 = (100, 0, 0)
// 当前块的入口速度向量
Vec3f entry_v = block.feedrate_profile.cruise * curr.enter_direction;
// 假设: 100 mm/s 向Y方向 = (0, 100, 0)
// 计算速度变化向量jerk向量
Vec3f jerk_v = entry_v - exit_v;
// jerk_v = (0, 100, 0) - (100, 0, 0) = (-100, 100, 0)
jerk_v = Vec3f(abs(jerk_v.x()), abs(jerk_v.y()), abs(jerk_v.z()));
// jerk_v = (100, 100, 0)
// 获取XYZ最大jerk
Vec3f max_xyz_jerk_v = get_xyz_max_jerk(...);
// max_xyz_jerk_v = (10, 10, 0.2)
// 检查是否超限
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];
// i=0 (X): v_factor *= 10/100 = 0.1
// i=1 (Y): v_factor *= 10/100 = 0.1 (再次降低)
// 最终 v_factor = 0.01
limited = true;
}
}
```
**物理意义**: 限制XYZ空间中的速度变化防止机械冲击
##### 步骤3.2: E轴独立jerk检查Line 2889-2922
```cpp
// 对于E轴a = E
float v_exit = prev.axis_feedrate[E]; // 前一块的E速度: 5 mm/s
float v_entry = curr.axis_feedrate[E]; // 当前块的E速度: 10 mm/s
// 应用XYZ的v_factor
if (limited) {
v_exit *= v_factor; // 5 * 0.01 = 0.05 mm/s
v_entry *= v_factor; // 10 * 0.01 = 0.1 mm/s
}
// 计算E轴的jerk区分同向和反向
float jerk;
if (v_exit > v_entry) { // 减速
if ((v_entry > 0.0f) || (v_exit < 0.0f)) {
jerk = v_exit - v_entry; // 同向减速
} else {
jerk = std::max(v_exit, -v_entry); // 反向
}
} else { // 加速
if ((v_entry < 0.0f) || (v_exit > 0.0f)) {
jerk = v_entry - v_exit; // 同向加速: 0.1 - 0.05 = 0.05
} else {
jerk = std::max(-v_exit, v_entry); // 反向
}
}
// 检查E轴jerk限制
float axis_max_jerk = get_axis_max_jerk(..., E); // 2.5 mm/s
if (jerk > axis_max_jerk) {
v_factor *= axis_max_jerk / jerk;
// 0.05 < 2.5,不需要进一步限制
limited = true;
}
```
**物理意义**: 限制挤出机的速度变化,防止挤出不均匀
##### 步骤3.3: 应用最终v_factorLine 2925-2926
```cpp
if (limited)
vmax_junction *= v_factor;
// vmax_junction = 150 * 0.01 = 1.5 mm/s
```
#### 阶段4: 设置入口速度 - Line 2963
```cpp
block.feedrate_profile.entry = vmax_junction; // 1.5 mm/s
```
### 可视化示例:直角转弯
```
场景:
- 前一移动X方向 100 mm/s
- 当前移动Y方向 100 mm/s
- X/Y jerk: 10 mm/s
计算:
┌─────────────────────────────────────────┐
│ 1. 速度向量 │
│ exit_v = (100, 0, 0) │
│ entry_v = (0, 100, 0) │
│ jerk_v = (100, 100, 0) │
├─────────────────────────────────────────┤
│ 2. jerk限制检查 │
│ X: 100 > 10 → v_factor = 10/100=0.1│
│ Y: 100 > 10 → v_factor = 0.1*0.1=0.01│
├─────────────────────────────────────────┤
│ 3. 最终连接速度 │
│ vmax_junction = 100 * 0.01 = 1 mm/s│
└─────────────────────────────────────────┘
速度曲线:
前一块 当前块
100 mm/s ┐ ┌ 100 mm/s
│\ /│
│ \ / │
│ \ / │
│ \ / │
1 mm/s └────\ /────┘
└─┘
连接点(1 mm/s)
没有jerk限制的理想情况
100 mm/s ┐ ┌────┬────┐
│ / \ │
│ / \ │
50 mm/s └─┘ └─┘
连接点(50 mm/s)
```
### 对时间的影响
**示例计算**
```
假设:
- 前一移动100mm100 mm/s
- 当前移动100mm100 mm/s
- 加速度1000 mm/s²
- jerk限制10 mm/s
无jerk限制连接速度50 mm/s
- 前一块减速:(100-50)/1000 = 0.05s距离2.5mm
- 前一块总时间2.5mm/(75mm/s) + 97.5mm/100 = 1.008s
- 当前块加速:(100-50)/1000 = 0.05s距离2.5mm
- 当前块总时间2.5mm/(75mm/s) + 97.5mm/100 = 1.008s
- 总计2.016s
有jerk限制连接速度1 mm/s
- 前一块减速:(100-1)/1000 = 0.099s距离5mm
- 前一块总时间5mm/(50.5mm/s) + 95mm/100 = 1.049s
- 当前块加速:(100-1)/1000 = 0.099s距离5mm
- 当前块总时间5mm/(50.5mm/s) + 95mm/100 = 1.049s
- 总计2.098s
时间增加2.098 - 2.016 = 0.082s (约4%增加)
```
---
## 问题3OK
换料gcode中的M109会被统计 ✓
---
## 问题4M400 P100的含义
### P参数的定义
**位置**: `src/libslic3r/GCode/GCodeProcessor.cpp:3883-3891`
```cpp
void GCodeProcessor::process_M400(const GCodeReader::GCodeLine& line)
{
float value_s = 0.0;
float value_p = 0.0;
// S参数
// P参数毫秒
if (line.has_value('S', value_s) || line.has_value('P', value_p)) {
value_s += value_p * 0.001; // 🔥 P转换为秒P/1000
simulate_st_synchronize(value_s);
}
}
```
### P100的含义
```
M400 P100
P参数 = 100毫秒
计算:
value_p = 100
value_s = 100 * 0.001 = 0.1秒
结果:
simulate_st_synchronize(0.1) // 添加0.1秒等待时间
```
### 是否会记录时间?
**答案:会**
**完整流程**
```cpp
// 1. 解析M400 P100
process_M400(line)
// 2. 提取参数
value_p = 100
value_s = 0.1
// 3. 调用同步
simulate_st_synchronize(0.1)
// 4. 添加到时间估算
for (size_t i = 0; i < machines.size(); ++i) {
machines[i].simulate_st_synchronize(0.1);
machines[i].calculate_time(0, 0.1); // distance=0, additional_time=0.1
// 在时间统计中添加0.1秒
}
```
### M400参数对比
| 命令 | S参数 | P参数 | 总等待时间 | 记录时间? |
|-----|-------|-------|-----------|----------|
| `M400` | 0 | 0 | 0秒 | ❌ 否 |
| `M400 S1` | 1 | 0 | 1秒 | ✅ 是 |
| `M400 P100` | 0 | 100 | 0.1秒 | ✅ 是 |
| `M400 S1 P500` | 1 | 500 | 1.5秒 | ✅ 是 |
### 实际使用场景
**GCode.cpp中的扫描模型**
```cpp
gcode += "M976 S1 P1 ; scan model before printing 2nd layer\n";
gcode += "M400 P100\n"; // 等待100毫秒
```
**目的**
- M976触发模型扫描
- M400 P100确保扫描命令完全执行
- 在时间估算中添加0.1秒
**U1的工具切换**
```cpp
if (printer_model == "Snapmaker U1" && toolchange) {
gcode += "M400\n"; // 无参数
}
```
**区别**
- 无参数的M400**不添加额外时间**
- 只是同步移动缓冲区
- 确保所有移动完成后再切换工具
---
## 总结
### 问题1答案E加速度限制
**实际使用5000** - 虽然extruding设置为20000但E轴分量会受到machine_max_acceleration_e (5000)的限制
### 问题2答案Jerk计算流程
1. 计算安全速度(限制单轴)
2. 计算XYZ速度变化向量
3. 应用jerk限制降低连接速度
4. 独立检查E轴jerk
5. 设置最终入口/出口速度
### 问题4答案M400 P100
- **P = 毫秒数**
- **P100 = 100毫秒 = 0.1秒**
- **会记录时间** ✅
- 通过`simulate_st_synchronize(0.1)`添加到时间估算
---
## 关键代码位置总结
| 功能 | 文件 | 行号 |
|-----|------|------|
| E轴加速度限制检查 | GCodeProcessor.cpp | 2834-2838 |
| get_axis_max_acceleration | GCodeProcessor.cpp | 4850-4862 |
| Jerk安全速度计算 | GCodeProcessor.cpp | 2842-2849 |
| Jerk连接速度计算 | GCodeProcessor.cpp | 2856-2929 |
| M400处理 | GCodeProcessor.cpp | 3883-3891 |
| U1的M400插入 | GCode.cpp | 6378-6380 |