1

I am currently creating a software model for controlling a simple (two-way) pneumatic cylinder. In essence, this controls just a movement from point A to point B. The controller has two outputs (OnMovingToA, OnMovingToB), which can be linked to a relay, valve, etc... to move the actuator to resp. A or B. The controller has two inputs (AtPositionA, AtPositionB) representing end-stops: a feedback mechanism that the position has been reached.

A user can interact with the controller/cylinder using commands/functions: MoveToA and MoveToB.

  • Upon calling MoveToA, the cylinder should move to A and stop when A has been reached (AtPositionA is true).
  • Upon calling MoveToB, the cylinder should move to B and stop when B has been reached (AtPositionB is true).

double acting cylinder

Sometimes we also use 3-state valves to control the cylinder, where the cylinder can also be stopped halfway. Therefore the command Stop is added as well.

  • When Stop is called during a movement, the cylinder most likely will stop in an undetermined intermediate position. The system then waits for the next MoveToA or MoveToB

enter image description here

Inside the controller, I use a state machine. Initially, I had the state machine of the controller modeled like this:

position and movement merged

some remarks:

  • The rising edge of AtPositionA is A reached
  • The falling edge of AtPositionA is A left
  • The rising edge of AtPositionB is B reached
  • The falling edge of AtPositionB is B left
  • With A left, I mean: exit the A position.
  • With B left, I mean: exit the B position.
  • Output OnMovingToA is set to true when Moving to A is active.
  • Output OnMovingToB is set to true when Moving to B is active.

At least one issue I have with the above is that, since we are dealing with real-world applications, it is possible to be at position A and to move to B simultaneously. (the cylinder can be blocked, or the end-stop can have some off-delay. Naturally, this is not allowed within state machines, so we have to work around this.

After giving it some thought, I figured that position and movement are in fact 2 different - although connected - properties of a system. Hence, I split the state machine into movement and position states:

enter image description here

I feel that the second one is the way to go, but I fear that this is a bit unconventional.

What state machine would be preferred in this scenario? Is this a matter of taste, or is there a clear guideline that puts one above the other?

2 Answers2

2

Splitting position and movement is a good way to simplify the state machine model. But we can do better. Change what you're modeling.

"The controller has two outputs (OnMovingToA, OnMovingToB)"
"The controller has two inputs (AtPositionA, AtPositionB)"

enter image description here

Input\Command | OnMovingToA OnMovingToB Idle
--------------+-----------------------------            
AtPositionA   | OnMovingToB OnMovingToB OnMovingToB 
AtPositionB   | OnMovingToA OnMovingToA OnMovingToA
AtPositionI   | OnMovingToA OnMovingToB OnMovingToA

Rather than model the piston, lets model what we want the controller to do. Here we're taking the previous controller command as state and position as input. The result is both the output and the new command state. This is enough to keep the piston moving. This way, rather than trying to remember how the piston should be moving we look at how we're telling the piston to move.

Idle can be thought of as meaning there is no previous command. The result of Idle AtPositionI is OnMovingToA arbitrarily, just to get things moving at start up. Otherwise it's unreachable. AtPositionI simply means not getting either position signal. If you're getting them both, something is wrong.

candied_orange
  • 108,538
  • Thank you for your feedback! Am I correct to understand that the controller that you have modeled is continuously moving back and forth? I went back to my question and saw that I didn't mention how the client interacts with the controller, so I have added that. The user basically has 3 buttons to interact with: MoveToA, MoveToB and Stop. Does that still go with what you had in mind? – Cédric Moers Jul 13 '22 at 07:59
  • 1
    @CédricMoers that's called an answer invalidating edit. At this point your question is under specified. It's not clear what should happen after the user presses MoveToA. Should it stop at A? Should it resume cycling? Do we even need the controller since the user is acting as one? You could add 3 "overridden" states to stop the automatic cycling. They'd just reflect whatever button had just been pressed. But if these 3 buttons stop the cycling, you have no way to resume cycling. So yes, the controller continuously moves the piston back and forth. If you wanted something else, be clear – candied_orange Jul 13 '22 at 09:25
  • Thank you for pointing that out, I wasn't aware of 'answer invalidating edits' being bad practice. I will make sure my questions are better defined from the start. The controller has the sole purpose of Moving towards A until A is reached (AtPositionA is true), the same goes for B. So there is no cycling involved, sorry that this was not clear. – Cédric Moers Jul 13 '22 at 10:09
  • @CédricMoers So when the controller is told "Move to A" with a momentary button push the controller must send, and continue to send, a "Move to A" signal to the piston until the piston signals it's at A. At that point the controller must stop that signal and idle. Same for B. Have I got that right? – candied_orange Jul 13 '22 at 12:01
1

I apologize for this answer not matching the question. The OP has yet to incorporate clarifying comments into the question.


Your comment clarified that the controller should not cycle the piston on its own. Here's an answer based on that clarification.

I still prefer modeling the controller rather than the piston. But I think we got shorted some inputs and outputs.

"The controller has two three inputs (AtPositionA, AtPositionB, AtPositionI)"
"The controller has two three outputs (OnMovingToA, OnMovingToB, OnIdle)"
The controller apparently has buttons that force these outputs/states. They have different names printed on the labels but the wires don't care.

That's better. This moore style FSM transition table has the controller maintain the last command until the goal is reached or it's stopped (made to idle):

Input\Command | OnMovingToA OnMovingToB OnIdle
--------------+-------------------------------            
AtPositionA   | OnIdle      OnMovingToB OnIdle        
AtPositionB   | OnMovingToA OnIdle      OnIdle        
AtPositionI   | OnMovingToA OnMovingToB OnIdle       

Each button press of the controller is a state change. This state machine controls when that button press is considered over based on the position inputs. The user controls when it starts.

There is a potential bug. When implementing this the button press state change could produce output without reading position. A OnMovingToA command could be issued when already AtPositionA. Avoidable but also easy to overlook. If critical a Mealy style FSM might model this better.

candied_orange
  • 108,538