[아두이노] 엔트리로 초음파레이더 졸작

IOT/아두이노|2019. 10. 8. 09:00

[아두이노] 엔트리로 초음파레이더 졸작



스크래치로 뭔가 표현한 작품을 하나 만들면 좋을 것 같아요. 엔트리에 초음파센서와 서보모터를 제어하는 블록이 있기에 이 두 블록을 가지고 표현할 수 있는 작품으로 떠오르는 것은 초음파레이더가 있더군요. 멋지고 좀 더 깔끔하게 블록을 만들면 좋은데 대충 post 주제를 정하고 막코딩을 해서 느낌만 비슷하게 초음파 레이더 원리 동작만 수행하는 간단한 졸작을 하나 만들어 봤네요.

1. 스크래치로 초음파레이더 설계


설계 :

  • 초음파센서 값 읽기
  • 초음파센서로 반경 180도 범위의 100미만 거리에 장애물을 감지하기 위해서 서보모터 회전
  • 엔트리 화면에 레이더 각도 바 표시
  • 초음파센서로 물체 감지했을 때 감지한 위치에 물체 표시

대충 4가지 형태로 나누어 표현 하겠습니다.

초음파센서 값 읽기


지난시간에 초음파센서값을 읽기를 했었습니다. 아래와 같은 표현을 하시면 됩니다.


변수블록에서 거리라는 변수를 만드시고 거리 블록에다가 초음파센서 센서값 블록을 배치하면 계속 반복하기로 실시간으로 현재 거리변수에 초음파센서 값이 저장되게 됩니다.

초음파센서로 반경 180도 범위의 100미만 거리에 장애물을 감지하기 위해서 서보모터 회전


서보모터를 제어하는 블록을 가지고 180도 회전을 좌/우로 왔다 갔다 해보도록 합시다.


위 블록을 보시면 우선 각도라는 변수 블록을 만들어 주세요. 그리고 초기값으로 0으로 처음 정하게 됩니다. 그리고 서보모터오 0도로 초기각도를 잡아 주는데 다음 동작을 수행하지 않도로 3초의 대기시간을 부여 합니다.

계속 반복하기로 각도는 1씩 증가하고 그 각도를 1도씩 증가한 각도로 회전을 하게 됩니다. 그리고 180도까지 회전했다가 반대로 180도에서 0도로 1도씩 감소시켜 0도가 될때까지 반복하게 됩니다 이렇게 해서 0~180도 회전을 왔다 갔다 하게 됩니다.

엔트리 화면에 레이더 각도 바 표시




회전을 시키면 그 회전된 각도를 엔트리에 표시하기 위해 하나의 바 이미지를 붓으로 그리는 표현을 했습니다.

초기 위치는 좌표(0,-100)로 레이더 바의 시작 위치가 됩니다 방향은 0도로 했기에 오른쪽에서 왼쪽으로 회전하게 됩니다. 초기 상태니 붓(펜)이 그려져 있으면 모두 지우라는 명령이고
붓의 색과 굵기를 초기로 지정합니다.

그다음 계속 반복하기 블록이 반시계방향으로 180도 회전했다가 시계방향으로 180도 회전하는 반복문이 안에 표현되어 있어 왔다 갔다 반복하면서 레이더 바의 움직임을 표시합니다. 이 바는 현재의 각도 위치만 표시 되어 야 하기 때문헤 한번 그리고 난뒤 다음 바를 그릴 때 먼저 모든 붓 지우기로 바을 지우고 나서 다시 그립니다.

반시계 방향으로 180도 회전


모든 붓 지우기는 이전 그려진 레이더 바를 지우는 명령이고 그리기 시작과 그리기 멈추기 사이에 붓으로 그리는 작업이 수행됩니다. 시작위치는 좌표(0,-100) 지점에서 이동방향이 200이면 좌표(0,-100)꼭지점에서 이동방향쪽으로 200지점까지 붓으로 그리게 됩니다. 즉, 하나의 선이 그려집니다. 그 선을 -1도 각도회 회전시키는 명령입니다. 이걸 180번 하기 때문에 1도씩 오른쪽에서 왼쪽으로 하나의 선이 그려집니다. 이전 선을 지우고 새로운 선이 그려지는 과정을 반복하게 됩니다. +1도 씩 180번 회전하면 반대로 왼쪽에서 오른쪽으로 레이더 바가 회전하겠죠.

초음파센서로 물체 감지했을 때 감지한 위치에 물체 표시


초음파센서로 장애물을 감지하면 장애물이 감지한 위치에 장애물임을 표시하는 오브젝트를 표시를 하겠습니다.


빨간 상자가 물체 표시 마크입니다. 그리고 총 세 블록으로 나누어서 블록코딩을 하였습니다.

첫번재 블록은 시작하면 장애물 표시가 엔트리 화면에 표시되면 안되겠죠. 그래서 모양을 숨겨야 합니다. 이 숨긴 본체 오브젝트 이미지는 사용하지 않고 복제본을 사용 할 꺼에요. 복제본을 사용하는 이유는 일정시간이 되면 소멸 시키기 위혀서 입니다. 무한으로 장애물 표시를 화면에 표시하면 안되겠죠. 일정 시간이 되면 자동으로 사라져야 하기 때문에 이 본체 이미지는 숨기고 복제본 이미지로 만들었다 삭제했다 이런식으로 해서 필요할 때만 생성하도록 하여 물체 그리기의 낭비를 줄입니다.

두번째 블록은 계속 반복하기가 있는데 만일 거리값이 100이하면은 100미만의 장애물만 감지하겠다는 의미가 100미만의 장애물리 감지되면 자신을 즉 모양숨기기를 했던 본체 원을 복제본을 만들겠다는 명령입니다. 복제본을 무한으로 연속 만들면 컴퓨터에 무리가 가기 때문에 0.5간격으로 체크해서 복제본을 만들게 됩니다.

세번째 블록은 복제본이 생성이 되면 수행되는 블록입니다. 장애물 감지된 위치에 복제본을 이동시켜야 하기 때문에 초기 지점인 좌표(0,-100)에거 장애물 감지한 거리값을 토대로 이동 방향으로 "거리x2"만큼 움직이기라는 블록으로 감지된 위치로 원을 표시합니다. 왜! 2를 곱했냐면 엔트리 창 화면의 100까지의 거리는 너무 짧아서 좀 더 크게 보기 위해서 2배 거리를 키워 화면상에 좀 크게 보이게 표시 했다고 생각하시면 됩니다. 여기서, 복제본을 이동시켰지만 원본 모양이 숨겨져 있기 때문에 숨겨진 복제본으로 이동하여 화면에 표시가 되지 않습니다. 그래서 모양보이기로 화면에 보여지게 하고 2초동안 장애물 표시를 하다가 해당 복제본이 삭제하기로 소멸시키게 표현 했네요.

이러헥 해서 초음파센서로 장애물이 감지되면 그 위치에 장애물 표시를 하고 표시된 마크는 2초후 소멸된다고 생각하시면 됩니다.

[결과]


2. 엔트리 초음파 레이더 회로도




3. 엔트리 블록 코딩



위 오브젝트 창에 전부 블록 코딩합니다.

[1단계] 초음파센서로 장애물 감지 블록 코딩


[2단계] 서보모터 회전과 붓으로 레이더 바 표시 블록 코딩


[3단계] 장애물 감지 시 장애물 표시 마크를 복제본을 생성하여 해당 위치에 장애물을 표시 했다가 2초 후 소멸 시키는 블록 코딩


4. 결과


한손에 폰을 들고 한돈에 초음파센서를 들고 찍다보니 영상이 많이 흔들리고 정확히 촬영이 되지 못했네요. 간단히 레이더 바로 현재의 각도를 표시하고 100 미만의 장애물 감지시 장애물 표시가 되게 나오도록 했네요. 참고로 서보모터의 회전은 위 블록코딩은 불안전 합니다. 그 이유는 지속적으로 회전을 시키라는 메시지를 아두이노에 보내고 아두이노는 그 메시지가 누족되기 때문입니다. 만약 딜레이 대기시간이 없다면 엔트리의 회전 레이더바가 180도 회전이 끝더라고 서보모터가 90도도 회전을 못하는고 회전이 누적되어 있게 됩니다. 180도를 왔다 갔다 한바퀴 돌고 난뒤에도 서보모터는 일정 각도뿐이 회전을 못하게 됩니다. 만약 중지 명령을 내리면 누적된 서보모터는 중지 명령이 떨어져도 누적된 회전만큼 계속 회전 동작을 수행합니다. 서보모터 따로 엔트리 따로 동작하는 결과가 발생하게 됩니다. 위 블록도 그냥 0.5초 대기를 줘서 서보모터의 회전각을 유사하게 맞춘 것이지 정확히 일치하지 않습니다. 단지 원리를 이해하기 위한 실험이여서 대충 블록 코딩을 했을 뿐이지 감안하시고 보시기 바랍니다.


노이즈 값도 장애물로 인식해서 장애물 표시가 뜨네요.

마무리


엔트리를 사용하면서 엔트리 따로 아두이노 따로 동작하는 현상이 발생하였습니다. 엔트리 블록 코딩은 엔트리 기준으로 동작하기 때문에 아두이노가 엔트리에 맞게 동작을 하는지 확인을 할 수 없습니다. 물론 엔트리가 중간의 특정핀에 전류가 공급되게 하고 그 전류를 다시 특정핀에서 확인하여 전류가 흐르는 상태인지 체크를 통해 중간에 체크 블록을 만들면 해결 되기는 합니다. 너무 복잡해지기 때문에 그 부분은 생략합니다.

아무튼 위 블록 코딩은 불안전환 코딩이고 엔트리가 무조건적인 명령문을 수행 할 뿐 아두이노의 서보모터 동작이 정상적으로 작동하는지 체크하지 못했기 때문에 졸작이라는 문구를 붙이게 되었네요. 그리고 초음파센서 거리 측정을 서보모터가 회전 했을 때 그 안에서 측정을 했어야 했는데 블록 코딩을 설명을 하기 위해서 분류했는데 그상태로 두고 말았네요. 완성하고 나니 이 부분이 참 아쉬운 부분이네요.


댓글()

[아두이노] 엔트리로 아두이노 제어

IOT/아두이노|2019. 10. 7. 09:00

[아두이노] 엔트리로 아두이노 제어



지난 시간까지 해서 S4A 스크래치와 ScratchX로 아두이노와 연결하여 제어를 해보았습니다. 오늘은 마지막으로 국산 엔트로로 아두이노를 연결하여 제어해 보는 시간을 갖도록 하겠습니다. 엔트리도 ScratchX 마찬가지로 온라인상에서 웹브라우저로 아두이노를 연결하여 제어를 하게 됩니다 ScratchX 플러그인을 설치하여 연결했다면 엔트리는 따로 PC에 연결 프로그램을 설치해야 연결 할 수 있습니다. 엔트리를 이용한 아두이노 제어는 의외로 간단하여 사용하기 편합니다.

이제부터 엔트리로 아두이노를 제어를 해봅시다.

1. 엔트리



엔트리 공식 사이트에 들어가사 작품만들기를 누르면 아래와 같이 기본 창이 뜹니다.


스크래치를 먼저 공부한 분들은 창이 처음에 좀 불편할 수 있고 블록들이 좀 더 많은데 스크래치는 간단히 최소 블록만 제공하는데 약간 엔트리는 약간 상황들을 더 추가한 블록들로 블록의 갯수가 좀 더 많습니다. 스크래치는 어떤 프로그램을 쓰더라고 기본베이스는 전부 동일합니다. 선택은 여러분들이 편한 걸 사용하시면 됩니다.

2. 엔트리에서 하드웨어 연결 프로그램 설치 및 연결


1) 하드웨어 연결 프로그램 설치


엔트리에 아두이노우노와 연결을 하기 위해서는 하드웨어 연결 프로그램을 설치해야 합니다.

하드웨어 블록은 누르면 아래와 같은 5개의 선택 항목이 나타납니다.


  • 연결 프로그램 다운로드 : 이 프로그램을 PC에 다운로드 받으시면 됩니다.
  • 연결 안내 다운로드 : 일반 PC 설치와 블루투스 설치에 관한 자세한 안내서입니다.
  • 엔트리 아두이노 소스 : 펌웨어 소스인데 안받으셔도 됩니다.
  • 하드웨어 연결하기 : 연결프로그램을 열고 연결하면 되기 때문에 구지 사용하지 않습니다.
  • 연결 프로그램 열기 : PC에 연결프로그램이 설치되어 있으면 이걸 클릭하면 연결프로그램이 실행 됩니다.

첫번째 연결 프로그램을 다운로드 받아서 설치하면 끝납니다.

2) 하드웨어 연결


연결 프로그램 열기를 클릭 하시면 PC에 설치된 연결 프로그램이 실행 되고 아래와 같은 창이 뜹니다.


위 그림을 보면 다양한 보드를 제공합니다. 아두이노 Uno 정품보드로 처음에 사용해 보세요. 그리고 초음파센서나 Servo모터를 사용할 경우 아두이노 Uno 확장모드를 사용하시면 됩니다.

아두이노 Uno 정품보드를 클릭을 해보세요. 아래와 같은 창으로 넘어갑니다.


현재 아두이노를 연결 안해서 연결중으로 표시되는 데 연결되면 연결성공이라고 뜹니다. 여기서, 처음 한번만 펌웨어 설치를 누르시면 됩니다. 연결이 제대로 안되면 드라이버 설치를 처음 한번 눌러서 설치하시면 됩니다. 참고로 이 창은 닫으시면 안되고 계속 열어놓으셔야 엔트리와 아두이노 간의 연결이 유지 됩니다.

3) 엔트리에서 아두이노가 인식 상태




위 그림처럼 "하드웨어가 연결되었습니다"라는 멘트가 뜨고 아두이노 Uno 정품보드 블록들이 생성 됩니다. 5개의 블록 뿐이 없습니다. 스크래치 블록과 5개의 블록을 가지고 블록코딩을 하시면 됩니다.

4) 엔트리에서 아두이노 Uno 정식보드 블록


5개의 블록들을 간단히 살펴보도록 하죠.ㅁ


analogRead(pin);

아날로그 입력으로 0~1023 사이의 값을 가져옵니다.



digitalRead(pin);

디지털 입력으로 해당핀에 0 or 1의값을 가져옵니다.



digitalWrite(pin, value)

디지털 출력으로 HIGH(켜기) or LOW(끄기)의 출력을 표현 하니다.



analogWrite(pin, value)

0~255사이의 아날로그 출력을 할 수 있습니다.



map(analogRead(pin), 0, 1023, 0, 100);

입력 숫자만 원하는 형태로 바꾸면 됩니다.

2. 엔트리와 아두이노 실험


실험은 아두이노 Uno 확장모드에서 이루어집니다. 아두이노 Uno 확장모드를 선택하고 펌웨어 설치를 다시 한번 해주세요.

그러면, 아래 그림처럼 블록이 몇개 더 생성 됩니다. 확장모드에서는 초음파센서와 서보모터와 피에저부조를 제어할 수 있는 블록이 추가되었네요.


1) 회로도





2) 블록 코딩



위 블록 코딩은 간단한 테스트 입니다.

첫번째 블록 코딩은 디지털 13번 핀을 1초 단위로 깜박이는 "Blink예제" 입니다.
두번째 블록 코딩은 거리라는 변수에 만들고 그 변수에 초음파센서값을 저장합니다. 그리고 엔트리봇이 1초동안 초음파센서로 측정한 거리 만큼 x좌표로 이동시키라는 블록 코딩입니다.

지난 시간에 다른 스크래치 프로그램에서 변수 선언에 배웠고 엔트리에서도 동일하니깐 설명은 생략합니다. 초음파센서는 아두이노에 연결하는 Trig, Echo핀만 주의해서 연결하고 해당 핀 값을 블록코딩에 정확히 기입하셔야 정확한 결과가 나옵니다.

3) 결과


영상을 보시면 왼쪽에 원이 있습니다. 이 원은 1초 단위로 색이 바뀝니다. 아두이노 Red LED와 같은 시간으로 동작합니다. 즉, 엔트리의 원와 아두이노 LED를 동일한 시간대에 동작을 수행합니다. 엔트리와 아두이노의 표현을 일치시키는 느낌이지요. 나중에 이런 느낌의 표현은 엔트리를 가지고 아두이노를 제어 할 때 많이 사용합니다.

그리고 거리는 제가 가지고 있는 초음파센서가 최대 145정도 거리 값이 나오더군요. 0~145사이를 앞에 장애물이 감지 될때 거리를 측정 할 수 있네요. 0~145사이의 x좌표로 엔트리봇이미지가 이동하게 됩니다. 별 의미 없고 초음파 센서로 엔트리봇을 움직이게 하는 간단한 테스트 입니다.


마무리


이렇게 해서 S4A 스크래치, ScratchX, 엔트리에서 아두이노를 연결하는 방법을 간단히 알아 보고 간단한 예제로 제어까지 하였습니다. 얼핏 보면은 스크래치로 아두이노 제어하는게 편해 보일꺼에요. 그냥 해당 블록을 배치하고 아두이노를 코딩하지 않고 쉽게 제어가 되기 때문에 구지 아두이노를 C언어를 공부하고 코딩 할 필요가 있을가 하고 생각하시는 분들도 있을 거에요. 그런데 실상은 전혀 그렇지 않습니다. 더 복잡하고 더 어렵습니다.

그 이유는 간단한 제어는 이미 블록이 제공 되기 때문에 그 블록을 사용하여 쉽게 아두이노 동작을 수행 했을 뿐 조금만 변화를 주면 블록 코딩은 너무 복잡해 집니다. 오늘 배운 아두이노 Uno 정품보드의 블록을 보시면 5개 블록만 제공합니다. 이 블록을 가지고 초음파센서와 Servo모터를 제어한다고 생각해 보세요. 답이 안보이죠. 다행히 아두이노 Uno 확장모드에서 해당 블록을 제공하기 때문에 쉽게 제어 할 수 있는 것 뿐이죠.

즉, 스크래치로 아두이노를 제어하기 위해서는 제어 할 블록이 없다면 그 블록은 여러분들이 만드셔야 합니다. 그리고 만들기 힘들 경우는 해당 펌웨어 소스에 가서 일부 소스 내용을 수정을 해야 합니다. 아니면 누군가 만들어 놓은 펌웨어 소스를 가져다가 사용해야 합니다. 스크래치로 수많은 부품을 제어를 할 때 쉽게 딱 만든 블록으로 코딩하기 힘듭니다. 오픈 블록이나 펌웨어 소스를 쉽게 찾을 수 없고 찾는 다 해도 단적인 제어만 가능하고요 여러 부품들을 연계해서 제어 한다면 무지 힘들꺼에요. 어느 순간이 되면 그냥 프로그램언어를 배우고 함수 단위 코딩을 하는게 더 쉽다는 것을 느끼게 될 꺼에요.

C언어 기본 문법을 배우고 오픈 라이브러리 함수들을 사용하여 함수 단위로 C언어 코딩을 하는게 나을 거라 생각 됩니다. 처음에는 C문법을 배우는게 좀 버거울 수 있지만 기본 개념만 잡아 놓으면 오히려 스크래치를 제어하는 것보다 쉽게 다양한 전자부품을 제어 할 수 있을 거에요. 스크래치는 그냥 어린아이들에게 전자 공부를 쉽게 하기 위한 도구로만 생각하시면 됩니다.

그리고, 스크래치와 아두이노 연계는 프로세싱과 아두이노 연계과 유사힙니다. 프로그램 언어에 관심이 있으면 처음부터 프로세싱과 아두이노로 나아가는 걸 추천 드려요. 처음에는 프로세싱와 아두이노 연계 표현이 어렵지만 나중에 어느정도 궤도에 오르시면 오히려 자유로운 표현을 쉽게 할 수 있어 편하게 느끼실 꺼에요. 참고로, 프로세싱과 순수 아두이노 소스는 오히려 오픈 소스가 더 많고 쉽게 찾을 수 있기 때문에 프로그램 언어 독해력만 있으면 충분히 독학으로 공부 할 수 있으니깐 한번 도전해 보세요.


댓글()

[아두이노] ScratchX로 아두이노 제어

IOT/아두이노|2019. 10. 4. 09:00

[아두이노] ScratchX로 아두이노 제어



지난 시간에 S4A 스크래치로 아두이노를 제어하는 방법을 알아 보았습니다. S4A 스크래치 말고도 다른 스크래치로도 아두이노를 제어 한다고 했었죠. S4A 스크래치는 해당 스크래치 프로그램을 PC에 설치 한 뒤에 아두이노를 연결했지만 이번에 배울 스크래치는 온라인 상에서 웹브라우저로 아두이노를 연결하여 제어 할 수 있는 ScratchX에 대해 이야기를 하고자 하겠습니다. 유사하게 국산 엔트리도 있지만 우선 ScratchX로 아두이노를 실험해 봅시다.

1. ScratchX



스크래치 형태로 여러가지 실험을 할 수 있는 베타 버전입니다. 오래 전 부터 베타 버전이였는데 아직도 베타 버전이네요. 온라인 상에서 스크래치x는 외부 하드웨어와 연동하여 다양한 실험을 할 수 있는 서비스를 제공하고 있습니다.


위 그림을 보시는 것처럼 다양한 확장 프로그램들 제공합니다. 원하는 실험을 선택하시면 해당 실험에 맞는 스크래칙 블록들이 세팅되어 있어서 특정한 전용 실험이 가능합니다. 첫번째 이미지는 아두이노인데 아두이노와 연결하여 실험할 수 있는 확장프로그램으로 생각하시면 됩니다.

2. 스크래치 플러그인 설치


온라인 상에서 스크래치 프로그램을 사용하기 위해서 Adobe 플래시 플레이어가 설치되어 있어야 합니다. 이 부분은 ScrtchX 사이트에 가셔서 해당 확장프로그램을 실행시켜보시면 Adobe 플래시 플레이어가 안깔려 있으면 설치하라는 멘트가 나오고 설치되어 있으면 활성화 할지를 선택하라는 멘트가 나올꺼에요. 여러분들이 직접 설치가 안되었으면 설치하고 활성화 안되었으면 활성화 시키면 됩니다. 이부분은 설명이 필요 없겠죠.

플러그인 설치하셔야 외부 아두이노와 연결을 할 수 있습니다.




플러그인 다운로드 주소로 가시면 Mac과 윈도우 버전으로 나뉘고 크롬과 다른웹 브라우저로 나뉩니다. 참고로 플러그인을 설치한다고 무조건 다 실행되지는 않습니다.

