KiCommand discussion and development - Easy pcbnew command line; 4.07 & 5.1.5/.6

Thank you. I’m a little concencend about postfix for non programmers as well. It may be relatively easy to learn for short command strings. My biggest concerns with regular procedural language are:

  • Difficulty of dealing with variables.
  • Difficulty in using/sharing multi line programs, as opposed to single line command strings).
  • If you really want procedural, then Python would be a better choice.

That said, I was also thinking (and in the very first stages, this started out to be) a simplified Python library that others could include. When I get some time, I could certainly convert the functions into a simplified library. Right now, the commands are lambda functions with a mixture of Python built in function calls and custom functions. The biggest hurdle is getting the arguments to be flexible: handling objects, lists of objects, and lists of lists of objects; and the variety of objects that need to be coerced into each other such as string, float, int, string as float/int, string as pcbnew constant.

A simplified library might give the best of both worlds. Simple command string or simplified Python program.

Edit to add: the biggest drawback of Python is the API and navigating the numerous functions and attributes for doing the simplest things like “give me all text”, “give me all vias”, “what is the slope of this line”, “how do I draw a line segment”, “what layers is the object on”, etc. That, I think, is the biggest advantage of KiCommand. You almost have to be a mid-level Python programmer to figure it out. I think with the simplified commands in KiCommand as a base, I’m hopeful I could construct a simplified Python library.

KiCommand updated on github. Added some drawing and geometry commands. Cleaned up the help system. It’s fairly well documented at this point. Be sure to save you work before executing commands. I’ve had a small number of crashes when executing some commands. I’ve cleaned up a few of those.

If anything gives you problems, you can file a bug on github, or comment here. I’ll be unavailable for a week or two.

Enjoy! Let me know how it works for you.

Some more updates on the development version, not yet released. I’ve noticed that no one has tried this out yet, but I’ll continue development for a little while at least. If this becomes useful to you, then let me know!

New commands in development version

rotate (Category: Geometry) 
    [SEGMENTLIST DEGREES] Rotate segments by DEGREES around
    additive center. 
