Advent of SysML v2 | Lesson 18 – State-Based Behaviors

Hello and welcome back to the Advent of SysML v2 – a daily, hands-on mini-course designed to bring you up to speed with the new SysML v2 standard and the modern Syside tooling that makes you productive from day one.

By the end of this lesson, you will:

  • Learn about modeling states and state transitions
  • Learn about nested states and parallel states
  • Learn about entry, exit, and do actions

This lesson is just a glimpse into what SysML v2 offers in terms of state-based modeling. We will focus on the most important aspects that can help you get started, and only mention the rest of the capabilities that might be of interest to you. Additionally, state machines are connected to several other aspects (like actions and structure), some of which will be discussed in the final lesson.

If you want to dive deeper into the world of SysML v2, check out The SysML v2 Book, where this topic is also discussed in more detail.

Reactive Systems and State Machines

Many of our systems operate by continuously reacting to different events that occur in their environment. The behavior of such systems is challenging to describe using workflow-like models (actions in SysML), as a significant part of their operation involves waiting for an event to occur and then reacting to it, potentially in an infinite loop.

The reaction is determined by the occurring event and the system’s history, which is encoded in its state. A state, in the mathematical sense, captures all the information that the system must memorize to decide how to react to an event. In engineering, we conventionally separate the value of different data variables from the control location of our logic, and refer only to the latter as a state. For example, a system can be on or off – these can be encoded as states because they fundamentally influence how the system will react to different stimuli.

Transitions from one state to another happen in response to an event when the system is in a specific state. Transitions usually also prescribe some kind of action to perform as the system’s reaction.

Together, states and transitions are often called state machines.

Events

Events are usually either changes in the value of something, timers expiring, or the reception of signals or messages from other entities communicating with the system. We will illustrate all three today, but let us first focus on communication.

As we saw in Lesson 13, items are suitable to model entities that are exchanged between systems or components. We will start our example model by modeling some items to capture the kinds of things our state machine will send and receive.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package L18_States {
private import ScalarValues::*;
item def StartMission;
item def EndMission;
item def Approach;
item def Next;

item def Command {
attribute cmd : String;
}
item def Status {
attribute status : String;
}

// …
}

There should be nothing new here, language-wise, but observe the patterns we used. There are four items from lines 4 to 7 that capture a specific command. They are empty because their definition already contains the necessary information. Modeling with these is often easier, but can result in a large number of item definitions. For the sake of simplicity, we will use these for the messages our state machine receives.

Alternatively, item definitions can define attributes to store parameters of the event. You can see this in lines 9 to 14, where we added string attributes to capture what kind of command or status the item represents. It would also be very elegant to list these in an enumeration (see Lesson 11). Modeling items this way can lower the number of elements, but requires more complex patterns in the state machine. For the sake of simplicity, we will use this for the messages our state machine sends.

States and Transitions

We can model states (in the engineering sense) with state definitions and usages. A state definition describes a “blueprint” for a state machine, which can be used in a specific context. The context is typically an entity (a part or an item), or another state, in which case the state usage represents a sub-state. We will discuss composite states shortly.

State machines are rarely standalone model elements because they need to communicate through ports and manage attributes. When modeling a state definition, it is best to model these as parameters of the state (not necessarily directed, but usually referential). They can be bound to ports and attributes to an actual part when the state definition is used in it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package L18_States {
private import ScalarValues::*;
item def StartMission;
item def EndMission;
item def Command {
attribute cmd : String;
}
// …

state def ReindeerController {
attribute reindeerCount : Integer;
attribute totalPower subsets ISQ::power;
attribute averageEnergy : Real;
ref port eyelet;
ref port hmi;

entry;
then idle;
state idle;
accept StartMission via hmi
if reindeerCount == 9 and totalPower >= 36 [SI::kW]
do send new Command(“Gee-up!”) via eyelet
then mission;
state mission;
accept EndMission via hmi
then idle;
}
}

In the example above, we have a state definition called “ReindeerController”, which represents the main logic of Santa’s sleigh and prescribes how to control the reindeer during the mission on Christmas Eve. The state definition has three attributes that must be accessed from the state machine, and two ports through which items will be sent and received. Recall that attribute usages are always referential, but we added the “ref” keyword to the ports to indicate that these are not ports of the state machine per se, but rather that the state machine should have access to them via these references.

