6. 센서, 모터의 사용

손지웅·2025년 5월 20일

Embedded Software

목록 보기
6/7

센서의 사용

아이폰 11 프로의 프로세서

  • 고성능 Big 코어와 저성능 Little 코어 등.. 좋은거 들어감

TrueDepth Camera

  • 3만개의 적외선 광선을 얼굴에 투사하고 반사광을 읽어서 3D로 얼굴 스케닝

아이폰의 내장 센서

  • 카메라, 터치아이디
  • 기압계 Barometer : 고도를 측정
  • 움직임 센서 : 3-axis accelerometer
  • 인접 센서, 조도 센서, 습도 센서
  • 자이로스코프
  • 전자 나침판, GPS 등

InvenSence Gyro ( 6축 )

  • 디지털 3축 각속도 센서 (gyroscopes)
  • 3 axis 방향의 회전각속도 측정. 단위는 degree per sec
  • 축당, 16bit ADC 사용
  • low-pass filer :특정 차단 주파수 이상의 주파수 신호를 감쇠시키고, 그 이하 주파수 신호만 통과시키는 필터
  • 저전력으로 동작

InvenSence AXLM

  • X,Y,Z축 가속도계. 단위는 g
  • 마찬가지로 축당 16bit ADC 사용
  • 인터럽트 사용 가능
  • 화면 깨우기 기능 등, 물체의 움직임이나 충격, 진동으로 인한 가속도를 측정한다.

가속도계 & 자이로스코프

자이로스코프 : 축 중심의 회전운동
가속도 : 축 방향으로 직선운동

MEMS AXLM ( 3축 )

가속도계, 자이로스코프 회로가 다 구현되어 있는 시스템

  • MEMS(micro electro mechinaical system) 물체의 공간이동 변위를 측정하는 회로로 구현

  • 축당 변위값 ADC -> 디지털 신호로

  • 자이로는 코리올리 가속으로 인한 공명하는 질량과 틀간의 변위를 측정한다. ( 회전하는 좌표계에서 직선 운동을 할 때, 운동 방향과 수직으로 생기는 가상의 가속도 )

  • MEM 내에는 진동하는 미세 질량이 있다. 센서가 회전하면 코리올리 힘 생김. 이걸로 계산

  • F= ma, 물체의 가속도는 힘으로부터 역추적한다.

Analog Device ADXL335

가속도 센서

  • 출력신호는 가속도에 비례하는 아날로그 전압값이다.
  • 아날로그 신호 3개 ( X,Y,Z 축의 가속도 )를 프로세서 내부에서 ADC를 거쳐 디지털 데이터로 변환한다.

Specification 예시

Sensor input에는 측정 범위 (+-3g ~ +-3.6g 즉 중력의 3배에서 3.6배까지 측정 가능) , 비선형성(센서 출력이 이론적인 직선에서 얼마나 벗어났는지 ), 센서 패키지가 기준 축에 대해 얼마나 틀어질 수 있는지, 축간에 서로 직각이 아닐 오차, 한 축에 가속도가 다른 축에 얼마나 영향을 미치는지.. 등이 표기되어 있다.

감도에는 1g에 따라 출력 전압이 얼마나 변하는지, 온도에 따라 얼마나 변하는지가 나와있다.

Zero g bias level 즉 가속도가 아예 없을때 기본적으로 나오는 전압 등이 표기되 있다.

자이로스코프

  • 물체가 어떤 축을 중심으로 회전할 때 각속도를 갖는다고 한다.
  • 회전각속도는 초당 회전수 or 각 으로 표시
  • 자이로는 저속으로 회전하는 물체의 축당 회전 변위를 측정하는데 사용한다.
  • 자이로 센서는 사람 머리카락 두께로 만듦

ST L3G4200D MEMS 3축 자이로


마찬가지로 센서의 측정 범위, 비선형성, 영점 오프셋 ( 회전하지 않을 때 가지는 오차 ) 등이 나와있다.

uBrain의 센서

초음파 센서, IR센서

초음파 거리센서

  • 초음파 송수신기와 제어회로로 구성
  • 송신기에서 나간 소리가 주변 물체에 반사되고 이를 수신기에서 감지 ( 3cm ~ 300cm )
  • 수신된 반사파를 제어회로에서 처리, 송신시간과 수신시간간의 차이로부터 거리를 계산한다.

