CAFE

영상처리및제어

[제어] 라즈베리파이 zero에서 드론 제작 (수정중)

작성자한창호|작성시간20.05.01|조회수4,330 목록 댓글 0

참고매뉴얼: 만들면서 배우는 아두이노 드론 (gameplusedu.com)

 

1. 라즈베리파이 zero를 이용한 드론 띄우기

1) 라즈비안 OS 설치

 

- 최신 raspbian 다운로드  (현재: 2020-02-13, Kernel 4.19)

  2020-02-13-raspbian-buster-full.zip (https://www.raspberrypi.org/downloads/raspbian/)

 

- Etcher (mSD 메모리 쓰기 프로그램)을 이용해서 micro SD에 최신 raspbian을 설치한다.

  balenaEtcher-Portable-1.5.45 (https://etcher.io)

 

 

2) PC 무선 Wifi로 모바일 핫스팟 설정

 

시작메뉴->설정  에서 모바일 핫스팟 클릭

편집을 먼저하고 다른 디바이스와 인터넷 연결 공유를 켠다.

네트워크 연결을 보면 새로운 [로컬 영역 연결* 10] 이 생긴것을 볼 수 있다.

- 라즈베리파이가 연결되면 다음과 같이 뜬다.

 

* 라즈베리파이를 핫스팟 또는 무선 공유기 연결

 

- 다음 두 파일을 PC 윈도우 상에서 micro SD ,boot 폴더에 복사한다. 

- 라즈베리파이에 SD 카드를 꽂고 usb 전원을 인가하여 연결을 확인하면 된다.

 

* ssh 파일은 우클릭에서 새로만들기->텍스트 문서 로 생성한 후에 확장자를 제거한다.

* wpa_supplicant.conf 는 다음을 복사해서 붙여넣기 한다. (메모장 사용가능)

country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="HotSpot"
        psk="12341234"
        key_mgmt=WPA-PSK
}
ssid는  공유기 ssid 네트워크 이름

psk는  암호

priority는 숫자가 높은 것이 우선순위가 높다
network={
        ssid="iptime2"
        psk="mypasswd"
        key_mgmt=WPA-PSK
        pairwise=CCMP
        group=CCMP
        priority=1
}
WIFI를 하나 더 추가하면

우선순위 (priority 값) 에 따라 선택하여 연결한다.

파란색은 생략 가능하다.

- 메모장으로 확인하면 아래 쪽에 Unix(LF)로 되어 있어야 정상적으로 동작한다.

 

 

* 무선 공유기에 연결된 경우

 

- PC에서 네트워크는 공유기의 WIFI로 접속한다. (무선 wifie 접속)

- PC에서 공유기 웹사이트(192.168.0.1)를 통해 라즈베리파이 접속 IP를 확인한다.

 

 

 

3) PC에서 putty로 연결하기

 

- 접속->SSH->키교환-> 그룹14, 그룹1을 위로 올린다:  Putty 접속 에러[expected key exchange group packed from server] 발생시 putty설정을 암호 알고리즘 선택 정책의 순서를 다음과 같이 순서를 변경한다. 

- 창(window)->변환->UTF-8 설정 (한글설정)

- Putty로 라즈베리파이 IP로 연결한다.  (접속 IP: 192.168.0.7,    아이디: pi,  패스워드: raspberry)

 

- 라즈베리파이 무선 Wifi 암호코드 암호화 하기 (외부노출 방지)

login as: pi
password: raspberry
$ sudo passwd root    <- 루트 암호를 설정한다. (암호는 raspberry로 동일하게)
$ su                           <- 루트로 로그인

wpa_passphrase iptime mypasswd   <-  암호화된 패스워드 생성
   network={
        ssid="iptime2"
        #psk="mypasswd"
        psk=7b2453f1c01d208a5fa5e26d102b5c35a01b74301a081034b597ec4bc80a8650
  }
$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf   <- 파일 내의 psk 암호 변경
$ reboot

 

 

 

2. 개발환경 구축

 

1) VSCode 설치

 - 다운로드:  Documentation for Visual Studio Code

F1 키를 널러 Remote-SSH: Connect to Host

 

주소에 pi@192.168.137.119라고 치고 암호를 치고 들어가면 된다.  다만, 버전 문제로 다음과 같은 오류가 발생할 수도 있다.

