November 19, 2024

디바이스마트 미디어:

[66호] 원하는 색상으로 제어가 가능한 아두이노 IoT 스마트 무드등 키트 -

2021-06-25

★2021 ICT 융합 프로젝트 공모전 결과 발표! -

2021-05-12

디바이스마트 국내 온라인 유통사 유일 벨로다인 라이다 공급! -

2021-02-16

★총 상금 500만원 /2021 ICT 융합 프로젝트 공모전★ -

2021-01-18

디바이스마트 온라인 매거진 전자책(PDF)이 무료! -

2020-09-29

[61호]음성으로 제어하는 간접등 만들기 -

2020-08-26

디바이스마트 자체제작 코딩키트 ‘코딩 도담도담’ 출시 -

2020-08-10

GGM AC모터 대량등록! -

2020-07-10

[60호]초소형 레이더 MDR, 어떻게 제어하고 활용하나 -

2020-06-30

[60호]NANO 33 IoT보드를 활용한 블루투스 수평계 만들기 -

2020-06-30

라즈베리파이3가 드디어 출시!!! (Now Raspberry Pi 3 is Coming!!) -

2016-02-29

MoonWalker Actuator 판매개시!! -

2015-08-27

디바이스마트 레이저가공, 밀링, 선반, 라우터 등 커스텀서비스 견적요청 방법 설명동영상 입니다. -

2015-06-09

디바이스마트와 인텔®이 함께하는 IoT 경진대회! -

2015-05-19

드디어 adafruit도 디바이스마트에서 쉽고 저렴하게 !! -

2015-03-25

[29호] Intel Edison Review -

2015-03-10

Pololu 공식 Distributor 디바이스마트, Pololu 상품 판매 개시!! -

2015-03-09

[칩센]블루투스 전 제품 10%가격할인!! -

2015-02-02

[Arduino]Uno(R3) 구입시 37종 센서키트 할인이벤트!! -

2015-02-02

[M.A.I]Ahram_ISP_V1.5 60개 한정수량 할인이벤트!! -

2015-02-02

[39호]스마트헬스케어시스템 “아비터”

39 ICT 아비터 (3)

2016 ictmain

  2016 ICT 융합 프로젝트 공모전 참가상  

스마트헬스케어시스템 <아비터>

글 | 한국외국어대학교 박대원, 우지훈, 허행찬

 

심사평
JK전자 요즘 대부분의 스마트폰에는 NFC기능이 포함되어 있기 때문에 아두이노와 스마트폰의 인터페이스를 블루투스로 하는것 보다는 스마트폰의 NFC를 활용하여 중간에 아두이노 없이 바로 NFC태그를 이용한다면 조금더 효율적일수 있을 것 같다. 또한 블루투스는 보안상의 문제로 페어링 과정을 거쳐야 하기 때문에 모든 운동기구에 항상 다른 블루투스와 슬레이브 연결을 해야 한다면 이용자 입장에서는 불편할 수도 있을 것 같다. 구현 방법을 다르게 해서 조금 더 쉽고, 편리하게 개발을 한다면 아이디어는 괜찮은 것 같다.
뉴티씨 현대에는 운동을 통한 개인의 육체 단련도 매우 중요하다. 건강이 담보되지 않은 생활이란 있을 수 없기 때문인데, 공동으로 사용하는 헬스기구에 대해 여러사람들이 함께 이용할 수 있도록 한 점 등이 좋은 아이디어로 보인다. 다만, 실제로 구현하면서 적용하지 못한 점 등이 실용성이나 기술성, 완성도 등에서 좋은 점수를 받지 못하였으며, 보고서의 완성도에서도 좋은 점수를 받지 못하였다.
다만, 앞으로 이 아이디어를 제대로 구현하고 좀 더 IoT 환경에 맞는 나은 제품을 구현한다면 좀 더 실용적인 좋은 제품이 될 것 같다.
칩센 재미있는 아이디어지만 이미 회원증 또는 스마트폰을 통한 기기 운용과 운동기록 등을 진행하는 업체도 있고 해당 아이디어들이 구현된 업체가 많은편이다. 게임과 같이 가벼운 보상을 줘서 다른 운동기기로 자연스럽게 바꿀 수 있게 하는게 더 좋았을 것 같다.
위드로봇 간단하지만 꼭 필요할 법한 부분에 착안한 아이디어에 높은 점수를 줍니다. 단, 앱까지 제작되어 스마트폰에서 동작될 때 이 작품의 진가가 드러나게 될 것 같습니다. 이 부분의 구현이 부족한 점이 아쉽습니다.

프로젝트 목표
본 프로젝트는 아두이노와 안드로이드를 복합적으로 응용하여, 소프트웨어와 하드웨어가 융합된 어플 개발 및 서비스제작을 목표로 한다. 이 시스템을 통하여 헬스장에서 일어날 수 있는 헬스기구 사용자간 발생할 수 있는 사소한 마찰 및 불미스러운 일을 미연에 방지하고, 유연한 순환과 유동적인 헬스시설 이용을 돕는데 그 목적을 두고 있다.

프로젝트 내용
먼저 헬스장 회원들은 해당 앱을 설치하고, 실행하면 사용할 기구와 블루투스 모듈을 통하여 연결한다. 그리고 해당 기구의 RFID 리더기에 회원카드를 인식하면, 회원 로그인이 된다. 그리고 아두이노로 연결된 헬스기구 상단에 LED가 소등된다. 다른 회원들은 소등되어있는 LED를 확인하고, 해당 기구가 사용 중이라는 사실을 알 수 있다.
또한 로그인 된 어플리케이션은 회원의 정보와 현재 운동중인 부위와 운동데이터를 실시간 확인이 가능하며, 해당 데이터는 트레이너에게 전달되어 회원관리도 가능하다. 그리고 어플 내 관리자 호출기능을 통하여 관리자 및 트레이너와 통화 역시 가능하여, 불편한 사항이나 문제가 발생했을 시에도 즉시에 해결이 가능하다.
기구마다 일정 최대 사용시간이 정해져 있어서 사용자가 최대 사용 시간동안 한 기구를 이용할 경우 자동 로그아웃이 되고 LED가 점등되어, 다른 사용자들이 해당 기구를 사용 할 수 있게 된다. 그리고 가장 최근에 기구를 사용했던 사람은 바로 연속해서 기구를 사용할 수 없고 5분간의 쿨타임 동안은 같은 기구를 재사용할 수 없다. 5분이 지난 이후에도 해당 기구의 사용자가 없을 경우에는 재사용이 가능하다.
만약 기구 사용 도중에 운동을 그만하고 싶을 경우에는 어플리케이션 상에서 로그아웃을 하면 자동으로 LED가 점등이 되며 사용정지모드가 된다.

수행방법
문제 상황에 대한 인식과 해결방법에 대해 논의하며 해결책에 다가가면서 그에 대한 환경을 조사하고 해당 기술을 개발한다. 개발에 들어갈 때 각각 업무를 크게 어플 UI, RFID 인식, 블루투스 장치 파트로 분담하여 개발한다. 시스템 프로그래밍 수업시간에 배웠던 아두이노를 이용하여 프로그래밍을 하고 더 나아가 안드로이드를 자체적으로 연구하여 앱 개발에 들어간다. 각 팀원들의 개발 성과물을 계속 검토하며 시스템의 안정도를 체크한다. 이때 디버깅 과정에서 오류의 발생 여부에 따라 팀별 피드백을 수행하여 보완점을 수정한다.

향후 응용 및 활용방법
과학기술의 발달로 인하여 사람들에게 생활의 편의를 제공하기 위한 제품과 아이디어가 출시되고 있다. 현대인의 삶의 질적인 만족을 충족시키기 위하여 여가와 관련된 다양한 시스템이 나오고 있는 추세이다. 우리가 개발하고자 하는 ‘아비터’시스템은 스마트폰에 내장된 어플과 헬스 기구에 설치된 아두이노와 RFID 그리고 블루투스를 통해 정보를 교환함으로써 원활한 스포츠 시설의 환경을 제공할 수 있다. 이를 통해 헬스장 회원의 기다림을 최소화할 수 있을 뿐만 아니라 헬스기구 사용자 간의 사소한 마찰을 방지함으로써 건강한 운동문화를 조성할 것이다.

프로젝트 제목
우리가 개발하는 서비스의 명칭으로서, 아비터란 중재자라는 뜻을 가지고 있다. 저희가 개발한 이 서비스가 헬스장에서 발생할 수 있는 여러 가지 불미스러운 일들을 중재할 수 있는 중재자 역할을 할 수 있기를 바라는 마음으로 네이밍 하였다.

프로젝트 개요
프로젝트 배경 및 필요성

39 ICT 아비터 (1)

과학기술의 발달 및 경제성장에 따라 현대인들은 삶의 질 향상을 위한 여가 욕구가 증가하고 있다. 현대인들은 제한된 시간 및 공간에서 그들의 여가생활에 대한 욕구를 충족시킬 수 있는 공간이 필요하다. 이러한 욕구를 충족시킬 수 있는 공간은 대표적으로 ‘헬스장’이다. 현대인들에게 헬스장은 단순히 살을 빼기 위한 목적이 아닌 건강, 스트레스 해소 및 사교범위 확장을 위한 새로운 여가활동을 할 수 있는 장소이다. 그러나 여가 욕구를 충족시키기 위한 헬스장은 헬스기구를 기다리는 잉여시간으로 인하여 여가 욕구 충족이라는 목적을 달성하는 데 한계가 존재한다. 그뿐만 아니라 헬스 회원의 장시간 운동기구 독점으로 인하여 헬스 회원 간의 언쟁 및 불필요한 다툼이 발생하기도 한다. 이러한 헬스장의 문제는 여가 욕구의 충족이라는 본연의 목적을 달성하지 못할 뿐 아니라 개인의 삶의 질을 하락시킬 수도 있는 장소가 될 수 있다.
따라서, 위와 같은 헬스장의 문제점 및 한계를 해결하기 위해 우리는 스마트폰에 내장된 어플리케이션과 헬스기구에 설치된 아두이노와 RFID 그리고 블루투스 모듈을 통해 어떤 헬스기구를 이용할 수 있는지 확인 가능한 시스템을 고안하였다. 또한, 우리가 고안한 ‘아비터’ 시스템을 통해 헬스장 회원의 운동데이터를 쉽게 확인할 수 있을 뿐만 아니라 동일 기구를 독점할 수 없도록 쿨타임 기능을 추가하여 건강한 운동문화를 조성할 수 있을 것이다. 이 시스템은 점차 증가하는 여가 욕구에 대응하여 쾌적한 여가생활을 즐길 수 있는 환경을 제공할 뿐만 아니라 건강한 운동문화를 조성하고자 하는데서 프로젝트를 시작하였다.

프로젝트 목표
먼저 이 아이디어를 생각하게 된 것은 요즘 대형마트 주차장에서 흔히 볼 수 있게 된 주정차 센서와 도서관 좌석 관리 시스템이다. 주정차 센서는 주차가 되어있으면 위쪽에 빨간불, 비어있는 공간이면 초록색으로 표시가 되어 어디가 비어있는지 쉽게 볼 수 있는 센서장치이다. 그리고 도서관 좌석 관리 시스템 역시 한눈에 도서관 남는 좌석을 확인할 수 있는 시스템이다. 우리는 이 두 가지를 헬스장에 접목하면 어떨까 생각하게 되었다. 그리고 헬스장 내에도 전용 카드를 사용하는 곳이 많아 연관 지어 생각해 IC 칩이 내장된 카드를 이용해 해당 어플과 연동해 이용을 편리하게 하도록 했다.
먼저 블루투스를 이용하여 기구 내 하드웨어부와 사용자의 스마트폰을 연결하고, 회원정보가 등록된 카드를 하드웨어부의 RFID 모듈에 스캔하면 카드 안의 회원정보가 데이터화 되어 어플로 확인이 가능하다. 또한 기구에 있는 사용 중 표시등으로 기구가 현재 사용 중인지 사용 가능한지를 알려준다. 이러한 기술을 이용하여 운동기구의 사용 시간을 제한하거나 연속으로 등록하지 못하는 등을 통해 운동기구의 독점을 막고 다양한 사람들로 하여금, 운동기구를 사용함에 있어 유연한 순환이 가능할 수 있도록 돕는다.
한 기구를 사용하기 위해 오랜 시간 기다리지 않아도 되고, 잠시 자리를 비운 동안 자리가 없어지거나, 다른 한 사람이 기구를 독점해서 쓰지 못하는 일이 없도록 도와, 보다 쾌적하고 원활하게 헬스장을 이용할 수 있도록 돕는다. 또 원래 있던 카드와 스마트폰 만으로 이를 제어할 수 있도록 하여 이용하는 입장에서 금액 부담을 줄였다. 이를 통해 사용자들이 좀 더 여유롭고 기분 좋은 여가생활을 누릴 수 있도록 하는데 목표가 있다.

향후 프로젝트 활용도 및 기대효과
과학기술의 발달 및 경제의 고도성장은 사람들에게 풍요로운 생활과 생활의 첨단화라는 혜택을 주었을 뿐만 아니라 여러 가지 생활상의 변화를 가져왔다. 이러한 변화 중 가장 대표적인 것으로 스마트폰의 사용과 여가생활에 대한 욕구증가라고 말할 수 있다.

39 ICT 아비터 (2)

위의 그래프를 통해 알 수 있듯이 스마트폰 사용은 점차 증가하였으며, 오늘날 스마트폰은 현대인과 뗄 수 없는 존재로 자리 잡았다.
이러한 스마트폰의 사용 증가는 개인의 건강 증진과 연관되어 새로운 삶의 문화를 창조해가고자 하는 여가생활에 대한 욕구를 더욱 더 효율적으로 충족시킬 수 있다. 우리 팀이 개발하는 시스템은 스마트폰을 통해 현대인들의 잉여시간 및 자원을 효율적으로 활용하도록 도와 건강한 삶을 영위할 수 있도록 한다. 예를 들어 헬스 기구를 이용하기 위해 헬스장의 다른 회원의 헬스 기구 이용이 끝날 때까지 무작정 기다리기보다 ‘아비터’라는 어플을 통해 현재 이용 가능한 헬스 기구를 한눈에 볼 수 있다. 또한, 헬스기구의 최대사용시간을 설정하여 모든 회원이 공평하게 헬스기구를 이용할 수 있게 된다. 이를 통해 헬스 기구를 이용하기 위한 기다림을 최소화할 수 있으며, 개인의 헬스기구 장시간 사용으로 인한 헬스장 회원들 간의 마찰을 방지하여 건강한 운동문화를 조성할 것이다. 또한 ‘아비터’시스템을 통해 다른 경쟁 헬스장과 비교하여 높은 고객 만족을 충족시켜 경쟁력을 갖출 수 있을 것이다.

프로젝트 설명
프로젝트 주요 동작 및 시스템 구성
수행 결과물로는 하드웨어적 결과물과 어플리케이션을 나누어 설명하도록 하겠다. 먼저 어플리케이션의 경우 너무 복잡하지 않은 필요한 정보와 화면만을 담아 무겁지 않게 개발한다.

39 ICT 아비터 (3)

APP 실행 첫 화면
어플리케이션을 실행하면, 나타나는 시동화면으로써, 헬스케어서비스라는 어플리케이션의 특징을 잘 나타낼 수 있도록, 로고를 디자인하였고, 활기찬 느낌을 주는 파란색으로 메인 색을 설정하였다. 화면을 터치하면 다음화면으로 넘어간다.

39 ICT 아비터 (4)

블루투스 연결화면
휴대폰과 운동기구를 블루투스를 이용하여 연결한다. 이때 블루투스 버튼을 누르게 되면, 주변에 블루투스를 잡게 되는데, 사용자는 본인이 사용할 기구의 신호를 찾아 연결한다. 연결이 되면 자동으로 다음화면으로 넘어간다.

39 ICT 아비터 (5)

사용자 ID카드 인식 화면
사용자의 헬스장 회원 ID카드를 대면, 회원의 정보가 운동기구에 입력된다. 카드를 인식하게 되면, 개인정보를 확인할 수 있는 화면으로 자동으로 넘어간다.

39 ICT 아비터 (6)

쿨 타임 화면
사용시간이 다 되거나 로그아웃을 할 경우 쿨 타임이 진행된다. 쿨 타임을 사용하는 이유는 같은 사람이 한 가지 기구를 연속해서 사용하여 독점하는 것을 방지하기 위함이다. 쿨 타임은 약 5분 정도를 두고, 5분 동안은 다른 회원들에게 사용할 수 있는 기회를 주게 되고, 5분 내에 아무도 사용하는 인원이 없을 경우는 재사용이 가능하다.

39 ICT 아비터 (7)

개인 정보 확인 화면
ID카드를 인식하면, 회원의 기본정보가 확인가능하다. 사용 중인 기구마다 각각의 유형의 기구별로 한 번에 이용 가능한 시간을 제한하여 이용시간을 실시간으로 확인 가능하다. 또한, 사용도중에 문제가 발생하거나 운동방법에 대해 궁금한 것이 있을 경우 관리자 호출을 통하여 바로 트레이너 및 관리자와 통화가 가능하다. 기구마다 배정된 최대운동시간이 다 되거나, 로그아웃버튼을 누르면 다음화면으로 넘어가고, 하드웨어부에 부착된 사용 중 표시등은 꺼진다.
또한 기구마다 현재 사용 중인 운동부위를 알려줌으로써, 관리자는 회원의 운동부위에 따른 운동량 데이터를 실시간으로 확인이 가능하고, 회원의 개인별 관리를 좀 더 편하게 할 수 있다.

개발환경
이와 같이 주요화면 5가지를 토대로 하여 어플리케이션을 제작한다.
다음은 하드웨어적 결과물에 관한 내용이다.

39 ICT 아비터 (8)
하드웨어의 경우, 헬스 기구마다 설치될 예정이고, 아두이노를 이용하여 블루투스 모듈과 RFID를 연결한다. 그리고 RFID 모듈은 회원카드 접지부가 된다. 회원카드를 접지부에 대면 회원의 정보가 RFID 모듈을 통하여 아두이노에 전송이 되고 그 정보는 블루투스를 통하여 회원의 휴대전화로 전송이 된다. 또한, 기구에는 ‘사용중’ 표시등이 설치되어 있기 때문에 회원이 휴대전화를 통하여 로그아웃을 하거나 사용종료를 하게 되면, 그 정보가 아두이노를 통하여 표시등이 꺼지게 된다.
이처럼 하드웨어적 부분까지 완성을 하게 되면, 오류검출, 디버깅 작업을 마지막으로 프로젝트를 마무리하게 된다.

