[Added] Panelize output

- First working version
This commit is contained in:
Salvador E. Tropea 2022-11-28 16:31:00 -03:00
parent 1036b26f0a
commit 99467d4d05
9 changed files with 1496 additions and 2 deletions

View File

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New output:
- `populate` to create step-by-step assembly instructions
With support for `pcbdraw` and `render_3d`.
- `panelize` to create a PCB panel containing N copies of the PCB.
- generic filters: options to filter by PCB side
- BoM:
- Option to link to Mouser site.

297
README.md
View File

@ -158,6 +158,9 @@ Notes:
[**KiCad PCB/SCH Diff**](https://github.com/INTI-CMNB/KiDiff) v2.4.3 [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://github.com/INTI-CMNB/KiDiff) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for `diff`
[**KiKit**](https://github.com/yaqwsx/KiKit) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://github.com/yaqwsx/KiKit) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for `panelize`
[**mistune**](https://pypi.org/project/mistune/) [![Python module](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/Python-logo-notext-22x22.png)](https://pypi.org/project/mistune/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/python3-mistune)
- Mandatory for `populate`
@ -2443,6 +2446,298 @@ Notes:
Internally we use 10 for low priority, 90 for high priority and 50 for most outputs.
- `run_by_default`: [boolean=true] When enabled this output will be created when no specific outputs are requested.
* Panelize
* Type: `panelize`
* Description: Creates a panel to fabricate various copies of the PCB at once.
It currently uses the KiKit tool, which must be available.
Consult KiKit docs for detailed information.
Note that you don't need to specify the units for all distances.
If they are omitted they are assumed to be `default_units`.
The same is valid for angles, using `default_angles`
* Valid keys:
- **`comment`**: [string=''] A comment for documentation purposes.
- **`dir`**: [string='./'] Output directory for the generated files.
If it starts with `+` the rest is concatenated to the default dir.
- **`name`**: [string=''] Used to identify this particular output definition.
- **`options`**: [dict] Options for the `Panelize` output.
* Valid keys:
- **`configs`**: [list(dict)|list(string)|string] One or more configurations used to create the panel.
Use a string to include an external configuration, i.e. `myDefault.json`.
You can also include a preset using `:name`, i.e. `:vcuts`.
Use a dict to specify the options using the KiBot YAML file.
* Valid keys:
- **`cuts`**: [dict] Specify how to perform the cuts on the tabs separating the board.
* Valid keys:
- `clearance`: [number|string] Specify clearance for copper around V-cuts.
- *cut_curves*: Alias for cutcurves.
- `cutcurves`: [boolean=false] Specify if curves should be approximated by straight cuts (e.g., for cutting tabs on circular boards).
Used for *vcuts*.
- `drill`: [number|string] Drill size used for the *mousebites*.
- `layer`: [string='Cmts.User'] Specify the layer to render V-cuts on. Also used for the *layer* type.
- `offset`: [number|string] Specify the *mousebites* and *vcuts* offset, positive offset puts the cuts into the board,
negative puts the cuts into the tabs.
- `prolong`: [number|string] Distance for tangential prolongation of the cuts (to cut through the internal corner fillets
caused by milling). Used for *mousebites* and *layer*.
- `spacing`: [number|string] The spacing of the holes used for the *mousebites*.
- `type`: [string='none'] [none,mousebites,vcuts,layer] Layer: When KiKit reports it cannot perform cuts, you can render the cuts
into a layer with this option to understand what's going on. Shouldn't be used for the final design.
- **`fiducials`**: [dict] Used to add fiducial marks to the (rail/frame of) the panel.
* Valid keys:
- *copper_size*: Alias for coppersize.
- `coppersize`: [number|string] Diameter of the copper spot.
- `hoffset`: [number|string] Horizontal offset from panel edges.
- `opening`: [number|string] Diameter of the solder mask opening.
- `type`: [string='none'] [none,3fid,4fid] Add none, 3 or 4 fiducials to the (rail/frame of) the panel.
- `voffset`: [number|string] Vertical offset from panel edges.
- **`framing`**: [dict] Specify the frame around the boards.
* Valid keys:
- `chamfer`: [number|string] Specify the size of chamfer frame corners.
- `cuts`: [string='both'] [none,both,v,h] Specify whether to add cuts to the corners of the frame for easy removal.
Used for *frame*.
- `fillet`: [number|string] Specify radius of fillet frame corners.
- `hspace`: [number|string] Specify the horizontal space between PCB and the frame/rail.
- *min_total_height*: Alias for mintotalheight.
- *min_total_width*: Alias for mintotalwidth.
- `mintotalheight`: [number|string] If needed, add extra material to the rail or frame to meet the minimal requested size.
Useful for services that require minimal panel size.
- `mintotalwidth`: [number|string] If needed, add extra material to the rail or frame to meet the minimal requested size.
Useful for services that require minimal panel size.
- *slot_width*: Alias for slotwidth.
- `slotwidth`: [number|string] Width of the milled slot for *tightframe*.
- `space`: [number|string] Specify the space between PCB and the frame/rail. Overrides `hspace` and `vspace`.
- `type`: [string='none'] [none,railstb,railslr,frame,tightframe] Railstb: Add rails on top and bottom.
Railslr: Add rails on left and right.
Frame: Add a frame around the board.
Tighframe: Add a frame around the board which fills the whole area of the panel -
the boards have just a milled slot around their perimeter.
- `vspace`: [number|string] Specify the vertical space between PCB and the frame/rail.
- `width`: [number|string] Specify with of the rails or frame.
- **`layout`**: [dict] Layout used for the panel.
* Valid keys:
- **`cols`**: [number=1] Specify the number of columns of boards in the grid pattern.
- **`rows`**: [number=1] Specify the number of rows of boards in the grid pattern.
- `alternation`: [string='none'] [none,rows,cols,rowsCols] Specify alternations of board rotation.
none: Do not alternate.
rows: Rotate boards by 180° on every next row.
cols: Rotate boards by 180° on every next column.
rowsCols: Rotate boards by 180° based on a chessboard pattern.
- *bake_text*: Alias for baketext.
- `baketext`: [boolean=true] A flag that indicates if text variables should be substituted or not.
- `hbackbone`: [number|string] The width of horizontal backbone (0 means no backbone). The backbone does not increase the
spacing of the boards.
- `hbonecut`: [boolean=true] If there are both backbones specified, specifies if there should be a horizontal cut where the backbones
cross.
- `hboneskip`: [number=0] Skip every n horizontal backbones. I.e., 1 means place only every other backbone.
- `hspace`: [number|string] Specify the horizontal gap between the boards.
- *rename_net*: Alias for renamenet.
- *rename_ref*: Alias for renameref.
- `renamenet`: [string='Board_{n}-{orig}'] A pattern by which to rename the nets. You can use {n} and {orig} to get the board number and original name.
- `renameref`: [string='{orig}'] A pattern by which to rename the references. You can use {n} and {orig} to get the board number and original
name.
- `rotation`: [number|string] Rotate the boards before placing them in the panel.
- `space`: [number|string] Specify the gap between the boards, overwrites `hspace` and `vspace`.
- `type`: [string='grid'] [grid] Currently fixed.
- `vbackbone`: [number|string] The width of vertical backbone (0 means no backbone). The backbone does not increase the
spacing of the boards.
- `vbonecut`: [boolean=true] If there are both backbones specified, specifies if there should be a vertical cut where the backbones
cross.
- `vboneskip`: [number=0] Skip every n vertical backbones. I.e., 1 means place only every other backbone.
- `vspace`: [number|string] Specify the vertical gap between the boards.
- **`page`**: [dict] Sets page size on the resulting panel and position the panel in the page.
* Valid keys:
- *page_size*: Alias for type.
- *size*: Alias for type.
- **`type`**: [string='inherit'] [inherit,custom,A0,A1,A2,A3,A4,A5,A,B,C,D,E,USLetter,USLegal,USLedger,A0-portrait,A1-portrait,A2-portrait,
A3-portrait,A4-portrait,A5-portrait,A-portrait,B-portrait,C-portrait,D-portrait,E-portrait,
USLetter-portrait,USLegal-portrait,USLedger-portrait] Paper size. The default `inherit` option inherits
paper size from the source board. This feature is not supported on KiCAD 5.
- `anchor`: [string='tl'] [tl,tr,bl,br,mt,mb,ml,mr,c] Point of the panel to be placed at given position. Can be one of tl, tr, bl, br
(corners), mt, mb, ml, mr (middle of sides), c (center). The anchors refer to the panel outline.
- `height`: [number|string] Height for the `custom` paper size.
- *pos_x*: Alias for posx.
- *pos_y*: Alias for posy.
- `posx`: [number|string] The X position of the panel on the page.
- `posy`: [number|string] The Y position of the panel on the page.
- `width`: [number|string] Width for the `custom` paper size.
- **`tabs`**: [dict] Style of the tabs used to join the PCB copies.
* Valid keys:
- `cutout`: [number|string] When your design features open pockets on the side, this parameter specifies extra cutout depth in order to
ensure that a sharp corner of the pocket can be milled. Used for *full*.
- `hcount`: [number=1] Number of tabs in the horizontal direction. Used for *fixed*.
- `hwidth`: [number|string] The width of tabs in the horizontal direction. Used for *fixed* and *spacing*.
- *min_distance*: Alias for mindistance.
- `mindistance`: [number|string] Minimal spacing between the tabs. If there are too many tabs, their count is reduced.
Used for *fixed*.
- `spacing`: [number|string] The maximum spacing of the tabs. Used for *spacing*.
- *tab_footprints*: Alias for tabfootprints.
- `tabfootprints`: [string='kikit:Tab'] The footprint/s used for the *annotation* type. You can specify a list of footprints separated by comma.
- `type`: [string='spacing'] [fixed,spacing,full,annotation] Fixed: Place given number of tabs on the PCB edge.
Spacing: Place tabs on the PCB edges based on spacing.
Full: Create tabs that are full width of the PCB.
Corner: Create tabs in the corners of the PCB.
Annotation: Add tabs based on PCB annotations.
- `vcount`: [number=1] Number of tabs in the vertical direction. Used for *fixed*.
- `vwidth`: [number|string] The width of tabs in the vertical direction. Used for *fixed* and *spacing*.
- `width`: [number|string] The width of tabs in both directions. Overrides both `vwidth` and `hwidth`.
Used for *fixed*, *spacing*, *corner* and *annotation*.
- **`tooling`**: [dict] Used to add tooling holes to the (rail/frame of) the panel.
* Valid keys:
- `hoffset`: [number|string] Horizontal offset from panel edges.
- `paste`: [boolean=false] If True, the holes are included in the paste layer (therefore they appear on the stencil).
- `size`: [number|string] Diameter of the holes.
- `type`: [string='none'] [none,3hole,4hole] Add none, 3 or 4 holes to the (rail/frame of) the panel.
- `voffset`: [number|string] Vertical offset from panel edges.
- `copperfill`: [dict] Fill non-board areas of the panel with copper.
* Valid keys:
- `clearance`: [number|string] Extra clearance from the board perimeters. Suitable for, e.g., not filling the tabs with
copper.
- `layers`: [string|list(string)] List of layers to fill. Can be a comma-separated string.
Using *all* means all external copper layers.
- `orientation`: [number|string] The orientation of the hatched strokes.
- `spacing`: [number|string] The space between the hatched strokes.
- `type`: [string='none'] [none,solid,hatched] How to fill non-board areas of the panel with copper.
- `width`: [number|string] The width of the hatched strokes.
- `debug`: [dict] Debug options.
* Valid keys:
- `deterministic`: [boolean=false] Deterministic.
- `drawBackboneLines`: [boolean=false] Draw backbone lines.
- `drawPartitionLines`: [boolean=false] Draw partition lines.
- `drawboxes`: [boolean=false] Draw boxes.
- `drawtabfail`: [boolean=false] Draw tab fail.
- `trace`: [boolean=false] Trace.
- `post`: [dict] Finishing touches to the panel.
* Valid keys:
- `copperfill`: [boolean=false] Fill tabs and frame with copper (e.g., to save etchant or to increase rigidity of flex-PCB panels).
- *mill_radius*: Alias for millradius.
- `millradius`: [number|string] Simulate the milling operation (add fillets to the internal corners).
Specify mill radius (usually 1 mm). 0 radius disables the functionality.
- `origin`: [string='tl'] [tl,tr,bl,br,mt,mb,ml,mr,c] Specify if the auxiliary origin an grid origin should be placed.
Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr (middle of sides), c (center).
Empty string does not changes the origin.
- *reconstruct_arcs*: Alias for reconstructarcs.
- `reconstructarcs`: [boolean=false] The panelization process works on top of a polygonal representation of the board.
This options allows to reconstruct the arcs in the design before saving the panel.
- *refill_zones*: Alias for refillzones.
- `refillzones`: [boolean=false] Refill the user zones after the panel is build.
This is only necessary when you want your zones to avoid cuts in panel.
- `script`: [string=''] A path to custom Python file. The file should contain a function kikitPostprocess(panel, args) that
receives the prepared panel as the kikit.panelize.Panel object and the user-supplied arguments as a
string - see `scriptarg`. The function can make arbitrary changes to the panel - you can append text,
footprints, alter labels, etc. The function is invoked after the whole panel is constructed
(including all other postprocessing). If you try to add a functionality for a common fabrication
houses via scripting, consider submitting PR for KiKit.
- *script_arg*: Alias for scriptarg.
- `scriptarg`: [string=''] An arbitrary string passed to the user post-processing script specified in script.
- `type`: [string='auto'] [auto] Currently fixed.
- `text`: [dict] Used to add text to the panel.
* Valid keys:
- `anchor`: [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
(middle of sides), c (center). The anchors refer to the panel outline.
- `height`: [number|string] Height of the characters (the same parameters as KiCAD uses).
- `hjustify`: [string='center'] [left,right,center] Horizontal justification of the text.
- `hoffset`: [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system.
- `layer`: [string='F.SilkS'] Specify text layer.
- `orientation`: [number|string] Specify the orientation (angle).
- `text`: [string=''] The text to be displayed. Note that you can escape ; via \.
Available variables in text: *date* formats current date as <year>-<month>-<day>,
*time24* formats current time in 24-hour format,
*boardTitle* the title from the source board,
*boardDate* the date from the source board,
*boardRevision* the revision from the source board,
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `voffset`: [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system.
- `width`: [number|string] Width of the characters (the same parameters as KiCAD uses).
- `text2`: [dict] Used to add text to the panel.
* Valid keys:
- `anchor`: [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
(middle of sides), c (center). The anchors refer to the panel outline.
- `height`: [number|string] Height of the characters (the same parameters as KiCAD uses).
- `hjustify`: [string='center'] [left,right,center] Horizontal justification of the text.
- `hoffset`: [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system.
- `layer`: [string='F.SilkS'] Specify text layer.
- `orientation`: [number|string] Specify the orientation (angle).
- `text`: [string=''] The text to be displayed. Note that you can escape ; via \.
Available variables in text: *date* formats current date as <year>-<month>-<day>,
*time24* formats current time in 24-hour format,
*boardTitle* the title from the source board,
*boardDate* the date from the source board,
*boardRevision* the revision from the source board,
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `voffset`: [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system.
- `width`: [number|string] Width of the characters (the same parameters as KiCAD uses).
- `text3`: [dict] Used to add text to the panel.
* Valid keys:
- `anchor`: [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
(middle of sides), c (center). The anchors refer to the panel outline.
- `height`: [number|string] Height of the characters (the same parameters as KiCAD uses).
- `hjustify`: [string='center'] [left,right,center] Horizontal justification of the text.
- `hoffset`: [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system.
- `layer`: [string='F.SilkS'] Specify text layer.
- `orientation`: [number|string] Specify the orientation (angle).
- `text`: [string=''] The text to be displayed. Note that you can escape ; via \.
Available variables in text: *date* formats current date as <year>-<month>-<day>,
*time24* formats current time in 24-hour format,
*boardTitle* the title from the source board,
*boardDate* the date from the source board,
*boardRevision* the revision from the source board,
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `voffset`: [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system.
- `width`: [number|string] Width of the characters (the same parameters as KiCAD uses).
- `text4`: [dict] Used to add text to the panel.
* Valid keys:
- `anchor`: [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
(middle of sides), c (center). The anchors refer to the panel outline.
- `height`: [number|string] Height of the characters (the same parameters as KiCAD uses).
- `hjustify`: [string='center'] [left,right,center] Horizontal justification of the text.
- `hoffset`: [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system.
- `layer`: [string='F.SilkS'] Specify text layer.
- `orientation`: [number|string] Specify the orientation (angle).
- `text`: [string=''] The text to be displayed. Note that you can escape ; via \.
Available variables in text: *date* formats current date as <year>-<month>-<day>,
*time24* formats current time in 24-hour format,
*boardTitle* the title from the source board,
*boardDate* the date from the source board,
*boardRevision* the revision from the source board,
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `voffset`: [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system.
- `width`: [number|string] Width of the characters (the same parameters as KiCAD uses).
- **`output`**: [string='%f-%i%I%v.%x'] Filename for the output (%i=panel, %x=kicad_pcb). Affected by global options.
- `default_angles`: [string='deg'] [deg,°,rad] Angles used when omitted.
- `default_units`: [string='mm'] [mm,cm,dm,m,mil,inch,in] Units used when omitted.
- `dnf_filter`: [string|list(string)='_none'] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `pre_transform`: [string|list(string)='_none'] Name of the filter to transform fields before applying other filters.
A short-cut to use for simple cases where a variant is an overkill.
- `title`: [string=''] Text used to replace the sheet title. %VALUE expansions are allowed.
If it starts with `+` the text is concatenated.
- `variant`: [string=''] Board variant to apply.
- `category`: [string|list(string)=''] The category for this output. If not specified an internally defined category is used.
Categories looks like file system paths, i.e. PCB/fabrication/gerber.
- `disable_run_by_default`: [string|boolean] Use it to disable the `run_by_default` status of other output.
Useful when this output extends another and you don't want to generate the original.
Use the boolean true value to disable the output you are extending.
- `extends`: [string=''] Copy the `options` section from the indicated output.
- `output_id`: [string=''] Text to use for the %I expansion content. To differentiate variations of this output.
- `priority`: [number=50] [0,100] Priority for this output. High priority outputs are created first.
Internally we use 10 for low priority, 90 for high priority and 50 for most outputs.
- `run_by_default`: [boolean=true] When enabled this output will be created when no specific outputs are requested.
* PCB Print
* Type: `pcb_print`
* Description: Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print` and `svg_pcb_print`.
@ -4533,7 +4828,7 @@ This case is [discussed here](docs/1_SCH_2_part_PCBs)
- **Original KiCad Automation Scripts**: Scott Bezek, Productize SPRL
- **KiBoM**: Oliver Henry Walters (@SchrodingersGat)
- **Interactive HTML BoM**: @qu1ck
- **PcbDraw/Populate**: Jan Mrázek (@yaqwsx)
- **PcbDraw/Populate/KiKit**: Jan Mrázek (@yaqwsx)
- **KiCost**: Dave Vandenbout (@devbisme) and Hildo Guillardi Júnior (@hildogjr)
- **KiCAD to Boardview exporter**: @whitequark
- **S-expression parser**: Takafumi Arakaki

View File

@ -1907,7 +1907,7 @@ This case is [discussed here](docs/1_SCH_2_part_PCBs)
- **Original KiCad Automation Scripts**: Scott Bezek, Productize SPRL
- **KiBoM**: Oliver Henry Walters (@SchrodingersGat)
- **Interactive HTML BoM**: @qu1ck
- **PcbDraw/Populate**: Jan Mrázek (@yaqwsx)
- **PcbDraw/Populate/KiKit**: Jan Mrázek (@yaqwsx)
- **KiCost**: Dave Vandenbout (@devbisme) and Hildo Guillardi Júnior (@hildogjr)
- **KiCAD to Boardview exporter**: @whitequark
- **S-expression parser**: Takafumi Arakaki

View File

@ -1206,6 +1206,420 @@ outputs:
format: 'classic'
# [string='%f-%i%I%v.%x'] Filename for the output (%i=netlist/IPC-D-356, %x=net/d356). Affected by global options
output: '%f-%i%I%v.%x'
# Panelize:
# It currently uses the KiKit tool, which must be available.
# Consult KiKit docs for detailed information.
# Note that you don't need to specify the units for all distances.
# If they are omitted they are assumed to be `default_units`.
# The same is valid for angles, using `default_angles`
- name: 'panelize_example'
comment: 'Creates a panel to fabricate various copies of the PCB at once.'
type: 'panelize'
dir: 'Example/panelize_dir'
options:
# [list(dict)|list(string)|string] One or more configurations used to create the panel.
# Use a string to include an external configuration, i.e. `myDefault.json`.
# You can also include a preset using `:name`, i.e. `:vcuts`.
# Use a dict to specify the options using the KiBot YAML file
configs:
# [dict] Fill non-board areas of the panel with copper
- copperfill:
# [number|string] Extra clearance from the board perimeters. Suitable for, e.g., not filling the tabs with
# copper
clearance: 0.5
# [string|list(string)] List of layers to fill. Can be a comma-separated string.
# Using *all* means all external copper layers
layers: 'F.Cu,B.Cu'
# [number|string] The orientation of the hatched strokes
orientation: 45
# [number|string] The space between the hatched strokes
spacing: 1
# [string='none'] [none,solid,hatched] How to fill non-board areas of the panel with copper
type: 'none'
# [number|string] The width of the hatched strokes
width: 1
# [dict] Specify how to perform the cuts on the tabs separating the board
cuts:
# [number|string] Specify clearance for copper around V-cuts
clearance: 0
# `cut_curves` is an alias for `cutcurves`
# [boolean=false] Specify if curves should be approximated by straight cuts (e.g., for cutting tabs on circular boards).
# Used for *vcuts*
cutcurves: false
# [number|string] Drill size used for the *mousebites*
drill: 0.5
# [string='Cmts.User'] Specify the layer to render V-cuts on. Also used for the *layer* type
layer: 'Cmts.User'
# [number|string] Specify the *mousebites* and *vcuts* offset, positive offset puts the cuts into the board,
# negative puts the cuts into the tabs
offset: 0
# [number|string] Distance for tangential prolongation of the cuts (to cut through the internal corner fillets
# caused by milling). Used for *mousebites* and *layer*
prolong: 0
# [number|string] The spacing of the holes used for the *mousebites*
spacing: 0.8
# [string='none'] [none,mousebites,vcuts,layer] Layer: When KiKit reports it cannot perform cuts, you can render the cuts
# into a layer with this option to understand what's going on. Shouldn't be used for the final design
type: 'none'
# [dict] Debug options
debug:
# [boolean=false] Deterministic
deterministic: false
# [boolean=false] Draw backbone lines
drawBackboneLines: false
# [boolean=false] Draw partition lines
drawPartitionLines: false
# [boolean=false] Draw boxes
drawboxes: false
# [boolean=false] Draw tab fail
drawtabfail: false
# [boolean=false] Trace
trace: false
# [dict] Used to add fiducial marks to the (rail/frame of) the panel
fiducials:
# `copper_size` is an alias for `coppersize`
# [number|string] Diameter of the copper spot
coppersize: 1
# [number|string] Horizontal offset from panel edges
hoffset: 0
# [number|string] Diameter of the solder mask opening
opening: 1
# [string='none'] [none,3fid,4fid] Add none, 3 or 4 fiducials to the (rail/frame of) the panel
type: 'none'
# [number|string] Vertical offset from panel edges
voffset: 0
# [dict] Specify the frame around the boards
framing:
# [number|string] Specify the size of chamfer frame corners
chamfer: 0
# [string='both'] [none,both,v,h] Specify whether to add cuts to the corners of the frame for easy removal.
# Used for *frame*
cuts: 'both'
# [number|string] Specify radius of fillet frame corners
fillet: 0
# [number|string] Specify the horizontal space between PCB and the frame/rail
hspace: 2
# `min_total_height` is an alias for `mintotalheight`
# `min_total_width` is an alias for `mintotalwidth`
# [number|string] If needed, add extra material to the rail or frame to meet the minimal requested size.
# Useful for services that require minimal panel size
mintotalheight: 0
# [number|string] If needed, add extra material to the rail or frame to meet the minimal requested size.
# Useful for services that require minimal panel size
mintotalwidth: 0
# `slot_width` is an alias for `slotwidth`
# [number|string] Width of the milled slot for *tightframe*
slotwidth: 2
# [number|string] Specify the space between PCB and the frame/rail. Overrides `hspace` and `vspace`
space: null
# [string='none'] [none,railstb,railslr,frame,tightframe] Railstb: Add rails on top and bottom.
# Railslr: Add rails on left and right.
# Frame: Add a frame around the board.
# Tighframe: Add a frame around the board which fills the whole area of the panel -
# the boards have just a milled slot around their perimeter
type: 'none'
# [number|string] Specify the vertical space between PCB and the frame/rail
vspace: 2
# [number|string] Specify with of the rails or frame
width: 5
# [dict] Layout used for the panel
layout:
# [string='none'] [none,rows,cols,rowsCols] Specify alternations of board rotation.
# none: Do not alternate.
# rows: Rotate boards by 180° on every next row.
# cols: Rotate boards by 180° on every next column.
# rowsCols: Rotate boards by 180° based on a chessboard pattern
alternation: 'none'
# `bake_text` is an alias for `baketext`
# [boolean=true] A flag that indicates if text variables should be substituted or not
baketext: true
# [number=1] Specify the number of columns of boards in the grid pattern
cols: 1
# [number|string] The width of horizontal backbone (0 means no backbone). The backbone does not increase the
# spacing of the boards
hbackbone: 0
# [boolean=true] If there are both backbones specified, specifies if there should be a horizontal cut where the backbones
# cross
hbonecut: true
# [number=0] Skip every n horizontal backbones. I.e., 1 means place only every other backbone
hboneskip: 0
# [number|string] Specify the horizontal gap between the boards
hspace: 0
# `rename_net` is an alias for `renamenet`
# `rename_ref` is an alias for `renameref`
# [string='Board_{n}-{orig}'] A pattern by which to rename the nets. You can use {n} and {orig} to get the board number and original name
renamenet: 'Board_{n}-{orig}'
# [string='{orig}'] A pattern by which to rename the references. You can use {n} and {orig} to get the board number and original
# name
renameref: '{orig}'
# [number|string] Rotate the boards before placing them in the panel
rotation: 0
# [number=1] Specify the number of rows of boards in the grid pattern
rows: 1
# [number|string] Specify the gap between the boards, overwrites `hspace` and `vspace`
space: null
# [string='grid'] [grid] Currently fixed
type: 'grid'
# [number|string] The width of vertical backbone (0 means no backbone). The backbone does not increase the
# spacing of the boards
vbackbone: 0
# [boolean=true] If there are both backbones specified, specifies if there should be a vertical cut where the backbones
# cross
vbonecut: true
# [number=0] Skip every n vertical backbones. I.e., 1 means place only every other backbone
vboneskip: 0
# [number|string] Specify the vertical gap between the boards
vspace: 0
# [dict] Sets page size on the resulting panel and position the panel in the page
page:
# [string='tl'] [tl,tr,bl,br,mt,mb,ml,mr,c] Point of the panel to be placed at given position. Can be one of tl, tr, bl, br
# (corners), mt, mb, ml, mr (middle of sides), c (center). The anchors refer to the panel outline
anchor: 'tl'
# [number|string] Height for the `custom` paper size
height: 210
# `page_size` is an alias for `type`
# `pos_x` is an alias for `posx`
# `pos_y` is an alias for `posy`
# [number|string] The X position of the panel on the page
posx: 15
# [number|string] The Y position of the panel on the page
posy: 15
# `size` is an alias for `type`
# [string='inherit'] [inherit,custom,A0,A1,A2,A3,A4,A5,A,B,C,D,E,USLetter,USLegal,USLedger,A0-portrait,A1-portrait,A2-portrait,
# A3-portrait,A4-portrait,A5-portrait,A-portrait,B-portrait,C-portrait,D-portrait,E-portrait,
# USLetter-portrait,USLegal-portrait,USLedger-portrait] Paper size. The default `inherit` option inherits
# paper size from the source board. This feature is not supported on KiCAD 5
type: 'inherit'
# [number|string] Width for the `custom` paper size
width: 297
# [dict] Finishing touches to the panel
post:
# [boolean=false] Fill tabs and frame with copper (e.g., to save etchant or to increase rigidity of flex-PCB panels)
copperfill: false
# `mill_radius` is an alias for `millradius`
# [number|string] Simulate the milling operation (add fillets to the internal corners).
# Specify mill radius (usually 1 mm). 0 radius disables the functionality
millradius: 0
# [string='tl'] [tl,tr,bl,br,mt,mb,ml,mr,c] Specify if the auxiliary origin an grid origin should be placed.
# Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr (middle of sides), c (center).
# Empty string does not changes the origin
origin: 'tl'
# `reconstruct_arcs` is an alias for `reconstructarcs`
# [boolean=false] The panelization process works on top of a polygonal representation of the board.
# This options allows to reconstruct the arcs in the design before saving the panel
reconstructarcs: false
# `refill_zones` is an alias for `refillzones`
# [boolean=false] Refill the user zones after the panel is build.
# This is only necessary when you want your zones to avoid cuts in panel
refillzones: false
# [string=''] A path to custom Python file. The file should contain a function kikitPostprocess(panel, args) that
# receives the prepared panel as the kikit.panelize.Panel object and the user-supplied arguments as a
# string - see `scriptarg`. The function can make arbitrary changes to the panel - you can append text,
# footprints, alter labels, etc. The function is invoked after the whole panel is constructed
# (including all other postprocessing). If you try to add a functionality for a common fabrication
# houses via scripting, consider submitting PR for KiKit
script: ''
# `script_arg` is an alias for `scriptarg`
# [string=''] An arbitrary string passed to the user post-processing script specified in script
scriptarg: ''
# [string='auto'] [auto] Currently fixed
type: 'auto'
# [dict] Style of the tabs used to join the PCB copies
tabs:
# [number|string] When your design features open pockets on the side, this parameter specifies extra cutout depth in order to
# ensure that a sharp corner of the pocket can be milled. Used for *full*
cutout: 1
# [number=1] Number of tabs in the horizontal direction. Used for *fixed*
hcount: 1
# [number|string] The width of tabs in the horizontal direction. Used for *fixed* and *spacing*
hwidth: 3
# `min_distance` is an alias for `mindistance`
# [number|string] Minimal spacing between the tabs. If there are too many tabs, their count is reduced.
# Used for *fixed*
mindistance: 0
# [number|string] The maximum spacing of the tabs. Used for *spacing*
spacing: 10
# `tab_footprints` is an alias for `tabfootprints`
# [string='kikit:Tab'] The footprint/s used for the *annotation* type. You can specify a list of footprints separated by comma
tabfootprints: 'kikit:Tab'
# [string='spacing'] [fixed,spacing,full,annotation] Fixed: Place given number of tabs on the PCB edge.
# Spacing: Place tabs on the PCB edges based on spacing.
# Full: Create tabs that are full width of the PCB.
# Corner: Create tabs in the corners of the PCB.
# Annotation: Add tabs based on PCB annotations
type: 'spacing'
# [number=1] Number of tabs in the vertical direction. Used for *fixed*
vcount: 1
# [number|string] The width of tabs in the vertical direction. Used for *fixed* and *spacing*
vwidth: 3
# [number|string] The width of tabs in both directions. Overrides both `vwidth` and `hwidth`.
# Used for *fixed*, *spacing*, *corner* and *annotation*
width: null
# [dict] Used to add text to the panel
text:
# [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
# (middle of sides), c (center). The anchors refer to the panel outline
anchor: 'mt'
# [number|string] Height of the characters (the same parameters as KiCAD uses)
height: 1.5
# [string='center'] [left,right,center] Horizontal justification of the text
hjustify: 'center'
# [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system
hoffset: 0
# [string='F.SilkS'] Specify text layer
layer: 'F.SilkS'
# [number|string] Specify the orientation (angle)
orientation: 0
# [string=''] The text to be displayed. Note that you can escape ; via \.
# Available variables in text: *date* formats current date as <year>-<month>-<day>,
# *time24* formats current time in 24-hour format,
# *boardTitle* the title from the source board,
# *boardDate* the date from the source board,
# *boardRevision* the revision from the source board,
# *boardCompany* the company from the source board,
# *boardComment1*-*boardComment9* comments from the source board
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system
voffset: 0
# [number|string] Width of the characters (the same parameters as KiCAD uses)
width: 1.5
# [dict] Used to add text to the panel
text2:
# [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
# (middle of sides), c (center). The anchors refer to the panel outline
anchor: 'mt'
# [number|string] Height of the characters (the same parameters as KiCAD uses)
height: 1.5
# [string='center'] [left,right,center] Horizontal justification of the text
hjustify: 'center'
# [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system
hoffset: 0
# [string='F.SilkS'] Specify text layer
layer: 'F.SilkS'
# [number|string] Specify the orientation (angle)
orientation: 0
# [string=''] The text to be displayed. Note that you can escape ; via \.
# Available variables in text: *date* formats current date as <year>-<month>-<day>,
# *time24* formats current time in 24-hour format,
# *boardTitle* the title from the source board,
# *boardDate* the date from the source board,
# *boardRevision* the revision from the source board,
# *boardCompany* the company from the source board,
# *boardComment1*-*boardComment9* comments from the source board
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system
voffset: 0
# [number|string] Width of the characters (the same parameters as KiCAD uses)
width: 1.5
# [dict] Used to add text to the panel
text3:
# [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
# (middle of sides), c (center). The anchors refer to the panel outline
anchor: 'mt'
# [number|string] Height of the characters (the same parameters as KiCAD uses)
height: 1.5
# [string='center'] [left,right,center] Horizontal justification of the text
hjustify: 'center'
# [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system
hoffset: 0
# [string='F.SilkS'] Specify text layer
layer: 'F.SilkS'
# [number|string] Specify the orientation (angle)
orientation: 0
# [string=''] The text to be displayed. Note that you can escape ; via \.
# Available variables in text: *date* formats current date as <year>-<month>-<day>,
# *time24* formats current time in 24-hour format,
# *boardTitle* the title from the source board,
# *boardDate* the date from the source board,
# *boardRevision* the revision from the source board,
# *boardCompany* the company from the source board,
# *boardComment1*-*boardComment9* comments from the source board
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system
voffset: 0
# [number|string] Width of the characters (the same parameters as KiCAD uses)
width: 1.5
# [dict] Used to add text to the panel
text4:
# [string='mt'] [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
# (middle of sides), c (center). The anchors refer to the panel outline
anchor: 'mt'
# [number|string] Height of the characters (the same parameters as KiCAD uses)
height: 1.5
# [string='center'] [left,right,center] Horizontal justification of the text
hjustify: 'center'
# [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system
hoffset: 0
# [string='F.SilkS'] Specify text layer
layer: 'F.SilkS'
# [number|string] Specify the orientation (angle)
orientation: 0
# [string=''] The text to be displayed. Note that you can escape ; via \.
# Available variables in text: *date* formats current date as <year>-<month>-<day>,
# *time24* formats current time in 24-hour format,
# *boardTitle* the title from the source board,
# *boardDate* the date from the source board,
# *boardRevision* the revision from the source board,
# *boardCompany* the company from the source board,
# *boardComment1*-*boardComment9* comments from the source board
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system
voffset: 0
# [number|string] Width of the characters (the same parameters as KiCAD uses)
width: 1.5
# [dict] Used to add tooling holes to the (rail/frame of) the panel
tooling:
# [number|string] Horizontal offset from panel edges
hoffset: 0
# [boolean=false] If True, the holes are included in the paste layer (therefore they appear on the stencil)
paste: false
# [number|string] Diameter of the holes
size: 1.152
# [string='none'] [none,3hole,4hole] Add none, 3 or 4 holes to the (rail/frame of) the panel
type: 'none'
# [number|string] Vertical offset from panel edges
voffset: 0
# [string='deg'] [deg,°,rad] Angles used when omitted
default_angles: 'deg'
# [string='mm'] [mm,cm,dm,m,mil,inch,in] Units used when omitted
default_units: 'mm'
# [string|list(string)='_none'] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: '_none'
# [string='%f-%i%I%v.%x'] Filename for the output (%i=panel, %x=kicad_pcb). Affected by global options
output: '%f-%i%I%v.%x'
# [string|list(string)='_none'] Name of the filter to transform fields before applying other filters.
# A short-cut to use for simple cases where a variant is an overkill
pre_transform: '_none'
# [string=''] Text used to replace the sheet title. %VALUE expansions are allowed.
# If it starts with `+` the text is concatenated
title: ''
# [string=''] Board variant to apply
variant: ''
# PCB Print:
# Supports PDF, SVG, PNG, EPS and PS formats.
# KiCad 5: including the frame is slow.

View File

@ -240,6 +240,7 @@ W_PARITY = '(W101) '
W_MISSFPINFO = '(W102) '
W_PCBDRAW = '(W103) '
W_NOCRTYD = '(W104) '
W_PANELEMPTY = '(W105) '
# Somehow arbitrary, the colors are real, but can be different
PCB_MAT_COLORS = {'fr1': "937042", 'fr2': "949d70", 'fr3': "adacb4", 'fr4': "332B16", 'fr5': "6cc290"}
PCB_FINISH_COLORS = {'hal': "8b898c", 'hasl': "8b898c", 'imag': "8b898c", 'enig': "cfb96e", 'enepig': "cfb96e",

627
kibot/out_panelize.py Normal file
View File

@ -0,0 +1,627 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2022 Salvador E. Tropea
# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
"""
Dependencies:
- name: KiKit
github: yaqwsx/KiKit
pypi: KiKit
downloader: pytool
role: mandatory
"""
import os
import re
import json
from tempfile import NamedTemporaryFile
from .error import KiPlotConfigurationError
from .gs import GS
from .kiplot import run_command
from .layer import Layer
from .misc import W_PANELEMPTY
from .optionable import BaseOptions
from .out_base import VariantOptions
from .macros import macros, document, output_class # noqa: F401
from . import log
logger = log.get_logger()
class PanelOptions(BaseOptions):
_num_regex = re.compile(r'([\d\.]+)(mm|cm|dm|m|mil|inch|in)')
_ang_regex = re.compile(r'([\d\.]+)(deg|°|rad)')
def add_units(self, ops):
for op in ops:
val = getattr(self, op)
if val is None:
continue
if isinstance(val, (int, float)):
setattr(self, op, str(val)+self._parent._parent.default_units)
else:
m = PanelOptions._num_regex.match(val)
if m is None:
raise KiPlotConfigurationError('Malformed value `{}: {}` must be a number and units'.format(op, val))
num = m.group(1)
try:
num_d = float(num)
except ValueError:
num_d = None
if num_d is None:
raise KiPlotConfigurationError('Malformed number in `{}` ({})'.format(op, num))
def add_angle(self, ops):
for op in ops:
val = getattr(self, op)
if isinstance(val, (int, float)):
setattr(self, op, str(val)+self._parent._parent.default_angles)
else:
m = PanelOptions._ang_regex.match(val)
if m is None:
raise KiPlotConfigurationError('Malformed angle `{}: {}` must be a number and its type'.format(op, val))
num = m.group(1)
try:
num_d = float(num)
except ValueError:
num_d = None
if num_d is None:
raise KiPlotConfigurationError('Malformed number in `{}` ({})'.format(op, num))
class PanelizePage(PanelOptions):
def __init__(self):
with document:
self.type = 'inherit'
""" *[inherit,custom,A0,A1,A2,A3,A4,A5,A,B,C,D,E,USLetter,USLegal,USLedger,A0-portrait,A1-portrait,A2-portrait,
A3-portrait,A4-portrait,A5-portrait,A-portrait,B-portrait,C-portrait,D-portrait,E-portrait,
USLetter-portrait,USLegal-portrait,USLedger-portrait] Paper size. The default `inherit` option inherits
paper size from the source board. This feature is not supported on KiCAD 5 """
self.page_size = None
""" {type} """
self.size = None
""" {type} """
self.anchor = 'tl'
""" [tl,tr,bl,br,mt,mb,ml,mr,c] Point of the panel to be placed at given position. Can be one of tl, tr, bl, br
(corners), mt, mb, ml, mr (middle of sides), c (center). The anchors refer to the panel outline """
self.posx = 15
""" [number|string] The X position of the panel on the page """
self.pos_x = None
""" {posx} """
self.posy = 15
""" [number|string] The Y position of the panel on the page """
self.pos_y = None
""" {posy} """
self.width = 297
""" [number|string] Width for the `custom` paper size """
self.height = 210
""" [number|string] Height for the `custom` paper size """
super().__init__()
def config(self, parent):
super().config(parent)
self.add_units(('posx', 'posy', 'width', 'height'))
class PanelizeLayout(PanelOptions):
def __init__(self):
with document:
self.type = 'grid'
""" [grid] Currently fixed """
self.hspace = 0
""" [number|string] Specify the horizontal gap between the boards """
self.vspace = 0
""" [number|string] Specify the vertical gap between the boards """
self.space = None
""" [number|string] Specify the gap between the boards, overwrites `hspace` and `vspace` """
self.rotation = 0
""" [number|string] Rotate the boards before placing them in the panel """
self.renamenet = 'Board_{n}-{orig}'
""" A pattern by which to rename the nets. You can use {n} and {orig} to get the board number and original name """
self.rename_net = None
""" {renamenet} """
self.renameref = '{orig}'
""" A pattern by which to rename the references. You can use {n} and {orig} to get the board number and original
name """
self.rename_ref = None
""" {renameref} """
self.baketext = True
""" A flag that indicates if text variables should be substituted or not """
self.bake_text = None
""" {baketext} """
self.rows = 1
""" *Specify the number of rows of boards in the grid pattern """
self.cols = 1
""" *Specify the number of columns of boards in the grid pattern """
self.alternation = 'none'
""" [none,rows,cols,rowsCols] Specify alternations of board rotation.
none: Do not alternate.
rows: Rotate boards by 180° on every next row.
cols: Rotate boards by 180° on every next column.
rowsCols: Rotate boards by 180° based on a chessboard pattern """
self.vbackbone = 0
""" [number|string] The width of vertical backbone (0 means no backbone). The backbone does not increase the
spacing of the boards """
self.hbackbone = 0
""" [number|string] The width of horizontal backbone (0 means no backbone). The backbone does not increase the
spacing of the boards """
self.vboneskip = 0
""" Skip every n vertical backbones. I.e., 1 means place only every other backbone """
self.hboneskip = 0
""" Skip every n horizontal backbones. I.e., 1 means place only every other backbone """
self.vbonecut = True
""" If there are both backbones specified, specifies if there should be a vertical cut where the backbones
cross """
self.hbonecut = True
""" If there are both backbones specified, specifies if there should be a horizontal cut where the backbones
cross """
super().__init__()
def config(self, parent):
super().config(parent)
if self.space:
self.hspace = self.vspace = self.space
self.add_units(('vbackbone', 'hbackbone', 'hspace', 'vspace', 'space'))
self.add_angle(('rotation', ))
class PanelizeTabs(PanelOptions):
def __init__(self):
with document:
self.type = 'spacing'
""" [fixed,spacing,full,annotation] Fixed: Place given number of tabs on the PCB edge.
Spacing: Place tabs on the PCB edges based on spacing.
Full: Create tabs that are full width of the PCB.
Corner: Create tabs in the corners of the PCB.
Annotation: Add tabs based on PCB annotations """
self.vwidth = 3
""" [number|string] The width of tabs in the vertical direction. Used for *fixed* and *spacing* """
self.hwidth = 3
""" [number|string] The width of tabs in the horizontal direction. Used for *fixed* and *spacing* """
self.width = None
""" [number|string] The width of tabs in both directions. Overrides both `vwidth` and `hwidth`.
Used for *fixed*, *spacing*, *corner* and *annotation* """
self.vcount = 1
""" Number of tabs in the vertical direction. Used for *fixed* """
self.hcount = 1
""" Number of tabs in the horizontal direction. Used for *fixed* """
self.mindistance = 0
""" [number|string] Minimal spacing between the tabs. If there are too many tabs, their count is reduced.
Used for *fixed* """
self.min_distance = None
""" {mindistance} """
self.spacing = 10
""" [number|string] The maximum spacing of the tabs. Used for *spacing* """
self.cutout = 1
""" [number|string] When your design features open pockets on the side, this parameter specifies extra cutout depth in order to
ensure that a sharp corner of the pocket can be milled. Used for *full* """
self.tabfootprints = 'kikit:Tab'
""" The footprint/s used for the *annotation* type. You can specify a list of footprints separated by comma """
self.tab_footprints = None
""" {tabfootprints} """
super().__init__()
def config(self, parent):
super().config(parent)
if self.width:
self.vwidth = self.hwidth = self.width
self.add_units(('vwidth', 'hwidth', 'width', 'mindistance', 'spacing', 'cutout'))
class PanelizeCuts(PanelOptions):
def __init__(self):
with document:
self.type = 'none'
""" [none,mousebites,vcuts,layer] Layer: When KiKit reports it cannot perform cuts, you can render the cuts
into a layer with this option to understand what's going on. Shouldn't be used for the final design """
self.drill = 0.5
""" [number|string] Drill size used for the *mousebites* """
self.spacing = 0.8
""" [number|string] The spacing of the holes used for the *mousebites* """
self.offset = 0
""" [number|string] Specify the *mousebites* and *vcuts* offset, positive offset puts the cuts into the board,
negative puts the cuts into the tabs """
self.prolong = 0
""" [number|string] Distance for tangential prolongation of the cuts (to cut through the internal corner fillets
caused by milling). Used for *mousebites* and *layer* """
self.clearance = 0
""" [number|string] Specify clearance for copper around V-cuts """
self.cutcurves = False
""" Specify if curves should be approximated by straight cuts (e.g., for cutting tabs on circular boards).
Used for *vcuts* """
self.cut_curves = None
""" {cutcurves} """
self.layer = 'Cmts.User'
""" Specify the layer to render V-cuts on. Also used for the *layer* type """
super().__init__()
def config(self, parent):
super().config(parent)
self.add_units(('drill', 'spacing', 'offset', 'prolong', 'clearance'))
res = Layer.solve(self.layer)
if len(res) > 1:
raise KiPlotConfigurationError('Must select only one layer for the V-cuts ({})'.format(self.layer))
class PanelizeFraming(PanelOptions):
def __init__(self):
with document:
self.type = 'none'
""" [none,railstb,railslr,frame,tightframe] Railstb: Add rails on top and bottom.
Railslr: Add rails on left and right.
Frame: Add a frame around the board.
Tighframe: Add a frame around the board which fills the whole area of the panel -
the boards have just a milled slot around their perimeter """
self.hspace = 2
""" [number|string] Specify the horizontal space between PCB and the frame/rail """
self.vspace = 2
""" [number|string] Specify the vertical space between PCB and the frame/rail """
self.space = None
""" [number|string] Specify the space between PCB and the frame/rail. Overrides `hspace` and `vspace` """
self.width = 5
""" [number|string] Specify with of the rails or frame """
self.fillet = 0
""" [number|string] Specify radius of fillet frame corners """
self.chamfer = 0
""" [number|string] Specify the size of chamfer frame corners """
self.mintotalheight = 0
""" [number|string] If needed, add extra material to the rail or frame to meet the minimal requested size.
Useful for services that require minimal panel size """
self.min_total_height = None
""" {mintotalheight} """
self.mintotalwidth = 0
""" [number|string] If needed, add extra material to the rail or frame to meet the minimal requested size.
Useful for services that require minimal panel size """
self.min_total_width = None
""" {mintotalwidth} """
self.cuts = 'both'
""" [none,both,v,h] Specify whether to add cuts to the corners of the frame for easy removal.
Used for *frame* """
self.slotwidth = 2
""" [number|string] Width of the milled slot for *tightframe* """
self.slot_width = None
""" {slotwidth} """
super().__init__()
def config(self, parent):
super().config(parent)
if self.space:
self.hspace = self.vspace = self.space
self.add_units(('hspace', 'vspace', 'space', 'width', 'fillet', 'chamfer', 'mintotalwidth', 'mintotalheight',
'slotwidth'))
class PanelizeTooling(PanelOptions):
def __init__(self):
with document:
self.type = 'none'
""" [none,3hole,4hole] Add none, 3 or 4 holes to the (rail/frame of) the panel """
self.hoffset = 0
""" [number|string] Horizontal offset from panel edges """
self.voffset = 0
""" [number|string] Vertical offset from panel edges """
self.size = 1.152
""" [number|string] Diameter of the holes """
self.paste = False
""" If True, the holes are included in the paste layer (therefore they appear on the stencil) """
super().__init__()
def config(self, parent):
super().config(parent)
self.add_units(('hoffset', 'voffset', 'size'))
class PanelizeFiducials(PanelOptions):
def __init__(self):
with document:
self.type = 'none'
""" [none,3fid,4fid] Add none, 3 or 4 fiducials to the (rail/frame of) the panel """
self.hoffset = 0
""" [number|string] Horizontal offset from panel edges """
self.voffset = 0
""" [number|string] Vertical offset from panel edges """
self.coppersize = 1
""" [number|string] Diameter of the copper spot """
self.copper_size = None
""" {coppersize} """
self.opening = 1
""" [number|string] Diameter of the solder mask opening """
super().__init__()
def config(self, parent):
super().config(parent)
self.add_units(('hoffset', 'voffset', 'coppersize', 'opening'))
class PanelizeText(PanelOptions):
def __init__(self):
with document:
self.type = 'simple'
""" [simple] Currently fixed """
self.text = ''
""" The text to be displayed. Note that you can escape ; via \\.
Available variables in text: *date* formats current date as <year>-<month>-<day>,
*time24* formats current time in 24-hour format,
*boardTitle* the title from the source board,
*boardDate* the date from the source board,
*boardRevision* the revision from the source board,
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board """
self.anchor = 'mt'
""" [tl,tr,bl,br,mt,mb,ml,mr,c] Origin of the text. Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr
(middle of sides), c (center). The anchors refer to the panel outline """
self.hoffset = 0
""" [number|string] Specify the horizontal offset from anchor. Respects KiCAD coordinate system """
self.voffset = 0
""" [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system """
self.orientation = 0
""" [number|string] Specify the orientation (angle) """
self.width = 1.5
""" [number|string] Width of the characters (the same parameters as KiCAD uses) """
self.height = 1.5
""" [number|string] Height of the characters (the same parameters as KiCAD uses) """
self.hjustify = 'center'
""" [left,right,center] Horizontal justification of the text """
self.vjustify = 'center'
""" [left,right,center] Vertical justification of the text """
self.thickness = 0.3
""" [number|string] Stroke thickness """
self.layer = 'F.SilkS'
""" Specify text layer """
super().__init__()
def config(self, parent):
super().config(parent)
self.add_units(('hoffset', 'voffset', 'width', 'height', 'thickness'))
self.add_angle(('orientation', ))
res = Layer.solve(self.layer)
if len(res) > 1:
raise KiPlotConfigurationError('Must select only one layer for the text ({})'.format(self.layer))
class PanelizeCopperfill(PanelOptions):
def __init__(self):
with document:
self.type = 'none'
""" [none,solid,hatched] How to fill non-board areas of the panel with copper """
self.clearance = 0.5
""" [number|string] Extra clearance from the board perimeters. Suitable for, e.g., not filling the tabs with
copper """
self.layers = 'F.Cu,B.Cu'
""" [string|list(string)] List of layers to fill. Can be a comma-separated string.
Using *all* means all external copper layers """
self.width = 1
""" [number|string] The width of the hatched strokes """
self.spacing = 1
""" [number|string] The space between the hatched strokes """
self.orientation = 45
""" [number|string] The orientation of the hatched strokes """
super().__init__()
def config(self, parent):
super().config(parent)
self.add_units(('width', 'spacing', 'clearance'))
self.add_angle(('orientation', ))
if not isinstance(self.layers, str) or self.layers != 'all':
if isinstance(self.layers, str):
self.layers = self.layers.split(',')
res = Layer.solve(self.layers)
self.layers = ','.join([la.layer for la in res])
class PanelizePost(PanelOptions):
def __init__(self):
with document:
self.type = 'auto'
""" [auto] Currently fixed """
self.copperfill = False
""" Fill tabs and frame with copper (e.g., to save etchant or to increase rigidity of flex-PCB panels) """
self.millradius = 0
""" [number|string] Simulate the milling operation (add fillets to the internal corners).
Specify mill radius (usually 1 mm). 0 radius disables the functionality """
self.mill_radius = None
""" {millradius} """
self.reconstructarcs = False
""" The panelization process works on top of a polygonal representation of the board.
This options allows to reconstruct the arcs in the design before saving the panel """
self.reconstruct_arcs = None
""" {reconstructarcs} """
self.refillzones = False
""" Refill the user zones after the panel is build.
This is only necessary when you want your zones to avoid cuts in panel """
self.refill_zones = None
""" {refillzones} """
self.script = ''
""" A path to custom Python file. The file should contain a function kikitPostprocess(panel, args) that
receives the prepared panel as the kikit.panelize.Panel object and the user-supplied arguments as a
string - see `scriptarg`. The function can make arbitrary changes to the panel - you can append text,
footprints, alter labels, etc. The function is invoked after the whole panel is constructed
(including all other postprocessing). If you try to add a functionality for a common fabrication
houses via scripting, consider submitting PR for KiKit """
self.scriptarg = ''
""" An arbitrary string passed to the user post-processing script specified in script """
self.script_arg = None
""" {scriptarg} """
self.origin = 'tl'
""" [tl,tr,bl,br,mt,mb,ml,mr,c] Specify if the auxiliary origin an grid origin should be placed.
Can be one of tl, tr, bl, br (corners), mt, mb, ml, mr (middle of sides), c (center).
Empty string does not changes the origin """
super().__init__()
def config(self, parent):
super().config(parent)
self.add_units(('millradius',))
class PanelizeDebug(PanelOptions):
def __init__(self):
with document:
self.drawPartitionLines = False
""" Draw partition lines """
self.drawBackboneLines = False
""" Draw backbone lines """
self.drawboxes = False
""" Draw boxes """
self.trace = False
""" Trace """
self.deterministic = False
""" Deterministic """
self.drawtabfail = False
""" Draw tab fail """
super().__init__()
class PanelizeConfig(PanelOptions):
def __init__(self):
with document:
self.page = PanelizePage
""" *[dict] Sets page size on the resulting panel and position the panel in the page """
self.layout = PanelizeLayout
""" *[dict] Layout used for the panel """
self.tabs = PanelizeTabs
""" *[dict] Style of the tabs used to join the PCB copies """
self.cuts = PanelizeCuts
""" *[dict] Specify how to perform the cuts on the tabs separating the board """
self.framing = PanelizeFraming
""" *[dict] Specify the frame around the boards """
self.tooling = PanelizeTooling
""" *[dict] Used to add tooling holes to the (rail/frame of) the panel """
self.fiducials = PanelizeFiducials
""" *[dict] Used to add fiducial marks to the (rail/frame of) the panel """
self.text = PanelizeText
""" [dict] Used to add text to the panel """
self.text2 = PanelizeText
""" [dict] Used to add text to the panel """
self.text3 = PanelizeText
""" [dict] Used to add text to the panel """
self.text4 = PanelizeText
""" [dict] Used to add text to the panel """
self.copperfill = PanelizeCopperfill
""" [dict] Fill non-board areas of the panel with copper """
self.post = PanelizePost
""" [dict] Finishing touches to the panel """
self.debug = PanelizeDebug
""" [dict] Debug options """
super().__init__()
def config(self, parent):
super().config(parent)
# Make None all things not specified
for k, v in self.get_attrs_gen():
if isinstance(v, type):
setattr(self, k, None)
class PanelizeOptions(VariantOptions):
def __init__(self):
with document:
self.output = GS.def_global_output
""" *Filename for the output (%i=panel, %x=kicad_pcb) """
self.configs = PanelizeConfig
""" *[list(dict)|list(string)|string] One or more configurations used to create the panel.
Use a string to include an external configuration, i.e. `myDefault.json`.
You can also include a preset using `:name`, i.e. `:vcuts`.
Use a dict to specify the options using the KiBot YAML file """
self.title = ''
""" Text used to replace the sheet title. %VALUE expansions are allowed.
If it starts with `+` the text is concatenated """
self.default_units = 'mm'
""" [mm,cm,dm,m,mil,inch,in] Units used when omitted """
self.default_angles = 'deg'
""" [deg,°,rad] Angles used when omitted """
super().__init__()
self._expand_id = 'panel'
self._expand_ext = 'kicad_pcb'
def config(self, parent):
super().config(parent)
if isinstance(self.configs, type):
logger.warning(W_PANELEMPTY+'Generating a panel with default options, not very useful')
self.configs = []
elif isinstance(self.configs, str):
self.configs = [self.configs]
def create_config(self, cfg):
with NamedTemporaryFile(mode='w', delete=False, suffix='.json', prefix='kibot_panel_cfg') as f:
logger.debug('Writing panel config to '+f.name)
cfg_d = {}
for k, v in cfg.get_attrs_gen():
if v:
cfg_d[k] = {k: v for k, v in v.get_attrs_gen() if v is not None}
js = json.dumps(cfg_d, indent=4)
logger.debugl(1, js)
f.write(js)
return f.name
def run(self, output):
cmd_kikit = self.ensure_tool('KiKit')
super().run(output)
to_remove = []
# Create the input PCB
if self._comps or self.title:
logger.debug('Creating modified PCB')
self.set_title(self.title)
self.filter_pcb_components(GS.board, do_3D=True)
fname = self.save_tmp_board()
self.unfilter_pcb_components(GS.board, do_3D=True)
self.restore_title()
to_remove.append(fname)
to_remove.append(fname.replace('kicad_pcb', 'kicad_pro'))
to_remove.append(fname.replace('kicad_pcb', 'kicad_prl'))
to_remove.append(fname.replace('kicad_pcb', 'pro'))
logger.debug('- Modified PCB: '+fname)
else:
fname = GS.pcb_file
# Create the command
cmd = [cmd_kikit, 'panelize']
# Add all the configurations
for cfg in self.configs:
cmd.append('--preset')
if isinstance(cfg, str):
if cfg[0] != ':' and not os.path.isfile(cfg):
raise KiPlotConfigurationError('Missing config file: '+cfg)
cmd.append(cfg)
else:
cfg_f = self.create_config(cfg)
to_remove.append(cfg_f)
cmd.append(cfg_f)
# Add the PCB and output
cmd.append(fname)
cmd.append(output)
try:
run_command(cmd)
finally:
# Remove temporals
for f in to_remove:
if os.path.isfile(f):
os.remove(f)
def get_targets(self, out_dir):
return [self._parent.expand_filename(out_dir, self.output)]
@output_class
class Panelize(BaseOutput): # noqa: F821
""" Panelize
Creates a panel to fabricate various copies of the PCB at once.
It currently uses the KiKit tool, which must be available.
Consult KiKit docs for detailed information.
Note that you don't need to specify the units for all distances.
If they are omitted they are assumed to be `default_units`.
The same is valid for angles, using `default_angles` """
def __init__(self):
super().__init__()
with document:
self.options = PanelizeOptions
""" *[dict] Options for the `Panelize` output """
self._category = 'PCB/fabrication'
@staticmethod
def get_conf_examples(name, layers, templates):
outs = []
for tpl in templates:
for out in tpl:
if out['type'] == 'panelize':
outs.append(out)
return outs

View File

@ -0,0 +1,62 @@
# Example KiBot config file for a basic panel
kibot:
version: 1
outputs:
- name: 'panel'
comment: "Create a 4x4 complex panel"
type: panelize
dir: Panel
options:
title: '+ (Panel)'
default_units: mm
configs:
- layout:
rows: 4
cols: 4
space: 2
hbackbone: 5
vbackbone: 5
hboneskip: 1
vboneskip: 1
page:
size: A0
tabs:
type: fixed
width: 3
vcount: 2
hcount: 0
cuts:
type: mousebites
drill: 0.5
spacing: 1mm
offset: 0.2
prolong: 0.5
framing:
type: railstb
width: 5
space: 3
copperfill:
type: hatched
clearance: 2
spacing: 0.5
width: 0.5
tooling:
type: 3hole
hoffset: 2.5
voffset: 2.5
size: 1.5
fiducials:
type: 3fid
hoffset: 5
voffset: 2.5
coppersize: 2
opening: 1
text:
text: "Panel for {boardTitle}"
anchor: mt
voffset: 2.5
hjustify: center
vjustify: center
post:
millradius: 1

View File

@ -548,6 +548,39 @@ deps = '{\
"url": "https://github.com/hildogjr/KiCost",\
"url_down": "https://github.com/hildogjr/KiCost/releases"\
},\
"KiKit": {\
"arch": null,\
"command": "kikit",\
"comments": [],\
"deb_package": "kikit",\
"downloader": {},\
"downloader_str": "pytool",\
"extra_arch": null,\
"extra_deb": null,\
"help_option": "--version",\
"importance": 10000,\
"in_debian": false,\
"is_kicad_plugin": false,\
"is_python": false,\
"name": "KiKit",\
"no_cmd_line_version": false,\
"no_cmd_line_version_old": false,\
"output": "panelize",\
"plugin_dirs": null,\
"pypi_name": "KiKit",\
"roles": [\
{\
"desc": null,\
"mandatory": true,\
"max_version": null,\
"output": "panelize",\
"version": null\
}\
],\
"tests": [],\
"url": "https://github.com/yaqwsx/KiKit",\
"url_down": "https://github.com/yaqwsx/KiKit/releases"\
},\
"LXML": {\
"arch": "python-lxml",\
"command": "lxml",\

View File

@ -0,0 +1,61 @@
# Example KiBot config file for a basic panel
kibot:
version: 1
outputs:
- name: 'panel'
comment: "Create a 4x4 complex panel"
type: panelize
options:
title: '+ (Panel)'
default_units: mm
configs:
- layout:
rows: 4
cols: 4
space: 2
hbackbone: 5
vbackbone: 5
hboneskip: 1
vboneskip: 1
page:
size: A3
tabs:
type: fixed
width: 3
vcount: 2
hcount: 0
cuts:
type: mousebites
drill: 0.5
spacing: 1mm
offset: 0.2
prolong: 0.5
framing:
type: railstb
width: 5
space: 3
copperfill:
type: hatched
clearance: 2
spacing: 0.5
width: 0.5
tooling:
type: 3hole
hoffset: 2.5
voffset: 2.5
size: 1.5
fiducials:
type: 3fid
hoffset: 5
voffset: 2.5
coppersize: 2
opening: 1
text:
text: My panel
anchor: mt
voffset: 2.5
hjustify: center
vjustify: center
post:
millradius: 1