SRF04 초음파 거리센서 동작 과정

  • CPU는 10us 길이의 트리거 펄스(아주 짧은 전기 신호)를 모듈의 trigger(시작 신호를 받는 입력 핀)에 입력해 제공한다.
  • SRF04는 8사이클동안 40khz의 초음파 신호를 송신기에서 송출, echo 출력라인을 high로 만든다.
  • 반향신호가 검출되면, echo 출력을 low로 만듦
  • SW를 이용하여 echo라인에 발생하는 펄스의 길이로부터 물체와의 거리를 계산한다.
  • Echo라인 : 반향신호를 검출하지 못할 시, 36ms 이후부터는 자동으로 low로 떨어져 리셋
  • 초음파 송신기의 빔 패턴은 폭이 좁은 모양이다. 즉 정면이 아닌 위치의 물체는 감지할 수 없다.

    센서의 트리거 펄스
    초음파 버스트
    에코 펄스 -> 초음파를 8사이클동안 쏘고 나서 1로 올림, 그리고 들어오면 0으로 내림
    이 에코펄스가 1인 시간을 통하여 이동거리 계산
    HOW ?
    속도 = 거리/시간
    속도는 343m/s로 정해짐.
    즉 이동거리 = 시간 * 속도
    를 2로 나누면됨.

uBrain 초음파센서 연결 상태

Echo 신호는 GPIO AF의 TIM3에 연결되어 있음 -> Input Capture 모드를 설정하여 인터럽트 핸들러에서 장애물까지의 거리를 계산한 USS_TRIG 신호로 3방향의 초음파 동시에 송출

초음파 센서 TRIG 신호의 연결

회로도를 참고하여 보면 GPIOF 포트의 핀 6번 즉 PF6에 연결되어 있다.
TIM10은 16비트 카운터를 이용하는 범용 타이머

STRM32F429의 범용 타이머 TIMx

  • input capture 모드 : 입력 신호의 길이를 측정
  • output compare 모드, PWM 모드 : 출력 파형을 생성

특징

  • TIM3, TIM10 은 16비트 카운터를 사용
  • TIM3는 최대 4개, TIM10은 최대 2개의 독립적인 채널 사용 가능
  • 인터럽트 생성 가능

TIM3의 input channel을 capture mode로 설정

3개의 채널로부터 각각 초음파 센서 3개의 echo 신호 입력을 읽음.

범용 타이머의 Input Capture mode

capture : 외부 신호가 들어온 순간, 타이머 카운터의 값을 저장

  • 타이머 카운터 값을 이용하여 시간의 흐름 측정
  • Capture/Compare 레지스터 TIMx_CCRx 값은 입력단의 ICx 신호가 검출된 직후 타이머의 카운터 값을 저장
  • Capture가 발생 -> TIMx_SR 레지스터의 CCxIF 플래그가 1, 인터럽트가 발생
  • 만약 CCxIF 가 이미 1인 상태에서 캡쳐가 발생했다면, CCxOF 플래그(overflow flag. 너무 신호가 빠른 주기로 들어와 못읽음) 가 1로 되며 인터럽트가 발생한다.
  • CCxIF 플래그는 TIMx_CCRx 레지스터에 있는 값을 소프트웨어에서 읽어가면 0으로 변경
  • CCxOF 플래그는 0으로 직접 값을 써줘서 변경

TIMx_CCR1을 이용한 TI1 입력 길이 측정

CCR : cpature compare register

  1. 입력 채널 선택. CCR1이 어느 입력 TI1에 연결될지 선택
  2. 입력 필터 설정. 필터를 설정하여 신호가 안정적으로 들어왔을 때만 캡쳐
  3. 상승 or 하강 엣지 중 어느 엣지에 캡쳐할 지 선택
  4. prescaler 변환. 모든 신호 변화마다 캡쳐를 할지, 몇번에 한번만 캡쳐할지 정한다.

Input Capture가 발생할 때의 동작

Input Capture 모드에서 거리 계산 방법

  1. Rising Edge를 감지하도록 설정
  2. Low 상태였던 외부 신호가 High가 되면 interrupt가 발생
  3. CCRx값을 저장 후 failing edge를 감지하도록 설정 변경
  4. High -> Low 가 되면, 인터럽트 발생
  5. 이때의 CCRx값을 저장 후, 다시 Rising Edge를 감지하도록 설정