단계별 제작 과정
수행 방법
문제 상황을 인식하고, 배경환경을 조사한다. 그리고 개발에 필요한 기술과 정보에 대하여 인지하고, 해당 기술에 대하여 팀원들이 모여 스터디를 시행한다. 관련 기술을 팀원끼리 분담하여 연구를 하고, 각자 본인이 맡은 분야에 대하여 다른 팀원에게 지도하는 방식으로 내부 세미나를 진행한다. 앱 디자인과 개발을 연구하고 해당 내용을 완성한다. 앱 개발이 끝나면, 운동기구를 구해서 실제로 하드웨어를 설계하기 위한 디자인팀과 아두이노를 활용한 하드웨어 개발팀으로 나뉘어 각각 하드웨어를 개발한다. 이 때 디자인팀과 개발팀 중 먼저 완료가 되는 팀은 어플리케이션과 하드웨어 연계 전에 어플리케이션에서 발생하는 독자적인 오류를 잡기 위하여 반복 디버깅한다. 하드웨어의 개발이 끝나면, 어플리케이션과 직접적 연결을 통하여 동작에 이상이 없는지 확인하고, 오류 발생 시 수정작업을 진행한다. 이 작업까지 끝나면 세부적인 사항을 조정하고, 팀원 간 최종회의 및 제품 구동을 통하여 보완점을 개선하고, 프로젝트를 마무리한다.

세부 추진 일정

39 ICT 아비터 (1)

목표 설정 및 성과 측정

39 ICT 아비터 (2)

프로토타입

39 ICT 아비터 (9)39 ICT 아비터 (10)

기타

소스코드

#include <SoftwareSerial.h>
SoftwareSerial bt(2, 3); //3번 핀은 아두이노의 RX와 연결
byte buffer[100];
// 17C24, 51B00
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);// 시리얼 모니터 통신설정
bt.begin(9600); //블루투스 시리얼 통신속도 선언
Serial.println(“CARD HERE!”);
int bufferPos = 0;
}

void loop() {
byte data;
char tagString[4];
int index = 0;
int kk = 0;
//////////////////BLUETOOTH/////////////////
/*if(bt.available()) //블루투스를 통해 데이터가 날아오면( 앱에서 버튼눌리면)
{
byte data = bt.read();//수신받은 데이터 저장
buffer[bufferPos++]=data;

for(int k=0;k<bufferPos;k++){
Serial.print((char)buffer[k]);
}

bufferPos = 0;
if(data==’\n’){ //문자열 종료
buffer[bufferPos]=’’;
}
}
if(Serial.available())//시리얼 모니터로 값을 주면
{
byte data = Serial.read();
buffer[bufferPos++]=data;
if(buffer[0] == ‘5’)
{
bt.write(“ 1234”);
}
bt.write(buffer,bufferPos);// 스마트폰으로 받은 데이터 출력
bufferPos=0;

if(data==’\n’){ //문자열 종료
buffer[bufferPos]=’’;
}
}
*/
////////////////RFID/////////////
while(Serial.available()){
// for(int index =0;index<=3;index++){
char readByte = Serial.read();
tagString[index] = readByte;
index++;
Serial.println(“tagString is : “);
Serial.println(tagString);
Serial.println(index);

bt.write(“1234”);
// }

//delay(1000);
}
}

 

회로도

39 ICT 아비터 (11)

 

39 ICT 아비터 (12)39 ICT 아비터 (13)

 

 

 

 

[38호]지능형 GPS & 장애물 감시 주행로봇

38 ict 지능형 (20)

2016 ictmain

2016 ICT 융합 프로젝트 공모전 참가상

지능형 GPS & 장애물 감시 주행로봇

글 | 가천대학교 도성곤, 박성진

심사평

JK전자 창의적이거나 기술적으로 완성도가 높은 작품은 분명히 아니다. 하지만 보고서의 내용을 읽어 보면서 기초 지식이 굉장히 부족한 상태에서 의욕만 가지고 작품 구현을 시작한 것으로 보이고 비록 완성도가 높은 작품은 아니지만, 공모전에 참가하고 작품 완성을 위해서 하나하나 배우면서 많은 고생을 했을 것이라는 것이 보고서에서 느껴진다. 작품에 참여한 모든 인원들 수고했고 앞으로 많은 발전이 있을 것이라 생각된다.

뉴티씨 GPS를 이용하여 입력된 장소를 찾아가는 것은 말하기는 쉬우나, 실제로 만들어보면 생각보다 난제가 많음을 알 수 있다. 움직이는 것은 많은 문제점을 내포하고 있으며, 아이디어를 구현하였다는 점에 큰 점수를 주고 싶다. 이 자체로 실용적이거나 하지는 않지만, 앞으로 좀 더 연구하여 자동주행에 적용될 수 있도록 한다면 좋을 것 같다. 이 분야를 공부하는 한가지 계기가 될 수 있지 않았을까 생각하며, 이 작품을 만든 학생의 미래를 꿈꿔본다.

칩센 보고서 내용처럼 공부를 목적으로 하는 부분은 충분히 만족했을 것 같다. 너무 어려운 주제를 선택한 것 같다.

위드로봇 고생을 많이 한 작품으로 보인다. 특히 실외에서 실험을 진행해야 하기에 더욱 그러했을 것이다. UART 통신 및 기타 센서 인터페이스를 위해 MCU의 기초부터 차근차근 학습하면 좀 더 수월하게 개발을 할 수 있을 것으로 보인다.

작품개요
동기
현재 애플, 구글과 같은 세계적인 IT 기업은 무인자동차를 미래 먹거리 산업으로 정하고 계속 연구를 진행하고 있다는 것을 언론으로 알게 되었고, 꼭 한번 직접 만들고 싶다는 생각을 하게 되었습니다. 그러나 실제 크기의 자동차를 만들기에는 무리가 있다고 생각하여 미니카 사이즈로 제작하는 것부터 시작하였습니다.

무인자동차를 만들면 많은 부분에 관한 기초를 익힐 수 있다고 생각했습니다. GPS, 적외선 센서를 사용해 봄으로써 다양한 분야에 응용이 가능할 것이라는 기대를 합니다. 예로 청소기 로봇을 들 수 있는데 청소기 로봇은 집안의 장애물을 파악하여 피하며 스스로 청소를 하는 로봇입니다. 기존의 청소기 역시 청소는 가능했으므로 기존의 청소기에 장애물을 피하는 능력이 있으면 로봇 청소기가 되는 것이고, 이러한 장애물을 피하는 알고리즘을 무인 자동차를 만들면서 생각해 볼 수 있습니다.

또 다른 예로 작년에 많은 관심을 일으켰던 드론에도 적용하는 것도 가능할 것입니다. 아마존에서는 드론을 이용하여 제품을 배달하려는 계획을 세웠는데 이를 위해서는 GPS를 통해 현재 위치를 파악하고 목적지까지 가는 방법을 생각해야 합니다. 향후 우리들이 이 분야에도 진입할 수 있다는 생각에, 한동안 작품을 만들면서 힘들지만 계속 동기부여를 할 수 있었습니다.

제품의 도전 과제
① 적외선 센서의 장애물 감지
② 로봇의 모터 움직임(차체의 무게 최소화)
③ GPS 센서의 위성신호 데이터 수신
④ 수신된 데이터 GLCD에 표시
⑤ 이 모두를 구동케 하는 전원 장치(스위치로 구동)

제품 결과
적외선 센서는 평균적으로 15cm 거리의 장애물을 인식합니다. 앞과 좌, 우의 인지로, 로봇이 움직이는 방향이 달라집니다. 만약, 1) 좌측에 장애물이 있다면 우측으로 방향을 정하고 90도 각도로 회전해 움직입니다. 2) 좌측과 우측에 모두 장애물이 있을 시 180도 각도로 회전해 반대 방향으로 움직입니다. 3) 장애물이 없을 시 계속 전진합니다. 이 구동은 실외나 실내 모두 작동됩니다.

GLCD는 LCD보다 더 세밀한 장치입니다. 원래는 LCD를 하려고 했지만, 더 큰 과제로 GLCD로 도전해 보았습니다. GLCD는 픽셀로 제어해서 LCD보다는 더 정밀한 형태들을 만들 수 있었습니다. 특히, LCD는 영문자와 다른 기호 등 정도만 제어할 수 있지만, GLCD는 우리가 만들 수 있으면 한글로도 표시가 가능했습니다.

작품을 만들면서 최대한 무게를 줄이고 크기는 작게 하는 방식으로 생각했습니다. 그러기 위해선 속도보단 최소한의 안정된 경도를 유지하고 각종 센서들에 붙여진 모듈을 제거하려고 노력하였습니다. 그래서 ATmega128과 연결된 각종 PORT 보드를 안 쓰고 직접 이 MCU의 pin만 있는 상태에서 리드선을 납땜했습니다. 그리고 실외용으로 쓰이는 것도 감안하여 플라스틱으로 된 바퀴보다는 고무로 된 바퀴로 대체하여 실외용에도 크게 손상되지 않게 만들었습니다.

작품에서 의외로 전원 장치를 만드는 것에 애를 많이 먹었습니다. 우리가 쓰고자 하는 센서들이 필요한 구동전압과 전류들이 각각 다르기 때문에 거기에 적합한 구동을 하기 위해서 익숙치 않은 회로설계를 하여야 했습니다. 그리고 전원 장치로는 스위치로 작동시키기 위해 슬라이드 스위치를 이용하였고 바로 건전지의 6V에 외부전원을 공급하면 회로가 상당한 열을 받는 것을 알게 되어 다이오드 등 내부 전압강하를 유도해 전원 전압을 각종 센서들이 작동할 수 있는 최소한의 전압으로 4.5V 내지 최대 5.1V까지 공급할 수 있게 하였습니다.

작품 설명
주요동작/특징
· 적외선 센서로 80~10cm의 거리를 인식, 그 안에 장애물을 피함.
· GPS 센서 모듈을 이용, 실외에 있을시 GPS 신호를 받으며 목표지점을 지정할 수 있음
· 받은 GPS 신호와 목표지점은 GLCD에 표시가 됨.
· ATmega128 Lite를 이용, 건전지 6V 전원으로 구동.

전체 시스템 구성
1. ATMEGA128을 활용, 전원 스위치로 전원을 제어.
2. DC 모터 드라이버를 활용해서 DC 모터를 제어하여 로봇 구동.
3.적외선 센서를 이용해서 장애물 감지.
4. 장애물을 감지하면 DC 모터가 그에 따라 각도 조절.
5. GPS 모듈을 사용해서 어떤 데이터가 들어오는지 로봇이 확인.
6. GPS 데이터를 GLCD로 전송.
7. GLCD에서 수신 받은 GPS 데이터를 확인하고 목표 좌표 데이터를 로봇으로 전송.
8. 로봇이 목표 좌표 데이터를 수신 받고 수신 받은 데이터를 하이퍼 터미널이나 GLCD로 확인.
9. 목표 거리만큼 소스 코드에 따라 DC모터 제어를 통해 주행.
10. 앞의 적외선 센서 프로그램 제어를 통해 목표 좌표로 가는 동안 장애물을 감지하면서 구동.

개발환경

38 ict 지능형 (1)

1) 개발 언어 – C언어
2) Tool – 이클립스, AVR studio4.19, RS232_terminal
3) 사용 시스템 – 디지털 멀티 미터, power supply

단계별 제작 과정

1. 자동차 차체에 두 개의 DC 모터를 연결하였습니다. 앞에 구동하려는 바퀴는 따로 철물점상에 사온 작은 룰러 형식의 바퀴로 쓰이게 했고 로봇이 주행하는데 더 원활하게 움직일 수 있었습니다.

38 ict 지능형 (2)

2. DC 모터는 나사와 모터 고정대를 이용, 접착제와 함께 단단하게 부착시켰습니다.

3. 모터 드라이버는 차체 내 가운데에 부착시켰고, 드라이버에 선이 있어 DC 모터와 연결하고 MCU PORT B에 10p 커넥터로 연결했습니다.

38 ict 지능형 (3)

4. PCB 기판은 기판의 모서리에 구멍에다 나사와 철막대 2개를 이용하여 고정시키고, 차체에 접착제를 붙였습니다.

38 ict 지능형 (4)

5. 로봇의 배터리는 원활하게 전류가 흐르게 하는 것과 동시에, ATmeg128에 외부 단자가 아닌 내부 전원 5v을 공급하는데 효용성이 있다고 판단하여, 1.5V 알칼리 건전지 4개를 쓰게 되었습니다, 그래서 4개를 연결하는 소켓(6V)을 ATmega128의 외부전원으로 선택하였고 PCB 기판 아래에 부착시켰습니다.

38 ict 지능형 (5)

6. 차체의 무게를 조금이라도 줄이기 위해 원래의 Atmega128을 모듈에서 빼고 PCB 기판에 부착시켰습니다. 여기에 구동전압을 최대 6V로 주지 않고 7805 IC 소자를 통해서 정전압 5V 직류로 구동되게 하였습니다.

38 ict 지능형 (7)

7. PCB 기판 위에 GPS 센서 모듈을 4pin 소켓을 꽂아 고정시켰고 통신이 원활하게 유지되도록 ATmega128 uart 통신 pin에 직접 연결하였습니다.

38 ict 지능형 (8)

8. 적외선센서 3개는 차체 앞에 간격을 동일하게 두면서 접착제로 고정시켰습니다.

38 ict 지능형 (9)

9. 기판 아래에 회로선을 모터 드라이브, 적외선 센서, GPS 센서 모듈, GLCD 센서 모듈과 연결되는 포트들에 납땜하였습니다.

38 ict 지능형 (10)

10. GLCD를 PCB 기판위에 ATmega128 PORT A와 PORT F에 기판 아래 pin에다가 납땜된 커넥터와 GLCD 모듈의 10p 커넥터와 연결하였습니다. GLCD에 표시되는 것은 현재 속도, 현재 좌표, 목표 좌표입니다.

38 ict 지능형 (11)

11. 최종적으로 PCB 기판 위에 정리되지 않는 선들은 최대한 기판 아래 납땜하였고 기판 차체 사이에 보이는 연결선들을 접착제로 붙여 정리하였습니다. 위에서 보면은 UART 선들과 전원선을 제외하고는 연결선들이 거의 보이지 않게 하였습니다.

38 ict 지능형 (12)

12.제품 소프트웨어 구성

· DC 모터 구동 소스

/*
Purpose: Go forward
Input: Void
Output: Void
*/
void forward()
{
PORTB=0×00;
PORTB|=0×02;
PORTB|=0×10;
PORTB|=0×04;
}

· 적외선 센서 핵심 소스

/*
Purpose: Read value from infrared sensor
Input: Pin number
Output: Value which is read from infrared sensor
*/
unsigned int read_adc(unsigned char ch){
ADMUX=ch|0×40; _delay_us(10);
ADCSRA|=0×40; while((ADCSRA&0×10)==0); ADCSRA|=0×10;
return ADC;
}

· GPS 센서 핵심 소스

/*
Purpose: Interrupt service routine
Input: GPS Signal
Output: Parsed value
*/
ISR(USART1_RX_vect)
{
unsigned char RX;
int i;
RX=UDR1;
if(RX==’$’))//각각의 신호의 시작을 나타내는 것(GPS신호는 5개가 들어온다).
{
rx_buf[0]=’$’;
rx_cnt=1;
}
else if(RX==0x0A)//1개의 신호가 끝났음을 의미
{
rx_buf[rx_cnt++]=0;
if(strncmp(“$GPRMC”, rx_buf, 6)==0)/이번에 받은 신호가 우리에게 필요한 신호인지 확인
{
GPS_cut=strtok(rx_buf, “,”);//필요한 신호라 판단되면 ,을 기준으로 문자열을 나눈다.

for(i=0; GPS_cut; i++)
{
GPRMC[i]=GPS_cut;
GPS_cut=strtok(0, “,”);
}
strcpy(valid, GPRMC[2]);
strcpy(cur_lon, GPRMC[5]);
strcpy(cur_lat, GPRMC[3]);
strcpy(speed, GPRMC[7]);
}
rx_cnt=0;
}

else if(RX==0x0D)
rx_buf[rx_cnt++]=0;
else if(RX==’,’)
{
if(rx_buf[rx_cnt-1]==’,’)
rx_buf[rx_cnt++]=’0’;
rx_buf[rx_cnt++]=RX;
}
else if(RX==’*’)
{
if(rx_buf[rx_cnt]==’,’)
rx_buf[rx_cnt++]=’,’;
rx_buf[rx_cnt++]=RX;
}
else
{
if(rx_cnt<180)
rx_buf[rx_cnt++]=RX;
}
}

· GLCD 센서 핵심 소스

/*
Purpose: Input cmd to GLCD
Input: pinNumber and command
Output: Void
*/
void write_cmd(unsigned char cs, unsigned char cmd)
{
//check_bf();
LCD_CTRL = cs & CS_ALL;
SetE(1);
LCD_OUTP = cmd;
delay(1);
SetE(0);
delay(1);
LCD_CTRL=0×00;
delay(10);
}

/*
Purpose: Write data to GLCD
Input: Pin number and char
Output: void
*/
void write_data(unsigned char cs, unsigned char ch)
{
LCD_CTRL = (cs & CS_ALL) | DI;
SetE(1);
LCD_OUTP = ch;
delay(1);
SetE(0);
delay(1);
LCD_CTRL=0×00;
delay(10);
}
/*
Purpose: Clear glcd
Input: Void
Output: Void
*/
void lcd_clear(void)
{
unsigned char i, j, x, y;
LCD_CTRL=0×00;
write_cmd(CS_ALL,0x3f);
write_cmd(CS_ALL,0xc0);
x = 0xB8; /* X start address */
y = 0×40; /* Y start address */
for(i = 0; i <= 7; i++)
{
write_cmd(CS_ALL,x);
write_cmd(CS_ALL,y);
for(j = 0; j < 64; j++)
write_data(CS_ALL,0×00); /* clear CS1 and CS2 */
x++;
}
}

/*
Purpose: Initiation of glcd
Input: Void
Output: Void
*/
void lcd_init(void)
{
write_cmd( CS_ALL, DISPON );
write_cmd( CS_ALL, 0xc0 );
write_cmd( CS_ALL, 0xb8 );
write_cmd( CS_ALL, 0×40 );
}