What follows is the definition of the state machine’s logic. Let us first look at lines 20 and 25. These are state usages that represent the sub-states of the reindeer controller. These state usages rarely have definitions, only when they are complex states, and it is worth reusing their description.

There are also two transitions in lines 21–24 and 26–27. The first one demonstrates all parts of a transition with the shorthand notation:

  • The source state is the immediately preceding state usage (just like with the shorthand form of successions in Lesson 17). We will see the long-hand notation a bit later.
  • The trigger of the transition is specified after the “accept” keyword (which is actually an accept action). This transition is triggered when an item of type “StartMission” is received via the “hmi” port. The “via” part is optional, but it is good practice to use ports when modeling communication.
  • The guard condition is specified after the “if” keyword, which is a Boolean expression that must be true to execute the transition. In this case, we refer to the reindeer count and the total power attributes and say that the mission can only be started if there are enough reindeer with sufficient power pulling the sleigh.
  • The effect of the transition is specified after the “do” keyword. In this case, it is a send action, which sends a new instance of the “Command” item via the “eyelet” port with the “Gee-up!” string as the value for the “cmd” attribute (refer to Lesson 11 for instantiation expressions).
  • Finally, the target state is specified after the “then” keyword.

The transition can occur if the source state is active, the trigger is satisfied (in this case, the state machine has received a matching item), and the guard condition is true. When it executes, the effect action is performed, the source state is deactivated, and the target state is activated. As a note to interested readers, the precise formal semantics for SysML v2 state machines is not yet clear, but the intent is that the v1 operational semantics remain legal.

The last one we have to observe in the snippet is lines 18 and 19. These lines denote the initial state, which becomes active once the state machine is activated. We will cover what “entry” is shortly.

Composite and Parallel States

Let us focus on states again. A “composite state” is a state that has nested state usages, also called sub-states. In SysML v2, it is no different from a “basic state” – they are both modeled with state usages (a state definition usually models a composite state, though). When a composite state is active, one or all of its sub-states must also be active. 

One or all? This is what the “parallel” keyword decides. A parallel composite state is defined with the “parallel” keyword after the name. In parallel states, all sub-states must be active when the state is active, and there can be no transitions between the states. If you are familiar with SysML v1, this corresponds to multiple regions – but there are no regions in SysML v2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package L18_States {
private import ScalarValues::*;
// …

state def ReindeerController {
// …
entry;
then idle;
state idle;
// …
state mission parallel {
state monitoringReindeer {
entry;
then nominal;
state nominal;
state lowEnergy;
// …
}
state controllingReindeer {
entry;
then takingOff;
state takingOff;
state flying;
state landing;
state waiting;
// …
}
}
// …
}
}

The model above illustrates both cases. In line 12, we turned the “mission” state into a composite state, and the “parallel” keyword indicates that it is also a parallel state. When it is active, both “monitoringReindeer” and “controllingReindeer” are active. This captures the fact that these two aspects are orthogonal and their sub-states will change independently.

The state usages “monitoringReindeer” and “controllingReindeer” in lines 13 and 20 are also composite but not parallel. In each one, exactly one of the sub-states will be active when they are active. These composite states could be extracted into another state definition, in which case it would be enough to type the usage with that definition instead of nesting the substates under the usage. This is useful if the corresponding aspect appears in many places in the model.

Entry, Exit, and Do Actions

It is already useful that we can perform actions when a transition occurs, but we can also link actions to states:

  • Entry actions are executed when a state becomes active, before anything else happens in the state.
  • Exit actions are executed when the state becomes inactive, as the last thing to happen in a state.
  • Do actions start after the entry action and are performed once, but they can be terminated early if the state is deactivated.

These actions can be used to model reactions to states becoming active or inactive for any reason (entry and exit), or to model that the state represents the ongoing performance of something (do).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package L18_States {
private import ScalarValues::*;
// …
item def Command {
attribute cmd : String;
}
// …

state def ReindeerController {
// …
ref port hmi;
// …
state mission parallel {
state monitoringReindeer {
entry;
then nominal;
state nominal;
state lowEnergy {
entry send new Status(“low energy”) via hmi;
do action blinkLed;
exit send new Status(“recharged”) via hmi;
}
// …
}
// …
}
// …
}
}

Lines 19 to 21 show all three kinds of actions in states. When we enter the “lowEnergy” state, the controller will send a status message with the text “low energy”. While we are in the state, it will perform the “blinkLed” action, which stops when we leave the state (let us assume that this action contains an infinite loop). Upon leaving the state, the controller will send a new status message with the text “recharged”.

