mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	time estimator wip
This commit is contained in:
		
							parent
							
								
									7308017ee8
								
							
						
					
					
						commit
						bc3d184d7c
					
				
					 4 changed files with 876 additions and 2 deletions
				
			
		|  | @ -60,7 +60,6 @@ include(${PerlEmbed_TEMP_INCLUDE}) | |||
| file(REMOVE ${PerlEmbed_TEMP_INCLUDE}) | ||||
| unset(PerlEmbed_TEMP_INCLUDE) | ||||
| 
 | ||||
| if (PerlEmbed_DEBUG) | ||||
|   # First show the configuration extracted by FindPerl & FindPerlLibs: | ||||
|   message(STATUS " PERL_INCLUDE_PATH      = ${PERL_INCLUDE_PATH}") | ||||
|   message(STATUS " PERL_LIBRARY           = ${PERL_LIBRARY}") | ||||
|  | @ -79,7 +78,6 @@ if (PerlEmbed_DEBUG) | |||
|   message(STATUS " LD                     = ${PerlEmbed_LD}") | ||||
|   message(STATUS " PerlEmbed_LDFLAGS      = ${PerlEmbed_LDFLAGS}") | ||||
|   message(STATUS " PerlEmbed_LDDLFLAGS    = ${PerlEmbed_LDDLFLAGS}") | ||||
| endif() | ||||
| 
 | ||||
| include(FindPackageHandleStandardArgs) | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,6 +5,13 @@ | |||
| #include "GCode/PrintExtents.hpp" | ||||
| #include "GCode/WipeTowerPrusaMM.hpp" | ||||
| 
 | ||||
| //############################################################################################################
 | ||||
| #include "GCodeTimeEstimator.hpp" | ||||
| #ifdef WIN32 | ||||
| #include "enrico/wintimer.h" | ||||
| #endif // WIN32
 | ||||
| //############################################################################################################
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <cstdlib> | ||||
| #include <math.h> | ||||
|  | @ -374,6 +381,87 @@ bool GCode::do_export(Print *print, const char *path) | |||
| 
 | ||||
|     if (! result) | ||||
|         boost::nowide::remove(path_tmp.c_str()); | ||||
| 
 | ||||
| //############################################################################################################
 | ||||
| #ifdef WIN32 | ||||
|     WinTimer timer; | ||||
|     timer.Start(); | ||||
| #endif // WIN32
 | ||||
| 
 | ||||
|     My_GCodeTimeEstimator timeEstimator; | ||||
|     timeEstimator.parse_file(path); | ||||
| #ifdef WIN32 | ||||
|     double timeParse = timer.GetElapsedTimeSec(); | ||||
| #endif // WIN32
 | ||||
|     timeEstimator.calculate_time(); | ||||
| #ifdef WIN32 | ||||
|     double timeCalculate = timer.GetElapsedTimeSec(); | ||||
| #endif // WIN32
 | ||||
|     std::cout << std::endl << ">>> estimated time: " << timeEstimator.get_time() << " seconds." << std::endl << std::endl; | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
|     std::cout << std::endl << "parse_file() -> Time: " << timeParse << std::endl << std::endl; | ||||
|     std::cout << std::endl << "calculate_file() -> Time: " << timeCalculate - timeParse << std::endl << std::endl; | ||||
| #endif // WIN32
 | ||||
| 
 | ||||
