
Raspberry Pi + Relay: Điều khiển thiết bị điện qua GPIO
Dùng relay 1 kênh 5V điều khiển đóng/ngắt thiết bị điện (đèn, quạt) qua GPIO Raspberry Pi, kèm cơ chế watchdog an toàn tự ngắt khi bật quá lâu.
Dự án nhập môn GPIO thứ ba: dùng module relay 1 kênh để đóng/ngắt một thiết bị điện (đèn, quạt, ổ cắm) bằng tín hiệu digital từ Raspberry Pi.
Bạn sẽ học nguyên lý relay active-low, cách điều khiển an toàn, và xây dựng một dịch vụ điều khiển có lịch bật/tắt tự động cùng cơ chế watchdog tự ngắt để tránh thiết bị bị bật "quên" quá lâu, một yêu cầu an toàn bắt buộc khi điều khiển tải điện thực tế.
Hướng dẫn chi tiết
Hướng dẫn dùng relay 1 kênh 5V để đóng/ngắt tải DC 5V/12V (đèn LED, quạt DC) qua GPIO Raspberry Pi, an toàn tuyệt đối cho người mới, kèm 3 mẫu code Python và cơ chế watchdog tự ngắt.
1. Giới thiệu
Module relay là cách phổ biến nhất để một vi điều khiển tín hiệu thấp (3.3V/5V, vài mA) điều khiển đóng/ngắt một tải công suất lớn hơn — nhờ cơ chế đóng/ngắt bằng cơ khí (cuộn dây nam châm điện hút tiếp điểm) và cách ly quang (opto-isolator) bảo vệ GPIO.
Relay module phổ biến trên thị trường thường là loại active-low: chân IN ở mức LOW (0V) thì relay đóng (kích hoạt), mức HIGH (3.3V/5V) thì relay mở (ngắt) — ngược với trực giác "HIGH = bật" thông thường, nên rất dễ nhầm khi mới học.
Bài này dùng tải DC 5V/12V (đèn LED 12V, quạt DC nhỏ, bơm mini 5V) làm chuẩn để bạn thực hành an toàn tuyệt đối, không rủi ro điện giật khi mới học GPIO/relay.
2. Linh kiện cần có
| Linh kiện | Số lượng | Giá tham khảo |
|---|---|---|
| Raspberry Pi 4 Model B (đã cài Raspberry Pi OS) hoặc các phiên bản khác | 1 | ~1.500.000đ |
| Relay Module 1 kênh 5V (có opto-isolator) | 1 | ~20.000đ |
| Dây jumper (male-female) | 3 sợi | ~5.000đ |
| Tải DC để test: đèn LED 12V/dải LED 12V, hoặc quạt DC nhỏ (kèm nguồn 12V/5V riêng cho tải) | 1 | ~30.000–50.000đ |
3. Sơ đồ kết nối
| Relay Module | Raspberry Pi 4 |
|---|---|
| VCC | 5V (Pin 2) |
| GND | GND |
| IN | GPIO18 (Pin 12) — active-low: LOW = relay đóng (BẬT) |
| COM / NO | Mắc nối tiếp trên dây dương (+) của tải DC 12V/5V, nguồn tải lấy từ adapter riêng — không lấy từ RPi |
An toàn: tải DC 12V/5V không gây nguy hiểm điện giật, có thể chạm tay vào dây khi đang test. Vẫn nên tắt nguồn tải khi đấu/tháo dây để tránh phát sinh tia lửa nhỏ hoặc chập chân relay.
4. Code ví dụ #1 — Bật/tắt relay cơ bản
Đóng/mở relay theo chu kỳ 3 giây để kiểm tra kết nối hoạt động đúng, đồng thời minh hoạ hàm tiện ích relay_on()/relay_off() đóng gói logic active-low.
#!/usr/bin/env python3
"""
Raspberry Pi + Relay 1 kenh - Dieu khien tai DC (den LED 12V, quat DC...) qua GPIO
Wiring:
Relay VCC -> RPi 5V
Relay GND -> RPi GND
Relay IN -> RPi GPIO18 (active-low: LOW = dong relay = BAT)
Relay COM/NO -> day duong (+) cua tai DC, nguon tai lay tu adapter rieng
"""
import RPi.GPIO as GPIO
import time
RELAY_PIN = 18
ACTIVE_LOW = True # module relay pho bien la active-low
def relay_on():
GPIO.output(RELAY_PIN, GPIO.LOW if ACTIVE_LOW else GPIO.HIGH)
def relay_off():
GPIO.output(RELAY_PIN, GPIO.HIGH if ACTIVE_LOW else GPIO.LOW)
def setup():
GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY_PIN, GPIO.OUT)
relay_off()
print("[BOOT] Relay controller ready. GPIO18 active-low.")
def main():
setup()
try:
while True:
print("Relay: BAT")
relay_on()
time.sleep(3)
print("Relay: TAT")
relay_off()
time.sleep(3)
except KeyboardInterrupt:
print("\n[EXIT] Dung boi nguoi dung")
finally:
relay_off()
GPIO.cleanup()
if __name__ == "__main__":
main()
5. Code ví dụ #2 — Điều khiển đèn theo lịch giờ tự động
Ứng dụng thực tế phổ biến: tự động bật đèn LED 12V vào buổi tối (18h) và tắt vào sáng sớm (6h) mà không cần can thiệp thủ công.
#!/usr/bin/env python3
"""
Raspberry Pi + Relay - Dieu khien den LED 12V theo lich gio tu dong
"""
import RPi.GPIO as GPIO
import time
from datetime import datetime
RELAY_PIN = 18
ON_HOUR = 18 # 18:00 bat den
OFF_HOUR = 6 # 06:00 tat den
CHECK_INTERVAL_S = 30
def relay_on():
GPIO.output(RELAY_PIN, GPIO.LOW)
def relay_off():
GPIO.output(RELAY_PIN, GPIO.HIGH)
def should_be_on(now=None):
now = now or datetime.now()
h = now.hour
if ON_HOUR > OFF_HOUR:
return h >= ON_HOUR or h < OFF_HOUR
return ON_HOUR <= h < OFF_HOUR
def setup():
GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY_PIN, GPIO.OUT)
relay_off()
print(f"[BOOT] Lich chieu sang tu dong: BAT {ON_HOUR}:00 -> TAT {OFF_HOUR}:00")
def main():
setup()
current_state = None
try:
while True:
want_on = should_be_on()
if want_on != current_state:
if want_on:
relay_on()
print(f"[{datetime.now():%H:%M:%S}] Den: BAT (theo lich)")
else:
relay_off()
print(f"[{datetime.now():%H:%M:%S}] Den: TAT (theo lich)")
current_state = want_on
time.sleep(CHECK_INTERVAL_S)
except KeyboardInterrupt:
print("\n[EXIT] Dung boi nguoi dung")
finally:
relay_off()
GPIO.cleanup()
if __name__ == "__main__":
main()
6. Code ví dụ #3 — Ứng dụng thực tế: dịch vụ điều khiển có watchdog an toàn
Phiên bản gần với triển khai thực tế nhất: tích hợp watchdog tự động ngắt nếu tải bị bật quá lâu (ví dụ 30 phút) — bảo vệ khỏi tình huống quên tắt gây quá nhiệt/lãng phí điện.
#!/usr/bin/env python3
"""
Raspberry Pi + Relay - Dich vu dieu khien an toan: watchdog tu ngat sau
thoi gian toi da, tranh tai DC bi bat "quen" gay qua nhiet.
"""
import RPi.GPIO as GPIO
import time
import json
RELAY_PIN = 18
MAX_ON_DURATION_S = 60 * 30 # 30 phut - tu dong tat neu bat qua lau
TELEMETRY_INTERVAL_S = 5.0
state = {"on": False, "on_since": None}
def relay_on():
GPIO.output(RELAY_PIN, GPIO.LOW)
state["on"] = True
state["on_since"] = time.time()
def relay_off():
GPIO.output(RELAY_PIN, GPIO.HIGH)
state["on"] = False
state["on_since"] = None
def setup():
GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY_PIN, GPIO.OUT)
relay_off()
print(f"[BOOT] Relay safety service ready. Watchdog max-on = {MAX_ON_DURATION_S}s")
def toggle():
if state["on"]:
relay_off()
print("Relay: TAT (toggle)")
else:
relay_on()
print("Relay: BAT (toggle)")
def main():
setup()
last_telemetry = 0.0
last_toggle_demo = time.time()
try:
while True:
now = time.time()
if state["on"] and state["on_since"] is not None:
if now - state["on_since"] > MAX_ON_DURATION_S:
print("[WARN] Watchdog: qua thoi gian BAT toi da -> tu dong TAT")
relay_off()
if now - last_toggle_demo > 10:
toggle()
last_toggle_demo = now
if now - last_telemetry >= TELEMETRY_INTERVAL_S:
telemetry = {
"actuator": "relay_1ch",
"on": state["on"],
"on_duration_s": round(now - state["on_since"], 1) if state["on_since"] else 0,
}
print(json.dumps(telemetry))
last_telemetry = now
time.sleep(0.5)
except KeyboardInterrupt:
print("\n[EXIT] Dung boi nguoi dung")
finally:
relay_off()
GPIO.cleanup()
if __name__ == "__main__":
main()
7. Lỗi thường gặp
| Lỗi | Nguyên nhân | Cách sửa |
|---|---|---|
| Relay kêu "tách" nhưng đèn không sáng dù đã nối đúng NO/COM | Đấu nhầm dây tải vào NC (Normally Closed) thay vì NO (Normally Open) | Kiểm tra lại: dùng NO nếu muốn "tắt mặc định, bật khi kích hoạt" |
| Relay tự kích hoạt (kêu tách) ngay khi Raspberry Pi vừa khởi động | Chân GPIO mặc định ở trạng thái floating trong lúc boot Linux | Không có cách khắc phục hoàn toàn bằng phần mềm; cân nhắc relay module có chốt cơ hoặc mạch trễ khởi động phần cứng |
Code gọi relay_on() nhưng relay không đóng | Nhầm active-low: nghĩ HIGH = bật nhưng module là active-low | Kiểm tra thông số module (đa số ghi "Low Level Trigger" trên board) |
| Chương trình dừng đột ngột nhưng relay vẫn đang đóng | Crash/kill process không qua try/finally | Luôn dùng cấu trúc try/finally như code mẫu |
8. Tổng kết
Qua dự án này, bạn đã nắm được cách dùng relay để điều khiển tải DC an toàn từ GPIO điện áp thấp, hiểu logic active-low thường gặp trên relay module giá rẻ, và các nguyên tắc an toàn: mặc định tắt khi khởi động, watchdog tự ngắt.
Ba mẫu code từ điều khiển cơ bản → lịch giờ tự động → dịch vụ có watchdog cho thấy lộ trình nâng cấp từ demo học tập lên một thành phần điều khiển đáng tin cậy hơn. Hướng mở rộng tiếp theo: ghép relay với cảm biến (ánh sáng, nhiệt độ) để tự động hoá theo điều kiện thực tế, hoặc điều khiển qua web/MQTT từ xa.