윈도우 64bit 운영체제에서는 크롬버전을 설치를 해도 연결이 안됩니다.


다른 웹브라우저용 플러그인을 설치를 해도 대부분 위처럼 연결이 안되거나 아예 플러그인이 인식이 대부분 안되네요.


위 그림처럼 파이어폭스에서 빨간불로 플러그인 인식이 안되더군요. 알아보니깐 윈도우 64bit에서는 안되고 32bit 특정 버전을 설치하면 인식이 된다고 하네요.

오기가 생겨서, 크롬, 파이어폭스, 오페라, 익스플로우, 엣지, 웨일, 오페라 네온, 스윙 브라우저들을 다 실행 시켜보았습니다. 연결인 안되는 노란불이 들어오거나 플러그인 인식이 안되는 빨간불이 들어오더군요. 딱 하나 스윙 브라우저가 정상적으로 인식이 되었습니다.

스윙 브라우저를 찬양하라!


스윙 브라우저에서 정상적으로 아두이노가 연결이 되었네요. 정상 연결인 초록불이 들어 왔습니다. 안되면 파이어폭스 특정 버전으로 다시 설치 할까 했는데 그럴 필요가 없어졌네요. 스윙 브라우저로 정상적으로 플러그인이 작동해도 다행이였어요.

3. 아두이노 펌웨어


아두이노에 펌웨어 소스를 이식해야 하는데 따로 다운로드를 받을 필요가 없습니다. 아두이노 IDE에서 제공되는 펌웨어 소스를 그대로 사용 가능합니다.


위 그림에 표시된 StandardFimata 소스를 아두이노에 이식한 후 ScratchX에 연결 하시면 됩니다.

4. ScratchX 실행


확장프로그램 중 아래 그림처럼 이미지를 클릭해서 들어 가시면 됩니다. 처음 블록 코딩을 잘 모르시는 분은 아래 sample project를 누르시면 됩니다. "blink 예제"가 세팅되어 있거든요.


전 그냥 이미지를 클릭하고 아무것도 되어 있지 않는 빈상태로 들어 갔네요.

추가블록에 아두이노 연결이 성공하면 아두이노 블록들이 표시 됩니다. 아두이노 블록과 스크래치 블록들을 조합하여 1번, 2번 블록을 아래 그림처럼 배치해 보세요.


1번 블록 : 13번 핀을 led A에 연결은 디지털pin으로 출력모드로 led_A~led_D로 4개의 출력모드로 되어 있습니다. 해당 핀을 연결한다는 것은 해당 13번 핀을 디지털 출력모드로 선언으로 이해하시는 것이 좋을 것 같아요.

const byte led_A = 13;
void setup()
{
  pinMode(led_A, OUTPUT);
}

2번 블록 : led_A핀을 켜기(HIGH)->1초대기-> led_A핀을 끄기(LOW) -> 1초대기 를 무한 반복합니다. 즉, 1초 단위로 깜박이는 동작을 수행하게 됩니다.

void loop()
{
  digitalWrite(led_A, HIGH);
  delay(1000); 
  digitalWrite(led_A, LOW);
  delay(1000); 
}

아두이노 코딩을 해보셨다면 대충 어떤 느낌의 블록 코딩인지 아시겠지요.

주의할 점은 스크래치를 실행을 누른다고 무조건 실행이 되지 않습니다. 위 1번 블록을 먼저 클릭해서 세팅을 한 뒤에 실행을 눌러야 정상적으로 동작합니다. 왜! 실행을 눌렀는데 13번 LED가 깜박이지 않는 거야 하고 실수를 범할 수 있으니 꼭 1번 블록 코딩을 먼저 클릭을 한번 한 뒤에 실행버턴을 눌러 실행하시기 바랍니다.

4. 실행


1) 회로도





2) ScratchX에서 블록 코딩



주의 : "when device is connected" 블록은 먼저 수동으로 클릭해서 세팅 한 후 클릭했을 때 실행을 수행하시기 바랍니다 그냥 클릭했을 때 누르면 작동 안해요.

3) 결과


정상적으로 Red LED가 깜박이네요.


마무리


ScratchX로 실험 할 때는 플러그인 문제가 가장 골치거리 입니다. 그리고 플러그인이 가끔 인식이 잘 안될 때가 있습니다. 다시 해당 확장 프로그램을 접속하시거나 아두이노의 USB를 PC에서 분리 했다가 다시 연결해 보세요. 몇번 시도하면 정상적으로 인식 됩니다.

S4A 스크래치 보다는 온라인 상에서 실시간으로 연결 할 수 있다는 장점이 있는데 문제는 플러그인 문제가 브라우저마다 인식 문제가 있기 때문에 불편 합니다. 그래도 따로 프로그램을 설치 할 필요없이 플러그인만 설치하면 되니깐 빠르게 인터넷이 연결 된 아무 PC에서 실험을 할 수 있어 괜찮은 것 같아요.

S4A 스크래치로 아두이노 연결하는 것만 post하기가 약간 그런 것 같아서 다른 스크래치도 다 연결해 보는 실험을 하면 괜찮을 것 같아서 ScratchX와 아두이노 연결 편을 post로 작성해 보았네요. 내일은 엔트리로 연결을 해보겠습니다. 한번에 스크래치와 아두이노 연결 부분을 post로 다 정리해 놓아야 겠어요.


댓글()

[아두이노] S4A 스크래치에서 아두이노로 이미지 조정하기

IOT/아두이노|2019. 10. 1. 09:00

[아두이노] S4A 스크래치에서 아두이노로 이미지 조정하기



오늘은 어제 이야기 하려다 못한 내용으로 아두이노로 스크래치 이미지를 컨트롤하는 실험을 해볼까 합니다. 스크래치와 아두이노는 서로 쌍방 통신이 가능합니다. 스크래치에서 아두이노에 연결된 Sensor를 읽을 수 있고 아두이노에서 스크래치에 그려지 이미지(케릭터)를 조정을 할 수 도 있습니다. 서로 쌍방 통신으로 읽기/출력이 가능하기 때문에 스크래치를 이용하면 재밌는 것들을 만들 수 있습니다. 어제는 스크래치에서 아두이노 출력하는 LED 깜박이기 였다면 오늘실험은 스크래치에서 아두이노 값을 읽어 오는 방법을 간단히 실험해 보겠습니다. 내용은 아두이노에 연결 된 가변저항기를 조절하여 스크래치 상 고양이 케릭터를 조정해보는 실험이 되겠습니다.

1. S4A 스크래치 이미지 세팅


무대 세팅 : 


무대 창을 누르면 스크립트/배경/소리가 있는데 여기서 배경에서 새로운 배경을 가져오기 눌러 스크래치에 제공되는 배경 이미지를 찾아 적당한 걸 가져오시면 됩니다. 참고로, 소리를 눌러보세요. 여러가지 사운드를 제공하는데 게임같은 것을 만들 때 배경음악으로 사용하면 좀 더 그럴싸한 표현을 할 수 있습니다.

스프라이트 고양이 추가 :


위 화살표를 보시고 스프라이트 파일 선택을 눌러서 고양이 이미지를 가져 옵니다, 참고로 왼쪽에 스프라이트 창에서 모양을 눌러 가져오기를 다시 눌러서 다른 고양이 장면을 가져 오세요. 그러면 하나의 스프라이트창에 두개의 이미지를 넣을 수 있습니다. 이렇게 하면 두 이미지를 교대로 교체하면 고양이 걷는 모션을 만들어 낼 수 있습니다. 참고로, 무대 세팅에서 배경 이미지도 무대에 여러개 배경 이미지를 배치 할 수 있습니다. 그렇게 되면, 무대는 상황에 따라 각기 다른 배경 이미지를 사용할 수 있게 됩니다.

이렇게 해서 이미지 세팅은 끝났습니다.

하지만 아래 창을 보시면 무대 창이 아두이노 이미지에 묻혀 있어서 뭔가를 만들려고 해도 아두이노 때문에 표현하기가 힘들어 보이죠.


위 아두이노 스프라이트 이미지는 삭제할 수 없습니다. 삭제하면 아두이노 연결이 안되니깐요. 그렇기 때문에 아두이노 스프라이트는 안보이게 숨겨야 합니다.

아두이노 핀 값을 출력하는 창은 마우스 오른쪽 버턴을 해당 창에서 클릭하면 아래와 같이 숨기기 기능 선택 창이 뜨고 숨기기로 안보이게 할 수 있습니다.


그 다음 아두이노 그림은 아래 창에서 편집을 눌러 주세요.


그러면 아래 창이 나타나고 지우기를 눌러주세요.


그리고 무대 배경 색의 점을 만드시든 적당한 티 안하는 점을 하나를 아무 위치에 찍어 주시고 확인을 눌러주세요. 그러면 해당 점이 아두이노우노가 됩니다.


이렇게 해서 아두이노 관련 이미지들이 사라졌습니다. 참고로 자세히 보시면 하얀 점이 있지요. 그냥 post 예시를 들기 위해서 하얀색 점으로 한 것이고요. 이 점을 마우스로 클릭해서 드래그 하시면 이동이 됩니다. 해당 점을 안보이는 곳으로 드래그 하시면 완벽하게 숨길 수 있습니다.

이렇게 해서 이미지 세팅이 끝났네요. 이제는 아두이노 세팅과 스크래치 블록코딩을 합시다.

2. 아두이노우노 조정기 만들기



위 그림처럼 간단합니다. 가변저항을 A0핀에 연결하여 가변저항을 돌리면 발생하는 가변저항값을 토대로 스트래치 이미지를 움직이게 할 꺼에요.

이제 아두이노우노에 S4A 스크래치를 사용할 수 있게 펌웨어 소스를 이식시켜야 합니다.



위 post에서 아두이노우노에 펌웨어 소스를 인식하는 방법을 지난시간에 이야기 했기 때문에 설명은 생략하고 위 post를 보시기 바랍니다.

이렇게 해서 아두이노우노에서 기본 세팅은 끝났습니다.


3. S4A 스크래치 블록 코딩


S4A 스크래치에서 가변저항 값 읽기


아두이노 가변저항기에서 가변저항값을 읽기 위해서는 우선 그 가변저항값을 저장하는 변수를 선언해야 합니다. 케릭터 이동에 가변저항값이 사용하기 때문에 변수 이름을 move라는 변수를 하나 만들겠습니다.


위 그림은 이미 만들어 진 상태의 모습입니다. 새로 만들 때는 변수만들기를 누르면 보시는 것과 같은 창이 뜨고 변수이름을 치시면 변수 하나가 생성이 됩니다. 실험에서는 가변저항값을 현재 가변저항값과 이전 가변저항값을 비교하기 위해서 move, premove라는 변수를 만들었는데 이 부분은 나중에 설명 드릴께요. 두개 변수가 필요하니깐 우선 변수만 만들어 놓으세요.

그럼 변수를 만들었으면 그 변수에 실제 아두이노 가변저항값을 읽어 올까요.


제어, 동작, 변수 항목에서 표시한 블록들을 사용하여 읽게 됩니다. 어느 블록이 어느 위치에 있는지 잘 확인해 주세요. 첨에는 블록 위치가 햇갈려 할 수 있으며 색으로 구별하시면 아마 쉽게 구별이 가능 할 꺼에요. 총 4개의 블록으로 코딩을 하게 됩니다.

설계 :

  • 센서값 읽기 <= 계속 무한으로 읽어야겠죠.(실시간 조정을 위함)
  • 읽은 센서값 저장 <= move 변수를 만들었으니 여기에 저장해야겠죠.


끝! 위 블록 코딩으로 S4A 스크래치에서 이제 아두이노 가변저항값을 읽어와서 move 변수에 계속 실시간으로 저장하게 됩니다. 아무때나 move 변수값을 체크하면 현재 아두이노 가변저항값을 확인 할 수 있게 되었습니다.

고양이 좌/우 이동


아두이노의 가변저항기를 돌리면 고양이가 좌/우로 움직이게 하려면 어떻게 해야 할까요. 우선 고양이를 좌/우 이동을 시켜 봐야 합니다. 지난 시간에 고양이를 좌/우로 왔다 갔다 하는 동작을 샘플로 했었죠. 그 방법을 응용 할 거에요.


위 블록으로 x좌표로 좌/우로 이동을 했었습니다.


설계 :

  • 가변저항값을 x좌표로 변환 (0~1023을 x좌표 -200~200 값으로 변환)
  • 고양이 걷기 동작 만들기
  • 고양이 이동 (가변저항기를 돌리면 돌린 만큼 고양이를 이동시킨다)

가변저항값을 x좌표로 변환 (0~1023을 x좌표 양쪽 끝지점 -200~200 값으로 변환)

가변저항값을 어떤 특정값의 범위로 맞추기 위해서는 아두이노에서 map()함수를 사용했습니다.

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

위 식을 줄여서 그냥 0~400사이의 값으로 나오게 바꿨네요.

(move - 0) * (400 - 0) / (1023 - 0) + 0

=> move*400/1023

이렇게 줄였습니다. 그러면 가변저항기를 돌리면 0~400사이로 줄어 들게 됩니다.

그 다음 x 좌표는 양쪽 끝점 기준으로 -200~200사이가 됩니다. 그래서 가변저항값이 200일 때 0이 되어야 합니다. 그럼 식에 -200을 해주면 됩니다.

x좌표 : (move*400/1023) - 200

이렇게 해서 실제 고양이가 이동 할 x좌표를 구할 수 있게 되었습니다.



고양이 걷기 동작 만들기

가변저항기를 돌리게 되면 move값이 갱신이 되고 그 값을 기준으로 고양이를 이동시킨다고 했죠.

여기서, 고양이는 언제 걷기를 하나요. 바로 고양이가 이동 할 때 입니다. 즉, 가변저항기를 돌리는 순간 고양이는 걷는 동작을 해야 합니다. 이 표현을 블록 코딩 하면 다음과 같습니다.


이 원리는 딜레이 없이 딜레이 함수를 사용할 때 시간값을 비교할 때 코딩했던 로직과 유사한 원리입니다. 시간의 변화가 특정 조건에 만족할 때 그 동작을 수행하고 끝나는 시점에 현재 시간값을 저장하고 다음 시간을 비교하는 원리를 이용하였습니다. 여기에서는 가변저항기가 변화가 일어나면 그 변화한 만큼 고양이를 이동시킨 후 끝나는 시점에 현재 move(가변저항) 값을 premove(이전저항)값에 저장하여 새로운 가변저항값과 비교하여 변화가 일어나는지 체크하는 용도로 사용 하였습니다. 그래서 현재 가변값과 이전 가변값을 비교하기 위해서 premove 변수를 하나 더 만들어 사용 했네요.

위 블록코딩을 살펴보면 아래와 같은 C코딩으로 표현을 해보았습니다.

premove=0; //초기값

while(1){
  if(move<>premove){
   다음모양(고양이걷기);
   premove=move;
  }
}

여기서, 다음모양은 위 고양이 이미지 세팅에서 고양이 스프라이트에 2개의 이미지를 저장 했었죠. 이때 A, B 이미지가 있는데 다음모양 블록은 현재 이미지에서 다음 이미지로 무조건 바꾸라는 명령입니다. 참고로 다음 이미지는 순차적으로 이미지가 바뀝니다. 여기에서는 2장의 이미지인데 1번 이미지에서 다음모양블록을 만나면 2번 이미지로 바뀌게 됩니다.


위 그림에서 a가 현재 이미지면 다음모양 하면 b 이미지로 교체 됩니다. 현재 이미지가 b이면 다음모양 하면 a 이미지가 됩니다.

위 블록코딩은 가변저항기를 돌리는 순간 if문에서 이전 가변저항값과 현재 가변저항값이 다른지 체크하게 되고 다르면 가변저항기가 움직였다는 소리가 되고 그 순간 다음모양 블록으로 고양이 이미지를 다음 이미지로 바뀌고 고양이가 걷는 동작을 만들어 내게 됩니다.

[결과]


위 결과는 고양이를 x좌표로 이동하는 블록이 없어서 실제 x좌표로 이동하지 않고 가변저항기를 돌리면 제자리 걷는 동작만 수행하네요.


고양이 이동 (가변저항기를 돌리면 돌린 만큼 고양이를 이동시킨다)

사용 블록 :


위 블록에다가 위의 x좌표 구한 블록식을 x 위치에 배치하면 됩니다.


이렇게 배치하면 가변저항기가 움직이면 x좌표값이 바뀌고 해당 값의 위치로 고양이가 이동하게 됩니다.

종합


[아두이노 스프라이트 블록코딩]


[고양이 스프라이트 블록코딩]


[결과]

4. 자연스럽게 고양이 걷는 동작 만들기


이 내용은 안보셔도 됩니다. 스크래치 영역이고 아두이노를 다루는 것이 목적이지 고양이를 자연스럼게 움직이게 하는게 목적이 아니기 때문에 생략하셔도 됩니다. 그냥 뭔가 걷는게 부자연스럽게 보여서 블록 코딩을 수정한 것 뿐입니다. 수정 된 블록 코딩으로 하면 오늘 post의 의미 전달이 잘 안될 것 같아서 따로 분리 해서 설명합니다.

이 내용은 좀 더 자연스럽게 고양이가 오른쪽으로 걸을 때 오른 방향을 바라보도록 하고 왼쪽으로 걷게 되면 왼쪽을 바라보게 하는 방식입니다.


위 그림이 핵심 블록 코딩입니다. 우선 화살표가 가리키는 모양의 아이콘을 클릭해주세요. 좌우 이동시 회전 방향을 나타냅니다. 방향전환을 할 때 회전방향을 어떤 방식으로 회전 시키느냐에 따라서 고양이의 움직임이 바뀌게 됩니다. 좌/우 방향으로 바라보도록 회전 시키려면 화살표가 가리키는 모양의 아이콘을 클릭하면 됩니다.

여기서, 고양이의 방향 전환은 어쩔 때 일어나는지 알아야 합니다. 현재시점과 이전시점을 기준으로 비교하면 방향을 알아 낼 수 있는 두가지 방법이 있는데 그 중 하나를 선택하여 실험 했네요.

방향 찾기 :

  • 현재 가변저항값과 이전 가변저항값를 비교하여 방향을 정한다.
  • 현재 x좌표값과 이전 x좌표값을 비교하여 방향을 정한다.

가변저항값이든 x좌표값이든 선택은 여러분 몫입니다. 방향 전환을 할 때 예를 들면, 이전 가변저항값이 100일 때 현재 가변저항값이 110이면 어떻게 될까요. 고양이가 x좌표로 10만큼 이동하게 됩니다. 오른쪽으로 이동하는 것이기 때문에 고양이는 오른쪽 방향이 됩니다. 만약 현재 가병저항값이 90이면 x좌표는 왼쪽으로 10만큼 이동하게 되는데 고양이는 왼쪽 방향이 되겠죠.


위 코딩은 완성된 블록 코딩인데 x좌표 변수를 하나 더 만들었네요. 그리고 move와 premove변수가 기존에 있기 때문에 방향찾기는 가변저항값을 비교하여 방향을 결정했네요.

나머지 블록은 앞에서 설명 드렸기 때문에 생략합니다.

[결과]


영상을 보시면 가변저항기로 조정하면 깔금하게 해당 방향으로 고양이가 방향 전환을 하네요.

마무리


아! 이야기를 너무 풀어서 설명하다 보니 길어졌네요.


댓글()

[아두이노] S4A 스크래치로 아두이노 제어

IOT/아두이노|2019. 9. 30. 09:00

[아두이노] S4A 스크래치로 아두이노 제어



오늘은 여러 종류의 스크래치가 있으며 그 중에 S4A 스크래치를 이용하여 아두이노를 제어하는 방법을 간단히 살펴보는 시간을 갖도록 하겠습니다. 집에 S4A가 설치되어 있어서 그냥 이 S4A 스크래치 프로그램으로 아두이노를 제어했네요. 다른 스크래치 프로그램으로도 아두이노를 제어를 할 수 있으니 다른 스크래치 프로그램으로 제어하고 싶다면 해당 아두이노 펌웨어 소스로 아두이노에 프로그램을 이식 시키면 됩니다.

그러면 S4A 스크래치로 간단히 아두이노를 제어를 해봅시다.

1. S4A 스크래치


스크래치 프로그램은 아이들에게 그래픽 환경에서 코딩을 배우는 목적으로 설계된 교육용 소프트웨어입니다. 스크래치는 배경 이미지 위에 다수의 스프라이트라는 창에 있는 이미지를 겹쳐 쌓는 형태로 해서 한장의 이미지가 완성 됩니다. 여기서 개별 이미지는 움직이는 동작을 부여 할 수 있는데 이때 블록 코딩을 통해 이미지에 살아 움직이는 효과를 표현합니다. 쉽게말하면, 애니메이션과 같은 작업을 블록 코딩으로 한다고 생각하시면 됩니다. 애니메이션에서 각 장면 장면들을 그리면서 그림에 움직이는 효과를 표현하잖아요. 그와 마찬가지로 스크래치도 각 장면 장면들을 블록 코딩으로 통해 이미지를 그리거나 이동시켜서 애니메이션과 같은 움직이는 효과를 표현 한다고 생각하시면 됩니다.


