# 사례 연구: Xenomai를 활용한 산업 제어 시스템

### 서론

Xenomai는 실시간 성능을 필요로 하는 다양한 산업 애플리케이션에 널리 사용되는 실시간 프레임워크이다. 이 장에서는 Xenomai를 활용하여 실시간 데이터 수집 및 제어 시스템을 구현하는 사례 연구를 통해 산업 제어 시스템의 구조와 동작 방법을 상세히 설명한다.

### 시스템 개요

#### 시스템 설계 요구사항

산업 제어 시스템은 여러 센서와 액추에이터를 제어하면서 안정적인 실시간 응답을 제공해야 한다. 주요 설계 요구사항은 다음과 같다:

* 실시간 응답성
* 높은 신뢰성 및 내구성
* 확장성
* 유지보수 용이성

### 아키텍처 개요

#### 하드웨어 구성

산업 제어 시스템의 하드웨어 구성 요소는 다음과 같다:

* **중앙 처리 장치(CPU)**: 시스템의 두뇌로, 실시간 연산을 수행한다.
* **센서**: 다양한 데이터를 수집한다. 예를 들어 온도, 압력, 습도 등을 측정한다.
* **액추에이터**: 특정 작업을 수행한다. 예를 들어 모터를 회전시키는 역할을 한다.
* **네트워크 인터페이스**: 다른 시스템과의 통신을 위한 네트워크 연결

#### 소프트웨어 구성

시스템 소프트웨어는 주로 Xenomai를 기반으로 구성되어 있다:

* **핵심 Xenomai 라이브러리**: 실시간 작업 스케줄링을 담당한다.
* **실시간 태스크**: 특정 주기마다 실행되는 작업, 센서 데이터 수집 및 제어 명령 전송 등을 수행한다.
* **IPC(Inter-process Communication)**: 데이터 공유 및 동기화를 위한 통신 메커니즘

### Xenomai 기반 실시간 태스크 설계

#### 실시간 태스크의 분류

실시간 태스크는 각기 다른 우선순위를 가지고 다음과 같이 분류된다:

* **고우선 태스크**: 짧은 주기로 자주 발생하는 긴급 작업. 예를 들어, 시스템 안정성 모니터링
* **저우선 태스크**: 긴 주기로 발생하거나, 긴급하지 않은 작업. 예를 들어 데이터 로깅 및 보고서 생성

#### 실행 주기 및 스케줄링

실시간 태스크는 실행 주기와 우선순위를 기반으로 스케줄링된다. 다음은 주요 설정 변수이다:

* **실행 주기 (T)**: 태스크가 주기적으로 실행되는 주기, 예를 들어 10ms
* **우선순위 (P)**: 태스크가 시스템 내 다른 작업에 비해 얼마나 중요한지를 나타낸다.

수식을 통해 스케줄링을 설명하면 다음과 같다:

$$
T\_i = \frac{1}{f\_i}
$$

여기서, $T\_i$는 i번째 태스크의 실행 주기이고, $f\_i$는 태스크의 실행 빈도이다.

#### 코드 예제

아래는 주기적으로 실행되는 실시간 태스크의 코드 예제이다:

```c
#include <xenomai/init.h>
#include <xenomai/native/task.h>

RT_TASK my_task;

void my_task_proc(void *arg) {
    while (1) {
        rt_printf("실시간 태스크 실행 중...\n");
        rt_task_sleep(rt_timer_ns2ticks(10000000)); // 10ms 주기
    }
}

int main(int argc, char *argv[]) {
    rt_task_create(&my_task, "MyTask", 0, 99, 0);
    rt_task_start(&my_task, &my_task_proc, NULL);

    pause();
    return 0;
}
```

### 센서 데이터 수집 및 처리

#### 데이터 수집 메커니즘

센서 데이터는 주기적으로 수집되며, 각 센서는 고유의 인터페이스를 통해 데이터를 보내게 된다:

* **폴링 방식**: 주기적으로 센서 상태를 확인하여 데이터를 읽는 방식
* **인터럽트 방식**: 센서에서 신호를 보내 데이터를 즉시 읽어들이는 방식

#### 데이터 전처리

수집된 데이터는 원시 상태로 사용하기 전에 전처리가 필요하다:

* **필터링**: 노이즈 제거
* **변환**: 센서 출력값을 의미 있는 단위로 변환
* **평균화**: 일관된 값을 얻기 위해 여러 샘플의 평균값 계산

#### 코드 예제

아래는 주기적으로 센서 데이터를 수집하고 전처리하는 예제 코드이다:

