Skip to main content
Summary

센서는 읽고, 액추에이터는 반응한다

지난 장에서는 LED를 켜고 버튼을 읽었다. 이번에는 같은 구조를 조금 넓힌다. 버튼 대신 온도, 습도, 거리, 밝기 같은 주변 환경을 읽는다. LED 대신 부저, 모터, 릴레이, 디스플레이처럼 실제 반응을 만드는 장치를 움직인다.

센서는 라즈베리파이에 정보를 넣어 주는 입력 장치다. DHT11이나 DHT22는 온도와 습도를 읽는다. 초음파 거리 센서는 앞에 있는 물체까지의 거리를 잰다. 조도 센서는 주변이 밝은지 어두운지 알려 준다.

액추에이터는 라즈베리파이의 판단을 실제 동작으로 바꾸는 출력 장치다. 부저는 소리를 낸다. 서보 모터는 정해진 각도로 움직인다. 릴레이 모듈은 라즈베리파이보다 큰 전압이나 전류를 쓰는 외부 장치를 켜고 끄는 데 사용된다. OLED 같은 작은 디스플레이는 센서값을 화면에 보여 준다.

기본 흐름은 단순하다.

  1. 센서값을 읽는다.

  2. 사람이 이해하기 쉬운 단위로 바꾼다.

  3. 기준값과 비교한다.

  4. 부저, 모터, 화면 같은 출력 장치를 제어한다.

  5. 이 과정을 반복한다.

이 구조를 익히면 라즈베리파이는 단순한 컴퓨터가 아니라 주변 환경에 반응하는 작은 장치가 된다.

센서와 액추에이터 연결하기AI 생성 이미지

센서마다 연결 방식이 다르다

센서를 고를 때는 "무엇을 측정하는가"만 보지 말고 "라즈베리파이에 어떻게 연결하는가"도 함께 봐야 한다.

가장 쉬운 방식은 디지털 GPIO 입력이다. 버튼처럼 HIGH 또는 LOW, 즉 1 또는 0에 가까운 상태를 읽는다. 일부 움직임 감지 센서나 간단한 스위치형 센서가 여기에 해당한다.

DHT11, DHT22 같은 온습도 센서는 한 개의 데이터 선으로 온도와 습도 값을 전달한다. 단순한 HIGH/LOW만 읽는 것은 아니고, 센서 전용 통신 방식에 맞는 라이브러리를 사용해 값을 가져온다. DHT11은 저렴하고 입문용으로 좋지만 정밀도와 측정 범위가 제한적이다. DHT22는 보통 더 넓은 범위와 나은 정밀도를 제공한다. 실습에서는 둘 중 하나만 안정적으로 읽어도 충분하다.

초음파 거리 센서는 소리를 보내고 되돌아오는 시간을 계산해 거리를 구한다. 흔히 쓰는 HC-SR04 계열 센서는 Trigger 핀으로 신호를 보내고 Echo 핀에서 돌아오는 시간을 읽는다. 이때 주의할 점이 있다. 많은 초음파 센서의 Echo 출력은 5V일 수 있다. 라즈베리파이 GPIO는 3.3V 입력 기준이므로, 5V 신호를 그대로 넣으면 보드가 손상될 수 있다. 3.3V 호환 모듈을 쓰거나 저항 분압 회로, 레벨 시프터를 사용해야 한다.

조도 센서는 조금 다르다. 주변 밝기에 따라 저항값이나 전압이 연속적으로 바뀐다. 이런 값을 아날로그 값이라고 한다. 문제는 라즈베리파이 GPIO가 기본적으로 아날로그 입력을 직접 읽지 못한다는 점이다. 그래서 조도 센서처럼 연속적인 전압을 읽으려면 MCP3008 같은 ADC 모듈이 필요하다. ADC는 Analog-to-Digital Converter의 줄임말로, 아날로그 전압을 라즈베리파이가 읽을 수 있는 숫자로 바꿔 주는 장치다.

I2C와 SPI도 자주 만난다. I2C는 SDA와 SCL 두 선으로 여러 센서나 디스플레이를 연결하는 방식이다. OLED 디스플레이, 기압 센서, 일부 온습도 센서에서 자주 사용된다. SPI는 선을 더 많이 쓰지만 빠른 통신에 유리하다. MCP3008 ADC처럼 SPI로 연결하는 부품도 많다.

