基于 STM32F103ZET6 的循轨避障蓝牙小车

一、系统总体方案

1.1 功能定义

  • 循迹:红外对管 / 灰度传感器,沿黑线自动行驶
  • 避障:超声波 + 红外,遇到障碍物自动减速 / 转向
  • 蓝牙遥控:手机 APP(SPP 串口协议)远程控制
  • 自动 / 手动模式切换

1.2 系统框图

复制代码
        ┌─────────────┐
        │ 蓝牙 APP    │
        │ (Android)   │
        └─────▲───────┘
              │ UART
        ┌─────┴───────┐
        │ STM32F103ZET6│
        │ 主控 MCU     │
        └─────▲───────┘
              │ PWM / GPIO
   ┌──────────┼──────────┐
   │          │          │
┌──▼───┐  ┌──▼───┐  ┌──▼───┐
│ 左电机 │  │ 右电机 │  │ 舵机 │
│ TB6612 │  │ TB6612 │  │ SG90 │
└──────┘  └──────┘  └──────┘
   ▲          ▲
   └────┬─────┘
        │
┌───────┴───────┐
│ 循迹 / 避障   │
│ 红外 / 超声   │
└───────────────┘

二、硬件设计(可直接打板)

2.1 核心器件选型

模块 型号 说明
MCU STM32F103ZET6 512KB Flash,足够复杂逻辑
电机驱动 TB6612FNG 双路直流,PWM调速
循迹 TCRT5000 × 5 模拟/数字均可
避障 HC-SR04 + IR 超声测距 + 红外防跌落
蓝牙 HC-05 / JDY-31 串口 SPP
电源 18650 × 2 7.4V → 5V/3.3V
稳压 LM2596 + AMS1117 7.4→5V→3.3V

2.2 引脚分配

电机控制
c 复制代码
/* 左电机 */
#define MOTOR_L_IN1  GPIO_PIN_0  // PA0
#define MOTOR_L_IN2  GPIO_PIN_1  // PA1
#define MOTOR_L_PWM  TIM2_CH1    // PA0

/* 右电机 */
#define MOTOR_R_IN1  GPIO_PIN_2  // PA2
#define MOTOR_R_IN2  GPIO_PIN_3  // PA3
#define MOTOR_R_PWM  TIM2_CH2    // PA1
循迹传感器(5路)
c 复制代码
#define TRACK_S1  GPIO_PIN_4  // PA4
#define TRACK_S2  GPIO_PIN_5  // PA5
#define TRACK_S3  GPIO_PIN_6  // PA6
#define TRACK_S4  GPIO_PIN_7  // PA7
#define TRACK_S5  GPIO_PIN_0  // PB0
避障传感器
c 复制代码
#define US_TRIG   GPIO_PIN_8   // PB8
#define US_ECHO   GPIO_PIN_9   // PB9
#define IR_LEFT   GPIO_PIN_10  // PB10
#define IR_RIGHT  GPIO_PIN_11  // PB11
蓝牙(UART1)
c 复制代码
#define BT_TX  GPIO_PIN_9   // PA9
#define BT_RX  GPIO_PIN_10  // PA10

三、STM32CubeMX 配置

3.1 时钟

  • HSE:8 MHz
  • PLL:×9 → 72 MHz

3.2 TIM 定时器

TIM 用途 频率
TIM2 电机 PWM 10 kHz
TIM3 舵机 PWM 50 Hz
TIM4 超声波计时 1 MHz

3.3 USART

  • USART1:蓝牙(115200, 8N1)
  • DMA:接收(减少中断)

四、核心软件实现(C 语言)

4.1 电机驱动(motor.c

c 复制代码
#include "motor.h"

void Motor_Init(void)
{
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
}

void Motor_SetSpeed(uint8_t left, uint8_t right)
{
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, left);
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, right);
}

void Motor_Forward(uint8_t speed)
{
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN1, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN1, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN2, GPIO_PIN_RESET);
    Motor_SetSpeed(speed, speed);
}

void Motor_TurnLeft(uint8_t speed)
{
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN1, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_L_IN2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN1, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, MOTOR_R_IN2, GPIO_PIN_RESET);
    Motor_SetSpeed(speed, speed);
}

4.2 循迹算法(track.c

c 复制代码
#include "track.h"

uint8_t Track_Read(void)
{
    uint8_t status = 0;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S1) << 0;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S2) << 1;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S3) << 2;
    status |= HAL_GPIO_ReadPin(GPIOA, TRACK_S4) << 3;
    status |= HAL_GPIO_ReadPin(GPIOB, TRACK_S5) << 4;
    return status;   // bit0~4:1=黑线
}

void Track_Control(void)
{
    uint8_t track = Track_Read();

    switch(track)
    {
        case 0b00100:  // 正中
            Motor_Forward(70);
            break;
        case 0b01100:  // 偏右
            Motor_TurnLeft(60);
            break;
        case 0b00011:  // 偏左
            Motor_TurnRight(60);
            break;
        case 0b11111:  // 十字路口
            Motor_Forward(80);
            HAL_Delay(500);
            break;
        default:
            Motor_Stop();
            break;
    }
}