3,5 의 CCRx 차를 이용하여 Count값 계산

주황색 신호는 외부에서 들어온 펄스 신호
T1,T2는 상승 엣지 -> 타이머는 해당 시점의 카운터 값을 캡쳐한다.
T2-T1 하여 T3 값을 얻음

타이머는 count 단위로 시간을 기록 즉 Timer 입럭 클럭 속도로 나눠줘야 함.

타이머 클럭은 1MHz, 1초에 1,000,000번 카운트
카운트 차 5000
펄스 폭 = 5000 / 1,000,000 = 0.005초

코드

Input Capture 모드 설정하기

  1. TIMHandle 구조체 인자값 정의 : 어떤 타이머를 쓸 지, 기본설정 등 정보를 담는 구조체 정의
  2. HAL_TIM_IC_Init() : 정의한 구조체를 바탕으로 타이머를 Input Capture 모드로 초기화
  3. Input Capture 구조체 인자값 정의 : 어떻게 캡쳐할 지 세부 설정을 담음
  4. HAL_TIM_IC_ConfigChannel 설정 : input Capture 구조체를 특정 타이머 채널에 적용
  5. HAL_TIM_Start_IT 인터럽트 활성화 : input capture 기능을 인터럽트와 함께 시작함
// TIM_HandleTypeDef 구조체 선언 및 기본 설정
TimHandle1.Instance = TIM3;                 // 사용할 타이머: TIM3

// 카운트 최대값 설정 (0xFFFF = 65535)
TimHandle1.Init.Period = 0xFFFF;            // 타이머가 0부터 65535까지 센다

// 프리스케일러(분주비) 설정: 타이머 입력 클럭을 나누는 값
TimHandle1.Init.Prescaler = uwPrescalerValue; // 원하는 분주비 값 사용

// 클럭 분주 설정 (일반적으로 0 또는 1)
TimHandle1.Init.ClockDivision = 0;          // 클럭 분주 사용 안함

// 카운터 모드 설정 (업카운트: 0→65535로 증가)
TimHandle1.Init.CounterMode = TIM_COUNTERMODE_UP;

// 타이머 초기화 (Input Capture 모드로 초기화)
HAL_TIM_IC_Init(&TimHandle1);

// Input Capture 설정 구조체 선언 및 값 지정
sICConfig1.ICPolarity  = TIM_ICPOLARITY_RISING;      // 상승 에지에서 캡처
sICConfig1.ICSelection = TIM_ICSELECTION_DIRECTTI;   // 직접 입력 캡처 사용
sICConfig1.ICPrescaler = TIM_ICPSC_DIV1;             // 프리스케일러 없음, 모든 신호에서 캡처
sICConfig1.ICFilter    = 0;                          // 입력 필터 사용 안함

// uBrain의 초음파는 TIM3의 2, 3, 4번 채널을 사용
HAL_TIM_IC_ConfigChannel(&TimHandle1, &sICConfig1, TIM_CHANNEL_2); // 2번 채널 설정
HAL_TIM_IC_Start_IT(&TimHandle1, TIM_CHANNEL_2);                  // 2번 채널 캡처 인터럽트 시작

HAL_TIM_IC_ConfigChannel(&TimHandle1, &sICConfig1, TIM_CHANNEL_3); // 3번 채널 설정
HAL_TIM_IC_Start_IT(&TimHandle1, TIM_CHANNEL_3);                  // 3번 채널 캡처 인터럽트 시작

HAL_TIM_IC_ConfigChannel(&TimHandle1, &sICConfig1, TIM_CHANNEL_4); // 4번 채널 설정
HAL_TIM_IC_Start_IT(&TimHandle1, TIM_CHANNEL_4);                  // 4번 채널 캡처 인터럽트 시작

초음파 Trigger 펄스의 생성

PWM(Pulse Width Modulation) Output 펄스 폭 변조하여 출력

  • 펄스의 폭을 사용자가 프로그래밍 하여, 출력 신호를 생성한다.
  • 초음파 신호의 트리거 신호 생성, 모터 속도 제어 신호 생성

