2017년 11월 13일 월요일

라즈베리파이3 C++로 DC 및 서보모터 제어하기

이번에 영상처리를 이용한 자율주행 자동차를 만들었다.
영상코드는 직접 제작한 것이 아니고 남의 소스를 빌려서 사용을 했다.
그래서 기본적으로 C++로 모터와 서보모터를 돌리는 소스 코드에 대해서 설명을 할 생각이다.

일단 라즈베리파이의 핀을 사용하는 방법에는 GPIO, wiringPi가 있다.
GPIO는 python에서 import를 해서 사용하는 방법이다.
wiringPi는 C++에서 헤더를 추가해서 사용하는 방법이다.

일단, wiringPi를 사용하기 위해서는
1. sudo apt-get install git-core
github에서 파일을 클론을 하거나 zip파일로 받아서 unzip을 통해서 사용해야 하기 때문에
git-core를 설치해주어야 한다.

2. git clone git://git.drogon.net/wiringPi
wiringPi를 클론을 통해 사용 할 수 있게 해주는 파일을 받아오는 작업이다.
커멘더가 실행이 완료되면 wiringPi가 깔려있는 폴더로 cd를 통해 이동

3. ./build
이동을 하고 해주어야 한다. 리눅스에서는 일반적인 파일을 실행할 때 ./filename 의 형태의 커맨드를 쳐주어야 한다. 커맨드가 끝나갈때 All Done. 이라는 문구와 함께 NOTE가 뜬다.

4. 자신이 사용할 핀을 알아보자
gpio readall 커멘드를 입력해주면 핀맵이 뜬다. 여기서 우리가 봐야 할 것은 wPi열에있는 숫자들이다. 실질적으로 GPIO넘버와 wiringPi넘버의 숫자가 일치 하지 않고 Physical 핀넘버와도 일치하지 않기 때문에 일반적으로 인터넷에 있는 코드를 쓴다고 하면 그에 맞는 핀에 연결을 해주어야 하고 이미 결선이 다 끝나있고 코드만 넣고 돌리면 되는 경우에는 핀맵을 보고 해당하는 핀번호로 소스를 맞게 짜주어야 한다.
간단하게 핀에 대해 설명을 하자면, 5V는 전원(power)이고 0V(GND)는 그라운드다. 그 이외에 네임에 GPIO라고 적힌 핀들은 입,출력으로 사용이 가능한 핀들이다.

5. PWM(pulse width modulation)을 위한 softPwm.h 추가
일반적으로 digital signal은 0 또는 1의 값을 갖기 마련이다.
하지만 사용자가 의도적으로 펄스의 폭을 조절하여 값을 다르게 해줄 수 있는데
C++코드에서 PWM을 사용하려면 softPwm헤더를 전처리기 부분에 추가를 해주어야 한다.
참고로 아두이노와는 다르게 PWM의 최댓값이 200이다.

아래는 직접 짠 소스코드의 일부분들을 설명과 함께 적었다.

#include <wiringPi.h>//wiringPi를 사용하기 위해 헤더를 추가했다.
#include <softPwm.h>//PWM을 사용하기 위해 헤더를 추가했다.
#include <stdio.h>
#include <stdlib.h>

그리고 #define 지시문을 사용하여 모터가 연결된 핀의 숫자를 상수화 시켰다.
#define L_M1 0//Left_Motor1 wPi(GEN0번에 연결을 했다.) 왼쪽모터
#define L_M2 2//Left_Motor2 wPi(GEN2번에 연결을 했다.) 왼쪽모터
#define R_M1 3//Right_Motor1 wPi(GEN3번에 연결을 했다.)오른쪽 모터
#define R_M2 1//Right_Motor2 wPi(GEN1번에 연결을 했다.)오른쪽 모터

참고로 L_M1이 HIGH L_M2 LOW 일때 모터가 정회전을 하고 LOW,HIGH일때 역회전을 한다. LOW,LOW일때는 모터가 정지를 한다.(우측모터에 대해서도 같습니다.)

if(wiringPiSetup()==-1) //wiringPi가 사용가능한지 알아보는 코드이다.
 exit(1);                    //사용이 불가능하면 종료가 된다.

