Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project: Autonomous Ski Lift Simulation for Safety & Efficiency (C example) #118

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
109 changes: 109 additions & 0 deletions examples/C/src/SkiLift/Lift.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* This project simulates the behavior of ski lifts with a focus on improving safety and reducing
* labor costs through automation using Lingua Franca. The simulation models key aspects of ski lift
* operations, including:
*
* 1. Passenger Flow & Lift Capacity: Ensuring smooth and efficient boarding/unboarding.
*
* 2. Safety Mechanisms: Detecting potential dangers and automating responses to prevent accidents.
*
* 3. Autonomous Control: Optimizing lift operations with minimal human intervention.
*
* The goal is to explore how automation can enhance safety while reducing operational costs, making
* ski lifts more efficient and reliable.
*
* @author Cheng Yen, Tsai
*/
target C

import EntryGate from "lib/EntryGate.lf"
import EntrySensor from "lib/EntrySensor.lf"
import LiftSensor from "lib/LiftSensor.lf"
import ObjectDetector from "lib/ObjectDetector.lf"
import ScreenPrinter from "lib/ScreenPrinter.lf"
import LiftMotion from "lib/LiftMotion.lf"

main reactor Lift {
state move: bool = true
state open: bool = false
state stay_cur_mode: bool = true
state count: int32_t = 0
state start_number: int32_t = 0
state end_number: int32_t = 0
state screen_wideth: int32_t = 80
state passenger_cnt: int32_t = 0
liftMotion = new LiftMotion()
entryGate = new EntryGate()
entrySensor = new EntrySensor()
liftSensor = new LiftSensor()
objectDetector = new ObjectDetector()
screenPrinter = new ScreenPrinter()

timer t(500 msec, 500 msec)

state gate_t_counter: int32_t = 0
state offset: int32_t = 0
timer t_gate(0, 1 sec)

// Start the program (When staff press the start button of the lift)
reaction(startup) -> screenPrinter.offset, screenPrinter.motion_msg {=
lf_set(screenPrinter.offset, self->offset);
lf_set(screenPrinter.motion_msg, "Moving");
self->offset = (self->offset + 1) % self->screen_wideth; // Update the offset for the next frame
=}

reaction(objectDetector.start_number) {=
if (objectDetector.start_number != 0) {
self->start_number = objectDetector.start_number->value;
}
=}

reaction(t) -> liftMotion.move, liftMotion.offset {=
self->count++;
if (self->count % 10 == 0) {
self->move = !self->move;
} else {
self->offset = (self->offset + 1) % self->screen_wideth; // Update the offset for the next frame
}

lf_set(liftMotion.move, self->move);
lf_set(liftMotion.offset, self->offset);
=}

reaction(t_gate) -> entryGate.open, screenPrinter.gate_msg {=
if (self->gate_t_counter % 4 == 0) {
self->open = true;
lf_set(entryGate.open, self->open);
lf_set(screenPrinter.gate_msg, "Open");
} else if (self->gate_t_counter % 4 == 1) {
self->open = false;
lf_set(entryGate.open, self->open);
lf_set(screenPrinter.gate_msg, "Close");
}
self->gate_t_counter ++;
=}

reaction(entrySensor.gate_1) {=
if (entrySensor.gate_1->value) {
self->passenger_cnt ++;
}
=}

reaction(entrySensor.gate_2) {=
if (entrySensor.gate_2->value) {
self->passenger_cnt ++;
}
=}

reaction(entrySensor.gate_3) {=
if (entrySensor.gate_3->value) {
self->passenger_cnt ++;
}
=}

reaction(objectDetector.end_number) {=
if (objectDetector.end_number != 0) {
self->end_number = objectDetector.end_number->value;
}
=}
}
97 changes: 97 additions & 0 deletions examples/C/src/SkiLift/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

<h1 align="center">
<br>
<img src="assets/cable-car-solid.svg" alt="Markdownify" width="200">
<br>
<br>
Autonomous Ski Lift System
<br>
</h1>

<h4 align="center">A safe and efficient ski lift system build with <a href="https://www.lf-lang.org/" target="_blank">Lingua Franca</a>.</h4>

<br>

<div display="block" align="center">
<video width="600" controls>
<source src="assets/demo.mov" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>


## About the Project

This project simulates the behavior of ski lifts with a focus on improving safety and reducing labor costs through automation using Lingua Franca. The simulation models key aspects of ski lift operations, including:

1. **Passenger Flow & Lift Capacity**
- Ensuring smooth and efficient boarding/unboarding.
2. **Safety Mechanisms**
- Detecting potential dangers and automating responses to prevent accidents.
3. **Autonomous Control**
- Optimizing lift operations with minimal human intervention.

The goal is to explore how automation can enhance safety while reducing operational costs, making ski lifts more efficient and reliable.

## How To Use

To clone and run this application, you'll need [Git](https://git-scm.com) and [Lingua Franca](https://www.lf-lang.org/docs/installation) installed on your computer. From your command line:

```bash
# Clone this repository
$ git clone https://github.com/lf-lang/playground-lingua-franca.git

# Go into the example folder of the repository
$ cd playground-lingua-franca/examples/C

# Compile the main reactor
$ lfc src/SkiLift/Lift.lf

# Run the program
$ bin/Lift
```

