Exporting DXF is mirrored - CMM Arm

I am working on building a CMM Arm with the end goal of exporting a 3D .DXF file of the object measured as well as a point cloud file (simple Tab Delimited Text file). I am having trouble with exporting the DXF as its saving as a mirrored image to the original (see processing screen shot and Solidworks import below). Where I believe I am falling into trouble is the scale and translate functions I call early on in the draw() function.

scale(1, -1); //Reverses the Y coordinate system
translate(0, -height); //Reverses the Y coordinate system

The reason I used this was to flip the Y axis so that it matches machine coordinates and not programming coordinates. If I need to I can change the hardware but that’s a bit of a nightmare at this point.

How can I export the dxf file in the correct orientation?


//============================================================
//  3D Digitizer
//  Used with 3D digitizer:
//  Program based off original concept by: http://fablab.ruc.dk/diy-digitizer/
//  4 Axis digitizing arm. Point Cloud export and surface shape
//============================================================

import processing.serial.*;
import peasy.*;
import processing.dxf.*;
PrintWriter output;

boolean record = false;
RawDXF dxf;

//============================================================
//-3D navigation
//============================================================
PeasyCam cam;

//============================================================
//-Digitizer
//============================================================
pointer digitizer = new pointer(this, 0);

//============================================================
//  GUI controls
//============================================================
ArrayList<control> controls = new ArrayList<control>();

control ctl_clear = new control(10, 10, 'q', "Clear", "Clear all");
control ctl_point = new control(10, 10+1*40, 'p', "Point", "Mark a point");
control ctl_circle = new control(10, 10+2*40, 'c', "Circle", "Mark a hole");
control ctl_feature = new control(10, 10+3*40, 'f', "Feature", "Start a feature. Use \"Modify\" to add points");
control ctl_modify = new control(10, 10+4*40, 'm', "Modify", "Modify last figure");
control ctl_pdf = new control(10, 10+5*40, 'z', ".pdf", "Export as flat PDF file");
control ctl_dxf = new control(10, 10+6*40, 'd', ".dxf", "Export as 3D .DFX file");

//============================================================
//  Objects
//============================================================
ArrayList<object> objects = new ArrayList<object>();

//============================================================
//  Setup
//============================================================
void setup()
{
  size(1200, 800, P3D);
  output = createWriter("positions.txt");
  //Set up visualizer
  cam = new PeasyCam(this, 300);
  cam.setMinimumDistance(50);
  cam.setMaximumDistance(1000);
  //Add GUI controls to display list
  controls.add(ctl_clear);
  controls.add(ctl_point); 
  ctl_point.typematic=true;
  controls.add(ctl_circle); 
  ctl_circle.typematic=true;
  controls.add(ctl_feature);
  controls.add(ctl_modify);
  ctl_modify.typematic=true;
  controls.add(ctl_pdf);
  controls.add(ctl_dxf);

  background(50);
}

//============================================================
//  Handy globals
//============================================================
float penX=0;
float penY=0;
float penZ=0;
float penA=0;
//PVector pen;

object currentObject=null; //-Last created object

//============================================================
//  Draw
//======================================================proce======

