mirror of
https://git-proxy.hk.martin98.com/https://github.com/SoftFever/OrcaSlicer.git
synced 2025-04-10 14:19:12 +08:00
pa calib: batch mode for pa pattern (#7199)
* pa calib: batch mode option
This commit is contained in:
parent
538db07127
commit
ecc16bfabf
@ -73,11 +73,20 @@ The pattern method is adapted from [Andrew Ellis' pattern method generator](http
|
||||
|
||||
[Instructions for using and reading the pattern method](https://ellis3dp.com/Print-Tuning-Guide/articles/pressure_linear_advance/pattern_method.html) are provided in [Ellis' Print Tuning Guide](https://ellis3dp.com/Print-Tuning-Guide/), with only a few Orca Slicer differences to note.
|
||||
|
||||
First and foremost, when you initiate the test, you'll only see a small rectangular prism on the plate. This object serves a few purposes:
|
||||
Test configuration window allow user to generate one or more tests in a single projects. Multiple tests will be placed on each plate with extra plates added if needed.
|
||||
|
||||
1. The test pattern itself is added in as custom G-Code at each layer, same as you could do by hand actually. The rectangular prism gives us the layers in which to insert that G-Code. This also means that **you'll see the full test pattern when you move to the Preview pane**
|
||||
1. Single test \
|
||||

|
||||
2. Batch mode testing (multiple tests on a sinle plate) \
|
||||

|
||||
|
||||
Once test generated, one or more small rectangular prisms could be found on the plate, one for each test case. This object serves a few purposes:
|
||||
|
||||
1. The test pattern itself is added in as custom G-Code at each layer, same as you could do by hand actually. The rectangular prism gives us the layers in which to insert that G-Code. This also means that **you'll see the full test pattern when you move to the Preview pane**:
|
||||

|
||||
2. The prism acts as a handle, enabling you to move the test pattern wherever you'd like on the plate by moving the prism
|
||||
3. The filament selected for the prism is also used for the test pattern
|
||||
3. Each test object is pre-configured with target parameters which are reflected in the objects name. However, test parameters may be adjusted for each prism individually by referring to the object list pane:
|
||||

|
||||
|
||||
Next, Ellis' generator provided the ability to adjust specific printer, filament, and print profile settings. You can make these same changes in Orca Slicer by adjusting the settings in the Prepare pane as you would with any other print. When you initiate the calibration test, Ellis' default settings are applied. A few things to note about these settings:
|
||||
|
||||
|
@ -110,13 +110,26 @@ We, therefore, need to run 12 PA tests as below:
|
||||
|
||||
### Identifying the flow rates from the print speed
|
||||
|
||||
#### OrcaSlicer 2.2.0 and later
|
||||
|
||||
Test parameters needed to build adaptive PA table are printed on the test sample:
|
||||
|
||||
<img width="452" alt="pa batch mode" src="https://github.com/user-attachments/assets/219c53b5-d53f-4360-963e-0985d9257bd7">
|
||||
|
||||
Test sample above was done with acceleration 12000 mm/s² and flow rate 27.13 mm³/s
|
||||
|
||||
|
||||
#### OrcaSlicer 2.1.0 and older.
|
||||
|
||||
As mentioned earlier, **the print speed is used as a proxy to vary the extrusion flow rate**. Once your PA test is set up, change the gcode preview to “flow” and move the horizontal slider over one of the herringbone patterns and take note of the flow rate for different speeds.
|
||||

|
||||
|
||||
|
||||
### Running the tests
|
||||
|
||||
Setup your PA test as usual from the calibration menu in Orca slicer. It is recommended that the PA step is set to a small value, to allow you to make meaningful distinctions between the different tests – **therefore a PA step value of 0.001 is recommended. **
|
||||
#### General tips
|
||||
|
||||
It is recommended that the PA step is set to a small value, to allow you to make meaningful distinctions between the different tests – **therefore a PA step value of 0.001 is recommended. **
|
||||
|
||||
**Set the end PA to a value high enough to start showing perimeter separation for the lowest flow (print speed) and acceleration test.** For example, for a Voron 350 using Revo HF, the maximum value was set to 0.05 as that was sufficient to show perimeter separation even at the slowest flow rates and accelerations.
|
||||
|
||||
@ -124,7 +137,19 @@ Setup your PA test as usual from the calibration menu in Orca slicer. It is reco
|
||||
|
||||
<img width="402" alt="PA calibration parameters" src="https://github.com/user-attachments/assets/b411dc30-5556-4e7c-8c40-5279d3074eae">
|
||||
|
||||
Once setup, your PA test should look like the below:
|
||||
#### OrcaSlicer 2.3.0 and newer
|
||||
|
||||
PA pattern calibration configuration window have been changed to simplify test setup. Now all is needed is to fill list of accelerations and speeds into relevant fields of the calibration window:
|
||||
|
||||

|
||||
|
||||
Test patterns generated for each acceleration-speed pair and all parameters are set accordingly. No additional actions needed from user side. Just slice and print all plates generated.
|
||||
|
||||
Refer to [Calibration Guide](./Calibration) for more details on batch mode calibration.
|
||||
|
||||
#### OrcaSlicer 2.2.0 and older
|
||||
|
||||
Setup your PA test as usual from the calibration menu in Orca slicer. Once setup, your PA test should look like the below:
|
||||
|
||||
<img width="437" alt="PA calibration test 1" src="https://github.com/user-attachments/assets/1e6159fe-c3c5-4480-95a1-4383f1fae422">
|
||||
<img width="437" alt="Pa calibration test 2" src="https://github.com/user-attachments/assets/c360bb18-a97a-4f37-b5a3-bb0c67cac2b6">
|
||||
@ -132,6 +157,9 @@ Once setup, your PA test should look like the below:
|
||||
Now input your identified print speeds and accelerations in the fields above and run the PA tests.
|
||||
|
||||
**IMPORTANT:** Make sure your acceleration values are all the same in all text boxes. Same for the print speed values and Jerk (XY) values. Make sure your Jerk value is set to the external perimeter jerk used in your print profiles.
|
||||
|
||||
#### Test results processing
|
||||
|
||||
Now run the tests and note the optimal PA value, the flow, and the acceleration. You should produce a table like this:
|
||||
|
||||
<img width="452" alt="calibration table" src="https://github.com/user-attachments/assets/9451e8e4-352f-4cfc-b835-dffa4420d580">
|
||||
|
BIN
doc/images/pa/pa-pattern-batch-objects.png
Normal file
BIN
doc/images/pa/pa-pattern-batch-objects.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
doc/images/pa/pa-pattern-batch-plater.png
Normal file
BIN
doc/images/pa/pa-pattern-batch-plater.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 462 KiB |
BIN
doc/images/pa/pa-pattern-batch.png
Normal file
BIN
doc/images/pa/pa-pattern-batch.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
doc/images/pa/pa-pattern-single.png
Normal file
BIN
doc/images/pa/pa-pattern-single.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -538,12 +538,19 @@ void CalibPressureAdvanceLine::delta_modify_start(double &startx, double &starty
|
||||
}
|
||||
|
||||
CalibPressureAdvancePattern::CalibPressureAdvancePattern(
|
||||
const Calib_Params ¶ms, const DynamicPrintConfig &config, bool is_bbl_machine, Model &model, const Vec3d &origin)
|
||||
const Calib_Params ¶ms, const DynamicPrintConfig &config, bool is_bbl_machine, const ModelObject &object, const Vec3d &origin)
|
||||
: m_params(params),CalibPressureAdvance(config)
|
||||
{
|
||||
this->m_draw_digit_mode = DrawDigitMode::Bottom_To_Top;
|
||||
|
||||
refresh_setup(config, is_bbl_machine, model, origin);
|
||||
refresh_setup(config, is_bbl_machine, object, origin);
|
||||
}
|
||||
|
||||
Vec3d CalibPressureAdvancePattern::handle_pos_offset() const
|
||||
{
|
||||
return Vec3d{0 - print_size_x() / 2 + handle_xy_size() / 2 + handle_spacing(),
|
||||
0 - max_numbering_height() / 2 - m_glyph_padding_vertical,
|
||||
max_layer_z() / 2};
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::flow_val() const
|
||||
@ -552,21 +559,21 @@ double CalibPressureAdvancePattern::flow_val() const
|
||||
double nozzle_diameter = m_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0);
|
||||
double line_width = m_config.get_abs_value("line_width", nozzle_diameter);
|
||||
double layer_height = m_config.get_abs_value("layer_height");
|
||||
double speed = m_config.opt_float("outer_wall_speed");
|
||||
double speed = speed_perimeter();
|
||||
Flow pattern_line = Flow(line_width, layer_height, m_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0));
|
||||
|
||||
return speed * pattern_line.mm3_per_mm() * flow_mult;
|
||||
};
|
||||
|
||||
void CalibPressureAdvancePattern::generate_custom_gcodes(const DynamicPrintConfig &config,
|
||||
bool is_bbl_machine,
|
||||
Model &model,
|
||||
const Vec3d &origin)
|
||||
CustomGCode::Info CalibPressureAdvancePattern::generate_custom_gcodes(const DynamicPrintConfig &config,
|
||||
bool is_bbl_machine,
|
||||
const ModelObject &object,
|
||||
const Vec3d &origin)
|
||||
{
|
||||
std::stringstream gcode;
|
||||
gcode << "; start pressure advance pattern for layer\n";
|
||||
|
||||
refresh_setup(config, is_bbl_machine, model, origin);
|
||||
refresh_setup(config, is_bbl_machine, object, origin);
|
||||
|
||||
gcode << move_to(Vec2d(m_starting_point.x(), m_starting_point.y()), m_writer, "Move to start XY position");
|
||||
gcode << m_writer.travel_to_z(height_first_layer() + height_z_offset(), "Move to start Z position");
|
||||
@ -590,6 +597,8 @@ void CalibPressureAdvancePattern::generate_custom_gcodes(const DynamicPrintConfi
|
||||
const int num_patterns = get_num_patterns(); // "cache" for use in loops
|
||||
|
||||
const double zhop_config_value = m_config.option<ConfigOptionFloats>("z_hop")->get_at(0);
|
||||
const auto accel = accel_perimeter();
|
||||
|
||||
// draw pressure advance pattern
|
||||
for (int i = 0; i < m_num_layers; ++i) {
|
||||
const double layer_height = height_first_layer() + height_z_offset() + (i * height_layer());
|
||||
@ -637,7 +646,7 @@ void CalibPressureAdvancePattern::generate_custom_gcodes(const DynamicPrintConfi
|
||||
// acceleration
|
||||
line_num = num_patterns + 4;
|
||||
gcode << draw_number(glyph_start_x(line_num), m_starting_point.y() + frame_size_y() + m_glyph_padding_vertical + line_width(),
|
||||
m_config.opt_float("default_acceleration"), m_draw_digit_mode, line_width(), number_e_per_mm,
|
||||
accel, m_draw_digit_mode, line_width(), number_e_per_mm,
|
||||
speed_first_layer(), m_writer);
|
||||
}
|
||||
|
||||
@ -653,6 +662,14 @@ void CalibPressureAdvancePattern::generate_custom_gcodes(const DynamicPrintConfi
|
||||
side_length = m_wall_side_length - shrink;
|
||||
to_x += shrink * std::sin(to_radians(90) - to_radians(m_corner_angle) / 2);
|
||||
to_y += line_spacing_first_layer() * (wall_count() - 1) + (line_width_first_layer() * (1 - m_encroachment));
|
||||
} else {
|
||||
/* Draw a line at slightly slower accel and speed in order to trick gcode writer to force update acceleration and speed.
|
||||
* We do this since several tests may be generated by their own gcode writers which are
|
||||
* not aware about their neighbours updating acceleration/speed */
|
||||
gcode << m_writer.set_print_acceleration(accel - 10);
|
||||
gcode << move_to(Vec2d(m_starting_point.x(), m_starting_point.y()), m_writer, "Move to starting point", zhop_height, layer_height);
|
||||
gcode << draw_line(m_writer, Vec2d(m_starting_point.x(), m_starting_point.y() + frame_size_y()), line_width(), height_layer(), speed_adjust(speed_perimeter() - 10), "Accel/flow trick line");
|
||||
gcode << m_writer.set_print_acceleration(accel);
|
||||
}
|
||||
|
||||
double initial_x = to_x;
|
||||
@ -713,7 +730,7 @@ void CalibPressureAdvancePattern::generate_custom_gcodes(const DynamicPrintConfi
|
||||
info.mode = CustomGCode::Mode::SingleExtruder;
|
||||
info.gcodes = gcode_items;
|
||||
|
||||
model.plates_custom_gcodes[model.curr_plate_index] = info;
|
||||
return info;
|
||||
}
|
||||
|
||||
void CalibPressureAdvancePattern::set_start_offset(const Vec3d &offset)
|
||||
@ -729,30 +746,30 @@ Vec3d CalibPressureAdvancePattern::get_start_offset()
|
||||
|
||||
void CalibPressureAdvancePattern::refresh_setup(const DynamicPrintConfig &config,
|
||||
bool is_bbl_machine,
|
||||
const Model &model,
|
||||
const ModelObject &object,
|
||||
const Vec3d &origin)
|
||||
{
|
||||
m_config = config;
|
||||
m_config.apply(model.objects.front()->config.get(), true);
|
||||
m_config.apply(model.objects.front()->volumes.front()->config.get(), true);
|
||||
m_config.apply(object.config.get(), true);
|
||||
m_config.apply(object.volumes.front()->config.get(), true);
|
||||
|
||||
_refresh_starting_point(model);
|
||||
_refresh_writer(is_bbl_machine, model, origin);
|
||||
_refresh_starting_point(object);
|
||||
_refresh_writer(is_bbl_machine, object, origin);
|
||||
}
|
||||
|
||||
void CalibPressureAdvancePattern::_refresh_starting_point(const Model &model)
|
||||
void CalibPressureAdvancePattern::_refresh_starting_point(const ModelObject &object)
|
||||
{
|
||||
if (m_is_start_point_fixed)
|
||||
return;
|
||||
|
||||
ModelObject *obj = model.objects.front();
|
||||
BoundingBoxf3 bbox = obj->instance_bounding_box(*obj->instances.front(), false);
|
||||
BoundingBoxf3 bbox = object.instance_bounding_box(*object.instances.front(), false);
|
||||
|
||||
m_starting_point = Vec3d(bbox.min.x(), bbox.max.y(), 0);
|
||||
m_starting_point.y() += m_handle_spacing;
|
||||
m_starting_point.x() -= m_handle_spacing;
|
||||
m_starting_point.y() -= std::sin(to_radians(m_corner_angle) / 2) * m_wall_side_length + (bbox.max.y() - bbox.min.y()) / 2;
|
||||
}
|
||||
|
||||
void CalibPressureAdvancePattern::_refresh_writer(bool is_bbl_machine, const Model &model, const Vec3d &origin)
|
||||
void CalibPressureAdvancePattern::_refresh_writer(bool is_bbl_machine, const ModelObject &object, const Vec3d &origin)
|
||||
{
|
||||
PrintConfig print_config;
|
||||
print_config.apply(m_config, true);
|
||||
@ -761,7 +778,7 @@ void CalibPressureAdvancePattern::_refresh_writer(bool is_bbl_machine, const Mod
|
||||
m_writer.set_xy_offset(origin(0), origin(1));
|
||||
m_writer.set_is_bbl_machine(is_bbl_machine);
|
||||
|
||||
const unsigned int extruder_id = model.objects.front()->volumes.front()->extruder_id();
|
||||
const unsigned int extruder_id = object.volumes.front()->extruder_id();
|
||||
m_writer.set_extruders({extruder_id});
|
||||
m_writer.set_extruder(extruder_id);
|
||||
}
|
||||
@ -837,7 +854,7 @@ size_t CalibPressureAdvancePattern::max_numbering_length() const
|
||||
}
|
||||
}
|
||||
|
||||
std::string sAccel = convert_number_to_string(m_config.opt_float("default_acceleration"));
|
||||
std::string sAccel = convert_number_to_string(accel_perimeter());
|
||||
most_characters = std::max(most_characters, sAccel.length());
|
||||
|
||||
/* don't actually check flow value: we'll print as many fractional digits as fits */
|
||||
|
@ -31,6 +31,10 @@ struct Calib_Params
|
||||
Calib_Params() : mode(CalibMode::Calib_None){};
|
||||
double start, end, step;
|
||||
bool print_numbers;
|
||||
|
||||
std::vector<double> accelerations;
|
||||
std::vector<double> speeds;
|
||||
|
||||
CalibMode mode;
|
||||
};
|
||||
|
||||
@ -249,16 +253,17 @@ class CalibPressureAdvancePattern : public CalibPressureAdvance
|
||||
|
||||
public:
|
||||
CalibPressureAdvancePattern(
|
||||
const Calib_Params ¶ms, const DynamicPrintConfig &config, bool is_bbl_machine, Model &model, const Vec3d &origin);
|
||||
const Calib_Params ¶ms, const DynamicPrintConfig &config, bool is_bbl_machine, const ModelObject &object, const Vec3d &origin);
|
||||
|
||||
double handle_xy_size() const { return m_handle_xy_size; };
|
||||
double handle_spacing() const { return m_handle_spacing; };
|
||||
Vec3d handle_pos_offset() const;
|
||||
double print_size_x() const { return object_size_x() + pattern_shift(); };
|
||||
double print_size_y() const { return object_size_y(); };
|
||||
double max_layer_z() const { return height_first_layer() + ((m_num_layers - 1) * height_layer()); };
|
||||
double flow_val() const;
|
||||
|
||||
void generate_custom_gcodes(const DynamicPrintConfig &config, bool is_bbl_machine, Model &model, const Vec3d &origin);
|
||||
CustomGCode::Info generate_custom_gcodes(const DynamicPrintConfig &config, bool is_bbl_machine, const ModelObject &object, const Vec3d &origin);
|
||||
|
||||
void set_start_offset(const Vec3d &offset);
|
||||
Vec3d get_start_offset();
|
||||
@ -266,6 +271,7 @@ public:
|
||||
protected:
|
||||
double speed_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_speed")->value; };
|
||||
double speed_perimeter() const { return m_config.option<ConfigOptionFloat>("outer_wall_speed")->value; };
|
||||
double accel_perimeter() const { return m_config.option<ConfigOptionFloat>("outer_wall_acceleration")->value; }
|
||||
double line_width_first_layer() const
|
||||
{
|
||||
// TODO: FIXME: find out current filament/extruder?
|
||||
@ -281,9 +287,9 @@ protected:
|
||||
int wall_count() const { return m_config.option<ConfigOptionInt>("wall_loops")->value; };
|
||||
|
||||
private:
|
||||
void refresh_setup(const DynamicPrintConfig &config, bool is_bbl_machine, const Model &model, const Vec3d &origin);
|
||||
void _refresh_starting_point(const Model &model);
|
||||
void _refresh_writer(bool is_bbl_machine, const Model &model, const Vec3d &origin);
|
||||
void refresh_setup(const DynamicPrintConfig &config, bool is_bbl_machine, const ModelObject &object, const Vec3d &origin);
|
||||
void _refresh_starting_point(const ModelObject &object);
|
||||
void _refresh_writer(bool is_bbl_machine, const ModelObject &object, const Vec3d &origin);
|
||||
|
||||
double height_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_print_height")->value; };
|
||||
double height_z_offset() const { return m_config.option<ConfigOptionFloat>("z_offset")->value; };
|
||||
@ -319,7 +325,7 @@ private:
|
||||
bool m_is_start_point_fixed = false;
|
||||
|
||||
const double m_handle_xy_size{5};
|
||||
const double m_handle_spacing{2};
|
||||
const double m_handle_spacing{1.2};
|
||||
const int m_num_layers{4};
|
||||
|
||||
const double m_wall_side_length{30.0};
|
||||
|
@ -9468,12 +9468,10 @@ void Plater::calib_pa(const Calib_Params& params)
|
||||
|
||||
void Plater::_calib_pa_pattern(const Calib_Params& params)
|
||||
{
|
||||
// add "handle" cube
|
||||
sidebar().obj_list()->load_generic_subobject("Cube", ModelVolumeType::INVALID);
|
||||
orient();
|
||||
changed_objects({ 0 });
|
||||
_calib_pa_select_added_objects();
|
||||
|
||||
std::vector<double> speeds{params.speeds};
|
||||
std::vector<double> accels{params.accelerations};
|
||||
std::vector<size_t> object_idxs{};
|
||||
/* Set common parameters */
|
||||
DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
DynamicPrintConfig& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config;
|
||||
@ -9491,17 +9489,18 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
||||
accel = print_config.option<ConfigOptionFloat>("default_acceleration")->value;
|
||||
// Orca: Set all accelerations except first layer, as the first layer accel doesnt affect the PA test since accel
|
||||
// is set to the travel accel before printing the pattern.
|
||||
print_config.set_key_value( "default_acceleration", new ConfigOptionFloat(accel));
|
||||
if (accels.empty()) {
|
||||
accels.assign({accel});
|
||||
const auto msg{_L("INFO:") + "\n" +
|
||||
_L("No accelerations provided for calibration. Use default acceleration value ") + std::to_string(long(accel)) + _L("mm/s²")};
|
||||
get_notification_manager()->push_notification(msg.ToStdString());
|
||||
} else {
|
||||
// set max acceleration in case of batch mode to get correct test pattern size
|
||||
accel = *std::max_element(accels.begin(), accels.end());
|
||||
}
|
||||
print_config.set_key_value( "outer_wall_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "inner_wall_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "bridge_acceleration", new ConfigOptionFloatOrPercent(accel, false));
|
||||
print_config.set_key_value( "sparse_infill_acceleration", new ConfigOptionFloatOrPercent(accel, false));
|
||||
print_config.set_key_value( "internal_solid_infill_acceleration", new ConfigOptionFloatOrPercent(accel, false));
|
||||
print_config.set_key_value( "top_surface_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "travel_acceleration", new ConfigOptionFloat(accel));
|
||||
print_config.set_key_value( "print_sequence", new ConfigOptionEnum(PrintSequence::ByLayer));
|
||||
|
||||
|
||||
//Orca: find jerk value to use in the test
|
||||
if(print_config.option<ConfigOptionFloat>("default_jerk")->value > 0){ // we have set a jerk value
|
||||
auto jerk = print_config.option<ConfigOptionFloat>("outer_wall_jerk")->value; // get outer wall jerk
|
||||
@ -9547,12 +9546,24 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
||||
);
|
||||
|
||||
// Orca: Set the outer wall speed to the optimal speed for the test, cap it with max volumetric speed
|
||||
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(CalibPressureAdvance::find_optimal_PA_speed(
|
||||
wxGetApp().preset_bundle->full_config(),
|
||||
(fabs(print_config.get_abs_value("line_width", nozzle_diameter)) <= DBL_EPSILON) ?
|
||||
(nozzle_diameter * 1.125) :
|
||||
print_config.get_abs_value("line_width", nozzle_diameter),
|
||||
print_config.get_abs_value("layer_height"), 0)));
|
||||
if (speeds.empty()) {
|
||||
double speed = CalibPressureAdvance::find_optimal_PA_speed(
|
||||
wxGetApp().preset_bundle->full_config(),
|
||||
(fabs(print_config.get_abs_value("line_width", nozzle_diameter)) <= DBL_EPSILON) ?
|
||||
(nozzle_diameter * 1.125) :
|
||||
print_config.get_abs_value("line_width", nozzle_diameter),
|
||||
print_config.get_abs_value("layer_height"), 0);
|
||||
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(speed));
|
||||
|
||||
speeds.assign({speed});
|
||||
const auto msg{_L("INFO:") + "\n" +
|
||||
_L("No speeds provided for calibration. Use default optimal speed ") + std::to_string(long(speed)) + _L("mm/s")};
|
||||
get_notification_manager()->push_notification(msg.ToStdString());
|
||||
} else if (speeds.size() == 1) {
|
||||
// If we have single value provided, set speed using global configuration.
|
||||
// per-object config is not set in this case
|
||||
print_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(speeds.front()));
|
||||
}
|
||||
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty();
|
||||
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->update_dirty();
|
||||
@ -9564,54 +9575,133 @@ void Plater::_calib_pa_pattern(const Calib_Params& params)
|
||||
const DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config();
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
const bool is_bbl_machine = preset_bundle->is_bbl_vendor();
|
||||
const Vec3d plate_origin = get_partplate_list().get_current_plate_origin();
|
||||
auto cur_plate = get_partplate_list().get_plate(0);
|
||||
|
||||
// add "handle" cube
|
||||
sidebar().obj_list()->load_generic_subobject("Cube", ModelVolumeType::INVALID);
|
||||
auto *cube = model().objects[0];
|
||||
|
||||
CalibPressureAdvancePattern pa_pattern(
|
||||
params,
|
||||
full_config,
|
||||
is_bbl_machine,
|
||||
model(),
|
||||
plate_origin
|
||||
*cube,
|
||||
cur_plate->get_origin()
|
||||
);
|
||||
|
||||
// scale cube to suit test
|
||||
GizmoObjectManipulation& giz_obj_manip = p->view3D->get_canvas3d()->
|
||||
get_gizmos_manager().get_object_manipulation();
|
||||
giz_obj_manip.set_uniform_scaling(true);
|
||||
giz_obj_manip.on_change(
|
||||
"size",
|
||||
0,
|
||||
pa_pattern.handle_xy_size()
|
||||
);
|
||||
giz_obj_manip.set_uniform_scaling(false);
|
||||
giz_obj_manip.on_change(
|
||||
"size",
|
||||
2,
|
||||
pa_pattern.max_layer_z()
|
||||
);
|
||||
// start with pattern centered on plate
|
||||
center_selection();
|
||||
const Vec3d plate_center = get_partplate_list().get_curr_plate()->get_center_origin();
|
||||
giz_obj_manip.on_change(
|
||||
"position",
|
||||
0,
|
||||
plate_center.x() - (pa_pattern.print_size_x() / 2)
|
||||
);
|
||||
giz_obj_manip.on_change(
|
||||
"position",
|
||||
1,
|
||||
plate_center.y() -
|
||||
(pa_pattern.print_size_y() / 2) -
|
||||
pa_pattern.handle_spacing()
|
||||
);
|
||||
/* Having PA pattern configured, we could make a set of polygons resembling N test patterns.
|
||||
* We'll arrange this set of polygons, so we would know position of each test pattern and
|
||||
* could position test cubes later on
|
||||
*
|
||||
* We'll take advantage of already existing cube: scale it up to test pattern size to use
|
||||
* as a reference for objects arrangement. Polygon is slightly oversized to add spaces between patterns.
|
||||
* That arrangement will be used to place 'handle cubes' for each test. */
|
||||
auto cube_bb = cube->raw_bounding_box();
|
||||
cube->scale((pa_pattern.print_size_x() + 4) / cube_bb.size().x(),
|
||||
(pa_pattern.print_size_y() + 4) / cube_bb.size().y(),
|
||||
pa_pattern.max_layer_z() / cube_bb.size().z());
|
||||
|
||||
arrangement::ArrangePolygons arranged_items;
|
||||
{
|
||||
arrangement::ArrangeParams ap;
|
||||
Points bedpts = arrangement::get_shrink_bedpts(&full_config, ap);
|
||||
|
||||
for(size_t i = 0; i < speeds.size() * accels.size(); i++) {
|
||||
arrangement::ArrangePolygon p;
|
||||
cube->instances[0]->get_arrange_polygon(&p);
|
||||
p.bed_idx = 0;
|
||||
arranged_items.emplace_back(p);
|
||||
}
|
||||
|
||||
arrangement::arrange(arranged_items, bedpts, ap);
|
||||
}
|
||||
|
||||
/* scale cube back to the size of test pattern 'handle' */
|
||||
cube_bb = cube->raw_bounding_box();
|
||||
cube->scale(pa_pattern.handle_xy_size() / cube_bb.size().x(),
|
||||
pa_pattern.handle_xy_size() / cube_bb.size().y(),
|
||||
pa_pattern.max_layer_z() / cube_bb.size().z());
|
||||
|
||||
/* Set speed and acceleration on per-object basis and arrange anchor object on the plates.
|
||||
* Test gcode will be genecated during plate slicing */
|
||||
for(size_t test_idx = 0; test_idx < arranged_items.size(); test_idx++) {
|
||||
const auto &ai = arranged_items[test_idx];
|
||||
size_t plate_idx = arranged_items[test_idx].bed_idx;
|
||||
auto tspd = speeds[test_idx % speeds.size()];
|
||||
auto tacc = accels[test_idx / speeds.size()];
|
||||
|
||||
/* make an own copy of anchor cube for each test */
|
||||
auto obj = test_idx == 0 ? cube : model().add_object(*cube);
|
||||
auto obj_idx = std::distance(model().objects.begin(), std::find(model().objects.begin(), model().objects.end(), obj));
|
||||
obj->name.assign(std::string("pa_pattern_") + std::to_string(int(tspd)) + std::string("_") + std::to_string(int(tacc)));
|
||||
|
||||
auto &obj_config = obj->config;
|
||||
if (speeds.size() > 1)
|
||||
obj_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(tspd));
|
||||
if (accels.size() > 1)
|
||||
obj_config.set_key_value("outer_wall_acceleration", new ConfigOptionFloat(tacc));
|
||||
|
||||
auto cur_plate = get_partplate_list().get_plate(plate_idx);
|
||||
if (!cur_plate) {
|
||||
plate_idx = get_partplate_list().create_plate();
|
||||
cur_plate = get_partplate_list().get_plate(plate_idx);
|
||||
}
|
||||
|
||||
object_idxs.emplace_back(obj_idx);
|
||||
get_partplate_list().add_to_plate(obj_idx, 0, plate_idx);
|
||||
const Vec3d obj_offset{unscale<double>(ai.translation(X)),
|
||||
unscale<double>(ai.translation(Y)),
|
||||
0};
|
||||
obj->instances[0]->set_offset(cur_plate->get_origin() + obj_offset + pa_pattern.handle_pos_offset());
|
||||
obj->ensure_on_bed();
|
||||
|
||||
if (obj_idx == 0)
|
||||
sidebar().obj_list()->update_name_for_items();
|
||||
else
|
||||
sidebar().obj_list()->add_object_to_list(obj_idx);
|
||||
}
|
||||
|
||||
pa_pattern.generate_custom_gcodes(
|
||||
full_config,
|
||||
is_bbl_machine,
|
||||
model(),
|
||||
plate_origin
|
||||
);
|
||||
model().calib_pa_pattern = std::make_unique<CalibPressureAdvancePattern>(pa_pattern);
|
||||
changed_objects({ 0 });
|
||||
changed_objects(object_idxs);
|
||||
}
|
||||
|
||||
void Plater::_calib_pa_pattern_gen_gcode()
|
||||
{
|
||||
if (!model().calib_pa_pattern)
|
||||
return;
|
||||
|
||||
auto cur_plate = get_partplate_list().get_curr_plate();
|
||||
if (cur_plate->empty())
|
||||
return;
|
||||
|
||||
/* Container to store custom g-codes genereted by the test generator.
|
||||
* We'll store gcode for all tests on a single plate here. Once the plate handling is done,
|
||||
* all the g-codes will be merged into a single one on per-layer basis */
|
||||
std::vector<CustomGCode::Info> mgc;
|
||||
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
|
||||
|
||||
/* iterate over all cubes on current plate and generate gcode for them */
|
||||
for (auto obj : cur_plate->get_objects_on_this_plate()) {
|
||||
auto gcode = model().calib_pa_pattern->generate_custom_gcodes(
|
||||
preset_bundle->full_config(),
|
||||
preset_bundle->is_bbl_vendor(),
|
||||
*obj,
|
||||
cur_plate->get_origin()
|
||||
);
|
||||
mgc.emplace_back(gcode);
|
||||
}
|
||||
|
||||
// move first item into model custom gcode
|
||||
auto &pcgc = model().plates_custom_gcodes[get_partplate_list().get_curr_plate_index()];
|
||||
pcgc = std::move(mgc[0]);
|
||||
mgc.erase(mgc.begin());
|
||||
|
||||
// concat layer gcodes for each test
|
||||
for (size_t i = 0; i < pcgc.gcodes.size(); i++) {
|
||||
for (auto &gc : mgc) {
|
||||
pcgc.gcodes[i].extra += gc.gcodes[i].extra;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::cut_horizontal(size_t obj_idx, size_t instance_idx, double z, ModelObjectCutAttributes attributes)
|
||||
@ -12385,14 +12475,7 @@ void Plater::reslice()
|
||||
|
||||
// Orca: regenerate CalibPressureAdvancePattern custom G-code to apply changes
|
||||
if (model().calib_pa_pattern) {
|
||||
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||
|
||||
model().calib_pa_pattern->generate_custom_gcodes(
|
||||
wxGetApp().preset_bundle->full_config(),
|
||||
preset_bundle->is_bbl_vendor(),
|
||||
model(),
|
||||
get_partplate_list().get_current_plate_origin()
|
||||
);
|
||||
_calib_pa_pattern_gen_gcode();
|
||||
}
|
||||
|
||||
if (printer_technology() == ptSLA) {
|
||||
|
@ -820,6 +820,7 @@ private:
|
||||
int start_next_slice();
|
||||
|
||||
void _calib_pa_pattern(const Calib_Params& params);
|
||||
void _calib_pa_pattern_gen_gcode();
|
||||
void _calib_pa_tower(const Calib_Params& params);
|
||||
void _calib_pa_select_added_objects();
|
||||
|
||||
|
@ -6,7 +6,20 @@
|
||||
#include "MainFrame.hpp"
|
||||
#include <string>
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void ParseStringValues(std::string str, std::vector<double> &vec)
|
||||
{
|
||||
vec.clear();
|
||||
std::replace(str.begin(), str.end(), ',', ' ');
|
||||
std::istringstream inss(str);
|
||||
std::copy_if(std::istream_iterator<int>(inss), std::istream_iterator<int>(), std::back_inserter(vec),
|
||||
[](int x){ return x > 0; });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wxBoxSizer* create_item_checkbox(wxString title, wxWindow* parent, bool* value, CheckBox*& checkbox)
|
||||
{
|
||||
wxBoxSizer* m_sizer_checkbox = new wxBoxSizer(wxHORIZONTAL);
|
||||
@ -59,14 +72,18 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater*
|
||||
wxString start_pa_str = _L("Start PA: ");
|
||||
wxString end_pa_str = _L("End PA: ");
|
||||
wxString PA_step_str = _L("PA step: ");
|
||||
wxString sp_accel_str = _L("Accelerations: ");
|
||||
wxString sp_speed_str = _L("Speeds: ");
|
||||
auto text_size = wxWindow::GetTextExtent(start_pa_str);
|
||||
text_size.IncTo(wxWindow::GetTextExtent(end_pa_str));
|
||||
text_size.IncTo(wxWindow::GetTextExtent(PA_step_str));
|
||||
text_size.x = text_size.x * 1.5;
|
||||
text_size.IncTo(wxWindow::GetTextExtent(sp_accel_str));
|
||||
text_size.IncTo(wxWindow::GetTextExtent(sp_speed_str));
|
||||
text_size.x = text_size.x * 1.1;
|
||||
wxStaticBoxSizer* settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _L("Settings"));
|
||||
|
||||
auto st_size = FromDIP(wxSize(text_size.x, -1));
|
||||
auto ti_size = FromDIP(wxSize(90, -1));
|
||||
auto ti_size = FromDIP(wxSize(140, -1));
|
||||
// start PA
|
||||
auto start_PA_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto start_pa_text = new wxStaticText(this, wxID_ANY, start_pa_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
@ -98,6 +115,27 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater*
|
||||
settings_sizer->Add(create_item_checkbox(_L("Print numbers"), this, &m_params.print_numbers, m_cbPrintNum));
|
||||
m_cbPrintNum->SetValue(false);
|
||||
|
||||
wxTextValidator val_list_validator(wxFILTER_INCLUDE_CHAR_LIST);
|
||||
val_list_validator.SetCharIncludes(wxString("0123456789,"));
|
||||
|
||||
auto sp_accel_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto sp_accel_text = new wxStaticText(this, wxID_ANY, sp_accel_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
m_tiBMAccels = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_PROCESS_ENTER);
|
||||
m_tiBMAccels->SetToolTip(_L("Comma-separated list of printing accelerations"));
|
||||
m_tiBMAccels->GetTextCtrl()->SetValidator(val_list_validator);
|
||||
sp_accel_sizer->Add(sp_accel_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
sp_accel_sizer->Add(m_tiBMAccels, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
settings_sizer->Add(sp_accel_sizer);
|
||||
|
||||
auto sp_speed_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto sp_speed_text = new wxStaticText(this, wxID_ANY, sp_speed_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
m_tiBMSpeeds = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_PROCESS_ENTER);
|
||||
m_tiBMSpeeds->SetToolTip(_L("Comma-separated list of printing speeds"));
|
||||
m_tiBMSpeeds->GetTextCtrl()->SetValidator(val_list_validator);
|
||||
sp_speed_sizer->Add(sp_speed_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
sp_speed_sizer->Add(m_tiBMSpeeds, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
settings_sizer->Add(sp_speed_sizer);
|
||||
|
||||
v_sizer->Add(settings_sizer);
|
||||
v_sizer->Add(0, FromDIP(10), 0, wxEXPAND, 5);
|
||||
m_btnStart = new Button(this, _L("OK"));
|
||||
@ -146,6 +184,8 @@ void PA_Calibration_Dlg::reset_params() {
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002));
|
||||
m_cbPrintNum->SetValue(true);
|
||||
m_cbPrintNum->Enable(true);
|
||||
m_tiBMAccels->Enable(false);
|
||||
m_tiBMSpeeds->Enable(false);
|
||||
break;
|
||||
case 2:
|
||||
m_params.mode = CalibMode::Calib_PA_Pattern;
|
||||
@ -153,6 +193,8 @@ void PA_Calibration_Dlg::reset_params() {
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.005));
|
||||
m_cbPrintNum->SetValue(true);
|
||||
m_cbPrintNum->Enable(false);
|
||||
m_tiBMAccels->Enable(true);
|
||||
m_tiBMSpeeds->Enable(true);
|
||||
break;
|
||||
default:
|
||||
m_params.mode = CalibMode::Calib_PA_Tower;
|
||||
@ -160,6 +202,8 @@ void PA_Calibration_Dlg::reset_params() {
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002));
|
||||
m_cbPrintNum->SetValue(false);
|
||||
m_cbPrintNum->Enable(false);
|
||||
m_tiBMAccels->Enable(false);
|
||||
m_tiBMSpeeds->Enable(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -197,6 +241,8 @@ void PA_Calibration_Dlg::on_start(wxCommandEvent& event) {
|
||||
}
|
||||
|
||||
m_params.print_numbers = m_cbPrintNum->GetValue();
|
||||
ParseStringValues(m_tiBMAccels->GetTextCtrl()->GetValue().ToStdString(), m_params.accelerations);
|
||||
ParseStringValues(m_tiBMSpeeds->GetTextCtrl()->GetValue().ToStdString(), m_params.speeds);
|
||||
|
||||
m_plater->calib_pa(m_params);
|
||||
EndModal(wxID_OK);
|
||||
|
@ -41,6 +41,8 @@ protected:
|
||||
TextInput* m_tiEndPA;
|
||||
TextInput* m_tiPAStep;
|
||||
CheckBox* m_cbPrintNum;
|
||||
TextInput* m_tiBMAccels;
|
||||
TextInput* m_tiBMSpeeds;
|
||||
Button* m_btnStart;
|
||||
|
||||
Plater* m_plater;
|
||||
|
@ -647,7 +647,8 @@ void CalibUtils::calib_pa_pattern(const CalibInfo &calib_info, Model& model)
|
||||
full_config.apply(printer_config);
|
||||
|
||||
Vec3d plate_origin(0, 0, 0);
|
||||
CalibPressureAdvancePattern pa_pattern(calib_info.params, full_config, true, model, plate_origin);
|
||||
auto *object = model.objects[0];
|
||||
CalibPressureAdvancePattern pa_pattern(calib_info.params, full_config, true, *object, plate_origin);
|
||||
|
||||
Pointfs bedfs = full_config.opt<ConfigOptionPoints>("printable_area")->values;
|
||||
double current_width = bedfs[2].x() - bedfs[0].x();
|
||||
@ -656,7 +657,7 @@ void CalibUtils::calib_pa_pattern(const CalibInfo &calib_info, Model& model)
|
||||
Vec3d offset = Vec3d(current_width / 2, current_depth / 2, 0) - half_pattern_size;
|
||||
pa_pattern.set_start_offset(offset);
|
||||
|
||||
pa_pattern.generate_custom_gcodes(full_config, true, model, plate_origin);
|
||||
model.plates_custom_gcodes[0] = pa_pattern.generate_custom_gcodes(full_config, true, *object, plate_origin);
|
||||
model.calib_pa_pattern = std::make_unique<CalibPressureAdvancePattern>(pa_pattern);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user