Wiki

Clone wiki

FlatCAM / Home

Welcome

This is development version of FlatCAM with focus to improve TCL script shell capabilities.

Double sided panelized PCB mill workflow

  • Create new Document (File > New)
  • Set Document size (File > Document properties)

DocumentProperties.png

  • Show Layers (Layer > Layers)
  • Rename main layer to "board"

Layer.png

  • In "board" layer create a path in any shape and size. The shape should be filled green and with no stroke.

ScreateGeometry.png

  • Make sure you only have a single merged shape, not serveral distinct ones. If you want to display some guiding graphics (such as the location of the pin headers for the Arduino shield), you can add them as sublayers of "board". In this case, make sure you give the board shape item itself the id "boardoutline". That is to say, although we talk (right click > Object properties)

CreateGeometry.png

  • !!! WARNING !!! do not forget to remove stroke !!! WARNING !!!

nostroke.png

  • Save as geometry.svg (File > Save), name is up to you
  • Create new Document (File > New)
  • Create any circuit in tabs Breadboard or Schematic

FritzingDesign.png FritzingDesignSchema.png

  • Go to tab PCB, select PCB1 (grey part) and select in Properties > Layers value "two layers(double-sided)"

FritzingPcbSelect.png

  • In Properties > shape leave "Rectangle", set same size as in geometry 50x30 mm and load image geometry.svg
  • If you does not create layer "silkscreen", then approve dialog "Can load, but". and also read and say ok on next dialog.
  • Now is time to place all your components, add some battery connection etc, fix schematic, add wires, make bigger thickness (Properties > width).
  • It is here to demonstrate double sided board, therefor put some wires to "top" layer (Placement > pcb layer)

FritzingUselessPcb.png

  • Save your project for example as "Useless.fzz"
  • Now is time to export Gerber files (File > Export > for production > Extended Gerber) , place it to your path like /path/to/gerber
  • Press Choose and you will get some files as (Useless_contour.gm1, Useless_copperBottom.gbl, Useless_copperTop.gtl, Useless_drill.txt, Useless_maskBottom.gbs, Useless_maskTop.gts, Useless_pnp.txt, Useless_silkTop.gto)

Prepare GCODE with FlatCAM Tcl script

  • Finally, easiest part is here start FlatCAM.py
  • Create directory /path/to/gerber/output
  • Open shell window (Tool>Command Line)
  • Modify paths in followed code and copy it into shell.... do not forget to press ENTER
  • You can also use it as file and pass it via parameter python FlatCAM.py --shellfile=/path/to/script.tcl
# Prepare gcode files for  given project
new
set_sys units MM

set PROJECT_NAME Uselles                                         ;# name of  project

#SETUP PATHS
set PATH_TO_GERBER /path/to/Gerber                               ;# path to working directory
set PATH_TO_GERBER_OUTPUT ${PATH_TO_GERBER}/output                  ;# path to output directory

#PANELIZATION
set COLUMNS 2
set ROWS 1

#TOOLS
set MINIMAL_ISOLATION 0.3    ;# in theory ENGRAVER_DIAMETER/2, but becouse we use mill is  good to add more copper if possible, this needs to be tested per design
set MAXIMAL_ISOLATION 1.0    ;# this will be used to generate more layers of isolation based on engraver diameter
set ENGRAVER_DIAMETER 0.4    ;# real diameter of engraver
set DRILL_DIAMETER 0.8         ;# diameter of drill ..this is join of alldrills  from tools  100,101,102,103,104,105,106,107,108,109,110
set CUTTER_DIAMETER 3        ;# diameter of drill
set ALIGN_DRILL_DIAMETER 3   ;# diameter of tool and pins    
set ISOLATION_OVERLAP 0.1     ;# overlap if there is more then one isolation pass

