main.c
0.02MB
stm32f4xx_it.c
0.01MB

알리에서 구입한 헥사콥터의 모터를 제어하기 위한 ESC이다.

 

드론에 사용되는 모터는 일반 브러시 모터가 아닌 BLDC 모터로 구동시키기 위해서는 ESC라는 제어기가 필요하다.

 

사용할 ESC는 고장날것을 대비해 값싼 ESC를 골랐으며 최대 500hz의 PWM 신호를 받아 BLDC 모터를 제어한다.

 

구입한 ESC의 입력 PWM 신호의 길이는 1ms에서 2ms이며, oneshot125, oneshot42등 다른 ESC protocol을 지원하지 않는다.

 

STM32F407 MCU에는 타이머를 사용하여 PWM 신호를 출력할 수 있으므로 타이머를 사용하여 PWM 신호를 출력하는 코드를 작성해 보겠다.

 

 

코드 생성 - (0)

Parameter Settings
NVIC Settings
PIN

TIM2와 TIM4의 Parameter Settings은 같은 설정을 사용한다. 하지만 TIM2의 interrupt만 사용하고 TIM4의 경우 interrupt는 사용하지 않을 것이다.

 

TIM2, TIM4 2개의 타이머는 최대 4개의 PWM신호를 출력할 수 있다. 따라서 절반인 3개씩 PWM 신호를 출력하여 반씩 나눠 ESC를 제어할 것이다.

 

PWM 신호의 주기를 2ms로 잡고 PWM 신호의 길이가 1ms 일 경우 1000, 2ms 일 경우 2000의 값을 사용한다.

 

PIN구성이 살짝 변했으며 사용하지 않는 SPI등은 빼고 나중에 필요할 경우 다시 설정하기로 했다.

 

 

코드 - main.c (1)

 

1
2
3
4
5
/* USER CODE BEGIN 0 */
 
uint32_t motor[6]={0,};
 
/* USER CODE END 0 */

 

TIMx_CCR 레지스터에 데이터를 입력할 motor 배열을 선언한다.

 

motor의 값은 1000에서 2000사이의 값을 저장하고 나중에 드론을 제어할 때 PID계산을 하고 나오는 결과값들을 저장할 배열이다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* USER CODE BEGIN 2 */
//----------------------------------------------------------------------------------- pwm timer
  LL_TIM_EnableIT_UPDATE(TIM2);
  LL_TIM_CC_EnableChannel(TIM2,LL_TIM_CHANNEL_CH1);
  LL_TIM_CC_EnableChannel(TIM2,LL_TIM_CHANNEL_CH2);
  LL_TIM_CC_EnableChannel(TIM2,LL_TIM_CHANNEL_CH3);
 
  LL_TIM_CC_EnableChannel(TIM4,LL_TIM_CHANNEL_CH1);
  LL_TIM_CC_EnableChannel(TIM4,LL_TIM_CHANNEL_CH2);
  LL_TIM_CC_EnableChannel(TIM4,LL_TIM_CHANNEL_CH3);
 
 
  LL_TIM_EnableCounter(TIM2);
  LL_TIM_EnableCounter(TIM4);
 
//-----------------------------------------------------------------------------------
 
/* USER CODE END 2 */
 

 

TIM2 타이머의 UPDATE interrupt를 enable한다. TIM4 interrupt는 사용하지 않고 TIM2의 interrupt에 맞춰 6개의 값들을 한 번에 업데이트할 생각이다.

 

TIM2, TIM4 타이머의 PWM 신호들이 지정된 핀들에서 출력되도록 enable한다.

 

