STM32 스마트 자동차(선 추적, 추종, 장애물 회피, 속도 측정, 블루투스, Wi-Fi, 4G, 음성 인식) 종합 가이드

1. 모듈 구동

1.1 모터 모듈 개발

L9110s 모듈은 양방향 DC 모터 제어에 사용됩니다. 모듈의 작동 원리는 다음과 같습니다:

  • IA1에 하이 레벨 입력, IB1에 로우 레벨 입력 시 모터 정방향 회전
  • IA1에 로우 레벨 입력, IB1에 하이 레벨 입력 시 모터 역방향 회전

연결 방식:

  • B-1A -- PA0
  • B-1B -- PB1
  • A-1A -- PA1
  • A-1B -- PB10

기본 동작 코드:

motor.c

#include "motor.h"

void 자동차_전진(void)
{
    // 좌측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 우측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}

void 자동차_후진(void)
{
    // 좌측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    // 우측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
}

void 자동차_좌회전(void)
{
    // 좌측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 우측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}

void 자동차_우회전(void)
{
    // 좌측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 우측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}

void 자동차_정지(void)
{
    // 좌측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    // 우측 모터
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}

1.2 PWM 속도 제어

PWM(펄스 폭 변조)를 사용한 모터 속도 제어 원리:

  • 전체 속도로 전진: LeftCon1A = 0; LeftCon1B = 1;
  • 완전 정지: LeftCon1A = 0; LeftCon1B = 0;
  • 주기(예: 20ms) 내에서 전진 시간이 길수록 속도가 빨라짐

PWM 속도 제어 코드:

// 메인 함수 내
TIM_HandleTypeDef htim2;

void PWM_속도_제어_테스트(void)
{
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
    
    while (1)
    {
        // 저속
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 8);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 8);
        HAL_Delay(1000);
        
        // 중속
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 15);
        __HAL_TIM_SetCompare(&htim2, CHANNEL_2, 15);
        HAL_Delay(1000);
        
        // 고속
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 25);
        __HAL_TIM_SetCompare(&htim2, CHANNEL_2, 25);
        HAL_Delay(1000);
    }
}

1.3 PWM를 이용한 회전 제어

회전 원리:

  • 우회전: 좌측 모터 속도 > 우측 모터 속도
  • 좌회전: 우측 모터 속도 > 좌측 모터 속도

PWM 회전 제어 코드:

void 회전_테스트(void)
{
    while (1)
    {
        // 우회전
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 10);  // 좌측 모터: 중속
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 20);  // 우측 모터: 고속
        HAL_Delay(1000);
        
        // 좌회전
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 20);  // 좌측 모터: 고속
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 10);  // 우측 모터: 중속
        HAL_Delay(1000);
    }
}

2. 선 추적 자동차

2.1 TCRT5000 센서 소개

TCRT5000 적외선 선 추적 센서 작동 원리:

  • 적외선 발 다이오드가 지속적으로 적외선을 발사
  • 검은색 선은 적외선을 흡수하므로, 센서는 검은색을 감지하면 하이 레벨 출력
  • 흰색 배경은 적외선을 반사하므로, 센서는 흰색을 감지하면 로우 레벨 출력

연결 방식:

  • VCC: 전원 양극(3-5V)
  • GND: 전원 음극
  • DO: TTL 스위치 신호 출력(0 또는 1)
  • AO: 아날로그 신호 출력(일반적으로 연결하지 않음)

2.2 선 추적 제어 원리

선 추적 알고리즘:

  • 양쪽 센서 모두 흰색 감지: 전진
  • 좌측 센서만 검은색 감지: 우회전
  • 우측 센서만 검은색 감지: 좌회전
  • 양쪽 센서 모두 검은색 감지: 정지

2.3 선 추적 핵심 코드

연결 방식:

  • 선 추적 센서(좌측) -- PB3
  • 선 추적 센서(우측) -- PB4
#define 좌측_센서값 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define 우측_센서값 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)

void 선_추적_제어(void)
{
    if (좌측_센서값 == GPIO_PIN_RESET && 우측_서서값 == GPIO_PIN_RESET)
        자동차_전진();
    else if (좌측_센서값 == GPIO_PIN_SET && 우측_센서값 == GPIO_PIN_RESET)
        자동차_우회전();
    else if (좌측_센서값 == GPIO_PIN_RESET && 우측_센서값 == GPIO_PIN_SET)
        자동차_좌회전();
    else if (좌측_센서값 == GPIO_PIN_SET && 우측_센서값 == GPIO_PIN_SET)
        자동차_정지();
}

