2021정보영재>피지컬컴퓨팅

4주차

스마트홈 교육용 키트 - 각자 도전하기

수업은? Python GUI 프로그램으로 스마트홈 구현 (처음부터 끝까지 스스로 만들기)

개요

▣ 주제: SmartHome

▣ 입력: 조도(cds), 거리(ir), 온습도(dht11)

▣ 출력: 전등(RGB LED), 환풍(12V 팬), 서보모터(5V)

▣ 시스템 상태 화면 표시

┌---------------------------┐

│ Humi: 64% Temp: 29.9°C │ <--- 온도, 습도

│ Ir : 0 Cds : 1016 │ <--- 거리, 조도

│ >L(0):0 >F(0):0 >D(0):0 │ <--- Lamp|Fan|Door(작동모드): 현재 상태(0-닫힘,1-열림)

└---------------------------┘

파이썬 GUI 프로그래밍

파이썬 코드: smartHome-1.py

파이썬 제어화면

▣ 제어 프로토콜(명령어 형식)

  • 전등 제어

L0(끄기), L1(켜기), L2(자동제어) *설정 조도

  • 환풍기 제어

F0(끄기), F1(켜기), F2(자동제어) *설정 온도

  • 출입문 제어

D0(닫기), D1(열기), D2(자동제어) *물체 접근

아두이노 회로 구성

펌웨어: smartHome.ino

#define DHTPIN 3 // 온습도 센서(dht)

#define servoPin 6 // 서보모터

#define FAN_PIN 7 // 환풍기

#define RED_PIN 9 // RGB(빨강)

#define GRN_PIN 10 // RGB(초록)

#define BLU_PIN 11 // RGB(파랑)

#define CDS_PIN A0 // 조도 센서(cds)

#define IR_PIN A1 // 적외선 센서(ir)

동작 영상

아두이노 1단계: 모듈 개발

모듈 개발의 장점

  1. 디버깅이 쉽다.

  2. 재사용 가능

  3. 시스템 확장 통합 용이

모듈 개발 방법

  1. 인터넷에서 신뢰할 만한 자료 찾기(개인 자료 보다 기업이나 아두이노 공식 홈페이지)

  2. 인터넷 상의 오픈소스 코드나 모듈의 예제 파일 실행하기

  3. 내가 원하는 기능 구현하기

  4. 시스템 통합을 위해 기능을 함수로 구현하기

모듈 개발 실제

입력은 getOOO.ino , 출력은 ctrlOOO.ino 파일의 형태로 개발

  1. 입력 센서

가. 조도센서(CDS) 1_getCDS.ino


#define CDS_PIN A0 // 조도 센서(cds)


int cdsValue; // 조도 센서값


void setup() {

Serial.begin(9600);

}


void loop() {

//조도 센서값 읽기(0~1023)

cdsValue = getCDS(CDS_PIN);


// 조도 센서 밝기값을 직렬 통신으로 출력

Serial.print("cds:"); Serial.println(cdsValue);

delay(500);

}


int getCDS(int pin){

return analogRead(pin);

}



. 적외선센서(IR) 2_getIR.ino

// 출처 https://create.arduino.cc/projecthub/Raushancpr/arduino-with-ir-sensor-1579b6

// 모듈 감지 거리 2 ~ 30cm, 각도 35 °, 탐지 거리는 전위차계에 의해 방향 전위차계,

// 탐지 거리는 증가합니다; 탐지 거리를 감소시키는 반 시계 방향 전위차계.

// 출력은 디지털(1:범위 내, 0:범위 밖)


#define IR_PIN A1 //적외선 센서(ir)


int irValue; //적외선 센서값


void setup() {

Serial.begin(9600); // 직렬통신 시작

pinMode(IR_PIN, INPUT);

}


void loop() {

// 적외선 센서값 읽기(사물이 범위 내이면 LOW)

irValue = getIR(IR_PIN);


// 적외선 센서값을 직렬 통신으로 출력

Serial.print("ir:");

Serial.println(irValue);


delay(50);

}


int getIR(int pin){

return analogRead(pin);

}




. 온습도센서(DHT11) 3_getDHT.ino

// 예제>DHT sensor library>DHTTester


// 라이브러리 포함

#include <DHT.h>


// 핀번호 매칭

#define DHTPIN 3 // 온습도센서 D3 핀

#define DHTTYPE DHT11 // DHT11


// 객체 인스턴스 생성

DHT dht(DHTPIN, DHTTYPE); // 온습도센서 인스턴스 생성


