Wiki
Clone wikiFlatCAM / Home
Welcome
This is development version of FlatCAM with focus to improve TCL script shell capabilities.
Double sided panelized PCB mill workflow
Create outline for PCB in [Inkscape](Link https://inkscape.org/en/)
- Create new Document (File > New)
- Set Document size (File > Document properties)
- Show Layers (Layer > Layers)
- Rename main layer to "board"
- In "board" layer create a path in any shape and size. The shape should be filled green and with no stroke.
- 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)
- !!! WARNING !!! do not forget to remove stroke !!! WARNING !!!
- If you want you can create another layer "silkscreen" follow this linkhttp://fritzing.org/learning/tutorials/designing-pcb/pcb-custom-shape/ , Fritzing will now stop yelling at you
- Save as geometry.svg (File > Save), name is up to you
Design with [Fritzing](Link fritzing.org)
- Create new Document (File > New)
- Create any circuit in tabs Breadboard or Schematic
- Go to tab PCB, select PCB1 (grey part) and select in Properties > Layers value "two layers(double-sided)"
- 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)
- 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
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
LinuxCNC bed probe leveling configuration
- I use *.pngc which I pass thru bed leveling filter
- TODO
LinuxCNC milling steps
Prepare
- Prepare grid in table as first in some grid (if not done before)
- put and hold double sided PCB on table, should be bigger then our product and clamped tightly
Drill align holes
- I am starting from top side
- Change tool to drill of desired diameter 3 mm
- Load "Useless-FCu.drl_3.ngc"
- Home machine, set touchoff X and Y to zero, Z close enough and mill align holes
- put align pins into align holes(this may be avoided, but it helps with PCB stabilization)
Mill traces for top layer
- Change tool to engraver
- Load "Useless-FCu.pngc"
- Connect probe wire to PCB
- Join probe on tool with crocodile clamp, orientate crocodile to avoid hitting align pins
- Touchoff Z close enough and probe PCB
- !!! WARNING !!! Remove crocodile clamp from tool
- Mill traces now(unpause), go for coffee ;)
Mill traces for top layer
- Leave same tool for engraving
- Remove wire if it still connected
- Remove PCB from clams and align pins
- Mirror PCB in this case over axis X (just wrap it upside down, top pins become bottom now)
- Align PCB with align pins
- Secure PCB with clamps
- Load "Useless-BCu.pngc"
- Connect probe wire to PCB
- Join probe on tool with crocodile clamp, orientate crocodile to avoid hitting align pins
- Touchoff Z close enough and probe PCB
- !!! WARNING !!! Remove crocodile clamp from tool
- Mill traces now(unpause), go for coffee ;)
Drill holes
- Change tool to drill of desired diameter 0.8 mm
- Load "Useless-BCu.drl_0.8.ngc"
- touchoff Z close enough and mill holes and go for coffee again;)
Cutout boards
- Change tool to mill boards out, in this case 3mm
- Touchoff Z close enough and cut boards, maybe toilet now ;)
Finale
- Remove wire if it still connected
- Remove PCB from clams and align pins
- Use fine sand paper to cleanup traces and cutouts
- If you are patient enough use heat transfer of silkscreen from Laser printer
- You are done...
Pictures of boards done with this method
Updated