uBrain에서 PWM 신호의 사용

  • 초음파 센서는 일정 길이 이상의 짧은 펄스가 입력되어야 초음파를 발생시킴
  • 해당 펄스는 TIM(TIMER)에서 제공하는 PWM가 만들어줌
  • 타이머의 카운터를 설정해서 주기적으로 일정 길이의 펄스를 만들어줌.

Duty Cycle : 한 주기에서 신호가 High 상태로 유지되는 시간의 비율
듀티비 : High 시간 / 전체 시간 * 100
PWM은 첫번째 그래프처럼 듀티비를 조절하여 속도나 LED 밝기 등을 제어할 수 있다.

초음파 센서를 위한 PWM OUTPUT 모드 설정

PWM모드는
TIMx_ARR ( auto reload register ) 을 이용하여 출력신호의 주기를 결정.
TIMx_CCRx (Capture/Compare register ) 을 이용하여 듀티비 결정
ARR = 5000 이고, CCR = 2500 이면 듀티비는 50%

1초에 2회 초음파 생성을 위하여, ARR = 0xFFFF로 설정하고 CCR = 2 설정했을 때 10us 이상의 듀티를 보장할 수 있도록 Prescalar 값을 설정하는 것이 핵심

1초에 2회 초음파 생성 -> 2Hz로 거리 측정
트리거 펄스의 길이는 10us 이상으로 생성. 펄스의 길이는 0.5초이다. 해당 주기를 타이머가 카운트하여 반복적으로 펄스를 내보낸다.

TIMx의 PWM 설정

TIM10 Trigger PWM 설정 코드

IR센서

Infrared laser 센서
초음파 센서와 비슷
발광부에서 적외선 방출, 수광부에서 적외선 감지.
적외선의 양! 에 따라 변하는 전류의 양을 ADC를 통해서 계산한다.
마찬가지로 3개의 IR센서는 GPIO Port C에 3개의 Analog 입력으로 설정하여 사용한다.

모터의 사용

Encoder DC Motor

DC Motor

  • 자석에 흐르는 전류의 방향과 세기를 조절하여 회전력 발생
  • 회전 방향과 이동거리 계싼을 위해 인코더 인터페이스 사용

DC 모터의 제어

  • DC 모터는 PWM을 이용하여 입력신호의 듀티비를 바꿔가며 입력하는 평균 전압을 변경하여 속도를 제어
  • On/Off 를 빠르게 반복함으로서 구동시간을 조절
  • Timer 기능을 이용하여 Pulse 당 high구간의 길이를 조

DC 모터 인터페이스

  • -+ Motor에 전압을 인가하여 회전수를 조절
  • HALL 센서(자기장 변화를 감지) 인코더를 이용하여 모터의 위치정보를 제공

모터 커넥터

  • -/+ 모터 출력신호 -> LOAD_1A, LOAD_2A / LOAD_1B, LOAD_2B
  • Hall Sensor Aout Bout 입력 신호 -> TACHOA0 TACH0A1 / TACH0B0 TACH0b1

uBrain STM 32에서의 모터제어 신호의 연결

그러니까 모터를 제어할 때 어떤 신호선이 모터 드라이버와 MCU간의 신호 연결을 하는 지
모터 제어할 때 어떤 신호선이 STM32의 어느 핀에 연결되는지 표시

  • 모터 드라이버의 입력 신호는 MC-1A 2A -> MCU의 GPIO포트 PC 67 에 연결
  • MC_1B 2B -> GPIO PD12 13에 연결
  • 활성화 신호인 MC-EN은 PB2에 연결
  • 회전 속도를 MCU로 입력받는 선. 모터의 속도 측정 TACHOA0 TACH0A1 -> PB4 5/ TACH0B0 TACH0b1 PA15 PB3 연결

모터 드라이버의 입력 신호 1A 2A 1B 2B EN
모터 속도 측정 신호 TACHO 는
STM32의 특정 핀들에 각각 연결되어 있어서 MCU는 해당 핀들을 read/write하여 묘터를 컨트롤할 수 있음.

uBrain 보드 모터 구동칩

  • 모터 출력 활성화 : MC_EN 한개를 2개의 EN에 연결
  • 모터출력 : MC_1A 2A / MC_1B 2B
  • CMOS 전압과 전류를 모터 구동을 위한 전류로 변환

