Sandify CLI

Hi all!

I just started a Sand Table build and would like to control the full experience from my phone. I have a lot of experience building games and building tools for game development, but wanted to try out something new as a hobby. Sand Table it is! After a lot of research I found Sandify! I was pulling my hair out on how to properly generate GCode that supports a SCARA (which is what I will be building) bot without going neck deep into Firmware land, but then found the conversion to “goofy” XY code approach which made a lot of sense to me.

Now what I am interested in, is running Sandify CLI to essentially convert Cartesian configured GCode to “Goofy”/Polar GCode. This would allow me to feed any supported GCode through the converter, and directly pass that onto UGS>GRBL all with the press of one button.

Has anyone here managed to run Sandify CLI yet? If so, any pointers?

PS: I know its a bit overkill to do it using Sandify since it can do a whole lot more than function as a converter, but the benefit is that I don’t have to write all sorts of support like .thr, .nc, etc! Just make use of the already amazing work that has been done and potentially contribute back to the project!

Cheers!
Paul

2 Likes

Welcome Paul!

Sandify is a beast, written in javascript, very interconnected with it’s front end. The frameworks are react, redux, and react-bootstrap. We made very little effort to make the math reusable. It is pretty embedded into sandify.

But, hope is not lost. The goofy scara stuff started as a python script, and wasn’t incorporated into sandify until I had a few people asking for it. The original math, and code to convert from thetarho to goofy gcode is here:

Theta rho is the format created by Bruce Shapiro for the sisyphus machines. Theta is the angle of the arm. Rho is a normalized (0 to 1) radius value for the distance from the center.

You asked for gcode to goofy gcode though. Let me tell you why thetarho is easier for this.

First off, a move in gcode is a line. But moves in goofy scara code are all arcs. Moving the shoulder and elbows always results in arcs, not lines (except for some arcs with infinite radii :slight_smile: ). Thetarho also only creates arcs. If you want to convert a square to scara or thetarho, you have to break it up into a couple of hundred commands to get a smooth line-like edge. If you want a cartesian gcode to scara gcode converter, you need to break up the lines.

Gcode for a square might look like this:

G1 X100 Y100
G1 X-100 Y100
G1 X-100 Y-100
G1 X100 Y-100
G1 X100 Y100

It can really look a lot of ways, but this is the best for human readability :slight_smile:. If you just took the coordinates (100,100) , (-100,100) and converted them to angles, your scara machine would draw a circle to get to each of those points.

So you really need to break that line up into (100,100), (99.9,100),(99.8,100)… etc. Then convert each point to scara angles. Sandify does this already when you import gcode and export theta rho. It is all in the exporter for theta rho. That could be rewritten easily enough.

The second trick is accumulating the angles over 2 pi. When the gcode goes from (-0.1,100) to (0.1,100); the naive approach would be to just convert each of those coordinates to shoulder angles independently. But that would result in an angle going from <2pi to >0. But you want it to go to >2pi. And the next time around, go over 4pi. Otherwise the arms would unwind every time they passed over that angle.

To fix that, sandify takes two consecutive points and computes the smallest angle to get there, and adds that to the start angle. That accumulator math is baked into the thetarho conversion. It is safe because we already broke every move into small ones that are definitely smaller than pi, so it is easy to be sure we won’t accidentally go the wrong way around the circle.

Compare that to converting thetarho format. This is the simplest thetarho script:

0.00 0.00
628 1.00

That goes from 0 angle to 100pi, as it also goes from the center (0) to the edge (1). That makes a big spiral that starts in the middle, makes 100 turns, and ends at the outside edge. The way sisyphus interprets between them, the radius at each turn will increase by 0.01. it will be a nice spiral.

If you just took those two end points and converted them to scara, it would be something like:

G1 X0.00 Y0.00
G1 X600 Y597

It is something like that, I’m not actually doing the math. There are 6 “units” in a circle. The shoulder would move 100 circles. The elbow would move 100 circles, minus a half circle to end up fully extending the arm.