#ALIGNING  
set ALIGN_OFFSET_X -15       ;# move to safe distance from 0 position in X axis
set ALIGN_MIN_OFFSET 10      ;# minimal distance of align pin from pcm
set ALIGN_OFFSET_Y 0         ;# safe distance from 0 position in Y axis (we use axis X in Y(0) as default aligning place)
set ALIGN_GRIG_X 10          ;# distance between holes on X axis
set ALIGN_GRIG_Y 50          ;# distance between holes on Y axis
set BOARD_HEIGHT 3           ;# height of PCB  with some  tolerance, but be carefull, it will cut and drill under board
set COPPER_HEIGHT 0          ;# height where cut will be done, becouse we will use bed leveling script  leave it on 0, without leveling set it to your value, but expect bad results
  
#OTHER
set CUTTOUT_SOLID_HEIGHT 0   ;# BUGGY/ when bigger then 0, cut solid  margin to specified depth,  gcode will be joined
set DEPTH_PER_PASS 0.7       ;# when cuttout separate it to more slices
set FEEDRATE 350             ;# speed of milling
set TRAVELZ 3                ;# travel height above bed

set LAYER_NAME UNSET

#CALCULATIONS
set MIN_ISOLATION_DIAMETER [expr ${MINIMAL_ISOLATION}*2]
set MAX_ISOLATION_DIAMETER [expr ${MAXIMAL_ISOLATION}*2]
set ISOLATION_WIDTH [expr ${MAX_ISOLATION_DIAMETER}-${MIN_ISOLATION_DIAMETER}]
set ISOLATION_STEP_PREDICTION [expr ${ENGRAVER_DIAMETER}-$ISOLATION_OVERLAP]
if { ${MINIMAL_ISOLATION} >= ${MAXIMAL_ISOLATION} } {
  set ISOLATION_PASSES 1
  set ISOLATION_STEP 0
} else {
  set ISOLATION_PASSES [expr int(${ISOLATION_WIDTH}/(${ISOLATION_STEP_PREDICTION}))] 
  set REAL_WIDTH [expr ${ISOLATION_PASSES}*${ISOLATION_STEP_PREDICTION}] 
  set WIDTH_DIFFERENCE [expr ${ISOLATION_WIDTH}-${REAL_WIDTH}]
  if { ${WIDTH_DIFFERENCE}> $ISOLATION_OVERLAP } {
    incr ISOLATION_PASSES
  }
  set ISOLATION_STEP [expr double(${ISOLATION_WIDTH})/double(${ISOLATION_PASSES})]
}


# procedures

proc globalpat {args} {
    foreach pattern $args {
        set varnames [info globals $pattern]
        if {[llength $varnames] != 0} {
            uplevel 1 global $varnames
        }
    }
}

proc bgsleep {delay} {
   set final_time [expr ([clock seconds] * 1.0) + (($delay * 1.0) / 1000.0)]

   set activation_var [join [list BGSLEEP WAIT FOR $final_time [expr rand()]] _]
   global $activation_var

   after $delay [list set $activation_var 1]
   vwait $activation_var
}


