Did a nifty change in QStateMachine yesterday: QStateMachine now inherits QState. QStateMachine::rootState() is gone; the state machine now is the root state. This allowed us to remove a fair amount of code and API from QStateMachine; most importantly, it makes application code nicer, as you can do new QState(machine) to create a top-level state, instead of the old new QState(machine->rootState()) (whee, that’s something we’ve wanted since day one!). Other than that, behavior and source compatibility is preserved.
An interesting question is… What should QState::machine() return when the state is a state machine? Itself?
Nope, it doesn’t. We now support embedding state machines within other state machines. If the parent of the state machine is a QState, machine() will return the machine of the parent state.
When a QStateMachine is a child state of another QState, the ancestor state machine will treat the nested machine as an atomic state in the state machine algorithm; effectively, the nested machine is treated as a black box. QStateMachine reimplements QState::onEntry() and calls start(), so that when a nested state machine is entered, it will automatically start running. The nested machine is self-contained; it maintains its own event queue and so on. Of course, you can’t have transitions from states in the nested machine to states in the parent machine; you’ll have to use e.g. the nested machine’s finished() signal to trigger a transition from the nested machine to another state in the parent machine (since the nested machine is a state of the parent machine, and not of itself). Well, that should go without saying.
OK, so we haven’t found a use case yet where you’d rather use nested state machines with separate event loops and all instead of just using normal group states within a single machine, where all states can be directly connected by transitions (maybe you can think of a scenario?). But a) it’s neat, and b) it works. As always, these qualities take presedence over any purported absence of use cases.
The documentation for QState still says that “the QState class provides a general-purpose state for QStateMachine”. Seeing as QStateMachine itself is now a QState, this begs the question: Who is really providing what for whom, to what end, and why?
Possibly related posts:
10 comments
Good design decision, I’ll try it out layer.
What about nested state machines, I seen such realisations before, that’s why it’s good to have such feature. But I’m forgot the scenario of those models, and unable to provide you with this scenario too:-)
Will there be changes in the “scxml” (http://qt.gitorious.org/qt-labs/scxml)?
and in “Qt State Machine Framework” (http://www.qtsoftware.com/products/appdev/add-on-products/catalog/4/Utilities/qt-state-machine-framework/)
Not related to this blog but to the State Machine framework. The new State Machine framework for Qt4.6 looks very promising. It would be nice if the framework would also include a Compiler for SCXML files to C++ (like uic, moc,…). Is something like this planned for Qt4.6. If not please consider this feature.
“The problem isn’t in the box its in the /band/”
A node provides node services for other nodes. No worries about the circular reference. The producer is the consumer!!
@Yurli: I fixed SCXML to work with the API changes (only had to remove a couple of ->rootState() calls). tag but it works according to the spec, which is slightly different than the behavior mentioned in this post. (for example, in SCXML the nested state machine is dynamically loaded from XML in runtime). In that sense, SCXML has to keep its own logic for nesting rather than reusing the QStateMachine one, which we try to do when the conditions permit
To your question, SCXML supported nested state machines before with the
Other than that, no changes for now.
@Yuriy: Currently there are no plans for new releases of the State Machine Framework; the primary purpose of SMF was to elicit feedback before the feature was integrated into Qt.
@Andreas Bacher: The SCXML compiler is not planned for 4.6; http://qt.gitorious.org/qt-labs/scxml will continue to be a separate project for now. But yeah, I’d like to see this in Qt too.
Hi! You have mentioned the “event queues” in the machines.
What I don’t understand is why you are mixing two things into the state machine.
1) The StateMachine
2) Asynchronous transitions via the event loop
I would like to use the StateMachine as a plain state machine without a running an event loop. Just to be sure that the machine is in the correct state after I have triggered the transition. For mutlithreading and asynchronous dispatching I can always connect the events/signals etc. via a queued connection. But the StateMachine itself must not know about this.
It would be an “KISS” like approach (http://en.wikipedia.org/wiki/KISS_principle) and much easier to use.
Greetings
Jens
It is getting better every iteration. Keep up good work. One “use case” that I could think of is that you can abstract sublevel machine tbd later.
Example: PID loop control. i.e. injector timing.
You have a long-term fuel trim function and a short-term fuel trim function. Generally, injectors are timed by moving around in a table, and taking in intake air temp, along with the flow rate of air. But the O2 sensors provide feedback based on measured results, so your long term value is set by the table, the short term comes from the 02 sensors to tweak it richer or leaner.
So you have a state machine of the primary mode (idle, accel, descel) and seconary mode of (+ injector pulse time, keep, – injector pulse time.) The engine isn’t a continuous flow system, as it is synchronous and you know where you are thanks to the crank angle sensor, so it is simplified (you know when to look for the result), but for liquid flows the state machine is much more applicable.
Comments on this entry are closed.