Add speed limiting based on maximum extrusion rate in mm^3/sec
[clinton/Smoothieware.git] / src / modules / tools / extruder / Extruder.cpp
index eb90e52..50d3d2e 100644 (file)
@@ -24,6 +24,8 @@
 #include "Gcode.h"
 #include "libs/StreamOutput.h"
 #include "PublicDataRequest.h"
+#include "StreamOutputPool.h"
+#include "ExtruderPublicAccess.h"
 
 #include <mri.h>
 
@@ -39,7 +41,6 @@
 #define extruder_default_feed_rate_checksum  CHECKSUM("extruder_default_feed_rate")
 
 // NEW config names
-#define extruder_checksum                    CHECKSUM("extruder")
 
 #define default_feed_rate_checksum           CHECKSUM("default_feed_rate")
 #define steps_per_mm_checksum                CHECKSUM("steps_per_mm")
@@ -60,9 +61,6 @@
 #define retract_zlift_length_checksum        CHECKSUM("retract_zlift_length")
 #define retract_zlift_feedrate_checksum      CHECKSUM("retract_zlift_feedrate")
 
-#define save_state_checksum                  CHECKSUM("save_state")
-#define restore_state_checksum               CHECKSUM("restore_state")
-
 #define X_AXIS      0
 #define Y_AXIS      1
 #define Z_AXIS      2
@@ -82,6 +80,7 @@
 Extruder::Extruder( uint16_t config_identifier, bool single )
 {
     this->absolute_mode = true;
+    this->milestone_absolute_mode = true;
     this->enabled = false;
     this->paused = false;
     this->single_config = single;
@@ -90,6 +89,8 @@ Extruder::Extruder( uint16_t config_identifier, bool single )
     this->volumetric_multiplier = 1.0F;
     this->extruder_multiplier = 1.0F;
     this->stepper_motor= nullptr;
+    this->milestone_last_position= 0;
+    this->max_volumetric_rate= 0;
 
     memset(this->offset, 0, sizeof(this->offset));
 }
@@ -214,6 +215,39 @@ void Extruder::on_set_public_data(void *argument)
 
     if(!pdr->starts_with(extruder_checksum)) return;
 
+    // handle extrude rates request from robot
+    // TODO if not in volumetric mode then limit speed based on max_speed
+    if(pdr->second_element_is(target_checksum)) {
+        if(!this->enabled || this->max_volumetric_rate == 0 || this->filament_diameter == 0) return;
+
+        float *d= static_cast<float*>(pdr->get_data_ptr());
+        float target= d[0]; // the E passed in on Gcode is in mm³ (maybe absolute or relative)
+        float isecs= d[1]; // inverted secs
+        float delta;
+
+        if(milestone_absolute_mode) {
+            delta= fabsf(target - milestone_last_position); // delta move
+            milestone_last_position= target;
+
+        }else{
+            delta= target;
+            milestone_last_position += target;
+        }
+
+        // return the rate change needed to stay within the max rate
+        float v= delta * isecs; // the flow rate in mm³/sec
+
+        // TODO need to take filament diameter into account for limiting to mm/sec of stepper
+        if(v > max_volumetric_rate) {
+            d[1] = max_volumetric_rate / v;
+        }else{
+            d[1]= 1.0F;
+        }
+        //THEKERNEL->streams->printf("requested flow rate: %f, corrected flow rate: %f\n", v, v * d[1]);
+        pdr->set_taken();
+        return;
+    }
+
     // save or restore state
     if(pdr->second_element_is(save_state_checksum)) {
         this->saved_current_position= this->current_position;
@@ -281,6 +315,23 @@ void Extruder::on_gcode_received(void *argument)
             }
             gcode->mark_as_taken();
 