uBrain 모터 인터페이스

모터 인터페이스는 PWM을 + - 방향으로 발생시키는 2개의 출력핀이 TIM3,4에 연결되어 있음
타이머에서 제공하는 Encoder Interface를 이용하여 현재 바퀴의 회전방향과 회전 수를 알아낼 수 있다.
왼쪽/오른쪽 두개의 모터 구동과 Encoder1,2 인터페이스가 연결되어 있음

STM32F429의 외부 인터럽트 EXTIx 연결도

EXTI External Interrupt, 외부 인터럽트

GPIO포트들의 각 핀들은 그룹으로 묶어서 EXTI0 ~ EXTI15 까지 총 16개의 외부 인터럽트를 발생시킬 수 있다.
uBrain에서는 2개의 인코더가 4핀에 연결되어 있으므로 EXTI 4 5 3 15를 발생시키도록 설정

모터 인코더의 원리

  • Hall 센서를 이용하여 자기장의 변위 측정, 두 개의 출력 AB의 위상 정보를 제공한다.
  • 90도의 다른 위상을 가지는 AB 신호 변화를 연속적으로 관찰하여 모터의 회전방향과 속도를 계산한다.
  • A 입력의 펄스 수 카운트 -> 회전당 펄스 수를 나누면 전체 회전수를 구할 수 있다.
  • uBrain의 경우 모터는 1회전에 26개의 펄스가 생성된다.

회전방향과 모터 위치 결정

  • 회전 방향은 각 모터 인코더의 2개의 센서 값을 체크하면 알 수 있다.
  • 타이머 인터페이스가 TI1, TI2 입력을 이용하여 TI1 상승 엣지에 인터럽트 설정한 후 인터럽트가 발생할 때 TI2가 0이면 forward, 1이면 backward로 회전 방향 판단
  • 인코더 모드에서 타이머의 클럭은 TI1 TI2 엣지에서 증가. 모터의 회전 방향에 따라 카운터가 증가하거나 감소
  • 따라서 해당 채널의 카운터 값을 읽거나 인터럽트 발생 횟수를 저장해 놓으면 현재 모터의 회전방향과 회전속도를 알아 낼 수 있다.

천천히 해보자. 인코더는 모터 축이 얼마나 어떤 방향으로 알려주는 센서이다. 대부분 2개의 신호선을 사용하고 AB 또는 TI1 TI2 라고 부른다. 한개는 얼마나 돌았는지만 알 수 있고, 두개가 있어야 어느 방향으로 도는지 알 수 있다.

두 신호가 0과 1로 바뀌는데 TI1이 상승할 때 TI2가 0이면 앞으로
TI1가 상승할 때 TI2가 1이면 뒤이다.

따라서 현재 채널의 카운터 값을 읽거나 인터럽트 발생 횟수를 저장해 놓으면 현재 모터의 회전방향과 회전속도를 알아 낼 수 있다.

GPIO EXTI 인터럽트 핸들러

// EXTI3 인터럽트가 발생하면 벡터테이블에서 이 함수로 점프함
void EXTI3_IRQHandler(void)
{
    // HAL 라이브러리의 공통 EXTI 인터럽트 핸들러 호출 (핀 번호 3)
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
}

// HAL 라이브러리의 EXTI 인터럽트 핸들러
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
    // EXTI 인터럽트가 실제로 발생했는지 확인
    if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
    {
        // 인터럽트 플래그를 클리어(0으로) 해줌 (다음 인터럽트 처리를 위해)
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
        // 사용자 정의 콜백 함수 호출 (main.c에서 구현)
        HAL_GPIO_EXTI_Callback(GPIO_Pin);
    }
}

