Random Ramblings on LabVIEW Design

Community Browser
Labels
cancel
Showing results for 
Search instead for 
Did you mean: 

Re: Parsing State Machines: An Iterative Design Process

swatts
Active Participant

Joerg Hampel is a guest blogger. As the owner of Hampel Software Engineering, a CLA and LabVIEW Champion, his professional interest lies in team development best practices.

 

G’day my marvellous mates (me speaking in the beloved non-comprehensible Steve Watts way)!

 

Last year, one of our customer projects called for a proper state machine for sequencing the actions and events in a test system. A robot, a PLC, a DAQ device and the operator play the most important parts in that system. Inspired by one of Steve’s recent ramblings and a previous heated discussion with another customer on how to integrate state machine logic into a DQMH module, I decided to set out and create a reference design for an HSE State Machine.

The Design

Steve was generous enough to share SSDC’s rock-solid state machine design with us. It basically advocates the use of states while the system is doing something, and transitions for leaving and changing between states.

 

Basic stateBasic state

Basic state

 

The screenshot shows a regular state with a VI waiting indefinitely (i.e. without timeout) for transitions to be sent from outside the state machine, and then decide on a per-state basis how to react to any given transition sent to the state machine.

 

SSDC uses queues for most of their communication needs, and also for sending transitions to their state machines. Seeing as DQMH uses events for communicating with or from a module, I did not want to introduce another mechanism which would potentially confuse team members and other users of our open-sourced code. After lots of discussion with Steve weighing the pros and cons, I decided to go with events.

 

Deviating further from the Original SSDC School of Pure State Machinery, I want our reference design to not only react to externally (i.e. explicitly) triggered transitions, but also be able to react implicitly to changing conditions in the system.

 

Polling state: Waiting while required system state is not reachedPolling state: Waiting while required system state is not reached

Polling state: Waiting while required system state is not reached

 

The screenshot shows a polling state that waits for a certain boolean value (which is acquired somewhere else) to turn from False to True. While it’s waiting, other transitions are evaluated periodically. If no transition is received, the case structure is left but the state doesn’t change, so the same case is entered again.

 

Polling state: Reacting to the expected system state change implicitlyPolling state: Reacting to the expected system state change implicitly

Polling state: Reacting to the expected system state change implicitly

 

When the required system change eventually happens, the transition from the current state to the next (that’s “Waiting for Radiator Ramp-Up” to “Waiting for Radiator Settling” in the example screenshot) happens implicitly, i.e. without triggering it from outside the state machine.

 

The reasoning behind this design decision is that evaluating a given system status inside the state machine gives context to the evaluation. If I need to debug the system, I will know immediately where to look for the logic.

 

Steve: “There's certainly no rule that says a shared transition scheme per state is required, I reckon that is acceptable from a design perspective (might cause some navigation issues if you're firing transitions outside of the state). So a minor cohesion hit, but with a simplicity benefit”

 

The Documentation

For a number of reasons, the only documentation in our projects that we can expect to be up-to-date and complete is the actual code itself. While that may or may not be sufficient for maintaining and expanding software, we still need to produce human-readable (i.e. readable without opening the IDE) information about the code. Some customers require this so they can file it. Others are interested in the current state of the project from time to time. For the real meat in this, though, read on…

 

So in order to satisfy the need for that human-readable documentation of our state machine, why not look into generating a state diagram programmatically from the LabVIEW code? With a bit of VI scripting - and a lot of trial and error - I was able to come up with a program that parses a VI for a case structure with a given label, and then drills down and identifies all the states, transitions and their interdependencies. These are then expressed in PlantUML, an awesome open-source tool that allows the generation of UML diagrams from a plain text language (many thanks to Benjamin Hinrichs for pointing me to PlantUML in the first place).

 

Excerpt of a programmatically generated PlantUML state diagramExcerpt of a programmatically generated PlantUML state diagram