초보자는 이렇게 구분하면 된다.

  • 단순한 켜짐/꺼짐 상태: 디지털 GPIO

  • 온도·습도 같은 센서 전용 데이터: 전용 라이브러리 사용

  • 밝기·가변저항처럼 연속적인 값: ADC 필요

  • 여러 센서나 작은 화면: I2C 또는 SPI 확인

센서값을 계속 읽는 기본 코드 패턴

센서는 한 번 읽고 끝나는 경우보다 계속 읽는 경우가 많다. 온도는 시간이 지나며 바뀌고, 거리는 물체가 움직이면 달라진다. 그래서 센서 코드는 보통 while True 반복문을 사용한다.

온습도 센서를 읽는 기본 형태는 다음과 비슷하다. 실제 핀 번호와 라이브러리는 사용하는 센서와 설치 환경에 맞게 조정해야 한다.

import time
import board
import adafruit_dht

dht = adafruit_dht.DHT22(board.D4)

while True:
    try:
        temperature = dht.temperature
        humidity = dht.humidity

        print(f"온도: {temperature:.1f}°C")
        print(f"습도: {humidity:.1f}%")

    except RuntimeError as error:
        print("센서 읽기 오류:", error.args[0])

    time.sleep(2)

여기서 중요한 부분은 네 가지다.

첫째, 반복해서 읽는다. while True는 프로그램을 계속 실행하게 한다. 멈추고 싶을 때는 터미널에서 Ctrl + C를 누른다.

둘째, 너무 자주 읽지 않는다. time.sleep(2)는 2초 기다리라는 뜻이다. 센서는 종류마다 권장 측정 간격이 있다. 너무 빠르게 읽으면 값이 흔들리거나 오류가 늘어날 수 있다.

셋째, 예외 처리를 한다. 센서는 가끔 값을 제대로 주지 못한다. 그때 프로그램이 바로 종료되면 자동화 장치로 쓰기 어렵다. try/except를 사용하면 일시적인 읽기 실패를 출력하고 다음 반복으로 넘어갈 수 있다. DHT 센서를 반복해서 읽고 오류를 처리하는 예제에서도 이런 패턴이 사용된다.1

넷째, 단위를 붙여 출력한다. 23.5보다 23.5°C가 이해하기 쉽다. 프로젝트가 커질수록 숫자만 출력하면 헷갈린다.

조건을 붙이면 자동화가 시작된다

센서값을 읽기만 하면 모니터링이다. 읽은 값을 기준으로 동작을 결정하면 자동화가 된다.

예를 들어 온도가 30°C 이상이면 경고음을 울리고, 그렇지 않으면 끄는 구조를 만들 수 있다.

if temperature >= 30:
    buzzer.on()
else:
    buzzer.off()

거리 센서라면 이렇게 생각할 수 있다.

if distance_cm < 20:
    buzzer.on()
else:
    buzzer.off()

하지만 실제 센서값은 완벽하게 고정되지 않는다. 물체가 20cm 근처에 있을 때 값이 19.8, 20.1, 19.9처럼 흔들리면 부저가 빠르게 켜졌다 꺼졌다 할 수 있다. 이때는 기준값을 하나만 쓰지 말고 여유 구간을 둔다.

예를 들어 20cm보다 가까우면 부저를 켜고, 25cm보다 멀어질 때만 끈다.

alarm_on = False

if distance_cm < 20:
    alarm_on = True
elif distance_cm > 25:
    alarm_on = False

이런 방식을 히스테리시스라고 한다. 말은 어렵지만 원리는 간단하다. 켜지는 기준과 꺼지는 기준을 다르게 두어 경계 근처의 흔들림을 줄이는 방법이다.

부저: 능동 부저와 수동 부저 구분하기

부저는 초보자가 쓰기 좋은 출력 장치다. 소리로 결과를 바로 확인할 수 있기 때문이다. 다만 능동 부저와 수동 부저를 구분해야 한다.

