setting up ci exports

This commit is contained in:
Stephen Hawes
2023-03-24 15:51:51 -04:00
parent dc8474710f
commit a310b79799
11 changed files with 1598 additions and 0 deletions

111
.github/workflows/export-bom.yaml vendored Normal file
View File

@@ -0,0 +1,111 @@
name: Export BOM
on:
workflow_dispatch:
release:
types: [ published ]
jobs:
generate-bom:
name: Generate BOM
runs-on: ubuntu-20.04
steps:
- name: Generate Short SHA Environment Variable
run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
- name: Install Python
run: |
sudo apt install python3
- name: Download repository
uses: actions/checkout@v2
- name: Generate BOM HTML Page for Release
if: github.event_name == 'release'
run: |
python3 .github/workflows/scripts/export-bom.py ${{ github.event.release.tag_name }}
- name: Generate BOM HTML Page for Workflow Dispatch
if: github.event_name != 'release'
run: |
python3 .github/workflows/scripts/export-bom.py ${SHORT_SHA}
- name: Install FreeCAD Python library
run: |
sudo apt -qq update
sudo apt-get -qq -y install python3
sudo apt-get -qq -y install python3-pip
sudo apt-get -qq -y install qt5-default
python3 -m pip install --upgrade pip
pip install pyside2==5.12.6
- name: Fetch FreeCAD
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "FreeCAD/FreeCAD"
version: "tags/0.19.2"
file: "FreeCAD_0.19-24291-Linux-Conda_glibc2.12-x86_64.AppImage"
target: "FreeCAD.AppImage"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install FreeCad
run: |
sudo chown runner:docker FreeCAD.AppImage
pwd
chmod +x FreeCAD.AppImage
./FreeCAD.AppImage --appimage-extract > /dev/null
- name: Generate STL files
run: |
cd .github/workflows/scripts
python3 export-stl.py
ls -al
- name: Install OpenSCAD
run: |
sudo add-apt-repository ppa:openscad/releases
sudo apt-get update
sudo apt-get install openscad
- name: Generate STL Images for Release
if: github.event_name == 'release'
run: |
sudo apt-get install xvfb
Xvfb :5 -screen 0 800x600x24 &
export DISPLAY=:5
python3 .github/workflows/scripts/generate-stl-img.py ${{ github.event.release.tag_name }}
- name: Generate STL Images for Workflow Dispatch
if: github.event_name != 'release'
run: |
sudo apt-get install xvfb
Xvfb :5 -screen 0 800x600x24 &
export DISPLAY=:5
python3 .github/workflows/scripts/generate-stl-img.py ${SHORT_SHA}
- name: Zip BOM Directory for Workflow Dispatch
if: github.event_name != 'release'
run: |
zip -r LumenPnP-BOM.zip LumenPnP-${SHORT_SHA} LumenPnP-${SHORT_SHA}/img
ls -al
- name: Zip BOM Directory for Release
if: github.event_name == 'release'
run: |
zip -r LumenPnP-BOM-${{ github.event.release.tag_name }}.zip LumenPnP-${{ github.event.release.tag_name }} LumenPnP-${{ github.event.release.tag_name }}/img
- name: upload BOM results
if: github.event_name != 'release'
uses: actions/upload-artifact@v2
with:
name: LumenPnP-BOM
path: LumenPnP-BOM.zip
- name: Upload Artifacts to Release
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
LumenPnP-BOM-${{ github.event.release.tag_name }}.zip

118
.github/workflows/export-ecad.yaml vendored Normal file
View File