proc do_layer {LAYER_NAME_LOCAL} {
  globalpat *
  set LAYER_NAME $LAYER_NAME_LOCAL           

  # LOAD
  if {${LAYER_NAME} == "Bottom"} {
    open_gerber ${PATH_TO_GERBER}/${PROJECT_NAME}_contour.gm1 -outname ${LAYER_NAME}_margin
    open_gerber ${PATH_TO_GERBER}/${PROJECT_NAME}_copper${LAYER_NAME}.gbl -outname ${LAYER_NAME}
    open_excellon ${PATH_TO_GERBER}/${PROJECT_NAME}_drill.txt -outname ${LAYER_NAME}_drills
  } else {
    open_gerber ${PATH_TO_GERBER}/${PROJECT_NAME}_contour.gm1 -outname ${LAYER_NAME}_margin
    open_gerber ${PATH_TO_GERBER}/${PROJECT_NAME}_copper${LAYER_NAME}.gtl -outname ${LAYER_NAME}
  }
  
  #MIRROR for Bottom
  if {${LAYER_NAME} == "Bottom"} {
    mirror ${LAYER_NAME} -box ${LAYER_NAME}_margin -axis X
    mirror ${LAYER_NAME}_margin -box ${LAYER_NAME}_margin -axis X
    mirror ${LAYER_NAME}_drills -box ${LAYER_NAME}_margin -axis X
  }

  #CUTOUT
  isolate ${LAYER_NAME}_margin -dia ${CUTTER_DIAMETER} -overlap 1
  if {${LAYER_NAME} == "Bottom"} {
    if {${CUTTOUT_SOLID_HEIGHT} > 0} {
      #do not cut gaps in solid  geometry
      exteriors ${LAYER_NAME}_margin_iso -outname ${LAYER_NAME}_margin_iso_exterior_solid    
    }
  }
  exteriors ${LAYER_NAME}_margin_iso -outname ${LAYER_NAME}_margin_iso_exterior
  delete ${LAYER_NAME}_margin_iso
  geocutout ${LAYER_NAME}_margin_iso_exterior -dia ${CUTTER_DIAMETER} -gapsize 0.3 -gaps 4
  
  #ISOLATE TRACES
  exteriors ${LAYER_NAME}_margin -outname ${LAYER_NAME}_exterior
  set ISOLATION_DIAMETER ${MIN_ISOLATION_DIAMETER}
  set ISOLATIONS_TO_CONCAT ""
  for {set I 0} {${I} < ${ISOLATION_PASSES}} {incr I} {
    isolate ${LAYER_NAME} -dia ${ISOLATION_DIAMETER} -overlap 1 -outname ${LAYER_NAME}_iso_${I}    
    set ISOLATIONS_TO_CONCAT [concat ${ISOLATIONS_TO_CONCAT} ${LAYER_NAME}_iso_${I}]
    set ISOLATION_DIAMETER [expr ${ISOLATION_DIAMETER}+${ISOLATION_STEP}]
  }

  #JOIN TRACES and basic exterior
  eval " join_geometries ${LAYER_NAME}_join_iso ${ISOLATIONS_TO_CONCAT} ${LAYER_NAME}_exterior"
  for {set I 0} {${I} < ${ISOLATION_PASSES}} {incr I} {
    delete  ${LAYER_NAME}_iso_${I}
  }
  
  #PANELIZE
  panelize ${LAYER_NAME}_margin_iso_exterior -box ${LAYER_NAME}_margin_iso_exterior -spacing_columns 0 -spacing_rows 0 -columns ${COLUMNS} -rows ${ROWS}
  panelize ${LAYER_NAME}_join_iso -box ${LAYER_NAME}_margin_iso_exterior -spacing_columns 0 -spacing_rows 0 -columns ${COLUMNS} -rows ${ROWS}
  if {${LAYER_NAME} == "Bottom"} {
    panelize ${LAYER_NAME}_drills -box ${LAYER_NAME}_margin_iso_exterior -spacing_columns 0 -spacing_rows -0 -columns ${COLUMNS} -rows ${ROWS}
    if {${CUTTOUT_SOLID_HEIGHT} > 0} {
      panelize ${LAYER_NAME}_margin_iso_exterior_solid -box ${LAYER_NAME}_margin_iso_exterior_solid -spacing_columns 0 -spacing_rows -0 -columns ${COLUMNS} -rows ${ROWS}
    }
  }

  #ALIGNHOLES
  if {${LAYER_NAME} == "Top"} {    
    aligndrill ${LAYER_NAME}_margin_iso_exterior_panelized -box ${LAYER_NAME}_margin_iso_exterior_panelized -dia ${ALIGN_DRILL_DIAMETER} -grid ${ALIGN_GRIG_X} -gridoffset ${ALIGN_OFFSET_X} -axisoffset ${ALIGN_OFFSET_Y} -minoffset ${ALIGN_MIN_OFFSET} -axis X
  }


  #CLEANUP
  delete ${LAYER_NAME}_margin_iso_exterior_solid
  delete ${LAYER_NAME}_margin_iso_exterior
  delete ${LAYER_NAME}_join_iso
  delete ${LAYER_NAME}_drills
  delete ${LAYER_NAME}_exterior
  delete ${LAYER_NAME}_iso


  #CNCJOBS
  if {${LAYER_NAME} == "Bottom"} {
    cncjob ${LAYER_NAME}_margin_iso_exterior_panelized -tooldia ${CUTTER_DIAMETER} -z_cut -${BOARD_HEIGHT} -z_move ${TRAVELZ} -multidepth True -depthperpass ${DEPTH_PER_PASS} -feedrate ${FEEDRATE}    
    if {${CUTTOUT_SOLID_HEIGHT} > 0} {
      cncjob ${LAYER_NAME}_margin_iso_exterior_solid_panelized -tooldia ${CUTTER_DIAMETER} -z_cut -${CUTTOUT_SOLID_HEIGHT} -z_move ${TRAVELZ} -multidepth True -depthperpass ${DEPTH_PER_PASS} -feedrate ${FEEDRATE}    
    }
    drillcncjob ${LAYER_NAME}_drills_panelized -tools 100,101,102,103,104,105,106,107,108,109,110 -drillz [expr -${BOARD_HEIGHT}] -travelz ${TRAVELZ} -feedrate ${FEEDRATE} -outname ${LAYER_NAME}_drills_${DRILL_DIAMETER}
  }  
  if {${LAYER_NAME} == "Top"} {
    drillcncjob ${LAYER_NAME}_margin_iso_exterior_panelized_aligndrill -tools 1 -drillz [expr -${BOARD_HEIGHT}] -travelz ${TRAVELZ} -feedrate ${FEEDRATE} -outname ${LAYER_NAME}_drills_${ALIGN_DRILL_DIAMETER}
  }  
  cncjob ${LAYER_NAME}_join_iso_panelized -tooldia ${ENGRAVER_DIAMETER} [expr -${COPPER_HEIGHT}] -z_move ${TRAVELZ} -feedrate ${FEEDRATE}
  

  #GENERATE GCODE TOP LAYER
  if {${LAYER_NAME} == "Bottom"} {    
    if {${CUTTOUT_SOLID_HEIGHT} > 0} {
#     while {[has_promises]} {
#        #loop here dummy, but  we have to do at least nothing ;)
#        update
#        bgsleep 500
#     }
     set SOLID_PREAMBLE [export_gcode ${LAYER_NAME}_margin_iso_exterior_solid_panelized_cnc]     
     write_gcode ${LAYER_NAME}_margin_iso_exterior_panelized_cnc ${PATH_TO_GERBER}/output/${PROJECT_NAME}_${LAYER_NAME}_cutout.ngc ${SOLID_PREAMBLE}     
    } else {
      write_gcode ${LAYER_NAME}_margin_iso_exterior_panelized_cnc ${PATH_TO_GERBER}/output/${PROJECT_NAME}_${LAYER_NAME}_cutout.ngc
    }
    write_gcode ${LAYER_NAME}_drills_${DRILL_DIAMETER} ${PATH_TO_GERBER}/output/${PROJECT_NAME}_${LAYER_NAME}_drill_${DRILL_DIAMETER}.ngc
  }
  if {${LAYER_NAME} == "Top"} {
    write_gcode ${LAYER_NAME}_drills_${ALIGN_DRILL_DIAMETER} ${PATH_TO_GERBER}/output/${PROJECT_NAME}_${LAYER_NAME}_drill_${ALIGN_DRILL_DIAMETER}.ngc
  }
  write_gcode ${LAYER_NAME}_join_iso_panelized_cnc ${PATH_TO_GERBER}/output/${PROJECT_NAME}_${LAYER_NAME}_traces.pngc    
}


