stm32毕设 stm32智能扫地机器人设计与实现

  • Post author:
  • Post category:其他


0 简介

Hi,大家好,这里是丹成学长,今天向大家介绍一个 单片机项目,大家可用于 课程设计 或 毕业设计

基于stm32的智能扫地机器人设计与实现

🧿 项目分享:
https://gitee.com/sinonfin/sharing

1 课题背景

随着人口老龄化的到来和人民对提升生活品质的需要, 人们对在现实生活场景中取代人力的服务机器人有着迫切的需要。 同时, 机电、 自动控制、 计算机、 传感器等技术的发展也为制造服务机器人提供了技术支持。 扫地机器人是服务机器人中技术最成熟和最为广泛使用的机器人。 它可以自动的在室内行走, 通过刷扫和吸尘将地面上的碎屑吸收进垃圾收集装置中, 完成清洁地面的任务,有效的减少了人们清洁地面这种简单重复的家务劳动, 节约了劳动力, 提高了生活品质。 对于许多忙于工作和生的人来说,扫地机器人已经成为家庭必备的产品。

2 硬件系统总体框架

在这里插入图片描述

学长设计的是一个传统的扫地机器人,它使用红外传感器和超声波传感器来检测障碍物,以及一个MPU6050运动传感器来计算旋转角度。使用两个直流减速电机驱动车轮实现行走,两边的编码器可以通过计算编码器产生的脉冲数量来计算车轮的速度和距离。为了方便实验过程及时获取传感器数据和向扫地机器人发送开机、关机命令,连接了一个ATK-ESP8266WIFI模块,使用笔记本电脑安装网络调试助手软件实现和WIFI模块的通讯。该平台的动力单元为一个电压为12V、容量为9000mAh电池包,为电机驱动提供电力,并经过稳压后为控制单元提供动力。主控制单元用于控制整个机器人,STM32F103ZET6被用作控制芯片,主控单元执行机械驱动、运动控制和传感器数据采集等任务。

2.1 电机驱动

由于单片机输出的电流不足以驱动电机,所以必须通过电机驱动模块驱动电机。对于直流电机通常使用H桥驱动芯片进行驱动,本课题采用了两块L298N驱动模块。L298N是专用驱动集成电路,属于H桥集成电路。使用了ST公司的原装全新芯片L298N,采用稳定性高的SMT工艺,使用了高质量的铝电解电容,使电路工作稳定。作为直流电机驱动时,可以同时驱动两路3-16V的直流电机。同时驱动板还提供了5V电源输出接口,可以用于5V单片机的电路系统供电。支持3.3VMCUARM控制,可以通过单片机方便的控制直流电机的功率和转动方向,也可以用于控制2相步进电机,5线4相步进电机。

在这里插入图片描述

虽然L298N驱动板可以个同时驱动两个直流电机,但长时间工作在大功率条件下,驱动板可能出现过热、烧板等问题。为了提高硬件系统稳定性,本课题中使用两块L298N驱动板,一块驱动板控制一个电机。L298N驱动板的IN3IN4EN2OUT3OUT4直接浮空,VCC输入12V电机驱动电源正极,负极接GND,VCC5V接5V电源正极,负极接地,EN1IN1连接STM32控制电机正反转和启停,IN2输入PWM波。OUT1OUT2连接电机。

在这里插入图片描述

2.2 红外线传感器

这次的项目中, 学长设计通过红外传感器检测扫地机器人运动方向是否有障碍物, 从而实现扫地机器人的自动避障的功能。 选用的E18-D80NK 型红外传感器电路如图所示。

在这里插入图片描述

红外传感器使用 5V 电源供电, STM32 通过读取黄色信号线的高低电平确定是否存在障碍物, 感应距离可以通过红外传感器上的旋钮在 3-77cm 的范围内进行调整。 在电路设计中在输出端黄线加上拉电阻 10K 到 5V 电源, 再接入单片机检测, 会比较稳定。

在这里插入图片描述

2.3 超声波传感器

在这里插入图片描述

学长选用US-100 超声波测距模块, US-100 超声波测距模块能够通过自带的温度传感器测量温度并对测量结果进行校正。 可以通过GPIO或串口与单片机通信, 性能稳定。