-> 현재 파이제로 에서는 Remote-SSH로는 연결이 불가능하다. 따라서 Samba로 연결 후 접근해 보자.

 

 

2) Samba로 연결하기

 

- 파이제로에서 삼바 설치하기

$ sudo apt-get -y install samba          # 삼바 설치
$ sudo adduser pi                               # 공유계정            pi  (이미 존재 하므로 생략 가능하다)
$ sudo smbpasswd -a pi                     # 공유계정 암호    raspberry
$ sudo nano /etc/samba/smb.conf              # 설정파일

# 맨 아래 추가한다.
[share]                              # [ ] 대괄호는 섹션을 정의, 윈도우에서 접근할 때 폴더 이름
comment = samba server      # 간단한 공유 폴더 설명
path = /home/pi/Desktop      # 공유 디렉토리 경로
browsable = yes
create mask = 0770
directory mask = 0771
writable = yes
printable = no                      # 다른 사용자들도 이용 여부 설정
valid user = pi                      # 공유 디렉토리를 이용할 수 있는 사용자를 설정
guesk ok = no

$ service smbd restart
$ service smbd status

- 윈도우 PC에서 네트워크에서 우클릭하여 네트워크 드라이브 연결을 한다.

  \\192.168.137.119\share        (ip주소\세션 이름)

- 이제 VSCode로 접근이 가능하다.

 

 

3) VNC Viewer로 연결하기

 

- 라즈베리파이에서 VNC 설치 및 설정

$ sudo df -h                                              (용량확인)
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get autoremove
$ sudo apt-get install realvnc-vnc-server realvnc-vnc-viewer    (VNC 설치)
$ sudo apt-get install fonts-nanum                 (한글 폰트)
$ sudo apt-get install fcitx fcitx-hangul            (한글 입력기)
$ sudo im-config -n fcitx                              (한글 입력기 지정)
$ sudo raspi-config                                     (환경설정)

    5. Interfacing Options -> VNC  ->  YES
    5. Interfacing Options -> SSH  ->  YES
    7. Advanced Options ->  Resolution  ->  DMT Mode 9 (800x600) 해상도 

 

- PC에서 VNC Viewer로 접속한다.  (다운로드: https://www.realvnc.com/en/connect/download/viewer/)

   (id: pi,  pw: raspberry)

위 화면에서 초기설정은 Cancel 한다.

터미널에서 Ctrl + Space 를 누르면 한글/영어 입력 모드 전환

 

 

 

3. 드론 프로그램 작성

 

1) drone 소스 및 라이브러리 (wiringPi) 설치

 

- 소스파일 (https://goo.gl/kdSe6P)  - 소스 폴더: droneRPI

- 깃허브:  (https://github.com/WiringPi/WiringPi)

  

  

단계설명
wiringPi 설치$ wget https://t1.daumcdn.net/cfile/cafe/99B1E5425EAD32AE1A
$ wget https://github.com/WiringPi/WiringPi/archive/refs/heads/master.zip
$ mv 99B1E5425EAD32AE1A aircopter.zip
$ sudo apt-get install zip unzip
$ unzip aircopter.zip
$ unzip master.zip
$ cd WiringPi-master
$ ./build
$ gpio -v
$ gpio readall
$ cd ..
편집$ nano dronRPi.cpp       또는 VSCode

컴파일 $ g++ _01_drone.cpp _02_gyro.cpp _03_balancing.cpp _04_remote.cpp _05_motor.cpp _06_print.cpp pca9685.cpp -o drone_rpi -lwiringPi
실행./drone_rpi

 

 

2) MPU6050 연결을 위한 I2C 시리얼통신 설정

 

라즈베리파이에서  /dev/i2c-1 을 open 하기위해 다음과 같이 설치한다.

단계첫 번째 시도두 번째 시도
설정방법 2가지sudo raspi-config
   Enable the I2C

reboot
nano /boot/config.txt
   dtparam=i2c_arm=on          (#을 제거한다.)
nano /boot/cmdline.txt
   bcm2708.vc_i2c_override=1   (맨 뒤에 추가한다.)
nano /etc/modules
   i2c-bcm2708                      (추가한다.)
   i2c-dev
sudo apt-get install i2c-tools libi2c-dev  (설치)
테스트i2cdetect -y 1 


     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77

 

 

3) 블루투스 (HM-10)을 ttyS0에 연결하기

 

라즈베리 파이 zero에서는 PL011 UART는 BT 모듈에 연결되고, 미니 UART는 리눅스 콘솔 출력에 사용된다. 그외의 모델에서는 PL011을 리눅스 콘솔 출력에 사용한다.

 

/dev/ttyAMA0 (PL011 UART)이 BT 모듈에 할당된 경우, enable_uart의 기본값은 0
/dev/ttyS0 (미니 UART)가 BT 모듈에 할당된 경우, enable_uart의 기본값은 1

Unable to open serial device: No such file or directory 에러는 _04_remote.cpp에서 블루투스를 ttyS0을 연결해 사용하고자하는데서 에러가 발생한 경우이다.

$ echo "enable_uart=1" >> /boot/config.txt           (ttyS0를 BT모듈로 사용)
$ systemctl stop serial-getty@ttyS0.service
$ systemctl disable serial-getty@ttyS0.service
$ nano /boot/cmdline.txt    
    #Remove console=serial0,115200                         (ttyS0은 콘솔 사용 금지)

$ ls -l /dev | grep serial                (확인)

>> serial0 -> ttyS0

>> serial1 -> ttyAMA0

 

 

4) 드론 컨트롤러로 블루투스 (HM-10) 연결하여 테스트하기