// 사용자 정의 콜백 함수 (main.c에서 구현)
// 실제로 핀 변화에 따라 동작을 코딩하는 부분
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    switch(GPIO_Pin)
    {
        case GPIO_PIN_15: // PA15, Encoder 2의 A=1 상태에서 인터럽트 발생
            encoder_right = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3); // Encoder 2의 B값 읽기
            if(encoder_right == 0) // B=0이면 Forward(정방향) 회전 중
            {
                motorInterrupt1++;     // 카운터 증가 (정방향)
                encoder_right = READY; // 상태 플래그 갱신
            }
            else if(encoder_right == 1) // B=1이면 Backward(역방향) 회전 중
            {
                motorInterrupt1--;     // 카운터 감소 (역방향)
                encoder_right = READY; // 상태 플래그 갱신
            }
            break;
        // (다른 핀에 대한 처리도 추가 가능)
    }
}
case GPIO_PIN_4: // Encoder 1 PB4에서 인터럽트 발생 시
    // Encoder 1의 B 신호(PB5)를 읽어서 방향 판단
    encoder_left = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5);

    if(encoder_left == 0) // B신호가 0이면 정방향(Forward) 회전
    {
        motorInterrupt2++;    // 카운터 증가 (정방향)
        encoder_left = READY; // 상태 플래그 갱신
    }
    else if(encoder_left == 1) // B신호가 1이면 역방향(Backward) 회전
    {
        motorInterrupt2--;    // 카운터 감소 (역방향)
        encoder_left = READY; // 상태 플래그 갱신
    }
    break;

회전수의 계산을 위한 Cailbration 필요성

예를 들어 모터가 한 바퀴 돌 때 인코더가 100개의 펄스 발생시키면
모터가 1바퀴 -> 카운터가 100만큼 증가 또는 감소
근데 카운터 변화량이 이동거리로 바로 가진 않음.

  • 모터가 한바퀴 회전 -> 인코더 신호로부터 계산된 카운터의 변화량에 따른 이동거리는 모터의 조립상태나 제적한 모터의 상태에 따라 다름. 인코더 값을 먼저 실험을 통해 측정한 후 자신의 로봇에 맞도록 코드를 조정해야 한다.
    이러한 과정을 Cailbration이라고 부름.
    기계바다, 베터리 충전 상황, 날씨, 장소 등에 따라 반드시 Cailbration이 필요하다.

  • 주행 전에 제어를 위한 세팅값을 측정을 통해 결정한다. (주행시간과 주행거리의 관계, 회전과 회전시간의 관계 )

  • parameter

  • 전진거리/전진시간

  • 좌회전각도/좌회전시간

  • 우회전각도/우회전시간

  • 모터 인코더 값 오차

    모터 사용을 위한 TIM3, TIM4 PWM 설정

  • uBrain에서는 2개의 모터를 사용 -> TIM3 TIM4 에 대해 동일한 PWM 모드 설정

  • 모터의 전원은 PB2 핀에 연결되어 있음. 1로 세팅하여 전원 공급

  • TIM3 4 두개의 채널을 두 방향의 PWM 출력으로 설정

  • 예제에서는 20000개의 펄스를 최대 출력으로 하는 듀티비를 제어한다.

  • Duty ratio = period / pulse * 100

  • 펄스의 조정 : 펄스길이 재설정 - 재적용 - HAL_TIM_start 순으로 설정

두 개의 모터 -> TIM3 TIM4 타이머의 PWM 신호로 제어, PB2 핀을 1로 올려 모터 전원을 킨다.
PWM의 Period와 Pulse 구간을 조정하여 듀티비 즉 모터 속도를 바꿀 수 있다.

인코더를 사용하기 위한 타이머 설정

// ===============================
// 인코더용 타이머 설정 코드 예시
// ===============================

// 1. TIM_Encoder_InitTypeDef 구조체 선언 및 초기화
TIM_Encoder_InitTypeDef sENConfig;

// 인코더 모드 설정: TI1과 TI2(두 신호선)를 모두 사용 (쿼드러처 인코더 모드)
sENConfig.EncoderMode = TIM_ENCODERMODE_TI12;

// 채널1, 채널2 모두 직접 입력으로 선택 (A, B 신호를 직접 받음)
sENConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sENConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;

// 채널1, 채널2 모두 상승 에지에서 신호 감지
sENConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sENConfig.IC2Polarity = TIM_ICPOLARITY_RISING;

// 입력 필터 사용 안 함 (노이즈가 심하면 값 조정 가능)
sENConfig.IC1Filter = 0;
sENConfig.IC2Filter = 0;

// 프리스케일러 사용 안 함 (모든 신호 변화에 반응)
sENConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sENConfig.IC2Prescaler = TIM_ICPSC_DIV1;

// 2. TIM_HandleTypeDef 구조체 선언 및 초기화
TIM_HandleTypeDef TimHandle3;