/*
Purpose: Pointing and turn on lcd
Input: X, Y value
Output: Void
void PointXY(int xpoint, int ypoint){ //픽셀 단위로 x,y축으로
int point=0×01, value; 조정
int x1, y1, y2, y3;
x1=xpoint%128;
y1=ypoint%64;
y2=y1/8;
y3=y1%8;
compare[y2][x1]|=(point<<y3);
value=compare[y2][x1];
if(x1<64){
write_cmd(CS_ALL, x+y2);
write_cmd(CS_ALL, y+x1);
write_data(_CS1, value);
} else {
write_cmd(CS_ALL, x+y2);
write_cmd(CS_ALL, y+x1-64);
write_data(_CS2, value);
}
}
Purpose: Pointing and delete
Input: X&Y value
Output: Void
*/
void Point_Del(int xpoint, int ypoint){
int point=0×01, value;
int x1, y1, y2, y3;

x1=xpoint%128;
y1=ypoint%64;
y2=y1/8;
y3=y1%8;
compare[y2][x1]&=(~(point<<y3));
value=compare[y2][x1];
if(x1<64){
write_cmd(CS_ALL, x+y2);
write_cmd(CS_ALL, y+x1);
write_data(_CS1, value);
} else {
write_cmd(CS_ALL, x+y2);
write_cmd(CS_ALL, y+x1-64);
write_data(_CS2, value);
}
}

재료

38 - ict - 지능형 - 50
· ATmega128 모듈(뉴티씨)
MUC는 ATmega128을 사용하였습니다. 뉴티씨 Lite 모델로 무게를 최소화하고 ADC, UART, LCD를 이용할 pin들은 따로 pin 포트를 사와 고정시키고 PCB기판 동박면에 센서 모듈을 장착시킬 수 있었습니다. 외부 전원은 5V-input 핀에 연결을 하였고 GPS센서는 UART1통신에 연결하였습니다. 리셋버튼으로 통신제어하기에도 용이했습니다.

38 ict 지능형 (13) 38 ict 지능형 (14)

· DC모터 & 듀얼 DC모터 드라이브(YS-2270/유틸전자)
저희는 DC모터를 가벼운 것으로 선택하였습니다. 세운상가에서 값싼 가격대에서 샀고 모터드라이버는 1.5A에 5V~12V까지 구동되는 걸로 구매했습니다. 빠른 속도를 요하는 게 아니라서 5V 내로 전압을 준 속도면 충분했습니다. 실제, 모든 센서 모듈과 같이 제어하고 나면 마지막으로 모터와 GLCD가 가장 전류를 많이 잡아먹었습니다. 나머지 센서들이 작동되고 두 센서가 모두 켜지기 위해서는 600mA까지 전류가 흘러야 구동이 되었습니다.

38 ict 지능형 (15)

· 적외선센서(lk-dms) 3개
10cm-80cm정도 거리를 인식합니다. 구동전압은 4.5V-5.5V입니다. 적외선 센서는 3개를 이용하였으며, 각 VCC와 GND를 공통 VCC선과 GND선에 연결하였고, MCU의 PORT F.1,2,3 에 Vout선을 납땜하였습니다. 대체적으로 하이터미널로 확인한 바 15cm내외로 수신을 잘 받아내었습니다.

38 ict 지능형 (16)

· GPS 센서모듈(us-technology-UST-SNR-GPS v2)
3.3V로 구동되는 GPS 센서는 위 그림처럼 위성신호에서 수신받은 데이터를 다시 MCU에 송신해줘야 하기 때문에 센서의 UART 통신모듈 핀 VCC/TX/RX/GND에서 GPS의 VCC와 GND는 연결해주고 TX를 MCU UART1 RX에 연결해줍니다. 위도, 경도에 PC를 연결하여 하이퍼터미널로 확인 또는 GLCD로 확인케 하였습니다.
위성신호 데이터는 ‘$GPRMC’라는 문장에서 나오는데 이 신호가 가는 것이 위도, 경도가 그 뒤를 따릅니다. ‘A’라는 문구가 뜨면 실내로 들어온 것이라 뜨게 됩니다.

· 정전압 레귤레이터 7805 소자

38 ict 지능형 (17)

전원문제를 해결하는데 사용하였습니다. 1.5V 건전지 4개를 연결하여 6V 외부전원이 들어오는데 5V로 정전압을 공급해야 했습니다. 순간적인 전압의 흔들림으로 인한 리플값을 잡아주기 위해서 세라믹 콘덴서를 양쪽에 병렬로 설치하였습니다.

38 ict 지능형 (18)

· GLCD 모듈(LG128643 LMD WH6V)
5V 구동전압을 가지고 128×64 dots 로 제어합니다. 이것을 픽셀이라 합니다.

38 ict 지능형 (19)

완성품

38 ict 지능형 (20)

작품후기
처음 시작했을 때 GPS 신호라든지 적외선 센서라든지 LCD라든지 제대로 배워본 적 없던 소자를 다루기 때문에 걱정이 정말 많이 들었다. 역시나 해보면서 너무 많은 것을 배워야 되는 일들이 한꺼번에 쏟아져서 자료들을 많이 검색해서 얻은 정보로 간신히 만든 정도이다. 처음 용산전자로 가서 모터가 뭔지도 모르고 시작했던 터라 물어보는 것도 시원찮아 꾸중도 많이 들었다. 같이 했던 조원과도 뜻을 맞추기도 힘들었고 계속할 수 있을지 계속 의문이 들었다.
얼마 안 된 시간에 조금씩 차체에서 원했던 모습들이 쌓여가는 것이 보여지는 걸로 위안 삼아 이를 악물고 버티면서 배워보려고 했다. 처음 소자를 구매하는 것부터 디바이스마트에서 제품 설명서를 보면서 이해할려고 최대한 노력하였다. 추운 날씨에 GPS를 실외에서 신호를 받아 가는 과정을 지켜보는 시간이 길어지면서 너무 힘이 들었지만, MCU를 샀던 사이트에서 소스를 가져와서 고쳐보고 다시 그 소스로 밖에서 확인하고 하는 과정을 몇 십번씩 하면서 결국엔 GPS 신호를 처음으로 받아봤던 기쁨은 잊을 수 없다. 역시나 완성품이라고 하기에는 볼품이 없는 것 같다. 다른 학생들이 작품을 보면서 우리들이 쏟아부었던 노력들을 쌍그리 무시할 정도로 냉담히 평가하면 할 말이 없어진다. 하지만, 지금까지 이런 어려운 과제를 하면서 배우고, 실행하였던 과정들이 지금은 굉장히 뜻깊고 잘했단 생각이 든다. 앞으로 또 이런 과제로 주어지게 된다면 더 잘하고 싶다. 특히 GPS를 아직도 제대로 이해하지 못하여서 GPS관련한 걸로 하고 싶다.

 

 

 

 

 

[38호]라즈베리파이 SENSE HAT 리뷰

Cap 2016-12-08 10-23-45-719

Cap 2016-12-08 10-23-45-719

라즈베리파이 SENSE HAT 리뷰

우주정거장으로 날아 간

라즈베리파이 Sense HAT

글 | 금강초롱 blog.naver.com/crucian2k3

우리는 누군가가 순발력과 재치가 있어 다른 사람에게 일종의 기쁨 내지는 편안함을 선사한다면 ‘그 사람 참 센스가 있더라’라는 칭찬성 멘트를 일상에서 사용하곤 합니다.

이번에는 이러한 의미로 흔히 사용하곤 하는 센스(Sense : 감각)와 알파벳 대문자로 HAT(hat : 모자, 머리)라는 키워드가 붙은 보드라 조금은 어색함을 느끼며 리뷰를 시작하게 되었습니다.

38 sr 금강초롱 (1)

HAT가 그냥 모자를 의미하지는 않을듯하여 잠시 찾아보니 Hardware Attached on Top(HAT : 업보드, 쉴드 보드 등)의 머리글자를 따서 HAT를 만들었음을 알 수 있었습니다. 그냥 멀티센서쉴드 정도로 명명하면 누구나 쉽게 이해 할 수 있지 않을까 생각도 듭니다만 아두이노 진영에서 사용하는 쉴드라는 용어는 가급적 쓰고 싶지 않았을 수도 있고 아두이노는 이탈리아 태생이고 라즈베리파이는 잉글랜드 태생이라 문화적인 차이에 기인하기도 한 것으로 여겨집니다.
한마디로 Sense HAT 보드는 라즈베리파이보드 기반에서 현존하는 어지간한 센서는 모두 장착된 올인원 쉴드보드 정도라고 보면 틀리지 않을 듯합니다.

필자가 느끼는 아쉬움을 거론한다면 바이브레이션모터와 피에조스피커를 꼽을 수 있을 것입니다. 만일 Sense HAT에 진동과 사운드를 발생시킬 수 있는 소자가 추가가 되었더라면 더욱 크게 히트치지 않았을까 생각을 해봤습니다.

여러분~ 이제 이 센스쟁이 모자(?)와 즐거운 여행을 떠나 볼까요?

이 글은 (주)엔티렉스의 지원을 받아 작성하게 되었습니다.

라즈베리파이의 파이는 파이썬에서 따왔을 만큼 파이썬 언어와 관련이 깊습니다. 파이썬으로 작성된 센스햇 라이브러리와 gcc 기반에서 작성된 예제를 차근차근 실행시켜 보면서 이 보드가 어떤 재미난(?) 일을 할 수 있는지를 살펴보도록 하겠습니다.

1. 개요

구분 I2C Addr. 성능(기능)
MCU 0×46 ATtiny88
자이로스코프 0x1C LSM9DS1, 각도측정센서 : ±245/500/2000dps
가속도계 0x1C LSM9DS1, 선형가속센서 : ±-2/4/8/16g
지자기센서 0x6A LSM9DS1, Magnetic Sensor: ± 4/8/12/16gauss
기압센서 0x5C LPS25H, 260 – 1260hPa absolute range
온도센서 0x5F HTS221, ± 2degC in the 0-65 degC
습도센서 0x5F HTS221, 20-80%Rh의 범위 내에서 정확도 +/- 4.5%, 15-40degC의 범위 내에서 정확도 +/- 0.5degC
디스플레이 모듈 0×46 LED2472G, 8×8 LED matrix display
조이스틱 0×46 ALPS SKRHABE010, 소형 5 button joystick

Sense HAT 보드는 Atmel사(현재는 Microchip사(PIC)에 인수합병 됨)의 8비트 MCU인 ATtiny88을 기반으로 설계되어졌으며 일반적으로 사용되는 거의 모든 종류의 센서가 총망라 되어 있습니다. 모션센서는 MPU6050등 6축으로 구성된 칩이 하비일렉트로닉스 시장에서는 널리 사용됩니다만 이 보드에서는 ST Microelectronics의 LSM9DS1을 사용하여 9축 정보를 제공하는 등 차별화를 시도하고 있는 점이 이채롭습니다.
각각의 센서에 대한 정보를 살펴보는 것이 Sense HAT 보드를 이해하는데 상당한 도움이 될 듯하며 우선 총괄적인 부분을 살펴보면 아래와 같습니다.
이제 이 글을 읽는 독자님들이 궁금해 할 각각의 센서를 개략적으로 살펴보도록 하겠습니다.

1.1. 9축 모션센서

38 sr 금강초롱 (2)
● 모델명 : LSM9DS1
● 칩벤더 : ST Microelectronics사
● 주요 기능
· 3축 가속도계, 3축 자이로, 3축 지자계 센서
· ±2/±4/±8/±16g 선형가속계 감도
· ±4/±8/±12/±16가우스 지자계 센서 감도
· ±245/±500/±2000dps angular rate full scale
· 16-bit 데이터 출력
· SPI / I2C serial 인터페이스
· Analog 부문 공급전압 1.9V to 3.6V
· “Always-on” eco power mode down to 1.9mA
· Programmable interrupt generators
· 온도센서 내장
· Embedded FIFO
· 위치, 움직임 감지 함수 내장
· 휴대기기를 위한 저전력소모 기능 내장

일전에도 다룬바 있는 Genuino 101 보드에서도 모션센서를 내장하고 있기는 합니다만 가속도계와 자이로센서로 구성된 6축을 채용하고 있습니다.
Sense HAT에 내장된 9축 모션센서는 피치, 롤, 요 정보를 제대로 출력해 줄 수 있으므로 쿼드콥터, 밸런싱로봇, 게임기 등등 움직임이 수반되는 기기에 응용해 볼 수 있을 것으로 봅니다.

1.2. 기압센서

38 sr 금강초롱 (3)
● 모델명 : LPS25H
● 칩벤더 : ST Microelectronics사
● 주요 기능
· 절대기압 범위 260 to 1260hPa
· 고 분해능 모드 : 1Pa RMS
· 저 소비전력 : (저 분해능 모드)4μA, (고 분해능 모드)25μA
· 과압성능(High overpressure capability) : 20x full scale
· 내장 온도보정 기능
· Embedded 24-bit ADC
· Selectable ODR from 1Hz to 25Hz
· SPI and I²C 인터페이스
· 동작전압 : 1.7 to 3.6V
· 충격성능(High shock survivability) : 10,000g

Sense HAT을 활용하여 대기 중 온도, 습도, 기압 정보를 얻어와 날씨정보를 표시하거나 고도정보를 표시하는 용도로 응용이 가능할 듯합니다.
흔히 사용되지 않는 기압센서를 이번 기회에 라즈베리파이 유저들이 간편하게 접근해 볼 수 있도록 세심한 배려를 해둠에 감사할 따름입니다.

1.3. 온습도센서

38 sr 금강초롱 (4)
● 모델명 : HTS221
● 칩벤더 : ST Microelectronics사
● 주요 기능
· 상대습도측정 범위 : 0 to 100%
· 온도측정범위 : -40 to +120°C
· 전원공급 : 1.7 to 3.6V
· 소비전력 : 2μA @ 1Hz ODR
· Selectable ODR from 1Hz to 12.5Hz
· 고감도 rH : 0.004% rH/LSB
· 습도정밀도 : ± 3.5% rH, 20 to +80% rH
· 온도정밀도 : ± 0.5°C, 15 to +40°C
· 온습도 데이터 출력 : 16-bit
· SPI and I²C 인터페이스
· 제조자 보정 후 출고
· 패키지사이즈 : Tiny 2 x 2 x 0.9mm

취미전자 등에 흔히 사용하는 DHT-xx 시리즈에 비해 넓은 온습도 측정범위를 가진 칩이 장착되어져 있습니다. 이 칩이 제공해주는 기능을 활용해 라즈베리파이로 에어컨, 자동제어 등의 실험을 해볼 수 있을 것으로 예상해 봅니다.

1.4. RGB 고휘도 LED 모듈

38 sr 금강초롱 (5)
● 모델명 : CLP6R-FKW
● 칩벤더 : CREE사
● 주요 기능
· 사이즈(mm) : 6.0 x 5.0
· 주파장(Dominant Wavelength) : Red (610 – 625nm), Green (514 – 534nm), Blue (460 – 480nm)
· 광도(Luminous Intensity, mcd) : Red (450 – 1800), Green (710 – 1800), Blue (280 – 710)
· 가시각 : 120 degree

풀칼라 표현이 가능한 RGB 고휘도 LED모듈로 Sense HAT에는 8행 8열, 즉 64개가 실장되어 있습니다. 매우 밝고 반응속도도 빠르며 픽셀마다 RGB 독립 혹은 혼합색 표현이 가능하므로 각종 정보 표출이나 게임 등에 재미난 활용가치가 있을 것으로 봅니다.
다만 ATtiny88에 의해 다이나믹 제어를 하고 있으므로 전체적인 리프레시 타임은 한계가 있습니다.
보다 효과적인 LED 통제를 위해 LED2472G 8채널 FULL COLOR LED 드라이버를 사용하고 있으며 컬럼 라인은 래치를 사용하여 MCU가 직접 제어를 하는 방식으로 설계되어 있습니다.

1.5. 5버튼 조이스틱

38 sr 금강초롱 (6)
● 모델명 : SKRHABE010
● 칩벤더 : ALPS사
● 주요 기능 : 4방향키 + center push 스위치
● 스위치 내부구조

2. Hello World에 도전하기

2.1. 기본환경

38 sr 금강초롱 (7)

우선 실험을 진행하기 위해서는 라즈베리파이3와 Sense HAT을 결합하고 여기에 라즈비안(운영체제)까지 깔려있는 상태여야 합니다.
라즈베리파이3를 사용한다면 와이파이모듈이 기본적으로 내장되어 있으므로 외부에서 간단히 접속할 수 있습니다.
와이파이 동글을 끼우지 않아도 되고 RJ45 잭을 꽂지 않아도 이더넷 환경이 만들어 진다는 것은 대단한 강점이라고 볼 수 있겠습니다.
여기까지의 상황에 대한 준비는 전월호(36호)의 ‘라즈베리파이를 활용한 인터넷 라디오 & 게임머신 작업기’편에서 다뤘으므로 참고하시기 바랍니다.
※ 필자의 블로그 참조 :
http://blog.naver.com/crucian2k3/220788282079

자, Tera Term을 띄워 라즈베리파이에 접속해 들어갑니다.

38 sr 금강초롱 (8)

SSH가 지원이 되는 터미널프로그램이라면 어떤 것이든 상관없습니다.
· 접속 아이디와 비밀번호 : pi / raspberry

이렇게 접속한 후 보여지는 첫 화면은 아래와 같습니다.

38 sr 금강초롱 (34)

2.2. Sense HAT API 설치
우선 라즈베리파이에 API(이하 라이브러리)가 설치되어 있어야 합니다.
공식 설치소개 페이지는 아래 주소를 참고 합니다.
https://www.raspberrypi.org/documentation/hardware/sense-hat/

$ sudo apt-get update
$ sudo apt-get install sense-hat
$ sudo reboot

이 라이브러리가 설치되면 자이로스코프, 가속도계, 지자기센서, 온도센서, 습도센서, 기압센서, 조이스틱 등을 자유롭게 접근할 수 있습니다.

이렇게 라이브러리를 설치한 후에 시험 삼아 Hello.py를 작성해 봅니다.
작성된 파일에 chmod 755 hello.py를 하여 실행파일로 만들어 줍니다.
파이썬으로 만들어진 파일을 실행을 시킬 때는 ./hello.py를 칩니다.

pi@raspberrypi:~/examples/crucian2k3 $ cat hello.py
#!/usr/bin/python

from sense_hat import SenseHat
sense = SenseHat()
sense.show_message(“Hello world!”)

pi@raspberrypi:~/examples/crucian2k3 $ chmod 755 hello.py
pi@raspberrypi:~/examples/crucian2k3 $ ls -al
total 12
drwxr-xr-x 2 pi pi 4096 Aug 31 22:27 .
drwxr-xr-x 6 pi pi 4096 Aug 31 22:22 ..
-rwxr-xr-x 1 pi pi 105 Aug 31 22:27 hello.py
pi@raspberrypi:~/examples/crucian2k3 $

동작하고 있는 장면은 아래와 같습니다.
‘Hello World’가 우에서 좌로 살짝 빠르게 스크롤 됩니다.
이처럼 스크롤이 일어나는 것은 Sense HAT 내부에 ATtiny88이 올려져 있기 때문입니다. 라즈베리파이 SOC는 ‘뿌려져라’라는 명령을 I2C 채널을 통해 ATtiny88로 보내고, MCU에서는 후처리를 알아서 담당하는 방식입니다. 일종의 역할분담입니다.

