아두이노 2륜 RC카 주행 패턴 실험 (아두이노)
아두이노 2륜 RC카 주행 패턴 실험 (아두이노)
- 온라인 가상시뮬레이터 : https://www.tinkercad.com
- RC Car post 과정 :
L293D Motor Shield+DC MOTOR 제어 (아두이노)
아두이노 RC카 준비 (아두이노)
아두이노 2륜 RC카 주행 패턴 실험 (아두이노)
2륜 RC카 Bluetooth를 통해 스마트폰(무선) 조정하기 (아두이노)
아두이노 RC카를 조정하는 다양한 코딩 접근법(아두이노)
지난시간에는 아두이노 2륜 RC카 조립과 시험 주행을 해보았습니다. 이제 본격적으로 주행 패턴을 만들어서 직접 만든 RC카의 주행 동작이 구체적으로 어떤식으로 움직이는지 살펴 볼 차례입니다. 그냥 Bluetooth로 DC Motor 회전의 방향만 조장하는 스마트폰 조정을 바로 할 수 있지만 그전에 자신이 만든 RC카가 어떤식으로 움직이는지 먼저 알아야 합니다. 나중에 직접 조정을 하거나 자율주행을 할 때 꼭 필요한 사전 지식입니다. RC카의 움직임을 미리 알아 두시면 어떤 상황이 될 때 전진 후진, 좌회전, 우회전, 정지 등의 패턴을 쉽게 만들어 낼 수 있게 됩니다. 꼭 필요한 실험이니깐 RC카가 이런식으로 주행 패턴을 만들어 내는구나 하고 배웠으면 합니다.
이제 본격적으로 주행 패턴을 만들어 보도록 하겠습니다.
![](https://steemitimages.com/640x0/https://i.imgur.com/vZqUZbe.jpg)
1. 2륜 RC카 회로도
- 준비물 : DC 기어모터 2개, L293D Motor Shield, AAx4개 배터리 케이스 배터리 홀더(6V), 아두이노우노
실제 2륜 RC카를 회로도로 살펴보면 아래 그림과 같습니다. 참고용으로 살펴보시기 바랍니다.
![](https://steemitimages.com/640x0/https://i.imgur.com/VBOtPsZ.jpg)
2. 아두이노 2륜 RC카 주행 패턴 만들기
DC Motor 2개를 제어하기 하기 위한 함수 motor1.run(), motor2.run() 로 FORWARD, BACKWARD. RELEASE 의 명령을 통해서 주행 패턴이 만들어 낼 수 있습니다.
AF_DCMotor motor1(3);
AF_DCMotor motor2(4);
위 motor 기준으로 왼쪽 모터는 3번 오른쪽 모터는 4번으로 했을 때 다음과 같습니다.
1) 전진과 후진
![](https://steemitimages.com/640x0/https://i.imgur.com/wxcA0vD.jpg)
![](https://steemitimages.com/640x0/https://i.imgur.com/qYW2VWA.jpg)
전진
motor1.run(FORWARD);
motor2.run(FORWARD);
후진
motor1.run(BACKWARD);
motor2.run(BACKWARD);
2) 좌회전과 우회전
![](https://steemitimages.com/640x0/https://i.imgur.com/ffzzX0U.jpg)
![](https://steemitimages.com/640x0/https://i.imgur.com/InejZ2I.jpg)
좌회전
motor1.run(RELEASE);
motor2.run(FORWARD);
우회전
motor1.run(FORWARD);
motor2.run(RELEASE);
3) 제자리 좌회전과 우회전
![](https://steemitimages.com/640x0/https://i.imgur.com/PHQV9kO.jpg)
![](https://steemitimages.com/640x0/https://i.imgur.com/01mchG2.jpg)
좌회전
motor1.run(BACKWARD);
motor2.run(FORWARD);
우회전
motor1.run(FORWARD);
motor2.run(BACKWARD);
4) 정지
motor1.run(RELEASE);
motor2.run(RELEASE);
3. 코딩
DC Motor
#include <AFMotor.h>
- AF_DCMotor motor(3) : M3핀을 DC Motor 제어용으로 사용.
- motor.setSpeed(200) : 모터 속도 200으로 설정
- motor.run(FORWARD) : FORWARD, BACKWARD, RELEASE 회전 명령 중 하나를 선택해서 실행 시킴.
Adafruit Industries에서 제공해주는 Motor 라이브러리를 이용하면 setSpeed(), run() 함수로 쉽게 DC Motor를 움직이게 할 수 있습니다.
위에서 주행 패턴에 대해서 간단히 살펴보았습니다. 그 동작을 실제로 코딩해서 실험을 해보도록 할까요.
[ 소스 ]
#include <AFMotor.h>
AF_DCMotor motor1(3);
AF_DCMotor motor2(4);
void setup() {
motor1.setSpeed(200);
motor2.setSpeed(200);
motor1.run(RELEASE);
motor2.run(RELEASE);
}
void loop() {
motor1.run(FORWARD); //전진
motor2.run(FORWARD);
delay(2000);
motor1.run(BACKWARD); //후진
motor2.run(BACKWARD);
delay(2000);
motor1.run(RELEASE); //정지
motor2.run(RELEASE);
delay(2000);
motor1.run(RELEASE); //좌회전
motor2.run(FORWARD);
delay(2000);
motor1.run(FORWARD); //우회전
motor2.run(RELEASE);
delay(2000);
motor1.run(BACKWARD); //제자리 좌회전
motor2.run(FORWARD);
delay(2000);
motor1.run(FORWARD); //제자리 우회전
motor2.run(BACKWARD);
delay(2000);
}
주의사항
![](https://steemitimages.com/640x0/https://i.imgur.com/8YogEAV.jpg)
위 사진을 보면 빨간색으로 표시한 부분이 있는데 덮개처럼 되어 있습니다. 아두이노우노에 프로그램을 업로드 할 때 이 덮개를 빼주세요. 덮개가 그대로 되어 있으면 아두이노우노에서 전원이 공급되는데 Motor Shield에 그대로 전원이 공급되어 프로그램 명령에 따라서 바로 DC Motor가 회전을 하게 됩니다. 덮개를 분리해 놓으면 Motor Shield에 전원이 공급되지 않기 때문에 RC카는 움직이지 않게 됩니다. 매번 실험에 우두이노우노에 프로그램을 업로드 할 때마다 Motor Shield를 아두이노우노에서 분리하지 말고 이 덮개만 빼주면 됩니다.
위에 표시된 덮개는 꼽아져 있으면 아두이노우노와 Motor Shield가 서로 전류를 공유하게 되고 분리하면 전류를 공유하지 않고 개별적으로 전류를 공급 받는 다고 생각하시면 됩니다. 쉽게 말해서 Motor Shield에 전원을 공급하는데 덮개가 되어 있으면 이 전류가 아두이노우노에도 전류가 공급됩니다, 반대로 아두이노우노에 전원이 공급되면 Motor Shield에도 전류가 공급된다고 생각하시면 됩니다. 하지만 덮개가 빠지면 아두이노우노에 전류가 공급되더라도 Motor Shield에 전류를 공급되지 않습니다. 반대로 Motor Shield에 전류가 공급되더라도 아두이노우노에는 전류가 공급되지 않습니다.
위 사진에서 표시한 위치의 덮개를 어떻게 하느냐에 따라서 아두이노우노와 Motor Shield의 전류 공급에 형태를 결정하게 됩니다.
4. 결과
5. 주행 패턴을 배열로 만들기
위 코딩을 보면 순차적으로 길게 나열된 소스입니다. 중복되는 코딩을 보면 뭔가 줄이고 싶은 마음이 생기지 않나요. 저같은 경우는 중복된 코딩을 보면 바로 거것을 배열로 만들어서 코딩량을 줄이고 싶어집니다. 즉, 중복코딩을 보면 바로 배열을 떠오릅니다. 그러면 한번 배열로 전부 만들어 볼까요.
1) 코딩
[패턴] : 2륜 RC카의 motor 패턴만들기
byte movePattern1[7]={1,2,4,1,4,1,2}; //motor1 Pattern
byte movePattern2[7]={1,2,4,4,1,2,1}; //motor2 Pattern
byte delayTime[7]={2,2,2,2,2,2,2}; //motor Rotation time
byte speedPattern1[7]={200,200,200,200,200,200,200}; //motor1 speed Pattern
byte speedPattern2[7]={200,200,200,200,200,200,200}; //motor2 speed Pattern
FORWARD, BACKWARD, RELEASE의 값은 라이브러리 헤더파일에 가면 해당 값을 확인 할 수 있습니다.
![](https://steemitimages.com/640x0/https://i.imgur.com/zRAsrsO.jpg)
위 사이트에 가시면 이렇게 확인이 가능합니다. define으로 정의한 변수명으로 표현할 필요 없이 직접 해당 값으로 표현 해도 됩니다. 보면 BRAKE라고 하나의 변수명이 더 있는데 사실 제가 쓰는 모터쉴드에서는 반응하지 않습니다. 정확히 소스를 살펴봐야 하는데 어떠한 반응도 보이지 않더군요. 그래서, BRAKE만 뺀 나머지 3개의 변수네임만 사용합니다.
실험한 위 소스에서는 Motor1, Motor2의 패턴을 개별 배열 변수로 해서 표현했습니다.
byte movePattern1[7]={1,2,4,1,4,1,2}; //motor1 Pattern
byte movePattern2[7]={1,2,4,4,1,2,1}; //motor2 Pattern
그리고, 회전 시간은 다음과 같이 1초가 1000입니다. 즉, 2초면 2000이 되기 때문에 나중에 delay()함수에서 "2*1000"으로 하면 되기 때문에 간단히 아래와 같이 표현 했습니다. 2초로 고정이니깐 구지 배열변수로 만들 필요가 없지 않냐고 생각 할 수 있지만 나중에 추가로 시간을 제어하기 위해서 우선 만들어 놓았습니다.
byte delayTime[7]={2,2,2,2,2,2,2}; //motor Rotation time
초 단위로 제어를 했지만 만약 좀 더 짧은 시간으로 제어한다면 다음과 같이 표혀을 해야 겠지요.
int delayTime[7]={2000,2000,2000,2000,2000,2000,2000}; //motor Rotation time
이렇게 하고
delay(delayTime[i]*1000);
이 표현에서
delay(delayTime[i]);
이렇게 곱하기 1000 부분을 지워 주면은 되겠죠. 실험은 초 단위로 하기 때문에 byte형으로 간단히 표현 했습니다.
마지막으로 speed 부분입니다. 위 실험에서는 200 speed로 고정이였습니다. 좀 더 다양한 패턴을 실험하기 위해서는 speed에 따른 주행거리를 계산을 해야 합니다. 나중에 speed에 따른 주행거리과 회전각도를 구하기 위해서는 속도와 시간의 값을 통해 수학적으로 계산해야 하기 때문에 측정하기 위해 별로로 배열변수로 다시 선언했습니다.
byte speedPattern1[7]={200,200,200,200,200,200,200}; //motor1 speed Pattern
byte speedPattern2[7]={200,200,200,200,200,200,200}; //motor2 speed Pattern
byte 자료형은 아두이노에서는 8bit 부호없는 숫자 0~255까지 표현이 가능합니다.
[소스]
#include <AFMotor.h>
AF_DCMotor motor1(3);
AF_DCMotor motor2(4);
byte movePattern1[7]={1,2,4,1,4,1,2}; //motor1 Pattern
byte movePattern2[7]={1,2,4,4,1,2,1}; //motor2 Pattern
byte delayTime[7]={2,2,2,2,2,2,2}; //motor Rotation time
byte speedPattern1[7]={200,200,200,200,200,200,200}; //motor1 speed Pattern
byte speedPattern2[7]={200,200,200,200,200,200,200}; //motor2 speed Pattern
int lenghtVal = 7; //pattern lenght
void setup() {
motor1.setSpeed(0);
motor2.setSpeed(0);
motor1.run(RELEASE);
motor2.run(RELEASE);
}
void loop() {
for(int i=0;i<lenghtVal;i++){
motor1.setSpeed(speedPattern1[i]);
motor2.setSpeed(speedPattern2[i]);
motor1.run(movePattern1[i]);
motor2.run(movePattern2[i]);
delay(delayTime[i]*1000);
}
}
위 결과는 위에서 직접 명령을 내린 코딩과 동일함으로 결과도 동일하게 나옵니다. 위에서 패턴 결과를 동영상으로 찍어서 보여드렸는데 구지 똑같은 영상을 찍을 필요가 없기 때문에 배열 변수로 패턴을 저장하여 실험한 결과물 영상은 생략합니다.
6. 추가 주행
같은 방향으로 회전을 진행하더라도 DC Motor 돌의 speed 값에 따라 진행방향이 바뀌게 됩니다.
![](https://steemitimages.com/640x0/https://i.imgur.com/Q9gDaVE.jpg)
대충 이런 느낌이겠죠.
motor1.setSpeed(130);
motor2.setSpeed(200);
motor1.run(FORWARD);
motor2.run(FORWARD);
오른쪽 motor2은 원을 크게 그리게 되고 왼쪽 motor1은 원을 작게 그리며 우회전을 하게 됩니다. 만약 반대면 왼쪽은 큰원을 그리고 오른쪽은 작은원을 그리는 좌회전이 되겠죠.
[소스]
#include <AFMotor.h>
AF_DCMotor motor1(3);
AF_DCMotor motor2(4);
void setup() {
motor1.setSpeed(0);
motor2.setSpeed(0);
motor1.run(RELEASE);
motor2.run(RELEASE);
}
void loop() {
motor1.setSpeed(130);
motor2.setSpeed(200);
motor1.run(FORWARD);
motor2.run(FORWARD);
delay(1000);
}
[결과]
7. 주의 사항
모터 쉴드에 전원을 6V으로 공급하기 때문에 실제 DC 기어모터에 제대로 된 힘을 발휘하지 못합니다. 아두이노에 연결하는 9V 전원 공급쪽으로 하면 DC 기어모터의 회전에 힘을 발휘하기는 합니다. 전원 공급이 약하면 회전력이 떨어집니다. DC 기어모터를 회전시킬 수 있는 힘이 약하기 때문에 speed 값이 낮아지면 정상적으로 해당 speed만큼 회전을 시키지 못합니다.
방금 한쪽은 200을 주고 한쪽을 130정도로 speed 값을 주고 실험한 이유는 100이하로 speed값을 주면 제가 쓰는 DC 기어모터를 정상적으로 회전을 시키지 못합니다. 130의 정도로 해야 겨우 반응을 보이는데 이것도 반응이 없는 경두도 발생했습니다. 싼 DC기어모터의 한계인지 모르겠네요. DC기어모터가 회전을 하려고 하는데 회전 기어를 움직이게 할 힘이 너무 약해서 돌지를 못하는 현상이 발생하더군요. 참고로 아두이노에서 5V usb로 연결하면 speed 일정값이하는 아예 반응하지 않고 DC기어모터에서 이상한 신호음만 크게 납니다. 문제가 있다는 신호인거죠. 싼 DC기어모터여서 그런지 약간 퍽퍽하고 또 전류 공급이 약하면 반응을 잘 못해서 실험에 약간 불편했네요.
그냥 RC카를 조정할 때 6V 전류를 한다면 주행 speed를 200으로 고정해놓고 주행 실험을 하시는게 편할 듯 싶네요. 좋은 모터를 쓰면 그렇게 까지 신경을 안쓰셔도 되겠지만요. 결론은 DC 기어모터의 퍽퍽함과 전류공급에 따라 DC Motor의 회전에 영향을 준다는 것이죠.
마무리
오늘 주행 패턴을 만들면서 사실 6V 전원 공급으로는 DC Motor를 정교하게 제어를 하기 어렵습니다. DC Motor를 오랫동안 사용하지 않아서 처음에는 speed를 200으로 해놓고 실험을 해도 회전을 제대로 시키지 못하더군요. 그냥 건전지를 DC Motor에 다이렉트로 연결하여 회전을 계속 시켰습니다. 그리고 나니 그제서야 DC Motor가 회전하더군요. 기어 부분에게 퍽퍽하고 싼 부품을 구매해서 그런지 제어하기가 좀 불편 했네요.
그래도 어느정도 패턴을 만들어 주행 실험을 하였습니다. 이 주행 결과를 다음 시간에 Bluetooth를 이용하여 스마트폰으로 무선 조정 실험을 할 예정입니다.
참고로, 위에서 주행 배열 변수를 구지 만든 이유는 따로 여러분들이 주행에 대한 실험을 할 수 있는 틀을 마련하기 위해서 입니다. 만약, 주행 정보를 이렇게 나눠 놓고 특정 움직임에 대한 RC카 주행을 기록해 놓는다고 상상해 보세요. 그 기록으로 주행을 시킨다면 어떻게 될까요. 예를들어, 같은 기록 데이터를 가지고 2대 이상의 RC카가 움직인다면 어떻게 될 까요. 아이돌 군무를 상상하면 쉬울 듯 싶네요. 같은 동작을 여러 RC카가 군무를 추듯이 주행을 하게 됩니다. 이런 개념을 갖게 되면은 나중에 군집 주행의 첫발을 내딛을 수 있겠죠.
그리고, 배열에 특정 동작에 대해서 순차적으로 증가 시키거나 감소시키는 값들로 채워 넣는다면 어떻게 될까요. 어떤 패턴 실험의 측정 도구로도 활용이 가능합니다. 시간에 따른 RC카의 주행 거리와 회전 각도들을 시간값의 변화를 배열로 미리 만들어 넣고 실험하여 측정도 가능 합니니다.
실험은 안했지만 여러분들이 한번 다음 실험을 해보셨으면 합니다. 시간과 speed 값에 의한 이동거리와 회전각도를 수학적으로 접근해 보세요. 아니면 그냥 무식하게 speed값을 고정 시키고 시간값에 의한 RC카의 바퀴휠 원둘레 길이를 가지고 시간대 별 이동거리와 회전각도를 눈으로 대충 근사거리와 근사각도를 가늠해 놓고 그걸 기준으로 RC카를 제어를 해보세요. 그러면 좀 더 정교한 제어가 가능해 집니다.
아무튼 오늘은 생각할 부분이 많습니다. 한번 상상의 나래를 펼쳐 보세요.
DCMotor motor 관련 내용을 알아갑니다.오늘 하루 기쁜날이 되시길 ㅎㅎ 글 잘 보고 갑니다
감사합니다.
오 신기하네요~
저도 한번 해보고 싶은데 어렵겠죠 ?
어렵지 않아요.
모터쉴드에 DC 기어모터를 연결하고 이미 만들어진 라이브러리을 다운 받아서 함수 motor2.setSpeed()과 motor1.run()만 아시면 쉽게 제어가 가능해요.
이전 post를 한번 읽어보세요.
누구나 쉽게 만들 수 있어요.
감탄감탄감탄감탄입니다!!! 대단!! 직접 손수 처음부터 끝까지 다 하신거죠??? 문과생은 그저 신기할뿐^^
핵심 코딩부분인 DC Motor 라이브러리만 가져다가 활용 한 것 뿐이라 대단한 것은 아니고요.
누구나 쉽게 만들 수 있는 주제여서 그렇게 어렵지 않아요.
RC카 프레임 몸체만 5800원짜리 구매하고 몇개 부품만 가져다가 조립한 것 뿐이라 손수 만들었다고 보기는 좀 어렵고요.
모터쉴드+모터+아두이노우노 이렇게 3개를 결합한 것 뿐이라 별거는 아니에요.
문과인 저에게는 정말 어려운 내용이네요.....
오늘은 살짝 코딩이 길어서 어려워 보일 수 있겠네요.
setSpeed(), run() 이 두개 함수만 가지고 표현한 거라 알고나면 그렇게 어렵지 않을 꺼에요.
주행방식을 분석하고 거기에 맞추어 코딩하는 과정이 재미있어 보이네요ㅎㅎ 나중에 꼭 제대로 코딩을 배워봐야겠습니다!
꼭 배워보세요. 은근 코딩이 잼있는 분야에요. ^^
짱짱맨 호출에 출동했습니다!!
짱짱맨 방문에 감사합니다.
서당개 3년안 풍월읊는다고 했는데, 저는 아무리 봐도 ㅠㅠ
이게 직접 해보시면 어렵지 않는데 처음 접할때가 약간 어려워하는 것 같아요.
가상시뮬레이터에서 직접 본인이 해보셔야 post를 따라올 수 있을 꺼에요.
글로만 보면 별거 아니고 함수 몇개안되는데 이걸로 제어가 되네 하고 넘어가는데요. 직접 체험하는 거랑 안하는 거랑은 천지 차이여서 가상시뮬레이터로 기초적인거라도 한번 도전해 보세요.
God Bless You!