vibrationlimit.t 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. use Test::More tests => 9;
  2. use strict;
  3. use warnings;
  4. BEGIN {
  5. use FindBin;
  6. use lib "$FindBin::Bin/../lib";
  7. use local::lib "$FindBin::Bin/../local-lib";
  8. }
  9. use Slic3r;
  10. use Slic3r::Geometry qw(epsilon);
  11. use Slic3r::Test;
  12. my $config = Slic3r::Config->new_from_defaults;
  13. # tolerance, in minutes
  14. # (our time estimation differs from the internal one because of decimals truncation)
  15. my $epsilon = 0.002;
  16. my $test = sub {
  17. my ($conf) = @_;
  18. $conf ||= $config;
  19. my $print = Slic3r::Test::init_print('2x20x10', config => $conf);
  20. my $min_time = 1 / ($conf->vibration_limit * 60); # minimum time between direction changes in minutes
  21. my %dir = (X => 0, Y => 0);
  22. my %dir_time = (X => 0, Y => 0);
  23. my %dir_sleep_time = (X => 0, Y => 0);
  24. my $last_cmd_pause = 0;
  25. Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
  26. my ($self, $cmd, $args, $info) = @_;
  27. if ($cmd !~ /^G[01]$/) {
  28. if ($cmd eq 'G4') {
  29. $last_cmd_pause = (($args->{P} // 0) / 1000 + ($args->{S} // 0)) / 60; # in minutes
  30. $dir_sleep_time{$_} += $last_cmd_pause for qw(X Y);
  31. $last_cmd_pause -= $epsilon; # error builds up
  32. }
  33. return;
  34. }
  35. # Z moves are slow enough that we can consider any vibration interrupted
  36. if ($info->{dist_Z}) {
  37. $dir_time{$_} += 99999 for qw(X Y);
  38. $last_cmd_pause = 0;
  39. return;
  40. } elsif ($info->{dist_E} != 0 && $info->{dist_XY} == 0) {
  41. my $time = abs($info->{dist_E}) / ($args->{F} // $self->F); # in minutes
  42. $dir_time{$_} += $time for qw(X Y);
  43. $last_cmd_pause = 0;
  44. return;
  45. }
  46. # compute move time (this assumes that the speed is XY-bound, which happens very likely)
  47. my $time = abs($info->{dist_XY}) / ($args->{F} // $self->F); # in minutes
  48. my $one_axis_would_trigger_limit_without_pause = 0;
  49. foreach my $axis (qw(X Y)) {
  50. # get the direction by comparing the new $axis coordinate with the current one
  51. # 1 = positive, 0 = no change, -1 = negative
  52. my $dir = $info->{"new_$axis"} <=> $self->$axis;
  53. # are we changing direction on this axis?
  54. if ($dir != 0 && $dir{$axis} != $dir) {
  55. # this move changes direction on this axis
  56. if ($dir{$axis} != 0) {
  57. if (($dir_time{$axis} + $dir_sleep_time{$axis}) < ($min_time - $epsilon)) {
  58. fail 'vibration limit exceeded';
  59. }
  60. $one_axis_would_trigger_limit_without_pause = 1
  61. if ($dir_time{$axis} - $last_cmd_pause) < $min_time;
  62. }
  63. $dir{$axis} = $dir;
  64. $dir_time{$axis} = 0;
  65. $dir_sleep_time{$axis} = 0;
  66. }
  67. $dir_time{$axis} += $time;
  68. }
  69. fail 'no unnecessary pauses are added'
  70. if $last_cmd_pause > $epsilon && !$one_axis_would_trigger_limit_without_pause;
  71. $last_cmd_pause = 0;
  72. });
  73. 1;
  74. };
  75. $config->set('gcode_comments', 1);
  76. $config->set('perimeters', 1);
  77. foreach my $frequency (5, 10, 15) {
  78. foreach my $gapfillspeed (20, 50, 100) {
  79. $config->set('vibration_limit', $frequency);
  80. ok $test->(), "vibrations limited to ${frequency}Hz (gap fill speed = ${gapfillspeed} mm/s)";
  81. }
  82. }
  83. __END__