【 아두이노에러해결#4】 서보모터 떨림, 흔들림, 불안정 현상 해결! servo shaking problem (SG-90)
아두이노/6. 아두이노에러 2019. 6. 21. 18:39【 아두이노에러해결#4】 서보모터 떨림, 흔들림, 불안정 현상 해결! shaking problem (SG-90)
아두이노에서 SG-90과 같은 서보 모터를 제어할 경우, 작동은 되지만, 한가지 골치 아픈 문제에 직면하게 된다. 바로 모터를 원하는 위치로 회전 시킨 후 정지(홀드)해야 하는 상황에서 가만 있지 않고 달달? 덜덜? 떨게 되는 것이다. 회전만 하면 되는 경우면 상관 없지만, 제어 된 위치를 고정적으로 유지시켜야 하는 상황에서는 굉장히 못 마땅한 동작이 아닐 수 없다. 이 문제의 해결방법은 국내(사이트)에는 자료가 거의 없는 상황이다. 그리고 해외에서도 관련된 고민? 사항이 특정 사이트의 Q&A에 종종 올라오고 있지만, 속 시원히 해결 되었다는 메세지는 잘 보지 못했다.
이와 관련하여, 본인도 블루투스 원격 제어 예제 회로를 구성하면서 같은 문제가 발생하였는데, 이 문제를 고민하는 과정에서 알게된 해결방법을 여기에 기술 하고자 한다.
[ 문제 증상 ]
1. 가변저항(Var)을 조절하여 그 입력 값에 따라 서보모터를 회전 시키는 예제.
(서보모터의 사시나무 떨듯 환장?하는 영상)
(물론 단순 가변저항 예제의 경우 거의 떨지 않는 경우도 있으나, 컨트롤을 위해 센서를 사용하거나, 회로 및 코드 구성이나 단계가 조금만 복잡해져도 떨림현상을 쉽게 목격할 수 있을 것이다)
[ 먼저 확인해 봐야할 문제 원인 ]
※ 먼저, 지금 설명드리는 예상 원인을 확인해보고, 해결이 안 된다면, 아래 내용으로 진행해 보세요.
서보 모터의 경우, 20ms를 한 주기로, 그 주기 속에, 1ms~2ms의 High 신호의 펄스로 정해진 각도로 움직이도록 설계되어 있습니다.
예를 들어, 1ms의 High 펄스가 입력되면, 서보모터가 0도의 위치로 회전하게 되며, 2ms의 High 펄스가 입력되면, 180도의 위치로 회전하게 되고, 1ms~2ms 사이의 High 펄스 값에 따라, 0도~180도 사이의 각도로 매칭되어 움직이게 됩니다.
혹은, 아래 이미지에 있는 설명대로, -90도 ↔ 0도 ↔ 90도 형태를 기준으로 (1ms ↔ 1.5ms ↔ 2ms) 생각할 수 있습니다. 어째튼 중요한 것은, 0~180도의 각을 움직이는 펄스 파형의 기준이 1ms~2ms 범위라는 것인데요,
문제는 서보모터의 경우 1ms~2ms의 범위에 제품마다 일치하지 않는 오차가 있다는 것이고, 많은 곳에서 제작되는 매우 저렴한 서보모터의 경우 이 오차가 제법 클 수 있습니다.
오류가 나는 경우의 예를 들면, 0도로 회전 시키기 위해 1ms의 신호를 주었으나, 실험에 사용된 서보모터의 실제적인 제어신호 범위가 1.2ms ~ 2.2ms 였다면, 1ms의 신호를 준 것이 서보모터가 회전하는 범위를 벗어나게 되는데, 강제로 이동시키는 신호가 오다보니 기어가 내장된 부분에서 떨림의 현상이 올 수 있다는 이야기입니다.
이런 경우의 해결책은, 제어범위를 실험을 통해서 확인해 내거나, 혹은, 제어범위를 초과하지 않게 미만의 범위로 신호를 주면 해결할 수 있습니다. 위 예의 경우, 1ms를 주지 말고 1.3ms나 1.2ms 이하로 신호를 주면 떨림이 해결될 수 있다는 말입니다. 그리고, 이상적인 180도 회전 서보모터의 경우 0도~179도 로 회전 하는 것이지만, 실제적으로는 2도~177도 정도의 범위를 갖는 것이 일반적이기 때문에, 만약 떨림이 있다면, 2~177도 사이의 제어 신호를 주는게 맞습니다.
[ 문제 원인 ]
1. 우선 본질적인 원인은 서보모터의 구조와 작동 방식에 있다.
(서보모터의 작동 원리) 위 이미지를 보면, 서보모터 신호라인으로 그림과 같은 펄스파(PWM)를 입력 시키는데, 기본적으로 입력되는 펄스 간격을 체크하여 지정된 각도 만큼 움직이도록 작동 된다.
펄스 자체의 반복주기는 20ms로 고정하고, 펄스의 폭을 1ms~2ms 사이로 조절하게 되면, 첫 펄스 파형과 그 다음 펄스 파형 사이의 간격(시간)이 달라지게 된다. 즉 1ms 일때 보다, 2ms로 갈수록 high 신호의 반복주기가 짧아지는 것이다. 따라서, 펄스 폭이 1ms인 펄스를 발생시켜 입력시켜 주면, 서모 모터를 0도에 위치시키도록 하고, 설정된 최대 폭인 2ms로 입력시키면, 180도로 회전 시키도록 설계 되어 있다. 그럼, 1ms와 2ms의 중간 값인 1.5ms를 넣어 주면 0도~180도의 중간 값인 90도의 위치로 회전축이 이동 된다. 역시, 1ms~2ms 펄스폭 사이에 있는 값에 따라 0도~180도로 회전 하게 되는 원리이다.
그런데, 0도가 되었든, 90도가 되었든, 해당 각도를 유지하려면 그 것에 맞는 펄스가 정확히 유지되어(일정하게) 입력되어야 하는데, 그렇지 못하기 때문에 결국 변동되는 펄스 폭 만큼 모터가 작동되면서 떨게 되는 것이다.
그럼, 펄스폭이 왜? 유지가 되기 힘든가? 여러가지 원인이 있지만, 주요한 원인을 고민해 보자면,
1. 서보모터가 작동하는 순간, 아두이노에 모터구동에 따른 노이즈가 입력되거나, 전력의 변동(요동)이 발생된다. 또는 출력저하 등의 이유로 전력의 불안정은 제어하는 센서의 값(또는 제어 코드 기준값)에 영향을 주게 된다. (센서를 이용한 제어보다, 가변저항등의 직접제어가 좀더 안정적인 이유임) . 결국, 서보모터 등과 관련하여 전원분리 및 안정적인 공급을 통해 해결하거나 다소 완화시킬 수 있다.
2. 사용하는 서보모터 마다 특성이 조금씩 차이 나는 것으로 보이며, 일반적으로 서보모터의 이론적인 제어 기준은 20ms 주기에 1~2ms의 신호로 제어 한다고 나와 있으나, 사용되는 모터마다 주기 범위등의 오차가 있어 해당 범위가 넘어가는 제어신호가 입력 될 경우, 흔들림이 발생할 수 있는 것으로 추측됨.
[ 문제 해결 ]
1. 기본 조치 : 조금전에 설명한 대로 기본적으로 서보모터를 구동하는 전원을 안정화 시키거나 보강해줄 필요가 있다. - 서보모터에도 별도의 전원을 공급하거나, 전원 보강을 위해 아두이노혹은 서보모터 쪽 전원(+,-)에 10uf~330uf 정도의 전해콘덴서를 연결 (극성 주의: 콘덴서의 +단자는 +전원에, -단자는 GND에 연결)
- 노이즈 제거를 위해 서보 모터 신호라인(주황색선)과 GND 사이에 극성이 없는 세라믹콘덴서을 달아 준다. (노이즈 바이패스)
2. 하드웨어적인 해결 :
- 슈미트 트리거 회로 혹은 IC를 이용하여 노이즈 등에 의한 원하는 펄스 파형이 나오지 않아 찌그러진 형태의 구형파가 입력되어 흔들림이 발생한다는 가정을 하여, 실험을 실시해 볼 가능성이 있어 보임. ( 이 부분은 가설을 이야기해 본 것이며, 실험이나 검증이 필요함, 당연히 원인이 구형파의 노이즈에 의함이 아닌 3번의 코드상에서의 해결책과 같은 VAR 입력값에 의한 것일 경우 이 방법은 적용해볼 필요 없음.)
3. 코드상에서 해결( 분기값, 임계값 등)
- 부가적인 하드웨어 없이, 소프트웨어(코드 보강)적으로도 개선 시킬 수 있다.
- 오류가 발생되지 않도록 컨트롤 데이터를 맞추어 준다.
: 예를 들어 가변저항의 입력값을 아날로그 단자(A0)로 받으면 0~1023의 값이 입력 되고, 이를 각도값인 0~180도로 맵핑 처리하게 되는데, 이 값을 좀더 정확하게 잡아 주면 좋다. → VAR = map(analogRead(A0), 0, 1023, 0,180) 라면, 좀더 정확하게 0, 179 로 하거나, 실제적인 서보모터의 특성상 180도 전체가 움직이지 않는 다고 보고, 5~175도 정도로 값을 조정해볼 수 있다. 또한 이 값의 범위를 오류 등에 의해 벗어 나지 않토록 constain 함수 처리를 해주면 좋다. → VAR = map(analogRead(A0), 0, 1023, 5, 175)); , VAR_OK = constrain(VAR, 5, 175);
이 경우는 모터의 양 쪽 끝에서 떠는 현상을 완화 시켜줄 것이다. 하지만, VAR 등으로 값을 변화 시킴에 따라 모터가 회전해야 하는 경우에 발생하는 떨림의 해결도 필요하다. 이 경우에는 VAR값에 의한 각도 값 "1,2,3,4,...179" 을 1단위로 모터회전 처리하지 말고, 유동 범위 값을 주어 처리하면 된다. 각도 값을 시리얼 모니터로 관찰 해보면 숫자 값 끝자리가 1~2 정도 왔다 갔다 하는 것을 볼 수있을 것이다. 이 런 값들이 모터 회전에 지속적으로 영향을 주니 모터가 떨게 된다. 따라서 이런 경우에는 값의 변화가 3~5이하는 모터가 회전 하지 않도록 하는 코드를 넣어 해결 할 수 있다. 아래에 이와 관련한 보강된 코드를 기술하였으니, 참고하길 바란다.
※ 즉, 본 게시글에서 해결한 방법은 VAR 값(ADC변환값)의 변화가 시리얼 모니터로 확인해 보면 1~2 값 정도씩 잦은 변화를 일으키고 있어 이것이 그대로 모터에 반영되다 보니 떨림이 나타나는 것으로 보이기 때문에, -4 ~ +4 사잇 값의 VAR값 변화는 그냥 무시하는 형태로 코드를 추가해 넣어 해결해 본 것으로 실습 하였으니 참고하세요.
- 서보모터 연결을 해제 하는 명령어를 이용한다.( detach() )
블루투스 통신회로에 이 것을 실험해 본 결과 가장 개선 효과가 큰 방법이었다. (적용 회로에 따라 다를 수 있음)
즉, 서보모터를 아두이노 코드 라이브러리로 제어할 때 서보모터와 연결 시키는 코드인 "attach(xx) " 함수를 사용하여 해당 핀 번호에 연결시켜 제어하게 되는데, 특정 순간에는 연결 해제하는 명령인 detach()를 사용하여 작은 입력 값의 변동에 대해서는 서보모터를 작동 시키지 않도록 하는 일종의 트릭을 사용해서 해결 할 수 있다.
[ 해결 코드 (예시)]
A. 기본 코드 예시)
#include <Servo.h>
#define servoPin 10
#define VAR A0
Servo myservo;
void setup() {
Serial.begin(9600);
myservo.attach(servoPin); //10번 핀과 모터 연결
pinMode(servoPin, OUTPUT);
}
void loop() {
int varValue = map(analogRead(VAR), 0, 1023, 0, 179);
Serial.println(varValue);
myservo.write(varValue);
delay(10); // 서버모터가 움직일 시간을 트
}
B. 보강 코드 예시)
#include <SoftwareSerial.h>
#include <Servo.h>
#define servoPin 10
Servo myservo;
#define VAR A0
int conVAR=0;
int currentVar=0;
int previousVar=0;
void setup() {
Serial.begin(9600);
myservo.attach(servoPin); //10번 핀과 모터 연결
pinMode(servoPin, OUTPUT);
}
void loop() {
conVAR = map(analogRead(VAR), 0, 1023, 0, 179);
currentVar = constrain(conVAR,2,178);
Serial.println(currentVar);
// 0~4 사이 값의 변화는 모터에 출력을 보내지 아니함 (값 조절 가능)
if ((currentVar > previousVar+4) or (currentVar < previousVar-4)) {
myservo.attach(servoPin);
myservo.write(currentVar);
delay(90); // 서버모터가 움직일 시간을 줌
previousVar = currentVar;
}
// 서보모터 연결을 해제하는 트릭으로 모터가 움직이지 않토록 함
myservo.detach(); // 서보모터 연결 해제
}
<보강된 코드로 해결 된 영상>
※ 매우 만족스럽게 해결 된 것을 볼 수 있다.
물론, 단순히 위의 기본 코드만 가지고, 별다른 센서 사용없이 직접제어를 한다면, 보강 코드 없이도 서보모터의 떨리는 증상 없이 잘 작동 할 수는 있다. 하지만, 서두에서 언급한 것 처럼, 특정 센서나 블루투스 모듈등을 사용하여 응용하거나 할 때 이런 문제가 심각하게 발생할 수 있다. 또한 반드시 해결하기를 원한다면, 이상과 같은 처리나 보강 코드로 해결을 시도해 보기 바란다. 물론, 적용하려는 회로에 따라 해결이 바로 안 될 수도 있겠지만, 앞서 설명한 내용을 차분히 되짚어 본다면, 충분한 해결점에 도달 할 수 있을 것으로 생각된다.
'아두이노 > 6. 아두이노에러' 카테고리의 다른 글
【 에러 디버깅 】 아두이노 스케치 IDE 사용중 'WProgram.h ' 라이브러리 에러 발생! (0) | 2020.11.10 |
---|---|
【아두이노 에러】잘 실행되던 아두이노IDE가 갑자기? 실행되지 않을 때, 해결법! (1) | 2020.06.19 |
【 아두이노에러잡기#3】 버튼 디바운싱 해결하기 (with LCD) (2) | 2019.03.18 |
【 아두이노 에러 잡기 】 #2 exit status 1 컴파일 에러 (0) | 2018.06.18 |
【 아두이노 에러 잡기 】 #01 exit status 1 stray '\' in program (0) | 2018.04.06 |