// 사용할 타이머 인스턴스 지정 (여기서는 TIM5)
TimHandle3.Instance = TIM5;

// 타이머의 주기(최대 카운트 값) 설정 (여기서는 1000)
TimHandle3.Init.Period = 1000;

// 타이머 프리스케일러 값 설정 (클럭을 얼마나 나눌지, uwPrescalerValue는 미리 계산된 값)
TimHandle3.Init.Prescaler = uwPrescalerValue;

// 클럭 분주 사용 안 함
TimHandle3.Init.ClockDivision = 0;

// 카운터가 증가(UP)하는 모드로 설정
TimHandle3.Init.CounterMode = TIM_COUNTERMODE_UP;

// 3. 인코더 모드로 타이머 초기화
HAL_TIM_Encoder_Init(&TimHandle3, &sENConfig);

// 4. 인코더 관련 타이머 채널 시작 (채널 1, 2 모두)
HAL_TIM_Encoder_Start(&TimHandle3, TIM_CHANNEL_1);
HAL_TIM_Encoder_Start(&TimHandle3, TIM_CHANNEL_2);

// ===============================
// 설명
// ===============================

// - 이 코드는 TIM5의 채널 1, 2를 인코더 입력(A, B 신호)으로 사용하도록 설정합니다.
// - 인코더 모드(TI12)를 사용하면, 두 신호의 위상 차이를 자동으로 분석해
//   모터가 어느 방향(정방향/역방향)으로 얼마나 회전했는지 타이머 카운터 값으로 알 수 있습니다.
// - 카운터 값이 증가(UP)하면 forward(정방향) 회전, 감소(Down)하면 backward(역방향) 회전을 의미합니다.
// - 실제로는 타이머 카운터 값을 읽어서 모터의 위치, 이동거리, 회전 방향 등을 소프트웨어에서 계산할 수 있습니다.
// - 좌측/우측 모터가 있다면, 타이머4도 동일하게 설정해서 각각의 인코더 신호를 읽을 수 있습니다.

uBrain 모터의 구동함수

// 모터를 전진(Forward)시키는 함수
void Motor_Forward(void)
{
    // 왼쪽 모터: TIMHandle1의 채널 1번 PWM 시작 (정방향)
    HAL_TIM_PWM_Start(&TimHandle1, TIM_CHANNEL_1);
    // 오른쪽 모터: TIMHandle2의 채널 2번 PWM 시작 (정방향)
    HAL_TIM_PWM_Start(&TimHandle2, TIM_CHANNEL_2);
}

// 모터를 후진(Backward)시키는 함수
void Motor_Backward(void)
{
    // 왼쪽 모터: TIMHandle1의 채널 2번 PWM 시작 (역방향)
    HAL_TIM_PWM_Start(&TimHandle1, TIM_CHANNEL_2);
    // 오른쪽 모터: TIMHandle2의 채널 1번 PWM 시작 (역방향)
    HAL_TIM_PWM_Start(&TimHandle2, TIM_CHANNEL_1);
}

// 모터를 좌회전(Left)시키는 함수
void Motor_Left(void)
{
    // 왼쪽 모터: TIMHandle1의 채널 2번 PWM 시작 (역방향)
    HAL_TIM_PWM_Start(&TimHandle1, TIM_CHANNEL_2);
    // 오른쪽 모터: TIMHandle2의 채널 2번 PWM 시작 (정방향)
    HAL_TIM_PWM_Start(&TimHandle2, TIM_CHANNEL_2);
    // → 왼쪽 바퀴는 뒤로, 오른쪽 바퀴는 앞으로 돌려서 제자리에서 좌회전
}

// 모터를 우회전(Right)시키는 함수
void Motor_Right(void)
{
    // 왼쪽 모터: TIMHandle1의 채널 1번 PWM 시작 (정방향)
    HAL_TIM_PWM_Start(&TimHandle1, TIM_CHANNEL_1);
    // 오른쪽 모터: TIMHandle2의 채널 1번 PWM 시작 (역방향)
    HAL_TIM_PWM_Start(&TimHandle2, TIM_CHANNEL_1);
    // → 왼쪽 바퀴는 앞으로, 오른쪽 바퀴는 뒤로 돌려서 제자리에서 우회전
}

0개의 댓글