2014-06-05 11:45:40 -07:00
/ *
Copyright ( c ) 2014 , Lars Brubaker
All rights reserved .
Redistribution and use in source and binary forms , with or without
2015-04-08 15:20:10 -07:00
modification , are permitted provided that the following conditions are met :
2014-06-05 11:45:40 -07:00
1. Redistributions of source code must retain the above copyright notice , this
2015-04-08 15:20:10 -07:00
list of conditions and the following disclaimer .
2014-06-05 11:45:40 -07:00
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
2015-04-08 15:20:10 -07:00
and / or other materials provided with the distribution .
2014-06-05 11:45:40 -07:00
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
The views and conclusions contained in the software and documentation are those
2015-04-08 15:20:10 -07:00
of the authors and should not be interpreted as representing official policies ,
2014-06-05 11:45:40 -07:00
either expressed or implied , of the FreeBSD Project .
* /
2018-03-29 12:31:36 -07:00
using MatterHackers.Agg ;
2014-06-05 11:45:40 -07:00
using MatterHackers.Agg.UI ;
using MatterHackers.Localizations ;
2018-04-03 18:17:27 -07:00
using MatterHackers.MatterControl.PrinterCommunication.Io ;
2014-06-05 11:45:40 -07:00
using MatterHackers.MatterControl.SlicerConfiguration ;
2015-04-08 15:20:10 -07:00
using MatterHackers.VectorMath ;
using System ;
2017-05-19 14:39:57 -07:00
using System.Collections.Generic ;
2014-06-05 11:45:40 -07:00
2014-06-06 16:05:18 -07:00
namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling
2014-06-05 11:45:40 -07:00
{
2018-03-29 12:31:36 -07:00
public abstract class LevelWizardBase : SystemWindow
2015-04-08 15:20:10 -07:00
{
2018-03-29 18:12:02 -07:00
protected PrinterConfig printer ;
protected WizardControl printLevelWizard ;
private static SystemWindow printLevelWizardWindow ;
2017-09-05 10:33:14 -07:00
private LevelingStrings levelingStrings ;
2015-04-08 15:20:10 -07:00
2018-03-29 16:16:31 -07:00
public LevelWizardBase ( PrinterConfig printer , RuningState runningState )
2018-03-29 12:31:36 -07:00
: base ( 500 , 370 )
2015-04-08 15:20:10 -07:00
{
2017-09-15 12:08:00 -07:00
levelingStrings = new LevelingStrings ( printer . Settings ) ;
this . printer = printer ;
2015-04-08 15:20:10 -07:00
AlwaysOnTopOfMain = true ;
2018-03-29 12:31:36 -07:00
levelingStrings = new LevelingStrings ( printer . Settings ) ;
string printLevelWizardTitle = ApplicationController . Instance . ProductName ;
string printLevelWizardTitleFull = "Print Leveling Wizard" . Localize ( ) ;
Title = string . Format ( "{0} - {1}" , printLevelWizardTitle , printLevelWizardTitleFull ) ;
List < ProbePosition > probePositions = new List < ProbePosition > ( ProbeCount ) ;
2018-03-29 16:48:54 -07:00
for ( int j = 0 ; j < ProbeCount ; j + + )
2018-03-29 12:31:36 -07:00
{
probePositions . Add ( new ProbePosition ( ) ) ;
}
printLevelWizard = new WizardControl ( ) ;
AddChild ( printLevelWizard ) ;
if ( runningState = = LevelWizardBase . RuningState . InitialStartupCalibration )
2017-05-19 14:39:57 -07:00
{
2018-04-03 12:10:33 -07:00
string part1 = "Congratulations on connecting to your new printer. Before starting your first print we need to run a simple calibration procedure." . Localize ( ) ;
string part2 = "The next few screens will walk your through the print leveling wizard." . Localize ( ) ;
string requiredPageInstructions = $"{part1}\n\n{part2}" ;
2018-03-29 12:31:36 -07:00
printLevelWizard . AddPage ( new FirstPageInstructions ( printer , levelingStrings . initialPrinterSetupStepText , requiredPageInstructions ) ) ;
}
2018-04-03 12:10:33 -07:00
// To make sure the bed is at the correct temp, put in a filament selection page.
bool hasHeatedBed = printer . Settings . GetValue < bool > ( SettingsKey . has_heated_bed ) ;
2018-03-29 12:31:36 -07:00
bool useZProbe = printer . Settings . Helpers . UseZProbe ( ) ;
2018-04-03 12:10:33 -07:00
int zProbeSamples = printer . Settings . GetValue < int > ( SettingsKey . z_probe_samples ) ;
var secondsPerManualSpot = 10 * 3 ;
var secondsPerAutomaticSpot = 3 * zProbeSamples ;
var secondsToCompleteWizard = ProbeCount * ( useZProbe ? secondsPerAutomaticSpot : secondsPerManualSpot ) ;
secondsToCompleteWizard + = ( hasHeatedBed ? 60 * 3 : 0 ) ;
printLevelWizard . AddPage ( new FirstPageInstructions ( printer ,
"Print Leveling Overview" . Localize ( ) ,
levelingStrings . WelcomeText ( ProbeCount , ( int ) Math . Round ( secondsToCompleteWizard / 60.0 ) ) ) ) ;
2018-03-29 12:31:36 -07:00
if ( ! useZProbe )
{
printLevelWizard . AddPage ( new CleanExtruderInstructionPage ( printer , "Check Nozzle" . Localize ( ) , levelingStrings . CleanExtruder ) ) ;
}
if ( hasHeatedBed )
{
string filamentSelectionPage = "{0}\n\n{1}" . FormatWith ( levelingStrings . materialPageInstructions1 , levelingStrings . materialPageInstructions2 ) ;
printLevelWizard . AddPage ( new SelectMaterialPage ( printer , levelingStrings . materialStepText , filamentSelectionPage ) ) ;
}
2018-04-03 12:10:33 -07:00
2018-03-29 12:31:36 -07:00
printLevelWizard . AddPage ( new HomePrinterPage ( printer , printLevelWizard ,
levelingStrings . HomingPageStepText ,
2018-04-04 13:45:10 -07:00
levelingStrings . HomingPageInstructions ( useZProbe , hasHeatedBed ) ,
2018-03-29 12:31:36 -07:00
useZProbe ) ) ;
2018-04-04 13:45:10 -07:00
2018-03-29 12:31:36 -07:00
if ( hasHeatedBed )
{
printLevelWizard . AddPage ( new WaitForTempPage ( printer , printLevelWizard , levelingStrings ) ) ;
}
string positionLabel = "Position" . Localize ( ) ;
string autoCalibrateLabel = "Auto Calibrate" . Localize ( ) ;
string lowPrecisionLabel = "Low Precision" . Localize ( ) ;
string medPrecisionLabel = "Medium Precision" . Localize ( ) ;
string highPrecisionLabel = "High Precision" . Localize ( ) ;
2018-04-03 12:10:33 -07:00
double bedRadius = Math . Min ( printer . Settings . GetValue < Vector2 > ( SettingsKey . bed_size ) . X , printer . Settings . GetValue < Vector2 > ( SettingsKey . bed_size ) . Y ) / 2 ;
2018-03-29 12:31:36 -07:00
2018-04-03 12:10:33 -07:00
double startProbeHeight = printer . Settings . GetValue < double > ( SettingsKey . print_leveling_probe_start ) ;
2018-03-29 18:12:02 -07:00
int i = 0 ;
2018-03-29 16:48:54 -07:00
foreach ( var goalProbePosition in GetPrintLevelPositionToSample ( ) )
2018-03-29 12:31:36 -07:00
{
2018-04-03 12:10:33 -07:00
var validProbePosition = EnsureInPrintBounds ( printer . Settings , goalProbePosition ) ;
2018-03-29 12:31:36 -07:00
2018-04-03 12:10:33 -07:00
if ( printer . Settings . Helpers . UseZProbe ( ) )
2018-03-29 12:31:36 -07:00
{
2018-04-03 18:17:27 -07:00
var stepString = $"{" Step ".Localize()} {i + 1} {" of ".Localize()} {ProbeCount}:" ;
2018-03-29 16:48:54 -07:00
printLevelWizard . AddPage ( new AutoProbeFeedback ( printer , printLevelWizard , new Vector3 ( validProbePosition , startProbeHeight ) , string . Format ( "{0} {1} {2} - {3}" , stepString , positionLabel , i + 1 , autoCalibrateLabel ) , probePositions , i ) ) ;
2018-03-29 12:31:36 -07:00
}
else
2017-05-19 14:39:57 -07:00
{
2018-04-03 18:17:27 -07:00
printLevelWizard . AddPage ( new GetCoarseBedHeight ( printer , printLevelWizard , new Vector3 ( validProbePosition , startProbeHeight ) , string . Format ( "{0} {1} {2} - {3}" , levelingStrings . GetStepString ( TotalSteps ) , positionLabel , i + 1 , lowPrecisionLabel ) , probePositions , i , levelingStrings ) ) ;
printLevelWizard . AddPage ( new GetFineBedHeight ( printer , printLevelWizard , string . Format ( "{0} {1} {2} - {3}" , levelingStrings . GetStepString ( TotalSteps ) , positionLabel , i + 1 , medPrecisionLabel ) , probePositions , i , levelingStrings ) ) ;
printLevelWizard . AddPage ( new GetUltraFineBedHeight ( printer , printLevelWizard , string . Format ( "{0} {1} {2} - {3}" , levelingStrings . GetStepString ( TotalSteps ) , positionLabel , i + 1 , highPrecisionLabel ) , probePositions , i , levelingStrings ) ) ;
2017-05-19 14:39:57 -07:00
}
2018-03-29 16:48:54 -07:00
i + + ;
2017-05-19 14:39:57 -07:00
}
2018-03-29 12:31:36 -07:00
printLevelWizard . AddPage ( new LastPagelInstructions ( printer , printLevelWizard , "Done" . Localize ( ) , levelingStrings . DoneInstructions , probePositions ) ) ;
}
2018-03-29 18:12:02 -07:00
public enum RuningState { InitialStartupCalibration , UserRequestedCalibration }
2018-03-29 16:48:54 -07:00
2018-03-29 18:12:02 -07:00
public abstract int ProbeCount { get ; }
public int TotalSteps = > ProbeCount * 3 ;
2018-03-29 12:31:36 -07:00
2017-09-15 12:08:00 -07:00
public static void ShowPrintLevelWizard ( PrinterConfig printer )
2016-04-18 11:31:31 -07:00
{
LevelWizardBase . RuningState runningState = LevelWizardBase . RuningState . UserRequestedCalibration ;
2017-09-15 12:08:00 -07:00
if ( printer . Settings . GetValue < bool > ( SettingsKey . print_leveling_required_to_print ) )
2016-04-18 11:31:31 -07:00
{
// run in the first run state
runningState = LevelWizardBase . RuningState . InitialStartupCalibration ;
}
2017-09-15 12:08:00 -07:00
ShowPrintLevelWizard ( printer , runningState ) ;
2016-04-18 11:31:31 -07:00
}
2017-09-15 12:08:00 -07:00
public static void ShowPrintLevelWizard ( PrinterConfig printer , LevelWizardBase . RuningState runningState )
2015-04-08 15:20:10 -07:00
{
if ( printLevelWizardWindow = = null )
{
2018-04-03 18:17:27 -07:00
// turn off print leveling
PrintLevelingStream . AlowLeveling = false ;
2017-09-15 12:08:00 -07:00
printLevelWizardWindow = LevelWizardBase . CreateAndShowWizard ( printer , runningState ) ;
2018-04-03 18:17:27 -07:00
2015-04-08 15:20:10 -07:00
printLevelWizardWindow . Closed + = ( sender , e ) = >
{
2018-04-03 18:17:27 -07:00
// If leveling was on when we started, make sure it is on when we are done.
PrintLevelingStream . AlowLeveling = true ;
2015-04-08 15:20:10 -07:00
printLevelWizardWindow = null ;
2017-06-07 15:56:02 -07:00
2018-03-29 18:12:02 -07:00
// make sure we raise the probe on close
2017-09-15 12:08:00 -07:00
if ( printer . Settings . GetValue < bool > ( SettingsKey . has_z_probe )
& & printer . Settings . GetValue < bool > ( SettingsKey . use_z_probe )
& & printer . Settings . GetValue < bool > ( SettingsKey . has_z_servo ) )
2017-06-07 15:56:02 -07:00
{
// make sure the servo is retracted
2017-09-15 12:08:00 -07:00
var servoRetract = printer . Settings . GetValue < double > ( SettingsKey . z_servo_retracted_angle ) ;
2018-01-04 17:30:48 -08:00
printer . Connection . QueueLine ( $"M280 P0 S{servoRetract}" ) ;
2017-06-07 15:56:02 -07:00
}
2015-04-08 15:20:10 -07:00
} ;
}
else
{
printLevelWizardWindow . BringToFront ( ) ;
}
}
2018-03-29 18:12:02 -07:00
public abstract IEnumerable < Vector2 > GetPrintLevelPositionToSample ( ) ;
2017-09-15 12:08:00 -07:00
private static LevelWizardBase CreateAndShowWizard ( PrinterConfig printer , LevelWizardBase . RuningState runningState )
2015-04-08 15:20:10 -07:00
{
2016-10-11 14:56:36 -07:00
// clear any data that we are going to be acquiring (sampled positions, after z home offset)
2018-04-03 18:17:27 -07:00
PrintLevelingData levelingData = new PrintLevelingData ( )
{
LevelingSystem = printer . Settings . GetValue < LevelingSystem > ( SettingsKey . print_leveling_solution )
} ;
2017-09-15 12:08:00 -07:00
printer . Settings . SetValue ( SettingsKey . baby_step_z_offset , "0" ) ;
2017-02-22 16:16:40 -08:00
2015-04-08 15:20:10 -07:00
LevelWizardBase printLevelWizardWindow ;
2018-03-30 14:48:55 -07:00
switch ( levelingData . LevelingSystem )
2015-04-08 15:20:10 -07:00
{
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe3Points :
2017-09-15 12:08:00 -07:00
printLevelWizardWindow = new LevelWizard3Point ( printer , runningState ) ;
2015-04-08 15:20:10 -07:00
break ;
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe7PointRadial :
2017-09-15 12:08:00 -07:00
printLevelWizardWindow = new LevelWizard7PointRadial ( printer , runningState ) ;
2015-08-01 14:44:53 -07:00
break ;
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe13PointRadial :
2017-09-15 12:08:00 -07:00
printLevelWizardWindow = new LevelWizard13PointRadial ( printer , runningState ) ;
2015-08-05 11:12:01 -07:00
break ;
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe3x3Mesh :
2017-09-15 12:08:00 -07:00
printLevelWizardWindow = new LevelWizard3x3Mesh ( printer , runningState ) ;
2017-05-19 14:39:57 -07:00
break ;
2018-04-04 13:45:10 -07:00
case LevelingSystem . Probe5x5Mesh :
printLevelWizardWindow = new LevelWizard5x5Mesh ( printer , runningState ) ;
break ;
2015-04-08 15:20:10 -07:00
default :
throw new NotImplementedException ( ) ;
}
printLevelWizardWindow . ShowAsSystemWindow ( ) ;
return printLevelWizardWindow ;
}
2018-03-29 18:12:02 -07:00
private Vector2 EnsureInPrintBounds ( PrinterSettings printerSettings , Vector2 probePosition )
{
// check that the position is within the printing arrea and if not move it back in
if ( printerSettings . Helpers . UseZProbe ( ) )
{
var probeOffset = printer . Settings . GetValue < Vector2 > ( SettingsKey . z_probe_xy_offset ) ;
2018-04-04 14:57:59 -07:00
var actualNozzlePosition = probePosition - probeOffset ;
2018-03-29 18:12:02 -07:00
// clamp this to the bed bounds
2018-04-04 14:57:59 -07:00
Vector2 bedSize = printer . Settings . GetValue < Vector2 > ( SettingsKey . bed_size ) ;
Vector2 printCenter = printer . Settings . GetValue < Vector2 > ( SettingsKey . print_center ) ;
RectangleDouble bedBounds = new RectangleDouble ( printCenter - bedSize / 2 , printCenter + bedSize / 2 ) ;
Vector2 adjustedPostion = bedBounds . Clamp ( actualNozzlePosition ) ;
2018-03-29 18:12:02 -07:00
// and push it back into the probePosition
2018-04-04 14:57:59 -07:00
probePosition = adjustedPostion + probeOffset ;
2018-03-29 18:12:02 -07:00
}
return probePosition ;
}
2015-04-08 15:20:10 -07:00
}
2018-03-29 18:12:02 -07:00
// this class is so that it is not passed by value
public class ProbePosition
2015-04-08 15:20:10 -07:00
{
2018-03-29 18:12:02 -07:00
public Vector3 position ;
2015-04-08 15:20:10 -07:00
}
}