Excerpt of a programmatically generated PlantUML state diagram

 

Big outlined arrows represent explicit transitions (i.e. transitions that are triggered somewhere outside the state machine), small filled arrows visualize implicit transitions that result from polling states, and polling transitions (i.e re-entering the same state over and over again) are visualised with dashed lines.

 

While implementing the parser, I already stumbled over a few flaws both in the design and the execution of my state machine code. 

 

For example, the polling case structure had the boolean value of the polling condition wired directly. It turned out that having an enum with readable values (“Check transitions…” and “Leave this state!” is what I settled on) instead of true and false is beneficial both to the readability of the code and to the automated parsing of it.

 

There were a few other places where I had to settle on a unified way of implementing things, define some extra labels and make them visible, and so on.

Circling back from Documentation to Design

What I didn’t expect, though, was the immediate impact that looking at the generated diagram had: An impact on visualising and understanding the state machine I was working on, and an impact on identifying flaws in both the naming and the sequencing of states and transitions.

 

Example of misleading combination/use of transitionsExample of misleading combination/use of transitions

Example of misleading combination/use of transitions

 

Image6.png

Example of questionable reuse of transitions

 

Having these diagrams readily available when discussing different design decisions makes it so much easier to explain the ideas and the theory behind each decision. One recent example is the question of whether to have different dedicated transitions instead of a fewer number of transitions but with parameters (the answer: yes!).

 

Steve: “That's really useful from a design perspective too. The cycle of looking at a diagram and seeing design issues is not something I've considered.”

 

It’s easy to see how this kind of documentation complements our design reviews, especially as it comes with very little effort due to the programmatic approach. And as we usually go through an iterative design process, both internally and with our customers, having up-to-date state diagrams handy without having to put in the work? That’s priceless!

Automation

Seeing as we already make extended use of server-side automation - aka continuous integration - our Release Automation Tools now generate not only documentation of our libraries and DQMH modules (go take a look at Wovalab’s Doc-Generator) but also of all our state machines. For all our internal and external projects. All fully automated on our build servers.

 

Where can I get that??

If I did my job right, you must be craving some automated documentation for yourself now. The way I see it, there are two options for you:

 

1. Visit rat.hampel-soft.com for more information on our ready-made tools

 

2. Take part in one of our DSH Pragmatic Software Development Workshops and start learning about this - and much more. Planning on coming to you in 2020 (Albuquerque, NM), NIWeek (Austin, TX), GDevConNA (Denver, CO), GDevCon (CERN), and eventually NIDays (Munich, Germany). Tickets will be available as soon as we know what's going on with the world.

 

Until then, keep on wirin’!

 

Love,

J.

Steve


Opportunity to learn from experienced developers / entrepeneurs (Fab,Joerg and Brian amongst them):
DSH Pragmatic Software Development Workshop


Random Ramblings Index
My Profile

Comments
FabiolaDelaCueva
Active Participant

Excellent article Joerg, thanks to Steve for letting you share your wisdom through his blog.

 

I will look in more detail to the code tomorrow, I couldn't find the event structure at a glance. My first concern with state machines is making sure first that I can abort it. This is why, at Delacor, we recommend the non-standard approach of executing the state machine within the timeout case of the event structure.

 

See tip 4 at https://delacor.com/tips-and-tricks-for-a-successful-dqmh-based-project/ 

 

On semi related note,  have  you checked out the old  State Diagram Toolkit?

http://sine.ni.com/nips/cds/view/p/lang/en/nid/215729

 