do_layer Top
do_layer Bottom
  • HURRAY, now we have created GCODE in /path/to/gerber/output

ftop.png

fbottom.png

fboth.png

Prepare drills to mill bed for pcb aligning

# Prepare drills to mill bed for pcb aligning
new
set_sys units MM


set PROJECT_NAME AlignDrillGrid                                     ;# name of  project

#setup  paths
set PATH_TO_GERBER /path/to/Gerber                                  ;# path to working directory
set PATH_TO_GERBER_OUTPUT ${PATH_TO_GERBER}/output                  ;# path to output directory

#dimensions
set MAX_X 250                ;# maximum width of grid
set MAX_Y 100                ;# maximum height of grid

#setup aligning
set ALIGN_DRILL_DIAMETER 3   ;# diameter of tool and pins
set ALIGN_OFFSET_X -15       ;# move to safe distance from 0 position in X axis
set ALIGN_OFFSET_Y 0         ;# safe distance from 0 position in Y axis (we use axis X in Y(0) as default aligning place)
set ALIGN_GRIG_X 10          ;# distance between holes on X axis
set ALIGN_GRIG_Y 50          ;# distance between holes on Y axis

#other settings
set FEEDRATE 100             ;# speed of milling
set DRILLZ 10                ;# depth of  drill in cnc table   
set TRAVELZ 3                ;# travel height above bed

