Sandtable Etch-a-Sketch

Hi folks!

I wrote some python code (SandSketch) to drive your sandtable like an etch-a-sketch using a PS5 DualSense controller and a PC. It worked out really well so I wanted to share it.

The joysticks behave like a standard etch-a-sketch - left one to move left and right, right one to move forwards and back. I also added a pretty intuitive way to draw arcs, circles, and spirals - you press the circle button to set a centerpoint, and then move away and press a button to draw an arc at that radius. You can move further away and do it again to do concentric circles. The left joystick does counterclockwise arcs and circles, the L1 button does a tight spiral, and the L2 button does a looser spiral. Right side does the same thing clockwise.

There are a couple of convenience buttons to home the table and to wipe either all or a designated part of the table.

It saves the gcode from your drawing to a file, and there’s another small program (SandSender) that just reads in gcode files and sends them over the network so you can save and replay your drawing.

I’m a better programmer than artist but here’s an example:

You shouldn’t need anything particularly special to run it beyond a PS5 controller. I paired my controller with my PC over Bluetooth and then I’m sending the gcode to the table over telnet (I have a Makerbase DLC32 board running GRBL which was already on the network). There are some constants at the top of the file to set the IP address and port, X/Y max dimensions, and machine speed.

I’m not really doing any error handling but so far the code has worked just fine.

You’ll need to have python3 installed and pip install pydualsense, time, asyncio, telnetlib3, and dataclasses.

Code is in the SandSketch directory here : GitHub - jscotkin/sandtable: AI voice control of ZenXY sandtable . Instructions in the and it prints them out when it runs.

Have fun!


That is a killer feature and a clever bit of code. It was easy to read, thank you.

Is gcode over telnet common? I wonder if fluidnc has that feature?

Thanks, Jeff! My lowrider with the jackpot is a couple hours away so I can’t check directly but I’m pretty sure it does. For instance this issue has pointers to tcp code : Feature: GCODE stream from telnet or websocket or serial · Issue #1012 · bdring/FluidNC · GitHub

I was actually surprised that the tcp side just worked - I expected to have to write a bunch of code to deal with buffering. But GBRL takes n messages, then blocks until it’s ready for more, so the simple loop does the trick. It appears from some tests I did (though I can’t prove it) that it’s properly merging commands as well to keep things smooth.

Btw if you play with the etch a sketch code you might want to tune the rate variable and sleep timer to make it feel smooth on your machine.


Gotta say I was.wondering the same.

I know I’ve used SSH sockets to do UUCP and send printer jobs, but I got to do both ends for that. (And it’s been decades since I’ve touched UUCP for anything. :rofl:)

Still, if a printer firmware has a TCP/IP stack, it should stand to reason that it can use TELNET for anything it could use a UART for… (no need for SSH.)

1 Like

Took another look - Fluidnc definitely supports TCP and Telnet. Scroll down to the section labeled Wifi Communication Methods.

“If you have $Telnet/Enable=True , you can communicate via telnet with the same protocol as serial. The default port is 23 and set by $Telnet/Port . If enabled, you should see it in your startup messages.”

Looks like it supports WebSockets as well, which is nice if you want to make a custom gui or route cleanly through firewalls, etc. Everyone keeps talking about that M5 pendant but it looks like it would be flexible enough to build a quick custom gui on any type of screen or form factor.

Have fun!


This is going to be in the queue to test as I get my ZXY back up to speed.

1 Like

Awesome - let me know if you have any questions or anything I can do to help!

ready for your Rmrrf??

Pushed a very minor fix - if you hit the button to home the table, it wasn’t requerying the x,y position so as soon as you started to move it would jump you somewhere unexpected.