TIM2, TIM4 타이머를 작동시켜 PWM 신호들이 출력되게 한다.

 

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
/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
//========================================================================================================================= ibus receiver
      if(condition_uart4){
          LL_DMA_DisableStream(DMA1,LL_DMA_STREAM_2);
          LL_DMA_ClearFlag_TE2(DMA1);
          LL_DMA_ClearFlag_HT2(DMA1);
          LL_DMA_ClearFlag_TC2(DMA1);
          LL_DMA_ClearFlag_DME2(DMA1);
          LL_DMA_ClearFlag_FE2(DMA1);
          LL_DMA_EnableStream(DMA1,LL_DMA_STREAM_2);
 
          if(uart4_dma_buf[0]==0x20 && uart4_dma_buf[1]==0x40){
              timer[0]=(uint32_t)(uart4_dma_buf[7]<<8+ uart4_dma_buf[6];
              timer[1]=(uint32_t)(uart4_dma_buf[5]<<8+ uart4_dma_buf[4];
              timer[2]=(uint32_t)(uart4_dma_buf[9]<<8+ uart4_dma_buf[8];
              timer[3]=(uint32_t)(uart4_dma_buf[3]<<8+ uart4_dma_buf[2];
              timer[4]=(uint32_t)(uart4_dma_buf[11]<<8+ uart4_dma_buf[10];
              timer[5]=(uint32_t)(uart4_dma_buf[13]<<8+ uart4_dma_buf[12];
          }
          motor[0]=timer[0];
          motor[1]=timer[1];
          motor[2]=timer[2];
          motor[3]=timer[3];
          motor[4]=timer[4];
          motor[5]=timer[5];
 
          uart_counter++;
          if(uart_counter>50){
              printf("%d\t%d\t%d\r\n%d\t%d\t%d\n\n\r",timer[0],timer[1],timer[2],timer[3],timer[4],timer[5]);
              uart_counter=0;
          }
          condition_uart4=0;
      }
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
 
 

 

PWM 값들이 실시간으로 변하는 것을 보기 위해 이전 글에서 사용한 코드에서 motor[0]=timer[0]; 부분들만 추가했다.

 

Transceiver의 조이스틱을 변경하면 PWM 신호들이 어떻게 변하는지 볼 수 있다.

 

 

코드 - stm32f4xx_it.c (2)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */
    if(LL_TIM_IsActiveFlag_UPDATE(TIM2)){
        LL_TIM_ClearFlag_UPDATE(TIM2);
        LL_TIM_OC_SetCompareCH1(TIM2,motor[0]);
        LL_TIM_OC_SetCompareCH2(TIM2,motor[1]);
        LL_TIM_OC_SetCompareCH3(TIM2,motor[2]);
        LL_TIM_OC_SetCompareCH1(TIM4,motor[3]);
        LL_TIM_OC_SetCompareCH2(TIM4,motor[4]);
        LL_TIM_OC_SetCompareCH3(TIM4,motor[5]);
    }
 
  /* USER CODE END TIM2_IRQn 0 */
  /* USER CODE BEGIN TIM2_IRQn 1 */
 
  /* USER CODE END TIM2_IRQn 1 */
}
 

 

TIM2의 UPDATE interrupt가 발생하면 TIM2, TIM4의 PWM 값들을 한 번에 변경한다.

 

 

결과 - (3)

 

실제 오실로스코프로 찍어본 PWM 파형이다. Transceiver의 조이스틱을 움직이면 파형의 길이가 변하며 LED에 연결하여 빛의 밝기가 변하는 모습도 관찰할 수 있다.

 

사진을 보면 주파수가 500hz보다 약간 작게 측정이 되는데 타이머의 값들을 조금씩 변경해 알맞은 값을 찾을 생각이다.

 

 

 

-

타이머를 사용하여 6개의 PWM 신호를 출력했다.

 

Receiver와 MPU6050 코드들에 비해 쉬운 내용이어서 빠르게 작성할 수 있었다.

 

실제 PID코드를 작성하면 motor 배열에는 모터의 출력 값들이 들어가게 된다. 또한 motor값의 범위는 1000에서 약 1950 정도로 잡을 것이다.

 

 

현재 남은 과정에는 헥사콥터 조립과 기본적인 회로 제작, 제어를 위한 PID코드, PID게인을 컴퓨터로 변경할 수 있게 하는 코드, 지자기 센서 제어 등등 여러 코드들을 작성해야 한다.

 

남은일이 아직 많이 남아있다.

 

 

 

모든 코드는 LL드라이버를 사용한다.

Posted by DDTXRX
,