Adding Height to the *.pos file

I have a question about adding height information of components to the *.pos file.
Has this been done, can it be done or am I barking up a dead tree?
I have search the forums but none specifically address this issue.
I understand that it is not in the standard file formatting for the pick and place.

What do you want to do with this height information?

The “normal” way is to add 3D models to your PCB and then export the whole PCB to a mechanical CAD program. Just a single number for height is not enough to encode at which location the parts have that height.

If this height is only for the P&P machine. I guess those machines normally have a table internally which knows how high each part is, and also which nozzle to use for footprints and such.

This is the height for a specific P&P machine, so we do not have to add each type of component.
Some what of a pain.

1 Like

I just created such a pos file (my first) and it’s a fairly simple format. It has the footprint and value names and X and Y coordinates. Hacking in an Z value should be fairly easy. For a one off a text editor or spreadsheet will do. For more automation writing a script would be more logical. This would probably also include a list of footprint names with matching heights.

Writing your own exporter is also an option. Maybe you can adopt one of the old BOM scripts for this. When the script runs from inside KiCad, you can first attach Z-heights as extra fields to your footprints.

Because this looks like an unusual custom feature, the chance someone else will do it (or implement it in KiCad itself) would be slim.

That is what I kind of figured that this is a one off, custom feature, slim to none somebody else has done… :frowning: …
I was hoping for some auto feature/ sw switch/button… Oh well…

I could hack from the schematic BOM *.csv file if I have that feature in the schematic symbol libraries…

Where is KiCad going to get the height information from for each of your components ? it would be down to you to add it anyway.

Is the generation of the *.pos file hardcoded somewhere or is it script-based?

Looking for a way to customize the output to satisfy my PnP machine’s shitty software, but I’m not particularly Python savvy. Hacking an existing script to my needs is do-able, writing one from scratch not so much.

Asking here because it seems an existing script would benefit the OP as well.

What can you do with the height information on components anyway? I imported a whole bunch of stuff from my CADSTAR library and they all came with a “height” field and value. But that’s useless in V8 KiCad because the rule area tool doesn’t include checking for component heights. This is pretty annoying and I’ll bet someone has already made a feature request. Also it’s a LOT easier for the PCB tool to grok the height info directly from the footprints on the board rather than having to plow through STEP files for every part. The “height” field is really just a first order check for placement. Let the mechanical folks deal with the STEP files after you do a 3D export. Another thing, not all components have a 3D STEP file readily available, but it’s a trivial matter to add the height value to
every footprint as a field parameter.

As far as I know there is no standard for the CPL (POS) file, each assembly house seems to use their own syntax. But usually they are just transpositions of the columns and maybe some massaging of the values. So it shouldn’t be an issue for you to add an extra column to suit your machine.

Which, of course, makes it all the more worthwhile to have the ability to customize it.

We have a small PnP machine here that needs its own format and I like to provide our assembly house with the format they require. Now, of course I can do this by fiddling around in Calc, but that is tedious and error-prone, so I would much prefer an automated method.

Python has a module for handling CSV data. Shuffling columns is trivial.

I agree the *.pos file is a pseudo standard and every P&P system is slightly different.
In my setup, I have always installed the step file in the footprints.
I can also add a parameter in the schematic symbol and/or the footprint with a “Height” parameter.
So the information could be available in various areas for easy pull of information while creating the *.pos file.

I agree that each P&P will have to fiddle with the *.pos file to their specific P&P system. But if all of the information is in one file it can easily be manipulated for their purpose, moved/ deleted, etc.

Change the line with to somewhere you like “c:\temp\mypos.csv”. Place in plugins folder and refresh kicad with Tools → External Plugins → Refresh Plugins

import pcbnew
from pcbnew import ToMM
import csv



class ExportPos( pcbnew.ActionPlugin ):
    def defaults( self ):
        self.name = "Custom POS File"
        self.category = "Modify PCB"
        self.description = "Export custom *.pos format"

    def Run( self ):
        pcb = pcbnew.GetBoard()
        with open("c:\\temp\\mypos.csv", "w", newline="") as f:
            writer = csv.writer(f)
            for fp in pcb.GetFootprints():
                Ref = fp.GetReference()
                Val = fp.GetValue()
                Package = fp.GetFieldByName("Footprint").GetText().split(":")[-1]
                (PosX, PosY) = ToMM(fp.GetPosition())
                Rot = fp.GetOrientationDegrees()
                
                Height = "NOT SET"
                try:
                    Height = fp.GetFieldByName("Height").GetText()
                except AttributeError:
                    pass
                    
                Side = "top" if fp.GetSide() == 0 else "bottom"
                
                writer.writerow([Ref, Val, Package, PosX, PosY, Rot, Height, Side])
                