+        } else if (gcode->m == 203 && ( (this->enabled && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier)) ) {
+            // M203 Exxx Vyyy Set maximum feedrates xxx mm/sec and/or yyy mm³/sec
+            if(gcode->get_num_args() == 0) {
+                gcode->stream->printf("E:%g V:%g", this->stepper_motor->get_max_rate(), this->max_volumetric_rate);
+                gcode->add_nl = true;
+
+            }else{
+                if(gcode->has_letter('E')){
+                    this->stepper_motor->set_max_rate(gcode->get_value('E'));
+                }
+                if(gcode->has_letter('V')){
+                    this->max_volumetric_rate= gcode->get_value('V');
+                }
+            }
+
+            gcode->mark_as_taken();
+
         } else if (gcode->m == 204 && gcode->has_letter('E') &&
                    ( (this->enabled && !gcode->has_letter('P')) || (gcode->has_letter('P') && gcode->get_value('P') == this->identifier)) ) {
             // extruder acceleration M204 Ennn mm/sec^2 (Pnnn sets the specific extruder for M500)
@@ -316,6 +367,10 @@ void Extruder::on_gcode_received(void *argument)
                 gcode->stream->printf(";E retract length, feedrate, zlift length, feedrate:\nM207 S%1.4f F%1.4f Z%1.4f Q%1.4f\n", this->retract_length, this->retract_feedrate*60.0F, this->retract_zlift_length, this->retract_zlift_feedrate);
                 gcode->stream->printf(";E retract recover length, feedrate:\nM208 S%1.4f F%1.4f\n", this->retract_recover_length, this->retract_recover_feedrate*60.0F);
                 gcode->stream->printf(";E acceleration mm/sec^2:\nM204 E%1.4f\n", this->acceleration);
+                gcode->stream->printf(";E max feed rate mm/sec:\nM203 E%1.4f\n", this->stepper_motor->get_max_rate());
+                if(this->max_volumetric_rate > 0) {
+                    gcode->stream->printf(";E max volumetric rate mm³/sec:\nM203 V%1.4f\n", this->max_volumetric_rate);
+                }
 
             } else {
                 gcode->stream->printf(";E Steps per mm:\nM92 E%1.4f P%d\n", this->steps_per_millimeter, this->identifier);
@@ -323,8 +378,13 @@ void Extruder::on_gcode_received(void *argument)
                 gcode->stream->printf(";E retract length, feedrate:\nM207 S%1.4f F%1.4f Z%1.4f Q%1.4f P%d\n", this->retract_length, this->retract_feedrate*60.0F, this->retract_zlift_length, this->retract_zlift_feedrate, this->identifier);
                 gcode->stream->printf(";E retract recover length, feedrate:\nM208 S%1.4f F%1.4f P%d\n", this->retract_recover_length, this->retract_recover_feedrate*60.0F, this->identifier);
                 gcode->stream->printf(";E acceleration mm/sec^2:\nM204 E%1.4f P%d\n", this->acceleration, this->identifier);
+                gcode->stream->printf(";E max feed rate mm/sec:\nM203 E%1.4f P%d\n", this->stepper_motor->get_max_rate(), this->identifier);
+                if(this->max_volumetric_rate > 0) {
+                    gcode->stream->printf(";E max volumetric rate mm³/sec:\nM203 V%1.4f P%d\n", this->max_volumetric_rate, this->identifier);
+                }
             }
             gcode->mark_as_taken();
+
         } else if( gcode->m == 17 || gcode->m == 18 || gcode->m == 82 || gcode->m == 83 || gcode->m == 84 ) {
             // Mcodes to pass along to on_gcode_execute
             THEKERNEL->conveyor->append_gcode(gcode);
@@ -390,6 +450,25 @@ void Extruder::on_gcode_received(void *argument)
             this->cancel_zlift_restore= true;
         }
     }
+
+    // handle some codes now for the volumetric rate limiting
+    // G90 G91 G92 M82 M83
+    if(gcode->has_m) {
+        switch(gcode->m) {
+            case 82: this->milestone_absolute_mode = true; break;
+            case 83: this->milestone_absolute_mode = false; break;
+        }
+
+    }else if(gcode->has_g) {
+        switch(gcode->g) {
+            case 90: this->milestone_absolute_mode = true; break;
+            case 91: this->milestone_absolute_mode = false; break;
+            case 92:
+                if(gcode->has_letter('E')) { this->milestone_last_position= gcode->get_value('E'); }
+                else if(gcode->get_num_args() == 0) { this->milestone_last_position= 0; }
+                break;
+        }
+    }
 }
 
 // Compute extrusion speed based on parameters and gcode distance of travel
@@ -459,7 +538,7 @@ void Extruder::on_gcode_execute(void *argument)
         } else if (gcode->g == 0 || gcode->g == 1) {
             // Extrusion length from 'G' Gcode
             if( gcode->has_letter('E' )) {
-                // Get relative extrusion distance depending on mode ( in absolute mode we must substract target_position )
+                // Get relative extrusion distance depending on mode ( in absolute mode we must subtract target_position )
                 float extrusion_distance = gcode->get_value('E');
                 float relative_extrusion_distance = extrusion_distance;
                 if (this->absolute_mode) {