2021 숭실 스마트 산학융합 공모전 아두이노 프로젝트

Hyeonu_Chun·2021년 6월 21일
0

아두이노 IDE code

//TRIG, ECHO PIN 정의//

const int TRIG = 2;
const int ECHO = 3;                  

//평균 이동 필터의 Buffer Size 정의//

//변수 정의//
float duration;

void setup(){
  
  Serial.begin(9600);       //시리얼 통신 설정
  Serial.flush();         //시리얼 통신 후 다시 시리얼 통신을 시작할 때, 들어오거나 남아있던 값을 제거
  
  //핀 모드 설정
  
  pinMode(TRIG,OUTPUT);     
  pinMode(ECHO,INPUT);
  digitalWrite(TRIG,LOW);
}

void loop(){
  
  digitalWrite(TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  
  duration = pulseIn(ECHO, HIGH);

  Serial.println(duration);

  delay(1000);
}

Python code

# pip install pySerial
import serial

arduino = serial.Serial('COM8', 9600)

class Student():
    def __init__(self):
        self.z=2
        print("z init as :", self.z)

a = list()

duration = 0
distance = 0

cm_distance = 0
new_cm_distance = 0

pre_distance = 0

sum_of_buffer = 0

new_duration = 0

alpha = 0.3
beta = 0.01

cnt = 0
s = 1  # 0.1

cnt_hit = 0
h = 1  # 0.1

outCount = 0

human_sig = False

for i in range(10):

    duration = float(arduino.readline().decode()[:-1])
    cm_distance = ((duration * 340) / 10000) / 2
    a.append(cm_distance)

    if cm_distance > 280:
        cm_distance = 280
    elif cm_distance < 2:
        cm_distance = 2

    sum_of_buffer += a[i]

pre_distance = sum_of_buffer / len(a)

while 1:
    new_duration = float(arduino.readline().decode()[:-1])
    new_cm_distance = ((new_duration * 340) / 10000) / 2

    if new_cm_distance < 190:
        distance = alpha * pre_distance + (1-alpha) * new_cm_distance

    elif new_cm_distance < 280:
        distance = (1-alpha) * pre_distance + alpha * new_cm_distance
    else:
        distance = (1-beta) * pre_distance + beta * new_cm_distance

    if distance > 280:
        distance = 280
    elif distance < 2:
        distance = 2

    print("distance(cm) :", int(distance), end=' ')

    cnt += s

    times = 100000 - cnt * 930  # 300000 - cnt * 930

    print("Sample Number :", cnt, end=' ')

    if distance <= 150:
        cnt_hit += h

    print("Human Cnt_Number :", cnt_hit, end=' ')

    if cnt_hit < 16.10:
        if times <= 60000:  #120000
            # delay(120000) 고정된 2분
            cnt = 0
            # 시간을 뽑아 실시간 기록하거나 찾을 필요없이 현회차와 전회차 비교해서 오차 확인 가능
            cnt_hit = 0
            times = 0
            outCount += 1
    else:
        human_sig = True
        print("Human_Signal :", human_sig)
        # delay(times) 측정되는 3분 중에 남는 시간 + 2분
        human_sig = False
        cnt = 0
        # 시간을 뽑아 엑셀이든 txt파일 데이터가 실시간으로 밀리지 않는지 확인하지 위해서
        cnt_hit = 0
        times = 0
        outCount = 0

    pre_distance = distance
    print("outCount :", outCount)
    # outCount 18cycle일때 경고 메세지, 24cycle일땐 out
    # 가방이나 물건 올려놨을때 움직임 없을때 확인하는 로직 현회차와 전회차 비교해서 오차 확인 가능
    # 실시간 실내/실외 온도나 습도에 따른 파라메타 변화 적용 or not

20210707 Ver2.5

Arduino IDE code

const int ECHO1=13;		// mini_size 3
const int TRIG1=12; 	// mini_size 2
const int ECHO2=9; 		// mini_size 5
const int TRIG2=8; 		// mini_size 4
const int ECHO3=3; 		// mini_size 7
const int TRIG3=2; 		// mini_size 6

#define SIZE 20 		// Buffer of setting Moving average filter
#define DIST 280*58.8 	// mini_size 50*58.8

int buffer1[SIZE];
int buffer2[SIZE];
int buffer3[SIZE];

const int maxdist = 280;	//mini_size 50
const int mindist = 2;		//mini_size 2
double kalman1(double U1);
double kalman2(double U2);
double kalman3(double U3);        

double tmp1 = 200;	//tmp_value for invalid, mini_size 32
double tmp2 = 200;	//tmp_value for invalid, mini_size 32
double tmp3 = 200;	//tmp_value for invalid, mini_size 32

long Cm1, Cm2, Cm3;
long duration1, duration2, duration3;

float sum1 = 0;
float sum2 = 0;
float sum3 = 0;
float distance1, distance2, distance3;

char ch;

double kalman1(double U1){
  static const double R1 = 40;
  static const double H1 = 1.00;
  static double Q1 = 10;
  static double P1 = 0;
  static double U_hat1 = 170;	// mini_size 20
  static double K1 = 0;
  K1 = P1*H1/(H1*P1*H1+R1);
  U_hat1 += + K1*(U1-H1*U_hat1);
  P1 = (1-K1*H1)*P1+Q1;
  return U_hat1;
}

double kalman2(double U2){
  static const double R2 = 40;
  static const double H2 = 1.00;
  static double Q2 = 10;
  static double P2 = 0;
  static double U_hat2 = 170;	// mini_size 20
  static double K2 = 0;
  K2 = P2*H2/(H2*P2*H2+R2);
  U_hat2 += + K2*(U2-H2*U_hat2);
  P2 = (1-K2*H2)*P2+Q2;
  return U_hat2;
}

double kalman3(double U3){
  static const double R3 = 40;
  static const double H3 = 1.00;
  static double Q3 = 10;
  static double P3 = 0;
  static double U_hat3 = 170;	// mini_size 20
  static double K3 = 0;
  K3 = P3*H3/(H3*P3*H3+R3);
  U_hat3 += + K3*(U3-H3*U_hat3);
  P3 = (1-K3*H3)*P3+Q3;
  return U_hat3;
}

void setup() {
  Serial.begin(9600);
  Serial.flush();
  pinMode(TRIG1,OUTPUT);
  pinMode(ECHO1,INPUT);
  digitalWrite(TRIG1,LOW);
  pinMode(TRIG2,OUTPUT);
  pinMode(ECHO2,INPUT);
  digitalWrite(TRIG2,LOW);
  pinMode(TRIG3,OUTPUT);
  pinMode(ECHO3,INPUT);
  digitalWrite(TRIG3,LOW);

  for(int i=0; i<=SIZE-1; i++)
  {
    digitalWrite(TRIG1,HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG1,LOW);
    duration1=pulseIn(ECHO1,HIGH);
    Cm1=duration1*0.034/2;
    if(Cm1>maxdist) Cm1=maxdist;
    else if(Cm1<mindist) Cm1=mindist;
    buffer1[i]=Cm1;
    sum1+=buffer1[i];
  }
  for(int i=0; i<=SIZE-1; i++)
  {
    digitalWrite(TRIG2,HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG2,LOW);
    duration2=pulseIn(ECHO2,HIGH);
    Cm2=duration2*0.034/2;
    if(Cm2>maxdist) Cm2=maxdist;
    else if(Cm2<mindist) Cm2=mindist;
    buffer2[i]=Cm2;
    sum2+=buffer2[i];
  }
  for(int i=0; i<=SIZE-1; i++)
  {
    digitalWrite(TRIG3,HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG3,LOW);
    duration3=pulseIn(ECHO3,HIGH);
    Cm3=duration3*0.034/2;
    if(Cm3>maxdist) Cm3=maxdist;
    else if(Cm3<mindist) Cm3=mindist;
    buffer3[i]=Cm3;
    sum3+=buffer3[i];
  }
  Serial.flush();
}

void loop() {
  if(Serial.available() >0){
    ch = Serial.read();
    if(ch == 'a') delay(1000);	// Break time
  }
  
  digitalWrite(TRIG1,HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG1,LOW);
  duration1=pulseIn(ECHO1,HIGH, DIST); // invaild value(280cm 이상) 1차 예외처리(timeout 조절)
  Cm1=duration1*0.034/2;

  if(Cm1==0) Cm1 = tmp1;  // 1차 예외처리 된 data 직전 typical data 사용
  else{
    if(Cm1>maxdist) Cm1=maxdist;  // extreme case 2차 예외처리(distance limiting)
    else if(Cm1<mindist) Cm1=mindist;
    tmp1 = Cm1;
  }

  sum1-=buffer1[0];
  for(int i=0; i<SIZE-1; i++)
  {
    buffer1[i]=buffer1[i+1];
  }
  buffer1[SIZE-1]=Cm1;
  sum1+=buffer1[SIZE-1];

  if(Cm1 > 150){	// mini_size 22
    distance1=sum1/SIZE;	// Moving average filtered distance 사용
  }
  else{
    distance1 = kalman1(Cm1);	// Kalman filtered distance 사용
  }

  delay(50);
  /////////////////////////////////////////////////////////////////////////////////////
  digitalWrite(TRIG2,HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG2,LOW);
  duration2=pulseIn(ECHO2,HIGH,DIST); // invaild value(280cm 이상) 1차 예외처리(timeout 조절)
  Cm2=duration2*0.034/2;

  if(Cm2==0) Cm2 = tmp2;  // 1차 예외처리 된 data 직전 typical data 사용
  else{
    if(Cm2>maxdist) Cm2=maxdist;  // extreme case 2차 예외처리(distance limiting)
    else if(Cm2<mindist) Cm2=mindist;
    tmp2 = Cm2;
  }

  sum2-=buffer2[0];
  for(int i=0; i<SIZE-1; i++)
  {
    buffer2[i]=buffer2[i+1];
  }
  buffer2[SIZE-1]=Cm2;
  sum2+=buffer2[SIZE-1];  

  if(Cm2 > 150){	// mini_size 22
    distance2=sum2/SIZE;	// Moving average filtered distance 사용
  }
  else{
    distance2 = kalman2(Cm2);	// Kalman filtered distance 사용
  }
  
  delay(50);
  ///////////////////////////////////////////////////////////////////////////////
  digitalWrite(TRIG3,HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG3,LOW);
  duration3=pulseIn(ECHO3,HIGH, DIST); // invaild value(280cm 이상) 1차 예외처리(timeout 조절)
  Cm3=duration3*0.034/2;

  if(Cm3==0) Cm3 = tmp3;  // 1차 예외처리 된 data 직전 typical data 사용
  else{
    if(Cm3>maxdist) Cm3=maxdist;  // extreme case 2차 예외처리(distance limiting)
    else if(Cm3<mindist) Cm3=mindist;
    tmp3 = Cm3;
  }

  sum3-=buffer3[0];
  for(int i=0; i<SIZE-1; i++)
  {
    buffer3[i]=buffer3[i+1];
  }
  buffer3[SIZE-1]=Cm3;
  sum3+=buffer3[SIZE-1];  

  if(Cm3 > 150){	// mini_size 22
    distance3=sum3/SIZE;	// Moving average filtered distance 사용
  }
  else{  // 3차 칼만필터 filtering 구간
    distance3 = kalman3(Cm3);	// Kalman filtered distance 사용
  }

  delay(50);

  //Serial.print(distance1); Serial.print(" "); Serial.println(Cm1);// Serial.print(" "); Serial.println(distance3);
  Serial.print(distance1); Serial.print(' '); Serial.print(distance2); Serial.print(' '); Serial.println(distance3);
  
  delay(50);
}

Python code (Server)

import serial
import time

select_comport = input('select port:')

arduino = serial.Serial(select_comport, 9600)

sample_cnt = 200
human_exist_dist = 150  # 22
yellow_card = 45
red_card = 60
sec = 1
line_list = list()
desk_list = list()
full_cycle_time = 60

with open("number_of_student.txt", "r") as f:
    line_tmp = f.readlines()
    max_desk_cnt = len(line_tmp)

cnt = max_desk_cnt * sample_cnt


class Desk:
    def __init__(self):
        self.distance = 0
        self.hit_cnt = 0
        self.out_cnt = 0
        self.flag = False
        self.stu_phone = ""

    def print_desk_info(self):
        print(self.stu_phone, "(Dist:", int(self.distance), "Hit:", self.hit_cnt, "Out:", self.out_cnt, end=')\t\t\t\t')


def read_distance():
    if arduino.readable():
        try:
            tmp_distance = arduino.readline().decode().split(' ')
            tmp_distance = [float(e) for e in tmp_distance]
            for m in range(max_desk_cnt - len(tmp_distance)):
                tmp_distance.append(0)
            return tmp_distance
        except ValueError:
            return [0]

# Initialize
for i in range(max_desk_cnt):
    desk_list.append(Desk())

first_time = time.time()  # real time checking

# Loop
while True:
    try:
        # 실시간으로 number_of_student value 들이 kiosk 에 의해 변했는지 확인
        with open("number_of_student.txt", "r") as f:
            line_list = f.readlines()
        for i in range(len(line_list)):
            temp = desk_list[i]
            temp.stu_phone = line_list[i][:-1]
            if temp.stu_phone == "0":  # 학생 번호가 있어야하는 위치에 0이 있으면 객체 데이터 초기화
                temp.flag = False
                temp.out_cnt = 0
                temp.hit_cnt = 0
            else:  # 학생 번호가 입장되었으면 flag value on (distance 에 따른 logic 실행)
                temp.flag = True

        dist_list = read_distance()  # 아두이노를 통해 들어온 데이터 1차 정제

        if len(dist_list) == max_desk_cnt:
            for i in range(max_desk_cnt):  # 각 센서의 데이터별로 처리 시작
                tmp_desk = desk_list[i]
                tmp_desk.distance = dist_list[i]

                cnt -= sec
                print(cnt, end=': ')
                if cnt == -sec:

                    cnt = max_desk_cnt * sample_cnt  # break time 이후 cnt 값 초기화
                    cycle_time = time.time() - first_time
                    print("BREAK")
                    if cycle_time < full_cycle_time:
                        time.sleep(full_cycle_time - cycle_time)
                    arduino.read_all()
                    with open("data_list.txt", "a") as f:  # cycle time 기록
                        f.write(str(cycle_time) + ";")
                        for j in desk_list:
                            f.write(str(j.hit_cnt) + ";")
                        f.write("\n")
                    for j in desk_list:  # break time 이후 cnt_hit 초기화
                        j.hit_cnt = 0
                    first_time = time.time()
                    break

                if tmp_desk.flag == True:  # flag 가 1일때, 즉 사람이 입장했을때 실행
                    if 0 < tmp_desk.distance <= human_exist_dist:  # 사람이 있다는 거리
                        tmp_desk.hit_cnt += sec
                    if cnt < max_desk_cnt:  # break 전 마지막 루프에서 cnt_hit 값에 따른 결과 처리
                        if tmp_desk.hit_cnt <= sample_cnt * 0.2:  # sensing time 의 20%, 사람이 일정이상 앉아 있지 않을 때
                            tmp_desk.out_cnt += 1
                            if tmp_desk.out_cnt == red_card:  # 퇴장 처리
                                with open("sign_list.txt", "a") as f:  # 퇴장 메세지 전송
                                    f.write(tmp_desk.stu_phone + "Red" + "\n")
                                with open("out_student.txt", "a") as f:  # kiosk 에게 퇴장한 사람 데이터 전송
                                    out_student_list = [str(i), "'", tmp_desk.stu_phone, "'", str(time.time()), "'",
                                                        str(time.strftime('%c', time.localtime(time.time()))), "\n"]
                                    f.writelines(out_student_list)
                                line_list[i] = "0\n"  # number_of_student 에서 받아들였던 데이터 수정
                                with open("number_of_student.txt", "w") as f:  # 수정된 number_of_student 데이터 전송
                                    for line in line_list:
                                        f.write(line)
                                tmp_desk.stu_phone = "0"  # 객체 데이터 수정
                                tmp_desk.flag = False
                                tmp_desk.out_cnt = 0
                                tmp_desk.hit_cnt = 0
                            elif tmp_desk.out_cnt == yellow_card:  # 경고 처리
                                with open("sign_list.txt", "a") as f:  # 경고 메세지 전송
                                    f.write(tmp_desk.stu_phone + "Yellow" + '\n')
                        else:   # 사람이 일정이상 앉아 있을 때
                            tmp_desk.out_cnt = 0
                tmp_desk.print_desk_info()
            print()
    except IOError:
        pass

Python code (Kiosk)

import os
import time
from openpyxl import load_workbook

data_list = list()

with open("number_of_student.txt", "r") as f:
    line_ori = f.readlines()
num_of_data = len(line_ori)


def read_data():
    with open("number_of_student.txt", "r") as p:
        line_ori_tmp = p.readlines()
    line_tmp = [line_ori_tmp[x][:-1] for x in range(num_of_data)]

    with open("out_student.txt", "r") as s:
        line_stu = s.readlines()
    if line_stu != "":
        for x in range(len(line_stu)):
            line_stu_tmp = line_stu[x].split("'")
            for data_tmp in data_list:
                if (data_tmp[0] == int(line_stu_tmp[0])) & (data_tmp[1] == line_stu_tmp[1]):
                    data_tmp[2] = int(-(float(line_stu_tmp[2]) - data_tmp[2]))
                    data_tmp.append(line_stu_tmp[3][:-1])
                    print(data_tmp)  # 엑셀에 프린트

                    wb_tmp = load_workbook('using_list.xlsx')
                    ws_tmp = wb_tmp['Sheet1']
                    ws_tmp.append(data_tmp)
                    wb_tmp.save('using_list.xlsx')

                    data_list.remove(data_tmp)
        with open("out_student.txt", "w") as s:
            s.write("")
    return line_tmp


while True:
    enter_or_exit = input("입장 / 퇴장 : ")
    line = read_data()
    if enter_or_exit == "입장":
        print("사용 가능한 좌석 : ")
        for i in range(num_of_data):
            if line[i] == '0':
                print(i+1, "번", end=" ")
        print()
        num_sit = input("입장할 좌석번호 / 나가기(0) : ")[:1]
        line = read_data()
        if num_sit.isnumeric() == 1:
            num_sit = int(num_sit) - 1
            if 0 <= num_sit < num_of_data:
                if line[num_sit] == '0':
                    num_student = input("사용자의 핸드폰 번호 : ")
                    line = read_data()
                    line[num_sit] = num_student
                    if (len(num_student) == 11) & (num_student.isnumeric() == 1) & (num_student[:2] == "01"):
                        data_list.append([num_sit, num_student, time.time(), time.strftime('%c', time.localtime(time.time()))])
                        with open("number_of_student.txt", "w") as f:
                            for j in range(num_of_data):
                                f.write(line[j]+'\n')
                        print("회원님의 자리는", num_sit + 1, "번 입니다.")
                    else:
                        print("잘못된 입력입니다.")
                else:
                    print("잘못된 좌석을 지정하였습니다.")
            else:
                print("잘못된 좌석을 지정하였습니다.")
        else:
            print("잘못된 좌석을 지정하였습니다.")
        print("메인화면으로 돌아갑니다.")
        input("아무버튼이나 눌러주세요.")
        os.system('cls')
    elif enter_or_exit == "퇴장":
        num_sit = input("퇴장할 좌석번호 / 나가기(0) : ")[:1]
        line = read_data()
        if num_sit.isnumeric() == 1:
            num_sit = int(num_sit) - 1
            if 0 <= num_sit < num_of_data:
                if line[num_sit] != '0':
                    num_student = input("사용자의 핸드폰 번호 : ")
                    if (len(num_student) == 11) & (num_student.isnumeric() == 1):
                        with open("number_of_student.txt", "r") as f:
                            line_ori = f.readlines()
                        line = [line_ori[x][:-1] for x in range(num_of_data)]
                        for data in data_list:
                            if (num_sit == data[0]) & (num_student == data[1]):
                                data[2] = int(time.time() - data[2])
                                # data[2] = data[2] // 60
                                data.append(time.strftime('%c', time.localtime(time.time())))
                                line_ori[num_sit] = "0\n"
                                with open("number_of_student.txt", "w") as f:
                                    for j in line_ori:
                                        f.write(j)
                                print(data)  # 엑셀에 프린트
                                wb = load_workbook('using_list.xlsx')
                                ws = wb['Sheet1']
                                ws.append(data)
                                wb.save('using_list.xlsx')
                                data_list.remove(data)
                                print(num_sit + 1, "번 자리가 퇴장처리 되었습니다. 이용해주셔서 감사합니다.")
                                break
                        else:
                            print("올바르지 않은 번호입니다.")
                    else:
                        print("잘못된 입력입니다.")
                else:
                    print("잘못된 좌석을 지정하였습니다.")
        else:
            print("잘못된 좌석을 지정하였습니다.")
        print("메인화면으로 돌아갑니다.")
        input("아무버튼이나 눌러주세요.")
        os.system('cls')
    else:
        print("잘못된 입력입니다.")
        print("메인화면으로 돌아갑니다.")
        input("아무버튼이나 눌러주세요.")
        os.system('cls')

Python code (Message)

import requests
import time

while 1:
    try:
        with open("sign_list.txt", "r") as f:
            signs = f.readlines()
            num_of_sign = len(signs)
        for i in range(num_of_sign):
            a = signs[i][:11] + " 고객님께 보내는 알림입니다.\n"
            if signs[i][11:-1] == "Yellow":
                b = "경고 알림: 15분 동안 자리를 비우셨습니다.\n25분 동안 자리를 비울시 퇴장 처리됩니다."
            else:
                b = "퇴장 알림: 25동안 자리를 비우셨습니다.\n좌석이 퇴장 처리됩니다."
            try:
                TARGET_URL = 'https://notify-api.line.me/api/notify'
                TOKEN = 'i8DYbNCp5k6B6m7QP4kfiLYzvJZNzQX27cMwd5E8Jo5'  # 발급받은 토큰
                headers = {'Authorization': 'Bearer ' + TOKEN}
                data = {'message': a+b}

                response = requests.post(TARGET_URL, headers=headers, data=data)
            except Exception as ex:
                print(ex)
        if num_of_sign != 0:
            with open("sign_list.txt", "w") as f:
                f.write("")
    except IOError:
        pass
    time.sleep(1)
profile
Stay hungry, stay foolish

0개의 댓글