ends (Category: Geometry) 
    Get the end points of the drawsegment (works with segment
    and arc types 
rotatepoints (Category: Geometry) 
    [POINTS CENTER DEGREES] Rotate POINTS around CENTER. POINTS
    can be in multiple formats such as EDA_RECT or a list of one
    or more points. 
remove (Category: Layer) 
    [OBJECTORLIST] remove items from board. Works with any items
    in Modules, Tracks, or Drawings. 
todrawsegments (Category: Layer) 
    [TRACKLIST LAYER] copy tracks in TRACKLIST to drawsegments
    on LAYER. Copies width of each track. 
tocopper (Category: Layer) 
    [DRAWSEGMENTLIST LAYER] put each DRAWSEGMENT on the copper
    LAYER. 
load (Category: Programming) 
    [FILENAME] executes commands from FILENAME. relative to
    ~/kicad/kicommand. Note that this command is not totally
    symmetric with the save command. 
save (Category: Programming) 
    [FILENAME] saves the user dictionary into FILENAME relative
    to ~/kicad/kicommand. Note that this command is not totally
    symmetric with the load command.
1 Like

Latest update pushed to GitHub. Should now work with 4.0.7.

Put file in plugins directory, then go to Scripting Console and enter:

import kicommand

Will show the KiCommand dialog.
Not all commands tested in 4.0.7.

Added scale and grid commands.

scale,grid explain

scale (Category: Draw) 
	[SEGMENTLIST FACTOR] Scale each item in SEGMENTLIST by
	FACTOR, using the midpoint of all segments as the center. 
grid (Category: Draw) 
	[SEGMENTLIST GRID] Move points of SEGMENTLIST to be a
	multiple of GRID. 

Here’s an example. With the existing commands, I created a new command called regularsize:

Usage: SIDELENGTH PARALLELANGLE regularsize

regularsize takes the selected segments, joins them into a regular polygon, then
   sizes the edges to the specified length, and places one of the edges parallel
   to the specified angle

Before:

30 mm 0 regularsize

After:

This works for any number of sides that you draw.

If you are interested, here is the regularsize command that I’ve defined:

You can use the see command and explain command to view details about user defined commands:

'regularsize see

: regularsize drawings selected copy connect copy
regular copy copy length delist stack 4 pick swap /f 
scale copy delist list angle delist 2 pick swap -f rotate
pop pop ; 

A lot of this is parameter manipulation (4 pick, copy, swap, pop) but it shows a little bit of the power of KiCommand. The key commands in the regularsize command are scale, angle and rotate.

'regularsize explain

: regularsize drawings selected copy connect copy regular copy copy length delist stack 4 pick swap /f scale copy delist list angle delist 2 pick swap -f rotate pop pop ; 
drawings (Category: Elements) 
    Get all top-level drawing objects (lines and text) 
selected (Category: Attributes) 
    [objects] Get selected objects 
: copy 0 pick ; 
0 - A literal value (argument) 
pick (Category: Stack) 
    [NUMBER] Copy the value that is NUMBER of objects deep in
    the stack to the top of the stack.
        Examples:
        0 pick - copies the top of the stack.
        1 pick - pushes a copy of the second item from the
    top of the stack onto the top of the stack. 
connect (Category: Action) 
    Using selected lines, connect all vertices to each closest
    one. 
: copy 0 pick ; 
0 - A literal value (argument) 
pick (Category: Stack) 
    [NUMBER] Copy the value that is NUMBER of objects deep in
    the stack to the top of the stack.
        Examples:
        0 pick - copies the top of the stack.
        1 pick - pushes a copy of the second item from the
    top of the stack onto the top of the stack. 
regular (Category: Draw) 
    [SEGMENTLIST] Move/stretch the selected segments into a
    regular polygon (equal length sides, equal angles). 
: copy 0 pick ; 
0 - A literal value (argument) 
pick (Category: Stack) 
    [NUMBER] Copy the value that is NUMBER of objects deep in
    the stack to the top of the stack.
        Examples:
        0 pick - copies the top of the stack.
        1 pick - pushes a copy of the second item from the
    top of the stack onto the top of the stack. 
: copy 0 pick ; 
0 - A literal value (argument) 
pick (Category: Stack) 
    [NUMBER] Copy the value that is NUMBER of objects deep in
    the stack to the top of the stack.
        Examples:
        0 pick - copies the top of the stack.
        1 pick - pushes a copy of the second item from the
    top of the stack onto the top of the stack. 
length (Category: Geometry) 
    [SEGMENTLIST] Get the length of each segment (works with
    segment and arc types 
delist (Category: Conversion) 
    [LIST] Output index 0 of LIST. 
stack (Category: Programming) 
    Output the string representation of the objects on the stack 
4 - A literal value (argument) 
pick (Category: Stack) 
    [NUMBER] Copy the value that is NUMBER of objects deep in
    the stack to the top of the stack.
        Examples:
        0 pick - copies the top of the stack.
        1 pick - pushes a copy of the second item from the
    top of the stack onto the top of the stack. 
swap (Category: Stack) 
    Switches the two top objects on the stack. 
/f (Category: Numeric) 
    [OPERAND1 OPERAND2] Return the the floating point OPERAND1 /
    OPERAND2. 
scale (Category: Draw) 
    [SEGMENTLIST FACTOR] Scale each item in SEGMENTLIST by
    FACTOR, using the midpoint of all segments as the center. 
: copy 0 pick ; 
0 - A literal value (argument) 
pick (Category: Stack) 
    [NUMBER] Copy the value that is NUMBER of objects deep in
    the stack to the top of the stack.
        Examples:
        0 pick - copies the top of the stack.
        1 pick - pushes a copy of the second item from the
    top of the stack onto the top of the stack. 
delist (Category: Conversion) 
    [LIST] Output index 0 of LIST. 
list (Category: Conversion) 
    [OBJECT] Make OBJECT into a list (with only OBJECT in it). 
angle (Category: Geometry) 
    [SEGMENTLIST] Return the angle of each segment in
    SEGMENTLIST. 
delist (Category: Conversion) 
    [LIST] Output index 0 of LIST. 
2 - A literal value (argument) 
pick (Category: Stack) 
    [NUMBER] Copy the value that is NUMBER of objects deep in
    the stack to the top of the stack.
        Examples:
        0 pick - copies the top of the stack.
        1 pick - pushes a copy of the second item from the
    top of the stack onto the top of the stack. 
swap (Category: Stack) 
    Switches the two top objects on the stack. 
-f (Category: Numeric) 
    [OPERAND1 OPERAND2] Return the the floating point OPERAND1 -
    OPERAND2. 
rotate (Category: Geometry) 
    [SEGMENTLIST DEGREES] Rotate segments by DEGREES around
    additive center. 
pop (Category: Stack) 
    Removes the top item on the stack. 
pop (Category: Stack) 
    Removes the top item on the stack.
3 Likes

Another update for overhauling the command definitions. They can (and should) now include categories and help text, which will show up in explain, see, helpcat, and seeall commands.

Defining commands and the details of the user, persist, and command dictionaries is now in the readme.

I’m testing with 4.0.7 stable, but this should also work in nightlies as an ActionPlugin (installation instructions are in the README file).

Please let me know if you have any problems or questions.

Enjoy!!

1 Like

Just stumbled upon your plugin …
Haven’t had the time to test it yet, but certainly will do so soon.
But from what I see here, I already love it!

Thanks,
Herbert

Awesome! Let me know how it goes for you.

Following up on this post where I explain how to put drawsegments commands into a file. Here’s another example:

-5,3,-5,2,-3,-2 mm drawsegments
-4,0,-5,-4,-5,-8,-4,-13,-4,-22,-2,-23,0,-22,0,-12,1,-10,2,-12,2,-22,4,-23,6,-22,6,-13,7,-8,7,-4,6,0 mm drawsegments
7,-10,8,-12,8,-18,9,-19,11,-18,11,-9,12,-7 mm drawsegments
6.5,-10,8,-10,10,-9,12,-7,13,-4,13,2,12,5,9,7 mm drawsegments
6,7,7,6,9,5,9,7,10,10,11,12,13,14,13,16,11,17,7,17,3,15 mm drawsegments
4,13,3,15,1,17,-2,17,-3,16,-4,14,-5,15 mm drawsegments
-1,9,-2,8,-3,8,-4,10,-5,15,-6,19,-8,22,-10,22,-11,21,-10,20,-9,20,-8,18,-8,10,-7,6,-6,4,-5,3,-2,2,-1,2,1,3,2,4 mm drawsegments
1,3,0,1,-2,0,-1,2 mm drawsegments
-2,0,-3,0,-1,-2 mm drawsegments
-8,16,-12,16,-13,15,-12,12,-10,10,-9,8,-8,3,-6.5,4.5 mm drawsegments
-2,11,-2,10,-3,10,-2,11 mm drawsegments
1,11,1,10,2,10,1,11 mm drawsegments 

KiCommand: elephant.txt load
hit F9 then F11
Select all the line elements of the drawing, then
KiCommand: drawings selected 180 rotate

This seems like a great way to keep Edge.Cuts outlines for boxes. I’m working on a way to interleave arcs within the sequence of lines to make it real simple.

The complexity right now is that you have to specify an arc by center, start, and angle. But this isn’t really natural for drawing an outline. There is a method called round which allows you to select two line segments, specify a radius, then round will create an arc with the specified radius that connects the two lines. Works great!

However, for inserting an arc into a series of line segments, it seems best to allow specifying two endpoints and connect them with a curve, where the endpoints are connecting to lines that are tangents of the arc.

For following specifications of cutouts, perhaps the intersection and radius work out well. I just have to figure out what the command strings look like and think about whether it can be improved.

1 Like

New update including fromsvg command.

See this post for an example.

2 Likes

Another fun thing:

Because CERN HQ is in Switzerland, I thought I’d find the rough coordinates for Switzerland’s borders and convert them into a file usable by KiCommand. If you save this into a file and then use the load command:

10.4712361532,46.8713542065,10.4575272152,46.5425001251,10.0513911482,46.5415271538,10.1363911903,46.2306911469,9.94694525824,46.3795820785,9.54486301486,46.3062451194,9.29378226635,46.5008271465,9.03666319477,45.8377731735,8.44500007067,46.2472182483,8.44145419034,46.4620821342,7.85574506735,45.9190541652,7.03805420048,45.9319361446,6.78347316919,46.1547182468,6.73778224139,46.4474910848,6.29555420208,46.3941640755,6.13326328943,46.149782144,5.96700924531,46.2072912201,6.11555417199,46.2615269953,6.12868207642,46.5880540927,6.9716631569,47.2919361484,6.99055429033,47.4972181779,7.38541820631,47.4333271207,7.58827317186,47.5844821721,8.5764180869,47.5913731023,8.40694522432,47.7018001508,8.56291802597,47.80666413,9.56672704172,47.5404542139,9.67034513489,47.3906910614,9.5335732618,47.2745450404,9.4746360771,47.0574540828,9.59863627664,47.0638360639,10.1094450479,46.8502732171,10.3907631769,47.0025641839,10.4712361532,46.8713542065 mm drawsegments delist

you’ll end up with this (I added the KiCad text manually):

Also included three more commands, rotate by 180 degrees, scale by a factor of 20, and round off the corners to 1mm radius.

drawings selected 180 rotate
drawings selected 20 scale
1 mm list drawings selected round

It works well EXCEPT for the few lines that have length less than the rounding radius.

Here’s a closeup of the top where this is a problem (I’ve highlighted the connecting line segment between the arcs):

1 Like

A major version update to KiCommand has been pushed to github.com.

The main additions are the unit tests and command to enable those unit tests. The tests included are equivalent to all of the KiCad python default unit tests.

  • It has been refactored to be a python package.
  • added unit tests equivalent to standard KiCad python tests. Invoke with “import kicommand.test” in the Script Console.
  • added parameters to make using kicommand.run() easier within other python scripts.
  • added ability to manipulate named user stacks (with spush spop, and scopy.
  • newboard creates a new board and puts it on the top of the Board stack. board now puts the top of the Board stack onto the main stack. board command is equivalent to Board scopy.
  • added ability to use different boards than what is in pcbnew UI (loading board from file, or created a new blank board). All commands using a board, now use the “current board” on the top of the Board user stack.
  • added ability to add new empty items such as modules and pads with newadd command, which creates a new empty specified element (such as MODULE or D_PAD) to a specified parent object (board or module, for example).

The new directory structure still works with 4.0.7, but has not specifically been tested with nightly. Please provide feedback on whether it works for you in nightly. It should automatically become available in the Tools > External Tools menu.

1 Like

Updated!

Still having issues with AutoPlugins in nightly. Should still work from Scripting Console and “import kicommand”

Updates::

  • RENAMED todrawsegments to tosegments to better fit nomenclature (see below)

  • Added commands regex, bool, printf, zip, fprintf, pwd, cduser, cdproject, cd

  • Added a couple more tests in kicommand.test

  • modified init.py to update import, user’s should still use “import kicommand”

  • Updated callargs to allow non-lists as input.
    Before: only a list of lists
    Now: A list of lists, a single list, or a single value.
    Before: [objectlist] [[arglist1],[arglist2]] where arglist1 applies to
    object1, arglist2 applies to object2, then arglist1 and 2 are alternated
    for each subsequent object.
    Now: if you only have one argument, or one argument list, it is used as the
    argument(s) for all objects.

SEGMENTS/POLY/POLYGON nomenclature:

“segments” as unconnected line segments (will extend later to nonlines such as arcs or curves) and “poly” as connected line segments.

  • “poly” is a single list of points where each point is a vertex of the joined lines.

  • “segments” are individual and independent x/y value pairs.

  • “polygon(s)” will refer to the upcoming polygon segments in v5/v6

Note that in either case, if a line is supposed to connect to the first point,
that first point (for poly) or segment (for segments) must be repeated at
the end of the list.

regex,bool,printf,zip,fprintf,pwd,cduser,cdproject,cd explain

Explaining regex,bool,printf,zip,fprintf,pwd,cduser,cdproject,cd 
regex (Category: Comparison) 
    [LIST REGEX] Create a LIST of True/False values
    corresponding to whether the values in LIST match the REGEX
    (for use prior to FILTER) 
bool (Category: Conversion) 
    [OBJECT] Return OBJECT as a boolean value or list. OBJECT
    can be a string, a comma separated list of values, a list of
    strings, or list of values. 
printf (Category: Output) 
    [LISTOFLISTS FORMAT] Output each list within LISTOFLISTS
    formatted according to FORMAT in Pythons {} string format
    (https://www.python.org/dev/peps/pep-3101/). 
zip (Category: Stack) 
    [LISTOFLISTS] Creates a list with parallel objects formed by
    each list in LISTOFLISTS ((1,2,3)(4,5,6)(7,8,9)) ->
    ((1,4,7)(2,5,8)(3,6,9)). 
fprintf (Category: Output) 
    [LISTOFLISTS FORMAT FILENAME] Output to FILENAME each list
    within LISTOFLISTS formatted according to FORMAT in Pythons
    {} string format
    (https://www.python.org/dev/peps/pep-3101/). 
pwd (Category: Programming) 
    Return the present working directory. 
cduser (Category: Programming) 
    Change working directory to ~/kicad/kicommand. 
cdproject (Category: Programming) 
    Return the project directory (location of .kicad_pcb file). 
cd (Category: Programming) 
    [PATH] Change working directory to PATH.
1 Like

For those watching this thread, please note that I just updated KiCommand to work with the current (5.1.5)-3 release build.

And of course there’s a new update to KiCommand to fix some additional things. I’ve changed the append command! It now matches the python functionality (adding the item to the list). If the item itself is a list, then it is added as a single item at the end of the list argument. concat now does what append used to do. There’s a whole slew of basic tests to verify KiCommand functionality. Use import kicommand.test in the Scripting Console to run the tests. On my machine, it takes about 3 minutes to execute all the tests.

There is new “SEE ALSO” section for each command help to indicate which commands are similar or that are useful in conjunction with the command.

There is more help when there’s an error, basically listing the real python error and stack trace.

regularsize is fixed. It contained old /f and -f commands which are now just / and -.

Please let me know if you have any suggestions. I’ve found the refobj and newly added valobj very useful. For example, print all modules reference values with modules refobj textfromobj print or only the selected modules with modules selected refobj textfromobj print.

You can work on a command in small steps, use print and stack liberally while testing, then aggregate all the commands into a single user definition (removing the interspersed print and stack commands). Quite useful!

Use helpcat, explain, and see commands to explore what’s available and how things are defined. Many commands are defined by a sequence of other commands. You can build and save your own commands for future use!

I’m interested to find out if people have found KiCommand useful.

1 Like

I edited the thread title

1 Like

KiCommand has been updated again, this time with a few new commands and even more tests. The tests help find bugs, and serve as examples of usage for KiCommand commands. They also can verify a proper installation and can find minor problems with different versions of KiCAD. Please report any failing tests along with the error messages found.

If you find an error that isn’t revealed in any current tests. Please let me know and I can fix it and add a new test.

The new Tutorial is going smoothly. It will walk you through the basics of KiCommand like how to use the stack, and basic calculations. Start there if you’re new to KiCommand!

Still to come are instructions on how to find and manipulate pcb elements. There is some information there, but it’s not fully organized yet. Stay tuned!

2 Likes

Added some new commands and fixed a nasty bug in the not command. So simple, it seemed like it didn’t need testing. I was wrong. Everyone should download the latest version.

I really want to reiterate that if you’ve been wondering what KiCommand can do, you should really walk through the Tutorial. There, you’ll learn the very basics of KiCommand. There’s a little bit about querying pcb components and using the filter command.

There’s definitely more to come.

Seeking help in testing! Does anyone have time to test KiCommand with either the nightly builds or earlier 4.x releases of KiCAD? There are pretty extensive tests now in KiCommand. It just requires three steps:

  1. Copy the kicommand folder into the appropriate plugins folder.
  2. Possibly create a user-level kicommand folder. This is a non-standard folder that holds user-created commands.
  3. From the Script Console, run import kicommand.test

Hopefully, there will be a wide variety of conditions tested: operating systems (Mac, Windows, and Linux), python version (2.x and 3.x), and KiCAD version.s (4.x and 5.x). Another variable might be the wx library version.

Please list here the KiCAD “About” information as well as the KiCommand commit number (such as “ 1be79a27”).

I’ll summarize the results on the KiCommand wiki page.

I’m working through a tutorial on drawing KiCAD elements using KiCommand,

Polygons are relatively new to KiCAD: they were introduced after KiCommand got started. The drawpoly command and drawsegments command are currently synonymous. I’m thinking of changing drawpoly to actually draw a KiCAD polygon element.

Would anyone have an issue if the drawpoly command changed so that it instead created a proper POLYGON KiCAD element?