본문 바로가기

Raspberry Pi/Servo-Motor

Raspberry Pi Servo-Motor C example

라즈베리파이에서 서보모터(Servo-Motor)를 제어하는 C언어 예



테스트 환경

Raspberry Pi B+

OS : Jessie (2016년)

언어 : C

Servo-Motor : Hitec HS-311


hs-311.pdf


HS-311 사용 정격

Control System: +Pulse Width Control 1500usec Neutral

Required Pulse: 3-5 Volt Peak to Peak Square Wave

Operating Voltage: 4.8-6.0 Volts

Operating Temperature Range: -20 to +60 Degree C

Operating Speed (4.8V): 0.19sec/60° at no load

Operating Speed (6.0V): 0.15sec/60° at no load

Stall Torque (4.8V): 42 oz/in (3.0 kg/cm)

Stall Torque (6.0V): 51 oz/in (3.7 kg/cm)

Current Drain (4.8V): 7.4mA/idle, 160mA no load operating

Current Drain (6.0V): 7.7mA/idle, 180mA no load operating

Dead Band Width: 5usec

Operating Angle: 45° one side pulse traveling 450usec

Direction: Multi-directional

Motor Type: Cored Metal Brush

Potentiometer Drive: 4 Slider/Direct Drive

Bearing Type: Top Resin Bushing

Gear Type: Nylon

Continuous Rotation Modifiable: Yes

Connector Wire Length: 11.81" (300mm)

Weight: 1.52oz (43g)


위에서 데이터시트의 요약정보를 보면, HS-311의 작동 전원전압은 4.8v~6.0v 이며, 제어는 3v~5v의 펄스인데, 라즈베리파이는 GPIO의 핀을 통해 3.3v의전압을 출력할 수 있고 5v 전원을 사용하기 위한 핀도 있으므로 라즈베리파이에서 HS-311 서보모터를 제어할 수 있다

서보모터가 중립(Neutral) 위치에 있도록 제어하려면 펄스의 폭이 1500마이크로 초(1.5밀리초)가 되어야 하며 펄스의 주기는 상관없다


서보모터에 외부전원을 연결하는 경우에는 아래처럼 라즈베리파이의 GND와 외부전원의 GND가 서로 연결되어야 한다

http://razzpisampler.oreilly.com/ch05.html




적색(전원 +)

흑색(전원 -)

황색(PWM제어)


서보모터의 전원은 라즈베리파이의 전원과 분리되어야 라즈베리파이가 안정적으로 작동한다

라즈베리파이의 GND, 서보모터 전원의 GND는 전기적으로 연결되어야 GND의 기준이 서로 동일하게 되어 안정적으로 작동한다

라즈베리파이와 서보모터의 신호선 사이에는 1Kohm의 저항을 연결하는 것이 좋다. GPIO 핀으로부터 예기치 못하게 높은 전압이 발생하는 경우에 서보모터의 신호선으로 유입되어 서보모터가 오작동하는 경우에 대비하기 위한 것이다


PWM 신호에 대한 서보모터의 반응

펄스의 폭이 1.5ms 일 경우에 중립에 위치한다

1.0ms, 1.5ms, 2.0ms



https://projects.drogon.net/raspberry-pi/wiringpi/software-pwm-library/


WiringPi에 대한 위의 사이트 내용을 정리하면 다음과 같다

#include <wiringPi.h>

#include <softPwm.h>

When compiling your program you must include the pthread library as well as the wiringPi library:

$ sudo gcc -o myprog myprog.c -lwiringPi -lpthread


You must initialise wiringPi with one of wiringPiSetup() or wiringPiSetupGpio() functions beforehand. wiringPiSetupSys() is not fast enough, so you must run your programs with sudo.


int softPwmCreate (int pin, int initialValue, int pwmRange) ;

This creates a software controlled PWM pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() function you used. Use 100 for the pwmRange, then the value can be anything from 0 (off) to 100 (fully on) for the given pin.


The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong.

pwmRange는 펄스간의 시간적 간격(주기, Cycle)을 의미한다. 즉, 한개의 펄스의 High, Low시간을 합한 총 시간을 말하며, 현재 펄스부터 다음 펄스까지의 시간적 간격으로 이해하면 된다. 일반적으로 서버모터의 펄스의 주기는 20ms 가 적당하다고 한다


void softPwmWrite (int pin, int value) ;

This updates the PWM value on the given pin. The value is checked to be in-range and pins that haven’t previously been initialised via softPwmCreate will be silently ignored.

int value 의 값은 pwmRange 보다 작아야 한다


Each “cycle” of PWM output takes 10mS with the default range value of 100, so trying to change the PWM value more than 100 times a second will be futile.

PWM의 주기(pwmRange)를 100으로 설정하면 10ms 에 해당하므로 WiringPi에서는 1/10,000로 초 단위가 사용되는 것으로 생각할 수 있다 


http://sparklingstar.tistory.com/entry/7-PWM-%EA%B3%B5%EB%B6%80-wiringPi


서보모터의 무한반복 회전 테스트

위의 정보를 바탕으로 아래의 코드를 작성하여 /home/pi/work/servo.c 로 저장하고 아래의 명령으로 컴파일한다

$ sudo gcc -o servo servo.c -lwiringPi -lpthread

컴파일 후 오류가 없으면 다음과 같이 프로그램을 실행한다

$ sudo ./servo

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <softPwm.h>

int main ()
{
  int pos = 10 ;
  int dir = 1 ;
  if (wiringPiSetup() == -1) exit(1) ;  //init wiringPi

  pinMode(0, OUTPUT) ;  // 0번핀을 OUTPUT으로 설정. WiringPi의 0번핀은 BCM GPIO 17번핀에 해당한다
  digitalWrite(0, LOW) ;  // 0 pin output LOW voltage
  softPwmCreate(0, 0, 200) ;  // 0번 핀의 초기 pwm 값을 LOW로 하고 PWM주기는 20ms 로 설정한다

  // 10은 1ms, 15는 1.5ms(1500마이크로 초), 20은 2.0ms 이므로, HS-311기종의 경우, 10은 최저각, 15는 중립, 20은 최고각을 가리킨다
  while(1) {
    pos += dir ;
    if (pos < 10 || pos > 20) dir *= -1 ;
    softPwmWrite(0, pos) ;
    delay(190) ;
  }
  return 0 ;
}