Add speed limiting based on maximum extrusion rate in mm^3/sec
authorJim Morris <morris@wolfman.com>
Sun, 16 Aug 2015 06:32:40 +0000 (23:32 -0700)
committerJim Morris <morris@wolfman.com>
Sun, 16 Aug 2015 06:32:40 +0000 (23:32 -0700)
set ground work for speed limiting based on extruder max_speed in mm/sec

src/modules/robot/Robot.cpp
src/modules/robot/Robot.h
src/modules/tools/extruder/Extruder.cpp
src/modules/tools/extruder/Extruder.h
src/modules/tools/extruder/ExtruderPublicAccess.h [new file with mode: 0644]
src/modules/utils/player/Player.cpp

index 5fe14de..938a4ac 100644 (file)
@@ -22,6 +22,7 @@ using std::string;
 #include "StepperMotor.h"
 #include "Gcode.h"
 #include "PublicDataRequest.h"
+#include "PublicData.h"
 #include "RobotPublicAccess.h"
 #include "arm_solutions/BaseSolution.h"
 #include "arm_solutions/CartesianSolution.h"
@@ -36,6 +37,7 @@ using std::string;
 #include "ConfigValue.h"
 #include "libs/StreamOutput.h"
 #include "StreamOutputPool.h"
+#include "ExtruderPublicAccess.h"
 
 #define  default_seek_rate_checksum          CHECKSUM("default_seek_rate")
 #define  default_feed_rate_checksum          CHECKSUM("default_feed_rate")
@@ -94,7 +96,6 @@ using std::string;
 #define  beta_checksum                       CHECKSUM("beta")
 #define  gamma_checksum                      CHECKSUM("gamma")
 
-
 #define NEXT_ACTION_DEFAULT 0
 #define NEXT_ACTION_DWELL 1
 #define NEXT_ACTION_GO_HOME 2
@@ -457,10 +458,12 @@ void Robot::on_gcode_received(void *argument)
 
                 check_max_actuator_speeds();
 
-                gcode->stream->printf("X:%g Y:%g Z:%g  A:%g B:%g C:%g ",
-                                      this->max_speeds[X_AXIS], this->max_speeds[Y_AXIS], this->max_speeds[Z_AXIS],
-                                      alpha_stepper_motor->get_max_rate(), beta_stepper_motor->get_max_rate(), gamma_stepper_motor->get_max_rate());
-                gcode->add_nl = true;
+                if(gcode->get_num_args() == 0) {
+                    gcode->stream->printf("X:%g Y:%g Z:%g  A:%g B:%g C:%g ",
+                                          this->max_speeds[X_AXIS], this->max_speeds[Y_AXIS], this->max_speeds[Z_AXIS],
+                                          alpha_stepper_motor->get_max_rate(), beta_stepper_motor->get_max_rate(), gamma_stepper_motor->get_max_rate());
+                    gcode->add_nl = true;
+                }
                 gcode->mark_as_taken();
                 break;
 
@@ -682,7 +685,7 @@ void Robot::reset_position_from_current_actuator_position()
 }
 
 // Convert target from millimeters to steps, and append this to the planner
-void Robot::append_milestone( float target[], float rate_mm_s )
+void Robot::append_milestone(Gcode *gcode, float target[], float rate_mm_s )
 {
     float deltas[3];
     float unit_vec[3];
@@ -726,12 +729,27 @@ void Robot::append_milestone( float target[], float rate_mm_s )
     // find actuator position given cartesian position, use actual adjusted target
     arm_solution->cartesian_to_actuator( transformed_target, actuator_pos );
 
+    float isecs= rate_mm_s / millimeters_of_travel;
     // check per-actuator speed limits
     for (int actuator = 0; actuator <= 2; actuator++) {
-        float actuator_rate  = fabs(actuator_pos[actuator] - actuators[actuator]->last_milestone_mm) * rate_mm_s / millimeters_of_travel;
-
-        if (actuator_rate > actuators[actuator]->get_max_rate())
+        float actuator_rate  = fabsf(actuator_pos[actuator] - actuators[actuator]->last_milestone_mm) * isecs;
+        if (actuator_rate > actuators[actuator]->get_max_rate()){
             rate_mm_s *= (actuators[actuator]->get_max_rate() / actuator_rate);
+        }
+    }
+
+    // if we have volumetric limits enabled we calculate the volume for this move and limit the rate if it exceeds the stated limit
+    // Note we need to be using volumetric extrusion for this to work as Ennn is in mm³ not mm
+    // We ask Extruder to do all the work, but as Extruder won;t even see this gcode until after it has been planned
+    // we need to ask it now passing in the relative data.
+    if(gcode->has_letter('E')) {
+        float data[2];
+        data[0]= gcode->get_value('E'); // E target (maybe absolute or relative)
+        data[1]= isecs; // inverted seconds
+        if(PublicData::set_value(extruder_checksum, target_checksum, data)) {
+            rate_mm_s *= data[1];
+            //THEKERNEL->streams->printf("Extuder has changed the rate by %f to %f\n", data[1], rate_mm_s);
+        }
     }
 
     // Append the block to the planner
@@ -797,12 +815,12 @@ void Robot::append_line(Gcode *gcode, float target[], float rate_mm_s )
                 segment_end[axis] = last_milestone[axis] + segment_delta[axis];
 
             // Append the end of this segment to the queue
-            this->append_milestone(segment_end, rate_mm_s);
+            this->append_milestone(gcode, segment_end, rate_mm_s);
         }
     }
 
     // Append the end of this full move to the queue