2.4 부드러운 회전 구현

PWM를 이용한 부드러운 회전 구현:

void 부드러운_회전_제어(void)
{
    if(좌측_센서값 == GPIO_PIN_RESET && 우측_센서값 == GPIO_PIN_RESET)
    {
        // 직진
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 25);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 25);
    }
    else if(좌측_센서값 == GPIO_PIN_SET && 우측_센서값 == GPIO_PIN_RESET)
    {
        // 우회전 (좌측 속도 > 우측 속도)
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 20);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 10);
    }
    else if(좌측_센서값 == GPIO_PIN_RESET && 우측_센서값 == GPIO_PIN_SET)
    {
        // 좌회전 (우측 속도 > 좌측 속도)
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 10);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 20);
    }
    else if(좌측_센서값 == GPIO_PIN_SET && 우측_센서값 == GPIO_PIN_SET)
    {
        // 정지
        자동차_정지();
    }
}

3. 추종/장애물 회피 자동차

3.1 적외선 장애물 감지 센서

작동 원리:

  • 선 추적 센서와 유사하나, 적외선 방향이 수평으로 향함
  • 장애물이 가까이 있으면 적외선이 반사되어 로우 레벨 출력
  • 장애물이 없으면 적외선이 반사되지 않아 하이 레벨 출력

3.2 추종 자동차 원리

추종 알고리즘:

  • 좌측 센서 장애물 감지, 우측 센서 미감지: 우회전
  • 우측 센서 장애물 감지, 좌측 센서 미감지: 좌회전
  • 양쪽 센서 모두 장애물 감지: 전진
  • 양쪽 센서 모두 장애물 미감지: 정지

3.3 추종 자동차 코드

연결 방식:

  • 추종 센서(좌측) -- PB5
  • 추종 센서(우측) -- PB6
#define 좌측_추종_센서값 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)
#define 우측_추종_센서값 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)

void 추종_제어(void)
{
    if(좌측_추종_센서값 == GPIO_PIN_RESET && 우측_추종_센서값 == GPIO_PIN_RESET)
        자동차_전진();
    else if(좌측_추종_센서값 == GPIO_PIN_SET && 우측_추종_센서값 == GPIO_PIN_RESET)
        자동차_우회전();
    else if(좌측_추종_센서값 == GPIO_PIN_RESET && 우측_추종_센서값 == GPIO_PIN_SET)
        자동차_좌회전();
    else if(좌측_추종_센서값 == GPIO_PIN_SET && 우측_추종_센서값 == GPIO_PIN_SET)
        자동차_정지();
}

3.4 초음파 센서 소개

HC-SR04 초음파 센서 작동 원리:

  • Trig 핀에 최소 10us 하이 레벨 신호 발생
  • Echo 핀이 로우에서 하이로 변하면 초음파 발사 시작
  • Echo 핀이 하이에서 로우로 변하면 초음파 수신 완료
  • Echo 핀의 하이 레벨 유지 시간으로 거리 계산
  • 거리(cm) = (시간(us) * 340m/s) / 2 / 10000

3.5 서보 모터 소개

SG90 서보 모터 특성:

  • PWM 신호로 각도 제어 (주파수 약 50Hz, 주기 20ms)
  • 각도 제어 범위: 0° ~ 180°
  • 각도별 PWM 펄스 폭:
  • 0.5ms: 0° (CCRx = 5)
  • 1.0ms: 45° (CCRx = 10)
  • 1.5ms: 90° (CCRx = 15)
  • 2.0ms: 135° (CCRx = 20)
  • 2.5ms: 180° (CCRx = 25)

3.6 장애물 회피 자동차 코드

연결 방식:

  • 서보 모터 -- PB9
  • 초음파 센서 Trig -- PB7
  • 초음파 센서 Echo -- PB8

서보 모터 제어 코드:

servo.c

#include "servo.h"
#include "gpio.h"
#include "tim.h"

void 서보_초기화(void)
{
    HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
    서보_중앙위치();
}

void 서보_중앙위치(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 15); // 90°
}

void 서보_좌측위치(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); // 0°
}

void 서보_우측위치(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 25); // 180°
}

초음파 센서 코드:

ultrasonic.c

#include "ultrasonic.h"
#include "gpio.h"
#include "tim.h"

