add calibration cubes

update to flow calibration scaling
This commit is contained in:
supermerill 2020-05-28 18:07:54 +02:00
parent 3404430ef7
commit ffec4ee330
12 changed files with 192 additions and 24 deletions

View File

@ -0,0 +1,2 @@
voron_design_cube_v6.amf is under GPL V3, made by vorondesign (https://github.com/VoronDesign/Voron-2)
xyzCalibration_cube is under CC BY-SA 3.0, made by iDig3Dprinting (https://www.thingiverse.com/thing:1278865)

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Calibration cube</title>
</head>
<body>
<h1>Calibration cube</h1>
<p>This page allow you to print the loved calibration cube. It's useful to see if your printer is accurate, and calibrate some settings. First thing is to select your goal.</p>
<h2>Goal: Dimensional accuracy</h2>
<p>You have to print two cubes, with different sizes. If the dimensional inaccuracy scale with the size of the cubes, then it's the steps/mm of your steppers that needs some adjustments (note: if it's the case, you should also adjust the flow, and maybe redo some calibrations if the change is big). If it doesn't scale, you can correct it by adjusting your xy compensation (slicing tab). With the voron cube, you can also test the hole calibration, as these are often too small.</p>
<h2>Goal: infill/perimeter overlap</h2>
<p>This test is about to see if the pattern of the infill can be seen on the perimeters. Try to reduce it as low as you can but check the top solid fill, as it can create artifacts if it's too low. It's better with the standard cube, as you have a larger top surface.</p>
<h2>Goal: external perimeter overlap</h2>
<p>As the external perimeter is printed last, the real position depends on the position and flow of the whole layer. So you have to be sure that your flow is perfect before doing this test. The main difference is between solid infill layers and sparse infill layers, as the solid one can push the external perimeter outwards. Decreasing the infill/perimeter overlap, decreasing the external perimeter overlap can help to reduce this effect.</p>
<h2>Notes</h2>
<p>These tests should be the last ones.</p>
<p>Default size of the standard cube is 20mm and the standard size of the voron cube is 30mm.</p>
<p>Licence for the standard calibration cube: CC BY-SA 3.0, <a href="https://www.thingiverse.com/thing:1278865">made by iDig3Dprinting</a></p>
<p>Licence for the voron calibration cube: GPL V3, <a href="https://github.com/VoronDesign/Voron-2">made by vorondesign</a></p>
</body>
</html>

Binary file not shown.

Binary file not shown.

View File

@ -48,7 +48,6 @@
<h2>Notes</h2>
<p>Most of the calibrations need to done is the right order. This one should be the third.</p>
<p>The temperature numbers will only be shown between 180 and 285. Higher or lower values won't be displayed but the test will be conducted successfully, you just have to remember them.</p>
<p>This tower is made with the 3D model created by gaaZolee and available here https://www.thingiverse.com/thing:2729076 with the CC BY-SA 3.0 licence.<p>
<p>Licence for models used for this calibration test: CC BY-SA 3.0</p>
<p>This tower is made with the 3D model <a href="https://www.thingiverse.com/thing:2729076">created by gaaZolee</a> with the CC BY-SA 3.0 licence.<p>
</body>
</html>

View File

@ -24,6 +24,8 @@ set(SLIC3R_GUI_SOURCES
GUI/CalibrationBedDialog.hpp
GUI/CalibrationBridgeDialog.cpp
GUI/CalibrationBridgeDialog.hpp
GUI/CalibrationCubeDialog.cpp
GUI/CalibrationCubeDialog.hpp
GUI/CalibrationFlowDialog.cpp
GUI/CalibrationFlowDialog.hpp
GUI/CalibrationOverBridgeDialog.cpp

View File

@ -0,0 +1,107 @@
#include "CalibrationCubeDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include "GUI_ObjectList.hpp"
#include "Tab.hpp"
#include <wx/scrolwin.h>
#include <wx/display.h>
#include <wx/file.h>
#include "wxExtensions.hpp"
#if ENABLE_SCROLLABLE
static wxSize get_screen_size(wxWindow* window)
{
const auto idx = wxDisplay::GetFromWindow(window);
wxDisplay display(idx != wxNOT_FOUND ? idx : 0u);
return display.GetClientArea().GetSize();
}
#endif // ENABLE_SCROLLABLE
namespace Slic3r {
namespace GUI {
void CalibrationCubeDialog::create_buttons(wxStdDialogButtonSizer* buttons){
wxString choices_scale[] = { "10mm", "20mm", "30mm", "40mm" };
scale = new wxComboBox(this, wxID_ANY, wxString{ "20mm" }, wxDefaultPosition, wxDefaultSize, 4, choices_scale);
scale->SetToolTip(_(L("You can choose the dimension of the cube. It's a simple scale, you can modify it in the right panel yourself if you prefer. It's just quicker to select it here.")));
scale->SetSelection(1);
wxString choices_goal[] = { "Dimensional accuracy (default)" , "infill/perimeter overlap", "external perimeter overlap"};
calibrate = new wxComboBox(this, wxID_ANY, wxString{ "Dimensional accuracy (default)" }, wxDefaultPosition, wxDefaultSize, 3, choices_goal);
calibrate->SetToolTip(_(L("Select a goal, this will change settings to increase the effects to search.")));
calibrate->SetSelection(0);
buttons->Add(new wxStaticText(this, wxID_ANY, wxString{ "dimension:" }));
buttons->Add(scale);
buttons->AddSpacer(40);
buttons->Add(new wxStaticText(this, wxID_ANY, wxString{ "goal:" }));
buttons->Add(calibrate);
buttons->AddSpacer(40);
wxButton* bt = new wxButton(this, wxID_FILE1, _(L("Standard Cube")));
bt->Bind(wxEVT_BUTTON, &CalibrationCubeDialog::create_geometry_standard, this);
bt->SetToolTip(_(L("Standard cubic xyz cube, with a flat top. Better for infill/perimeter overlap calibration.")));
buttons->Add(bt);
buttons->AddSpacer(10);
bt = new wxButton(this, wxID_FILE1, _(L("Voron Cube")));
bt->Bind(wxEVT_BUTTON, &CalibrationCubeDialog::create_geometry_voron, this);
bt->SetToolTip(_(L("Voron cubic cube with many features inside, with a bearing slot on top. Better to check dimensional accuracy.")));
buttons->Add(bt);
}
void CalibrationCubeDialog::create_geometry(std::string calibration_path) {
Plater* plat = this->main_frame->plater();
Model& model = plat->model();
plat->reset();
std::vector<size_t> objs_idx = plat->load_files(std::vector<std::string>{
Slic3r::resources_dir()+"/calibration/cube/"+ calibration_path}, true, false);
assert(objs_idx.size() == 1);
const DynamicPrintConfig* printConfig = this->gui_app->get_tab(Preset::TYPE_PRINT)->get_config();
const DynamicPrintConfig* filamentConfig = this->gui_app->get_tab(Preset::TYPE_FILAMENT)->get_config();
const DynamicPrintConfig* printerConfig = this->gui_app->get_tab(Preset::TYPE_PRINTER)->get_config();
/// --- scale ---
//model is created for a 0.4 nozzle, scale xy with nozzle size.
const ConfigOptionFloats* nozzle_diameter_config = printerConfig->option<ConfigOptionFloats>("nozzle_diameter");
assert(nozzle_diameter_config->values.size() > 0);
float nozzle_diameter = nozzle_diameter_config->values[0];
float cube_size = 30;
if (calibration_path == "xyzCalibration_cube.amf")
cube_size = 20;
int idx_scale = scale->GetSelection();
float xyzScale = (10/cube_size) * (idx_scale+1);
//do scaling
model.objects[objs_idx[0]]->scale(xyzScale, xyzScale, xyzScale);
/// --- translate ---
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 });
/// --- custom config ---
int idx_goal = calibrate->GetSelection();
if (idx_goal == 1) {
model.objects[objs_idx[0]]->config.set_key_value("perimeters", new ConfigOptionInt(1));
model.objects[objs_idx[0]]->config.set_key_value("fill_pattern", new ConfigOptionEnum<InfillPattern>(ipCubic));
} else if (idx_goal == 2) {
model.objects[objs_idx[0]]->config.set_key_value("perimeters", new ConfigOptionInt(3));
//add full solid layers
}
//update plater
plat->changed_objects(objs_idx);
plat->is_preview_shown();
//update everything, easier to code.
ObjectList* obj = this->gui_app->obj_list();
obj->update_after_undo_redo();
plat->reslice();
plat->select_view_3D("Preview");
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,30 @@
#ifndef slic3r_GUI_CalibrationCubeDialog_hpp_
#define slic3r_GUI_CalibrationCubeDialog_hpp_
#include "CalibrationAbstractDialog.hpp"
namespace Slic3r {
namespace GUI {
class CalibrationCubeDialog : public CalibrationAbstractDialog
{
public:
CalibrationCubeDialog(GUI_App* app, MainFrame* mainframe) : CalibrationAbstractDialog(app, mainframe, "Calibration cube") { create("/calibration/cube/cube.html"); }
virtual ~CalibrationCubeDialog(){ }
protected:
void create_buttons(wxStdDialogButtonSizer* sizer) override;
void create_geometry(std::string cube_path);
void create_geometry_voron(wxCommandEvent& event_args) { create_geometry("voron_design_cube_v6.amf"); }
void create_geometry_standard(wxCommandEvent& event_args) { create_geometry("xyzCalibration_cube.amf"); }
wxComboBox* scale;
wxComboBox* calibrate;
};
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -54,9 +54,12 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
float nozzle_diameter = nozzle_diameter_config->values[0];
float xyScale = nozzle_diameter / 0.4;
//scale z to have 6 layers
const ConfigOptionFloatOrPercent* first_layer_height = printConfig->option<ConfigOptionFloatOrPercent>("first_layer_height");
const ConfigOptionFloat* layer_height = printConfig->option<ConfigOptionFloat>("layer_height");
float zscale = first_layer_height->get_abs_value(nozzle_diameter) + 5 * layer_height->value;
const ConfigOptionFloatOrPercent* first_layer_height_setting = printConfig->option<ConfigOptionFloatOrPercent>("first_layer_height");
double first_layer_height = first_layer_height_setting->get_abs_value(nozzle_diameter);
double layer_height = nozzle_diameter / 2.;
first_layer_height = std::max(first_layer_height, nozzle_diameter / 2.);
float zscale = first_layer_height + 5 * layer_height;
zscale *= (1 + 0.3 * (10. / delta));
//do scaling
if (xyScale < 0.9 || 1.2 < xyScale) {
@ -69,18 +72,19 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
//add sub-part after scale
float zshift = (1 - zscale) / 2;
float zscale_number = (first_layer_height + layer_height) / 0.4;
if (delta == 10.f && start == 80.f) {
add_part(model.objects[objs_idx[0]], Slic3r::resources_dir()+"/calibration/filament_flow/m20.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[1]], Slic3r::resources_dir()+"/calibration/filament_flow/m10.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[2]], Slic3r::resources_dir()+"/calibration/filament_flow/_0.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[3]], Slic3r::resources_dir()+"/calibration/filament_flow/p10.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[4]], Slic3r::resources_dir()+"/calibration/filament_flow/p20.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[0]], Slic3r::resources_dir()+"/calibration/filament_flow/m20.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number});
add_part(model.objects[objs_idx[1]], Slic3r::resources_dir()+"/calibration/filament_flow/m10.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
add_part(model.objects[objs_idx[2]], Slic3r::resources_dir()+"/calibration/filament_flow/_0.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
add_part(model.objects[objs_idx[3]], Slic3r::resources_dir()+"/calibration/filament_flow/p10.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
add_part(model.objects[objs_idx[4]], Slic3r::resources_dir()+"/calibration/filament_flow/p20.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
} else if (delta == 2.f && start == 92.f) {
add_part(model.objects[objs_idx[0]], Slic3r::resources_dir()+"/calibration/filament_flow/m8.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[1]], Slic3r::resources_dir()+"/calibration/filament_flow/m6.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[2]], Slic3r::resources_dir()+"/calibration/filament_flow/m4.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[3]], Slic3r::resources_dir()+"/calibration/filament_flow/m2.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[4]], Slic3r::resources_dir()+"/calibration/filament_flow/_0.amf", Vec3d{ 9,0,zshift });
add_part(model.objects[objs_idx[0]], Slic3r::resources_dir()+"/calibration/filament_flow/m8.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
add_part(model.objects[objs_idx[1]], Slic3r::resources_dir()+"/calibration/filament_flow/m6.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
add_part(model.objects[objs_idx[2]], Slic3r::resources_dir()+"/calibration/filament_flow/m4.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
add_part(model.objects[objs_idx[3]], Slic3r::resources_dir()+"/calibration/filament_flow/m2.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
add_part(model.objects[objs_idx[4]], Slic3r::resources_dir()+"/calibration/filament_flow/_0.amf", Vec3d{ 3 + 6 * xyScale,0,zshift }, Vec3d{ 1,1, zscale_number });
}
for (size_t i = 0; i < 5; i++) {
add_part(model.objects[objs_idx[i]], Slic3r::resources_dir()+"/calibration/filament_flow/O.amf", Vec3d{ 0,0,zscale/2.f + 0.5 }, Vec3d{1,1,xyScale });
@ -118,14 +122,8 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) {
model.objects[objs_idx[i]]->config.set_key_value("thin_walls", new ConfigOptionBool(true));
model.objects[objs_idx[i]]->config.set_key_value("thin_walls_min_width", new ConfigOptionFloatOrPercent(50,true));
model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(true));
model.objects[objs_idx[i]]->config.set_key_value("layer_height", new ConfigOptionFloat(nozzle_diameter/2));
if (nozzle_diameter < 0.3) {
//ensure that the first layer is good and safe, mandatory as we mess wit the first_layer_height.
model.objects[objs_idx[i]]->config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(nozzle_diameter, false));
model.objects[objs_idx[i]]->config.set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(150, true));
} else {
model.objects[objs_idx[i]]->config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(std::max(0.2f, nozzle_diameter / 2), false));
}
model.objects[objs_idx[i]]->config.set_key_value("layer_height", new ConfigOptionFloat(layer_height));
model.objects[objs_idx[i]]->config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(first_layer_height, false));
model.objects[objs_idx[i]]->config.set_key_value("external_infill_margin", new ConfigOptionFloatOrPercent(100, true));
model.objects[objs_idx[i]]->config.set_key_value("solid_fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinearWGapFill));
model.objects[objs_idx[i]]->config.set_key_value("top_fill_pattern", new ConfigOptionEnum<InfillPattern>(ipSmooth));

View File

@ -42,6 +42,7 @@
#include "slic3r/Config/Snapshot.hpp"
#include "CalibrationBedDialog.hpp"
#include "CalibrationBridgeDialog.hpp"
#include "CalibrationCubeDialog.hpp"
#include "CalibrationFlowDialog.hpp"
#include "CalibrationOverBridgeDialog.hpp"
#include "CalibrationTempDialog.hpp"
@ -592,6 +593,10 @@ void GUI_App::filament_temperature_dialog()
{
change_calibration_dialog(nullptr, new CalibrationTempDialog(this, mainframe));
}
void GUI_App::calibration_cube_dialog()
{
change_calibration_dialog(nullptr, new CalibrationCubeDialog(this, mainframe));
}
// static method accepting a wxWindow object as first parameter
bool GUI_App::catch_error(std::function<void()> cb,

View File

@ -137,6 +137,7 @@ public:
void filament_temperature_dialog();
void bridge_tuning_dialog();
void over_bridge_dialog();
void calibration_cube_dialog();
//void support_tuning(); //have to do multiple, in a submenu
void load_project(wxWindow *parent, wxString& input_file) const;
void import_model(wxWindow *parent, wxArrayString& input_files) const;

View File

@ -775,7 +775,9 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { wxGetApp().bridge_tuning_dialog(); });
append_menu_item(objectsMenu, wxID_ANY, _(L("Ironing pattern calibration")), _(L("Create a test print to help you to set your over-bridge flow ratio and ironing pattern.")),
[this](wxCommandEvent&) { wxGetApp().over_bridge_dialog(); });
append_menu_item(objectsMenu, wxID_ANY, _(L("Calibration cube")), _(L("Print a calibration cube, for various calibration goals.")),
[this](wxCommandEvent&) { wxGetApp().calibration_cube_dialog(); });
}
// Help menu