A new release of SysML is upcoming. The latest version is v2.0 beta 1 - it's a modeling language that helps you design also complex systems.
The standard is developed by the OMG (https://www.omg.org/spec/SysML) and its member companies. While SysML v1 has been around for several years and is based on UML, SysML v2 represents a significant evolution.
I wanted to explore the current status of SysML v2 and understand what it would mean to support it as another input or output format for code generation.
A really nice feature of SysML v2 is that it specifies both a textual representation of a model as well as a graphical one. You can work either on text or graphically and can switch between one or the other view – whatever is more convenient for you. Of course, the modeling tool must support this.
To get started, it is highly recommended to use a tool. I found and the following tools:
More is available here: https://mbse4u.com/mbse-tools/
A microwave oven is the example used in all the SinelaboreRT manuals and examples. I wanted to model that too in SysML v2. This is a perfect example because it's a familiar embedded system that combines hardware and software components.
My approach was to break down the oven into its parts (similar to how you might break down a software system into classes or modules) and model the interactions via ports (think of these as interfaces) and the main behavior with a state machine.
This step was quite simple and feels very natural. The physical parts of the oven became model parts . I organized everything in a package .
The language also supports formal documentation, so tools can extract the “doc” parts later for generating documentation. Here's what the basic structure looks like:
private import ScalarValues::*; package OvenPackage { part def MicrowaveController{ doc /* * The controller interacting with all the peripheral parts */ } part def Motor{ doc /* * Motor driving the rotating plate */ } part def CountDownTimer{ doc /* * Timer that once started counts down to zero and stops the oven * Can be paused and changed any time. */ } part def Door{ doc /** * Representing the door that emits events if closed or opened */ } part def Display{ doc /** * General display to show oven status */ } part def LedDisplay :> Display{ doc /** * Specialization of generic display that has only some LEDs to show the oven status */ } part def TimeWheel{ doc /** * Rotary wheel that can increment and decrement the cooking time. */ } }
The graphical view shows the parts as expected. Notice how each part is represented as a box, similar to a class diagram in UML.
This is where it gets interesting but also more complex. SysML v2 has many concepts for modeling interactions, and it can feel overwhelming at first. I'm still learning which concepts work best for different scenarios. But others seem to have similar questions (see https://mbse4u.com/2024/12/02/which-sysml-v2-element-to-choose/) One preferred approach is to let parts interact using ports (I think of these as interfaces or connection points). Ports can transfer events and data flows. Given my background in state-based, event-triggered systems, it felt natural to first model the events I could identify.
My design approach was to let the MicrowaveController
receive events from the Door
and the CountDownTimer
, while it sends events to the Motor
and Radiator
. This creates a clear flow of information and control.
For modeling events, I found several approaches in examples. I ended up modeling them as enums, though attributes and item-based concepts also seem possible.
// definition of events from door sensor enum def DoorSensorEvents{ evDoorOpened; evDoorClosed; } // definition of events to control motor enum def BinaryCommands{ On; Off; } // events from the time selection interface enum def TimerEvents{ evTimeout; } enum def TickEvents{ evTick; }
Now let's define the ports. Think of these as the interfaces that define how parts communicate. The OnOffPort
can be reused for both the Radiator and the Motor since they both respond to simple on/off commands.
// ports to connect parts port def TimerPort{ out timeEvent : TimerEvents; out attribute timeInSec : Positive; } port def DoorEventsPort { out doorEvt : DoorSensorEvents; } port def OnOffPort{ in motorCmd:BinaryCommands; } port def TickPort{ out tick:TickEvents; }
Now let's add the ports to the parts. Here's an example showing how to add ports to parts. The ~
symbol indicates a “conjugate” port (the opposite direction - if sometinng is `in` on one side, the conjugate is `out` on the other side).
part def Radiator{ doc /* * Element generating the micro waves */ in port onOffPort : OnOffPort; } part def MicrowaveController{ doc /* * The controller interacting with all the peripheral parts */ in port doorPort : ~DoorEventsPort; // receive in port timerPort: ~TimerPort; out port motorPort : OnOffPort; // send out port radiatorPort : OnOffPort; // send }
The generated graphical representation now shows the ports on each part.
Now let's connect the parts together. SysML allows modeling connections in different ways - you can use explicit interfaces, or connect parts directly. Here's how to define the complete `Oven` with all its internal connections:
part oven:Oven{ part controller : MicrowaveController; part motor : Motor; part cdTimer : CountDownTimer; part display : LedDisplay; part door: Door; part radiator: Radiator; part tick:Ticker; connect door.doorPort to controller.doorPort; connect cdTimer.timerPort to controller.timerPort; connect tick.tickPort to cdTimer.tickPort; connect controller.motorPort to motor.motorPort; connect controller.radiatorPort to radiator.onOffPort; }
The generated diagram shows the complete system structure. Unfortunately, there's no way yet to control the image layout to make port names more readable - more powerful tools will realize this in a better way for sure. However, the overall structure is clear at first glance. You can also see that the display isn't connected yet (a task for you:-)).
SysML allows adding attributes of various complexity to parts. Attributes can have units, and SysML v2 comes with a comprehensive standard library that defines SI units and much more.
This makes it possible to model real-world properties like power consumption for key parts. Many practical use cases come to mind here - think of reasoning battery life, thermal management, or resource requirements.
This was the most interesting part for me to understand what capabilities the new SysML v2 language offers. State machines are familiar to most embedded software developers - they help model how a system responds to events and changes its behavior over time.
Let's add a state machine to the MicrowaveController
. Initially, the syntax looks clear and easy. The default state is expressed with entry; then Off;
- this means “start in the Off state.”
part def MicrowaveController { state MicrowaveControllerStateMachine{ entry; then Off; state Off{ } state Run{ } state Pause{ } } }
The generated PlantUML image shows a simple state machine with three states, which looks promising for modeling behavior.
Now let's add transitions to the state machine. Here's how the syntax works:
first Run
means “from the Run state”accept DoorSensorEvents via doorPort
means “listen for events on the doorPort”if
statement specifies which specific event triggers the transitionthen Pause
defines the target stateA nice new feature is that transitions can be triggered at defined points in time or after a certain duration. Due to the textual specification option it is now easy to write down. This was always a weak point in UML tools.
Entry/Do/Exit
actions are also possible. In the example, we use Do
actions to send events (the payload) via ports to connected parts. You can also use action calls with input and output parameters.
state MicrowaveControllerStateMachine{ entry; then Off; transition first Run accept DoorSensorEvents via doorPort if (doorPort.doorEvt==DoorSensorEvents::evDoorOpened) then Pause ; transition first Pause accept DoorSensorEvents via doorPort if (doorPort.doorEvt==DoorSensorEvents::evDoorClosed) then Run ; transition first Off accept DoorSensorEvents via doorPort if (doorPort.doorEvt==DoorSensorEvents::evDoorClosed) then Run ; transition first Run accept TimerEvents via timerPort if (timerPort.timeEvent==TimerEvents::evTimeout) then Off ; transition first Pause accept TimerEvents via timerPort if (timerPort.timeEvent==TimerEvents::evTimeout) then Off ; state Off{ do send BinaryCommands::Off via motorPort; } state Run{ do send BinaryCommands::On via motorPort; } state Pause{ do send BinaryCommands::Off via motorPort; } }
The state machine can be visualized, though automatic layout engines have their limitations in creating optimal diagrams.
As we've seen, SysML v2 allows modeling nested state machines (parallel states are also possible) and defining transitions with relevant actions within states.
If you're familiar with UML state machines, you'll quickly notice that some features aren't (yet) available. For example, there are no Choice
or Flat/Depp History
. I'm not sure if this will be added later or was excluded by design. To make up your own mind checkout chapter 7.17 page 108ff of the present spec.
SysML v2 is very promising, especially because of its textual representation. This opens up many new use cases and makes them much easier to implement. Think about version controlling models in Git, making diffs, and collaborative development - all the practices software developers are familiar with.
Reasoning on models will also become normal. Consider the power consumption example above - you could automatically calculate total system power requirements. Or imagine using AI to ask questions about a model. (By the way, current AI tools make many errors when answering questions about SysML v2 syntax - I guess there simply isn't enough training material yet, or it's too new.)
Does it make sense to directly generate C/C++ or any other language code from SysML models? The pure model won't be sufficient. For example, the interaction of parts via ports can be realized in very different ways depending on the targeted system. So a mapping between the model and implementation is required, and that mapping should be flexible to adapt to concrete needs (e.g., using OS signals in one case or queues in another).
What do you think? How could you benefit from using SysML v2?
I'm still learning SysML v2 myself, so if you're an experienced SysML practitioner and have suggestions for modeling this example more naturally or effectively, I'd love to hear from you!
Feel free to share:
Thanks in advance for your insights!