void TIM2_Delay_us(uint16_t us)
{
    __HAL_TIM_ENABLE(&htim2);
    __HAL_TIM_SetCounter(&htim2, 0);
    while(__HAL_TIM_GetCounter(&htim2) < us);
    __HAL_TIM_DISABLE(&htim2);
}

double 거리_측정(void)
{
    // 1. Trig에 10us 하이 레벨 신호 발생
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
    TIM2_Delay_us(20);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
    
    // 2. Echo가 하이 레벨로 변하면 타이머 시작
    while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_RESET);
    HAL_TIM_Base_Start(&htim2);
    __HAL_TIM_SetCounter(&htim2, 0);
    
    // 3. Echo가 로우 레벨로 변하면 타이머 정지
    while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_SET);
    HAL_TIM_Base_Stop(&htim2);
    
    // 4. 거리 계산
    uint32_t 시간 = __HAL_TIM_GetCounter(&htim2);
    return (시간 * 0.034 / 2); // cm 단위
}

장애물 회피 메인 코드:

#define MIDDLE 0
#define LEFT 1
#define RIGHT 2

char 서보_방향 = MIDDLE;
double 중앙_거리, 좌측_거리, 우측_거리;

void 장애물_회피_제어(void)
{
    // 서보 중앙 위치
    if(서보_방향 != MIDDLE){
        서보_중앙위치();
        서보_방향 = MIDDLE;
        HAL_Delay(300);
    }
    
    중앙_거리 = 거리_측정();
    
    if(중앙_거리 > 35){
        // 전진
        자동차_전진();
    }
    else if(중앙_거리 < 10){
        // 후진
        자동차_후진();
    }
    else
    {
        // 정지 후 좌우 거리 측정
        자동차_정지();
        
        // 좌측 거리 측정
        서보_좌측위치();
        HAL_Delay(300);
        좌측_거리 = 거리_측정();
        
        // 중앙 복귀
        서보_중앙위치();
        HAL_Delay(300);
        
        // 우측 거리 측정
        서보_우측위치();
        서보_방향 = RIGHT;
        HAL_Delay(300);
        우측_거리 = 거리_측정();
        
        // 방향 결정
        if(좌측_거리 < 우측_거리){
            자동차_우회전();
            HAL_Delay(150);
            자동차_정지();
        }
        else{
            자동차_좌회전();
            HAL_Delay(150);
            자동차_정지();
        }
    }
    HAL_Delay(50);
}

4. 속도 측정 자동차

4.1 인코더 모듈

인코더 모듈 특성:

  • 모터 회전 속도 측정에 사용
  • 회전체의 구멍을 통과할 때마다 펄스 출력
  • 구멍이 있으면 하이 레벨, 없으면 로우 레벨 출력

연결 방식:

  • VCC: 3.3V (5V 연결 시 중복 트리거 발생)
  • OUT: PB14

4.2 속도 측정 원리

속도 계산 방법:

  • 바퀴 1회전 거리 = 2 × π × 반지름 = π × 지름 (6.5cm)
  • 인코더 1회전당 20개 펄스
  • 1펄스당 이동 거리 = π × 6.5cm / 20 ≈ 1.02cm
  • 1초간 펄스 수 측정 → 속도(cm/s) = 펄스 수

4.3 속도 측정 코드

unsigned int 펄스_카운트 = 0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_14)
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)
            펄스_카운트++;
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    printf("속도: %d cm/s\n", 펄스_카운트);
    펄스_카운트 = 0;
}

// 메인 함수
void 속도_측정_시작(void)
{
    HAL_TIM_Base_Start_IT(&htim2); // 1초 주기 타이머 인터럽트 시작
}

4.4 OLED 화면에 속도 표시

연결 방식:

  • SCL -- PB6
  • SDA -- PB7

OLED 표시 코드:

#include "oled.h"
#include "i2c.h"
#include "oledfont.h"

char 속도_메시지[24];

void 속도_표시(int 속도값)
{
    sprintf(속도_메시지, "속도:%2d cm/s", 속도값);
    Oled_Show_Str(2, 2, 속도_메시지);
}

// 인터럽트 콜백에서 호출
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    속도_표시(펄스_카운트);
    펄스_카운트 = 0;
}

5. 원격 제어 자동차

5.1 블루투스 제어

블루투스 모듈 특성:

  • 시리얼 투전 모드로 동작
  • AT 명령어로 설정
  • 데이터를 그대로 전달 (투전 기능)

