두번째 드론을 조립해 보자. 기존 제품 중 많이 사용하는 R1-F450 프레임을 이용하여 제작해보자. 소스는 바로 전 소형 드론 소스와 동일하며, 모터부분을 수정했다.
--- 부품 리스트 ---
아두이노 Uno (16MHz)
드론 프레임 (R1-450) - 최강 아두이노 드론 키트 R1-F450 - 올퍼스트에듀 165,000원
MPU-6050 자이로센서
HM-10 블루투스 모듈
모터 - A2212/13T, 1000KV BLDC 모터
배터리 - LiPo (11.1V 2700mAh)
충전기 - iMax B6 LiPro Balance Charger
프로펠러 보호대 및 프로펠러 추가
--- 전체 소스코드 ---
drone_simple_v1.04.zip - BLDC 모터로 수정, 시리얼통신 checksum 버그 수정 (def.h에서 모델 선택)
1. 드론 조립
1) 바닥판에 ESC (Electronic Speed Controller) 연결
- 납을 듬뿍 묻혀 굵은 검은색/빨간색 전선이 푹 파뭍이도록 납땜을 한다.
2) 모터와 프레임을 조립
- 상판을 조립한다.
- 프로펠러를 연결한다. (프로펠러는 확실하게 조이지 않으면 이탈하여 프로펠러 혼자 하늘 높이 날아간다.)
- ESC는 꼭 단단하게 끈으로 고정해야 한다. 그럻지 않으면 모터 속도 오류가 발생하기도 한다.
완성된 모습, 하지만 실험 중 프로펠러가 박살난 그림밖에 없어서...
3) 상판위에 쿠션을 깔기
- 쿠션 장치가 없으면 자이로센서 노이즈가 엄청나다. 꼭 필요함.
- 쿠션은 상판에 양면 테이프로 고정하였음. 고무줄은 아두이노 보드 고정하기 위한 장치 (좀 불안함)
4) 아두이노 보드와 회로보드 설치
- 양면 테이프로 붙였다. 그리고 고무줄로 다시 고정 함.
- 회로보드는 ESC 제어보드, MPU-6050 보드, HM-10 블루투스 보드, 아두이노 파워 (5v) 등을 연결한다.
- 다음 그림에서 빨간 부분은 주의해야 한다. 아두이노 보드가 USB 전원 을 사용할 경우 노란색선(내부전원 사용)은 단락시킨다.
- 회로 배선 구성은 다음과 같다.
- 모터 배선은 3가닥이 나와 있는데 CW는 차례로 연결하고, CCW는 엇갈리게 연결해야 한다.
모터 CW 빨간색 - 첫번째 ESC 모터 CCW 노란색 - 첫번째 ESC
검은색 - 두번째 검은색 - 두번째
노란색 - 세번째 빨간색 - 세번째
- 회로 보드 배선도
- 다음 배선도에서 주의할 것 은 아두이노 내부전원을 공급하기 위한 전원을 어느것을 사용할 것인가? 이다.
아두이노 전원 (1) - 컨넥터 (ESC와 5V)를 합선하면 모터의 ESC로부터 전원을 Vin으로 공급하여 아두이노를 구동시킨다.
아두이노 전원 (2) - 어댑터 연결한다. 이때는 컨넥터 (ESC와 5V) 를 끊는다. (합선 방지)
- 아두이노용 어댑터와 배터리에 연결된 모터(ESC) 전원을 합선시키면 충돌 이 난다.
2. PID 제어 실험
(참고 동영상: https://www.youtube.com/watch?v=YNzqTGEl2xQ&feature=youtu.be )
(PID 동영상: https://www.youtube.com/watch?v=BZzMQTMsXEM)
- PID 제어를 실험하기 위해 그림과 같이 양쪽 방향을 끈으로 묶고 모터는 2개만 동작 시킨다.
- PID 값이 제대로 맞으면 pitch 또는 roll 제어도 정확하게 동작한다.
- PID 값이 잘못될 경우, 회전을 하기도 하고, 마치 줄을 탈출하려고 시도하는 것처럼 보이는데, 상당히 위험하다.
- 기체가 단단하게 조여있지 않으면, 이때 망가지는 많은 경험을 하게 된다.
- MPU-6050도 단단하게 고정한다.
- ESC 제어보드도 단단하게 고정한다.
- 프로펠러도 단단하게 고정한다.
현재까지 조정된 PID 값이며, Trim 값도 5를 주었다. 이륙시 한쪽으로 자꾸 기울어서 조정을 했다.
static struct { float Kp[3], Ki[3], Kd[3]; // PID 값 int16_t angleTrim[3]; // Hovering시 영점 조정 (미세조정) uint8_t checksum; // MUST BE ON LAST POSITION OF CONF STRUCTURE! } conf;
void initParameters() {
// Kp[Pit,Roll,Yaw] Ki[Pit,Roll,Yaw] Kd[Pit,Roll,Yaw] angleTrim[Pit,Roll,Yaw] conf = { { 0.41, 0.41, 0.14 }, { 0.0007, 0.0007, 0.0055 }, { 0.06, 0.06, 0 }, { 5,5,0 } }; }
* 이중 PID 사용하기
- 하나의 PID 값만으로 제어하기가 매우 어렵다. 이때는 이중 PID를 이용하면 훨씬 조정하기 쉬워진다. 다음과 같은 방법으로 설정해보자.
LPF 구하기 - LPF를 사용하면 overshooting을 많이 줄일 수 있다. 반응 속도가 느린것 같으면 앞 계수(0.7)를 더 낮춘다.
AccLPF = AccLPF * 0.7 + Acc 값 * 0.3;
GyroLPF = GyroLPF * 0.98 + Gyro 값 * 0.02;
이중 PID 개요
Perr1 = 조종기 각도 - AccLPF
1차 P값 구하기
Perr2 = 1차 P값 - GyroLPF
2차 P값 구하기
2차 PID로 자이로만 적용한다.
1차 PID, 2차 PID 모두 적용
Trim
Kp1 = 0, Ki1 = 0, Kd1 = 0; // 1차 PID
Kp2 = 3, Ki2 = 0, Kd2 = 0; // 2차 PID
이때 드론의 양쪽 날개가 균형을 이루며, 한쪽으로 힘을 주면 반대(원래 위치)로 돌아오려고 한다.
다만, 서서히 각도가 틀어진다.
Kp1 = 2 , Ki1 = 0, Kd1 = 0; // 1차 PID
Kp2 = 3 , Ki2 = 0, Kd2 = 0; // 2차 PID
이때는 양쪽 날개가 평형을 유지하며 위로 날아 오른다. 단, 옆으로 이동 할 수 있다.
호버링시 한쪽으로 이동하며 위로 올라가는 경우 Trim 값을 조정하여 해결할 수 있다.
3. 소스분석
- 위 소스는 전의 소형 드론 소스와 거의 동일하며, 다만, 모터 제어부분이 다르다.
- 모터 (A2212/ 13T, 1000Kv)
- 모터 캘리브레이션은 사용하지 않아도 제어가 가능하다. 다만, 사용하는 방법은 다음과 같다.
/* * 캘리브레이션 하기 * (1) 이 소스를 업로드 한다. -> 최대값 180으로 출력함 * (2) 모터 배터리를 연결한다. -> 삐삐삐 (도레미), 삐 소리 발생 * (3) 최소값 0을 입력한다. -> 삐삐 -> 삐~~~ (높은음) 소리 발생 * (4) 캘리브레이션이 완료 * * 모터 속도, value는 PWM high일때의 duty ___^^^___^^^___ * write(int value) : value의 범위는 0 ~180 * writeMicroseconds(int value) : value의 범위는 1000 ~ 2000 */
void initMotor() { for(uint8_t i=0; i< NUMBER_MOTOR; i++) esc_motor[i].attach(PWM_PIN[i], 1000, 2000);
// ESC calibration //for(uint8_t i=0; i< NUMBER_MOTOR; i++) esc_motor[i].writeMicroseconds(2000); //delay(8000);
for(uint8_t i=0; i< NUMBER_MOTOR; i++) esc_motor[i].writeMicroseconds(0); // init delay(300); }
void writeMotors() // [1000;2000] => [125;250] { int16_t maxMotor,i;
// ----------------------------------------------------------------------- // apply to motors motor[0] = rcCommand[THROTTLE] - axisPID[PITCH] - axisPID[ROLL] + axisPID[YAW]; //REAR_R motor[1] = rcCommand[THROTTLE] + axisPID[PITCH] - axisPID[ROLL] - axisPID[YAW]; //FRONT_R motor[2] = rcCommand[THROTTLE] - axisPID[PITCH] + axisPID[ROLL] - axisPID[YAW]; //REAR_L motor[3] = rcCommand[THROTTLE] + axisPID[PITCH] + axisPID[ROLL] + axisPID[YAW]; //FRONT_L
// ----------------------------------------------------------------------- // normalize the Motors values for(i=0; i< NUMBER_MOTOR; i++) if (motor[i]>maxMotor) maxMotor=motor[i]; for(i=0; i< NUMBER_MOTOR; i++) { // 하나의 모터가 최대치를 초과할때, 전체 모터를 초과 크기만큼 전부 내린다. if (maxMotor > MAX_THROTTLE) motor[i] -= maxMotor - MAX_THROTTLE; motor[i] = constrain(motor[i], MIN_THROTTLE, MAX_THROTTLE); // 착륙시 또는 dis-armed 이면 모터를 정지한다. if (rcData[THROTTLE] < MIN_RC_CHECK || !fARMED) motor[i] = MINCOMMAND; } for(i=0; i< NUMBER_MOTOR; i++) esc_motor[i].writeMicroseconds(motor[i]);
}
4. 배터리 충전
- LiPro Balance Charger, 2.7A, 11.1V (3s) 로 설정한 후 Enter키를 1초간 꾹 눌러서 충전 실행한다.
- 충전이 끝나면 (12.6V) 삐삐 소리가 난다고 함.
- Lipo 배터리 2.7A, 11.1V (3s) - 3개의 셀로 구성 3s x 3.7V = 11.1V - 과충전(4.2V이상), 과방전(2.7V 이하) 화재발생 가능함. 하나의 셀의 중간 전압이 3.7V 임.
- 4일이상 사용안할 경우 저장모드로 충/방전 해야함
5. 드론 실험
- 이륙시 옆으로 이동하는 경우가 있으니 넓은 장소에서 동작할 필요가 있다.
- 착륙시 조정 미흡으로 다리가 부러졌다. 그래서 아예 떼어 버렸다.
- 날개에 무릅이 맞았더니 피가나서 딱정이가 생겼다. ㅠㅠ, 그래서 날개 보호대(흰색)를 구입하여 달았다.
- LPF를 넣고 이중 PID 방법을 사용하였을 경우 훨씬 쉽게 PID를 구할 수 있었고, 안정적으로 동작하는 것을 확인하였다.
- 따라서 현재 위 소스를 수정하여 이중 PID를 적용해보자.
카페 게시글
영상처리및제어
[제어] 아두이노 Uno에서 드론(R1-F450) 제작 (수정중)
한창호
추천 0
조회 3,408
19.01.22 11:23
댓글 0
북마크
번역하기
공유하기
기능 더보기
다음검색