- 스마트폰에서 드론 제어앱을 이용하여 BT로 라즈베리파이를 연결하여 에 데이터를 송수신 하는 프로그램이다.

- 또한 엔터키를 치면 HM-10을 위한 AT 명령을 입력할 수 있다.

// test_hm10.cpp
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>

int kbhit()
{
    struct termios oldt, newt;                  /* 터미널에 대한 구조체 */
    int ch, oldf;
    tcgetattr(0, &oldt);                        /* 현재 터미널에 설정된 정보를 $
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);           /* 정규 모드 입력과 에코를 해제$
    tcsetattr(0, TCSANOW, &newt);               /* 새로 값으로 터미널을 설정한>$
    oldf = fcntl(0, F_GETFL, 0);
    fcntl(0, F_SETFL, oldf | O_NONBLOCK);       /* 입력을 논블로킹 모드로 설정>$
    ch = getchar();
    tcsetattr(0, TCSANOW, &oldt);               /* 기존의 값으로 터미널의 속성>$
    fcntl(0, F_SETFL, oldf);
    if(ch != EOF) {
        ungetc(ch, stdin);                      /* 앞에서 읽은 위치로 이전으로 $
        return 1;
    }
    return 0;
}

int main()
{
  int cnt_msg;
  int serial_port;
  char cmd[100];

  wiringPiSetup();

  if((serial_port = serialOpen("/dev/ttyS0", 115200)) < 0) {
    fprintf(stderr, "Unable to open serial device: %s\n", strerror(errno));
    return 1;
  }

  while(1) {
    // Bluetooth Serial 테스트
    if(serialDataAvail(serial_port)) {
      while(serialDataAvail(serial_port)) {
          char dat = serialGetchar(serial_port);
          printf("%c",dat);  //fflush(stdout);
          /*if(dat == '$') cnt_msg=0; else cnt_msg++;
          if(cnt_msg==4) printf("Type=%3d | ", dat);
          else if(cnt_msg==5) printf("R=%3d | ", dat);
          else if(cnt_msg==6) printf("P=%3d | ", dat);
          else if(cnt_msg==7) printf("Y=%3d | ", dat);
          else if(cnt_msg==8) printf("T=%3d", dat);*/
      }
      printf("\n");
    }

    // AT command mode for HM-10 (Enter Key 입력시)
    if(kbhit()) {
      getchar(); // remove buffer
      printf(">> AT, AT+NAME?, AT+ADDR?, AT+PASS?, AT+TYPE?, AT+BAUD? \nEnter A$
      scanf("%s",&cmd);
      int len = strlen(cmd);
      int i = 0;
      while(i<len) serialPutchar(serial_port,cmd[i++]);
      serialPutchar(serial_port,'\r');
      serialPutchar(serial_port,'\n');
      getchar();
    }
  }
  return 0;
}

 

* 블루투스 4.0 BLE (HM-10) 설정 하기

nano test_hm10.cpp                                         # 위 소스코드로 작성한다.
g++ test_hm10.cpp -o test_hm10 -lwiringPi         # 컴파일 한다.
./test_hm10                                                    # 실행한다.