위 그림처럼 배경 이미지 위에 개별 스프라이트 창에 고양이와 곤충 이미지 그림이 있습니다. 배경이 이미지 위에 고양이와 곤충이 배치 된 한장의 그림입니다. 여기서 고양이와 곤충을 개별적으로 블록 코딩이 하여 움직임을 부여 하여 애니메이션 효과로 표현 할 수 있습니다. 보면 이미지가 무대창, 스프라이트창으로 이미지가 개별적으로 나뉩니다. 그 이유는 각 창마다 블록 코딩을 개별적으로 하기 위해서 입니다. 진짜 이 프로그램이 대단한 것은 각 창마다 개별 코딩을 하는데 독립적인 동작을 개별적으로 처리 합니다. 우리가 프로그램 언어로 사용하여 이 개념을 코딩하려면 동시에 작업을 처리하는 코딩은 복잡해 지는데 이 복잡한 코딩을 스크래치는 내부에서 기본 바탕으로 세팅 되어 있어 동시 작업 처리에 대한 복잡한 생각을 할 필요가 없습니다. 각 이미지 별로 독립적인 개별 동작 코딩만 하면 되기 때문에 쉽게 코딩을 할 수 있습니다. 단점은 동시에 처리 시 우선 순위를 정하는 작업이 어렵습니다. 즉, 고양이와 곤충이 서로 충돌하는 장면을 연출한다고 해봅시다. 여기서 고양이와 곤충이 충돌 처리 동작 코딩이 복잡해 지는데 고양이가 곤충 충돌이 먼저 일어 났는지 곤충이 고양이와 충돌이 먼저 일어 났는지에 따라 결과가 달라지기 때문에 이 부분은 좀 복잡해 집니다. 스크래치도 동시 처리라고 하지만 실제 실행시키면 고양이와 곤충의 충돌 이벤트 시간이 다릅니다. 먼저 시작하는 쪽이 고양이 일지 곤충일지는 상황마다 다릅니다. 단지 인간이 감지했을 때 동시처리 되는 것처럼 보일 뿐이죠. 이게 왜! 단점이냐면요. 예를 들어 우주선 게임이 있는데 우주선에서 총알이 발사 됩니다 여기서 총알이미지가 몬스터와의 충돌 이벤트 처리가 어렵고 문제가 발생 할 수 있습니다. 총알은 몬스터에 충돌하면 사라지는 코딩을 넣고 몬스터는 총알과 총돌하면 피가 깍이거나 죽는 코딩을 넣는다고 상상해 봅시다. 이때 총알이 먼저 몬스터에 충돌하는 이벤트가 실행하면 총알이 사라질 때 몬스터 코딩에서는 총알이 충돌을 감지 못 할 수 있습니다. 총알은 몬스터에 공격하는데 몬스터는 총알이 총돌했는지 감지하기 전에 총알이 먼저 사라지기 때문에 몬스터 입장에서는 충돌 이벤트가 발생하지 않게 됩니다. 스크래치는 개별 코딩으로 동시처리 하지만 개별 코딩에서 서로 영향을 미치는 코딩에서는 처리하기가 복잡해 집니다.

사설은 이만하고, 이제 애니메이션 처럼 그림을 움직이게 해봅시다.


위 그림에서 보는 것 처럼 스크립트라는 창에다 왼쪽 블록들을 배치하여 고양이 스프라이트가 움직이게 합니다.

[블록 코딩]


블록 내용은 클릭이 되면 실행아래 블록들이 실행 됩니다. 여기서 제일 먼저 무한반복 블록이 실행된는데 무한 반복 블록 안에 잇는 동작을 순차적으로 실행하고 그 과정을 무한 반복하게 됩니다. 어떤 동작을 무한 반복하는지 볼까요. 현재 스프라이트를 x좌표로 20만큼 이동한 후 0.5초 후 다시 x좌표로 -20만큼 이동하고 0.5초 대기합니다. 이 과정을 무한 반복하라는 블록 코딩입니다. 그러면 배경이미지 기준으로 고양이 스프라이트 이미지가 x축으로 +20, -20으로 왔다 갔다하게 됨으로 고양이가 움직이는 애니메이션처럼 움직이게 됩니다. 여기서, 좀 더 디테일적으로 표현하면 고양이를 길이미지를 만들어 놓고 그 위에서 걸어가게도 할 수 있으며 고양이가 걷거, 뛰기, 점프(중력), 소리 효과도 부여할 수 있는데 그걸 넣으면 복잡해 보일 수 있기 때문에 단순히 좌/우로 움직이는 간단한 표현만 코딩했네요. 지금 스크래치 post가 아니고 아두이노를 제어하는 것이 목적임으로 이 내용은 생략합니다.

공부를 하고 싶으신 분들은 MIT 공대에서 만든 아래 스크래치 사이트에 가셔서 온라인 상에서 연습 해보세요. 튜토리얼이 잘 나와 있기 때문에 여러분들이 이곳에서 따라 연습해 보시면 이해하실 수 있을 꺼에요. 스크래치에 대해 post 한 것 같은데 기억이 잘 안나서 다시 이야기 합니다.



생활코딩 강좌에 가시면 이 강좌를 만드신 분이 아주 자세히 영상물로 설명하고 있어서 성인 기준 반나절이면 충분히 마스터 할 거라 생각됩니다.

추가로,



자격증 문제인데 샘풀문제를 한번 풀어보세요. 주기적으로 이전 시험 출제 문제들을 공개하는데 한번 문제를 풀어보는 것도 재밌을 꺼에요. 1급은 좀 난이도가 있더군요. 초등학생 수준은 3급 자격증이고 1~2급은 어느정도 연습과 코딩 능력을 갖춰야 할 수준이고요.

2. S4A 스크래치 설치 및 아두이노 펌웨어



위 사이트에 가셔서 다운로드 페이지로 넘어가시면 아래와 같은 창이 뜹니다.


설치 운영체제를 선택하는데 전 윈도우라서 윈도우 설치 프로그램 다운 받았으며 아두이노우노에 펌웨어 소스는 아래 표시된 곳에서 다운로드 받으시면 됩니다. 아두이노 소스가 다운로드 됩니다.

1) 아두이노우노에 펌웨어 시키기



위 S4A 공식 사이트에서 다운 받은 소스를 아두이노 IDE에서 위 그림처럼 S4AFirmware16이라는 소스를 업로드 시키면 됩니다. 이렇게 하면 아두이노우노 세팅은 끝납니다. 아주 간단하지요. 참고로 S4A 스크래치 프로그램을 실행 시킨 상태에서는 하지 마세요. 아두이노 IDE에서 먼저 세팅 해 놓고 나서 펌웨어가 성공하면 그다음에 S4A 스크래치 실행 시키기 바랍니다.

2) S4A 스크래치 실행


아두이노우노가 PC에 연결된 상태이면 아래 왼쪽 그림처럼 보드 검색 중인 상태 표시가 처음 표시 됩니다 그리고 자체적으로 인식 작업을 수행하고 아두이노우노가 인식을 하게 되면 오른쪽 그림처럼 아두이노우노가 일부 핀값들의 값들이 읽어와 표시 됩니다. 수치 변화가 실시간으로 이루어지면 정상적으로 아두이노우노가 인식했다고 보시면 됩니다. 이 수치는 아두이노칩 자체에 전류가 공급되면 각 핀마다 미세하지만 전류가 흐르게 됩니다. 일종의 노이즈가라고 생각하시면 돼요. 노이즈 값들이 실시간으로 읽어온다고 생각하시면 될 듯 싶네요.


3. S4A 스크래치에서 아두이노 우노 동작시키기


간단히 Blink 예제를 실행 시켜 볼까요.

[Blink 예제]

void setup() { 
  pinMode(13, OUTPUT);
}

void loop() {
  digitalWrite(13, HIGH);  
  delay(1000);               
  digitalWrite(13, LOW);  
  delay(1000);               
}

[S4A 스크래치 블록 Blink 예제]


두 코딩을 비교하면 아래 블록 코딩이 쉬워 보일꺼에요. 하지만 전 블록 코딩을 싫어 합니다. 제가 원하는 위치에 원하는 선언과 코딩을 하는데 약간 제약이 따르고 정해진 블록으로만 상상코딩을 해야 하기 때문에 상상코딩에 장애요인으로 저에게 오더군요. 익숙치 않는 원인도 있겠지만 왠지 이런식으로 코딩하면 뭔가 막힌 것 같은 코딩이 되어서 블록 코딩은 싫어 합니다. 하지만 비전공자나 아이들의 경우는 이런 코딩이 더 쉽고 편할 수 있습니다.

아무튼 스크래치로 아두이노를 제어 할 경우 실시간으로 반응을 체크 할 수 있는 장점이 있습니다. 방금 블록 코딩한 13번핀에 LED을 깜박이게 하는 동작을 수행 할 때 아두이노에 다시 프로그램을 이식할 필요 없이 바로 제어가 됩니다. A0핀에 센서를 읽고 싶다면 아날로그 읽기블록을 배치하면 바로 A0에 연결된 센서값을 읽어오게 됩니다. 실시간 코딩으로 실시간 반응을 확인할 수 있어 스크래치로 아두이노를 제어가 더 재밌을 수 있습니다. 실시간 처리가 가능한 이유는 이미 아두이노우노를 펌웨어 할 때 각 핀의 역할을 사전에 지정해 놓았기 때문입니다. 이미 디지털핀과 아날로그 핀 동작을 스크래치 블록에 맞게 세팅되어 활성화 된 상태이기 때문에 해당 블록을 사용하면 해당 핀 동작을 실시간으로 결과를 얻게되는 구조이지요. 문제는 특정 핀을 특정 동작만 하고 다른 동작을 수행할 수 없어 강제성을 갖고 있다는 점이 단점이라고 할 수 있습니다.

[결과]


추가로, tinkercad 가상시뮬레이터 실험


tinkercad 에서도 아두이노 우노를 위 그림처럼 블록 코딩이 가능합니다. 예전에 tinkecad 가상시뮬레이터를 소개 할때 이 부분을 설명했지만 이번 post내용에 연결되는 부분이라 다시 거론합니다.

[결과]


가상시뮬레이터에서도 연습이 되니깐 혹시 아두이노우노가 없으시다면 가싱시뮬레이터에서 블록 코딩을 해보세요.

마무리


스크래치에 그려진 이미지와 아두이노를 연동하여 재밌는 간단한 표현까지 post 하려고 했더니 잡이야기를 하다보니 post가 길어졌네요. 다음 post에서는 간단히 고양이 이미지를 만들고 고양이를 아두이노로 조정해보는 내용으로 post 하겠습니다. 고양이 움직임에 대해 간단히 상황을 설정하고 아두이노에서 조정하려면 몇가지 아두이노에서도 설정해야 하기 때문에 좀 내용이 애매하게 길어질 것 같아서 오늘 내용은 여기서 멈추겠습니다. 사실 하루치 post로 간단히 소개만 하고 넘어 가려고 했는데 좀 길어졌네요.

S4A와 연동한 아두이노는 스프라이트 이미지로 아두이노우노를 제어 할 수 있고 반대로 아두이노우노에서 스프라이트 이미지를 제어 할 수 있습니다. 쌍방 통신이 가능하여 상상하는 목적에 따라서 다양한 결과물을 얻을 수 있기 때문에 한번 사용해 보셨으면 합니다.

댓글()

[아두이노] 아두이노 전기 전도성 펜

IOT/아두이노|2019. 9. 6. 09:00

[아두이노] 아두이노 전기 전도성 펜



1. 전기 전도성 펜


전도성이란 "전기가 얼마나 잘 흐르는가를 나타내는 성질"을 말합니다. 전기가 통하는 금속으로 금, 은, 구리, 철, 백금, 주석, 알리미늄, 아연, 텅스텐, 니켈 등이 있습니다. 오늘 소개하는 전기 전도성 펜은 잉크에 전기 전동성 물질이 들어 있어서 펜으로 그림을 그리면 그림을 그린 선에는 전류가 흐르는 통로가 만들어 진다. 그림으로 그린 선이 일종의 회로도의 전선 부분을 담당하게 됩니다. 참고로, 전기 전동성 잉크펜은 일리노이 대학 제니퍼 교수가 처음 개발하였습니다.


위 전기 전도성 펜으로 아래 밧데리, LED, 저항이 세개 있다면 종이 위에 전도성 펜으로 선을 그리면 LED에 불이 들어오게 됩니다.


아니면, 위 그림처럼 표현하면 전기 전도성 펜을 사용 가치가 있을까라는 생각이 들꺼에요. 아래와 같이 이렇게도 표현해서 LED에 불이 들어 옵니다. 뭔가 카드 같은 걸 만들 때 사용하면 좋겠죠.


잉크 자체가 전기가 흐르는 성분이 들어 있기 때문에 잉크가 마르면 그림을 그린 선 자체가 전선이 됩니다. 그래서 공간적 제약이 없이 자유 자제로 그림을 그릴 수 있는 모든 사물이나 장소가 회로도가 될 수 있습니다.

전기 전도성 펜이 좋은 점은 회로도를 만들 때 기판에 전선을 연결하고 납땜을 해야 하는 불편함을 해결 됩니다 아이들도 쉽게 다룰 수 있어 상상력을 끌어 올리기 좋습니다. 아이들과 아두이노를 공부할 때 활용하면 아이들의 흥미를 유발할 수 있는 좋은 소재가 생각 되네요.

유튜브에서 전도성 펜이라는 단어로 검색하시면 진짜 다양한 작품들을 감상하실 수 있습니다. 간단한 표현에서 부터 고퀄리티 작품들도 쉽게 찾아 볼 수 있으니 한번 검색하셔서 전도성 펜이 어떤 펜인지 시각적으로 감상을 해보세요.

참조영상물 출처 : 서울시 · Seoul이라는 게시자가 올린 작품인데 아이들과 이런 걸 만들면 재밌을 거라 생각되네요.

서울시 · Seoul : https://www.youtube.com/watch?v=DWJMkZtY_Rw

아래 영상물은 영메이커와 KocoaFab에서 만든 영상물인데 아두이노 공부하신분들에게 볼만한 영상물입니다.

영메이커 : https://www.youtube.com/watch?v=N9c6-qic7y8
KocoaFab : https://www.youtube.com/watch?v=c9w3Uw8DPo0

제 영상물이 아니기 때문에 직접 올릴 수 없고 영상물 게시자와 출처내용과 링크 주소만 표시 합니다. 직접 해당 유튜브로 가셔서 확인하시거나 아니면 별도로 유튜브에서 전도성 펜이란 키워드로 검색하셔서도 쉽게 검색되고 링크한 영상물보다 더 멋진 영상물들이 수두룩 하니 직접 검색을 통해서 찾아보시기 바랍니다.

2. 전기 전도성 실



전기전도성 실은 스테인리스 스틸 재질의 섬유로서 일정 길이만큼 저항값을 가지고 있다고 합니다. 전자섬유는 섬유에 전기 신호를 전달 할 수 있기 때문에 웨어러블 기술과 접목한 전자 의류 연구가 국내에서 활발이 진행되고 있다고 하네요. 미래의 의류에는 웨어러블 전자의류로 다양한 기능이 탑재 되어 우리 생활에 많은 영향을 미칠 거라 생각되네요.

참조영상물 출처

김주현 : https://www.youtube.com/watch?v=efCwCIhTkAg
숙명여대 이지선 교수님의 딸 해나양이 직접 디자인해서 제작한 작품이라고 하네요.

제 영상물이 아니기 때문에 직접 올릴 수 없고 영상물 게시자와 출처내용과 링크 주소만 표시 합니다.

유튜브에서 전도성 실이라는 키워드로 검색하시면 다양한 작품들을 보실 수 있을 꺼에요. 위 유튜브 김주현님이 올린 영상물을 가셔서 보시면 토끼인형에 LED 불이 들어오게 하는 작품인데 귀여워서 링크 주소를 걸어 놨네요.

마무리


전기 전도성 펜은 그림을 그릴 수 있는 모든 곳이 회로도 됩니다. 카드나 종이모형에 LED 조명을 달면 시각적으로 재밌는 작품들을 만들 수 있습니다. 그리고 그림을 그릴 수 있는 모든 곳에 사용 할 수 있어 그림을 그리는 곳이 바로 전자회로가 됩니다. 전기 전도성 실의 경우도 마찬가지 입니다. 의류 같은 곳에다가 전기 전도성 실을 사용하면 옷에 실제 전선을 연결할 필요 없이 실로 그 역할을 대신하기 때문에 천에 실을 바느질을 하여 회로도를 만들어도 잘 티가 나지 않으면 옷의 불편함을 줄일 수 있습니다. 가령 의류에 LED를 달아 이퀄라이저를 표현하면 진짜 재밌을 것 같아 보입니다.

마지막으로, 이외에 전기 전도성 소재들이 많습니다. 어떤 것들이 있는지 한번 찾아보세요. 다양한 전기 전도성 소재을 가지고 아두이노와 접목하면 많은 것들을 할 수 있을 꺼에요. 상상코딩 소재에 이만한 좋은 소재는 없을거라 생각 됩니다.

댓글()

[아두이노] 아두이노 라이브러리 만들기

IOT/아두이노|2019. 9. 5. 09:00

[아두이노] 아두이노 라이브러리 만들기



지금까지 아두이노를 코딩 할 때 아두이노 표준 라이브러리 함수를 사용하거나 누군가 만들어 놓은 라이브러리 함수들을 가져다 편하게 코딩을 해왔습니다. 그런 라이브러리 함수는 어떻게 만들어지는 걸까 궁금한 적이 아마 있을거에요. 누군가 만들어 놓읗 라이브러리 함수만 쓰는 것은 재미가 없습니다. 한번 쯤 자신이 만든 라이브러리 함수를 사용해보고 싶은 생각을 가져 보셨을 거라 생각 합니다. 그리고 사용되는 부품에 따라서 뭔가 2% 부족한 함수이거나 이런 동작을 수행하는 함수가 있었으면 하고 원한 적이 있을 꺼에요. 이런 라이브러리 함수는 만드는 방법이 궁금하실 것 같아서 한번 라이브러리 함수를 만드는 방법을 알아두면 좋을 것 같아서 간단히 소개합니다.

1. 클래스


C언어에서 C++으로 넘어가면서 객체지향 프로그램에 대해 배우게 되는데 처음 클래스라는 개념을 배우게 되는데 클래스는 객체를 생성하기 위한 변수와 함수를 묶어 놓은 틀이라고 말합니다. 그리고 클래스의 정의와 특징들을 열거하자면 좀 복잡하고 쉽게 그 의미를 이해하기 쉽지 않습니다. 그냥 간단히 객체를 붕어빵이라고 하면 클래스는 붕어빵틀이라고 생각에서 출발해 주세요. 클래스는 완전 실체화 되지 않는 틀이라고 생각하고 객체는 실제 그 틀을 실체화 한 대상으로 생각하면 될 듯 싶네요.

그리고 클래스는 캡슐화 의미만 가지고 있으면 됩니다. 변수와 함수들을 하나의 주제로 묶어 만들어 놓은 틀로 생각하시면 됩니다.

예를 들어, 우리가 자동차를 코딩으로 비유해 봅시다.


자동차는 위 그림처럼 엔진, 핸들, 바퀴, 몸체, 의자, 창문 등등 여러가지 자동차 부품들이 모여서 한대의 자동차를 만들게 됩니다. 일반 코딩은 자동차 부품들을 한번에 하나의 틀로 일체화 된 코딩이라고 생각해 봅시다. 이런식의 코딩을 하게 되면 나중에 자동차 엔진이 맘에 안들어 다른 엔진으로 바꾸는 일이 생기면 이 엔진에 해당되는 코딩 위치와 이 엔진과 다른 부품과 연결된 위치를 전부 찾아내어 수정해야 합니다. 즉, 한번 뭔가를 업그레이드 할려면 전체 코딩 소스를 수정해야 한다는 복잡해 지겠죠. 여기서 자동차의 각 부품을 클래스 단위로 캡슐화 한다면 어떻게 될까요. 부품별로 나누고 객체화 시키면 나중에 엔진을 교체하고 싶을 때 해당 엔진 객체만 다른 객체로 바꾸면 쉽게 수정이 가능해 집니다.


위 그림에서 3개의 엔진이 있을 때 엔진을 교체한다면 엔진 클래스 A, B, C 중 자신이 원하는 클래스를 가져다가 사용하시면 됩니다. 즉, A엔진에서 C엔진으로 교체할 경우 C엔진 클래스로 변경만 하면 되기 때문에 코딩이 쉬워집니다. 전체 소스에서 클래스 접근 부분만 수정하면 되기 때문에 쉽게 코딩이 됩니다. 클래스 단위로 엔진이 만들어 지지 않았다면 어떤 현상이 발생할까요. 전체 소스에서 엔진이 어디서 부터 어디까지 인지 또는 엔진과 연결된 다른 부품에서 엔진과 다른 부품과의 경계를 구분하기가 어려워 엔진 코딩영역인지 다른 부품영역인지 나누는 것이 쉽지 않게 됩니다. 코딩을 길게 하다면 나사(변수)가 엔진에 사용하는 나사인지 바퀴에 사용하는 나사인지도 구별하기 힘들게 되는 문제점을 가지게 됩니다.

그래서 클래스라는 것을 이용합니다. 각 부품을 클래스화 하면 각 부품을 개별적으로 접근 제어 통제가 됩니다. 엔진에 대한 동작은 엔진 클래스에 안에서만 동작하고 바퀴에 대한 동작은 바퀴클래스 안에서만 동작하기 때문에 개별적 동작 제어가 되기 때문에 실제 프로그램을 설계할 때 클래스 단위로 접근 되기 때문에 그 경계가 명확하고 부품별 제어는 쉬워집니다. 왜 클래스를 배워야 하는지 아시겠지요.

이제 클래스에 대해 알아보도록 합시다.

2. 클래스 문법


클래스 기본 구조는 아래와 같습니다.

[클래스 구조]

class 클래스명
{
  private: //접근권한
    멤버변수1;  //내부접근
    멤버함수2;  //내부접근
  public: //접근권한
    멤버변수2;  //외부접근
    멤버함수2;  //외부접근
};

클래스명으로 하나의 클래스를 만드는 데 내부에서 private, public, protected 로 접근 권한을 부여합니다.

  • private : 내부에서만 접근 가능하고 외부에서는 접근 불가능
  • public : 내부에서 접근 가능할 뿐만 아니라 외부에서도 접근 가능
  • protected : 현재 클래스에서는 private 성격을 가지지만 다른 클래스에 상속 될 경우 다른 클래스에서 접근 불가능
    현재 클래스에서만 접근 가능한 제한 된 성격을 지니고 있음

private와 public만 기본적으로 알아두시면 됩니다. private은 클래스 내부에서만 접근되고, public은 클래스 밖에서도 접근 할 수 있다는 개념만 잡아 두세요. 우리가 러이브러리 함수를 호출하여 사용할 때 public 접근지정자에 선언된 함수들을 호출하여 사용되어 왔습니다.

클래스명 클래스객체;

클래스객체.멤버함수2();

이러헥 아두이노에서 사용되어 왔지요.

[생성자 & 소멸자 함수] : 생성자와 소멸자 함수는 클래스명과 동일해야 함.

  • 생성자 함수 : 클래스 객체가 생성과 동시에 호출되는 함수
  • 소멸자 함수 : 클래그 객체가 소멸과 동시에 호출되는 함수
class abc
{
  public:
    abc(){
          생성자함수;
    }
    ~abc(){
          소멸자함수;
    }       
}

abc 클래스를 객체변수를 다음과 같이 선언됩니다.

abc obj;
abc::abc(){
  생성자함수;
}

이렇게 abc()함수가 호출됩니다.

아두이노에서 LCD 라이브러리 함수를 사용할 때를 생각해 봅시다. 처음 객체선언 할 때 을 보면 다음과 같습니다.

예)

#include <LiquidCrystal.h>

