본문 바로가기
정나우/STM32

산업용 모터 엔코더 값 받기

by 정_나우 2023. 5. 20.

모터를 제어할 때 open-loop으로 제어하면 정확한 제어를 하기 어렵습니다.

 

그래서 내가 준 신호와 실제 값 사이를 비교해서 부족한만큼 더 신호를 가해주거나

오버한만큼 줄여주는 feed-back제어가 필요합니다.

 

feed-back 제어를 하기 위해서는 모터의 상태를 읽어오는 무언가가 필요한데

그것에 엔코더입니다.

 

이번 글에서는 산업용 모터에서 엔코더 값을 어떻게 받아오는지 알아보겠습니다.


1. 배선

제가 사용하는 서보앰프의 배선도입니다.

 

CN1A 중계 단자대의 6, 16, 7, 17 에서 엔코더 신호가 나오는 것을 확인할 수 있습니다.

 

엔코더 신호를 STM board에 연결하기 전에

 

라인 리시버 (신호를 깔끔하게 만들기 위해)와

레벨 쉬프터(STM이 받을 수 있는 전압 크기로 낮추기 위해)를 거쳐서

STM board로 가게 배선을 해줍니다.

 

 

라인 리시버 연결도

라인 리시버의 출력핀 1Y, 2Y를 레벨 쉬프터에 연결하고

레벨 쉬프터의 출력핀을 STM의 엔코터 핀에 연결해주었습니다.

 

원래 신호에 노이즈가 많고 크기가 4.6V였는데

라인 리시버를 사용해서 신호가 깔끔해졌고, 레벨 쉬프터 덕분에 신호의 크기가 STM32가 받을 수 있는 크기인 3V로 작아졌습니다.


2. 코드

엔코더를 사용하기 위해서는 엔코더 타이머를 사용해야 합니다.

 

STM32CubeIDE를 사용했고, Timer → TIM1 (엔코더 모드가 가능한 아무 타이머 가능) 

Combined channel → Encoder Mode

로 설정해줍니다.

 

 

 

그리고 Parmeter Settings에서 Counter Period를

자신이 사용하는 엔코터 펄스수x4 - 1 를 해줍니다.

 

Counter Period에 엔코더 신호의 Edge수를 넣어야 하기 때문에 펄스수x4 - 1를 해주는 겁니다.

(-1을 하는 이유는 0부터 세기 때문에)

매뉴얼과 실제로 확인해 본 결과 펄스 4000

 

그리고 4체배를 사용하기 위해  Encoder Mode를 TI1 and TI2로 설정해줍니다.

 

 

 

그리고 NVIC Setting에서도 update 설정을 해줍니다.

 

사용하는 모터가 여러 개라 엔코더 타이머를 여러개 쓴다면 다른 엔코더는 Global Interrupt 설정을 해줍니다.

 

 

 

 

CubeIDE에서 GUI로 설정하는 건 여기까지고 이제 Ctrl+C로 Code Generate를 해준 뒤 maic.c로 넘어갑니다.

 

타이머를 사용하기 때문에 당연히 타이머를 실행시켜줘야 합니다.

그리고 엔코더도 작동시켜줍니다.

  HAL_TIM_Base_Start_IT(&htim1);
  HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_1 | TIM_CHANNEL_2);

 

 

 

엔코더를 읽는 함수를 주기가 10ms인 타이머에 맞춰서 실행되게 만들어줍니다.

 

이렇게 만들면 main문 안에서 함수 이름만 불러와 사용할 수 있습니다.

void Encoder_pulse_x(void)
{
   x_Encoder_cnt= TIM1->CNT;
   x_Encoder_Current_cnt = (16000-1)*(x_Sign_cnt - 1) + x_Encoder_cnt;
   x_Angle = 360*((float)x_Encoder_Current_cnt/(16000-1));
   x_location = 10*(x_Angle/360);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
   if(htim -> Instance == TIM1)
   {
      if(TIM1 -> CNT <= 8000){
         x_Sign_cnt++;
      }
      else{
         x_Sign_cnt--;
      }
   }

   if(htim -> Instance == TIM6)
   {
      Encoder_pulse_x();
      Encoder_pulse_y();
      Encoder_pulse_z();
   }
}

 

   location을 계산할 때 10은 제가 사용한 리니어 액츄에이터의 리드 값(한바퀴 회전했을 때 얼마나 앞으로 가는지)입니다.

 

속도를 계산하고 싶으면 이전의 위치 값과 현재의 위치값을 빼고 

그 뺀 값을 인터럽트 주기만큼 나눠주면 됩니다. (미분)

 

그리고 디버그로 실행하서 Live expression에 변수를 불러와 값이 잘 받아지는지 확인하면 끝입니다.

댓글