- 위 프로그램 test_hm10을 실행시키, 엔터키를 치면 HM-10을 설정할 수 있는 AT Command 입력 대기상태 (>>)가 된다.

>> AT
OK
>> AT+NAME?      (BLE 이름)
OK+NAME:AIR8523
>> AT+PASS?
OK+Get: 000000    (비밀번호)
>> AT+BAUD?
OK+Get: 4       (0: 9600, 1: 19200,  2: 38400,  3: 57600,  4: 115200,  5: 4800, 6: 2400, 7: 1200, 8: 230400)
>> AT+TYPE?
OK+Get: 0       (0: 모듈 bond 모드: Not need PIN Code)
>> AT+MODE?
OK+Get: 2       (0: Trasmission Mode,  1: PIO collection Mode + Mode 0,  2: Remote Control Mode + Mode 0)
>> AT+ROLE?
OK+Get: 0       (0: Peripheral (=Slave),  1: Central (=Master) )
>> AT+ADTY?
OK+Get: 0       (0: Advertising ScanResponse, Connectable 불루투스 페어링 모드)

 

5) 앱으로 연결 하기

 

- 다두이노 V1.0 버전 - 연결이 잘 안될 수 있다.

- 스마트폰에서 PlayStore에서 다두이노 드론 V2.0을 다운받아 설치한다.

 

- 아래쪽 가운데 Scan 버튼을 누른 후 connect 버튼을 눌러 연결한 후 동작시켜 보자.

 

 

 

6) 모터 테스트

 

- PCA9685 Datasheet https://www-users.cs.york.ac.uk/~pcc/Circuits/dome/datasheet/PCA9685_2.pdf

- PCA9685는 16개의 PWM 신호를 생성하여 16개의 모터를 제어할 수 있다.  (16-Channel PWM Servo Driver)

- PCA9685는 I2C 통신(1:N 통신 가능) 방식으로 SCL가 SDA를 연결한다.

 

- PWM 생성 방법은 LED_ON과 LED_OFF를 사용하여 PWM의 duty cycle을 조절한다.

- 하나의 LED 에는 ON_L, ON_H, OFF_L, OFF_H 로 4 byte로 구성된다. 총 16개의 LED 가 있다. (LED0~LED15)

- 예를 들어 LED_ON = 409, LED_OFF = 1228 이라면 PWM의 duty cycle은 (1228-409/4096) x 100%= 20%  이다.

 

- PCA9685 모드1과 모드2의 Control Registers

- LED ON/OFF,  PRE_SCALE 제어 레지스터

 

- 라즈베리Pi 터미널 창에서 PCA9685와 MPU6050 장치를 테스트해보자.

명령어결과
i2cdetect -li2c 시리얼포트 검색

i2c-1 i2c        bcm2835 I2C adapter       I2C adapter
i2cdetect -y 1i2c 1번 포트에 연결된 PCA9685 장치 검색

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --       (48번은 PCA9685 장치)
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --       (68번은 MPU6050 장치)
70: 70 -- -- -- -- -- -- 77                        
i2cdump -y 1 0x40