That would do exactly the same spiral. When X was at 6, Y would be at 5.97, which would make the radius of the ball 0.01 from the center to the outer edge.

Even huge arcs like that one will be mapped correctly. Anything from sandify will definitely be converted correctly. I also think any pattern from the web in thetarho would be converted correctly.

Any patterns in gcode that you want in scara can be converted in sandify by importing and exporting as thetarho, then converting to scara using that script. Or just export the scara directly.

I hope that gives you some ideas.

I’m curious, why do you want to store the original files in cartesian gcode, and not in scara gcode?

Hi Jeff,

Apologies for the long delay on replying. Got caught up with work and some travel!

In the meanwhile I have managed to get the bot working, and successfully run some sandify exported fiels on it! (Or well, they look correct, but nothing is drawn on sand yet… So hard to say if 100% accurate)

I also had some time to write the CLI version of Sandify that convertes Cartesian XY to “SCARA XY” using source code from Sandify. Thanks for your pointers! You can find said code here: CartesianGCodeToScara/gcode_to_scara.py at main · Ambrosiussen/CartesianGCodeToScara · GitHub
Thoughts?

I can now just pass in any cartesian Gcode and I will get a SCARA XY Gcode file back! Right now its simply converting, but I plan on adding more to it :slight_smile:

My end goal is to be able to (in addition to a library of default drawings) be able to draw on a little tablet I have on the table. That drawing will be in XY and thus need to be converted. I also want to be able to support Gcode coming from various other places. (like .thr) Hence the desire to be able to convert.

Cheers!

1 Like

I didn’t run your code, but my eye ball compiler thinks it looks good. I have a few nits, but they are based on my personal preference, and I don’t see anything wrong with your code (software developers can be agitated by the silliest things).

How big do the numbers get when you use 360 units per circle? My guess if you don’t need 3 units of precision when you are using numbers that big. But also, it probably isn’t a big deal. It is easy for me to forget that computers are doing the math, and not me. :slight_smile:

The code works! I have tested it on the bot already :slight_smile:
But please do share your feedback, regardless of nitpicky-ness.

My units per circle are based on the Steps per Degree setting for my GRBL firmware. Calculated as follows:
Steps per Degree = 1/((1.80)*(1/MicroSteps)*(GearsEngine/GearsDriver))

I use 32 microsteps with the DRV8825 and NEMA17 stepper motors, and my gears have 20 and 66 teeth! Gives me 58,667. Now 360mm == 1 revolution.

That makes sense. You can pick whatever scale of unit there. 360 makes a lot of sense because one rev is a whole number. My only concern is I didn’t want something with 100 revolutions, or 1,000 revolutions to start printing 2.356e6 instead of whole numbers. I’m not sure grbl will handle those large numbers well.

To combat that, I made up my own unit, which has 6 per rev. It is sort of 2pi, but a whole number for each rev. You would change your 360 in your code to 6 and then divide your steps per mm by 60.

This is an imaginary concern. One I have worried about, but I doubt I have ever seen the problem. If you keep an eye out, you will have this solution ready in case you have that issue. Changing the format might also make an easy fix.

Alright:

  • I don’t think you need the vector class. Numpy should be able to do that math without needing a new object.
  • cartesian_xy_from_theterho is more accurately scara_xy_from_theta_rho. Because the return isn’t cartesian
  • The for loop with vertex1 and vertex2 would make more sense to me if you had something like:
previousVertex = None
for nextVertex in vertices:
  if previousVertex:
    # Do something with the two vertices
  previousVertex = nextVertex
  • The gcode may not always have X and Y defined. Sandify code does, but you may want to handle cases where only X or only Y is defined. The missing var will be whatever was there before. I am sure you will find a few odd quirks about gcode as you import more files. A gcode reading library might help.
  • You could determine the scale automatically, from the max distance from the center. Unless you don’t want to scale it.

In general, it works fine as it is. These won’t really make much difference, if at all. Since you need to look at it more than me, you should use the style and techniques that make sense to you.

1 Like