-    this->append_milestone(target, rate_mm_s);
+    this->append_milestone(gcode, target, rate_mm_s);
 
     // if adding these blocks didn't start executing, do that now
     THEKERNEL->conveyor->ensure_running();
@@ -910,12 +928,12 @@ void Robot::append_arc(Gcode *gcode, float target[], float offset[], float radiu
         arc_target[this->plane_axis_2] += linear_per_segment;
 
         // Append this segment to the queue
-        this->append_milestone(arc_target, this->feed_rate / seconds_per_minute);
+        this->append_milestone(gcode, arc_target, this->feed_rate / seconds_per_minute);
 
     }
 
     // Ensure last segment arrives at target location.
-    this->append_milestone(target, this->feed_rate / seconds_per_minute);
+    this->append_milestone(gcode, target, this->feed_rate / seconds_per_minute);
 }
 
 // Do the math for an arc and add it to the queue
index 90e1867..d42a298 100644 (file)
@@ -56,7 +56,7 @@ class Robot : public Module {
 
     private:
         void distance_in_gcode_is_known(Gcode* gcode);
-        void append_milestone( float target[], float rate_mm_s);
+        void append_milestone( Gcode *gcode, float target[], float rate_mm_s);
         void append_line( Gcode* gcode, float target[], float rate_mm_s);
         //void append_arc(float theta_start, float angular_travel, float radius, float depth, float rate);
         void append_arc( Gcode* gcode, float target[], float offset[], float radius, bool is_clockwise );
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) {
index 362d8d5..5c1cc8e 100644 (file)
@@ -61,7 +61,9 @@ class Extruder : public Tool {
 
         float saved_current_position;
         float volumetric_multiplier;
-        float feed_rate;               // mm/sec for SOLO moves only
+        float feed_rate;                // default rate mm/sec for SOLO moves only
+        float milestone_last_position;  // used for calculating volumemetric rate, last position in mm³
+        float max_volumetric_rate;      // used for calculating volumetric rate in mm³/sec
 
         float travel_ratio;
         float travel_distance;
@@ -81,6 +83,7 @@ class Extruder : public Tool {
             bool single_config:1;
             bool retracted:1;
             bool cancel_zlift_restore:1; // hack to stop a G11 zlift restore from overring an absolute Z setting
+            bool milestone_absolute_mode:1;
         };
 
 
diff --git a/src/modules/tools/extruder/ExtruderPublicAccess.h b/src/modules/tools/extruder/ExtruderPublicAccess.h
new file mode 100644 (file)
index 0000000..d5c16cd
--- /dev/null
@@ -0,0 +1,6 @@
+#pragma once
+
+#define extruder_checksum                    CHECKSUM("extruder")
+#define save_state_checksum                  CHECKSUM("save_state")
+#define restore_state_checksum               CHECKSUM("restore_state")
+#define target_checksum                      CHECKSUM("target")
index dbe2fba..c728dc7 100644 (file)
@@ -29,6 +29,7 @@
 #include "PlayerPublicAccess.h"
 #include "TemperatureControlPublicAccess.h"
 #include "TemperatureControlPool.h"
+#include "ExtruderPublicAccess.h"
 
 #include <cstddef>
 #include <cmath>
 #define before_resume_gcode_checksum      CHECKSUM("before_resume_gcode")
 #define leave_heaters_on_suspend_checksum CHECKSUM("leave_heaters_on_suspend")
 
-
-#define extruder_checksum                 CHECKSUM("extruder")
-#define save_state_checksum               CHECKSUM("save_state")
-#define restore_state_checksum            CHECKSUM("restore_state")
-
 extern SDFAT mounter;
 
 Player::Player()