능동 부저는 내부에 소리를 만드는 회로가 들어 있다. 그래서 GPIO 출력으로 전압을 켜고 끄는 것만으로 "삐" 소리를 낼 수 있다. 온도가 기준보다 높거나, 거리가 너무 가까울 때 경고음을 내는 용도에 적합하다. 능동 부저는 단순한 HIGH/LOW 제어만으로 안정적인 소리를 낼 수 있다는 점이 장점이다.2

수동 부저는 내부 발진 회로가 없다. 그래서 단순히 전압을 걸어도 원하는 소리가 나지 않거나 약하게 반응할 수 있다. 수동 부저로 음을 내려면 PWM을 사용해야 한다. PWM은 빠르게 켜고 끄는 신호를 만들어 특정 주파수의 소리를 내는 방식이다. 주파수를 바꾸면 다른 음을 만들 수 있다. 멜로디를 연주하려면 수동 부저가 더 적합하다.2

입문 프로젝트에서 경고음만 필요하다면 능동 부저를 선택하는 편이 쉽다.

from gpiozero import Buzzer
from time import sleep

buzzer = Buzzer(17)

while True:
    buzzer.on()
    sleep(0.2)
    buzzer.off()
    sleep(1)

부저도 전류를 사용한다. 작은 부저 하나는 단순 실습에서 GPIO로 제어할 수 있는 경우가 많지만, 부품 사양을 확인하는 습관이 필요하다. 소리가 큰 부저나 모듈형 경보 장치는 별도 전원이 필요할 수 있다.

서보 모터와 릴레이는 더 조심해야 한다

LED와 작은 부저는 비교적 단순하다. 하지만 서보 모터, DC 모터, 릴레이는 더 조심해야 한다. 이 장치들은 GPIO 핀 하나가 감당하기 어려운 전류를 요구할 수 있다.

서보 모터는 보통 전원, GND, 신호선 세 가닥을 사용한다. 신호선은 라즈베리파이 GPIO에 연결하고, 전원은 모터 사양에 맞는 별도 전원을 쓰는 것이 안전하다. 이때 라즈베리파이 GND와 외부 전원 GND는 함께 연결해야 한다. 이를 공통 GND라고 한다. 기준점이 같아야 라즈베리파이의 신호를 모터가 제대로 이해할 수 있다.

서보 모터는 PWM 신호로 각도를 제어한다. 예를 들어 0도, 90도, 180도처럼 원하는 위치로 움직일 수 있다. 하지만 모터가 움직일 때 순간적으로 전류를 많이 먹을 수 있으므로, 라즈베리파이의 5V 핀에서 여러 모터를 직접 공급하는 방식은 피하는 것이 좋다.

릴레이 모듈은 작은 신호로 큰 전원을 켜고 끄는 스위치 역할을 한다. 조명, 팬, 펌프 같은 장치를 제어하는 프로젝트에서 자주 등장한다. 그러나 릴레이가 외부 전원, 특히 가정용 AC 전원을 다루는 순간 위험도가 크게 올라간다. 초보자는 고전압 AC를 직접 다루지 말고, 저전압 장치나 안전한 완제품 모듈부터 연습해야 한다.

모터나 릴레이처럼 코일이 들어간 장치는 전원이 끊길 때 역전류가 생길 수 있다. 이 역전류는 라즈베리파이를 손상시킬 수 있다. 그래서 모터 드라이버, 트랜지스터, 다이오드 보호 회로, 릴레이 모듈처럼 보호가 포함된 부품을 사용한다.

기억할 규칙은 세 가지다.

  • GPIO는 신호용이지 전원 공급용이 아니다.

  • 전류가 큰 장치는 별도 전원을 사용한다.

  • 외부 전원을 쓰면 GND를 공유하고, 보호 회로를 확인한다.

작은 거리 경고기 만들기

지금까지의 내용을 하나로 묶어 보자. 목표는 물체가 가까워지면 부저가 울리는 거리 경고기다.

구성은 다음과 같다.

  • 입력: 초음파 거리 센서

  • 처리: 거리값을 cm 단위로 계산

  • 판단: 20cm보다 가까우면 위험, 25cm보다 멀어지면 해제

  • 출력: 능동 부저 켜기/끄기

