|
|
#include <avr/eeprom.h> // ****************************************** uint8_t calculate_sum(uint8_t *cb , uint8_t siz)
// conf 구조체 내용을 eeprom에서 불러온다. eeprom_read_block((void*)&conf, (void*)0, sizeof(conf)); // 저장된 내용이 데이터가 깨졌을 경우 초기 값으로 대체 // conf 구조체 내용을 eeprom에 저장한다. //readEEPROM(); |
2. MPU-6050 자이로 센서 읽기
- 아두이노 Serial1 을 사용하여 read()함수로 데이터를 읽어 처리할때 드론이 뜨지 못한다. 직접 i2c 함수로 접근하는게 더 빠름.
- angle 각도 (pitch, roll, yaw)를 이용하여 PID 제어를 할 경우 드론이 휘청 거린다. 자이로와 가속도의 누적 데이터로 인한 반응이 떨어져서 생기는 현상
- 레지스터 설정에서 자이로센서는 LPF (DLPF_CFG)로 설정해야 오차를 줄일 수 있다.
[실습] 다음 소스를 이용하여 다음 정보를 시리얼모니터로 출력하시오.
가속도센서(accelation) 원시 데이터 (acc_raw)과 자이로센서(gyrometer) 원시 데이터 (gyro_raw)
Roll, Pitch, Yaw 각도
PWR_MGMT_1 레지스터 (0x6B)
CONFIG 레지스터 (0x1A)
GYRO_CONFIG 레지스터 (0x1B)
ACCEL_CONFIG 레지스터 (0x1C)
MPU6050 레지스터 map
Sensitivity Scale Factor gyroscop:
65.5는 각속도를 의미하며, 최대 500도/sec의 범위를 갖는다. 즉, -32768~32767 범위의 값은 - 500~500 도/sec로 표현된다.
1 도/sec = 32768 / 500 = 65.5
2 도/sec = 32768 / 500 * 2 = 131
500도/sec = 32768 / 500 * 500 = 32768
* Wire.h를 이용한 MPU-6050 제어 코드
#include <Wire.h> #define MPU6050_ADDRESS 0x68 // address pin AD0 low (GND), default for FreeIMU v0.4 and InvenSense board #define ACC_2G 512 // ACCEL_CONFIG -- AFS_SEL= 0 (Full Scale = +/-2G) enum xyz { X, Y, Z }; int16_t gyro_raw[3] = {0,0,0}; // Gyroscope(자이로스코프) 원시 데이터 int16_t acc_raw[3] = {0,0,0}; // Accelerometer(가속계) 원시 데이터 // ***************************************************************************************
TWBR = ((F_CPU / 400000L) - 16) / 2; //24 또는 // 400kHz I2C clock (200kHz if CPU is 8MHz)
// Configure power management
// Configure the gyro's sensitivity // Configure the acceleromter's sensitivity // Configure low pass filter // ***************************************************************************************
// *************************************************************************************** // calculate time // 영점 조정하기 // Calculate total 3D acceleration vector : √(X² + Y² + Z²) // To prevent asin to produce a NaN, make sure the input value is within [-1;+1] // Calculate gyro angle
// 상보필터 (각도를 구하기 위해 dt를 곱하고, 4를 다시 곱해 원래의 raw값으로 복원) } void setup() { initMPU6050(); // 자이로센서 설정 void loop() { |
* I2C 통신 모듈 사용할 경우 추가 코드 부분 (다음은 위 소스와 다른 부분만 보여준다.)
#define I2C_SPEED 400000L //400kHz fast mode, it works only with some WMP clones // *************************************************************************************** i2c_init(); // I2C 통신 for MPU6050
//PWR_MGMT_1 -- SLEEP 0; CYCLE 0; TEMP_DIS 0; CLKSEL 3 (PLL with Z Gyro reference) i2c_writeReg(MPU6050_ADDRESS, 0x6B, 0x03); //CONFIG -- EXT_SYNC_SET 0 (disable input pin for data sync) ; // default DLPF_CFG = 0 => ACC bandwidth = 260Hz GYRO bandwidth = 256Hz) i2c_writeReg(MPU6050_ADDRESS, 0x1A, MPU6050_DLPF_CFG); //GYRO_CONFIG -- FS_SEL = 3: Full scale set to 2000 deg/sec calibMPU6050(); } // *************************************************************************************** acc_raw[X] = (rawADC[0]<<8) | rawADC[1]; gyro_raw[X] = ( ((rawADC[8]<<8) | rawADC[9]) >> 2 ); // 노이즈를 줄이기. 노이즈로 잘 뜨지 않는 현상이 있다. // *************************************************************************************** void i2c_beginTransmission(uint8_t address,int mode) void i2c_endTransmission(void) void i2c_write(uint8_t data) uint8_t i2c_read(uint8_t ack) uint8_t i2c_readAck() { return i2c_read(1); }
void waitTransmissionI2C() size_t i2c_read_to_buf(uint8_t add, void *buf, size_t size) size_t i2c_read_reg_to_buf(uint8_t add, uint8_t reg, void *buf, size_t size) /* transform a series of bytes from big endian to little endian and vice versa. */ void i2c_writeReg(uint8_t add, uint8_t reg, uint8_t val) |
시리얼모니터를 통해 pitch, roll, yaw의 각도를 정확히 살펴본다.
3. 모터 동작
[실습] 다음 소스를 이용하여 시리얼모니터에서 1~4번 번호를 입력하면 한개의 모터가 최소값에서 최대값으로 동작하도록 한다.
즉, 각각 하나씩 모터 속도를 증가시켜 보자.
Realacc R20 RC 쿼드콥터 - 검정색 백색 (CCW) 적색 청색 (CW)
모터구동을 위한 PWM 설정 (참고:Timer/Counter 4 with PWM)
#include <Wire.h> /*************** Motor THROTTLE for ESC (Electronic Speed Controller) **************/ /***************************************************************************************** #define NUMBER_MOTOR 4 /* to calibrate all ESCs connected to MWii at the same time (useful to avoid unplugging/re-plugging each ESC) // rc (Remote Control) functions // 입력받은 조작키 값을 재조정한 최종 명령값, [-500;+500] for ROLL/PITCH/YAW- ESC, [1000;2000] for THROTTLE int16_t axisPID[3] = {0,0,0}; /************************************************************************************* TCCR4E |= (1<<ENHC4); // enhanced pwm mode
// ----------------------------------------------------------------------- /************************************************************************************* /************************************************************************************* |
4. HM-10 자동 설정
- 공장 초기화 된 경우 HM-10은 다음과 같은 소스를 이용해 현재 시스템에 맞게 초기화할 필요가 있다.
- 다음 소스 중 resetHM10() 함수를 Setup() 함수내에 한번만 실행하면 된다.
// ----------------------------------------------------------- // 명령어를 보내고 Response를 받는다. void resetHM10() char str[100]; // 상태 확인 sendCmd("AT+NAME?"); |
5. HM-10 블루투스 통신
[실습] 다음 소스를 이용하여 컨트롤 앱에서 전송하는 데이터를 받아보자. 데이터는 rcCommand이며, Roll, Pitch, Yaw, Throttle 정보를 갖고 있다.
다두이노 드론 앱을 다운받아 설치한다.
(1) 오른쪽 상단을 누르면 bluetooth를 연결할 수 있다.
(2) 연결이 성공한 후, 다음 화면에서 아래쪽 UNLOCK를 누르면 Arm 모드가 되어 동작이 가능하다.
위 드론 제어판에서 보내는 프로토콜은 다음과 같다. 데이터 영역에는 Roll, Pitch, Yaw, Throttle 등의 조작 명령을 포함한다.
request: $M< [크기] [명령어] [...데이터...] [CRC] |
블루투스 HM-10 이 serial에 연결되어 있다.
/***************************************************************************************** #define RC_CHANS 8 // rc chain 개수 /******************************* 송수신 명령어 *************************************/ #define MSP_TRIM_UP 153 // 영점 조정 #define MSP_SET_RCDATA 150 // 리모콘에서 보낸 데이터를 rcData에 설정하기 /*************** Motor THROTTLE for ESC (Electronic Speed Controller) **************/ // 통신 및 송수신 버퍼 uint8_t BuffTX[TX_BUFFER_SIZE]; // 전송 버퍼 static enum _serial_state { // 프로토콜 구조 // Bluetooth 통신을 통해 조작키로부터 입력받은 값. interval [1000;2000] // 조작키의 입력값을 재조정한 최종 명령값, [-500;+500] for ROLL/PITCH/YAW- ESC, [1000;2000] for THROTTLE // ************************************************************************************************* void serialComm() while (Serial1.available()) { // ************************************************************************************************* switch(cmd_msp) { default: // we do not know how to handle the (valid) message, indicate error MSP $M! // evaluate all other incoming serial data // ******************************************************* void serialize16(int16_t a) { serialize8((a ) & 0xFF); serialize8((a>>8) & 0xFF); } void serialize8(uint8_t a) void UartSendData() // 버퍼에서 수신된 데이터 읽어오기 void setup() void loop() |
6. PID 제어
PID 값은 Kp=1.94, Ki=0.0037, Kd=0.36 으로 설정하여 테스트 한다. 다음 소스에서 anglrTrim은 영점조정을 위한 값으로 기본값은 0이다.
주의: 4개의 모터를 제어하기 위해 자이로센서의 값만을 이용하여 제어한다. Roll, Pitch, Yaw의 각도를 얻어 제어를 하면, 변화 속도가 느린 관계로 바른 제어가 어렵다., 즉, 누적되고, 보정된 (상보필터) 각도가 오히려 민감한 반응에는 느리게 처리된다.
// ****************************************** void LoadDefaults() void calcPID() static float error_prev[3] = {0,0,0}; // ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------ float scale = 4.0 / GYRO_SSF * dt; // 자이로센서값의 비율에 맞추어 error 비율을 조정한다. for(axis=0;axis<3;axis++) { // errors for gyro // PID = e.Kp + ∫e.Ki + Δe.Kd axisPID[axis] = PTerm + ITerm - DTerm; } |
7. 시운전
1) 평평한 바닥에 놓고 스위치를 켠다. 이때 calibration이 동작된다. 만약 바닥이 기울어진 경우 상승시 한쪽으로 기운다.
2) Hovering 연습 - 드론을 이륙시키고, 가만히 제자리에 있도록 훈련한다.
3) 전진/후진 연습 - 조금 앞으로 전진 후, 제자리 멈추고, 다시 후진을 하는 훈련을 한다.
추후 점검 사항 FAQ 모음
* 자이로센서 값이 오차가 많이 발생하면 상승하기 어렵다.
* YAW 값이 음수/양수가 바뀌면 회전할 수 있다.