| /*
 | ||||
|     unsigned int i = 0; | ||||
|     const My_GCodeTimeEstimator::BlocksList& blocks = timeEstimator.get_blocks(); | ||||
|     float maxXYZ[3] = { 0.0f, 0.0f, 0.0f }; | ||||
|     unsigned int maxID[3] = { 0, 0, 0 }; | ||||
|     for (const My_GCodeTimeEstimator::Block& block : blocks) | ||||
|     { | ||||
|       ++i; | ||||
|       std::cout << std::endl << "Block: "  | ||||
|                              << i  | ||||
|                              << " ("  | ||||
|                              << block.delta_pos[My_GCodeTimeEstimator::X]  | ||||
|                              << ", "  | ||||
|                              << block.delta_pos[My_GCodeTimeEstimator::Y]  | ||||
|                              << ", "  | ||||
|                              << block.delta_pos[My_GCodeTimeEstimator::Z]  | ||||
|                              << ") - f: " | ||||
|                              << block.feedrate | ||||
|                              << " - a: " | ||||
|                              << block.acceleration | ||||
|                              << " - s: (" | ||||
|                              << block.entry_feedrate | ||||
|                              << ", " | ||||
|                              << block.exit_feedrate | ||||
|                              << ")" | ||||
|                              << std::endl; | ||||
| 
 | ||||
|       float dx = ::abs(block.delta_pos[My_GCodeTimeEstimator::X]); | ||||
|       float dy = ::abs(block.delta_pos[My_GCodeTimeEstimator::Y]); | ||||
|       float dz = ::abs(block.delta_pos[My_GCodeTimeEstimator::Z]); | ||||
| 
 | ||||
|       if (maxXYZ[My_GCodeTimeEstimator::X] < dx) | ||||
|       { | ||||
|         maxXYZ[My_GCodeTimeEstimator::X] = dx; | ||||
|         maxID[My_GCodeTimeEstimator::X] = i; | ||||
|       } | ||||
| 
 | ||||
|       if (maxXYZ[My_GCodeTimeEstimator::Y] < dy) | ||||
|       { | ||||
|         maxXYZ[My_GCodeTimeEstimator::Y] = dy; | ||||
|         maxID[My_GCodeTimeEstimator::Y] = i; | ||||
|       } | ||||
| 
 | ||||
|       if (maxXYZ[My_GCodeTimeEstimator::Z] < dz) | ||||
|       { | ||||
|         maxXYZ[My_GCodeTimeEstimator::Z] = dz; | ||||
|         maxID[My_GCodeTimeEstimator::Z] = i; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     std::cout << std::endl << "MAX DX: " << maxID[My_GCodeTimeEstimator::X] << " - " << maxXYZ[My_GCodeTimeEstimator::X] << std::endl; | ||||
|     std::cout << std::endl << "MAX DY: " << maxID[My_GCodeTimeEstimator::Y] << " - " << maxXYZ[My_GCodeTimeEstimator::Y] << std::endl; | ||||
|     std::cout << std::endl << "MAX DZ: " << maxID[My_GCodeTimeEstimator::Z] << " - " << maxXYZ[My_GCodeTimeEstimator::Z] << std::endl; | ||||
| 
 | ||||
|     timeEstimator.print_counters(); | ||||
| */ | ||||
| //############################################################################################################
 | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,8 +2,592 @@ | |||
| #include <boost/bind.hpp> | ||||
| #include <cmath> | ||||
| 
 | ||||
| //###########################################################################################################
 | ||||
| #include <fstream> | ||||
| static const std::string AXIS_STR = "XYZE"; | ||||
| static const float MMMIN_TO_MMSEC = 1.0f / 60.0f; | ||||
| static const float MILLISEC_TO_SEC = 0.001f; | ||||
| static const float INCHES_TO_MM = 25.4f; | ||||
| static const float DEFAULT_FEEDRATE = 0.0f; // <<<<<<<<< FIND A PROPER VALUE
 | ||||
| static const float DEFAULT_ACCELERATION = 3000.0f; | ||||
| static const float DEFAULT_AXIS_MAX_FEEDRATE[] = { 600.0f, 600.0f, 40.0f, 25.0f }; | ||||
| static const float DEFAULT_AXIS_MAX_ACCELERATION[] = { 9000.0f, 9000.0f, 100.0f, 10000.0f }; | ||||
| 
 | ||||
| static const float DEFAULT_AXIS_MAX_JERK[] = { 10.0f, 10.0f, 0.2f, 2.5f }; // from firmware
 | ||||
| // static const float DEFAULT_AXIS_MAX_JERK[] = { 20.0f, 20.0f, 0.4f, 5.0f }; / from CURA
 | ||||
| 
 | ||||
| static const float MINIMUM_FEEDRATE = 0.01f; | ||||
| static const float MINIMUM_PLANNER_SPEED = 0.05f; // <<<<<<<< WHAT IS THIS ???
 | ||||
| static const float FEEDRATE_THRESHOLD = 0.0001f; | ||||
| //###########################################################################################################
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| //###########################################################################################################
 | ||||