void draw()
{

  //-Get coordinated from digitizer
  digitizer.update();      //-Update globals

  scale(1, -1);            //Reverses the Y coordinate system
  translate(0, -height);   //Reverses the Y coordinate system

  translate(-135, 650);    // Moves the background

  PVector pd=new PVector(digitizer.tip.x, digitizer.tip.y);
  penA=digitizer.rotation;

  pd.rotate(-penA);

  penX=pd.x;   
  penY=pd.y;
  penZ=digitizer.tip.z;
  //  pen=digitizer.tip;


  background(0);

  //-Draw pad
  stroke(250);
  //  fill(10,10,10,128);
  noFill();
  rect(-45, -10, 305, 235);

  rotateZ(penA);

  // Draw Tool Home Location
  stroke(100, 500, 0);
  line(248, 277, -52, 258, 277, -52);  // Horizontal Line
  line(248, 287, -52, 248, 277, -52);  // Vertical Line

  //-Draw Orign Triad
  stroke(255, 0, 0);  // X Axis Line
  line(0, 0, 20, 0);
  stroke(0, 255, 0);  // Y Axis Line
  line(0, 0, 0, 20);
  stroke(0, 0, 255);  // Z Axis Line
  line(0, 0, 0, 0, 0, 20);

  /*
  //-Draw all objects flat projection
   for (object obj : objects)
   {
   obj.project();
   }
   */

  if (record == true) {
    beginRaw(DXF, "output.dxf"); // Start recording to the file
  }

  //-Draw all objects
  for (object obj : objects)
  {
    obj.draw();
  }

  if (record == true) {
    endRaw();
    record = false; // Stop recording to the file
  }


  //-Draw cursor
  pushMatrix();
  rotateZ(-penA);
  translate(digitizer.tip.x, digitizer.tip.y, digitizer.tip.z);
  stroke(0, 255, 0);
  noFill();
  box(5);
  popMatrix();


  //-Draw Heads Up Display
  cam.beginHUD();  
  color faceColor=color(98, 206, 198);
  color textColor=color(75, 42, 0);
  stroke(50);
  fill(98, 206, 198);
  rect(width-115, 10, 105, 90);
  fill(75, 42, 0);
  textSize(15);
  //-Coordinates
  text("X: "+penX, width-110, 30);
  text("Y: "+penY, width-110, 50);
  text("Z: "+penZ, width-110, 70);
  text("R: "+penA, width-110, 90);
  pushStyle();
  //-Update GUI controls 
  if (ctl_clear.update())
  {
    objects.clear();
  }
  if (ctl_point.update())
  {
    currentObject=new gpoint(penX, penY, penZ);
    objects.add(currentObject);
    point(penX, penY, penZ);
    output.println(penX + "\t" + penY + "\t" + penZ);
  }
  if (ctl_circle.update())
  {
    currentObject=new gcircle(penX, penY, penZ);
    objects.add(currentObject);
  }
  if (ctl_feature.update())
  {
    currentObject=new gfeature(penX, penY, penZ);
    objects.add(currentObject);
  }
  if (ctl_modify.update())
  {
    if (currentObject!=null)
    {
      currentObject.modify(new PVector(penX, penY, penZ));
    }
  }
  // XXX PDF File Save
  if (ctl_pdf.update())
  {
    
    record = true; // DXF record switch

    output.flush(); // Writes the remaining data to the file
    output.close(); // Finishes the file
    //exit(); // Stops the program



    /*
    beginRaw(DXF, "output.dxf"); 
     background(255);
     translate(width/2, height/2);
     //    scale(2.84832);
     for (object obj : objects)
     {
     obj.export();
     }
     endRaw();
     
    /*
     String s="3D_"+Integer.toString(year())+"_"+Integer.toString(day())+"_"+Integer.toString(hour())+"_"+Integer.toString(minute())+"_"+Integer.toString(second())+".pdf";
     beginRecord(PDF, s); 
     background(255);
     translate(width/2, height/2);
     scale(2.84832);
     for (object obj : objects)
     {
     obj.export();
     }
     endRecord();
     */
  }

  //-Draw GUI controls
  for (control ctl : controls)
  {
    if (ctl.change)
      ctl.draw();
    if (ctl.mouseOver)
      ctl.drawHelp();
  }
  popStyle();
  cam.endHUD();
}

3 Likes

For reference here is the CMM Arm (Faro Arm) that I made. It reads rotary encoders via an Arduino and spits out coordinates via Serial to Processing.

3 Likes

It is a bit hard for me to understand what your requirements are. You are intentionally flipping your coordinates with scale/translate, but you don’t want them flipped. Can you explain this part more? Why not just… stop flipping them?

1 Like

Machine Coordinates and Processing coordinates are not the same. A move in Y+ is inverse in
machine coordinates. As such I inverted the Y coordinate in processing and this allows for the movement in the arm to read correctly in processing. Sense what I am using this for is based around machine coordinates I was hoping to keep using this system. But as I have posted its saving the 3D model backwards. Hope this makes a bit more sense?