Triggers

The final thing to learn today is the three kinds of triggers we mentioned in the beginning. Below, you can see the complete example model, with several new transitions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package L18_States {
    private import ScalarValues::*;
   
    item def StartMission;
    item def EndMission;
    item def Approach;
    item def Next;

    item def Command {
        attribute cmd : String;
    }
    item def Status {
        attribute status : String;
    }

    state def ReindeerController {
        attribute reindeerCount : Integer;
        attribute totalPower subsets ISQ::power;
        attribute averageEnergy : Real;
        ref port eyelet;
        ref port hmi;

        entry;
            then idle;
        state idle;
            accept StartMission via hmi
                if reindeerCount == 9 and totalPower >= 36 [SI::kW]
                do send new Command(“Gee-up!”) via eyelet
                then mission;
        state mission parallel {
            state monitoringReindeer {
                entry;
                    then nominal;
                state nominal;
                state lowEnergy {
                    entry send new Status(“low energy”) via hmi;
                    do action blinkLed;
                    exit send new Status(“recharged”) via hmi;
                }

                transition nominal2low
                    first nominal
                    accept when averageEnergy < 50
                    then lowEnergy;
                transition low2nomnal
                    first lowEnergy
                    accept when averageEnergy >= 50
                    then nominal;
            }
            state controllingReindeer {
                entry;
                    then takingOff;
                state takingOff;
                    accept after 60 [SI::s]
                    then flying;
                state flying;
                    accept a : Approach via hmi
                    do send new Command(“Whoa!”) via eyelet
                    then landing;
                state landing;
                    accept after 5 [SI::minute]
                    then waiting;
                state waiting;
                    accept Next via hmi
                    do send new Command(“Gee-up!”) via eyelet
                    then takingOff;
            }
        }
            accept EndMission via hmi
            then idle;
    }
}

Let us start with a quick detour: we mentioned that transitions also have a longhand notation. You can see this in lines 41-48, where we declare transitions with the “transition” keyword, give them a name, and then denote the source state with the “first” keyword. The rest is also included in the shorthand.

Back to triggers. The trigger is always an accept action, called an accepter, which can have different payload parameters to model different triggers.

  • Reception trigger: If the payload is declared with a definition (like we did in the example, for instance, in line 26), the accepter is triggered when an instance of that definition is received. That instance can actually be accessed if we also give it a name, like in line 57, where the received “Approach” instance will be stored in the usage “a”.
  • Change trigger: If the payload is declared with the “when” keyword (like in lines 43 and 47), the accepter is triggered when the subsequent Boolean expression becomes true. This is useful for reacting to changes in the value of one or more features.
  • Relative time trigger: If the payload is declared with the “after” keyword (like in lines 54 and 61), the transition must wait at least the specified amount of time before executing.
  • Absolute time trigger: If the payload is declared with the “at” keyword (not demonstrated here), the transition must wait until the time instant specified after the keyword.

These triggers enable the modeling of a diverse set of reactive systems. If you find yourself struggling with action models trying to figure out how to control when actions should execute, remember that they might be better modeled with state machines instead.

Challenge for Tomorrow

Modeling actions takes a lot of practice in SysML. Let’s start right away with today’s challenge. Head over to Syside Cloud and do the tasks below.

Santa’s Sleigh Cruise Control

Your challenge is to complete a cruise control system for Santa’s sleigh – similar to what you’d find in a car, but adapted for magical reindeer-powered flight. The skeleton model provides a SantaSleighCruiseControl state definition with comprehensive transition tables describing the required behavior. Your tasks are:

  1. Define the event items needed for state transitions 
  2. Add the attributes for cruise control and weather monitoring with their default values as specified in the TODOs
  3. Implement the top-level states with their transitions based on the State Transition Summary table
  4. Make cruising a parallel state containing two independent sub-state machines for speed regulation and weather monitoring (also refer to their state transition summary tables).

This challenge exercises composite states, parallel states, change event triggers, guard conditions, and proper use of the pattern for initial states. Use the transition tables as your guide—they contain all the information you need. Good luck!

Summary

In this episode, you saw the basics of modeling state-based behavior in SysML v2. There is more, but this already gives you a very powerful tool. It is now time to try it at Syside Cloud by doing the challenge – and don’t forget to come back tomorrow for another episode of the Advent of SysML v2!

Cookies