//LiquidCrystal(rs, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(3, 4, 8, 9, 10, 11);

위 처럼 lcd(3,4,8,9,10,11)로 객체변수가 선언되면 lcd()생성자 함수가 호출됩니다.

class LiquidCrystal
{
  public:
    LiquidCrystal(int a, int b, int c, int d, int e, int f){
      생성자함수 수행 명령 코딩;
    }
    ~LiquidCrystal(){
      소멸자함수 수행 명령 코딩;
    }
};

대충 a,b,c,d,e,f은 실제 변수명이 아니라 예를 든 것일 뿐 실제 따른 변수명이겠죠. 예를 들것 뿐입니다. 이렇게 클래스 객체변수를 선언하면 선언과 동시에 생성자 함수가 호출됩니다.

소멸자 함수는 이 클래스 객체변수가 delete 될 때 소멸자 함수가 호출됩니다.

이제는 쉽게 클래스를 이해하기 위해서 예를 들어 실험해 봅시다.

예) 두수의 합을 클래스로 만들기

Calc이라는 클래스를 만듭니다. 두 수 이니깐 2개의 멤버변수를 만드는데 해당 클래스 내에서만 접근하고 외부에서는 이 변수를 접근하지 못한다고 하면 다음과 같이 코딩합니다.

class Calc
{
  private:
    int a=0;
    int b=0;
};

여기서, 생성자 함수를 통해서 외부에서 a,b값을 받고, sum()함수로 입력받은 두수의 덧셈을 수행 해봅시다.

class Calc
{
  private:
    int a=0;
    int b=0;
  public:
    Calc(int val1, int val2){
      a=val1;
      b=val2;       
    }
    int sum();
};
int Calc::sum(){ //클래스 외부로 빼면
  return a+b;  
}

sum()함수는 생성자 함수처럼 클래스 내부에서 표현해도 되지만 외부로 빼면 위 코딩처럼 표현하시면 됩니다. 특정 동작 코딩이 꽤! 길어진다면 클래스 내부에서 코딩하면 지져분하게 보입니다. 그래서 외부로 빼서 클래스를 보기 편하게 최소화 코딩을 하면 좋습니다.

아무튼 이렇게 표현하고 아두이노 가상시뮬레이터에서 그 결과를 살펴볼까요.

[소스]

class Calc
{
  private:
    int a=0;
    int b=0;
  public:
    Calc(int val1, int val2){
      a=val1;
      b=val2;       
    }
    int sum();
};
int Calc::sum(){ //클래스 외부로 빼면
  return a+b;  
}

Calc obj(2,3); //객체변수 선언

void setup()
{  
  Serial.begin(9600);
  Serial.println(obj.sum());
}

void loop()
{
}

[결과]

5

위 예제를 보면 클래스 만들기가 그렇게 어렵지 않죠.

3. 라이브러리 만들기


아두이노 Blink 예제를 가지고 간단히 클래스를 만들어 볼까요.

[기본 틀]

#ifndef LED_H    
#define LED_H

클래스 코딩

#endif   

우선, 위 기본틀을 이해해 주세요. #ifndef ~ #endif 구조문을 기본 틀로서 해당 파일이 한번만 포함되도록 제한하는 방식으로 중복 인크루드 되는 걸 막는 구문입니다. 두번 포함 되지 않게 하는 표현으로 생각 하세요. #ifndef은 전처리기로 LED_H라는 정의된 식별자가 있는 지 체크하는데 없으면 처음 한번은 해당 코딩 소스를 인크루드 합니다. 안에 보시면 #define으로 LED_H가 정의하는 문장이 있죠. 처음에는 없으니깐 한번 인크루드하는데 안에서 정의를 하니깐 다음 번에는 인크루드하지 않습니다. 두번 참조되는 것을 막는 구문으로 정리하시면 됩니다.

Blink 예제로 실험 한다고 했죠. 클래스를 만들어 볼까요.

[Led.h 파일]

#ifndef LED_H    
#define LED_H

#include "arduino.h"

class Led
{
  private:
      int LedPin;
  public:
      Led(int Pin){ 
         LedPin = Pin;
         pinMode(LedPin, OUTPUT);         
      }
      ~Led(){
      }
public:
      void LedHigh();
      void LedLow();
};

#endif   

[Led.cpp 파일]

#include "Led.h"
void Led::LedHigh(){
  digitalWrite(LedPin,HIGH);
}
void Led::LedLow(){
  digitalWrite(LedPin,LOW);
}

여기서, PinMode(), DigitalWrite()함수 코딩을 직접해야 하는데 너무 길어서 인용했네요. 참고로 arduino.h 파일에 아두이노 표준 함수들이 들어 있기 때문에 선언해 주셔야 클래스 안에 아두이노 변수, 상수, 함수들을 사용할 수 있습니다.

간단히 위 클래스 함수에 대해 설명하면,

  • 생성자 Led()함수로 핀번호가 입력되면 무조건 해당 핀번호는 출력모드로 지정합니다.
  • LedHigh()와 LedLow()함수로 해당 핀번호로 High or Low 신호를 출력하게 됩니다.

이런식으로 자신만의 클래스를 만들 수 있습니다. 클래스 만드는 법이 간단하죠.



위 자료 출처에 가셔서 라이브러리 함수 내부 코딩을 보시면 꽤 긴 코딩을 보실 수 있을꺼에요 오늘 post는 의미 전달이 목적이라 실제 내부로직을 위 자료 출처의 소스처럼 코딩해야 합니다. 그러면 너무 복잡하고 의미전달도 안되겠죠. 간단히 클래스라는 개념만 오늘 배우는 시간이기 때문에 간단히 예제 클래스를 만들어 실험 했네요.

4. 라이브러리 추가하기


만든 클래스를 라이브러리에 추가하려면 아래와 같은 과정을 수행합니다.

먼저,


Led 클래스 이름을 전부 통일 시켜주세요.


위 그림처럼 아두이노 IDE가 깔려있는 폴더에서 라이브러리 폴더를 찾아주세요. 그안에 방금 만든 폴더를 추가하시면 끝납니다.


위그림에서 보시는 것 같이 라이브러리가 추가 된 것을 확인 할 수 있을 꺼에요.

5. 라이브러리 실행


1) 회로도


  • 준비물 : Red Led 1개, 저항 220옴 1개, 아두이노우노
  • 내용 : Led를 13번 핀에 연결하시오


2) 코딩


위에서 만든 라이브러리를 이용하면.

[실제 코딩]

#include <Led.h>

Led obj(13); //객체선언

void setup()
{   
}

void loop()
{
  obj.LedHigh(); //13번핀을 High상태로
  delay(1000);
  obj.LedLow(); //13번핀을 Low상태로
  delay(1000);
  
}

[가상시뮬레이터 코딩] : 인크루드를 할 수 없으니 해당 클래스를 복사해 와야 합니다.

class Led
{
  private:
      int LedPin;
  public:
      Led(int Pin){
         LedPin = Pin;
         pinMode(LedPin, OUTPUT);         
      }
      ~Led(){
      }
public:
      void LedHigh();
      void LedLow();
};

void Led::LedHigh(){
  digitalWrite(LedPin,HIGH);
}
void Led::LedLow(){
  digitalWrite(LedPin,LOW);
}

Led obj(13);

void setup()
{   
}
void loop()
{
  obj.LedHigh();
  delay(1000);
  obj.LedLow();
  delay(1000);
  
}

3)결과


Led 클래스를 인크루드 할 수 없기 때문에 클래스를 복사해서 가상시뮬레이터로 돌려 봤네요.


마무리


오늘은 클래스를 만들어 보는 시간을 가졌습니다. 아두이노를 코딩하다보면 많은 라이브러리 함수들을 사용합니다. 사용하다보면 뭔가 2% 부족한 함수들이 있습니다. 이 기능과 저 기능이 합쳐졌으면 하는 함수들이 있는가 하면은 자신이 뭔가 특정 동작을 수행하는 함수를 만들 때가 있습니다 .이 함수를 나중에 다른 곳에 사용하고 싶어지는 경우가 생길 때 직접 여러분들이 여러분들의 전용 클래스를 만들어 놓으면 나중에 해당 함수를 가져다 쓸 때 편하게 사용할 수 있습니다.

나중에 도움이 많이 되니깐 이번에 클래스를 만드는 연습을 해 놓으셨으면 합니다.

댓글()

[아두이노] 로봇 팔 관절 제어

IOT/아두이노|2019. 9. 4. 09:00

[아두이노] 로봇 팔 관절 제어



오늘은 마지막 시간으로 인터넷 로봇팔 키트로 판매하는 제품들의 일반적 특징들을 기반으로 해서 가상시뮬레이터에서 간단히 실험 해보는 시간을 갖도록 하겠습니다.

1. 로봇 팔


시중에 판매되는 로봇 팔 키트의 구조가 아래와 같은 형태로 디자인 되어 있더군요. 편의 상 원은 Servo Motor이고 회전되는 부위라고 가정한 디자인 입니다. 실제로는 좀 다르겠지요.


  • A 지점 : Servo Motor가 수평방향으로 회전하여 로봇팔의 몸통을 회전시키게 됩니다.
  • B, C지점 : Servo Motor가 수직방향으로 회전하여 로봇팔의 움직임을 만들어 냅니다.
  • D 지점 : Servo Motor가 집게를 제어합니다.

총 4개의 Servo Motor로 로봇팔 모양을 간단히 로봇팔 모형을 만들어 키트로 판매하더군요. 이걸 한번 가상시뮬레이터에서 실험해 보면 재밌을 것 같아서 실험을 하였습니다.

만약, 로봇 손이였다면 손가락 관절을 전부 다 제어해야 하기 때문에 너무 노가다 디자인을 해야 하기 때문에 간단한 집게 로봇팔을 실험 대상으로 했네요.

2. 로봇 팔


  • 준비물 : 가변 저항 4개, Servo Motor 4개, 아두이노우노, 외부전원
  • 내용 : 디지털Pin 4개를 Servo Motor 핀에 연결하고 가변저항도 A0~A3에 연결하시오


위 그림을 보면 지난시간에 6족 보행로봇 다리를 제어하는 실험을 가상시뮬레이터에서 했던 회로도와 같습니다. 관절 제어이기 때문에 회전만 제어하는 실험이라서 회로도는 같습니다. 같은 회로도이지만 어떻게 디자인 하느냐에 따라서 달라질 뿐이죠.

참고로 가변저항은 로봇팔을 제어하는 조종기가 됩니다. 몸통 회전 A와 로봇팔 움직임 B, C와 집게 D 제어로 총 4개의 제어값을 만들어야 합니다. 그래서 4개의 가변저항을 통해 조정하게 됩니다.

만약, 조이스틱으로 한다면 조이스틱은 X,Y 값을 만들어 내는데 4개의 제어값이 필요하니깐 조이스틱을 2개 연결하면 조정이 가능 합니다. 그리고 Bluetooth를 연결한다면 무선으로 스마트폰에서 조정이 가능합니다.

가상시뮬레이터에서는 가변 저항으로 조정했지만 실제로 제작해서 한다면 조이스틱이나 스마트폰으로 무선 조정을 하면 재미있겠죠.

3. 코딩


지난 시간의 6족 보행 로봇을 제어 하려면 보행 로봇의 움직임 패턴을 만들어야 하지만 로봇 팔은 그럴 필요가 없습니다. 집게 로봇 팔은 가변저항으로 간단히 제어가 가능하기 때문에 가변저항을 읽는 부분만 코딩하시면 됩니다.

가변저항 읽기 : analogRead()함수로 간단히 가변저항 값을 읽을 수 있습니다.

Servo Motor는 0~180도 회전을 할 수 있기 때문에 아날로그 읽기 0~1023값을 map()함수로 0~180으로 변환 시키야 합니다. 아래와 같이 가변저항값을 읽으면 됩니다.

int angle1 = map(analogRead(A0),0,1023,0,180);

A 모통 회전 : Servo Motor를 가변저항 값으로 회전 시키면 됩니다.

servo[0].write(angle1);

끝! 엄청 간단하죠.

종합해보면,

#include <Servo.h>

Servo servo[4];
const byte servoPin[4] = {2,3,4,5};

void setup()
{ 
  for(int i=0;i<4;i++){
    servo[i].attach(servoPin[i]);  
    servo[i].write(90);
    
  }
  delay(1000);
}

void loop()
{
  int angle1 = map(analogRead(A0),0,1023,0,180);
  int angle2 = map(analogRead(A1),0,1023,0,180);
  int angle3 = map(analogRead(A2),0,1023,0,180);
  int angle4 = map(analogRead(A3),0,1023,0,180);
  
  servo[0].write(angle1);
  servo[1].write(angle2);
  servo[2].write(angle3);
  servo[3].write(angle4);
  delay(100);  
}

위 코딩에서 중복되는 4번의 코딩 라인을 for문으로 처리하면 코딩 라인을 최소화 할 수 있습니다. 그 부분은 여러분들이 직접 수정해 보세요.

4. 결과


사실 집게 로봇팔에 대한 가상시뮬레이터 결과를 이해하기 위해서는 실제 모형을 보고 이해해야 하는데 단순히 Servo Motor회전으로 연상이 안될 수 있습니다. 아두이노 부품 판매 사이트에 가셔서 로봇팔 제품을 보시고 그래도 이해가 안되신다면 그 제품에 대한 영상물을 Youtube로 찾아 보시면 아마 있을꺼에요. 보고 움직임을 이해하시고 머리속에서 집게 로봇팔을 좌표계에 배치하고 움직이는 이미지와 가상시뮬레이터의 Servo Motor 회전을 같이 연결하여 상상하면서 보시기 바랍니다.


마무리


오늘 post 내용은 예전에 Servo Motor 제어편에서 간단히 가변저항을 이용하여 회전 시킨 회로도 입니다. 복습 post이지만 관절에서 빠질 수 없는 내용이기에 글을 쓰게 되었네요. 한개의 Servo Motor를 4개로 늘어 났을 뿐이고 코딩도 동일합니다. 재밌는 것은 Servo Motor를 가변저항으로 조정했던 원리가 오늘 로봇팔 제어가 되었다는 것이죠.

간단한 원리도 생각하는 관점에 따라 이렇게 재밌는 표현을 할 수 있습니다. 평소 사소한 원리일지라도 잘 정리 해놓으면 이렇게 상상력을 더해 재밌는 실험을 할 수 있습니다.

댓글()

[아두이노] 관절과 좌표계

IOT/아두이노|2019. 9. 3. 09:00

[아두이노] 관절과 좌표계



로봇팔이나 6족 보행로봇 같은 관절형 로봇은 Servo Motor나 Stepper Motor의 회전 각을 통해 관절의 움직임을 만들어 내게 됩니다. 처음 공부하시는 분들은 로봇팔이 Servo Motor의 회전각을 통해 어떻게 관절의 움직임을 만들어내는지 잘 연상이 안될 수 있습니다. 공감지각능력이 뛰어난 분들이나 관철력이 뛰어난 분들이라면 쉽게 이해할 수 있지만 약간 관절의 움직임에 대해 모르더라도 어려워 하지 마세요.

관절의 움직임을 이해하는데 좌표계를 머리속에 담아 놓으시면 쉽게 관절의 움직임을 이해 할 수 있습니다. 어떤 사물의 움직임을 표현한다면 그 움직임은 모두 좌표계에 배치되고 그 좌표계를 기준으로 회전한다고 머리속에 그려놓고 이해하시면 쉽게 이해 할 수 있습니다.

1. 관절



위 그림처럼 관절의 역활을 Servo Motor가 역할을 수행합니다. Servo Motor가 회전을 하게 되면 어떻게 될까요. 긴 막대기가 Servo Motor와 위치한 방향에서 그냥 원을 그리면 회전을 하게 됩니다. 이 회전이 관절형 로봇의 움직임을 만들어 낸다는 것이 잘 연상이 안되실거에요.

지난 시간에 6족 보행로봇에 대해 관찰 post를 썼는데 그때 다리 하나의 관절 제어를 다시 복습해 볼까요.


위 그림에서 각 관절 A, B, C를 방금 위에 Servo Motor와 합쳐진 원통막대 하나를 3개로 서로 연결되었을 때 다리 하나의 움직임을 만들어 냈습니다. 그림을 보면 A관절은 변화가 없고 B, C관절이 일정 각도로 위로 회전되었을 때 3관절의 다리가 그림처럼 움직임을 만들어 냈습니다.

다른 그림을 살펴볼까요.


손을 주먹형태로 쥐었을 때 손가락 하나의 움직임을 위 그림과 같은 모향을 만들어 냅니다. 주먹을 쥔 모양이니 위 그림에서 관절이 3개로 나뉘고 90도씩 회전했을 때 주먹이 쥐어지는 모습이 만들어 냅니다.

위 두 그림에서 관찰이 뛰어나신 분이라면 움직임을 이해 하셨을 꺼에요. Servo Motor의 회전과 위 그림에서의 원통막대기가 그 회전각만큼 움직였을 때 만들어내는 움직임을 머리속에서 그려 낼 수 있으면 관절 동작을 이해 할 수 있습니다.

혹시 이해가 안되신다면 이글을 보시는 여러분들이 직접 자신의 손을 주먹형태로 쥐어 보시고 관절이 Servo Motor라고 생각하시고 회전각도를 살펴보시기 바랍니다. 이해가 안될때는 실제 현실에서 그 움직임을 만들어 관찰하시면 됩니다.

그런데 복잡한 움직임을 만들기 위해 각 관절을 회전시킨다면 각 관절의 회전각을 쉽게 머리속에서 연상하기 어렵습니다. 즉, 손을 웨이브를 타는 동작으로 움직여 보세요. 아니면 직접 춤을 제자리에서 춰보세요. 그 때 손, 팔, 몸통, 다리 등 등의 각 관절에 기하학적인 움직임으로 춤을 출 때 각 춤의 동작에서 관절의 회전각을 머리속에 그리려고 할 때 쉽게 연상이 되 않습니다. 어떻게 하면 관절의 움직을 머리속에서 그려낼 수 있을까요. 바로 관절을 좌표계를 기준으로 관절의 움직임을 이해하시면 좀 더 쉽게 머리속에서 연상하실 수 있습니다. 그 방법에 대해 설명하겠습니다.

2. 좌표계


제가 처음 좌표계를 접했을 때가 컴퓨터그래픽스 과목을 배울 때였습니다. 그 때 OpenGl로 교수님이 컴퓨터라는 가상공간에 점을 찍고 선을 그리고 면을 만들고 3D 도형을 좌표계를 기준으로 그리는 방법을 배웠는데 이때부터 좌표계를 머리속에 담아두게 되었습니다. 의자를 컴퓨터 그래픽스로 표현할 때 현실에서의 의자를 좌표계를 기준으로 머리속에 현실 의자를 배치 할 수 있게 되니깐 의자의 모양을 좌표계 기준으로 그릴 수 있게 되었고 그 좌표계 기준으로 그려지 모양을 이동/회전을 통해 움직임을 만들어 낼 수 있게 되었습니다. 그 때 로봇손을 컴퓨터그래픽스로 그리게 되었고 호기심으로 로봇 손가락을 각 마디를 좌표계를 기준으로 그리게 되었는데 그 좌표계를 회전 시키니 그 좌표계을 기준으로 그려진 손가락 마디가 회전되는 것을 우연히 알게 되었습니다. 첨에는 잘 몰랐는데 그게 관절 제어를 한 것이였죠. 사실 교수님께서 가르쳐준것은 그냥 좌표계이 물체를 그리는 작업과 물체를 이동시키는 방법에 대해서만 설명을 했는데 로봇손을 OpenGl로 표현하고 손가락의 각 마디를 회전시킴으로 주먹을 쥐었다 펴는 동작을 만들게 되었는데 그 걸 보시고 교수님이 칭찬을 해 주신 기억이 나네요. 대단한 것은 아니였지만 각 마디 마다 개별 좌표계로 손가닥 마디마다 회전을 시켰는데 그게 나중에 관절 제어였다는 것을 알게 되었습니다.

관절제어는 좌표계를 머리속에 그릴 수 있으면 쉽게 제어를 할 수 있습니다. 그 방법을 설명하기 전에 우선 좌표계에 물체를 그려 낼 수 있어야 합니다.


좌표계는 x,y,z 3축으로 구성되어 있습니다. 모든 사물을 이 좌표계에 올려놓을 수 있습니다. 사각형을 올려 놓아 볼까요.


위 그림의 Box를 좌표계에 그려 보세요. 머리속에서 길이가 1인 Box를 좌표계에 그릴 수 있게 된다면 좌표계가 여러분의 머리속에 들어 있게 됩니다.

Box를 그릴 수 있게 된다면 의자를 그려보세요.


단, 그릴 때 각 부위 별로 개별 좌표계로 그려보세요.


위 좌표계로 다리와 앉는 부위를 좌표게로 그리게 됩니다. 그리고 다리 부위는 OpenGl에서 복사해서 4개의 다리를 만드는데 각 다리는 개별 좌표계가 기준이 됩니다.

이 때 전체 좌표계를 기준으로 방금 만든 다리와 앉는 부위를 배치하면 아래와 같이 완성이 됩니다.


여기서 각 다리는 개별 좌표계(0,0,0)을 기준을 4개의 다리와 앉는 부위가 그려지고 전체 좌표계에서 방금 그림 부위를 배치하면 위와 같은 의자가 완성이 됩니다.

물체를 좌표계 기준으로 그리고 그 물체를 또 다른 좌표계를 기준으로 배치하여 의자와 같은 특정 물체를 만드는 방법을 좌표계를 기준으로 머리속에서 그려 보세요. 이게 어느정도 머리속에서 완성이 되면 관절 제어에 대해 알아 봅시다.

관절 제어를 좌표계 기준으로 회전


위 그림처럼 원통 막대가 하나가 있다고 가정하고 좌표계 기준으로 그려 봅시다. 이걸 x축을 기준으로 회전 시키면 어떻게 될까요.


이처럼 좌표계에서 x축 기준으로 회전을 하게 됩니다. 다른 축으로 회전을 시킨다면 현실에서 여러분 주변있는 펜같은 것을 가지고 각 축별 회전을 시켜 보세요. 좌표계를 기준으로 물체의 회전을 이해 하실 수 있습니다.

다음으로 넘어가겠습니다.

좌표계의 부모-자식 관계 회전


