[53호]엑기스 특강 : 코딩으로 배우는 센서
배우면 바로 써먹는 엑기스 특강
코딩으로 배우는 센서
지난 2월 23일, 고액 연봉 도전 프로젝트 시리즈 중에 하나인 ‘코딩으로 배우는 센서’ 특강이 디바이스마트 주최 및 펌웨어뱅크 주관으로 판교 경기창조문화허브에서 김형태 저자와 함께 진행되었다.
김형태 강사는 전자공학과 신호처리 전공을 했으며, 현재 펌웨어뱅크 대표로써 산업용 로봇과 임베디드 제어 설계 개발을 현업으로 하며 책 집필과 응용 강의에 전념하고 있다. 주말임에도 불구하고 선착순으로 진행된 특강에 수강하고자 하는 개발자와 학생 20명이 빠르게 신청해 조기 마감되었다. 최근 코딩의 관심과 메이커 인구의 확산으로 오픈소스 하드웨어 아두이노를 이용한 입출력 장치를 제어하는 정규 교과과정 개설이 크게 늘었으며 인공지능과 IoT, 빅데이터를 활용하는 사례 또한 늘고 있다. 이에 따라 각종 경진대회나 창업, 발명품 등에서 센서를 다루는 기회가 많아져 저자는 임베디드 기반 프로젝트에 맞는 센서 활용법에 포커스를 맞췄다.
이번 특강은 코딩으로 배우는 센서 책 출간 기념으로 개최되었으며, 저자가 설계한 Cortex-M0 보드 + MDK-ARM 컴파일러 + JTAG 장비의 펌웨어 코드 센서 동작을 실습하는 강의로 초보 임베디드 개발자들이 혼자서도 할 수 있는 실력을 배양하고 현장에서도 무리 없이 바로 사용할 수 있도록 효율적인 센서 적용 방법을 학습할 수 있는 자리였다. 강의에서는 노트북을 제외한 Cortex-M0 Module와 센서 실험용인 EVB 메인보드, JTAG, 센서 등을 모두 대여를 해주어서 편리했으며, 특히 소스코드를 저자의 네이버 카페(https://cafe.naver.com/fws/338)에서 확인해 다운로드를 할 수 있다는 점이 좋았다. 또한 특강 전 저저와의 질의응답 시간이 마련되어 궁금했던 사항들을 해소할 수 있었다.
강의는 2 세션으로 나누어 진행했다. 1 세션에서는 김형태 강사의 간략한 소개와 더불어 사진에서 볼 수 있듯이, 소스코드를 강의 시간에 보여주면서 임베디드에 대해 전반적으로 쉽게 이해할 수 있도록 사전설명 시간을 가졌고 특히 JTAG를 활용하는 방법을 알려주어 유용했다는 후문이다.
2 세션에서는 온도 및 습도 센서와 조이스틱 센서 등 각종 센서의 응용 방법, 회로와의 연결 방법, 코드에 대한 설명을 했으며 수강자들이 바로 적용해 연결해보며 체험을 통해 익히도록 했다. 이 과정에서 수강자들이 원활하게 따라가지 못하거나 질문을 하면, 강사가 적극적으로 소통하고 직접 알려주어 더욱 유익한 특강이 되었다.
특강을 미처 수강하지 못했더라도 디바이스마트에서 ‘코딩으로 배우는 센서’ 책을 구매해 책에서 알려주는 대로 스스로 수행해 결과물을 낼 수 있다.
[53호]한이음엑스포2018
HANIUM EXPO 2018
한이음엑스포2018
4차 산업혁명을 이끌어갈 대학생들의 아이디어를 한눈에 볼 수 있었던 2018 한이음 엑스포가 11월 30일부터 이틀간 일산 킨텍스에서 개최되었다. 대학생 멘티와 지도교수, 기업전문가 ICT 멘토가 팀을 이루어 현업 실무 기술이 반영된 프로젝트를 수행하는 ICT 인재 양성 프로그램이었던 한이음 공모전에서 선정된 작품들이 다양한 주제별로 진열이 되어있었다. ICT 멘토링은 대학생들이 기업 전문가와 약 1년간 실제 ICT 및 SW 개발 프로젝트를 수행하도록 지원되는 사업이다. 대학생들은 다양한 ICT 분야 기업전문가 멘토에게 지도를 받고 멘토는 ICT 분야의 실무 노하우를 전수하고 비전을 제시했다. 이번에는 ICT 멘토링에 대학생 2239명과 기업 전문가 238명이 참여해 무려 655개 프로젝트를 수행하였다고 전해진다.
이번 공모전에서 대상을 받은 피아노빔팀은 AR, AI를 이용해 피아노 연주 기반의 리듬게임을 할 수 있는 어플리케이션을 개발하였다. 이 작품은 피아노 악보를 처음 접하거나 익숙하지 않은 초보자 또는 아동이 피아노 악보를 보지 않고도 피아노를 연주할 수 있도록 도와준다. 이 작품은 또한 앱 내에 사용자가 원하는 노래가 없더라도 원하는 노래의 악보를 스마트폰 카메라로 촬영하고 앱으로 불러오면 해당 악보의 노래를 연주할 수가 있다는 점이 큰 장점이다. 사용자가 연주한 노래를 앱에서 인식이 되어 노래가 얼마나 유사한지에 따라서 점수 및 등급 등의 피드백도 제공받을 수 있다. 이 어플리케이션을 이용하면, 몰입도와 흥미를 향상시켜 어린이들도 피아노에 보다 쉽게 접근할 수 있으며 피아노 학원에서 주어지는 과제도 앱을 활용해서 여러 번 연습을 할 수 있다.
Thinkar(띵카)팀은 라즈베리파이 및 딥러딩을 이용한 자율 주행 소방차를 출품했다. 우리나라는 소방인력이 현저하게 부족한데, 이를 해결할 수 있는 보다 정교한 무인 소방차를 제시하고자 작품을 만들었다고 한다. 이 작품의 특징은, 불이 난 곳을 스스로 인식하여 화재를 진압하고 도로 주행부터 화재 진압까지 모든 과정이 무인으로 진행이 된다는 점이다. 또한 어플리케이션 사용자에게는 화재 알림 서비스도 제공이 된다. 이 작품을 활용한다면 소방시설 및 인력이 부족한 곳에 배치해 화재 초기진압을 할 수 있다. 어플리케이션과의 연동을 통해서 화재의 정확한 위치 파악과 화재 상황을 눈으로 확인이 가능해 빠르게 대피를 할 수 있다. 더운 여름철에는 화재 현장 이외에도 뜨거운 도로에 물을 뿌리거나 농어촌에 급수차 역할로도 충분히 활용이 가능하다.
자율 주행 소방차를 뒤이어, Rokie팀의 ‘모바일 제어 스마트 크루즈 컨트롤 자동차’를 볼 수 있었다. 이 작품은 사용자가 모바일 어플리케이션을 통해 스마트 크루즈 컨트롤 기능이 구현된 자동차의 실시간 정보 값을 모니터링하고 운전할 수 있는 작품으로, 자동차의 안전 주행 기술에 대해 탐구한 프로젝트이다. 안드로이드 스튜디오를 이용해 만든 어플리케이션과 Atmega128이 블루투스 양방향 통신을 모바일 제어 기술을 구현했으며 초음파 센서 및 PSD 센서를 이용해 각 방향에 거리 데이터를 습득해 자동차의 주행을 안전하게 한다. 조이스틱 컨트롤러를 활용해 제어하는 방식으로 자동차를 조종하며 흥미를 느낄 수 있다. 거리 측정 센서를 앞, 뒤, 좌, 우에 부착하면 다방면의 장애물을 인식한다. 실제 자동차처럼 서보모터를 이용해 자동차의 회전을 구현하였다. 이 작품을 사용하면 스마트 크루즈 기능을 학습해 안전 제어 기술의 원리와 모바일 기기의 블루투스 제어 원리 및 기술을 습득할 수 있다.
WE FIT 팀에서는 웨어러블 디바이스와 키넥트를 활용한 1:N 홈트레이닝 헬스케어 시스템을 선보였다. 웨어러블 디바이스와 키넥트 센서를 이용해 다중 사용자 간의 운동 자세 측정 결과값을 비교 및 분석할 수 있는 ‘홈 트레이닝 자세교정 시스템’이다. 이 애플리케이션을 활용하여 종류에 제한이 없는 운동을 할 수 있으며, 우리 몸의 정교한 자세를 측정이 가능하며 다중 사용자 간에도 통신 기능이 탑재되어 있어 실시간 통신이 가능하다는 점이 장점이다. 재활 및 PT 등 다양하게 활용할 수 있어 활용도가 높다.
인하대학교 학생들이 선보인 붕붕카는 GTA 게임과 레이싱 컨트롤러를 이용해 자율주행 알고리즘을 평가, 검증하는 자율주행 시뮬레이터이다. 이 작품은 기존 자율주행 시뮬레이터의 비용이 상당히 높고 사용 및 유지보수가 어려웠던 점을 보완했으며, 손쉽게 접할 수 있는 게임과 컨트롤러를 활용하여 조작 및 활용이 간편하다. 자율 주행을 연구하는 연구원이 쉽게 자율 주행 알고리즘 및 시스템을 개발할 수 있는 지원 플랫폼으로 활용할 수 있다.
비주얼서보잉 기반 원격제어 모바일 로봇은 영상 처리로 알고리즘을 통한 물체를 검출하고 비주얼 센싱 기술을 사용해 선택된 물체의 좌표를 추정해 로봇을 특정 물체로 이동하도록 유도하는 것을 목표로 한다. 이 작품으로 원격 조종만 하는 것이 아닌 로봇에 탑재되어 있는 카메라로 현장 상황을 실시간으로 보며 조작할 수 있다. USB 카메라에서 받아온 영상을 OpenCV를 통해 탐색하고자 하는 물체의 특장점을 찾아 물체를 인식하고 움직임을 추적할 수 있도록 한다. 활용 목적에 따라서 엔터테인먼트 혹은 산업용 로봇 등 다양한 분야에 활용이 가능하다. 특히 사람이 갈 수 없는 위험 지역에 투입되어 작은 규모로 수행이 가능하다는 점이 경제적이다.
만든 이의 열정적인 설명이 돋보였던 LeapMotion과 VR을 이용한 청소년 영어 교육 애플리케이션 ‘AlphaVR(알파블)’은 VR과 디스플레이, 3D 입력 디바이스 Leap Motion(립모션)을 결합하여 제작한 청소년용 영어 학습 애플리케이션이다. Leap Motion을 사용하여 별도의 도구 없이 VR 환경에서 영어 단어를 학습할 수 있는 서비스를 제공해 손의 자유로운 움직임을 이용해 공부를 활동적으로 즐길 수 있다. VR 학습 공간의 제작과 3D 모델링으로 사용자가 재미와 흥미를 느낄 수 있는 교육 콘텐츠를 제공하며 가상현실 속에서 사용자가 직관적으로 손을 사용할 수 있다. 카드 보드와 같은 보급형 VR HMD를 사용한 작품으로 비교적 저렴한 가격으로 가상현실 콘텐츠를 즐길 수 있다. 이 작품을 실제 교육 시설에 도입하면 학생들의 수업 집중도도 향상이 되며 사실적인 체험형 교육 환경이 조성될 것으로 기대된다. 또한 앞으로 이 애플리케이션을 활용해 노인 대상의 영어 교육 프로그램으로도 발전시킬 수 있는 가능성이 있다.
반려동물을 기르는 가구가 많아진 만큼, 반려동물을 위한 서비스를 제공하는 챗봇을 이용한 강아지 질병관리 전문가 시스템 닥터멍 서비스 작품이 돋보였다. 챗봇을 통해 강아지의 증상을 사용자에게 입력을 받고, 특정 추론 매커니즘을 거쳐 질병을 추론해 진단해주는 서비스이다. 반려견의 질병뿐만 아니라 건강관리의 전반적인 측면에서 전문성을 바탕으로 편리하게 관리가 가능하다. 특히 챗봇이라는 사용자가 다루기 쉬운 사용자 맞춤형 인터페이스를 활용하기 때문에 손쉽게 서비스에 접근해 정보를 제공받을 수 있는 사용자가 직접 질병을 찾아내는 중간 과정을 최소화한다는 측면에서 시간이 크게 절약되며 경제적으로도 효율적이다. 작품의 기능은 3가지로, 첫번 째는 사용자가 애완견의 질병 증상을 입력하면 챗봇이 질병 추론 알고리즘을 통해 애완견의 증상에 대한 질병을 추론한다. 이때 사용자가 입력한 증상과 일치하는 증상을 DB에서 찾고, 해당 증상에 대한 세부 증상을 사용자가 선택한다. 두번 째 기능은 강아지 약품 검색 기능이다. 사용자가 동물 병원에서 처방받은 약품이나 알고 싶은 약품의 이름을 입력하면 해당 약품의 대한 정보를 알려준다. 세번 째는 강아지의 종류에 따라 자주 발생하는 질병을 알려줘 만족도 있는 서비스를 제공 받을 수 있다.
VR/AR을 이용한 립모션 아티스트는 다양한 환경에서도 서로 합심해 그림 및 도형 놀이를 할 수 있는 재미있는 창작 프로그램이다. 싱글 및 멀티 플레이를 선택 가능해 혼자서도 놀이를 할 수 있으며, 여러명이 협동해서 제어도 가능하다. 자신이 그린 그림을 PC에 저장해 출력도 가능해 놀이로만 즐기는 것이 아니라 남길 수 있다. 이 작품은 특히 저예산으로 제작한 작품으로 경제적인 장점이 있으며 반복적인 테스트를 진행한 작품으로 게임을 플레이할 때 보다 안정적이다. 또한, 상세한 매뉴얼을 제공해 플레이하기에 편리하다. 창의력을 높이고, 심리 치료의 효과를 향상시켜 의료와 교육 분야 등에 다양하게 활용될 수 있다.
자율주행 택시 아나콘다는 라즈베리파이를 사용하여 만든 RC카와 안드로이드 기반 어플리케이션을 결합하였다. 사용자가 어플리케이션으로 자율주행택시를 호출하면 사용자가 있는 위치로 아나콘다가 자율주행하여 이동하고, 탑승 후 사용자가 어플로 설정한 도착지점까지 자율주행을 한다. 구동 환경 조건을 실외로 설정하여 미리 학습되어있는 자료를 통해 물체를 인식하는 Haar-Cascade classifiler를 적용하여 네트워크에 연결되어있지 않더라도 도로상황을 직접 감지해 정지 및 주행을 할 수 있다. 자율주행 택시를 이용하면 범죄율, 졸음 운전, 음주운전 사고를 효과적으로 줄일 수 있다는 장점이 있으며 승차 거부 또한 없애 사용자가 원할 때 적재적소에서 택시를 활용 가능하다는 기대효과가 있다.
‘2018 SW 인재 페스티벌’의 일환으로 열린 이번 행사에서 실제 제품이나 어플리케이션 및 서비스로 출시해도 될 만큼 완성도가 높은 작품들이 많았다. 이외에도 현장 면접을 위한 채용 박람회 등 약 50여 개의 기업이 참가해 다양한 행사를 함께 진행해 취업 준비생들이 취업 특강과 컨설팅을 받을 수 있어, 학생들에게 더욱 유용했다. 내년에는 어떤 참신한 아이디어의 작품들이 준비되어 있을지 기대하며 관람기를 마친다.
[53호]Ardu-economy bank
2018 ICT 융합 프로젝트 공모전 참가상
Ardu-economy bank
글 | 성균관대학교 김소윤, 박재형, 안태준, 최민수
1. 심사평
칩센 굉장히 친절한 보고서에 높은 평가를 줍니다. 서두에 목표를 아이들 경제 교육과 코딩 교육을 삼았는데 이 부분에 대해 어떤 기대치를 가질 수 있는지에 대한 부분이 없어서 좀 아쉽습니다.
뉴티씨 동전의 무게까지 재서 인식한 학습에 좋은 스마트 저금통을 구현하였다. 실생활은 센서를 반드시 사용해야 하는데, 그러한 센서 인식 부분을 이렇게 학습하는 것은 매우 유용하다고 생각합니다. 또한, 모터도 활용하여 동전을 밀어주는 부분도 구현하였네요. 코딩 교육을 받는 학생들 입장에서, 재미있게 해볼 수 있는 작품이라고 생각됩니다.
위드로봇 전체적인 완성도는 높으나 기존 제품 대비 창의성이 부족합니다. 기존 제품과의 차별성에서부터 아이디어를 도출하여 과제를 진행했으면 더 좋은 결과가 나왔을 것 같습니다.
2. 작품 개요
다양한 결제 시스템의 발달로 인해 동전의 유동량이 줄어들었지만, 여전히 동전은 어린아이들에게 돈의 가치와 노동의 의의를 깨닫게 해주며 올바른 소비 습관을 만드는 좋은 매개체입니다. 부모들은 저금통을 이용하여 아이의 조기 경제교육을 할 수 있습니다. 아이들은 물건을 사고 팔 때 돈을 주고받는 놀이를 하면서 모든 물건을 살 수 없음을 깨닫고 돈을 아끼거나 낭비하는 것을 알게 됩니다. 아이가 심부름을 하면 조금씩 용돈을 주고 저금을 하도록 하는 것은 아이가 돈의 소중함을 깨닫게 해줍니다.
다가오는 4차 산업혁명을 준비하기 위해 전 세계적으로 코딩 열풍이 불고 있습니다. 미국, 영국, 중국, 인도, 이스라엘 등 IT 선두국가들에선 이미 코딩 과목이 정규교육과정에 깊숙이 자리 잡고 있습니다. 우리나라 교육도 ‘국영수코’ 라고 할 만큼 코딩이 주목받고 있는 추세입니다. 어린 시절부터 코딩을 배우는 초등학생들이 늘고 있으며 코딩학원도 증가하는 추세입니다.
따라서 저희는 이 두 가지 흐름을 만족시킬 수 있는 저금통을 만들기로 했습니다. 어린이 사용자를 타겟으로 하여 아두이노로 작동하는 저금통을 만들었습니다. 어린 아이들을 위해 키트로 만들게 된다면 교육용으로 잘 활용될 수 있을 것이라 생각합니다.
3. 제품 이론
3.1. Cantilever Beam(외팔보)
Cantilever beam의 곡률과 변형의 관계는 다음의 식으로 설명할 수 있다.
이 때, Flexure formula는 다음의 식으로 주어진다. 이를 y에 대해 정리해 볼 수 있다. 또한 strain의 식은 아래의 세 번째 식과 같다.
두 식을 합해서 strain에 대해 다음의 식을 도출해 볼 수 있다.
이 때 빔 단면의 Moment of inertia는 이므로 식을 다음과 같이 다시 정리해 볼 수 있다.
3.2. Wheatstone Bridge
Wheatstone Bridge는 cantilever beam의 원리를 이용하여, beam의 상/하단에 저항을 연결함으로써 저항 값의 변화를 통해 beam의 휘어짐을 측정하고, 가해진 응력을 계산할 수 있도록 하는 application이다. 빔의 상단에 R1, R4의 두 저항을 연결하고, 하단에 R2, R3의 저항을 부착하였다고 하자. 이 때, 공급 전압(ν8)과 (R1+R2)||(R3+R4) 로 연결이 되어 있다고 하자. R1과 R4는 빔이 변형됨에 따라 저항 값이 R0+ΔR로 늘어날 것이고, R2와 R3의 저항 값은 R0-ΔR로 감소할 것이다. 이 때, R1과 R2측에 흐르는 전류를 ia라고 하고, R3과 R4측에 흐르는 전류를 ib라고 하였을 때, 각각의 전류를 다음의 식으로 나타내 볼 수 있다.
이 때, R1과 R2사이의 노드를 a node, R3과 R4사이의 노드를 b node라고 하였을 때, a, b 노드 사이의 전압 차이를 ν0로 정의할 것이다. 이 때 ν0는 다음과 같이 유도해 볼 수 있다.
이 때, Cantilever beam에서 유도한 strain의 식을 대입할 것이다.
이 때 이기 때문에 다음과 같이 식을 적어줄 수 있다.
이를 ν0의 식에 대입하면 다음과 같이 식을 유도할 수 있다.
유도된 식을 통해, 두 지점의 전위차를 이용하여 가해지는 응력을 계산할 수 있다.
4. 개발 환경
4.1. 아두이노
2005년 이탈리아의 Massimo Banzi와 David Cuartielles가 처음 개발하였다. 영어로 ‘아두이노’, 이탈리아어로 ‘아르두이노’라고 읽는다. 이탈리아어로 우리는 사귄다 힘세고 강한 친구를 ‘강력한 친구’ 라는 뜻이다. 임베디드 개발 경험이 전혀 없는 사람을 위해 개발된 교육용 플랫폼이기 때문에 소프트웨어 개발에 생소한 사용자들도 쉽게 프로그래밍할 수 있도록 설계되어 있다. 이러한 아두이노 IDE를 통해 작성된 프로그램이나 코드를 ‘스케치(Sketch)’라고 부른다.
아두이노의 통합 개발 환경(IDE)은 Java와 C를 기반으로 개발되는 크로스 플랫폼 응용 소프트웨어이며, 구문 강조, 괄호 찾기, 자동 들여쓰기 기능이 포함된 에디터와 한 번의 클릭으로 컴파일과 업로드가 가능한 컴파일러 기능을 포함하고 있다. 아두이노 동작을 위해서 C++ 언어 기반을 사용한다. 컴파일러는 avr-gcc을 사용한다. 따라서 avr-gcc가 제공하는 많은 C언어의 표준라이브러리를 함수를 사용할 수 있다. 실행 시, 개인용 컴퓨터와 시리얼 통신을 할 수 있는 모니터를 제공한다. 보통 USB을 통해 업로드를 하므로 아두이노 보드는 USB를 UART 통신으로 바꾸는 방법이 제공되고, MCU를 실행할 때는 이 UART 통신을 이용하여 필요한 통신을 할 수 있다. 이렇게 되려면 아두이노의 MCU는 부트로더가 올라가 있어야 한다.
아두이노 개발환경은 C++을 사용하여 원하는 동작을 하도록 코딩을 하고 이것을 보드에 업로드하면 아두이노가 동작한다. 아두이노 업로드는 플래시 메모리에 써지므로 다음부터는 전원만 인가하면 동작한다.
4.2. 마이크로컨트롤러
마이크로컨트롤러 혹은 MCU라고 불리며, 중앙처리장치(CPU)와 주변장치들을 하나의 칩으로 집약시켜 컨트롤 기능에 특화시킨 칩을 지칭하는 말이다. 간단하게 하나의 칩으로 이루어진 소형 컴퓨터라고 할 수 있다.
4.3. AVR
아트멜이란 반도체 회사에서 제작/판매하는 마이크로컨트롤러 시리즈 중 하나로, 아두이노 우노에 사용된 ATmega328이 AVR에 속하는 마이크로컨트롤러이다. 또한 아두이노 레오나르도, 메가등도 AVR 마이크로컨트롤러를 사용한다.
5. 주요 동작 및 특징
5.1. 모드 1 – 동전 투입 모드
전체 동작을 총 네 가지 모드로 나누어서 각각에 대해 코딩을 진행하였다. 첫 번째 모드는 동전을 투입하는 모드로써, 동전을 투입하면, 로드셀에 부착되어 있는 판에 동전이 올라가도록 하여, 로드셀이 무게를 측정한 후 투입된 동전의 무게를 바탕으로 동전의 권종을 판단한 후 비휘발성 메모리에 현재까지 투입된 동전의 누적 금액을 저장하였고, 서보모터를 작동시켜 동전을 하단의 서랍으로 떨어뜨리도록 하였다.
또한, 동전을 투입해도 되는지 판단할 수 있도록 적/녹색의 LED를 부착하여, 동전을 투입하여도 되는 경우에는 초록색 LED를, 무게를 측정 중이거나, 다른 모드의 코드를 실행중이기 때문에 동전을 투입하면 안 되는 경우에는 적색의 LED를 점등하도록 하였다. 모드 1에서는 LCD의 화면을 통해, 현재 저금통에 들어있는 금액과, 현재의 목표금액이 표시되도록 하였으며, 목표금액을 달성하였을 경우, 적/녹색의 LED를 번갈아 점멸하고 LCD의 화면에 목표금액을 달성하였음을 축하하는 메시지를 띄우도록 하였다.
5.2. 모드 2 – 목표금액 설정 모드
모드 2는 사용자가 키패드를 조작하여 목표금액을 스스로 설정할 수 있도록 하였다. 목표금액은 동전을 저장하는 저금통이니 만큼, 최대 목표금액을 100만원 미만으로 입력하도록 제한하였다. 사용자가 원하는 금액을 입력하고 확인 버튼인 ‘*’ 버튼을 누르게 되면, 새로운 목표금액이 아두이노의 비휘발성 메모리에 저장이 되고, 매번 코드의 loop 문을 돌 때마다, 비휘발성 메모리에 저장된 값을 읽어오도록 하였다. 입력 중간에 ‘#’ 버튼을 누르게 된다면 입력하던 금액 값을 초기화하고, 다음 모드인 모드 3으로 넘어가도록 하였다.
3. 모드 3 – 잠금 해제 모드
본 저금통을 설계할 때에, 원래의 사용자가 아닌 다른 사람이 저금통을 열어서 돈을 꺼내지 못 하도록 서보모터를 이용한 잠금장치가 항상 작동하도록 하였다. 하지만, 원래의 사용자가 원할 때에는 저금통의 잠금장치를 해제하고 돈을 꺼낼 수 있도록 모드 3을 만들게 되었다. 원래 입력해놓았던 비밀번호 네 자리를 누르게 되면(초기값 : 0000) 서보모터가 회전하여 잠금이 5초간 풀리고, 이후에는 다시 잠금을 유지하도록 설계하였다.
5.4. 모드 4 – 비밀번호 재설정 모드
모드 4에서는 사용자가 원하는 비밀번호를 설정할 수 있도록 하였다. 이를 위해 사용자는 기존에 사용하던 비밀번호를 입력하여야 하며, 입력한 비밀번호가 기존에 사용하던 비밀번호와 일치하는 경우에 새로운 비밀번호 네 자리를 입력하도록 하였고, 새로 설정된 비밀번호를 디스플레이 상에 표시하도록 하였다.
5.5. 전체 시스템 구성
동전 인식부는 다음과 같이 구성되어 있으며 동전 인식판에 동전이 놓이면 로드셀로 인식한 뒤 회전팔을 회전시켜 동전을 쓸어내어 아래쪽의 서랍에 동전이 들어가도록 한다.
서랍 잠금장치는 다음과 같이 구성되어 있으며 비밀번호가 맞았을 시에 서보 모터를 회전시켜 서랍을 빼낼 수 있도록 하였다.
제품 전체 모습은 다음과 같으며 상단에 키패드와 LCD, 상태표시 LED를 배치하여 입력과 확인이 편하도록 설계하였다.
6. 단계별 제작 과정
아두이코노미 뱅크를 제작하기 위해 제일 먼저 코딩을 하였다. 팀원 한명씩 모드를 하나씩 맡아 코딩을 한 후 아두이노에 연결하고 취합하여 각 모드가 정상적으로 작동하는지 확인하였다.
코딩을 마친 후 외형 제작을 시작하였다. 서랍과 틀은 목재를 주문할 때 크기를 맞춰 주문하였기 때문에 바로 우드락 본드로 제작을 하고, 로드셀의 정확도를 높여 주기위해 필요한 로드셀 밑판, 동전이 투입되었을 때 동전을 서랍에 떨어뜨리기 위해 필요한 기구들을 놓을 판, 서보모터와 로드셀 윗판과의 높이를 맞추기 위한 서보모터 밑판을 톱질을 하여 제작하였다.
톱질이 끝난 후 로드셀을 조립했다. 로드셀 윗판과 밑판을 우드락 본드로 붙인 후 우드락 본드로 전체 판에 고정시켰다. 서보모터가 동전을 더 잘 떨어뜨리기 위해 필요한 케이블 타이를 감은 후 알맞은 높이로 잘라 주었다.
서랍 위판에 동전을 넣을 구멍을 만들기 위해 드릴로 위판에 동전 투입구를 뚫었다.
아두이코노미 뱅크의 LCD와 키패드, LED가 들어갈 수 있는 공간을 만들어 고정시켰다. 이때 LED가 확실히 고정이 되도록 점퍼선과 납땜을 했다.
최종적으로 서랍과 로드셀, 서랍 위판을 조립하고 아두이코노미 뱅크가 정상적으로 작동하는지 확인하였다.
7. 회로도
우리는 아두이노 우노에 각각의 모듈을 연결하여 전체 시스템을 구성하였다. 사용된 모듈에는 로드셀, LCD, 키패드 모듈과 잠금장치, 동전 투입부에 들어가는 서보모터 2개가 있다. 또한, 상태를 나타내기 위한 적색과 녹색의 LED를 각각 하나씩 연결하였다. 5V 전원을 인가하고 GND 를 각각의 모듈에 일괄적으로 넣어주기 위해서 breadboard를 이용하여 전원을 공급해주었다. 이 때 LCD 모듈의 경우에는, I2C 통신을 위하여 SCK(Serial Clock)과 SDA(Serial Data)핀에 연결을 하여야 하기 때문에 해당 기능을 담당하는 A4, A5 번 핀에 연결을 해주었다.
8. 전체 CODE 설명
#include <EEPROM.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <HX711.h>
#include <Servo.h>
#define arm_servoPin 9
#define lock_servoPin 10
#define DOUT A2 // 로드셀 객체 선언할 때 앞 쪽 포트
#define SCK A3 // 로드셀 객체 선언할 때 뒤 쪽 포트
#define SDA A4 // LCD 객체 선언할 때 앞 쪽 포트
#define SCL A5 // LCD 객체 선언할 때 뒤 쪽 포트
#define steadyLED 12
#define processingLED 13
#define arm_angle 90 // 팔이 돌아가는 최대 각도
long save; // 누적금액
long goal; // 목표금액
int save_EEPROM = 10; // 누적금액 비휘발성 저장변수
int goal_EEPROM; // 목표금액 비휘발성 저장변수
int star_EEPROM; // 코드가 보드에 업로드 되고 처음 시작됨을 보여주는 비휘발성 저장변수, 여기서 읽어온 값이 255면 처음 시작
char escape; // 처음 루프문에서 탈출하게 하는 변수, #을 받으면 break 한다
float c10 = 1.22; // 10원의 무게
float c50 = 4.0; // 50원의 무게
float c100 = 5.5; // 100원의 무게
float c500 = 7.7; // 500원의 무게
int p; // p는 동전이 올려졌음을 표시하기 위한 변수
int k = 0; // k는 mode를 설정할 때 사용하는 변수
int s; // 동전의 종류를 의미
float weight; // 로드셀에서 받는 무게
int angle; // 서보모터의 각을 의미하는 global 변수
int count; // 비밀번호 입력시 입력된 숫자 개수
int tru; // 비밀번호 비교시 맞은 자릿수 개수
int modeToggle; // 모드가 변했을 때 1, 모드가 변하지 않았을 때 0
char password[4] = {’9′,’5′,’0′,’9′};
int int_password;
const byte ROWS = 4; //키패드 4행
const byte COLS = 3; //키패드 3열
int goalAddStart = 1; // 목표 금액 시작 주소
int goalAddress1 = goalAddStart; // 첫번째 목표 금액 주소
int goalAddress2 = goalAddStart + 1; // 두번째 목표 금액 주소
int goalAddress3 = goalAddStart + 2; // 세번째 목표 금액 주소
int goalAddress4 = goalAddStart + 3;
int goalAddress5 = goalAddStart + 4;
int goalAddress6 = goalAddStart + 5;
String inpGoal; // 현재 입력 중인 목표 금액
int mode2_cursor = 0; //mode2에서 lcd 커서 위치를 나타내는 변수
int mode3_cursor = 0;//mode3에서 lcd 커서 위치를 나타내는 변수
int mode4_cursor = 0;//mode4에서 lcd 커서 위치를 나타내는 변수
int mode = 1;
/*1. 동전을 받는 모드
2. 목표금액 설정 모드
3. 비밀번호 입력 및 누적 금액 초기화
4. 비밀번호 재설정*/
char keys[ROWS][COLS] = {
{’1′,’2′,’3′},
{’4′,’5′,’6′},
{’7′,’8′,’9′},
{‘*’,’0′,’#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
Servo armServo; // 동전을 밀어내는 서보 모터
Servo lockServo; // 잠금장치 서보 모터
LiquidCrystal_I2C lcd(0x3F,20,4); // LCD 객체 선언
HX711 scale(DOUT,SCK); // 로드셀 객체 선언
// 함수들 모음
void modeButton(Keypad Kp) { // mode 버튼을 누를 때마다 mode가 변하게 하는 함수입니다.
char key = Kp.getKey();
if(key == ‘#’){
modeToggle = 1;
delay(500);
k++;
delay(50);
k = (k%4) ;
mode = k+1;
}
}
float cali(float input){ // gram 단위로 calibration 하는 함수입니다.
float m = (7.7-5.42)/(136809.65-131866.56);
float n = 5.42 – 131866.56*m;
float output;
output = m*input + n;
return output;
}
void changeAngle(Servo myServo){ // 팔을 편도운동으로 움직이는 함수입니다.
if(angle==0){
myServo.write(arm_angle);
angle = arm_angle;
}
else{
myServo.write(0);
angle = 0;
}
delay(1000);
}
void withdrawal(Keypad Kp){ // 모드3 비밀번호 입력해서 돈 빼는 함수. 추가설명
char key = Kp.getKey(); // 키패드 입력받는 부분. keypad.getKey()는 라이브러리에 있는 함수
if (key) {//key라는 게 얻어졌다면.
delay(300);
if(key == ‘#’){
delay(300);
k++;
k = (k%4) ;
mode = k+1;
modeToggle = 1;
}
else if(key==password[count]) //입력번호와 비밀번호가 맞을시 count,tru++해줍니다.
{
count++;
tru++;
lcd.setCursor(mode3_cursor,3);
lcd.print(key);
mode3_cursor++;
}
else if(key!=password[count])//입력번호와 비밀번호가 틀릴시 count만 ++ 해줍니다.
{
count++;
lcd.setCursor(mode3_cursor,3);
lcd.print(key);
mode3_cursor++;
}
}
if(count==4)//count개수가 4가 되어 4자리 입력이 끝났을때
{
delay(300);
mode3_cursor = 0;
lcd.setCursor(0,3);
lcd.print(” “);
if(tru>=4){//트루도 4라면 비밀번호 정답입니다!
lcd.setCursor(0, 2); //커서를 (0,2)으로 보냅니다
lcd.print(“Correct Password “); //(3, 0)부터 비밀번호 맞았다고 LCD에 띄우기
lockServo.write(90); //정답이니까 서보모터 돌려서 잠금장치 해제합니다
delay(6000); // LCD에 글자 띄우고 돈뺄시간 6초 줍니다
lcd.setCursor(0, 2);
lcd.print(” “);
saving(0,11);
lockServo.write(0); // 다시 잠그기
tru=0;
count=0;
}
else{
lcd.setCursor(0, 2); //커서를 (4, 0)으로 보내라
lcd.print(“Wrong Password “); //(4, 0)부터 비밀번호 틀렸다고 LCD에 띄웁니다
delay(2000); // LCD에 글자 띄우는 시간 2초 줍니다
lcd.setCursor(0, 2);
lcd.print(” “);
tru=0;
count=0;
}
}
}
void newPassword(Keypad Kp, char pass[4]){ // 모드4 비밀번호 바꾸는 함수입니다. 추가설명
lcd.setCursor(0, 2); //커서를 (0, 2)으로 이동
lcd.print(“Enter original PW “); //(0, 2)부터 기존 비밀번호 입력하라고 LCD에 띄우기
char key = Kp.getKey(); // 키패드 입력받는 부분. keypad.getKey()는 라이브러리에 있는 함수
if (key) {//key라는 게 얻어졌다면.
delay(300);
if(key == ‘#’){ //‘#’ 누르면 모드를 바꿉니다.
delay(300);
k++;
k = (k%4) ;
mode = k+1;
modeToggle = 1;
}
else if(key == password[count]) { //입력번호와 비밀번호의 count번의 자리수가 맞을시 count,tru++해줍니다.
count++;
tru++;
lcd.setCursor(mode4_cursor,3);
lcd.print(key);
mode4_cursor++;
}
else if(key!=password[count]) {//입력번호와 비밀번호가 틀릴시 count만 ++ 해줍니다.
count++;
lcd.setCursor(mode4_cursor,3);
lcd.print(key);
mode4_cursor++;
}
if(count==4){//count개수가 4가 되어 4자리 입력이 끝났을때
delay(300);
mode4_cursor = 0;
lcd.setCursor(0,3);
lcd.print(” “);
if(tru>=4){
//트루도 4라면 비밀번호 정답입니다!
count = 0;
lcd.setCursor(0, 2); //커서를 (0, 2)으로 보냅니다
lcd.print(“Enter new PW “); //(0, 2)부터 새로운 비밀번호 입력하라고 LCD에 띄웁니다
while(count != 4){
key = Kp.getKey();
if(key){
delay(100);
if(’0′<= key <=’9′){
pass[count] = key;
count ++;
lcd.setCursor(mode4_cursor,3);
lcd.print(key);
mode4_cursor++;
}
}
}
count = 0;
tru = 0;
delay(300);
mode4_cursor = 0;
passwordSaving(password,21);
lcd.setCursor(0,3);
lcd.print(“New Password: “);
int lc;
for(lc=0;lc<4;lc++){
lcd.print(password[lc]);
}
delay(2000);
lcd.setCursor(0,3);
lcd.print(” “);
lcd.setCursor(0,2);
lcd.print(” “);
}
else{
lcd.setCursor(0, 2); //커서를 (0, 2)으로 보냅니다
lcd.print(“Wrong Password “); //(0, 2)부터 비밀번호 틀렸다고 LCD에 띄웁니다
delay(2000); // LCD에 글자 띄우는 시간 2초 줍니다
lcd.print(” “);
tru=0;
count=0;
}
}
}
}
void saving(long saved, int room_num){ // EEPROM에 정보 저장하기 room_num에 시작하는 주소 적기 목표금액(1), 누적금액(11), 비밀번호(21) 추가설명
int room_start=room_num+1;//자리수 첫번째 자리
long ssss=saved; //for문에 사용
int num=0;//자리수
int a=0;//저장할때 거듭제곱할때 사용
int i=0;//for문에 사용
int k=0;//for문에 사용
int b=0;//저장하는 숫자
long ten=1;//10 거듭제곱할때 쓰이는 수
float zero=1;//0.1 거듭제곱할때 쓰이는 수
long savedd=0;
while(saved>0){
saved=saved/10;
num++;
}
//자릿수 측정. 추가설명
a=num-1;//자릿수보다 하나 빼준 걸로 거듭제곱해야 합니다.
EEPROM.write(room_num,num);//자리수 저장
for(i=room_start;i<num+room_start;i++){
for(int k=0;k<a;k++){
ten=ten*10;
}
for(int k=0;k<a;k++){
zero=zero*0.1;
}
b=ssss*zero;//저장할 자리수
ssss=ssss-b*ten;//여기서 위에 꺼 10빼줘서 2만 남깁니다.
EEPROM.write(i,b);//저장
a=a-1;//거듭제곱할 수 바꿔줍니다.
ten=1;
zero=1;
}
for(int i=room_start; i<EEPROM.read(room_num)+room_start;i++){
int value=EEPROM.read(i);
}
}
int returning(int room_num){//누적금액을 불러오는 함수. 추가설명
int room_start=room_num+1;
long savedd=0;
int k=0;
int i=0;
long ten=1;
int a=EEPROM.read(room_num)-1;//받을 때 쓸 자릿수에서 1을 빼준다.
for(int i=room_start; i<EEPROM.read(room_num)+room_start;i++){
for(int k=0;k<a;k++){
ten=ten*10;
}
savedd=savedd+ten*EEPROM.read(i);
ten=1;
a=a-1;//거듭제곱할 수 바꿔줍니다.
}
return savedd;
}
void readPassword(int adds, char pass[4]){ //EEPROM에서 비밀번호를 불러오는 함수입니다.
int hyy;
int ua;
for(hyy=adds;hyy<adds+4;hyy++){
ua = EEPROM.read(hyy);
pass[hyy-adds] = char(ua);
}
}
void getGoal(Keypad Kk){
if(inpGoal.length()>=7){
//LCD에 입력할 수 있는 금액의 범위를 넘었다고 출력하는 코드입니다.
inpGoal = “”;
}
else{
char tempInput = Kk.getKey();
String tempGoal(tempInput); // String 형으로 키패드 입력 읽어옵니다.
if (tempGoal != NO_KEY){
if ((tempGoal != “#”)&&(tempGoal != “*”)){ // 숫자 입력의 경우
inpGoal = inpGoal + tempGoal; // 현재 입력된 키패드의 입력을 추가합니다.
lcd.setCursor(mode2_cursor,3);
lcd.print(tempGoal);
mode2_cursor++;
// 현재 입력되고 있는 숫자의 값을 실시간으로 lcd에 출력하는 함수입니다.
}
else if (tempGoal == “#”){ // ‘#’가 입력되면 모드를 바꿉니다.
delay(300);
inpGoal = “”; // 입력 중이었던 목표 금액 초기화
k++;
k = (k%4) ;
mode = k+1;
modeToggle = 1;
}
else if (tempGoal == “*”){ // * 입력(확인 버튼)의 경우입니다.
mode2_cursor = 0;
goal = inpGoal.toInt(); // char 형 변수 int 형 변수로 변환합니다.
long goal1, goal2, goal3; // EEPROM에 저장할 목표 금액 자릿수 별 숫자
goal1 = floor(goal/10000);
goal2 = floor((goal-goal1*10000)/100);
goal3 = floor(goal-goal1*10000-goal2*100);
EEPROM.write(goalAddress1, goal1);
EEPROM.write(goalAddress2, goal2);
EEPROM.write(goalAddress3, goal3);
k++;
k = (k%4) ;
mode = k+1;
modeToggle = 1;
inpGoal = “”; // 입력 중이었던 목표 금액 초기화
}
}
tempGoal=”";
delay(150);
}
}
void mode2(Keypad Kp){
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
getGoal(Kp);
}
long readGoal(){ //EEPROM에 저장된 목표 금액을 읽어와서 int 형으로 반환
long goal_EEPROM1, goal_EEPROM2, goal_EEPROM3; // EEPROM에 저장된 숫자들을 임시로 저장할 변수
goal_EEPROM1 = EEPROM.read(goalAddress1);
goal_EEPROM2 = EEPROM.read(goalAddress2);
goal_EEPROM3 = EEPROM.read(goalAddress3);
return (goal_EEPROM1*10000 + goal_EEPROM2*100 + goal_EEPROM3);
}
void passwordSaving(char pass[4], int addr){
int ha;
for(ha=addr;ha<addr+4;ha++){
EEPROM.write(ha,pass[ha-addr]);
}
}
/*
readGoal 함수 사용하는 대신에 Setup() 함수에서 goal = EEPROM.read(goalAddress1)*10000 + EEPROM.read(goalAddress2)*100 + EEPROM.read(goalAddress3)
으로 읽어와도 무관합니다
*/
void setup() {
armServo.attach(arm_servoPin);
lockServo.attach(lock_servoPin);
armServo.write(0);
lockServo.write(0);
angle = 0;
Serial.begin(9600);
pinMode(steadyLED, OUTPUT);
pinMode(processingLED, OUTPUT);
pinMode(menuButton, INPUT_PULLUP);
lcd.init();
lcd.clear();
lcd.backlight();
}
void loop() {
modeButton(keypad);
save = returning(11);
readPassword(21,password);
goal = readGoal();
if(k==0){ Mode1입니다. 추가설명
if(modeToggle==1){
lcd.clear();
}
lcd.setCursor(0,0);
lcd.print(“MODE: 1″);
lcd.setCursor(0,2);
lcd.print(“SAVED: “);
lcd.print(save);
lcd.setCursor(0,3);
lcd.print(“GOAL: “);
lcd.print(goal);
digitalWrite(steadyLED,HIGH);
digitalWrite(processingLED,LOW);
weight = cali(scale.get_units());
if(weight > c10 -0.2){ // 무게가 동전의 범주 안에 있을때
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
delay(500); // 동전의 무게가 안정될 때까지 기다리는 시간을 줍니다.
weight = cali(scale.get_units()); // 안정된 동전의 무게를 다시 받습니다.
//동전 종류를 판별합니다. 추가설명 if((weight<c10+0.5)&(c10-0.5<weight)){ //10원 동전의 무게의 범위에 들어올 때
s = 10;
p=1;
}
if((weight<c50+0.5)&(c50-0.5<weight)){ //50원 동전의 무게의 범위에 들어올 때
s = 50;
p=1;
} if((weight<c100+0.5)&(c100-0.5<weight)){ //100원 동전의 무게의 범위에 들어올 때
s = 100;
p=1;
}
if((weight<c500+1)&(c500-1<weight)){ //500원 동전의 무게의 범위에 들어올 때
s = 500;
p=1;
}
if(p==1){ // 올라온 동전을 저장. 추가설명
changeAngle(armServo);
p=0;
save = save + s;
saving(save,11);
}
}
if(modeToggle == 1){modeToggle = 0;}
if(save>=goal){ // 목표금액에 도달하였을 때 led를 반짝이는 코드입니다.
if(goal!=0){
int jjj;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(“MODE: 1″);
lcd.setCursor(0,2);
lcd.print(“Congratulation!!”);
for(jjj=0;jjj<50;jjj++){
digitalWrite(steadyLED,HIGH);
digitalWrite(processingLED,LOW);
delay(100);
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
delay(100);
}
saving(0,11);
lcd.clear();
}
}
}
else if(k==1){
if(modeToggle==1){
lcd.clear();
}
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
lcd.setCursor(0,0);
lcd.print(“MODE: 2″);
lcd.setCursor(0,1);
lcd.print(“Enter your GOAL and”);
lcd.setCursor(0,2);
lcd.print(“Press ‘*’”);
if(modeToggle == 1){modeToggle = 0;}
mode2(keypad);
}
else if(k==2){
if(modeToggle==1){
lcd.clear();
}
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
lcd.setCursor(0,0);
lcd.print(“MODE: 3″);
lcd.setCursor(0,2);
lcd.print(“Enter the Password”);
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
if(modeToggle == 1){
count = 0;
}
if(modeToggle == 1){modeToggle = 0;}
withdrawal(keypad);
}
else if(k==3){
if(modeToggle==1){
lcd.clear();
}
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
lcd.setCursor(0,0);
lcd.print(“MODE: 4″);
digitalWrite(steadyLED,LOW);
digitalWrite(processingLED,HIGH);
if(modeToggle == 1){modeToggle = 0;}
newPassword(keypad, password);
}
}
9.1. Mode1
동전을 받기 전 if(k==0)는 현재 mode가 1임을 나타내는 조건문이다. 여기서 k는 mode1을 의미한다. lcd.setCursor(0,1), lcd.print(“MODE: 1″)는 lcd(0,1)에 현재 mode1이라는 것을 표시한다. 동전을 받은 후 weight = cali(scale.get_units());는 hx711을 통해 무게를 받고 cali() 함수를 통해 그램 단위로 조정한 후, 그 값을 weight 변수에 저장한다. if(weight > c10 – 0.2)는 hx711을 통해 받은 weight 값이 동전의 무게 범위에 해당하는지 확인하는 과정이다. 이 과정에서 로드셀의 미세한 오차로 인한 오작동을 방지할 수 있다. digitalWrite(steadyLED,LOW)와 digitalWrite(processingLED,HIGH)는 투입된 동전이 저장되기 전까지 새로운 동전을 투입하지 않도록 LED로 표시해주는 것이다. delay(500), weight = cali(scale.get_units()): 투입된 동전이 정상상태가 될 때까지 대기한 후, 동전의 무게를 다시 측정하도록 하였다.
9.2. 동전의 종류를 판별하는 코드
동전의 무게를 이용해 종류를 판별하며 동전 개체 간의 무게 편차를 고려하여 오차 범위를 0.5 그램으로 설정하였다. (500원의 경우, 1 그램) 그 다음 동전의 무게를 int형 변수 s에 저장하고 int형 변수 p에 1을 저장하여 동전이 로드셀 위에 있음을 표현한다.
9.3. 동전을 저장하는 코드
p를 통해 동전이 로드셀 위에 있음을 표현하고 changeAnlge() 함수를 이용해 서보 모터를 작동하여 동전을 로드셀 위에서 밀어낸다. 그 후 p에 0을 대입하여 동전이 떨어졌음을 표현한다. 그 후 누적금액을 나타내는 save 변수에 s를 더해 추가된 금액을 표현하고 saving() 함수를 이용하여 EEPROM 영역에 누적금액을 저장하도록 하였다.
9.4. saving 함수
누적금액이 0보다 작아질 때까지 10으로 나눠주어 자릿수를 구하는 함수이다. EEPROM.write(room_num,num)은 이 자릿수를 누적금액을 저장하는 첫 번째 주소에 저장해 나중에 누적금액을 불러올 때 쓸 수 있게 하였다. 만약 1239080을 저장한다고 한다면 이 숫자를 10^-6을 곱해주면 1이 된다. 이 수를 저장하고 1239080에서 1*10^6을 곱한 수를 빼주면 저장한 1은 빠지고 239080만이 남게 된다. 이 수를 다시 10^-6인수를 곱하여 2를 저장하고 이 과정을 자릿수만큼 하게 되면 자릿수와 누적금액의 수가 차례대로 주소에 저장된다. b=ssss*zero로 저장할 수를 구한다. ssss=ssss-b*ten로 이미 저장한 수를 빼줘 다음에 저장할 수만 나올 수 있도록 하였다. EEPROM.write(i,b); 여기서 알맞은 주소에 수를 저장한다.
9.5. returning 함수
1239080이 누적금액이라고 한다면 1000000+200000+30000+9000+000+80+0 와 같이 각 자리의 숫자를 더하여 누적금액을 불러오도록 하였다. 그러기 위해서는 각각의 자릿수와 그 숫자에 맞는 10의 제곱수가 필요하다. saving 함수와 마찬가지로 각각의 자릿수에 곱해줄 10의 제곱수를 만들고, savedd=savedd+ten*EEPROM.read(i);을 통해 자릿수와 맞는 10의 제곱수와 자릿수를 곱한 수를 더해줘 저장되어있던 누적금액을 구해준다. ten=1을 통해 거듭제곱할 수를 초기화 시켜줘 다음 for 문이 실행될 때 알맞은 10의 거듭제곱 수를 구할 수 있게 하였다. a=a-1을 통해 다음 거듭제곱을 해줘야 하는 횟수를 구하였다.
9.6. getGoal 함수
목표금액을 설정하는 함수를 void getGoal()로 선언하였다. 이 때, 목표금액은 동전으로 모으려고 하는 금액이기 때문에 100만원 미만의 금액으로, 최대 999,999원을 저장할 수 있도록 하였다. 먼저, 함수 내에서 If else 문을 통해 현재 입력되고 있는 목표금액의 자릿수가 7자리를 넘지 않게 필터링을 하였다. 만약 현재 입력되고 있는 목표금액의 자릿수가 7자리를 넘지 않는 경우, 변수 tempGoal에 현재 키패드의 입력값을 String 형식으로 받아오도록 하였다. ‘tempGoal != NO_KEY’의 판단문을 통해, 키패드에 입력값이 있는지의 여부를 판단하였다. 이후, 키패드의 입력이 있었을 경우에, ‘(tempGoal != “#”) && (tempGoal != “*”)’의 판단문을 통해, 숫자 키패드를 눌렀을 경우, 입력되어 온 목표금액 값을 저장하는 String 형 변수인 inpGoal의 뒤에 현재 입력된 키패드 값인 tempGoal을 추가해주었다. 만약 입력이 “#”이었을 경우, inpGoal 변수를 초기화하고 현재의 모드인 모드 2에서 모드 3으로 넘어가도록 하였다. 만약 입력된 키패드 값이 “*”이었다면, 여태까지 입력하였던 값을 목표금액으로 설정하고 모드를 모드 3으로 변경하도록 하였다. 우선, 목표금액을 저장하는 long 형 전역변수 goal에 목표금액 값을 입력하기 위하여, String 형 변수인 inpGoal을 toInt 명령어를 이용하여 long 형 변수인 goal 에 숫자 값으로 저장되도록 하였다. 또한, EEPROM 라이브러리를 이용하여 아두이노의 비휘발성 메모리에 목표금액 값을 저장하도록 하였다. 이 때, EEPROM의 각 주소에 들어갈 수 있는 데이터의 크기가 제한되어 있으므로, 전체 목표금액을 100진수로 취급하여 각 자리를 분리하여 저장하도록 하였다. 이후 모드를 모드 3으로 변경하고, 입력받은 목표금액을 저장하는 변수인 inpGoal을 초기화하도록 하였다.
9.7. readGoal 함수
readGoal 함수는 EEPROM에 저장된 목표금액을 읽어오는 함수이다. 100진법으로 분할하여 EEPROM에 저장한 데이터 값을 각각 읽어와서 10진수로 변환하여 그 값을 return 하도록 하였다. 결과적으로 함수에서 return하는 데이터가 long 형으로 출력되도록 하기 위하여 함수의 선언을 long 형으로 하였다.
9.8. withdrawal 함수
mode3에서 비밀번호를 확인하는 과정은 키패드로 받은 key를 password와 비교하는 것이다. key와 password의 첫째 자리를 비교하여 같을 경우 count와 tru를 1 각각 더해주고 다를 경우에는 count만 1을 더해줍니다. 둘째 자리, 셋째 자리, 넷째 자리도 마찬가지로 비교하면 비밀번호가 맞았을 경우에는 count와 tru가 둘 다 4가 된다. 만약 한자리라도 비밀번호와 틀렸을 시 count는 4이지만 tru는 값이 달라진다. 이로써 비밀번호 정답여부를 판단할 수 있다. 비밀번호가 맞다고 판단되면 LCD에 표시하고 잠금장치를 6초 동안 풀어준다. 비밀번호가 틀리다고 판단되면 LCD에 틀렸다고 2초 동안 메시지를 띄운다.
9.9. newPassword 함수
mode4에서 새 비밀번호를 설정하는 방법은 먼저 withdrawal 함수와 마찬가지 방법으로 비밀번호를 확인한다. 비밀번호가 맞으면 count=0로 다시 설정하고 count=4가 될 때까지 한자리씩 새 비밀번호를 입력 받도록 하였다. 이후, 비밀번호를 passwordSaving 함수를 이용해 저장하도록 하였다.
10. 참고문헌
· Giorgio Rizzoni, James Kearns. (2016) Principles and Applications of Electrical Engineering, 6th Ed., McGraw-Hill, New York
· R. C. Hibbeler, (2014) Mechanics of Materials, 9th Ed., Pearson, London
· Author Unknown, “Arduino,” Internet: https://namu.wiki/w/Arduino?from=%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8, [Mar. 27, 2018]
· Author Unknown, “아두이노,” Internet: https://ko.wikipedia.org/wiki/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8, [Dec. 14, 2017]
· Author Unknown, “아두이노 기초1. 아두이노란?,” Internet: http://codingrun.com/61, [Aug. 08, 2016]
[53호]아~ 시원해~(보조배터리 쿨팩)
2018 ICT 융합 프로젝트 공모전 참가상
아~ 시원해~(보조배터리 쿨팩)
글 | 동양미래대학교 백동준, 한석규, 박민엽, 최재훈, 이정민, 김태윤
1. 심사평
칩센 보고서에 회의록까지 첨부하여 실제 프로젝트 진행이 어떤 형식으로 이루어졌는지 이해하는 부분에 도움을 많이 줍니다. 실제 작품 완성도 면에서는 아쉬움이 있습니다. 아이스팩이기 때문에 어떤 형태로 사용할지에 대한 고민도 들어갔으면 합니다.
뉴티씨 팀원들이 함께 단계별로 아이디어를 내서 구현해가면서 함께 학습하는 좋은 작품이었습니다. 단계별로 마이크로컨트롤러를 학습하여 동작시켜볼 수 있는 좋은 기회가 되었을 것입니다. 다만, 실용성 면에서는 조금 부족한 작품이 된 것 같습니다.
위드로봇 아이디어 고민 단계에서부터 정리된 보고서가 인상적입니다. 다만 펠티어 소자를 단순 활용하는 것에서 벗어나 좀 더 기존 제품에서 볼 수 없었던 창의적인 부분이 아쉽습니다.
2. 작품 개요
2월 말 부터 시작하여 약 2주간 4~6회의 정기모임을 실시하여 아이디어 회의를 시작, 다양한 의견을 종합했다. 다양한 아이디어들 중 보조배터리에 쿨팩을 결합한 아이디어가 돋보였고, 동아리원들의 동의 하에 자세한 자료 조사를 실시하였다. 겨울에 보조배터리와 손난로가 결합한 상품들은 판매가 되고 있으나 우리가 생각한 제품은 생산 또는 개발 중에 있지 않다는 것을 확인하였고 보조배터리에 USB를 연결하여 작동시키는 선풍기만 있다는 것을 파악했다. 하지만 선풍기의 경우 USB를 꽂아 사용하는 불편함도 있을 뿐만 아니라 여름에 뜨거운 공기로 인해 선풍기의 역할을 제대로 못한다는 것을 파악했다. 반면 겨울철 보조배터리의 경우 열을 이용하여 만든 제품으로 별도의 USB 포트를 사용할 필요가 없고, 열 전달 효과 또한 뛰어났다. 따라서 우리는 보조배터리의 내부를 냉각시켜 마치 쿨팩을 손에 쥐고 있는 듯한 제품을 만들어 보기로 결정했다.
3. 작품 설명
이번에 저희 동아리에서 만든 작품은 보조배터리 쿨팩, ‘아~ 시원해~’ 라는 작품으로 현재 시중에 나와 있는 보조배터리와 손난로가 함께 결합된 제품에서 아이디어를 얻어 ‘왜 여름에 사용할 수 있는 보조배터리와 쿨팩(시원한 소재)이 결합된 제품은 없는가?’ 라는 의문에서 시작했다. 처음 작품을 제작하기에 앞서 냉각을 총 4단계로 제어를 할 수 있도록 회로 구성 및 제작에 돌입하여 실험을 진행했고, 트랜지스터를 이용하여 온도 제어를 실시했으나, 펠티에 소자의 특성상 많은 전류가 흘러 트랜지스터로는 제어에 어려움을 느꼈다. 또한 최근 들어 여름에 이상기온으로 인한 무더위가 지속되고 있어, 최대한 냉각의 효과를 내기위해 제어를 이용하기 보다는 우리 원했던 최적의 온도(9℃ ~ 12℃)를 유지하는 것이 더욱 효율적이다. 는 판단 하에 3Pin Slide Switch를 이용하여 사용자가 간편하게 사용할 수 있도록 구성했다. 또한 향후 작품이 채택되어 생산 및 판매가 되는 경우를 대비해 최소한의 회로 System을 구성하는 것을 목표로 하였고 결과적으로 보조배터리의 역할을 충실히 할 뿐만 아니라 간단한 스위칭 조작으로 선풍기 보다 뛰어난 냉각 효과를 배터리 내부에서 작동시켜 외부 USB 단자로 전자기기를 충전하면서, 쿨팩으로 이용할 수 있도록 제작을 하였다.
3.1. 주요 동작 및 특성
3.1.1. 펠티에 소자의 동작 및 특성
펠티에 효과란?
펠티에효과는 두 종류의 금속을 접속하여 전류를 흐르게 하면 두 금속의 접합부에서 열의 발생 또는 흡수가 일어나는 현상으로. 1834년 J. C. A Peltier가 발견한 열전현상의 일종이다. 이것은 이종금속에서는 금속 내의 전자의 퍼텐셜에너지에 차가 있기 때문에 퍼텐셜에너지가 낮은 상태에 있는 금속으로부터 높은 상태에 있는 금속에게 전자를 운반하는데 밖으로부터 에너지를 얻어야 할 필요가 있으므로 두 금속의 접점에서 열에너지를 빼앗기고, 역의 경우에는 열에너지가 방출되게 된다. 일반적으로 이 효과에 의하여 단위시간에 두 종류의 금속의 접점에서 발생 또는 흡수되는 열량은 전류의 세기에 비례하고, 두 금속의 종류에 따라 정해진 값을 가진다. 이 값을 두 금속의 대한 펠티에계수라고 하고, 그 크기는 두 금속의 전자의 퍼텐셜에너지의 차에 상당하는 열전력과 절대온도에 비례하게 된다. 즉, 이 효과를 요약하면, 기전력에 의해서 이동하는 자유전자 보다 높은 페르미 준위로의 이동을 위해서 에너지를 흡수해야만 하는 상황에서 가장 구하기 쉬운 열에너지를 흡수하여 이동함으로써 전자를 내어주는 편에서는 지속적으로 열이 흡수되고, 반대편에서는 지속적으로 열이 방출된다는 것이다. 간단한 구조와 환경친화성, 그리고 높은 신뢰성 (물리적인 동작 구조를 전혀 가지지 않는 전기회로로만 구성도기 때문에 고장 날 여지가 거의 없다.) 을 가지고 있어서 활용도가 더욱 높아졌다.
위의 펠티에 효과를 바탕으로 이번 작품에서 구현하고자 하는 펠티에 소자를 이용한 냉각을 구현하기 위해선 두 개의 서로 다른 금속이 2개의 접점을 가지고 있어야 한다는 전제조건이 필요하다. 그러나 하나의 소자로는 큰 냉각효과를 기대하기 어려우며, 그래서 펠티에 소자를 사용한 붙인 형태를 하고 있다. 그 구조를 보자.
맨 아래와 맨 위에는 세라믹 층이 있으며, 이것은 열을 효율적으로 전달하면서도 전기의 흐름을 제한하는 역할을 한다. 그 아래에 있는 전도체 층과 반도체 층이 실질적인 냉각 ‘엔진’ 이다. 그리고 가장 아래층에는 역시 절연체인 세라믹이 위치해 있다. 반도체 층의 경우 P형 반도체와 N형 반도체 전체가 직렬로 이어져서 최대한의 냉각 효율을 끌어내도록 구성되어 있다.
기본적으로, 펠티에 소자는 서로 다른 반도체, 즉 P형 반도체와 N형 반도체의 접합에 기반하고 있다. 여기에 사용되는 반도체는 일반적으로 반도체라고 불리는 갈륨-비소 반도체를 사용하지 못한다. 이것은 TEM의 특성상 최고의 효율을 내기 위해서는 세 가지 조건이 조화를 이루어야 하는데, 이 세 가지는 제벡 계수(약자로 π를 사용)가 높아야 하며, 전기저항이 낮아야 하며, 열전도성 또한 최대한 낮아야 한다. 제벡 계수가 높다는 것은 적은 전력으로도 높은 냉각효과를 가질 수 있다는 것을 의미한다. 전기저항이 개입되는 이유는 반도체 스스로의 발열 때문이다. 열로 손실되는 에너지의 양은 저항 값의 제곱에 비례하기 때문에 저항이 낮으면 낮을수록 소자 자체의 발열이 적어서 소자 자체의 발열로 인한 전체적인 온도의 상승을 억제할 수 있다. 물론 전력 역시 적게 소모하게 된다. 열전도성이 낮아야 한다는 것은 전위차에 의해 유도된 소자 양단의 온도차를 그대로 유지시키기 위함이다. 만약 열전도성이 높다면 양단의 온도차를 만들어준 것이 무의미하게 되기 때문이다. 이러한 모든 성질을 종합한 것이 ‘메리트 상수’ 라는 것이다. 메리트 상수는 Z라는 약자로 표기되며 공식은 아래와 같다.
현재 가장 많이 사용되는 펠티에 소자로는 텔루오르화 비스무스(Bi2Te3), 텔루오르화 납(PbTe)이 있다.
하지만, 펠티에 소자는 가격이 비싸고 고온에서 소자가 파괴되며 발열부의 온도를 잘 제어하지 못하면 발열부의 온도가 냉각부도 전도되면서 효율이 급격하게 떨어지는 문제와 많은 양의 전기와 주변의 공기에 포함되어 잇는 수분이 얼어붙는 응결현상도 발생한다. 따라서 이러한 문제를 줄이려면 발열부의 냉각이 잘 이루어지도록 하여야 한다.
이번 작품에서 사용할 펠티에 소자는 ‘SP1848’ 이라는 모델로 주로 CPU나 냉장고의 냉매로 이용되는 소자로 아래 그림과 같은 형태로 되어있고, 구성 표에 의해 온도 차가 발생한다.
Specifications (Power input when used in Peltier Effect)
· 40mm x 40mm x 3.3mm
· Open-circuit voltage:(V) 0.97 1.8 2.4 3.6 4.8
· Temperature difference: (°) 20 40 60 80 100
· Current: (MA) 225 368 469 558 669
Voltage meter 및 LCD System
이번 작품의 경우 Arduino와 적절한 스위치 활용, 그리고 시각적인 편리함을 주기 위한 LCD Panel 등을 이용하여 향후 작품이 생산, 제작 과정에 들어갈 것을 고려하여 최소한의 전자기기들을 이용하여 작품을 구성하였다. 또한 Arduino의 활용을 통하여 Voltage meter, Yellow green Standard 16×2 Character LCD System을 구현하여 사용자 편의 인터페이스를 위해 최선을 다하였다.
3.2. 전체 System 구성
펠티에 소자 동작 및 LCD System 활용을 통한 ON/OFF 표시
펠티에 소자를 활용한 쿨팩 기능은 사용자가 구동하고자 할 때 스위치 ON/OFF를 통하여 간단하게 동작을 할 수 있도록 구성하였다. 또한 Arduino 와 연결된 LCD Panel을 통하여 현재 쿨팩의 기능을 사용하고 유무를 사용자가 눈으로 확인 할 수 있도록 ON/OFF 메시지 (1과 0으로 표현)를 구현하였다.
보조배터리 역할 및 LCD Panel을 통한 충·방전 System 표현
보조배터리로써 역할과 주 전원으로 이용 될 리튬이온배터리 3개 (LGEBF1L1865), USB 충전 모듈(모델명)을 통하여 배터리를 충·방전 할 수 있도록 구성하였고, 또한 충·방전을 시각적으로 보여주기 위해 Arduino에 전압 측정 모듈(Voltage Sensor)을 설치한 후 배터리와 연결하고, 연결된 배터리는 Yellow green Standard 16×2 Character LCD(BONA MC1602-13)와 연결하여 현재 리튬이온배터리의 전압의 크기를 확인할 수 있게 만들어 사용자의 편의를 더해 주었다.
냉각효과 증대를 위한 방열 System 구성
펠티에 소자의 경우 위에 언급한 것처럼 한쪽은 발열 한쪽은 흡열이 되기 때문에 발열이 되는 부분을 다양한 방열 도구를 통하여 냉각을 해주어야 한다. 따라서 이번 작품에서는 펠티에 소자의 방열을 위하여 40*40*10 DC 5V / 0.15A의 방열 팬과, 40*40*11의 방열 팬을 각 펠티에마다 설치하여 방열 System을 구성했다.
펠티에 소자에서 나오는 열을 배출하기 위하여 방열 팬과 회로(리튬이온 배터리, Arduino, LCD)사이에 약 1cm의 공간을 두고, 보조배터리 후방부에 작은 구멍을 뚫어 열을 효율적으로 배출 할 수 있도록 하였다. 또한, 신체와 접촉하는 면(냉각 효과를 전달할 수 있는 면)은 펠티에 소자에서 전달할 수 있는 냉각효과를 최대한 전달하기 위하여 음료수 캔 정도의 얇은 알루미늄 판과 펠티에 소자 접촉면을 방열테이프를 통하여 연결하였다. 방열 팬과 방열판으로 인한 부피 때문에 의 11 * 11 * 6.5 Case를 구하여 사용하였다.
3.3. 개발 환경
작품을 개발하기에 앞서 가장 주요한 펠티에 소자 제어와 LCD System 구성을 위하여 C언어를 기반으로 한 Arduino Uno(초기 Nano로 진행하였으나 성능차이로 인해 제장 중 Uno로 변경)를 이용하였습니다.
초기 LCD System 및 냉각 효과 4단 제어 관련 소스코드
#include <LiquidCrystal.h>
LCD패널을 구동 시키기 위해 기본값 설정
(LiquidCrystal.h의 기능을 추가 시키겠다.)
LiquidCrystal lcd(2,3,4,5,6,7);
LCD에 들어가는 데이터 선 핀번호 지정
16×2LCD 기준으로 하여 RS,E,D4,D5D6,D7 순입니다.
각종 변수와 핀번호 설정
int L = 0; (레벨 값표시) int buttontog = 0; 버튼 조작 int buttonre = 0; 버튼 리턴 조작
float vout = 0.0; 센서 출력 float vin = 0.0; 센서 입력 int buttog = 0; 버튼 조작
float R1 = 30000.0; 센서 내부 저항값 float R2 = 7500.0; 센서내부 저항값 int buttre = 0; 버튼 리턴 조작
int value = 0; 가치값(연산보조) int VOIN = A0; (전압측정센서의 아날로그 센서 인풋핀 번호)
void setup(){ // 한번만 실행(초기실행)
lcd.begin(16,2); // lcd를 사용 시작 하겠다 라는 명령어
pinMode(VOIN,INPUT); pinMode(8,INPUT); pinMode(9,INPUT);
pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT);
pinMode(13,OUTPUT); 각 트렌지스터 쪽으로 빠지는 출력과, 버튼 입력 , 센서값 측정 핀 설정
value = analogRead(VOIN); vout = (value * 5.0 ) /1024.0; vin = vout /(R2 / ( R1 + R2));
아날로그 보조 연산 값 //계산 값//최종적으로 출력되는 전압 값
lcd.setCursor(0,0); lcd.write(“Level = “); lcd.print(L); lcd.setCursor(0,1); lcd.write(“voltage = “); lcd.print(vin);
(0,0)부터 시작해서 Level = 라는 문고를 출력 lcd 에 L 값을 출력 (0,1);부터 시작 하여 voltate = 라는 문구 출력 vin(출력값)출력
buttontog = digitalRead(8); //버튼 조작 값 설정
buttog = digitalRead(9); //또 다른 버튼 조작 값 설정
if(buttontog != buttonre) //버튼에 입력이 들어 왔을 때
{if(buttontog == HIGH) //버튼 핀으로 출력값 생성하여 연속 적인 실행을 막음
{L++;} //레벨값을 올려줌
}
else{}
buttonre = buttontog; //버튼을 초기값 으로 설정
if(buttog != buttre) //위와 동일 대신 문구를 비슷하게 해서
{if(buttog == HIGH) //알기 쉽게 해놓은 것 뿐입니다.
{L–;} //레벨값을 낮춰줌
else{}
}
buttre = buttog;
버튼이 한번에 한번씩밖에 동작이 되게 끔 하는 소스 코드 설계
if(L>=5)
{L=4;
digitalWrite(13,LOW);//digitalWrite(12,LOW); digitalWrite(11,LOW);
digitalWrite(10,LOW);
}else if(L==4)
{digitalWrite(13,HIGH);//digitalWrite(12,LOW); digitalWrite(11,LOW);
digitalWrite(10,LOW);
}else if(L==3)
{digitalWrite(13,LOW); //digitalWrite(12,HIGH); digitalWrite(11,LOW);
digitalWrite(10,LOW);
}else if(L==2)
{digitalWrite(13,LOW); digitalWrite(12,LOW); digitalWrite(11,HIGH);
digitalWrite(10,LOW);
}else if(L==1)
{digitalWrite(13,LOW); digitalWrite(12,LOW); digitalWrite(11,LOW);
digitalWrite(10,HIGH);
}else if(L<=0)
{digitalWrite(13,LOW); digitalWrite(12,LOW); digitalWrite(11,LOW);
digitalWrite(10,LOW); L=1;
}else{
}
} 각 레벨 마다 다른 출력 값 레벨 5 와 0 일 때 모든 출력은 정지 시키고 1~4안으로 다시 리턴 시키는 방식으로 레벨에서 벗어나는 값을 방지
초기 전압 측정 모듈 관련 소스코드
float vout = 0.0;
float vin = 0.0;
float R1 = 30000.0;
float R2 = 7500.0;
int SPIN = A0;
int value = 0;
void setup(){
pinMode(SPIN, INPUT);
Serial.begin(9600);
Serial.print(“Voltage:”);
}
void loop(){
value = analogRead(SPIN);
vout = (value * 5.0) / 1024.0;
vin = vout / ( R2 / ( R1 + R2) );
Serial.print(“V: “);
Serial.println(vin,2);
delay(1000);
}
#include <LiquidCrystal.h> // LCD기능을 불러온다.
LiquidCrystal lcd(2,3,4,5,6,7); // LCD에 들어가는 데이터 선 핀번호 지정
16×2LCD 기준으로 하여 RS,E,D4,D5D6,D7 순입니다.
int L = 0;// (레벨 값표시) int RUN1=0;// LCD에 표기할 cool run 정수
float vout = 0.0; // 센서 출력 float vin = 0.0; // 센서 입력
float R1 = 30000.0; // 센서 내부 저항값 float R2 = 7500.0; // 센서 내부 저항값
int value = 0; // 가치값(연산보조) int VOIN = A0; // 전압측정센서의 아날로그 센서 인풋 핀 번호
void setup(){ // 처음 시작할 때 지정 또는 초기 상태에서의 한 번의 동작을 요구함
lcd.begin(16,2); // 16X2LCD의 사용을 시작한다.
pinMode(VOIN,INPUT); pinMode(8,INPUT); //VOIN에 설정되어있는 A0핀을 인풋으로 설정 및 8번핀을 인풋으로 설정 한다.
}
void loop(){ // 이 구간을 반복적으로 실행 한다.
value = analogRead(VOIN); vout = (value * 5.0 ) /1024.0; vin = vout /(R2 / ( R1 + R2));
아날로그 보조 연산 값//계산 값//최종적으로 출력되는 전압 값
L = digitalRead(8); //레벨값을 D8번 핀의 읽는 값으로 설정한다.
if(L>=1){RUN1 = HIGH;}else{RUN1 = LOW;} // 레벨값에 따라서 작동한다는 것을 LCD에 표기한다.
lcd.setCursor(0,0); lcd.write(“cool run = “); lcd.print(RUN1); lcd.setCursor(0,1); lcd.write(“voltage = “); lcd.print(vin);
//LCD에 0,0 자리에서 다음 문구를 생성하고 상수는 런 값을 표기한다.
//0,1(2째 줄)자리부터 전압에 대한 문구를 생성하고 뒤에 측정값을 표기한다.
4. 단계별 제작과정
4.1. 초기 4단계 제어 관련 회로 제작 및 시험
4.3. 펠티에 소자 병합 및 완성본
4.4. 펠티에 소자 냉각성능 실험
방열판, 방열 팬 등을 이용한 단계별 실험 진행
4.5. 4단계 회로, 펠티에 실험 진행 성능차이 없음 확인(초기 Nano 사용)
4.6. Uno로 변경 후 회로 제작 및 배터리 제작
4.7. 케이스 시뮬레이션
4.8. 최종 기판 작업 실시
4.9. 최종 작품 제작 전 시뮬레이션
4.10. 최종 작품 구동 및 평가
5. 참고문헌
· http://www.peltier.co.kr/shop/item.php?it_id=1354755775&ca_id=602010&page=1&sort1=&sort2=
· HAPPYCAMPUS – 제벡효과와 펠티에효과의 원리와 그 이용
· Technoa – 펠티어 효과와 펠티어 소자
· 한국동력기계공학회지 제 10권 제 4호 – 펠티에 소자 및 히트싱크펠티에 성능 실험
6. 펠티에 성능 실험
[53호]어린이와 노약자를 위한 휴대용 타격게임
1. 심사평
칩센 학생다운 재미있는 작품으로 판촉활동에 도움이 될 것 같습니다. 좀 더 눈에 띄는 리액션이 있었으면 좋았을 것 같습니다.
뉴티씨 딱밤의 세기를 측정하는 실내용 게임을 제작한다는 재미있는 설정으로 시작된 프로젝트네요. 친근하고 재미있게 작품을 만들면서, 여러 가지 기술을 습득할 수 있는 기회가 되었다는 점에서 좋은 점수를 얻었지만, 전반적인 완성도나, 작품을 보는 사람들의 이해도의 측면에서 조금 더 디자인적인 측면을 고려하였으면 하는 아쉬움이 남는 작품이었습니다. 하지만, 여러 가지 내부의 기술들을 모두 구현하려고 노력하여 구현한 점 등은 높은 점수를 드립니다.
위드로봇 압력 센서를 활용하여 ‘딱밤’의 세기를 측정하는 게임을 만든다는 아이디어가 재미있습니다. 전체적인 작품의 완성도 잘 되었습니다만 보고서에서 결과에 대한 분석 및 기타 개선할 부분이 정리가 되면 더 좋았었을 것 같습니다.
2. 작품 개요
2.1. 주제
자신의 ‘딱밤’의 파워를 측정 할 수 있는 미니 게임기. 친근하고 포근한 이미지를 주기위해 마동석과 에뛰드 하우스를 모티브로 디자인한 귀여운 게임기
2.2. 개발 동기
길거리 펀치 머신을 이용하지 못하는 아이들이나 어른들을 위해서 집에서도 할 수 있는 작고 간단한 타격 게임을 만들고 싶었습니다. 길거리 펀치 머신은 날씨의 제약을 많이 받기 때문에 비가 오는 날이나 무척 추운 날에는 잘 하지 않게 됩니다. 심지어 건강한 성인들 중에서도 길거리 타격 게임을 이용하다가 다치는 경우가 일상 다반사입니다. 그래서 전 연령대가 집에서도 재미있게 할 수 있는 게임을 만들어보고자 싶었습니다. 미니 타격 게임을 생각하다가 모든 사람들이 잘 알고 있는 딱밤을 생각하게 되었고 그것을 주제로 친근한 에뛰드 하우스와의 콜라보로 제작하게 되었습니다.
3. 작품 설명
3.1. 주요 동작 및 특징
3.1.1. 사용 기술
① 타이머를 이용한 서보모터 2개 컨트롤
② Bluetooth를 이용한 핸드폰과 ATmega128통신
③ 압력센서를 통한 표적 인식
④ CLCD기능을 이용한 최고점수와 현재점수 표현
⑤ ADC를 이용한 LED제어
3.1.2. 동작 원리 및 시스템 구성
블루투스(HC-06)을 이용한 핸드폰 어플 블루투스터미널과 ATmega128의 Bluetooth 통신 기능입니다. 블루투스 칩의 Tx핀과 ATmega128의 PE0(Rx)핀을 가변저항을 이용하여 5[V]->3.3[V]로 변환하여 연결하고, 블루투스 칩의 Rx핀과 PE1(Tx)핀을 직접 연결하여 핸드폰과 ATmega128을 연결합니다. 블루투스 터미널 어플에서 설정한 세 가지 버튼(주먹, 보자기, 가위)을 선택하여 ATmega128에서 난수 함수(rand 함수 이용)를 발생시켜 얻은 세 가지 결과(주먹, 보자기, 가위)와 비교를 하여 승, 무, 패를 결정하여 핸드폰 어플 화면에 결과를 띄우고, 동시에 ATmega128로 결과를 전송합니다.
void Timer_init()
{
ETIMSK = (1 << TOIE3); // timer 3 overflow
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
// TIMER1 비교일치 COM1A. COM1B 사용
TCCR1B = (1 << WGM3) | (1 << WGM12) | (1 << CS11) | (1 << CS10);
// 분주비 64, 입력캡처 사용
TCCR3A = 0×00; // timer 3
TCCR3B = 0×04; // 분주비 256 사용
ICR1 = 4999; // 입력캡처 사용 – > 50Hz
TCNT3H = 0xFF; // 처음 타이머 초기값이라 필요 없음 아무값 상관 X
TCNT3L = 0×05;
}
타이머 1번과 3번의 자체 타이머를 이용하여 서보모터 2개를 동시에 컨트롤함으로써 블루투스와 연결된 가위바위보 게임에서 블루투스 가위바위보 중/이겼을 시/ 졌을 시에 모터를 움직임으로 표적의 이동을 나타내는데 표적 제어는 서보모터(MG-995)를 이용하여 표적을 계속 좌우로 움직이게 하였습니다.
void ADC_init()
{
ADMUX = (0 << ADLAR) | (0 << REFS0) | (0 << REFS1); // AREF 사용 , ADC 0 사용
ADCSRA = (1<<ADEN) | (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // 프리스케일 128 분주비랑 adc 허용
}
압력센서(FSR-402)를 이용하여 표적을 인식합니다. 이 센서에 힘이 가해지면 저항값이 낮아지게 되고, 위의 회로와 같이 전압 분배 법칙을 이용하였습니다. 입력된 ADC값은 0~5[V] 값으로 Atmega128의 PF0핀으로 입력을 받습니다. 회로를 구성할 때 가변저항을 같이 사용했기 때문에 눌렀을 때 전압이 증가하는 전압 비를 조절할 수 있고, 가변저항을 돌리는 방향에 따라 조금만 눌러도 5[V]가 되기도 합니다. 이를 이용하여 딱밤의 세기를 조절할 수 있습니다.
현재 사용하고 있는 가변저항 10[]이고 값은 2.43[]입니다. 레지스터는 ADMUX이고 기준전압은 AREF로 5[V] 어댑터를 이용하여 기준전압을 설정했고, ADMUX = 0×00을 넣어 ADC0를 사용했습니다. ADCSRA 레지스터로 프리스케일을 허용해주고, 분주비는 128로 설정했습니다.
Vref값은 ADC값을 받은 후 다른 변수에 저장하여 계산하였는데 계산식은 (*ADC0) = (float) (*temp) * 512.0 / 1024.0 로 계산하였습니다. 앞에 별은 C언어에서 포인터를 사용하였기 때문에 적어준 겁니다. 10bit는 1024기 때문에 이 계산식을 이용하면 0부터 511까지 값을 얻을 수 있습니다.
void LCD_init()
{
_delay_ms(75);
write_instruction(0×30); // 기능 설정 데이터 길이 8비트,표시행수 1행, 문자폰트 5*7도트 사용
_delay_ms(25);
write_instruction(0×30);
_delay_ms(5);
write_instruction(0×30);
_delay_ms(5);
write_instruction(0x3C); // 기능 설정 데이터 길이 8비트, 표시행수 2행, 문자폰트 4*10도트 사용
_delay_ms(5);
write_instruction(0×08); // 화면표시 OFF, 커서 OFF, 커서 위치에 있는 블링크 기능 OFF
_delay_ms(5);
write_instruction(0×01); // 화면 모두 지움, 커서가 홈위치로 돌아감
_delay_ms(5);
write_instruction(0×06); // 엔트리 모드셋, 커서의 진행방향 오른쪽+방향, 화면자동시프트 OFF ( ON 설정시 화면이 자동으로 밀려서 감)
_delay_ms(5);
write_instruction(0x0c); // 화면표시 ON , 커서 OFF ,커서 위치에 있는 블링크 기능 OFF(블링크 ON설정시 커서 부분에 검은색 깜빡임)
_delay_ms(5);
}
CLCD 기능을 이용하여 압력센서에서 변환된 ADC 값을 변수로 받아 CLCD에 숫자 값을 표시해 줍니다. 여기서 처음 주목해야할 CLCD에 PIN은 4번입니다. CLCD 4번을 이용하여 CLCD를 초기화하여 사용 가능하게 하고, 데이터 입력이 가능한 상태로 만듭니다. 그리고 PIN 5번에서 데이터를 쓰거나 읽는 것을 조정할 수 있어 PIN 4번과 5번을 이용하여 ADC 값을 받아서 CLCD에 데이터를 쓸 수 있게 CLCD를 준비시킵니다. 우리가 받을 ADC값은 치는 사람에 따라 숫자 값이 0~511까지 변합니다. 그래서 이 숫자 값을 변수로 지정을 해서 CLCD로 입력을 시켜야 하지만 CLCD는 3자리 변수를 받지 않으니 SCORE라는 변수를 지정하고
(int)Score/100, (int)Score/10%10, (int)Score%10을 이용하여 숫자를 백의자리 십의자리 일의자리 수로 나눕니다. 이렇게 하나씩 떼어진 숫자에 +‘0’을 해줌으로써 CLCD에 아스키 코드의 값이 들어갈 수 있게 해주어 ADC에서 계산된 값을 CLCD pin 7~14번으로 넘겨 데이터를 써줄 수 있습니다. 이 원리로 사용자가 압력센서에 가한 압력의 크기를 측정해 실질적으로 자신의 That-Bam 파워 수치를 확인 가능하게 해줍니다.
void LED_control(int temp) // LED 제어 함수
{
int Floor = 0;
while(temp>0)w
{
if(Floor == 0){
Floor = 1;
}
else
Floor = (Floor << 1)+1;
temp–;
}
PORTC = Floor;
}
LED 제어 소스 설명
temp 변수는 0~512로 변환된 ADC값을 128로 나누고 1을 더하여 0~8 사이값으로 변환해놓은 값을 인자로 받는 변수입니다. 따라서 Floor라는 변수를 선언하고 temp를 0이 될 때 까지 마이너스 해주면 크기에 비례하는 LED값을 PORTC로 출력할 수 있게됩니다.
위에서 나온 압력센서 제어와 비슷하게 ADC를 이용합니다. LED는 압력센서로 받은 전압을 ADC로 변환 하고, 그 값을 즉각적으로 8개의 비트로 나누어 LED에 크기에 비례하는 LED를 켜주게 됩니다. 전체를 켜지 않고, Shift register를 이용하여 8개중 크기에 비례하게 1개씩만 들어오게 했으며, 크기가 0일때는 모든 LED에 불이 들어오지 않습니다.
3.2. Software Architecture (소프트웨어 구조)
위 그림은 프로그램의 진행을 나타내는 순서도입니다. 왼쪽의 그림은 핸드폰에서의 순서도, 오른쪽 그림은 Atmega128에서의 순서도입니다.
주요 동작과정은 Atmega128쪽에 표시되어 있습니다.
각 순서도를 참고하면, 프로그램의 동작 방법을 알 수 있습니다.
3.3. System Architecture (시스템 구조)
위의 그림은 시스템 구조를 블록다이어 그램으로 나타낸 그림입니다.
Atmega128에서 외부 기기를 제어할 때 사용한 기능들을 표시하였습니다.
화살표에 제어를 하는 기능들이 어떤 역할을 수행하는지 표시해 놓았습니다.
블록다이어그램을 보면 이번 프로젝트에서 설계한 하드웨어가 어떤 식으로 동작하는지 대략적으로 알 수 있습니다.
3.4. 개발 환경(개발 언어, Tool, 사용 시스템 등)
3.4.1. 주요 구성 부품
기본 부품
서보모터 (MG-995)
최대 120 degree까지 움직일 수 있습니다. 주파수를 50Hz(주기 20ms)로 맞추면 duty 비를 조절하여 모터를 제어할 수 있다.
Operating voltage : 4.8 ~ 7.2 [V]
압력센서 (FSR-402)
최대 10KG의 하중까지의 값을 측정할 수 있다. 압력센서는 0.45[]~100[] 사이의 저항값을 가지고 있는 소자입니다.
왼쪽에 그림에서 보면 소자에는 2개의 핀이 존재합니다. 한쪽에는 VCC를 연결하고 한쪽에는 ADC를 연결해주면 사용할 수 있습니다.
3.4.2. 개발 환경
개발언어 : C programming
개발Tool : AVR Studio
4. 단계별 제작 과정
5. 기타(회로도, 소스코드, 참고문헌 등)
5.1. 회로도
5.2. 참고 문헌
Atmega128 데이터 시트 (http://www.alldatasheet.co.kr/)
6. 완성사진