Edit: adding a picture before some one thinks I am talking about the State Chart (which I didn't like at all)

State Diagram for a Cat.jpg

Figure 7.7 shows the LabVIEW code generated and maintained via the State Diagram Editor
Page 499 of #LabVIEW Graphical Programming 5th edition

 

Regards,  

Fab

 

PS: wash your hands and don't touch your face!

For an opportunity to learn from experienced developers / entrepeneurs (Steve, Joerg, and Brian amongst them):
Check out DSH Pragmatic Software Development Workshop!

DQMH Lead Architect * DQMH Trusted Advisor * Certified LabVIEW Architect * Certified LabVIEW Embedded Developer * Certified Professional Instructor * LabVIEW Champion * Code Janitor

Have you been nice to future you?
joerg.hampel
Active Participant

I will look in more detail to the code tomorrow, I couldn't find the event structure at a glance. My first concern with state machines is making sure first that I can abort it.


SSDC's state machine works with queues, so there are no event structures in the original template. Each case of the state machine has its own "timeout-or-no-timeout" definition, depending on whether a timeout is wired to the dequeue VI.

 

Seeing as I replaced queues with user events, the "Wait for Transition.vi" that used to dequeue transitions is now processing user events instead, so that's where the event structure now lives.

 

For non-polling states, there is no timeout wired to the "Wait for Transition" VI. In order to exit, the correct transition needs to be sent:

cust-sm-design-01.png

 

For polling states, the timeout case is the default, which is used to stay in the current state:

cust-sm-design-02.png

I find this to be quite elegant. While it may be a lot of work to add a new transition to many states, the architecture makes it easy to have very granular control over the per-state transitions.




DSH Pragmatic Software Development Workshops (Fab, Steve, Brian and me)
Release Automation Tools for LabVIEW (CI/CD integration with LabVIEW)
HSE Discord Server (Discuss our free and commercial tools and services)
DQMH® (The Future of Team-Based LabVIEW Development)


FabiolaDelaCueva
Active Participant

Excellent Joerg!

 

No wonder I couldn't find the event structure!

 

Here is a picture of our State Machine for DQMH:

FabiolaDelaCueva_0-1584367243129.png

 

And the video showing how we made it that I mentioned above for tip 4 at https://delacor.com/tips-and-tricks-for-a-successful-dqmh-based-project/%C2%A0

 

Is here:

With all the extra time we have now, I will add to my list of projects to explore, how to make the above state machine work more like Steve's.

 

Thanks again for sharing,

Fab

For an opportunity to learn from experienced developers / entrepeneurs (Steve, Joerg, and Brian amongst them):
Check out DSH Pragmatic Software Development Workshop!

DQMH Lead Architect * DQMH Trusted Advisor * Certified LabVIEW Architect * Certified LabVIEW Embedded Developer * Certified Professional Instructor * LabVIEW Champion * Code Janitor

Have you been nice to future you?
Villar
Member

Since I started using the DQMH framework, I always needed to be monitoring events or triggers coming from sensors, PLCs or as you mention from the user. First I used an additional whileloop in the Main VI, in which I always asked for the status of external digital signals or sensors, I did not use the event structure inside with the timeout event, I remember that I had scanning problems using event structure with timeout at zero or a small value, for some reason I think that the whileloop with a wait or wait until the next multiple runs faster, by the way I'm talking about LabVIEW running on PC.

Another alternative that I started using with DQMH, is to create a dedicated module for monitoring and controlling digital signals. In this module I create a child class of Delacor QMH_Message Queue and modify Delacor_lib_QMH_Dequeue Message VI, here I force it to always enter a state of waiting for an event.

 

 

Villar_0-1584437402017.png

 

Regards

 

Jesus Villar

 

FabiolaDelaCueva
Active Participant

Jesús, 

 

If you could post that on the DQMH forum, we could discuss alternatives and get to the bottom of why the timeout case in the event structure was not working for you. We have used it without issues.

 

Great use of the option we give people to create their own DQMH Queue! I am glad it is working for you and it is not wrong. For anyone who comes to this blog post and decides to do something similar, I do recommend that you keep in mind our reasoning for not providing the timeout input. We described it in the block diagram of the Delacor QMH Dequeue Message VI, where it states:

 

"Note that the Dequeue Element function does not have a timeout wired. In an event-drive framework like the Delacor QMH, generating messages with events is preferable to polling for a "no message" situation."

 

Thanks for sharing your approach,

Fab

For an opportunity to learn from experienced developers / entrepeneurs (Steve, Joerg, and Brian amongst them):
Check out DSH Pragmatic Software Development Workshop!

DQMH Lead Architect * DQMH Trusted Advisor * Certified LabVIEW Architect * Certified LabVIEW Embedded Developer * Certified Professional Instructor * LabVIEW Champion * Code Janitor

Have you been nice to future you?
Villar
Member

Fab

Sorry I think you might have misunderstood what I wrote this is what I meant

 

(Fabiola, problamente no explique bien mi punto de vista, no estoy diciendo que la estructura de eventos no me haya trabajado con DQMH. Estoy de acuerdo que la mejor forma de pasar eventos es por dynamic events o user events. Pero en el pasado tuve problemas con el escaneo de hardware NI DIO (ejemplo: NI 6514, 6515,6528,6527) para detectar señales externas digitales, cuando tenía un estado "Idle " con una estructura de eventos con un timeout y pedía la lectura de de las lineas digitales NI Daqmx. Por alguna razon nadamas quitaba la estructura de eventos y la lectura era más rapida.  Todas estas tarjetas mencionadas, son de escaneo por software y no por hardware).

 

event time out.PNG

 

Para no perder el enfoque DQMH framework de trabajar por modulos, empeze a crear un módulo dedicado al monitoreo de DIO.

 

En este módulo, solo cambio el Dequeue Element VI, el contenido es el mismo, pero agrego la función de preguntar por elementos en la cola, de lo contrario conecto mi estado directamente al mensaje para que entre al case en el Message Handling Loop, donde monitoreo las senales digitales externas, pero no estoy metiendo el mensaje a la cola, simplemente una constante hacia el case, de esta manera siempre estoy listo para recibir el evento dinamico. Probablemente no es lo mas correcto, pero me ha funcionado.

 

Fabiola como hemos platicado, yo estoy utilizando DQMH framework para desarrollar mis proyectos y estoy muy satisfecho con él.

 

Te mande un link para compartirte el código

 

Gracias por tus comentarios

swatts
Active Participant

Jesús, 

You get a Kudos for being my first non-English comment. It makes me very happy. 

Steve


Opportunity to learn from experienced developers / entrepeneurs (Fab,Joerg and Brian amongst them):
DSH Pragmatic Software Development Workshop


Random Ramblings Index
My Profile

Ozfarmboy
Active Participant

Hi Joerg,

 

So are you using the events for transitions and the queue for states?

 

 

Christopher Farmer

Certified LabVIEW Architect and LabVIEW Champion
DQMH Trusted Advisor
https://wiredinsoftware.com.au

joerg.hampel
Active Participant
So are you using the events for transitions and the queue for states?

Chris, the original SSDC template uses queues to send transitions to the state machine (SSDC generally uses queues as their preferred means of communication afaik).

 

I modified this in that I created a private DQMH request event which replaces the queues. The VI that listens for transitions has an event structure inside which is registered to that private request event.

 

The state "lives" on the shift register of the state machine loop (i.e. it is handed over from iteration to iteration via the shift register).

 

The Message queue of the DQMH module isn't used for anything state machine specific.




DSH Pragmatic Software Development Workshops (Fab, Steve, Brian and me)
Release Automation Tools for LabVIEW (CI/CD integration with LabVIEW)
HSE Discord Server (Discuss our free and commercial tools and services)
DQMH® (The Future of Team-Based LabVIEW Development)


Ozfarmboy
Active Participant

Hi Joerg,

 

I wrote this comment after reading your post.  But then I checked out your templates, and after opening up the code it made more sense.

 

Thanks!

Christopher Farmer

Certified LabVIEW Architect and LabVIEW Champion
DQMH Trusted Advisor
https://wiredinsoftware.com.au