@@ -0,0 +1,118 @@
name: Export ECAD
on:
workflow_dispatch:
release:
types: [ published ]
jobs:
export-ecad:
name: Export ECAD
runs-on: ubuntu-latest
container: setsoft/kicad_auto:dev_k6
steps:
- name: Generate Short SHA Environment Variable
run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
- name: Update system repositories, Install Required Libraries and Initialize git-lfs
run: |
apt update
apt -y install git git-lfs zip librsvg2-bin imagemagick
git lfs install
- name: Checkout Repository
uses: actions/checkout@v2
with:
lfs: true
- name: Extract branch name
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
id: extract_branch
- name: Update the PCBs with on default branch with git hash
if: github.event_name == 'release' || steps.extract_branch.outputs.branch == env.main_branch
run: |
export COMMIT=$(git rev-parse --short HEAD)
echo "COMMIT = ${COMMIT}"
echo "ref: ${{ github.ref }}"
echo "default: ${{ env.default }}"
sed -i "s!<<hash>>!${COMMIT}!" pnp/pcb/mobo/mobo.kicad_pcb
sed -i "s!<<hash>>!${COMMIT}!" pnp/pcb/ring-light/ringLight.kicad_pcb
sed -i "s!<<hash>>!${COMMIT}!" pnp/pcb/staging-plate/staging-plate.kicad_pcb
sed -i "s!<<hash>>!${COMMIT}!" pnp/pcb/datum/datum.kicad_pcb
sed -i "s!<<hash>>!${COMMIT}!" pnp/pcb/ftp/ftp.kicad_pcb
- name: Update the PCBs with the git hash and BETA.
if: steps.extract_branch.outputs.branch != env.main_branch
run: |
export COMMIT=$(git rev-parse --short HEAD)
echo "COMMIT = ${COMMIT}"
sed -i "s!<<hash>>!BETA-${COMMIT}!" pnp/pcb/mobo/mobo.kicad_pcb
sed -i "s!<<hash>>!BETA-${COMMIT}!" pnp/pcb/ring-light/ringLight.kicad_pcb
sed -i "s!<<hash>>!BETA-${COMMIT}!" pnp/pcb/staging-plate/staging-plate.kicad_pcb
sed -i "s!<<hash>>!BETA-${COMMIT}!" pnp/pcb/datum/datum.kicad_pcb
sed -i "s!<<hash>>!BETA-${COMMIT}!" pnp/pcb/ftp/ftp.kicad_pcb
- name: Generate Mobo Export Files
run: |
cd pcb/mobo
rm -rf mobo/
kibot -c ../../../.github/workflows/scripts/kibot/config-4layer.kibot.yaml -e mobo.kicad_sch -b mobo.kicad_pcb -d mobo
zip -r -j mobo.zip mobo/
- name: Generate Slot Export Files
run: |
cd pcb/feederFloor
rm -rf feeder-floor/
kibot -c ../../../.github/workflows/scripts/kibot/config-2layer.kibot.yaml -e feederFloor.kicad_sch -b feederFloor.kicad_pcb -d slot
zip -r -j slot.zip slot/
- name: Generate Indexing Wheel Export Files
run: |
cd pcb/indexingWheel
rm -rf indexing-wheel/
kibot -c ../../../.github/workflows/scripts/kibot/config-2layer.kibot.yaml -e indexingWheel.kicad_sch -b indexingWheel.kicad_pcb -d indexing-wheel
zip -r -j indexing-wheel.zip indexing-wheel/
- name: Generate Light Diffusion Export Files
run: |
cd pcb/light-diffusion
rm -rf light-diffusion/
kibot -c ../../../.github/workflows/scripts/kibot/config-2layer.kibot.yaml -e light-diffusion.kicad_sch -b light-diffusion.kicad_pcb -d light-diffusion
zip -r -j light-diffusion.zip light-diffusion/
- name: Generate Photon 8mm Fiducial Export Files
run: |
cd pcb/photon-8mm-fid
rm -rf photon-8mm-fid/
kibot -c ../../../.github/workflows/scripts/kibot/config-2layer.kibot.yaml -e photon-8mm-fid.kicad_sch -b photon-8mm-fid.kicad_pcb -d photon-8mm-fid
zip -r -j photon-8mm-fid.zip photon-8mm-fid/
- name: Zip PCB Export Files for Artifacts
run: |
cd pcb/
zip -r -j Feeder-PCBs.zip photon-8mm-fid/photon-8mm-fid.zip light-diffusion/light-diffusion.zip indexingWheel/indexing-wheel.zip feederFloor/slot.zip mobo/mobo.zip
- name: Zip PCB Export Files for Release
run: |
cd pcb/
zip -r -j Feeder-PCBs-${{ github.event.release.tag_name }}.zip photon-8mm-fid/photon-8mm-fid.zip light-diffusion/light-diffusion.zip indexingWheel/indexing-wheel.zip feederFloor/slot.zip mobo/mobo.zip
- name: Upload PCB Export Files as Artifacts
uses: actions/upload-artifact@v2
with:
name: Feeder-PCBs.zip
path: pcb/Feeder-PCBs.zip
if-no-files-found: error
retention-days: 60
- name: Upload Artifacts to Release
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
pcb/Feeder-PCBs-${{ github.event.release.tag_name }}.zip

98
.github/workflows/export-mcad.yaml vendored Normal file
View File

@@ -0,0 +1,98 @@
name: Export MCAD
on:
release:
types: [ published ]
workflow_dispatch:
jobs:
export-mcad:
name: Export MCAD
runs-on: ubuntu-20.04
steps:
- name: Generate Short SHA Environment Variable
run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
- name: Download repository
uses: actions/checkout@v2
- name: Install FreeCAD Python library
run: |
sudo apt -qq update
sudo apt-get -qq -y install python3
sudo apt-get -qq -y install python3-pip
sudo apt-get -qq -y install qt5-default
python3 -m pip install --upgrade pip
pip install pyside2==5.12.6
- name: Fetch FreeCAD
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "FreeCAD/FreeCAD"
version: "tags/0.19.2"
file: "FreeCAD_0.19-24291-Linux-Conda_glibc2.12-x86_64.AppImage"
target: "FreeCAD.AppImage"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install FreeCad
run: |
sudo chown runner:docker FreeCAD.AppImage
pwd
chmod +x FreeCAD.AppImage
./FreeCAD.AppImage --appimage-extract > /dev/null
- name: Generate DXF files
run: |
cd .github/workflows/scripts
python3 export-csm.py
pwd
ls -al
cd csm-export
ls -al
env:
LD_LIBRARY_PATH: /home/runner/work/feeder/feeder/squashfs-root/usr/lib
- name: Generate STL files
run: |
cd .github/workflows/scripts
python3 export-stl.py
- name: Compress STL and DXF files for Release
if: github.event_name == 'release'
run: |
cd .github/workflows/scripts/stl-export
zip -9 -j /home/runner/work/feeder/feeder/Feeder-STLs-${{ github.event.release.tag_name }}.zip *.stl
cd ../csm-export
- name: Compress STL and DXF files for Artifacts
if: github.event_name != 'release'
run: |
cd .github/workflows/scripts/stl-export
zip -9 -j ~/Feeder-STLs.zip *.stl
cd /home/runner/work/feeder/feeder/.github/workflows/scripts/csm-export
- name: Upload STLs as Artifacts
if: github.event_name != 'release'
uses: actions/upload-artifact@v2
with:
name: Feeder-STLs
path: ~/Feeder-STLs.zip
if-no-files-found: error
retention-days: 60
- name: Upload DXFs as Artifacts
if: github.event_name != 'release'
uses: actions/upload-artifact@v2
with:
name: Feeder-DXFs
path: ~/Feeder-DXFs.zip
if-no-files-found: warn
retention-days: 60
- name: Upload STLs and DXFs Release
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: Feeder-STLs-${{ github.event.release.tag_name }}.zip

