The Processing `arc()` command isn’t robust enough for my tastes so I wrote a new one that gives me more control over the things I care about. Along the way it lets me validate my arc code for the Makelangelo’s support of gcode commands G02 and G03. If people are learning Gcode then their arc() command would be helpful if it looked the same as a gcode command. Don’t you agree?

View this post on Instagram

A post shared by Marginally Clever Robots (@imakerobots) on

## Gcode G02 and G03

`G02 X[decimal number] Y[decimal number] I[decimal number] J[decimal number];`
`G03 X[decimal number] Y[decimal number] I[decimal number] J[decimal number];`

• G02 indicates a clockwise arc.
• G03 is a counter-clockwise arc.
• Arcs begin at the current tool location.
• Arcs end at (X,Y).
• Arc center is (I,J).

I’m going to make a processing method that follows the same format.

`drawArc(float sx,float sy,float ex,float ey,float cx,float cy,boolean cw)`

• cw=true is a G02 clockwise arc.
• cw=false is a G03 counter-clockwise arc.
• Arcs begin at (sx,sy).
• Arcs end at (ex,ey).
• Arc center is (cx,cy).

This method works even if the arc is not a perfect circle.

## The processing arc example code

```/**
* Illustrating G02 (clockwise) and G03 (counter-clockwise) arcs.
* 2016-06-29 Dan Royer (dan@marginallyclever.com)
* CC-by-SA
*/
void setup() {
size(500,500);
drawOneRandomArc();
//drawArc(250+125,250+0,250+0,250+125,250+0,250+0,true);
}

void draw() {}

void drawOneRandomArc() {
// start of arc
float sx = random(width);
float sy = random(height);
// end of arc
float ex = random(width);
float ey = random(height);
// center of arc
float cx = random(width);
float cy = random(height);

boolean clockwise = (random(2)==1);

stroke(random(255),random(255),random(255));
drawArc(sx,sy,ex,ey,cx,cy,clockwise);
}

// returns angle of dy/dx as a value from 0...2PI
float atan3(float dy,float dx) {
float a=atan2(dy,dx);
if(a<0) a=(PI*2.0)+a;
return a;
}

// draw an arc
void drawArc(float sx,float sy,float ex,float ey,float cx,float cy,boolean cw) {
println("start =("+sx+","+sy+")");
println("end =("+ex+","+ey+")");
println("center =("+cx+","+cy+")");
println("clockwise="+cw);

float dx = sx - cx;
float dy = sy - cy;
float angle1=atan3(dy,dx);
float sr=sqrt(dx*dx+dy*dy);
dx = ex - cx;
dy = ey - cy;
float angle2=atan3(dy,dx);
float er=sqrt(dx*dx+dy*dy);

// find angle of arc (sweep)
float sweep=angle2-angle1;

if(!cw && sweep<0) angle2+=2*PI;
else if(cw && sweep>0) angle1+=2*PI;

sweep = angle2-angle1;
float dr = er-sr;
println("angle1="+angle1);
println("angle2="+angle2);
println("sweep="+sweep);

println("green is start");
stroke(0,255,0);
line(cx,cy,sx,sy);
println("red is end");
stroke(255,0,0);
line(cx,cy,ex,ey);

// get length of arc
// float len=theta*circ/(PI*2.0);
// simplifies to
float len1 = abs(sweep) * sr;
float len = sqrt( len1 * len1 + dr * dr );

int i, segments = max( ceil( len / 10 ), 1);
float r, nx, ny, a, scale;

strokeWeight(2);
println("segments="+segments);
for(i=0;i<=segments;++i) {
// interpolate around the arc
scale = ((float)i)/((float)segments);
a = sweep * scale + angle1;
r = dr * scale + sr;
//print("R="+r);
//println("\tS="+scale);
nx = cx + cos(a) * r;
ny = cy + sin(a) * r;
// send it to the planner
stroke(scale*255,255-scale*255,0);
line(sx,sy,nx,ny);
sx = nx;
sy = ny;
}
}```

## How the processing arc code would work in a CNC machine

The stroke() command would be removed. The line() command would be send to the layer that does the Inverse Kinematics and then runs Bresenham’s algorithm to move the motors along the line. We piggy back on the existing G00/G01 line ability to make our arcs.

## Now you try

Copy the Processing arc code from Github into Processing and draw some choice arcs. Make a happy face. Write the same arcs as gcode commands. Load them in the Makelangelo. Draw your happy face on a piece of paper with the robot. Tweet me a pic.