<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>NTREXGO - 디바이스마트, 엔티렉스 컨텐츠 통합 사이트 &#187; 최우수상</title>
	<atom:link href="http://www.ntrexgo.com/archives/tag/%ec%b5%9c%ec%9a%b0%ec%88%98%ec%83%81/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ntrexgo.com</link>
	<description>엔티렉스, 디바이스마트 컨텐츠 통합 사이트</description>
	<lastBuildDate>Thu, 03 Mar 2022 06:47:11 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>[67호]메타버스를 이용한 문서 보안 시스템</title>
		<link>http://www.ntrexgo.com/archives/40440</link>
		<comments>http://www.ntrexgo.com/archives/40440#comments</comments>
		<pubDate>Wed, 25 Aug 2021 00:00:35 +0000</pubDate>
		<dc:creator>디바이스마트 매거진</dc:creator>
				<category><![CDATA[디바이스마트 매거진]]></category>
		<category><![CDATA[특집]]></category>
		<category><![CDATA[ict]]></category>
		<category><![CDATA[공모전]]></category>
		<category><![CDATA[디바이스마트]]></category>
		<category><![CDATA[매거진]]></category>
		<category><![CDATA[메타버스]]></category>
		<category><![CDATA[문서보안]]></category>
		<category><![CDATA[시스템]]></category>
		<category><![CDATA[융합]]></category>
		<category><![CDATA[최우수상]]></category>
		<category><![CDATA[프로젝트]]></category>

		<guid isPermaLink="false">http://www.ntrexgo.com/?p=40440</guid>
		<description><![CDATA[디바이스마트매거진 67호 &#124; 더욱 함양된 보안성을 갖춘 문서 보안 시스템을 구축하기 위해 메타버스를 이용해보기로 했다. 메타버스를 이용한 보안 시스템의 취약성은 아직 발견된 것이 없으며, 컴퓨터와 휴대폰 두 개의 디바이스를 이용하여 보안 시스템을 구축하기 때문에 더 높은 보안 장벽을 갖는다는 장점이 있다. ]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-1.png" rel="lightbox[40440]"><img alt="67 ict_ 최우수상 메타버스 (1)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-1-620x203.png" width="620" height="203" /></a></p>
<p><span style="color: #ff6600;font-size: medium"><strong>2021 ICT 융합 프로젝트 공모전 최우수상</strong></span></p>
<p><span style="font-size: x-large"><strong>메타버스를 이용한 문서 보안 시스템</strong></span></p>
<p style="text-align: right">글 | 광운대학교 최예지, 최혁순</p>
<p>&nbsp;</p>
<p><span style="color: #0000ff"><strong>1.심사평</strong></span><br />
<strong>칩센</strong> 우선 Leap Motion과 unity을 통한 가상현실을 이용하는 것이 실제로는 처음 보고, 매우 흥미로웠습니다. 일반적인 실제 사용의 단계라면 어쩌면 번거로울 수도 있겠으나, 작품의 기획 의도인 강화된 보안이 필요한 경우에는 매우 유용한 기술로 판단됩니다. 다단계의 보안 단계를 만들고, AWS를 이용하여 떨어져 있는 다중의 사용자들 간에 보안 적용된 특정 정보 (작품에서는 문서)의 접근 권한을 만들어주는 것 또한 익숙하지 않은 저에게는 매우 놀라웠습니다. 세부적인 기술 내역에 대하여 저도 검토해봐야겠다는 생각이 드는 작품입니다. 다만 소프트웨어적인 구현만으로 이루어진 점은 개인적으로 조금 아쉽고, 동일한 보안 해제 방식을 통해 특정 목적을 가진 기기를 컨트롤할 수 있는 형태라면 기술의 범위가 충분히 확장될 수 있지 않을까 합니다.</p>
<p><strong>펌테크</strong> 날로 중요시되는 컴퓨터 보안에 메타버스 개념을 접목한 독창적이고 색다른 형태의 작품으로 핵심요소인 소프트웨어 개발에 따른 각각의 SDK, 개발툴 등을 작품의 성격에 맞게 효율적으로 구성하였으며 전체적으로 작품의 기획의도, 기술 구현도, 완성도 등에서 우수한 작품이라고 생각됩니다.</p>
<p><strong>위드로봇</strong> Leap motion을 이용한 제스처로 보안을 처리한 아이디어가 돋보이는 작품입니다. 공모전의 성격을 감안하여 LeapMotion을 대치할 수 있는 기술까지 같이 연구가 진행되었다면 더욱 훌륭한 연구가 되었을 것 같습니다.</p>
<p><strong>뉴티씨</strong> 매우 독특한 발상으로 잘 만들어진 작품입니다. 스마트폰에만 의존하는 보안 시스템에서 발전하여 Cloud server를 활용하여 보다 높은 수준의 보안 시스템을 구현한 예가 될 수 있습니다. 작품의 모양이나 시스템의 표현 방법이나 사용 방법 등을 대폭 개선하면, 좋은 제품으로 탄생할 수도 있을 것 같습니다. 아파트 현관이나 특정 사무실의 보안 시스템도 그런 식으로 만드는 것도 방법인 것 같습니다. 앞으로 기대가 됩니다.</p>
<p><span style="color: #0000ff"><strong>2. 작품 개요</strong></span><br />
개인 휴대폰을 이용한 문서 공유, 개인 정보 저장, 신상 정보를 이용한 거래 등의 서비스들이 늘어나고 있다. 등본이나 각종 증명서, 회사 기업 자료 등 중요한 문서 파일을 휴대폰에 저장하기도 하고, 회원가입 정보나 여러 사이트의 비밀번호, 개인 정보를 휴대폰에 저장하기도 하며, 인터넷 뱅킹, 휴대폰 결제와 같은 개인정보를 이용한 서비스들을 휴대폰을 통해 사용한다. 이러한 휴대폰 속 개인정보를 이용한 서비스들과 휴대폰에 저장하는 개인정보, 주요 문서들이 늘어남에 따라 이를 악용한 범죄 또한 늘어나고 있다. 이러한 범죄에 우리가 노출됨에 있어 가장 큰 문제는 오직 핸드폰의 보안에만 의존하고 있다는 점이다. 휴대폰에 저장된 대부분의 주요 문서나 개인 정보가 오직 핸드폰의 보안 또는 어플 자체의 보안에만 의존하고 있다. 우리는 이러한 문제점을 인식하고 더욱 함양된 보안성을 갖춘 문서 보안 시스템을 구축하기 위해 메타버스를 이용해보기로 했다. 메타버스를 이용한 보안 시스템의 취약성은 아직 발견된 것이 없으며, 컴퓨터와 휴대폰 두 개의 디바이스를 이용하여 보안 시스템을 구축하기 때문에 더 높은 보안 장벽을 갖는다는 장점이 있다. 이러한 장점을 가진 메타버스 중 우리는 Leap Motion과 Unity를 이용해 시스템을 구축하기로 했다. Leap Motion은 손의 움직임을 인식하는 장치로 이를 이용하면 오직 손의 움직임만을 이용하여 잠금을 해제하는 보안장치를 만들 수 있기 때문에 잠금을 해제하는 기록을 데이터로 남기기 어려워 보안에 유리하다. 또한 Unity를 이용한 3D 가상현실을 만들어 여기에 Leap Motion을 적용한다면, 보안 장치를 사용하는 사용자가 아닌 이상 보안 장치 해제 방식을 파악하기 어려워 보안에 유리하다. 우리는 이러한 장점을 이용하여 Leap Motion, Unity를 이용한 메타버스 문서 보안 시스템을 제작하기로 했다.</p>
<p><span style="color: #0000ff"><strong>3. 작품 설명</strong></span><br />
<span style="color: #33cccc"><strong>3.1. 주요 동작 및 특징</strong></span><br />
시스템은 Leap Motion을 이용한 1차 보안과 Unity와 앱을 이용한 2차 보안, 1차 보안과 2차 보안 사이의 서버 통신으로 이루어져 있다.<br />
Leap Motion을 이용해 손의 동작을 감지하고 정해진 동작이 수행되면 웹 서버인 AWS DynamoDB로 동작이 수행됨을 알리는 정보가 넘어간다. 서버 통신을 통해 Leap Motion을 이용한 1차 보안이 해제됨을 감지한 AWS DynamoDB는 이 정보를 핸드폰에 설치된 어플로 넘긴다. 어플에서 정보를 받으면 Unity와 앱을 이용한 2차 보안이 실행되고, 2차 보안에서 정해진 순서대로 번호를 터치하게 되면 문서의 잠금이 해제된다.</p>
<p><span style="color: #993366"><strong>Leap Motion을 이용한 1차 보안</strong></span><br />
Leap Motion에 정해진 동작을 수행하면 그 동작에 해당하는 마법진이 생성되고, 정해진 손짓을 통해 생성된 마법진을 뒤로 보낼 수 있다. 정해진 동작을 순서대로 수행하면 그 동작에 해당하는 4종류의 마법진이 순서대로 생성되고, 이 4종류의 마법진을 정해진 손짓을 통해 순서대로 뒤로 보내 circle에 통과시키면 보안이 해제된다. 이때 4종류의 마법진을 정해진 순서대로 circle에 통과시키지 않으면 보안 잠금이 해제되지 않는다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-2.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40500" alt="67 ict_ 최우수상 메타버스 (2)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-2.png" width="500" height="322" /></a></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p><strong>[코드 가-1] 위 사진에 해당하는 코드</strong></p>
<p>if ((frame.Hands[1].GrabStrength == 1.0) &amp;&amp; (frame.Hands[1].PinchStrength == 1.0)) //왼손 grab 후 pinch<br />
{<br />
count += 1;<br />
if (count &gt; 3)<br />
count = 0;<br />
}<br />
if (count == 0)<br />
{<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0) //왼손, 오른손 손가락 pinch<br />
{<br />
fstone.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; fstone.state == 1) //윗줄 후 왼손, 오른손 no pinch<br />
{<br />
GameObject realplz = Instantiate(fstobj) as GameObject; // 첫 번째 오브젝트 생성</p>
<p>realplz.transform.position = new Vector3(0, 0.5f,0.5f);<br />
fstone.state = 0;<br />
}<br />
}<br />
</div>
<p>그림 가-1과 같이 양 손을 pinch 후 떼어내면 마법진이 생성된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-3.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40501" alt="67 ict_ 최우수상 메타버스 (3)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-3.png" width="497" height="616" /></a></p>
<p>&nbsp;</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p><strong>[코드 가-2] 위 사진에 해당하는 코드 </strong></p>
<p>if ((frame.Hands[1].GrabStrength == 1.0) &amp;&amp; (frame.Hands[1].PinchStrength == 1.0)) //왼손 grab 후 pinch{<br />
count += 1;<br />
if (count &gt; 3)<br />
count = 0;<br />
}<br />
if (count == 0){<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0) //왼손, 오른손 손가락 pinch{<br />
fstone.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; fstone.state == 1) //윗줄 후 왼손, 오른손 no pinch{<br />
GameObject realplz = Instantiate(fstobj) as GameObject; // 첫 번째 오브젝트 생성<br />
realplz.transform.position = new Vector3(0, 0.5f,0.5f);<br />
fstone.state = 0;<br />
}<br />
}<br />
else if (count == 1){<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0) //왼손, 오른손 pinch{<br />
second.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; second.state == 1) //윗 줄 후 왼손, 오른손 no pinch{<br />
GameObject realplz = Instantiate(scdobj) as GameObject; //두 번째 오브젝트 생성<br />
realplz.transform.position = new Vector3(0, 0.5f, 0.5f);<br />
second.state = 0;<br />
}<br />
}<br />
else if (count == 2)<br />
{<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0) //왼손, 오른손 pinch{<br />
third.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; third.state == 1) //윗 줄 후 왼손, 오른손 no pinch{<br />
GameObject realplz = Instantiate(thdobj) as GameObject; //세 번째 오브젝트 생성<br />
realplz.transform.position = new Vector3(0, 0.5f, 0.5f);<br />
third.state = 0;<br />
}<br />
else if (count == 3)<br />
{<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0) //왼손, 오른손 pinch{<br />
fourth.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; fourth.state == 1) //윗 줄 후 왼손, 오른손 no pinch{<br />
GameObject realplz = Instantiate(fthobj) as GameObject; //네 번째 오브젝트 생성<br />
realplz.transform.position = new Vector3(0, 0.5f, 0.5f);<br />
fourth.state = 0;<br />
}<br />
}<br />
</div>
<p>왼손 grab 후 오른손 pinch 한 번 할 때마다 object, 즉 마법진이 변경된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-4.png" rel="lightbox[40440]"><img class="alignnone size-large wp-image-40502" alt="67 ict_ 최우수상 메타버스 (4)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-4-481x620.png" width="481" height="620" /></a></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p><strong>[코드 가-3] 위 사진에 해당하는 코드</strong></p>
<p>if (HandPalmYam &gt; -2f &amp;&amp; HandPalmYam &lt; 3.5f &amp;&amp; (frame.Hands[1].GrabStrength==1.0 )) //왼손 grab 후 오른손 흔듦{<br />
Debug.Log(&#8220;앞&#8221;);<br />
this.transform.Translate(0, 2 * Time.deltaTime,0); //오브젝트 앞으로 이동<br />
}<br />
if ((frame.Hands[1].GrabStrength == 1.0) &amp;&amp; (frame.Hands[0].GrabStrength == 1.0)) //양손 grab<br />
Destroy(gameObject); //오브젝트 사라짐<br />
</div>
<p>&nbsp;</p>
<p>왼손 grab 후 오른손 흔들면 object, 즉 마법진이 앞으로 이동하다가 circle에 닿으면 사라지게 된다. 이때, 마법진 4종류가 정해진 순서대로 circle에 닿아야만 잠금이 해제된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-5.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40503" alt="67 ict_ 최우수상 메타버스 (5)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-5.png" width="498" height="295" /></a></p>
<p>Object, 즉 마법진은 계속해서 회전하고 있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-7.png" rel="lightbox[40440]"><img class="alignnone size-large wp-image-40505" alt="67 ict_ 최우수상 메타버스 (7)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-7-620x98.png" width="620" height="98" /></a></p>
<p>코드 가-5에 의해 object, 즉 마법진이 circle에 닿으면 사라지게 된다. 또한 4종류의 마법진이 정해진 순서대로 circle에 닿아야만 보안이 해제된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-8.png" rel="lightbox[40440]"><img class="alignnone size-large wp-image-40506" alt="67 ict_ 최우수상 메타버스 (8)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-8-620x206.png" width="620" height="206" /></a></p>
<p><span style="color: #993366"><strong>1차 보안과 2차 보안 사이의 서버 통신</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-9.png" rel="lightbox[40440]"><img class="alignnone size-large wp-image-40507" alt="67 ict_ 최우수상 메타버스 (9)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-9-620x396.png" width="620" height="396" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-10.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40508" alt="67 ict_ 최우수상 메타버스 (10)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-10.png" width="559" height="356" /></a></p>
<p>Leap Motion을 이용한 1차 보안이 해제됨을 알리는 정보가 AWS DynamoDB로 넘어간다. AWS DynamoDB는 받은 정보를 다시 2차 보안에 사용되는 앱에 넘기고, 앱은 정보를 받으면 보안 해제 시스템이 작동된다. 2차 보안 앱은 1차 보안이 해제되기 전까지는 실행되지 않고, 로딩창에 머무르게 된다. 1차 보안이 해제되었다는 정보를 넘겨받아야 실행이 되는 구조이다.<br />
[그림 나-2]는 DynamoDB에서 leapmotion의 데이터가 초기설정 값인 0000이었지만, 1차 보안을 해제한 후 1234로 바뀐 모습이다.<br />
private void Start() //AWS에서 계정에 대한 인증과 권한을 부여받는 코드이다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>{<br />
UnityInitializer.AttachToGameObject(this.gameObject);<br />
credentials = new CognitoAWSCredentials(&#8220;ap-northeast-2:ceafc145-14a2-4c03-b397-22368bc8ab4f&#8221;, RegionEndpoint.APNortheast2);<br />
DBclient = new AmazonDynamoDBClient(credentials, RegionEndpoint.APNortheast2);<br />
context = new DynamoDBContext(DBclient);<br />
}</p>
[DynamoDBTable("character_info")]
public class Character<br />
{<br />
[DynamoDBHashKey] // Hash key.<br />
public string id { get; set; }<br />
[DynamoDBProperty]
public int item { get; set; }<br />
}</p>
<p>public void FindItem() //DB에서 캐릭터 정보 받기<br />
{<br />
context.LoadAsync&lt;Character&gt;(&#8220;leapmotion&#8221;, (AmazonDynamoDBResult&lt;Character&gt; result) =&gt;<br />
{<br />
// id가 leapmotion인 캐릭터 정보를 DB에서 받아옴<br />
if (result.Exception != null)<br />
{<br />
Debug.LogException(result.Exception);<br />
// 정보를 받아오지 못했을 때의 예외처리</p>
<p>return;<br />
}<br />
c = result.Result;<br />
Debug.Log(c.item); //찾은 캐릭터 정보 중 아이템 정보 출력<br />
}, null);<br />
}</p>
<p>void Update()<br />
{</p>
<p>FindItem();<br />
if (c!=null) //앱 실행 후 초기화되는 aws에서 정보를 받아오는 변수이므로 받아온 정보가 null값인지를 먼저 확인한다.<br />
{<br />
if (c.item == 1234)<br />
{<br />
GameObject.Destroy(this.gameObject);<br />
SceneManager.LoadScene(&#8220;realA&#8221;);<br />
}<br />
}<br />
</div>
사용자가 4번에 걸쳐서 원을 서클에 통과시키면, 4개의 원이 지정된 패턴과 일치하는지를 판별 후, 맞다면 AWS에 접속하여 DynamoDB의 leapmotion이라는 데이터의 값을 1234로 변경해준다.</p>
<p><span style="color: #993366"><strong>Unity와 앱을 이용한 2차 보안</strong></span><br />
AWS DynamoDB로 전달된 1차 보안이 해제됨을 알리는 정보는 만들어둔 핸드폰에 전달된다. 정보를 받은 핸드폰은 앱을 실행시킨다. 실행된 앱에서 정해진 물체에 카메라를 가져가면 키패드가 생성되고, 생성된 키패드에 비밀번호를 순서대로 입력하면 2차 보안이 해제되어 문서를 열람할 수 있게 된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-11.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40509" alt="67 ict_ 최우수상 메타버스 (11)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-11.png" width="580" height="433" /></a></p>
<p>AR 키패드 화면으로 넘어왔지만, 지정된 물체를 비추지 않아, 키패드가 나타나지 않는 모습이다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-12.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40510" alt="67 ict_ 최우수상 메타버스 (12)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-12.png" width="574" height="414" /></a><br />
지정된 물체를 비추고 나서, 키패드가 나타나는 모습이다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>if (count == 4) //사용자가 키패드를 누른 횟수를 센다<br />
{<br />
Debug.Log(&#8220;full&#8221;);<br />
for (int i = 0; i &lt; 4; i++)<br />
{<br />
if (answer[i] != realanswer[i]) //입력 비밀번호랑 정답 비밀번호랑 비교<br />
{<br />
SceneManager.LoadScene(&#8220;retry&#8221;);<br />
break;<br />
}</p>
</div>
기본적으로 앱은 AWS와 계속해서 통신을 하고 DynamoDB의 leapmotion 데이터의 값을 반복해서 불러들이는 작업을 하고, 받아온 값이 최초 설정값인 0000이 아닌 1234일 때, 씬을 변경하여 앱을 실행시키는 역할을 한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-13.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40511" alt="67 ict_ 최우수상 메타버스 (13)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-13.png" width="579" height="399" /></a></p>
<p><span style="color: #33cccc"><strong>3.2. 전체 시스템 구성</strong></span><br />
위 시스템은 Leap Motion을 이용한 1차 보안과 Unity와 앱을 이용한 2차 보안, 1차 보안과 2차 보안 사이의 서버 통신으로 이루어져 있다.<br />
Leap Motion을 이용해 손의 동작을 감지하고 정해진 동작이 수행되면 웹 서버인 AWS DynamoDB로 동작이 수행됨을 알리는 정보가 넘어간다. 서버 통신을 통해 Leap Motion을 이용한 1차 보안이 해제됨을 감지한 AWS DynamoDB는 이 정보를 핸드폰에 설치된 어플로 넘긴다. 어플에서 정보를 받으면 Unity와 앱을 이용한 2차 보안이 실행되고, 2차 보안 앱에서 지정된 물체를 비추게 되면 키패드가 나타나고, 키패드에 비밀번호를 입력하게 되면 2차 보안이 해제되면서 문서의 잠금이 해제된다. 따라서 키패드를 거치기 전, 지정된 물체를 알고 있어야 하고, 그것을 비추어야만 비밀번호를 입력할 수 있다는 점에서 2차 보안 속에 한 단계의 보조 보안단계가 더 있다고 볼 수 있다.</p>
<p><span style="color: #33cccc"><strong>3.3. 개발 환경</strong></span><br />
위 시스템은 Leap Motion을 이용한 1차 보안과 Unity와 앱을 이용한 2차 보안, 1차 보안과 2차 보안 사이의 서버 통신으로 이루어져 있다. 먼저 Leap Motion을 이용한 1차 보안에서 Leap Motion과 Unity를 이용하며, 이를 위해 Leap Motion SDK와 개발 Tool로 Unity 2D, Unity 3D를 사용하였다. 또한 Unity 개발 언어로 C#을 이용하였으며 3D 가상 현실 환경을 구축하기 위해 Asset store를 사용하였다. 또한 개발 언어를 위한 Tool로 Visual Studio를 사용하였다. 다음으로 1차 보안과 2차 보안 사이의 서버 통신을 위한 시스템으로 AWS와 DynamoDB를 사용하였다. 마지막으로 App과 Unity를 이용한 2차 보안에서 App 개발과 보안 환경 구축을 위해 개발 Tool로 Unity 2D, Unity 3D를 사용하였다. 또한 Unity 개발 언어로 C#을 이용하였으며 3D 가상 현실 환경을 구축하기 위해 Asset store와 Vuforia를 사용하였다. 또한 개발 언어를 위한 Tool로 Visual Studio를 사용하였다.</p>
<p><strong><span style="color: #993366">Leap Motion을 이용한 1차 보안</span></strong><br />
생체 움직임 감지를 위해 Leap Motion을 사용하였으며, Leap Motion을 사용하기 위해 Leap Motion SDK를 사용하였다. Leap Motion 이용을 위한 증강 현실을 구현하기 위한 개발 Tool로 Unity 2D와 Unity 3D를 사용하였으며, Unity 개발 언어로 C#을 사용하고, 개발 언어를 사용하기 위한 Tool로 Visual Studio를 사용하였다. 3D 증강 현실 구현을 위해 Asset Store를 사용하였으며, AR엔진으로 Vuforia를 이용하였다.</p>
<p><span style="color: #993366"><strong>1차 보안과 2차 보안 사이의 서버 통신</strong></span><br />
1차 보안에서의 정보를 서버로 옮기고, 서버에 저장된 정보를 다시 휴대폰 앱으로 전송하기 위한 웹 서버를 구축하였다. 이때 AWS를 사용하여 웹서버를 구축하였다. 웹 서버로 통신한 정보를 저장하기 위해 DynamoDB를 데이터베이스로 사용하였다.</p>
<p><span style="color: #993366"><strong>Unity와 App을 이용한 2차 보안</strong></span><br />
증강 현실을 이용한 App 개발을 위한 개발 Tool로 Unity 2D와 Unity 3D를 사용하였으며, Unity 개발 언어로 C#을 사용하고, IDE로 Visual Studio를 사용하였다. 3D 증강 현실 구현을 위해 Asset Store를 사용하였으며, AR엔진으로 Vuforia를 이용하였다.</p>
<p><span style="color: #0000ff"><strong>4. 단계별 제작 과정</strong></span><br />
시스템은 ‘Leap Motion을 이용한 1차 보안’과 ‘Unity와 앱을 이용한 2차 보안’, ‘1차 보안과 2차 보안 사이의 서버 통신’으로 단계를 나누어 제작하였다.</p>
<p><span style="color: #33cccc"><strong>4.1. Leap Motion을 이용한 1차 보안</strong></span><br />
이 단계에서는 먼저 Leap Motion을 Unity와 연동시킨 뒤 Leap Motion의 동작 인식 감도를 확인하였다. 이후 Unity를 이용해 Leap Motion을 이용하기 위한 3D 가상 현실과 보안 시스템을 구축하였고, 가상 현실과 보안 시스템을 제어하기 위한 코드를 작성하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-1.jpg" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40498" alt="67 ict_ 최우수상 메타버스 (1)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-1.jpg" width="567" height="401" /></a></p>
<p>그림 4-1-1과 같이 Leap Motion을 이용하기에 앞서 Leap Motion을 Unity에 연동시키고, Unity에서의 Leap Motion 작동 여부와 실제 작동 환경을 테스트하였다. 이후 Leap Motion의 손동작 인식 감도를 확인하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-14.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40512" alt="67 ict_ 최우수상 메타버스 (14)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-14.png" width="569" height="380" /></a><br />
다음으로 그림 4-4-2와 같이 Leap Motion이 사용되는 가상 현실을 Unity를 통해 구축하였다. 배경과 바닥을 3D object와 asset을 이용하여 구현했으며, 손동작에 따라 생성되고 작동될 3D object를 만들었다. 마지막으로 코드 3-1-가-1,2,3,4,5와 같이 Leap Motion에 감지된 동작에 따라 실행될 기능에 대해 코드를 작성하였다. 왼손 grab 후에 pinch 한 번 할 때마다 object가 바뀌고, 양손을 pinch 후에 떼면 object가 생성되는 코드, 왼손 grab 후 오른손을 흔들면 object가 앞으로 이동하는 코드, 양손 grab시에 object가 사라지는 코드, object가 회전하는 코드, object가 circle에 닿으면 사라지는 코드, object가 정해진 순서대로 circle에 닿으면 그 정보를 관리자 object에 전달하는 코드를 작성하였다.</p>
<p><span style="color: #33cccc"><strong>4.2. 1차 보안과 2차 보안 사이의 서버 통신</strong></span><br />
이 단계에서는 먼저 1차 보안을 담당하는 노트북과 2차 보안을 담당하는 핸드폰 App사이의 서버 통신을 위한 웹서버를 구축하였다. 이후 노트북의 정보가 구축한 웹서버로 전달되는지 여부를 확인하였다. 다음으로 웹서버에 저장된 데이터 베이스가 휴대폰 App으로 전달되는지 여부를 확인하였다. 마지막으로 1차 보안이 해제됨을 알리는 정보를 웹 서버에 전달하고 웹 서버는 이를 데이터 베이스에 저장하여 2차 보안을 담당하는 휴대폰 App으로 전달하는 코드를 작성하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-15.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40513" alt="67 ict_ 최우수상 메타버스 (15)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-15.png" width="571" height="297" /></a></p>
<p>그림 4-2-1과 같이 웹서버를 구축하였다. DynamoDB에 leapmotion 데이터가 저장되어 있는 모습을 볼 수 있다.</p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-16.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40514" alt="67 ict_ 최우수상 메타버스 (16)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-16.png" width="569" height="112" /></a></p>
<p>그림 4-2-2와 같이 1차 보안과 웹 서버 사이의 서버 통신이 원활하게 이루어지는지 확인하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-17.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40515" alt="67 ict_ 최우수상 메타버스 (17)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-17.png" width="568" height="108" /></a></p>
<p>그림 4-2-3과 같이 웹 서버에 저장된 데이터 베이스가 2차 보안을 담당하는 휴대폰 App으로 잘 전달되는지 여부를 확인하였다. DynamoDB의 데이터 leapmotion의 정보를 잘 받았는지 확인하는 콘솔로그 창이다.<br />
코드 4-2-1과 같이 1차 보안이 해제됨을 알리는 정보를 웹 서버에 전달하고 웹 서버는 이를 데이터 베이스에 저장하여 2차 보안을 담당하는 휴대폰 App으로 전달하는 코드를 작성하였다.</p>
<p><span style="color: #00ccff"><strong>4.3. Unity와 App을 이용한 2차 보안</strong></span><br />
이 단계에서는 노트북에서 Unity를 이용하여 2차 보안의 가상 현실을 만든 뒤, 순서대로 정해진 비밀번호를 입력하면 문서 보안이 해제되는 코드를 작성하였다. 이후 제작한 App을 휴대폰에 복제하였다. 마지막으로 제작한 App이 구축한 웹 서버를 통해 1차 보안이 해제됨을 알리는 데이터 베이스를 전달하면 App이 실행되도록 하는 코드를 작성하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-18.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40516" alt="67 ict_ 최우수상 메타버스 (18)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-18.png" width="566" height="368" /></a></p>
<p>그림 4-3-1과 같이 Unity를 이용하여 2차 보안에 사용할 가상 현실을 제작했다.<br />
그림 4-3-2와 같이 앞서 노트북으로 만든 App을 휴대폰에 빌드하여 휴대폰으로 App이용이 가능하게 만들었다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-19.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40517" alt="67 ict_ 최우수상 메타버스 (19)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-19.png" width="283" height="350" /></a></p>
<p><strong> <span style="color: #0000ff">5. 사용한 제품 리스트</span></strong></p>
<p>‘Leap Motion을 이용한 1차 보안’과 ‘Unity와 앱을 이용한 2차 보안’, ‘1차 보안과 2차 보안 사이의 서버 통신’으로 나누어져 있다. 이 중 Leap Motion을 이용한 1차 보안 단계에서 Leap Motion Controller제품을 사용하였다.</p>
<p><span style="color: #0000ff"><strong>6. 회로도</strong></span><br />
작품의 전체 회로도는 그림 6-1과 같다. Leap Motion과 노트북이 1차 보안을 위해 연결되어 있으며, 2차 보안인 휴대폰 App과 웹 서버를 통해 연결되어 있다.</p>
<p><del><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-20.png" rel="lightbox[40440]"><img class="alignnone size-full wp-image-40518" alt="67 ict_ 최우수상 메타버스 (20)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict_-최우수상-메타버스-20.png" width="564" height="269" /></a></del></p>
<p><span style="color: #0000ff"><strong>7. 소스코드</strong></span><br />
<span style="color: #33cccc"><strong>7.1. Leap Motion을 이용한 1차 보안 코드</strong></span><br />
<span style="color: #993366"><strong>Leap Motion Hand model 코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>void Update(){<br />
controller = new Controller();<br />
Frame frame = controller.Frame();<br />
List&lt;Hand&gt; hands = frame.Hands;<br />
Frame previous = controller.Frame(1);<br />
Hand previous_leapHand = previous.Hands[0];<br />
Vector handOrigin = frame.Hands[0].PalmPosition;<br />
Vector previoushandOrigin = previous_leapHand.PalmPosition;<br />
if ((frame.Hands[1].GrabStrength == 1.0) &amp;&amp; (frame.Hands[1].PinchStrength == 1.0)){<br />
count += 1;<br />
if (count &gt; 3)<br />
count = 0;<br />
}<br />
if (count == 0) {<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0)<br />
{<br />
fstone.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; fstone.state == 1) {<br />
GameObject realplz = Instantiate(fstobj) as GameObject;</p>
<p>realplz.transform.position = new Vector3(0, 0.5f,0.5f);<br />
fstone.state = 0;<br />
}<br />
}<br />
else if (count == 1){<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0){<br />
second.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; second.state == 1){<br />
GameObject realplz = Instantiate(scdobj) as GameObject;</p>
<p>realplz.transform.position = new Vector3(0, 0.5f, 0.5f);<br />
second.state = 0;<br />
}<br />
}<br />
else if (count == 2) {<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0){<br />
third.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; third.state == 1){<br />
GameObject realplz = Instantiate(thdobj) as GameObject;<br />
realplz.transform.position = new Vector3(0, 0.5f, 0.5f);<br />
third.state = 0;<br />
}<br />
else if (count == 3){<br />
if (frame.Hands[0].PinchStrength == 1.0 &amp;&amp; frame.Hands[1].PinchStrength == 1.0){<br />
fourth.state = 1;<br />
}<br />
if (frame.Hands[0].PinchStrength &lt; 1.0 &amp;&amp; frame.Hands[1].PinchStrength &lt; 1.0 &amp;&amp; fourth.state == 1){<br />
GameObject realplz = Instantiate(fthobj) as GameObject;<br />
realplz.transform.position = new Vector3(0, 0.5f, 0.5f);<br />
fourth.state = 0;<br />
}<br />
}<br />
strength1 = frame.Hands[0].GrabStrength;<br />
strength2 = frame.Hands[1].GrabStrength;<br />
Debug.Log(&#8220;왼손??&#8221; + strength2);<br />
Debug.Log(&#8220;오른손??&#8221; + strength1);<br />
}<br />
}<br />
</div>
<p><span style="color: #993366"><strong>Leap Motion New Behavior 코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>Controller controller;<br />
float HandPalmPitch;<br />
float HandPalmRoll;<br />
float HandPalmYam;<br />
float HandWristRot;<br />
Rigidbody rb;<br />
void Start(){<br />
}<br />
void Update(){<br />
controller = new Controller();<br />
Frame frame = controller.Frame();<br />
List&lt;Hand&gt; hands = frame.Hands;<br />
if (frame.Hands.Count &gt; 0){<br />
Hand fristHand = hands[0];<br />
}<br />
HandPalmPitch = hands[0].PalmNormal.Pitch;<br />
HandPalmRoll = hands[0].PalmNormal.Roll;<br />
HandPalmYam = hands[0].PalmNormal.Yaw;<br />
HandWristRot = hands[0].WristPosition.Pitch;<br />
Debug.Log(&#8220;Pitch : &#8221; + HandPalmPitch);<br />
Debug.Log(&#8220;Roll : &#8221; + HandPalmRoll);<br />
Debug.Log(&#8220;Yam : &#8221; + HandPalmYam);<br />
if (HandPalmYam &gt; -2f &amp;&amp; HandPalmYam &lt; 3.5f &amp;&amp; (frame.Hands[1].GrabStrength==1.0 )){<br />
Debug.Log(&#8220;앞&#8221;);<br />
this.transform.Translate(0, 2 * Time.deltaTime,0);<br />
}<br />
this.transform.Rotate(0, 30, 0);<br />
if ((frame.Hands[1].GrabStrength == 1.0) &amp;&amp; (frame.Hands[0].GrabStrength == 1.0))<br />
Destroy(gameObject);<br />
}<br />
}<br />
</div>
<p><span style="color: #993366"><strong>Leap Motion 관리자 object 코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>using System.Collections;<br />
using System.Collections.Generic;<br />
using UnityEngine;<br />
public class c1direc : MonoBehaviour{<br />
GameObject director;<br />
void Start(){<br />
director = GameObject.Find(&#8220;director&#8221;);<br />
}<br />
void Update(){<br />
if (this.transform.position.z &gt; 3){<br />
director.GetComponent&lt;director&gt;().arr[director.GetComponent&lt;director&gt;().ind] = 0;<br />
director.GetComponent&lt;director&gt;().ind += 1;<br />
}<br />
}<br />
}<br />
</div>
<p><span style="color: #33cccc"><strong>7.2. 1차 보안과 2차 보안 사이의 서버 통신 코드</strong></span><br />
<span style="color: #993366"><strong>Leap Motion 서버 통신 director 코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>public class director : MonoBehaviour<br />
{<br />
int count;<br />
public int [] arr = { -1, -1, -1, -1 };<br />
int[] arranswer = { 0, 1, 2, 3 };<br />
DynamoDBContext context;<br />
AmazonDynamoDBClient DBclient;<br />
CognitoAWSCredentials credentials;<br />
Character c;<br />
public Camera a;<br />
private void Start()<br />
{<br />
UnityInitializer.AttachToGameObject(this.gameObject);<br />
credentials = new CognitoAWSCredentials(&#8220;ap-northeast-2:ceafc145-14a2-4c03-b397-22368bc8ab4f&#8221;, RegionEndpoint.APNortheast2);<br />
DBclient = new AmazonDynamoDBClient(credentials, RegionEndpoint.APNortheast2);<br />
context = new DynamoDBContext(DBclient);<br />
}<br />
[DynamoDBTable("character_info")]
public class Character<br />
{<br />
[DynamoDBHashKey] // Hash key.<br />
public string id { get; set; }<br />
[DynamoDBProperty]
public int item { get; set; }<br />
}<br />
private void CreateCharacter() //캐릭터 정보를 DB에 올리기<br />
{<br />
Character c1 = new Character<br />
{<br />
id = &#8220;leapmotion&#8221;,<br />
item = 1234,<br />
};<br />
context.SaveAsync(c1, (result) =&gt;<br />
{<br />
if (result.Exception == null)<br />
Debug.Log(&#8220;Success!&#8221;);<br />
else<br />
Debug.Log(result.Exception);<br />
});<br />
}<br />
void Update() //써클을 통과한 원이 지정된 패턴과 일치하는지 확인 후, 일치하면 서버에 정보를 보냄<br />
{</p>
<p>for(int i = 0; i &lt;= 3; i++)<br />
{<br />
if (arr[i] == arranswer[i])<br />
{<br />
count += 1;<br />
}<br />
else if (arr[i] != arranswer[i])<br />
break;<br />
}<br />
if (count== 4)<br />
{<br />
CreateCharacter();<br />
Debug.Log(&#8220;카운트!!!!!!!!!!!!!!!!!111&#8243;);<br />
}<br />
</div>
<p><span style="color: #33cccc"><strong>7.3. Unity와 App을 이용한 2차 보안 코드</strong></span><br />
<span style="color: #993366"><strong>서버와 통신을 하는 direc코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>private void Start() //AWS에 접속해서 인증받고 권한을 받아오는 단계<br />
{<br />
UnityInitializer.AttachToGameObject(this.gameObject);<br />
credentials = new CognitoAWSCredentials(&#8220;ap-northeast-2:ceafc145-14a2-4c03-b397-22368bc8ab4f&#8221;, RegionEndpoint.APNortheast2);<br />
DBclient = new AmazonDynamoDBClient(credentials, RegionEndpoint.APNortheast2);<br />
context = new DynamoDBContext(DBclient);</p>
<p>}</p>
[DynamoDBTable("character_info")]
public class Character<br />
{<br />
[DynamoDBHashKey] // Hash key.<br />
public string id { get; set; }<br />
[DynamoDBProperty]
public int item { get; set; }<br />
}<br />
public void FindItem() //DB에서 캐릭터 정보 받기<br />
{<br />
context.LoadAsync&lt;Character&gt;(&#8220;leapmotion&#8221;, (AmazonDynamoDBResult&lt;Character&gt; result) =&gt;<br />
{<br />
// id가 leapmotion인 캐릭터 정보를 DB에서 받아옴<br />
if (result.Exception != null)<br />
{<br />
Debug.LogException(result.Exception);<br />
return;<br />
}<br />
c = result.Result;<br />
Debug.Log(c.item); //찾은 캐릭터 정보 중 아이템 정보 출력<br />
}, null);<br />
}<br />
void Update()<br />
{</p>
<p>FindItem();<br />
if (c!=null) //앱 실행 후 초기화되는 aws에서 정보를 받아오는 변수이므로 받아온 정보가 null값인지를 먼저 확인한다.<br />
{<br />
if (c.item == 1234)<br />
{</p>
<p>GameObject.Destroy(this.gameObject);<br />
SceneManager.LoadScene(&#8220;realA&#8221;);<br />
} }}<br />
</div>
<p><span style="color: #993366"><strong>입력한 비밀번호를 확인하는 director 코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>public class director : MonoBehaviour<br />
{<br />
public int[] answer = new int[4] { -1, -1, -1, -1 }; //입력받을 비밀번호를 저장할 배열<br />
int[] realanswer = new int[4] { 2, 1, 3, 0 }; //원래 비밀번호 정답<br />
public int count = 0;<br />
int point = 0;<br />
void Start()<br />
{<br />
a.enabled = true;<br />
iinteraction = GameObject.Find(&#8220;iinteraction&#8221;);<br />
interaction1 = GameObject.Find(&#8220;interaction1&#8243;);<br />
interaction2 = GameObject.Find(&#8220;interaction2&#8243;);<br />
interation3 = GameObject.Find(&#8220;interation3&#8243;);<br />
}<br />
// Update is called once per frame<br />
void Update()<br />
{<br />
Debug.Log(count);<br />
if (count == 4) //네개의 비밀번호를 입력받으면 일치하는 비밀번호인지 확인하는 코드<br />
{<br />
Debug.Log(&#8220;full&#8221;);<br />
for (int i = 0; i &lt; 4; i++)<br />
{<br />
if (answer[i] != realanswer[i])<br />
{<br />
SceneManager.LoadScene(&#8220;retry&#8221;);<br />
break;<br />
}<br />
}<br />
}<br />
if (point ==4)<br />
SceneManager.LoadScene(&#8220;EndScene&#8221;);<br />
}<br />
</div>
<p><span style="color: #993366"><strong>어떤 키패드가 눌렸는지 확인하는 interaction1 코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>void Start()<br />
{ director = GameObject.Find(&#8220;director&#8221;);<br />
mat = GetComponent&lt;Renderer&gt;().material;<br />
mat.SetFloat(&#8220;_Mode&#8221;, 2);<br />
mat.SetInt(&#8220;_SrcBlend&#8221;, (int)UnityEngine.Rendering.BlendMode.SrcAlpha);<br />
mat.SetInt(&#8220;_DstBlend&#8221;, (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);<br />
mat.SetInt(&#8220;_ZWrite&#8221;, 0);<br />
mat.DisableKeyword(&#8220;_ALPHATEST_ON&#8221;);<br />
mat.EnableKeyword(&#8220;_ALPHABLEND_ON&#8221;);<br />
mat.DisableKeyword(&#8220;_ALPHAPREMULTIPLY_ON&#8221;);<br />
mat.renderQueue = 3000;<br />
defaultColor = new Color32(255, 255, 255, 255);<br />
selectedColor = new Color32(255, 0, 0, 255);</p>
<p>mat.color = defaultColor;<br />
}<br />
void Update()<br />
{<br />
if (die == 1)<br />
{<br />
Destroy(gameObject);<br />
}<br />
}<br />
void touchBegan() //키패드의 어떤 숫자가 눌렸는지 확인하는 코드<br />
{<br />
director.GetComponent&lt;director&gt;().count+=1;<br />
director.GetComponent&lt;director&gt;().answer[director.GetComponent&lt;director&gt;().count-1] = 1;<br />
</div>
<p><span style="color: #0000ff"><strong>8. 참고 문헌</strong></span><br />
[1] https://bit.ly/3wcnOow<br />
[2] https://bit.ly/2QNPyjk<br />
[3] https://bit.ly/31u0aWz<br />
[4] https://amzn.to/39rTzQU<br />
[5] https://bit.ly/3wfrber<br />
[6] https://amzn.to/3dneDJx<br />
[7] https://bit.ly/31y7Abi</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ntrexgo.com/archives/40440/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[67호]LoRa 통신 기반의 오픈소스 IoT 플랫폼을 활용한 스마트 공원 관리</title>
		<link>http://www.ntrexgo.com/archives/40437</link>
		<comments>http://www.ntrexgo.com/archives/40437#comments</comments>
		<pubDate>Wed, 25 Aug 2021 00:00:32 +0000</pubDate>
		<dc:creator>디바이스마트 매거진</dc:creator>
				<category><![CDATA[디바이스마트 매거진]]></category>
		<category><![CDATA[특집]]></category>
		<category><![CDATA[ict]]></category>
		<category><![CDATA[iot플랫폼]]></category>
		<category><![CDATA[lora통신기반]]></category>
		<category><![CDATA[공모전]]></category>
		<category><![CDATA[공원관리]]></category>
		<category><![CDATA[디바이스마트]]></category>
		<category><![CDATA[매거진]]></category>
		<category><![CDATA[최우수상]]></category>

		<guid isPermaLink="false">http://www.ntrexgo.com/?p=40437</guid>
		<description><![CDATA[디바이스마트 매거진 67호 &#124; 스마트파크는 공원 내 시설 및 자연생태환경에 대한 관리를 웹을 통해 손쉽게 할 수 있고, 공원관리에서 수집되는 정보를 바탕으로 데이터 시각화를 제공한다.]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-1.png" rel="lightbox[40437]"><img alt="67 ict 최우수상_스마트파크 (1)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-1-620x204.png" width="620" height="204" /></a></p>
<p><span style="color: #ff6600"><strong>2021 ICT 융합 프로젝트 공모전 최우수상</strong></span></p>
<p><strong>LoRa 통신 기반의 오픈소스 IoT 플랫폼을 활용한 스마트 공원 관리 : 스마트 파크(Smart Park)</strong></p>
<p>글 | 숭실대학교 김성호, 이경주, 이하늘</p>
<p><span style="color: #3366ff"><strong>1. 심사평</strong></span><br />
<strong>칩센</strong> 사용한 센서의 용도, 센싱 된 데이터의 전송 방법인 LoRa 무선 통신, 컨트롤을 위한 시나리오 등등이 모두 IoT 센서 솔루션을 위한 구성이 잘 되어 있는 듯합니다. 또한 목적 사용자와 적용 환경에 대한 부분도 타겟을 명확히 하여 개발의 목적과 필요한 조건의 한도를 구분한 기획 의도가 돋보입니다. 센서 환경 변화에 대하여 알림이 발생하였을 때 메일로 발송하여 확인하기 보다는 서버로 직접 전송하여, 관리 시스템의 UI 등으로 즉시 보여주면 더 좋았을것 같습니다.</p>
<p><strong>펌테크</strong> 실용성, 아이디어, 창의성이 아주 돋보이는 작품으로 LoRa 통신을 기반으로 스마트 공원관리에 꼭 필요한 핵심적 요소를 효율적이면서도 최적의 시스템으로 구현했으며 전체적으로 작품 기획, 기술 구현도, 완성도 면에서 상당히 뛰어나고 훌륭한 작품이라고 생각됩니다.</p>
<p><strong>위드로봇</strong> 다양한 센서와 IoT 적용에 유리한 테마파크를 현장으로 설정하여 구현한 재미있는 작품입니다.<br />
뉴티씨 매우 훌륭한 작품입니다. 실용화가 가능한 아이디어라고 생각되며, 디자인만 좀 개선하고 프로그램 등을 좀 개선하면 좋은 제품이 될 수 있다고 생각합니다. 공원에 적용하면, 환경미화원님들이 편리하게 이용하여, 깔끔하면서도 꼭 필요할 때만 환경미화원님들이 쓰레기를 비우고, 자동으로 공원의 식물에 물을 줄 수 있고, 가로등도 제어할 수 있어서, 매우 좋은 시스템으로 생각됩니다.</p>
<p><strong>엔티렉스 부설연구소</strong> 오픈소스를 이용하였지만, 시스템 구성에 맞게 시설물관리(쓰레기통, 통행량에 따른 조도 제어등)을 제어하며 관리를 할 수 있으며, 네트워크를 이용하여 여러 개의 공원을 관리할 수 있게 개발을 진행했던것 같습니다. 전체적으로 공원관리에 맞게 개발이 잘 이루어져 있으며, 웹을 통해서 사용자가 육안으로 쉽게 관리할 수 있을 것 같습니다. 그리고 시제 제작 데모를 이용하여, 각 기능을 잘 구현 하였으며, 데이터 수집 등을 잘 처리한 것 같습니다.</p>
<p><span style="color: #3366ff"><strong>2. 작품 개요</strong></span><br />
<span style="color: #008080"><strong> 2.1. 배경 및 목적</strong></span><br />
급격한 도시화, 인구 밀집, 자산 및 자원 낭비 등 도시화로 인해 발생하는 각종 문제에 대응하기 위해 도시 패러다임으로 ‘스마트 시티’가 등장하였다. 그중 행복의 질에 큰 영향을 미치는 도시 공간 중 하나인 공원은 ‘스마트 파크’로 진화하고 있다. 스마트 파크는 다양한 첨단 기술을 활용하여 이용자의 공원 체험 향상, 공원 운영·관리의 효율성을 높이며 도시가 직면한 사회 및 환경문제를 해결하는 지속 가능한 공원이다.<br />
스마트 파크의 국내 사례로 대구에 도입된 ‘IoT See Park’는 4차산업혁명 핵심기술을 공원에 접목하여 인공지능 CCTV, 전역 무료 WiFi, 스마트 휴게시설(태양광 벤치), 스마트 방향 표지판 등의 서비스를 제공하고 있다. 또한 세종시 호수공원에는 체험존 AR(GPS 기반 방향 안내 앱）, VR 체험관 등 AR/VR을 사용한 공원 체험 향상 관련 서비스를 제공한다. 이처럼 대부분의 스마트공원은 이용자 중심 공원 서비스 제공에 초점이 맞춰져 있다. 반면에 스마트공원 관리 측면에서는 서비스 구축이 미비하다. 이에 본 작품은 관리를 목적으로 한 IoT 중심의 지능형 스마트 공원관리시스템인 스마트파크를 구현하였다. 스마트파크는 공원 내 시설 및 자연생태환경에 대한 관리를 웹을 통해 손쉽게 할 수 있고, 공원관리에서 수집되는 정보를 바탕으로 데이터 시각화를 제공한다.</p>
<p><span style="color: #008080"><strong>2.2. 오픈소스 IoT 플랫폼 개선 및 활용</strong></span><br />
스마트파크은 스마트 공원의 센서 데이터를 수집, 전처리, 관리, 시각화, 데이터에 따른 명령수행 등의 기능이 있다. 이를 구성하기 위해 본인이 참여했던 IoT 오픈소스를 스마트파크을 위한 기능 및 서버를 추가·개선하여 사용하였다.</p>
<p><span style="color: #00ccff"><strong>데이터 수집</strong></span><br />
Kafka를 사용하여 스마트 공원의 센서 네트워크로부터 방대한 양의 센서 데이터를 수집할 수 있도록 하였다. 수집한 데이터를 전처리 서버로 보내기 위한 브로커 역할을 한다.</p>
<p><strong><span style="color: #00ccff">데이터 전처리</span></strong><br />
서버 프레임워크로 제작한 서버를 이용하여 데이터 전처리, 로직 검사 작업을 수행한다. 센서 데이터의 등록정보(공원이름, 서비스이름 등등) 추가 및 현재 데이터가 등록된 명령(액추에이터 동작, 이메일전송 등등)수행 조건을 만족하는지에 대한 검사하는 역할을 한다.</p>
<p><span style="color: #00ccff"><strong>관리 및 시각화</strong></span><br />
전처리된 데이터를 NoSQL데이터 베이스인 ElasticSearch에 저장하여 관리한다. 수많은 센서 데이터값이 계속해서 추가되므로 Write 기능에 강점을 가진 데이터 베이스를 선택하였다. 또한, Kibana를 사용하여 ElasticSearch에 저장된 데이터들을 분석, 시각화할 수 있도록 하였다.</p>
<p><span style="color: #008080"><strong>2.3. 스마트파크 IoT 플랫폼으로 관리하는 3가지 스마트 기기(센서노드)</strong></span><br />
본 프로젝트에서는 인체감지를 통해 보행량에 따른 밝기 조절이 가능한 스마트 가로등 관리, 쓰레기통 적재량 확인·알림, 센서를 이용한 수목 관리 등 IoT 중심의 지능형 스마트 공원관리시스템인 스마트파크(Park)를 구현하였다.<br />
스마트파크에서 활용이 가능한 스마트 기기 총 세 가지를 제작했다.<br />
구현한 세 가지 스마트기기는 모두 공통적으로 LoRa통신을 한다. LoRa는 LPWAN(저전력 장거리 무선통신)기술로, LoRa통신을 통해 저전력으로 광범위한 통신을 가능하게 했다. LoRa의 데이터 전송속도가 빠른 편은 아니지만, 공원 관리를 위해 이용되는 센서 데이터들은 실시간 처리보다는 아주 천천히 변화하는 센서 데이터들이며 장거리 통신이 요구되기 때문에 LoRa통신은 본 공원관리 시스템에 적합한 통신이다.</p>
<p><span style="color: #00ccff"><strong>스마트 가로등</strong></span><br />
크게 세 가지 기능이 있다.<br />
(a) 평균적으로 보행자 수가 많은 시간대에 밝기를 밝게 하고 적은 경우에는 밝기를 낮춤으로써 전력소비를 줄일 수 있다<br />
(b) 자동 점소등 시스템이 가능하다. 가로등 상단 부분에 장착된 조도센서를 통해 어두워질 경우 자동으로 점등이 가능하다.<br />
(c) 부점등 알림 기능이 있다. 가로등 하부(바닥) 부분에 부점등 확인을 위한 조도 센서가 장착되어 가로등이 켜져있는 밤에 조도센서(바닥 위치)에서 받은 값이 어두운 값이면 조명이 제대로 안 켜진 상태로 자동적으로 판단하여 관리자에게 알림을 줄 수 있다.</p>
<p><span style="color: #00ccff"><strong>쓰레기 관리</strong></span><br />
스마트 쓰레기통 관리의 경우에는 쓰레기통의 적재량을 주기적으로 알 수 있으며, 로직 등록 기능을 통해 쓰레기가 많이 쌓이면 이메일과 같은 알림을 줄 수 있다. 쓰레기통에 쓰레기가 완전히 채워지기 전에 미리 알림을 주어 쓰레기 수거에 도움을 줄 수 있다. 따라서 공원의 더 나은 청결을 기대할 수 있다.</p>
<p><span style="color: #00ccff"><strong>스마트 수목 관리</strong></span><br />
수목 관리의 경우, 토양센서를 통해 토양의 수분을 측정하고 수분이 부족하면 수중모터를 통해 물을 주도록 한다. 로직 등록 기능을 이용한 자동화로 공원의 수목 관리를 더 편리하게 할 수 있다는 장점이 있다.</p>
<p><span style="color: #0000ff"><strong>3. 작품 설명</strong></span><br />
<span style="color: #008080"><strong> 3.1. 주요 동작</strong></span><br />
<span style="color: #00ccff"><strong> 스마트 쓰레기통</strong></span><br />
공원 내 비치된 쓰레기통의 적재량 정보 파악<br />
쓰레기통에 쓰레기가 가득 차면 쓰레기통을 비워주기 위해 알림을 줄 수 있다.<br />
쓰레기통의 적재량은 쓰레기통의 뚜껑에 부착된 초음파 센서를 통해 거리를 탐지하여 알 수 있다. 이를 통해 얻은 값은 LoRa통신을 통해 LoRa Gateway로 전송된다. LoRa Gateway는 네트워크 서버(싱크 노드)로 전달을 해주어 최종적으로는 백엔드 서버로 값이 전달된다.</p>
<p><span style="color: #00ccff"><strong>적재량 모니터링 및 알람</strong></span><br />
쓰레기통의 적재량을 모니터링하며 일정 수준 이상의 쓰레기가 쌓이면 쓰레기가 넘치기 전에 쓰레기를 수거할 수 있도록 알림을 줄 수 있다. 사용자는 프론트엔드 웹에서 직접 조건을 추가하여 적재량이 몇 프로 이상일 경우에 이메일과 같은 알림을 주도록 설정이 가능하다.</p>
<p><strong>데모</strong><br />
다음은 쓰레기통 전면이다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-1.jpg" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40601" alt="67 ict 최우수상_스마트파크 (1)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-1.jpg" width="498" height="279" /></a></p>
<p>위 사진은 뚜껑 내부에는 초음파 센서가 부착된 모습이다. 거리 측정으로 적재량을 판단한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-2.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40604" alt="67 ict 최우수상_스마트파크 (2)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-2.png" width="505" height="231" /></a></p>
<p>위는 쓰레기통 적재량 변화값을 시각화한 그림이다. 이와 같이 각 공원 쓰레기통의 적재량을 한 눈에 확인할 수 있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-3.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40606" alt="67 ict 최우수상_스마트파크 (3)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-3.png" width="503" height="325" /></a></p>
<p>쓰레기통 적재량이 90프로 이상일 경우, 이메일을 전송하도록 로직을 등록한 것이고 그림 6은 이메일 수신 화면이다.</p>
<p><span style="color: #00ccff"><strong>마트 가로등</strong></span></p>
<p><strong>보행자 통행량 측정</strong><br />
시간별/요일별/계절별/지역별 유동인구 측정 및 분석을 하여 유동인구가 많은 가로등만 점등하여 에너지 절약할 수 있다. 결과적으로 유동인구에 따라 가로등의 밝기를 조절하여 에너지를 절약한다.</p>
<p><strong>PIR 센서를 통한 통행량 측정</strong><br />
유동인구(보행자 통행량)은 가로등에 PIR 모션감지 센서를 부착하여 지속적으로 움직임을 감지한다. 모션 감지가 오랫동안 일어날수록 유동인구에 대한 누적값이 증가한다. 이와 같은 방법으로 센서노드에서 얻은 모션감지의 수치를 백엔드 서버까지 전달하게 된다.</p>
<p><strong>데모</strong><br />
<span style="color: #99ccff"><strong>가로등 유동인구에 따른 밝기 조절</strong></span><br />
다음 사진과 같이 가로등의 상단 부분 LED 옆에 PIR 모션 감지 센서가 부착되어 있다. 모션 감지 센서에서 움직임이 감지되는 시간이 증가할수록 통행량에 대한 값이 증가하게 된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-4.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40608" alt="67 ict 최우수상_스마트파크 (4)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-4.png" width="503" height="218" /></a></p>
<p><strong>방문자 수 변화</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-5.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40609" alt="67 ict 최우수상_스마트파크 (5)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-5.png" width="512" height="486" /></a><br />
위 그림은 방문자 수 데이터를 시각화한 자료이다. 직접 센서로 측정해 테스트하고 있는 sangdo의 방문자 수 변화를 볼 수 있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-6.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40610" alt="67 ict 최우수상_스마트파크 (6)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-6.png" width="510" height="243" /></a></p>
<p>위는 보행량에 따라 led 밝기 조절 로직이다. 스마트파크(park)에서는 실질적인 데이터를 수집할 수 없기에 value 범위를 임의값으로 설정하였고, 실제로는 대시보드에 나타난 방문자 수를 참고하여 value 범위를 설정해야한다.</p>
<p><strong>보행량에 따른 밝기 조절</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-7.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40611" alt="67 ict 최우수상_스마트파크 (7)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-7.png" width="509" height="336" /></a></p>
<p>위와 같이 유동인구에 따라 가로등 LED 밝기가 달라진다.</p>
<p><span style="color: #99ccff"><strong>가로등 부점등 검사 (고장 알림)</strong></span><br />
가로등 하부의 조도 센서를 통해 가로등의 전구의 조도를 측정 후 LED ON이어야 하는 상태에서 조도가 측정되지 않으면 가로등이 부점등 상태임을 이메일로 알린다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-8.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40612" alt="67 ict 최우수상_스마트파크 (8)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-8.png" width="510" height="465" /></a></p>
<p>그림 14는 부점등 상태일 경우 이메일을 전송하도록 로직을 등록한 것이다. illuminance는 가로등 상단에 있는 조도센서(낮과 밤 판별)의 데이터이고, Lampilluminance는 가로등 하부에 위치한 조도센서(부점등 판별)의 데이터이다. 이때 조도센서의 값이 90 ~ 100 이하라면 어두운 것으로 판단한다. illuminance &lt; 90 인 경우 LED가 ON되어야 하고, 이때 LED는 아래의 조도센서를 향해 빛을 쏘기 때문에 Lampilluminance는 LED 불빛을 감지해 100 이상이어야 한다. LED가 정상적으로 켜지지 않아 Lampilluminance의 값이 100 이하라면 부점등 상태로 판단한다. 따라서 0 &lt; illuminance &lt; 90 이고 0 &lt; Lampilluminance &lt; 100일 때 부점등 상태라 판단해 이메일을 보내도록 로직을 등록했다. 오른쪽 그림은 어두운 상태에서 LED가 정상적으로 켜졌으나, 가로등 하부 조도센서를 손으로 가려 부점등 상태를 조성한 것이다.</p>
<p><span style="color: #99ccff"><strong>밝기에 따른 가로등 자동 점·소등</strong></span></p>
<p><span style="color: #33cccc"><strong><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-9.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40613" alt="67 ict 최우수상_스마트파크 (9)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-9.png" width="509" height="228" /></a></strong></span><br />
밝을 경우에는 로직에 등록된 LED 액추에이터 명령을 통해 LED가 자동으로 꺼지고, 어두울 경우 액추에이터 명령을 통해 자동으로 켜질 수 있도록 로직을 등록했다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-10.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40614" alt="67 ict 최우수상_스마트파크 (10)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-10.png" width="510" height="259" /></a></p>
<p>가로등 상단의 조도센서를 통해 어두워지거나 밝아질 경우 자동 점/소등한다.<br />
두 번째 그림에서 볼 수 있듯이 밝을 경우 LED를 OFF하고, 세 번째 그림에서 조도센서를 가려 인위적으로 어두운 환경을 만들었을 때 LED가 ON되는 것을 확인할 수 있다.</p>
<p><span style="color: #00ccff"><strong>스마트 수목 관리</strong></span><br />
온도, 습도, 토양 등 측정센서 설치 및 생장 환경 관련 데이터 측정한다. 공원 내의 수목주변의 온도와 습도, 일조량, 토양내 습도 등을 측정 분석하여 알릴 수 있다. 실외의 온도와 습도 일조량, 등을 컨트롤하기는 힘들어 보이므로 모니터링 및 알림 기능을 통해 관리를 도울 수 있다.</p>
<p><strong>관수 기능 자동 제어</strong><br />
토양 센서를 이용해 습도를 측정하여 필요할 경우 관수 시설을 제어하는 기능을 갖고 있다.<br />
토양 수분 센서를 이용하여 토양의 수분이 부족할 경우 액추에이터 명령을 통해 수중모터(펌프)를 작동시켜 토양에 물을 준다. 센서노드는 토양 수분 센서의 값을 일정 주기로 게이트웨이로 전송한다. 센서 데이터는 센서노드 -&gt; 게이트웨이 -&gt; 싱크노드 -&gt; 백엔드 순으로 전달된다.</p>
<p><strong>데모</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-11.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40615" alt="67 ict 최우수상_스마트파크 (11)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-11.png" width="504" height="200" /></a><br />
첫 번째 그림에서 볼 수 있듯이 수중모터 제어를 위해 액추에이터로 pump를 등록했다. 토양수분 값이 일정 값 이상이면 사용자가 등록한 액추에이터 값에 따라 수중모터가 동작하도록 로직을 등록했다.<br />
백엔드는 토양수분 센서가 일정 값 이상인지 조건을 확인하여 조건에 부합하면 액추에이터 신호를 싱크노드에 전달하여, 싱크노드-&gt;게이트웨이-&gt;센서노드 순서로 액추에이터 명령이 전달된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-12.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40616" alt="67 ict 최우수상_스마트파크 (12)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-12.png" width="506" height="205" /></a></p>
<p>왼쪽 사진은 등록된 로직에 따라 사용자가 설정한 범위 내 습도값이 해당될 시 액추에이터를 작동시켜 수중모터로 물을 공급하는 모습이다. 오른쪽은 토양수분을 그래프로 시각화한 자료이다.</p>
<p><span style="color: #00ccff"><strong>데이터 시각화</strong></span><br />
의미가 없거나 혹은 단순한 의미만을 지닌 데이터로부터 실시간으로 의미있는 정보를 찾는 것 자체가 가치를 창출하는 일이다. 스마트파크는 단순한 센서데이터 들을 이용해 여러 가지 의미 있는 정보를 대시보드에 시각화 하였다.</p>
<p><strong>공원 검색기능</strong><br />
원하는 기간, 원하는 공원을 선택하면 선택된 데이터만을 필터링하여 볼 수 있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-13.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40617" alt="67 ict 최우수상_스마트파크 (13)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-13.png" width="502" height="194" /></a></p>
<p><strong>공원 별 센서값 시각화 보드</strong><br />
공원의 모든 센서값을 시각화한 보드를 통해 센서값의 비교 및 확인하여 공원 별 기상정보 비교분석이 가능하다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-14.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40618" alt="67 ict 최우수상_스마트파크 (14)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-14.png" width="508" height="214" /></a></p>
<p><strong>공원 별 방문자 수 비교 분석 기능</strong><br />
공원 별 방문자 수 데이터 시각화를 통해 비교 분석이 가능하다. 각 공원 별 방문자 수를 한 눈에 알아볼 수 있고, 어느 시간대, 어느 요일에 유동량이 많은지를 쉽게 알 수 있어 이를 이용해 방문자 수에 따른 가로등 제어, 공원 내 행사 일정 선택 등 다양한 방면의 활용이 가능하다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-15.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40619" alt="67 ict 최우수상_스마트파크 (15)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-15.png" width="508" height="273" /></a></p>
<p><strong>공원 별 쓰레기통 적재량 비교분석 기능</strong><br />
원하는 공원의 쓰레기통 적재량을 실시간으로 체크할 수 있으며, 요일 날짜별 쓰레기통 적재량을 한 눈에 볼 수 있어, 쓰레기통 추가 배치, 수거 등에 유용한 활용이 가능하다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-16.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40620" alt="67 ict 최우수상_스마트파크 (16)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-16.png" width="506" height="188" /></a></p>
<p><strong>서비스 유지보수의 용이</strong><br />
IoT서비스 플랫폼에서 지속적으로 안정적인 서비스가 제공되기 위해서는 센서를 비롯한 하드웨어들의 헬스 체크가 필요하다. 스마트파크에서는 서비스 노드의 헬스 정보를 수시로 체크하여 웹 UI상에 나타내 주므로 헬스 정보 확인이 가능하며 문제 발생 시 빠른 유지보수가 가능하다.</p>
<p><strong>유연한 확장성</strong><br />
플랫폼의 운영자가 스마트파크이 관리할 새로운 공원을 하거나, 새로운 IoT서비스를 추가할 경우 웹상에서 몇 가지 조작만으로 공원 및 서비스 등록이 가능해, 유연한 확장성을 보여준다.</p>
<p><span style="color: #008080"><strong>3.2. 주요 특징</strong></span><br />
<strong> <span style="color: #00ccff">UI에서 IoT 디바이스 관리, 데이터 시각화</span></strong></p>
<p><strong>네비게이션 바</strong></p>
<p><strong><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-17.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40621" alt="67 ict 최우수상_스마트파크 (17)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-17.png" width="508" height="68" /></a></strong><br />
MANAGEMENT 탭의 구성요소로 Sensor, Node, Sink, Actuator가 있다. SERVICE 탭의 구성요소로 LogicCore가 있다. 사용자는 LogicCore에서 로직을 등록할 수 있다. Kibana 탭의 구성요소로 Dashboard가 있다. Dashboard에서 데이터 시각화를 제공한다.</p>
<p><strong>등록(register)</strong></p>
<table style="width: 620px" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td><img class="alignnone  wp-image-40622" alt="67 ict 최우수상_스마트파크 (18)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-18.png" height="252" /></td>
<td><img class="alignnone size-full wp-image-40623" alt="67 ict 최우수상_스마트파크 (19)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-19.png" width="193" height="252" /></td>
<td></td>
</tr>
</tbody>
</table>
<p>센서 : register sensor 버튼을 클릭하면 그림 33과 같이 등록 페이지가 나타나고, 사용자는 센서 정보 (센서 이름, 종류, value)를 입력해 센서 등록을 할 수 있다.</p>
<p>싱크 : register sink를 클릭 후 싱크 정보 (싱크 이름, topic, ip:port)를 입력해 싱크를 등록할 수 있다. 스마트파크(park)에서는 싱크를 한강 공원 단위로 설정해 진행하였다.<br />
노드 : 노드 등록은 그림 32와 사진과 같이 노드 이름, 위치 (지도를 클릭하면 해당 위치의 위도 경도를 얻음), 노드의 종류(가로등, 쓰레기통, 수목), 해당 노드에서 사용할 센서, 싱크를 선택해 등록할 수 있다.</p>
<p>이때 노드는 가로등, 쓰레기통, 수목을 의미한다.<br />
액추에이터 : register actuator를 클릭 후 액추에이터 이름을 입력해 등록할 수 있다. 본 프로젝트에서는 토양 습도를 토대로 관수 제어를 하기 위한 pump 액추에이터와 조도에 따라 led 밝기를 조절하기 위한 led 액추에이터를 등록하였다.<br />
각 정보를 입력후 submit 버튼을 클릭하면 센서, 싱크, 액추에이터, 노드의 정보를 서버로 POST한다.</p>
<p><strong>table</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-20.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40624" alt="67 ict 최우수상_스마트파크 (20)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-20.png" width="518" height="424" /></a></p>
<p>센서, 싱크, 액추에이터 : 위와 같이 사용자가 등록한 센서, 싱크, 액추에이터의 정보를 table의 형태로 확인 가능하고, 휴지통 img를 클릭하여 삭제할 수 있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-21.png" rel="lightbox[40437]"><img class="alignnone  wp-image-40625" alt="67 ict 최우수상_스마트파크 (21)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-21.png" width="520" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-23.png" rel="lightbox[40437]"><img class="alignnone  wp-image-40627" alt="67 ict 최우수상_스마트파크 (23)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-23-443x620.png" width="520" /></a></p>
<p>노드 : 노드는 table을 볼 수 있는 두 가지 옵션 (All, Map)이 있다.</p>
<p>· All 옵션 : default로 설정되어있는 노드 table이며 사용자는 싱크별 노드 table을 볼 수 있다. 스마트파크(park)에서는 한강 공원별 가로등, 쓰레기통, 수목 노드가 table로 나타나 있다.</p>
<p>· Map 옵션 : 마지막 사진과 같이 지도상에서 마커 형태로 노드 위치를 나타낸다. 각 노드의 종류가 마커 이미지로 구분되어 있고, 마커를 클릭하여 해당 노드의 정보를 볼 수 있다. 이때 사용자는 지도를 움직이며 마커 위치를 확인할 수 있다. 마커 이미지 색상은 가로등 : 파란색 / 쓰레기통 : 노란색 / 나무 : 초록색이다.</p>
<p>· 노드 헬스체크 : 사용자는 색상별로 노드의 상태를 확인할 수 있다. 웹 소켓으로 서버와 통신하기 때문에 실시간으로 확인이 가능하다.</p>
<p>· 노드의 상태</p>
<p style="padding-left: 30px">회색 : 알 수 없는 상태<br />
초록 : 연결된 상태<br />
노랑 : 직전에 연결이 끊긴 상태 (초록과 빨강의 사이)<br />
빨강 : 연결이 끊긴 상태</p>
<p>로직코어 (LogicCore)</p>
<p style="padding-left: 30px">· Logic 등록 : 사용자는 LogicCore table에서 register logic 버튼을 클릭해 로직을 등록할 수 있다.</p>
<p>Logic 정보</p>
<p style="padding-left: 30px">· 로직 이름<br />
· 센서 : 센서에 로직 등록<br />
· 시간 범위 : 해당 로직이 작업을 수행할 시간 설정<br />
· value 범위 : 해당 로직이 동작할 value 설정<br />
· action :  사용자가 설정한 시간과, value 범위 내 센서값이 해당할 때 실행할 작업<br />
◎ email : 해당 이메일로 알림 메시지 발송<br />
◎ actuator : value, sleep 값을 받아 해당 액추에이터 작동<br />
register logic에서 각 요소(시간, value, action)를 카드라 할 때 value 카드와 action 카드는 왼쪽 하단 Add ~ 버튼을 통해 추가할 수 있고, value 카드와 시간 카드는 Add scope 버튼을 통해 범위를 추가할 수 있다.<br />
· Logic table : 아래 왼쪽 사진과 같이 등록한 logic을 table의 형태로 볼 수 있고, 휴지통 img를 클릭하여 삭제할 수 있다.<br />
· Show logic : table에서 show logic 버튼을 클릭하면 아래 오른쪽 사진과 같이 로직의 구조를 볼 수 있다.</p>
<p style="padding-left: 30px">이처럼 스마트파크(park)은 웹에서 센서, 노드, 싱크, 액추에이터를 등록하고, 사용자 맞춤 로직을 생성할 수 있기에 스마트공원 관리에 용이하다.</p>
<p><strong>kibana dashboard</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-24.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40628" alt="67 ict 최우수상_스마트파크 (24)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-24.png" width="505" height="270" /></a></p>
<p>home 또는 kibana dashboard 메뉴를 통해 시각화된 데이터 확인이 가능하다.</p>
<p><span style="color: #00ccff"><strong>LPWAN 통신 방법인 LoRa 통신, 직접 구현한 LoRa WAN 프로토콜로 작동</strong></span><br />
날씨 상태, 토양 수분 레벨 또는 가로등과 같이 이러한 응용 분야에서 측정되거나 제어되는 크기/양은 모두 확장된 시간 범위에 걸쳐 매우 느리게 변화한다. 또한, 센서 노드가 서로 멀리 떨어져 있는 경우가 많고 배터리로 구동되는 경우가 많으므로, 최적의 무선 프로토콜은 최소한의 전력 소비로 긴 거리에 걸쳐 작은 데이터 패킷을 효율적으로 전송할 수 있어야 한다.<br />
따라서 대표적인 LPWAN(저전력 무선 장거리 통신) 기술 중 비면허 대역 주파수를 이용하는 LoRa 통신을 선택했다. 1Ghz 이하의 대역은 다른 주파수에 비해 서로 간섭력이 낮아 무선 파장 및 효율적 측면에서 좋기 때문에 원거리 통신을 위해서 적합하다. End-Device(센서노드)와 LoRa 게이트웨이, 싱크노드를 구현하여 LoRaWAN 프로토콜을 따르도록 구현했다. End-Device의 LoRaWAN 프로토콜은 C언어로 구현하였으며, LoRa Gateway의 LoRaWAN은 Python으로 구현했다. LoRaWAN의 모든 Mac Command가 구현된 것은 아니지만 필요한 몇가지 Mac Command가 작동하도록 구현했다. DevStatusReq와 DevStatusAns의 Mac Command를 통해 센서노드의 배터리와 수신신호의 수치를 파악할 수 있다. 또한 RFU의 예약된 공간에는 ActuatorReq와 ActuatorAns의 Mac Command를 구현하여 이 명령을 이용하여 액추에이터 작동이 가능하도록 했다. Actuator는 백엔드 서버에서 오는 명령을 End-Device에서 처리하는 기능을 말한다. 예를 들면 백엔드에서 모터를 작동시키거나 LED의 밝기를 조절하는 등의 명령을 센서노드에 전달할 수 있다.</p>
<p><span style="color: #00ccff"><strong>백엔드 서버 특징</strong></span><br />
5G 시대가 도래하면서 IoT(사물 인터넷) 관련 데이터의 가치가 더욱 커질 전망이다. IoT 기술의 특성상 수많은 데이터와 로그를 빠르게 적재, 분석하는 것이 필수적이다. 스마크파크는 Kafka &#8211; DataLogic서비스 &#8211; ElasticSearch로 데이터 파이프라인을 구성하여 방대한 센서 데이터의 준 실시간 처리가 가능하다.</p>
<p><span style="color: #008080"><strong>3.3. 전체 시스템 구성</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-25.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40629" alt="67 ict 최우수상_스마트파크 (25)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-25.png" width="507" height="329" /></a></p>
<p><span style="color: #ff9900"><strong>3.3.1. 프론트엔드</strong></span><br />
<strong><span style="color: #00ccff">컴포넌트 구조</span></strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-26.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40630" alt="67 ict 최우수상_스마트파크 (26)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-26.png" width="506" height="289" /></a></p>
<p>위 그림은 컴포넌트 구조를 간단히 map으로 표현한 것이다, App에서 모든 컴포넌트를 route한다.</p>
<p style="padding-left: 30px">· ‘~ Management’ : sensor, node, sink, actuator를 관리하는 컴포넌트이다. 각각의 resigter 컴포넌트를 호출해 정보를 등록하고, 각 table 컴포넌트에서 해당 list를 table 형태로 출력한다.<br />
· Register Logic : 로직 등록 컴포넌트이다. 하위 컴포넌트 InputCards에서 사용자가 입력한 time, sensor, value, action, actuator card의 정보 넘겨주고 이를 바탕으로 로직을 등록한다.<br />
· LogicTable : 등록된 로직을 list로 나타내는 컴포넌트이다.<br />
· showLogic : logic table에서 show logic을 클릭할 시 호출되는 컴포넌트이다. 하위 컴포넌트 showCards에서 사용자가 등록한 정보를 가져와 해당 로직의 정보를 출력한다.<br />
· kibanaDashboard : 데이터 시각화를 제공하는 컴포넌트이다.</p>
<p><span style="color: #ff9900"><strong>3.3.2. 백엔드</strong></span><br />
<span style="color: #00ccff"><strong>데이터 파이프라인</strong></span><br />
<strong>개요</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-27.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40631" alt="67 ict 최우수상_스마트파크 (27)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-27.png" width="506" height="210" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-28.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40632" alt="67 ict 최우수상_스마트파크 (28)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-28.png" width="504" height="208" /></a></p>
<p>그림 48처럼 센서데이터가 라즈베리파이(Sink Node, 공원)에서 최종 저장소로 바로 전송되는 경우 라즈베리파이 내에서 측정값과 등록정보(metaData)를 모두 관리해야 하기 때문에 센서 네트워크에 매우 큰 부담을 준다. 또한 스마트파크의 매우 많은 라즈베리파이가 하나의 저장소로 데이터를 전송하는 경우 Elasticsearch에게 매우 높은 가용성과 처리량을 요구하게 된다.</p>
<p>따라서 그림 49와 같이 우리는 최종 저장소 이전에 데이터를 처리할 수 있는 DataLogic서비스를 추가하였다. 센서 네트워크에서는 측정값과 각 Node의 고유ID만 관리하고 DataLogic서비스에서 데이터 처리 서비스(데이터에 등록정보를 추가)를 지원한다. 해당 서버는 측정값을 이용해 등록된 이벤트를 처리하는 기능도 지원하는데, 이는 다음에 설명하겠다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-29.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40633" alt="67 ict 최우수상_스마트파크 (29)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-29.png" width="508" height="472" /></a></p>
<p>여러 공원의 데이터 값을 하나의 데이터 처리 서비스로 전송하는 것 또한 데이터 처리 서비스에 너무 많은 부담을 준다. 그렇다고 여러 개의 데이터 처리 서비스를 구현하기에는 구성이 너무 복잡해지며, 특정 서버에 요청이 몰릴 경우 몇몇 요청은 처리하지 못하고 누락될 수 있다.<br />
따라서 센서네트워크와 서버 사이에 Kafka를 배치해주었다. Kafka는 데이터를 임시로 저장하는 Queue역할을 하며 기본적으로 클러스터 환경을 제공하여 높은 처리량과 고가용성을 보장한다. DataLogic서비스는 자신이 필요할 때만 Kafka에 데이터를 요청하기 때문에 과부하로 문제가 될 가능성이 배제된다.</p>
<p><strong>구성</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-30.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40634" alt="67 ict 최우수상_스마트파크 (30)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-30.png" width="507" height="370" /></a></p>
<p><span style="color: #99ccff;background-color: #ffffff">Kafka</span><br />
producer &#8211; Broker(Kafka) &#8211; Consumer 구조의 스트림 처리 플랫폼이다. 여러 공원으로부터 데이터를 저장받아 임시저장한 후 DataLogic서비스에 안정적으로 데이터를 제공한다.<br />
라즈베리파이에서 카프카로 전송되는 데이터의 예시는 오른쪽 그림과 같다.</p>
<p><span style="color: #99ccff"><strong>DataLogic</strong></span><br />
서버 세부설명 파트에서 자세히 설명한다.</p>
<p><span style="color: #99ccff"><strong>엘라스틱서치</strong></span><br />
방대한 센서데이터를 지속적으로 저장하기 위해서 Write능력이 뛰어난 데이터 베이스가 필요하다. 따라서 Write 효율에 중점을 둔 NoSQL데이터베이스인 Elasticsearch를 데이터 베이스로 사용하였다.<br />
Elasticsearch에 준 실시간으로 저장된 센서 데이터는 비교/분석을 위한 시각화와 공공데이터 배포를 위해 사용된다.</p>
<p><span style="color: #99ccff"><strong>Kibana</strong></span><br />
Paul Brunet의 InfoWorld 칼럼에 따르면 요즘 시대는 더 많은 데이터에 접속할 수 있는 상태지만, 이런 수많은 데이터에서 효과적으로 인사이트를 획득하는 능력은 감소했다고 한다. 이제 우리가 고민해야 할 지점은 ‘데이터를 어떻게 잘 활용할 것인가?’이다. 많은 양의 데이터를 한눈에 볼 수 있고, 데이터 분석에 대한 전문 지식이 없어도, 누구나 쉽게 데이터의 패턴을 알아낼 수 있도록 시각화된 데이터 대시보드를 구현하였다.</p>
<p><span style="color: #00ccff"><strong>서버 상세설명</strong></span></p>
<p><span style="color: #00ccff"><strong><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-31.png" rel="lightbox[40437]"><img class="alignnone  wp-image-40635" alt="67 ict 최우수상_스마트파크 (31)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-31-620x476.png" width="520" /></a></strong></span></p>
<p><span style="color: #99ccff"><strong>서버 아키텍쳐</strong></span><br />
클린 아키텍처를 적용하여 특정 계층에 대한 수정이 다른 계층에 거의 영향을 주지 않도록, 그리고 같은 계층 내에서는 일관되고 응집력 있는 결합을 제공할 수 있도록 서버의 계층을 구분하였다. 상당히 분량이 많은 앱이더라도 소스코드 전반을 쉽게 파악할 수 있고 복잡한 수정 사항이 생겼을 때라도, 어떤 부분들을 고치면 되는지 금방 파악할 수 있도록 하였다.</p>
<p><strong>Application &#8211; Registration</strong><br />
<span style="color: #99ccff"><strong>개요</strong></span><br />
등록 정보를 관리하기 위한 API Server이다. 프론트엔드에서 등록한 메타데이터, 로직데이터 등을 백엔드의 데이터 베이스에 저장하고, 이 데이터 베이스를 읽어서 프론트엔드, DataLogic, HealthCheck 등의 서비스에 정보를 제공 및 컨트롤하는 역할을 수행한다.</p>
<p><span style="color: #99ccff"><strong>구성</strong></span><br />
모든 서비스는 이용자가 어떤 기능을 요구하거나, 개발자가 어떤 아이디어를 생각해내 서비스를 확장시켜야 하는 상황이 생기기 마련이다. 이때를 대비해 유연하게 확장이 가능하도록 서버를 구성하여야 한다. 스마트파크의 모든 서버는 각 기능 단위로 서비스를 만들어 큰 서비스를 구성하는 방식인 마이크로 서비스 아키텍처로 구성하였다.</p>
<p><span style="color: #99ccff"><strong>기능</strong></span><br />
스마트파크를 구성하는 마이크로 서비스들을 컨트롤하는 역할을 한다. Registration은 센서 데이터 스트림 처리를 담당하는 마이크로서비스(DataLogic)와 센서 데이터 스트림 노드(아두이노)의 헬스 상태 처리를 담당하는 마이크로서비스(HealthCheck)에게 등록정보를 제공한다. 이후 등록정보의 변경이 발생할 경우에도 마이크로 서비스 들에게 등록 정보를 제공해준다.</p>
<p><span style="color: #99ccff"><strong>DB</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-32.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40636" alt="67 ict 최우수상_스마트파크 (32)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-32-620x315.png" width="620" height="315" /></a></p>
<p>스마트파크의 데이터베이스는 위 사진과 같이 스키마가 정의되어있다. 싱크 노드, 센서 노드 등의 메타데이터를 구조적으로 저장 및 조회한다. 데이터베이스로 쓰인 애플리케이션은 mySql이다.</p>
<p><strong>LogicCore &#8211; DataLogic</strong><br />
DataLogic서비스는 Kafka에서 데이터를 읽어온 뒤 등록정보를 바탕으로 메타데이터를 추가한다. 보강된 데이터를 기반으로 사용자가 지정한 이벤트의 처리동작과 Elasticsearch로의 데이터 저장을 수행한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-33.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40637" alt="67 ict 최우수상_스마트파크 (33)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-33-620x319.png" width="620" height="319" /></a></p>
<p><span style="color: #99ccff"><strong>등록정보 추가</strong></span></p>
<p><span style="color: #99ccff"><strong><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-34.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40638" alt="67 ict 최우수상_스마트파크 (34)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-34-620x390.png" width="620" height="390" /></a></strong></span><br />
DataLogic서버는 처음 실행될 때 Registration 서버에 등록정보를 요청한다. Registration서버는 요청한 DataLogic서비스를 자신의 서버 내에 등록한 후 서버 내 DB에 저장된 Sink node와 Sensor node의 등록정보들을 반환해 주고 DataLogict는 이 등록정보를 서버의 메모리 내에 보관한다.<br />
DataLogic서비스가 실행되고 있는 도중에 등록정보가 변경될 경우 Registration서버는 업데이트된 정보를 등록된 모든 DataLogic서비스에게 알려주어 등록정보를 동기화할 수 있도록 한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-35.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40639" alt="67 ict 최우수상_스마트파크 (35)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-35-620x395.png" width="620" height="395" /></a></p>
<p>센서 데이터마다 적절한 메타데이터를 얻기 위해 DataLogic서비스에서 DB에 접근할 수 없기 때문에 등록정보를 메모리에 동기화시킨다. 이후 Kafka에서 읽어온 센서 데이터에 sensor-id, node-id에 해당하는 메타데이터를 추가한다.</p>
<p><span style="color: #99ccff"><strong>이벤트 처리</strong></span><br />
수집한 센서 데이터에서 프론트엔드에서 유저가 미리 지정해둔 특정한 이벤트를 검사하기 위한 기능이다. JSON 형식의 센서 데이터의 특정 필드 값을 기준으로 조건을 검사하는 filter기능과 actuator동작신호 전송, Email전송 등 특정 이벤트를 수행하는 action기능으로 구성되어있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-36.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40640" alt="67 ict 최우수상_스마트파크 (36)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-36-620x414.png" width="620" height="414" /></a></p>
<p><span style="color: #99ccff"><strong>Elastic search저장</strong></span></p>
<p>DataLogic서비스 내에서 수많은 (보강된)센서 데이터들이 생성된다. 이 데이터 하나당 Indexing(Write) API를 호출하면 네트워크에 과부하가 걸리므로 이를 방지하기 위해 데이터를 효율적으로 저장하여야 한다.<br />
따라서 저장할 데이터를 적재하다가 특정 byte 이상이 쌓이면 한 번에 Bulk Indexing(배치 처리)하도록 구현하였다. 또한, Elastic search의 Sharding기능을 통해 자체적으로 쓰기 성능을 향상시켰다.</p>
<p><span style="color: #00ccff"><strong>HealthCheck</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-37.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40641" alt="67 ict 최우수상_스마트파크 (37)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-37-578x620.png" width="578" height="620" /></a></p>
<p>그림 60과 같이 수많은 노드의 정상 작동여부와 배터리 잔량을 전송받아 각 노드의 헬스 상태를 결정한 후 헬스 상태가 변경된 노드의 헬스 정보와 배터리 잔량을 프론트엔드로 전송하는 역할을 수행한다.<br />
먼저 라즈베리파이로부터 연결된 모든 아두이노의 상태 정보를 bool 형태로 전달받는다. 전달받은 상태정보를 이용해 헬스 정보를 업데이트한 후 그림 61과 같이 헬스 정보가 기록된 Map 자료구조에 저장한 후, 업데이트 내역이 있는 아두이노의 헬스정보를 추려내어 웹소켓을 통해 프론트엔드로 전송한다. 배터리 잔량은 받은 값을 그대로 전송한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-38.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40642" alt="67 ict 최우수상_스마트파크 (38)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-38-620x174.png" width="620" height="174" /></a><br />
헬스 정보 업데이트 기준은 전달받은 상태정보와 가장 최근의 상태를 위 사진과 같은 기준으로 비교해서 결정한다.</p>
<p><span style="color: #ff9900"><strong>3.3.3. 도커(Docker)</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-39.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40643" alt="67 ict 최우수상_스마트파크 (39)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-39-620x408.png" width="620" height="408" /></a></p>
<p>플랫폼 서비스는 고객(서비스 운영자)이 플랫폼의 모든 실행 환경을 손쉽게 사용자의 환경으로 가져올 수 있어야 한다. 이를 위해 스마트파크의 모든 서버는 도커 컨테이너 위에서 실행가능하게 도커 이미지로 변환하여 배포한다. 도커 컨테이너(단일 컨트롤 호스트 상에서 여러개의 고립된 리눅스 시스템들을 실행하기 위한 운영 시스템 레벨 가상화 방법)를 이용하면 서버 환경을 재구축하는 부가적인 작업 없이 개발 당시의 환경(라이브러리, 설정값, 종속성 및 파일)을 로컬에서 애뮬레이션할 수 있다. 다시 말해 큰 수정 없이 어느 환경에서든 모든 서버가 작동되도록 배포할 수 있다.</p>
<p><span style="color: #ff9900"><strong>3.3.4. 센서 네트워크(NodeMCU-Raspberry Pi-싱크노드)</strong></span><br />
<span style="color: #00ccff"><strong>백엔드에 데이터가 도달하기 전까지의 상세구조 그림</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-40.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40644" alt="67 ict 최우수상_스마트파크 (40)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-40-620x419.png" width="620" height="419" /></a></p>
<p><span style="color: #00ccff"><strong>오픈소스 사용 (Flask와 MQTT통신 설명)</strong></span><br />
<span style="color: #99ccff"><strong>싱크노드-Flask 사용</strong></span><br />
싱크노드가 웹서버를 운영함으로써 서버로부터 HTTP요청을 받을 수 있다. 서버는 특정 싱크노드에 HTTP 요청을 하여 액추에이터 명령을 내리게 된다. 싱크노드(네트워크 서버)에서 웹서버를 운영하기 위해 Flask 오픈소스를 이용했다.</p>
<p><span style="color: #99ccff"><strong>Paho MQTT Client 사용</strong></span><br />
IoT 통신은 경량화와 유연성을 갖추어야 한다. 여러 통신 방법 중 MQTT는 M2M, IoT를 위한 프로토콜로서, 최소한의 전력과 패킷량으로 통신하는 프로토콜로 IoT통신에 적합하다. MQTT 통신을 위해서는 Paho client 오픈소스를 이용했다. 따라서 우리는 게이트웨이와 싱크노드간에 Mosquitto 브로커와 MQTT 통신을 이용해서 경량화된 통신을 이용한다.</p>
<p><strong><span style="color: #00ccff">LoRaWAN 프로토콜 이용</span></strong><br />
<span style="color: #99ccff"><strong>Class A와 C</strong></span><br />
LoRaWAN 프로토콜에는 세 가지 A, B, C 클래스의 디바이스 유형이 있다.<br />
센서 네트워크에서 끝단에 위치한 센서노드들의 클래스를 이 세 가지 A, B, C 유형 중 하나를 지정하여 사용하게 된다. 현재 구현하여 이용이 가능한 센서노드의 클래스는 A와 C 두가지다.<br />
A Class 통신 방식은 LoRa Device와 LoRa Gateway 사이에서 LoRa Device가 Gateway에게 메시지를 전송한 이후, 잠시 동안 두 번에 걸쳐 메시지 수신이 허용되는 방식이다. 송신하기 전에는 송신과 수신 모두 동작을 하지 않다가 송신이 진행되면, 그 순간에 잠시 동안 두 번에 수신 윈도우를 허용할 기회를 제공한다. 즉 A Class는 수신을 위해서 송신이 진행되어야 하며 송신 위주의 서비스에 주로 사용된다. 상시전원을 사용하지 않고 배터리로 운영하는 경우에 사용되기 때문에 가장 적은 전력을 사용하는 Class이다.<br />
C Class 통신 방식은 수신 가능 상태를 유지하기 위해 다른 Class에 비해 최소 지연시간을 갖는다. 송신 시간을 제외하고는 수신을 계속 대기하는 상태가 지속되므로 세 가지 Device Class 중에서 가장 많은 전력을 소비한다. 그 때문에 충분한 전력 공급이 가능한 상황에서 이용되는 Device Class이다. 대부분의 순간 수신상태를 유지하기 때문에 수신이 중요한 서비스(예를 들면 Actuator 기능 및 원격제어)에 이용된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-41.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40645" alt="67 ict 최우수상_스마트파크 (41)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-41-620x366.png" width="620" height="366" /></a></p>
<p><strong>OTAA 활성화 방법(Join과정 및 암호화 방법)</strong><br />
새로운 최종 장치 (LoRa 장치)가 LoRa 네트워크에 추가되려면 활성화 프로세스를 거쳐야 한다. LoRaWAN 프로토콜에는 ABP 통신과 OTAA통신 두가지 활성화 방법이 존재한다. 현재 OTAA모드를 기준으로 작동되도록 구현되어있다.<br />
센서노드가 가입 요청 메시지를 보내 가입 절차를 시작한다. 참여 요청에 DevEUI, AppEUI 및 DevNonce가 포함된다. DevEUI 및 AppEUI는 각각 Global End Device 및 Application Identifier를 나타내며 IEEE 나타내며 EUI-64 주소 공간 형식을 따른다. 우리 프로젝트에서는 센서노드의 EUI 주소값은 Arduino 코드에 하드코딩하여 지정한다. Join 활성화 과정에서는 App Key를 이용하여 AES-128 암호화하며, NwkSKey와 App_SKey가 활성화 과정으로 인해 생성된 이후에는 이 둘 중 하나를 이용하여 메시지를 AES-128 암호화한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-42.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40646" alt="67 ict 최우수상_스마트파크 (42)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-42-620x408.png" width="620" height="408" /></a></p>
<p>위 그림은 OTAA모드 활성화 프로세스 과정을 나타낸다. AppKey는 최종 장치와 서버간에 미리 공유되는 Key값이다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-43.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40647" alt="67 ict 최우수상_스마트파크 (43)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-43-620x105.png" width="620" height="105" /></a></p>
<p>왼쪽 그림은 Join Request 메시지의 구조이다. End Device는 다음의 요청을 보낸다.<br />
Join Request 메시지는 암호화되지 않는다. Dev Nonce는 엔드 장치에서 랜덤하게 생성된 값으로 이전에 수신한 요청의 DevNonce 값과 중복되는 Dev Nonce의 요청은 받아들이지 않아 공격을 방지한다.<br />
오른쪽 그림은 Join Accept 메시지의 구조이다. 메시지를 App Key로 AES-128 암호화한다.</p>
<p><strong>메시지의 프레임 구조</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-44.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40648" alt="67 ict 최우수상_스마트파크 (44)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-44-620x369.png" width="620" height="369" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-45.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40649" alt="67 ict 최우수상_스마트파크 (45)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-45-597x620.png" width="597" height="620" /></a></p>
<p><strong>구현한 MAC Command</strong><br />
LoRaWAN은 다음과 같은 Mac Command, Command ID를 갖도록 되어있다. DevStatusReq와 DevStatusAns 명령을 이용하여 End-Device의 배터리 수준과 SNR 수신 신호 상태 값을 얻을 수 있다.<br />
우리 프로젝트에서는 RFU 영역인 CID 0x0E를 액추에이터 작동을 지시하는 명령(ActuatorReq, ActuatorAns)으로 따로 구현하여 사용하도록 했다.</p>
<p><strong>Network Server(Sink Node) 동작 및 기능</strong><br />
<span style="color: #99ccff"><strong>데이터 전송</strong></span><br />
싱크노드는 여러 게이트웨이에서 mosquitto 브로커를 통해 mqtt통신으로 들어온 센서노드별 데이터를 취합하여, 이를 백엔드 측의 데이터 큐인 Kafka로 전송해주는 역할을 한다.</p>
<p><span style="color: #99ccff"><strong>헬스체크를 위한 센서노드 상태체크 명령 전달</strong></span><br />
또한 센서노드들의 상태를 체크하는 것은 IoT플랫폼의 기능에 있어서 필수적이다.<br />
싱크노드에서는 주기적으로 센서노드들에게 DevStatusReq요청을 보내도록 “command/downlink/ActuatorReq/&lt;센서노드ID&gt;”토픽으로 MQTT 메시지를 발행하여 게이트웨이에서 센서노드들에게 DevStatusReq Mac Command를 전달하도록 한다. DevStatusAns을 정상적으로 답장한 센서노드들의 상태를 “정상”으로 판단하고 이를 백엔드의 헬스체크 서버에 알려준다.<br />
이러한 상태 체크 과정에서 배터리 상태와 SNR 수신 신호에 대한 정보를 알 수 있으며, 백엔드 서버에는 각 센서노드의 상태와 배터리 수준을 함께 알려준다.</p>
<p><span style="color: #99ccff"><strong>액추에이터 명령 수신 및 게이트웨이로 전달</strong></span><br />
백엔드 서버로부터 오는 명령으로 LED 또는 모터들을 제어할 수 있어야 한다. 싱크노드에서는 백엔드로부터 오는 명령을 Flask 웹서버에 들어온 HTTP요청으로 수신한다.<br />
Flask 웹서버로 수신한 HTTP 액추에이터 요청을 json 데이터와 함께 수신하면 싱크노드는 이를 “command/downlink/ActuatorReq/&lt;센서노드ID&gt;”토픽으로 MQTT 메시지를 발행한다. 센서노드 측에서는 명령을 받기 위해 “command/downlink/+/&lt;센서노드 ID&gt;”를 구독했기 때문에 MQTT프로토콜을 통해 액추에이터 명령을 받을 수 있다.</p>
<p><span style="color: #008080"><strong>3.4. 개발 환경</strong></span><br />
<span style="color: #ff9900"><strong> 3.4.1 개발언어 및 라이브러리</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-46.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40650" alt="67 ict 최우수상_스마트파크 (46)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-46-507x620.png" width="507" height="620" /></a></p>
<p><span style="color: #ff9900"><strong>3.4.2. 포트 포워딩</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-47.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40651" alt="67 ict 최우수상_스마트파크 (47)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-47.png" width="506" height="264" /></a></p>
<p><span style="color: #0000ff"><strong>4. 단계별 제작 과정</strong></span><br />
<span style="color: #008080"><strong> 4.1. 센서네트워크 구축</strong></span><br />
<span style="color: #ff9900"><strong> 4.1.1. 싱크노드 구현</strong></span><br />
싱크노드의 메인코드에서의 동작 순서이다.</p>
<p style="padding-left: 30px">1. Flask 웹서버 실행<br />
2. Kafka Producer 생성<br />
3. mqtt 클라이언트 생성<br />
4. HealthCheck를 담당, 관리하는 클래스 생성<br />
5. Actuator관련 동작을 담당하는 클래스 생성<br />
6. MQTT Callback함수 등록 및 MQTT Client의 Loop 시작<br />
7. HealthCheck를 위한 TCP 소켓 생성<br />
8. 쓰레드 생성-&gt;쓰레드 핸들러로 HealthCheck를 담당하는 함수 등록<br />
9. 헬스체크 쓰레드 시작</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-48.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40652" alt="67 ict 최우수상_스마트파크 (48)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-48.png" width="506" height="294" /></a></p>
<p><strong><span style="color: #ff9900">4.1.2. NodeMCU LoRa 연결</span></strong><br />
사용하는 LoRa 모듈(SX-1278)의 Pin 구성은 다음과 같다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-49.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40653" alt="67 ict 최우수상_스마트파크 (49)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-49.png" width="280" height="189" /></a></p>
<p>ANT에는 안테나를 연결한다. SCK는 SPI-Clock Input을 담당한다. MISO는 SPI-Data Out을 담당한다. MOSI는 SPI-Data In을 담당한다. NSS는 SPI-Chip Select를 담당한다.<br />
LoRa 통신 모듈과 NodeMCU간의 연결은 다음의 표와 같다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-50.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40575" alt="67 ict 최우수상_스마트파크 (50)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-50.png" width="505" height="261" /></a></p>
<p>나머지 디지털 핀과 아날로그 핀들은 센서나 LED, 모터제어를 위해 사용한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-51.png" rel="lightbox[40437]"><img alt="67 ict 최우수상_스마트파크 (51)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-51.png" width="258" height="390" /></a></p>
<p><span style="color: #ff9900"><strong>4.1.3. NodeMCU</strong></span><br />
<strong>LoRaWAN 코딩</strong><br />
NodeMCU의 LoRaWAN은 https://git.antares.id/lorawan-loraid/arduino-loraid의 코드를 뼈대로 하여 개선하였다. (지원가능한 주파수 채널 확장, MacCommand처리기능 추가, 수신이 되지 않는 문제 수정.)</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<table style="width: 620px" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-52.png" rel="lightbox[40437]"><img alt="67 ict 최우수상_스마트파크 (52)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-52.png" width="318" height="370" /></a></td>
<td><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-53.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40578" alt="67 ict 최우수상_스마트파크 (53)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-53-327x620.png" width="327" height="620" /></a></td>
</tr>
</tbody>
</table>
<p>다음은 LoRaWAN통신 코드이다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>#include &#8220;ToIoTwithLoRaWAN.h&#8221;<br />
#include &#8220;config.h&#8221;<br />
const sRFM_pins RFM_pins = {<br />
.CS = 10,<br />
.RST = 9,<br />
.DIO0 = 2,<br />
.DIO1 = 3,<br />
.DIO2 = -1,<br />
.DIO5 = -1,<br />
};ToIoTwithLoRaWAN t;<br />
double value = 0.0;<br />
void setup() {<br />
t.setupToIoTwithLoRaWAN(nodeId, interval, 0);<br />
// LoRaWAN //LoRaWAN Setting<br />
/*~~~중략~~~*/<br />
// Join procedure<br />
bool isJoined;<br />
do {<br />
Serial.println(&#8220;Joining&#8230;&#8221;);<br />
isJoined = lora.join();<br />
//wait for 3s to try again<br />
delay(3000);<br />
}while(!isJoined);<br />
Serial.println(&#8220;Joined to network&#8221;);<br />
}</p>
<p>void loop() {<br />
t.pub(&#8220;sensor-uuid-1&#8243;, 1, value);<br />
t.rcv();<br />
wdt_reset();<br />
}</p>
</div>
<p>현재 타이머 시간과 과거에 측정한 타이머 시간이 interval보다 크다는 것은 interval만큼 타이머 시간이 흘렀다는 것을 의미한다. 따라서 interval만큼의 시간을 주기로 하여 메시지를 송신하는 것이다.<br />
QOS 변수는 사용자가 설정하는 값으로 1이상일 때, ACK를 수신해야지만 다음 새로운 메시지를 전송하도록 한다. QOS==0 이라면, ACK 수신여부와 관계없이 새로운 메시지를 계속 전송한다.<br />
앞으로 센서노드는 위 LoRaWAN 통신코드를 베이스로 한다. 센서, 액추에이터에 대한 코드를 이 코드에 추가하여 가로등, 수목관리, 쓰레기통을 구현한다.</p>
<p><span style="color: #ff9900"><strong>4.1.4. 싱글채널 게이트웨이 제작과정</strong></span><br />
기존의 LoraWAN 게이트웨이를 국내에서 접하기는 어렵게 되어 있어서 접하기 쉽도록 라즈베리 파이를 이용한 싱글채널 게이트웨이를 직접 구현하기로 했다.<br />
LoRa 통신을 가능하게 해주는 LoRa 통신 모듈을 연결하기 위해 왼쪽 사진과 같이 납땜 작업을 했다. 오른쪽 사진과 같이 안테나를 통신 모듈에 연결하고 각 핀을 라즈베리파이에 연결했다.<br />
Lora 모듈과 라즈베리파이는 아래와 같이 연결했다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-54.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40579" alt="67 ict 최우수상_스마트파크 (54)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-54.png" width="566" height="297" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-55.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40580" alt="67 ict 최우수상_스마트파크 (55)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-55.png" width="570" height="292" /></a></p>
<p><span style="color: #ff9900"><strong>4.1.5. LoRa 게이트웨이(라즈베리파이) LoRaWAN 코딩</strong></span><br />
게이트웨이의 LoRaWAN 프로토콜을 다음과 같이 구조화하여 파이썬으로 구현했다.</p>
<p><span style="color: #00ccff"><strong>LoRaWAN 프로토콜 전체적인 코드 구성</strong></span><br />
다음은 Python으로 구현한 LoRaWAN프로토콜의 라이브러리 구조이다.<br />
· AES_CMAC.py: AES-128 암호화를 위한 함수들을 정의했다.<br />
· CID.py: Mac Command들의 Command ID를 정의했다. MacCommand처리를 위한 함수들을 정의했다.<br />
· Channel.py: 사용할 주파수 채널을 선택할 수 있도록 채널에 대한 정보들을 정의했다.<br />
· DataPayload.py: 데이터 페이로드(FRM Payload)를 처리하기 위한 클래스와 메소드를 정의했다.<br />
· Direction.py: Mac Header(MHDR)의 각 메시지들이 어떤 방향으로 향하는 메시지인지 정의하는 클래스와 메소드이다. (UP: 센서노드-&gt;게이트웨이 / DOWN: 게이트웨이-&gt;센서노드)<br />
· FHDR.py: Frame Header에 대한 클래스와 메소드를 정의한다.<br />
· JoinAcceptPayload.py: JoinAccept에 대한 메시지를 생성하거나 읽기 위한 Payload 처리코드<br />
· JoinRequestPayload.py:JoinRequest에 대한 메시지를 생성하거나 읽기 위한 Payload처리코드<br />
· LoRaMAC.py: 작업 상태를 정의하는 코드. (수신상태, 송신상태, 대기상태)<br />
· MHDR.py: Mac Header 정보들을 정의하는 클래스와 메소드<br />
· MacCommandPayload.py: MacCommand를 Frame Payload에 넣어서 전달하기 위한 코드<br />
· MacPayload.py: Mac Payload를 생성하거나 읽기 위한 코드<br />
· MalformedPacketException: 패킷 예외 처리에 대한 코드<br />
· PhyPayload.py: Physical Payload를 생성하거나 읽기 위한 코드</p>
<p><span style="color: #00ccff"><strong>LoRa WAN 프로토콜 코드 주요동작 순서</strong></span><br />
일반적인 데이터 수신과 송신의 Payload 처리는 다음과 같은 순서로 동작한다.<br />
PhyPayload.py-&gt;MacPayload.py-&gt;DataPayload.py (주요 코드 순서, 다른 코드는 생략) : 전원이 켜진 센서노드는 네트워크에 접속하기 위해 주기적으로 JoinRequest 신호를 전송한다.<br />
JoinRequest를 수신하게 되어 읽는 경우에는 다음과 같은 순서로 동작한다. : PhyPayload.py-&gt;MacPayload.py-&gt;JoinRequestPayload.py<br />
JoinAccept를 송신하는 경우에는 다음과 같은 순서로 동작한다. : PhyPayload.py-&gt;MacPayload.py-&gt;JoinAcceptPayload.py<br />
MacPayload를 송신하는 경우에는 다음과 같은 순서로 동작한다. : PhyPayload.py-&gt;MacPayload.py-&gt;MacCommandPayload.py</p>
<p><span style="color: #00ccff"><strong>센서노드(NodeMCU)와 게이트웨이간 LoRa통신 확인</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-56.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40581" alt="67 ict 최우수상_스마트파크 (56)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-56-515x620.png" width="515" height="620" /></a></p>
<p>위와 같이 센서노드와는 LoRaWAN통신을 하고 싱크노드와는 MQTT 통신을 한다.</p>
<p><span style="color: #ff9900"><strong>4.1.6. 헬스체크 구현</strong></span><br />
헬스체크는 센서노드의 상태를 체크하는 기능이다. 싱크노드(네트워크 서버)는 LoRaWAN 프로토콜의 Mac Command인 DevStatusReq를 센서노드로 주기적으로 전송하게 한다. 이를 주기적으로 처리하기 위해 HealthCheck 담당 쓰레드를 하나 만들어서 주기적으로 게이트웨이에게 명령을 전달해주고 TCP소켓을 열어 백엔드 측의 헬스체크 서버와 통신하도록 했다. 센서노드로부터 DevStatusAns의 응답을 정상적으로 수신하면 센서노드의 상태를 정상으로 판단하고 그렇지 않으면 불량으로 판단한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-57.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40582" alt="67 ict 최우수상_스마트파크 (57)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-57.png" width="566" height="122" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-58.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40583" alt="67 ict 최우수상_스마트파크 (58)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-58-555x620.png" width="555" height="620" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-59.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40584" alt="67 ict 최우수상_스마트파크 (59)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-59.png" width="566" height="144" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="color: #ff9900"><strong>4.1.7. 액추에이터 구현</strong></span><br />
센서노드가 액추에이터 명령인 ActuatorReq를 수신하면 받은 액추에이터 ID를 타켓으로 동작시켜야 한다. 액추에이터 명령 패킷은 다음과 같은 Payload를 갖는다.<br />
명령 메시지 구조 : Actuator ID, Sleep, Value, Sleep, Value, …<br />
Actuator ID는 동작시킬 액추에이터의 ID를 의미한다.(각각의 액추에이터는 자신의 ID를 갖는다.)<br />
Sleep은 액추에이터에 값을 넣어 실행시키기까지의 대기시간을 의미한다.<br />
Value는 액추에이터를 동작시키기 위한 값을 의미한다.<br />
아래는 액추에이터를 관리하기 위한 Actuator 구조체 정의부이다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>struct Actuator{<br />
int actuatorId;<br />
int value[6];<br />
unsigned long interval[6];<br />
unsigned long previousMillis= 0;<br />
short int running_index=0;<br />
bool run= false;<br />
short values_len= 0;<br />
};</p>
<p>&nbsp;</p>
</div>
<p>위에서 받은 액추에이터 명령 메시지를 위와 같은 구조체에 입력하여 관리하게 된다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>Void Loop(){<br />
If(millis() &#8211; previousMillis &gt; interval)<br />
{<br />
PreviousMillis = millis();<br />
~~~~~~~~~~<br />
}<br />
}</p>
</div>
<p>액추에이터에서 delay가 발생하더라도 LoRa통신에는 영향이 없도록 하기 위해 다음과 같이 루프문과 타이머를 이용하는 구조로 코드를 작성했다. 위의 코드에서 interval은 대기시간이다. previousMillis는 전에 저장한 타이머 시간을 의미한다. Millis() 함수는 현재 타이머 시간을 의미한다.<br />
즉, 위의 코드는 타이머 시간을 측정하여 interval에 저장된 시간만큼 지났을 때, if문 내부의 코드가 실행되는 구조이다. 액추에이터 동작 함수에도 LoRa에 지장이 가지 않도록 하기 위해 위의 구조를 적용했다.<br />
액추에이터의 경우 각자의 구조체 안에 자신만의 대기시간을 저장하는 interval 변수를 갖도록 하여 개별적으로 동작할 수 있다.</p>
<p><span style="color: #ff9900"><strong>4.1.8. 가로등 제작 과정</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-60.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40585" alt="67 ict 최우수상_스마트파크 (60)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-60.png" width="567" height="259" /></a><br />
먼저 가로등의 뼈대가 되는 모형에 4&#215;2 LED를 부착하고 LED의 밝기를 조절했다. LED의 밝기는 analogWrite()함수로 아날로그 신호를 주면 조절할 수 있다. 위 사진과 같이 밝기 조절을 테스트했다.<br />
다음으로 보행자 통행량을 측정하기 위한 PIR모션센서를 테스트했다. PIR 센서를 다음과 같이 LED 옆에 부착하고 NodeMCU와 연결하여 테스트했다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-61.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40586" alt="67 ict 최우수상_스마트파크 (61)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-61.png" width="569" height="318" /></a></p>
<p>일정 간격의 시간동안 모션이 감지되면 위와 같이 Welcome!이 출력된다.<br />
보행자 통행량 측정에 이 PIR 센서를 활용하기 위해서 주기적으로 이 모션이 감지되는 횟수가 얼마나 많은지 카운트를 누적하여 누적한 카운트 값을 백엔드 서버에 전해준다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-2.jpg" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40603" alt="67 ict 최우수상_스마트파크 (2)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-2.jpg" width="565" height="293" /></a></p>
<p>위는 바닥과 상단에 부착된 조도센서 사진이다. 왼쪽 사진은 부점등 확인을 위해 조도 센서를 가로등 바닥부분에 부착하였다. 기판에 저항과 cds센서를 납땜하여 연결했다. 오른쪽 사진은 밝기를 측정하기 위해 상단에 조도 센서를 부착하였다. 상단의 조도센서는 밤에 자동 점등, 아침에 자동 불을 끄기위해 달았다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-62.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40587" alt="67 ict 최우수상_스마트파크 (62)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-62.png" width="569" height="242" /></a></p>
<p>아날로그 핀에 연결하여 조도 센서값을 확인했다.<br />
다음은 가로등 센서노드의 메인 코드이다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>#include &#8220;ToIoTwithLoRaWAN.h&#8221;<br />
#include &#8220;config.h&#8221;<br />
/*~~~중략~~~*/<br />
ToIoTwithLoRaWAN t;<br />
double value = 0.0;<br />
// Actuator 2<br />
struct Actuator a2;<br />
Servo myservo;/<br />
/ PIR, CdS, LED 관련 핀 제어변수 선언<br />
/*~~~중략~~~*/<br />
void setup() {<br />
pinMode(pirPin, INPUT);<br />
pinMode(cdsPin1, INPUT);<br />
pinMode(cdsPin2, INPUT);<br />
pinMode(ledPin, OUTPUT);<br />
t.setupToIoTwithLoRaWAN(nodeId, interval, 0);<br />
// LoRaWAN Setting<br />
/*~~~중략~~~*/<br />
// Actuator setting a2.actuatorId = 2;<br />
// LED actuator<br />
// Join procedure bool isJoined;<br />
do {<br />
Serial.println(&#8220;Joining&#8230;&#8221;);<br />
isJoined = lora.join();<br />
//wait for 3s to try again<br />
delay(3000); }<br />
while(!isJoined);<br />
Serial.println(&#8220;Joined to network&#8221;);<br />
}<br />
void loop() {<br />
cdsVal1 = analogRead(cdsPin1);<br />
cdsVal2 = analogRead(cdsPin2);<br />
pirVal = digitalRead(pirPin);<br />
if (pirVal == HIGH) {<br />
if (pirState == LOW){<br />
Serial.println(&#8220;Welcome!&#8221;); // 시리얼 모니터 출력<br />
pirCnt=pirCnt+1.0;<br />
pirState = HIGH;<br />
}<br />
}<br />
else {<br />
if (pirState == HIGH){<br />
Serial.println(&#8220;Good Bye~&#8221;); // 시리얼 모니터 출력<br />
pirState = LOW;<br />
}<br />
}<br />
t.pub(&#8220;5,6,9&#8243;, 3, cdsVal1, pirCnt, cdsVal2);<br />
t.rcv();<br />
t.set_target_actuator(&amp;a2);<br />
t.actuator_LED(&amp;a2, ledPin);<br />
wdt_reset();<br />
}</p>
</div>
<p>세 가지 부품(LED, PIR센서, 조도센서)과 LoRa SX1278 모듈을 NodeMCU와 연결하고 위의 코드로 데이터가 잘 전달되는지 확인한다. LED 밝기 조절을 위해 LED를 액추에이터로 등록하여 액추에이터 ID를 2번으로 설정해주었다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-63.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40588" alt="67 ict 최우수상_스마트파크 (63)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-63.png" width="571" height="304" /></a></p>
<p><span style="color: #ff9900"><strong>4.1.9. 수목관리 시스템 제작 과정</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-3.jpg" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40605" alt="67 ict 최우수상_스마트파크 (3)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-3.jpg" width="568" height="592" /></a></p>
<p>먼저 시연을 위해 다음의 화분을 준비하였다. 토양수분을 측정하기 위한 센서를 NodeMCU보드와 연결이 편하도록 다음과 같이 기판에 부착하였다. NodeMCU는 LoRa통신 모듈과 연결돼있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-64.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40589" alt="67 ict 최우수상_스마트파크 (64)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-64.png" width="568" height="318" /></a></p>
<p>물을 주기 위해서는 수중모터와 수중모터를 제어하는 L9110s 모터드라이버를 사용했고, 수중모터를 LoRa통신으로 제어할 수 있도록 액추에이터로 등록했다. 코드 부분에서는 수중모터를 제어하기 위한 Actuator 구조체를 선언했다.<br />
액추에이터 신호가 왔을때 수중모터가 작동하여 물을 주는 것을 확인했다. 다음은 수목관리 센서노드의 코드이다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>#include &#8220;ToIoTwithLoRaWAN.h“<br />
#include &#8220;config.h&#8221;<br />
/*~~~중략~~~*/<br />
int IN1=D3; // A-IA연결 A<br />
int IN2=D1; // A-IB연결 /A<br />
int pin_A0 = A0;<br />
ToIoTwithLoRaWAN t;<br />
float value = 0.0;<br />
// Actuator Struct to use motor<br />
struct Actuator a1;</p>
<p>void setup() {<br />
t.setupToIoTwithLoRaWAN(nodeId, interval, 0);<br />
pinMode(pin_A0, INPUT);<br />
// Actuator Setting<br />
pinMode(IN1,OUTPUT);<br />
pinMode(IN2,OUTPUT);<br />
digitalWrite(IN1,LOW);<br />
digitalWrite(IN2,LOW);<br />
a1.actuatorId = 1;<br />
for(int i=0; i &lt; a1.values_len; i++)<br />
a1.value[i] = 0;<br />
// LoRaWAN Setting</p>
<p>/*~~~중략~~~*/<br />
// Join procedure<br />
bool isJoined;<br />
do {<br />
Serial.println(F(&#8220;Joining&#8230;&#8221;));<br />
isJoined = lora.join();<br />
Serial.println(isJoined);<br />
//wait for 3s to try again<br />
delay(3000);<br />
}while(!isJoined);<br />
delay(1);<br />
Serial.println(F(&#8220;Joined to network&#8221;));<br />
}<br />
void loop() {<br />
value = analogRead(A0);<br />
t.pub(&#8220;7&#8243;, 1, value);<br />
t.rcv();<br />
t.set_target_actuator(&amp;a1);<br />
t.actuator_L9110(&amp;a1, IN1, IN2);<br />
wdt_reset();<br />
}</p>
</div>
<p><span style="color: #ff9900"><strong>4.1.10. 쓰레기통 제작 과정</strong></span></p>
<p>다음과 같이 뚜껑에는 초음파 센서를 접착제를 이용해서 부착하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-4.jpg" rel="lightbox[40437]"><img alt="67 ict 최우수상_스마트파크 (4)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-4.jpg" width="283" height="333" /></a></p>
<p>Echo Pin은 디지털 핀 D1에 연결, Trig Pin은 디지털 핀 D3에 연결했다.<br />
다음은 쓰레기통 센서노드의 메인코드이다. 초음파 센서로 측정한 적재량 백분율 계산, LoRa통신 기능을 한다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>#include &#8220;ToIoTwithLoRaWAN.h&#8221;<br />
#include &#8220;config.h&#8221;<br />
/*~~~중략~~~*/<br />
int trigPin = D3;<br />
int echoPin = D1;<br />
ToIoTwithLoRaWAN t;<br />
void setup() {<br />
t.setupToIoTwithLoRaWAN(nodeId, interval, 0);<br />
pinMode(trigPin, OUTPUT);<br />
pinMode(echoPin, INPUT);<br />
// LoRaWAN Setting</p>
<p>/*~~~중략~~~*/<br />
// Join procedure<br />
bool isJoined;<br />
do {<br />
Serial.println(&#8220;Joining&#8230;&#8221;);<br />
isJoined = lora.join();<br />
Serial.println(isJoined);<br />
//wait for 3s to try again<br />
delay(3000);<br />
}while(!isJoined);<br />
delay(1);<br />
Serial.println(&#8220;Joined to network&#8221;);<br />
}<br />
double MyPreviousMillis;<br />
double MyInterval = 10;<br />
double distance;<br />
double MAX_distance=18.0;<br />
void ultrasound() {<br />
float duration;<br />
if(millis() &#8211; MyPreviousMillis &gt; MyInterval) {<br />
digitalWrite(trigPin, LOW);<br />
delayMicroseconds(2);<br />
digitalWrite(trigPin, HIGH);<br />
delayMicroseconds(10);<br />
digitalWrite(trigPin, LOW);<br />
// echoPin 이 HIGH를 유지한 시간을 저장 한다.<br />
duration = pulseIn(echoPin, HIGH);<br />
// HIGH 였을 때 시간(초음파가 보냈다가 다시 들어온 시간)을 가지고 거리를 계산 한다.<br />
// 340은 초당 초음파(소리)의 속도, 10000은 밀리세컨드를 세컨드로, 왕복거리이므로 2로 나눠준다.<br />
distance = ((double)(340 * duration) / 10000) / 2;<br />
MyPreviousMillis = millis();<br />
}<br />
}<br />
double value;<br />
void loop() {<br />
ultrasound();<br />
value = ((MAX_distance &#8211; distance)/MAX_distance)*100;<br />
t.pub(&#8220;8&#8243;, 1, value);<br />
t.rcv();<br />
wdt_reset();<br />
}</p>
</div>
<p>수직으로 쓰레기통 바닥을 향해 거리를 측정하여 값이 작아질수록 쓰레기가 쌓인 것이다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-65.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40590" alt="67 ict 최우수상_스마트파크 (65)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-65.png" width="568" height="340" /></a></p>
<p>하지만 이 거리값을 cm단위로 그대로 전달하지 않고 적재된 양을 100분율로 계산하여 서버에 전달한다. 계산은 다음과 같다. (쓰레기 적재량 데이터의 단위는 %.)<br />
Value = (쓰레기통 바닥까지의 거리 &#8211; 측정된 거리) / (쓰레기통 바닥까지의 거리) * 100</p>
<p><span style="color: #008080"><strong>4.2. 데이터 스트리밍 시스템 구축</strong></span><br />
<span style="color: #ff9900"><strong>4.2.1. Data Logic 서비스</strong></span><br />
Kafka에 적재된 데이터를 DataLogic서비스로 consume후 Unmarshal하여 DataLogic내의 구조체에 저장할 수 있도록 consumer를 생성한다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>func NewKafkaConsumer() *group {<br />
//&#8212;중략&#8212;<br />
// kafkaConsumer 설정<br />
cfg := sarama.NewConfig()<br />
cfg.Version = sarama.V0_10_2_0<br />
cfg.Consumer.Offsets.Initial = sarama.OffsetNewest<br />
// kafkaConsumer 생성<br />
kafkaConsumer.client, err = sarama.NewConsumerGroup([]string{setting.Kafkasetting.Broker}, setting.Kafkasetting.GroupID, cfg)<br />
if err != nil {<br />
panic(err)<br />
}<br />
// &#8212;중략&#8212;<br />
go func() {<br />
for {<br />
// kafka로부터 데이터 Consume<br />
= err = kafkaConsumer.client.Consume(ctx, setting.Kafkasetting.Topics, &amp;consumer)<br />
if err != nil {<br />
log.Panicf(&#8220;Error from consumer: %v&#8221;, err)<br />
}<br />
if ctx.Err() != nil {<br />
return<br />
}<br />
consumer.ready = make(chan bool)<br />
}<br />
}()<br />
return kafkaConsumer<br />
}</p>
</div>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-66.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40591" alt="67 ict 최우수상_스마트파크 (66)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-66.png" width="567" height="59" /></a></p>
<p>메모리에 저장되어있는 등록정보를 데이터에 추가 할 수 있도록 한다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>func (lcuc *logicCoreUsecase) ToLogicData(kd *model.KafkaData) (model.LogicData, error) {<br />
n, err := lcuc.rr.FindNode(kd.NodeID) // NodeID를 key로 검색하여 해당 Node의 메타데이터를 가져옴<br />
//&#8211;중략&#8211;<br />
s, err := lcuc.rr.FindSensor(kd.SensorID) // SensorID를 key로 검색하여 해당 Sensor의 메타데이터를 가져옴<br />
//&#8211;중략&#8211;<br />
vl := map[string]float64{}<br />
for i, v := range s.SensorValues {<br />
vl[v] = kd.Values[i] // Kafaka로 읽은 센서 데이터 값 map에 넣음<br />
}<br />
return model.LogicData{ // 등록정보 추가된 센서 데이터 return<br />
SensorID: kd.SensorID,<br />
SensorName: s.Name,<br />
Values: vl,<br />
Node: *n,<br />
Timestamp: kd.Timestamp,<br />
}, nil<br />
}</p>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-90.png" rel="lightbox[40437]"><img class="alignnone  wp-image-40657" alt="67 ict 최우수상_스마트파크 (90)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-90-620x69.png" width="520" /></a></p>
<p>해당 센서값이 설정된 이벤트 조건을 만족하는지 검사한다. 로직을 만족할 경우 이벤트를 실행한다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>func (ve *ValueElement) Exec(d *model.LogicData) {<br />
// &#8211;중략&#8211;<br />
for _, rg := range ve.Range {<br />
if rg.Min &lt;= v &amp;&amp; v &lt; rg.Max { //value가 등록한 조건을 충족하는지 검사<br />
isRange = true<br />
}<br />
}<br />
if isRange {<br />
ve.BaseElement.Exec(d) //충족할 경우 다음으로 등록된 Filter혹은 Action 수행<br />
}<br />
}</p>
<p>func (ae *ActuatorElement) Exec(d *model.LogicData) {<br />
// &#8211;중략&#8211;<br />
if ok {<br />
ae.Interval[d.Node.Name] = false<br />
go func() {</p>
<p>res := Actuator{ // Actuator에게 전할 명령 객체 생성<br />
Nid: d.Node.Nid,<br />
Aid: ae.Aid,<br />
Values: ae.Values,<br />
}<br />
pbytes, _ := json.Marshal(res)<br />
buff := bytes.NewBuffer(pbytes) // 명령을 buffrer에 담음<br />
addr := (*adapter.AddrMap)[d.Node.Sid] // 등록정보로 부터 해당 노드의 Sink주소 가져옴</p>
<p>// Sink 라즈베리파이의 Flask 서버로 동작명령 Post<br />
resp, err := http.Post(&#8220;http://&#8221;+addr.Addr+&#8221;/actuator&#8221;, &#8220;application/json&#8221;, buff)<br />
if err != nil {<br />
panic(err)<br />
}<br />
defer resp.Body.Close()<br />
}()<br />
// &#8211;중략&#8211;<br />
}<br />
}</p>
</div>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-67.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40592" alt="67 ict 최우수상_스마트파크 (67)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-67.png" width="568" height="61" /></a></p>
<p>등록정보가 포함되어 완성된 데이터를 엘라스틱 서치에 인덱싱 한다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>func (ec *client) insertDoc(d *model.Document) {<br />
ec.docBuf = append(ec.docBuf, d) // 버퍼에 데이터 적재<br />
if len(ec.docBuf) &gt;= (ec.bufSize &#8211; 10) { // 데이터 개수가 일정 수준에 달하면<br />
ec.bulk() // 벌크 인덱싱 실행<br />
}<br />
}</p>
</div>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-68.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40593" alt="67 ict 최우수상_스마트파크 (68)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-68.png" width="571" height="307" /></a></p>
<p><span style="color: #ff9900"><strong>4.2.2. Health Check 서비스</strong></span><br />
각 Sink로부터 헬스 정보를 받는다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-69.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40594" alt="67 ict 최우수상_스마트파크 (69)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-69.png" width="568" height="84" /></a></p>
<p>받은 헬스 정보 중 변경 사항이 있는 노드의 헬스 정보만을 버퍼에 추가하여 웹소켓을 통해 front-end로 보낼 수 있도록 한다.<br />
버퍼에 담긴 헬스 정보를 프론트 엔드로 전송한다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>// 어답더 계층의 NodeState상태와 메모리 계층의 statusRepo의 status table을 동기화시켜 주는 것<br />
func (sr *statusRepo) updateNodeStatus(sinkID int, ns []adapter.NodeState, t time.Time) []model.NodeStatus {<br />
// &#8211;중략&#8211;<br />
// update the status checked from the sink node<br />
for _, v := range ns { // v는 NodeSate 배열 중 한 원소<br />
nsTable[v.NodeID] = true<br />
nodeState, ok := sr.table[sinkID][v.NodeID]
// if new nodeState, regist new state<br />
if !ok {<br />
tempState := model.NewStatus(v.State, t)<br />
sr.table[sinkID][v.NodeID] = tempState<br />
res = append(res, model.NodeStatus{NodeID: v.NodeID, State: tempState.State, Battery: v.Battery})<br />
continue<br />
}<br />
if isChanged := nodeState.UpdateState(v.State, t); isChanged { // 헬스정보가 변경되었을 경우 res배열에 추가<br />
res = append(res, model.NodeStatus{NodeID: v.NodeID, State: nodeState.State, Battery: v.Battery})<br />
}<br />
sr.table[sinkID][v.NodeID] = nodeState // 상태 테이블(map)에 상태 저장<br />
}<br />
// &#8211;중략&#8211;<br />
return res<br />
}</p>
</div>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-70.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40595" alt="67 ict 최우수상_스마트파크 (70)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-70.png" width="569" height="60" /></a></p>
<p><span style="color: #008080"><strong>4.3. 웹 프론트 환경 구축</strong></span><br />
<span style="color: #ff9900"><strong> 4.3.1 노드 마커</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>addMarker(position: any, map: any) {<br />
if ( position.kind === &#8216;streetlemp&#8217;) var imageSrc = &#8216;https://user-images.githubusercontent.com/50009240/111455569-4edede80-8759-11eb-952f-2df28fdcdc4c.png&#8217;<br />
else if ( position.kind === &#8216;trashcan&#8217;) var imageSrc = &#8216;https://user-images.githubusercontent.com/50009240/111451567-e857c180-8754-11eb-9299-0ea55e430b17.png&#8217;<br />
else var imageSrc = &#8216;https://user-images.githubusercontent.com/50009240/111451575-ebeb4880-8754-11eb-8459-eed8f0983c55.png&#8217;</p>
<p>var imageSize = new window.kakao.maps.Size(30 , 35),<br />
markerImage = new window.kakao.maps.MarkerImage(imageSrc, imageSize), // 마커이미지 생성<br />
marker = new window.kakao.maps.Marker({<br />
map: map,<br />
position: position.latlng, // 마커의 위치<br />
image: markerImage // 마커 이미지<br />
});<br />
return marker;<br />
}</p>
</div>
<p>카카오맵 api를 사용해 지도 및 지도 위 마커를 나타냈다. addMarker 함수의 파라미터로 받은 position는 노드 이름, 종류, 정보(싱크, 센서, id), 지도 내 좌표를 포함하고 있다. 따라서 노드의 종류에 따라 마커 이미지를 다르게 했고, 해당 노드의 지도 내 좌표에 마커를 생성했다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-71.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40596" alt="67 ict 최우수상_스마트파크 (71)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-71.png" width="570" height="265" /></a></p>
<p><span style="color: #ff9900"><strong>4.3.2. rest api</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>componentDidMount() {<br />
this.getsensorList(); // 센서리스트 GET하는 함수<br />
this.getsinkList(); // 싱크리스트 GET하는 함수<br />
}</p>
<p>// Get sensor list from backend<br />
getsensorList() {<br />
var url = SENSOR_URL;</p>
<p>fetch(url)<br />
.then((res) =&gt; res.json())<br />
.then((data) =&gt; {<br />
this.setState({ sensorList: data }); // 얻은 데이터를 sensorList에 저장<br />
})<br />
.catch((error) =&gt; console.error(&#8216;Error:&#8217;, error));<br />
}</p>
</div>
<p>위는 백으로부터 센서 리스트를 GET해오는 코드이다. component DidMount는 컴포넌트가 화면에 나타나게 됐을 때 호출된다. 여기서 fetch()를 통해 해당 url로부터 노드 리스트, 센서 리스트 등의 정보를 GET한다. 백으로부터 얻은 데이터는 해당 구조체에 저장해 사용한다. 위 코드와 같이 REST API를 통해 백으로부터 정보를 얻어오고, 센서, 노드 등을 등록할 시 REST API (POST)를 사용해 백으로 정보를 보냈다.</p>
<p><span style="color: #ff9900"><strong>4.3.3. 헬스 체크</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>export interface nodeHealthCheckElem {<br />
nid: number;<br />
state: number;<br />
battery: number;<br />
}</p>
</div>
위는 HealthCheck 구조체이다. 각 노드의 헬스 상태를 가져와야 하므로 노드의 id인 nid, 연결 상태를 의미하는 state, 배터리 상태인 battery로 구조체가 이루어져 있다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>&nbsp;</p>
<p>import { w3cwebsocket as W3CWebSocket } from &#8216;websocket&#8217;;<br />
const client = new W3CWebSocket(HEALTHCHECK_URL) // 웹소켓 오브젝트 생성</p>
<p>componentWillMount() {<br />
client.onopen = () =&gt; { // 웹소켓 연결 확인<br />
console.log(&#8216;WebSocket Client for Health Check Connected&#8217;);<br />
};<br />
client.onmessage = (message: any) =&gt; {//서버로부터 수신된 메시지 전달<br />
console.log(message);<br />
this.setState({<br />
nodeState: JSON.parse(message.data),<br />
// 헬스정보 nodeState에 저장<br />
});<br />
this.getHealthStateMap(); // health map update<br />
this.getBatteryStateMap(); // battery map update<br />
};<br />
}</p>
</div>
<p>위는 웹소켓을 통해 헬스와 배터리 상태를 얻어오는 코드이다. ‘const client = new W3CWebSocket(HEALTHCHECK_URL);’ 를 통해 새 웹소켓 오브젝트를 생성하고, onopen 핸들러로 연결이 수립되었는지 확인한다. WebSockets는 event-driven API로써 메시지가 수신되면 “message” 이벤트가 onmessage 함수로 전달되게 된다. 따라서 백으로부터 받은 노드 id, health, battery 정보가 onmessage 함수로 전달되고, 이를 nodeState에 저장한다. 그 후 getHealthStateMap(), getBatteryStateMap() 함수에서 nodeState를 바탕으로 각각 health, battery 정보가 저장되어 있는 map을 업데이트 한다. 각 map에 저장된 health, battery 정보를 토대로 nodeTable, MapNodeTable에서 상태를 나타낸다.</p>
<p><span style="color: #0000ff"><strong>5. 회로도</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-72.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40597" alt="67 ict 최우수상_스마트파크 (72)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-72.png" width="574" height="366" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-73.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40598" alt="67 ict 최우수상_스마트파크 (73)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-73.png" width="565" height="358" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-74.png" rel="lightbox[40437]"><img class="alignnone size-full wp-image-40599" alt="67 ict 최우수상_스마트파크 (74)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-74.png" width="557" height="356" /></a></p>
<p><span style="color: #0000ff"><strong>6. 임시 데이터 프로듀싱 서버</strong></span></p>
<p><span style="color: #008080"><strong>6.1. 기능</strong></span><br />
실제로 모든 공원에 센서를 설치하여 데이터를 얻는 것은 매우 어려우므로 실제 공공 통계 데이터를 처리 및 프로듀싱 하여 데이터 실시간 스트리밍 및 시각화, 매니지먼트 기능의 데모를 구현한다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-75.png" rel="lightbox[40437]"><img class="alignnone size-large wp-image-40600" alt="67 ict 최우수상_스마트파크 (75)" src="http://www.ntrexgo.com/wp-content/uploads/2021/08/67-ict-최우수상_스마트파크-75-620x148.png" width="620" height="148" /></a></p>
<p><span style="color: #008080"><strong>6.2. OPEN DATA</strong></span><br />
<span style="color: #00ccff"><strong>서울 열린 데이터 광장</strong></span><br />
· 스마트서울 도시데이터 센서(S-DoT) 환경정보<br />
· 미세먼지, 온도, 습도, 조도<br />
· 서울시 한강공원 이용객 현황 통계<br />
· 월별 한강공원 이용객</p>
<p><span style="color: #00ccff"><strong>기상자료개방포털</strong></span><br />
· 농업기상관측 정보<br />
· 토양수분</p>
<p><span style="color: #0000ff"><strong>7. 참고문헌 및 출처</strong></span><br />
· 카카오맵 api : https://apis.map.kakao.com/web/sample/multipleMarkerEvent2/<br />
· 서울 열린 데이터 광장 &#8211; 스마트서울 도시데이터 센서(S-DoT) 환경정보 https://opengov.seoul.go.kr/data/20303041<br />
· 서울 열린 데이터 광장 &#8211; 서울시 한강공원 이용객 현황 통계 https://data.seoul.go.kr/dataList/10798/S/2/datasetView.do<br />
· 기상자료개방포털 &#8211; 농업기상관측(AAOS) https://data.kma.go.kr/data/grnd/selectAgrRltmList.do?pgmNo=72<br />
· 대구 스마트공원 기사 : http://news.khan.co.kr/kh_news/khan_art_view.html?art_id=201709151701001<br />
· 세종 스마트공원 기사 :https://www.korea.kr/news/visualNewsView.do?newsId=148850085<br />
· LoRaWAN v1.0.4 Alliance-Specification 문서 : https://lora-alliance.org/resource_hub/lorawan-104-specification-package/<br />
· LoRaWAN Alliance-Specification 문서 : https://lora-alliance.org/wp-content/uploads/2020/11/lorawantm_specification_-v1.1.pdf<br />
· LoRaWAN Alliance-What-is-lorawan 문서 : https://lora-alliance.org/wp-content/uploads/2020/11/what-is-lorawan.pdf</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ntrexgo.com/archives/40437/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[61호]시각장애인을 위한 음성 안내 버스표지판</title>
		<link>http://www.ntrexgo.com/archives/38621</link>
		<comments>http://www.ntrexgo.com/archives/38621#comments</comments>
		<pubDate>Wed, 26 Aug 2020 00:00:36 +0000</pubDate>
		<dc:creator>디바이스마트 매거진</dc:creator>
				<category><![CDATA[디바이스마트 매거진]]></category>
		<category><![CDATA[특집]]></category>
		<category><![CDATA[61호]]></category>
		<category><![CDATA[ict]]></category>
		<category><![CDATA[공모전]]></category>
		<category><![CDATA[디바이스마트]]></category>
		<category><![CDATA[매거진]]></category>
		<category><![CDATA[융합]]></category>
		<category><![CDATA[최우수상]]></category>
		<category><![CDATA[프로젝트]]></category>

		<guid isPermaLink="false">http://www.ntrexgo.com/?p=38621</guid>
		<description><![CDATA[디바이스마트매거진 61호 &#124; 기존 버스정류시설은 시각장애인에게 많은 불편함을 야기시키고 있으며 이를 해결할 시스템이 필요하다고 생각된다.]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-30-02-020.png" rel="lightbox[38621]"><img class="alignnone size-large wp-image-38833" alt="Cap 2020-10-23 16-30-02-020" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-30-02-020-620x175.png" width="620" height="175" /></a></p>
<p><strong>2020 ICT 융합 프로젝트 공모전 최우수상</strong></p>
<p><span style="font-size: x-large"><strong>시각장애인을 위한 음성 안내 버스표지판</strong></span></p>
<p style="text-align: right">글 | 인하대학교 박민아, 이상우, 이승화</p>
<p><span style="color: #0000ff"><strong>1. 심사평</strong></span><br />
<strong>칩센</strong> 데모에서도 인천시 Bus API를 사용하였듯이 기존 시스템과 연계를 하기 위해서는 보완해야 하는 사항이 많아 보이지만, 이러한 부분을 제외한 장치 자체로는 명확한 목적성을 가진 작품으로 생각됩니다. 기획한 의도에 따른 동작을 보여주긴 하였으나, 비콘등의 무선 장치가 절대적인 데이터를 가지거나, 정확한 거리 측정 등을 할 수가 없으므로 이를 보완할 수 있는 방안을 장치에 어떻게 도입할지에 대한 고민이 필요해 보입니다.<br />
<strong>펌테크</strong> 세심한 관찰력이 반영된 실생활과 밀접한 아이디어와 실용성이 우수한 작품이라고 생각합니다. 기획 의도에 맞게 전체 시스템을 안정적이고 완성도 높게 구현하였고 제출된 보고서 구성 내용도 명확하고, 충실했다고 생각이 듭니다. 전체적으로 기획 의도, 기술 구현도, 완성도 등에서 상당히 뛰어나고 상업적으로 손색이 없는 우수한 작품으로 생각됩니다.<br />
<strong>위드로봇</strong> 실제 필요한 기능을 잘 구현한 작품입니다. 좀 더 다듬으면 실제 상품화도 가능할 것으로 보입니다.</p>
<p><span style="color: #0000ff"><strong>2. 작품 개요</strong> </span><br />
<span style="color: #008080"><strong>2.1. 배경 및 목적</strong></span><br />
21세기에 들어 장애인과 같은 교통약자들의 사회참여 욕구 및 기회가 증가하면서 이들을 위한 이동수단의 확보와 교통정보제공 문제가 사회적 이슈로 대두되고 있다.[1] 그러나 장애인을 위한 대중교통 서비스는 많은 불편함을 호소하며 해결되지 않은 문제로 남아있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-30-903.png" rel="lightbox[38621]"><img alt="Cap 2020-10-23 16-35-30-903" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-30-903.png" width="620" height="290" /></a></p>
<p>&lt;표 1&gt;에 따르면 시각장애인은 통행 중에 다른 통행자들에게 도움을 받는 비중이 가장 큰 것으로 나타났다. 시각장애인은 스스로 버스정류장의 정보를 알아내기에 많은 제약이 있는 것을 확인할 수 있었다. 또한 &lt;표 2&gt;에 따르면 대중교통의 안전도 또한 불만족의 경우가 많았다. 지하철의 경우와 비교할 때 만족도의 차이가 매우 컸으며 버스정류장 및 버스 시설의 개선이 이루어져야 할 것으로 확인된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-39-871.png" rel="lightbox[38621]"><img class="alignnone size-full wp-image-38835" alt="Cap 2020-10-23 16-35-39-871" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-39-871.png" width="620" height="511" /></a><br />
MBC 뉴스에서도 실제 버스를 이용하는데 어려움을 겪는 사례를 소개하였다. 시각장애인은 버스 정류시설을 이용하며 도착 버스를 확인하지 못해 혼동을 느끼고 있었으며 이렇게 버스 탑승에 어려움을 겪기 때문에 보통 30~40분의 시간을 허비한다고 대답하였다.<br />
이를 통해 일반 버스정류시설은 시각장애인에게 많은 불편함을 야기시키고 있으며 이를 해결할 시스템이 필요하다고 생각되었다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-45-887.jpg" rel="lightbox[38621]"><img class="alignnone size-full wp-image-38836" alt="Cap 2020-10-23 16-35-45-887" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-45-887.jpg" width="620" height="359" /></a></p>
<p><span style="color: #008080"><strong>2.2. 문제인식</strong> </span><br />
한 시각장애인 단체에서 청와대 국민청원에 시각장애인의 버스 탑승 문제에 있어 개선이 필요하다는 청원을 발의하였다.[3] 이 청원에 따르면 시각장애인 버스 탑승에 있어 문제점은 크게 두가지이다.</p>
<p>(1) 버스정류장 정보를 알 수 없다.<br />
시각장애인이 버스정류장에 도착했을 때 해당 정류장이 어느 정류장인지 확인하기 어렵고, 이 때문에 도착하는 버스 정보를 쉽게 파악하기 어렵다.<br />
(2) 버스번호를 파악할 수 없다.<br />
시각장애인이 버스 도착 정보를 알 수가 없어 버스 탑승에 어려움을 겪는다. 정류장에서 &#8216;&#8211;번 버스가 곧 도착합니다.&#8217;라는 안내음이 송출된다고 할지라도 버스가 안내된 순서대로 진입하지 않거나, 많은 버스가 한꺼번에 오는 경우 때문에 특정 버스에 탑승하기 어렵다.</p>
<p><span style="color: #008080"><strong>2.3. 해결방안</strong></span><br />
앞서 제시된 문제를 해결하기 위해 음성인식 기반 버스표지판을 제시하였다. 현재 대부분의 버스정류장에는 이미 음성안내 시스템이 존재하지만 기존 시스템의 문제점은 사용자가 알 수 있는 정보가 오직 잠시 후 도착하는 버스 안내밖에 없다는 것이다. 정류장에 정차하는 버스 정보나 버스가 몇분 후 도착하는지는 시각적인 정보로만 제공되기 때문에 시각장애인이 이용하는 데에는 어려움이 존재한다.<br />
따라서 기존 버스정류장 안내 시스템의 한계를 극복하고 시각장애인이 버스탑승 시 느끼는 불편함을 해결하기 위해 음성인식을 기반으로 시각장애인에게 원하는 정보를 제공하는 시스템을 택하였다. 이 시스템에 대한 간략한 도식은 다음과 같다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-55-137.png" rel="lightbox[38621]"><img class="alignnone size-full wp-image-38837" alt="Cap 2020-10-23 16-35-55-137" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-35-55-137.png" width="620" height="422" /></a></p>
<p>음성안내 버스표지판이 동작하는 방식은 먼저 시각장애인이 비콘을 소지한 상태에서 버스 정류장에 다가가면 버스 음성 안내가 시작된다. 이후 탑승하려는 버스 번호를 마이크에 말하면 이를 인식해 해당 정류장에 정차하는지 여부를 알려주고 남은 시간이 몇분인지 알려준다. 이 탑승버스 번호는 LED에 점등되어 버스 운전기사가 인식하여 시각장애인이 대중교통 서비스를 타는것을 돕도록 한다. 이 정보는 버스기사 뿐만 아니라 주위 사람들도 의식적으로 시각적인 확인이 가능하기 때문에 현재처럼 버스가 오더라도 탑승하지 못하는 문제를 해결할 수 있을 것으로 보인다.</p>
<p><span style="color: #0000ff"><strong>3. 작품 설명</strong></span><br />
<span style="color: #008080"><strong>3.1. 주요 동작 및 특징</strong></span></p>
<div id="attachment_38838" class="wp-caption alignnone" style="width: 304px"><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-36-01-994.png" rel="lightbox[38621]"><img class="size-large wp-image-38838" alt="Cap 2020-10-23 16-36-01-994" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-36-01-994-294x620.png" width="294" height="620" /></a><p class="wp-caption-text">그림3. &lt;전체 시스템 동작 순서도&gt;</p></div>
<p>(1) 사용자 접근 : 하드웨어 사용 전력을 최소화하고 시스템의 남용을 방지하기 위하여 사용자(비콘) 접근시에만 하드웨어가 켜지도록 한다. 사용자가 3m이내에 있는 경우에는 하드웨어에서 “&#8211;정류장 입니다.” 소리가 발생하여 정류장 위치를 알리도록 한다.<br />
(2) 탑승 버스 인식 : 표지판에 접근하여 탑승하려는 버스 번호를 마이크에 말하면 버스번호와 도착 예상 시간을 안내한다. 또한 이렇게 인식된 버스 번호는 LED에 표시된다.<br />
(3) 버스 안내 : 버스가 정류장에 도착 예정시 잠시후 도착한다는 안내 메세지를 출력한다. 버스기사는 LED를 통해 탑승하려는 사용자가 있는것을 인지하여 사용자의 탑승을 돕는다.</p>
<p><span style="color: #008080"><strong>3.2. 전체 시스템 구성</strong> </span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-37-42-886.png" rel="lightbox[38621]"><img class="alignnone size-full wp-image-38839" alt="Cap 2020-10-23 16-37-42-886" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-37-42-886.png" width="620" height="387" /></a></p>
<p>라즈베리파이는 서버로부터 버스정보를 받아오고 음성 텍스트 변환 및 텍스트 음성 변환을 제어한다. 텍스트-&gt;음성 변환 파일은 라즈베리파이 상에 저장되므로 스피커는 라즈베리파이에서 출력되도록 한다.<br />
비콘은 단뱡항 통신으로 페어링이 필요하지 않고 비교적 넓은 범위에서부터 인식가능 하고, 비용적인 측면을 고려해서 통신모듈로 사용하였다. 단, 비콘과 LCD에 대해서는 효율적인 구성 코드 효율적인 사용을 위해 아두이노를 이용하여 제어하였다.<br />
버스 정보 데이터셋은 공공데이터포털(www.data.go.kr)에서 제공하는 인천광역시 버스 정보를 사용하였다. 내부 알고리즘을 간소화하기 위해 데이터를 DB화 하지 않고 필요시에 요청하는 형식을 선택하였다.</p>
<p><span style="color: #0000ff"><strong>4. 단계별 제작 과정</strong></span><br />
<span style="color: #008080"><strong>4.1. 간트 차트</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-37-48-304.png" rel="lightbox[38621]"><img class="alignnone size-full wp-image-38840" alt="Cap 2020-10-23 16-37-48-304" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-37-48-304.png" width="620" height="437" /></a></p>
<p><span style="color: #008080"><strong>4.2. 제작 과정</strong></span><br />
<span style="color: #33cccc"><strong>4.2.1. 하드웨어</strong></span><br />
아래 첨부한 사진 순서대로 스피커, 마이크 그리고 라즈베리파이를 표지판 내부에 넣고 외부에는 시각장애인 마크 및 LED만 확인할 수 있도록 만들었다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-37-57-070.png" rel="lightbox[38621]"><img class="alignnone size-full wp-image-38841" alt="Cap 2020-10-23 16-37-57-070" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-37-57-070.png" width="620" height="403" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-38-05-537.png" rel="lightbox[38621]"><img class="alignnone size-full wp-image-38842" alt="Cap 2020-10-23 16-38-05-537" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-38-05-537.png" width="620" height="507" /></a></p>
<p><span style="color: #33cccc"><strong>4.2.2. 소프트웨어 개발환경</strong></span><br />
Raspberry Pi B<br />
- 개발 언어: Python<br />
- Tool: terminal<br />
- 사용 시스템<br />
1) Google Cloud Platform (Sound To Text &amp; Text To Sound)<br />
2) 인천 Bus API</p>
<p><span style="color: #0000ff"><strong>5. 기대효과</strong></span><br />
<strong>사회적 측면</strong><br />
대중교통 또는 여객시설은 누구나 이용할 수 있는 공공재이다. 하지만 현재 국내의 대중교통 시설과 건물들은 비장애인들에게 초점이 맞춰져 있기 때문에 장애인들은 교통 수단 이용에 많은 제약을 받고 있다. 이동권의 제한은 개인적, 사회적 욕구를 원천적으로 제거시키는 것으로까지 이어진다. 따라서 이동권 관련 문제는 단순히 물리적 제약과 관련 된 것이 아니라 인간의 기본적인 권리와도 연관된 사회적인 문제로 볼 수 있다.[4] 따라서 시각장애인을 위한 음성 안내 버스표지판을 통해 시각장애인의 기본적 권리를 보장하며 사회참여 기회를 증진시킬 수 있을 것이다.</p>
<p><strong>경제적 측면</strong><br />
하나의 표지판 당 기기의 개발비용은 약 10만원 전후로 생산이 가능할 것으로 예상된다. 비용 사용 목록은 다음과 같다. 라즈베리파이3 (Model B+ 기준 40,000원) + LED 표시등 + 비콘(HM-10 Module 기준 8000원)로 측정할 수 있다. 이때 공공재 안내 표지판 및 표지판을 설치하는 비용은 지방 정부나 정부의 보조를 생각하여 제외하고 예상 비용을 측정했다. 동시에 많은 기기를 만들어 내면 더욱 저렴한 금액으로 시각장애인에게 쉽게 도움이 될 수 있다.<br />
인천시 버스 정류장의 개수는 5908개(출처: https://www.data.go.kr/, 인천광역시 버스노선별 정류장 현황, 통계 기준일 2020년 1월)이 기기 한개 생산 단가를 약 10만원으로 가정할 때 5억 908만원으로 한 해의 버스재정지원액의 0.0023%를 넘지 않을 것으로 예측할 수 있었다. 이를 확인하더라도 충분한 발전가능성과 효율을 가지고 있다고 할 수 있다. (출처:https://www.incheon.go.kr/open/OPEN030101)</p>
<p><span style="color: #0000ff"><strong>6. 시연영상</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-38-21-713.jpg" rel="lightbox[38621]"><img class="alignnone size-large wp-image-38843" alt="Cap 2020-10-23 16-38-21-713" src="http://www.ntrexgo.com/wp-content/uploads/2020/08/Cap-2020-10-23-16-38-21-713-329x620.jpg" width="329" height="620" /></a></p>
<p><span style="color: #0000ff"><strong>7. 개선방안</strong></span><br />
시각장애인을 위한 음성안내 표지판에는 몇 가지 개선사항이 존재한다.<br />
1) 라즈베리파이3를 이용하여 표지판을 만들기 때문에 전력의 사용이 원할해야 한다. 마이크로 5핀을 통해 전력을 충분히 끌어 낼 수 있어야 하기 때문에 기존 버스정류장 내의 전력을 이용할 수 있다면 상용화하는데 더 수월할 것이라고 생각한다.<br />
2) LED 제작에 있어서 비용적인 측면에 제한이 있었다. 하지만 비용적인 제한이 없다면 즉, 상용화시킨 표지판에서는 표시등을 더욱 크게하여 시각적으로 잘 보이게 할 수 있을 것이다. 이 방법을 통해서 더욱 완성도가 높은 제품을 만들 수 있을 것으로 기대된다.<br />
3) iBeacon의 인식거리, 음성인식의 정확도, 버스api의 정확도 등 제품의 전체적인 정확도를 향상시킨다면 보다 정확한 결과를 기대할 수 있다.</p>
<p><span style="color: #0000ff"><strong>8. 소스코드</strong></span><br />
<span style="color: #008080"><strong>8.1. 메인 코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>import gspeech<br />
import threading<br />
import time<br />
import re<br />
import sys</p>
<p>import requests<br />
import argparse<br />
from luma.led_matrix.device import max7219<br />
from luma.core.interface.serial import spi, noop<br />
from luma.core.render import canvas<br />
from luma.core.legacy import text<br />
from luma.core.legacy.font import proportional, LCD_FONT</p>
<p>import urllib.request<br />
from urllib.request import urlopen<br />
from urllib.parse import urlencode<br />
from urllib.parse import quote_plus<br />
from urllib.parse import unquote<br />
from bs4 import BeautifulSoup<br />
import bs4</p>
<p>from Hi import sound_play<br />
from blesca import find</p>
<p>from google.cloud import texttospeech</p>
<p>#전역변수 선언<br />
busrouteID = []
buslistinform = []
buslist = []
bstopnm = []
target_buses = []
led_tag=0</p>
<p>def demo(w, h, block_orientation, rotate, bus1, bus2):<br />
serial = spi(port=0, device=0, gpio=noop())<br />
print(&#8220;Created device&#8221;)<br />
device = max7219(serial, width=w, height=h, rotate=rotate, block_orientation=block_orientation)</p>
<p>with canvas(device) as draw:<br />
text(draw, (1, 0), bus1, fill=&#8221;white&#8221;, font=proportional(LCD_FONT))<br />
text(draw, (1, 8), bus2, fill=&#8221;white&#8221;, font=proportional(LCD_FONT))</p>
<p>def led_control() :<br />
global led_tag<br />
led_tag = 1</p>
<p># 정류소 경유노선 목록조회<br />
# 공공데이터포털(data.go.kr)으로 url요청을 해 데이터를 받는다<br />
# 받아오는 정보는 정류장 이름, 정류장에 정차하는 버스의 노선 명칭, 노선 고유 번호<br />
# 서버에 데이터를 받아오지 않고 받아온 html에서 크롤링 하는 방식<br />
# 리턴값은 정차 버스 리스트, 정류장 이름, (2차원 리스트)버스 노선 명칭과 고유번호 이다<br />
# 버스 정류장 고유 정보이므로 최초 한번만 받아옴</p>
<p>def get_busstopinfor(buslistinform, bstopId):<br />
decode_key = unquote(&#8221;) #개인 고유 발급 키<br />
url = &#8216;http://apis.data.go.kr/6280000/busStationService/getBusStationViaRouteList&#8217;<br />
queryParams = &#8216;?&#8217; + urlencode({quote_plus(&#8216;ServiceKey&#8217;): decode_key,<br />
quote_plus(&#8216;pageNo&#8217;): &#8217;1&#8242;,<br />
quote_plus(&#8216;numOfRows&#8217;): &#8217;10&#8242;,<br />
quote_plus(&#8216;bstopId&#8217;): bstopId})<br />
request = urllib.request.Request(url + queryParams)<br />
request.get_method = lambda: &#8216;GET&#8217;<br />
response_body = urlopen(request)<br />
a = response_body.read()<br />
soup = BeautifulSoup(a, &#8216;html.parser&#8217;)<br />
num = soup.find(&#8216;numofrows&#8217;)<br />
num = int(num.get_text())</p>
<p>table = soup.find(&#8216;serviceresult&#8217;)<br />
for tr in table.find_all(&#8216;msgbody&#8217;):<br />
tds = list(tr.find_all(&#8216;itemlist&#8217;))</p>
<p>blank = 0<br />
for itemlist in tds:<br />
routeno = itemlist.find(&#8216;routeno&#8217;).text<br />
routeid = itemlist.find(&#8216;routeid&#8217;).text<br />
getbstopnm = itemlist.find(&#8216;bstopnm&#8217;).text<br />
buslistinform.append([routeno, routeid, blank])<br />
buslist.append(routeno)<br />
bstopnm.append(getbstopnm)</p>
<p>return buslist, bstopnm, buslistinform</p>
<p># 버스 도착정보 목록조회<br />
# 받아오는 정보는 버스 노선 고유번호, 버스 도착시간<br />
# 이 데이터셋에서는 버스 고유번호를 제공하지 않는다. 따라서 버스 노선 고유번호를 받아와 앞서 정류소 경유노선 목록조회에서 받아온<br />
# 2차원 리스트 버스 고유번호 / 버스 노선 고유번호에서 버스 노선 고유번호를 비교해 같은 리스트에 도착시간을 추가한다<br />
# 따라서 2차원 리스트 buslistinform의 요소는 [(버스 고유번호, 버스 노선 고유번호, 버스 도착시간)]
<p>def get_businfor(bustopid):<br />
decode_key = unquote(&#8221;) #개인 고유 발급 키<br />
url = &#8216;http://apis.data.go.kr/6280000/busArrivalService/getAllRouteBusArrivalList&#8217;<br />
queryParams = &#8216;?&#8217; + urlencode({quote_plus(&#8216;ServiceKey&#8217;): decode_key,<br />
quote_plus(&#8216;pageNo&#8217;): &#8217;1&#8242;,<br />
quote_plus(&#8216;numOfRows&#8217;): &#8217;10&#8242;,<br />
quote_plus(&#8216;bstopId&#8217;): bustopid})<br />
request = urllib.request.Request(url + queryParams)<br />
request.get_method = lambda: &#8216;GET&#8217;<br />
response_body = urlopen(request)<br />
a = response_body.read()</p>
<p>soup = BeautifulSoup(a, &#8216;html.parser&#8217;)<br />
table = soup.find(&#8216;serviceresult&#8217;)<br />
for tr in table.find_all(&#8216;msgbody&#8217;):<br />
tds = list(tr.find_all(&#8216;itemlist&#8217;))</p>
<p>for itemlist in tds:<br />
routeid = itemlist.find(&#8216;routeid&#8217;).text<br />
arrivalestimatetime = itemlist.find(&#8216;arrivalestimatetime&#8217;).text<br />
for i in range(0, len(buslistinform)):<br />
if (buslistinform[i][1] == routeid):<br />
buslistinform[i][2] = arrivalestimatetime</p>
<p>return buslistinform</p>
<p># 버스 도착시간을 리턴하는 함수. parameter는 버스 번호이며 buslistinform에서 버스 번호를 조회해 버스번호를 리턴함.<br />
def get_bus_arrivetime(busnum):<br />
for i in range(0, len(buslistinform)):<br />
if buslistinform[i][0] == busnum:<br />
return buslistinform[i][2]
def main():</p>
<p>gsp = gspeech.Gspeech()<br />
gsp.pauseMic()<br />
global target_buses<br />
global led_tag<br />
global buslistinform</p>
<p>while True:</p>
<p>find()<br />
gsp.resumeMic()</p>
<p>compare_numbers = []
choosen_bus = []
<p># Google TTS를 이용하여 정류장 이름+음성안내를 합성해 송출한다<br />
client = texttospeech.TextToSpeechClient()<br />
bus_stop_notice = &#8216;정류장입니다. 확인할 버스 번호를 말씀해주세요&#8217;<br />
bus_stop_name = bstopnm[0]
synthesis_input = texttospeech.types.SynthesisInput(text=bus_stop_name + bus_stop_notice)</p>
<p>voice = texttospeech.types.VoiceSelectionParams(<br />
language_code=&#8217;ko-KR&#8217;,<br />
ssml_gender=texttospeech.enums.SsmlVoiceGender.NEUTRAL)</p>
<p>audio_config = texttospeech.types.AudioConfig(<br />
audio_encoding=texttospeech.enums.AudioEncoding.MP3)</p>
<p>response = client.synthesize_speech(synthesis_input, voice, audio_config)</p>
<p>bus_notice = &#8216;bus.mp3&#8242;<br />
with open(bus_notice, &#8216;wb&#8217;) as out:<br />
out.write(response.audio_content)<br />
gsp.pauseMic()<br />
sound_play(bus_notice)<br />
gsp.resumeMic()</p>
<p># 음성인식 될 때까지 대기. 받아온 음성은 stt에 저장된다</p>
<p>stt = gsp.getText()<br />
if stt is None:<br />
break<br />
# 받아온 음성에서 버스번호만 찾아온다. ex) 511번 알려줘 ==&gt; get_numbers = ['511']
get_numbers = re.findall(&#8220;\d+&#8221;, stt)</p>
<p># 구글 STT로 인식된 번호가 정류장 정차 버스 리스트에 존재하는지 확인. 확인후 존재한다면 compare_numbers에 입력<br />
compare_numbers = list(set(buslist).intersection(get_numbers))<br />
# 리스트에 존재한다면 구글 TTS로 음성변환<br />
all_check_num = &#8220;번 버스&#8221;.join(compare_numbers)</p>
<p># 일치하는 번호가 없는경우 &#8220;해당 버스 번호는 없습니다&#8221; 음성 인식 출력<br />
if len(compare_numbers) == 0:<br />
mismatch_notice = &#8220;/home/pi/mismatch.mp3&#8243;<br />
gsp.pauseMic()<br />
sound_play(mismatch_notice)<br />
gsp.resumeMic()</p>
<p># 물어본 버스가 하나 이상 존재하는 경우 버스번호와 도착시간 음성 인식 변환 후 출력<br />
else:<br />
for i in range(0, len(compare_numbers)):<br />
target_bus = compare_numbers[i] # 타겟버스 번<br />
target_bus_arrivalestimate = get_bus_arrivetime(target_bus)<br />
minute=int(int(target_bus_arrivalestimate) / 60)<br />
second=int(target_bus_arrivalestimate)-(60*minute) #<br />
synthesis_input_match = texttospeech.types.SynthesisInput(text=target_bus<br />
+ &#8220;번 버스 약 &#8221;<br />
+ str(minute)<br />
+ &#8220;분&#8221;<br />
+ str(second)<br />
+ &#8220;초 후 도착합니다&#8221; )<br />
response_match = client.synthesize_speech(synthesis_input_match, voice, audio_config)<br />
match_notice = &#8216;match.mp3&#8242;</p>
<p>with open(match_notice, &#8216;wb&#8217;) as out:<br />
out.write(response_match.audio_content)<br />
gsp.pauseMic()</p>
<p>sound_play(match_notice)<br />
gsp.resumeMic()<br />
time.sleep(1)</p>
<p># 물어본 버스 번호가 1개일 경우<br />
if (len(compare_numbers) == 1):<br />
synthesis_input_match = texttospeech.types.SynthesisInput(text=compare_numbers[0]
+ &#8220;번 버스 도착 시 bus_choice = &#8220;몇 번 버스로 안내해드릴까요??&#8221;<br />
synthesis_input_match = texttospeech.types.SynthesisInput(text=bus_choice)<br />
response_match = client.synthesize_speech(synthesis_input_match, voice, audio_config)<br />
choice_notice = &#8216;choice.mp3&#8242;</p>
<p>with open(choice_notice, &#8216;wb&#8217;) as out:<br />
out.write(response_match.audio_content)<br />
sound_play(choice_notice)<br />
stt = gsp.getText()<br />
get_choice = re.findall(&#8220;\d+&#8221;, stt)<br />
choosen_bus = list(set(compare_numbers).intersection(get_choice))</p>
<p>while (len(choosen_bus) == 0) :<br />
time.sleep(0.5)<br />
stt = gsp.getText()<br />
get_choice = re.findall(&#8220;\d+&#8221;, stt)<br />
choosen_bus = list(set(compare_numbers).intersection(get_choice))<br />
if len(choosen_bus) &gt; 0 :<br />
break</p>
<p># 선택한 버스 안내 음성<br />
for i in range(0, len(choosen_bus)):<br />
synthesis_input_match = texttospeech.types.SynthesisInput(text=choosen_bus[i]
+ &#8220;번 버스 도착 시 안내해드리겠습니다.&#8221;)<br />
response_match = client.synthesize_speech(synthesis_input_match, voice, audio_config)<br />
final_notice = &#8216;final.mp3&#8242;</p>
<p>with open(final_notice, &#8216;wb&#8217;) as out:<br />
out.write(response_match.audio_content)안내해드리겠습니다.&#8221;)<br />
response_match = client.synthesize_speech(synthesis_input_match, voice, audio_config)<br />
one_notice = &#8216;one.mp3&#8242;</p>
<p>with open(one_notice, &#8216;wb&#8217;) as out:<br />
out.write(response_match.audio_content)<br />
gsp.pauseMic()</p>
<p>sound_play(one_notice)<br />
gsp.resumeMic()<br />
target_buses.append(compare_numbers[0]) # 타겟 버스 리스트에 추가.<br />
led_control()<br />
print(&#8220;led on&#8221;)</p>
<p>else: # 물어본 버스가 2개 이상인 경우 선택 음성 안내</p>
<p>gsp.pauseMic()<br />
sound_play(final_notice)<br />
gsp.resumeMic()<br />
target_buses.append(choosen_bus[i]) # 타겟 버스 리스트에 추가<br />
led_control()<br />
print(&#8220;led on&#8221;)</p>
<p># 타겟 버스(탑승하려는 버스) 도착시간 확인</p>
<p>while (len(target_buses) &gt; 0 ):<br />
gsp.pauseMic()<br />
for i in range(0, len(target_buses)):<br />
flag = check_bus_arrive(target_buses[i])<br />
# 버스 잔여 시간이 100 초 이하인지 판단<br />
time.sleep(1)<br />
if flag == True: # 100초 미만일경우 버스 도착안내메세지<br />
synthesis_input_match = texttospeech.types.SynthesisInput(text=target_buses[i]
+ &#8220;번 버스 잠시 후 도착합니다&#8221;)<br />
response_match = client.synthesize_speech(synthesis_input_match, voice, audio_config)<br />
arrive_notice = &#8216;arrive.mp3&#8242;<br />
with open(arrive_notice, &#8216;wb&#8217;) as out:<br />
out.write(response_match.audio_content)<br />
gsp.pauseMic()<br />
sound_play(arrive_notice)</p>
<p>led_control()</p>
<p>time.sleep(7)<br />
target_buses.remove(target_buses[i])<br />
led_control()<br />
break</p>
<p>if (len(target_buses) == 0):<br />
break<br />
continue</p>
<p># 버스 url송출해 실시간으로 도착정보 가져오는 함수<br />
def get_realtime_businform():<br />
while True:<br />
global buslistinform<br />
get_businfor(163000167) time.sleep(10)</p>
<p># parameter 값에 대해 도착시간이 90초 미만인지 확인해주는 함수<br />
def check_bus_arrive(target_bus):<br />
target_bus_arrivalestimate = int(get_bus_arrivetime(target_bus))<br />
if (target_bus_arrivalestimate &lt; 90): # 90초 미만이면 True, else False<br />
return True<br />
else:<br />
return False</p>
<p># led 제어하는 함수<br />
def led_controller():<br />
global target_buses<br />
global led_tag</p>
<p>while True:<br />
parser = argparse.ArgumentParser(description=&#8217;matrix_demo arguments&#8217;,<br />
formatter_class=argparse.ArgumentDefaultsHelpFormatter)</p>
<p>parser.add_argument(&#8216;&#8211;width&#8217;, type=int, default=32, help=&#8217;Width&#8217;)<br />
parser.add_argument(&#8216;&#8211;height&#8217;, type=int, default=16, help=&#8217;height&#8217;)<br />
parser.add_argument(&#8216;&#8211;block-orientation&#8217;, type=int, default=-90, choices=[0, 90, -90],<br />
help=&#8217;Corrects block orientation when wired vertically&#8217;)<br />
parser.add_argument(&#8216;&#8211;rotate&#8217;, type=int, default=0, choices=[0, 1, 2, 3], help=&#8217;Rotation factor&#8217;)</p>
<p>args = parser.parse_args()<br />
# led tag= 1 일때마다 led 표시 값 갱신<br />
if (led_tag==1) :</p>
<p>if len(target_buses) == 1 :<br />
demo(args.width, args.height, args.block_orientation, args.rotate,target_buses[0], &#8220;&#8221;)<br />
elif len(target_buses) &gt; 1 :<br />
demo(args.width, args.height, args.block_orientation, args.rotate,target_buses[0], target_buses[1])<br />
else :<br />
demo(args.width, args.height, args.block_orientation, args.rotate, &#8220;&#8221;, &#8220;&#8221;)<br />
led_tag=0</p>
<p>if __name__ == &#8220;__main__&#8221; :<br />
get_busstopinfor(buslistinform, 163000167)<br />
t = threading.Thread(target=main)<br />
t2 = threading.Thread(target=get_realtime_businform)<br />
t3 = threading.Thread(target=led_controller)<br />
t.start()<br />
t2.start()<br />
t3.start()</p>
</div>
<p><span style="color: #008080"><strong>8.2. find() : 비콘 검색함수 </strong></span></p>
<p><span style="color: #000000"><div class="symple-box gray none" style="text-align:left; width:100%;"> 
</span></p>
<p>from bluepy.btle import Scanner, DefaultDelegate</p>
<p>class ScanDelegate(DefaultDelegate):<br />
def __init__(self):<br />
DefaultDelegate.__init__(self)<br />
def handleDiscovery(self, dev, isNewDev, isNewData):<br />
if isNewDev:<br />
print (&#8220;Discovered device&#8221;, dev.addr)<br />
elif isNewData:<br />
print (&#8220;Received new data from&#8221;, dev.addr)<br />
def find():<br />
beacon = 1<br />
scanner = Scanner()</p>
<p>while (beacon ==1):<br />
devices = scanner.scan(3.0)<br />
for dev in devices:<br />
print (&#8220;Device %s (%s), RSSI=%d dB&#8221; % (dev.addr, dev.addrType, dev.rssi))<br />
for (adtype, desc, value) in dev.getScanData():<br />
print (&#8220;%s = %s&#8221; % (desc, value))<br />
if(value == &#8216;Helper&#8217;and dev.rssi &gt; -52):<br />
beacon = 0<br />
break<br />
else:<br />
beacon = 1<br />
if beacon ==0:<br />
break</p>
<p>if __name__ == &#8216;__main__&#8217;:<br />
find()</p>
<p><span style="color: #000000"></div></span><br />
<span style="color: #008080"><strong>8.3. sound_play() : 음성안내 실행 함수</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>import pygame<br />
import time</p>
<p>def sound_play(name):<br />
file = name<br />
pygame.mixer.init()<br />
pygame.mixer.music.load(file)<br />
pygame.mixer.music.play()<br />
clock = pygame.time.Clock()<br />
while pygame.mixer.music.get_busy():<br />
clock.tick(3)<br />
pygame.mixer.quit()</p>
</div>
<span style="color: #008080"><strong>8.4. Gspeech module : 구글에서 제공하는 샘플코드 사용</strong> </span><br />
· TTS : https://cloud.google.com/text-to-speech/docs/samples?hl=ko<br />
· STT : https://cloud.google.com/speech-to-text/docs/samples?hl=ko</p>
<p><span style="color: #0000ff"><strong>9. 참고문헌</strong></span><br />
[1] 김원호, 이유화, 김시현, 이유화, 김시현. &#8220;시각장애인 대중교통 이용실태 분석 및 대중교통시설 내 보행지원 시스템 구축방안.&#8221; 서울도시연구 10 no.3 (2009): 97-114.<br />
[2] MBCNEWS. (2019, 12 25). [소수의견] 버스 탄 시각장애인 봤나요…타고 내리는 게 전쟁 [비디오파일]. 검색경로 https://www.youtube.com/watch?v=saoX-lR-iJ0&amp;feature=emb_title<br />
[3] &#8220;시각장애인도 버스를 탈 수 있게 해주세요.&#8221; (2020년 3월 1일). 청와대. n.d. 수정, https://www1.president.go.kr/petitions/583770.<br />
[4] &#8220;인간공학적 시선으로 본 장애인의 이동권.&#8221; LG챌린저스. n.d. 수정, 2020년 3월 20일 접속, http://www.lgchallengers.com/wp-content/uploads/global/global_pdf/S0410.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ntrexgo.com/archives/38621/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[43호]Smart Pad</title>
		<link>http://www.ntrexgo.com/archives/33817</link>
		<comments>http://www.ntrexgo.com/archives/33817#comments</comments>
		<pubDate>Tue, 25 Jul 2017 00:00:52 +0000</pubDate>
		<dc:creator>디바이스마트 매거진</dc:creator>
				<category><![CDATA[디바이스마트 매거진]]></category>
		<category><![CDATA[특집]]></category>
		<category><![CDATA[43호]]></category>
		<category><![CDATA[Feature]]></category>
		<category><![CDATA[ict]]></category>
		<category><![CDATA[공모전]]></category>
		<category><![CDATA[디바이스마트]]></category>
		<category><![CDATA[매거진]]></category>
		<category><![CDATA[융합]]></category>
		<category><![CDATA[최우수상]]></category>
		<category><![CDATA[프로젝트]]></category>

		<guid isPermaLink="false">http://www.ntrexgo.com/?p=33817</guid>
		<description><![CDATA[디바이스마트 매거진 43호 &#124; 최근 웨어러블 디바이스들이 많이 출시가 되고 있고 있습니다. 웨어러블 디바이스는 신체에 부착하여 컴퓨팅 행위를 할 수 있는 모든 것들을 뜻하고, 일부 컴퓨팅 기능 수행이 이용 가능한 애플리케이션까지 포함된 기기를 의미합니다. ]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/Cap-2017-10-18-13-15-49-260.png" rel="lightbox[33817]"><img class="alignnone size-large wp-image-34236" alt="Cap 2017-10-18 13-15-49-260" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/Cap-2017-10-18-13-15-49-260-620x137.png" width="620" height="137" /></a></p>
<p><span style="background-color: #ffff00;font-size: x-large"><strong>2017 </strong></span></p>
<p><span style="font-size: x-large"><strong>ICT 융합 프로젝트 공모전 </strong><strong>최우수상</strong></span></p>
<p><span style="font-size: x-large"><strong>Smart Pad</strong></span></p>
<p style="text-align: right">글 | 단국대학교 정의동, 양지현, 최진우</p>
<p><span style="color: #000080"><strong>심사평</strong></span><br />
<strong>칩센</strong> 유사한 작품이 있었으나, 시제품의 완성도와 시연의 구성이 매우 좋았습니다. 작품과 같은 제품을 기획할 때 운동량 측정 등 여러 부가 기능에 대한 고려를 많이 하느라 메인 기능의 부각을 저하시키는 경우가 많이 있는데, 보고서 및 시연 영상에서 핵심 기능을 강조함으로서 제품의 기획의도를 더 잘 이해하게 만들었습니다. 추가적으로 연동하는 스마트장치의 네비게이터에서 이미 인지한 정보를 다른이에게 공유한다는 내용 또한 흥미를 끌게 하는 작품입니다. 신발 깔창에 제품을 설치하는 방식인데, 좀 더 심플한 액세서리 개념으로 적용하는 방법은 없을지 고민을 해보는 것도 좋아 보입니다.</p>
<p><strong>뉴티씨</strong> 당장 제품으로 만들어도 될 만큼 좋은 작품입니다. 그대로 출시해도 될 것 같지만, 이 기술을 따로 VR이나 AR에 적용하면 더 많은 가시적인 효과를 볼 가능성이 있겠습니다.</p>
<p><strong>위드로봇</strong> 동영상 데모가 훌륭합니다. GPS 위치 오차가 심한 지역에서는 동영상처럼 적절한 서비스를 제공하기가 어려울 수 있습니다. 이 부분에 대한 대비책이 있다면 매우 훌륭한 서비스를 제공하는 제품이 될 것 같습니다.</p>
<p><span style="color: #000080"><strong>작품 개요</strong></span><br />
최근 웨어러블 디바이스들이 많이 출시가 되고 있고 있습니다. 웨어러블 디바이스는 신체에 부착하여 컴퓨팅 행위를 할 수 있는 모든 것들을 뜻하고, 일부 컴퓨팅 기능 수행이 이용 가능한 애플리케이션까지 포함된 기기를 의미합니다. 인간과 사물 그리고 기기 등 연결대상과 그 범위가 빠른 속도로 확대되고, 사용자를 네트워크와 연결시키는 웨어러블 디바이스의 중요성이 부각되고 있는 시점에서 생각해 낸 웨어러블 디바이스는 SMART PAD입니다.</p>
<p><strong>일반 사람들 ver.</strong><br />
많은 웨어러블 디바이스들이 나오고 있지만 깔창으로 나오고 있는 것들은 대부분 칼로리 측정기, 만보계 기능을 하는 것인데 이것에 착안하였고 길치, 방향치인 사람들도 올바른 방향으로 길을 찾아갈 수 있게 알려주면 좋겠다는 생각과 요새 납치, 유괴에 관해 이슈가 되는 점에 대해 보호자에게 현재위치를 알리는 것이 필요하다는 생각에 더해 Smart PAD란 것을 생각하게 되었습니다.<br />
또한 내 하루 일과를 알 수 있고 여행일기를 쓰면 좋겠다는 생각 또한 발자취 메뉴와 여행일기 메뉴를 생각 하게 되었습니다. 이 스마트 패드로 사람들이 지도에 시간을 할애하는 것이 아닌 주변을 돌아보며 다닐 수 있고 안전한 귀가길, 여행자에게는 여행일기에 더불어 하루종일 나의 발자취 또한 매일 저장할 수 있게 하는 것이 목적입니다.</p>
<p><strong>시각장애인 ver.</strong><br />
깔창에 진동모터를 부착하여 앞, 뒤, 좌, 우를 진동으로 길을 알려주는 웨어러블 디바이스입니다. 그뿐만 아니라 일반 사람들이 걷다가 신호등이 고장난 곳, 공사 중인 곳 등을 3초 이상 멈추게 되면 사용자의 위치를 서버에 보내 지도에 표시합니다. 많은 사용자가 표시한 지역을 활용하여 시각장애인분들이 그 지역을 피할 수 있도록 합니다.</p>
<p><span style="color: #000080"><strong>작품 설명</strong></span><br />
<span style="color: #0000ff"><strong>주요 동작 및 특징</strong></span><br />
<span style="color: #00ccff"><strong>하드웨어</strong></span><br />
· 양쪽 발에 아두이노 미니 프로, 진동모터, 가속도/지자기/자이로 센서, 블루투스, 압력센서 등을 부착한다.<br />
· 안드로이드에 tmap api를 사용하여 MAP을 보여준다.<br />
· 안드로이드 어플리케이션 내에 두 가지 방법 중(촉각적-진동/청각적방법) 하나를 선택한다.<br />
· 어플리케이션에 현재 방향과 다음 방향을 알려줄 알고리즘을 적용한다.<br />
· 깔창에 달린 가속도, 자이로, 지자기 센서를 사용해 절대적인 현재 위치를 파악한다.<br />
· 길을 가다가 멈출 경우 압력센서로 멈춰있는지 걷고 있는지 판단하여 블루투스 1:N 통신으로 현재 위치를 안드로이드에게 전달한다.<br />
· 안드로이드 어플리케이션에서 위에서 말한 알고리즘으로 다음 방향을 구한다.<br />
· 블루투스 통신으로 다음 방향을 전달한다.<br />
· 깔창에 부착된 진동모터 또는 청각적인 알림으로 방향을 알 수 있다.<br />
· 촉각적 방법일 경우 &#8211; 앞이면 양발의 ‘앞’에 달린 진동 모터를 뒤면 양발의 ‘뒤’에 달린 진동모터를 왼쪽 방향이면 ‘왼발’을 오른쪽 방향이면 ‘오른발’ 진동모터를 울리게 한다.<br />
· 청각적 방법일 경우 음성으로 어느 방향으로 가야 하는지 알려준다.<br />
· 음성인식으로 목적지를 정할 수 있다.<br />
· 안드로이드 어플리케이션 메뉴는 아래와 같다.<br />
1. 현재위치부터 목적지까지의 길을 보여주는 메뉴,<br />
2. 길을 상세히 설명한 메뉴,<br />
3. 최근 검색 메뉴,<br />
4. 사용자가 하루 종일 다닌 발자취를 보여주고, 여행 메모(사진,동영상)를 할 수 있는 여행 다이어리 메뉴<br />
5. 하루 종일 얼마나 걸었는지를 알려주는 메뉴<br />
6. 보호자에게 사용자 위치를 알림 메뉴<br />
앞서 말한 4번 메뉴를 통해 사용자의 그 날 하루 발자취와 여행일기를 쓸 수 있다.<br />
현재 있는 곳에서 사진을 찍은 경우, 나중에 그 장소에서 무얼 했는지, 얼마나 그 장소에 있었는지를 알 수 있다.</p>
<p><span style="color: #00ccff"><strong>소프트웨어</strong></span><br />
<strong>길찾기 알고리즘</strong></p>
<p><strong><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-1.png" rel="lightbox[33817]"><img alt="44 ict smart pad (1)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-1.png" width="620" height="359" /></a></strong><br />
1. 현재 위치와 그 다음 가야할 곳 (1m 앞)의 위치를 알아냅니다.<br />
2. getAngle이라는 함수를 만들어서 현재위치와 다음 위치까지의 각도를 알아냅니다. bearingTo(destination)을 사용하여 알아낼 수 있습니다.<br />
3.이를 이용하여 방향벡터를 구할 수 있으므로 어느 방향인지 판단을 할 수 있습니다.<br />
4. 그 전에 현재 사용자가 바라보는 방향의 정보를 깔창으로부터 받아와 절대 방향을 생성합니다.<br />
5. 절대 방향을 토대로 진행방향과 비교를 하여 다음 방향을 구합니다.<br />
6. 다음 방향을 깔창에 진동으로 알려줍니다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-2.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34213" alt="44 ict smart pad (2)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-2.png" width="620" height="231" /></a></p>
<p>7. 현재위치를 계속해서 갱신해야만 사용자가 움직이면서 계속해서 다음 방향을 새로 구할 수 있습니다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-3.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34215" alt="44 ict smart pad (3)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-3.png" width="620" height="366" /></a></p>
<p>&nbsp;</p>
<p><strong>어플리케이션 모습</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-4.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34217" alt="44 ict smart pad (4)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-4.png" width="620" height="427" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-5.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34219" alt="44 ict smart pad (5)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-5.png" width="620" height="419" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-6.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34221" alt="44 ict smart pad (6)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-6.png" width="620" height="422" /></a></p>
<p><strong>용도 및 사용방법</strong></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-7.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34222" alt="44 ict smart pad (7)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-7.png" width="620" height="245" /></a></p>
<p>음성인식 또는 text 방법으로 목적지를 설정합니다. 어플리케이션의 방향설정 알고리즘을 통해 다음 위치를 구하면 위의 그림처럼 발에 진동이 울려 방향을 알 수 있다. 여행일기 메뉴에서는 오늘 하루의 발자취와 일기(사진, 메모)등을 쓸 수 있다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-8.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34223" alt="44 ict smart pad (8)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-8.png" width="620" height="352" /></a></p>
<p>어플에 나온 화살표 방향이 진동방향을 알려준다. 왼쪽은 사람이 느낀 방향을 손가락으로 나타낸 사진이다.</p>
<p><strong>주요 사용자 및 수혜자</strong><br />
처음 가는 길에 대한 방향정보를 알려주어 목적지에 도달할 수 있게 하기 때문에 여행자 또는 길치, 방향치에게 편의를 줄 수 있다. 또한 청각적인 도움 또는 촉각적 도움을 주기 때문에 시각장애인에게 또한 편의를 줄 수 있다.</p>
<p><strong>특장점 및 활용계획</strong><br />
지도가 아닌 주변에 시각을 씀으로써 안전하게 목적지에 도달할 수 있을 뿐만 아니라 보호자에게 사용자의 위치를 알릴 수 있고 여행일기 또는 하루 일지를 씀으로써 오늘 하루에 대해 돌아 볼 수 있다.</p>
<p><span style="color: #00ccff"><strong>서버와 빅데이터 활용부문</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-1.jpg" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34210" alt="44 ict smart pad (1)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-1.jpg" width="620" height="244" /></a></p>
<p>&nbsp;</p>
<p>일반 사용자가 신호등이 고장난 곳, 공사중인 곳에서 3-5초 정도 서있으면 사용자의 위치를 모바일에서 GPS 데이터를 받아서 서버로 전송합니다. 그리고나서 서버는 데이터베이스에 위치정보를 저장합니다. 위치 정보가 많이 쌓여서 지도상으로 정보를 조회하고 싶을 때는, 데이터 베이스에서 모아놓은 정보를 조회하여 서버단에서 지도를 조회할 수 있도록 합니다. 위 그림은 서버에서 지도 정보를 조회했을 때 나타나는 대략적인 화면입니다. 사용자가 정지한 지점 여러 군데가 데이터베이스에 저장되어 있는데, 서버는 데이터베이스에서 정보를 조회하여 밀집되어 기록되어 있는 위치가 있는지 확인하게 됩니다. 이때 KNN 알고리즘을 사용하여 밀집되어 있는 위치를 찾고, 밀집도에 따라서 구분을 달리하여 해당 지점을 표시하여 한눈에 개선할 지점을 조회할 수 있습니다.<br />
또한 어플리케이션에서 구현한 알고리즘을 통해 개선되어야할 위치를 피하여 사용자(시각장애인)에게 길을 알려줍니다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-9.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34224" alt="44 ict smart pad (9)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-9.png" width="620" height="391" /></a></p>
<p>&nbsp;</p>
<p><span style="color: #0000ff"><strong>전체 시스템 구성</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-10.png" rel="lightbox[33817]"><img alt="44 ict smart pad (10)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-10.png" width="620" height="579" /></a></p>
<p>· T map API를 이용해 MAP 구현<br />
· 방향 Algorithm을 구축하여 사용자가 가야 할 방향 구하기<br />
· 길 찾기 중 보호자에게 SMS로 알람<br />
· 아두이노와 Bluetooth 통신을 통한 데이터 송신 및 수신<br />
1) 지자기센서 사용해 절대방향 수신<br />
2) 자이로,가속도 센서를 사용해 운동량, 만보계량 수신<br />
3) 알고리즘에서 구한 방향 송신</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-11.png" rel="lightbox[33817]"><img alt="44 ict smart pad (11)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-11.png" width="620" height="348" /></a><br />
· GPS신호 데이터를 이용한 경로 개선</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-12.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34227" alt="44 ict smart pad (12)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-12.png" width="620" height="348" /></a></p>
<p>· 작품규격<br />
사이즈 : 220 x 90 x 40(mm)</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-13.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34228" alt="44 ict smart pad (13)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-13.png" width="620" height="280" /></a></p>
<p><span style="color: #0000ff"><strong>개발 환경(개발언어, Tool, 사용시스템 등)</strong></span><br />
· 개발언어 &#8211; C언어 / java : 개발 Tool에서 쓰이는 언어가 C언어이기 때문에 자연스레 C언어를 이용하여 코딩 및 소스구현을 하게 되었습니다. 이클립스에서 쓰는 언어는 java이기 때문에 java를 공부하고 소스를 구현하였습니다.<br />
· 개발 Tool &#8211; 아두이노 IDE tool : 아두이노 프로미니를 사용하여 아두이노 전용 tool인 IDE tool을 사용하였습니다.<br />
· 개발 Tool &#8211; 이클립스 : 안드로이드 스튜디오가 나오기전 이클립스를 사용했었는데 이클립스로 java 공부할 때 사용하여 구현하다보니 이클립스가 더 편해져서 이클립스를 사용하여 app 개발을 했습니다.<br />
· 사용 시스템 &#8211; 아두이노 프로미니 : 깔창에 들어가려면 작은 mcu를 사용해야되고 센서와 모터가 많이 들어가기 때문에 핀이 많이 필요하여 타이니두이노 보단 아두이노 프로미니가 적합하다고 생각했습니다. 깔창에 있는 아두이노에선 연산을 많이 요구하지 않기 때문에 속도면에서 빠르지 않아도 된다고 생각하여 아두이노 프로미니를 선택하였습니다.</p>
<p><span style="color: #000080"><strong>단계별 제작 과정</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-14.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34229" alt="44 ict smart pad (14)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-14.png" width="620" height="579" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-2.jpg" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34212" alt="44 ict smart pad (2)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-2.jpg" width="620" height="350" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-3.jpg" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34214" alt="44 ict smart pad (3)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-3.jpg" width="620" height="347" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-4.jpg" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34216" alt="44 ict smart pad (4)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-4.jpg" width="620" height="347" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-5.jpg" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34218" alt="44 ict smart pad (5)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-5.jpg" width="620" height="344" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-6.jpg" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34220" alt="44 ict smart pad (6)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-6.jpg" width="620" height="343" /></a></p>
<p>&nbsp;</p>
<p><span style="color: #000080"><strong>기타(회로도, 소스코드, 참고문헌 등)</strong></span><br />
<span style="color: #0000ff"><strong>회로도</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-15.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34230" alt="44 ict smart pad (15)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-15.png" width="620" height="392" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-16.png" rel="lightbox[33817]"><img class="alignnone size-full wp-image-34231" alt="44 ict smart pad (16)" src="http://www.ntrexgo.com/wp-content/uploads/2017/07/44-ict-smart-pad-16.png" width="620" height="253" /></a><br />
<span style="color: #0000ff"><strong> 소스코드</strong></span><br />
<span style="color: #3366ff"><strong>이클립스</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>public synchronized float getAngle(){<br />
TMapPoint point1 = point_st ;<br />
//TMapPoint pOINT2 = Point();</p>
<p>Location here = new Location(&#8220;Start&#8221;);<br />
here.setLatitude(point1.getLatitude());<br />
here.setLongitude(point1.getLongitude());</p>
<p>Location destination = new Location(&#8220;End&#8221;);<br />
//destination.setLatitude(point2.getLatitude());<br />
///destination.setLongitude(point2.getLongitude());<br />
destination.setLongitude(Destlatitude);<br />
destination.setLongitude(Destlongitude);</p>
<p>if(point1==null || destination == null<br />
|| (point1.getLatitude() == 0 &amp;&amp; point1.getLognitude() == 0)<br />
|| (Destlatitude == 0 &amp;&amp; Destlongitude == 0)) {</p>
<p>return -1;<br />
; else {<br />
mAngle = here.bearingTo(destination); //Angles: -180 ~ 180<br />
}<br />
/* if(point1 == null || point2 == null<br />
|| (point2.getLatitude() == 0 &amp;&amp; point2.getLongitude() == 0)<br />
|| (Destlatitude == 0 &amp;&amp; Destlongitude == 0)) {<br />
return -1;<br />
; else {<br />
mAngle = here.bearingTo(destination); //Angles: -180 ~ 180<br />
} * //도착지점<br />
if(mAngle &lt; 0) {<br />
mAngle += 360; //convert to 0~360 range<br />
}<br />
//mangle.setText(Float.toString(mAngle));<br />
return mAngle;<br />
}<br />
private void Battery&#8230;Check(float battery)<br />
</div>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>if(gpsLocation ! = null) {<br />
updateCooridiate(gpsLocation);<br />
} else if (networkLocation !=null) {<br />
updateCooridiate(networkLocation);<br />
}else{<br />
updateCooridiate(passiveLocation);<br />
}<br />
}<br />
@override<br />
prodected void onResume() {<br />
// TODO Auto-generated method stub<br />
super.onResume();<br />
setup();<br />
}<br />
/////////<br />
@override<br />
public void onStart() {<br />
// TODO Auto-generated method stub<br />
super.onstart();<br />
Location location = mLocationManager/getLastKnownLocation(LocationManager.NETWORK_PROVIDER)<br />
Location gpsLocation = null;<br />
Location networkLocation = null;<br />
Location passiveLocation = null;</p>
<p>// gps가 항상 정확하지 않음으로, 프로바이더 두개를 사용하는 것이 가장 정확도가 높다.</p>
<p>gpsLocation = requestUpdatesFromProvider(LocationManager.GPS_PROVIDER);<br />
networkLocation = requestUpdatesFromProvider(LocationManager.NETWORK_PROVIDER);<br />
passiveLocation = requestUpdatesFromProvider(LocationManager.PASSIVE_PROVIDER);</p>
<p>if (gpsLocation ! = null) {<br />
updateCooridiate(gpsLocation);<br />
} else if(networkLocation ! = null) {<br />
updateCooridiate(networkLocation);<br />
} elsle {<br />
updateCoorkdiate(passiveLocation);<br />
</div>
<p><strong><span style="color: #3366ff">방향 알고리즘 부분</span></strong></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>public void checkAngle1()<br />
{<br />
if((rpAngle &gt;= 270) &amp;&amp; (rpAngle &lt;= 360))<br />
{<br />
compass(&#8216;F&#8217;);<br />
}<br />
else if((rpAngle &gt;= 0) &amp;&amp; (rpAngle &lt;= 89))<br />
{<br />
compass(&#8216;R&#8217;);<br />
}<br />
else if((rpAngle &gt;= 90) &amp;&amp; (rpAngle &lt;= 180))<br />
{<br />
compass(&#8216;B&#8217;);<br />
}<br />
else<br />
{<br />
compass(&#8216;L&#8217;);<br />
}<br />
}<br />
</div>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>public class httprequest extends Thread<br />
{</p>
<p>double v1 = 0;<br />
double v2 = 0;<br />
public httprequest(double v1, double v2)<br />
{<br />
this.v1 = v1;<br />
this.v2 = v2;<br />
}<br />
public void run() {<br />
// TODO Auto-generated method stub</p>
<p>String url = &#8220;http://ec2-54-148-213-31.us-west-2.compute.amazonaws.com:5000/&#8221;;</p>
<p>String str1 = Double.toString(v1);<br />
String str2 = Double.toString(v2);</p>
<p>uri += str1;<br />
uri += &#8216;/&#8217;;<br />
uri += str2;</p>
<p>RequestBundle rb = new RequestBundle();<br />
rb.setUrl(uri);<br />
rb.setHttpMethod(HttpMethod.GET);<br />
Mat&lt;String, Object &gt; mmap = new HashMap&lt;String, Object&gt;();<br />
APIRequest api = new APIRequest();</p>
<p>try {<br />
api.request(rb);<br />
} catch (malformedURLException e) {<br />
// TODO Auto-generated catch block<br />
e.printStackTrace();<br />
} catch (IOException e) {<br />
</div>
<p><strong><span style="color: #3366ff">아두이노 소스</span></strong><br />
<span style="color: #00ccff"><strong>왼쪽 발</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>#include &lt;SoftwareSerial.h&gt;<br />
SoftwareSerial blue(2,3);//rx tx<br />
#include &lt;Wire.h&gt; //I2C Arduino Library<br />
#include &lt;String.h&gt;<br />
int Stream_control =8; //20<br />
int Stream_status =7;</p>
<p>#define address 0x1E //0011110b, I2C 7bit address of HMC5883<br />
float thetan=0;<br />
float m[10]={0,};<br />
float sum_theta=0;<br />
float sum_thetan=0;<br />
char dir;<br />
char dir2=0;<br />
int dir_sum=0;<br />
int FSR_Pin = A0;<br />
int FSRReading;<br />
float Rfsr;<br />
int Vibrate_pins[4] = {5,0,4,6}; // LED 연결 핀<br />
boolean Vibrate_state[4];<br />
int Battery_Pin = A1;<br />
int Battery_Check;<br />
float Battery;<br />
int step = 0;</p>
<p>void setup(){<br />
//Initialize Serial and I2C communications<br />
Serial.begin(9600);<br />
blue.begin(9600);<br />
Wire.begin();</p>
<p>//Put the HMC5883 IC into the correct operating mode<br />
Wire.beginTransmission(address); //open communication with HMC5883<br />
Wire.write(0&#215;02); //select mode register<br />
Wire.write(0&#215;00); //continuous measurement mode<br />
Wire.endTransmission();</p>
<p>for(int i = 0; i &lt; 3; i++){<br />
pinMode(Vibrate_pins[i], OUTPUT);<br />
Vibrate_state[i] = false;<br />
digitalWrite(Vibrate_pins[i], Vibrate_state[i]);}<br />
pinMode(Stream_control,OUTPUT); //40<br />
pinMode(Stream_status,INPUT);<br />
}</p>
<p>void loop(){</p>
<p>int x,y,z;<br />
Wire.beginTransmission(address);<br />
Wire.write(0&#215;03);<br />
Wire.endTransmission();</p>
<p>Wire.requestFrom(address, 6);<br />
if(6&lt;=Wire.available()){<br />
x = Wire.read()&lt;&lt;8; //X msb<br />
x |= Wire.read(); //X lsb<br />
z = Wire.read()&lt;&lt;8; //Z msb<br />
z |= Wire.read(); //Z lsb<br />
y = Wire.read()&lt;&lt;8; //Y msb<br />
y |= Wire.read(); //Y lsb<br />
}</p>
<p>FSRReading = analogRead(FSR_Pin);<br />
Rfsr = ((9.78 * FSRReading)/(1-(FSRReading/1023.0)));<br />
delay(250);</p>
<p>Battery_Check = analogRead(Battery_Pin);<br />
Battery = Battery_Check/4.2;<br />
if (blue.available()){</p>
<p>byte data = blue.read();<br />
digitalWrite(Stream_control,HIGH);</p>
<p>blue.write(65);<br />
blue.write(84);<br />
blue.write(79);<br />
blue.write(50);<br />
blue.write(13);</p>
<p>int a=digitalRead(Stream_status);<br />
// Serial.println(a);<br />
if(a==0)<br />
{<br />
digitalWrite(Stream_control,LOW);<br />
// delay(800);<br />
Serial.println(data);<br />
blue.write(data);<br />
blue.write(13);<br />
//Serial.print(&#8220;ATO1:&#8221;);<br />
// Serial.println(data);<br />
delay(800);<br />
}/*<br />
if(data &gt;= &#8217;1&#8242; &amp;&amp; data &lt;= &#8217;5&#8242;)<br />
{</p>
<p>if((data==&#8217;4&#8242;)||(data==&#8217;1&#8242;)||(data==&#8217;2&#8242;))<br />
{<br />
digitalWrite(Stream_control,HIGH);</p>
<p>blue.write(65);<br />
blue.write(84);<br />
blue.write(79);<br />
blue.write(49);<br />
blue.write(13);</p>
<p>int a=digitalRead(Stream_status);<br />
// Serial.println(a);<br />
if(a==0)<br />
{<br />
digitalWrite(Stream_control,LOW);<br />
// delay(800);<br />
Serial.println(data);<br />
blue.write(data);<br />
blue.write(13);<br />
//Serial.print(&#8220;ATO1:&#8221;);<br />
// Serial.println(data);<br />
delay(800);<br />
}<br />
}*/<br />
if(data==&#8217;5&#8242;)<br />
{<br />
step = 1;<br />
}<br />
if((Rfsr&gt;1000)&amp;&amp;(step==1))<br />
{<br />
step=0;<br />
theta(x,y);<br />
}<br />
Serial.println((char)data);<br />
int index = data &#8211; &#8217;0&#8242; &#8211; 1;<br />
Vibrate_state[index] = !Vibrate_state[index];<br />
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);<br />
delay(2000);<br />
Vibrate_state[index] = !Vibrate_state[index];<br />
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);<br />
}<br />
//}<br />
theta(x,y);<br />
}</p>
<p>void theta(int mx, int my)<br />
{<br />
thetan = atan2(my,mx)*(180/3.14159265) +180;<br />
compass(thetan);<br />
// Serial.println(dir);<br />
}</p>
<p>void compass(float sum_theta)<br />
{<br />
if ((sum_theta&gt;=53) &amp;&amp; (sum_theta &lt;=160))<br />
{<br />
dir = &#8216;E&#8217;;<br />
}<br />
else if ((sum_theta&gt;=6) &amp;&amp; (sum_theta &lt;=52))<br />
{<br />
dir = &#8216;F&#8217;;<br />
}<br />
else if (((sum_theta&gt;=322) &amp;&amp; (sum_theta &lt;=360))||((sum_theta&gt;=0) &amp;&amp; (sum_theta &lt;=5)))<br />
{<br />
dir = &#8216;G&#8217;;<br />
}<br />
else if ((sum_theta&gt;=161) &amp;&amp; (sum_theta &lt;=320))<br />
{<br />
dir = &#8216;H&#8217;;</p>
<p>}<br />
compass_print(dir);<br />
}<br />
void compass_print(char dir)<br />
{<br />
//Serial.println(dir);<br />
//if(Rfsr&gt;1000)<br />
// {<br />
//blue.println(sum_theta);</p>
<p>if(dir != dir2)<br />
{<br />
digitalWrite(Stream_control,HIGH);<br />
delay(800);<br />
// BTSerial.println(&#8220;AT&#8221;);<br />
blue.write(65);<br />
blue.write(84);<br />
blue.write(79);<br />
blue.write(50);<br />
blue.write(13);<br />
// BTSerial.write((char)&#8217;T');<br />
//Serial.print(&#8220;okay&#8221;);<br />
delay(10);</p>
<p>int a=digitalRead(Stream_status);<br />
// Serial.println(a);<br />
// if(a==0)<br />
// {<br />
digitalWrite(Stream_control,LOW);<br />
delay(800);<br />
blue.write(dir);<br />
blue.write(13);<br />
//Serial.println(BTSerial.println());<br />
// }<br />
}</p>
<p>dir2 = dir;<br />
// }<br />
}<br />
</div>
<p><span style="color: #00ccff"><strong>오른쪽 발</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>#include &lt;SoftwareSerial.h&gt;<br />
SoftwareSerial blue(2,3);//rx tx<br />
// 데이터(문자열)을 받을 버퍼의 크기.<br />
#define BUFF_SIZE 20<br />
// 데이터 버퍼<br />
uint8_t buffer[BUFF_SIZE];<br />
uint8_t index = 0;<br />
uint8_t data;<br />
int Vibrate_pins[4] = {8,7,0,4};<br />
int Vibrate_state[4];// LED 연결 핀<br />
int FSR_Pin = A0;<br />
int FSRReading;<br />
float Rfsr;<br />
int cnt;<br />
int i;</p>
<p>void setup(){<br />
//Initialize Serial and I2C communications<br />
Serial.begin(9600);<br />
blue.begin(9600);<br />
//digitalWrite(8, HIGH);<br />
// digitalWrite(4, HIGH);<br />
for(int i = 0; i &lt; 3; i++){<br />
pinMode(Vibrate_pins[i], OUTPUT);<br />
Vibrate_state[i] = false;<br />
digitalWrite(Vibrate_pins[i], Vibrate_state[i]);}<br />
}<br />
void loop(){</p>
<p>if (blue.available()){</p>
<p>//byte data = blue.read();</p>
<p>data = blue.read();<br />
// if(data == 13)<br />
// {<br />
// Serial.println(data);</p>
<p>if(data &gt;= &#8217;1&#8242; &amp;&amp; data &lt;= &#8217;4&#8242;)<br />
{<br />
Serial.print(&#8220;buffer:&#8221;);<br />
Serial.println(data);<br />
int index = buffer[0] &#8211; &#8217;0&#8242; &#8211; 1;<br />
Vibrate_state[index] = !Vibrate_state[index];<br />
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);<br />
delay(2000);<br />
Vibrate_state[index] = !Vibrate_state[index];<br />
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);<br />
// for(i=0;i&lt;index;i++)<br />
// buffer[i]=0;<br />
// index=0;</p>
<p>}</p>
<p>/*buffer[index++] = data;<br />
// 버퍼가 꽉 찼거나 문자열이 끝났을 때,<br />
// 루프에서 나간다.<br />
Serial.print((char)data);<br />
if(index == BUFF_SIZE || data == 13)<br />
{Serial.println(data);<br />
Serial.print(&#8220;buffer:&#8221;);<br />
Serial.println(buffer[0]);<br />
if(buffer[0] &gt;= &#8217;1&#8242; &amp;&amp; buffer[0] &lt;= &#8217;4&#8242;)<br />
//if(data &gt;= &#8217;1&#8242; &amp;&amp; data &lt;= &#8217;4&#8242;)<br />
{</p>
<p>int index = buffer[0] &#8211; &#8217;0&#8242; &#8211; 1;<br />
Vibrate_state[index] = !Vibrate_state[index];<br />
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);<br />
delay(2000);<br />
Vibrate_state[index] = !Vibrate_state[index];<br />
digitalWrite(Vibrate_pins[index], Vibrate_state[index]);<br />
for(i=0;i&lt;index;i++)<br />
buffer[i]=0;<br />
index=0;</p>
<p>}</p>
<p>// 9600bps 기준으로 delay 를 1ms 을 줘야 한다.<br />
delay(1);<br />
//}<br />
FSRReading = analogRead(FSR_Pin);<br />
Rfsr = ((9.78 * FSRReading)/(1-(FSRReading/1023.0)));<br />
delay(250);<br />
if(Rfsr&gt;1000)<br />
{<br />
cnt++;<br />
if(cnt&gt;1000){<br />
blue.println(&#8220;5&#8243;);<br />
cnt=0;<br />
}<br />
}<br />
}<br />
}<br />
</div>
<p><span style="color: #0000ff"><strong>참고문헌</strong></span><br />
· 카페 [임베디드 공작소]
· 200개의 단계별 예제로 배우는 안드로이드드 4.0 [한동호 저자]
· 그 외 네이버 지식인, 네이버 카페 “당근이의 AVR 갖구 놀기”</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ntrexgo.com/archives/33817/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[42호]제 6의 손가락 : 4절 링크를 이용한 수평 유지 로봇 SRF</title>
		<link>http://www.ntrexgo.com/archives/34059</link>
		<comments>http://www.ntrexgo.com/archives/34059#comments</comments>
		<pubDate>Thu, 25 May 2017 00:00:53 +0000</pubDate>
		<dc:creator>디바이스마트 매거진</dc:creator>
				<category><![CDATA[디바이스마트 매거진]]></category>
		<category><![CDATA[특집]]></category>
		<category><![CDATA[42호]]></category>
		<category><![CDATA[ict]]></category>
		<category><![CDATA[공모전]]></category>
		<category><![CDATA[디바이스마트]]></category>
		<category><![CDATA[매거진]]></category>
		<category><![CDATA[융합]]></category>
		<category><![CDATA[최우수상]]></category>
		<category><![CDATA[프로젝트]]></category>

		<guid isPermaLink="false">http://www.ntrexgo.com/?p=34059</guid>
		<description><![CDATA[디바이스마트 매거진 42호 &#124; 이 작품은 여분의 보조 손가락 SRF (Supernumerary Robotic Finger)를, 신체에 별도의 센서를 부착하지 않고도 신체 정보를 얻어 조절할 수 있다. SRF는 사람의 팔에 부착되어 쟁반과 같은 면적이 넓은 물체를 손으로 들 때, 물체가 균형을 잃지 않도록 보조해 주는 것을 목적으로 한다. ]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.ntrexgo.com/wp-content/uploads/2016/05/2016-ictmain.png" rel="lightbox[34059]"><img class="alignnone size-large wp-image-31056" alt="2016 ictmain" src="http://www.ntrexgo.com/wp-content/uploads/2016/05/2016-ictmain-620x156.png" width="620" height="156" /></a></p>
<p><span style="font-size: large;background-color: #000000;color: #ffffff"><strong>2016 ICT 융합 프로젝트 공모전 우수상</strong></span></p>
<p><span style="font-size: xx-large"><strong>제 6의 손가락 : 4절 링크를 이용한 </strong></span></p>
<p><span style="font-size: xx-large"><strong>수평 유지 로봇 SRF</strong></span></p>
<p><span style="font-size: x-large">(Supernumerary Robotic Finger)</span></p>
<p>&nbsp;</p>
<p style="text-align: right"><strong>글 | 고려대학교 최주헌</strong></p>
<p>&nbsp;</p>
<p><span style="color: #008000"><strong>심사평</strong></span></p>
<p><strong>JK전자</strong> 기능적으로는 어느 정도 구현이 되었으니 힘이 있는 모터를 사용해서 조금 더 무거운 것을 올려도 균형을 잡을 수 있다면 인체에 부착하여 무거운 짐을 옮길 때 사용하면 편리하겠네요.<br />
뉴티씨 균형 유지라는 매우 어려운 주제이지만, 누구나 쉽게 이해할 수 있도록 프로젝트를 구성하여 좋은 작품으로 평가된다. 알고리즘 등에 보다 집중하여 구현하고 설명을 한다면 더 좋은 작품이 될 것으로 보이며, 움직임이 보다 빠르게 구현될 수 있도록 하여, 빠른 움직임에서도 빠르게 대처될 수 있도록 개선하는 작업이 필요해 보이며, 앞으로 좀 더 연구하여 매우 훌륭한 작품을 만들기를 바라며, 좋은 점수를 받았다.<br />
<strong></strong></p>
<p><strong>칩센</strong> 좋은 아이디어와 훌량한 완성도를 가지고 있다. 장애를 가진 사람에게도 도움이 될 아이디어 같다.<br />
<strong></strong></p>
<p><strong>위드로봇</strong> 아이디어와 작품의 완성도가 무척 높습니다. 제어기를 좀 더 세심하게 설계하여 평판의 기울기 정도를 좀 더 잘 제어할 수 있으면 재미있는 상품이 나올 수 있을 것 같습니다.</p>
<p><span style="color: #008000"><strong>작품 개요</strong> </span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-1.jpg" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34060" alt="42 ict 4절 링크를 이용한 (1)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-1.jpg" width="302" height="452" /></a></p>
<p>전지와 MCU(Micro Controller Unit)의 소형화 추세에 따라 웨어러블 로봇이 각광받고 있다. 최근에는 “사람의 팔, 다리가 여러 개이면 어떨까?” 라는 아이디어에서 나온 여분의 신체부위 로봇 SRL(Supernumerary Robotic Limbs)이 개발되고 있다. 하지만 이러한 SRL은 사람의 의도를 파악하기 위해, 추가하고자 하는 신체부위에 많은 센서를 부착해야 하는 문제가 있다. 이 작품은 여분의 보조 손가락 SRF (Supernumerary Robotic Finger)를, 신체에 별도의 센서를 부착하지 않고도 신체 정보를 얻어 조절할 수 있다. SRF는 사람의 팔에 부착되어 쟁반과 같은 면적이 넓은 물체를 손으로 들 때, 물체가 균형을 잃지 않도록 보조해 주는 것을 목적으로 한다. 이때 필요한 신체 정보는 SRF End Point에 부착된 센서를 통해 4절링크 모델로 분석하여 얻어낸다. 제작한 SRF로 수평 유지 실험결과 수평 유지에 큰 도움을 주는 것을 확인하였다. 위 작품을 통해 로봇과 인간사이의 조화 연구에 새로운 접근 방향을 제시할 것으로 본다.</p>
<p><span style="color: #008000"><strong>작품 설명</strong> </span><br />
<span style="color: #99cc00"><strong>주요 동작 및 특징</strong> </span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-2.jpg" rel="lightbox[34059]"><img class="alignnone size-large wp-image-34061" alt="42 ict 4절 링크를 이용한 (2)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-2-559x620.jpg" width="559" height="620" /></a></p>
<p>본 작품은 쟁반과 같은 넓은 평면 물체의 균형을 잡아주는 여분의 보조 손가락(SRF) 웨어러블 로봇으로, 손목에 로봇이 부착된다. 로봇의 센서가 쟁반에 부착되어 쟁반의 지면과의 기울기를 측정하고 이에 따라 로봇의 서보 모터를 제어하여 쟁반의 균형을 유지한다. 본 작품은 기존의 SRF로봇들이 수행하는 물건을 잡는 기능이 아니라 물체의 균형을 잡는 새로운 기능을 시도하여 SRF 연구에 새로운 방안을 제시한다.</p>
<p><span style="color: #99cc00"><strong>전체 시스템 구성</strong> </span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-3.jpg" rel="lightbox[34059]"><img class="alignnone size-large wp-image-34063" alt="42 ict 4절 링크를 이용한 (3)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-3-595x620.jpg" width="595" height="620" /></a></p>
<p>본 작품은 물체의 균형을 잡아주는 2개의 서보모터(AX-12)와 물체의 기울기를 측정하는 IMU 센서(EBIMU-9DOFV3), 이들의 상호작용을 일으키는 연결 Joint들, 모터 제어와 센서 값을 받아들이는 MCU(아두이노MEGA)로 구성된다. 이와 같은 로봇 디자인이 나오게 된 이유는 단계별 제작과정에 구체적으로 서술하였으며 작동방식은 첨부한 영상을 통해 보다 이해하기 쉽게 하였다.</p>
<p><span style="color: #33cccc"><strong>SRF 전체 구성</strong></span><br />
SRF 로봇은 사람 손목에 부착되며 2개의 흡착판은 평면 물체에 부착된다. 각각의 서보 모터는 로봇과 부착된 물체의 Roll, Pitch를 조절하여 지면과의 수평을 조절할 수 있다. MCU는 IMU 센서 값에 측정되는 Roll Pitch 값을 받아들여 지평면과의 수평을 유지하도록 모터를 제어한다. 제어방식은 PID 제어 방식이며, 처음에 모터 각속도에 따른 평면 물체의 각속도 변화를 통해 사람 손가락과 로봇 End Point간의 거리를 측정, 제어 상수를 결정한다.<br />
이러한 과정을 통해 SRF 로봇은 손가락에 별도의 센서를 부착하지 않고도 손의 위치를 파악하여 손위의 평면 물체 기울기를 유지할 수 있도록 보조해준다.</p>
<p><span style="color: #99cc00"><strong>개발 환경(개발 언어, Tool, 사용 시스템 등) </strong></span><br />
· C언어를 이용하여 아두이노 MEGA 사용(아두이노 스케치)<br />
· SRF 손목 부착 방식 (구버전)<br />
· 서보모터와 IMU 센서는 시리얼통신을 이용</p>
<p><span style="color: #008000"><strong>단계별 제작 과정</strong> </span><br />
<span style="color: #99cc00"><strong>SRF 모델 설정</strong></span><br />
손위의 평판 기울기를 조절하기 위해서는 평판과 만나는 최소 3개의 점으로 평면이 필요하며, 3점 간의 거리를 조절하여 3차원 상의 기울기 Roll. Pitch, Yaw의 각도를 조절할 수 있다.<br />
3차원 상에서 지면과 수평을 이루기 위해서는 평판과 지면 사이의 각이 전부 0이 되면 된다. 즉 수평면 사이의 각인 Roll, Pitch가 0이 되도록 3개의 점을 조절하면 된다. 그렇기에 손의 변화에 맞춰 Roll, Pitch 값이 0에 수렴하도록 SRF를 2자유도 모델로 설정하여 설계하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-2.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34062" alt="42 ict 4절 링크를 이용한 (2)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-2.png" width="620" height="349" /></a></p>
<p>위 모델을 통해 사람 손을 단순화 시켜보면 평판과접하는 5개의 손가락은 그림(Fig 1)처럼, 평판과 수평면 사이 각을 조절하는데 필요한 3개의 점 중 하나의 점으로 볼 수 있다. 이렇게 할 경우 손의 점을 기준으로 나머지 점 2개의 위치를 조절하여 손위의 평판과 수평면과 평행하게 조절할 수 있다. 본 작품은 이러한 모델을 통해 하드웨어 설계를 진행 하였다.</p>
<p><span style="color: #99cc00"><strong>SRF 하드웨어 디자인</strong></span><br />
2자유도의 SRF는 2개의 서보모터(Dynamixel AX-12), 4개의 링크, 조인트, End Point로 구성되어 있으며 아래 그림(Fig 2)과 같은 형태로 설계하였으며 이에 따른 D-H 변수는 표 1과 같다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-3.png" rel="lightbox[34059]"><img class="alignnone  wp-image-34064" alt="42 ict 4절 링크를 이용한 (3)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-3-591x620.png" width="620" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-4.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34066" alt="42 ict 4절 링크를 이용한 (4)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-4.png" width="620" height="294" /></a></p>
<p>이때 θ1과 θ1만 서보 모터를 이용하여 제어하도록 설계하였는데, 그 이유는 2차원 상에서 보았을 때 그림(Fig 3)의 형태처럼 손위의 평판과 SRF의 End Point로 결합할 경우 2자유도 모델이 되기 때문이다.<br />
이때 SRF와 평판과 손의 관계가 4절 링크 형상을 띄기 때문에 이러한 관계를 이용하여 평판의 수평 조절을 제어할 수 있다. Joint 1은 End point와 함께 Universal Joint의 역할을 하여 Motor2 제어시 손목의 꺾임을 막는다. 평판의 수평 조절을 위해서는 손의 형상에 따른 임의로 주어진 평판 위 1개의 점을 통해 2개의 점을 조절하면 되기때문에, End Point 설계시 평판과 2점이 만나 부착될 수 있도록 하였다. 또한 End Point는 평판에 부착되어 평판의 Roll, Pitch 값과 End Point의 Roll, Pitch 값은 동일하기 때문에 End Point에 IMU Sensor를 부착하여 평판의 기울기 정보를 얻어내도록 하였다. (Fig 4)</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-4.jpg" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34065" alt="42 ict 4절 링크를 이용한 (4)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-4.jpg" width="620" height="781" /></a></p>
<p>이러한 설계를 통해 NX 3D모델링 프로그램과 3D프린터를 이용하여 제작한 SRF는 위 그림(Fig 5)과 같다. 부품 제작 과정은 아래에 기재하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-5.jpg" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34067" alt="42 ict 4절 링크를 이용한 (5)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-5.jpg" width="620" height="393" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-5.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34068" alt="42 ict 4절 링크를 이용한 (5)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-5.png" width="620" height="789" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-6.jpg" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34069" alt="42 ict 4절 링크를 이용한 (6)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-6.jpg" width="620" height="780" /></a></p>
<p><span style="color: #99cc00"><strong>SRF 제어</strong></span><br />
설계한 SRF를 이용하여 평판이 수평을 유지하도록 하기 위해서는 End Point에 부착된 IMU 센서가 측정하는 Roll, Pitch 값을 0에 수렴하도록 모터 2개를 제어해야 한다. 각각의 모터는 Roll과 Pitch를 제어할 수 있는데 Motor1의 경우 그림(Fig 6.)처럼 Pitch 값을 제어할 수 있다.<br />
SRF는 그림(Fig 7)처럼 팔에 부착되어 있으며 초록색 사각형은 모터, 노란색 원은 Revolute-joint를 의미한다. SRF의 링, 팔, 평판의 움직임은 4절 링크와 같기 때문에, 표 1. D-H변수를 사용하면 θ1을 통해 θ3와 θ5가 정해진다. θ1통해 IMU센서로 측정되는 Roll 값을 제어 할 수 있으므로 Pitch가 0이 되도록 Motor1을 PID 제어로 제어하였다.<br />
하지만 θ1과 Pitch값을 조절하는 시스템이 일정하지 않고 손의 길이 a0 평판의 길이 a4에 따라 관계가 바뀌기 때문에 컨트롤러의 Kp, Ki, Kd 상수 값은 IMU로 측정되는 각속도 값과 θ1 사이의 관계를 통해 지속적으로 변화시키도록 하였으며 그 과정은 이와 같다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-6.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34070" alt="42 ict 4절 링크를 이용한 (6)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-6.png" width="620" height="444" /></a></p>
<p>4절 링크 관계식을 이용하기위한 링크 별 길이 정보는 표 2와 같으며 팔 길이 a0 손목에서 손까지의 일반적인 길이 20cm로 정하였다. 이때 손과 SRF 사이의 평판 길이 a4가 잡는 방식에 따라 변하기 때문에, w1이 일정할 경우 a4의 변화와 링크a1의 회전 상태인 θ1에 따른 각속도 w6의 값의 변화를 알아야 한다. 4절 링크 관계식으로 이를 계산하면 아래 그림(Fig 7)과 같이 선형적인 관계임을 볼 수 있다. 이를 통해 측정된 w6와 θ1값을 통하여 w4를 측정 할 수 있으며 이를 이용하여 Kp, Ki, Kd 상수 값을 변경 시킨다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-7.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34072" alt="42 ict 4절 링크를 이용한 (7)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-7.png" width="620" height="406" /></a></p>
<p>Pitch 값의 수평 제어 후 Roll의 수평 제어의 경우, Motor2의 회전축과 Roll의 회전축이 일치하여 Motor2의 움직임이 Roll 값의 변화와 같다. 이러한 선형적인 관계이므로 PID 제어를 통해 Roll 값이 0이 되도록 제어하였다. Motor2를 제어하면 그림(Fig. 8)과 같이 평판과 손 SRF 사이의 간격이 &#8220;r&#8221;로 일정하기 때문에 Motor2의 회전축이 변하게 되고 손목을 꺾게 된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-8.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34074" alt="42 ict 4절 링크를 이용한 (8)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-8.png" width="620" height="395" /></a></p>
<p>그렇기 때문에 하드웨어 디자인에서 Joint 1을 넣어 End point와 함께 Universal Joint역할을 하게하여 손목 꺾임을 방지하였다. 대신 Motor2의 제어는 2D에서본 4절링크의 링크 길이를 변화시키기 때문에 평형에 맞추어진 Pitch 값에 변화를 주게 된다.<br />
Motor2에 의한 Pitch 변화에 바로 반응하기 위해 그림(Fig. 9)와 같은 제어 시스템을 사용하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-9.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34075" alt="42 ict 4절 링크를 이용한 (9)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-9.png" width="620" height="339" /></a></p>
<p><span style="color: #99cc00"><strong>SRF 성능 실험</strong></span><br />
로봇 설계 후 손의 위치 변화에 따른 평판의 각도 측정값은 다음과 같다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-10.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34076" alt="42 ict 4절 링크를 이용한 (10)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-10.png" width="620" height="641" /></a></p>
<p>외부에서 각도 변화가 주어졌을 때 SRF의 대응을 확인하기 위해, 일정한 주기로 평판을 변화시키며 이에 따른 SRF End Point 값을 측정한 결과. 그림(Fig 10, Fig 11)과 같이 SRF는 손의 움직임에 의한 평판의 진폭을 2배 이상 감소시키며 이를 통해 SRF의 목표인 수평 보조 기능을 잘 수행함을 확인할 수 있으며 충분히 빠른 시간에 반응하는 것을 확인할 수 있다.</p>
<p><span style="color: #99cc00"><strong>결론</strong></span><br />
본 작품은 물체의 수평 유지를 목적으로 하는 SRF에 대한 것으로, SRF가 사용자의 의도를 파악하는 방식으로는 로봇과 신체를 하나의 기구학적 모형으로 해석하고 이로부터 신체 정보를 얻음으로써 신체에 별도의 센서를 부착하지 않고도 수평유지라는 목적을 달성하는 방법을 제시하였다.<br />
이러한 방식의 SRF는 착용자에게 센서를 장착하는 대신 로봇 자체의 센서를 이용하기 때문에 착용자로부터 아무런 조건의 제한을 받지 않는다. 이 점을 이용하여 사람뿐만 아니라 향후 구조물 등에 부착되도록 하여 물체의 수평을 유지하는 역할을 수행할 수 있다. 또한 기존의 웨어러블 로봇의 인체 의도 파악 연구에 새로운 해결 방안을 제시하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-7.jpg" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34071" alt="42 ict 4절 링크를 이용한 (7)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-7.jpg" width="620" height="717" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-8.jpg" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34073" alt="42 ict 4절 링크를 이용한 (8)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-8.jpg" width="620" height="363" /></a></p>
<p><span style="color: #008000"><strong>기타(회로도, 소스코드, 참고문헌 등)</strong></span><br />
<span style="color: #99cc00"><strong>회로도</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-11.png" rel="lightbox[34059]"><img class="alignnone size-full wp-image-34077" alt="42 ict 4절 링크를 이용한 (11)" src="http://www.ntrexgo.com/wp-content/uploads/2017/08/42-ict-4절-링크를-이용한-11.png" width="620" height="350" /></a></p>
<p><span style="color: #99cc00"><strong>소스코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>#define Roll_initial 512<br />
#define Pitch_initial 512<br />
#define Yaw_initial 512<br />
#define Angle_MarginP 0.5<br />
#define Angle_Margin 0.5<br />
#define Kd 0.01 // D 제어<br />
#define Ky 0.3 // Roll 제어에 따른 Pitch 제어<br />
#define Ki 0.05 // i제어<br />
#define Motor_Speed 1000<br />
#define Speed_High 700<br />
#define Speed_Low 300<br />
#define Kp1 0.5<br />
#define ID_Roll 8<br />
#define ID_Pitch 4<br />
#define ID_Yaw 2<br />
int flag=1;<br />
int sequence1 =1;<br />
double Kp=2.5; // P제어<br />
int sa=0;<br />
double wr=0;<br />
double wp=0;<br />
char *str;<br />
char *p;<br />
int temp;<br />
double fRoll;<br />
double fPitch;<br />
double Roll, Pitch, Yaw;<br />
long Motor_R, Motor_P, Motor_Y;<br />
double ip=0;<br />
double ir=0;<br />
double Time = 0;<br />
double dt = 0.025;<br />
double maxw=0;<br />
void setup()<br />
{<br />
Serial.begin(115200); //Serial Monitor<br />
Serial1.begin(1000000); // Serial for Motor<br />
Serial2.begin(115200); // Serial for IMU</p>
<p>Motor_R = Roll_initial;<br />
Motor_P = Pitch_initial;<br />
Motor_Y = Yaw_initial;<br />
sequence1 =1;<br />
Motor(512,512, 512, 100);<br />
delay(1000);<br />
Motor(513,600,513, 100);<br />
delay(10);<br />
}void loop()<br />
{<br />
//시리얼 통신으로 IMU 센서값 받아들임<br />
temp=Serial2.available();<br />
if(temp&gt;40)<br />
{<br />
char b[60]={0};<br />
char c[60]={0};<br />
for(int i=0; i&lt;temp; i++)<br />
{<br />
b[i]=Serial2.read();<br />
}<br />
for(int i=0; i&lt;temp; i++)<br />
{<br />
if(b[i]==42)<br />
{<br />
for(int j=i; j&lt;temp; j++)<br />
{<br />
if(b[j]==13)<br />
{<br />
for(int k=0; k&lt;j-i-1; k++)<br />
{<br />
c[k]=b[k+i+1];<br />
}<br />
break;<br />
}<br />
}<br />
}<br />
}<br />
str = strtok_r(c,&#8221;,&#8221;,&amp;p);<br />
Roll = atof(str);<br />
str = strtok_r(NULL,&#8221;,&#8221;,&amp;p);<br />
Pitch = atof(str);<br />
Time += dt;</p>
<p>Serial.print(fRoll);<br />
Serial.print(&#8220;,&#8221;);<br />
Serial.print(fPitch);<br />
Serial.print(&#8220;,&#8221;);<br />
Serial.print(Time);<br />
Serial.println();<br />
//시간에 따른 IMU 센서값 출력<br />
delay(10);<br />
}else{<br />
Serial.begin(115200); //Serial Monitor<br />
Serial1.begin(1000000); // Serial for Motor<br />
Serial2.begin(115200); // Serial for IMU<br />
Serial.println(&#8220;Loop Start&#8221;);<br />
}<br />
//0값 노이즈 제거<br />
if(Pitch!=0){<br />
wp=(fPitch-Pitch)/0.03;<br />
ip+=fPitch*0.03;<br />
fPitch=Pitch;</p>
<p>}<br />
if(Roll!=0){</p>
<p>wr=(fRoll-Roll)/0.03; //Rol 각속도 측정<br />
Serial.print(&#8220;w is &#8211; &#8220;);<br />
Serial.print(wr);<br />
if(maxw&lt;abs(wr)&amp;&amp;abs(wr)&lt;100){ //초기 값 세팅에서 손가락 길이 알기위한 w가 측정 노이즈 보정위해 100이상은 무시<br />
maxw=abs(wr);</p>
<p>}<br />
Serial.print(&#8220;max w is &#8211; &#8220;);<br />
Serial.print(maxw);<br />
ip+=fRoll*0.03;</p>
<p>fRoll=Roll;<br />
}<br />
if(sequence1){ //전원 연결시 스캐닝과정 초기 Roll Pitch 값이 0이 되도록 단순제어<br />
if (0&lt;abs(maxw)&amp;&amp;abs(maxw)&lt;25){//w값에 따른 Kp값 변경<br />
Kp=3;<br />
}else if(26&lt;abs(maxw)&amp;&amp;abs(maxw)&lt;50){<br />
Kp=2,3;<br />
}else if(51&lt;abs(maxw)&amp;&amp;abs(maxw)){<br />
Kp=1.7;<br />
}<br />
if (abs(fPitch) &gt; Angle_MarginP)<br />
{</p>
<p>if(Pitch &gt; 0){<br />
if(Motor_P&lt;824){<br />
Motor_P+=1;<br />
}<br />
}<br />
else if(fPitch &lt; 0)<br />
{<br />
if(Motor_P&gt;200){</p>
<p>Motor_P-=1;</p>
<p>}<br />
}<br />
}</p>
<p>if (abs(fRoll) &gt; Angle_Margin)<br />
{</p>
<p>if(fRoll &lt; 0){<br />
if(Motor_R&lt;700){</p>
<p>Motor_R+=3;</p>
<p>}<br />
}<br />
else if(fRoll &gt; 0)<br />
{<br />
if(Motor_R&gt;300){<br />
Motor_R-=3;</p>
<p>}<br />
}<br />
}<br />
Motor(Motor_R,Motor_Y, Motor_P, 100);</p>
<p>}else{</p>
<p>//스캐닝 후 PID 제어</p>
<p>if (abs(fPitch) &gt; Angle_MarginP)<br />
{<br />
Motor_P+=wp*Kd+Ki*ip;<br />
if(Pitch &gt; 0){<br />
if(Motor_P&lt;824){<br />
Motor_P+=abs(fPitch)*Kp1;<br />
}<br />
}<br />
else if(fPitch &lt; 0)<br />
{<br />
if(Motor_P&gt;200){</p>
<p>Motor_P-=abs(fPitch)*Kp1;</p>
<p>}<br />
}<br />
Motor_R+=Ky*abs(fPitch);<br />
}</p>
<p>if (abs(fRoll) &gt; Angle_Margin)<br />
{</p>
<p>if(fRoll &lt; 0){<br />
if(Motor_R&lt;700){<br />
Motor_R+=wr*Kd+ip*Ki;<br />
Motor_R+=abs(fRoll)*Kp;</p>
<p>}<br />
}<br />
else if(fRoll &gt; 0)<br />
{<br />
if(Motor_R&gt;300){<br />
Motor_R-=abs(fRoll)*Kp;<br />
Motor_R+=wr*Kd+ip*Ki;<br />
}<br />
}<br />
}<br />
Motor(Motor_R,Motor_Y, Motor_P, Motor_Speed); //모터와 시리얼 통신<br />
}<br />
if((abs(fRoll)&lt;Angle_MarginP)&amp;&amp;(abs(fPitch)&lt;Angle_MarginP)){<br />
sequence1=0;<br />
Motor_Y-=1;</p>
<p>}<br />
Serial.println (sequence1);<br />
delay(15);<br />
}<br />
void Motor(unsigned int Pos_1, unsigned int Pos_2, unsigned int Pos_3, unsigned int Speed) //모터 시리얼 통신 함수<br />
{ unsigned char Check_Sum;<br />
int Num_Actuator = 3;<br />
unsigned char ID_1 = 8;<br />
unsigned char ID_2 = 2;<br />
unsigned char ID_3 = 4;<br />
unsigned char Length = 5*Num_Actuator+4;</p>
<p>Serial1.write(0xFF);<br />
Serial1.write(0xFF);<br />
Serial1.write(0xFE); //Broadcast ID<br />
Serial1.write(Length); //Length<br />
Serial1.write(0&#215;83); //Instruction<br />
Serial1.write(0x1E); //Address<br />
Serial1.write(4); //Data Length</p>
<p>Serial1.write(ID_1);<br />
Serial1.write(Pos_1);<br />
Serial1.write(Pos_1&gt;&gt;8);<br />
Serial1.write(Speed);<br />
Serial1.write(Speed&gt;&gt;8);<br />
Serial1.write(ID_2);<br />
Serial1.write(Pos_2);<br />
Serial1.write(Pos_2&gt;&gt;8);<br />
Serial1.write(Speed);<br />
Serial1.write(Speed&gt;&gt;8);<br />
Serial1.write(ID_3);<br />
Serial1.write(Pos_3);<br />
Serial1.write(Pos_3&gt;&gt;8);<br />
Serial1.write(Speed);<br />
Serial1.write(Speed&gt;&gt;8);<br />
Check_Sum = ~(0xFE + Length + 0&#215;83 + 0x1E + 4 + (ID_1+ID_2+ID_3) + (Pos_1+Pos_2+Pos_3) + ((Pos_1&gt;&gt;8)+(Pos_2&gt;&gt;8)+(Pos_3&gt;&gt;8)) + 3*(Speed+(Speed&gt;&gt;8)));<br />
Serial1.write(Check_Sum);<br />
}<br />
</div>
<p>&nbsp;</p>
<p><span style="color: #99cc00"><strong>참고문헌</strong></span><br />
[1] C. Davenport, F. Parietti, and H. H. Asada, “Design and biomechanicalanalysis of supernumerary robotic limbs,” in ASME 2012 5th Annual Dynamic Systems and Control Conference joint with the JSME 2012. 11th Motion and Vibration Conference, pp. 787-793, 2012.<br />
[2] Domenico Prattichizzo, Monica Malvezzi, Infan Hussain and Gionata Salvietti “The Sixth-Finger: a Modular Extra-Finger to Enhance Human Hand Capabilites”in The 23rd IEEE International Symposium on Robot and Human Interactive Communication 2014<br />
[3] Arthur G.Erdman and George N.Sandor, Sridhar Kota Mechanism Design Analysis and Synthesis 4Edition, Prentice Hall</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ntrexgo.com/archives/34059/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[31호]Safe 다리미</title>
		<link>http://www.ntrexgo.com/archives/29610</link>
		<comments>http://www.ntrexgo.com/archives/29610#comments</comments>
		<pubDate>Wed, 15 Jul 2015 08:20:44 +0000</pubDate>
		<dc:creator>디바이스마트 매거진</dc:creator>
				<category><![CDATA[디바이스마트 매거진]]></category>
		<category><![CDATA[특집]]></category>
		<category><![CDATA[31호]]></category>
		<category><![CDATA[Feature]]></category>
		<category><![CDATA[ict]]></category>
		<category><![CDATA[safe]]></category>
		<category><![CDATA[공모전]]></category>
		<category><![CDATA[다리미]]></category>
		<category><![CDATA[디바이스마트]]></category>
		<category><![CDATA[매거진]]></category>
		<category><![CDATA[융합]]></category>
		<category><![CDATA[최우수상]]></category>
		<category><![CDATA[프로젝트]]></category>

		<guid isPermaLink="false">http://www.ntrexgo.com/?p=29610</guid>
		<description><![CDATA[디바이스마트 매거진 31호 &#124; 다리미 사용 직후 뜨거움의 정도를 LED Bar의 밝기를 통해 시각화 하였다. 이에 따라 다리미의 온도를 간단하게 인지하여 화상 사고를 예방한다. ]]></description>
				<content:encoded><![CDATA[<p><span style="font-size: x-large"><strong><a href="http://www.ntrexgo.com/archives/29610/31ict-%ec%b5%9c%ec%9a%b0%ec%88%98%ec%83%81" rel="attachment wp-att-29631"><img class="alignnone size-full wp-image-29631" alt="31ict 최우수상" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31ict-최우수상.jpg" width="620" height="261" /></a></strong></span></p>
<p><span style="font-size: x-large"><strong>2014 ICT 융합 프로젝트 공모전 최우수상</strong></span></p>
<p><span style="font-size: large"><strong>Safe 다리미</strong></span></p>
<p style="text-align: right">글 | 한국외국어대학교 전자공학과 한재준, 이홍준</p>
<p><span style="font-size: medium;color: #ffffff;background-color: #000080"><strong>심 사 평</strong></span></p>
<p>싱크웍스 재미있는 아이디어인 것 같다. 작은 기능이지만 실생활에 도움이 될 것 같다.<br />
jk전자 간단한 부품과 회로를 이용하였지만 실제 다리미에 적용을 하면 사용하는 사람의 편의성이 많이 좋아질것 같다. 기울기 센서를 이용하여 전원을 자동 차단하는 안전 장치와 특히 다림질을 하려는 직물에 따라서 LED로 쉽게 알려주는 기능은 아주 편리하게 사용할 수 있을것 같다.<br />
뉴티씨 매우 참신한 아이디어로 판단되며 실질적으로 사용될 수 있을 것으로 생각된다. 다리미 회사에서 이를 채용하여 사용한다면, 보다 안전한 다리미가 될 수 있지 않을까 생각된다. 작품의 구현도 어렵지 않지만, 잘 구현하였고, 보고서 작성도 잘 된 것으로 생각된다.</p>
<p><span style="font-size: medium;color: #ffffff;background-color: #000080"><strong>작품 개요</strong></span></p>
<p>다리미 사용 직후 뜨거움의 정도를 LED Bar의 밝기를 통해 시각화 하였다. 이에 따라 다리미의 온도를 간단하게 인지하여 화상 사고를 예방한다. 그리고 다리미가 넘어진 경우 자동으로 전원을 차단하여 안전한 다리미의 작동을 보장한다. 또한 면, 실크, 아크릴 등 각각의 옷감을 다림질하기에 적절한 온도가 되었는지를 알려주어 사용 편의성을 높였다.</p>
<p><span style="color: #ffffff;font-size: medium;background-color: #000080"><strong>작품 설명</strong></span></p>
<p><span style="color: #0000ff"><strong>■ 온도 시각화</strong></span></p>
<div id="attachment_29633" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-1" rel="attachment wp-att-29633"><img class="size-full wp-image-29633" alt="그림 1. 온도에 따른 LED Bar의 밝기" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-1.jpg" width="620" height="343" /></a><p class="wp-caption-text">그림 1. 온도에 따른 LED Bar의 밝기</p></div>
<p>다리미를 사용한 직후 열을 식히기 위하여 다리미를 세워둔 경험이 있을 것이다. 다림질을 직접 한 사람은 다리미의 온도를 가늠할 수 있지만, 다림질을 하지 않은 사람은 무심코 뜨거운 다리미를 건드리게 되어 화상을 입을 수 있다. 이러한 사고를 방지하기 위하여 다리미 온도를 LED Bar의 밝기를 통해 시각화 했다. 방금 다림질이 끝난 매우 뜨거운 온도에서는 LED Bar를 밝게 켜서 위험하다는 것을 알리고, 시간이 흘러 서서히 식어 감에 따라 LED Bar의 밝기는 점차 줄어든다. 다리미가 완전히 식을 경우 LED Bar를 꺼서 안전하다는 것을 알린다.</p>
<p><span style="color: #0000ff"><strong>■ 자동 전원 차단</strong></span><br />
다리미의 전원이 켜진 상태에서 실수로 다리미가 넘어진다면 옷감이 타거나, 심할 경우 화재가 일어날 수 있다. 이러한 경우를 예방하기 위해 기울기 스위치와 푸쉬 스위치를 사용하여 위험 상황 여부를 판단하고, 만약 위험 상황이 발생할 경우 릴레이 스위치를 OFF 시켜 전원을 자동으로 차단한다.</p>
<p><span style="color: #0000ff"><strong>■ 적정 옷감 표시</strong></span><br />
대부분의 다리미는 온도조절 다이얼을 돌려 적절한 옷감을 다릴 수 있게 한다.</p>
<div id="attachment_29635" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-2" rel="attachment wp-att-29635"><img class="size-full wp-image-29635" alt="그림 2. 온도 조절 다이얼의 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-2.jpg" width="620" height="313" /></a><p class="wp-caption-text">그림 2. 온도 조절 다이얼의 모습</p></div>
<p>Safe 다리미는 온도조절 다이얼을 돌려 선택한 온도가 실제로 각각의 옷감에 알맞은 온도로 예열이 되었는지를 알려주는 기능을 수행 한다. 다리미의 온도가 100 ~ 120도일 때 초록 LED(면), 121 ~ 140도일 때 노랑 LED(실크), 141도 이상일 때 빨강 LED(아크릴)가 점등 된다.</p>
<p><span style="color: #800080"><strong>주요 동작 및 특징</strong></span><br />
<span style="color: #0000ff"><strong>■ 온도 시각화</strong></span><br />
온도를 시각화하기 위해 온도계(LM35), LED Bar, MCU(MSP430G 2452), 트랜지스터(TIP122), 승압IC(MC34063) 등이 사용되었다. LED Bar는 12V 전압을 사용하기 때문에 승압회로를 이용하여 3V -&gt; 12V로 승압하였다. 또한 다리미의 AC 전원이 차단된 이후에도 온도 시각화가 이루어져야 하므로 AAA 배터리를 전원으로 사용하였다.</p>
<div id="attachment_29637" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-3" rel="attachment wp-att-29637"><img class="size-full wp-image-29637" alt="그림 3. 온도 시각화 블록 다이어그램" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-3.jpg" width="620" height="431" /></a><p class="wp-caption-text">그림 3. 온도 시각화 블록 다이어그램</p></div>
<p>① 다리미 히팅 판넬의 온도를 측정하기 위해 아날로그 온도계를 사용하였다. 아날로그로 출력된 온도 값은 MCU(Micro Controller Unit)의 ADC(Analog to Digital Converter)를 통하여 디지털 값으로 변환된다.</p>
<div id="attachment_29638" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-4" rel="attachment wp-att-29638"><img class="size-full wp-image-29638" alt="그림 4. 다리미 히팅 판넬에 온도계를 부착한 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-4.jpg" width="620" height="311" /></a><p class="wp-caption-text">그림 4. 다리미 히팅 판넬에 온도계를 부착한 모습</p></div>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>// 온도를 100번 측정하여 평균값을 구함<br />
void readTemp() {<br />
adcSum = 0;<br />
//adcDiv = 100;<br />
for (i = 0; i &lt; adcDiv; i++) {<br />
ADC10CTL0 |= ENC + ADC10SC; // Sampling and<br />
conversion start<br />
adcSum += ADC10MEM;<br />
__delay_cycles(100);<br />
}<br />
adcAve = adcSum / adcDiv;<br />
temp = (adcAve * 2.5 / 1023.0) * 100;<br />
}</p>
<p><strong>코드 1. 온도 값 측정</strong></p>
</div>
<p>신뢰성 있는 온도 값을 확보하기 위해 온도를 100번 측정 한 후 평균을 낸 값을 사용한다.</p>
<p>② MCU가 온도 값을 읽은 후 그에 비례하여 3V 전압의 PWM(Pulse Width Modulation) 신호를 출력한다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>//PWM 출력을 위한 타이머 설정<br />
void timerAInit() {<br />
P1DIR |= BIT2 + BIT3; // P1.2 and P1.3 output<br />
P1SEL |= BIT2 + BIT3; // P1.2 and P1.3 TA1/2 options<br />
CCR0 = 2000; // PWM Period<br />
CCTL1 = OUTMOD_7; // CCR1 reset/set<br />
TACTL = TASSEL_2 + MC_1; // SMCLK, up mode<br />
}</p>
<p>//온도에 따른 PWM 듀티비 조절(LED Bar 밝기 조절)<br />
//LED Bar의 밝기를 효과적으로 나타내기 위해 두개의 방정식 사용<br />
void tempWarningLed() {<br />
if (cTemp &lt; 80) {<br />
CCR1 = cTemp * 3 &#8211; 120;<br />
} else {<br />
CCR1 = cTemp * 25 &#8211; 1880;<br />
}<br />
}</p>
<p><strong>코드 2. 온도 값에 따른 PWM 출력 설정</strong></p>
</div>
<p>③ ②에서 출력된 3V PWM 신호는 트랜지스터(TIP122)와 승압 회로(MC34063)를 만나 12V 전압의 PWM 신호로 변환 된다. 출력되는 신호의 듀티비는 온도에 따라 0% ~ 100% 까지 조절되며, 아래와 같이 LED Bar의 밝기를 조절할 수 있다.</p>
<div id="attachment_29639" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-5" rel="attachment wp-att-29639"><img class="size-full wp-image-29639" alt="그림 5. 듀티비에 따른 LED Bar의 밝기 변화" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-5.jpg" width="620" height="346" /></a><p class="wp-caption-text">그림 5. 듀티비에 따른 LED Bar의 밝기 변화</p></div>
<p><strong style="color: #0000ff">■ 자동 전원 차단</strong></p>
<p>다리미의 전원이 연결된 상태에서 다리미가 넘어지는 상황이 발생할 경우 다리미의 전원을 자동 차단한다. 이를 위해 릴레이 스위치(JS1-3V), 푸쉬 스위치(BL150-L-M), 기울기 스위치(SW-200) 등이 사용되었다.</p>
<div id="attachment_29640" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-6" rel="attachment wp-att-29640"><img class="size-full wp-image-29640" alt="그림 6. 자동 전원차단 회로의 블록 다이어그램" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-6.jpg" width="620" height="383" /></a><p class="wp-caption-text">그림 6. 자동 전원차단 회로의 블록 다이어그램</p></div>
<p style="padding-left: 30px">①. 기울어짐에 따라 접점이 ON/OFF가 되는 스위치로서, 다리미가 서 있을 경우 접점이 OFF 되고, 다리미가 누워 있을 경우 접점이 ON 된다.</p>
<p style="padding-left: 30px">②. 다리미를 사용 할 때 자연스럽게 검지 손가락으로 푸쉬 스위치가 눌릴 수 있도록 다리미 손잡이 안쪽에 위치한다. ①번과 ②의 데이터를 종합하여 위험상황이 발생했는지 감지한다. 만약 다리미가 기울어진 상태에서 푸쉬 스위치가 눌리지 않았다면 위험 상황으로 간주되고, 다리미가 기울어졌으나 푸쉬 스위치가 눌린 상황이라면 다리미를 정상적으로 사용하는 상황으로 간주된다. 또한 다리미가 서있는 상황은 안전한 상황으로 간주된다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>//푸쉬 스위치, 기울기 스위치 설정 및 인터럽트 설정<br />
void swInit() {<br />
P2OUT |= BIT4 + BIT5; //P2.4 = 푸쉬 스위치, P2.5 = 기울기 스위치<br />
P2REN |= BIT4 + BIT5;</p>
<p>P2IE |= BIT4 + BIT5;<br />
P2IES |= BIT4 + BIT5;<br />
P2IFG &amp;= ~(BIT4 + BIT5);<br />
_BIS_SR(GIE);<br />
}</p>
<p>//릴레이 스위치 설정<br />
void relayInit() {<br />
P1DIR |= BIT5;<br />
relayOn<br />
;<br />
}</p>
<p>//기울기 스위치 인터럽트 서비스 루틴<br />
#pragma vector=PORT2_VECTOR<br />
__interrupt void Port_2(void) {<br />
//기울어졌을 때<br />
if (!(P2IN &amp; BIT5)) {<br />
ledSwOn<br />
;<br />
//스위치가 눌리지 않았을 때<br />
if (!(P2IN &amp; BIT4)) {</p>
<p>//위험한 온도일 때<br />
if (cTemp &gt; 40) {<br />
relayOff //위험상황 감지 시 릴레이 OFF<br />
;<br />
}<br />
//위험 상황이 아닐 때<br />
} else {<br />
relayOn<br />
;<br />
}<br />
//위험 상황이 아닐 때<br />
} else {<br />
ledSwOff<br />
;<br />
relayOn<br />
;<br />
}<br />
P2IFG &amp;= ~(BIT4 + BIT5);<br />
}</p>
<p><strong>코드 3. 위험 상황 감지를 위한 인터럽트 설정과 위험 상황 발생 시 릴레이 OFF</strong></p>
</div>
<p>③ 릴레이 스위치로써 위험 상황 감지 시 접점을 OFF 시킨다. 아래 그림은 위험 상황이 발생한 경우와 안전한 상황의 모습을 나타낸다.</p>
<div id="attachment_29641" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-7" rel="attachment wp-att-29641"><img class="size-full wp-image-29641" alt="그림 7. 위험 상황이 발생한 경우의 모습 (220V OFF, 다리미가 누워있고 푸쉬 스위치가 눌리지 않음)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-7.jpg" width="620" height="317" /></a><p class="wp-caption-text">그림 7. 위험 상황이 발생한 경우의 모습 (220V OFF, 다리미가 누워있고 푸쉬 스위치가 눌리지 않음)</p></div>
<div id="attachment_29642" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-8" rel="attachment wp-att-29642"><img class="size-full wp-image-29642" alt="그림 8. 정상적으로 다리미를 사용할 때의 모습 (220V ON, 다리미가 누워있지만 푸쉬 스위치가 눌려 있음)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-8.jpg" width="620" height="318" /></a><p class="wp-caption-text">그림 8. 정상적으로 다리미를 사용할 때의 모습 (220V ON, 다리미가 누워있지만 푸쉬 스위치가 눌려 있음)</p></div>
<p><strong style="color: #0000ff">■ 적정 옷감 표시</strong></p>
<p>온도 조절 다이얼을 조작함에 따라 다리미의 실제 온도 값이 어떠한 옷감에 적절한지를 알려주기 위해 초록, 노랑, 빨강 LED를 통해 알려 준다.</p>
<div id="attachment_29643" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-9" rel="attachment wp-att-29643"><img class="size-full wp-image-29643" alt="그림 9. 각각의 옷감에 맞는 적절한 온도를 알려주기 위한 표시기의 블록다이어그램" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-9.jpg" width="620" height="381" /></a><p class="wp-caption-text">그림 9. 각각의 옷감에 맞는 적절한 온도를 알려주기 위한 표시기의 블록다이어그램</p></div>
<p>온도계로 다리미의 온도를 측정하여 온도조절 다이얼로 선택한 온도가 실제로 옷감에 적절한지를 알려준다.</p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>//적정 옷감 표시<br />
void tempLevelLed() {<br />
//다림질 하기에 온도가 낮을경우<br />
if (cTemp &lt; 100) {<br />
ledGreenOff<br />
;<br />
ledYellowOff<br />
;<br />
ledRedOff<br />
;<br />
}</p>
<p>//온도가 면 재질에 적합할 경우<br />
if (cTemp &gt; 100 &amp;&amp; cTemp &lt;= 120) {<br />
ledGreenOn<br />
ledYellowOff<br />
;<br />
ledRedOff<br />
;<br />
}<br />
//온도가 실크 재질에 적합할 경우<br />
if (cTemp &gt; 120 &amp;&amp; cTemp &lt;= 140) {<br />
ledYellowOn<br />
ledGreenOff<br />
;<br />
ledRedOff<br />
;<br />
}<br />
//온도가 아크릴 재질에 적합할 경우<br />
if (cTemp &gt; 150) {<br />
ledRedOn<br />
ledGreenOff<br />
;<br />
ledYellowOff<br />
;<br />
}</p>
<p>}</p>
<p><strong>코드 4. 온도에 따른 LED ON/OFF</strong></p>
</div>
<p><span style="color: #800080"><strong>전체 시스템 구성</strong></span></p>
<div id="attachment_29634" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-1-2" rel="attachment wp-att-29634"><img class="size-full wp-image-29634" alt="그림 10. Safe 다리미의 전체 시스템 구성" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-1.png" width="620" height="475" /></a><p class="wp-caption-text">그림 10. Safe 다리미의 전체 시스템 구성</p></div>
<p><span style="color: #800080"><strong>개발 환경(개발 언어, Tool, 사용시스템 등)</strong></span><br />
MCU : TI MSP430(MSP430G2542)<br />
소프트웨어 통합 개발 환경 : Code Composer Studio v5.5(TI MCU 통합 개발 환경)<br />
개발 언어 : C<br />
사용 시스템 : 64비트 Windows 7 기반 PC<br />
사용 장비 : PC, JTAG Debugger, 파워 서플라이, 멀티미터, 인두 등</p>
<p><span style="color: #ffffff;font-size: medium;background-color: #000080"><strong>단계별 제작 과정</strong></span></p>
<p><span style="color: #800080"><strong>부품 소개</strong></span></p>
<div id="attachment_29644" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-10" rel="attachment wp-att-29644"><img class="size-full wp-image-29644" alt="31 safe 다리미 (10)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-10.jpg" width="620" height="403" /></a><p class="wp-caption-text">그림 11. Safe 다리미 제작에 필요한 부품의 모습</p></div>
<div id="attachment_29636" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-2-2" rel="attachment wp-att-29636"><img class="size-full wp-image-29636" alt="31 safe 다리미 (2)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-2.png" width="620" height="388" /></a><p class="wp-caption-text">표 1. Safe 다리미 제작에 필요한 부품 목록</p></div>
<p>&nbsp;</p>
<p><span style="color: #800080"><strong>기울기 스위치 부착</strong></span><br />
다리미의 기울여짐을 알기 위하여 글루건을 이용하여 기울기 스위치를 부착한다.</p>
<div id="attachment_29645" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-11" rel="attachment wp-att-29645"><img class="size-full wp-image-29645" alt="그림 12. 다리미 밑판에 기울기 센서를 부착한 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-11.jpg" width="620" height="351" /></a><p class="wp-caption-text">그림 12. 다리미 밑판에 기울기 센서를 부착한 모습</p></div>
<p><strong>온도 센서 부착</strong><br />
다리미의 온도를 측정하기 위하여 히팅 판넬 뒷부분에 온도계를 부착한다.</p>
<div id="attachment_29646" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-12" rel="attachment wp-att-29646"><img class="size-full wp-image-29646" alt="그림 13. 다리미 히팅 판넬에 온도센서를 부착한 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-12.jpg" width="620" height="315" /></a><p class="wp-caption-text">그림 13. 다리미 히팅 판넬에 온도센서를 부착한 모습</p></div>
<p><strong>LED Bar 부착</strong><br />
다리미의 뜨거움 정도를 표시하기 위한 LED Bar를 다리미 내부에 부착한다.</p>
<div id="attachment_29647" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-13" rel="attachment wp-att-29647"><img class="size-full wp-image-29647" alt="그림 14. 다리미 내부에 LED Bar를 부착한 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-13.jpg" width="620" height="315" /></a><p class="wp-caption-text">그림 14. 다리미 내부에 LED Bar를 부착한 모습</p></div>
<p><strong>적정 옷감 표시용 LED 부착</strong><br />
드릴을 이용하여 구멍을 뚫어 초록, 노랑, 빨강 LED를 부착한다.</p>
<div id="attachment_29648" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-14" rel="attachment wp-att-29648"><img class="size-full wp-image-29648" alt="그림 15. 다리미 손잡이에 적정 옷감 표시용 LED를 부착한 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-14.jpg" width="620" height="315" /></a><p class="wp-caption-text">그림 15. 다리미 손잡이에 적정 옷감 표시용 LED를 부착한 모습</p></div>
<p><strong>푸쉬 스위치 부착</strong><br />
푸쉬 스위치를 부착하기 위해 드릴로 적절한 구멍을 뚫어 부착한다.</p>
<div id="attachment_29649" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-15" rel="attachment wp-att-29649"><img class="size-full wp-image-29649" alt="그림 16. 다리미 손잡이 밑 부분에 푸시 스위치를 부착한 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-15.jpg" width="620" height="277" /></a><p class="wp-caption-text">그림 16. 다리미 손잡이 밑 부분에 푸시 스위치를 부착한 모습</p></div>
<p><strong>만능 PCB 절단</strong><br />
만능 PCB를 다리미 내부에 장착 시킬 수 있도록 적절하게 자른다.</p>
<div id="attachment_29650" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-16" rel="attachment wp-att-29650"><img class="size-full wp-image-29650" alt="그림 17. 만능 PCB에 절단할 부분을 그린 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-16.jpg" width="620" height="317" /></a><p class="wp-caption-text">그림 17. 만능 PCB에 절단할 부분을 그린 모습</p></div>
<div id="attachment_29651" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-17" rel="attachment wp-att-29651"><img class="size-full wp-image-29651" alt="그림 18. 절단한 PCB를 다리미 밑판에 넣은 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-17.jpg" width="620" height="317" /></a><p class="wp-caption-text">그림 18. 절단한 PCB를 다리미 밑판에 넣은 모습</p></div>
<p>&nbsp;</p>
<p><strong>부품 납땜</strong><br />
MCU, 승압회로, 트랜지스터 등의 부품을 납땜한다. Safe 다리미의 회로도는 5장을 통해 확인할 수 있다.</p>
<div id="attachment_29652" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-18" rel="attachment wp-att-29652"><img class="size-full wp-image-29652" alt="그림 19. 각종 부품을 납땜한 모습 (전면)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-18.jpg" width="620" height="347" /></a><p class="wp-caption-text">그림 19. 각종 부품을 납땜한 모습 (전면)</p></div>
<div id="attachment_29653" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-19" rel="attachment wp-att-29653"><img class="size-full wp-image-29653" alt="그림 20. 각종 부품을 납땜한 모습 (후면)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-19.jpg" width="620" height="347" /></a><p class="wp-caption-text">그림 20. 각종 부품을 납땜한 모습 (후면)</p></div>
<div id="attachment_29654" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-20" rel="attachment wp-att-29654"><img class="size-full wp-image-29654" alt="그림 21. 릴레이와 배터리 홀더의 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-20.jpg" width="620" height="347" /></a><p class="wp-caption-text">그림 21. 릴레이와 배터리 홀더의 모습</p></div>
<div id="attachment_29655" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-21" rel="attachment wp-att-29655"><img class="size-full wp-image-29655" alt="그림 22. 모든 부품의 납땜을 완료한 후 밑판을 닫기 전의 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-21.jpg" width="620" height="347" /></a><p class="wp-caption-text">그림 22. 모든 부품의 납땜을 완료한 후 밑판을 닫기 전의 모습</p></div>
<p><strong>완성 모습</strong></p>
<p>Safe 다리미의 완성 모습이다. 손잡이 아래쪽에 푸쉬 스위치가 위치해 있고, 손잡이 위쪽에 적정 옷감 표시용 LED가 위치해 있다. 또한 다리미 내부에 기울기 스위치, 릴레이 스위치, 온도 센서, LED Bar, MCU 등의 각종 부품이 위치해 있다.</p>
<div id="attachment_29656" class="wp-caption alignnone" style="width: 630px"><a href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-22" rel="attachment wp-att-29656"><img class="size-full wp-image-29656" alt="그림 23. Safe 다리미의 완성 모습" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-22.jpg" width="620" height="345" /></a><p class="wp-caption-text">그림 23. Safe 다리미의 완성 모습</p></div>
<p><strong>작동 확인</strong></p>
<table style="width: 620px;background-color: #f9f9f9" border="0">
<tbody>
<tr>
<td><a style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;font-size: 13px;line-height: 19px" href="http://www.ntrexgo.com/archives/29610/31-safe-%eb%8b%a4%eb%a6%ac%eb%af%b8-23" rel="attachment wp-att-29657"><img class="alignnone size-full wp-image-29657" alt="31 safe 다리미 (23)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-23.jpg" width="620" height="361" /></a><span style="line-height: 19px"> </span><img class="alignnone size-full wp-image-29632" style="line-height: 19px" alt="31 safe 다리미 (24)" src="http://www.ntrexgo.com/wp-content/uploads/2015/07/31-safe-다리미-24.jpg" width="620" height="176" /></td>
</tr>
<tr>
<td>
<p style="text-align: center">그림 24. Safe 다리미의 작동 모습</p>
</td>
</tr>
</tbody>
</table>
<p>■ 50도 ~ 90도 : 온도에 따라 LED Bar의 밝기가 조절된다.</p>
<p>■ 110도 ~ 150도 : 다리미의 온도가 충분히 뜨거우므로 LED Bar의 밝기는 100%를 유지하고 면, 실크, 아크릴 옷감에 적절한 온도를 알려준다.</p>
<p><span style="font-size: medium;color: #ffffff;background-color: #000080"><strong>소스코드</strong></span></p>
<div class="symple-box gray none" style="text-align:left; width:100%;"> 
<p>#include &lt;msp430.h&gt;</p>
<p>#define ledGreenOn P2OUT |= BIT0;<br />
#define ledYellowOn P2OUT |= BIT1;<br />
#define ledRedOn P2OUT |= BIT2;<br />
#define ledGreenOff P2OUT &amp;= ~BIT0;<br />
#define ledYellowOff P2OUT &amp;= ~BIT1;<br />
#define ledRedOff P2OUT &amp;= ~BIT2;<br />
#define ledSwOn P2OUT |= BIT3;<br />
#define ledSwOff P2OUT &amp;= ~BIT3;<br />
#define relayOn P1OUT &amp;= ~BIT5;<br />
#define relayOff P1OUT |= BIT5;</p>
<p>float adcSum, adcAve;<br />
int i, cTemp, temp, adcDiv = 100;</p>
<p>//릴레이 스위치 설정<br />
void relayInit() {<br />
P1DIR |= BIT5;<br />
relayOn<br />
;<br />
}</p>
<p>//푸쉬 스위치, 기울기 스위치 설정 및 인터럽트 설정<br />
void swInit() {<br />
P2OUT |= BIT4 + BIT5; //P2.4 = 푸쉬 스위치, P2.5 = 기울기 스위치<br />
P2REN |= BIT4 + BIT5;</p>
<p>P2IE |= BIT4 + BIT5;<br />
P2IES |= BIT4 + BIT5;<br />
P2IFG &amp;= ~(BIT4 + BIT5);</p>
<p>_BIS_SR(GIE);<br />
}</p>
<p>//온도값 측정을 위한 ADC 설정<br />
void adcInit() {<br />
ADC10CTL0 = SREF_1 + REFON + REF2_5V + ADC10SHT_2 + ADC10ON;<br />
ADC10CTL1 = INCH_0;<br />
ADC10AE0 |= BIT0;</p>
<p>}</p>
<p>//PWM 출력을 위한 타이머 설정<br />
void timerAInit() {<br />
P1DIR |= BIT2 + BIT3; // P1.2 and P1.3 output<br />
P1SEL |= BIT2 + BIT3; // P1.2 and P1.3 TA1/2 options<br />
CCR0 = 2000; // PWM Period<br />
CCTL1 = OUTMOD_7; // CCR1 reset/set<br />
TACTL = TASSEL_2 + MC_1; // SMCLK, up mode<br />
}</p>
<p>void ledInit() {<br />
P2DIR |= BIT0 + BIT1 + BIT2 + BIT3;<br />
}</p>
<p>// 온도를 100번 측정하여 평균값을 구함<br />
void readTemp() {<br />
adcSum = 0;<br />
//adcDiv = 100;<br />
for (i = 0; i &lt; adcDiv; i++) {<br />
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start<br />
adcSum += ADC10MEM;<br />
__delay_cycles(100);<br />
}<br />
adcAve = adcSum / adcDiv;<br />
temp = (adcAve * 2.5 / 1023.0) * 100;<br />
}</p>
<p>//온도가 너무 낮거나 너무 높을 경우에 최소, 최대 값을 설정<br />
void calTemp() {<br />
if (temp &lt; 40) {<br />
cTemp = 40;<br />
}</p>
<p>if (temp &gt; 150) {<br />
cTemp = 150;<br />
}</p>
<p>if (temp &gt;= 40 &amp;&amp; temp &lt;= 150)<br />
cTemp = temp;<br />
}</p>
<p>//온도에 따른 PWM 듀티비 조절(LED Bar 밝기 조절)<br />
//LED Bar의 밝기를 효과적으로 나타내기 위해 두개의 방정식 사용<br />
void tempWarningLed() {</p>
<p>if (cTemp &lt; 80) {<br />
CCR1 = cTemp * 3 &#8211; 120;<br />
} else {<br />
CCR1 = cTemp * 25 &#8211; 1880;<br />
}</p>
<p>}</p>
<p>void tempLevelLed() {<br />
//다림질 하기에 온도가 낮을경우<br />
if (cTemp &lt; 100) {<br />
ledGreenOff<br />
;<br />
ledYellowOff<br />
;<br />
ledRedOff<br />
;<br />
}</p>
<p>//온도가 면 재질에 적합할 경우<br />
if (cTemp &gt; 100 &amp;&amp; cTemp &lt;= 120) {<br />
ledGreenOn<br />
ledYellowOff<br />
;<br />
ledRedOff<br />
;<br />
}<br />
//온도가 실크 재질에 적합할 경우<br />
if (cTemp &gt; 120 &amp;&amp; cTemp &lt;= 140) {<br />
ledYellowOn<br />
ledGreenOff<br />
;<br />
ledRedOff<br />
;<br />
}<br />
//온도가 아크릴 재질에 적합할 경우<br />
if (cTemp &gt; 150) {<br />
ledRedOn<br />
ledGreenOff<br />
;<br />
ledYellowOff<br />
;<br />
}</p>
<p>}</p>
<p>int main(void) {<br />
WDTCTL = WDTPW + WDTHOLD; //워치독 타이머 종료</p>
<p>ledInit();<br />
relayInit();<br />
swInit();<br />
adcInit();<br />
timerAInit();</p>
<p>while (1) {<br />
P2OUT |= BIT5;<br />
readTemp();<br />
calTemp();<br />
tempWarningLed();<br />
tempLevelLed();<br />
}<br />
}</p>
<p>#pragma vector=PORT2_VECTOR<br />
__interrupt void Port_2(void) {</p>
<p>//기울어졌을 때<br />
if (!(P2IN &amp; BIT5)) {<br />
ledSwOn<br />
;<br />
//스위치가 눌리지 않았을 때<br />
if (!(P2IN &amp; BIT4)) {</p>
<p>//위험한 온도일 때<br />
if (cTemp &gt; 40) {<br />
relayOff //위험상황 감지시 릴레이 OFF<br />
;<br />
}<br />
//위험 상황이 아닐 때<br />
} else {<br />
relayOn<br />
;<br />
}<br />
//위험 상황이 아닐 때<br />
} else {<br />
ledSwOff<br />
;<br />
relayOn<br />
;<br />
}</p>
<p>P2IFG &amp;= ~(BIT4 + BIT5);<br />
}<br />
</div>
<p><span style="color: #ffffff;font-size: medium;background-color: #000080"><strong>회로도</strong></span></p>
<div id='wpdm_file_13' class='wpdm_file wpdm-only-button'><div class='cont'><div class='btn_outer'><div class='btn_outer_c' style='background-image: url(http://www.ntrexgo.com/wp-content/plugins/download-manager/icon/file_extension_pdf.png);'><a class='btn_left  ' rel='13' title='[31호]safe 다리미' href='http://www.ntrexgo.com/?wpdmact=process&did=MTMuaG90bGluaw=='  >Download</a><span class='btn_right'>&nbsp;</span></div></div><div class='clear'></div></div></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ntrexgo.com/archives/29610/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[25호]DIY 프로젝트 공모전- 차선 인식을 통한 차량의 능동적 안전시스템 개발</title>
		<link>http://www.ntrexgo.com/archives/25916</link>
		<comments>http://www.ntrexgo.com/archives/25916#comments</comments>
		<pubDate>Tue, 01 Jul 2014 04:12:26 +0000</pubDate>
		<dc:creator>디바이스마트 매거진</dc:creator>
				<category><![CDATA[디바이스마트 매거진]]></category>
		<category><![CDATA[특집]]></category>
		<category><![CDATA[diy]]></category>
		<category><![CDATA[공모전]]></category>
		<category><![CDATA[안전시스템]]></category>
		<category><![CDATA[인식]]></category>
		<category><![CDATA[최우수상]]></category>
		<category><![CDATA[프로젝트]]></category>

		<guid isPermaLink="false">http://www.ntrexgo.com/?p=25916</guid>
		<description><![CDATA[디바이스마트매거진 25호 &#124; 전기 자동차에 대한 관심이 증가하면서, 기술 개발의 패러다임이 기계시스템에서 점차 전기시스템으로 바뀌고 있다. 이와 같은 흐름에서 엔진과 같은 차량의 구동퍼텐셜을 제공하는 시스템은 전기시스템으로 점차 대체될 가능성이 매우 높지만, 보행 편의수단으로써 뛰어난 편의성을 제공하는 차량에 대한 수요는 여전히 높을 것으로 예상된다. 차량에 대한 수요의 증가는 앞으로 차량의 기술개발은 인간에게 기술적 혜택을 제공하는 것과 더불어 안전에 대한 시스템 연구도 동시에 강구되어야 한다.]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/2013-diy-최우수.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27064" alt="2013 diy 최우수" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/2013-diy-최우수.jpg" width="620" height="316" /></a></p>
<p>&nbsp;</p>
<p style="text-align: right"><strong><span style="font-size: medium">글 | 명지대학교 김병조, 김윤정, 오현환, 이준환, 하늘 </span></strong></p>
<p>&nbsp;</p>
<p><span style="color: #ffffff;background-color: #0000ff"><strong>심사평</strong></span><br />
<strong>NTREX Lab</strong> 본 내용은 학부생의 졸업작품 발표로는 아주 우수한 내용이지만, 이 내용이 DIY 공모전에 어울리는지 알 수 없습니다. 만약 어울린다면, 좋은 점수를 줄 수 있지만..<br />
<strong>싱크웍스</strong> 커다란 라인트레이서 같지만 작은 것을 움직이는 것과 큰 것을 움직이는 것에는 또 다른 기술적 고려가 필요하다. 본 프로젝트 기술은 무인 자동차를 개발하는 곳에서 필수적인 기술로 알고 있다. 기계공학과 학생들임에도 불구하고 전자, 전기적인 요소 기술이 필요한 복합 기술을 이용하여 작품을 만들었다는 것에 대해서 높게 평가한다.<br />
<strong>펌테크</strong> 학생의 실력이라고 생각하기 어려울 정도의 작품 구성, 완성도가 돋보입니다. 영상처리, 하우징 설계, 소프트웨어 구현 사항이 아주 훌륭합니다.<br />
<strong>JK전자</strong> 현재에도 일부 네비게이션 등에 추가 어플리케이션으로 구현이 되고 있는 기능으로 영상 처리를 통하여 중앙선 혹은 차선 침범에 대해서 Alarm을 해주는 시스템이 있습니다. 하지만 이번 과제에서는 추가적으로 결과에 대해서 적극적으로 차량을 컨트롤 하는 부분까지 진행을 한 것은 조금 더 진보한 시스템인 것 같습니다.</p>
<p><span style="color: #ffffff;background-color: #0000ff"><strong>작품개요</strong></span></p>
<table style="width: 620px" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>제작기간</td>
<td colspan="2">2012.04.01. ~ 2012.11.31.</td>
</tr>
<tr>
<td>제작비용</td>
<td colspan="2">50만원 (부족비용은 장비대여 및 폐차 부품 재가공)</td>
</tr>
<tr>
<td rowspan="5">응모자 참여활동 요약</td>
<td>김병조</td>
<td>차량 구동시스템 구성 및 프로그래밍</td>
</tr>
<tr>
<td>김윤정</td>
<td>차량 기구 및 응력 해석</td>
</tr>
<tr>
<td>오현환</td>
<td>하드웨어 제작, 영상처리 알고리즘 설계 (교점, 방정식 유도)</td>
</tr>
<tr>
<td>이준환</td>
<td>영상처리 프로그래밍 및 테스트</td>
</tr>
<tr>
<td>하늘</td>
<td>차량 모델링 및 테스트</td>
</tr>
</tbody>
</table>
<p>전기 자동차에 대한 관심이 증가하면서, 기술 개발의 패러다임이 기계시스템에서 점차 전기시스템으로 바뀌고 있다. 이와 같은 흐름에서 엔진과 같은 차량의 구동퍼텐셜을 제공하는 시스템은 전기시스템으로 점차 대체될 가능성이 매우 높지만, 보행 편의수단으로써 뛰어난 편의성을 제공하는 차량에 대한 수요는 여전히 높을 것으로 예상된다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-1.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27025" alt="figure 1" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-1-620x268.png" width="620" height="268" /></a></p>
<p>차량에 대한 수요의 증가는 앞으로 차량의 기술개발은 인간에게 기술적 혜택을 제공하는 것과 더불어 안전에 대한 시스템 연구도 동시에 강구되어야 한다. 이에 따라 본 작품은 차량의 안전시스템 개발의 일환으로, 컴퓨터 비젼 기술을 이용한 차량의 안전시스템 개발에 대한 제안서이며, 그 구체적인 방법은 도로상황에서 카메라를 통해 차선을 실시간으로 인식하여 차량이 위험 상황에서 차선을 이탈하는 경우, 시스템이 능동적으로 차량 구동에 개입하여 제어하는 능동안전시스템이 탑재된 지능형 차량 개발에 있다. 시스템 개발에 있어 고려해야할 설계 요소는 크게 두 가지 사안으로 차량의 능동적 조향제어를 위한 구동시스템을 구축하는 것과 실시간으로 수집되는 영상에서 차선을 안정적으로 인식하는 기술을 확보하는 것이었다.</p>
<p><span style="color: #ffffff;background-color: #0000ff"><strong>작품설명</strong></span><br />
<span style="color: #0000ff"><strong>3.1주요 동작 및 특징</strong></span><br />
<span style="color: #008000"><strong>3.1.1 Acquire Image → Set Image ROI → Lane Detecting</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-2.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27027" alt="figure 2" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-2-620x360.png" width="620" height="360" /></a></p>
<p>&nbsp;</p>
<p><strong style="color: #008000">3.1.2 Parameter → Line Equation (Two-Line : Match Point)</strong></p>
<p>주요 동작을 살펴보면, 시스템은 1차적으로 캠을 통해 수집되는 영상정보를 이미지의 형태로 캡쳐하여 원본 이미지 정보를 얻어낸다. 이후 이미지는 바로 영상처리에 관여되기 이전에 영상처리에 간섭할 수 있는 불필요한 정보를 최소화 하기 위해 “Set Image ROI”라는 내장함수를 활용해 이미지를 우리가 관심이 있는 영역인 “HOT SPOT” 영역을 제외한 나머지 이미지를 삭제한다. 이후 이 당시에는 허프라인 함수를 통해 엣지를 검출하여 기본적인 라인을 검출하여 결과 이미지에 라인을 그리도록 하였다.</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-3.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27026" alt="figure 3" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-3-620x378.png" width="620" height="378" /></a></p>
<p>앞서 이미지 상에 라인을 그릴 수 있다는 것은 이미지 필터를 통해 직선을 그리기 위한 기본적인 좌표들이 계산되었음을 어렵지 않게 예측 할 수 있다. 나아가 이는 이러한 좌표정보를 통해서 간단한 방정식을 유도할 수 있음을 의미하며, 식 정리를 통해 기본적인 좌표들을 반환받고 이를통해 두 차선의 방정식을 유도한 후 교점을 계산하여 그릴 수 있다는 것을 의미한다. 실제로는 대부분의 교점이 이미지 화면 외부로 발생되기 때문에 화면상에 그릴 수 없으나, 본 조향제어에서는 교점의 x좌표를 가지고 판단하고 직관성을 높이기 위해서 그림3에서 빨간색으로 그린 원처럼 y좌표의 경우는 limit을 두어 이미지 내에서 그릴 수 있도록 보정을 해주었다.</p>
<p><span style="color: #008000"><strong>3.1.3 Judgement State → Control Vehicle</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-4.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27028" alt="figure 4" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-4-620x280.png" width="620" height="280" /></a><br />
영상처리를 통해 검출된 차선으로부터 교점을 구한 것은 차량의 위험상태 판단을 위한 일종의 물리적인 의미를 가지기 때문인 것으로 판단했기 때문이다. 이는 도로정보를 실시간으로 수집하는 카메라가 차량에 고정되어 있어 그림과 같은 상황이 발생되므로 카메라가 고정될 경우 두 차선 사이에서 차량의 상대적인 위치를 알 수 있을 것이라 예상하여 적용했다.</p>
<p><span style="color: #008000"><strong>3.1.4 Process Diagram</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-5.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27029" alt="figure 5" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-5-620x221.png" width="620" height="221" /></a></p>
<p><span style="color: #0000ff"><strong>3.2 전체 시스템 구성</strong></span></p>
<table style="width: 620px" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>구분</td>
<td>설명</td>
<td>노트</td>
</tr>
<tr>
<td>차량 구동시스템 제어</td>
<td>차량의 기본적인 운동을 위한 구동, 조향,제동부를 전기, 전자적으로 자동제어를 하기위해 모터를 기본적인 액츄에이터로 사용하여 기구적인 설계 및 제작.</td>
<td></td>
</tr>
<tr>
<td>영상카메라 실시간 영상수집</td>
<td>WEB &#8211; CAM을 통해 수집된 영상정보를 실시간으로 이미지를 캡쳐하여 이미지<br />
필터 처리를 통해 목표달성을 위한 파라미터들을 실시간으로 계산하여 차량을 제어.</td>
<td>Open-CV 함수<br />
재프로그래밍하여<br />
작성</td>
</tr>
</tbody>
</table>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-6.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27030" alt="figure 6" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-6-620x379.png" width="620" height="379" /></a></p>
<p><span style="color: #008000"><strong>3.2.1 Driving System</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-7.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27031" alt="figure 7" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-7-620x370.png" width="620" height="370" /></a><br />
영상처리의 결과를 바탕으로 차량의 구동을 자동적으로 제어하는 것이 요구되었기 때문에 차량의 기본적인 운동을 위한 차량의 구동시스템은 모두 전기적으로 제어하기 용이한 모터를 액츄에이터로 선정하여 모든 차량의 설계가 진행되었다.<br />
조향부의 경우는 맥슨 사의 24V급의 DC모터와 전용 컨트롤러를 장착하였으며, 모터의 샤프트와 랙앤 피니언이 기구적으로 연결되어 있어, 모터의 위치제어를 통해 차량의 조향을 제어할 수 있도록 설계 및 제작되었다. 구동부와 제동부의 경우 동일하게 DC모터 및 해당 컨트롤러를 장착하였고, 구동부의 경우는 감속기의 효과를 위해 기어비를 계산하여 적정한 잇수의 스프라킷을 결속하여 체인-스프라킷 형태로 구성이 되어있다. 제동부의 경우는 와어링을 통해 유압 실린더의 유압을 기계적으로 제어하게 구성하였다.<br />
기본적으로 조향부의 경우는 상위제어기인 노트북과 컨트롤러의 USB통신을 통해 위치제어를 하고, 구동부의 경우 노트북과 시리얼통신으로 통신하고 있는 AVR보드에서 스로틀을 기계적으로 조작해 속도조절을 위한 0~5V의 아날로그 신호를 제어한다. 제동부, 역시 AVR 보드를 통해 제어되며 간단한 ON-OFF 제어를 통해 조작하도록 구성하였다.</p>
<p><span style="color: #008000"><strong>3.2.2 Image Filtering System</strong></span></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-88.jpg" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27032" alt="fig 88" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-88-620x331.jpg" width="620" height="331" /></a><br />
이미지 필터링 코딩환경은 기본적으로 VC# 환경에서 작성이 되었으며, 기본적으로는 OpenCV에서 제공하는 dll 파일을 참조하였고, 이를 주제에 맞도록 프로그래밍하여 전체적인 시스템을 구성하였다. 영상 이미지는 기본적으로 노트북과 연결된 캠을 통하여 정보를 실시간으로 수집받는 형태이며, 이를 위해 루프로 구성되어 있는 프로그램을 실시간으로 실행하면서 전체적인 시스템은 동작한다.</p>
<p style="text-align: left"><img class="wp-image-27033" alt="fig09" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig09.bmp" width="620" /><br />
그림 9는 실제로 차선을 일직선으로 구성하여 모의실험을 진행한 그림으로 해당 그림은 관심영역을 설정하지 않은 경우와 적용한 경우를 비교 테스트를 한 화면이다. 관심영역을 설정하여 자르지 않으면 왼쪽 그림과 같은 불필요한 부분을 차선으로 인식하는 오류를 범하여 작동 오차가 발생하게 된다.</p>
<p style="text-align: center"><img class="wp-image-27034 aligncenter" alt="fig10" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig10.bmp" width="620" height="280" /></p>
<p style="text-align: left">그림 10는 차선을 통해 간단한 방정식을 구성해서 교점을 인식해 도시하도록 한 화면이다. 두 차선이 검출될 경우의 연장선에 대한 교점은 차선 사이의 차량의 상대적인 위치를 나타낼 수 있는 물리적인 의미로 보고 있다.</p>
<p style="text-align: left"><strong style="color: #0000ff">3.3 개발 환경 (개발언어, Tool, 사용시스템)</strong></p>
<table style="width: 620px" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>구분</td>
<td>개발언어</td>
<td>Tool</td>
<td>사용시스템</td>
<td>노트</td>
</tr>
<tr>
<td>영상처리 프로그래밍</td>
<td>C# Language</td>
<td>Visual Studio + with Open CV</td>
<td>Notebook(상위제어기)</td>
<td>웹캠을 통해 실시간으로<br />
영상처리하여구동부 제어를 위한<br />
하위제어기 제어(USB + Serial Communication)</td>
</tr>
<tr>
<td>차량 구동부 제어</td>
<td>C Language</td>
<td>AVR Studio</td>
<td>AVR board(하위제어기)</td>
<td>Serial Communication을 통한 DC 컨트롤러 스로틀 명령제어 (기계식)5단계 속도변경 분해능</td>
</tr>
<tr>
<td>차량 조향부 제어</td>
<td>C Language</td>
<td>Visual Studio</td>
<td>상위제어기에 조향제어 명령 포함</td>
<td>모터 컨트롤러를 통해 조향모터 위치제어<br />
모터와 랙-앤 피니언을 기구적으로 연결하여<br />
차량의 조향 제어</td>
</tr>
<tr>
<td>차량 제동부 제어</td>
<td>C Language</td>
<td>AVR Studio</td>
<td>AVR board + DAC(하위제어기)</td>
<td>차량 구동부와 동일. (단순 ON-OFF 제어)</td>
</tr>
</tbody>
</table>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-11.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27036" alt="figure 11" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-11-620x418.png" width="620" height="418" /></a></p>
<p>개발환경은 기본적으로 비쥬얼 스튜디오를 통해 프로그램은 작성되었다. AVR 보드 부분은 하위제어기의 개념으로 사용되고 있으며 기본적으로 C언어로 프로그램이 작성되어있다. 상위제어기는 노트북에서 실시간으로 실행되는 프로그래밍 언어이며, 기본적으로 C#언어로 구성되어있다.</p>
<p><span style="color: #0000ff"><strong>3.4 실험내용</strong></span><br />
<span style="color: #008000"><strong>3.4.1. RC 차량 테스트</strong></span></p>
<table style="width: 620px" border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>기간</td>
<td>내용</td>
<td>실험환경</td>
</tr>
<tr>
<td>2012년도 1학기&nbsp;</p>
<p>2012. 05. 30. ~ 2012. 06. 15</td>
<td>1. 직선 차선<br />
시스템 점검&nbsp;</p>
<p>2. 곡선 차선<br />
시스템 점검</td>
<td>1. RC 모델차량 구성 : 조향 (서보모터), 구동 (DC모터), 프레임 (RC카)<br />
2. RC 모델 전용 카메라 : DRC 3.0 (바램시스템 카메라)<br />
3. RC 차량 제어 :<br />
- 아트메가 보드를 통한 차량제어 (AT mega 128)<br />
- 블루투스 모듈(FB755AX)을 통해 노트북으로부터 제어명령 수신 및 동작<br />
4. 영상처리 (비쥬얼 C# 환경) : DRC Station을 통해 영상정보 수집 및 블루투스 명령을 통한 RC 차량 제어</td>
</tr>
</tbody>
</table>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig12.bmp" rel="lightbox[25916]"><img class="alignnone  wp-image-27038" alt="fig12" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig12.bmp" width="620" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig13.bmp" rel="lightbox[25916]"><img class="alignnone  wp-image-27039" alt="fig13" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig13.bmp" width="620" /></a></p>
<p>&nbsp;</p>
<p>각각 직선 차선에서의 실험과 곡선 차선에서의 실험을 실시한 그림이며, RC차량을 통해 1차적으로 실험을 진행하였다. RC 차량을 통한 실험은 전체적인 시스템을 점검하기 위해 실시되었으며, 실제로 제작차량에 적용하여 실험을 실시한 시점에는 프로그래밍적으로 많은 변경이 있었다.</p>
<p><span style="color: #008000"><strong>3.4.2. 제작 차량 테스트</strong></span></p>
<table style="width: 620px" border="1" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<td>기간</td>
<td>내용</td>
</tr>
<tr>
<td>2012. 04. 01. ~<br />
2012. 05. 30</td>
<td>공학설계<br />
- 차량설계,구조해석, 제작차량 프레임제작<br />
- RC모델 실험 차량 제작</td>
</tr>
<tr>
<td>2012. 05. 30. ~<br />
2012. 06. 25</td>
<td>시스템 구축<br />
- 제작차량 완성, 차량 구동시스템 자동제어<br />
- RC모델 차량 무단이탈 방지 기능 실험 테스트</td>
</tr>
<tr>
<td>2012. 07. 30. ~<br />
2012. 10. 31</td>
<td>모의도로 실험<br />
- 통합 프로그램 작성, 영상 테스트 실험 (실내/외)<br />
- 제작 차량 모의도로 실험</td>
</tr>
<tr>
<td>2012. 10. 31. ~<br />
2012. 11. 31</td>
<td>실제도로 실험<br />
- 알고리즘 보완 ( 영역분할 / 두 차선의 교점방정식)<br />
- 제작 차량 실제도로 실험</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><a style="font-family: Verdana, Arial, Helvetica, sans-serif;font-size: 11px;line-height: normal" href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig14.bmp" rel="lightbox[25916]"><img class="alignnone  wp-image-27037" alt="fig14" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig14.bmp" width="620" /></a><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig15.bmp" rel="lightbox[25916]"><img class="alignnone  wp-image-27041" alt="fig15" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig15.bmp" width="620" /></a><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig16.bmp" rel="lightbox[25916]"><img class="alignnone  wp-image-27040" alt="fig16" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig16.bmp" width="620" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-17.png" rel="lightbox[25916]"><img class="alignnone size-large wp-image-27042" alt="figure 17" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/figure-17-620x165.png" width="620" height="165" /></a></p>
<p>모의 실험 테스트 이후 실시된 제작 차량의 테스트는 모의적으로 조성된 공간에서 실시한 RC 차량 테스트에 비해 실제 도로 환경으로 실험이 옮겨지고 HW가 커지면서, 전체적인 퍼포먼스가 약해졌으나, 영역분할 등의 알고리즘을 강화하는 노력 등을 통해 시연 성공률을 높여 시스템의 가능성을 점검할 수 있었다.</p>
<p><span style="color: #ffffff;background-color: #0000ff"><strong>4. 단계별 제작과정</strong></span></p>
<table style="width: 620px" border="1" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<td>기간</td>
<td>내용</td>
<td>실험환경</td>
</tr>
<tr>
<td>2012년도<br />
2학기<br />
2012. 10. 01.<br />
~ 2012. 11. 31</td>
<td>1. 간이도로<br />
모의 실험<br />
2. 차량 작동<br />
테스트<br />
3. 종합실험</td>
<td>1. 제작차량 구성 :<br />
- 영상처리부 :<br />
노트북 탑재,<br />
노트북 내장 캠을 통한 이미지 캡쳐<br />
- 구동시스템부 :<br />
프레임 (탄소강파이프) 용접 가공, Maxon<br />
DC motor (24v), Controller Epos (70/10), DC<br />
motor (36V / 1000W), DC motor (24V), DC<br />
controller(36/24V), ATmega128,<br />
기타 전기 부속품&#8230;<br />
2. 실험장소 : 공학관 건물 뒤편</td>
</tr>
</tbody>
</table>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-22.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27051" alt="fig 22" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-22.jpg" width="620" height="273" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-23.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27052" alt="fig 23" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-23.jpg" width="620" height="273" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-24.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27053" alt="fig 24" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-24.jpg" width="620" height="273" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-25.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27055" alt="fig 25" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-25.jpg" width="620" height="273" /></a></p>
<p>&nbsp;</p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-26.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27056" alt="fig 26" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-26.jpg" width="620" height="796" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-27.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27054" alt="fig 27" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-27.jpg" width="620" height="796" /></a>  <a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-28.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27059" alt="fig 28" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-28.jpg" width="620" height="827" /></a><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-30.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27061" alt="fig 30" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-30.jpg" width="620" height="809" /></a> <a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-29.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27060" alt="fig 29" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-29.jpg" width="620" height="313" /></a></p>
<p><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-31.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27063" alt="fig 31" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-31.jpg" width="620" height="815" /></a><a href="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-32.jpg" rel="lightbox[25916]"><img class="alignnone size-full wp-image-27062" alt="fig 32" src="http://www.ntrexgo.com/wp-content/uploads/2014/07/fig-32.jpg" width="620" height="316" /></a></p>
<p>제출한 본 응모작은 차량의 능동 안전 시스템 개발에 대한 시스템 구축에 대한 제안이며, 그 내용은 차량을 능동적으로 제어하기 위한 구동시스템을 설계하고, 컴퓨터 비젼분야를 활용하여 차량이 차선을 이탈하는 문제 상황에서의 안전 시스템을 제안하였으며, 제안된 시스템을 실험을 통해 검증하는 단계까지 진행하였다. 앞으로 해당 연구가 상용화단계에 이르기까지 당면한 과제들이 산적해 있는 것이 사실이지만, 학부생의 자격으로 1년 가까운 시간 동안, 실과에 준하는 프로젝트를 진행하고 개연성 있는 결과를 낼 수 있어, 개인의 역량과 팀별 협동능력을 신장시키는 좋은 계기가 된 것 같아 함께 해준 분 모두에게 감사드린다.</p>
<p><span style="color: #ffffff;background-color: #0000ff"><strong>5. 기타</strong></span></p>
<p><span style="color: #0000ff"><strong>5.1. 소스코드 구조</strong></span></p>
<div class="symple-box yellow none" style="text-align:left; width:100%;"> 
<p>using System;<br />
using System.Collections.Generic;<br />
using System.ComponentModel;<br />
using System.Data;<br />
using System.Drawing;<br />
using System.Text;<br />
using System.Windows.Forms; // SERIAL COMMUNICATION<br />
: PRE_UTTILIES<br />
using System.IO.Ports; // SERIAL COMMUNICATION :<br />
PRE_UTTILIES<br />
using Microsoft.Win32; // SERIAL COMMUNICATION :<br />
PRE_UTTILIES<br />
using System.Runtime.Interop S er vices; // SER I A L<br />
COMMUNICATION : PRE_UTTILIES<br />
using CapstonDesignVision; // SERIAL COMMUNICATION<br />
: PRE_UTTILIES<br />
using EposCmd.Net; // EPOS :<br />
using EposCmd.Net.DeviceCmdSet.Operation; // EPOS :<br />
using OpenCvSharp; // WEB_CAM : Image<br />
Processing<br />
namespace CapstonDesignVision<br />
{<br />
public partial class Form1 : Form<br />
{<br />
#region SECTION 0 : INITIAL DEFINE<br />
// 프로그램 동작 초기설정 세팅<br />
#endregion<br />
#region SECTION 1 : SERIAL COMMUNICATION<br />
// 시리얼 통신 부 변수 및 함수 정의 (프로토 타입)<br />
#endregion<br />
#region SECTION 2 : EPOS CONTROLL<br />
// 조향부 컨트롤러 조작 관련 변수 및 함수 정의 (프로토 타입)<br />
#endregion<br />
#region SECTION 3 : IMAGE<br />
// 이미지 필터 변수 및 함수 정의 (기본 처리 필터, 영상분할, 허프직선 포함)<br />
#endregion<br />
#region SECTION 4 : ROOF<br />
// 프로그램 동작 명령시 반복적으로 실행되는 타이머 루프<br />
(이미지 수집 → 영상분할 → 영상처리 → 교점검출 → 판단 → 차량제어 → 이미지 삭제)</p>
<p>#endregion<br />
}<br />
}</p>
</div>
<p><span style="color: #0000ff"><strong>5.2. 테이블 정리</strong></span></p>
<table style="width: 620px" border="1" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<td style="text-align: center">구분</td>
<td style="text-align: center">내용</td>
<td style="text-align: center">노트</td>
</tr>
<tr>
<td rowspan="3">소스코드</td>
<td>Form1</td>
<td>메인 프로그램 작성 &#8211; 통합<br />
(시리얼통신, 조향부 컨트롤, 영상처리<br />
코드 포함.)</td>
</tr>
<tr>
<td>Form1.Designer</td>
<td>윈도우 리소스</td>
</tr>
<tr>
<td>globalKeyboardHook</td>
<td>시리얼 통신 부 클래스</td>
</tr>
<tr>
<td rowspan="5">참고문헌</td>
<td>1. h t t p:// t r a m p e r 2 . b l o g .<br />
me/100070878701</td>
<td>영상처리에대한 전반적인 개념 숙지 및<br />
프로그래밍 실무 참고</td>
</tr>
<tr>
<td>도서 &#8211; LEARNING OPEN CV 제<br />
대로 배우기</td>
<td>영상처리 이론 습득</td>
</tr>
<tr>
<td>http://blog.naver.com/PostView.<br />
n h n ? b l o g I d = m y c p p &amp; l o g<br />
No=120103606802</td>
<td>관심영역 설정 (SetImageROI 참고)</td>
</tr>
<tr>
<td>ht tp://blo g.n aver.c om/blu<br />
e s e alh?Re dire ct = L o g&amp;lo g<br />
No=20044187187</td>
<td>무인 자율주행 차량에 대한 참고</td>
</tr>
<tr>
<td>h t t p :// c a f e . n a v e r . c o m /<br />
opencv/7897\</td>
<td>Open CV KOREA 카페</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.ntrexgo.com/archives/25916/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