A관절 좌표계는 부모 좌표계이고 B관절 좌표계는 A의 자식 관계입니다. A좌표계를 기준으로 회전하면 B 관절은 같이 따라서 회전하게 됩니다. 다음 B관절 좌표계를 기준으로 보면 C관절은 B관절의 자식 관계입니다 B관절을 회전하게 되면 C관절은 따라서 같이 회전을 하게 됩니다. C관절 회전에 경우는 A, B관절을 회전하지 않습니다. 즉, 부모 좌표계가 회전하면 자식좌표계는 따라서 같이 회전을 하고 자식 좌표계가 회전하면 부모 좌표계는 회전하지 않습니다. 이 개념을 머리속에 담아 주세요.

이제 3개의 원통을 하나의 좌표계를 기준으로 배치해서 좌표계로 살펴 봅시다.


위 그림처럼 개별적인 3개의 좌표계를 가지고 있습니다. 하지만 각 좌표계는 부모-자식 관계로 좌표계의 영역에 묶여 있는데 각 좌표계의 회전을 할 때 다른 좌표계도 영향은 부모-자식 관계로 영향을 받습니다.

정리하면,

  • 왼쪽 A좌표계를 회전하면 B,C좌표계가 같이 회전한다.
  • 가운데 B좌표계가 회전하면 A좌표계는 현재 상태를 그냥 유지하고 C좌표계가 회전합니다.
  • 오른쪽 C좌표계가 회전하면 A, B좌표계는 현재 상태를 그냥 유지한다.

각 물체를 좌표계에 올려놓고 각 좌표계는 부모-자식관계로 정의해놓고 좌표계를 회전하면 각 물체의 움직임을 만들어 낼 수 있게 됩니다.

좌표계로 물체를 배치할 수도 회전시킬 수도 있습니다.

이런 좌표계를 머리속에 담아 놓으셔야 합니다. 현재 여러분이 이 글을 보고 있는 전자기기가 스마트폰이면 스마트폰을 좌표계에 올려놓고 회전시켜보세요. 좌표계 기준으로 움직이는 각도가 몇도인지 계산해 보세요. 이 각도값을 좌표계 기준으로 몇도인지 알게 된다면 아두이노 관절 로봇의 관절 제어 코딩이 쉬워집니다.

좌표계의 회전각을 코딩화

A관절을 x축으로 45도 회전시킨다면.

Servo.write(45);

여기서 B, C관절은 현재 각도에서 A관절이 45도 회전된 각도의 위치로 움직이게 됩니다. 이게 머리속 좌표계에서 그려져야 합니다.

그래야 관절제어를 쉽게 할 수 있습니다.

정리하면,

  • 좌표계 기준으로 마디를 배치하고 각 마디는 개별 좌표계를 갖는다.
  • 좌표계 기준으로 각 마디의 부모-자식관계 구조로 되어 있다.
  • 좌표계 기준으로 마디의 회전각도를 계산한다.
  • 좌표계는 관절이고 그 회전각은 실제 Servo Motor의 회전 값이 된다.

마무리


관절제어는 좌표계를 기준으로 회전 하고 각 관절은 개별적 좌표계를 가지고 각 좌표계는 부모-자식 관계의 구조로 좌표계가 묶여 있습니다. 좌표계를 관절로 생각해서 물체를 회전 시키면 물체의 움직임을 만들어 낼 수 있습니다. 그리고 좌표계를 기준으로 바라보면 쉽게 그 움직임을 수치화 할 수 있습니다. 좌표계를 기준으로 특정 축을 기준으로 회전 된 각도는 Servo Motor의 회전각이 되어 관절의 움직임을 만들어 내게 됩니다.

그래서 관절제어를 할 때 좌표계를 머리속에 담아놓고 관절 제어를 하면 여러가지의 움직임을 어렵지 않게 만들어 낼 수 있습니다. 지난 시간에 가상시뮬레이터에서 Servo Motor 세개를 나란히 배치하고 이게 6족 보행로봇의 다리이고 전진/후진 동작이라고 했는데 사실 잘 연상이 안되셨을 꺼에요. 만약 그 Servo Motor가 여러분의 머리 속 좌표계에 배치되어 진다면 가상시뮬레이터에서 단순히 일렬로 3개의 Servo Motor가 회전 되었지만 머리 속 좌표계에서 이 회전이 실제 6족 보행 로봇의 다리 움직임으로 그려지게 될 것입니다.

댓글()

[아두이노] 아두이노 관련 자료 관찰 후 원리 실험

IOT/아두이노|2019. 9. 2. 09:00

[아두이노] 아두이노 관련 자료 관찰 후 원리 실험



핀터레스트에서 6족 보행로봇에 관련 이미지들을 한번 검색 중 가장 맘에 드는 ICStation 팀의 Hexapod4 Spider Robot 작품 post안에 Youtube 영상만 보고 움직임을 관찰하고 제 나름대로 한번 재해석 하는 시간을 지난 시간에 가졌었습니다. 마지막에 원리에 대한 실험에 대해 간단히 언급만 하고 끝냈는데 뭔가 좀 아쉬워서 가상시뮬레이터에서 동작 회전 원리에 대해 간단히 테스트 해볼 수 있는 방법에 대해 설명을 할까 합니다. 아주 간단한 한 동작만 실험해 봤네요.


위 그림처럼 6족 보행로봇에서 다리 하나만 간단히 회전을 시켜 동작 원리를 이해하는 시간을 갖도록 하겠습니다.

1. 검색 후 찾은 6족 보행로봇의 다리 한부분




위 그림에서 관절을 어떻게 회전 시켜야지 전진과 후진을 만들 수 있을까요. 위 출처에 가셔서 Youtube 동영상을 보고 오세요. 이걸 제작한 팀이 만든 영상물이 있는데 보행 움직임을 관찰하기 좋은 예제입니다.

ICStation 팀의 Hexapod4 Spider Robot 작품의 동영상을 보고 동작 코딩을 상항하시면 됩니다.

1) 전진



지난시간의 이미지 입니다.


여기서, 각 관절을 어떻게 회전해야지 위 그림처럼 전진 동작을 할 수 있을까요.


  • 1단계 : 초기다리 상태
  • 2단계 : 다리 전진하기 전 B, C관절 45도 위로 회전(다리 들어올리는 동작)
  • 3단계 : A관절을 수평 45도 앞으로 회전(다리의 진행방향)
  • 4단계 : 다리가 전진 상태가 되었을 때 B, C 관절을 45도 아래로 회전(다리를 내리는 동작)
  • 5단계 : A관절을 수평 45도 뒤로 회전(다리가 지탱하기 때문에 몸체가 앞으로 전진하게 됨)

Youtube 속 6족 보행로봇의 다리 움직임을 보면 대충 전진 동작 패턴이 위의 과정으로 진행되는 것 같더군요.

2) 전진 코딩


사실 전진 패턴을 만들면 패턴 변수를 만들어서 담아 놓으면 그 패턴변수값으로 컨트롤 하면 됩니다. 하지만 여러 관절의 패턴 동작을 일일히 만드는 과정은 시간이 좀 걸리고 오늘은 동작 회전에 대한 부분만 간단히 설명하기 때문에 패턴변수를 만들지 않겠습니다. 사실 패턴변수를 만들면 각 동작에 대한 Servo모터의 회전 딜레이 값을 따로 패턴변수로 만들어야 하는데 이 딜레이값은 실제로 Servo모터를 회전시키면서 보정해야 하는 작업이라서 가상으로는 짐작 코딩뿐이 할 수 없기 때문에 복잡한 패턴변수를 만드는 작업은 생략하고 단순하게 전진 동작 패턴에 대해 각 단계 별 동작 명령을 단순하게 코딩으로 전개 할 예정입니다.

원리 코딩이니깐 감안하고 머리속에서 상상하시면서 보시기 바랍니다. 실제는 다르게 동작할 수 있고 이 post는 의미 전달 post입니다.


위 그림의 좌표계를 이해하셔야 합니다. 각 관절의 좌표계를 기준으로 회전값을 줄 예정입니다.

[초기화] 1단계 상태입니다.

  for(int i=0;i<3;i++){
    servo[i].attach(servoPin[i]);  
    servo[i].write(90);
    
  }
  delay(1000);

Servo모터가 전부 90도로 회전 되었을 때 1단계 다리 모양이 만들어 진다고 가정하겠습니다.

[전진]

  servo[1].write(135);  //B관절 다리 올리기
  servo[2].write(135);  //C관절 다리 올리기   
  delay(500);
  servo[0].write(45);  //A관절 전진
  delay(500);
  servo[1].write(90);  //B관절 다리 내리기    
  servo[2].write(90);  //C관절 다리 내리기
  delay(500);
    
  //마지막 몸체이동
  servo[0].write(90);  //A관절 몸체 이동
  delay(1000);

패턴변수로 만들어서 했다면 위 코딩이 좀 복잡하게 설명 되었을 꺼에요. 대충 동작 회전 의미는 이해하셨죠. 실제 이 코딩으로 6족 보행로봇을 정상적으로 움직일 수 없습니다. 다리 하나의 관절에 대한 원리의 의미 동작을 코딩화 실험한 것일 뿐입니다.

실제로 전진하기 위해서는


위 그림에서 1, 4번 다리가 동시에 앞으로 전진 한 후 다음 2,5번 전진하고 마지막으로 3,6번이 전진 한 후에 마지막 몸체이동을 시키면 6족 보행로봇이 전진 시켜야 됩니다.. 사실 위 코딩은 원리를 이해하기 위한 코딩일 뿐 실제로는 다른 결과를 얻을 수 있기 때문에 더이상 깊게 코딩하지 않겠습니다.

위 코딩이 전진이 된다면 후진은 어떻게 해야 할까요. 반대로 코딩하면 됩니다.

[후진]

  servo[1].write(135);     
  servo[2].write(135);     
  delay(500);
  servo[0].write(135);  
  delay(500);
  servo[1].write(90);     
  servo[2].write(90);  
  delay(500);
    
  //마지막 몸체이동
  servo[0].write(90);  
  delay(1000);

원리는 간단하죠.

그러면 좌/후 회전은 어떻게 할까요. 앞명 다리와 후면 다리를 기준으로 다리의 각도를 만들어서 움직여야 하는데 약간 전진/후진과는 좀 더 다리의 회전 컨트롤이 복잡하지만 한번 상상력을 동원해서 동작 회전을 만들어 보셨으면 합니다.

2. 가상시뮬레이터 동작 실험


1) 회로도


  • 준비물 : Servo모터 3개, 아두이노우노, 외부전원
  • 내용 : 2,3,4번 핀을 Servo모터에 연결한다.


2) 코딩


#include <Servo.h>

Servo servo[3];
const byte servoPin[3] = {2,3,4}; //Servo Motor Pin

void setup()
{ 
  for(int i=0;i<3;i++){
    servo[i].attach(servoPin[i]);  
    servo[i].write(90);    
  }
  delay(1000);
}

void loop()
{
  //전진
  servo[1].write(135);     
  servo[2].write(135);     
  delay(500);
  servo[0].write(45);  
  delay(500);
  servo[1].write(90);     
  servo[2].write(90);  
  delay(500);
  servo[0].write(90);  
  delay(1000);
  
  //후진
  servo[1].write(135);     
  servo[2].write(135);     
  delay(500);
  servo[0].write(135);  
  delay(500);
  servo[1].write(90);     
  servo[2].write(90);  
  delay(500);
  servo[0].write(90);  
  delay(1000);  
}

3) 결과


아래 움짤을 보면 2번핀에 연결된 Servo모터는 A관절로 오른쪽으로 이동하면 전진이고 왼쪽으로 이동하면 후진이라고 상상을 해주세요. 그리고 3,4번 핀은 B, C 관절은 다리를 올리는 회전과 내리는 회전을 한다고 상상을 해주세요. 그러면 A관절로 전진/후진 하기전에 B, C 관절이 다리를 올리는 회전을 하고 A관절이 전진/후진 회전을 한 후 B, C 관절이 다리를 내리는 회전을 한다고 머리속에서 그려가면서 상상하시면 되겠습니다.


혹시 제작을 해보시겠다면 다음과 같은 준비물이 필요합니다.

  • Servo Motor - 16개
  • 16채널12비트 PWM/서보모터쉴드(I2C interface)
  • 아두이노우노
  • 외부전원장치

마무리


오늘은 특정 이미지나 영상을 보고 관찰했을 때 그 관찰을 토대로 가상시뮬레이터로 동작 원리를 실험하는 코딩을 해보았습니다. 하지만 위 코딩은 상상속에서 간단히 테스트 할거라 실제로 위 코딩이 정상적으로 보행을 만들어 낼지는 미지수입니다. 단지 동작 원리를 이해하기 위한 가상시뮬레이터에서 유사 실험으로 간단히 테스트를 한 것 뿐입니다. 가상시뮬에터에서 특정 대상을 관찰하고 얻는 원리를 이렇게 실험 할 수 있다는 것을 보여드리는게 오늘 목적이였네요.

마지막으로, 하나의 움직을 회전으로 가상시뮬레이터에서 실험 했는데 현실에서는 정상적으로 보행이 만들어지지 않을 것 같은 찜찜함이 남는 post네요.

댓글()

[아두이노] 핀터레스트에서 찾은 자료 관찰

IOT/아두이노|2019. 8. 30. 09:00

[아두이노] 핀터레스트에서 찾은 자료 관찰



핀터레스트에서 6족 보행로봇에 관련 이미지들을 한번 검색을 하였습니다. 그중에서 가장 맘에 드는 ICStation 팀의 Hexapod4 Spider Robot 작품 post를 발견했는데 자세한 내용은 보지 않고 그안에 Youtube 영상만 보고 움직임을 관찰하고 제 나름대로 한번 재해석 하는 시간을 가졌습니다. 해당 post의 글을 읽게 되면 상상력이 이 post를 쓰신 저자의 생각에 묶일 것 같아서 최대한 제 나름대로 해석하고 원리를 이해해 보고자 했네요.


오늘 post의 핵심은 아두이노 관련 자료를 핀터레스트에서 찾고 그 찾은 post를 보면서 관찰을 통해 원리를 이해하고 그걸 자신의 것으로 만드는 과정입니다.

1. 핀터레스트에서 찾은 6족 보행로봇



위 출처에 가시면 ICStation 팀의 Hexapod4 Spider Robot 작품이 나와 있습니다. 메인 사진을 보시면 다음과 같은데 Servo모터의 관절을 관찰해 봅시다.


출처 : ICStation 팀의 Hexapod4 Spider Robot 이미지

이걸 좀 더 보기 편하게 그려봤네요.


사진과 그림을 그리고 나니 대충 동작 제어가 어느정도 가늠이 되더군요. 그렇다면 ICStation 팀의 Hexapod4 Spider Robot 이 과연 어떻게 움직이게 했을지 궁금해지더군요. 다행히 Youtube로 6족 보행로봇의 움직이는 영상이 담겨져 있었네요.

관절의 움직임을 집중적으로 관찰했네요.

2. 6족 보행로봇 관절 동작 관찰


1) A관절 동작



위 그림에서 관절 A지점의 Servo모터가 수평으로 좌/우 움직이는 동작을 수행하더군요. 위 그림은 전진했을 때 각 관절이 앞쪽으로 45도 방향으로 움직인 상태이고 여기서 다시 몸체만 반대 방향으로 회전시키면 다리는 몸체를 지탱하는 중심축이 되고 몸체가 앞으로 전진하게 되고 다시 위 그림처럼 다리를 움직이고 45도 각도가 되면 몸체를 반대방향으로 회전시키면 몸체가 또 앞으로 전진하고 이런식으로 다리가 먼저 45도 앞으로 전진하고 몸체가 뒤 따라오는 식으로 영상을 보시면 A관절 움직임을 알 수 있을거에요. A관절은 수평으로 몸체을 움직이는 핵심이 됩니다.

2) B관절 동작



B관절은 다리를 들어올리는 동작을 담당하네요. 수직으로 위아래로 움직이면 진행 방향으로 다리를 움직이기 전에 다리를 올려서 해당 다리가 몸체를 지탱하는 중심축을 해제시킨다고 생각하시면 됩니다. 그리고 움직이기 편하게 다리가 올라간 상태를 만듭니다. 그리고 A관절의 회전시킨 방향이 진로 방향이 되고 그 방향에서 다시 B관절이 아래로 움직이고 해당 다리가 6족 보행로봇 몸체를 지탱하는 중심축으로 되돌아가게 됩니다. 다시 설명하면은 6개의 다리가 몸체를 지탱하는 중심축이 되는데 여기서 일부 다리는 중심축을 해제시키고 보행 방향으로 움직이고 다시 몸체를 지탱하는 중식축으로 돌아가는 동작 과정을 거치면서 보행하기 위한 움직임을 만들어 냅니다.

3) C관절 동작



B관절과 함꼐 몸체를 지탱하는 실제 중심다리입니다. 위 그림처럼 지면과 배치된다고 상상해보면 지면과의 몸체의 높이가 달라지고 딱딱한 움직임보다 좀 더 자연스럽게 움직이는 곤충과 유사한 움직임을 만들 어 낼 수 있는 다리 인 것 같아 보입니다. C관절이 없이 A, B관절이 움직인다고 상상을 해보세요. 뭔가 딱딱한 움직임이 연상 되실 꺼에요. 좀 더 자연스러운 움직임을 만들어내기 위해 C관절까지 표현한 것 같습니다. 보행 방향으로 움직이기 전 B관절을 들어올릴 때 C관절도 같이 들어올려서 움직임을 부드럽게 만들었네요. 그리고 지면과의 접촉에서도 C관절의 용도는 많아 보입니다. 제가 실제로 만들어 보지 못하고 잠깐 어제 우연히 검색해서 찾은 post라서 6족 보행로못에 대해 정확한 이야기를 할 수 없기 때문에 좀 설명이 애매하네요. 하지만 곤충과 흡사하게 다리의 움직임을 C관절을 통해서 좀 더 부드럽게 움직여진다는 것은 영상을 통해 알 수 있었습니다. 움직임의 패턴이 AxBxC 의 가지수로 많기 때문에 다른 6족 보행로봇보다는 꽤 흥미를 끄는 보행로봇 같아 보였습니다.

3. 전진 동작 관찰


동영상에 여러 동작 중 전진 동작을 한번 관찰해 봅시다.


위 그림에서 이미지 A가 초기 상태이고 위에서 관절 움직임을 정면 방향으로 전진 할 경우 이미지 B의 형태로 다리 관절이 전부 이동하게 됩니다. 그 때 몸체는 이미지 C처럼 관절을 움직이면 몸체는 앞으로 이동하게 됩니다. 이때 다리가 몸체를 지탱을 확실히 해야지 몸체가 앞으로 전진하겠죠. 순서는 A->B->C->B->C ... 이렇게 움직임으로서 앞으로 전진하는 것 같더군요.

4. 보행 동작 실험


가상시뮬레이터에서 실험을 한다면 Servo모터 3개를 이용하여 다리 하나의 관절 제어 코딩을 설계하시면 됩니다. 즉, 6개의 다리를 제어가 아닌 딱 하나의 다리만 제대로 보행동작 패턴 회전을 만들어 원리를 이해 하고 다리 1개를 동작 할 수 있게 된다면 똑같은 원리로 6개의 다리를 제어하면 됩니다.

아무튼 아래와 같이 가상시뮬레이터에서 3개의 Servo모터의 회전 패턴을 만들면 됩니다.


대충 이렇게 3개를 가상시뮬레이터서 준비하고 나머지 관찰한 관절 움직임을 코딩하면 됩니다. 관절 다리의 움직임은 이 세개의 Servo모터 회전을 순차적 회전 패턴을 만들어서 전진 보행을 만들어 내면 됩니다.

마지막으로, 제가 post하는 순서를 잘 읽어주시기 바랍니다. 특정 검색된 post의 이미지에서 어떻게 관찰을 했는지 그 관찰을 제가 어떻게 접근했는지를 보시고 다른 post에 대해 탐구하실 때 써먹으시면 합니다. 오늘 post의 관찰 핵심은 관절 다리 한개의 3개의 Servo모터 제어입니다. 이 3개의 Servo모터를 어떤식으로 패턴 회전을 시키느냐에 따라 6족 보행로봇이 움직이게 됩니다. 여러분들이 3개의 Servo모터를 회전 시킬 수 있으면 충분히 6족 보행로봇을 움직이게 할 수 있을거라 생각됩니다.

마무리


오늘 post는 아두이노와 관련 된 작품 하나를 관찰하는 과정을 간단히 이야기를 했네요. 참고로 실제로 제작을 한다면 다음과 같은 준비물이 필요합니다. 6족 보행 로봇은 총 18의 Servo모터를 필요 합니다. Servo모터를 많이 사용하기 때문에 그냥 아두이노로 제어 할 수 없습니다. Servo Motor Controller Driver가 필요 합니다. 다수의 Servo모터를 제어할 수 있습니다. 그리고 6족 보행로봇 뼈대, 아두이노, 외부전원 공급장치가 있으면 6족 보행로봇을 만들 수 있겠죠.

댓글()

[아두이노] 핀터레스트에서 아두이노 검색

IOT/아두이노|2019. 8. 29. 09:00

[아두이노] 핀터레스트에서 아두이노 검색



우연히 발견한 핀터레스트라는 사이트를 소개 합니다. 꽤 재밌는 사이트이더군요. 관심있는 주제로 검색을 하면 관련 이미지들을 모아 정리해서 보여주는데 자료 수집용으로 괜찮은 사이트 같아 보였습니다. 핀터레스트는 이용자들이 관련 이미지들을 스크랩하고 그 정보를 다른 사람들과 공유하는 소셜 네트워크 서비스를 제공한다고 하네요. 여기서 재밌는 것은 관련 검색어로 찾은 이미지를 클릭하면 해당 이미지의 post로 넘어 가기 전 해당 이미지와 유사한 다른 이미지들이 검색이 됩니다. 그리고 선택한 이미지를 보면 하단에 저정한 이용자 아디가 있는데 그 아디를 클릭하면 해당 블로그로 가고 그 블로그 안에 또다른 이미지 정보들을 확인 할 수 있어 이용자들 간의 수집 된 정보를 공유되고 있네요. 정보 공유 방식이 효율적이여서 원하는 정보를 수집할 때 유용할 것 같아서 소개합니다.

참고로, 아두이노 뿐만 아니라 다양한 주제의 post들을 공유되고 있는데 관련 단어로 검색을 하면 비슷한 개념의 이미지들을 검색이 되기 때문에 아두이노에 관심 있는 분들이나 다른 주제에 관심있는 분들도 사용하기에 괜찮은 사이트 같더군요. 특정 단어에 대한 관련 이미지들이 검색되는데 관련 이미지의 정확도가 높아서 유용한 사이트인 것 같네요.

