This example shows how to model a two-car elevator system with some of the common features expected in modern elevators such as call queuing, fire alarm responses, hall calls etc.
Showcases the advantages of using atomic subcharts in such an application by comparing a model before and after introducing this construct.
Illustrates the workflow needed to modify the elevator system model to use atomic subcharts.
Simulating the above model brings up the following graphical user interface (GUI):
This GUI allows users to click on buttons on each floor hallway, represented as empty squares under each floor number, or to click on buttons inside the individual elevator cars, represented as the numbered white buttons on a yellow background at the bottom of the GUI.
The chart Elevator System consists of three main components as shown here:
The workhorses of this chart are the subcharts Elevator_A and Elevator_B: these subcharts represent the elevator cars in the model. The elevator cars are controlled by the Elevator_Manager subchart.
Each of these subcharts manages a queue of user requests:
The Elevator_Manager manages the hall queue: this queue holds all the requests generated when pressing a button at any of the floors.
Each of the elevator cars has its own queue that represents all the user requests that it needs to process.
The main purpose of the Elevator_Manager chart is to process and delegate all incoming user requests (represented as input events in the model) to either Elevator_A or Elevator_B depending on criteria such as proximity to the request and availability.
Elevator Cars (Elevator_A and Elevator_B subcharts)
Each elevator car iteratively processes requests in its queue and continually updates both its status (BUSY, IDLE, etc) and its position. The updated position is then used to drive the GUI representation of the elevator car: to move the car or open its doors.
Click here to open the original model.
Refer to the subcharts above. Note that the elevator car subcharts have almost identical code (states, functions, local variables, etc) to process their individual user request queues. Because the elevator cars respond the same way to different inputs, the subcharts used to represent their behavior are prime candidates for linked atomic subcharts.
You can replace the elevator car subcharts with two links to a library atomic subchart that represents an elevator car as shown below:
In the above example, Elevator_A and Elevator_B both refer to chart Elevator in the library model sf_elevator_lib. You can then tweak the library atomic subchart without having to modify the linked instances.
One other use of atomic subcharts in the new model is in the GUI Controller chart: since the logic for controlling each GUI elevator car is identical (click here to open original chart) we can also make the GUI car controller a library atomic subchart and just link to it twice. Click here to open the GUI Controller chart with linked atomic subcharts.
To open up the final model that uses atomic subcharts as described above, click here.
All the logic specific to a elevator car is now housed inside a separate Stateflow® chart. This design has several benefits:
Team development is easier. Because the elevator logic and the elevator manager logic are now in different model files, different users can work on these different portions without merge conflicts at submission time.
Because Stateflow® does simulation through code-generation, separating the chart into two speeds up the process of testing incremental changes during simulation.
Because the library elevator chart is now reused, changes to the logic can be made once instead of being duplicated in multiple places.
This reuse also assists Simulink® Coder™ in generating reusable code for both elevators. In this case, the code for the elevator subsystem reduces by almost 500 lines of code: from about 1500 lines to about 1000 lines.
Separating the logic for an elevator into a chart also allows users to control code generation file-packaging options for the elevator chart.
To convert the elevator car subcharts to atomic subcharts, a few steps are needed. These steps reflect the rules that govern the use of atomic subcharts. For a description of these rules, click here and here.
The approach taken below is to make a library atomic subchart out of the Elevator_A subchart and then use linked instances of this library instead of the elevator car subcharts.
Step 1. Export Elevator_Manager functions and data to make them visible to atomic subcharts
Because atomic subcharts cannot call functions defined in a container chart unless they are exported, we need to pull the functions in the Elevator_Manager which are called by Elevator_A and Elevator_B to the chart level: doing so will make these functions visible to the atomic subcharts.
To export the functions at the chart level, migrate all the functions used by the elevator car subcharts out of the Elevator_Manager chart and into the parent chart as shown below:
The migrated graphical functions need to be renamed to distinguish them from the functions inside the elevator car subcharts. For example, the function
deregister can be renamed to
After that you need to set the Elevator System chart's
Export Chart Level Functions property to be true. Now modify the Elevator_Manager to use these functions.
Note: The elevator car subcharts directly access a local variable (
hall_call_status) defined in the Elevator_Manager subchart. Because atomic subcharts can only access chart-level data these variables need to be re-parented to the containing chart (Elevator System). The variable
hall_call_queue also needs to be re-parented to Elevator System because it is used by one of the exported functions.
The Elevator_A subchart should then be modified to use the newly scoped variable.
Step 2. Make Elevator_A fully defined and independent of Elevator System
To make the Elevator_A subchart fully defined, do the following:
Using the Model explorer, migrate the constant Stateflow® data objects such as
NUM_FLOORS to Elevator_A. These constants are used by both elevator cars.
Update Elevator_A to call the newly renamed exported functions of Elevator System.
Step 3. Create a library atomic subchart to replace elevator car subcharts
Once you have satisfied all the requirements to make Elevator_A an atomic subchart, right-click on the subchart and select
Make Contents -> Atomic Subcharted. Subchart Elevator_A will now have the label (Atomic) as shown below:
For more information on how to convert a state to an atomic subchart, click here.
Next, create a library atomic subchart using Elevator_A. Once you have created the library atomic subchart (shown below), do the following:
Change the Scope of the Stateflow® data object
position from Local to Output. This will enable you to link up the atomic subchart's output to that of the containing chart.
(Optional) Rename the inputs and outputs of the atomic subchart to be more general. For example, replace
Once you are done with the above, save the library model and then copy and paste the atomic subchart twice inside the Elevator System chart to replace the subcharts Elevator_A and Elevator_B.
Click here to open up the library model.
Step 4. Map data and events for both linked atomic subcharts to those of parent chart
The chart Elevator System has 4 outputs, 2 outputs for each elevator car subchart: each elevator car subchart outputs the current position and the current status on whether the elevator door is open. These outputs need to be mapped appropriately to the individual elevator car subcharts.
One of the Elevator System inputs (
fire_alarm) is fed directly to the elevator car subcharts so that also needs to be mapped.
Since the elevator cars need to know about the status of each hall floor button (stored in Elevator System's
hall_call_status variable), we need to map that to a data store memory in the atomic subchart.
Lastly, the input events used by each elevator car, namely the clock and car call request events, need to be mapped to those of Elevator System.
Below is a screenshot of the dialog box used to perform the above mappings: