[아두이노 쿼드콥터] pid 제어 전후 비교

Posted by Doony
2015. 11. 10. 00:42 아두이노 드론 프로젝트

한동안 포스팅이 뜸했네요. 면접 시즌도 겹치고 해서 아무래도 진행상황이 좀 더뎠습니다 ㅠㅠ


먼저 저희가 해결해야할 상황은, 블루투스로 신호 전송시 값이 튀는 것이었습니다.

안드로이드로 신호를 쏴주면, 쏴줄 때 갑자기 뭔가 신호값이 튀어서 모터 출력이 급 최대가 되었다가 다시 돌아오는...

그래서 결과적으로 제어가 안되는 상황이었는데요.


저희가 현재 기본적으로 만들고 있는 통신체계는 이러합니다. (나중에는 라즈베리파이가 껴서 달라질 겁니다. 일단은 이정도. 만약 영상 전송까지 하지 않으실 분들은 그냥 아래처럼 하시면 됩니다.)


1. 안드로이드 블루트스 신호줌 (조종기)

2. 아두이노에서 신호를 받고 변속기 제어


네.. 뭔가 단계별로 쓰려고 했는데 두단계밖에 없네요 ㅎㅎㅎ


암튼 그래서 아두이노에서 블루투스로 신호를 받는 알고리즘이 필요합니다. 안드로이드에서 블루투스를 쏴주는 건 안드로이드 앱들을 사용했습니다. 그냥 플레이스토어를 찾아봐도 여러가지 찾으실 수가 있거든요.



저희가 사용하던 방법은 일단 소프트시리얼을 사용한 방법이었습니다.

TX, RX를 아두이노 우노의 2, 3번핀에 각각 연결해서 하는 방식으로, 인터넷 뒤져보면 많이 나오는데요.


이렇게 하니까 값이 튀더라고요. 그래서 두가지 정도가 문제가 아닐까 생각했습니다.


첫째, baud rate의 문제다. 시리얼 통신 rate은 230400인데 블루투스는 9600이라 그런게 아닐까!!!

-> 실험 결과, 뭘 하든 다 튀더라고요 ㅎㅎㅎㅎㅎ


둘째, softwareserial 이 문제다! 이걸하지말고, 아두이노 우노의 0, 1번 핀, 즉 tx과 rx 핀에 각각 직접 해보자!

-> 일단 baud rate은 모두 115400으로 맞춰주고 해본 결과, 첫번째만큼 튀진 않습니다.


다만, 두번째 방법도 신호를 전송했을 때 이번엔 오히려 출력이 약해지는? 그런 게 있더라고요.

첫번째만큼 확 튀진 않지만 어쨌든 값이 불안정한건 마찬가지였습니다.


그래서 결과적으로 아직도 해결하지 못했구요, 다음번에는 baud rate 조절을 통해 실험해볼 생각입니다.




일단 블루투스로는 게인값 조정정도만하고, (출력값 조절 시 확 튀어서 의미가 없었습니다)

pid 제어를 해보기로 하였습니다.


참고로, 모든 코드가 필요하신 분들은, 저희 Y.NGneers 카톡 아이디 추가해주시면 파일 보내드리겠습니다!

카카오톡에 yngneers 라고 검색하시면 하나 나올거에요~~ 말 걸어주시면 바로 보내드립니다!


일단 핵심 부분입니다.




void PID_control_y() { //front and back



  // Y-direction P + PID

  error_y = desired_angle - kalAngleY; //angle def

  P_angle_pid = P_angle_gain * error_y; //angle def + P control


  rate_y = (kalAngleY - kalAngleY1) / 0.0065;


  error_pid_y = P_angle_pid - gyro_y; // Pcontrol_angle - angle rate = PID Goal



  m_y = m_y1 + G1 * error_pid_y + G2 * error_pid_y1 + G3 * error_pid_y2; // PID 계산식


  PID_value = constrain(PID_scaler * abs(m_y), 0, max_output);

///////////////PID_value가 pid를 통해 나온 값입니다. pid_scaler는 그냥 1로 두었습니다. 딱히 필요하진 않구요. 

//constrain이란건, 첫번째 값의 범위를 0~max_output 사이로 제한시키라는 겁니다. 0보다 작으면 0이 되고, max_output으로 지정한 숫자보다 크면 max_output이란 값이 저장됩니다.


  if (error_pid_y >= 0) { ////////////////////////이 부분은, pid를 통해 나온 값의 부호에 따라

    front.write(PID_value+min_output);/////////각각 모터에 출력을 걸어주라는 소리입니다.

    

  }

  if (error_pid_y < 0) {

    back.write(PID_value+min_output);

    

  }


  kalAngleY1 = kalAngleY;

  error_pid_y2 = error_pid_y1; //이부분은 pid 제어를 위해, 이전 값들을 새롭게 저장하는 부분

  error_pid_y1 = error_pid_y;

  m_y1 = m_y;


}



이 부분은 y축 방향 pid 제어 코드입니다. 이와 똑같은게 x 축으로도 하나 더있구요.

여기서 중요한 부분은, 굵은 글씨로 되어있는 부분입니다.


굵은 부분이 이번에 바꾼 알고리즘 부분인데요.


처음에 저희가 했던 코드는 굵은 부분이 그냥 PID_value가 들어갔습니다.

그런데 pid_value는 constrain 함수 때문에 min과 max 값으로 제한이 되어있었어요. (지금은 0과 max로 바뀐 상태)


그래서 문제가 발생했습니다.

각도 차이가 남에 따라 pid 값이 생기긴하는데, 그 값이 0부터 ~~~~~~~~ 끝까지 변하는데요.

min 값때문에 제한이 되어있다보니, 아무리 0으로 가도 minimum 값이 계속 유지되는게 문제였습니다.


그림으로 표현해볼까요?




네 발로 그렸습니다. 

먼저 빨간줄은 저희가 원래 입력했던 pid_value의 min 값입니다. 즉 아무리 작아도 이거보단 크게 설정해놓은 거지요.

그래서 어떤 일이 발생했느냐? 우측 그림을 보시면 됩니다.


원래 pid값인 검은색은 min보다 작게 내려가는데, 저희가 constrain으로 걸어놓은 min값때문에 빨간색이 입력되게 됩니다.

자연스럽지가 않죠? 저 꺾이는 부분 때문에 정밀한 제어가 힘들다는 얘기입니다.


그렇다면 위에 제가 올린, 지금 사용하는 코드는 어떤 것이냐?





이러합니다.

min값을 constrain 안에 두지 않고, 굵은 글씨로 해놓았듯이 입력값에 더해버린거죠.

즉 검은 그래프를 그대로 위로 평행이동한 꼴입니다. 이렇게되면 훨씬 정밀한 제어가 가능해진다는 소립니다.


그래서 비교영상을 준비했어요.





이건 pid 제어가 제대로 안될때입니다.

보시다시피, 정밀 제어가 되지 못하고 계속 시소만 타는 모습을 보실 수 있습니다. 





이게 위 코드를 적용한 것입니다.

시리얼 모니터로 확인해본 결과, 약 1도 정도 시소 타는 것을 확인할 수 있었습니다. 아까보단 확실히 정밀해졌죠?
이제 문제는 게인값만 맞추면 된다는 사실!






아직까지 해결해야할 문제들이 많습니다.

우선 실험 조건이 매우 열악해서....... 출력을 크게 해볼 수가 없는 상황이고요.

출력을 키우면 묶어놓은 줄이 흔들려서 pid 제어 자체가 불가능해지는 상황이 와버립니다.


그리고 블루투스로 신호를 쏴줄 때 값이 튀는 것 때문에, 조종기 역할을 지금 제대로 못해주고 있습니다.

이 부분이 앱 문제인지, 바우드 레이트 문제인지는 실험을 통해 더 검증해나갈 생각입니다.