120
.github/workflows/scripts/export-bom.py vendored Normal file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/python3
import os
from platform import release
import sys
import csv
# make directory for bom html file and assets
dirName = "Feeder-" + sys.argv[1]
if not os.path.exists(dirName):
os.mkdir(dirName)
print("Directory " , dirName , " Created ")
else:
print("Directory " , dirName , " already exists")
# make html file that will become our BOM
f = open(dirName + "/bom_" + sys.argv[1] + ".html", "w")
f.write("""
<!DOCTYPE html>
<head>
<style>
body {
background-color: #222;
padding: 30px;
font-family: helvetica;
color: #fff
}
table {
width: 100%;
position: relative;
border-collapse: collapse;
}
h1 {
color:white;
}
.optional {
background-color: #430;
}
tr.titlerow th {
background-color: goldenrod;
position: sticky;
top: 0;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 2px solid #fff
}
a {
color:goldenrod;
}
img {
width: 150px;
}
#logo {
width: 250px;
position: absolute;
top: 30px;
right: 50px;
}
tr:hover {
background-color: #444;
}
</style>
</head>
<body>
<h1>
""")
#write page title based on script
f.write("LumenPnP BOM " + sys.argv[1])
#write the beginning of table, and row for header
f.write("</h1><a href='https://www.github.com/opulo-inc/feeder/releases/' target='_blank' rel='noopener noreferrer'><h2>Download the Source Here</h2></a><a href='https://www.opulo.io/' target='_blank' rel='noopener noreferrer'><img src='https://cdn.shopify.com/s/files/1/0570/4256/7355/files/opulo-white-alpha_1200x1200.png?v=1644515300' id='logo'/></a><table>")
with open('bom.csv') as bom:
csv_reader = csv.reader(bom, delimiter=',')
line_count = 0
for row in csv_reader:
column = 0
if line_count == 0: #if header row, just print what's there
f.write("<tr class='titlerow'>")
while column < len(row):
f.write("<th style='color:black;'>" + row[column] + "</th>")
column += 1
else: #if content row
if row[6] != "":
f.write("<tr class='optional'>")
else:
f.write("<tr>")
while column < len(row):
# handling images
if column == 1 and row[3] != "FDM":
f.write("<th><img src='" + row[column] + "' /></th>")
elif column == 1 and row[3] == "FDM":
f.write("<th><img src='img/" + row[0] + ".png' /></th>")
# handling links
elif (column == 4 or column == 5) and row[3] != "FDM" and row[column] != "":
f.write("<th><a href='" + row[column] + "' target='_blank' rel='noopener noreferrer'/>Link</a></th>")
# all other cells
else:
f.write("<th>" + row[column] + "</th>")
column += 1
f.write("</tr>")
line_count += 1
f.write("</table></body></html>")
f.close()

127
.github/workflows/scripts/export-csm.py vendored Normal file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/python3
import math
import os
import sys
import traceback
from pathlib import Path
from typing import List
import time
freecad_paths = [
'/home/runner/work/feeder/feeder/squashfs-root/usr/lib', # For CI when using AppImage
'/usr/lib/freecad/lib/', # For CI
'/usr/lib/freecad-daily-python3/lib/', # For Ubuntu
'/usr/lib64/freecad/lib64/', # For Fedora
'/Applications/FreeCAD.app/Contents/MacOS', # For Mac OS X
'c:/Program Files/FreeCAD 0.18/bin/', # For Windows
'c:/Program Files/FreeCAD 0.19/bin/', # For Windows
]
# Font file relative to this python script
font_folder = '../../../lib/fonts'
for path in freecad_paths:
if os.path.exists(path):
print(f"Added possible FreeCAD path: {path}")
sys.path.append(path)
# Must be after sys.path.append above...
import FreeCAD
import importDXF
print('Python version:',sys.version,'FreeCAD version:',FreeCAD.Version())
def process_csm_file(cad_file: Path, output_folder: Path):
print("Processing " + cad_file.name)
doc = FreeCAD.open(str(cad_file.absolute()))
name = cad_file.name[:-6]
# name_options = [obj.String for obj in doc.Objects if
# obj.isDerivedFrom("Part::Part2DObject") and obj.Label == "PN"]
# if name_options:
# name = name_options[0]
# else:
# # If there is no part number embossed throw error
# raise ValueError("Part " + cad_file.name + " doesn't have a ShapeString called PN for part number emboss")
output_file=os.path.join(output_folder,name+'.dxf')
print("Output file "+output_file)
#output_file=os.path.join(output_folder,os.path.splitext(os.path.basename(cad_file))[0]+'.dxf')
# if cad_file.name[:8] != name[:8]:
# # STL model file name does not match the part number embedded in the file
# raise ValueError(
# "Part " + cad_file.name[:8] + " doesn't match the part number in the FreeCad model - " + name[:8])
body = [obj for obj in doc.Objects if obj.Label == "Body"]
if len(body) == 0:
print(f"Cannot find body object. {len(doc.Objects)} objects present")
for obj in doc.Objects:
print(f"- {obj.Label}")
raise Exception(f"Object named 'Body' not found in model {cad_file.name}")
body = body[0]
# Find font references in the model and ensure they point to the correct font file
fonts = [obj for obj in doc.Objects if
obj.isDerivedFrom("Part::Part2DObject") and hasattr(obj, "FontFile")]
for obj in fonts:
font_file_property = obj.getPropertyByName('FontFile')
new_font_file = os.path.join(font_folder, os.path.split(font_file_property)[1])
if not os.path.isfile(new_font_file):
raise FileNotFoundError(f"Cannot find font file {new_font_file}")
if new_font_file != font_file_property:
print(f"\tCorrected '{obj.Label}' font file name from {font_file_property}")
setattr(obj, "FontFile", new_font_file)
obj.touch()
# Recompute the model to ensure its valid and does not contain broken references or edges
# Mark each object as "changed"
for obj in doc.Objects:
obj.touch()
# Recompute the entire document
t0 = time.perf_counter()
doc.recompute(None, True, True)
t1 = time.perf_counter()
total = t1 - t0
print(f"\tRecompute of model took {total:3f}s")
__objs__=[]
__objs__.append(body)
importDXF.export(__objs__,output_file)
if __name__ == '__main__':
# Create output folder if needed
output_directory = Path('csm-export')
output_directory.mkdir(parents=True, exist_ok=True)
csm_path = Path('../../../src/cad/CSM')
files = sorted(csm_path.glob('*.FCStd'))
exceptions: List[Exception] = []
for f in files:
try:
process_csm_file(f, output_directory)
except Exception as ex:
print(f"****")
print(f"\tAn error occurred while processing {str(f)}:")
print(f"\t{ex}")
traceback.print_exc()
print(f"****")
exceptions.append(ex)
if exceptions:
verb = "was" if len(exceptions) == 1 else "were"
noun = "exception" if len(exceptions) == 1 else "exceptions"
print(f"There {verb} {len(exceptions)} {noun}")
assert len(exceptions) == 0

