Skip to main content

Featured

YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors review

 YOLO 버전이 v7 버전으로 논문이 발표되었다. papers with code에서 쉽게 확인할 수 있으며 이 논문은 모듈 최적화 기법 위주이다. CSPNet이라던지 RepVGG 같은 관련 네트워크들을 간단하게 공부하고 논문을 이해하는 것을 추천한다. 아래는 official github이며 ReadMe를 보면 쉽게 사용 방법을 알 수 있다. https://github.com/wongkinyiu/yolov7 또한 본 논문은 아래와 같다. Wang, Chien-Yao, Alexey Bochkovskiy, and Hong-Yuan Mark Liao. "YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors." arXiv preprint arXiv:2207.02696 (2022). 그렇다면 간략하게 논문에 대해 알아보도록 한다. - Abstract YOLOv7이 알려진 모든 detector들보다 정확도와 속도 면에서 성능을 능가하고 있다고 설명한다. 또한 이 네트워크를 오직 COCO 데이터셋으로만 훈련했다고 설명한다. 다른 네트워크들보다 확실히 좋은 성능을 내고 있다는 것으로 abstract에서 소개하고 있다. - Introduction  이 논문에서 제안한 real-time detector는 주로 mobile GPU나 GPU 장치를 지지할 수 있다는 것을 희망한다고 한 것을 보아 GPU가 필요하다는 것으로 이해하였다. 또한 이 논문에서 제안된 방법들의 개발 방향을 현재 real-time detector들의 개발 흐름과 다르다고 설명한다. 훈련 과정의 최적화에 집중했다고 한다. 그래서 중점적인 것이 정확도를 향상시키기 위한 훈련 cost를 강화화는 최적화된 모듈과 최적 기법이라고 설명한다.  논문의 제목에서 나오는데 제안된 모듈들과 최적 기법들을 trainable bag-of-freebies라고 칭한다. 최근에, model re-pa...

Toy Quad Rotor FCC Review 2 : STEVAL-FCU001V1

이번 포스팅에서는 STEVAL-FCU001V1의 코드에 대해 간략히 살펴볼 것이다. 
먼저 stm32에서 제공되는 코드의 링크는 다음과 같다.

Code Link : 
 https://github.com/STMicroelectronics-CentralLabs/ST_Drone_FCU_F401

살펴볼 코드는 Official release with BLE Remocon이며 위치는 다음과 같다. 

File Path :
ST_Drone_FCU_F401-master\ST_Drone_FCU_F401-master\STM32 FW Project\Official release with BLE Remocon - 170318\Src

코드 설명에 앞서 쿼드 콥터의 최소한의 기능에 대해 설명하려한다.

쿼드 콥터를 띄우려면 크게 무선 통신과 제어로 나눌 수 있다.

해당 FCC는 사용자와 블루투스 모듈을 통해 스마트폰 앱을 가지고 쿼드로터의 상태와 명령을 주고받는다.

제어로는 최소한으로 자세제어를 요구한다. 즉, 사용자 자세, 위치 또는 고도명령을 추종하는 제어기가 포함되어야만 한다.

Src에 포함되어있는 코드들은 다음과 같다.


해당 파일을 보드에 업로드하면 기본 동작에 무리가 없기때문에 main.c 파일을 먼저 살펴 보자, main.c 코드에서 while 문 안에 있는 코드중 일부를 가져왔다.

기본적으로 "일정한 주기"로 "센서 데이터 획득"을 하고 "자세를 측정과 추정"하고 "제어"를 한다.

