diff --git a/docs/Makefile b/docs/Makefile index 3aab51b0a..8f51b9905 100755 --- a/docs/Makefile +++ b/docs/Makefile @@ -44,6 +44,11 @@ source/configuration/sup_variants.rst: ../kibot/var_*.py ../kibot/config_reader. source/configuration/sup_globals.rst: ../kibot/globals.py ../kibot/config_reader.py ../src/kibot --rst --help-global-options > $@ +source/rotations.rst: ../kibot/misc.py ../kibot/config_reader.py + ../src/kibot --help-list-rotations > $@ + +source/offsets.rst: ../kibot/misc.py ../kibot/config_reader.py + ../src/kibot --help-list-offsets > $@ help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) @@ -51,7 +56,8 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). $(SPHINXTARGETS): Makefile source/configuration/sup_outputs.rst source/dependencies.rst source/usage.txt source/configuration/sup_preflights.rst \ - source/configuration/sup_filters.rst source/configuration/sup_variants.rst source/configuration/sup_globals.rst source/errors.rst + source/configuration/sup_filters.rst source/configuration/sup_variants.rst source/configuration/sup_globals.rst source/errors.rst \ + source/rotations.rst source/offsets.rst @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/source/configuration/sup_filters.rst b/docs/source/configuration/sup_filters.rst index 92edea020..270845a88 100644 --- a/docs/source/configuration/sup_filters.rst +++ b/docs/source/configuration/sup_filters.rst @@ -134,7 +134,7 @@ Supported filters - ``comment`` :index:`: ` [string=''] A comment for documentation purposes. - ``extend`` :index:`: ` [boolean=true] Extends the internal list of rotations with the one provided. Otherwise just use the provided list. - Note that the provided list has more precendence than the internal list. + Note that the provided list has more precedence than the internal list. - ``invert_bottom`` :index:`: ` [boolean=false] Rotation for bottom components is negated, resulting in either: `(- component rot - angle)` or when combined with `negative_bottom`, `(angle - component rot)`. - ``mirror_bottom`` :index:`: ` [boolean=false] The original component rotation for components in the bottom is mirrored before applying diff --git a/docs/source/notes_position.rst b/docs/source/notes_position.rst index 9650b2b50..73067d363 100644 --- a/docs/source/notes_position.rst +++ b/docs/source/notes_position.rst @@ -13,6 +13,10 @@ But some conventions can make them tricky. Some manufacturers, like `JLCPCB `__, uses conventions that are incompatible with KiCad. + +Simple pick and place rotation correction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + The `following blog `__ explains how to adapt the position files generated by KiCad to what @@ -23,6 +27,40 @@ You can achieve the same using KiBot. Here is a configuration example that generates the BoM and position files in the same way JLCKicadTools does: +.. code:: yaml + + kibot: + version: 1 + + import: + - file: JLCPCB + + +The ``JLCPCB`` templates creates files compatible with JLCPB, including adjusts +for the most common components rotations. + +This assumes KiBot can figure out which field was used to indicate the part number +used by LCSC (JLC uses `LCSC `__ as supplier). +If you need to force the field name you can use something like: + +.. code:: yaml + + kibot: + version: 1 + + globals: + # Make it match the name used by your project + field_lcsc_part: LCSC + + import: + - file: JLCPCB + + +This example is very simple, but also very specific for a particular manufacturer. +For this reason we will see how the ``JLCPCB`` template is implemented, so you can +adapt it. A similar result can be obtained using: + + .. code:: yaml kibot: @@ -33,22 +71,15 @@ does: comment: 'Only parts with JLC code' type: generic include_only: - - column: 'LCSC#' + - column: _field_lcsc_part regex: '^C\d+' - variants: - - name: rotated - comment: 'Just a place holder for the rotation filter' - type: kibom - variant: rotated - pre_transform: _rot_footprint - outputs: - name: 'position' comment: "Pick and place file, JLC style" type: position options: - variant: rotated + pre_transform: _rot_footprint_jlcpcb output: '%f_cpl_jlc.%x' format: CSV units: millimeters @@ -81,22 +112,29 @@ does: - field: References name: Designator - Footprint - - field: 'LCSC#' + - field: _field_lcsc_part name: 'LCSC Part #' csv: hide_pcb_info: true hide_stats_info: true quote_all: true -The ``only_jlc_parts`` filter is used to generate the BoM and assumes -you put the JLC component code in a field named ``LCSC#`` (JLC uses -`LCSC `__ as supplier). Note that the author of the -blog simply used ``Field4`` for this and his script searches for any -field containing the ``^C\d+`` pattern. I think this isn’t a good idea -and I suggest using a defined name, like in this example. +The ``only_jlc_parts`` filter is used to generate the BoM. +The special field name ``_field_lcsc_part``is the result of KiBot autodetection. +You can force a value using the global option ``field_lcsc_part``, like in: + +.. code:: yaml + + globals: + # Make it match the name used by your project + field_lcsc_part: LCSC -The ``rotated`` variant is used only to apply the ``_rot_footprint`` -transformation filter. This filter is an internal filter of type +Note that the author of the blog simply used ``Field4`` for this and his script +searches for any field containing the ``^C\d+`` pattern. KiBot can also autodetect +the field name, but I think this isn’t a good idea and I suggest using a defined +name, using the above definition. + +The ``_rot_footprint_jlcpcb`` is an internal filter of type ``rot_footprint``. Here is the same configuration file making explicit use of the rotation filter: @@ -105,31 +143,29 @@ use of the rotation filter: kibot: version: 1 - filters: - - name: fix_rotation - comment: 'Adjust rotation for JLC' - type: rot_footprint + globals: + field_lcsc_part: LCSC + filters: - name: only_jlc_parts comment: 'Only parts with JLC code' type: generic include_only: - - column: 'LCSC#' + - column: _field_lcsc_part regex: '^C\d+' - variants: - - name: rotated - comment: 'Just a place holder for the rotation filter' - type: kibom - variant: rotated - pre_transform: fix_rotation + - name: fix_rotation + comment: 'Adjust rotation for JLC' + type: rot_footprint + negative_bottom: false + mirror_bottom: false outputs: - name: 'position' comment: "Pick and place file, JLC style" type: position options: - variant: rotated + pre_transform: fix_rotation output: '%f_cpl_jlc.%x' format: CSV units: millimeters @@ -162,13 +198,14 @@ use of the rotation filter: - field: References name: Designator - Footprint - - field: 'LCSC#' + - field: _field_lcsc_part name: 'LCSC Part #' csv: hide_pcb_info: true hide_stats_info: true quote_all: true + As you can see we now create a filter named ``fix_rotation`` of type ``rot_footprint``: @@ -177,29 +214,15 @@ As you can see we now create a filter named ``fix_rotation`` of type - name: fix_rotation comment: 'Adjust rotation for JLC' type: rot_footprint + negative_bottom: false + mirror_bottom: false -Using it, instead of the internal filter named ``_rot_footprint``, is +Using it, instead of the internal filter named ``_rot_footprint_jlcpcb``, is the same here. But you can then customize the filter. -The filter supports the following options: - -- ``extend``: [boolean=true] Extends the internal list of rotations - with the one provided. Otherwise just use the provided list. -- ``negative_bottom``: [boolean=true] Rotation for bottom components is - computed via subtraction as ``(component rot - angle)``. Note that - this should be coherent with the ``bottom_negative_x`` of the - position output. -- ``invert_bottom``: [boolean=false] Rotation for bottom components is - negated, resulting in either: ``(- component rot - angle)`` or when - combined with ``negative_bottom``, ``(angle - component rot)``. -- ``rotations``: [list(list(string))] A list of pairs regular - expression/rotation. Components matching the regular expression will - be rotated the indicated angle. Special names ``_top`` and - ``_bottom`` will match all components on that side of the board. - In order to add a new rotation or just change an existing one you just need to use the ``rotations`` option. As an example: the internal list -of rotations rotates QFN packages by 270 degrees, no suppose you want to +of rotations rotates QFN packages by 270 degrees, now suppose you want to rotate them just 90 degrees. The filter will look like this: .. code:: yaml @@ -207,43 +230,138 @@ rotate them just 90 degrees. The filter will look like this: - name: fix_rotation comment: 'Adjust rotation for JLC' type: rot_footprint + negative_bottom: false + mirror_bottom: false rotations: - ["^QFN-", 90.0] This regular expression will match any footprint starting with ``QFN-`` and rotate it 90 degrees. -The internal list of rotations is: - -====================================================== ======== -Footprint Rotation -====================================================== ======== -``^Bosch_LGA-8_2x2.5mm_P0.65mm_ClockwisePinNumbering`` 90.0 -``^R_Array_Convex_`` 90.0 -``^R_Array_Concave_`` 90.0 -``^SOT-223`` 180.0 -``^SOT-23`` 180.0 -``^TSOT-23`` 180.0 -``^SOT-353`` 180.0 -``^QFN-`` 270.0 -``^LQFP-`` 270.0 -``^TQFP-`` 270.0 -``^SOP-(?!18_)`` 270.0 -``^TSSOP-`` 270.0 -``^DFN-`` 270.0 -``^SOIC-`` 270.0 -``^VSSOP-10_`` 270.0 -``^CP_EIA-3216-18_`` 180.0 -``^CP_EIA-3528-15_AVX-H`` 180.0 -``^CP_EIA-3528-21_Kemet-B`` 180.0 -``^CP_Elec_8x10.5`` 180.0 -``^CP_Elec_6.3x7.7`` 180.0 -``^CP_Elec_8x6.7`` 180.0 -``^CP_Elec_8x10`` 180.0 -``^(.*?_\|V)?QFN-(16\|20\|24\|28\|40)(-\|_\|$)`` 270.0 -``^PowerPAK_SO-8_Single`` 270.0 -``^HTSSOP-28-1EP_4.4x9.7mm*`` 270.0 -====================================================== ======== +Note that the order in this list is relevant. The first match will be applied. + +You can also use a customized filter using the internal template, here is an +example: + +.. code:: yaml + + kibot: + version: 1 + + filters: + - name: fix_rotation + comment: 'Adjust rotation for JLC' + type: rot_footprint + negative_bottom: false + mirror_bottom: false + rotations: + - ["^QFN-", 90.0] + + import: + - file: JLCPCB + definitions: + _KIBOT_POS_PRE_TRANSFORM: fix_rotation + + +You can create filters for different assembly houses and generate independent +position files for each manufacturer. The next sections explains more details +related to this. + + +Fixing offsets in position files +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The same mechanism used to change rotations can be applied to offsets in the positions. +You just need to add new offsets to the ``offsets`` option, like in the following example: + +.. code:: yaml + + - name: fix_rotation + comment: 'Adjust rotation for JLC' + type: rot_footprint + negative_bottom: false + mirror_bottom: false + offsets: + - ["^QFN-20", "1,0.5"] + +This will shift the component center of QFN-20 footprints 1 mm in the X axis and 0.5 mm in the Y axis. +The signs of this correction depends on many options, in general they are compatible with the JLCKicadTools tool. + + +Understanding the rotations problem +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The rotation you get in the position file depends on the following factors: + +1. How KiCad footprints are oriented. In general KiCad footprints has their pin 1 at the top left corner. +2. How the manufacturer machine software interprets the angle. KiCad mirrors components on the bottom side, but JLCPCB doesn't (november 2023) +3. How chips are oriented in the tape reel. Some manufacturers even support multiple orientations for the same component. + +This means the problem isn't that simple to solve. The internal database of rotations is just a list of common cases, but can't solve any +problem. In fact you can have two components with the same footprint and different rotations in the same project. + +To solve this problem you can: + +- Provide a list of rotations and offsets using the ``rotations_and_offsets`` option +- Use special fields to specify the rotations and offsets + + +Fine grained rotation and/or offset adjusts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using the configuration file +============================ + +The ``rotations`` and ``offsets`` options of the `rot_footprint` filter can apply adjusts to components based on their footprint. +This covers the most common cases. But if you have two components with the same footprint and different rotation adjusts you can't +solve the problem. Of course you could use different names for the footprints, even when they are the same, just to allow matching +them using different regular expressions. But you can also use the ``rotations_and_offsets`` option. Another case is when you need +to provide adjusts for different manufacturers and the rotations for the same footprint depends on the manufacturer. + +When using the ``rotations_and_offsets`` option you can specify which field is used to match the component. So you can use any +field you want, not just the footprint. This gives you freedom to match components using customized fields. The following example +will adjust U103 rotation by 180 degrees: + +.. code:: yaml + + filters: + - name: fix_rotation + comment: 'Adjust rotation for JLC' + type: rot_footprint + negative_bottom: false + mirror_bottom: false + rotations_and_offsets: + - field: Reference + regex: U103 + angle: 180.0 + + +Note that this rotation will have more precedence than the rotations database. Also note that you can eliminate the rotations +database using the ``extends`` option. So you can create different filters with different mechanisms to adjust the rotations and +offsets for different manufacturers. + +Note that after matching a rule in the ``rotations_and_offsets`` list the values are applied and no farther search is done for +this component. If you need to adjust the rotation, but keep searching for an offset, you can use the ``apply_angle``. +The ``apply_offset`` option is the counterpart for the offset. + + +Using the schematic +=================== + +If you want to have more metadata inside the project you can use fields to specify the rotations and offsets. +The `JLC-Plugin-for-KiCad `__ implements corrections embedding the adjusts +in the schematic fields. You can apply it using KiBot filters. The ``rot_fields`` and ``offset_fields`` options can be used +to specify a list of field names that contains such adjusts. Note that you can create different filters for different +manufacturers specifying different field names. + +The way asjusts are applied is compatible with the `JLC-Plugin-for-KiCad` plugin. If you want to apply adjusts computed like +in the ``rotations_and_offsets``, ``rotations`` and ``offsets`` options just disable the ``bennymeg_mode`` option. Also note +that `JLC-Plugin-for-KiCad` v3.1.0 computes the adjusts for the bottom layer in a way that isn't compatible with JLCPCB, +at least on november 2023. + +Using the default options a rotation filter will look for fields named ``JLCPCB Rotation Offset`` and/or ``JLCRotOffset`` for +rotations and ``JLCPCB Position Offset`` and/or ``JLCPosOffset`` for offsets. The search isn't case sensitive, so using things +like ``jlcrotoffset`` is accepted. .. index:: @@ -273,3 +391,21 @@ Additionally we support: Important: These files doesn’t support manual panelization with repeated reference names, you’ll get the coordinates for just one component because this is a BoM. + + +.. index:: + pair: rotations; supported + +Internal list of rotations +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. include:: rotations.rst + + +.. index:: + pair: offsets; supported + +Internal list of offsets +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. include:: offsets.rst diff --git a/docs/source/rotations.rst b/docs/source/rotations.rst new file mode 100644 index 000000000..3aca2ccb9 --- /dev/null +++ b/docs/source/rotations.rst @@ -0,0 +1,59 @@ +======================================================= ======== +Footprint Rotation +======================================================= ======== +``^(.*?_|V)?QFN-(16|20|24|28|40)(-|_|$)`` 270 +``^BatteryHolder_Keystone_1060_1x2032`` -180 +``^Bosch_LGA-`` 90 +``^CP_EIA-`` 180 +``^CP_Elec_`` 180 +``^C_Elec_`` 180 +``^DFN-`` 270 +``^D_SOT-23`` 180 +``^Diodes_PowerDI3333-8`` 270 +``^ESP32-W`` 270 +``^HTSSOP-`` 270 +``^JST_GH_SM`` 180 +``^JST_PH_S`` 180 +``^LED_WS2812B-2020_PLCC4_2.0x2.0mm`` 90 +``^LED_WS2812B_PLCC4`` 180 +``^LQFP-`` 270 +``^MSOP-`` 270 +``^PUIAudio_SMT_0825_S_4_R*`` 270 +``^PinHeader_2x03_P1\.27mm_Vertical`` 90 +``^PinHeader_2x05_P1\.27mm_Vertical`` 90 +``^PowerPAK_SO-8_Single`` 270 +``^QFN-`` 270 +``^Quectel_L80-R`` 270 +``^RP2040-QFN-56`` 270 +``^R_Array_Concave_`` 90 +``^R_Array_Convex_`` 90 +``^Relay_DPDT_Omron_G6K-2F-Y`` 270 +``^SC-74-6`` 180 +``^SO-`` 270 +``^SOIC-`` 270 +``^SOIC127P798X216-8N`` 270 +``^SOP-(?!(18_|4_))`` 270 +``^SOT-143`` 180 +``^SOT-223`` 180 +``^SOT-23`` 180 +``^SOT-353`` 180 +``^SOT-363`` 180 +``^SOT-89`` 180 +``^SSOP-`` 270 +``^SW_DIP_SPSTx01_Slide_Copal_CHS-01B_W7.62mm_P1.27mm`` -180 +``^SW_SPST_B3`` 90 +``^TDSON-8-1`` 270 +``^TO-277`` 90 +``^TQFP-`` 270 +``^TSOP-6`` 270 +``^TSOT-23`` 180 +``^TSSOP-`` 270 +``^Transformer_Ethernet_Pulse_HX0068ANL`` 270 +``^UDFN-10`` 270 +``^USB_C_Receptacle_HRO_TYPE-C-31-M-12*`` 180 +``^USON-10`` 270 +``^VSON-8_`` 270 +``^VSSOP-10_`` 270 +``^VSSOP-8_`` 180 +``^VSSOP-8_3.0x3.0mm_P0.65mm`` 270 +======================================================= ========