196
.github/workflows/scripts/export-stl.py vendored Normal file
View File

@@ -0,0 +1,196 @@
#!/usr/bin/python3
import math
import os
import sys
import traceback
from pathlib import Path
from typing import List
import time
import csv
freecad_paths = [
'/home/runner/work/feeder/feeder/squashfs-root/usr/lib', # For CI when using AppImage
'/usr/lib/freecad/lib/', # For CI
'/usr/lib/freecad-daily-python3/lib/', # For Ubuntu
'/usr/lib64/freecad/lib64/', # For Fedora
'/Applications/FreeCAD.app/Contents/MacOS', # For Mac OS X
'c:/Program Files/FreeCAD 0.18/bin/', # For Windows
'c:/Program Files/FreeCAD 0.19/bin/', # For Windows
]
# Font file relative to this python script
font_folder = '../../../lib/fonts'
for path in freecad_paths:
if os.path.exists(path):
print(f"Added possible FreeCAD path: {path}")
sys.path.append(path)
import FreeCAD
import MeshPart
print('Python version:')
print(sys.version)
print('FreeCAD version:')
print(FreeCAD.Version())
def process_file(cad_file: Path):
print("Processing " + cad_file.name)
doc = FreeCAD.open(str(cad_file.absolute()))
bom = open("../../../bom.csv")
csv_reader = csv.reader(bom, delimiter=',')
count = 0
flag = False
for row in csv_reader:
if row[0] == cad_file.name[:-6]:
print("found a part!")
print(row[0])
count = row[2]
print(count)
if count != "-" and count != "":
flag = True
break
#generates name with quantity
if flag:
name = cad_file.name[:-6] + "_" + count + "x"
print("making count name")
else:
name = cad_file.name[:-6]
print("making no count name")
# # Getting file name from part number emboss
# name_options = [obj.String for obj in doc.Objects if
# obj.isDerivedFrom("Part::Part2DObject") and obj.Label == "PN"]
# if name_options:
# name = name_options[0]
# else:
# # If there is no part number embossed throw error
# raise ValueError("Part " + cad_file.name + " doesn't have a ShapeString called PN for part number emboss")
# if cad_file.name[:8] != name[:8]:
# # STL model file name does not match the part number embedded in the file
# raise ValueError(
# "Part " + cad_file.name[:8] + " doesn't match the part number in the FreeCad model - " + name[:8])
body = [obj for obj in doc.Objects if obj.Label == "Body"]
if len(body) == 0:
print(f"Cannot find body object. {len(doc.Objects)} objects present")
for obj in doc.Objects:
print(f"- {obj.Label}")
raise Exception(f"Object named 'Body' not found in model {cad_file.name}")
body = body[0]
# Find font references in the model and ensure they point to the correct font file
fonts = [obj for obj in doc.Objects if
obj.isDerivedFrom("Part::Part2DObject") and hasattr(obj, "FontFile")]
for obj in fonts:
font_file_property = obj.getPropertyByName('FontFile')
new_font_file = os.path.join(font_folder, os.path.split(font_file_property)[1])
if not os.path.isfile(new_font_file):
raise FileNotFoundError(f"Cannot find font file {new_font_file}")
if new_font_file != font_file_property:
print(f"\tCorrected '{obj.Label}' font file name from {font_file_property}")
setattr(obj, "FontFile", new_font_file)
obj.touch()
# Recompute the model to ensure its valid and does not contain broken references or edges
# Mark each object as "changed"
for obj in doc.Objects:
obj.touch()
# Recompute the entire document
t0 = time.perf_counter()
doc.recompute(None, True, True)
t1 = time.perf_counter()
total = t1 - t0
print(f"\tRecompute of model took {total:3f}s")
# Now check for any invalid shapes
# for obj in doc.Objects:
# if 'Invalid' in obj.State:
# raise Exception(f"Shape '{obj.Name}' in model '{cad_file.name}' is invalid")
shape = body.Shape.copy(False)
print_planes = [obj for obj in doc.Objects if obj.Label == "PrintPlane"]
if print_planes:
plane = print_planes[0]
matrix = plane.Placement.Matrix.inverse()
matrix.rotateX(math.pi)
shape = shape.transformShape(matrix)
# Very useful debug info if shape orientation gets funky
# print(f"\t\tShape Placement: {shape.Placement}")
# print(f"\t\tPlane Placement: {plane.Placement}")
# print(f"\t\tPlane Offset: {plane.AttachmentOffset}")
# print(f"\t\tMin X: {round(min(v.Point.x for v in shape.Vertexes), 2)}")
# print(f"\t\tMax X: {round(max(v.Point.x for v in shape.Vertexes), 2)}")
# print(f"\t\tMin Y: {round(min(v.Point.y for v in shape.Vertexes), 2)}")
# print(f"\t\tMax Y: {round(max(v.Point.y for v in shape.Vertexes), 2)}")
# print(f"\t\tMin Z: {round(min(v.Point.z for v in shape.Vertexes), 2)}")
# print(f"\t\tMax Z: {round(max(v.Point.z for v in shape.Vertexes), 2)}")
else:
print(f"\tWarning, missing PrintPlane object in file {cad_file.name}")
# Delete any STL files with similar names (to cater for increments in version number)
delete_files = Path('stl-export').glob(name[0:9] + '??.stl')
for to_delete in delete_files:
print(f"\tDeleting previous STL model {to_delete}")
os.remove(to_delete)
# Generate STL
mesh = doc.addObject("Mesh::Feature", "Mesh")
mesh.Mesh = MeshPart.meshFromShape(Shape=shape, LinearDeflection=0.01, AngularDeflection=0.025, Relative=False)
mesh.Mesh.write("stl-export/" + name + ".stl")
FreeCAD.closeDocument(doc.Name)
print(f"\tGenerated file 3D-Prints/{name}.stl")
if __name__ == '__main__':
# Create output folder if needed
output_directory = Path('stl-export')
output_directory.mkdir(parents=True, exist_ok=True)
fdm_path = Path('../../../pnp/cad/FDM')
exceptions: List[Exception] = []
# Use command line supplied file list if we have one
files = []
for p in sys.argv[1:]:
# Strip any folder names from parameter and assume it's a file in FDM folder
files.append(fdm_path.joinpath(Path(Path(p).name)))
# If no command line, scan the folder
if len(files) == 0:
files = sorted(fdm_path.glob('*.FCStd'))
for f in files:
try:
process_file(f)
except Exception as ex:
print(f"****")
print(f"\tAn error occurred while processing {str(f)}:")
print(f"\t{ex}")
traceback.print_exc()
print(f"****")
exceptions.append(ex)
if exceptions:
verb = "was" if len(exceptions) == 1 else "were"
noun = "exception" if len(exceptions) == 1 else "exceptions"
print(f"There {verb} {len(exceptions)} {noun}")
assert len(exceptions) == 0

