얼굴 인식 프로그램이 얼굴을 인식하였을 때, 환영 및 Farewell! 인사를 출력하는 아두이노를 설계하였다.
이전에 랩실에 구비되어 있던 도트 매트릭스를 이용하여 구현을 시도하였다.
하지만 매트릭스가 구형이라 매뉴얼 부족과 확장성 및 이해 부족으로 8x8 매트릭스를 구입해 사용하기로 하였다.
NEED THINGS
-Arduino Uno
-8x8 LED Matrix 4개 (8x32)
Additional library
-Led Control
Matrix Edit
-8x8 Matrix Editor
8x8 매트릭스가 4개 연결된 8x32 매트릭스를 사용한다.
Vcc - 5V
GND - GND
Din - Digital 12
Clk - Digital 11
CS - Digital 10
물리적 핀을 위와 같이 연결한다.
전체 코드
GitHub
#include "LedControl.h"
LedControl.h
를 호출하여 라이브러리 사용을 선언한다.
이 라이브러리는 스케치-라이브러리 포함하기-라이브러리 관리
를 통해 설치할 수 있다.(참고)
//LedControl(Din, Clk, Cs, # of LED Module)
LedControl lc = LedControl(12,11,10,4);
Din, Clk, Cs 연결 핀 번호와, 연결한 8x8 매트릭스 모듈 개수를 파라미터로 넘겨, LedControl형 변수를 선언한다.
우리는 8x8 LED 매트릭스에 글자가 출력되도록 하고 싶다. 그러기 위해서는 위와 같이 도트 매트릭스에 문자가 각각 어떻게 표현될 수 있는지 바이트 단위의 배열로 미리 선언을 해주어야 한다.
대문자와 소문자 알파벳의 출력 화면을 바이트 단위의 데이터로 선언한다.
const byte UPPER[][8] = {//upper case alphabet
{
//A
B00000000,
B00111100,
B01100110,
B01100110,
B01111110,
B01100110,
B01100110,
B01100110
},
//B
{
B00000000,
B01111100,
B01100110,
B01100110,
B01111100,
B01100110,
B01100110,
B01111100
},
...
};
const byte LOWER[][8] = {//lower case alphabet
//a
{
B00000000,
B00000000,
B00000000,
B00111100,
B00000110,
B00111110,
B01100110,
B00111110
},
//b
{
B00000000,
B01100000,
B01100000,
B01100000,
B01111100,
B01100110,
B01100110,
B01111100
},
...
};
추가로, 우리는 글자를 전광판처럼 흘러가도록 출력하고 싶다.
이때, 글자 출력 후 NULL 4칸이 함께 출력되어(4개의 매트릭스이기 때문에 4개) 글자가 모두 매트릭스에서 지나간 후 사라지도록 NULL을 선언해준다.
또한 "Hello,Name"이 출력되도록 comma도 선언해준다.
const byte NONE[][8] = {
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000
};
const byte COMMA[8]{
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B01100000,
B01100000,
B00100000
};
Arduino 실행 시 처음에 한 번만 수행되는 setup 함수에 아래와 같이 매트릭스를 세팅해준다.
우리는 추후에 이름 문자열을 파이썬에서 아두이노로 전달해, 아두이노가 LED 출력을 수행할 수 있도록 설계할 것이다.
즉 시리얼 통신
을 통해 출력할 데이터를 전달하면, 그에 따라 아두이노는 LED 출력을 달리 한다.
이 작업을 수행하기 위해서는 시리얼 통신
에 대한 작업이 필요하다.
void setup() {
for(int num=0; num<4; num++) // 매트릭스 0번부터 3번까지 세팅
{
lc.shutdown(num,false); // 0~3번까지 매트릭스 절전모드 해제
lc.setIntensity(num,2); // 0~3번까지 매트릭스의 밝기 0~15까지 가능
lc.clearDisplay(num); // 0~3번까지 매트릭스 led를 초기화
}
Serial.begin(9600);//Board Rate 9600
}
Serial.begin(9600)
Board Rate 9600
는 아두이노와 통신할 때의 속도를 의미하는데, 시리얼 모니터에서 설정한 값과 일치해야 한다.
아두이노 실행시 반복적으로 실행되는 loop함수에서는 매번 입력이 들어왔을 때, 매트릭스에 글자가 출력될 수 있도록 처리를 해준다.
void loop() {
char temp[100];
if(Serial.available() > 0){
//Serial.readBytesUntil(character, buffer, length)
byte leng = Serial.readBytesUntil('\n', temp, 100);// enter 이전까지 받아서 temp에 저장
Serial.println(temp);
...
Serial.available()
시리얼 입력값이 있을 때,
Serial.readBytesUntil()
enter 이전 값까지 받아 char형 변수 temp에 저장해준다.
최대 100개의 char 데이터만큼 받는다.
100개보다 적은 개수의 데이터가 입력되면 입력받은 갯수만큼 저장되고, 초과되면 나누어져 temp에 저장된다.
그 다음,
매트릭스 출력 형식에 맞게 char형 문자열 temp를 변환하여 저장한다.
...
//making full name matrix
byte name_b[leng + 4][8];//name buffer ('name' + none)
for(int i=0; i< leng; i++){
if(temp[i] >= 'a' && temp[i] <= 'z'){ //lower case
int idx = temp[i] - 'a';
memcpy(&name_b[i], &LOWER[idx], sizeof(LOWER[idx]));
}
else if(temp[i] >= 'A' && temp[i] <= 'Z'){ //upper case
int idx = temp[i] - 'A';
memcpy(&name_b[i], &UPPER[idx], sizeof(UPPER[idx]));
}
else if(temp[i] == ' ') //space
memcpy(&name_b[i], &NONE[0],sizeof(NONE[0]));
else if(temp[i] == ',') //comma
memcpy(&name_b[i], &COMMA,sizeof(COMMA));
else if(temp[i] == '-') //mommy duck
memcpy(&name_b[i], &DUCK[0],sizeof(DUCK[0]));
else if(temp[i] == '_') //little duck
memcpy(&name_b[i], &DUCK[1],sizeof(DUCK[1]));
}
for(int i=0; i<4 ; i++){ //Null
memcpy(&name_b[leng+i], &NONE[0],sizeof(NONE[0]));
}
...
각각의 문자열 입력에 따라 매트릭스 표현 방식을 대응시켜 name buffer에 저장한다.
또한 위에서 언급한 것과 같이 출력 문자열 마지막에 4칸의 NULL을 붙여 부드럽게 출력되도록 한다.
이제,
문자열 shift 작업을 위해 빈 배열을 준비한다.
//matrix buffer shift
byte matrix[4+1][8]; //matrix buffer
for (int i = 0; i < 4; i++){
for (int j = 0; j < 8; j++) {
matrix[i][j] = B00000000;
}
}
4개의 매트릭스에 데이터가 순차적으로 옮겨질 수 있게 작업을 수행해준다.
for(int i=0; i < leng+4; i++){
memcpy(&matrix[4], &name_b[i], sizeof(name_b[i]));
for(int j=0; j < 8; j++){
for(int k=0; k <8 ; k++){
matrix[0][k] = (matrix[0][k] << 1) | (matrix[1][k] >> 7);
matrix[1][k] = (matrix[1][k] << 1) | (matrix[2][k] >> 7);
matrix[2][k] = (matrix[2][k] << 1) | (matrix[3][k] >> 7);
matrix[3][k] = (matrix[3][k] << 1) | (matrix[4][k] >> 7);
matrix[4][k] = (matrix[4][k] << 1);
}
// 출력
for (int k = 0; k < 8; k++) {
// lc.setRow(matrix_number,Row,value)
lc.setRow(0, k, matrix[3][k]);
lc.setRow(1, k, matrix[2][k]);
lc.setRow(2, k, matrix[1][k]);
lc.setRow(3, k, matrix[0][k]);
}
delay(10); // 시프트 속도 10ms
}
}
}//end of if
}//end of loop()
아두이노로 데이터를 전송하기 위해 파이썬에서 작업이 필요하다.
먼저, pip를 이용해 파이썬 시리얼 통신에 대한 라이브러리를 설치해준다.
pip install pyserial
시리얼 통신을 하고자 하는 파이썬 파일에서 모듈을 import 한다.
import serial
시리얼 통신을 위한 변수를 선언한다.
ser = serial.Serial('com3', 9600)
time.sleep(2)
출력할 문자열을 선언하고, 시리얼 통신을 해준다.
hello_name = "Hello,"+name
self.ser.write(hello_name.encode())
프로그램을 통해 얼굴이 인식되면, 누구인지 판별하여 그 사람의 이름이 출력된다!
"Hello, Huttzza!"
slm 1606m 모듈 가지고계신가요?