1) 핀터레스트에서 아두이노 검색


아두이노 관련 이미지들이 수집 되어 아래 사진처럼 보여줍니다. 약간 포괄적인 검색이 되는데 사진들을 보면 아두이노의 상상력을 자극하는 이미지로 가득하네요.


위와 같이 아두이노를 검색하면 1차 검색으로 아두이노로 표현한 수많은 작품들이 포괄적으로 검색됩니다. 그런데 위에서 아무 이미지나 클릭해보시면 바로 해당 이미지의 post로 가는게 아니라 해당 이미지와 같은 주제로 2차 검색이 이러우 집니다.

그러면, 어떻게 2차 검색이 이루어지는 볼까요.

2) 특정 이미지 검색


아두이노 검색에서 6족 보행로봇 이미지가 마음에 들어서 한번 클릭 해봤네요. 그랬더니 아래 사진과 같이 6족 보행로봇과 비슷한 개념의 이미지들이 가득하네요.


즉, 아두이노->6족 보행로봇에 대한 관련 이미지들이 검색이 되었네요. 여기서 처음 클릭은 6족 보행로봇 이미지에서 다시 클릭하면 해당 6족 보행로봇 post로 최종적으로 넘어가서 정보를 확인 할 수 있게 되는 구조네요.

참고로 특정 이미지 클릭하여 위와 같은 이미지 창이 뜨면 하단에 이용자 아디가 표시 됩니다. 그 아디를 클릭하면 또 다른 공유 자료를 확인 할 수 있습니다.

한번 클릭해 봅시다.

3) 해당 이미지 저장한 이용자 클릭



위 사진처럼 이용자 아디를 클릭하면 해당 블로그로 넘어갑니다.


들어가보니 원하는 결과가 아니였지만 이렇게 이용자들 간의 정보를 공유가 이루어지네요.

이렇게 원하는 이미지를 클릭하고 그 이미지를 공유한 이용자 블로그에 들어가면 그 이미지를 수집한 이용자가 그 이미지와 관련 된 다른 수집 이미지를 검색 할 수 있다는 장점을 있네요. 즉, 누군가 특정 주제에 대해 자료를 수집하고 그 수집한 자료를 자신의 블로그에 정리되어 공유 되어 있다면 우리는 그 자료를 수집하는 시간을 절약 할 수 있습니다.

이제 이미지가 담겨져 있는 post가 대체 어떤 내용이 있는지 한번 살펴봅시다.

4) 특정 이미지 클릭


특정 이미지를 클릭하면 해당 post로 넘어 갑니다. 기대했던 정보는 아니지만 아래 사진처럼 정보를 얻을 수 있네요.


이렇게 원하는 정보를 수집할 수 있고 자신의 블로그에 스크랩하여 공유할 수 있어서 꽤 유용한 사이트 같네요.

마무리


우선 핀터레스트 사이트 자체가 최종 post까지 가지 않더라도 아두이노 관련 검색어로 검색 된 이미지만 보셔도 됩니다. 아두이노의 경우 상상력을 자극하는 이미지들이 많기 때문에 아두이노 공부하시는 분들에게 도움이 될 듯 싶네요.

댓글()

[아두이노] 아두이노 bit 계산

IOT/아두이노|2019. 8. 28. 09:00

[아두이노] 아두이노 bit 계산



지난시간에 int형을 byte로 쪼개고 다시 쪼개진 byte를 int형으로 합치는 코딩을 간단히 이야기 한 적이 있습니다.

  int x = 0B0000000100000001;//257
  
  //쪼개기
  byte a = x>>8;
  byte b = x;
    
  //합치기
  int c = (a<<8)|b;
  
  Serial.println(a);
  Serial.println(b);
  Serial.println(c);

[결과]

1 <=a
1 <=b
257 <=c

아두이노는 int형이 2byte형으로 구성되어 있으며 쪼개기/합치기 코딩을 하면 결과는 위와 같이 결과로 출력됩니다. 여기서 좀 더 깊게 자료형 변수의 값을 byte 단위로 쪼개지는 것에서 더 나아가 쪼개진 byte를 bit로 접근해보고 싶어지더군요. 그래서, 아두이노 홈페이지에 레퍼런스를 살펴보니 bit 관련 함수들이 제공되어서 bit 계산 함수를 정리하는 시간을 가져보고 싶어서 post를 쓰게 되었네요.

bit 관련 함수에 대해서 본격적으로 살펴 봅시다.

1. bit 함수



아두이노 함수는 총 7개를 제공해줍니다. 각 함수에 대해서 살펴 봅시다.

1) bit(n) 함수 : n번째 위치의 bit 값을 출력



예) 5이면 => bit(5) =>32

이렇게 n번째 위치의 bit 값을 반환합니다.

2) bitRead(x,n) : X 데이터 값에 n번째 위치의 bit 읽기


byte x = 0B00001111;  

byte x의 값은 아래 표로 나타냅니다.


여기서 bitRead(x,n)함수를 사용하여 특정 위치의 bit를 읽어 봅시다.

byte x = 0B00001111;  

Serial.println(bitRead(x, 1));

[결과]

1 <= 1번째위치 bit값

3) bitClear(x,n) : x 데이터 값에 n번째 위치의 bit 값을 지우기


byte x = 0B00001111;  

byte x의 값은 아래 표로 나타냅니다.


bitClear(x,1);

이렇게 x값을 1번째 위치의 bit를 지우게 됩니다.


byte x = 0B00001111; // 15
Serial.println(x); 
bitClear(x,1);
Serial.println(x); 

[결과]

15 <= x
13 <=bitClear(x,1)

대충 어떤 느낌인지 아시겠지요.

4) bitSet(x,n) : x 데이터 값에 n번째를 1로 세팅


위의 bitClear(x,n)함수는 0으로 초기화 한다면 bitSet(x,n) 반대로 1로 세팅하는 함수입니다.


위 표로 보시면 값이 어떻게 변하는지 쉽게 확인이 되시죠.

byte x = 0B00001111; // 15
bitClear(x,1);
Serial.println(x); 
bitSet(x,1);
Serial.println(x); 

[결과]

15 <=x
13 <=bitClear(x,1)
15 <=bitSet(x,1)

5) highByte(y)와 lowByte(y) 함수


  • highByte(y) : y 변수값의 최상위 byte 값을 반환합니다. 하지만 큰 자료형일 경우 두번째로 작은 byte를 반환하게 됩니다.
  • lowByte(y) : y 변수값의 최하위 byte 값을 반환합니다.

한번 어떤값이 나오는지 확인 해 볼까요.

예를 들면,

  int y= 0B0000111100000111;

int형은 2byte로 구성되어 있습니다. 각각 8bit로 나누어 상위 byte와 하위 byte루 구분 할 수 있습니다. 즉, 방금 이야기 한 highByte(y)와 lowByte(y) 함수로 상위 byte와 하위 byte가 반환되는지 확인하시면 되겟죠.

  int y= 0B0000111100000111;
    
  Serial.println(highByte(y));
  Serial.println(lowByte(y));

[결과]

15 <=00001111
7  <=00000111

대충 어떤 느낌으로 반환되는지 아시겠지요.

6) bitWrite(x, n, b) : x 데이터 값에서 n번째 위치값을 b(0 or 1)로 변경


byte x = 0B00001111;  

byte x의 값을 bitWrite(x, 1, 0) 함수를 사용하면 아래 표처럼 결과를 얻게 됩니다.


  byte x = 0B00001111;  

  bitWrite(x, 1, 0); 
  Serial.println(x);

[결과]

13 <=00001101

2. 실험



1) 코딩


위에서 설명한 함수들을 순서대로 출력해 보았습니다.

void setup()
{
  Serial.begin(9600);

  byte x = 0B00001111;  
  int y = 0B0000111100000111;
  
  //x값 출력
  Serial.println(x); 
  
  //5번째 bit값 출력
  Serial.println(bit(5));
  
  //x 데이터의 1번째 bit를 출력
  Serial.println(bitRead(x, 1));
  
  //x 데이터의 1번째 bit를 0으로 초기화
  bitClear(x,1);  
  Serial.println(x);

  //x 데이터의 1번째 bit를 1로 세팅
  bitSet(x,1);  
  Serial.println(x);

  //y 데이터의 상위byte와 하위byte를 출력
  Serial.println(highByte(y));
  Serial.println(lowByte(y)); 
  
  //x 데이터 1번째 bit를 0로 변환
  bitWrite(x,1,0); 
  Serial.println(x);
}

void loop()
{

}

2) 결과


결과를 보시면 숫자만 쭉 나열 되어 있는데 위 코딩에 주석으로 단 글을 읽으면서 순서대로 어떻게 값이 바뀌는지 비교하면서 결과를 확인하시기 바랍니다.



마무리


오늘은 지난시간에 I2C 통신에서 int형 값을 byte로 쪼개고 다시 합치는 과정에서 문득 조금 더 bit단위까지 컨트롤 해보고 싶어져서 이렇게 정리를 하게 되었네요. 위 함수들은 막상 사용하려고 하면 어디에서 사용하지 잘 떠오르지 않을거에요. 그나마 위 함수중에서 가장 많이 사용했던 것은 bitRead()함수입니다. 아두이노를 할때 특정 패턴을 만들 때 0 or 1로 만드는 경우가 많고 특정 패턴을 저장한 변수의 크기를 줄이기 위해서 bit 패턴을 종종 만듭니다. 이렇게 만들어진 bit 패턴을 읽기 위해서 bitRead()함수를 자주 사용 했었습니다. 하지만 다른 함수들은 사용하는 사례가 그렇게 많지 않지만 오늘 배운 함수들 알아 두시면 나중에 도움이 될꺼에요. bit 단위로 컨트롤 할 수 있기 때문에 아두이노에서 접근하는 데이터를 가장 작은 bit 단위로 접근할 수 있고 변수 공간을 효율적으로 관리할 수 있어서 자원 낭비를 최소화 할 수 있습니다.

댓글()

[아두이노] 아두이노와 스마트폰의 만남

IOT/아두이노|2019. 8. 27. 09:00

[아두이노] 아두이노와 스마트폰의 만남



아두이노에 스마트폰을 연동하면 어떤 일이 벌어질까요. 지금까지 아두이노 실험에서는 아두이노와 스마트폰 간의 Bluetooth 통신이였습니다. 아두이노에서 측정한 센서값을 Bluetooth 통신을 통해 스마트폰에 그 결과를 출력하거나 스마트폰의 조정기 어플을 이용하여 아두이노를 컨트롤 하는 실험만 했었습니다. 단순히 아두이노와 스마트폰 사이에 무선 통신을 통해 데이터를 주고 받는 동작만이 전부였었죠. 사실 아두이노와 스마트폰의 사이에 딱 하나 Bluetooth 기능만 있는게 아닙니다. 스마트폰에 내장된 다양한 센서 부품들이 있는데 이 기능들을 잘만 아두이노와 연동하면 많은 것들을 만들어 낼 수 있습니다.

스마트폰에 내장된 고급 부품들이 많고 그 부품들의 데이터를 손쉽게 얻을 수 있습니다. 아두이노를 공부하시는 분들은 스마트폰에 내장된 부품의 기능을 사용할 때 해당 부품에 대한 오류 처리 코딩 부분을 생략 할 수 있습니다. 실제 아두이노에서 해당 부품을 구매해서 아두이노에 연결 할 경우 거기서 발생 할 수 있는 문제와 오류들을 해결하고 거기에 맞는 코딩을 수작업으로 일일히 체크하고 코딩해야 합니다. 하지만 스마트폰에 내장 되 부품을 이용하면 해당 부품의 데이터만 읽는 부분만 신경 쓰면 되기 때문에 코딩하기가 편해집니다. 참고로, 센서 읽기와 그 센서 데이터를 Bluetooth 통신을 통해 아두이노에게 명령만 내리면 되기 때문에 아두이노를 컨트롤 하기 쉽고 고퀄리티 작품을 제작하기에 효과적입니다.


스마트폰을 이용하려면 아두이노와 연동 할 스마트폰 센서는 어떻게 접근 할 수 있어야 합니다. 그 부분을 오늘 이야기 할까 합니다. 스마트폰 센서와 어플에 대해 간단히 소개하고 아두이노와 스마트폰이 연동을 하면 어떤 가능성이 있는지 살펴보도록 합시다.

1. 스마트폰 센서


스마트폰에는 어떤 센서가 내장되어 있을까요?


스마트폰에는 가속센서, 중력센서, 자이로센서, 온도센서, 압력센서, 조도센서, 근접센서, GPS센서, 지자기센서, 방향센서 ... 등이 탑재되어 있습니다. 스마트폰에 내장 된 센서들을 보면 아두이노에서 실험했던 일부 센서들이 있습니다. 그리고 특정 센서는 고가로 아두이노에서 실험을 한다면 부품 가격 때문에 저가의 부품을 사용하게 되고 그러면 만족할 만한 정확한 결과를 얻기 힘듭니다. 실험 제작 단가가 올라가겠죠.

아두이노에서 스마트폰과 연동을 하면 스마트폰에 탑재된 센서들을 다 사용할 수 있습니다. 스마트폰의 다양한 센서를 이용하여 아두이노를 동작시킬 수 있습니다.

예를 들면, 스마트폰으로 모바일 비행 시뮬레이터 게임 같은 것을 할 때 스마트폰 몸체를 좌/우 위/아래로 움직이면 모바일 게임 내 비행기 조정하는 게임을 한번 쯤 해보셨을 꺼에요. 바로 스마트폰 내에 내장된 자이로/가속 센서 값을 이용하여 조정을 하게 되는데 현실에서 이 조정값을 Bluetooth를 통해 아두이노로 보내면 그 값을 토대로 RC카 or 로보팔 같은 것을 실제 조정을 할 수 있게 됩니다.

다양한 센서를 읽을 수 있게 되면 Bluetooth를 통해 아두이노에 활용한다면 꽤 재밌는 것들을 만들 수 있겠죠.

2. 안드로이드 폰 센서 읽기



안드로이드 폰을 기준으로 이야기 하면 위 출처에 가시면 Sensor 부분을 읽으시면 됩니다.


안드로이든 폰에 내장된 센서를 어떻게 읽을 수 있는지 그 방법에 대해 자세히 나와 있습니다.

자바스크립트로 코딩부분까지 자세히 나와 있는데 어플로 센서 값을 읽고 어플 안에 Bluetooth 통신 코딩까지 합쳐진다면 이 어플을 통해서 아두이노를 제어 할 수 있게 되겠죠.

어플을 만들려면 아래 안드로이드 스튜디오와 같은 어플 개발 툴들을 사용 할 수 있어야 겠죠.



몇년 전에 봤던 강좌인데 나름 볼만 하네요. 최근판은 어떤지 모르겠네요.

직접 안드로이드 어플로 만들어 봐야 하는데 오래 전에 잠깐 재미로 봤던 거라서 다시 안드로이드 스튜디오를 사용 하려면 공부를 다시 해야하기 때문에 시간이 좀 소요되어 이 부분을 못 보여드리네요.

나중에 안드로이드 스튜디오를 다시 공부하게 된다면 한번 만들어 볼 날이 오겠죠.

스마트폰에 내장된 센서들을 사용하기 위해서는 어플 공부를 하셨으면 합니다.

스마트폰을 아두이노와 연동을 하면 뭘 할 수 있을까요?

간단히 사례와 상상을 이야기 해보겠습니다.

3. 아두이노와 스마트폰의 만남 후 가능성



위 그림을 폰드론 에토스 이미지 입니다. 보시면 아두이노 관점으로 해석하면 드론의 조정 핵심 부분을 스마트폰이 대신하게 됩니다 .스마트폰이 두뇌가 됩니다. 스마트폰에는 드론 컨트롤에 필요한 부품들이 내장되어 있기 때문에 어플로 로직만 잘 짜시면 나머지 아두이노는 폰이 명령한대로 드론모터만 제어하면 됩니다. 이렇게 스마트폰으로 드론을 컨트롤하면 다양한 것들을 할 수 있게 됩니다. 스마트폰에 카메라를 이용하여 고급 촬영이 가능하고 드론에 필요한 고급부품을 스마트폰이 대신하기 때문에 아두이노는 실질적으로 드론모터를 컨트롤하는 기능만 잘 표현하면 됩니다. 제작비를 대폭 줄이고 고급기능을 사용할 수 있게 됩니다.

미래의 전자기기는 이처럼 스마트폰과 연동한 제품들이 많이 만들어 질거라 생각됩니다.

한가지 가능성을 상상을 해보면 저번에 post한 [아두이노] 시각장애인을 위한 스마트 지팡이 원리 이해 내용에서 스마트 지팡이를 만약 스마트폰에 연동을 하게 된다면 어떤 것들을 할 수 있을까요.

위 그림처럼 스마트폰의 카메라를 이용 할 수 있게 되면 어떻게 될까요. 정면의 보행길과 사물을 인식할 수 있는 영상처리를 할 수 있겠죠. 이말은 실제 보행유도선이 깔림 보드블록이 없어도 영상으로 가상 보행유도선을 만들어 낼 수 있고 그 정보로 시각장애인을 안내할 수 있게 될거라 생각됩니다. 이걸로 자율보행스마트지팡이를 제작 하면 좋겠죠. 그리고 현재의 위치를 GPS 정보를 알 수 있는데 이 센서를 이용하여 주변의 건물이나 사물을 식별하고 그 정보를 스마트폰으로 제공받을 수도 있겠죠. 시각장애인은 이어폰으로 현재 상황 정보를 소리로 들을 수 있게 되겠죠. 간단히 상상을 해봤습니다. 아두이노 스마트지팡이에 스파트폰을 연결하면 다양한 결과물을 만들어 낼 수 있기 때문에 그 가능성은 엄청납니다.

참고로, 디지털 영상처리에 대해 관심을 가졌으면 합니다. 요즘 핫한 자율주행차에 핵심 기술입니다. 자율보행스마트지팡이로 주변 환경과 사물 인식에 대해 연구하시면 스마트지팡이에서 끝나지 않고 나중에 자율주행차에서도 그 기술을 활용할 수 있을 거라 생각됩니다. 프로그램을 배우는 학생분들은 서점에 가셔서 디지털 영상처리 책을 한번 읽어보시고 관심을 가졌으면 합니다. 저도 영상처리에 관심이 한때 많았고 3D Rendering 쪽으로 코딩 공부를 했었고 영상 인식부분은 자료가 부족하여 제대로 공부를 제대로 못해 봤습니다. 혹시 프로그램에 관심있으신 분이라면 자율주행차나 뭔가 영상인식에 관심을 가진 분들이라면 영상처리를 공부해 보셨으면 합니다. 이 기술은 나중에 아두이노와 같은 것들과 접목하면 고퀄리티 작품을 만들어 낼 수 있는 기반이 됩니다.

마무리


아두이노와 스마트폰을 연동하기 위해서는 어플을 필수로 배우셔야 합니다. 어플 공부가 쉽지는 않습니다. 코딩에 대해서 어느정도 능력이 탑재되어 있어야 합니다. 그럼에도 어플 공부를 추천하는 이유는 스마트폰의 다양한 센서 기능을 활용할 수 있고 그걸 활용하면 아두이노로 엄청난 걸 만들 수 있기 때문입니다. 뭔가 제대로 아두이노 작품을 만들어 보고 싶다면 스마트폰과의 연동에 관한 연구를 하셨으면 합니다. 그리고 영상인식에 관심이 있다면 디지털 영상처리 책을 구매하셔서 공부해보셨으면 합니다.

스마트폰을 활용하기 위해서는 스마트폰의 센서값을 읽을 수 있어야 합니다. 안드로이드폰이면 안드로이드 폰에서 센서값을 읽는 함수를 사용할 수 있어야 합니다. 읽은 센서값에 대한 동작 명령을 아두이노에 보내야 하기 때문에 Bluetooth 코딩도 알아야 합니다. 그러면 어플을 만들 수 있는 개발 툴을 사용 할 수 있어야 합니다. 앱 제작 공부를 해야 합니다. 어플을 만들 수 있는 능력이 있어야 아두이노와 스마트폰의 연동을 제대로 할 수 있게 됩니다. 스마트폰의 센서를 사용하기 위해서는 어플 공부를 해야 하는 어려움이 있지만 꼭 공부해보셨으면 해요.

어플을 공부하시면 나중에 스팀 블록체인과 관련한 어플도 제작 가능하기 때문에 꼭 이쪽 분야가 아니더라도 다른 분야에서도 많이 활용되니깐 공부해보셨으면 합니다.

댓글()

[아두이노] 아두이노 간 I2C 통신 응용

IOT/아두이노|2019. 8. 26. 09:00

[아두이노] 아두이노 간 I2C 통신 응용



지난 시간까지는 가상시뮬레이터로만 I2C 통신에 대해 실험했었는데 오늘은 몇가지 실제 부품을 가지고 아두이노 간 I2C 통신 실험을 할까 합니다. 상황 설정은 슬레이브 아두이노에 조도센서를 연결하여 조도센서 값을 측정하고 마스터 아두이노는 조도센서값을 슬레이브 아두이노에게 요청하고 응답 받은 조도센서값을 I2C 통신을 통해 16x2 LCD 모듈에 결과를 출력해보면 재밌을 것 같아서 한번 도전해봤습니다. 사실 부품이 몇개 없어서 좀 더 새로운 실험을 하고 싶었는데 있는 부품으로만 I2C 통신을 하다 보니깐 부품의 제약이 따라 기존의 실험했던 부품을 다시 사용하여 약간 복습 실험이 되고 말았네요.

이제 실험을 본격적으로 시작해 봅시다.


1. 회로도


  • 준비물 : 조도센서 1개, 저항 1k옴 1개, 16x2 LCD 모듈 1개, 뻥판, 아두이노우노, 아두이노마이크로
  • 내용 : 아두이노우노, 아두이노마이크로, 16x2 LCD SDA, SCL핀을 서로 공유한다.

아두이노우노가 2대 였다면 좋았을텐데 아두이노우노가 1대뿐이고 다행히 아두이노마이크로가 있어서 마스터/슬레이브 아두이노로 I2C 통신을 할 수 있었네요.

참고로 아두이노우노와 아두이노마이크로의 SDA, SCL핀 번호가 다릅니다.

아두이노우노 A4(SDA), A5(SCL) => 아두이노마이크로 D2(SDA), D3(SCL)

보드마다 핀번호가 다르니깐 꼭 확인하시고 연결하세요.