블루투스 제어 코드:

#include "bluetooth.h"
#include "motor.h"

char 수신_버퍼[20];

void 블루투스_명령_처리(void)
{
    if(!strcmp(수신_버퍼, "전진")){
        자동차_전진();
        HAL_Delay(10);
    }
    else if(!strcmp(수신_버퍼, "후진")){
        자동차_후진();
        HAL_Delay(10);
    }
    else if(!strcmp(수신_버퍼, "좌회전")){
        자동차_좌회전();
        HAL_Delay(10);
    }
    else if(!strcmp(수신_버퍼, "우회전")){
        자동차_우회전();
        HAL_Delay(10);
    }
    else{
        자동차_정지();
    }
}

5.2 Wi-Fi 제어

ESP-01s Wi-Fi 모듈 특성:

  • AT 명령어 인터페이스
  • AP/Station 모드 지원
  • TCP/UDP 프로토콜 지원

Wi-Fi 연결 코드:

void WiFi_연결_설정(void)
{
    // Wi-Fi 모드 설정
    AT_명령_전송("AT+CWMODE=1\r\n");
    HAL_Delay(1000);
    
    // AP 연결
    AT_명령_전송("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n");
    HAL_Delay(3000);
    
    // TCP 서버 시작
    AT_명령_전송("AT+CIPMUX=1\r\n");
    HAL_Delay(1000);
    AT_명령_전송("AT+CIPSERVER=1,8080\r\n");
    HAL_Delay(1000);
}

5.3 4G 제어

EC03-DNC 4G 모듈 특성:

  • 시리얼 AT 명령어 인터페이스
  • 투전 모드 지원
  • TCP/UDP 프로토콜 지원

4G 제어 코드: (블루투스 코드와 유사하나, 연결 방식만 변경)

void 모듈_초기화(void)
{
    // 4G 모듈 시작
    AT_명령_전송("AT\r\n");
    HAL_Delay(1000);
    
    // 네트워크 연결 확인
    AT_명령_전송("AT+CREG?\r\n");
    HAL_Delay(1000);
    
    // TCP 서버 연결
    AT_명령_전송("AT+CIPSTART=0,\"TCP\",\"서버_IP\",포트\r\n");
    HAL_Delay(2000);
}

6. 음성 인식 제어

6.1 음성 모듈 설정

SU-03T/LD3320 음성 인식 모듈 특성:

  • 미리 정의된 음성 명령어 인식
  • 시리얼 인터페이스
  • 최대 10개 명령어 저장 가능

연결 방식:

  • 음성 모듈 제어 핀 -- PA15 (추종 모드)
  • 음성 모듈 제어 핀 -- PA13 (장애물 회피 모드)
  • 음성 모듈 제어 핀 -- PA14 (선 추적 모드)

6.2 음성 제어 코드

#define 추종_모드 1
#define 장애물_회피_모드 2
#define 선_추적_모드 3

int 현재_모드 = 0;

void 음식_인식_모드_전환(int 모드)
{
    if(모드 == 추종_모드){
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_14, GPIO_PIN_RESET);
        현재_모드 = 추종_모드;
    }
    else if(모드 == 장애물_회피_모드){
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_14, GPIO_PIN_RESET);
        현재_모드 = 장애물_회피_모드;
    }
    else if(모드 == 선_추적_모드){
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_13, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_14, GPIO_PIN_SET);
        현재_모드 = 선_추적_모드;
    }
}

void 메인_제어_루프(void)
{
    // 음성 명령어에 따른 모드 전환
    if(음식_인식_완료()){
        if(strcmp(인식된_명령어, "추종") == 0){
            음식_인식_모드_전환(추종_모드);
        }
        else if(strcmp(인식된_명령어, "회피") == 0){
            음식_인식_모드_전환(장애물_회피_모드);
        }
        else if(strcmp(인식된_명령어, "추적") == 0){
            음식_인식_모드_전환(선_추적_모드);
        }
    }
    
    // 현재 모드에 따라 제어
    switch(현재_모드){
        case 추종_모드:
            추종_제어();
            break;
        case 장애물_회피_모드:
            장애물_회피_제어();
            break;
        case 선_추적_모드:
            선_추적_제어();
            break;
    }
}

태그: STM32 스마트 자동차 PWM 제어 선 추적 초음파 센서

6월 29일 22:13에 게시됨