ExportPos().register()

Anybody know how i can get the project directory in a python script?

ok, sorry I am not a programmer. :frowning: just a lowly HW engineer…
How do I make this script into a working python program/file?
I have the KICAD directory “C:\Program Files\KiCad\8.0\share\kicad\scripting\plugins” but it seems as if I need more than to copy the above script into a *.csv file…
To my knowledge a .csv file is for excel, etc not python ".py".
Yes, go ahead and flame if needed. :slight_smile:

@BlackCoffee

Yeah no, this is a kicad plugin if you launch a script inside kicad it does not know anything useful when querried with vanilla python API, it will just report about where python or kicad. Not really useful. I need kicad to tell what the project directory is.

yeah well what file do i reference? How do i find it. there’s a billion files on disk.

so no cwd, does not point to anything other then python install dir/kicad install (depending on os)

hard coded works i off course did that already but that’s just stupid if you run the script on another project you just overwrote the file.

@kdeckstein

put the code in a py file in the kicad plug directory then change the line saying
with open("c:\\temp\\mypos.csv", "w", newline="") as f: so that it points to where you want things dumped.

Err no i tested both and they dont work, atleast on my OS. They would work fine if this was a OS level script launched form a command line but it is not… But yeah super useful

os.getcwd()
'C:\\Program Files\KiCAD\\8.0'

That is useful!

Never mind i can get the board filename with

board.GetFileName()

And parse the part form there.

Yes obviously they work in context that knows where you are. So yes i can get where by script is obviously. But I Dont want to do know that. Its pretty clear i want to know what the current open kicad project directory For the kicad project currently loaded is. Both of your screenshots point to plugin directory of the script.

But if a user wants to export something it would be bonkers to get it into the directory where plugins are. But rather you need where the board is. *

I did not ask how to use python but rather how to use kicads autogenerated api to get the location where the project is none of python standard commands can give me that. They can help me parse it when i get it though.

* even that isnt optimal, if user has some wierd ideas on how to use board files.

Use this script instead. then you dont really need to change the hardcoded folder name. put in a .py file on in your plugin dir and refresh the plugins then just run the script from tools → external plugins

import pcbnew
from pcbnew import ToMM
import csv
import os



class ExportPos( pcbnew.ActionPlugin ):
    def defaults( self ):
        self.name = "Custom POS File"
        self.category = "Modify PCB"
        self.description = "Export custom *.pos format"

    def Run( self ):
        pcb = pcbnew.GetBoard()
        
        path =  os.path.join(os.path.dirname(str(pcb.GetFileName())),"custompos.csv")
        with open(path, "w", newline="") as f:
            writer = csv.writer(f)
            for fp in pcb.GetFootprints():
                Ref = fp.GetReference()
                Val = fp.GetValue()
                Package = fp.GetFieldByName("Footprint").GetText().split(":")[-1]
                (PosX, PosY) = ToMM(fp.GetPosition())
                Rot = fp.GetOrientationDegrees()
                
                Height = "NOT SET"
                try:
                    Height = fp.GetFieldByName("Height").GetText()
                except AttributeError:
                    pass
                    
                Side = "top" if fp.GetSide() == 0 else "bottom"
                
                writer.writerow([Ref, Val, Package, PosX, PosY, Rot, Height, Side])
                
ExportPos().register()

Running creates a file custompos.csv in your project directory.

Anyway this is more of scaffold for you changing it to work like you want

Well given that all inbuilt tools default to the project directory this does not remove the need of fetching current project directory.

You used the OS… good for you.

Yes, but i did not ask how to assemble the file path. I have written a million lines* of python im pretty familiar with the standard library thank you. I asked how to get the path for the project the answer could have been:

board.GetFileName()

not:

os.path.dirname(os.path.abspath(file))

Since i didnt know how to get file. Newertheless the board.GetFileName()
isnt entirely optimal (since you might have multiple board files open) it would be better if there was a command pcbnew.GetProjectFolder() for reasons mentioned even where you ought to start your file browser.

Not going to do any gui progtamming because its not relevant to the task of knowing how to dump data to a file. Knowing how to find a reasonable location is.

* Apparently not quite a million. Only about 750,000. Though most of that is python 2.