pinMode(6,OUTPUT); //서보모터를 제어하기 위해서 핀 6번을 출력(OUTPUT)으로 설정 하겠다는 코드이다. 참고로 서보모터가 조금 기이한데, 일단 사용한 서보모터는 SG90이다.
아두이노에서 사용을 해본사람이라면 기본으로 90이 정중앙이고 0도가 좌측 180이 우측 이지만 여기서는 값이 조금 이상했다 이 부분에 대해서는 서보를 움직이는 코드가 나왔을때 다시 언급을 할 것이다.
그리고 아두이노에서 하듯이 pinMode(연결된핀,OUTPUTorINPUT);
핀은 꼭 맞춰줘야 동작이 가능하고 출력은 말그대로 무언가를 사용 혹은 구동시킬때 쓰이고 입력은 값이나 수치등을 받아들일때 사용한다.

전처리기 부분에서 모터를 정의 해줬던것을 다 OUTPUT으로 설정을 했다.

softPwmCreate(6, 0 ,200);
softPwmCreate(5, 0 ,200);
softPwmCreate(4, 0 ,200);// DC모터를 돌릴때 L298N 모터드라이버를 사용했다.
그래서 ENA(좌측DC모터 속도조절을 위한 핀 = wPi 4번핀에 연결),
ENB(우측DC모터 속도조절을 위한 핀 = wPi 5번핀에 연결)과
서보모터의 신호핀(6번핀)을 PWM을 사용하겠다고 선언을 해줬다.

조향중에서 void start() 함수에 대해서만 설명을 하고 마칠 것이다.
실제로 DC모터와 서보모터의 차이에 의해서 같은 코드를 넣어도 다른 결과가 나오기 때문에 간단하게만 설명을 할 예정이다.
void start()
{
  softPwmWrite(6,20);//본인이 사용해본 결과 15가 중앙이고 그이상는 좌측 그이하는 우측을 향해 모터가 돌아갔다. 이건 나만 그런 것 일수 있으니 만약 이 글을 읽고 해보실 분은 수치를 직접 하나씩 넣어보시고 중앙을 찾아주어야 할 것이다.
  delay(100); //딜레이를 적당 시간을 줘야 서보가 반응을 한다 더 짧게 줘도 된다.
  digitalWrite(L_M1,1);
  digitalWrite(L_M2,0);
  softPwmWrite(4,180);//1,2,3줄은 좌측모터가 정회전이고 속도를 제어하는 코드이다
  digitalWrite(R_M1,1);
  digitalWrite(R_M2,0);
  softPwmWrite(5,180);//4,5,6줄은 우측모터가 정회전이고 속도를 제어하는 코드이다.
  delay(time);//time에 해당하는 시간 만큼 모터 두개가 정회전
}
저장을 filename(하고싶은것).cpp로 저장을 해주시면 돼겠습니다.
컴파일 하는 방법은 g++ -o exe파일로 만들이름 파일명.cpp -lwiringPi -lthread이다.
실행은 ./(exe파일로 만든이름)을 적어주면 실행이 된다.

원래 맨 처음에는 라즈베리파이에 아두이노IDE를 설치해서 거기서 코드를 짜고 업로드 시켜서 하는 방법을 했었다. 많은 난관이 있었는데, 일단 서로 통신(아두이노-파이)이 돼야하고 아무래도 각 보드의 핀의 출력값이 다르기 때문에 컨버터 역할을 해주는 작은 회로가 필요하다 근데 엄청 간단하지만 납땜을 해서 만들었는데 엄청 귀찮았다. 그리고 파이에서 아두이노에 소스코드를 업로딩 할때 시리얼통신핀(Tx,Rx)가 연결 돼있으면 avrdude에러가 뜬다 맨처음에는 이게 뭔가 싶어서 다뒤져봤는데 핀연결 때문에 안됐었다.
모든 문제를 해결을 한 것 같았으나 통신문제가 있어서 라즈베리파이 하나로 돌리기로 바꾼 이후로 C++로 코드를 짜게 됐다.(영상처리코드와 호환을 위해서)
모터(DC,Servo)코드와 영상처리 코드가 합쳐질때 컴파일 오류가 나서 시간이 오래 걸렸다

한가지 드는 의문은 아두이노에서는 255가 최대이고 softPwm헤더에서는 200이 최대인데
아두이노에서 255를 준 DC모터보다 파이에서 200을 준 DC모터가 더 빨랐다
앞으로는 글을 깔끔하고 사진도 첨부해가면서 자주 써봐야겠다.

댓글 없음:

댓글 쓰기

신고20191215