mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-06-11 06:23:08 +00:00
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
This commit is contained in:
474
doc/developer-reference/Time_Estimation_Detailed_Answers.md
Normal file
474
doc/developer-reference/Time_Estimation_Detailed_Answers.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# 补充问题的详细答案
|
||||
|
||||
> **日期**: 2025-12-06
|
||||
> **问题来源**: 时间预估分析的进一步确认
|
||||
|
||||
---
|
||||
|
||||
## 问题1:E最大加速度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轴比例)**
|
||||
|
||||
---
|
||||
|
||||
## 问题2:Jerk怎么参与计算的
|
||||
|
||||
### 完整计算流程
|
||||
|
||||
#### 阶段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_factor(Line 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)
|
||||
```
|
||||
|
||||
### 对时间的影响
|
||||
|
||||
**示例计算**:
|
||||
|
||||
```
|
||||
假设:
|
||||
- 前一移动100mm,100 mm/s
|
||||
- 当前移动100mm,100 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%增加)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 问题3:OK
|
||||
|
||||
换料gcode中的M109会被统计 ✓
|
||||
|
||||
---
|
||||
|
||||
## 问题4:M400 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 |
|
||||
Reference in New Issue
Block a user