Tuesday, June 18, 2013

Frankenplotter - drawing more than just circles and stars

Having discrete commands that drew specific shapes was all well and good, and gave me a decent idea of the functionality of the Frankenplotter.  But I wanted it to do something more, so I started browsing the web for various test vector files.

Eventually, I found one of a Starship Enterprise in .svg format, and figured that would make a good test case.

I inspected the file and found its <path> element.  The file was made up of a number of move and draw commands, but most of the drawing was being done with "c" and "z" commands for drawing relative-positioned cubic Bezier curves with closure. I was too tired for math and needed something easier.

So instead, I installed Inkscape and found ways to flatten the Beziers and save the whole thing out again.  This devolved the output to M and L commands (move absolute, draw absolute).

I added "input" command handling to the Arduino to understand the M and L commands.  For the first M command encountered, it doesn't actually move (since there is no concept of origin), but establishes an origin value for wherever the pen currently is.   It assumes I've pre-positioned the pen at some reasonable location on the page for starting the drawing.  Subsequently, every M or L command that comes along is used to determine a delta x, delta y movement.  After each movement, I update the "current location" variables.

I tried sending the whole file over to the Arduino, using a terminal window on the Mac, and plain Unix commands (cat filename > /dev/tty.usbmodem621, or something like that).  It would work for the first ten or 11 lines, but then crap out.  It was intriguing seeing the system react to the first several lines, and disappointing to see it stop.

As it turned out, the reason the program would crap out after ten or eleven lines was that I was overflowing the Arduino's Serial.read buffer, and that effectively killed the whole approach.  Serial functions in Arduino land are not blocking.

I tried another solution with a bit of Perl for sending the commands to the Frankenplotter, rather than just using cat.  The perl script would throttle the data transfer by sending a line, and then delaying a fixed amount of time.  That would give the Arduino a chance of keeping up.  With some tuning, the script worked, but it made things painfully slow.  Really, I had to be careful of the long vectors which would take a long time for motor movement, so I had to make my throttling delay long enough for the long vectors.  But for short vectors, I'd draw a little bit and then I'd go into the wait state for the Perl to send another command, and with so many short vectors, it would take forbloodyever.  I could have adjusted the code to be sensitive to the hypotenuse of each vector, and then compensated for estimated motor timing in each axis (since one moves faster than the other).

Instead of fixed or estimated delays, I knew the right solution required a call and response.  I needed a way to send a command, and wait for a response.  That required bidirectional communication.  For Perl, that meant getting some TTY libraries I didn't have.  I tried using ppm to download and install them, but building those required a C compiler, and since I was running Mac OS 10.6.8, I couldn't install the C compiler without becoming an Apple developer.

So then I switched to Java.  I found rxtx libraries that I could download, but then found that they weren't available in for my chipset architecture.  But in searching and trusting a site out there, I found rxtx 10.6.8 libraries for 32-bit and 64-bit.

Once I had that, I changed the Arduino code to return a "Z" character to the TTY port after each motor movement was completed.  The rxtx example code didn't do exactly what I wanted, but it wasn't too hard to figure out how to write my own code to suit my needs.  I made it so the Java code would send its M or L commands, and then wait to hear a Z before sending another one.  That worked!  Here's an example of how things started looking.



The scaling was hardcoded in the program, so eventually I added two more commands: S would allow establishment of a scale factor, and Z would indicate file completion to the Frankenplotter, allowing it to disable motors.  I also used Excel to analyze the full vector set to see max, min, and origin information, and that gave me an idea of where to put the pen before starting to draw.

To avoid the divots in the scanner bed, I stole a piece of glass from a picture frame, and taped it inside the scanner bed to act as the drawing surface.  I also took out any remaining electronics from the scanner bed.  The height of the glass surface forced me to cut off a plastic fin from beneath the scanner carriage, a fin that was originally used by the scanner to do hard-limit detection (using an optosensor that the fin would slide through).

You can see that I still don't have a pen up/down function, so there are lots of goofy lines drawn within and across the image.

No comments:

Post a Comment