View File

@@ -0,0 +1,42 @@
#
# Exports 3D STL files to a static image for documentation
#
import glob
import subprocess
import os
import sys
dirName = "Feeder-" + sys.argv[1] + "/img"
if not os.path.exists(dirName):
os.mkdir(dirName)
print("Directory " , dirName , " Created ")
else:
print("Directory " , dirName , " already exists")
for name in glob.glob(".github/workflows/scripts/stl-export/*.stl"):
print(name)
file=os.path.abspath(name)
f = open("./render_image.scad", "w")
f.write("import(\"")
f.write(file)
f.write("\", convexity=3);")
f.close()
base = os.path.splitext(file)[0]
base = dirName + "/" + os.path.basename(name)
base = base[:-4]
print(base)
head, sep, tail = base.partition('_')
base = head
subprocess.call(["openscad","-o",base+".png", "--quiet", "--render", "--projection=o", "--viewall","--colorscheme","BeforeDawn", "--imgsize", "512,512", "--hardwarnings", "./render_image.scad" ])
#subprocess.call(["/Applications/OpenSCAD.app/Contents/MacOS/OpenSCAD","-o",base+".png", "--quiet", "--render", "--projection=o", "--viewall","--colorscheme","BeforeDawn", "--imgsize", "512,512", "--hardwarnings", "./render_image.scad" ])
if os.path.exists("./render_image.scad"):
os.remove("./render_image.scad")

View File

