Handling Multiplicity in State Machines

Overview

Multiplicity defines the number of instances that can exist for a given part or reference property. For example, assume the UAV in this tutorial is a quadcopter with exactly four distinct motors: one to power each propeller. This translates to a multiplicity of 4..4 (minimum of 4 and maximum of 4) in SysML. In this section, you will use a repeating substate to have the flight controller arm each motor one by one.

This section covers the following concepts:

Figure A1: Iterating through a property with multiplicity greater than one

Prerequisites

Prerequisite Description
Moxie Installation You must have installed Moxie.
Tutorial Project You must start this section with the Moxie simulation project from the previous section. If you did not complete the previous section, you can use the following project from the Moxie installation: \documentation\tutorialFiles\02\ChangeEvents.mdzip
Recommended Reading Before completing this section, you may want to read the following help topic:

Instructions

Create a block for the motors

  1. Open the project from the previous section.
  2. In the System Definition (the BDD), select the Thing block, click the downward-pointing Generalization button () on the context toolbar, and then click anywhere on the canvas to add a new block.
  3. Select the new block on the diagram and enter Motor as its name.
  4. Click the Create Element button () on the upper-right corner of the block and select Part Property.
  5. Enter armDuration : FixedDuration as the property's name and type.
  6. Double-click the new property, set the Visibility to public, set the Aggregation to shared, and click Close.
  7. Select the Motor block again, click the Create Element button () on the upper-right corner of the block, and select Operation (or press CtrlAltO).
  8. Enter arm as the operation's name.
  9. Double-click the new operation, set the Visibility to public, and click Close.

Assign the block to properties

The Motor block should be a part property of the UAV and reference property of the flight controller, with a multiplicity of four in both cases, indicating that there are exactly four motors for a single UAV and flight controller.

  1. Select the UAV block, click the Directed Composition button () on the context toolbar, and then click the Motor block.
  2. Double-click the new association and in the Role of Motor category, set the Name to motors and the Multiplicity to 4.
  3. In the Role of UAV category, set the Multiplicity to 1 and click Close.
  4. In the toolbar to the left of the BDD canvas, select Directed Association, click the FlightController block, and then click the Motor block.
  5. Double-click the new association and in the Role of Motor category, set the Name to motors and the Multiplicity to 4.
  6. In the Role of FlightController category, set the Multiplicity to 1 and click Close.
  7. Select the FlightController block, click the Create Element button () on the upper-right corner of the block, and select Value Property.
  8. Enter motorsArmed : Integer as the property's name and type.
  9. Double-click the new property, set the Visibility to private, and click Close.

Figure B1: The system definition (BDD)

Create instance specifications for the motors

The four motors each need their own instance specification. However, assuming they are identical, they will all take the same amount of time to arm, so they can share a single armDuration instance specification.

  1. Right-click the Motor block and select Tools > Create Instance....
  2. In the 1. Select parts page, select the armDuration property, click the cell to the right of Value, and then click the ... button in the right corner of the cell.
  3. Select the Simulation > armingWaitDuration instance specification, click Creation Mode, and then click Clone.
  4. Set the Name to the string armDuration and click Close, OK, and then Next >.
  5. In the 2. Select a package page, select the Simulation package and click Next >.
  6. In the 3. Create a diagram page, clear the Create a new diagram checkbox and click Finish.
  7. In the Containment Tree, set the seconds value of the new armDuration instance specification to 3.
  8. Copy (CtrlC) the motor instance specification, select the Simulation package, and paste (CtrlV) the instance specification three times.
  9. Rename the four motor instance specifications to uav.frontLeftMotor, uav.frontRightMotor, uav.rearLeftMotor, and uav.rearRightMotor.

Assign the instance specifications to properties

  1. Open the Instance Specification Diagram.
  2. Drag the the four motor instance specifications from the Containment Tree into the uav instance specification on the diagram and click OK for each of them.
  3. For each motor instance specification:
    Select it, click the Link button () on the context toolbar, click on the uav instance specification to add the link, and then click OK on both pages of the dialog window.
  4. Double-click the uav.flightController instance specification and select Slots from the left pane of the specification window.
  5. In the center pane, select the motors slot and click Create Value.
  6. Click Multiple Selection, then the Add Recursively button () to add all four motor instance specifications, and then OK and Close.
  7. Drag the Simulation > armDuration instance specification from the Containment Tree into the uav instance specification on the diagram.
  8. (Optional) For each motor instance specification:
    Select it, click the Link button () on the context toolbar, and then click on the armDuration instance specification to add the link.

Figure B2: The instance specification diagram

Create a state with entry and exit behaviors

States can activate behaviors upon entry and exit just like transitions activate behaviors in their effects. These entry and exit behaviors activate regardless of which transitions are taken into and out of the state. Also like with transition effects, Moxie requires these behaviors to be opaque behaviors with bodies written as opaque expressions.

  1. In the FlightController State Machine diagram, select State from the toolbar to the left of the canvas, click the transition from the Idle state to the choice pseudostate, and then click After Transition.
  2. Enter ArmingMotors as the new state's name.
  3. Double-click the transition from Idle to ArmingMotors.
  4. In the Effect category, set the Behavior Type to <UNSPECIFIED> and click Close.
  5. Double-click the ArmingMotors state.
  6. In the Entry category, set the Behavior Type to OpaqueBehavior.
  7. Set the Body and Language to the string motorsArmed = 0;.
  8. In the Exit category, set the Behavior Type to OpaqueBehavior.
  9. Set the Body and Language to the string isArmed = true; and click Close.

Model the internal behavior with a repeating substate

Similarly to how you modeled simultaneous behavior by nesting states inside a composite superstate, you can model the internal behavior of a state by nesting substates inside of it.

  1. In the toolbar to the left of the state machine canvas, select Initial and click in the ArmingMotors state to add an initial pseudostate.
  2. Click the Transition button () on the context toolbar, right-click in the state and select State, and then enter ArmingMotor as its name.
  3. Click the Transition button () on the context toolbar again. Then right-click in the state and select Final State to add a final pseudostate.
  4. Select the ArmingMotor state again, click the Transition button () on the context toolbar, and click the ArmingMotor state (or click the Transition to Self button ()).
  5. Double-click the transition-to-self on the ArmingMotor state.
  6. In the Trigger category, set the Event Type to TimeEvent, set When to the string motors.getValueAt(motorsArmed).armDuration, and set Is Relative to true.
  7. Set the Guard to the string motorsArmed < motors.size() and (optionally) add a line break before motorsArmed < motors.size().
  8. In the Effect category, set the Behavior Type to OpaqueBehavior, set the Body and Language to the string motors.getValueAt(motorsArmed).arm(); motorsArmed += 1;, and (optionally) add line breaks before motors.getValueAt(motorsArmed).arm(); and motorsArmed += 1;. Then click Close.
  9. Double-click the transition from the ArmingMotor state to the final pseudostate, set the Guard to the string motorsArmed == motors.size(), and click Close.
  10. Run () the simulation and observe that the flight controller arms the motors one by one before setting itself as ready for takeoff.

    Figure B3: The flight controller state machine

  11. Save your work before continuing.

Next Tutorial!