(i2c 
1번 포트에서 0x40(PCA9685)장치의 레지스터 읽기
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 11 04 e2 e4 e8 e0 00 00 00 10 00 00 00 10 00 00    ??????...?...?..
10: 00 10 00 00 00 10 00 00 00 10 00 00 00 10 00 00    .?...?...?...?..
20: 00 10 00 00 00 10 00 00 00 10 00 00 00 10 00 00    .?...?...?...?..
30: 00 10 00 00 00 10 00 00 00 10 00 00 00 10 00 00    .?...?...?...?..
40: 00 10 00 00 00 10 XX XX XX XX XX XX XX XX XX XX    .?...?XXXXXXXXXX
50: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
60: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
90: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
a0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
b0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
c0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
d0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
e0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
f0: XX XX XX XX XX XX XX XX XX XX 00 00 00 00 1e 00    XXXXXXXXXX....?.
i2cget -y 1 0x40 0x00 
(i2c 1번 포트에서 0x40(PCA9685) 장치의 0x00 레지스터 값 읽기)

0x11
i2cget -y 1 0x68 0x75
(i2c 1번 포트에서 0x68(MPU6050) 장치의 0x75 레지스터 값 읽기)

0x68                                          (MPU6050 디바이스 ID 값)

 

- 다음 구동 소스를 통해 4개의 모터를 정/역회전, 속도를 변경시켜보자.

- 모터 구동을 하기 위해 배터리 전원을 연결한다. 스위치는 왼쪽으로 밀어야 배터리 전원이 ON 된다.

 

test_motor.cpp

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

// PCA9685 register
#define MODE1             0x00
#define PRE_SCALE      0xFE
#define LED0_ON_L       0x06     (LED0 에는 ON_L, ON_H, OFF_L, OFF_H 4 byte가 있다.  LED0~ LED15)
#define LED0_OFF_L      0x08
#define ALLCALL            0x01     (전체 호출, i2c 조소1에 대한 pca9685 응답)
#define SLEEP               0x10     (Oscillator turn off)
#define AI                      0x20     (Auto Increment Register)
#define RESTART          0x80     (Restart signal)

int i2c_addr = 0x40;       (PCA9685 디바이스 주소)
int i2c_port = 0;
int pin[4]= { 0, 2, 1, 3 };  // motor id

int main(void)
{
  // setup i2c 통신
  wiringPiSetup();
  if((i2c_port = wiringPiI2CSetup(i2c_addr)) < 0) {
    fprintf(stderr, "Unable to open pca9685 device: %s\n", strerror(errno));
    return 1;
  }

  // setup PCA9685
  int freq = 1000;
  int prescale = (int)(25000000.0f / ( 4096 * freq));
  wiringPiI2CWriteReg8(i2c_port, MODE1, ALLCALL | AI | SLEEP);
  wiringPiI2CWriteReg8(i2c_port, PRE_SCALE, prescale);  // 프리스케일 설정시 SLEEP으로 잠시 멈춘다.
  wiringPiI2CWriteReg8(i2c_port, MODE1, ALLCALL | AI | RESTART);

  // run motor
  for(int i=0;i<4;i++) {   // PWM은 LED0~LED15로 16개의 모터를 제어하며, 4byte로 duty cycle을 구성한다.
    wiringPiI2CWriteReg16(i2c_port, LED0_OFF_L+pin[i]*4, (4096/10) & 0x1FFF);
    delay(1000);
  }

  // stop motor
  for(int i=0;i<4;i++)
    wiringPiI2CWriteReg16(i2c_port, LED0_OFF_L+pin[i]*4, 0);
}

 

$ g++ test_motor.cpp -o test_motor -lwiringPi

$ ./test_motor

 

7) MPU6050 테스트

 

- 참고: [MPU6050] 2. 각도값 계산 및 진동 제거하기 (tistory.com)

- 배선연결은 SCL과 SDA를 라즈베리파이의 i2c통신인 SCL/SDA에 각각 연결한다. PCA9685와 같이 연결한다.

- 자이로 설정:  Full Scale Range는 2000도/Sec로 설정하면 된다. (GYRO_CONFIG)

- LPF를 설정하여 노이즈를 줄일 수 있다.  (DLPF_CFG)

 

- MPU6050 자이로/가속도 센서로부터 데이터를 얻어보자. (다음 소스는 C 코드이다.)

// test_mpu6050.cpp
#include <stdio.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

#define MPU6050_ADDR    0x68
#define PWR_MGMT_1      0x6B
#define MPU6050_ACCEL_XOUT_H    0x3B
#define MPU6050_GYRO_XOUT_H     0x43
#define PWR_MGMT_1      0x6B
#define PWR_MGMT_2      0x6C
#define DLPF_CFG        0x1A
#define GYRO_CONFIG     0x1B
#define ACCEL_CONFIG    0x1C

#define ACCEL_SCALE_MODIFIER_2G         16384.0
#define ACCEL_SCALE_MODIFIER_4G         8192.0
#define ACCEL_SCALE_MODIFIER_8G         4096.0
#define ACCEL_SCALE_MODIFIER_16G        2048.0

#define GYRO_SCALE_MODIFIER_250DEG      131.0
#define GYRO_SCALE_MODIFIER_500DEG      65.5
#define GYRO_SCALE_MODIFIER_1000DEG     32.8
#define GYRO_SCALE_MODIFIER_2000DEG     16.4