@@ -0,0 +1,215 @@
# Example KiPlot config file
kibot:
version: 1
filters:
- name: only_jlc_parts
comment: 'Only parts with JLC code'
type: 'generic'
include_only:
- column: 'JLCPCB'
regex: '^C\d+'
- name: fix_rotation
comment: 'Adjust rotation for JLC'
type: rot_footprint
rotations:
- ["^TI_SO-", 270.0]
- ["^SO-", 270.0]
- ["^HTSSOP-", 270.0]
- ["^SSOP-", 270.0]
global:
variant: default
variants:
- name: default
comment: 'Just a place holder for the rotation filter'
type: kibom
variant: default
- name: jlcpcb
comment: 'JLCPCB requires some rotational transforms'
type: kibom
variant: jlcpcb
pre_transform: fix_rotation
preflight:
# Disable ERC for now while GPereira updates these items.
run_erc: false
update_xml: true
# Disable DRC for now while GPereira updates these items.
run_drc: false
check_zone_fills: true
ignore_unconnected: false
outputs:
- name: 'ibom'
comment: 'Interactive Bill of Materials'
type: ibom
dir: ibom
- name: 'bom'
comment: 'Bill of Materials'
type: bom
dir: .
options:
csv:
hide_pcb_info: true
hide_stats_info: true
format: CSV
- name: 'html_bom'
comment: 'HTML BOM'
type: bom
dir: .
options:
html:
datasheet_as_link: Datasheet
digikey_link: Digikey
title: 'Index MOBO Bill of Materials'
- name: 'print_sch'
comment: "Print schematic (PDF)"
type: pdf_sch_print
dir: .
options:
output: Schematic.pdf
#removing to prevent ci from hanging while exporting pdf
# - name: 'print_front'
# comment: "Print F.Cu+Dwgs.User"
# type: pdf_pcb_print
# dir: .
# options:
# output_name: PCB.pdf
# separated: true
# layers:
# - layer: F.Cu
# description: 'Front Copper'
# - layer: B.Cu
# description: 'Back Copper'
# - layer: F.SilkS
# description: 'Front Silk'
# - layer: B.SilkS
# description: 'Rear Silk'
- name: 'gerbers'
comment: "Gerbers for the board house"
type: gerber
dir: gerbers
options:
# generic layer options
exclude_edge_layer: true
exclude_pads_from_silkscreen: false
use_aux_axis_as_origin: false
plot_sheet_reference: false
plot_footprint_refs: true
plot_footprint_values: true
force_plot_invisible_refs_vals: false
tent_vias: true
# gerber options
line_width: 0.1
subtract_mask_from_silk: false
use_protel_extensions: false
gerber_precision: 4.6
create_gerber_job_file: true
use_gerber_x2_attributes: false
use_gerber_net_attributes: false
output: '%f.%i'
layers:
# When Moving to Four Layer, Set G2L and G3L as the suffixes
- layer: F.Cu
suffix: GTL
- layer: B.Cu
suffix: GBL
- layer: F.SilkS
suffix: GTO
- layer: B.SilkS
suffix: GBO
- layer: F.Mask
suffix: GTS
- layer: B.Mask
suffix: GBS
- layer: Edge.Cuts
suffix: GKO
- name: 'drill_file'
comment: 'Drill file for Board House'
type: excellon
dir: gerbers
options:
metric_units: false
pth_and_npth_single_file: true
- name: board_top
comment: "Top layer view"
type: pcbdraw
dir: .
options:
format: png
- name: board_bottom
comment: "Bottom layer view"
type: pcbdraw
dir: .
options:
format: png
bottom: true
- name: 'pick_and_place_file'
comment: 'Pick and Place Location File'
type: position
dir: gerbers
options:
format: CSV
- name: 'bom_jlc'
comment: "BoM for JLC"
type: bom
options:
output: '%f_bom_jlc.%x'
# exclude_filter: only_jlc_parts
ref_separator: ','
columns:
- field: Value
name: Comment
- field: References
name: Designator
- field: Footprint
name: Footprint
- field: JLCPCB
name: 'LCSC Part #'
csv:
hide_pcb_info: true
hide_stats_info: true
quote_all: true
- name: 'pick_and_place_jlc'
comment: 'Pick and place file, JLC style'
type: position
options:
output: '%f_cpl_jlc.%x'
format: CSV
units: millimeters
separate_files_for_front_and_back: false
only_smd: true
variant: jlcpcb
columns:
- id: Ref
name: Designator
- id: PosX
name: "Mid X"
- id: PosY
name: "Mid Y"
- id: Side
name: Layer
- id: Rot
name: Rotation
- name: 'step_file'
comment: 'STEP file generation'
type: step
dir: .

View File

