Arduino, 서보모터

서보모터 SG-90

  • 모터드라이버, 회전센서, 모터, 제어회로가 내장된 기어 박스를 포함하고 있는 형태의 모터로, 스텝모터보다 힘이 강함
  • 보통 선이 3가닥이며, 회전수와 각도 등의 움직임 제어가 가능
  • 아두이노에서 많이 다루는 SG90 제품의 경우 0~180˚ 제어가 가능
  • 아두이노UNO의 USB 전류량이 500mA 정도가 한계이므로 별도의 전원을 사용하지 않으면 1~2개의 서보모터만 사용 가능

라이브러리 추가하기

서보모터를 사용하기 위한 Servo 라이브러리는 아두이노 IDE에 기본으로 포함되어 있다.

  • 스케치> 라이브러리 포함하기> Servo 를 선택하면,
  • #include <servo.h> 라이브러리가 스케치에 추가 된다.

schematic

SG90 Brown Red Orange
Arduino GND 5V 10

sketch : 서보모터 180º 회전 왕복하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <Servo.h>

Servo servomotor; // servomotor 선언
int position = 0;

void setup() {
servomotor.attach(10); // servomotor 핀 설정
}

void loop() {
for(position = 0; position < 180; position++)
{
servomotor.write(position); // pos값의 위치로 이동
delay(15);
}
for(position = 180; position > 0; position--) // 같은 방법으로 역회전
{
servomotor.write(position);
delay(15);
}
}
  • servomotor.write(숫자)를 사용할때, 숫자는 현재 위치에서의 ‘회전각’을 의미하는 것이 아니다!
  • 초기 위치를 0º로 기준삼아, 표시된 숫자의 각도 위치로 이동하라는 의미이다. 예를들어서 servomotor.write(90)와 servomotor.write(30)을 연속으로 실행하면,
    • 90도를 회전한 뒤, 추가로 30도를 회전하여 120도 위치에 있다 → ×
    • 90도의 위치로 회전한 뒤, 역회전하여 (처음위치를 기준으로) 30도의 위치로 이동한다. → ○
  • 단, servo.h 라이브러리를 사용하면, 스케치 내에서 analogWrite를 사용할 수 없다는 단점도 있다.

sketch: 시리얼모니터에서 각도값을 입력받아 회전시키기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <Servo.h>
Servo servomotor;
int a = 0;

void setup() {
servomotor.attach(10);
Serial.begin(9600); // Serial 통신을 설정
while(!Serial);
Serial.println("Servor Mortor");
}

void loop() {
if(Serial.available()){ // Serial 모니터창에 어떤 값이 들어오면 실행
a = Serial.parseInt(); // Serial 모니터창에서 받은 값을 a에 넘겨줌
if(a>=0 && a<=180)
{
Serial.print("angle : ");
Serial.println(a);
servomotor.write(a); // a값에 해당하는 각도의 위치로 이동
delay(15);
}
}
}


서보모터 SG-90: 라이브러리 없이 사용하기

for SG90 with Arduino

  • Frequency of that signal should be 50hz.
  • Its range is 544-2450 micro seconds for 0-180 degree angle.
  • Again its a little complex.
  • For example 0 degree signal will be something like 5 volts for 544 micro seconds and 0 volt for 19465.
  • highDelay
    • the time in which we want to keep voltage high on pin 10 and this unit is in micro seconds.
  • lowDelay
    • the time in which want to keep voltage zero across pin 10 again this unit is going to be in micro seconds
  • only HIGH part of signal wont operate servo. we have to send complete HIGH and LOW signal to make servo work.
  • deg_factor
    • signal range (2450 - 544) for SG90 divided by 180 which is equal to 10.6 something that we make 11 as an integer.
  • Loop = 20000;
    • 20000 micro seconds or 20 milli seconds is signal cycle or u can say total signal should be equal to 20 milli seconds including HIGH and LOW input. (50Hz)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int servoPin = 10;        // servo is connected to pin 10.
int initialDelay = 544;
int highDelay, lowDelay;

int deg;
int deg_factor = 10;
int Loop = 20000;

void setup() {
pinMode (servoPin, OUTPUT);
}

void loop() {
for (deg = 0;deg <= 180; deg++) {
servoWrite(servoPin, deg);
}
for (deg = 180;deg >= 0; deg--) {
servoWrite(servoPin, deg);
}
}

