Version 6 of the program is based on the concept of industrial automation where autonomous workcells are arranged in a
production line with pallets are used to convey workpieces from one workcell to another. The pallets hold both the
workpiece and a wireless module containing information about the workpiece. The pallet is passed to the workcell which
reads the wireless module and then performs the required task, if any, on the workpiece, writes to the wireless module
and then passes the pallet to the next workcell.
There is no other interaction between the workcells other than having a big green button to start and a big red button
to stop. The workcells run completely asynchronously except for pallet transfer between workcells.
Because the application is intensely graphical, the workcells are emulated using tkinter frames. The frames have their
own event loops so the workcell can run independently. Communication between workcells is done by signal passing. Two
types of signals are used, request, when the sending workcell knows the recipient workcell name in advance, and status
when the sending workcell doesn't know the recipients in advance.
The signal itself is an object containing a string workcell name for the signal receiver, a string trigger and an
optional payload object. Depending on the internal state of the workcell, it will associate a trigger with a particular
method or ignore it. The use of the optional payload is also dependent on the internal state of the workcell.
A Hub object is used synchronize signal passing between workcells. Each workcell name must be unique and this is
guaranteed by having each workcell register with the Hub. Each workcell also passes a reference to its transfer method
to the Hub. This is the only public method of the workcell and there are no public variables.
All workcells, except for the Hub, inherit from a transceiver class which encapsulates all the communication functions.
The signal trigger must be unique so it is made by concatenating a workcell name with a tag. For a request message,
because the receiver name is known, the receiver name is concatenated to the tag. For a status message where only the
sender name is known, the sender name is concatenated to the tag. Because the workcell names are guaranteed to be
unique, the resulting trigger will also be unique. The transceiver class handles the concatenation and only the tag and
signal type needs to be passed to it.
Because status signal senders cannot know their receiver names in advance, the receivers have to subscribe to the
sending workcell to receive status messages. When the receiving workcell is instantiated it may subscribe to a sending
workcell that hasn't been instantiated. When this happens, the Hub will register the sending workcell name and save the
subscription requests. When the sending workcell is finally instantiated, the subscription requests will be sent to it.
The Hub inherits from tkinter's Frame object to take advantage of its event loop. This is preferred to using the
threading module because functions must be run atomically. By using the Frame's 'after' method, it's possible to
guarantee that one function has completed before another can be called. After the function has completed, the after
method is called to schedule the next event loop queue read.
Tkinter widgets call functions directly which may cause race conditions and is not very flexible. To ameliorate this, a
special Requestify class is used to return a function reference for a tkinter's widget command option. A Requistify
instance will be passed a workcell name, tag and optional payload and will supply a function reference for the tkinter
widget's command parameter. When the tkinter widget executes the command function, a status signal will be issued using
the given workcell name and tag. The workcell with the same name as that passed to the Requestify object will see the
signal as a request while other workcells will see a status signal.
A major advantage of this method is that the tkinter hierarchy becomes flat. Any workcell can communicate with any other
workcell regardless of its place in the tkinter hierarchy because there are no direct function calls. Also, the response
of any workcell to any widget events can be easily changed at any time.
To implement the big green, and big red buttons, the Hub provides a broadcast method. Any workcell can broadcast a
signal with a tag which the Hub will send as request signals to all registered workcells. The Hub itself is a workcell
and it can be stopped by broadcasting a 'Shutdown' tag by any other workcell. Other workcells can also use the shutdown
request for initiating their own shutdown procedures.