위 그림을 보시면 아두이노우노(마스터)와 아두이노마이크로(슬레이브)는 각각 다른 역할을 수행합니다.

  • 아두이노우노 : 16x2 LCD 모듈에 결과 출력을 담당
  • 아두이노마이크로 : 조도센서에 연결되어 조도센서값 읽기를 담당

아두이노우노는 아두이노마이크로에게 조도센서값을 요청하고 아두이노마이크로는 요청에 대해 응답하고 조도센서값을 아두이노우노에게 보내게 됩니다. 아두이노우노는 조도센서값을 읽은 후 16x2 LCD 모듈에 결과를 출력하게 됩니다.

2. 코딩



1) 마스터 아두이노 코딩


설계 :

  • 슬레이브 아두이노에게 조도센서값 요청과 수신
  • 16x2 LCD 모듈에 조도센서값 출력

슬레이브 아두이노에게 조도센서값을 요청

조도센서값은 0~1023사이의 아날로그 신호를 읽게 됩니다. 그러면 슬레이브 아두이노에서 조도센서값을 byte 단위로 보내면 총 4자리 숫자가 전송됩니다. 원래 다른방법이 있지만 왠지 4자리 숫자를 쪼개고 합치는 방식으로 처리하고 싶어지더군요.

우선, 요청을 하면 최대 4자리이기 때문에 아래와 같이 요청을 하게 했습니다.

 Wire.requestFrom(1,4); 

문제는 조도센서값이 0~1023이기 때문에 한자리~네자리로 숫자 데이터로 표현되니깐 최대 4자리 4byte형태를 유지해서 데이터를 수신하게 설정한다면 다음과 같습니다.

[합치기]

  while(Wire.available())
  {
    byte a=Wire.read(); //1의자리
    byte b=Wire.read(); //10의자리
    byte c=Wire.read(); //100의자리
    byte d=Wire.read(); //1000의자리
    m_cds = d*1000+c*100+b*10+a;     
  }

사실 int형의 데이터를 전송하고 int형이 2byte이니깐

int형 <= (앞byte<<8)|뒤byte)

예)

  int k = 1023;
  
  //쪼개기
  byte a = k>>8;
  byte b = k;
    
  //합치기
  int c = (a<<8)|b;

이렇게 하면 되겠지만 한번 색다르게 접근 했네요.

16x LCD모듈에 조도센서값을 출력

LiquidCrystal_I2C 라이브러리 함수를 이용합니다.

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2);  // 0x27 or 0x3F

출력은 슬레이브 아두이노에서 요청한 값이 m_cds변수에 저장되니깐 그 값을 lcd.print(m_cds)함수로 출력하면 됩니다.

void output(){
 lcd.print("                "); //지우기
 lcd.setCursor(0, 1); //2번째 줄의 0번째칸
 lcd.print("CDS : "); 
 lcd.setCursor(7, 1); //2번째 줄의 7번째칸
 lcd.print(m_cds);    
}

2) 슬레이브 아두이노 코딩


설계 :

  • 조도센서값 읽기
  • 마스터 아두이노 요청 시 응답처리

조도센서값 읽기

m_cds = analogRead(cdspin);

마스터 아두이노 요청 시 응답 처리

Wire.onRequest(requestEvent);

[쪼개기]

void requestEvent() {
  int val = m_cds; //조도센서값
  for(int i=0;i<4;i++){
    Wire.write(val%10);  //자리수 출력
    val=val/10;
  }  
}

3) 종합 코딩


[마스터 아두이노]

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x3F,16,2);  // 0x27 or 0x3F
int m_cds=0;
void setup()
{
  lcd.init(); //초기화
  lcd.backlight(); //배경불켜기
  lcd.setCursor(0, 0);
  lcd.print("Hello World");
  delay(1000);
  lcd.clear();  
}

void loop() {

  Wire.requestFrom(1,4); //슬레이브(1)에 4byte 요청   
  while(Wire.available())
  {
    byte a=Wire.read();
    byte b=Wire.read();
    byte c=Wire.read();
    byte d=Wire.read();
    m_cds = d*1000+c*100+b*10+a;     
  }
  output();  
  delay(500);
}

void output(){
 lcd.print("                ");
 lcd.setCursor(0, 1);
 lcd.print("CDS : ");
 lcd.setCursor(7, 1);
 lcd.print(m_cds);    
}

[슬레이브 아두이노]

#include <Wire.h>

const byte cdspin = A0;
int m_cds = 0;

void setup() {
  Wire.begin(1);
  Wire.onRequest(requestEvent);
}

void loop() {  
  m_cds = analogRead(cdspin);
  Serial.println(m_cds);   
  delay(500);   
}

void requestEvent() {
  int val = m_cds;
  for(int i=0;i<4;i++){
    Wire.write(val%10);  
    val=val/10;
  }  
}

3. 결과


영상을 보시면 좀 지져분하게 만들어 졌네요. 조도센서를 손으로 가리면 조도센서값이 작아지는데 이 조도센서값은 아두이노마이크로에서 측정이 됩니다. 그리고 아두이노우노, 아두이노마이크로, 16x2 LCD I2C 모듈은 SDA, SCL 핀은 공유되어 있고 아두이노우노에서 16x2 LCD I2C모듈을 제어합니다. 아두이노마이크로에서 조도센서측정 작업을 수행하고 아두이노우노는 조도센서값을 요청과 조도센서값을 출력 작업을 수행합니다. 그 결과가 아래 영상에서 확인 할 수 있습니다.


마무리


오늘 실험 내용은 예전 실험 했던 내용인데 하나의 아두이노우노에서 조도센서를 측정하고 16x2 LCD 모듈에 출력해도 됩니다. 이 작업을 구지 나누어 두 대의 아두이노에 역할을 분담 시켰습니다. 이렇게 I2C 통신을 이용하면 많은 부품을 아두이노 한대로 제어하는 것보다 여러대로 나누어 제어를 할 수 있습니다. 한곳에서 많은 부품을 제어하려면 각각의 부품의 소요되는 시간과 중간에 다른 동작의 개입할 때 까다로운 코딩을 설계해야 하는데 여러대로 분산 제어한다면 분산된 부품은 각각의 아두이노에서 해당 동작만 코딩하면 되기 때문에 코딩이 어느정도 쉬워질 거라 생각되네요.

조도센서로 실험했지만 여러분들은 다른 부품을 가지고 실험을 해보세요. 다양한 실험을 해야지 다양한 상상을 할 수 있으니깐요.


댓글()

[아두이노] n:m 아두이노 간 I2C 통신

IOT/아두이노|2019. 8. 23. 09:00

[아두이노] n:m 아두이노 간 I2C 통신



지난 시간에 마스터 아두이노와 슬레이브 아두이노 간 통신을 기본적으로 다뤘습니다. post를 정리하다가 문득 슬레이브 간의 I2C 통신이 하고 싶어져서 한번 도전을 해보았습니다. 지난 시간의 코딩한 방법으로 반복 코딩하면 재미가 없기 때문에 print(), println()함수를 이용하여 데이터를 전송하고 수신할 때는 문자열로 읽는 방식으로 코딩을 해봤습니다.

그러면, 어떻게 처리했는지 살펴보도록 하죠.

1. 1:1 슬레이브 아두이노 I2C 통신 회로도


준비물 : 아두이노우노 2개
내용 : 아두이노우노의 A4(SDA), A5(SCL)핀을 서로 공유한다.


가정은 마스터 아두이노는 있다고 가정한 상태에서 슬레이브 간 통신을 실험으로 각 아두이노에 주소를 부여하고 주소 간의 통신을 하는 실험으로 1:1 통신을 실험합니다.


실험은 1:1 통신이지만 연결하는 갯수에 따라서 n:m 통신이 가능합니다. post를 읽은 후 2대 이상의 아두이노를 서로 데이터를 전송해 보세요.

2. 코딩



코딩은 슬레이브 아두이노 간의 데이터 전송을을 해보도록 하죠.

슬레이브 아두이노 간 데이터 전송


설계 :

  • A 슬레이브 아두이노에서 B 슬레이브 아두이노로 데이터 전송

[데이터 전송] : print(), println()함수로 이번에 실험을 했습니다.

  Wire.beginTransmission(2);                
  Wire.println("a1/test1!");           
  Wire.endTransmission(); 

데이터 전송은 슬레이브 간 보낼 수 있다고 했죠. 그래서 기존 데이터 전송 코딩은 동일 합니다.

[문자열 데이터 수신] : 문자열로 이번에 읽는 실험을 했습니다.

void receiveEvent(int howMany) { //전송 데이터 호출시 명령
  while (Wire.available()) { 
    String inString = Wire.readStringUntil('\n'); 
    Serial.println(inString);         
  }      
}

데이터 전송과 수신은 지난 시간과 동일하게 표현하면 재미 없기 때문에 좀 색다르게 표현 했네요. 반대의 경우 방금했던 코딩을 동일하게 코딩하시면 됩니다.

슬레이브 아두이노 1,2 코딩을 해볼까요.

[슬레이브 아두이노 1]

#include <Wire.h>

void setup() {
  Wire.begin(1); //슬레이브 주소                  
  Wire.onReceive(receiveEvent); //마스터 데이터 전송시 receiveEvent함수 호출
  Serial.begin(9600); 
}

void loop() {
  Wire.beginTransmission(2);                
  Wire.println("a1/test1!");           
  Wire.endTransmission();  
  delay(200);  
}
void receiveEvent(int howMany) { //전송 데이터 호출시 명령
  while (Wire.available()) { 
    String inString = Wire.readStringUntil('\n');      
    Serial.println(inString);
  }      
}

[슬레이브 아두이노 2]

#include <Wire.h>

void setup() {
  Wire.begin(2); //슬레이브 주소                  
  Wire.onReceive(receiveEvent); //마스터 데이터 전송시 receiveEvent함수 호출
  Serial.begin(9600); 
}

void loop() {
  Wire.beginTransmission(1);                
  Wire.println("b2/test2!");           
  Wire.endTransmission();  
  delay(500);  
}

void receiveEvent(int howMany) { //전송 데이터 호출시 명령
  while (Wire.available()) { 
    String inString = Wire.readStringUntil('\n');      
    Serial.println(inString);
  }      
}

참고로 딜레이 시간이 동일하게 되면 같은 시간에 데이터를 보내고 같은 시간에 데이터를 읽게 됩니다. 그러면 좀 문제가 생기겠지요. 가상시뮬레이터에서 데이터를 정상적으로 읽지 못하더군요. 그래서 시간 차를 다르게 했습니다. 즉, 시분할 스케줄링 처리를 해줘야 할 듯 싶네요. 아니면 지난 시간에 했던 1:N 연결을 통해서 마스터 아두이노에서 컨트롤 타워 연결을 수행하여 각 슬레이 간의 데이터 통신을 제어하는 방법이 가장 쉬울 듯 싶네요.

추가로, delay()함수를 쓰기 싫으면 다음과 같이 코딩하면 됩니다.

unsigned long timeVal = 0;

void loop() {
  if(millis()-timeVal>200){
     Wire.beginTransmission(2);                
     Wire.println("a1/test1!");           
     Wire.endTransmission();  
     timeVal=millis();
  }
}

3. 결과


각 슬레이브 아두이노가 상대 슬레이브 아두이노에 데이터를 전송하고 그 결과를 문자열로 읽고 시리얼모니터로 결과를 출력합니다. 나중에 여기에 마스터 아두이노를 연결하여 마스터와 슬레이브 아두이노 간 통신을 하는 동시에 슬레이브 간의 통신을 별도로 수행할 때 오늘 배운 내용을 적용하면 되겠죠.


마무리


오늘은 print(), println()함수로 데이터를 보내봤습니다. 그리고 수신할 때는 한번에 문자열로 읽어 보았습니다. 문자열로 읽을 경우 문자열 안에 데이터를 보낸 슬레이브주소코드를 같이 넣어서 보내면 누가 어떤 데이터를 보냈는지 쉽게 확인 할 수 있습니다. 쉽게 말해서, 문자열 "식별코드주소/전송데이터" 형태로 데이터를 보내고 수신하는 아두이노는 식별코드주소와 전송데이터를 분리해 내면 다수의 아두이노를 식별하고 해당 명령을 적절하게 수행할 수 있습니다.

그리고, 식별코드주소 뿐 아니라 여기에 요청코드를 넣게 되면 요청코드를 확인 후 요청한 식별코드주소을 토대로 상대 아두이노로 응답 메시지를 보내면 쌍방 통신도 가능해 지겠죠. Wire 라이브러리 요청/응답 함수를 사용하지 않더라도 데이터 전송함수를 이용하면 그 전송 된 메시지를 가지고 응답 처리를 유사하게 표현이 가능합니다. 한번 연구해 보세요.

여러분들은 계속 I2C 통신을 이용하는데 여러대의 아두이노가 있을 때 여러가 상황을 만들고 각 상황에 대해서 어떤식으로 통신을 할 것인지 상상의 나래를 펼쳐 보셨으면 합니다.

댓글()

[아두이노] 1:N 아두이노 간 I2C 통신

IOT/아두이노|2019. 8. 22. 09:00

[아두이노] 1:N 아두이노 간 I2C 통신



지난시간에 아두이노간 I2C 통신 실험을을 하기 위해서 공유선을 A4(SDA), A5(SCL)핀에 연결하여 2대의 아두이노 간 통신을 했었습니다. 오늘은 마스터 아두이노와 2대의 슬레이브 아두이노 간의 통신을 연장해서 실험을 해보겠습니다. 지난 시간의 실험 내용에서 아두이노가 한 대 더 추가되었을 뿐 변동 사항은 거의 없습니다. 오늘 실험은 마스터 아두이노에 슬레이브 아두이노 2대를 연결하여 실험하지만 더 많은 아두이노로 통신 하시고 싶다면 2대 이상 연결하여 실험을 하셔도 됩니다. 슬레이브 아두이노의 갯수는 여러분들이 정해서 실험하시면 됩니다.

이제 1:N 아두이노들 간의 I2C 통신 실험을 해보도록 하죠.

1. 1:N 아두이노 I2C 통신 회로도


준비물 : 아두이노우노 3개
내용 : 아두이노우노의 A4(SDA), A5(SCL)핀을 서로 공유한다.



회로도의 선 연결은 지난 시간에 아두이노 간의 I2C 통신 회로도에서 아두이노 한대가 더 추가 된 회로도 입니다.

2. 코딩



사전 학습에서 사용된 코딩을 약간만 수정하시면 됩니다.

1) 마스터 아두이노 코딩


설계 :

  • 각 슬레이브 아두이노에 데이터 전송
  • 각 슬레이브 아두이노에 데이터 요청과 수신

동작은 위 2가지 형태로 실험이 이루어 집니다. 아래 그림처럼 그림A와 그림B 동작을 마스터 아두이노는 각 슬레이브 아두이노 간의 순차적으로 동작하게 됩니다.


[지난소스]

  //데이터 전송
  Wire.beginTransmission(1);                 
  Wire.write("good ");       
  Wire.write(x);             
  Wire.endTransmission();    
     
  delay(500);
    
  //데이터 요청 & 수신
  Wire.requestFrom(1, 4); //슬레이브(1)에 4byte 요청
  while (Wire.available()) {
    char c = Wire.read(); 
    Serial.print(c);        
  }  

지난시간에 슬레이브 아두이노에 특정 데이터를 전송한 뒤에 다시 데이터를 요청 했었습니다. 1대가 아니고 2대의 슬레이브 아두이노에 데이터를 전송하고 데이터를 요청하도록 수정 한다면 어떻게 해야 할까요.

동작은 설계에서 딱 두개의 동작만을 수행 합니다. 데이터를 전송하고 데이터를 요청한다. 이 두가지 동작을 2대의 슬레이브 아두이노와 통신을 해야 한다면 지난 소스을 적용한다면 2번 반복 수행해야 겠죠. 그러면, 위 코딩을 복사해서 길게 두번 코딩해야 할까요. 그럴 필요는 없습니다. for문으로 두번만 위 코딩을 반복시키면 됩니다.

각 슬레이브 주소를 1, 2번으로 지정해 주고 아래와 같이 코딩하면 됩니다.

  for(int i=1;i<3;i++){
    Wire.beginTransmission(i);                
    Wire.write("test ");       
    Wire.write(i);             
    Wire.endTransmission();    
     
    delay(500);
    Wire.requestFrom(i, 4);   
    while (Wire.available()) {
        char c = Wire.read(); 
        Serial.print(c);        
    }
  }   

간단하죠. 여기서, 아두이노가 N대를 연결한다면 for문의 i값의 N 횟수 만큼 반복되도록 숫자만 변경해주면 여러대의 슬레이브 아두이노와 통신을 할 수 있게 됩니다.

2) 슬레이브 아두이노 코딩


설계 :

  • 데이터 수신 처리
  • 데이터 요청 응답

지난 시간의 코딩과 동일합니다. 식별 번호만 바꿨네요. "ok1"으로 해당 슬레이브 아두이노의 요청 메시지만 수정했네요.

  Wire.onRequest(requestEvent); //요청시 requestEvent함수 호출
  Wire.onReceive(receiveEvent); //데이터 전송 받을 때 receiveEvent함수 호출
void receiveEvent(int howMany) { //전송 데이터 호출시 명령
  while (Wire.available()>1) { 
    char ch = Wire.read(); 
    Serial.print(ch);         
  }
  int x = Wire.read();    
  Serial.println(x);      
}
void requestEvent() { //마스터 요청 시 수행 함수
  Wire.write("ok1\n");   
}

여기서, 두 대의 슬레이브 아두이노로 실험하니깐 요청이 들어오면 "ok1", "ok2"로 메시지가 출력되게 코딩하면 됩니다.

종합해보면,

[마스터 아두이노]

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600); 
}

void loop() {  
  for(int i=1;i<3;i++){
    Wire.beginTransmission(i);                
    Wire.write("test ");       
    Wire.write(i);             
    Wire.endTransmission();    
     
    delay(500);
    Wire.requestFrom(i, 4);   
    while (Wire.available()) {
        char c = Wire.read(); 
        Serial.print(c);        
    }
  }   
}

[슬레이브 아두이노 1]

#include <Wire.h>

void setup() {
  Wire.begin(1); //슬레이브 주소                
  Wire.onRequest(requestEvent); //마스터 요청시 requestEvent함수 호출
  Wire.onReceive(receiveEvent); //마스터 데이터 전송시 receiveEvent함수 호출

  Serial.begin(9600);           
}

void loop() {
  delay(500);
}

void receiveEvent(int howMany) { //전송 데이터 호출시 명령
  while (Wire.available()>1) { 
    char ch = Wire.read(); 
    Serial.print(ch);         
  }
  int x = Wire.read();    
  Serial.println(x);      
}
void requestEvent() { //마스터 요청 시 수행 함수
  Wire.write("ok1\n"); 
  
}

[슬레이브 아두이노 2]

#include <Wire.h>

void setup() {
  Wire.begin(2);                
  Wire.onRequest(requestEvent); //마스터 요청시 requestEvent함수 호출
  Wire.onReceive(receiveEvent); //마스터 데이터 전송시 receiveEvent함수 호출
  Serial.begin(9600); 
}

void loop() {
  delay(500);
}

void receiveEvent(int howMany) { //전송 데이터 호출시 명령
  while (Wire.available()>1) { 
    char ch = Wire.read(); 
    Serial.print(ch);         
  }
  int x = Wire.read();    
  Serial.println(x);      
}
void requestEvent() { //마스터 요청 시 수행 함수
  Wire.write("ok2\n");   
}

3. 결과


위 코딩으로 1:N 아두이노 간의 I2C 통신을 할 수 있게 되었습니다. 가상시뮬레이터에서 결과가 어떻게 나오는지 영상으로 살펴보세요.


마무리


오늘은 1:1 I2C 통신하는 방식에서 1:N I2C 통신을 실험 했습니다. 오늘 내용은 지난 시간에 했던 내용을 for문 하나가 추가 되었을 뿐 따로 추가된 부분은 없습니다. 여러대를 연결하면 각 슬레이브 아두이노로 데이터를 보내고 각 슬레이브 아두이노에 데이터를 요청하면 거기에 맞게 각 슬레이브 아두이노는 데이터 수신과 데이터 요청에 대한 응답 처리 코딩만 하면 됩니다.

오늘은 그냥 복습차원으로 반복 학습 post입니다. 1:1 통신을 할 수 있으면 1:N 통신을 잘 생각하면 쉽게 떠올릴 수 있는데 혹시 1:N이 잘 연상이 안되는 분들이 있을 것 같아서 지난시간에 마무리 글로 1:N 통신으로 연장해서 상상을 해보시라고 했는데 못하시는 분들을 위해 이렇게 post로 다시 이야기를 하게 되었습니다.


댓글()

[아두이노] 아두이노 간 I2C 통신

IOT/아두이노|2019. 8. 21. 09:00

[아두이노] 아두이노 간 I2C 통신



오늘은 아두이노 간 통신을 I2C 방식을 이용하여 실험을 할까 합니다. 예전에 시리얼통신을 할 때 한꺼번에 소개 했어야 했는데 미뤄졌네요. 지난 시간에 시리얼 통신으로 다수 명령 처리 방법에 대한 post를 하다 보니 다수 아두이노 통신을 통해 명령을 처리해보고 싶어져서 다수 통신 실험을 위해 I2C 방식을 소개하면서 다뤄보고 싶어 이렇게 post를 쓰게 되었습니다. 통신에 대한 복습차원으로 좋을 것 같아서 겸사겸사 이야기를 이여 갑니다.

이제부터, I2C 방식으로 어떻게 통신이 이루어지는지 살펴 보겠습니다.

1. I2C 통신을 위한 Wire 라이브러리



위 참고 출처에 가시면 아두이노 공식 홈페이지에 Wire 라이브러리에 대해 자세히 나와 있습니다. 그리고, Master Reader/Slave Writer, Master Writer/Slave receiver 예제가 있는데 이 예제를 통해서 아두이노 간 통신을 배우시면 되겠습니다.

아두이노 간 통신을 하기 위해서 Wire 라이브러리를 이용하여 I2C 통신을 할 수 있는데 아두이노우노의 A4(SDA), A5(SCL)핀에 아두이노들 간의 공유선을 이용하여 통신이 이루어 집니다. 만약, 다른 보드를 이용할 경우 해당 보드의 SDA, SCL핀이 몇번 핀인지 확인하시고 해당핀을 공유선에 연결하시면 됩니다.

Boardpins
UnoA4 (SDA), A5 (SCL)
Mega256020 (SDA), 21 (SCL)
Leonardo, Micro2 (SDA), 3 (SCL)
Due20 (SDA), 21 (SCL), SDA1, SCL1

