PressureRegulator.pm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. # A pure perl (no C++ implementation) G-code filter, to control the pressure inside the nozzle.
  2. package Slic3r::GCode::PressureRegulator;
  3. use Moo;
  4. has 'config' => (is => 'ro', required => 1);
  5. has 'enable' => (is => 'rw', default => sub { 0 });
  6. has 'reader' => (is => 'ro', default => sub { Slic3r::GCode::Reader->new });
  7. has '_extrusion_axis' => (is => 'rw', default => sub { "E" });
  8. has '_tool' => (is => 'rw', default => sub { 0 });
  9. has '_last_print_F' => (is => 'rw', default => sub { 0 });
  10. has '_advance' => (is => 'rw', default => sub { 0 }); # extra E injected
  11. use Slic3r::Geometry qw(epsilon);
  12. # Acknowledgements:
  13. # The advance algorithm was proposed by Matthew Roberts.
  14. # The initial work on this Slic3r feature was done by Luís Andrade (lluis)
  15. sub BUILD {
  16. my ($self) = @_;
  17. $self->reader->apply_print_config($self->config);
  18. $self->_extrusion_axis($self->config->get_extrusion_axis);
  19. }
  20. sub process {
  21. my $self = shift;
  22. my ($gcode, $flush) = @_;
  23. my $new_gcode = "";
  24. $self->reader->parse($gcode, sub {
  25. my ($reader, $cmd, $args, $info) = @_;
  26. if ($cmd =~ /^T(\d+)/) {
  27. $self->_tool($1);
  28. } elsif ($info->{extruding} && $info->{dist_XY} > 0) {
  29. # This is a print move.
  30. my $F = $args->{F} // $reader->F;
  31. if ($F != $self->_last_print_F || ($F == $self->_last_print_F && $self->_advance == 0)) {
  32. # We are setting a (potentially) new speed or a discharge event happend since the last speed change, so we calculate the new advance amount.
  33. # First calculate relative flow rate (mm of filament over mm of travel)
  34. my $rel_flow_rate = $info->{dist_E} / $info->{dist_XY};
  35. # Then calculate absolute flow rate (mm/sec of feedstock)
  36. my $flow_rate = $rel_flow_rate * $F / 60;
  37. # And finally calculate advance by using the user-configured K factor.
  38. my $new_advance = $self->config->pressure_advance * ($flow_rate**2);
  39. if (abs($new_advance - $self->_advance) > 1E-5) {
  40. my $new_E = ($self->config->use_relative_e_distances ? 0 : $reader->E) + ($new_advance - $self->_advance);
  41. $new_gcode .= sprintf "G1 %s%.5f F%.3f ; pressure advance\n",
  42. $self->_extrusion_axis, $new_E, $self->_unretract_speed;
  43. $new_gcode .= sprintf "G92 %s%.5f ; restore E\n", $self->_extrusion_axis, $reader->E
  44. if !$self->config->use_relative_e_distances;
  45. $new_gcode .= sprintf "G1 F%.3f ; restore F\n", $F;
  46. $self->_advance($new_advance);
  47. }
  48. $self->_last_print_F($F);
  49. }
  50. } elsif (($info->{retracting} || $cmd eq 'G10') && $self->_advance != 0) {
  51. # We need to bring pressure to zero when retracting.
  52. $new_gcode .= $self->_discharge($args->{F}, $args->{F} // $reader->F);
  53. }
  54. $new_gcode .= "$info->{raw}\n";
  55. });
  56. if ($flush) {
  57. $new_gcode .= $self->_discharge;
  58. }
  59. return $new_gcode;
  60. }
  61. sub _discharge {
  62. my ($self, $F, $oldSpeed) = @_;
  63. my $new_E = ($self->config->use_relative_e_distances ? 0 : $self->reader->E) - $self->_advance;
  64. my $gcode = sprintf "G1 %s%.5f F%.3f ; pressure discharge\n",
  65. $self->_extrusion_axis, $new_E, $F // $self->_unretract_speed;
  66. $gcode .= sprintf "G92 %s%.5f ; restore E\n", $self->_extrusion_axis, $self->reader->E
  67. if !$self->config->use_relative_e_distances;
  68. $gcode .= sprintf "G1 F%.3f ; restore F\n", $oldSpeed
  69. if $oldSpeed;
  70. $self->_advance(0);
  71. return $gcode;
  72. }
  73. sub _unretract_speed {
  74. my ($self) = @_;
  75. return $self->config->get_at('retract_speed', $self->_tool) * 60;
  76. }
  77. 1;