Nothing beats a scripting engine when it comes time to customize and psypnp provides both cool scripts to use with OpenPnP right away, and a set of python modules to make creating your own really easy.
The project is split into two parts:
- a set of scripts that automate away a lot of the drudgery of configuring the pick & place and give you nice control over the machine; and
- a library of modules that the scripts use to do their thing and that you can use when writing your own to take care of annoying details, like getting user input or saving some data for use later on.
At the time of writing, the scripts are split into sub-directories to provide various functions
The zzz_repl script is awesome if you’re looking into OpenPnP scripting, debugging your own code, or just to make a quick programmatic change to the OpenPnP internals.
To use this, make sure you start up OpenPnP from some terminal (i.e. the command line), make sure debugging is on at some high level (e.g. TRACE) in the Log panel, and then launch the script.
OpenPnP will get a bit frozen, but that’s ok: back in that terminal you can now type python. Enter “machine” or “2+2” and you’ll see that you are running a Python REPL.
To get out, hit CTRL+D (under Linux, dunno how it works elsewhere), and OpenPnP will come back to life.
There’s a lot of talk about this in the second video of the Python Scripting Deep Dive series. It’s worth checking out, because in addition to
project: high level view
Project scripts deal with high level management of projects. I’m working on an auto-configuration (BOM -> feeder setup) script which will be included shortly.
This directory does already include a generate_map which creates an SVG image of your configured feed setup:
You will need to also install a compatible version of the SVGWrite library. Put the stuff in there next to the psypnp directory in …whatever…./lib/.
go: move the nozzle
Under go/ you’ll find simple ways to move the machine, that are smart enough to avoid making the mistake of triggering motion before the machine is homed.
- home: (0,0) sweet (0,0)
- noz_absolute: move the nozzle to some absolute set of coordinates
- noz_relative: move the nozzle by some amount, from where it’s sitting
- nozzle_to_bottomcam: woosh the nozzle over to where you’ve configure the bottom view camera
- set_rotation: precisely set the rotation of the nozzle
- z_absolute: lower the nozzle to some height (note that with openpnp 0 is top and anything negative is downward)
config: play with the setup
Scripts in config let you manage and verify various elements of machine setup. For example:
- feeders_check_height: will allow you to move the nozzle to exactly where it expects to go for a pick, one feeder at a time, to verify the entire setup before starting a run
- feeders_level: useful with feeders that have all the same level for their component (top), sets the configured Z for each matching feeder to some value taking into account the height set for each assigned part package. This is great with things like 3d printed holders.
- bottompipe_clone*: copies the pipeline for bottom vision from some template component to batches of others
When doing setup, I’m often moving from one side of my feeder to the other (e.g. to verify the label I stuck on the other side) and the feeder/ scripts (like crosssmall_feeder_left) allow me to do so in one click and then come back to my original spot in another.
The length traveled is configurable (using the set_crosssmall_distance) and will be remembered in non-volatile storage between runs of these scripts.
Though my scripts are useful, they won’t deal with every situation. If you have the coder bent they can be a great intro to using the features of the psypnp library of python modules.
The Python REPL terminal, described above, will be your best friend when working on OpenPnP scripts, but coming in close second are the modules included here.
To use the library
Getting access to the modules, which we don’t want polluting the Scripts menu and are therefore outside of the normal search path, requires the use of some boilerplate code to extend the PYTHONPATH in the Jython interpreter. Open up any one of the included scripts and paste the BOILERPLATE section there in the top.
The nv (non-volatile) module lets you stash data (either single values or a whole dict()) into permanent storage for use during later runs.
A single file holds all the values for all the scripts (just a python pickle). Each script selects some main “key” in the common dictionary, under which it gets its own dict() to do with what it pleases.
The simplest way to use this is with the NVStorage object. Simply:
mystore = psypnp.nv.NVStorage('scriptname') if mystore.some_value is None: # never set mystore.some_value = 42 # default, now stored if mystore.name == 'Bob': # didn't even check if it exists, # it'll be None if it didn't print("Hi, bob") mystore.name = 'Bob rox' # now stored
It has some extra options (like suspending autosave of assignments) that you can learn about within the module source.
Otherwise, you can use the various functions directly in the nv module, like get_subvalue/set_subvalue:
lgth = nv.get_subvalue('scriptname', 'length', 20) # defaults to 20 if never set wdth = nv.get_subvalue('scriptname', 'width') if wdth is None: # was never set ui.showError("Not good!")
The UI module is, evidently, related to interacting with the user. It’s just a wrapper around what already is supported by OpenPnP but makes things easy.
psypnp.ui.showMessage("something to say")
just pops up a message for the user, and
does what it says on the box.
astr = psypnp.ui.getUserInput("string please", "some default") anint = psypnp.ui.getUserInputInt("number", 42) # and aflt = psypnp.ui.getUserInputFloat("floaty", 3.14)
Show a popup with some text and an input field. The getUserInput() will return None if the user cancels. They all have a second (optional) argument for something to set as the default value.
There are also functions to easily get confirmation or a choice from a list of options.
if psypnp.ui.getConfirmation("Sure?", "Do you want to play a game?"): # we are go pass
or you can set your own list of options:
options = ['Abort', 'Go Anyway', 'I dunno'] val = psypnp.ui.getOption("Not Homed Yet", "Not homed! What should we do?", options, options) if val == 1: # wants to go anyway... pass
The repl module is where the repetitive magic of the zzz_repl script happens.
You can use it directly in your own scripts, all you basically need is to call runInterpreter() but it’s more interesting if you do something like:
import psypnp.repl # get some standard helpers and stuff v = psypnp.repl.getStandardEnvVars() # add your own things of interest v['myobj'] = SomeClassImTesting('testo2') # now myobj will be instantiated and in the REPL shell # run it and start hacking psypnp.repl.runInterpreter(v)
There are lots of modules to explore and play with. The most interesting at the moment may be:
- psypnp.util with functions like should_proceed_with_motion() to check everything is safe before moving and ask the user when not certain
- psypnp.search with functions to search for parts and feeders by name, by part or package
- psypnp.csv_file with wrappers for standard CSV imports with helpers to aid in processing the various entries
Getting psypnp and Going Further
I hope you find the scripts and modules useful.
If you make anything interesting with this, please let me know. Do the same if there’s anything specific you’d like to see in the future.