// 시간 변수

unsigned long now = 0; // 현재 시각

unsigned long prevMillis = 0; // 온습도 이전 측정 시각

const long DHTinterval = 2000; // 온습도 측정 간격


// 센서값 변수

float temperature = 0.; // 온도(dht) 값

float humidity = 0.; // 습도(dht) 값


void setup() {

Serial.begin(9600);

Serial.println(F("DHT11 test!"));

dht.begin();

}


void loop() {

if (isTimeToReadDHT()) { // DHT값 읽은 시간이 되었으면

getDHT(); // 온습도 읽기 (2초 간격으로)

//결과 출력

Serial.print(F("Humidity: "));

Serial.print(humidity,0);

Serial.print(F("% Temperature: "));

Serial.print(temperature,1);

Serial.println(F("°C "));

}

}


// DHT값 읽을 때가 되었나?

boolean isTimeToReadDHT() {

now = millis(); // 현재 시각

if (now - prevMillis >= DHTinterval) return true;

else return false;

}


// DHT값 읽기

void getDHT() {

humidity = dht.readHumidity(); // 습도 읽기

temperature = dht.readTemperature(); // 온도 읽기

if (isnan(humidity) || isnan(temperature) ) { // DHT 읽기 오류 검사

Serial.println("Failed to read from DHT sensor!");

return;

}

prevMillis = now; // 현재 시각 저장

}



DHT 라이브러리 설치

툴>라이브러리관리>dht검색

adafruit 라이브러리 설치

예제 실행

파일> 예제

>DHT sensor library

>DHTtester


2. 출력 장치

가. RGB LED 4_ctrlRGB.ino

//출처: http://wiki.vctec.co.kr/opensource/arduino/rgbled


#define RED_PIN 9

#define GRN_PIN 10

#define BLU_PIN 11


void setup()

{

pinMode(RED_PIN, OUTPUT);

pinMode(GRN_PIN, OUTPUT);

pinMode(BLU_PIN, OUTPUT);

}


void loop()

{

// setColor(255, 0, 0); // red

// delay(1000);

// setColor(0, 255, 0); // green

// delay(1000);

// setColor(0, 0, 255); // blue

// delay(1000);

// setColor(255, 255, 0); // yellow

// delay(1000);

// setColor(80, 0, 80); // purple

// delay(1000);

// setColor(0, 255, 255); // aqua

// delay(1000);


// policeLight();


// randomLight();


lampOnOff(0);

delay(500);

lampOnOff(1);

delay(500);


}


//조명 제어

void lampOnOff(int onoff) {

setColor(onoff * 255, onoff * 255, onoff * 255);

}


//경찰 경보등

void policeLight() {

setColor(255, 0, 0); // red

delay(100);

setColor(0, 0, 255); // blue

delay(100);

}


// 랜덤 동작

void randomLight() {

setColor(random(256), random(256), random(256));

delay(random(200));

}


// RGB 동작

void setColor(int red, int green, int blue)

{

analogWrite(RED_PIN, red);

analogWrite(GRN_PIN, green);

analogWrite(BLU_PIN, blue);

}



. 5_ctrlFAN.ino

#define FAN_PIN 7


void setup()

{

pinMode(FAN_PIN, OUTPUT);

}


void loop()

{

fanOnOff(1);

delay(1000);

fanOnOff(0);

delay(2000);


}


//환풍기 on off 제어

void fanOnOff(int onoff) {

digitalWrite(FAN_PIN, onoff);

}



. 서보모터 6_ctrlServo.ino

// 원하는 각도로 이동하여 멈추기


#include <Servo.h>


#define servoPin 6 //서보모터 핀번호


Servo myServo; // 서보모터 객체 생성


void setup() {

servoMove(0);

delay(500);

servoMove(90);

delay(500);

servoMove(180);

delay(500);

}


void loop() {

}


void servoMove(int servoPos){

//myServo.attach(servoPin); // 서보모터 연결

myServo.write(servoPos);

//delay(500);

//myServo.detach(); // 서보모터 분리(떨림 현상 방지)

}



3. 소스 코드

module.zip

아두이노 2단계: 모 통합

  1. 하나의 폴더에 각 모듈의 ino 파일 모으기

2. 공통 요소 모으기

  1. 라이브러리, 변수, 객체 => parameter.h

  2. setup()

  3. loop()

  4. 소개, 참고 => 0_intro.ino

