Saturday, June 7, 2025

Arrakis 2.0 update

What's the simplest user interface of all?

Creating new patterns to run on on a sand table using Sandify is a complicated process that requires a lot of specialized knowledge and some experience with Sandify. First I generate the pattern in a size that will fit on the table. This takes me anywhere between a few minutes and a few hours, depending on my mood and what I'm seeing in the patterns in Sandify. After that, I run a post-processor (that I had to write myself) to assign two speeds to the drawing, then I upload it to the table, using the controller's 3D printer style web interface, and run the pattern to test it. If I like it, it stays in the memory on the table's controller board. Once I have a bunch of working patterns stored on the table, I often want to string them together in sequences so that I don't have to select and run them one by one. That requires some knowledge about the GCODE used by the controller. None of this process is what anyone would call "user-friendly".


A pattern preview from Sandify.




When I take Arrakis 2.0 to public venues like Maker Faires, I manually compose a macro file that runs a sequence of drawing and erase patterns. The patterns in the sequence are generated and/or chosen for the specific event/venue, and then I set up another macro that runs at power up and calls the pattern sequence macro. That way I don't need to do anything with the table but set it up and power it on and it will run unattended as it works through the pattern sequence macro, assuming there are no typos (and it's very easy for typos too creep into the file!). This is what that type of macro looks like:

M98 P/gcodes/maker_faire_milwaukee_2021.gcode
G04 S60
M98 P/gcodes/wipe01.gcode
M98 P/gcodes/ARRAKIS_90000_90000.gcode
G04 S60
M98 P/gcodes/wipe02.gcode
M98 P/gcodes/091821_04_18000_60000.gcode
G04 S60
M98 P/gcodes/wipe03_circle_center_out.gcode
M98 P/gcodes/090421_01_30000_60000.gcode
G04 S60
M98 P/gcodes/wipe01.gcode
M98 P/gcodes/091721_04_18000_60000.gcode
G04 S60
M98 P/gcodes/wipe02.gcode
M98 P/gcodes/091621_01_18000_60000.gcode
G04 S60
M98 P/gcodes/wipe01.gcode
M98 P/gcodes/090921_02_12000_60000.gcode
G04 S60
...

It's nice to operate the table this way, but it runs the same pattern sequence every time the table is powered up. That's OK at a Maker Faire, but not so good in my living room.

Composing the pattern sequence macro requires careful attention to detail. A single error in any of the file names will cause cause the table to stop dead. If I make a sequence that runs for 12 hours, the only way to be sure there are no typos is to run the file for the entire 12 hours. If it fails when I'm not watching it, I can't tell where it failed (maybe there's a log file somewhere that I don't know about), so I have to hunt through the file to try to find the error. It can be very tedious.

If I were better at writing software, I might try to write a dedicated user interface that would allow the selection of files to run from a phone or computer, providing previews of the patterns and allow composing sequences on-the-fly. Some day, if I am sufficiently motivated, I may try to do that. In the meantime, with the help of DC42 at the reprap forums, I was able to take advantage of one of the nicer features built into RepRap Firmware on the Duet2 controller board- specifically, the random function, to implement the simplest user interface possible- the power switch!

Now I store drawing files on the table's SD card in a folder called: 0:/gcodes/draw/ and erase files in a folder called 0:/gcodes/wipe/. I was able to put together a simple macro file that calls out a random erase pattern, followed by a random drawing pattern, followed by a 60 second delay, followed by much more of the same.

The new random sequence macro file looks like this:

; filename RS
M98 P{"/gcodes/wipe/"^random(22)^".gcode"} ; erase
M98 P{"/gcodes/draw/"^random(224)^".gcode"} ; draw a pattern
G04 S60 ; delay 60 seconds
M98 P{"/gcodes/wipe/"^random(22)^".gcode"} ; erase
M98 P{"/gcodes/draw/"^random(224)^".gcode"} ; draw a pattern
G04 S60 ; delay 60 seconds
M98 P{"/gcodes/wipe/"^random(22)^".gcode"} ; erase
M98 P{"/gcodes/draw/"^random(224)^".gcode"} ; draw a pattern
G04 S60 ; delay 60 seconds
etc.

The 'random' function returns an integer value between 0 and the number in parentheses minus 1. The first M98 command randomly selects one of 22 different erase patterns that are stored on the SD card in the wipe folder, with names like 0.gcode, 1.gcode, ... 21.gcode. The second M98 command selects one of 224 drawing patterns stored in the draw folder, also with names like 0.gcode, 1.gcode, ... 223.gcode. 

There are really only 3 lines in the file and all the others are just copies. If the first three lines work, the entire file will work, which makes testing super fast and easy. This doesn't make generating new patterns any easier, but it sure makes running the table simple and more enjoyable.

There's no provision to ensure that a pattern file doesn't get called multiple times during a sequence, but I can live with that. Also, if I delete one pattern or erase file, I need to rename all of them or replace the one I deleted with a file that has the same name. I think I can set up a test to see if the file exists before the table tries to draw it.

At some point I may try to use the looping capability in RepRap Firmware to make the random file smaller, but right now, it's very easy to copy and paste the statements as shown to make a very long sequence (even months long!), so my motivation is low. If I ever do mess with the looping, I'll update this post.

No comments:

Post a Comment

Leave comments or a questions here and I'll try to post a response as soon as I can.