void servoWrite(int servo, int duty)
{
highDelay = initialDelay + (duty * deg_factor); // setting angle

digitalWrite(servo, HIGH);
delayMicroseconds(highDelay);

lowDelay = Loop - highDelay;
digitalWrite(servo, LOW);
delayMicroseconds(lowDelay);

delay(500);
}

시리얼 모니터에 입력한 문자로 서보모터 회전시키기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int servoPin = 10;        // servo is connected to pin 10.
int initialDelay = 544;
int highDelay, lowDelay;

int deg = 90; // servo initial degree
int deg_factor = 10;
int Loop = 20000;

void setup() {
Serial.begin(9600);
pinMode (servoPin, OUTPUT);
}

void loop() {
servoWrite(servoPin, deg);

while(Serial.available() > 0)
{
char flag=Serial.read();
delay(2);

if(flag=='l') {
deg = deg - 5;
if(deg < 0) {
deg = 0;
}
}

if(flag=='r') {
deg = deg + 5;
if(deg > 180) {
deg = 180;
}
}
}

void servoWrite(int servo, int duty)
{
highDelay = initialDelay + (duty * deg_factor); // setting angle

digitalWrite(servo, HIGH);
delayMicroseconds(highDelay);

lowDelay = Loop - highDelay;
digitalWrite(servo, LOW);
delayMicroseconds(lowDelay);

delay(500);
}
  • l 을 입력하면, 5도 좌회전하며, ll을 입력하면 10도 좌회전한다.
  • r 을 입력하면, 5도 우회전하며, rr을 입력하면 10도 우회전한다.


서보모터와 인터럽트 동시에 사용하기

서보모터가 180도 회전하는 동안, 스위치를 누르면 13번 LED가 토글되도록 만들어보자.


schematic


sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
int servoPin = 10;        // servo is connected to pin 10.
int initialDelay = 544;
int highDelay, lowDelay;

int deg;
int deg_factor = 10;
int Loop = 20000;

#define swPin 2
#define ledPin 13
#define debounceTime 500 // Set debounce Time (unit ms) 버튼을 누른 후 0.5sec 이내에는 버튼 체크하지 않음

boolean state = false;

void setup() {
pinMode(servoPin, OUTPUT);
pinMode(swPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(swPin), swInterrupt, FALLING);
}

void loop() {
for (deg = 0;deg <= 180; deg++) {
servoWrite(servoPin, deg);
}
for (deg = 180;deg >= 0; deg--) {
servoWrite(servoPin, deg);
}
}

void servoWrite(int servo, int duty)
{
highDelay = initialDelay + (duty * deg_factor); // setting angle

digitalWrite(servo, HIGH);
delayMicroseconds(highDelay);

lowDelay = Loop - highDelay;
digitalWrite(servo, LOW);
delayMicroseconds(lowDelay);

delay (15);
}

void swInterrupt() {
static unsigned long lastTime = 0;
unsigned long now = millis();

if((now-lastTime) > debounceTime) {
state=!state;
}
lastTime = now;

digitalWrite(ledPin, state);
}
  • 스위치를 눌렀다 뗄 때, 물리적 요인에 의해 다시 스위치가 눌리는 효과가 나타나기도 함 (chattering)
  • Chattering 효과를 방지하기 위해, 하드웨어적으로 콘덴서를 붙이거나, 소프트웨어적으로 debounce 시간을 만들어 해결해야 한다.


레이저 모듈 추가: 서보모터 날개에 부착

schematic


sketch

13번 핀에 레이저모듈을 연결하므로 위 스케치를 그대로 이용



조도센서 추가

반대편에 조도센서를 놓고, 레이저 모듈이 움직이는 동안 버튼을 눌러 조도센서를 정확하게 맞추면 점수가 올라가는 게임을 만들어보자.



Keypad에서 값을 입력받아 회전시키기

schematic


sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <Servo.h>
#include <Keypad.h>

Servo servomotor;
int pos = 0;

const byte ROWS = 4; // 키패드 배열 선언
const byte COLS = 4;

char keys[ROWS][COLS] = { // 키패드 정의
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'},
};

byte rowPins[ROWS] = {9, 8, 7, 6}; // 키패드 연결 핀 설정
byte colPins[COLS] = {5, 4, 3, 2};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
servomotor.attach(10);
}

