#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"
#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")
#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
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;
}
// 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];
// 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
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();
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
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 );
#include "Gcode.h"
#include "libs/StreamOutput.h"
#include "PublicDataRequest.h"
+#include "StreamOutputPool.h"
+#include "ExtruderPublicAccess.h"
#include <mri.h>
#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")
#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
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;
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));
}
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;
}
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)
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);
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);
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
} 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) {
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;
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;
};
--- /dev/null
+#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")
#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()