3. 시스템 구현

  1. 입력 (센서, 명령어)

  2. 처리

  3. 출력

  4. 화면

smartHome.zip

파이썬 GUI 프로그램

소스 코드 smartHome-1.py

# 직렬 통신으로 아두이노 전등(L), 환풍(F), 출입(D) 제어

from tkinter import *

import tkinter.font

import serial

import threading


# Humi: 0% Temp: 0.0°C

# Ir : 1 Cds : 910

# > L(0):0 > F(0):0 > D(0):0


arduino = serial.Serial('COM4' , 57600)


txtlst = ['line1','line2','line3']


if arduino.readable():

print(arduino.readline().decode())


root = Tk()

root.title("스마트홈 제어")

myFont = tkinter.font.Font(family="Arial", size=12, weight="bold")


def updateState():

global txtlst

if arduino.readable():

state = arduino.readline().decode()

if(state[0]=='H'): txtlst[0] = state

if(state[0]=='I'): txtlst[1] = state

if(state[0]=='>'): txtlst[2] = state

txtState.delete(1.0,"end")

txtState.insert(1.0, txtlst[0])

txtState.insert(2.0, txtlst[1])

txtState.insert(3.0, txtlst[2])

threading.Timer(0.1, updateState).start() # 0.1초 간격으로 아두이노 상태 수신


def cmdBtnClick(cmd):

arduino.write(cmd.encode('utf-8'))

txtCmdTx.delete(1.0,"end")

txtCmdTx.insert(1.0, "Tx>> "+ cmd)


txtState = Text(root, width=30, height=3, font ="Consolas 16", relief="sunken") # 30글자, 3줄

txtState.insert(1.0, " Welcome! AIoT ver. 0.1")

txtState.grid(row=0, column=0, columnspan=3, padx=6, pady=10)


btnLampON = Button(root, bg="red", width=10, height=1, text="전등 ON", font=("Arial", 11, "bold"), command=lambda:cmdBtnClick("L1"))

btnLampON.grid(row=1, column=0, padx=1, pady=5)


btnLampOFF = Button(root, bg="orangered", width=10, height=1, text="전등 OFF", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("L0"))

btnLampOFF.grid(row=1, column=1, padx=1, pady=5)


btnLampAuto = Button(root, bg="tomato", width=10, height=1, text="전등 자동", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("L2"))

btnLampAuto.grid(row=1, column=2, padx=1, pady=5)


btnFanON = Button(root, bg="lime", width=10, height=1, text="환풍 ON", font=("Arial", 11, "bold"), command=lambda:cmdBtnClick("F1"))

btnFanON.grid(row=2, column=0, padx=1, pady=5)


btnFanOFF = Button(root, bg="lawngreen", width=10, height=1, text="환풍 OFF", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("F0"))

btnFanOFF.grid(row=2, column=1, padx=1, pady=5)


btnFanAuto = Button(root, bg="chartreuse", width=10, height=1, text="환풍 자동", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("F2"))

btnFanAuto.grid(row=2, column=2, padx=1, pady=5)


btnDoorON = Button(root, bg="deepskyblue", width=10, height=1, text="출입 Open", font=("Arial", 11, "bold"), command=lambda:cmdBtnClick("D1"))

btnDoorON.grid(row=3, column=0, padx=1, pady=5)


btnDoorOFF = Button(root, bg="lightskyblue", width=10, height=1, text="출입 Close", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("D0"))

btnDoorOFF.grid(row=3, column=1, padx=1, pady=5)


btnDoorAuto = Button(root, bg="skyblue", width=10, height=1, text="출입 자동", font=("Arial", 11 ,"bold"), command=lambda:cmdBtnClick("D2"))

btnDoorAuto.grid(row=3, column=2, padx=1, pady=5)


lblCmdTx = Label(root, font ="Consolas 12", text="보낸 명령")

lblCmdTx.grid(row=4, column=0, padx=3, pady=10)


txtCmdTx = Text(root, width=22, height=1, font ="Consolas 14", relief="sunken") # 22글자, 1줄

txtCmdTx.insert(1.0, " Welcome! SmartHome")

txtCmdTx.grid(row=4, column=1, columnspan=2, pady=10)


lblVersion = Label(root, text="SmartHome ver0.2 by KSYUN, Copyleft 2021")

lblVersion.grid(row=5, column=0, columnspan=3, padx=1, pady=5)


updateState() # 현재 상태 계속 모니터링


root.mainloop()

arduino.close()

smartHome-1.py

화면 설계