4.3 避障算法(avoid.c

c 复制代码
#include "avoid.h"

float Ultrasonic_GetDistance(void)
{
    uint32_t time_us;

    HAL_GPIO_WritePin(GPIOB, US_TRIG, GPIO_PIN_SET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(GPIOB, US_TRIG, GPIO_PIN_RESET);

    while(HAL_GPIO_ReadPin(GPIOB, US_ECHO) == GPIO_PIN_RESET);
    __HAL_TIM_SET_COUNTER(&htim4, 0);
    while(HAL_GPIO_ReadPin(GPIOB, US_ECHO) == GPIO_PIN_SET);
    time_us = __HAL_TIM_GET_COUNTER(&htim4);

    return (time_us / 58.0f);  // cm
}

void Avoid_Control(void)
{
    float dist = Ultrasonic_GetDistance();
    uint8_t ir_left = HAL_GPIO_ReadPin(GPIOB, IR_LEFT);
    uint8_t ir_right = HAL_GPIO_ReadPin(GPIOB, IR_RIGHT);

    if(dist < 20 || ir_left == 0 || ir_right == 0)
    {
        // 后退 + 转向
        Motor_Backward(60);
        HAL_Delay(300);
        Motor_TurnLeft(70);
        HAL_Delay(400);
    }
}

4.4 蓝牙协议(bluetooth.c

c 复制代码
#include "bluetooth.h"

uint8_t bt_rx_buf[32];
uint8_t bt_rx_len = 0;

void Bluetooth_Parse(uint8_t *data, uint8_t len)
{
    if(len < 2) return;

    if(data[0] == 0xA5 && data[len-1] == 0x5A)
    {
        uint8_t cmd = data[1];
        uint8_t val = data[2];

        switch(cmd)
        {
            case 0x01:  // 前进
                Motor_Forward(val);
                break;
            case 0x02:  // 后退
                Motor_Backward(val);
                break;
            case 0x03:  // 左转
                Motor_TurnLeft(val);
                break;
            case 0x04:  // 右转
                Motor_TurnRight(val);
                break;
            case 0x05:  // 自动模式
                system_mode = MODE_AUTO;
                break;
            case 0x06:  // 手动模式
                system_mode = MODE_MANUAL;
                break;
        }
    }
}

void USART1_IRQHandler(void)
{
    uint8_t ch;
    if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
    {
        ch = USART1->DR;
        if(bt_rx_len < sizeof(bt_rx_buf))
            bt_rx_buf[bt_rx_len++] = ch;
    }
}

五、主循环逻辑(main.c

c 复制代码
int main(void)
{
    HAL_Init();
    SystemClock_Config();

    MX_GPIO_Init();
    MX_TIM2_Init();
    MX_USART1_UART_Init();

    Motor_Init();
    Bluetooth_Init();

    while(1)
    {
        if(system_mode == MODE_AUTO)
        {
            Track_Control();
            Avoid_Control();
        }
        else if(system_mode == MODE_MANUAL)
        {
            // 蓝牙控制已在中断中处理
        }

        HAL_Delay(10);
    }
}

参考代码 基于STM32F103ZET6实现循轨避障蓝牙小车 www.youwenfan.com/contentcsv/115832.html

六、手机蓝牙 APP(通用协议)

功能 发送数据 说明
前进 A5 01 64 5A 速度 100
后退 A5 02 64 5A 速度 100
左转 A5 03 50 5A 速度 80
自动 A5 05 01 5A 进入自动
手动 A5 06 01 5A 进入手动

可用 蓝牙串口助手App Inventor 自制 APP。


七、调试与常见问题

7.1 电机抖动

  • PWM 频率太低 → 设为 10 kHz
  • 电源不足 → 18650 单独供电

7.2 循迹不准

  • 传感器间距 2~3 cm
  • 黑线宽度 1.5~2 cm
  • 增加软件滤波(连续 3 次确认)

7.3 蓝牙断连

  • 波特率 115200
  • 远离电机电源线
相关推荐
kebidaixu1 小时前
FreeRTOS 移植到 STM32F407VETX 记录(五)
stm32·单片机·嵌入式硬件
listhi5202 小时前
基于单片机的步进电机控制系统
单片机·嵌入式硬件
灯琰12 小时前
STM32L051K6U6 IAP要点记录-LL库
stm32·单片机·嵌入式硬件
MAR-Sky2 小时前
stc8h系列单片机使用中断号超过32的插件解决办法
单片机·嵌入式硬件
kebidaixu3 小时前
FreeRTOS 移植到 STM32F407VETX 记录(四)
stm32
结城明日奈是我老婆3 小时前
基于stm32f103c8t6最小系统板俩块版通讯
stm32·单片机·嵌入式硬件
weixin_456808383 小时前
【沁恒蓝牙开发】从机判断主机是否使能CCCD
单片机·嵌入式硬件
深圳英康仕4 小时前
一款面向AGV智能搬运机器人的RK3588工控机的数据资料整理
嵌入式硬件·rk3588·工控机·agv·智能搬运机器人