|   float My_GCodeTimeEstimator::Block::move_length() const | ||||
|   { | ||||
|     float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); | ||||
|     return (length > 0.0f) ? length : ::abs(delta_pos[E]); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::Block::calculate_trapezoid() | ||||
|   { | ||||
|     float accelerate_distance = estimate_acceleration_distance(entry_feedrate, feedrate, acceleration); | ||||
|     float decelerate_distance = estimate_acceleration_distance(feedrate, exit_feedrate, -acceleration); | ||||
| 
 | ||||
|     float distance = move_length(); | ||||
| 
 | ||||
|     float plateau_distance = distance - accelerate_distance - decelerate_distance; | ||||
| 
 | ||||
|     // Not enough space to reach the nominal feedrate.
 | ||||
|     // This means no cruising, and we'll have to use intersection_distance() to calculate when to abort acceleration 
 | ||||
|     // and start braking in order to reach the exit_feedrate exactly at the end of this block.
 | ||||
|     if (plateau_distance < 0.0f) | ||||
|     { | ||||
|       accelerate_distance = clamp(0.0f, distance, intersection_distance(entry_feedrate, exit_feedrate, acceleration, distance)); | ||||
|       plateau_distance = 0.0f; | ||||
|     } | ||||
| 
 | ||||
|     trapezoid.distance = distance; | ||||
|     trapezoid.accelerate_until = accelerate_distance; | ||||
|     trapezoid.decelerate_after = accelerate_distance + plateau_distance; | ||||
|     trapezoid.entry_feedrate = entry_feedrate; | ||||
|     trapezoid.exit_feedrate = exit_feedrate; | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::Block::max_allowable_speed(float acceleration, float target_velocity, float distance) | ||||
|   { | ||||
|     return ::sqrt(sqr(target_velocity) - 2.0f * acceleration * distance); | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::Block::estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration) | ||||
|   { | ||||
|     return (acceleration == 0.0f) ? 0.0f : (sqr(target_rate) - sqr(initial_rate)) / (2.0f * acceleration); | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::Block::intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) | ||||
|   { | ||||
|     return (acceleration == 0.0f) ? 0.0f : (2.0f * acceleration * distance - sqr(initial_rate) + sqr(final_rate)) / (4.0f * acceleration); | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::Block::acceleration_time_from_distance(float initial_feedrate, float distance, float acceleration) | ||||
|   { | ||||
|     float discriminant = sqr(initial_feedrate) + 2.0f * acceleration * distance; | ||||
| 
 | ||||
|     // If discriminant is negative, we're moving in the wrong direction.
 | ||||
|     // Making the discriminant 0 then gives the extremum of the parabola instead of the intersection.
 | ||||
|     discriminant = std::max(0.0f, discriminant); | ||||
|     return (-initial_feedrate + ::sqrt(discriminant)) / acceleration; | ||||
|   } | ||||
| 
 | ||||
|   My_GCodeTimeEstimator::My_GCodeTimeEstimator() | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::parse(const std::string& gcode) | ||||
|   { | ||||
|     _reset(); | ||||
|     GCodeReader::parse(gcode, boost::bind(&My_GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::parse_file(const std::string& file) | ||||
|   { | ||||
|     _reset(); | ||||
|     GCodeReader::parse_file(file, boost::bind(&My_GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::calculate_time() | ||||
|   { | ||||
|     _time = get_additional_time(); | ||||
| 
 | ||||
|     for (const Block& block : _blocks) | ||||
|     { | ||||
|       const Block::Trapezoid& trapezoid = block.trapezoid; | ||||
|       float plateau_distance = trapezoid.decelerate_after - trapezoid.accelerate_until; | ||||
| 
 | ||||
|       _time += Block::acceleration_time_from_distance(block.entry_feedrate, trapezoid.accelerate_until, block.acceleration); | ||||
|       _time += plateau_distance / block.feedrate; | ||||
|       _time += Block::acceleration_time_from_distance(block.exit_feedrate, (trapezoid.distance - trapezoid.decelerate_after), block.acceleration); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_axis_position(EAxis axis, float position) | ||||
|   { | ||||
|     _state.axis[axis].position = position; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec) | ||||
|   { | ||||
|     _state.axis[axis].max_feedrate = feedrate_mm_sec; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_axis_max_acceleration(EAxis axis, float acceleration) | ||||
|   { | ||||
|     _state.axis[axis].max_acceleration = acceleration; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_axis_max_jerk(EAxis axis, float jerk) | ||||
|   { | ||||
|     _state.axis[axis].max_jerk = jerk; | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_axis_position(EAxis axis) const | ||||
|   { | ||||
|     return _state.axis[axis].position; | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_axis_max_feedrate(EAxis axis) const | ||||
|   { | ||||
|     return _state.axis[axis].max_feedrate; | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_axis_max_acceleration(EAxis axis) const | ||||
|   { | ||||
|     return _state.axis[axis].max_acceleration; | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_axis_max_jerk(EAxis axis) const | ||||
|   { | ||||
|     return _state.axis[axis].max_jerk; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_feedrate(float feedrate_mm_sec) | ||||
|   { | ||||
|     _state.feedrate = std::max(feedrate_mm_sec, MINIMUM_FEEDRATE); | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_feedrate() const | ||||
|   { | ||||
|     return _state.feedrate; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_acceleration(float acceleration) | ||||
|   { | ||||
|     _state.acceleration = acceleration; | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_acceleration() const | ||||
|   { | ||||
|     return _state.acceleration; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_dialect(My_GCodeTimeEstimator::EDialect dialect) | ||||
|   { | ||||
|     _state.dialect = dialect; | ||||
|   } | ||||
| 
 | ||||
|   My_GCodeTimeEstimator::EDialect My_GCodeTimeEstimator::get_dialect() const | ||||
|   { | ||||
|     return _state.dialect; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_units(My_GCodeTimeEstimator::EUnits units) | ||||
|   { | ||||
|     _state.units = units; | ||||
|   } | ||||
| 
 | ||||
|   My_GCodeTimeEstimator::EUnits My_GCodeTimeEstimator::get_units() const | ||||
|   { | ||||
|     return _state.units; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_positioningType(My_GCodeTimeEstimator::EPositioningType type) | ||||
|   { | ||||
|     _state.positioningType = type; | ||||
|   } | ||||
| 
 | ||||
|   My_GCodeTimeEstimator::EPositioningType My_GCodeTimeEstimator::get_positioningType() const | ||||
|   { | ||||
|     return _state.positioningType; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::add_additional_time(float timeSec) | ||||
|   { | ||||
|     _state.additional_time += timeSec; | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_additional_time() const | ||||
|   { | ||||
|     return _state.additional_time; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::set_default() | ||||
|   { | ||||
|     set_units(Millimeters); | ||||
|     set_dialect(Unknown); | ||||
|     set_positioningType(Absolute); | ||||
| 
 | ||||
|     set_feedrate(DEFAULT_FEEDRATE); | ||||
|     set_acceleration(DEFAULT_ACCELERATION); | ||||
| 
 | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       EAxis axis = (EAxis)a; | ||||
|       set_axis_max_feedrate(axis, DEFAULT_AXIS_MAX_FEEDRATE[a]); | ||||
|       set_axis_max_acceleration(axis, DEFAULT_AXIS_MAX_ACCELERATION[a]); | ||||
|       set_axis_max_jerk(axis, DEFAULT_AXIS_MAX_JERK[a]); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   float My_GCodeTimeEstimator::get_time() const | ||||
|   { | ||||
|     return _time; | ||||
|   } | ||||
| 
 | ||||
|   const My_GCodeTimeEstimator::BlocksList& My_GCodeTimeEstimator::get_blocks() const | ||||
|   { | ||||
|     return _blocks; | ||||
|   } | ||||
| 
 | ||||
| //  void My_GCodeTimeEstimator::print_counters() const
 | ||||
| //  {
 | ||||
| //    std::cout << std::endl;
 | ||||
| //    for (const CmdToCounterMap::value_type& counter : _cmdCounters)
 | ||||
| //    {
 | ||||
| //      std::cout << counter.first << " : " << counter.second << std::endl;
 | ||||
| //    }
 | ||||
| //  }
 | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_reset() | ||||
|   { | ||||
| //    _cmdCounters.clear();
 | ||||
| 
 | ||||
|     _blocks.clear(); | ||||
| 
 | ||||
|     set_default(); | ||||
|     set_axis_position(X, 0.0f); | ||||
|     set_axis_position(Y, 0.0f); | ||||
|     set_axis_position(Z, 0.0f); | ||||
| 
 | ||||
|     _state.additional_time = 0.0f; | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     if (line.cmd.length() > 1) | ||||
|     { | ||||
|       switch (line.cmd[0]) | ||||
|       { | ||||
|       case 'G': | ||||
|         { | ||||
|           switch (::atoi(&line.cmd[1])) | ||||
|           { | ||||
|           case 1: // Move
 | ||||
|             { | ||||
|               _processG1(line); | ||||
|               break; | ||||
|             } | ||||
|           case 4: // Dwell
 | ||||
|             { | ||||
|               _processG4(line); | ||||
|               break; | ||||
|             } | ||||
|           case 20: // Set Units to Inches
 | ||||
|             { | ||||
|               _processG20(line); | ||||
|               break; | ||||
|             } | ||||
|           case 21: // Set Units to Millimeters
 | ||||
|             { | ||||
|               _processG21(line); | ||||
|               break; | ||||
|             } | ||||
|           case 28: // Move to Origin (Home)
 | ||||
|             { | ||||
|               _processG28(line); | ||||
|               break; | ||||
|             } | ||||
|           case 90: // Set to Absolute Positioning
 | ||||
|             { | ||||
|               _processG90(line); | ||||
|               break; | ||||
|             } | ||||
|           case 91: // Set to Relative Positioning
 | ||||
|             { | ||||
|               _processG91(line); | ||||
|               break; | ||||
|             } | ||||
|           case 92: // Set Position
 | ||||
|             { | ||||
|               _processG92(line); | ||||
|               break; | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           break; | ||||
|         } | ||||
|       case 'M': | ||||
|         { | ||||
|           switch (::atoi(&line.cmd[1])) | ||||
|           { | ||||
|           case 109: // Set Extruder Temperature and Wait
 | ||||
|             { | ||||
|               _processM109(line); | ||||
|               break; | ||||
|             } | ||||
|           case 203: // Set maximum feedrate
 | ||||
|             { | ||||
|               _processM203(line); | ||||
|               break; | ||||
|             } | ||||
|           case 204: // Set default acceleration
 | ||||
|             { | ||||
|               _processM204(line); | ||||
|               break; | ||||
|             } | ||||
|           case 566: // Set allowable instantaneous speed change
 | ||||
|             { | ||||
|               _processM566(line); | ||||
|               break; | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
| //      CmdToCounterMap::iterator it = _cmdCounters.find(line.cmd);
 | ||||
| //      if (it == _cmdCounters.end())
 | ||||
| //        _cmdCounters.insert(CmdToCounterMap::value_type(line.cmd, 1));
 | ||||
| //      else
 | ||||
| //        ++it->second;
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG1(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     float lengthsScaleFactor = (get_units() == Inches) ? INCHES_TO_MM : 1.0f; | ||||
| 
 | ||||
|     // gets position changes from line, if present
 | ||||
|     float new_pos[Num_Axis]; | ||||
| 
 | ||||
|     if (get_positioningType() == Absolute) | ||||
|     { | ||||
|       for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|       { | ||||
|         new_pos[a] = line.has(AXIS_STR[a]) ? line.get_float(AXIS_STR[a]) * lengthsScaleFactor : get_axis_position((EAxis)a); | ||||
|       } | ||||
|     } | ||||
|     else // get_positioningType() == Relative
 | ||||
|     { | ||||
|       for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|       { | ||||
|         new_pos[a] = get_axis_position((EAxis)a); | ||||
|         new_pos[a] += (line.has(AXIS_STR[a]) ? line.get_float(AXIS_STR[a]) * lengthsScaleFactor : 0.0f); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // updates feedrate from line, if present
 | ||||
|     if (line.has('F')) | ||||
|       set_feedrate(line.get_float('F') * MMMIN_TO_MMSEC); | ||||
| 
 | ||||
|     // fills block data
 | ||||
|     Block block; | ||||
| 
 | ||||
|     // calculates block movement deltas
 | ||||
|     float max_abs_delta = 0.0f; | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       block.delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a); | ||||
|       max_abs_delta = std::max(max_abs_delta, ::abs(block.delta_pos[a])); | ||||
|     } | ||||
| 
 | ||||
|     // is it a move ?
 | ||||
|     if (max_abs_delta == 0.0f) | ||||
|       return; | ||||
| 
 | ||||
|     // calculates block feedrate
 | ||||
|     float feedrate = get_feedrate(); | ||||
| 
 | ||||
|     float distance = block.move_length(); | ||||
|     float invDistance = 1.0f / distance; | ||||
| 
 | ||||
|     float axis_feedrate[Num_Axis]; | ||||
|     float min_feedrate_factor = 1.0f; | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       axis_feedrate[a] = feedrate * ::abs(block.delta_pos[a]) * invDistance; | ||||
|       if (axis_feedrate[a] > 0.0f) | ||||
|         min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / axis_feedrate[a]); | ||||
|     } | ||||
|      | ||||
|     block.feedrate = min_feedrate_factor * feedrate; | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       axis_feedrate[a] *= min_feedrate_factor; | ||||
|     } | ||||
| 
 | ||||
|     // calculates block acceleration
 | ||||
|     float acceleration = get_acceleration(); | ||||
| 
 | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       float axis_max_acceleration = get_axis_max_acceleration((EAxis)a); | ||||
|       if (acceleration * ::abs(block.delta_pos[a]) * invDistance > axis_max_acceleration) | ||||
|         acceleration = axis_max_acceleration; | ||||
|     } | ||||
| 
 | ||||
|     block.acceleration = acceleration; | ||||
| 
 | ||||
|     // calculates block exit feedrate
 | ||||
|     float exit_feedrate = block.feedrate; | ||||
| 
 | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       float half_axis_max_jerk = 0.5f * get_axis_max_jerk((EAxis)a); | ||||
|       if (axis_feedrate[a] > half_axis_max_jerk) | ||||
|         exit_feedrate = std::min(exit_feedrate, half_axis_max_jerk); | ||||
|     } | ||||
| 
 | ||||
|     block.exit_feedrate = exit_feedrate; | ||||
| 
 | ||||
|     // calculates block entry feedrate
 | ||||
|     float vmax_junction = exit_feedrate; | ||||
|     if (!_blocks.empty() && (_prev.feedrate > FEEDRATE_THRESHOLD)) | ||||
|     { | ||||
|       vmax_junction = block.feedrate; | ||||
|       float vmax_junction_factor = 1.0f; | ||||
| 
 | ||||
|       for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|       { | ||||
|         float abs_delta_axis_feedrate = ::abs(axis_feedrate[a] - _prev.axis_feedrate[a]); | ||||
|         float axis_max_jerk = get_axis_max_jerk((EAxis)a); | ||||
|         if (abs_delta_axis_feedrate > axis_max_jerk) | ||||
|           vmax_junction_factor = std::min(vmax_junction_factor, axis_max_jerk / abs_delta_axis_feedrate); | ||||
|       } | ||||
| 
 | ||||
|       // limit vmax to not exceed previous feedrate
 | ||||
|       vmax_junction = std::min(_prev.feedrate, vmax_junction * vmax_junction_factor); | ||||
|     } | ||||
| 
 | ||||
|     block.entry_feedrate = std::min(vmax_junction, Block::max_allowable_speed(-acceleration, MINIMUM_PLANNER_SPEED, distance)); | ||||
| 
 | ||||
|     // calculates block trapezoid
 | ||||
|     block.calculate_trapezoid(); | ||||
| 
 | ||||
|     // updates previous cache
 | ||||
|     _prev.feedrate = feedrate; | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       _prev.axis_feedrate[a] = axis_feedrate[a]; | ||||
|     } | ||||
| 
 | ||||
|     // updates axis positions
 | ||||
|     for (unsigned char a = X; a < Num_Axis; ++a) | ||||
|     { | ||||
|       set_axis_position((EAxis)a, new_pos[a]); | ||||
|     } | ||||
| 
 | ||||
|     // adds block to blocks list
 | ||||
|     _blocks.push_back(block); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     EDialect dialect = get_dialect(); | ||||
| 
 | ||||
|     if (line.has('P')) | ||||
|       add_additional_time(line.get_float('P') * MILLISEC_TO_SEC); | ||||
| 
 | ||||
|     // see: http://reprap.org/wiki/G-code#G4:_Dwell
 | ||||
|     if ((dialect == Repetier) || | ||||
|         (dialect == Marlin) || | ||||
|         (dialect == Smoothieware) || | ||||
|         (dialect == RepRapFirmware)) | ||||
|     { | ||||
|       if (line.has('S')) | ||||
|         add_additional_time(line.get_float('S')); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     set_units(Inches); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG21(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     set_units(Millimeters); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG28(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     // todo
 | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG90(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     set_positioningType(Absolute); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG91(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     // >>>>>>>> THERE ARE DIALECT VARIANTS
 | ||||
| 
 | ||||
|     set_positioningType(Relative); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processG92(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     // todo
 | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processM109(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     // todo
 | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processM203(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     EDialect dialect = get_dialect(); | ||||
| 
 | ||||
|     // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
 | ||||
|     if (dialect == Repetier) | ||||
|       return; | ||||
| 
 | ||||
|     // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
 | ||||
|     float factor = (dialect == Marlin) ? 1.0f : MMMIN_TO_MMSEC; | ||||
| 
 | ||||
|     if (line.has('X')) | ||||
|       set_axis_max_feedrate(X, line.get_float('X') * factor); | ||||
| 
 | ||||
|     if (line.has('Y')) | ||||
|       set_axis_max_feedrate(Y, line.get_float('Y') * factor); | ||||
| 
 | ||||
|     if (line.has('Z')) | ||||
|       set_axis_max_feedrate(Z, line.get_float('Z') * factor); | ||||
| 
 | ||||
|     if (line.has('E')) | ||||
|       set_axis_max_feedrate(E, line.get_float('E') * factor); | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processM204(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     if (line.has('S')) | ||||
|       set_acceleration(line.get_float('S')); // <<<< Is this correct ?
 | ||||
| 
 | ||||
|     if (line.has('T')) | ||||
|     { | ||||
|       // what to do ?
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void My_GCodeTimeEstimator::_processM566(const GCodeReader::GCodeLine& line) | ||||
|   { | ||||
|     if (line.has('X')) | ||||
|       set_axis_max_jerk(X, line.get_float('X') * MMMIN_TO_MMSEC); | ||||
| 
 | ||||
|     if (line.has('Y')) | ||||
|       set_axis_max_jerk(Y, line.get_float('Y') * MMMIN_TO_MMSEC); | ||||
| 
 | ||||
|     if (line.has('Z')) | ||||
|       set_axis_max_jerk(Z, line.get_float('Z') * MMMIN_TO_MMSEC); | ||||
| 
 | ||||
|     if (line.has('E')) | ||||
|       set_axis_max_jerk(E, line.get_float('E') * MMMIN_TO_MMSEC); | ||||
|   } | ||||
| //###########################################################################################################
 | ||||
| 
 | ||||
| void | ||||
| GCodeTimeEstimator::parse(const std::string &gcode) | ||||
| { | ||||
|  |  | |||
|  | @ -6,6 +6,210 @@ | |||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| //###########################################################################################################
 | ||||
|   class My_GCodeTimeEstimator : public GCodeReader | ||||
|   { | ||||
|   public: | ||||
|     enum EUnits : unsigned char | ||||
|     { | ||||
|       Millimeters, | ||||
|       Inches | ||||
|     }; | ||||
| 
 | ||||
|     enum EAxis : unsigned char | ||||
|     { | ||||
|       X, | ||||
|       Y, | ||||
|       Z, | ||||
|       E, | ||||
|       Num_Axis | ||||
|     }; | ||||
| 
 | ||||
|     enum EDialect : unsigned char | ||||
|     { | ||||
|       Unknown, | ||||
|       Marlin, | ||||
|       Repetier, | ||||
|       Smoothieware, | ||||
|       RepRapFirmware, | ||||
|       Teacup, | ||||
|       Num_Dialects | ||||
|     }; | ||||
| 
 | ||||
|     enum EPositioningType | ||||
|     { | ||||
|       Absolute, | ||||
|       Relative | ||||
|     }; | ||||
| 
 | ||||
|   private: | ||||
|     struct Axis | ||||
|     { | ||||
|       float position;         // mm
 | ||||
|       float max_feedrate;     // mm/s
 | ||||
|       float max_acceleration; // mm/s^2
 | ||||
|       float max_jerk;         // mm/s
 | ||||
|     }; | ||||
| 
 | ||||
|     struct State | ||||
|     { | ||||
|       EDialect dialect; | ||||
|       EUnits units; | ||||
|       EPositioningType positioningType; | ||||
|       Axis axis[Num_Axis]; | ||||
|       float feedrate;                     // mm/s
 | ||||
|       float acceleration;                 // mm/s^2
 | ||||
|       float additional_time;              // s
 | ||||
|     }; | ||||
| 
 | ||||
|     struct PreviousBlockCache | ||||
|     { | ||||
|       float feedrate;                // mm/s
 | ||||
|       float axis_feedrate[Num_Axis]; // mm/s
 | ||||
|     }; | ||||
| 
 | ||||
|   public: | ||||
|     struct Block | ||||
|     { | ||||
|       struct Trapezoid | ||||
|       { | ||||
|         float distance;         // mm
 | ||||
|         float accelerate_until; // mm
 | ||||
|         float decelerate_after; // mm
 | ||||
|         float entry_feedrate;   // mm/s
 | ||||
|         float exit_feedrate;    // mm/s
 | ||||
|       }; | ||||
| 
 | ||||
|       float delta_pos[Num_Axis]; // mm
 | ||||
|       float feedrate;            // mm/s
 | ||||
|       float acceleration;        // mm/s^2
 | ||||
|       float entry_feedrate;      // mm/s
 | ||||
|       float exit_feedrate;       // mm/s
 | ||||
| 
 | ||||
|       Trapezoid trapezoid; | ||||
| 
 | ||||
|       // Returns the length of the move covered by this block, in mm
 | ||||
|       float move_length() const; | ||||
| 
 | ||||
|       void calculate_trapezoid(); | ||||
| 
 | ||||
|       // Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the 
 | ||||
|       // acceleration within the allotted distance.
 | ||||
|       static float max_allowable_speed(float acceleration, float target_velocity, float distance); | ||||
| 
 | ||||
|       // Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the given acceleration:
 | ||||
|       static float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration); | ||||
| 
 | ||||
|       // This function gives you the point at which you must start braking (at the rate of -acceleration) if 
 | ||||
|       // you started at speed initial_rate and accelerated until this point and want to end at the final_rate after
 | ||||
|       // a total travel of distance. This can be used to compute the intersection point between acceleration and
 | ||||
|       // deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed)
 | ||||
|       static float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance); | ||||
| 
 | ||||
|       // This function gives the time it needs to accelerate from an initial speed to reach a final distance.
 | ||||
|       static float acceleration_time_from_distance(float initial_feedrate, float distance, float acceleration); | ||||
|     }; | ||||
| 
 | ||||
|     typedef std::vector<Block> BlocksList; | ||||
| 
 | ||||
|   private: | ||||
| //    typedef std::map<std::string, unsigned int> CmdToCounterMap;
 | ||||
| //    CmdToCounterMap _cmdCounters;
 | ||||
| 
 | ||||
|     State _state; | ||||
|     PreviousBlockCache _prev; | ||||
|     BlocksList _blocks; | ||||
|     float _time; // s
 | ||||
| 
 | ||||
|   public: | ||||
|     My_GCodeTimeEstimator(); | ||||
| 
 | ||||
|     void parse(const std::string& gcode); | ||||
|     void parse_file(const std::string& file); | ||||
| 
 | ||||
|     void calculate_time(); | ||||
| 
 | ||||
|     void set_axis_position(EAxis axis, float position); | ||||
|     void set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec); | ||||
|     void set_axis_max_acceleration(EAxis axis, float acceleration); | ||||
|     void set_axis_max_jerk(EAxis axis, float jerk); | ||||
| 
 | ||||
|     float get_axis_position(EAxis axis) const; | ||||
|     float get_axis_max_feedrate(EAxis axis) const; | ||||
|     float get_axis_max_acceleration(EAxis axis) const; | ||||
|     float get_axis_max_jerk(EAxis axis) const; | ||||
| 
 | ||||
|     void set_feedrate(float feedrate_mm_sec); | ||||
|     float get_feedrate() const; | ||||
| 
 | ||||
|     void set_acceleration(float acceleration); | ||||
|     float get_acceleration() const; | ||||
| 
 | ||||
|     void set_dialect(EDialect dialect); | ||||
|     EDialect get_dialect() const; | ||||
| 
 | ||||
|     void set_units(EUnits units); | ||||
|     EUnits get_units() const; | ||||
| 
 | ||||
|     void set_positioningType(EPositioningType type); | ||||
|     EPositioningType get_positioningType() const; | ||||
| 
 | ||||
|     void add_additional_time(float timeSec); | ||||
|     float get_additional_time() const; | ||||
| 
 | ||||
|     void set_default(); | ||||
| 
 | ||||
|     // returns estimated time in seconds
 | ||||
|     float get_time() const; | ||||
| 
 | ||||
|     const BlocksList& get_blocks() const; | ||||
| 
 | ||||
| //    void print_counters() const;
 | ||||
| 
 | ||||
|   private: | ||||
|     void _reset(); | ||||
| 
 | ||||
|     // Processes GCode line
 | ||||
|     void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Move
 | ||||
|     void _processG1(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Dwell
 | ||||
|     void _processG4(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set Units to Inches
 | ||||
|     void _processG20(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set Units to Millimeters
 | ||||
|     void _processG21(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Move to Origin (Home)
 | ||||
|     void _processG28(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set to Absolute Positioning
 | ||||
|     void _processG90(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set to Relative Positioning
 | ||||
|     void _processG91(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set Position
 | ||||
|     void _processG92(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set Extruder Temperature and Wait
 | ||||
|     void _processM109(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set maximum feedrate
 | ||||
|     void _processM203(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set default acceleration
 | ||||
|     void _processM204(const GCodeReader::GCodeLine& line); | ||||
| 
 | ||||
|     // Set allowable instantaneous speed change
 | ||||
|     void _processM566(const GCodeReader::GCodeLine& line); | ||||
|   }; | ||||
| //###########################################################################################################
 | ||||
| 
 | ||||
| class GCodeTimeEstimator : public GCodeReader { | ||||
|     public: | ||||
|     float time = 0;  // in seconds
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri