[아두이노 자작 쿼드콥터]아두이노를 활용한 각각의 모터 제어

Posted by Doony
2015. 9. 22. 23:25 아두이노 드론 프로젝트

지난 번 아라미르 드론 포스팅을 하고 난 이후로 시간이 많이 흘렀습니다. 

포스팅이 밀렸는데요.....ㅜㅜ 그동안의 결과물을 부지런히 올려서 밀린 포스팅이 없도록 하겠습니다 (아자!) 


지난번까지 PWM 신호를 활용하여 모터를 돌리는 실험을 했는데요. 하지만 이 실험에는 문제가 있었습니다. 4개의 모터에 아두이노로부터 같은 PWM 값이 들어간 것이죠. 이번 포스팅에서는 각각의 모터를 제어해보겠습니다. 


우선, 변속기에서 내보내는 4개의 s선을 각각 아두이노의 다른 핀에 꼽았습니다. 아래 그림과 같이 말이죠 이전에는 변속기에 부착된 throttle hub에 연결했기에 변속기로부터 각각의 모터로 동일한 신호가 출력되었습니다. 하지만 드론의 움직임을 제어하기 위해선 각각의 모터의 출력이 달라야하기에 각각의 아두이노 핀에서 다른 PWM 신호를 주고자 합니다. 





그럼 이에 맞춰 코딩을 수정해야겠죠?

저번에 했던 코딩을 (아래 그림을 참조하세요!) 세번 더 복사하면 되지 않을까 하는 충동이 생길 수도 있지만, 안타깝게도 그러면 문제가 발생합니다. 왜냐하면 저번 코딩에서 저희가 모터에 신호를 줄 때 delayMicroseconds(r)를 썼기 때문이죠. 아두이노에서 delayMicroseconds(r) 함수를 쓰게 되면 이전까지 신호를 받았던 그 상태에서 r 마이크로초만큼 그 상태를 유지하게 됩니다. 




그렇기에 저번에 했던 코딩에 이어 나머지 세 개의 pin에 대해 동일한 방식으로 PWM 신호를 주게 된다면, 각각의 모터로 신호를 주고 출력하는데 시간차가 발생하겠죠. 그렇게 되면 신속하고 정확한 움직임 제어가 불가능하게 됩니다. 이미 알고 계신 분들도 많겠지만 이러한 상황을 위해 보통 Timer 라이브러리를 활용합니다.



그럼 이제 저희가 수정해 본 코딩을 함께 보시겠습니다! 혹시 보시다가 저희 방법이 비효율적이고 조금 더 효율적인 방법이 있으면 알려주세요!

처음 setup 부분입니다. 


우선 저번과 다른 점은 TimerOne 라이브러리를 썼는데요. 또한 저번에 하나만 정의해줬던 r 변수 (PWM 출력값 조절 변수, 시리얼 통신으로 입력) 를 이번에는 r1,r2,r3,r4,r5 총 5개를 정의해줬습니다. (각각에 모터에 PWM을 전달해야하기 때문이겠죠? r5의 경우에는 r5를 넣지 않으면 r4에 해당하는 모터에 이유를 알 수 없는 delay가 발생하더라구요)

마지막 두 줄은 위에서 불러온 TimerOne 라이브러리를 활용하는 것인데요. 50 마이크로초마다 motor라는 함수를 반복해줍니다. 쉽게 생각하시면 50마이크로초마다 반복하는 loop의 역할을 하는 것이죠.

 

그럼 50마이크로초마다 반복되는 motor라는 함수를 보겠습니다.




함수를 잘 살펴 보면 motor함수가 매번 실행될 때마다 count값이 1씩 올라가고 count가 400이 되면 pin이 high 상태로 켜지게 되고 count값은 0으로 초기화됩니다. 그리고 반복된 motor 함수의 실행으로 인해 count 값이 1씩 올라가다가 20+r1, 20+r2, 20+r3, 20+r4가 되면 신호가 low로 바뀌게 됩니다 (r1, r2, r3, r4 값은 이후 코딩에서 시리얼 통신을 통해 받게 됩니다) 


혹시 이 [아두이노 자작 쿼드콥터] 변속기와 아두이노 신호서 얘기했던 PWM신호의 원리 기억나시나요? 



즉 전체 count 400의 5%인 20의 듀티값은 정지, 10%인  40의 듀티값은 최고 속도인데요.  r1,r2,r3,r4의 값에 따라 신호가 HIGH인체 지속되는 시간이 달라지게 되는 것입니다. 즉, 모터의 출력을 조정하는 것이죠. 

또한 시리얼 통신을 통해 0~20 사이의 값을 r1,r2,r3,r4에 각각 넣어주게 된다면 각각의 모터가 다른 속도로 회전하게 되겠죠.


이를 통해 지난 번에 코드 안에 있었던 loop와 delay를 사용하지 않고 timer와 count로 대체하여 PWM 신호를 생성하는데 성공했습니다. 보시기 편하게 전체 코딩을 여기에 붙여놓겠습니다. 


#include <TimerOne.h>


int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5=0;

int count = 0;

void setup() {

  // put your setup code here, to run once:

  pinMode(7, OUTPUT);

  pinMode(8, OUTPUT);

  pinMode(9, OUTPUT);

  pinMode(4, OUTPUT);

  digitalWrite(7, LOW);

  digitalWrite(8, LOW);

  digitalWrite(9, LOW);

  digitalWrite(4, LOW);

  Serial.begin(9600);



  Timer1.initialize(50);

  Timer1.attachInterrupt(motor);

}


void motor() {

  if (count == 20 + r1) {

    digitalWrite(4, LOW);

  }

  if (count == 20 + r2) {

    digitalWrite(9, LOW);

  }

  if (count == 20 + r3) {

    digitalWrite(8, LOW);

  }

  if (count == 20 + r4) {

    digitalWrite(7, LOW);

  }



  if (count == 400) {

    digitalWrite(4, HIGH);

    digitalWrite(9, HIGH);

    digitalWrite(8, HIGH);

    digitalWrite(7, HIGH);

    count = 0;

  }

  count += 1;

}


void loop() {

  Serial.println(r1);

  Serial.println(count);

}


void serialEvent()

{

  while (Serial.available()) {

    r1 = Serial.parseInt();  

    r2 = Serial.parseInt();

    r3 = Serial.parseInt();

    r4 = Serial.parseInt(); 

    r5=Serial.parseInt();

  }

}




이 코드를 기반으로 아두이노로 각각의 모터를 켜고 끄는 영상입니다. 다음 번엔 각각의 모터로 PID 제어하는 과정을 포스팅 하겠습니다. 


조만간 다시 찾아뵐게요!