1. 길고 긴 시작
때는 2015년, 한창 Kickstarter 에 열을 올려, 이것 저것에 투자(?) 하고 있을 때,
당시 저에게는 너무 생소한 Gimbal 이라는 것을 접하게 됩니다.
지금이야 드론이나 스포츠 경기 촬영, 또는 일반인이 손으로 가지고 다니면서 흔들림 방지 해주는 분야에까지 널리 사용되지만,
이 때까지만 해도 이런 종류의 기기는 전문가 집단만 사용하고 있었죠.
다 제껴두고 아래 소개 동양상 보고 홀딱 반해서 투자하게 됩니다. 75 USD...
* Gimbal for your Lights Camera or Action
- https://www.kickstarter.com/projects/2035152529/gimbal-for-your-lights-camera-or-action/description
일단 동영상을 함 봐보세요. 2015년 감각으로... 사고싶어 지죠?!
당시에는, 아무 생각 없이 투자한 것이라, 어떻게 활용할지, 어떻게 컨트롤 할지 상상도 못하고 있었습니다.
제품이 도착 후, servo 로 움직인다는 것을 알고 (도착해서야!) arduino 를 활용해 기본적인 동작만 확인하고 쳐박에 두었습니다.
왜냐 하면, arduino 에 대한 지식이 얕았기에 뭘 더 할 수가 없었거든요.
아래는 지금까지 gimbal 과 관련된 포스트 들 입니다.
* Hardware | Arduino 로 Servo 를 움직여 보자
- https://chocoball.tistory.com/entry/Hardware-Arduino-Servo
* Hardware | Arduino 의 Sensor Shield 사용해 보기
- https://chocoball.tistory.com/entry/Hardware-Arduino-Sensor-Shield
* Hardware | Dual-axis XY Joystick Module
- https://chocoball.tistory.com/entry/Hardware-dual-axis-XY-Joystick-Module
마지막으로 Joystick 모듈을 사용해 보고서, 드디어! gimbal 활용의 완성판을 작성할 수 있을것 같아, 이 글을 쓰기 시작했습니다.
2. 연결
최종 목적은 Joystick 을 가지고, Gimbal 을 상하좌우 움직이는 것 입니다.
이게 단순하지만, Joystick 의 운동 한계성으로 그리 쉽게는 되지 않더군요.
일단, Arduino > Joystick > Gimbal (servo) 를 아래와 같이 연결합니다.
Joystick | Arduino Nano -------------------------- GND | GND 5V | 5V VRX | A0 VRY | A1 SW | D2 -------------------------- Servo 1 | -------------------------- RED | 5V BLACK | GND SIGNAL | D9 -------------------------- Servo 2 | -------------------------- RED | 5V BLACK | GND SIGNAL | D8 --------------------------
실제 diagram 은 다음과 같습니다.
실제 코드에서는 Joystick 의 SW_pin 이 D2 에 연결되는 등, 위의 그림과 조금 다릅니다만, 대략적인 연결 구조만 보시면 되겠습니다.
3. 간단 구동
일단 Joystick 이 유효한 방법인지 알아볼 수 있는 간단한 코드 입니다.
인터넷 어디에선가 참조했는데 링크를 까먹었습니다. 간단한 연결법이라 검색해서 쉽게 찾을 수 있습니다.
#include "Servo.h" Servo myservo1; // create servo object to control a servo Servo myservo2; int potpin1 = A0; // analog pin used to connect the potentiometer int potpin2 = A1; int val; // variable to read the value from the analog pin void setup() { myservo1.attach(9); myservo2.attach(10); // attaches the servo on pin 9 to the servo object } void loop() { val = analogRead(float(potpin1)); // reads the value of the potentiometer (value between 0 and 1023) val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180) myservo1.write(val); // sets the servo position according to the scaled value delay(15); // waits for the servo to get there val = analogRead(float(potpin2)); // reads the value of the potentiometer (value between 0 and 1023) val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180) myservo2.write(val); // sets the servo position according to the scaled value delay(15); }
아래는 연결하고 실제 구동 영상입니다.
잘 돌아가쥬?
단, 여기서 문제점들이 몇가지 있습니다.
- ripple value
회로적인 문제로 ripple 값이 발생하여, 조이스틱을 움직이지 않았지만 덜덜 떨거나 깔끔한 움직임이 나오지 않습니다.
ripple 를 제거 해야 합니다.
- speed
돌아가는 속도가 너무 빨라, 원하는 방향으로 위치하기가 힘듭니다.
- available range
X 축의 경우, 90 돌아가지만, gimbal 은 360 가 돌아가게끔 되어 있습니다.
CCTV 등 에 사용된다고 가정하면, 필요 없는 각도나 회전은 발생하지 않게끔 해야 합니다.
- last position
Joystick 의 성질 상, 움직힘 후 가운데로 되돌아 옵니다.
특정 위치를 잡게 하려면 동작시키지 않을 때에는 마지막 위치를 기억하고 있어야 합니다.
- centering
어떤 위치에서든 다시 초기 위치로 되돌아 오는 기능이 있으면 편할 것 같습니다.
이 글의 나머지 부분은, 결국 위의 문제를 해결하는 내용으로 진행됩니다.
4. Ripple Value
Joystick 을 가만히 놔둬도 계속 떨거나, 움직일 때 자연스럽지 못합니다.
Serial Monitor 로 값의 변화를 찍어 봤죠.
아무것도 안했는데도 값이 출렁 거립니다.
전후값을 비교해 보니, 가만히 있어도 최대 11 정도 값이 변하는 것을 알 수 있습니다.
그래프로 도식화 해보면, 그 현상을 충분히 알 수 있습니다.
이는 전기적인 ripple 일 수도 있습니다.
* How can I filter out noise from ADC lines without delay or signal change?
+5V +5V | | (sensor)---resistor---+---(Arduino) | | | | capacitor | | | | GND----------------GND-----GND
이 경우 RC 필터를 넣으면 됩니다. 캐패시터 값으로 0.1uF capacitor 를 사용하면 적절하다고 하네요.
So if you are sampling at around 1000 Samples/second (i.e., a sampling interval of 1 millisecond), then 100 Ohms of resistance and (roughly) 100 uF ceramic capacitor may be adequate. (The RC time constant here is RC == 100 Ohms x 100 uF = 10 milliseconds).
다만, 저항이 들어가면서 값의 외곡이 생기니 software 적으로 처리하기로 합니다.
0 512 1023 <---------------|---------------> 497 | | 527
그럼 어떻게 하느냐.
Joystick 에서 arduino 로 보내지는 전체 analog 신호 0~1023 에서,
정 가운데 앞뒤로 15씩 잘라, 이 구간의 ripple 이나 작은 움직임을 무시하기로 합니다.
... if ( (0 <= val) && (val < 497) ) { myservo1.write(angle1--); } else if ((527 <= val) && (val < 1024)) { myservo1.write(angle1++); ...
위의 코드에서 보면, 중간값을 잘라 낸 앞뒤 값에서 val 을 읽어 들이는 것으로 했습니다.
5. Speed & Last Poision
원래 소스에서는 최종 위치로 바로 움직이도록 값을 넣어 주지만, 수정된 소스에서는 각도를 1도씩 움직이게 했습니다.
그러면서, delay 값을 낮춘 채로 유지했습니다.
... if ( (0 <= val) && (val < 497) ) { myservo1.write(angle1--); } else if ((527 <= val) && (val < 1024)) { myservo1.write(angle1++); } else { // do nothing } ... delay(10); ... if ( (0 <= val) && (val < 497) ) { myservo2.write(angle2--); } else if ((527 <= val) && (val < 1024)) { myservo2.write(angle2++); } else { // do nothing } ... delay(10); }
속도에 변화를 더 주고 싶으면, angle 은 1도씩 움직이는 것은 놔두고, delay 를 조정 합니다.
저는 delay(10) 이 가장 적절했습니다.
또한, 최종 각도를 입력하는 것이 아닌, 한쪽 방향으로 움직임만 있으면 (exist) 1도씩 움직이게 한 결과,
자연스럽게 마지막 위치에서 멈춰있게 되었습니다.
6. Available Range
180도로 움직이는 Servo 를 풀로 사용하면, 카메라를 달았을 때, 촬영 범위를 벗어나거나 회전하게 됩니다.
일단 Y 축 servo 를 생각하면,
천장과 땅바닥을 촬영 각도에서 빼게 된다면, 전체 180 도에서 140도로 좁히면 됩니다.
그렇다면, 20 > 160 도 사이를 움직이게 코딩해 줍니다.
X 축은 180 회전이 720도 회전, 90 회전이 360도, 45 회전이 180도, 22.5 회전이 되어야 비로서 90도가 됩니다.
즉, 좌우로 22.5 를 먹여야 원하는 좌우 180도로 움직이는 결과가 되지요.
... if ( (67 < angle1) && ( angle1 < 112) ) { // making available range ... } else if ( angle1 == 67) { angle1++; } else if ( angle1 == 112) { angle1--; } ... if ( (20 < angle2) && ( angle2 < 160) ) { // making available range ... } else if ( angle2 == 20) { angle2++; } else if ( angle2 == 160) { angle2--; } ...
코딩에서는 90도가 center 이므로, 이 중간을 기준으로 좌우 +/- 한 값으로 범위를 정의했습니다.
위의 소스 마지막 부분에서, 각도의 끝에 있는 값에서 +1 / -1 씩 해준 이유는, 계속 범위 안에 들기 하기 위함입니다.
이게 없으면, 1도씩 움직이던 angle 값이, 범위 밖으로 나가면서 예외상황에 빠지게 됩니다.
코딩 해보신 분이라면, 예외사항 처리가 얼마나 중요한지 아실꺼예요.
7. Centering
Joystick 에서 SW_pin 이 존재합니다.
유일하게 digital 입력이며, 조이스틱을 누르면 딸깍 하는 소래를 내는 그 부분 입니다.
마침 잘 된 거죠. Centering 을 이 SW_pin 을 사용하면 됩니다.
#include "Servo.h" const int SW_pin = 2; // digital pin for centering ... void setup() { pinMode(SW_pin, INPUT); digitalWrite(SW_pin, HIGH); ... } void loop() { if (!digitalRead(SW_pin)) { angle1 = 90; angle2 = 90; myservo1.write(angle1); myservo2.write(angle2 ); } ... }
SW_pin 에 입력이 있으면, 중앙이 되는 90 도를 강제적으로 input 하게 하면 됩니다.
8. 정리
지금까지 해결했던 문제들을 한데 모아 소스코드로 만들면 아래와 같이 됩니다.
#include "Servo.h" const int SW_pin = 2; // digital pin for centering Servo myservo1; // create servo object to control a servo Servo myservo2; int potpin1 = A0; // analog pin used to connect the potentiometer int potpin2 = A1; int val; // variable to read the value from the analog pin int angle1 = 90; int angle2 = 90; void setup() { pinMode(SW_pin, INPUT); digitalWrite(SW_pin, HIGH); myservo1.attach(9); myservo2.attach(10); // attaches the servo on pin 9 to the servo object myservo1.write(angle1); myservo2.write(angle2); delay (1000); // initalizing } void loop() { if (!digitalRead(SW_pin)) { angle1 = 90; angle2 = 90; myservo1.write(angle1); myservo2.write(angle2 ); } val = analogRead(float(potpin1)); // reads the value of the potentiometer (value between 0 and 1023) if ( (67 < angle1) && ( angle1 < 112) ) { // making available range if ( (0 <= val) && (val < 497) ) { myservo1.write(angle1--); } else if ((527 <= val) && (val < 1024)) { myservo1.write(angle1++); } else { // do nothing } } else if ( angle1 == 67) { angle1++; } else if ( angle1 == 112) { angle1--; } delay(10); val = analogRead(float(potpin2)); // reads the value of the potentiometer (value between 0 and 1023) if ( (20 < angle2) && ( angle2 < 160) ) { // making available range if ( (0 <= val) && (val < 497) ) { myservo2.write(angle2--); } else if ((527 <= val) && (val < 1024)) { myservo2.write(angle2++); } else { // do nothing } } else if ( angle2 == 20) { angle2++; } else if ( angle2 == 160) { angle2--; } delay(10); }
코드의 최적화는 생각하지 않고, 오로지 구현에만 신경쓴 소스입니다.
모든 구현이 들어간 코드를 입힌 동영상 입니다.
원하는 수준까지 동작 구현이 되어서 기분이 좋네요.
향후, ESP8266 을 이용하여 원격 조정이나 Web UI 를 통한 컨트롤도 가능하겠습니다.
모두 happy arudino~!
'Hardware' 카테고리의 다른 글
Hardware | 공기질 측정용 MiCS-6814 센서를 사용해 보자 - 1 (26) | 2019.10.12 |
---|---|
Hardware | LCD2004 를 arduino 로 컨트롤 해보기 - 1 (0) | 2019.10.08 |
Hardware | 재생토너 chip 교환기 - 2 (0) | 2019.10.04 |
Hardware | SMD 부품 납땜용 오븐 취득기 (0) | 2019.10.02 |
Hardware | ebook 크레마 사운드업 액정 수리기 (27) | 2019.10.01 |