38 sr 금강초롱 (9)
아래는 Tera Term에서 명령을 내리는 모든 과정을 캡처한 것입니다.
여기서

$ ls -al hello.py는 hello.py가 실행이 가능한 상태인 755 퍼미션이 들어가 있는지 보는 것입니다.

$ cat hello.py는 hello.py에 무슨 내용이 담겨져 있는지 리스팅 해보는 것입니다.

$ ./hello.py는 리눅스 등 유닉스 기반의 OS에서는 실행할 때 실행파일명과 경로를 반드시 명기해야 하며 ./는 현재 경로를 의미 합니다.

38 sr 금강초롱 (10)

여기까지는 잘 따라 오셨나요?
일단 Hello Word에 성공하였다면 Sense HAT을 갖고 놀고, 즐길 수 있는 만반의 준비가 끝났다고 볼 수 있습니다.
사실 이러한 제품을 구상하고 만드는 사람이 어렵지 쓰는 사람은 그저 그 분들의 노고에 감사해하며 잘 써주면 그만일 듯합니다.

3. Sense HAT 학습을 위한 재단의 배려

이제부터 Sense HAT을 학습에 어떻게 이용할 수 있는지를 살펴보도록 하겠습니다.
라즈베리파이 재단에서는 가르치는 선생님을 위한 페이지, 공부하고자 하는 학생을 위한 페이지, 그리고 활용할 수 있는 실습코너 등을 준비해 놓고 있습니다.
정말 어지간한 정성이 아니고선 보기 힘든 싸이트라고 생각 됩니다.
필자는 모든 코너를 따라가며 실행해 보았습니다.
정말 감탄이 절로 나올 정도로 잘 만들어져 있음을 알 수 있었습니다.
이 글을 읽는 독자님들도 한번쯤 방문해 보실 것을 강력히 권합니다.
우측 상단에 ‘Help / Teach / Learn / Make’ 가 메인 링크입니다.

38 sr 금강초롱 (11)
https://www.raspberrypi.org/learning/getting-started-with-the-sense-hat/
재단에서 신경 써서 만들어 놓은 것 중에 시뮬레이터라는 것도 있습니다.
라즈베리파이보드와 Sense HAT을 갖고 있지 않더라도 간단한 실험을 여기에서 해볼 수 있습니다. 크롬웹브라우져에서는 별 탈 없이 구동되나 인터넷익스플로러 상에서는 약간의 문제가 있어 보입니다. 아래는 Rainbow.py를 구동시켜본 장면입니다.

38 sr 금강초롱 (12)

4. Sense HAT 활용을 위한 API 접근

Sense HAT으로 뭔가를 해보고자 한다면 라즈베리파이 재단에서 공개한 API에 대해 학습해 보는 것이 순서일 듯합니다.
API는 일종의 라이브러리라고 이해해도 무방하며 이 역시 파이썬으로 제작이 되어 있습니다. 아래 주소에서 최신판에 대한 확인이 가능합니다.

https://github.com/RPi-Distro/python-sense-hat

이 API는 Sense HAT이 가지고 있는 모든 종류의 센서를 비롯하여 조이스틱까지를 핸들링 할 수 있도록 파이선 기반으로 작성되어 있으며, 파이선 자체가 워낙 가독성이 좋으므로 언어를 잘 몰라도 어떻게 동작이 되는지를 짐작해 보는데 큰 무리는 없다고 봅니다.
프로그램은 sense_hat.py에 본격적으로 기술되어 있습니다.
이장에서 언급하는 API는 아래 주소를 참조 하였습니다.

https://pythonhosted.org/sense-hat/api/

4.1. LED 매트릭스 핸들링과 관련된 API(라이브러리)
LED 매트릭스는 RGB 색상을 가지는 LED가 8*8로 배열되어 있으며 ATtiny88 AVR에 의해 제어됩니다. 포드절약을 위해 다이나믹 디스플레이 방식을 사용함에 따라 한번에 8개의 LED가 점등한 후 나머지는 소등하는 방식으로 바르게 반복하여 원하는 글자나 문양을 표현해 낼 수 있습니다.
만일 라즈베리파이 메인 SOC에게 이 일을 시키면, LED 매트릭스에 글자 표시하느라 다른 일을 제대로 할 수 없을 것입니다.

4.1.1. set_rotation
● 기능 : 라즈베리파이를 거꾸로 사용하거나 옆으로 사용하여야 하는 상황에서 이미지의 방향을 회전시킬 수 있는 기능을 제공합니다.
이 함수는 인자를 2개 갖습니다. 첫 번째 인자는 회전하는 각도를 담고 두 번째 인자는 갱신시킬 것인지를 결정하며, 만일 두 번째 인자를 생략하면 작동으로 True가 입력되어 갱신이 일어납니다. 이러한 기능은 아래 함수에서 똑같이 적용됩니다.

38 sr 금강초롱 (3)

● 예제 코드

#!/usr/bin/python

from sense_hat import SenseHat
sense = SenseHat()
sense.set_rotation(180)
# 다른 방법으로 이렇게 할 수도 있음
sense.rotation = 180

4.1.2. flip_h
● 기능 : LED 매트릭스에 표출된 이미지를 수평방향으로 반전시킵니다.
반전된 RGB 값이 들어 있는 목록정보가 리턴됩니다.
파라메터에 값을 넣지 않으면 True가 자동으로 입력되어 리프레시가 일어납니다.

38 sr 금강초롱 (7)

 

#!/usr/bin/python
from sense_hat import SenseHat

sense = SenseHat()
sense.flip_h()

4.1.3. flip_v
● 기능 : LED 매트릭스에 표출된 이미지를 수직방향으로 반전시킵니다.
반전된 RGB 값이 들어 있는 목록정보가 리턴됩니다.
파라메터에 값을 넣지 않으면 True가 자동으로 입력되어 리프레시가 일어납니다.

38 sr 금강초롱 (4)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
sense.flip_v()

4.1.4. set_pixels
● 기능 : 화소값의 64바이트 길이를 갖는 리스트에 기반하여 LED매트릭스 행렬을 업데이트 합니다. 이 함수는 리턴값이 없습니다.

38 sr 금강초롱 (8)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()

X = [255, 0, 0] # Red
O = [255, 255, 255] # White

question_mark = [
O, O, O, X, X, O, O, O,
O, O, X, O, O, X, O, O,
O, O, O, O, O, X, O, O,
O, O, O, O, X, O, O, O,
O, O, O, X, O, O, O, O,
O, O, O, X, O, O, O, O,
O, O, O, O, O, O, O, O,
O, O, O, X, O, O, O, O
]

sense.set_pixels(question_mark)

4.1.5. get_pixels
64바이트의 RGB정보가 포함된 목록이 리턴됩니다.
픽셀리스트에 담겨진 정보가 RGB565 포맷 즉 R:5, G:6, B:5로 됨에 따라 컬러비트 손실이 발생됨에 유의해야 합니다.

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
pixel_list = sense.get_pixels()

4.1.6. set_pixel
● 기능 : x, y로 지정된 픽셀의 색좌표를 설정 할 수 있습니다.

38 sr 금강초롱 (9)

from sense_hat import SenseHat

sense = SenseHat()

# examples using (x, y, r, g, b) //각각의 좌표와 r,g,b를 넣는 방법
sense.set_pixel(0, 0, 255, 0, 0)
sense.set_pixel(0, 7, 0, 255, 0)
sense.set_pixel(7, 0, 0, 0, 255)
sense.set_pixel(7, 7, 255, 0, 255)

red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)

# examples using (x, y, pixel) // 튜플로 엮어서 한방에 넣는 방법이 있음
sense.set_pixel(0, 0, red)
sense.set_pixel(0, 0, green)
sense.set_pixel(0, 0, blue)

4.1.7. get_pixel
● 기능 : 지정된 좌표의 픽셀의 r,g,b 값을 반환합니다.

38 sr 금강초롱 (10)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
top_left_pixel = sense.get_pixel(0, 0)

4.1.8. load_image
● 기능 : 8*8로 구성된 rgb 이미지를 LED 매트릭스에 표시합니다.
rgb로 변환되어 표출된 픽셀값을 반환합니다.

38 sr 금강초롱 (11)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
invader_pixels = sense.load_image(“space_invader.png”, redraw=False)

4.1.9. clear
● 기능 : LED 매트릭스를 단일 색상으로 정리합니다. 기본적으로는 블랭크(아무것도 없는 상태, off)로 만들어 줍니다.

38 sr 금강초롱 (12)

#!/usr/bin/python

from sense_hat import SenseHat
from time import sleep

sense = SenseHat()

red = (255, 0, 0)

sense.clear() # no arguments defaults to off
sleep(1)
sense.clear(red) # passing in an RGB tuple
sleep(1)
sense.clear(255, 255, 255) # passing in r, g and b values of a colour

4.1.10. show_message
● 기능 : 오른쪽에서 왼쪽으로 스크롤되는 텍스트 메시지를 보여줍니다. 배경화면의 색상을 지정해줄 수 있습니다.

38 sr 금강초롱 (13)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
sense.show_message(“One small step for Pi!”, text_colour=[255, 0, 0])

4.1.11. show_letter
● 기능 : LED 매트릭스에 하나의 문자를 표출합니다.

38 sr 금강초롱 (14)

#!/usr/bin/python

import time
from sense_hat import SenseHat

sense = SenseHat()

for i in reversed(range(0,10)):
sense.show_letter(str(i))
time.sleep(1)

4.1.12. low_light
● 기능 : Sense HAT을 어두운 환경에서 사용 시 조도를 낮춰서 사용할 수 있도록 해줍니다.

#!/usr/bin/python

import time
from sense_hat import SenseHat

sense = SenseHat()
sense.clear(255, 255, 255)
sense.low_light = True
time.sleep(2)
sense.low_light = False

4.1.13. gamma
● 기능 : 고급사용자를 위한 기능입니다. 일반 유저는 위의 low_light 정도만 사용해도 문제가 없습니다.
Sense HAT 파이선API는 리눅스프레임 버퍼로 데이터가 넘어갈 때 565포맷으로 변환을 시키며 이 값이 LED 매트릭스 제어용 MCU인 AtTiny88 AVR로 전달됩니다.
감마테이블이 이 값이 변환되는 과정에 관여하는 것으로서 0~31사이의 값으로 정의되어 있습니다.

38 sr 금강초롱 (15)

#!/usr/bin/python

import time
from sense_hat import SenseHat

sense = SenseHat()
sense.clear(255, 127, 0)

print(sense.gamma) # 현재의 감마 값
time.sleep(2)

sense.gamma = reversed(sense.gamma) # 감마 값을 반전 시켜 봄
print(sense.gamma)
time.sleep(2)

sense.low_light = True # low_light 함수를 적용해봄
print(sense.gamma) # 이때 감마값이 어떻게 변화하는지를 관찰
time.sleep(2)

sense.low_light = False

4.1.14. gamma_reset
● 기능 : 감마 룩업테이블을 원위치 시켜줍니다.

#!/usr/bin/python

import time
from sense_hat import SenseHat

sense = SenseHat()
sense.clear(255, 127, 0)
time.sleep(2)
sense.gamma = [0] * 32 # Will turn the LED matrix off
time.sleep(2)
sense.gamma_reset()

4.2. 환경센서(습도, 온도, 기압)용 API(라이브러리)
Sense HAT에는 별로 흔치 않은 기압센서가 장착되어져 있습니다.
이 센서를 활용하여 날씨, 고도 등 재미난 어플리케이션을 만들어 볼 수 있을 듯 합니다.
또한 온습도센서는 매우 컴팩트하여 과연 잘 동작 될 수 있을까 의문이 들기도 하지만 라즈베리파이를 활용하여 온실이나 실내 환경제어에도 응용해 볼 수 있는 방법을 제시해 주는데 부족함이 없으리라 봅니다.

4.2.1. get_humidity
● 기능 : 습도 센서에서 상대 습도의 비율을 가져옵니다.

38 sr 금강초롱 (16)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
humidity = sense.get_humidity()
print(“Humidity: %s %%rH” % humidity)

# alternatives
print(sense.humidity)

4.2.2. get_temperature
● 기능 : 습도센서에서 섭씨의 현재 온도 값을 얻어 옵니다.
내부적으로 get_temperature_from_humidity() 함수를 호출함

38 sr 금강초롱 (17)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
temp = sense.get_temperature()
print(“Temperature: %s C” % temp)

# alternatives
print(sense.temp)
print(sense.temperature)

4.2.3. get_temperature_from_humidity
● 기능 : 습도센서에서 섭씨의 현재 온도 값을 얻어옵니다.

38 sr 금강초롱 (18)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
temp = sense.get_temperature_from_humidity()
print(“Temperature: %s C” % temp)

4.2.4. get_Temperature_from_pressure
● 기능 : 압력 센서에서 섭씨의 현재 온도를 가져옵니다.

38 sr 금강초롱 (19)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
temp = sense.get_temperature_from_pressure()
print(“Temperature: %s C” % temp)

4.2.5. get_pressure
● 기능 : 압력 센서에서 밀리바의 현재 압력을 가져옵니다.

38 sr 금강초롱 (20)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
pressure = sense.get_pressure()
print(“Pressure: %s Millibars” % pressure)

# alternatives
print(sense.pressure)

4.3. IMU Sensor API(라이브러리)
IMU(관성측정유닛) 센서는 X, Y, Z축을 측정할 수 있는 3종의 센서로 되어 있습니다. 이렇게 3종의 센서를 사용하여 9축의 모션센싱 기능을 수행할 수 있습니다.

· 자이로스코프
· 가속도계
· 지자기센서(나침반)

4.3.1. set_imu_config
● 기능 : 자이로스코프, 가속도계, 지자기센서를 활성화시킬지 비활성화시킬지를 설정합니다.

38 sr 금강초롱 (21)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
sense.set_imu_config(False, True, False) # gyroscope only

4.3.2. get_orientation_radians
● 기능 : 피치, 롤, 요축의 정보로부터 라디안을 얻어옵니다.

38 sr 금강초롱 (23)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
orientation_rad = sense.get_orientation_radians()
print(“p: {pitch}, r: {roll}, y: {yaw}”.format(**orientation_rad))

# alternatives
print(sense.orientation_radians)

4.3.3. get_orientation_degrees
● 기능 : 피치, 롤, 요축의 정보로부터 각도를 얻어옵니다.

38 sr 금강초롱 (24)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
orientation = sense.get_orientation_degrees()
print(“p: {pitch}, r: {roll}, y: {yaw}”.format(**orientation))

4.3.4. get_orientation
● 기능 : get_orientation_degrees()와 동일한 기능을 수행합니다.

38 sr 금강초롱 (23)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
orientation = sense.get_orientation()
print(“p: {pitch}, r: {roll}, y: {yaw}”.format(**orientation))

# alternatives
print(sense.orientation)

4.3.5. get_compass
● 기능 : 자이로스코프와 가속도계가 set_imu_config에서 disable 되면 지자기센서로부터 북쪽방위 정보를 얻어올 수 있습니다.

38 sr 금강초롱 (25)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
north = sense.get_compass()
print(“North: %s” % north)

# alternatives
print(sense.compass)

4.3.6. get_compass_raw
● 기능 : 원시 x, y, z축 자력계 데이를 출력합니다.

38 sr 금강초롱 (26)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
raw = sense.get_compass_raw()
print(“x: {x}, y: {y}, z: {z}”.format(**raw))

# alternatives
print(sense.compass_raw)

4.3.7. get_gyroscope
● 기능 : set_imu_config에서 지자기센서, 가속도 센서를 사용하지 않도록 하면 자이로스코프 센서를 사용하여 현재 방향정보를 가져올 수 있습니다.

38 sr 금강초롱 (27)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
gyro_only = sense.get_gyroscope()
print(“p: {pitch}, r: {roll}, y: {yaw}”.format(**gyro_only))

# alternatives
print(sense.gyro)
print(sense.gyroscope)

4.3.8. get_gyroscope_raw
● 기능 : 원시 x, y, z축 자이로스코프 데이터를 가져옵니다.

38 sr 금강초롱 (28)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
raw = sense.get_gyroscope_raw()
print(“x: {x}, y: {y}, z: {z}”.format(**raw))

# alternatives
print(sense.gyro_raw)
print(sense.gyroscope_raw)

4.3.9. get_accelerometer
● 기능 : set_imu_config에서 지자기센서, 자이로스코프를 사용하지 않도록 하면 가속도계만으로 현재 방향 정보를 얻어올 수 있습니다.

38 sr 금강초롱 (29)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
accel_only = sense.get_accelerometer()
print(“p: {pitch}, r: {roll}, y: {yaw}”.format(**accel_only))

# alternatives
print(sense.accel)
print(sense.accelerometer))

4.3.10. get accelerometer_raw
● 기능 : x, y, z축의 가속도계 원시데이터를 가져옵니다.

38 sr 금강초롱 (31)

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
raw = sense.get_accelerometer_raw()
print(“x: {x}, y: {y}, z: {z}”.format(**raw))

# alternatives
print(sense.accel_raw)
print(sense.accelerometer_raw)

4.4. 조이스틱관련 API(라이브러리)
조이스틱은 손잡이도 없이 좀 빈약하게 붙어 있습니다.
조이스틱과 관련된 라이브러리는 stick.py에 파이썬으로 짜여져 있습니다.

4.4.1. InputEvent
조이스틱의 이벤트는 튜플로 반환되며 아래와 같은 3가지 형태가 있습니다.
· timestamp : 이벤트가 발생한 시간으로, “초”
· direction : 조이스틱이 이동한 방향으로, 문자열로 구성, “up, “down”, left”, right”, “push” 등
· action : 발생한 상황에 대한 문자열 “pressed”, “released”, “held”

4.4.2. wait_for_event
● 기능 : 조이스틱 이벤트가 발생할 때까지 대기합니다.

#!/usr/bin/python

from sense_hat import SenseHat
from time import sleep

sense = SenseHat()
event = sense.stick.wait_for_event()
print(“The joystick was {} {}”.format(event.action, event.direction))
sleep(0.1)
event = sense.stick.wait_for_event()
print(“The joystick was {} {}”.format(event.action, event.direction))

조이스틱을 한쪽 방향으로 전환시켜 제대로 동작되는 지를 확인코자 하는 경우의 예제

#!/usr/bin/python

from sense_hat import SenseHat
from time import sleep

sense = SenseHat()
event = sense.stick.wait_for_event()
print(“The joystick was {} {}”.format(event.action, event.direction))
sleep(0.1)
event = sense.stick.wait_for_event(emptybuffer=True)
print(“The joystick was {} {}”.format(event.action, event.direction))

4.4.3. get_events
● 기능 : 이벤트의 목록을 튜플로 출력합니다.

#!/usr/bin/python

from sense_hat import SenseHat

