[Variants] Added some limited support for `kikit separate`

This commit is contained in:
Salvador E. Tropea 2022-12-18 17:14:38 -03:00
parent fafd5d2f6d
commit da2d5f1001
16 changed files with 678 additions and 69 deletions

View File

@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- New output:
- `vrml` export the 3D model in Virtual Reality Modeling Language (#349)
- Variants:
- Added some limited support for `kikit separate`
- PCB_Print:
- Images not showing in custom frames. (#352)

View File

@ -146,6 +146,7 @@ Notes:
[**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`, `stencil_3d`, `stencil_for_jig`
- Optional to separate multiboard projects for general use
[**LXML**](https://pypi.org/project/LXML/) [![Python module](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/Python-logo-notext-22x22.png)](https://pypi.org/project/LXML/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/python3-lxml) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for: `pcb_print`, `pcbdraw`
@ -1038,6 +1039,28 @@ Note that the **_kibom_...** filters uses a field named `Config`, but you can cu
Use '_var_rename' to transform VARIANT:FIELD fields.
Use '_var_rename_kicost' to transform kicost.VARIANT:FIELD fields.
Use '_kicost_rename' to apply KiCost field rename rules.
- `sub_pcbs`: [list(dict)] Used for multi-board workflows as defined by KiKit.
I don't recommend using it, for detail read
[this](https://github.com/INTI-CMNB/KiBot/tree/master/docs/1_SCH_2_part_PCBs).
But if you really need it you can define the sub-PCBs here.
Then you just use *VARIANT[SUB_PCB_NAME]* instead of just *VARIANT*.
* Valid keys:
- **`name`**: [string=''] Name for this sub-pcb.
- *ref*: Alias for reference.
- **`reference`**: [string=''] Use it for the annotations method.
This is the reference for the `kikit:Board` footprint used to identify the sub-PCB.
When empty the sub-PCB is specified using a rectangle.
- *bottom_right_x*: Alias for brx.
- *bottom_right_y*: Alias for bry.
- `brx`: [number|string] The X position of the bottom right corner for the rectangle that contains the sub-PCB.
- `bry`: [number|string] The Y position of the bottom right corner for the rectangle that contains the sub-PCB.
- `file_id`: [string=''] Text to use as the replacement for %v expansion.
When empty we use the parent `file_id` plus the `name` of the sub-PCB.
- `tlx`: [number|string] The X position of the top left corner for the rectangle that contains the sub-PCB.
- `tly`: [number|string] The Y position of the top left corner for the rectangle that contains the sub-PCB.
- *top_left_x*: Alias for tlx.
- *top_left_y*: Alias for tly.
- `units`: [string='mm'] [millimeters,inches,mils,mm,cm,dm,m,mil,inch,in] Units used when omitted.
- `variant_field`: [string='Config'] Name of the field that stores board variant for component.
- `variants_blacklist`: [string|list(string)=''] List of board variants to exclude from the BOM.
- `variants_whitelist`: [string|list(string)=''] List of board variants to include in the BOM.
@ -1061,6 +1084,28 @@ Note that the **_kibom_...** filters uses a field named `Config`, but you can cu
Use '_var_rename' to transform VARIANT:FIELD fields.
Use '_var_rename_kicost' to transform kicost.VARIANT:FIELD fields.
Use '_kicost_rename' to apply KiCost field rename rules.
- `sub_pcbs`: [list(dict)] Used for multi-board workflows as defined by KiKit.
I don't recommend using it, for detail read
[this](https://github.com/INTI-CMNB/KiBot/tree/master/docs/1_SCH_2_part_PCBs).
But if you really need it you can define the sub-PCBs here.
Then you just use *VARIANT[SUB_PCB_NAME]* instead of just *VARIANT*.
* Valid keys:
- **`name`**: [string=''] Name for this sub-pcb.
- *ref*: Alias for reference.
- **`reference`**: [string=''] Use it for the annotations method.
This is the reference for the `kikit:Board` footprint used to identify the sub-PCB.
When empty the sub-PCB is specified using a rectangle.
- *bottom_right_x*: Alias for brx.
- *bottom_right_y*: Alias for bry.
- `brx`: [number|string] The X position of the bottom right corner for the rectangle that contains the sub-PCB.
- `bry`: [number|string] The Y position of the bottom right corner for the rectangle that contains the sub-PCB.
- `file_id`: [string=''] Text to use as the replacement for %v expansion.
When empty we use the parent `file_id` plus the `name` of the sub-PCB.
- `tlx`: [number|string] The X position of the top left corner for the rectangle that contains the sub-PCB.
- `tly`: [number|string] The Y position of the top left corner for the rectangle that contains the sub-PCB.
- *top_left_x*: Alias for tlx.
- *top_left_y*: Alias for tly.
- `units`: [string='mm'] [millimeters,inches,mils,mm,cm,dm,m,mil,inch,in] Units used when omitted.
- `variant`: [string|list(string)=''] Board variant(s).
- `kicost`: KiCost variant style
The `variant` field (configurable) contains one or more values.
@ -1086,6 +1131,28 @@ Note that the **_kibom_...** filters uses a field named `Config`, but you can cu
- `separators`: [string=',;/ '] Valid separators for variants in the variant field.
Each character is a valid separator.
Only supported internally, don't use it if you plan to use KiCost.
- `sub_pcbs`: [list(dict)] Used for multi-board workflows as defined by KiKit.
I don't recommend using it, for detail read
[this](https://github.com/INTI-CMNB/KiBot/tree/master/docs/1_SCH_2_part_PCBs).
But if you really need it you can define the sub-PCBs here.
Then you just use *VARIANT[SUB_PCB_NAME]* instead of just *VARIANT*.
* Valid keys:
- **`name`**: [string=''] Name for this sub-pcb.
- *ref*: Alias for reference.
- **`reference`**: [string=''] Use it for the annotations method.
This is the reference for the `kikit:Board` footprint used to identify the sub-PCB.
When empty the sub-PCB is specified using a rectangle.
- *bottom_right_x*: Alias for brx.
- *bottom_right_y*: Alias for bry.
- `brx`: [number|string] The X position of the bottom right corner for the rectangle that contains the sub-PCB.
- `bry`: [number|string] The Y position of the bottom right corner for the rectangle that contains the sub-PCB.
- `file_id`: [string=''] Text to use as the replacement for %v expansion.
When empty we use the parent `file_id` plus the `name` of the sub-PCB.
- `tlx`: [number|string] The X position of the top left corner for the rectangle that contains the sub-PCB.
- `tly`: [number|string] The Y position of the top left corner for the rectangle that contains the sub-PCB.
- *top_left_x*: Alias for tlx.
- *top_left_y*: Alias for tly.
- `units`: [string='mm'] [millimeters,inches,mils,mm,cm,dm,m,mil,inch,in] Units used when omitted.
- `variant`: [string=''] Variants to match (regex).
- `variant_field`: [string='variant'] Name of the field that stores board variant/s for component.
Only supported internally, don't use it if you plan to use KiCost.

View File

@ -73,6 +73,8 @@ Dependencies:
github: yaqwsx/KiKit
pypi: KiKit
downloader: pytool
- from: KiKit
role: Separate multiboard projects
- name: Xvfbwrapper
python_module: true
debian: python3-xvfbwrapper

View File

@ -268,6 +268,7 @@ USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101
DISABLE_3D_MODEL_TEXT = '_Disabled_by_KiBot'
RENDERERS = ['pcbdraw', 'render_3d']
PCB_GENERATORS = ['pcb_variant', 'panelize']
KIKIT_UNIT_ALIASES = {'millimeters': 'mm', 'inches': 'inch', 'mils': 'mil'}
class Rect(object):

View File

@ -501,3 +501,49 @@ class BaseOptions(Optionable):
self._expand_id = cur_id
self._expand_ext = cur_ext
return res
class PanelOptions(BaseOptions):
""" A class for options that uses KiKit's units """
_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, def_units=None):
if def_units is None:
def_units = self._parent._parent.units
for op in ops:
val = getattr(self, op)
if val is None:
continue
if isinstance(val, (int, float)):
setattr(self, op, str(val)+def_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, def_units=None):
if def_units is None:
def_units = self._parent._parent.units
for op in ops:
val = getattr(self, op)
if isinstance(val, (int, float)):
setattr(self, op, str(val)+def_units)
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))

View File

@ -8,9 +8,9 @@ from glob import glob
import math
import os
import re
from tempfile import NamedTemporaryFile, mkdtemp
from tempfile import NamedTemporaryFile, mkdtemp, TemporaryDirectory
from .gs import GS
from .kiplot import load_sch, get_board_comps_data
from .kiplot import load_sch, get_board_comps_data, load_board
from .misc import Rect, W_WRONGPASTE, DISABLE_3D_MODEL_TEXT, W_NOCRTYD
if not GS.kicad_version_n:
# When running the regression tests we need it
@ -710,27 +710,41 @@ class VariantOptions(BaseOptions):
m.Models().pop()
self._highlighted_3D_components = None
def apply_sub_pcb(self):
with TemporaryDirectory(prefix='kibot-separate') as d:
dest = os.path.join(d, os.path.basename(GS.pcb_file))
self._sub_pcb.load_board(dest)
def filter_pcb_components(self, board, do_3D=False, do_2D=True, highlight=None):
if not self._comps:
if not self._comps and not self._sub_pcb:
return False
self.comps_hash = self.get_refs_hash()
if do_2D:
self.cross_modules(board, self.comps_hash)
self.remove_paste_and_glue(board, self.comps_hash)
if hasattr(self, 'hide_excluded') and self.hide_excluded:
self.remove_fab(board, self.comps_hash)
if do_3D:
# Disable the models that aren't for this variant
self.apply_3D_variant_aspect(board)
# Remove the 3D models for not fitted components (also rename)
self.remove_3D_models(board, self.comps_hash)
# Highlight selected components
self.highlight_3D_models(board, highlight)
if self._comps:
self.comps_hash = self.get_refs_hash()
if do_2D:
self.cross_modules(board, self.comps_hash)
self.remove_paste_and_glue(board, self.comps_hash)
if hasattr(self, 'hide_excluded') and self.hide_excluded:
self.remove_fab(board, self.comps_hash)
if do_3D:
# Disable the models that aren't for this variant
self.apply_3D_variant_aspect(board)
# Remove the 3D models for not fitted components (also rename)
self.remove_3D_models(board, self.comps_hash)
# Highlight selected components
self.highlight_3D_models(board, highlight)
if self._sub_pcb:
# Current implementation isn't efficient
self.apply_sub_pcb()
return True
def unfilter_pcb_components(self, board, do_3D=False, do_2D=True):
if not self._comps:
return
if self._sub_pcb:
# Undo the sub-PCB: just reload the PCB
GS.board = None
load_board()
return
if do_2D:
self.uncross_modules(board, self.comps_hash)
self.restore_paste_and_glue(board, self.comps_hash)
@ -918,4 +932,7 @@ class VariantOptions(BaseOptions):
if self.variant:
# Apply the variant
comps = self.variant.filter(comps)
self._sub_pcb = self.variant._sub_pcb
else:
self._sub_pcb = None
self._comps = comps

View File

@ -17,10 +17,9 @@ from tempfile import NamedTemporaryFile
from .error import KiPlotConfigurationError
from .gs import GS
from .kiplot import run_command, config_output
from .layer import Layer
from .misc import W_PANELEMPTY
from .optionable import BaseOptions
from .misc import W_PANELEMPTY, KIKIT_UNIT_ALIASES
from .optionable import PanelOptions
from .out_base import VariantOptions
from .registrable import RegOutput
from .macros import macros, document, output_class # noqa: F401
@ -40,47 +39,6 @@ def update_dict(d, u):
return d
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.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 PanelOptionsWithPlugin(PanelOptions):
def __init__(self):
with document:
@ -584,7 +542,6 @@ class PanelizeConfig(PanelOptions):
class PanelizeOptions(VariantOptions):
_extends_regex = re.compile(r'(.+)\[(.+)\]')
_unit_alias = {'millimeters': 'mm', 'inches': 'inch', 'mils': 'mil'}
def __init__(self):
with document:
@ -688,7 +645,7 @@ class PanelizeOptions(VariantOptions):
if configs:
list(map(self.solve_extends, filter(lambda x: 'extends' in x, configs)))
super().config(parent)
self.units = PanelizeOptions._unit_alias.get(self.units, self.units)
self.units = KIKIT_UNIT_ALIASES.get(self.units, self.units)
if isinstance(self.configs, type):
logger.warning(W_PANELEMPTY+'Generating a panel with default options, not very useful')
self.configs = []

View File

@ -4,6 +4,7 @@
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
from collections import OrderedDict
from copy import copy
from .optionable import Optionable
from .error import KiPlotConfigurationError
@ -59,7 +60,21 @@ class RegOutput(Optionable, Registrable):
@staticmethod
def add_variants(variants):
RegOutput._def_variants.update(variants)
for k, v in variants.items():
# Do we have sub-PCBs
if v.sub_pcbs:
# Add a variant for each sub-PCB
for sp in v.sub_pcbs:
name = k+'['+sp.name+']'
vn = copy(v)
vn._sub_pcb = sp
if sp.file_id:
vn.file_id = sp.file_id
else:
vn.file_id += '_'+sp.name
RegOutput._def_variants[name] = vn
else:
RegOutput._def_variants[k] = v
@staticmethod
def is_variant(name):

View File

@ -1,14 +1,82 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 Salvador E. Tropea
# Copyright (c) 2020-2021 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
from .registrable import RegVariant
from .optionable import Optionable
from .optionable import Optionable, PanelOptions
from .fil_base import apply_exclude_filter, apply_fitted_filter, apply_fixed_filter, apply_pre_transform
from .error import KiPlotConfigurationError
from .misc import KIKIT_UNIT_ALIASES
from .gs import GS
from .kiplot import load_board, run_command
from .macros import macros, document # noqa: F401
class SubPCBOptions(PanelOptions):
def __init__(self):
super().__init__()
self._unkown_is_error = True
with document:
self.name = ''
""" *Name for this sub-pcb """
self.reference = ''
""" *Use it for the annotations method.
This is the reference for the `kikit:Board` footprint used to identify the sub-PCB.
When empty the sub-PCB is specified using a rectangle """
self.ref = None
""" {reference} """
self.tlx = 0
""" [number|string] The X position of the top left corner for the rectangle that contains the sub-PCB """
self.top_left_x = None
""" {tlx} """
self.tly = 0
""" [number|string] The Y position of the top left corner for the rectangle that contains the sub-PCB """
self.top_left_y = None
""" {tly} """
self.brx = 0
""" [number|string] The X position of the bottom right corner for the rectangle that contains the sub-PCB """
self.bottom_right_x = None
""" {brx} """
self.bry = 0
""" [number|string] The Y position of the bottom right corner for the rectangle that contains the sub-PCB """
self.bottom_right_y = None
""" {bry} """
self.units = 'mm'
""" [millimeters,inches,mils,mm,cm,dm,m,mil,inch,in] Units used when omitted """
self.file_id = ''
""" Text to use as the replacement for %v expansion.
When empty we use the parent `file_id` plus the `name` of the sub-PCB """
def is_zero(self, val):
return isinstance(val, (int, float)) and val == 0
def config(self, parent):
super().config(parent)
if not self.name:
raise KiPlotConfigurationError('Sub-PCB without a name')
self.units = KIKIT_UNIT_ALIASES.get(self.units, self.units)
if (not self.reference and self.is_zero(self.tlx) and self.is_zero(self.tly) and self.is_zero(self.brx) and
self.is_zero(self.bry)):
raise KiPlotConfigurationError('No reference or rectangle specified for {} sub-PCB'.format(self.name))
self.add_units(('tlx', 'tly', 'brx', 'bry'), self.units)
def get_separate_source(self):
if self.reference:
return "annotation; ref: {}".format(self.reference)
return "rectangle; tlx: {}; tly: {}; brx: {}; bry: {}".format(self.tlx, self.tly, self.brx, self.bry)
def load_board(self, dest):
# Make sure kikit is available
command = GS.ensure_tool('global', 'KiKit')
# Execute the separate
cmd = [command, 'separate', '-s', self.get_separate_source(), GS.pcb_file, dest]
run_command(cmd)
# Load this board
GS.board = None
load_board(dest)
class BaseVariant(RegVariant):
def __init__(self):
super().__init__()
@ -38,6 +106,18 @@ class BaseVariant(RegVariant):
self.dnc_filter = Optionable
""" [string|list(string)=''] Name of the filter to mark components as 'Do Not Change'.
Use '_kibom_dnc' for the default KiBoM behavior """
self.sub_pcbs = SubPCBOptions
""" [list(dict)] Used for multi-board workflows as defined by KiKit.
I don't recommend using it, for detail read
[this](https://github.com/INTI-CMNB/KiBot/tree/master/docs/1_SCH_2_part_PCBs).
But if you really need it you can define the sub-PCBs here.
Then you just use *VARIANT[SUB_PCB_NAME]* instead of just *VARIANT* """
self._sub_pcb = None
def config(self, parent):
super().config(parent)
if isinstance(self.sub_pcbs, type):
self.sub_pcbs = []
def get_variant_field(self):
""" Returns the name of the field used to determine if the component belongs to the variant """

View File

@ -576,17 +576,24 @@ deps = '{\
"extra_arch": null,\
"extra_deb": null,\
"help_option": "--version",\
"importance": 30000,\
"importance": 30100,\
"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",\
"output": "global",\
"plugin_dirs": null,\
"pypi_name": "KiKit",\
"roles": [\
{\
"desc": "Separate multiboard projects",\
"mandatory": false,\
"max_version": null,\
"output": "global",\
"version": null\
},\
{\
"desc": null,\
"mandatory": true,\

View File

@ -0,0 +1,173 @@
(kicad_pcb (version 20171130) (host pcbnew 5.1.9-73d0e3b20d~88~ubuntu20.04.1)
(general
(thickness 1.6)
(drawings 18)
(tracks 0)
(zones 0)
(modules 3)
(nets 1)
)
(page A4)
(layers
(0 F.Cu signal)
(31 B.Cu signal)
(32 B.Adhes user)
(33 F.Adhes user)
(34 B.Paste user)
(35 F.Paste user)
(36 B.SilkS user)
(37 F.SilkS user)
(38 B.Mask user)
(39 F.Mask user)
(40 Dwgs.User user)
(41 Cmts.User user)
(42 Eco1.User user)
(43 Eco2.User user)
(44 Edge.Cuts user)
(45 Margin user)
(46 B.CrtYd user)
(47 F.CrtYd user)
(48 B.Fab user)
(49 F.Fab user)
)
(setup
(last_trace_width 0.25)
(trace_clearance 0.2)
(zone_clearance 0.508)
(zone_45_only no)
(trace_min 0.2)
(via_size 0.8)
(via_drill 0.4)
(via_min_size 0.4)
(via_min_drill 0.3)
(uvia_size 0.3)
(uvia_drill 0.1)
(uvias_allowed no)
(uvia_min_size 0.2)
(uvia_min_drill 0.1)
(edge_width 0.2)
(segment_width 0.2)
(pcb_text_width 0.3)
(pcb_text_size 1.5 1.5)
(mod_edge_width 0.12)
(mod_text_size 1 1)
(mod_text_width 0.15)
(pad_size 1.524 1.524)
(pad_drill 0.762)
(pad_to_mask_clearance 0)
(aux_axis_origin 0 0)
(visible_elements FFFFFF7F)
(pcbplotparams
(layerselection 0x010fc_ffffffff)
(usegerberextensions false)
(usegerberattributes true)
(usegerberadvancedattributes true)
(creategerberjobfile true)
(excludeedgelayer true)
(linewidth 0.150000)
(plotframeref false)
(viasonmask false)
(mode 1)
(useauxorigin false)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(psnegative false)
(psa4output false)
(plotreference true)
(plotvalue true)
(plotinvisibletext false)
(padsonsilk false)
(subtractmaskfromsilk false)
(outputformat 1)
(mirror false)
(drillshape 1)
(scaleselection 1)
(outputdirectory ""))
)
(net 0 "")
(net_class Default "This is the default net class."
(clearance 0.2)
(trace_width 0.25)
(via_dia 0.8)
(via_drill 0.4)
(uvia_dia 0.3)
(uvia_drill 0.1)
)
(module kikit:Board (layer F.Cu) (tedit 605A1488) (tstamp 605A707C)
(at 185 90)
(descr "Mark board for extraction")
(fp_text reference B3 (at -4.5 -5) (layer Dwgs.User)
(effects (font (size 1 1) (thickness 0.15)) (justify left))
)
(fp_text value Board (at -7.25 -5) (layer Dwgs.User)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_line (start 0 0) (end -1.25 -4) (layer Dwgs.User) (width 0.2))
(fp_line (start -1.25 -4) (end -9.25 -4) (layer Dwgs.User) (width 0.2))
(fp_line (start 0 0) (end 0.5 -1) (layer Dwgs.User) (width 0.2))
(fp_line (start 0 0) (end -1 -0.5) (layer Dwgs.User) (width 0.2))
)
(module kikit:Board (layer F.Cu) (tedit 605A1488) (tstamp 605A706E)
(at 135 90)
(descr "Mark board for extraction")
(fp_text reference B2 (at -4.5 -5) (layer Dwgs.User)
(effects (font (size 1 1) (thickness 0.15)) (justify left))
)
(fp_text value Board (at -7.25 -5) (layer Dwgs.User)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_line (start 0 0) (end -1 -0.5) (layer Dwgs.User) (width 0.2))
(fp_line (start 0 0) (end 0.5 -1) (layer Dwgs.User) (width 0.2))
(fp_line (start -1.25 -4) (end -9.25 -4) (layer Dwgs.User) (width 0.2))
(fp_line (start 0 0) (end -1.25 -4) (layer Dwgs.User) (width 0.2))
)
(module kikit:Board (layer F.Cu) (tedit 605A1488) (tstamp 605A7057)
(at 100 90)
(descr "Mark board for extraction")
(fp_text reference B1 (at -4.5 -5) (layer Dwgs.User)
(effects (font (size 1 1) (thickness 0.15)) (justify left))
)
(fp_text value Board (at -7.25 -5) (layer Dwgs.User)
(effects (font (size 1 1) (thickness 0.15)))
)
(fp_line (start 0 0) (end -1.25 -4) (layer Dwgs.User) (width 0.2))
(fp_line (start -1.25 -4) (end -9.25 -4) (layer Dwgs.User) (width 0.2))
(fp_line (start 0 0) (end 0.5 -1) (layer Dwgs.User) (width 0.2))
(fp_line (start 0 0) (end -1 -0.5) (layer Dwgs.User) (width 0.2))
)
(gr_text C (at 185 100) (layer F.SilkS) (tstamp 605A709F)
(effects (font (size 5 5) (thickness 1)))
)
(gr_text B (at 145 100) (layer F.SilkS) (tstamp 605A709D)
(effects (font (size 5 5) (thickness 1)))
)
(gr_text A (at 100 100) (layer F.SilkS)
(effects (font (size 5 5) (thickness 1)))
)
(gr_line (start 200 100) (end 190 100) (layer Edge.Cuts) (width 0.2) (tstamp 605A142A))
(gr_line (start 200 105) (end 200 100) (layer Edge.Cuts) (width 0.2))
(gr_line (start 190 105) (end 200 105) (layer Edge.Cuts) (width 0.2))
(gr_line (start 190 100) (end 190 105) (layer Edge.Cuts) (width 0.2))
(gr_line (start 210 90) (end 180 90) (layer Edge.Cuts) (width 0.2) (tstamp 605A1425))
(gr_line (start 210 110) (end 210 90) (layer Edge.Cuts) (width 0.2))
(gr_line (start 180 110) (end 210 110) (layer Edge.Cuts) (width 0.2))
(gr_line (start 180 90) (end 180 110) (layer Edge.Cuts) (width 0.2))
(gr_line (start 150 110) (end 135 110) (layer Edge.Cuts) (width 0.2) (tstamp 605A1415))
(gr_line (start 150 100) (end 150 110) (layer Edge.Cuts) (width 0.2))
(gr_line (start 160 100) (end 150 100) (layer Edge.Cuts) (width 0.2))
(gr_line (start 160 90) (end 160 100) (layer Edge.Cuts) (width 0.2))
(gr_line (start 135 90) (end 160 90) (layer Edge.Cuts) (width 0.2))
(gr_line (start 135 110) (end 135 90) (layer Edge.Cuts) (width 0.2))
(gr_circle (center 100 100) (end 110 100) (layer Edge.Cuts) (width 0.2))
)

View File

@ -0,0 +1,16 @@
EESchema Schematic File Version 4
EELAYER 30 0
EELAYER END
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title ""
Date ""
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
$EndSCHEMATC

View File

@ -0,0 +1,152 @@
(kicad_pcb (version 20211014) (generator pcbnew)
(general
(thickness 1.6)
)
(paper "A4")
(layers
(0 "F.Cu" signal)
(31 "B.Cu" signal)
(32 "B.Adhes" user "B.Adhesive")
(33 "F.Adhes" user "F.Adhesive")
(34 "B.Paste" user)
(35 "F.Paste" user)
(36 "B.SilkS" user "B.Silkscreen")
(37 "F.SilkS" user "F.Silkscreen")
(38 "B.Mask" user)
(39 "F.Mask" user)
(40 "Dwgs.User" user "User.Drawings")
(41 "Cmts.User" user "User.Comments")
(42 "Eco1.User" user "User.Eco1")
(43 "Eco2.User" user "User.Eco2")
(44 "Edge.Cuts" user)
(45 "Margin" user)
(46 "B.CrtYd" user "B.Courtyard")
(47 "F.CrtYd" user "F.Courtyard")
(48 "B.Fab" user)
(49 "F.Fab" user)
)
(setup
(pad_to_mask_clearance 0)
(pcbplotparams
(layerselection 0x00010fc_ffffffff)
(disableapertmacros false)
(usegerberextensions false)
(usegerberattributes true)
(usegerberadvancedattributes true)
(creategerberjobfile true)
(svguseinch false)
(svgprecision 6)
(excludeedgelayer true)
(plotframeref false)
(viasonmask false)
(mode 1)
(useauxorigin false)
(hpglpennumber 1)
(hpglpenspeed 20)
(hpglpendiameter 15.000000)
(dxfpolygonmode true)
(dxfimperialunits true)
(dxfusepcbnewfont true)
(psnegative false)
(psa4output false)
(plotreference true)
(plotvalue true)
(plotinvisibletext false)
(sketchpadsonfab false)
(subtractmaskfromsilk false)
(outputformat 1)
(mirror false)
(drillshape 1)
(scaleselection 1)
(outputdirectory "")
)
)
(net 0 "")
(footprint "kikit:Board" (layer "F.Cu")
(tedit 605A1488) (tstamp 00000000-0000-0000-0000-0000605a7057)
(at 100 90)
(descr "Mark board for extraction")
(attr through_hole)
(fp_text reference "B1" (at -4.5 -5) (layer "Dwgs.User")
(effects (font (size 1 1) (thickness 0.15)) (justify left))
(tstamp cc934527-b84e-4ca1-ad52-399f8e7bf3df)
)
(fp_text value "Board" (at -7.25 -5) (layer "Dwgs.User")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 43c89b73-cf56-4390-ad99-0ff92ac35d30)
)
(fp_line (start 0 0) (end 0.5 -1) (layer "Dwgs.User") (width 0.2) (tstamp 2d675f93-d44f-485c-8207-150c12492452))
(fp_line (start 0 0) (end -1.25 -4) (layer "Dwgs.User") (width 0.2) (tstamp 87358536-a504-44ce-8c66-b8b876d8894f))
(fp_line (start -1.25 -4) (end -9.25 -4) (layer "Dwgs.User") (width 0.2) (tstamp 982364b6-bcbd-41ff-a125-84aef9991943))
(fp_line (start 0 0) (end -1 -0.5) (layer "Dwgs.User") (width 0.2) (tstamp dd80f3b3-31f9-4741-adf5-c81fa1f4c68b))
)
(footprint "kikit:Board" (layer "F.Cu")
(tedit 605A1488) (tstamp 00000000-0000-0000-0000-0000605a706e)
(at 135 90)
(descr "Mark board for extraction")
(attr through_hole)
(fp_text reference "B2" (at -4.5 -5) (layer "Dwgs.User")
(effects (font (size 1 1) (thickness 0.15)) (justify left))
(tstamp 5c8f7927-58c0-47ef-854e-3dd8cc0bf312)
)
(fp_text value "Board" (at -7.25 -5) (layer "Dwgs.User")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp bb77f266-f95c-4d63-b73d-9eb5f6c9f1bc)
)
(fp_line (start 0 0) (end -1 -0.5) (layer "Dwgs.User") (width 0.2) (tstamp 17e1baca-0f8f-4171-b616-6601bb7efd5b))
(fp_line (start -1.25 -4) (end -9.25 -4) (layer "Dwgs.User") (width 0.2) (tstamp 2cc0aca6-d467-4eed-bd95-c60b0cdb0ccc))
(fp_line (start 0 0) (end 0.5 -1) (layer "Dwgs.User") (width 0.2) (tstamp 3605dbc5-2619-4e06-bf86-49f1c1817220))
(fp_line (start 0 0) (end -1.25 -4) (layer "Dwgs.User") (width 0.2) (tstamp 500b75b0-5ef8-4f0f-8bab-ed9123c39485))
)
(footprint "kikit:Board" (layer "F.Cu")
(tedit 605A1488) (tstamp 00000000-0000-0000-0000-0000605a707c)
(at 185 90)
(descr "Mark board for extraction")
(attr through_hole)
(fp_text reference "B3" (at -4.5 -5) (layer "Dwgs.User")
(effects (font (size 1 1) (thickness 0.15)) (justify left))
(tstamp 01bee0de-da40-4390-898d-9738e5a86bcc)
)
(fp_text value "Board" (at -7.25 -5) (layer "Dwgs.User")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 3f2b141b-7bc9-4979-84f7-000f6c66c53b)
)
(fp_line (start 0 0) (end 0.5 -1) (layer "Dwgs.User") (width 0.2) (tstamp 0ef8c6c7-83b7-4ec8-8948-2e70fa334d77))
(fp_line (start -1.25 -4) (end -9.25 -4) (layer "Dwgs.User") (width 0.2) (tstamp 181c6f00-96c3-4bb7-ba16-c3fde41797ab))
(fp_line (start 0 0) (end -1.25 -4) (layer "Dwgs.User") (width 0.2) (tstamp 5e41870a-537a-491e-a56f-ec6759e82e36))
(fp_line (start 0 0) (end -1 -0.5) (layer "Dwgs.User") (width 0.2) (tstamp f1ebaa83-56da-4499-929a-773021ade5b3))
)
(gr_line (start 150 110) (end 135 110) (layer "Edge.Cuts") (width 0.2) (tstamp 00000000-0000-0000-0000-0000605a1415))
(gr_line (start 210 90) (end 180 90) (layer "Edge.Cuts") (width 0.2) (tstamp 00000000-0000-0000-0000-0000605a1425))
(gr_line (start 200 100) (end 190 100) (layer "Edge.Cuts") (width 0.2) (tstamp 00000000-0000-0000-0000-0000605a142a))
(gr_line (start 160 100) (end 150 100) (layer "Edge.Cuts") (width 0.2) (tstamp 51ee268f-1cdb-4d7d-9c21-906f097e0468))
(gr_line (start 180 90) (end 180 110) (layer "Edge.Cuts") (width 0.2) (tstamp 64c01c4a-0872-44ed-b267-b18d90185def))
(gr_line (start 210 110) (end 210 90) (layer "Edge.Cuts") (width 0.2) (tstamp 7197a3a4-13b0-4964-97bb-d3c67b25d3cc))
(gr_line (start 160 90) (end 160 100) (layer "Edge.Cuts") (width 0.2) (tstamp 993fe7e0-bb83-477b-b768-ddb19b694f3e))
(gr_line (start 135 90) (end 160 90) (layer "Edge.Cuts") (width 0.2) (tstamp a3e28d38-69cd-42a1-b425-f1a15302e858))
(gr_line (start 180 110) (end 210 110) (layer "Edge.Cuts") (width 0.2) (tstamp afbb53e6-3063-40ce-bb83-3604be396e1d))
(gr_line (start 190 105) (end 200 105) (layer "Edge.Cuts") (width 0.2) (tstamp c0684255-d65e-4027-adfe-519b7fcde519))
(gr_line (start 135 110) (end 135 90) (layer "Edge.Cuts") (width 0.2) (tstamp c30d7998-579c-409d-b75a-00fa9f4eed59))
(gr_circle (center 100 100) (end 110 100) (layer "Edge.Cuts") (width 0.2) (fill none) (tstamp c817e371-265a-41a5-8be4-97a10008c2fc))
(gr_line (start 150 100) (end 150 110) (layer "Edge.Cuts") (width 0.2) (tstamp d2bf3808-d0b7-47de-a1f9-f2e94b771c7b))
(gr_line (start 190 100) (end 190 105) (layer "Edge.Cuts") (width 0.2) (tstamp da6b8bc6-f48f-49c2-9e3e-3bb909ccfe9a))
(gr_line (start 200 105) (end 200 100) (layer "Edge.Cuts") (width 0.2) (tstamp e6c0520a-00d5-4fde-85e1-681298498d17))
(gr_text "B" (at 145 100) (layer "F.SilkS") (tstamp 00000000-0000-0000-0000-0000605a709d)
(effects (font (size 5 5) (thickness 1)))
)
(gr_text "C" (at 185 100) (layer "F.SilkS") (tstamp 00000000-0000-0000-0000-0000605a709f)
(effects (font (size 5 5) (thickness 1)))
)
(gr_text "A" (at 100 100) (layer "F.SilkS") (tstamp eb565a94-7da3-44d3-82d1-76c30d6f561a)
(effects (font (size 5 5) (thickness 1)))
)
)

View File

@ -0,0 +1,14 @@
(kicad_sch (version 20211123) (generator eeschema)
(uuid 2e1c5c17-733f-432d-ac13-7421fd62239d)
(paper "A4")
(lib_symbols
)
(sheet_instances
(path "/" (page "1"))
)
)

View File

@ -8,7 +8,7 @@ outputs:
type: panelize
options:
title: '+ (Panel)'
default_units: mm
units: mm
configs:
- layout:
rows: 4

View File

@ -0,0 +1,60 @@
# Example KiBot config file
kibot:
version: 1
global:
hide_excluded: true
pcb_finish: ENIG
solder_mask_color: blue
variants:
- name: 'default'
comment: 'Default variant'
type: ibom
sub_pcbs:
- name: A
tlx: 89
tly: 89
brx: 111
bry: 111
- name: B
ref: B2
- name: C
ref: B3
outputs:
- name: 'pcb_A'
comment: "PCB A"
type: pcb_variant
options:
variant: default[A]
title: 'Hello %V'
- name: 'pcb_B'
comment: "PCB B"
type: pcb_variant
options:
variant: default[B]
title: 'Hello %V'
- name: 'pcb_C'
comment: "PCB C"
type: pcb_variant
options:
variant: default[C]
title: 'Hello %V'
- name: draw_A
type: pcbdraw
options:
variant: default[A]
- name: draw_B
type: pcbdraw
options:
variant: default[B]
- name: draw_C
type: pcbdraw
options:
variant: default[C]