#calculations
set ALIGN_COLUMS [expr ${MAX_X}/${ALIGN_GRIG_X}]
set ALIGN_ROWS [expr ${MAX_Y}/${ALIGN_GRIG_Y}]


#create geometries
aligndrillgrid grid -dia ${ALIGN_DRILL_DIAMETER} -gridx ${ALIGN_GRIG_X} -gridoffsetx ${ALIGN_OFFSET_X} -gridy ${ALIGN_GRIG_Y} -gridoffsety ${ALIGN_OFFSET_Y} -columns ${ALIGN_COLUMS} -rows ${ALIGN_ROWS}
drillcncjob grid -tools 1 -drillz ${DRILLZ} -travelz ${TRAVELZ} -feedrate ${FEEDRATE} -outname drills_${ALIGN_DRILL_DIAMETER}

#write GCODE
write_gcode drills_${ALIGN_DRILL_DIAMETER} ${PATH_TO_GERBER}/output/${PROJECT_NAME}_${ALIGN_DRILL_DIAMETER}.ngc

aligndrill.png

LinuxCNC bed probe leveling configuration

  • I use *.pngc which I pass thru bed leveling filter
  • TODO

LinuxCNC milling steps

Prepare

  1. Prepare grid in table as first in some grid (if not done before)
  2. put and hold double sided PCB on table, should be bigger then our product and clamped tightly

Drill align holes

  1. I am starting from top side
  2. Change tool to drill of desired diameter 3 mm
  3. Load "Useless-FCu.drl_3.ngc"
  4. Home machine, set touchoff X and Y to zero, Z close enough and mill align holes
  5. put align pins into align holes(this may be avoided, but it helps with PCB stabilization)

Mill traces for top layer

  1. Change tool to engraver
  2. Load "Useless-FCu.pngc"
  3. Connect probe wire to PCB
  4. Join probe on tool with crocodile clamp, orientate crocodile to avoid hitting align pins
  5. Touchoff Z close enough and probe PCB
  6. !!! WARNING !!! Remove crocodile clamp from tool
  7. Mill traces now(unpause), go for coffee ;)

Mill traces for top layer

  1. Leave same tool for engraving
  2. Remove wire if it still connected
  3. Remove PCB from clams and align pins
  4. Mirror PCB in this case over axis X (just wrap it upside down, top pins become bottom now)
  5. Align PCB with align pins
  6. Secure PCB with clamps
  7. Load "Useless-BCu.pngc"
  8. Connect probe wire to PCB
  9. Join probe on tool with crocodile clamp, orientate crocodile to avoid hitting align pins
  10. Touchoff Z close enough and probe PCB
  11. !!! WARNING !!! Remove crocodile clamp from tool
  12. Mill traces now(unpause), go for coffee ;)

Drill holes

  1. Change tool to drill of desired diameter 0.8 mm
  2. Load "Useless-BCu.drl_0.8.ngc"
  3. touchoff Z close enough and mill holes and go for coffee again;)

Cutout boards

  1. Change tool to mill boards out, in this case 3mm
  2. Touchoff Z close enough and cut boards, maybe toilet now ;)

Finale

  1. Remove wire if it still connected
  2. Remove PCB from clams and align pins
  3. Use fine sand paper to cleanup traces and cutouts
  4. If you are patient enough use heat transfer of silkscreen from Laser printer
  5. You are done...

Pictures of boards done with this method

DSC_0116.JPG DSC_0117.JPG

Updated