본문 바로가기

카테고리 없음

아두이노 히터 PID 제어

먼저, 아두이노에 대해서 간단하게 설명하자면 아두이노는 쉽고 간단하게 전자 장치를 제어할 수 있도록 설계된 오픈 소스 플랫폼이다. 아두이노 IDE에서 사용하는 프로그래밍 언어는 C++ 문법을 기반으로 하고 복잡한 C++ 언어를 간소화하고 필수적인 기능만 뽑아냈기 때문에 간단한 코딩으로 원하는 기능을 구현할 수 있다.

 

PID 제어에 대해서도 간단하게 설명하자면 PID 제어는 오차값을 비례, 적분, 미분을 통해 목표치에 안정적이고 원하는 속도로 도달하도록 제어하는 역할을 한다. P(Proportional)제어는 오차값에 비례해서 제어 신호를 생성하고 목표치에 도달하는 속도를 제어하는 역할을 한다. I(Integral)제어는 누적되는 오차값에 비례해서 제어 신호를 생성하고 정상상태 오차를 줄여주는 역할을 한다. D(Derivative)제어는 오차가 변화하는 속도에 비례해서 제어 신호를 생성하고 시스템이 빠르게 목표치에 접근하면서 과도하게 넘어가지 않도록 해주는 역할을 한다. 

 

이번 달에 대학교에서 아두이노를 이용한 액츄에이터 이론 및 실습 교육을 받았는데 그 내용을 요약해서 블로그에 정리하겠다. 첫 번째로, 히터의 PID 제어를 위한 하드웨어 설계를 하고 아두이노 IDE를 통해 소프트웨어를 구성해봤다. 

<브레드보드 기반 하드웨어 회로>

설계한 하드웨어에 대해 전체적으로 간략하게 설명하자면 마이크로컨트롤러는 라즈베리 파이 사에서 제작한 RP 2040 - Zero를 사용했고 온도 센서는 DS18B20을 사용했으며 히터와 테이프로 고정시켜놨다. RP 2040 - Zero 8번 핀을 통해 온도 센서로부터 측정되는 온도 데이터를 송수신하도록 노란 색선을 8번 핀에 연결한 모습이다. 또한, 모터 드라이브로 히터에 전력을 공급하도록 설계했다. 

 

#include <OneWire.h> //1-Wire 통신을 지원하는 라이브러리 불러오기 

#include <DallasTemperature.h> //각 센서를 고유한 ID로 구별할 수 있게 해주고 데이터를 읽어 들이는데 더 용이하게 해주는 라이브러리이다. 

 

OneWire oneWire(8); //OneWire의 객체 생성 -> 8번 핀을 통해 온도 센서와 1 - Wire 통신을 하도록 설정

DallasTemperature DS18B(&oneWire); //DallasTemperature의 객체 생성

 

float temp; //현재 온도값 변수 선언

float pretemp; //이전 온도값 변수 선언

 

int PWM;

 

#define Kp 23 //비례 게인 Kp = 23로 저장

#define Ki 0.2 //적분 게인 Ki = 0.2로 저장

#define Kd 2.0 //미분 게인 Kd = 2.0으로 저장

 

float ref = 40; //ref: 목표 온도

float err; //목표 온도와 현재 온도의 차이

float sum = 0; //오차를 누적한 값(적분)

float dev = 0; //dev: 현재 온도와 이전 온도의 차이(미분)

float PID; //pid 제어신호

 

void setup() {

Serial.begin(9600);

pinMode(1,OUTPUT); //1번 핀을 출력핀으로 설정

digitalWrite(1,LOW); //모터 드라이브는 스위칭 소자의 대각선 운전을 통해 정회전/역회전을 제어한다. 히터에 단일 방향으로 일정하게 전력을 공급해주기 위해서는 다른 대각선에 있는 스위칭 소자를 오프시켜놔야한다. 여기서 0번 핀과 1번 핀 중에 1번 핀을 LOW로 설정해놨다. 

DS18B.begin(); //온도 센서의 통신 초기화 

delay(100);

}

 

void loop() {

DS18B.requestTemperatures(); //객체의 동작 수행 -> 연결된 온도 센서에게 온도 측정을 요청함

temp = DS18B.getTempCByIndex(0); //객체의 동작 수행 및 결과 저장 -> 첫 번째 온도 센서에서 섭씨 온도를 읽어옴, 0은 센서의 인덱스 번호이며 첫 번째 센서를 의미한다. 여러 개의 센서가 사용 될 경우 각 센서마다 인덱스 번호가 부여된다. 

err = ref - temp; //오차값 = 목표 온도값 - 현재 온도값

sum = sum + err; //누적 오차값

sum = constrain(sum,-200,200); //적분이 과도하게 커지는 것을 방지하기 위해 적분 값의 범위를 제

dev = pretemp - temp; //이전 온도값 - 현재 온도값

pretemp = temp; //이전 온도값에 현재 온도값 저장

PID = Kp * err + Ki * sum + Kd * dev;

PWM = map(PID,-50,200,0,255); //map(): 주어진 범위를 다른 범위로 변환하는 함수

PWM = constrain(PWM,0,200);

analogWrite(0,PWM); //0번 핀을 PWM 신호 생성 핀으로 설정

Serial.print("err : ");

Serial.print(err);

Serial.print(" PWM : ");

Serial.print(PWM);

Serial.print(" temp : ");

Serial.println(temp);

delay(500);

}

 

※1 - Wire: 데이터 라인 하나로 여러 개의 센서들과 동시에 통신할 수 있도록 해주는 통신 프로토콜이다. 

프로토콜: 서로 다른 전자 장치들이 데이터를 언제 주고 언제 받을 지 그리고 어떤 형식으로 줄지 약속이 되어야만 통신이 원활하게 되기 때문에 규칙을 정해야 하는데 이러한 통신 규약을 프로토콜이라고 한다. 

 

 

위의 영상은 결과값이고 목표 온도 40도에 도달하기 위해 아두이노 코드를 기반으로 히터에 적용한 PID 제어가 잘 작동하고 있는 지 확인할 수 있다. 현재 온도가 40도보다 낮아서 40도에 도달하기 위해 히터에 더 큰 전력을 공급해야 하니까 PWM 값이 커지는 것을 알 수 있고 40도에 엄청 근접하게 도달하는 시점부터 40도를 넘기면서 부터는 히터에 공급되는 전력을 줄여야 하니까 PWM값이 점점 작아지는 것을 볼 수 있을 것이다. 

 

히터에 적용한 PID 제어의 역할

P제어: 오차가 클수록 히터에 더 큰 전력을 공급하고, 오차가 작아지면 전력을 줄여서 목표 온도에 빠르게 접근할 수 있도록 한다.

I제어: 목표 온도 근처까지 왔지만 약간의 차이가 지속적으로 남아 있다면, 적분 항이 누적된 오차를 보상해 이 차이를 줄이도록 한다.

D제어: 온도가 목표 값에 가까워질수록 미분 항이 변화 속도를 줄여서 과도하게 온도가 오르지 않도록 방지해 안정적인 상태에 도달하게 한다.