void loop() {
char keyValue = keypad.getKey();

if(keyValue) {
switch(keyValue) {
case '0' : // 시리얼 모니터에 0을 입력하면
servomotor.write(0); // 0도 위치로 이동
delay(15);
break;
case '1' : // 시리얼 모니터에 1을 입력하면
servomotor.write(15); // 15도 위치로 이동
delay(15);
break;
case '2' :
servomotor.write(30); // 30도 위치로 이동
delay(15);
break;
case '3' :
servomotor.write(45); // 45도 위치로 이동
delay(15);
break;
case '4' :
servomotor.write(60); // 60도 위치로 이동
delay(15);
break;
case '5' :
servomotor.write(75); // 75도 위치로 이동
delay(15);
break;
case '6' :
servomotor.write(90); // 90도 위치로 이동
delay(15);
break;
case '7' :
servomotor.write(120); // 120도 위치로 이동
delay(15);
break;
case '8' :
servomotor.write(150); // 150도 위치로 이동
delay(15);
break;
case '9' :
servomotor.write(180); // 180도 위치로 이동
delay(15);
break;
default :
break;
}
}
delay(10);
}


비밀번호 확인하여 서보모터 회전시키기

서보모터의 날개를 금고의 개폐장치로 사용하여, 비밀번호 금고를 만들어 보자.


sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <Keypad.h>
#include <Servo.h>

int tru=0; // 비밀번호가 맞는지 확인
int count=0; // 4자리수 카운트
char PW[4]={'1','2','3','A'}; //비밀번호

Servo servomotor;

// 키패드 설정 시작
const byte ROWS = 4;
const byte COLS = 4;

byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

char keys[ROWS][COLS] = {
{'1','2','3', 'A'},
{'4','5','6', 'B'},
{'7','8','9', 'C'},
{'*','0','#', 'D'}
};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
// 키패드 설정 끝

void setup() {
Serial.begin(9600);
servomotor.attach(10); // 서보모터 핀 설정
}

void loop() {
char key = keypad.getKey(); // 키패드 입력 변수

if (key) {
Serial.println(key);
if(key==PW[count]) { // 입력번호와 비밀번호가 맞으면
count++; // 자리수 카운트 1증가
tru++; // 맞은수 값 1증가
}
else if(key!=PW[count]) { // 입력번호와 비밀번호가 틀리면
count++; // 자리수 카운트 값만 1증가
}

if(key=='#') // #을 누르면
re(); // 초기화
if(count==4) { // 4자리 입력받은 값이
if(tru==4) // 모두 맞으면
Su(); // 성공
else // 그렇지 않으면(4자리는 입력했는데, 모두 맞지는 않았으면)
Fa(); // 실패
tru=0; // tru, count값 초기화
count=0;
}
}
}

void Su() { // 성공했을 때 실행
servomotor.write(90); // 90도 돌려서 도어락 열림
Serial.println("open the door");
}

void Fa() { // 실패한 경우는 도어락 잠금 유지
servomotor.write(0);
Serial.println("close the door");
}

void re() { // 비밀번호 입력중 #을 입력하면 초기화하고 도어락 잠금 유지
tru=0;
count=0;
servomotor.write(0);
Serial.println("password reset");
}


Joystick을 사용하여 2개의 서보모터 제어하기

schematic


sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define JSTICKPIN A0      // joystick is connected to pin 11

int servoPin = 10; // servo is connected to pin 10
int initialDelay = 544;
int highDelay, lowDelay;

int deg, Jstick, duty;
int deg_factor = 10;
int Loop = 20000;

void setup() {
pinMode (servoPin, OUTPUT);
}

void loop() {
PrintValue();

Jstick = analogRead(JSTICKPIN);
deg = map(Jstick, 0, 1023, 0, 180);
servoWrite(servoPin, deg);
}

void servoWrite(int servo, int duty)
{
highDelay = initialDelay + (duty * deg_factor); // setting angle

digitalWrite(servo, HIGH);
delayMicroseconds(highDelay);

lowDelay = Loop - highDelay;
digitalWrite(servo, LOW);
delayMicroseconds(lowDelay);

delay (15);
}

void PrintValue() {
Serial.print(analogRead(JSTICKPIN));
Serial.println (" Joystick Value");
}
Author

chemidot

Posted on

2018-09-08

Updated on

2021-11-17

Licensed under

댓글