US-100 超声波测距模块具有1个模式选择跳线和5Pin接口, 本课题使用串口模式, 必须插上跳线帽, 5个接口1号Pin接VCC 5V电源, 2号Pin接外部电路UART 的 TX 端, 3号Pin接外部电路UART的 RX 端, 4号Pin接外部电路的地。5 号Pin接外部电路的地。

在这里插入图片描述

2.4 MPU6050

MPU6050 是全球首例 9 轴运动处理传感器, 它集成了 3 轴 MEMS 陀螺仪, 3 轴 MEMS 加速度计, 以及一个可扩展的数字运动处理器 DMP。

MPU6050 电路连接图

在这里插入图片描述

2.5 ATK-ESP8266 WI FI 模块

ATK-ESP8266是ALIENTEK推出的一款高性能的UART-WiFi(串口-无线)模块, ATK-ESP8266板载ai-thinker公司的ESP8266模块。

ATK_ESP8266 模块电路连接图
在这里插入图片描述

2.6 电源管理模块

电源管理模块用于给控制系统个电路模块供电, 由于电池电压为 12V, 主控芯片供电电压为 3. 3V, 不能直接为主控芯片供电, 同时部分外部功能模块需要 5V 电压供电, 因此本课题设计有降压电路、 电压选择电路和 3. 3V/5V 输出电路, 可以满足控制系统的供电需要。 DC_IN 用于外部直流电源输入, 范围是DC6~24V, 输入电压经过 MP2359 芯片转换为 5V 电源输出, 其中 D4 是防反接二极管, 避免外部直流电源极性搞错的时候, 烧坏控制系统电路。

在这里插入图片描述

3 软件系统设计

学长设计的整体软件架构如下:

在这里插入图片描述

3.1 MPU6050 数据读取

MPU6050 传感器内部包含陀螺仪和加速度计, 而且自带了数字运动处理器,即 DMP通过 InvenSense 提供的 MPU6050 嵌入式运动驱动库, 可以将陀螺仪和加速度计的原始数据直接转换成四元数输出, 通过四元数转换可以直接计算出欧拉角从而得到: 航向角(yaw) 、 横滚角(roll) 和俯仰角(pitch)。

学长这里选定了以 I2C 通信对 MPU6050 的 DMP 输出的四元数进行读取。

初始化 I2C 接口, 编程代码下

1 void HmcIICInit(void)
2.{
3. /*GPIO 初始化*/
4. GPIO_InitTypeDef GPIO_InitStructure;
5. /* 配置硬件 IIC 需要的变量 */
6. I2C_InitTypeDef I2C_InitStructure;
7.
8. /* 使能与 I2C1 有关的时钟 */
9. RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB,ENABLE );
10. RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
11.
12. /* PB6-I2C1_SCL、 PB7-I2C1_SDA*/
13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
14. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
15. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
16. GPIO_Init(GPIOB, &GPIO_InitStructure);
17.
18. /*IIC 外设初始化*/
19.
20. /* I2C 配置 */
21. I2C_InitStructure.I2C_Mode = I2C_Mode_I2C ; //配置为普通 IIC 模式
22. //I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
23.//I2C_InitStructure.I2C_OwnAddress1 = SlaveAddress;
24. I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能自动应答
25. I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
26. I2C_InitStructure.I2C_ClockSpeed = 50000; //5K 的速度
27.
28.
29. /* I2C1 初始化 */
30. I2C_Init(I2C1, &I2C_InitStructure);
31.
32. /* 使能 I2C1 */
33. I2C_Cmd (I2C1,ENABLE);
34. /*允许应答模式*/
35. I2C_AcknowledgeConfig(I2C1, ENABLE);

配置系统时钟源并使能角速度传感器和加速度传感器, 代码实现如下:

1. u8 MPU_Init(void)
2. {
3. u8 res;
4. IIC_Init();//初始化 IIC 总线
5. MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); //复位 MPU6050
6. delay_ms(100);
7. MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00); //唤醒 MPU6050
8. MPU_Set_Gyro_Fsr(3); //陀螺仪传感器, ±2000dps
9. MPU_Set_Accel_Fsr(0); //加速度传感器,±2g
10. MPU_Set_Rate(50); //设置采样率 50Hz
11. MPU_Write_Byte(MPU_INT_EN_REG, 0X00); //关闭所有中断
12. MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); //I2C 主模式关闭
13. MPU_Write_Byte(MPU_FIFO_EN_REG,0X00); //关闭 FIFO
14. MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80); //INT 引脚低电平有效
15. res=MPU_Read_Byte(MPU_DEVICE_ID_REG);
16. if(res==MPU_ADDR)//器件 ID 正确
17. {
18. MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X01); //设置 CLKSEL, PLL X 轴为参考
19. MPU_Write_Byte(MPU_PWR_MGMT2_REG, 0X00); //加速度与陀螺仪都工作
20. MPU_Set_Rate(50); //设置采样率为 50Hz
21. }else return 1;
22. return 0;
23. }
24. //设置 MPU6050 陀螺仪传感器满量程范围
25. //fsr: 0,±250dps;1,±500dps;2, ±1000dps;3,±2000dps
26.//返回值:0, 设置成功

在这里插入图片描述

3.2 超声波传感器数据读取

编写超声波发送函数, 串口发送0X55到超声波模块。相关代码如下;

1. void uart_init(u32 bound) {
2. //GPIO端口设置
3. GPIO_InitTypeDef GPIO_InitStructure;
4. USART_InitTypeDef USART_InitStructure;
5. NVIC_InitTypeDef NVIC_InitStructure;
6.
7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1| RCC_APB2Periph_GPIOA,  ENABLE) ;
//使能USART1, GPIOA时钟
8. //USART1_TX PA. 9
9. GPIO_InitStructure. GPIO_Pin = GPIO_Pin_9; //PA. 9
10. GPIO_InitStructure. GPIO_Speed = GPIO_Speed_50MHz;
11. GPIO_InitStructure. GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
12. GPIO_Init(GPIOA, &GPIO_InitStructure) ;
13.
14.//USART1_RX PA. 10
15. GPIO_InitStructure. GPIO_Pin = GPIO_Pin_10;
16. GPIO_InitStructure. GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
17. GPIO_Init(GPIOA, &GPIO_InitStructure) ;
18.
19. //Usart1 NVIC 配置
20.
21. NVIC_InitStructure. NVIC_IRQChannel = USART1_IRQn;
22. NVIC_InitStructure. NVIC_IRQChannelPreemptionPriority=3 ; //抢占优先级3
23. NVIC_InitStructure. NVIC_IRQChannelSubPriority = 3; //子优先级3
24. NVIC_InitStructure. NVIC_IRQChannelCmd = ENABLE; //IRQ 通
道使能
25. NVIC_Init(&NVIC_InitStructure) ; //根据指定的参数初始化VIC寄存器
26.
27. //USART 初始化设置
28.
29. USART_InitStructure. USART_BaudRate = bound; //一般设置为9600;
30. USART_InitStructure. USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
31. USART_InitStructure. USART_StopBits = USART_StopBits_1; //一个停止位
32. USART_InitStructure. USART_Parity = USART_Parity_No; //无奇偶校验位
33. USART_InitStructure. USART_HardwareFlowControl  =
USART_HardwareFlowControl_None; //无硬件数据流控制
34. USART_InitStructure. USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模35.
36.USART_Init(USART1, &USART_InitStructure) ; //初始化串口
37. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE) ; //开启中断
38. USART_Cmd(USART1, ENABLE) ; //使能串口
39.
40. }

3.3 电机控制

3.3.1 PID控制

扫地机器人在二维平面内运动, 主要对航向角进行控制, 在运动过程中受到地面阻力、 碰撞等各种因数的影响, 无法建立精确的数学模型来编写算法对扫地机器人进行精确的控制, 所以本课题中使用 PID 控制算法对扫地机器人进行控制。

PID(比例(proportion) 、 积分(integral) 、 导数(derivative) ) 控制器作为最早实用化的控制器已有近百年历史, 现在仍然是应用最广泛的工业控制器。 PID 控制器简单易懂, 使用中不需精确的系统模型等先决条件, 因而成为应用最为广泛的控制器。

PID流程

在这里插入图片描述

PID实现