일정 시간 주기는 tim9_event_flag를 이용해 알 수 있는데 이 번수는 800hz마다 1로 설정되며 다음 계산을 위해 0으로 초기화 한다. 자세한 코드에 대한 설명위해 주석을 추가하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
   if (tim9_event_flag == 1) // 800Hz Timer flag On
    {     
      tim9_event_flag = 0;// clear the flag
          
      count1++;// loop를 거칠 때 마다 증가하는 counter

      //=== 변수 초기화 ===
      acc_ahrs.AXIS_X = 0; //X축 가속도 데이터 정보 저장 변수 초기화
      acc_ahrs.AXIS_Y = 0; //Y축 가속도 데이터 정보 저장 변수 초기화
      acc_ahrs.AXIS_Z = 0; //Z축 가속도 데이터 정보 저장 변수 초기화
      gyro_ahrs.AXIS_X = 0;//X축 자이로 데이터 정보 저장 변수 초기화
      gyro_ahrs.AXIS_Y = 0;//Y축 자이로 데이터 정보 저장 변수 초기화
      gyro_ahrs.AXIS_Z = 0;//Z축 자이로 데이터 정보 저장 변수 초기화
 
     //============ 가속도, 자이로 센서 정보 업데이트 =============
      for(i=0;i<FIFO_Order;i++)
      {
        acc_ahrs.AXIS_X += acc_ahrs_FIFO[i].AXIS_X;
        acc_ahrs.AXIS_Y += acc_ahrs_FIFO[i].AXIS_Y;
        acc_ahrs.AXIS_Z += acc_ahrs_FIFO[i].AXIS_Z;
        gyro_ahrs.AXIS_X += gyro_ahrs_FIFO[i].AXIS_X;
        gyro_ahrs.AXIS_Y += gyro_ahrs_FIFO[i].AXIS_Y;
        gyro_ahrs.AXIS_Z += gyro_ahrs_FIFO[i].AXIS_Z;
      }
     //=========================================================

    //====FIFO_Order_Recip 1/5=================================
      acc_ahrs.AXIS_X  *= FIFO_Order_Recip;
      acc_ahrs.AXIS_Y  *= FIFO_Order_Recip;
      acc_ahrs.AXIS_Z  *= FIFO_Order_Recip;
      gyro_ahrs.AXIS_X *= FIFO_Order_Recip;
      gyro_ahrs.AXIS_Y *= FIFO_Order_Recip;
      gyro_ahrs.AXIS_Z *= FIFO_Order_Recip;
     //=========================================================
       
    //====xxx_fil_int는 int32_t로 형변환 하여 저장 하기위한 변수==
      acc_fil_int.AXIS_X = (int32_t) acc_ahrs.AXIS_X;  
      acc_fil_int.AXIS_Y = (int32_t) acc_ahrs.AXIS_Y;  
      acc_fil_int.AXIS_Z = (int32_t) acc_ahrs.AXIS_Z;  
      gyro_fil_int.AXIS_X = (int32_t) gyro_ahrs.AXIS_X;  
      gyro_fil_int.AXIS_Y = (int32_t) gyro_ahrs.AXIS_Y;  
      gyro_fil_int.AXIS_Z = (int32_t) gyro_ahrs.AXIS_Z;  
     //=========================================================
 
      // AHRS update, quaternion & true gyro data are stored in ahrs
      // ahrs_fusion_ag는 가속도계와 자이로 센서 측정치를 이용하여
     // 동체의 자세를 추정하는 함수이다.
      ahrs_fusion_ag(&acc_ahrs, &gyro_ahrs, &ahrs);
 
      // Calculate euler angle drone
      // QuaternionToEuler는 함수명과 동일하게
     // Quaternion을 Euler로 변환하는 함수이다.
      QuaternionToEuler(&ahrs.q, &euler_ahrs);
      
      #ifdef REMOCON_BLE
         //전달된 조종기 신호를 받아서 처리하는 부분
         //조종기 신호는 사용자 APP에서 전잘되는 정보를 기반으로 하고
         //rudder (joydata[2]), throtle(joydata[3]),
          //aileron(joydata[4]) 그리고 elevator(joydata[5])가 있다.
     //추가적으로 빼고 더하는 부분은 제어 입력(오일러 각도)으로 사용
         //하기위해 적용된 Scale Factor 같은 것이다.
          gRUD = (joydata[2]-128)*(-13);
          gTHR =  joydata[3]*13;
          gAIL = (joydata[4]-128)*(-13);
          gELE = (joydata[5]-128)*13;
          
          /* joydata[6]: seek bar data*/
          /* joydata[7]: additional button data
                        first bit: Takeoff (0 = Land,  1 = Takeoff)
                        second bit: Calibration When it changes status is active
                        third bit: Arming (0 = Disarmed,  1 = Armed) */
          // joydata[7]은 rudder, throtle... 과다르게 버튼과 같은 0 또는 1
         // 과 같은 상태만 필요로하기 때문에 1비트로 충분히 충당할 수 있기 때문에
// first bit, second bit.. 등으로 상태를 나눠서 한 바이트로 보내준 것이다.
         // 가장 중요한 버튼으로 3번 째 비트인 Arming이 있다. 이를 활성화 시키면
// 모터에 제어신호가 전달되기 때문에 모터가 동작하게 된다.
// 그렇지 않을경우 모터가 동작하지 않는다. 즉 사용자 안전을 위해 꼭 필요한 기능
          gJoystick_status = joydata[7];
          if ((gJoystick_status&0x04)==0x04){//3번째 비트가 on:1 됬을 경우
//모터에 제어신호를 인가할 수 있도록 활성화한다.
            rc_enable_motor = 1;//모터 신호 인가 활성화
            fly_ready = 1;//이륙 준비 OK
            BSP_LED_On(LED2);// 확인을 위한 LED 점멸
          }
          else {//3번째 비트가 0이면 모터에 신호 인가 X
            rc_enable_motor = 0;//모터 신호 인가 X
            fly_ready = 0;
          }
 
          if (connected){//사용자 스마트폰 어플과 블루투스 어플이 연동 되었는지 확인
            rc_connection_flag = 1; // 연결되었다면 flg 1로 설정
            /* BLE Remocon connected flag for enabling motor output */
            SendMotionData();//드론의 자세 데이터 전송
            SendBattEnvData();//배터리 상태 전송
            SendArmingData();
          }
          else{//연동되지 않았을 경우
            rc_connection_flag = 0;//connection flg 0으로 설정
            gTHR=0;//throtle 급발진이 생기지 않도록 0으로 설정
            rc_enable_motor = 0;//모터도 회전하지 않도록 신호 인가 flg 0으로 설정
            fly_ready = 0;
            BSP_LED_Off(LED1);
            BSP_LED_Off(LED2);
          }
          
          if (joydata[7]&0x02){//foydata[7]의 두번째 비트가 on될 경우
            rc_cal_flag = 1;//기체에 장착되어 있는 센서를 캘리브레이션한다
            BSP_LED_On(LED1);
          }
          
      #endif
      
      // Get target euler angle from remote control
      //RC로 받은 조종기 조이스틱 정보를 euler 각도로 제어를 위해 변환하는 과정
      GetTargetEulerAngle(&euler_rc, &euler_ahrs);


     //조종기의 Throtle의 최소 입력이하의 정보가 들어왔을 때 0으로 초기화
     //안전기능과 같다. throtle을 가장 아래로 내렸을 경우 자세제어가 발산할 수
     //있기 때문에 넣기도 한다.
      if(gTHR<MIN_THR)
      {
        euler_ahrs_offset.thx = 0;
        euler_ahrs_offset.thy = 0;
      }

      //센서를 통해 얻어진(추정된) 동체의 자세가 radian이므로 degree로 변환
      Fly_origin.X_Degree = (int16_t)(euler_ahrs.thx * 5730);
      Fly_origin.Y_Degree = (int16_t)(euler_ahrs.thy * 5730);
      Fly_origin.Z_Degree = (int16_t)(euler_ahrs.thz * 5730);

      if(gTHR<MIN_THR)//위와 같은 이유로 안전기능
      {
        euler_rc.thz = 0;
        euler_ahrs.thz = 0;
      }
      //앞서 계산된 블루투스를 통해 입력받은 사용자 요구 각도를 계산한 값을
//자세 제어를 위해 저장하는 변수
      euler_rc_fil.thx = euler_rc.thx;
      euler_rc_fil.thy = euler_rc.thy;
      euler_rc_fil.thz = euler_rc.thz;
      
     //자세제어 진행
      FlightControlPID_OuterLoop(&euler_rc_fil, &euler_ahrs, &ahrs, &pid);
      
cs


생각보다 코드의 구조는 간단하다고 느꼇을 것이라고 생각된다.

만약 자세 제어를 조금 다르게 바꾸고 싶다면 FlightControlPID_OuterLoop와 같은 함수를 생성하여 나만의 제어기를 넣어서 제어해볼 수 있고, 해당 함수 내에서 수정또한 가능하다.
(그냥 원래 코드는 남겨놓고 혼선이 생길 수 있으므로 다른 함수로서 만들어하는 걸 추천)

자세 측정및 추정 부분을 다르게 하고 싶다. 하면 ahrs_fusion부분과 같이 부수적인 함수를 대신할 수 있는 새로운 함수를 만들어 Estimation 기법을 넣어서 자세 추정을 해볼 수 있다.








Comments