#define ACCEL_RANGE_2G  0x00
#define ACCEL_RANGE_4G  0x08
#define ACCEL_RANGE_8G  0x10
#define ACCEL_RANGE_16G 0x18

#define GYRO_RANGE_250DEG       0x00
#define GYRO_RANGE_500DEG       0x08
#define GYRO_RANGE_1000DEG      0x10
#define GYRO_RANGE_2000DEG      0x18

#define RAD_TO_DEG              57.295779513082

 int main()
 {
   short gX,gY,gZ;
   int port;

   if (port = open("/dev/i2c-1", O_RDWR)) < 0) {
     printf("Unable to open i2c-1 device: %s\n", strerror(errno));
     exit(-1);
   }
   printf("Connected to i2c-1\n");

   wiringPiSetup();

   ioctl(i2c_port, I2C_SLAVE, MPU6050_ADDR);
   wiringPiI2CWriteReg8(i2c_port, PWR_MGMT_1, 0x80);   // PWR_MGMT_1 -- DEVICE_RESET 1
   delay(5);

   wiringPiI2CWriteReg8(port, DLPF_CFG, 0x03);         // DLPF_CFG -- 0x01: 2ms, 0x03: Acc 4.9ms, Gyro 4.8ms
   wiringPiI2CWriteReg8(port, GYRO_CONFIG, GYRO_RANGE_2000DEG);  // 초당 2000 deg를 분석한다.
   wiringPiI2CWriteReg8(port, ACCEL_CONFIG, ACCEL_RANGE_8G);
   wiringPiI2CWriteReg8(port, PWR_MGMT_10x03);   // PWR_MGMT_1 -- DEVICE RESET 0; SLEEP 0; CHECK, 시작
   printf("MPU6050 is initialized.\n");

   while(1) {
     gX = (wiringPiI2CReadReg8(port, 0x43) & 0xFF) <<8  | (wiringPiI2CReadReg8(port, 0x44) & 0xFF);
     gY = (wiringPiI2CReadReg8(port, 0x45) & 0xFF) <<8  | (wiringPiI2CReadReg8(port, 0x46) & 0xFF);
     gZ = (wiringPiI2CReadReg8(port, 0x47) & 0xFF) <<8  | (wiringPiI2CReadReg8(port, 0x48) & 0xFF);

    aY = ( wiringPiI2CReadReg8(port, 0x3B) << 8  | wiringPiI2CReadReg8(i2c_port, 0x3C) ) >> 2;
    aX = ( wiringPiI2CReadReg8(port, 0x3D) << 8  | wiringPiI2CReadReg8(i2c_port, 0x3E) ) >> 2;
    aZ = ( wiringPiI2CReadReg8(port, 0x3F) << 8  | wiringPiI2CReadReg8(i2c_port, 0x40) ) >> 2;

     printf("aX=%6d | aY=%6d | aZ=%6d \t gX=%6d | gY=%6d | gZ=%6d\n", aX, aY, aZ, gX,gY,gZ);
   }
 }

 

$ g++ test_mpu6050.cpp -o test_mpu6050 -lwiringPi

$ ./test_mpu_6050

 

- MPU6050 센서를 움직였을 때의 결과값이다. 차후 0으로 보정해야 한다.

 수평일 때 x축으로 움직였을 때 z축으로 움직였을 때
gX=    35 | gY=   -57 | gZ=   -62
gX=    24 | gY=   -55 | gZ=  -103
gX=    30 | gY=   -56 | gZ=   -50
gX=    44 | gY=   -44 | gZ=   -88
gX=    18 | gY=   -63 | gZ=   -71
gX=    40 | gY=   -68 | gZ=   -88
gX=    39 | gY=   -50 | gZ=   -74
gX= -2774 | gY=   -41 | gZ=   244
gX= -2765 | gY=   -38 | gZ=   290
gX= -2765 | gY=   -68 | gZ=   287
gX= -2774 | gY=   -31 | gZ=   319
gX= -2778 | gY=    -4 | gZ=   316
gX= -2790 | gY=    -7 | gZ=   333
gX= -2806 | gY=   -21 | gZ=   341
gX=    78 | gY=   -75 | gZ=  -819
gX=    75 | gY=   -46 | gZ=  -927
gX=   244 | gY=   393 | gZ= -1216
gX=   -70 | gY=  -109 | gZ= -1628
gX=   169 | gY=  -200 | gZ= -1960
gX=    36 | gY=  -103 | gZ= -2384
gX=   137 | gY=   -75 | gZ= -2594

 