이 프로젝트에서 핵심은 코드보다 구조다.

alarm_on = False

while True:
    distance = read_distance_cm()
    print(f"거리: {distance:.1f} cm")

    if distance < 20:
        alarm_on = True
    elif distance > 25:
        alarm_on = False

    if alarm_on:
        buzzer.on()
    else:
        buzzer.off()

    time.sleep(0.2)

read_distance_cm() 함수 안에는 초음파 센서를 실제로 읽는 코드가 들어간다고 생각하면 된다. 처음부터 모든 코드를 한 번에 완성하려고 하지 말자. 먼저 거리만 출력한다. 그다음 부저만 따로 켜고 끈다. 마지막으로 둘을 조건문으로 연결한다. 이렇게 나누면 문제가 생겼을 때 원인을 찾기 쉽다.

센서값이 흔들릴 때 안정화하는 방법

현실의 센서값은 늘 조금씩 흔들린다. 온도는 천천히 변하지만, 습도는 측정할 때마다 약간씩 달라질 수 있다. 초음파 거리 센서는 물체의 표면, 각도, 주변 소음에 영향을 받는다. 조도 센서는 그림자나 형광등 깜빡임에도 반응할 수 있다.

안정적인 프로젝트를 만들려면 값을 그대로 믿기보다 조금 다듬어야 한다.

가장 쉬운 방법은 여러 번 읽어 평균을 내는 것이다.

def average(values):
    return sum(values) / len(values)

거리값을 5번 읽어 평균을 내면 순간적인 튐을 줄일 수 있다. 단, 평균을 많이 낼수록 반응이 느려진다. 경고 장치처럼 빠른 반응이 필요한 경우에는 너무 많은 샘플을 쓰지 않는 것이 좋다.

두 번째 방법은 최소 변화폭을 정하는 것이다. 예를 들어 온도가 0.1°C 바뀔 때마다 화면을 갱신하면 숫자가 계속 흔들려 보일 수 있다. 0.5°C 이상 변했을 때만 갱신하면 더 안정적으로 보인다.

세 번째 방법은 임계값에 여유를 두는 것이다. 앞에서 본 것처럼 20cm에서 켜고 25cm에서 끄면 부저가 불안정하게 깜빡이는 일을 줄일 수 있다.

네 번째 방법은 간단한 보정이다. 온도계와 비교했을 때 센서가 항상 1°C 높게 나온다면 코드에서 1을 빼서 표시할 수 있다. 단, 보정값은 센서와 환경에 따라 다르므로 무조건 적용하지 말고 비교 후 결정해야 한다.

프로젝트를 안전하게 확장하는 순서

센서와 액추에이터를 함께 쓰면 라즈베리파이 프로젝트가 훨씬 재미있어진다. 하지만 복잡한 회로를 한 번에 만들면 어디서 문제가 생겼는지 알기 어렵다.

다음 순서로 진행하자.

  1. 센서만 연결해 값을 출력한다.

  2. 액추에이터만 연결해 켜고 끄거나 움직여 본다.

  3. 센서값과 조건문을 연결한다.

  4. 값이 흔들리면 평균, 여유 구간, 보정을 적용한다.

  5. 장시간 실행해 발열, 전원, 오류 메시지를 확인한다.

라즈베리파이는 외부 세계와 연결될 때 가장 강력해진다. 온도와 습도를 읽고, 거리를 판단하고, 밝기에 따라 반응하는 순간 단순한 컴퓨터가 작은 자동화 장치로 바뀐다. 이번 장의 핵심은 특정 센서 하나를 외우는 것이 아니다. 입력을 읽고, 조건을 판단하고, 안전하게 출력하는 흐름을 익히는 것이다. 이 흐름은 다음 장에서 네트워크와 원격 접속을 만나 더 넓은 프로젝트로 이어진다.

참고

1Python GPIO Tutorial: Control LEDs, Buttons, and Sensors on Raspberry Pi - PCBSync

2How to Use Buzzers on the Raspberry Pi

책 목록

라즈베리파이 첫걸음: 설치부터 GPIO·서버·IoT 프로젝트까지

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기