sense = SenseHat()
while True:
for event in sense.stick.get_events():
print(“The joystick was {} {}”.format(event.action, event.direction))

4.4.4. direction_up, direction_left, direction_right, direction_down, direction_middle, direction_any
● 기능 : 조이스틱을 움직인 방향을 추적하는 이벤트로 활용됩니다.

#!/usr/bin/python

from sense_hat import SenseHat, ACTION_PRESSED, ACTION_HELD, ACTION_RELEASED
from signal import pause

x = 3
y = 3
sense = SenseHat()

def clamp(value, min_value=0, max_value=7):
return min(max_value, max(min_value, value))

def pushed_up(event):
global y
if event.action != ACTION_RELEASED:
y = clamp(y – 1)

def pushed_down(event):
global y
if event.action != ACTION_RELEASED:
y = clamp(y + 1)

def pushed_left(event):
global x
if event.action != ACTION_RELEASED:
x = clamp(x – 1)

def pushed_right(event):
global x
if event.action != ACTION_RELEASED:
x = clamp(x + 1)

def refresh():
sense.clear()
sense.set_pixel(x, y, 255, 255, 255)

sense.stick.direction_up = pushed_up
sense.stick.direction_down = pushed_down
sense.stick.direction_left = pushed_left
sense.stick.direction_right = pushed_right
sense.stick.direction_any = refresh
refresh()
pause()

여기까지 라즈베리파이 재단에서 발표한 API를 살펴 봤습니다.
필자가 느끼는 소감은 한마디로 ‘지극정성’이 들어가 있는 프로젝트란 생각이 들 정도입니다. 맛보기가 아니라 이 제품을 활용하여 무엇인가를 실제로 만들어 볼 수 있도록 준비를 다 해 놨습니다.
한걸음 더 나아가 배우고자 하는 사람을 위한 페이지, 가르치고자 하는 페이지를 만들어 줄 정도니 그 정성 대단하다 아니할 수 없을듯합니다.

5. API를 활용한 실제 실험 결과

5.1 실험환경 준비
위의 2.2에서 API를 설치하고 나면 다음과 같은 프로그램이 쭉~ 설치가 되어 있습니다. 우선 제대로 된 테스트를 하기위해 몇 가지 사전 준비를 합니다.
인스톨이 끝나고 나면 아래 주소에 파일이 들어가 있습니다.
/usr/src/sense-hat/examples

이 파일 들을 pi의 홈디렉토리로 복사합니다.
cp /usr/src/sense-hat/examples ~/ -a

여기에 소개되어 있는 프로그램들은 C, C++로 짜여져 있으며 각 디렉토리에서 컴파일을 하여야 실행을 해볼 수 있습니다.
컴파일은 간단하여 해당 디렉토리에서 make를 하는 것만으로 간단히 끝납니다.
API간 전체적인 구성은 아래와 같습니다.

38 sr 금강초롱 (32)

5.2. 파이선으로 작성된 기본예제 실험
우선 디렉토리를 python-sense-hat으로 이동합니다.

38 sr 금강초롱 (13)

컬러 패턴을 보내는 예제와 스네이크바이트의 라즈베리파이향 게임을 하는 장면입니다. 스네이크바이트는 전설과도 같은 게임이라고 생각합니다.

38 sr 금강초롱 (14)

다음으로 무지개와 흐르는 문자를 표시해 봤습니다.

화면에 표출되는 영상이 다이나믹디스플레이 방식이므로 사진에 잘 찍히지 않을 수도 있습니다만 육안으로 보는데는 별 지장이 없습니다.

38 sr 금강초롱 (15)

실행을 할 때는 아래와 같이 경로가 명확히 지정되어져야 합니다.

38 sr 금강초롱 (16)

첫 번째 실험으로 사용한 color_cycle.py는 다음과 같이 짜여져 있음을 알 수 있습니다.

pi@raspberrypi:~/examples/python-sense-hat $ cat colour_cycle.py

#!/usr/bin/python
import time
from sense_hat import SenseHat // SenseHat API를 로드한다.
sense = SenseHat()
r = 255
g = 0
b = 0
msleep = lambda x: time.sleep(x / 1000.0)
def next_colour(): // next_colour 라는 함수를 선언한다.
global r
global g
global b
if (r == 255 and g < 255 and b == 0):
g += 1
if (g == 255 and r > 0 and b == 0):
r -= 1
if (g == 255 and b < 255 and r == 0):
b += 1
if (b == 255 and g > 0 and r == 0):
g -= 1
if (b == 255 and r < 255 and g == 0):
r += 1
if (r == 255 and b > 0 and g == 0):
b -= 1
while True: // 실제 실행이 일어나는 부분이다.
sense.clear([r, g, b])
msleep(2)
next_colour() // 위에서 작성한 함수를 호출한다.

pi@raspberrypi:~/examples/python-sense-hat $

5.3. IMU 실험
RTIMULib 디렉토리에서 9축 모션센서의 동작 상태를 실험해 볼 수 있습니다. 파이썬 프로그램은 당연히 라이브러리는 위에서 언급한 것으로 짜여져 있습니다.

38 sr 금강초롱 (18)

다음으로는 C++언어 기반으로 짜여진 예제입니다.
pi@raspberrypi:~/examples/RTIMULib/RTIMULibDrive로 이동한 후
make를 하면 실행파일인 RTIMULibDrive를 얻을 수 있습니다.

38 sr 금강초롱 (19)

실행하는 방법은 파이썬과 동일 합니다.
pi@raspberrypi:~/examples/RTIMULib/RTIMULibDrive $ ./RTIMULibDrive라고 치면 됩니다.
화면 하단부에 Sample rate, roll, pitch, yaw의 값이 보입니다.

38 sr 금강초롱 (20)

라즈베리파이를 움직이면 이에 추종하여 롤, 피치, 요 값이 변하는 것을 확인할 수 있습니다. 이 정보를 균형로봇이나 쿼드콥터 등에 응용해 볼 수 있을 것 같습니다.

위 실험의 소스코드는 라이브러리를 이용하는 방식으로 비교적 간단합니다.

pi@raspberrypi:~/examples/RTIMULib/RTIMULibDrive $ cat RTIMULibDrive.cpp

////////////////////////////////////////////////////////////////////////////
//
// This file is part of RTIMULib
//
// Copyright (c) 2014-2015, richards-tech, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the “Software”), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include “RTIMULib.h”

int main()
{
int sampleCount = 0;
int sampleRate = 0;
uint64_t rateTimer;
uint64_t displayTimer;
uint64_t now;

// Using RTIMULib here allows it to use the .ini file generated by RTIMULibDemo.
// Or, you can create the .ini in some other directory by using:
// RTIMUSettings *settings = new RTIMUSettings(“<directory path>”, “RTIMULib”);
// where <directory path> is the path to where the .ini file is to be loaded/saved

RTIMUSettings *settings = new RTIMUSettings(“RTIMULib”);

RTIMU *imu = RTIMU::createIMU(settings);

if ((imu == NULL) || (imu->IMUType() == RTIMU_TYPE_NULL)) {
printf(“No IMU found\n”);
exit(1);
}

// This is an opportunity to manually override any settings before the call IMUInit
// set up IMU

imu->IMUInit();

// this is a convenient place to change fusion parameters

imu->setSlerpPower(0.02);
imu->setGyroEnable(true);
imu->setAccelEnable(true);
imu->setCompassEnable(true);

// set up for rate timer

rateTimer = displayTimer = RTMath::currentUSecsSinceEpoch();

// now just process data

while (1) {
// poll at the rate recommended by the IMU

usleep(imu->IMUGetPollInterval() * 1000);

while (imu->IMURead()) {
RTIMU_DATA imuData = imu->getIMUData();
sampleCount++;

now = RTMath::currentUSecsSinceEpoch();

// display 10 times per second

if ((now – displayTimer) > 100000) {
printf(“Sample rate %d: %s\r”, sampleRate, RTMath::displayDegrees(“”, imuData.fusionPose));
fflush(stdout);
displayTimer = now;
}

// update rate every second

if ((now – rateTimer) > 1000000) {
sampleRate = sampleCount;
sampleCount = 0;
rateTimer = now;
}
}
}
}

pi@raspberrypi:~/examples/RTIMULib/RTIMULibDrive $

6. 마무리

Sense HAT은 라즈베리파이재단에서 Astro Pi Mission의 일부로 제작되어 실제 우주정거장에 보내진 제품입니다. 아래 사진 속 QR코드로 확인 가능합니다.

Cap 2016-12-08 11-17-15-048

그래서 그런지도 모르겠습니다만 매우 정성이 들어간 설명이 존재하고, 예제프로그램과 API 역시 섬세하게 만들어졌음을 알 수 있었습니다.
학교 등 교육기관에서 컴퓨터 프로그래밍과 센서가 융복합된 과제와 학습을 진행하는데 더할 나위 없이 좋은 제품이 아닐까하는 생각이 듭니다.
위에서도 언급을 한 바가 있습니다만, Sense HAT을 가르치는 자를 위한 별도의 페이지와 Sense HAT을 배우고자하는 이를 위한 페이지 그리고 Sense HAT을 활용하여 창의적인 무엇인가를 해보는 프로젝트를 위한 페이지로 구성된 것 자체가 필자에게는 적잖은 신선함으로 다가왔습니다.
마치 모범답안을 보는 그런 느낌마저 들었습니다.
더군다나 라즈베리파이보드와 Sense HAT이 없이도 학습을 해 볼 수 있는 시뮬레이션 웹싸이트까지 준비해 놓고 있으므로, 이 정도면 제대로 준비해두었다 아니할 수 없을 듯합니다.
이번 리뷰를 진행하는 기간 동안 극강(?)의 회사업무와 숨이 막히는 폭염이 겹쳐서 살짝 고전은 하였습니다만, 이런 훌륭한 제품을 접할 기회가 있었다는 점 하나만으로도 충분히 보람있는 시간이 아니었나 생각됩니다.
다음 편에서는 라즈베리파이와 아두이노의 한계를 뛰어넘는 강력한 컴퓨팅파워를 자랑하는 ‘LattePanda’ 최신형보드에 대해 집중적으로 살펴보려 합니다.
감사합니다.

7. 참고자료
1. 라즈베리파이 가이드
https://www.raspberrypi.org/learning/astro-pi-guide/
2. API레퍼런스
http://pythonhosted.org/sense-hat/api/
3. 파이선에서 지원하는 센스헷 설치 페이지
https://pythonhosted.org/sense-hat/
4. 센스햇 예제
https://github.com/RPi-Distro/python-sense-hat/blob/master/examples/README.md
5. 아스트로파이 페이지의 예제프로그램
https://astro-pi.org/get-involved/program-the-sense-hat/python/
6. 원디하나님 블로그
http://windy.luru.net/1863
7. 우주정거장 실험 관련 영상물
https://astro-pi.org/updates/coding-challenges-update/
8. Sense HAT 시뮬레이터 주소
https://www.raspberrypi.org/learning/getting-started-with-the-sense-hat/worksheet/

 

38 sr 금강초롱 (33)

[38호]카멜레온 DIY LED 이야기 ④

38 PTB (33)

38 PTB (39)

 

카멜레온 DIY LED 이야기 4

LED ART 1 : I ♥ U와 변색 카멜레온

 

글 | 신상석 ssshin@jcnet.co.kr

디바이스마트 매거진 독자 여러분, 안녕하세요. 앞으로 5회에 걸쳐 [카멜레온 DIY LED 이야기]를 진행할 신상석입니다.
이 이야기는 WS2812B라는 컬러 LED를 기반으로 제작된 [카멜레온 DIY LED] 시리즈를 이용하여 생활에 필요한 다양한 형상을 꾸며보고 이것을 다양한 컬러로 디스플레이 해보는 내용입니다. 앞으로 진행할 내용에 대하여 간단히 알아보면 다음과 같습니다. (약간 변경될 수도 있습니다.)
앞으로 즐겁고 유익한 강의가 될 수 있도록 많은 격려와 성원 부탁드립니다.

 

디바이스마트매거진 독자 여러분, 안녕하세요. 반갑습니다.
[카멜레온 DIY LED 이야기] 네번째 시간입니다.
아, 참, 그리고 앞으로는 [카멜레온 DIY LED] 대신 줄인 말로 [카DL]을 주로 사용할까 합니다. 아무래도 3글자가 편하겠죠?
그러면, 기본 준비물부터 챙겨 보도록 하지요. GO~

직선(BAR) 모듈과 곡선(ARC) 모듈

카DL의 기본 구성품은 그리 많지는 않지만, 직선과 곡선, 방향자, 기본 도형을 가지고 있어서 똑같지는 않지만 비슷한 정도로는 어떤 형상이든 모두 구현이 가능합니다. 왜냐하면 임의의 형상은 이것을 이루는 직선과 곡선의 조합으로 표현이 가능하기 때문입니다. 물론, 정밀도에서는 조금 차이가 날 것이므로 완전 똑같게는 안되겠지만 잘만 만들면 상당히 비슷하게 됩니다.
카DL은 직선(BAR) 형태로 다음의 6가지 모듈을 제공합니다. 실제로 JLED-BAR-1만으로도 구성은 가능하겠지만 이렇게 되면 너무나 많은 연결이 필요하므로 길이가 다른 6가지 모듈을 제공하여 사용의 편의성을 제공하고 있습니다. 이 6가지 모듈은 길이가 각각 1, 2, 3, 4, 5, 10cm 로 설계되어 있어 연결된 형상의 크기를 매우 쉽게 예측할 수 있는 것도 장점입니다. 급할 때는 자 대용으로도 사용이 가능하지요.

38 PTB (1)

기본 직선(BAR) 모듈에 대응하여 카DL이 제공하는 기본 곡선(ARC) 모듈은 다음의 12가지 모듈입니다. 곡선의 경우는 원의 일부인 원호에 해당되는 부분을 제공하는데 모든 원호에 대하여 제공할 수는 없으므로 대표적인 3가지 다른 곡률을 가진 원을 정하여 제공합니다. 개수는 3개가 연속된 것과 4개가 연속된 것의 2종류를 제공하고, 방향성에 따라 UP, DOWN의 2종류로 나누어 제공하므로, 총 3 x 2 x 2 = 12 가지가 기본 모듈이 됩니다. (방향은 왼쪽이 IN, 오른쪽이 OUT입니다.)

38 PTB (2)
모듈의 이름은 이 원호 모듈을 이용하여 원을 만들 경우, 사용되는 총 LED의 개수와 모듈이 포함한 원의 개수, 그리고 방향을 포함하여 만들어집니다. JLED-ARC12-D3 모듈을 예로 들면, 이 모듈은 LED 3개로 이루어진 DOWN(D) 방향의 LED로, LED가 총12개(이 모듈 4개)가 모이면 아래와 같이 원(지름 약 40mm 정도)이 되는 모듈입니다.

38 PTB (3)
여러 개의 서로 다른 원호 모듈을 이용하면 부드러운 곡선을 표현할 수 있는데, 예를 들어 아래와 같은 지렁이 형상을 만들 수 있습니다.

38 PTB (4)
오, 그러면 직선(BAR) 모듈과 곡선(ARC) 모듈을 함께 섞어서 사용한다면 여러가지 임의의 형상을 만들 수도 있겠네요. 예. 맞습니다. 동물도 만들 수 있고, 글자도 만들 수 있고, 메뚜기도 만들 수 있고, 조금은 어렵겠지만 뽀로로도 만들 수 있겠습니다. 아래는 몇가지 예입니다.

38 PTB (5)
너무 오래 설명만 하면 재미가 없으니까 다른 모듈이 더 필요해지면 그 때 가서 또 설명하기로 하고, 우리의 1단계 목표인 [I ♥ U] 제작에 들어가 봅시다.

I ♥ U

1단계 : 형상 설계하기
제작을 하기 위하여 가장 먼저 해야 할 일은 규격을 정하는 것입니다. 아래와 같은 사항을 정해 놓고 시작하는 것이 좋겠습니다.
첫번째로 결정해야 할 것은 형상입니다. 무엇을 만들지, 어떤 형상으로 만들지를 정해야 합니다. 우리는 이미 정했죠! [I ♥ U] 형태로 가로로 길게 만드는 것으로 하겠습니다.

두번째로 결정해야 할 것은 용도입니다. 어떤 용도로 어느 장소에 설치할 것인가? 소품 형태로 어떤 곳에 놓아도 되는 형태로 만들 것인지, 벽이나 유리창에 간판처럼 붙여놓을 것인지 등이지요. 일단 우리는 휴대용 소품으로 들고 다닐 수 있는 투명 아크릴 박스 형태로 꾸며보기로 하지요. 아크릴 박스 형태는 온라인 아크릴 전문점에서 다양한 크기의 박스 형태를 구입할 수 있습니다.

세번째는 크기가 되겠습니다. 용도에 알맞게 하기 위하여 크기를 결정하기도 하지만 크기는 소요되는 비용과도 어느 정도의 비례하므로 이것도 고려 대상이 됩니다. 크기가 너무 크면 비용이 많이 들 뿐만 아니라, 전원 공급이나 고정 방법 등에서도 제약을 받을 수 있습니다. 그렇다고 너무 작으면 원하는 형상을 표현하는데 어려움이 따르거나 형상이 부자연스러워질 수도 있으므로 알맞은 크기를 선택하여야 합니다. 우리는 비용은 적게 들면서도 형상은 또렷하게 나타낼 수 있는 정도의 크기로 전체 크기가 25cm (가로) X 10cm (세로) X 7cm (두께) 정도의 아크릴박스에 들어가는 정도로 하겠습니다. (사실은 미리 생각해서 준비한 박스입니다.)

마지막으로 해야 할 일은 디자인입니다. 디자인을 하기 위하여는 일단, 카DL이 제공하는 모든 형상을 알고 이것을 선택적으로 사용하여 디자인하는 것이 좋습니다. 디자인은 사실 제작하는 사람의 취향이나 능력에 따라 조금씩 달라질 수 있습니다. 디자인 감각이 있는 사람은 좀 더 예쁘고 세련되게 만들 수 있을 것이고, 그렇지 않은 사람은 약간은 어색하거나 투박한 형상으로 만들 가능성이 높겠지요. 제가 사용할 디자인은 제이씨넷 [신승현]님이 만들어 준 것인데 8cm X 8cm 사각형을 기준으로 아래와 같이 디자인하였습니다. 직선(BAR) 모듈과 곡선(ARC) 모듈을 다양하게 사용하였고, 방향자 모듈도 사용한 것이 보입니다. 제가 보기에는 디자인이 꽤 괜찮습니다.

38 PTB (6)