> **Note:**
> Or you can compile and run the program simply using VS Code, [see section "Running Locally"](https://github.com/lf-lang/playground-lingua-franca).


## Components (Reactors)

<table>
<tr>
<td> <img src="assets/Lift.png" alt="Lift" width="400">
<td> <a href="Lift.lf">Lift.lf</a>: The main reactor that controls all timed and startup events, receives signals from sensors, and manages the lift behavior.</td>
</tr>
<tr>
<td> <img src="assets/EntryGate.png" alt="EntryGate" width="400">
<td> <a href="lib/EntryGate.lf">EntryGate.lf</a>: Uses a modal model to control the opening and stopping of the entry gate.</td>
</tr>
<tr>
<td> <img src="assets/ScreenPrinter.png" alt="ScreenPrinter" width="400">
<td> <a href="lib/ScreenPrinter.lf">ScreenPrinter.lf</a>: Manages stdout behavior for the ski lift simulation. This reactor handles printing lift animations, clearing lines, and refreshing the displayed output to ensure smooth and dynamic visualization.</td>
</tr>
<tr>
<td> <img src="assets/EntrySenor.png" alt="EntrySensor" width="400">
<td> <a href="lib/EntrySensor.lf">EntrySensor.lf</a>: Processes data from the sensor placed at the entry gate. This reactor tracks the number of people attempting to board the lift, ensuring accurate passenger flow management.</td>
</tr>
<tr>
<td> <img src="assets/LiftSensor.png" alt="LiftSensor" width="400">
<td>
<a href="lib/LiftSensor.lf">LiftSensor.lf</a>: Processes data from two sensors—one at the start of the lift and one at the end.
<ul>
<li><strong>Start sensor:</strong> Detects when a lift chair is ready to carry passengers in the ready area. If triggered, it signals the gate to open, allowing the next group of passengers to board.</li>
<li><strong>End sensor:</strong> Detects when a lift chair reaches the unloading area. If triggered, it checks whether any passengers remain in the exit area, ensuring a smooth and safe unloading process.</li>
</ul>
</td>
</tr>
<tr>
<td> <img src="assets/ObjectDetector.png" alt="ObjectDetector" width="400">
<td> <a href="lib/ObjectDetector.lf">ObjectDetector.lf</a>: Detects the number of people on the ready and exit areas.</td>
</tr>
<tr>
<td> <img src="assets/LiftMotion.png" alt="LiftMotion" width="400">
<td> <a href="lib/LiftMotion.lf">LiftMotion.lf</a>: Uses a modal model to control the motion of the lift.</td>
</tr>
</table>


Binary file added examples/C/src/SkiLift/assets/EntryGate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/C/src/SkiLift/assets/EntrySenor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/C/src/SkiLift/assets/Lift.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/C/src/SkiLift/assets/LiftMotion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/C/src/SkiLift/assets/LiftSensor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/C/src/SkiLift/assets/ObjectDetector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/C/src/SkiLift/assets/cable-car-solid.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/C/src/SkiLift/assets/demo.mov
Binary file not shown.
25 changes: 25 additions & 0 deletions examples/C/src/SkiLift/lib/EntryGate.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @author Cheng Yen, Tsai
*/
target C


reactor EntryGate {
input open: bool // Toggle mode

mode OPEN {
reaction(open) -> reset(CLOSE) {=
if (open->value) {
lf_set_mode(CLOSE);
}
=}
}

initial mode CLOSE {
reaction(open) -> reset(OPEN) {=
if (!open->value) {
lf_set_mode(OPEN);
}
=}
}
}
33 changes: 33 additions & 0 deletions examples/C/src/SkiLift/lib/EntrySensor.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @author Cheng Yen, Tsai
*/
target C

preamble {=
#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
=}
reactor EntrySensor {
preamble {=
int random_bool() {
srand((unsigned int)time(NULL));
double true_probability = 0.8;
double random_value = (double)rand() / RAND_MAX;
if (random_value < true_probability) {
return 1;
}
return 0;
};
=}
output gate_1: bool
output gate_2: bool
output gate_3: bool

timer t(0, 200 msec);
reaction(t) -> gate_1, gate_2, gate_3 {=
lf_set(gate_1, random_bool());
lf_set(gate_2, random_bool());
lf_set(gate_3, random_bool());
=}
}
31 changes: 31 additions & 0 deletions examples/C/src/SkiLift/lib/LiftMotion.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
target C
import ScreenPrinter from "ScreenPrinter.lf"
reactor LiftMotion {
input move: bool // Toggle mode
input offset: int32_t
screenPrinter = new ScreenPrinter()

initial mode MOVING {
reaction(move, offset) ->
reset(MOVING), reset(STOPPED), screenPrinter.motion_msg, screenPrinter.offset {=
if (move->value) {
lf_set(screenPrinter.offset, offset->value);
lf_set_mode(MOVING);
} else {
lf_set_mode(STOPPED);
lf_set(screenPrinter.motion_msg ,"Stop");
}
=}
}

mode STOPPED {
reaction(move) -> reset(MOVING), reset(STOPPED), screenPrinter.motion_msg {=
if (!move->value) {
lf_set_mode(STOPPED);
} else {
lf_set_mode(MOVING);
lf_set(screenPrinter.motion_msg ,"Moving");
}
=}
}
}
14 changes: 14 additions & 0 deletions examples/C/src/SkiLift/lib/LiftSensor.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @author Cheng Yen, Tsai
*/
target C

reactor LiftSensor {
output start_ready: bool
output end_ready: bool

reaction(startup) -> start_ready, end_ready {=
lf_set(start_ready, true);
lf_set(end_ready, true);
=}
}
14 changes: 14 additions & 0 deletions examples/C/src/SkiLift/lib/ObjectDetector.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @author Cheng Yen, Tsai
*/
target C

reactor ObjectDetector {
output start_number: int32_t
output end_number: int32_t

reaction(startup) -> start_number, end_number {=
lf_set(start_number, 3);
lf_set(end_number, 3);
=}
}
Loading
Loading