@@ -0,0 +1,247 @@
# Example KiPlot config file
kibot:
version: 1
filters:
- name: only_jlc_parts
comment: 'Only parts with JLC code'
type: 'generic'
include_only:
- column: 'JLCPCB'
regex: '^C\d+'
- name: fix_rotation
comment: 'Adjust rotation for JLC'
type: rot_footprint
rotations:
- ["^TI_SO-", 270.0]
- ["^SO-", 270.0]
- ["^HTSSOP-", 270.0]
- ["^SSOP-", 270.0]
- ["^MSOP-", 270.0]
- ["^USB_C_Receptacle_Palconn", 180.0]
global:
variant: default
variants:
- name: default
comment: 'Just a place holder for the rotation filter'
type: kibom
variant: default
- name: jlcpcb
comment: 'JLCPCB requires some rotational transforms'
type: kibom
variant: jlcpcb
pre_transform: fix_rotation
preflight:
run_erc: true
update_xml: true
# Disable DRC for now while GPereira updates these items.
run_drc: false
check_zone_fills: true
ignore_unconnected: false
outputs:
- name: 'ibom'
comment: 'Interactive Bill of Materials'
type: ibom
dir: ibom
- name: 'bom'
comment: 'Bill of Materials'
type: bom
dir: .
options:
csv:
hide_pcb_info: true
hide_stats_info: true
format: CSV
- name: 'html_bom'
comment: 'HTML BOM'
type: bom
dir: .
options:
html:
datasheet_as_link: Datasheet
digikey_link: Digikey
title: 'Index MOBO Bill of Materials'
- name: 'print_sch'
comment: "Print schematic (PDF)"
type: pdf_sch_print
dir: .
options:
output: Schematic.pdf
# removing to prevent ci from hanging from long export time
# - name: 'print_front'
# comment: "Print F.Cu+Dwgs.User"
# type: pdf_pcb_print
# dir: .
# options:
# output_name: PCB.pdf
# separated: true
# layers:
# - layer: F.Cu
# description: 'Front Copper'
# - layer: In1.Cu
# description: 'Layer 2'
# - layer: In2.Cu
# description: 'Layer 3'
# - layer: B.Cu
# description: 'Back Copper'
# - layer: F.SilkS
# description: 'Front Silk'
# - layer: B.SilkS
# description: 'Rear Silk'
- name: 'gerbers'
comment: "Gerbers for the board house"
type: gerber
dir: gerbers
options:
# generic layer options
exclude_edge_layer: true
exclude_pads_from_silkscreen: false
use_aux_axis_as_origin: false
plot_sheet_reference: false
plot_footprint_refs: true
plot_footprint_values: true
force_plot_invisible_refs_vals: false
tent_vias: true
# gerber options
line_width: 0.1
subtract_mask_from_silk: false
use_protel_extensions: false
gerber_precision: 4.6
create_gerber_job_file: true
use_gerber_x2_attributes: false
use_gerber_net_attributes: false
output: '%f.%i'
layers:
# When Moving to Four Layer, Set G2L and G3L as the suffixes
- layer: F.Cu
suffix: GTL
- layer: In1.Cu
suffix: G2L
- layer: In2.Cu
suffix: G3L
- layer: B.Cu
suffix: GBL
- layer: F.SilkS
suffix: GTO
- layer: B.SilkS
suffix: GBO
- layer: F.Mask
suffix: GTS
- layer: B.Mask
suffix: GBS
- layer: Edge.Cuts
suffix: GKO
- name: 'drill_file'
comment: 'Drill file for Board House'
type: excellon
dir: gerbers
options:
metric_units: false
pth_and_npth_single_file: true
- name: board_top
comment: "Top layer view"
type: pcbdraw
dir: .
options:
format: png
- name: board_bottom
comment: "Bottom layer view"
type: pcbdraw
dir: .
options:
format: png
bottom: true
- name: 'pick_and_place_file'
comment: 'Pick and Place Location File'
type: position
dir: gerbers
options:
format: CSV
- name: 'bom_jlc'
comment: "BoM for JLC"
type: bom
options:
output: '%f_bom_jlc.%x'
# exclude_filter: only_jlc_parts
ref_separator: ','
columns:
- field: Value
name: Comment
- field: References
name: Designator
- field: Footprint
name: Footprint
- field: JLCPCB
name: 'LCSC Part #'
csv:
hide_pcb_info: true
hide_stats_info: true
quote_all: true
- name: 'pick_and_place_jlc'
comment: 'Pick and place file, JLC style'
type: position
options:
output: '%f_cpl_jlc.%x'
format: CSV
units: millimeters
separate_files_for_front_and_back: false
only_smd: true
variant: jlcpcb
columns:
- id: Ref
name: Designator
- id: PosX
name: "Mid X"
- id: PosY
name: "Mid Y"
- id: Side
name: Layer
- id: Rot
name: Rotation
- name: 'pick_and_place_jlc_with_connectors'
comment: 'Pick and place file, JLC style with connectors'
type: position
options:
output: '%f_cpl_jlc_conn.%x'
format: CSV
units: millimeters
separate_files_for_front_and_back: false
only_smd: false
variant: jlcpcb
columns:
- id: Ref
name: Designator
- id: PosX
name: "Mid X"
- id: PosY
name: "Mid Y"
- id: Side
name: Layer
- id: Rot
name: Rotation
- name: 'step_file'
comment: 'STEP file generation'
type: step
dir: .

View File

@@ -0,0 +1,95 @@
# Example KiPlot config file
kibot:
version: 1
global:
variant: default
variants:
- name: default
comment: 'Just a place holder for the rotation filter'
type: kibom
variant: default
preflight:
# Disable ERC for now while GPereira updates these items.
run_erc: false
update_xml: true
# Disable DRC for now while GPereira updates these items.
run_drc: false
check_zone_fills: true
ignore_unconnected: false
outputs:
- name: 'gerbers'
comment: "Gerbers for the board house"
type: gerber
dir: gerbers
options:
# generic layer options
exclude_edge_layer: true
exclude_pads_from_silkscreen: false
use_aux_axis_as_origin: false
plot_sheet_reference: false
plot_footprint_refs: true
plot_footprint_values: true
force_plot_invisible_refs_vals: false
tent_vias: true
# gerber options
line_width: 0.1
subtract_mask_from_silk: false
use_protel_extensions: false
gerber_precision: 4.6
create_gerber_job_file: true
use_gerber_x2_attributes: false
use_gerber_net_attributes: false
output: '%f.%i'
layers:
# When Moving to Four Layer, Set G2L and G3L as the suffixes
- layer: F.Cu
suffix: GTL
- layer: B.Cu
suffix: GBL
- layer: F.SilkS
suffix: GTO
- layer: B.SilkS
suffix: GBO
- layer: F.Mask
suffix: GTS
- layer: B.Mask
suffix: GBS
- layer: Edge.Cuts
suffix: GKO
- name: 'drill_file'
comment: 'Drill file for Board House'
type: excellon
dir: gerbers
options:
metric_units: false
pth_and_npth_single_file: true
- name: board_top
comment: "Top layer view"
type: pcbdraw
dir: .
options:
format: png
- name: board_bottom
comment: "Bottom layer view"
type: pcbdraw
dir: .
options:
format: png
bottom: true
- name: 'step_file'
comment: 'STEP file generation'
type: step
dir: .

View File

@@ -0,0 +1,229 @@
# Example KiPlot config file
kibot:
version: 1
filters:
- name: only_jlc_parts
comment: 'Only parts with JLC code'
type: 'generic'
include_only:
- column: 'JLCPCB'
regex: '^C\d+'
- name: fix_rotation
comment: 'Adjust rotation for JLC'
type: rot_footprint
rotations:
- ["^TI_SO-", 270.0]
- ["^SO-", 270.0]
- ["^HTSSOP-", 270.0]
global:
variant: default
variants:
- name: default
comment: 'Just a place holder for the rotation filter'
type: kibom
variant: default
- name: jlcpcb
comment: 'JLCPCB requires some rotational transforms'
type: kibom
variant: jlcpcb
pre_transform: fix_rotation
preflight:
# Disable ERC for now while GPereira updates these items.
run_erc: false
update_xml: true
# Disable DRC for now while GPereira updates these items.
run_drc: false
check_zone_fills: true
ignore_unconnected: false
outputs:
- name: 'ibom'
comment: 'Interactive Bill of Materials'
type: ibom
dir: ibom
- name: 'bom'
comment: 'Bill of Materials'
type: bom
dir: .
options:
csv:
hide_pcb_info: true
hide_stats_info: true
format: CSV
- name: 'html_bom'
comment: 'HTML BOM'
type: bom
dir: .
options:
html:
datasheet_as_link: Datasheet
digikey_link: Digikey
title: 'Index MOBO Bill of Materials'
- name: 'print_sch'
comment: "Print schematic (PDF)"
type: pdf_sch_print
dir: .
options:
output: Schematic.pdf
- name: 'print_front'
comment: "Print F.Cu+Dwgs.User"
type: pdf_pcb_print
dir: .
options:
output_name: PCB.pdf
separated: true
layers:
- layer: F.Cu
description: 'Front Copper'
- layer: B.Cu
description: 'Back Copper'
- layer: F.SilkS
description: 'Front Silk'
- layer: B.SilkS
description: 'Rear Silk'
- name: 'gerbers'
comment: "Gerbers for the board house"
type: gerber
dir: gerbers
options:
# generic layer options
exclude_edge_layer: true
exclude_pads_from_silkscreen: false
use_aux_axis_as_origin: false
plot_sheet_reference: false
plot_footprint_refs: true
plot_footprint_values: true
force_plot_invisible_refs_vals: false
tent_vias: true
# gerber options
line_width: 0.1
subtract_mask_from_silk: false
use_protel_extensions: false
gerber_precision: 4.6
create_gerber_job_file: true
use_gerber_x2_attributes: false
use_gerber_net_attributes: false
output: '%f.%i'
layers:
# When Moving to Four Layer, Set G2L and G3L as the suffixes
- layer: F.Cu
suffix: GTL
- layer: B.Cu
suffix: GBL
- layer: F.SilkS
suffix: GTO
- layer: B.SilkS
suffix: GBO
- layer: F.Mask
suffix: GTS
- layer: B.Mask
suffix: GBS
- layer: Edge.Cuts
suffix: GKO
- layer: F.Paste
suffix: GTP
- layer: B.Paste
suffix: GBP
- name: 'drill_file'
comment: 'Drill file for Board House'
type: excellon
dir: gerbers
options:
metric_units: false
pth_and_npth_single_file: true
- name: board_top
comment: "Top layer view"
type: pcbdraw
dir: .
options:
format: png
show_components: all
style:
board: '#242424'
copper: '#404040'
silk: '#ffffff'
pads: '#bfbfbf'
- name: board_bottom
comment: "Bottom layer view"
type: pcbdraw
dir: .
options:
format: png
bottom: true
show_components: all
style:
board: '#242424'
copper: '#404040'
silk: '#ffffff'
pads: '#bfbfbf'
- name: 'pick_and_place_file'
comment: 'Pick and Place Location File'
type: position
dir: gerbers
options:
format: CSV
- name: 'bom_jlc'
comment: "BoM for JLC"
type: bom
options:
output: '%f_bom_jlc.%x'
# exclude_filter: only_jlc_parts
ref_separator: ','
columns:
- field: Value
name: Comment
- field: References
name: Designator
- field: Footprint
name: Footprint
- field: JLCPCB
name: 'LCSC Part #'
csv:
hide_pcb_info: true
hide_stats_info: true
quote_all: true
- name: 'pick_and_place_jlc'
comment: 'Pick and place file, JLC style'
type: position
options:
output: '%f_cpl_jlc.%x'
format: CSV
units: millimeters
separate_files_for_front_and_back: false
only_smd: true
variant: jlcpcb
columns:
- id: Ref
name: Designator
- id: PosX
name: "Mid X"
- id: PosY
name: "Mid Y"
- id: Side
name: Layer
- id: Rot
name: Rotation
- name: 'step_file'
comment: 'STEP file generation'
type: step
dir: .