영문자 I 와 U는 카DL 모듈이 가능한 직접 연결이 될 수 있도록 하면 누가 디자인해도 거의 이런 모양으로 나올 것 같고, 하트(♥)는 사람마다 다르게 디자인할 것 같은데, 이런 경우 2가지 사항은 꼭 고려하면서 디자인하셔야 합니다. 하나는 LED의 모양 및 배치입니다. 카DL에 실제로 전원이 들어와서 불이 켜질 때의 모습을 상상하여 원하는 모습으로 나타날 수 있도록 모듈을 선택하고 배치하는 것이 중요합니다. 실제로 동작하는 것은 LED 불빛이므로 아래와 같이 카DL의 동그란 LED를 색칠해 본 후 이것이 괜찮게 보이는지를 판단해 보는 것이 하나의 방법입니다.

38 PTB (7)

다른 하나는 연결성입니다. 형상 때문에 어쩔 수 없이 연결이 직접적으로 될 수 없는 부분이 생기게 되는데 이런 상황이 가능한 적게 생기도록(즉, 직접 연결이 가능한 많아지도록) 디자인하는 것이 중요합니다. 왜냐하면 직접 연결은 간단한 커넥터(JLED-CON-0)로만 쉽게 연결되기 때문입니다. 또한, 모서리 부분은 카DL의 직선(BAR) 모듈과 곡선(ARC) 모듈만으로는 표현하기 어려운 부분이 있을 수 있으므로 필요에 따라 방향자(DIR) 모듈이나 도형(FIGURE) 모듈도 섞어서 사용하면 좀 더 자연스러운 형상을 만들 수 있습니다.

38 PTB (8)

아, 참, 방향자(DIR) 모듈은 위에서 설명을 하지 않았죠. 카멜레온 DIY LED는 모서리의 직접 연결을 위하여 아래와 같은 6가지 방향자(DIR)를 제공합니다. 이것은 UP 또는 DOWN 방향으로 각각 45도, 90도, 135도 방향 전환 시 사용할 수 있으며, 가끔씩은 도형적인 의미로도 사용됩니다.
위 하트 모양에서는 오른쪽과 같이 동그라미로 표시된 부분에 안성맞춤으로 사용이 되었네요.

38 PTB (9)

2단계 : 형상 제작하기
자, 이제 설계(디자인)가 완료되었으니 구현할 차례입니다. 일반적으로 카DL을 구현하는 방법은 하나의 골판지 또는 폼보드 등을 밑판으로 하여 카DL을 관통하여 모양을 잡고, 뒤쪽에서 커넥터와 케이블을 이용하여 고정시키는 방법이 가장 편하고 쉽습니다. 도화지, 아트지, 스티로폼, 책받침과 같은 얇은 플라스틱 등등 상당히 많은 다양한 재료를 사용하여 보았지만, 현재까지는 2mm 두께의 폼보드가 가장 편리하고, 그 다음으로는 1mm 정도 두께의 골판지가 편리한 것으로 보입니다. 조립할 때 한가지 주의해야 할 것은 카DL은 방향성이 있으므로 신호선의 IN과 OUT 방향을 잘 보고 연결해야 한다는 점입니다. 각 모듈의 V(+5V)와 G(GND) 신호는 동일한 신호끼리 연결하여야 하는 것은 물론, 앞 모듈의 O(Data Out)핀은 반드시 다음에 연결할 모듈의 I(Data In)핀에 연결해야만 카DL 전체 형상이 정상적으로 동작할 수 있습니다.
그러면, 이제 실제로 골판지를 밑판으로 사용하여 순서대로 제작해 보겠습니다.

(1) 검정색 골판지를 가로 239mm, 세로 94mm의 사각형으로 자릅니다. (아크릴 두께가 있어 양쪽으로 3mm씩은 여유를 둡니다.)

(2) 카DL을 모양에 맞추어 골판지 위에 원하는 형태로 놓아 봅니다. (뒤집어 놓으면 균형을 잘 잡을 수 있습니다.)

(3) 카DL을 조립합니다. 방향성을 잘 확인하고, 위치를 잘 잡아가며 조립하여야 자신이 원하는 형태가 되므로 주의하여야 합니다. 특히 2개의 카DL이 직접 연결되는 부분은 정확하게 연결되도록 위치를 잘 잡아서 조립하여야 나중에 커넥터(JLED-CON-0)를 쉽게 연결할 수 있습니다. 한편, 카DL은 연결 핀이 뾰족하게 나와 있어 골판지를 관통하여 조립할 때 매우 조심하여야 합니다. 잘못하면 연결 핀에 손이 찔려 상처가 날 수도 있습니다.

(4) 골판지를 뒤로 돌려서, 직접 연결되는 카DL은 JLED-CON-0를 이용하여 연결하고(JLED-CON-0는 2핀 점퍼 3개를 동시에 각각 연결하는 형태인 2×3 점퍼임) 직접 연결되지 않는 카DL은 JLED-CABLE3-MM10 또는 JLED-CABLE3-MM20 케이블을 이용하여 연결합니다. 이 때 전원 및 데이터 신호가 서로 일치하도록 방향성을 확인하면서 연결해야 합니다. (V-V, O-I, G-G가 연결되도록 함)

38 PTB (10)

 

38 PTB (11)

 

38 PTB (12)

 

38 PTB (13)

 

 

3단계 : 아두이노 연결하기

이제 만들어진 형상을 제어하기 위하여 아두이노를 연결하도록 하겠습니다. 아두이노는 일반적으로 가장 많이 사용하는 아두이노 UNO를 사용해도 되지만, 우리는 제어기를 아크릴박스에 넣어서 휴대용으로 제작하려 하므로, 크기가 작고 가격이 저렴한 아두이노를 선택하는 것이 좋겠습니다. 아두이노 NANO도 좋고, 아두이노 Pro Micro 등 어떤 것도 좋은데, 여기서는 기왕이면 크기가 엄지 손가락 크기로 가장 작고 가격도 상대적으로 저렴한 아두이노 Pro Micro(아두이노 Leonardo의 소형 버전)를 사용하는 것으로 하겠습니다.

38 PTB (14)

아두이노 Pro Micro는 납땜이 되지 않은 상태의 것이 많은데 아래와 같은 핀 배열을 가지고 있습니다. 카DL과 연결할 신호는 VCC와 GND, 데이터 1포트이므로, 연결하기 쉽게 빨강색 네모 박스의 신호를 연결하도록 하겠습니다. 데이터신호로 A3 신호를 사용하는 것이지요. (아날로그 핀은 디지털핀으로도 사용 가능합니다.) 좀 더 편리하게 사용하려면 이 3핀의 신호를 터미널블록으로 처리한 카DL 전용 아두이노인 JARDUINO-PROMICRO-1을 사용하는 것도 방법입니다. (여기서는 이것을 사용하겠습니다.)

38 PTB (15)

JARDUINO-PROMICRO-1의 3핀을 카DL 형상의 첫번째 모듈의 입력과 연결하면 되는데, 이 때 JLED-START-1을 아두이노와 카DL 첫번째 모듈 사이에 삽입하는 것이 좋습니다. JLED-START-1은 카DL 모듈을 여러 개 연결하거나 장시간 사용하는 경우 전체 모듈의 안정성을 위하여 제어기(아두이노)와 카DL 첫번째 모듈 사이에 장착하는 안정화 모듈로 안정화를 위한 대용량 커패시터와 저항을 내장하고 있습니다. 신호선 연결은 일반적인 카DL 모듈과 동일하게 연결합니다. (V-V, O-I, G-G)

38 PTB (16)

4단계 : 아두이노 스케치 프로그램하기
하드웨어는 모두 완성되었으므로, 이제는 스케치 프로그램만 작성하면 될 것 같습니다. 자신이 원하는 형태로 [I ♥ U]가 움직이도록 프로그램을 작성해 보시지요. 지난 시간에 라이브러리를 이용하는 방법을 익혔으므로 너무 어렵게 생각하지 말고 일단 지난번 배운 라이브러리만을 이용하여 구현해 보겠습니다. 한가지 예로 지난 회에서 언급하였던 Adafruits 프로그램 중 strandtest 프로그램을 데이터 핀 번호와 LED 개수, 그리고 색상과 delay 시간 등만 아주 조금 바꾸고 그대로 실행시켜 보겠습니다. 설명은 프로그램 내의 주석을 참조하시기 바랍니다.

—————————————————
#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

#define PIN A3 // JARDUINO-PROMICRO-1 사용으로 데이터 핀은 A3

Adafruit_NeoPixel strip = Adafruit_NeoPixel(53, PIN, NEO_GRB + NEO_KHZ800); // [I ♥ U] LED 갯수 = 53

void setup() {
strip.begin();
strip.show();
}
void loop() {
colorWipe(strip.Color(255, 0, 0), 20); // 빨강색으로 하나씩 순서대로 채우기
colorWipe(strip.Color(0, 255, 0), 20); // 녹색으로 하나씩 순서대로 채우기
colorWipe(strip.Color(0, 0, 255), 20); // 파랑색으로 하나씩 순서대로 채우기

theaterChase(strip.Color(127, 127, 0), 20); // 노랑색(Yellow) 사이키 조명 디스플레이
theaterChase(strip.Color( 0, 127, 127), 20); // 심홍색(Magenta) 사이키 조명 디스플레이
theaterChase(strip.Color(127, 0, 127), 20); // 청록색(Cyan) 사이키 조명 디스플레이
theaterChase(strip.Color(127, 127, 127), 20); // 흰색(White) 사이키 조명 디스플레이

rainbow(20); // // 전체가 같은 색으로 동시에 변하면서 디스플레이
rainbowCycle(20); // // 전체가 다르게 다양한 색으로 변하면서 디스플레이
theaterChaseRainbow(20); // // 다양한 색으로 변하면서 사이키 조명 디스플레이
}

// 하나씩 순서대로 채우기 함수
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}

// 전체가 같은 색으로 동시에 변하면서 디스플레이하는 함수
void rainbow(uint8_t wait) {
uint16_t i, j;

for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i+j) & 255));
}
strip.show();
delay(wait);
}
}

// 전체가 다르게 다양한 색으로 변하면서 디스플레이하는 함수
void rainbowCycle(uint8_t wait) {
uint16_t i, j;

for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}

// 한가지 색의 사이키 조명 디스플레이
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();

delay(wait);

for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}

// 다양한 색으로 변하면서 사이키 조명 디스플레이
void theaterChaseRainbow(uint8_t wait) {
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
}
strip.show();

delay(wait);

for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}

// 0~255까지의 값을 전달하면 4 바이트 컬러값을 리턴하는 함수
// 임의의 고르게 분포된 컬러값을 생성하기 위하여 사용
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 – WheelPos;
if(WheelPos < 85) {
return strip.Color(255 – WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 – WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 – WheelPos * 3, 0);
}
}
—————————————————-

 

5단계 : 업로드하고 실행시키기
이제 프로그램까지 준비가 되었으니 업로드하고 실행시켜 볼 차례입니다. 한가지 주의하여야 할 것은 앞에서도 언급했듯이 아두이노 Pro Micro는 아두이노 Leonardo의 소형 버전이므로, 업로드시 스케치 프로그램의 [보드] 선택 항목을 “UNO”가 아닌 “Leonardo”로 선택하여야 하는 것입니다. 나머지 업로드 방법은 일반적인 아두이노와 동일합니다.
아래에 업로드 된 프로그램이 실행되는 예를 몇 가지 보였습니다.

38 PTB (17)

 

38 PTB (18)

 

38 PTB (19)

오우, 아주 화려하게 잘 동작합니다. 생각했던 것보다 꽤 밝아서 눈이 조금 부실 정도입니다. 밤에는 멀리서도 아주 잘 보일 것 같네요. (혹시, 은은한 밝기를 원하시면 스케치 프로그램 작성 시 색상을 조절하시면 됩니다.)

6단계 : 외관을 정리하고 고정하기
위의 사진에서는 아크릴 상자에 넣어진 모습으로 동작하는데, 사실은 아크릴 상자에 넣지않은 상태에서 동작을 테스트하고 원하는 형태로 잘 동작하면 그 때 아크릴 상자에 조립하는 것이 순서입니다. 조립시에는 먼저, 연결된 카DL 형상을 아크릴 상자의 앞면에 밀착시키고, JLED-START-1과 JARDUINO-PROMICRO-1 은 뒤쪽으로 빼 놓습니다.

38 PTB (20)

38 PTB (21)

38 PTB (22)

38 PTB (23)

준비한 휴대폰 보조 배터리(용량이 큰 것일수록 좋음. 적어도 5000mAh 이상의 배터리 권장)를 아크릴 박스 뒷면에 위치시킵니다. 휴대성 및 전원 공급 용량의 이유로 업로드 후 실제 동작 시에는 전원 공급을 USB 케이블로 하지 않고 휴대폰 보조 배터리 등으로 하는 것이 좋습니다. 위 사진에서 보듯 찍찍이를 아크릴의 한쪽 면과 휴대폰 보조 배터리의 한쪽 면에 각각 붙인 후 서로 밀착시켜 정리하면 깔끔한 모양을 유지할 수 있습니다. USB 케이블을 이용하여 휴대폰 보조 배터리와 JARDUINO-PROMICRO-1을 연결하면 완성입니다.

7단계 : 내가 원하는 곳에 놓고 감상하기
모든 것이 원하는 대로 잘 동작합니다. 이제 내가 원하는 곳에 가져다 놓고 감상할 시간입니다. 주변 사람에게 자랑도 좀 하구요. 연인이나 친구에게 선물할 수도 있겠습니다. 저는 일단, 거실 앞쪽에 한 번 놓아 보았습니다. 괜찮게 된 것 같네요.

38 PTB (26)

 

38 PTB (25)

 

38 PTB (26)

불을 꺼보니 LED의 움직임이 더욱 선명하게 나타나는 것이 환상적입니다. 오~ 예~
이 정도면 자동차 뒤 유리창에 놓아도 괜찮을 장식이 될 것 같습니다. 뒷 차에 부담을 주는 정도가 안되도록 밝기는 조절해야 하겠죠? 기회가 되면 [I ♥ U] 뿐만 아니라 내가 원하는 모양을 만들어 응용도 해보시기 바랍니다.

변색 카멜레온

[I ♥ U]가 잘 만들어졌으니, 좀 더 고급 단계인 [변색 카멜레온]에 도전해 보겠습니다. [I ♥ U]에서 했던 방법과 똑같은 순서대로 진행해 봅니다.

1단계 : 형상 설계하기
이제 긴 설명은 생략하고 조금 단순화하여 빠르게 진행해 보겠습니다.

· 형상 : 카멜레온
· 용도 : 실제 카멜레온처럼 일부분씩 색상을 다르게 나타낼 수 있고, 약간의 움직임도 표현할 수 있는 창문에 부착하는 전광판 형태로 제작
· 크기 : A4 용지 크기와 비슷한 30cm X 20cm에 들어가는 크기
· 디자인 : 아래 참조 (이번 디자인도 제이씨넷 [신승현]님의 디자인입니다.)

38 PTB (27)

카멜레온과 같은 동물 형상은 조금은 복잡하므로 특징을 잘 살려서 단순하게 표현하는 것이 중요합니다. (이것은 재능이 조금은 필요한 부분이므로 자신이 직접 하기가 어려우면 잘 할 수 있는 다른 사람에게 부탁하는 것도 방법입니다.) 아, 참, 그리고 기본 설계 도구가 궁금하실 분도 있을 것 같은데 위 그림은 오토캐드를 이용하여 카DL 기본 형상을 라이브러리처럼 모두 만들어 놓은 상태에서 이것을 배치하고 연결하여 만든 그림임을 밝혀둡니다. 이렇게 하기가 쉽지 않으면 그냥 손으로 대강의 모습을 스케치 한 후 카DL을 직접 배열해 가면서 진행해도 되겠습니다.

이미 한 번 이야기한 것처럼 카DL은 방향성이 있으므로 이것을 잘 고려하여 형상을 만들어야 합니다. 또한, 첫 시작점을 어디로 잡을 것인지, 연결되는 순서는 어떻게 할 것인지도 전체적인 모양을 고려하여 결정하는 것이 좋습니다.

저는 목 부분에서 시작하여 얼굴 ▶ 등 ▶ 꼬리 ▶ 배 ▶ 뒷다리 ▶ 앞다리 ▶ 피부 ▶ 눈 ▶ 혀의 순으로 연결되도록 카DL을 배치하였습니다. 여기서 새로 선보인 것은 눈 형상에 해당되는 JLED-HEXA-7 입니다. 6각형 모서리에 LED(WS2812B)가 하나씩 있고 가운데에도 1개가 있는 형상으로 카DL 도형(FIGURE) 그룹 중의 하나입니다. 카DL의 도형(FIGURE) 그룹은 아래와 같이 7개의 도형으로 구성되어 있으므로 필요에 따라 알맞은 것을 골라 사용하면 됩니다.

38 PTB (28)

2단계 : 형상 제작하기
1단계에서 배열한 순서대로 카DL을 조립해 봅니다. 지난번과 마찬가지로 직접 연결되는 부분이 잘 조립될 수 있도록 하는 것에 주의하여야 하며, 한 가지 팁을 더 이야기하면 직접 연결되는 부분은 순서대로 차례차례 조립하는 것이 좋습니다. 순서 없이 조립을 진행하다 보면 중간에 직접 연결되는 부분을 조립할 때 서로 어긋나서 이미 진행하였던 조립을 다시 수정하여야 하는 상황이 발생할 수도 있기 때문입니다. 아래 그림에서는 화살표로 방향과 연결 관계를 미리 표시하여 가능한 이 순서대로 조립을 진행합니다. 또한 카DL의 원호(ARC) 그룹인 경우는 Up 방향 모듈과 Down 방향 모듈의 구분이 쉽지 않으므로, 그림 상에서 “U”, “D”를 간단히 명시해 놓고 조립을 진행하면 실수를 줄일 수 있습니다.
아래는 조립이 완성된 상태의 앞면입니다.

38 PTB (29)

3단계 : 아두이노 연결하기
이번에는 제어기로 가장 많이 사용하는 아두이노 UNO를 사용하도록 하겠습니다. 아두이노 UNO와 JLED-START-1까지 연결한 뒷면 모습은 아래와 같습니다. 데이터핀은 디지털 핀 6번을 사용하였습니다. 아두이노와 JLED-START-1의 입력쪽을 각각 +5V- V(VCC), GND-G(GND), D6-I(Data In)의 짝으로 연결합니다.

4단계 : 아두이노 스케치 프로그램하기
그 동안에는 다른 사람들이 제공하였던 라이브러리와 스케치 프로그램을 그대로 이용하면서 값만 조금 바꾸어 사용하였는데, 이번에는 조금 더 적극적으로 내가 표현하고 싶은 동작과 색상을 정하고 이것을 스케치 프로그램으로 구현하도록 해 보겠습니다. 필요하다면 새로운 함수도 정의하여 작성하도록 하지요. 일단, 동작과 색상을 표로 간단하게 기술해 봅시다.

