벌써 오유로 출석한지 3일째되네요~
이번에는 기술이민 증빙용 두번째 자료입니다. ㄷㄷㄷ
테크닉 모터에는 M모터, L모터, XL모터 그리고 서보모터가 있는데, 앞에 3개 모터(M, L, XL)는 사이즈와 힘만 다른 모터입니다.
그냥 360도 계속 회전합니다. 전압을 반대로 걸면 반대로 돌구요.
주행같은 동작에 적합합니다.
DC모터라고도 하지요.
근데 서보모터는 좌우로 90도만 회전하는 모터입니다.
그래서 조향같은 동작에 적합하지요.
이번에는 서보모터 제어하는 방법입니다.
1. 준비작업
파워펑션 연장선을 준비하여 절반으로 자르고, 피복을 벗겨줍니다.
피복을 벗긴 연장선의 끝에 납을 묻혀서 브레드보드에 꽂기 편하도록 해둡니다.
저는 회사에 있는 핀을 이용해서 핀이랑 납땜을 해버렸습니다.
이러면 브레드보드에 꽂기 더 편하거든요. (브레드보드랑 간격도 동일해서)
연장선의 핀맵은 아래 사진을 참조합니다.
기존 DC 모터들은 중간에 C1, C2만 연결하였지만, 서보모터는 모든 선을 다 연결해야합니다.
1번과 4번핀으로 전원이 공급되고, C1, C2핀의 전압에 따라 좌우로 돌아가게 됩니다.
2. 회로 꾸미기
아래 회로도를 참조하여 브레드보드에 회로를 구성합니다.
서보모터의 경우 아두이노보드의 PWM 출력 기능을 이용하므로 DC모터처럼 별도의 IC가 필요하지 않습니다.
주의해야할점은 PWM를 지원하는 핀에 C1, C2를 연결해야합니다.
아두이노 우노의 경우 3, 5, 6, 9, 10, 11 핀이 PWM 기능을 지원합니다.
C1 = 0V, C2 = 0V : 중앙정렬
C1 = 5V, C2 = 0V : 오른쪽 90도회전
C1 = 0V, C2 = 5V : 왼쪽 90도 회전
이런식으로 동작하는데, PWM으로 제어한 전압값에 따라 90도가 되기도 하고, 45도가 되기도 합니다.
핀맵
2번핀 : 블루투스 통신용 rx
3번핀 : 블루투스 통신용 tx
9번핀 : 서보모터 제어 C1
10번핀 : 서보모터 제어 C2
3. 코딩
아래 소스를 참조하여 코딩합니다.
9번핀과 10번핀을 analogWrite 함수로 PWM 기능을 쓸수있습니다.
0부터 255까지 입력이 가능합니다.
서보모터가 좌우로 90도를 회전한다고 가정하면 다음과 같이 동작합니다.
9번핀 = 0
10번핀 = 0
=> 중앙 정렬
9번핀 = 255
10번핀 = 0
=> 오른쪽 90도 회전
9번핀 = 0
10번핀 = 255
=> 왼쪽 90도 회전
9번핀 = 128
10번핀 = 0
=> 오른쪽 45도 회전
주의할점은 두 핀중에서 하나만 입력값 들어가야한다는 점입니다.
둘다 입력하면 어떻게 될지는 저도 안해봐서 모르겠지만 부하가 걸리겠죠? ㅎㅎ
그래서 반대로 동작할때는 꼭 다른핀의 입력값을 0으로 넣어주세요.
// 코딩시작 ==============================================================
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2,3);//HC-06 블루투스 모듈 설정 rx, tx
int pinC1 = 9; // c1 제어
int pinC2 = 10; // c2 제어
byte rcvByte; // 블루투스 데이터 읽기
unsigned long tm; // 시퀀스 동작 주기 확인용 시간 변수
int bSeqRun=0; // 시퀀스 동작 명령
int stepSeqRun=0; //시퀀스 동작 구분 변수
void setup() {
// 아두이노 전원 인가시 1회만 실행됨
// 블루투스 모듈 동작시킴
mySerial.begin(9600);
Serial.begin(9600);
// 핀 설정
pinMode(pinC1, OUTPUT);
pinMode(pinC2, OUTPUT);
// 핀 기본값 0
analogWrite(pinC1, 0);
analogWrite(pinC2, 0);
tm = millis(); // 현재 시간으로 설정
}
void loop() {
// 계속 반복 동작하는 부분
if (mySerial.available() > 0) { // 블루투스로 데이터를 읽었을때...
rcvByte = mySerial.read(); // 블루투스로 읽은 데이터를 rcvByte에 넘겨줌.
if (rcvByte == 'f') MtrMove(1, 255); // f 문자가 입력되었으면 +방향 동작
if (rcvByte == 'b') MtrMove(0, 255); // b 문자가 입력되었으면 -방향 동작
if (rcvByte == 'l') MtrMove(1, 128); // l 문자가 입력되었으면 +방향 절반 동작
if (rcvByte == 'r') MtrMove(0, 128); // r 문자가 입력되었으면 -방향 절반 동작
if (rcvByte == 's') { // s 문자가 입력되었으면 정지, 시퀀스도 정지
MtrMove(0, 0);
bSeqRun = 0;
stepSeqRun = 0;
}
if (rcvByte == 'q') { // q 문자가 입력되었으면 시퀀스 동작
bSeqRun = 1;
}
}
if (bSeqRun == 1) { //시퀀스동작변수에 1이 입력되면
SeqStart(); // 시퀀스동작 함수 실행
}
}
void MtrMove(int dir, int val) // dir : 모터방향, val : 이동범위
{
if (dir == 1) { // 모터방향이 1이면 C1 동작, 아니면 C2 동작
analogWrite(pinC1, val);
analogWrite(pinC2, 0 );
}
else {
analogWrite(pinC1, 0 );
analogWrite(pinC2, val);
}
}
void SeqStart()
{
unsigned long nowtm = millis(); // 현재 시간을 설정
if (nowtm - tm > 1000) { // 1초 마다 실행하도록 하는 조건문. [현재시간]과 [동작주기확인용시간]의 차이가 1000ms이 넘으면 실행. (단위는 1/1000초)
tm = nowtm; // 동작주기확인용 변수에 현재 시간 기록
switch (stepSeqRun) { // 동작 구분 변수의 값에 따라 해당부분의 명령을 수행
case 0 : {
MtrMove(1, 255); // +방향으로 회전
stepSeqRun++; // 다음 동작으로 넘어감.
break;
}
case 2 : { // 2초후
MtrMove(0, 0); // 정지
stepSeqRun++;
break;
}
case 3 : { // 1초후
MtrMove(0, 255); // -방향으로 회전
stepSeqRun++;
break;
}
case 5 : { // 2초후
MtrMove(0, 0); // 정지
stepSeqRun=0; // 다시 처음으로
break;
}
default : { // 동작 구분 변수와 일치하는 항목이 없을때 수행.
stepSeqRun++;
break;
}
}
Serial.println(stepSeqRun);
}
}
// 코딩끝 ==============================================================
4. 스마트폰 설정
이번에도 Bluetooth controller 어플을 이용하여 제어를 하고 있습니다.
키를 다음 화면과 같이 설정해주세요.
l, r은 이름짓기도 귀찮아서 걍 써버린...;;;;
항상 블루투스로 제어하기때문에 매번 기능 만들때마다 설정해줘야하네요. ㅎㅎㅎ
참고로 앱인벤터를 이용하면 안드로이드용 어플도 간단히 만들수있습니다.
저도 블루투스 제어용으로 만들어보긴했는데 안이쁜데다가(디자인 잼병...ㅠㅠ) 기능 수정하려면
매번 코딩해야해서 걍 이거 계속 쓰네요.
5. 동작 영상
전진/후진 버튼을 누르면 각 방향으로 최대치(90도) 돌아가고, l/r 버튼을 누르면 각 방향으로 절반(45도)만큼 돌아갑니다.
시퀀스는 그냥 최대치로 왔다, 갔다 시킨거구요.
다음번에는 초음파센서로 거리를 측정하는 방법을 올려보겠습니다.
감사합니다~