To be clear in the programming, 98% of it is not my code. Standing on the shoulders of giants and all.

This is the way processing uses coordinates:

Machine coordinates:

2 Likes

Here is an image with the physical coordinates of the Faro arm I am using, look at the bottom right corner I drew the Triad on the surface plate.

2 Likes

Think I got it figured out. It was all to do with where I placed my beginRaw statement in the draw() function. I did not realize that when you call beginRaw it cancels out any scale/translate function. So, I had to re-initialize them both right after I began recording.

  if (record == true) {
    beginRaw(DXF, "output.dxf"); // Start recording to the file
    scale(1, -1);
    translate(-100, -100);
  }

Its not pretty, but I am learning…

3 Likes

Not exactly it cancels out, but rather that both beginRaw() & beginRecord() internally creates a temp [u]PGraphics[/u] which is initialized w/ default styles & transforms, just like the sketch’s main canvas. :nerd_face:

I recall a long time ago I had created a separate initCanvas() invoked both from setup() and right after each beginRecord(), so both the main canvas & temporary PGraphics would have the same styles: :bulb:

3 Likes

Amazing!!. im about to build something similar atm.
For now I just scaled up a arm project I found but the updgrade I had in my mind the whole time looks about like yours do.

Right now im just trying to get a .pdf out to see how the tolerance is.The scale is super off and im kind of stuck.

So glad I found this post!. Great work!

My arm:

2 Likes

HI Bryan,

I love your design for the 4 rotary arm, do you have any plans on sharing the Arduino code for this design? I’ve have the 3 rotary working, but it would be great to get a 4th rotary set up.

Thanks
Michael

1 Like

Hello Michael,
You can find the code for the 4 axis arm on my GitHub repository.
https://github.com/BL-Shopwork/CCM-Arm

3 Likes

@Bryan1 i seen your GitHub page for your build, I am trying to replicate your build but i have different encoders.

I was wondering if you would be willing to share the “fine details” about your build such as the excel spreadsheets/CAD/part numbers for the encoders you used.

Looking at your pictures i was able to see the part number on the encoders is “E38S6G5-600B-G24N” unfortunately i tried to search this with no luck finding any data sheets

2 Likes

Hello,
The encoders I purchased are 600P/R AB phase encoders. You can buy them on ebay or many other sellers online.

What version are you going to build? the 4 axis or the 5 axis? Do you have access to a CNC machine and lathe? All my parts are machined.

1 Like

i will be building the 4 axis version.

Yes i do have access to machines to create the parts

1 Like

Uploaded the Solidworks files to GitHub as well as the Excel file I used for some of the math troubleshooting.

2 Likes

used your coding, got a java error. this due to you using PI vs computer

1 Like

Is this a statement? Question? Comment?

2 Likes

ĂŤt was a question, I downloaded files from
ttps://github.com/BL-Shopwork/CCM-Arm
uploaded arduino CMM_Digitizer_DH_v4 to uno board

these files not there, but CMM_Digitizer_DH_v4 calls for them.
#include “math.h”
#include “Geometry.h”

I’m new to this and any help would be appreciated. When running CMM_DXF_V8, got multiple java errors

1 Like

This is unequivocally not a beginner project. You need to install libraries in your Arduino IDE for the code to compile.

With respect to the processing code you have not posted any errors for us to read and as such nobody is going to have the first clue on how to help you. Sorry if this comes across as rude but we cant help you if you dont give us any information. That being said the likely errors your getting from processing is from your port # being wrong for the connected arduino.

1 Like

Hello, your project is very interesting. I am having the same problems in Java commented by the user Clay2. Can you give me an idea of what is going on?

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at processing.core.PApplet.runSketch(PApplet.java:10697)
at processing.core.PApplet.main(PApplet.java:10467)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at processing.core.PApplet.runSketch(PApplet.java:10691)
… 1 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 2
at CMM_DXF_V8$pointer.(CMM_DXF_V8.java:945)
at CMM_DXF_V8.(CMM_DXF_V8.java:58)
… 6 more