基于 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
  • 远离电机电源线
相关推荐
AOI小白新手上路12 小时前
江科协51单片机 17-2 红外遥控电机调速实验调试总结
单片机·嵌入式硬件·51单片机
oshan201214 小时前
零基础STM32入门教程--10-PWM 呼吸灯
stm32·单片机·嵌入式硬件
记帖15 小时前
STM32C5A3R开发(7)----ADC电压采集
嵌入式硬件·adc·dac·stm32cubeide·stm32c5·stm32cubemx2·stm32c5a3rgt6
自小吃多17 小时前
器件移动、旋转、镜像、对齐、等间距操作笔记
笔记·嵌入式硬件
jianqiang.xue18 小时前
智能体整体架构设计:四大模块与目录组织
单片机·嵌入式硬件·物联网·架构·esp32
Messy create19 小时前
【BMS-AFE-温度检测】
stm32·单片机·能源
东莞市永盛电气19 小时前
三相208V变380V变压器,出海工业设备供电适配方案
python·单片机·嵌入式硬件
桃蹊、20 小时前
串口/网络透传实战:FreeRTOS 多任务架构与连接池设计
stm32·物联网·wifi·freertos
Learn-Share_HY20 小时前
[IT Network]如何配置反向路徑過濾器(rp_filter),以解決路由不對稱問題?
linux·嵌入式硬件·物联网·网络协议·tcp/ip·http·iot
深圳市宝华视联21 小时前
医院内网部署手术示教系统注意事项
嵌入式硬件·实时互动·音视频·实时音视频·视频编解码·嵌入式实时数据库