# 3daxi.pl - Plot in X, Y, and Z with AxiDraw Plotter # - Chris Pirazzi and Paul Haeberli # # For details, see https://lurkertech.com/3daxi # # Accesses AxiDraw using server described at https://lurkertech.com/axiserver # use utf8; use strict; use English qw( -no_match_vars ); use Carp qw(cluck confess); use Data::Dumper; use Math::Trig qw(pi); use IO::Socket::INET; # auto-flush on socket $| = 1; # create a connecting socket my $socket = new IO::Socket::INET ( PeerHost => 'mycomputer.local', # <-- hostname of server PeerPort => '12345', # <-- port of server Proto => 'tcp', ); die "cannot connect to the server $!\n" unless $socket; print "connected to the server\n"; sub cmd { my $s = shift; # data to send to a server my $size = $socket->send($s . "\n"); print "sent [$s]\n"; # receive a response of up to 4096 characters from server my $response = ""; $socket->recv($response, 4096); chomp $response; print "received response: [$response]\n"; print "\n"; #exit if ('OK' ne $response); } # servo levels ("min"/"max") # - SC,5,Z (up) or SC,4,Z (dn) # - Z in [1,65535] (for Axidraw [7500,28000]) # - controls a pulse width in ns for a servo controller # - units of 83ns of duty cycle (units of 1/12000th of a second) # - e.g. 16000 * 83ns = 1.33ms # - wider pulse makes the pen go higher in z # - pulses are sent out each 24ms # # servo rate SC,10,R # - if R=0 then SC,5 takes effect immediately # - new pulse width starts coming out immediately after cmd executes # - I guess this means hardware goes as fast as it can # - if R != 0 then when you issue SC,5 # - first the hardware outputs the old rate # - then every 24ms # - the system adds/subtracts R to to get towards the new rate # - until enough 24ms periods happened to get to new rate # - so R = height unit change per 24ms # - so if we have desired speed S = height unit change per ms # R = S*24 # my $pen_x; my $pen_y; my $pen_z; sub pen_z_to { my $dst_z = shift; my $ms = shift; my $dz = abs($dst_z - $pen_z); my $S = $dz / (0.0 + $ms); # choose servo rate $R that will make a $dz change happen in $ms ms # my $R = $S * 24.0; print "dz=$dz ms=$ms S=$S R=$R\n"; $R = int($R); cmd("SC,10,$R"); # servo rate cmd("SC,4,$dst_z"); # pen down pos, default 12000, more higher # XXX third arg should be $ms according to dox: CONFUSED cmd("SP,1,0"); # pen down $pen_z = $dst_z; } sub pen_up { cmd("SC,10,0"); # servo rate ("quick as posible") cmd("SP,0,200"); # pen up (200ms enough for "quick as possible") } #cmd("R"); # reset # set pen up pos nice and high cmd("SC,5,20000"); # pen up pos, default 16000, more higher # quickly put pen in known down pos cmd("SC,10,0"); # servo rate ("quick as possible") $pen_z = 20000; cmd("SC,4,$pen_z"); # pen down pos, default 12000, more higher cmd("SP,1,200"); # pen down (200ms enough for "quick as possible") # assume xy pos $pen_x = 0; $pen_y = 0; sub move_to { my $x = int(shift); my $y = int(shift); my $z = int(shift); my $ms = int(shift); print "===== move to x=$x y=$y z=$z ms=$ms\n"; print "cur pos pen_x=$pen_x pen_y=$pen_y pen_z=$pen_z\n"; my $dx = $x - $pen_x; my $dy = $y - $pen_y; print "dx=$dx dy=$dy\n"; # returns immediately, does not delay next command, move takes $ms pen_z_to($z, $ms); # returns immediately, does not delay next command, move takes $ms cmd("XM,$ms,$dx,$dy"); # move xy # ... somehow magically next command delayed by $ms?! HOW??? $pen_x = $x; $pen_y = $y; } # centerburst # starting at 0,0,20000 # my $orad = 6000; my $slices = 18; for(my $out_to_in = 0; $out_to_in < 1; $out_to_in++) { for(my $i=0; $i < $slices; $i++) { my $phase = ($out_to_in ? 0 : 0.5); my $ang = 2*pi * (($i + $phase) / $slices); pen_up(); if ($out_to_in) # thick out to thin in { move_to($orad + $orad * sin($ang), $orad + $orad * cos($ang), 20000, 10000); # let ink flow down move_to($orad + $orad * sin($ang), $orad + $orad * cos($ang), 9000, 200); move_to($orad, $orad, 16000, 1200); } else # thick in to thin out { move_to($orad, $orad, 20000, 5000); # let ink flow down move_to($orad, $orad, 9000, 200); move_to($orad + $orad * sin($ang), $orad + $orad * cos($ang), 16000, 1200); } } } pen_up(); move_to(0, 0, 20000, 2000); $socket->close();