[카멜레온 형상의 동작 및 색상]

단계 동작과 색상 참조 사항
1 머리를 녹색으로 켜기
2 등과 배, 꼬리를 파랑색으로 켜기
3 뒷다리와 앞다리를 보라색으로 켜기
4 피부를 노랑색으로 켜기
5 눈을 주황색으로 켜기
6 앞다리와 뒷다리를 번갈아 가면서 켜기 2번 반복
6 혀를 빨강색으로 내밀었다가 집어넣기
7 눈은 싸이키로 반짝반짝, 피부도 싸이키로 반짝반짝
8 전체가 동일한 랜덤색으로 앞에서부터 뒤로 천천히 변신 3번 반복
9 전체가 개별적으로 무지개색으로 변신 약 5초간
10 완전히 사라짐 약 5초간

※ 10단계까지 진행을 마치면 다시 1단계부터 무한 반복합니다.

 [프로그램 구현 방법]

연결순서 그룹구분 시작번호 끝번호
1 머리 0 3
1
2 3
2
5
7
3 꼬리 5
8
8
3
4 8
4
8
9
5 뒷다리 9
0
9
9
6 앞다리 1
0
0
1
1
1
7 피부 1
2
2
1
3
2
8 1
3
3
1
3
9
9 1
4
0
1
4
7

색상이 바뀌는 동작은 그룹별로 처리되어야 하므로, 이것을 효과적으로 처리할 수 있는 기능은 우리가 새로 만들어야 할 것 같습니다. 음… 당장 엄밀하게 정의하지는 못하겠지만, 현재 우리가 사용하고 있는 기능을 LED 번호의 특정 범위에서 실행할 수 있는 함수로 확장하여 정의하면 매우 편리할 것 같네요. 예를 들어 colorWipe(color, wait)로 정의된 기능을 이용하여 colorWipeFT(from, to, color, wait)와 같이 시작 LED 번호인 from과 끝 LED 번호인 to를 파라미터로 더 정의하여 사용하면 좋을 것 같습니다. 이것은 원래 제공되었던 프로그램을 그대로 가져다가 쓰면서 for 루프를 사용하여 from부터 to까지 적용하면 되므로 별로 어렵지는 않을 것으로 생각됩니다. 예를 들어 colorWipeFT(from, to, color, wait) 함수 하나만 작성해 보면 아래와 같이 됩니다.

void colorWipeFT(uint16_t from, uint16_t to, uint32_t color, uint16_t wait)
{
/* 일정 범위의 카DL을 하나씩 순서대로 채우는 함수
- from : from LED 번호
- to : to LED 번호
- color : 32비트 RGB 컬러 코드, 0x00RRGGBB 형태
- wait : LED 사이의 동작 간격(딜레이)
*/

for (int i=from; i<=to; i++) // 원래 범위가 (0~끝)인 것을 (from~to)로 수정
{
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}

원래 colorWipe( ) 프로그램 내에서 for (uint16_t i=0; i<strip.numPixels(); i++) 로 표현된 부분을 for (int i=from; i<=to; i++) 로 바꾸기만 하면 쉽게 colorWipeFT( )가 작성되는 것을 볼 수 있습니다. 다른 함수들도 이런 방법을 잘 응용하면 쉽게 만들 수 있겠지요?
또, 한가지 미리 알아둘 것은 randomSeed( ) 함수와 random( ) 함수에 관련된 것입니다. 이 부분은 C 함수에서도 많이 나오는 라이브러리 함수인데 아두이노에서도 라이브러리 로 제공됩니다. random( ) 함수를 이용하면 임의의 값(난수)을 얻을 수 있으므로 스케치 프로그램을 실행시킬 때 다양성을 부여하기가 매우 쉽습니다. 예를 들어 카DL 형상에 색상을 표현할 때 이 random( ) 함수를 적용하여 표현한다면 함수가 실행될 때마다 값이 달라져 표현되는 색이 실행할 때마다 변하는 임의성을 확보할 수가 있겠습니다. 함수를 사용하는 방법은 아래와 같습니다.

randomSeed(seed)

· 기능 : seed 값에 따른 난수표의 시작 포인트를 결정하여, 추후 random( ) 함수 사용시 난수를 제공할 수 있는 준비를 함, seed 값이 같으면 random( )의 return 값은 동일한 값이 됨
· seed : 정수값
· 반환값 : 없음

random(max)
random(min, max)

· 기능 : min과 max 사이의 임의의 난수값을 제공
· min : 반환값 범위의 최소값으로 long 타입이며 이 값은 포함됨
· max : 반환값 범위의 최대값으로 long 타입이며 이 값은 포함이 되지 않음
· 반환값 : 0~max 또는 min~max 사이의 정수

많이 사용되는 예로는,

randomSeed(analogRead(0));
randNumber = random(256);

과 같이 사용하여 0~255까지의 난수를 얻는 방법이 있습니다. 즉, 아두이노에서 아날로그 포트 중 하나인 A0 포트에 아무 것도 연결하지 않은 상태의 값을 읽으면 임의의 값이 읽히는 것을 이용하여 randomSeed(seed) 함수를 결정하고, 이후 원하는 범위의 값은 random(max)를 이용하여 추출해 내는 것이지요.
자, 이제 기본 준비가 되었으니 실제 카멜레온 형상에 대한 스케치 프로그램을 직접 작성해 보겠습니다. 가능하면 여러분들도 나름대로 먼저 충분히 작성해 본 다음에 아래 내용과 비교 검토해 보기를 권장합니다.

—————————————————-
/* 카멜레온 만들기 */

#define RED 0x00ff0000 // 빨강
#define GREEN 0x0000ff00 // 녹색
#define BLUE 0x000000ff // 파랑
#define YELLOW 0x00ffff00 // 노랑
#define SKYBLUE 0x0073d1f7 // 하늘색
#define PINK 0x00f69fa8 // 분홍
#define BLACK 0×00000000 // 검정(OFF)
#define BROWN 0x0088563f // 갈색
#define ORANGE 0x00f3753a // 오렌지색
#define DEEPBLUE 0x002a365c // 남색

#define HEAD_FROM 0 // 머리 시작 번호
#define HEAD_TO 31 // 머리 끝 번호
#define SPINE_FROM 32 // 등 시작 번호
#define SPINE_TO 57 // 등 끝 번호
#define TAIL_FROM 58 // 꼬리 시작 번호
#define TAIL_TO 83 // 꼬리 끝 번호
#define BELLY_FROM 84 // 배 시작 번호
#define BELLY_TO 89 // 배 끝 번호
#define LEG_B_FROM 90 // 뒷다리 시작 번호
#define LEG_B_TO 99 // 뒷다리 끝 번호
#define LEG_F_FROM 100 // 앞다리 시작 번호
#define LEG_F_TO 111 // 앞다리 끝 번호
#define SKIN_FROM 112 // 피부 시작 번호
#define SKIN_TO 132 // 피부 끝 번호
#define EYE_FROM 133 // 눈 시작 번호
#define EYE_TO 139 // 눈 끝 번호
#define TONGUE_FROM 140 // 혀 시작 번호
#define TONGUE_TO 147 // 혀 끝 번호

#define TWINKLE_LOOP 3 // twinkle 함수 실행시 깜빡깜빡 사이키 조명 횟수
#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

#define PIN 6 // 6번 핀을 데이터 핀으로 이용

Adafruit_NeoPixel cdl = Adafruit_NeoPixel(147, PIN, NEO_GRB + NEO_KHZ800);
// cdl 구조체 설정, 카멜레온 LED 총 개수 = 147
void setup() {
cdl.begin();
cdl.show();
randomSeed(analogRead(0)); // random( ) 함수 사용을 위한 준비, seed = A0 포트 read 값
}

void loop() {
uint8_t r, g, b;
uint16_t i;
uint32_t color;
colorWipeFT(HEAD_FROM, HEAD_TO, GREEN, 0); // 머리를 녹색으로 켜기
delay(300);
colorWipeFT(SPINE_FROM, SPINE_TO, SKYBLUE, 0); // 등을 하늘색으로 켜기
colorWipeFT(BELLY_FROM, BELLY_TO, SKYBLUE, 0);// 배를 하늘색으로 켜기
colorWipeFT(TAIL_FROM, TAIL_TO, BLUE, 0); // 꼬리를 파랑색으로 켜기
delay(300);
colorWipeFT(LEG_F_FROM, LEG_F_TO, BROWN, 0); // 앞발을 갈색으로 켜기
colorWipeFT(LEG_B_FROM, LEG_B_TO, BROWN, 0);// 뒷발을 갈색으로 켜기
delay(300);
colorWipeFT(SKIN_FROM, SKIN_TO, YELLOW, 0); // 피부를 노랑색으로 켜기
colorWipeFT(EYE_FROM, EYE_TO, PINK, 0); // 눈을 핑크색으로 켜기
delay(300);
for (i=0; i<4; i++) // 앞발과 뒷발을 번갈아 가면서 켜고 끄기, 4번 실행
{
colorWipeFT(LEG_F_FROM, LEG_F_TO, DEEPBLUE, 0);// 앞발은 남색으로 켜고
colorWipeFT(LEG_B_FROM, LEG_B_TO, BLACK, 0); // 뒷발은 끄기
delay(200);
colorWipeFT(LEG_B_FROM, LEG_B_TO, DEEPBLUE, 0); // 뒷발은 남색으로 켜고
colorWipeFT(LEG_F_FROM, LEG_F_TO, BLACK, 0); // 앞발은 끄기
delay(200);
}
colorWipeFT(LEG_F_FROM, LEG_F_TO, DEEPBLUE, 0); // 앞발을 남색으로 켜기
delay(200);
tongueFT(TONGUE_FROM, TONGUE_TO, RED, 50); // 혀를 빨강색으로 내밀었다가 집어넣기
twinkleFT(EYE_FROM, EYE_TO, PINK, 20); // 눈을 핑크색으로 깜빡이기
colorWipeFT(EYE_FROM, EYE_TO, PINK, 0); // 눈을 모두 켜기
twinkleFT(SKIN_FROM, SKIN_TO, YELLOW, 20); // 피부를 노랑색으로 깜빡이기
colorWipeFT(SKIN_FROM, SKIN_TO, YELLOW, 0); // 피부를 모두 켜기
delay(300);
for (i=0; i<3; i++) {
r = random(256); // 난수 1개 얻어 r 값으로 할당
g = random(256); // 난수 1개 얻어 g 값으로 할당
b = random(256); // 난수 1개 얻어 b 값으로 할당
color = cdl.Color(r, g, b); // r, g, b로 RGB 컬러값 결정
colorWipeFT(0, cdl.numPixels()-1, color, 10); // 위 컬러로 전체를 차례로 색칠
delay(500);
}
rainbowCycle(20); // 각 카DL을 다양한 색으로 표현
colorWipeFT(0, cdl.numPixels()-1, BLACK, 0); // 모든 카DL 소등(OFF)
delay(3000);
}

/* colorWipeFT( ) : 일정 범위의 카DL을 하나씩 순서대로 채우는 함수
- from : from LED 번호
- to : to LED 번호
- color : 32비트 RGB 컬러 코드, 0x00RRGGBB 형태
- wait : LED 사이의 동작 간격(딜레이)
*/
void colorWipeFT(uint16_t from, uint16_t to, uint32_t color, uint16_t wait)
{
uint16_t i;
for (i=from; i<=to; i++) // 원래 범위가 (0~끝)인 것을 (from~to)로 수정
{
cdl.setPixelColor(i, color);
cdl.show();
delay(wait);
}
}

/* tongueFT( ) : 일정 범위의 카DL을 혀를 내밀었다가 다시 거둬들이도록 동작처럼 움직이도록 하는 함수
- from : from LED 번호
- to : to LED 번호
- color : 32비트 RGB 컬러 코드, 0x00RRGGBB 형태
- wait : LED 사이의 동작 간격(딜레이)
*/
void tongueFT(uint16_t from, uint16_t to, uint32_t color, uint16_t wait)
{
uint16_t i;
for (i=from; i<= to; i++) // 혀를 내미는 동작
{
cdl.setPixelColor(i, color);
cdl.show();
delay(wait);
}
delay(wait);
for (i=to; i>= from; i–) // 혀를 거둬들이는 동작
{
cdl.setPixelColor(i, BLACK);
cdl.show();
delay(wait);
}
delay(wait);
}

/* twinkleFT( ) : 일정 범위의 카DL을 사이키 조명처럼 번쩍번쩍하면서 움직이도록 하는 함수
- from : from LED 번호
- to : to LED 번호
- color : 32비트 RGB 컬러 코드, 0x00RRGGBB 형태
- wait : LED 사이의 동작 간격(딜레이)
*/
void twinkleFT(uint16_t from, uint16_t to, uint32_t color, uint16_t wait)
{
uint16_t i, j;
for(j=0; j<TWINKLE_LOOP; j++)
{
for(i=from; i<=to; i=i+2) // 1개는 켜고, 그 다음 1개는 끔(BLACK)
{
cdl.setPixelColor(i, color);
if (i+1<=to)
cdl.setPixelColor(i+1, BLACK);
cdl.show();
}
delay(wait);
for(i=from; i<=to; i=i+2) // 위와 반대로, 켜진 것은 끄고(BLACK), 꺼진 것은 켬
{
cdl.setPixelColor(i, BLACK);
if (i+1<=to)
cdl.setPixelColor(i+1, color);
cdl.show();
}
delay(wait);
}
}

// 지난 회에 사용하였던 함수
// 전체가 다르게 다양한 색으로 변하면서 디스플레이하는 함수
void rainbowCycle(uint8_t wait) {
uint16_t i, j;

for(j=0; j<256*5; j++) {
for(i=0; i< cdl.numPixels(); i++) {
cdl.setPixelColor(i, Wheel(((i * 256 / cdl.numPixels()) + j) & 255));
}
cdl.show();
delay(wait);
}
}

// 지난 회에 사용하였던 함수
// 0~255까지의 값을 전달하면 4 바이트 컬러값을 리턴하는 함수
// 임의의 고르게 분포된 컬러값을 생성하기 위하여 사용
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 – WheelPos;
if(WheelPos < 85) {
return cdl.Color(255 – WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return cdl.Color(0, WheelPos * 3, 255 – WheelPos * 3);
} else {
WheelPos -= 170;
return cdl.Color(WheelPos * 3, 255 – WheelPos * 3, 0);
}
}
—————————————————-

※ 프로그램 정리 및 테스트는 한밭대학교 윤병우님이 도움을 주었습니다.

 

5단계 : 업로드하고 실행시키기
조금 긴 과정이었지만 스케치 프로그램 작성이 완료되었습니다. 이번에는 아두이노 UNO 이므로 업로드시 스케치 프로그램의 [보드] 선택 항목을 “UNO”로 선택하고 업로드와 실행을 진행하면 되겠습니다. 자, 원하는 대로 잘 움직이는지 살펴 볼까요? 아, 참, 여기서 한가지만 더 주의!!! 바로 전에 실행했던 [I ♥ U] 제작 시와 다르게 고려하여야 할 것 하나는 휴대폰 보조 배터리 용량입니다.

38 PTB (31)

이번 [변색하는 카멜레온]의 경우는 147개의 WS2812B가 사용되므로 전류 소모량이 상당히 되므로 최소 약 2A의 전류 공급 용량을 갖는 휴대폰 보조 배터리를 사용하시기 바랍니다. LED를 켜다가 전류 용량이 부족하면 그대로 정지하거나 리셋되어 다시 처음부터 시작할 수 있습니다.

38 PTB (32)

 

38 PTB (33)

38 PTB (34)

38 PTB (35)

38 PTB (36)

38 PTB (37)

38 PTB (38)

성공입니다! 발이 왔다가는 하는 동작과 혀를 날름거리는 동작도 잘 된 것 같습니다. 몸 전체 컬러를 변화시킬 때는 random() 함수를 이용하므로 루프가 반복될 때마다 새로운 색상으로 변화하므로 지루하지 않다는 장점도 있네요. 외관을 잘 다듬어서 지난번에 만든 것처럼 아크릴 판에 넣거나, 창문이나 유리판에 고정시켜 보조 간판처럼 사용하는 것이 가능할 것 같습니다. OK~

이 정도면 이제 어떤 형상, 어떤 컬러, 어떤 움직임도 시간만 주어진다면 모두 만들 수 있을 것 같은 자만심(?)도 드네요. 여러분도 상상의 나래, 창조의 나래를 펴서 자신만의 디자인과 자신만의 프로그램으로 동작하는 카DL 소품을 한 번쯤 만들어 보시기 바랍니다.
오늘 모두 수고 많으셨습니다. 다음 시간에는 [카멜레온 DIY LED 이야기]의 마지막 시간으로, [특별한 크리스마스 트리] 제작을 포함하여 생활 속에서 응용할 수 있는 재미있는 카DL 소품을 함께 만들어 보는 시간을 갖도록 하겠습니다. 좋은 하루 되시기 바랍니다. 감사합니다.

 

 

 

 

 

[38호]로꾸꺼 보트

38 ict 로꾸꺼 (1)

2016 ictmain

2016  ICT 융합 프로젝트 공모전 참가상

로꾸꺼 보트

글 | 한국교통대학교 임성묵, 전동흡, 박재호, 오성석, 신민철

심사평

뉴티씨 해양 오염 등을 모니터링하거나, 원격으로 조정하여 보트를 통하여 수질개선을 시도하거나 현재의 상태를 보면서 대책을 강구할 수 있는 등 좋은 아이디어인데, 실제 구현까지는 아직 많은 단계가 남아있는 듯 하다. 이를 실제로 구현하여, 실제 사용 데모 등을 찍어서 함께 보여준다면 보다 좋은 작품이 될 것으로 생각하며, 많은 개선 여지를 남기고 있는 작품이다.

칩센 학생들이 도전하기 쉬운 주제지만 완성도가 조금 아쉽다.

위드로봇 보트를 위·아래 대칭 형태로 제작하는 아이디어가 무척 재미있다. 문제는 이렇게 제작한 보드가 실제 강이나 바다에서 동작하는데 문제가 없는지를 조사해 봐야 할 것 같은데, 그 부분에 대한 조사가 없는 것이 아쉽다.

작품개요
기존 무선 모터보트의 단점을 개선한다.

38 ict 로꾸꺼 (1)

① 보트의 전복을 방지
잔잔한 호숫가든 파도가 치는 바닷가든, 충돌의 가능성과 물살에 의해 전복이 되는 위험성이 있다.
: 일반적인 RC보트의 구조로는 파도가 조금 높고, 바람의 세기가 강해지면 쉽게 전복된다. 때문에 보트가 전복이 되더라도 상관없이 계속해서 정찰할 수 있도록 보트의 구조를 위·아래 대칭으로 만들었다. 보트가 전복되었을 때 카메라의 구도가 뒤집히고 좌우 모터의 위치가 바뀌기 때문에 자이로 센서의 값을 이용하여 컨트롤러의 방향에 맞게 보트의 앞·뒷면을 판단하고 카메라의 스트리밍 화면을 똑바로 볼 수 있게 화면을 조정해 준다.

38 ict 로꾸꺼 (2)

② 시야의 확보
보트가 시야에서 가려지면 컨트롤을 할 수 없다.
: 카메라를 통해서 시야를 확보했다. 카메라는 액션캠을 이용했다. 액션캠의 장점이 작고 가볍고 내구성이 좋으며 다각도를 촬영할 수 있다는 점 때문에 보트에 활용하기 적합하다. 그리고 움직이면서 촬영할 수 있기 때문에 일반 캠코더로는 불가능한 역동적인 동영상 촬영이 가능하다. 가장 큰 장점은 실시간 카메라 스트리밍을 이용하여 보트의 주변 환경정보를 받아들일 수 있으며 장거리에서도 주변 상황에 맞추어 보트를 작동하는 것이 가능하다.

③ 장거리 동작 가능
RC보트의 전파 도달거리는 약 50~60m정도로 그 범위를 벗어나게 되었을 경우 컨트롤로는 더 이상 조작을 할 수 없다.
: UDP통신을 이용하여 WIFI가 가능한 지역이라면 어디서든 원격으로 조정이 가능하다. 사람의 시야 밖에서도 카메라를 통해 주변 상황을 스트리밍 할 수 있기 때문에 원활한 조작이 가능하다. LTE를 이용하여 좀 더 원활한 조작을 하고 싶었지만 LTE 주파수는 기업에서 구매하여 사용하고 있기 때문에 개발하지 못하였다.

38 ict 로꾸꺼 (4)

④ 컨트롤방식의 다양성
기존의 RC보트의 컨트롤은 조이스틱만을 이용해 조작한다.
: 조이스틱을 이용한 조작과 더불어 자이로센서를 이용하여 컨트롤러의 기울기에 따른 조작을 할 수 있게 하여 컨트롤방식의 다양성을 부여하였다.

작품설명
주요동작 및 특징

38 ict 로꾸꺼 (5)

① 스위치

38 ict 로꾸꺼 (6)
1) 자이로센서로 보트가 동작한다. 조이스틱 모듈로는 동작하지 않는다.
2) 조이스틱 모듈로 보트가 동작한다. 자이로센서로는 동작하지 않는다.
※ 스위치를 위 1처럼 하기 전에 컨트롤러가 좌, 우, 앞으로 기울지 않은 상태에서 해야 한다.