- 각도 구하기

 

가속도와 자이로 센서로부터 얻은 데이터로 각도를 구해보자. 상보필터를 통해 자이로센서의 누적오차를 보정할 수 있다.

 

- 자이로 값으로 각도를 계산하는 코드이다. 상보필터를 사용해서 보정한다.

double xx = ((double)acc_raw[X] * (double)acc_raw[X]);
double yy = ((double)acc_raw[Y] * (double)acc_raw[Y]);
double zz = ((double)acc_raw[Z] * (double)acc_raw[Z]);

// accelation degree
acc_deg[PITCH]= -atan2(acc_raw[X],sqrt(yy+zz)) * RAD_TO_DEG;
acc_deg[ROLL] = -atan2(acc_raw[Y],sqrt(xx+zz)) * RAD_TO_DEG;
acc_deg[YAW]  = 0;

// gyro rate
gyro_rate[PITCH]= (double)gyro_raw[X] / GYRO_SCALE_MODIFIER_500DEG;
gyro_rate[ROLL] = (double)gyro_raw[Y] / GYRO_SCALE_MODIFIER_500DEG;
gyro_rate[YAW]  = (double)gyro_raw[Z] / GYRO_SCALE_MODIFIER_500DEG;

dt.t_now = micros();

dt.t_period = (dt.t_now - dt.t_prev) / 1000000.0;
dt.t_prev = dt.t_now;

// Calc angle using complimentary filter (상보필터)
comp_angle[PITCH] = 0.93*(comp_angle[PITCH]+ gyro_rate[PITCH] * dt.t_period) $
comp_angle[ROLL]  = 0.93*(comp_angle[ROLL] + gyro_rate[ROLL]  * dt.t_period) $
comp_angle[YAW]  += gyro_rate[YAW] * dt.t_period;

 

 

8) PID 제어

 

- 드론이 제대로 이륙을 못할 경우 PID 값을 수정해보자.

 

- PID 기초: https://m.blog.naver.com/lagrange0115/220616818649

 

결과 창을 살펴보자

 

- ACC(PRY): 각속도 (Acceleration)가 오차가 발생하는 것을 보여준다. 안정적일 필요가 있다.

- GyroRate: 자이로 값으로 0에 가만히 있어야 한다.

- PID1: 각속도에 대한 PID 제어 값이 적용된 term 값들이다.

- PID2: 자이로에 대한 PID 제어 값이 적용된 term 값들이다.

- Motor(ABCD): 모터에 전달되는 최종 값이다.

- th: throttle 값으로 컨트롤 앱에서 속도를 올리면 모터가 빠르게 동작한다.

- dt: 시간 간격이다.  미분 시간

 

 

9) 최종 테스트

 

- 보드 스위치를 왼쪽을 밀어서 배터리 전원 (ON) 을 사용하며, USB 전원을 제거한다.

 

 

- putty 또는 VNC Viewer를 통해 라즈베리파이에 연결하고, 터미널창에서  ./drone_rpi 를 실행한다.

 

- 드론 컨트롤러 앱을 이용해서 블루투스를 연결하고, 드론을 동작 시킨다.

 

* 배터리 문제

 

  - 한 동안 드론이 바닥에 붙어 뜨질 않아서 소스코드 문제인줄 알았는데 결국 배터리 문제로 판정 났다. 충전시 전압이 4.3v 는 되야 드론이 뜬다.

비교불량 배터리정상 배터리
모양빵빵하게 부풀어 올러 곧 터질 것 같다.납작하다.
전압완충시 4.0v 이하  방전시 3.7v 이하완충시 4.3v,  방전시 3.7v

 - 불량/정상 배터리 차이 영상이다.

 

* 원격 파일 복사

 

PC에서 파일을 가져오려면 다음과 같이 cmd 창에서 scp 명령어를 이용해 가져올 수 있다.

 

>> scp pi@192.168.0.3:/home/pi/Desktop/droneRPi/droneRPi.cpp .

 

scp [IP주소]:폴더/파일 [저장폴더]

 

 

* 수정중인 파일

- 하나의 파일로 만들어 보았다. 현재 테스트 중

 

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
맨위로

카페 검색

카페 검색어 입력폼