```c
#include <stdio.h>
#include <xenomai/native/task.h>

#define NUM_SENSORS 3
#define DATA_LENGTH 100

RT_TASK data_collect_task;

int sensor_data[NUM_SENSORS][DATA_LENGTH];

void data_collect_proc(void *arg) {
    int sensor_idx;
    while (1) {
        for (sensor_idx = 0; sensor_idx < NUM_SENSORS; sensor_idx++) {
            sensor_data[sensor_idx][0] = read_sensor(sensor_idx);
            filter_data(sensor_data[sensor_idx]);
            convert_data(sensor_data[sensor_idx]);
            store_data(sensor_data[sensor_idx]);
        }
        rt_task_sleep(rt_timer_ns2ticks(5000000)); // 5ms 주기
    }
}

int main(int argc, char *argv[]) {
    rt_task_create(&data_collect_task, "DataCollectTask", 0, 99, 0);
    rt_task_start(&data_collect_task, &data_collect_proc, NULL);

    pause();
    return 0;
}
```

### 액추에이터 제어

#### 제어 명령 생성 및 전송

액추에이터 제어는 실시간으로 생성된 제어 명령을 액추에이터에 전달함으로써 수행된다:

* **PID 제어**: Proportional-Integral-Derivative 컨트롤러를 사용하여 시스템을 안정화하고 원하는 상태로 유지
* **상태 피드백 제어**: 현재 상태를 피드백 받아 제어 시스템을 최적화

#### 명령 전송 메커니즘

명령 전송은 다음과 같은 방식으로 이루어진다:

* **Direct Memory Access (DMA)**: 대량 데이터 전송시 효율적으로 사용
* **직렬 통신 (UART, I2C, SPI)**: 특정 장치에 명령을 전송할 때 사용
* **이더넷 통신**: 원거리 장치 제어 시 사용

#### 코드 예제

아래는 주기적으로 액추에이터를 제어하는 예제 코드이다:

```c
#include <xenomai/native/task.h>

RT_TASK control_task;

void control_proc(void *arg) {
    int control_cmd;
    while (1) {
        control_cmd = generate_control_cmd();
        send_control_cmd(control_cmd);
        rt_task_sleep(rt_timer_ns2ticks(10000000)); // 10ms 주기
    }
}

int main(int argc, char *argv[]) {
    rt_task_create(&control_task, "ControlTask", 0, 99, 0);
    rt_task_start(&control_task, &control_proc, NULL);

    pause();
    return 0;
}
```

### 데이터 통신 및 동기화

#### IPC (Inter-process Communication) 기법

다수의 실시간 태스크가 동시에 실행되면서 데이터를 공유하고 통신하기 위해 IPC 기법이 사용된다. 주요 IPC 기법은 다음과 같다:

* **파이프(pipe)**
* **큐(queue)**
* **공유 메모리(shared memory)**

#### 동기화 메커니즘

동기화는 경쟁 조건을 방지하고 데이터 일관성을 유지하기 위해 매우 중요하다. 주요 동기화 메커니즘은 다음과 같다:

* **뮤텍스(Mutex)**
* **세마포어(Semaphore)**
* **이벤트(Event)FLAGS**

#### 코드 예제

아래는 큐를 사용해 데이터 통신을 구현하는 예제 코드이다:

```c
#include <xenomai/native/task.h>
#include <xenomai/native/queue.h>

RT_QUEUE my_queue;

RT_TASK producer_task;
RT_TASK consumer_task;

void producer_proc(void *arg) {
    while (1) {
        int data = generate_data();
        rt_queue_write(&my_queue, &data, sizeof(data), Q_NORMAL);
        rt_task_sleep(rt_timer_ns2ticks(1000000)); // 1ms 주기
    }
}

void consumer_proc(void *arg) {
    int data;
    while (1) {
        if (rt_queue_read(&my_queue, &data, sizeof(data), TM_INFINITE) > 0) {
            process_data(data);
        }
    }
}

int main(int argc, char *argv[]) {
    rt_queue_create(&my_queue, "MyQueue", 10 * sizeof(int), Q_FIFO);
    
    rt_task_create(&producer_task, "ProducerTask", 0, 99, 0);
    rt_task_start(&producer_task, &producer_proc, NULL);

    rt_task_create(&consumer_task, "ConsumerTask", 0, 99, 0);
    rt_task_start(&consumer_task, &consumer_proc, NULL);

    pause();
    return 0;
}
```

Xenomai를 활용한 산업 제어 시스템은 높은 신뢰성과 실시간 응답성을 제공하여 다양한 산업 애플리케이션에 적합한다.