②자이로센서

38 ict 로꾸꺼 (7)
컨트롤러를 번호의 방향대로 기울였을 때,
1) 보트가 제자리에서 왼쪽으로 돈다.
2) 보트가 제자리에서 오른쪽으로 돈다.
3) 보트가 앞으로 나아간다.
4) 보트가 앞으로 나아가며 컨트롤러를 기울인 방향으로 선회한다.

③ 조이스틱

38 ict 로꾸꺼 (8)
조이스틱을 다음 번호의 위치로 움직였을 때,
1) 보트가 제자리에서 왼쪽으로 돈다.
2) 보트가 제자리에서 오른쪽으로 돈다.
3) 보트가 앞으로 나아간다.
4) 보트가 앞으로 나아가며 조이스틱을 움직인 방향으로 선회한다.

전체 시스템 구성

38 ict 로꾸꺼 (1)
① 사용자 ▶ 보트
: 컨트롤러의 자이로 센서와 조이스틱 모듈에서 출력되는 값을 UDP 통신을 통해 보트의 라즈베리파이로 전송하여 보트의 움직임을 제어한다.
② 보트 ▶ 사용자
: 액션캠에서 받아들이는 영상정보를 라즈베리파이에서 MMAL 용 motion 프로그램을 사용한다. 사용자의 pc인 J-player로 전송하여 IP에 따라 실시간으로 받아들인다.

38 ict 로꾸꺼 (9)

① Brushless Motor
: ESC(Electric Speed Controller)를 통해 라즈베리파이의 GPIO핀에서 PWM 신호를 받아 컨트롤러에 따른 모터의 출력을 제어한다.
② 액션캠
: 라즈베리파이와의 USB연결을 통해 영상정보를 받아오고 라즈베리파이를 통해 UDP 통신으로 전송한다. 사용자의 PC에서 J-Player 화면으로 실시간으로 영상정보를 전송한다.
③ 자이로 센서
: I2C 통신을 이용하여 자이로 센서의 가속도 값을 라즈베리파이로 전송하여 보트의 상·하를 구별할 수 있도록 한다.

38 ict 로꾸꺼 (10)

① 무선 컨트롤러
: I2C 통신을 이용하여 자이로 센서의 자이로 가속도 값을 상보필터를 사용하여 X축과 Y축 값의 정보를 받아온다. 받아온 값을 UDP 통신을 통해 보트의 라즈베리파이로 전송한다. SPI 통신을 이용하여, 조이스틱의 방향에 따라 출력되는 아날로그 값을 디지털 값으로 변환하고 UDP 통신을 통해 보트의 라즈베리파이로 전송한다.
② 실시간 영상 수신
: 보트의 액션캠 영상정보를 사용자 PC에 J-Player를 이용하여 보트 라즈베리파이 IP를 통해 실시간으로 영상을 수신한다.

38 ict 로꾸꺼 (2)

· 컨트롤러의 스위치 값이 1이면 자이로 센서의 출력 값을 보트의 라즈베리파이로 전송한다.
· 컨트롤러의 스위치 값이 0이면 조이스틱의 방향에 따른 출력 값을 보트가 가지고 있는 모터제어 값에 맞게 변환하여 보트의 라즈베리파이로 전송한다.

38 ict 로꾸꺼 (3)

· 액션캠이 실행되어 실시간으로 영상정보전송을 시작한다.
· 자이로센서의 Z축 가속도 값을 수신하여 상·하를 구분한다.
· Z축 가속도 값에 따라 프로펠러의 포트를 선택한다.
· 컨트롤러로부터 받아오는 Roll/Pitch 값을 모터제어 함수를 거쳐, 조건에 따라 양측모터의 출력을 제어하여 보트를 동작시킨다.

개발환경
① 개발 보드
· 라즈베리파이
② 개발 환경
· 리눅스 기반의 Raspbian OS
③ 활용 프로그램
· J player
· Motion-MMAL(영상 전송을 위한 리눅스 프로그램)
④ 개발 언어
· python

단계별 제작과정

38 ict 로꾸꺼 (11)

① 보트의 외형을 기능이 잘 작동할 수 있도록 설계한다.

38 ict 로꾸꺼 (12)

② Sketch Up 프로그램을 이용하여 설계한 모형을 3D로 그려본다.

38 ict 로꾸꺼 (13)

③ 방수·단열재인 아이소핑크를 이용하여 보트의 외형을 제작한다.
· 크기에 맞게 아이소핑크를 자른다.
· ESC를 납땜한다.

38 ict 로꾸꺼 (14)

· 모터를 ESC와 연결하여 부착한다.
· ESC선을 내부로 집어넣는다.

38 ict 로꾸꺼 (15)

· 배터리/라즈베리파이/자이로센서/카메라를 내부에 부착한다.
· Glue-gun으로 모서리 방수처리를 한다.

38 ict 로꾸꺼 (16)

④ 컨트롤러를 제작한다.

38 ict 로꾸꺼 (17)

⑤ 컨트롤러와 보트에 코드를 작성한다.

38 ict 로꾸꺼 (18)

소스코드
① 컨트롤러

#필요한 라이브러리
import smbus
import time
import math
import string
import socket
import RPi.GPIO as GPIO
import os
import spidev

#ADC 변환위한 채널 설정
roll_ch = 1
pitch_ch = 2

#자이로, 가속도 센서 사용을 위해 정의 및 필요함수
power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c
gyro_scale = 131.0
accel_scale = 16384.0
address = 0×68
bus = smbus.SMBus(1)
bus.write_byte_data(address, power_mgmt_1, 0)

#UDP 통신 위한 선언
UDP_IP =”192.168.59.152”
UDP_PORT = 5005
sock1 = socket.socket(socket.AF_INET, #Internet
socket.SOCK_DGRAM) #UDP

#스위치 값 읽어오기 위한 선언
GPIO.setmode(GPIO.BCM)
GPIO.setup(23,GPIO.IN)

#조이스틱 모듈 값을 adc컨버터로 읽어오기 위한 선언 및 함수
spi = spidev.SpiDev()
spi.open(0,0)
def ReadChannel(channel):
adc = spi.xfer2([1,(8+channel)<<4,0])
data = ((adc[1]&3) << 8) + adc[2] return data

#UDP 통신을 위한 함수
def send(a,b):
for i,j in [(a,’a’),(b,’b’)]:
i = str(i)
buffer1 = j+i[0:] sock1.sendto(buffer1, (UDP_IP, UDP_PORT))

#자이로, 가속도 센서 사용을 위한 필요함수
def read_all():
raw_gyro_data = bus.read_i2c_block_data(address, 0×43, 6)
raw_accel_data = bus.read_i2c_block_data(address, 0x3b, 6)
gyro_scaled_x = twos_compliment((raw_gyro_data[0] << 8) +raw_gyro_data[1]) / gyro_scale
gyro_scaled_y = twos_compliment((raw_gyro_data[2] << 8) +raw_gyro_data[3]) / gyro_scale
gyro_scaled_z = twos_compliment((raw_gyro_data[4] << 8) +raw_gyro_data[5]) / gyro_scale

accel_scaled_x = twos_compliment((raw_accel_data[0] << 8) +raw_accel_data[1]) / accel_scale
accel_scaled_y = twos_compliment((raw_accel_data[2] << 8) +raw_accel_data[3]) / accel_scale
accel_scaled_z = twos_compliment((raw_accel_data[4] << 8) +raw_accel_data[5]) / accel_scale
return (gyro_scaled_x, gyro_scaled_y, gyro_scaled_z, accel_scaled_x, accel_scaled_y, accel_scaled_z)
def twos_compliment(val):
if (val >= 0×8000):
return -((65535 – val) + 1)
else:
return val
def dist(a, b):
return math.sqrt((a * a) + (b * b))
def get_y_rotation(x,y,z):
radians = math.atan2(x, dist(y,z))
return -math.degrees(radians)
def get_x_rotation(x,y,z):
radians = math.atan2(y, dist(x,z))
return math.degrees(radians)

#COMPLEMENTARY FILTER 함수
def com():
global last_com_x
global last_com_y
K = 0.98
K1 = 1 – K
time_diff = 0.001
(gyro_scaled_x, gyro_scaled_y, gyro_scaled_z, accel_scaled_x, accel_scaled_y, accel_scaled_z) = read_all()
last_1x = get_x_rotation(accel_scaled_x, accel_scaled_y, accel_scaled_z)
last_1y = get_y_rotation(accel_scaled_x, accel_scaled_y, accel_scaled_z)

gyro_offset_x = gyro_scaled_x
gyro_offset_y = gyro_scaled_y

gyro_total_x = (last_1x) – gyro_offset_x
gyro_total_y = (last_1y) – gyro_offset_y

(gyro_scaled_x, gyro_scaled_y, gyro_scaled_z, accel_scaled_x,
accel_scaled_y, accel_scaled_z) = read_all()

gyro_scaled_x -= gyro_offset_x
gyro_scaled_y -= gyro_offset_y

gyro_x_delta = (gyro_scaled_x * time_diff)
gyro_y_delta = (gyro_scaled_y * time_diff)

gyro_total_x += gyro_x_delta
gyro_total_y += gyro_y_delta

rotation_x = get_x_rotation(accel_scaled_x, accel_scaled_y, accel_scaled_z)
rotation_y = get_y_rotation(accel_scaled_x, accel_scaled_y, accel_scaled_z)
last_1x = K * (last_1x + gyro_x_delta) + (K1 * rotation_x)
last_1y = K * (last_1y + gyro_y_delta) + (K1 * rotation_y)

last_com_x=last_1x
last_com_y=last_1y

while 1:

#스위치 값이 0이라 조이스틱 값 전송
if GPIO.input(23)==0 :

#조이스틱 값 읽어오기
roll = ReadChannel(roll_ch)
pitch = ReadChannel(pitch_ch)

#알맞은 값으로 변환하기 위한 과정
if roll>510 and roll<530 :
roll = 520
elif roll>1020:
roll = 1020
elif roll<3:
roll = 3

roll_last = (((roll-520)-10)/16.3)
if roll_last<10 and roll_last>-10:
roll_last = 0
if roll_last>0 :
roll_last += 10
if roll_last<0 :
roll_last -= 10

if pitch>530 :
pitch = 520
elif pitch<3 :
pitch = 3

pitch_last = -(((pitch-520)-10)/16.3)
if pitch_last<5 :
pitch_last = 0
if pitch_last>10 :
pitch_last += 10

#알맞은 값으로 변환하기 위한 과정

#전송
send(roll_last,pitch_last)
print “roll:”,roll_last
print “pitch:”,pitch_last
time.sleep(0.3)

#스위치 값이 1이라 자이로, 가속도 값 전송
elif GPIO.input(23)==1 :

#COMPLEMENTARY FILTER 함수적용
com()
xro=last_com_x
yro=last_com_y

#전송
send(xro,yro)
print “xro:”,xro
print “yro:”,yro
time.sleep(0.3)

② 보트

#필요한 라이브러리
from Tkinter import*
import RPi.GPIO as GPIO
from RPIO import PWM
import time
import math
import string
import socket
import smbus

#UDP 통신을 위한 선언
UDP_IP =”192.168.59.152”
UDP_PORT = 5005
sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock1.bind((UDP_IP, UDP_PORT))
bus = smbus.SMBus(1)
address = 0×68
bus.write_byte_data(address, power_mgmt_1, 0)
#자이로, 가속도 센서 사용위해 정의 및 필요함수

#전송값 초기화
xro=0
yro=0

#자이로, 가속도 센서을 사용위해 정의 및 필요함수
power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c

def read_byte(adr):
return bus.read_byte_data(address, adr)
def read_word(adr):
high = bus.read_byte_data(address, adr)
low = bus.read_byte_data(address, adr+1)
val = (high << 8) + low
return val
def read_word_2c(adr):
val = read_word(adr)
if (val >= 0×8000):
return -((65535 – val) + 1)
else:
return val
def dist(a,b):
return math.sqrt((a*a)+(b*b))
def get_y_rotation(x,y,z):
radians = math.atan2(x, dist(y,z))
return -math.degrees(radians)
def get_x_rotation(x,y,z):
radians = math.atan2(y, dist(x,z))
return math.degrees(radians)

####모터 동작을 위한 함수####
#모터가 돌지 않는 경우
def STOP():
PWM.Servo().set_servo(motor_1,1000)
PWM.Servo().set_servo(motor_2,1000)

#방향 회전없이 앞으로만 가는 경우
def STRAIGHT(a) :
a=a//1
a=1400+(10*a)
PWM.Servo().set_servo(motor_1,a)
PWM.Servo().set_servo(motor_2,a)

#제자리 회전을 위한 경우
def S_TURN(a) :
if a==1:
PWM.Servo().set_servo(motor_1,1200)
PWM.Servo().set_servo(motor_2,1800)
elif a==2:
PWM.Servo().set_servo(motor_1,1800)
PWM.Servo().set_servo(motor_2,1200)

#앞으로 가면서 방향 회전을 하는 경우
def R_L_TURN(a,b) :
a=a//1
b=b//1
b=1400+(10*b)
if a<-10:
a=a*10
PWM.Servo().set_servo(motor_1,b)
PWM.Servo().set_servo(motor_2,b+a)
elif a>10:
a=a*10
PWM.Servo().set_servo(motor_1,b-a)
PWM.Servo().set_servo(motor_2,b)

#전체 모터 제어 함수
def ACTION(xro,yro):
if yro <=10 and xro<10 and xro>-10 :
STOP()
elif yro <=10 and xro>40 :
S_TURN(1)
elif yro <=10 and xro<-40 :
S_TURN(2)
elif yro>10 and yro<=50 and xro<10 and xro>-10 :
STRAIGHT(yro)
elif yro>10 and yro<=50 :
R_L_TURN(xro,yro)
while 1:

#가속도 값 z값을 읽어옴
accel_zout = read_word_2c(0x3f)
print “accel_zout: “, accel_zout

#읽어온 가속도 z값으로 모터 핀 번호 변경
if accel_zout>15000:
motor_1=4
motor_2=18
elif accel_zout<=15000:
motor_1=18
motor_2=4

#조종 라즈베리파이가 보낸 값을 받아옴
for i in range(1,2):
data, addr = sock1.recvfrom(1024)
if data[0]==’a’:
xro = string.atof(data[1:])
elif data[0]==’b’:
yro = string.atof(data[1:])
print(“x_rotation=%f\t” %(xro))
print(“y_rotation=%f\t” %(yro))

#받아온 값으로 부터 모터 제어실행
ACTION(xro,yro)

기대효과
해양 정찰을 할 경우 암초, 바다의 포식자, 혹은 위험 물질로 인해 갈 수 없는 곳은 사람을 대신해 배로 정찰이 가능하다. 특히 해초가 많은 곳에서 일반적인 RC보트나 배로는 모터에 해초가 감겨서 쉽게 고장날 수 있다. 이런 장소들을 ‘로꾸꺼 보트’는 모터 위치가 물 위에 있기 때문에 고장의 염려없이 갈 수 있다. 수시로 보트들이 돌아가면서 충전하고 정찰하는 시스템을 구축해 놓아 녹조·적조 현상을 감지하여 빠른 조치가 가능하고 지속적인 해양기후 탐지를 통해 배들의 안전한 운항이 가능하다.
다리를 지을 때 육지에서는 교량을 만드는 부분을 모든 각도에서 볼 수 없기 때문에 사람이 보기 힘든 각도에서 촬영하여 사람들이 쉽게 분석할 수 있도록 한다. 강물의 폭이 넓어지고 깊이가 깊어지면 수질 검사나 생태계 조사를 위해서 배를 타고 가서 조사를 하는 번거로움이 있다. 수심이 얕을 경우에도 물의 오염 정도가 심각할 경우에는 사람이 직접 들어가기 보다는 ‘로꾸꺼 보트’를 이용해 수질 검사 및 생태계 조사가 가능하다.

참고문헌
· 파이썬 UDP 프로젝트 : wiki.python.org/moin/UdpCommunication
· 파이썬 참조 : www.python.org/
· 라즈베리파이 공식 홈페이지 : www.raspberrypi.org
· jpeg 공식 홈페이지 : https://jpeg.org/

회로도

① 컨트롤러

38 ict 로꾸꺼 (19)
② 보트

38 ict 로꾸꺼 (20)