struct _pid{
    float SetSpeed;            //定义设定值
    float ActualSpeed;        //定义实际值
    float err;                //定义偏差值
    float err_last;            //定义上一个偏差值
    float Kp,Ki,Kd;            //定义比例、积分、微分系数
    float voltage;            //定义电压值(控制执行器的变量)
    float integral;            //定义积分值
    float umax;
    float umin;
}pid;

void PID_init(){
    printf("PID_init begin \n");
    pid.SetSpeed=0.0;
    pid.ActualSpeed=0.0;
    pid.err=0.0;
    pid.err_last=0.0;
    pid.voltage=0.0;
    pid.integral=0.0;
    pid.Kp=0.2;
   pid.Ki=0.1;       //注意,和上几次相比,这里加大了积分环节的值
    pid.Kd=0.2;
    pid.umax=400;
    pid.umin=-200;
    printf("PID_init end \n");
}
float PID_realize(float speed){
    int index;
    pid.SetSpeed=speed;
    pid.err=pid.SetSpeed-pid.ActualSpeed;

   if(pid.ActualSpeed>pid.umax)  //灰色底色表示抗积分饱和的实现
    {

       if(abs(pid.err)>200)      //蓝色标注为积分分离过程
        {
            index=0;
        }else{
            index=1;
            if(pid.err<0)
            {
              pid.integral+=pid.err;
            }
        }
    }else if(pid.ActualSpeed<pid.umin){
        if(abs(pid.err)>200)      //积分分离过程
        {
            index=0;
        }else{
            index=1;
            if(pid.err>0)
            {
            pid.integral+=pid.err;
            }
        }
    }else{
        if(abs(pid.err)>200)                    //积分分离过程
        {
            index=0;
        }else{
            index=1;
            pid.integral+=pid.err;
        }
    }

    pid.voltage=pid.Kp*pid.err+index*pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);

    pid.err_last=pid.err;
    pid.ActualSpeed=pid.voltage*1.0;
    return pid.ActualSpeed;
}

3.4 扫地机器人路径规划

3.4.1 弓字型行走

在没有障碍物或房间结构变化不大的情况下, 扫地机器人可应用巡航路径规划算法。

步骤 1

扫地机器人从 MPU6050 模块获得偏航角, 并将此偏航角设定为参考角。然后扫地机器人在基于参考角调整偏航角的同时开始向前移动。 距离 D 由编码器记录, D 的值将被分配给一个名为 pre_Walkingcount 的变量。 当超声波传感器检测到障碍物的存在时, 机器人会降低速度以避免碰撞发生。 如果红外传感器返回低电平, 则该算法切换到步骤 2。

在这里插入图片描述

步骤 2

机器人向左旋转 90 度。 然后 机器人用编码器记录向前移动的距离 d。如果 d= Ic ,代表扫地机器人的清洁端口的宽度, 机器人再向左旋转 90 度。 之后, 算法切换到步骤 3。 步骤 2 的编程实现中, 编写了实现扫地机器人左转 90°函数 Left_turn()和直行 的函数 Straight_go()。

在这里插入图片描述

步骤 3

步骤 3 类似于步骤 1, 但方向相反。 当机器人遇到障碍物时, 将距离 D与变量 pre_Walkingcount 进行比较。 比较的结果将决定重新覆盖算法是否工作。如 果 D= pre_Walkingcount, 算 法切 换 到 步 骤 4, D 值将 被 分 配 给变 量
pre_Walkingcount。 通过与前面的距离进行比较, 机器人可以决定要运行哪种算法。

步骤 4

机器人向右转 90 度。 然后机器人用编码器记录向前移动的距离 d。 如果 d= Ic , 机器人向右转动 90 度。 之后, 算法切换到步骤 1, 并开始另一个新的循环

在这里插入图片描述

4 测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

机器人路径主要基于弓字形路径, 利用重复覆盖算法对障碍物后方的区域进行清洗。 与具有随机避障算法的扫地机器人相比, 新算法的机器人能够覆盖94. 61%的地面, 提高了扫地机器人的效率。

展示视频

毕业设计:基于stm32的扫地机器人

5 最后

🧿 项目分享:
https://gitee.com/sinonfin/sharing


版权声明:本文为m0_71992198原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。