이제 아두이노홈페이지에 나와 있는 Master Reader/Slave Writer, Master Writer/Slave receiver 예제로 기반으로 간단히 설명을 드리겠습니다.

1) 아두이노 주소 지정


아두이노 간의 식별은 주소로 구별합니다. 주소를 지정하는 방식은 다음과 같습니다.

Master : Wire.begin()
Slave : Wire.begin(address)

위 함수를 보면 아무것도 안적혀 있으면 Master가 되고 address를 지정해 주면 그 address가 해당 아두이노의 슬레이브 주소(7bit)가 됩니다. 이렇게 주소를 지정하면 상대 아두이노에서 해당 주소을 통해서 데이터를 보낼 수 있고 받을 수 있습니다.

2) 데이터 전송


Wire.beginTransmission(1); // 슬레이브주소 1번 전송시작
Wire.write("good\n");        // 문자열 전송
Wire.endTransmission();    // 전송 중단

데이터를 보낼 때 beginTransmission(address)와 endTransmission()함수가 쌍을 이루고 write()함수로 데이터를 해당 주소지로 보내게 됩니다. write()함수가 쓰기 불편하시면 print() println()함수로 쓰셔도 됩니다. 참고로 Wire.send()함수와 같이 봐주시기 바랍니다.

3) 데이터 수신


setup()함수에 한번만 표현하고 데이터가 수신이 되면 receiveEvent 함수가 호출이 됩니다.

Wire.onReceive(receiveEvent); //데이터 수신 시  receiveEvent()함수 호출

호출된 함수 내부의 코딩은 시리얼통신 때 배웠던 코딩과 동일합니다.

void receiveEvent(int howMany) { //전송 데이터 처리 명령
  while (Wire.available()) { 
    char ch = Wire.read(); 
    Serial.print(ch);         
  }  
}

4) 요청/응답


위에서는 단순히 일방적으로 데이터를 보내고 받는 방식이라면 여기에서는 데이터를 특정 슬레이브 아두이노에게 데이터를 요청하고 해당 슬레이브 아두이노는 요청을 확인 한 후 데이터를 보내게 됩니다.

마스터 아두이노에서 요청은 다음과 같습니다.

Wire.requestFrom(1, 4); //슬레이브(1)에 6byte 요청

while (Wire.available()) { //보내온 데이터가 있을 시 데이터 읽기
  char c = Wire.read(); 
  Serial.print(c);        
}  

슬레이브 아두이노에서 응답은 다음과 같습니다.

Wire.onRequest(requestEvent); //요청할 때마다 호출

위 함수는 setup()함수에 한번만 표현하고 데이터 요청이 올 때 requestEvent()함수가 호출되게 됩니다.

호출된 함수 내부의 코딩은 간단한 메세지 전송만 보내게 표현해 보겠습니다.

void requestEvent() { //요청 시 수행 함수
  Wire.write("ok!\n");   
}

정리를 하면, Wire.requestFrom(1, 4) 함수은 마스터 아두이노에서 슬레이브(1) 아두이노에게 요청을 하고 4byte을 읽겠다는 의미이고, Wire.onRequest(requestEvent) 함수는: 슬레이브(1) 아두이노는 요청을 받게 되면 requestEvent()함수를 호출하고 그 안에 있는 write()함수를 통해 마스터 아두이노에 데이터를 보내게 됩니다.

2. I2C 아두이노 간 통신 회로도


준비물 : 아두이노우노 2개
내용 : 아두이노우노의 A4(SDA), A5(SCL)핀을 서로 공유한다.


회로도의 선 연결은 어렵지 않죠. A4, A5 선만 잘 연결하시면 됩니다. 참고로 실제로 실험하실 때는 여러분들이 사용하시는 보드에 따라 선 연결이 다릅니다. 여러분들이 사용하는 보드의 SDA, SCL 핀이 몇번인지 확인하시고 연결하셔야 합니다. 아두이노우노의 경우는 A4, A5로 연결하면 됩니다.

3. 코딩



사전 학습으로 위 아두이노공식 홈페이지에 가시면 Master Reader/Slave Writer, Master Writer/Slave receiver 예제가 있는데 있는데 위 회로도에다가 코딩만 복사하셔어 가상시뮬레이터에서 돌려 보세요.

Master Reader/Slave Writer, Master Writer/Slave receiver 예제를 합쳐진 코딩으로 실험을 해보겠습니다.

위 공식홀페이지의 예제에서는 마스터 아두이노에서 x값을 순차적으로 슬레이브 아두이노에 보내는 동작과 마스터 아두이노에서 데이터 요청하고 슬레이브 아두이노에서 응답하는 동작을 하는 예제입니다.

실험은 마스터에서 x값을 순차적으로 슬레이브로 보내면서 슬레이브 아두이노에게 데이터 요청을 동시에 수행하고 슬레이브 아두이노는 데이터는 수신하면서 요청이 들어오면 응답을 수행하도록 해보겠습니다.

1) 마스터 아두이노 코딩


설계 :

  • 데이터 전송
  • 슬레이브 아두이노에 데이터 요청과 수신

먼저, Wire 라이브러를 함수를 사용하기 때문에 아래와 같인 선언 해주셔야 합니다.

#include <Wire.h>

그리고, 마스터 아두이노이기 때문에 주소지정은 다음과 같습니다.

void setup() {
  Wire.begin();
    
    Serial.begin(9600);           
}

한번만 수행되면 되니깐 Setup()함수 내에서 표현합니다.

데이터 전송하기

int x = 0;
Wire.beginTransmission(1);                
Wire.write("good\n");       
Wire.write(x);             
Wire.endTransmission();
x++;
if(x==6)x=0;  

데이터 요청과 수신

Wire.requestFrom(1, 4); //슬레이브(1)에 4byte 요청
while (Wire.available()) {
    char c = Wire.read(); 
    Serial.print(c);        
}    

2) 슬레이브 아두이노 코딩


설계 :

  • 데이터 수신 처리
  • 데이터 요청 응답

슬레이브 아두이노는 다음과 같이 코딩합니다.

#include <Wire.h>

void setup() {
  Wire.begin(1); //슬레이브 주소                
  Wire.onRequest(requestEvent); //요청시 requestEvent함수 호출
  Wire.onReceive(receiveEvent); //데이터 전송 받을 때 receiveEvent함수 호출
    
  Serial.begin(9600);           
}

마스터 아두이노와 다른 접은 Wire.begin(address) 함수의 주소를 지정해 줘야 합니다. 데이터 수신과 요청에 대한 onReceive()함수와 onRequest()함수를 setup()함수에 한번만 표현합니다.

이제 데이터 수신과 요청에 대한 이벤트 호출함수에 대한 동작만 코딩하면 됩니다.

데이터 수신하기

void receiveEvent(int howMany) { //전송 데이터 읽기
  while (Wire.available()>1) { 
    char ch = Wire.read(); 
    Serial.print(ch);         
  }
  int x = Wire.read();    
  Serial.println(x);      
}

데이터 요청 응답하기

void requestEvent() { //요청 시 수행 함수
  Wire.write("ok!\n");   
}

종합해보면,

[마스터 아두이노 소스]

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600); 
}

byte x = 0;

void loop() {
  Wire.beginTransmission(1);                
  Wire.write("good ");       
  Wire.write(x);             
  Wire.endTransmission();    
     
  delay(500);
  
  Wire.requestFrom(1, 4); //슬레이브(1)에 4byte 요청
  while (Wire.available()) {
    char c = Wire.read(); 
    Serial.print(c);        
  }    
  x++;
  if(x==6)x=0;  
}

위 코딩을 보면 데이터 전송과 데이터 요청 사이의 delay()함수를 주었습니다. 그 이유는 서로 충돌이 일어나지 않게 일정시간 딜레이 주었는데 한번 딜레이 함수없이 가상시뮬레이터에서 실행 시켜보세요. 어떤 결과가 나오는지 확인을 하시기 바랍니다.

[슬레이브 아두이노 소스]

>#include <Wire.h>

void setup() {
  Wire.begin(1); //슬레이브 주소                
  Wire.onRequest(requestEvent); //요청시 requestEvent함수 호출
  Wire.onReceive(receiveEvent); //데이터 전송 받을 때 receiveEvent함수 호출

  Serial.begin(9600);           
}

void loop() {
  delay(500);
}

void receiveEvent(int howMany) { //전송 데이터 읽기
  while (Wire.available()>1) { 
    char ch = Wire.read(); 
    Serial.print(ch);         
  }
  int x = Wire.read();    
  Serial.println(x);      
}
void requestEvent() { //요청 시 수행 함수
  Wire.write("ok!\n");   
}

여기서 available()함수에서 왜 1보다 커야 하는지 한번 0보다 크다일 때와 1보다 크다 일때는 비교해보세요. 그 차이점을 구별하시기 바랍니다.

4. 결과


결과는 마스터 아두이노는 "good " 문자열과 x값을 0~5까지의 값을 슬레이브 아두이노에 보내고 슬레이브 아두이노는 전송 된 "good 숫자"의 값을 읽고 시리얼모티너로 출력합니다. 그리고 슬레이브 아두이노는 데이터 요청이 오면 "ok!\n"문자열 값을 마스터 아두이노에 보내고 마스터 아두이노는 "ok!\n"문자열을 읽고 시리얼모니터로 요청/응답이 정상적으로 처리 되었는지 해당 메시지로 확인 할 수 있습니다.


마무리


오늘은 아두이노 간 I2C 통신을 실험 해 보았습니다. 2대의 아두이노 간 통신이였지만 여러 대의 슬레이브 아두이노에 주소 지정을 하시게 되면 1:N 통신이 가능합니다. 다수의 아두이노 통신을 할 수 있는데 한번 오늘 배운 내용을 기반으로 연장해서 실험을 해보세요.


댓글()

[아두이노] 시리얼 통신으로 다수 명령 처리 방법

IOT/아두이노|2019. 8. 19. 09:00

[아두이노] 시리얼 통신으로 다수 명령 처리 방법



시리얼통신으로 통해 전송되는 하나의 패턴 문자열에 대한 처리에 대해 다뤘습니다. 문득 아두이노에 연결 된 여러개의 부품을 통신을 통해 제어를 할 경우에 대해 어떻게 처리하면 좋을지 궁금해 지더군요. 하나의 패턴 문자열을 통해 A부품을 제어했다면 또다른 패턴문자열로 B부품을 제어할 일이 생길 경우가 있습니다. 여러개의 서로 다른 패턴 문자열을 아두이노우노에서 동시에 처리하고자 할 때 기초적인 방법으로 처리하는 상상코딩을 해보도록 하겠습니다.

1. 부품 패턴 문자열


LED와 Servo Motor를 통신을 통해 제어를 한다면 어떻게 할까요.

LED(A부품)패턴 문자열 : LED 핀이 13번일 경우를 가정해 봅시다.

String inString = "a13,1" or "a13,0";
  • "a13,1" => a부품이고 13번 pin에 상태는 1이다.
digitalWrite(13,1);
  • "a13,0" => a부품이고 13번 pin에 상태는 0이다.
digitalWrite(13,0);

위 A 패턴문자열을 통해서 13번 핀을 HIGH(1) or LOW(0) 상태를 지정할 수 있게 됩니다.

Servo Motor(B부품)패턴 문자열" : Servo pin이 7번일 경우를 가정해 봅시다.

String inString = "b90";
  • "b90" => b부품이고 회전각 90도이다.
servo.write(90);

위 B 패턴문자열을 통해서 고정 Servo Motor 핀을 특정각으로 회전 시킬 수 있게 됩니다.

예를들어, 2개의 패턴 문자열을 통신을 통해 전송되고 아두이노는 서로 다른 문자열이 입력되면 해당 문자열에 맞은 동작을 처리하도록 하기 위해서는 어떻게 할까요. 바로, 문자열을 분해하여 부품 패턴형태를 선택문(switch)문으로 분리해 내면 됩니다.

2. 다수 패턴 문자열을 선택


패턴 형태를 앞글자 첫번째 알파벳으로 지정하게 했습니다. 즉, a,b로 2개의 부품의 패턴부품으로 분류가 됩니다.

a,b의 부품 패턴을 선택문을 통해서 해당 부품을 지정할 수 있습니다.

  • 문자열 읽기 :
String inString = Serial.readStringUntil('\n');   
  • 첫번째 문자(부품패턴) 읽기 : 문자열에서 특정 위치의 알파벳은 charAt(위치)함수로 해당 문자를 읽어옴
char ch = inString.charAt(0); //문자열에서 첫문자 읽기
  • 패턴 선택
switch(ch){
  case 'a':  
           A부품 문자열 읽기;
           A부품 LED동작;
           break;
  case 'b':
           B부품 문자열 읽기;
           B부품 Servo Motor동작;
           break;
}

예를 들어, 두개의 부품 a,b 부품를 제어하는 명령인데 실제로 뭔가를 만들 때는 여러개 부품을 통신에을 통해 제어 할때는 여러개의 case를 만들면 되겠죠.

2개 부품을 읽을 때는 아래와 같이 2개의 case를 살펴봅시다.

  • "a13,1" or "a13,0" 읽기(A부품)
index_pin = inString.indexOf(',');     
index_state = inString.length(); 
pin = inString.substring(1, index_pin).toInt();     
state = inString.substring(index_pin+1,index_state).toInt(); 
  • "b90" 읽기(B부품)
index_servo = inString.length();   
angle = inString.substring(1, index_servo).toInt(); 
  • "a13,1" or "a13,0" 동작(A부품)
void LedOutput(int pin, int state){
  digitalWrite(pin, state);
}
  • "b90" 동작(B부품)
void ServoOutput(int angle){
  servo.write(angle);  
}

처리 동작을 보면 단순합니다. 실제는 좀 복잡한 제어 명령으로 출력함수를 코딩하겠죠.

종합해보면,

#include <Servo.h>

Servo servo;
const byte servoPin = 7;
const byte redPin = 13;
const byte greenPin = 11;
const byte bluePin = 9;

int index_pin, index_state;
int pin, state;
int index_servo, angle;


void setup()
{
  Serial.begin(9600); 
  pinMode(redPin,OUTPUT);
  pinMode(greenPin,OUTPUT);
  pinMode(bluePin,OUTPUT);
  
  servo.attach(servoPin); 
  servo.write(0);
  delay(1000);
}

void loop()
{  
  if(Serial.available()){
    String inString = Serial.readStringUntil('\n');    
    
    char ch = inString.charAt(0);
    
    switch(ch){
      case 'a':                 
                index_pin = inString.indexOf(',');     
                index_state = inString.length(); 
                pin = inString.substring(1, index_pin).toInt();     
                state = inString.substring(index_pin+1,index_state).toInt(); 
                LedOutput(pin,state);
                break;
      case 'b':
                index_servo = inString.length();   
                angle = inString.substring(1, index_servo).toInt();       
                ServoOutput(angle);
                break;                                
    }      
  } 
}

void LedOutput(int pin, int state){
  digitalWrite(pin, state);
}

void ServoOutput(int angle){
  servo.write(angle);  
} 

부품 2개를 시리얼통신을 통해서 제어해 보는 간단한 코딩입니다. 여러 부품을 제어할 때는 switch문을 이용하여 여러개의 패턴 문자열에 대한 처리 동작을 코딩을 표현하시면 다수의 부품을 제어할 수 있습니다.

위 코딩이 실제로 동작하는지 가상시뮬레이터로 돌려 볼까요.

3. 회로도


준비물 : LED 3개, 저항 220옴 3개, Servo Motor 1개, 아두이노우노
내용 : LED은 13, 11, 9번 핀에 연결하고 Servo Motor은 7번핀에 연결하시오.


LED핀은 12,11,10이렇게 하셔도 됩니다. 사실 회로도의 배선을 가상시뮬레이터에서 디자인할 때 최소화 하기 위해서 한칸씩 띄워서 연결햇네요.


4. 결과


LED와 Servo Motor에 대한 명령을 시리얼 통신을 통해 패턴 문자열을 아두이노에 보내고 그 명령들을 아두이노가 처리하는 과정을 간단히 테스트 했습니다.


마무리


오늘은 다수의 패턴 문자열을 만들고 각 문자열에 맞는 동작처리를 하는 방법을 살펴 보았습니다. 이 방법은 어디에다가 쓸까요. 가령, 다양한 부품들을 통신을 통해 한꺼번에 제어할 할때 유용합니다. 즉, 다양한 명령을 문자열로 아두이노로 전송을 하게 되면 각 문자열의 명령들을 아두이노가 식별하고 해당 부품의 동작 명령을 내릴 수 있습니다.

예를 들어, 아두이노가 웹서버에 연결되어 있다고 상상해 봅시다. 웹서버에서는 아두이노로 "A 모터를 돌려라!", "B 부품의 전원을 공급하라", "C 부품으로 온도를 측정하여 온도를 알려달라!" 등 다양한 명령을 내린다고 상상해 봅시다. 아두이노는 이런 다양한 명령을 어떻게 처리해야 할까요. 바로 오늘 소개한 방식으로 다양한 명령 패턴문자열로 보내오고 그 문자열을 위에서 코딩했던 방식으로 switch문을 통해서 분류하여 선택한다면 원하는 동작을 수행 할 수 있게 됩니다.

간단한 원리지만 활용도 면에서 꽤 유용하니깐 참고해 주세요.


댓글()

[아두이노] 아두이노 피아노 만들기

IOT/아두이노|2019. 8. 16. 09:00

[아두이노] 아두이노 피아노 만들기



예전 post를 정리하면서 피에조부저의 응용 예제로 빼먹었던 아두이노 피아노 만들기를 이번에 post로 작성하게 되었습니다. 원리는 피에조부저 제어편에서 "도레미파솔라시도" 음을 순서대로 FOR문을 통해 멜로디를 출력했던 소스에서 이 멜로디 음을 스위치버턴을 이용하여 아두이노 피아노로 구현해 보았습니다. 실험은 가상시뮬레이터에서 이루어 집니다.

이제 어떻게 만들는지 살펴보도록 하죠.

1. 피아노 이해



피아노의 건반을 아두이노를 이용하여 표현을 해 볼까요. 피아노는 건반과 사운드로 나눌 수 있습니다. 건반을 누르면 해당 음으로 소리로 출력이 됩니다. 이 부분을 아두이노로 표현한다면 다음과 같습니다.

  • 건반 = 스위치 버턴
  • 사운드 = 피에조부조


스위치 버턴을 누르면 피에조부저로 해당 음을 출력하면 간단히 아두이노 피아노를 만들 수 있겠죠.

2. 아두이노 피아노 회로도


준비물 : 스위치버턴 8개, 피에조부저 1개, 아두이노우노
내용 : 스위치 버턴을 2,3,4,5,6,7,8,9번 핀에 연결하고 피에조부저는 12번에 연결하시오.



9번부터 2번까지 "도레미파솔라시도"의 건반핀으로 사용 할 예정입니다.

3. 코딩



피에조부저 제어편에 가시면 기본 멜로디 "도레미파솔라시도" 출력 예제가 있습니다. 그 소스를 기반으로 실험합니다.

  • 기본음계
#define NOTE_C5  523   //도 (5옥타브 음계 데이터)
#define NOTE_D5  587   //레
#define NOTE_E5  659   //미
#define NOTE_F5  698   //파
#define NOTE_G5  784   //솔
#define NOTE_A5  880   //라
#define NOTE_B5  988   //시
#define NOTE_C6  1047  //도
  • 스위치버턴 변수
const byte melodyPin[] = {9,8,7,6,5,4,3,2}; //스위치버턴
  • 멜로디 출력 변수
const byte tonepin = 12; //피에조부저
  • 음계 변수
const int melody[] = { NOTE_C5, NOTE_D5, NOTE_E5, NOTE_F5, NOTE_G5, NOTE_A5, NOTE_B5, NOTE_C6 }; //도레미파솔라시도
int noteDurations = 50; //톤길이
  • 스위치버턴 누름 동작
for(int i=0;i<8;i++){ //8개의 건반을 빠르게 체크
   if(digitalRead(melodyPin[i])==LOW){ //내부풀업스위치버턴 누르면
     tone(tonepin, melody[i],noteDurations); //해당 스위치 버턴 음 출력
     delay(noteDurations);  //음길이 최소
     noTone(tonepin); //음 중단
   }
 }

총 0~7까지의 배열위치의 스위치버턴 상태를 체크합니다. 8개의 스위치 버턴 상태를 체크하기 때문에 위에서 for문을 이용하여 순차적으로 체크를 하게 됩니다. 해당 스위치 버턴이 눌르게 되면 최소 누른 음과 길이를 50만큼 음이 울리게 지정했습니다. 이렇게 한 이유는 2개 이상의 스위치 버턴을 누를 때 2개이상의 음이 동시에 울리는 착시음 효과를 나타내기 위해 최소음길이로 지정했네요. 이 원리는 예전에 여러개의 LED를 하나의 제어선을 이용하여 시간차로 동시에 서로 다른 LED에 불이 들어오게 하는 원리와 비슷합니다.

종합해보면,

#define NOTE_C5  523   //도 (5옥타브 음계 데이터)
#define NOTE_D5  587   //레
#define NOTE_E5  659   //미
#define NOTE_F5  698   //파
#define NOTE_G5  784   //솔
#define NOTE_A5  880   //라
#define NOTE_B5  988   //시
#define NOTE_C6  1047  //도

const byte melodyPin[] = {9,8,7,6,5,4,3,2}; //스위치버턴
const byte tonepin = 12; //피에조부저
const int melody[] = { NOTE_C5, NOTE_D5, NOTE_E5, NOTE_F5, NOTE_G5, NOTE_A5, NOTE_B5, NOTE_C6 }; //도레미파솔라시도
int noteDurations = 50; //톤길이

void setup()
{
  for (int i = 0; i < 8; i++) {
    pinMode(melodyPin[i], INPUT_PULLUP); //내부풀업스위치 지정
  }    
}

void loop()
{
  for(int i=0;i<8;i++){ //8개의 건반을 빠르게 체크
    if(digitalRead(melodyPin[i])==LOW){ //내부풀업스위치버턴 누르면
      tone(tonepin, melody[i],noteDurations); //해당 스위치 버턴 음 출력
      delay(noteDurations); //음길이 최소
      noTone(tonepin); //음 중단
    }
  }
}

4. 결과


간단히 "학교종"을 연주해 보았습니다.


마무리


오늘은 예전에 피에조부저에 대해서 post하면서 빼먹은 피에조부저 응용 예제로 아두이노 피아노를 간단히 실험을 하였습니다.


댓글()