打印
[其他ST产品]

基于STM32红外避障小车的设计(有代码)

[复制链接]
1337|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
4c1l|  楼主 | 2022-8-29 23:00 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
什么是避障小车 用红外光电传感器,探测到物体即输出脉冲,输入到单片机中处 理一下,再对电机驱动模块进行控制,实现壁障的功能,这样的避障小车又称为简单的避障机器人。
各种避障方法:
1、红外线避障 2、超声波避障
红外避障原理 基本硬件 红外发射管和接收管:分离式和一体式

变送电路:模拟量;数字量:将模拟量经过比较器输出开关量

使用特权

评论回复
评论
4c1l 2022-8-29 23:01 回复TA
———————————————— 版权声明:本文为CSDN博主「ShawnWang1994」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/ShawnWang1994/article/details/106760347 
沙发
4c1l|  楼主 | 2022-8-29 23:02 | 只看该作者
选择模块简介:


不怕光HJ-IR2传感器 • 1、HJ-IR2相当于一个红外电子开关,检测到障碍输出低电平,平 时高电平。。 • 2、前方有障碍物时,红外管发出的红外信号经红外接收管接收 回来后,经集成的芯片放大,比较后,输出一低电平,点亮模块 上的LED发光管,同时可以输出一个低平信号,信号可以作为单 片机的信号输入检测控制外部各种驱动模块之用。 • 3、模块三线制,VCC为电原+5V,OUT为信号输出端,GND接电源 负极。 • 4、探测距离大概为1~30CM(探测距离的长短和供电电压、电流还 有周围环境有关,这里只作为参考) • 5、工作电压5V 工作电流 18-30ma左右。

使用特权

评论回复
板凳
4c1l|  楼主 | 2022-8-29 23:02 | 只看该作者
2路壁障模块的输出 :

在一般电子设计比赛等对壁障模块功能要求不高的场合,完全可 以采用比较器输出开关量,这样编程简单,易于实现; 1路壁障模块模块则输出1路开关量,可以接单片机的普通输入IO 口;

使用特权

评论回复
地板
4c1l|  楼主 | 2022-8-29 23:03 | 只看该作者
路壁障模块原理 :

根据小车的运行情况有以下几种运动方式:
若没有被任何一个探头检测到,小车直行; 左边探头检测到物体时小车向右转 ; 右这探头检测到物体时小车向左转 •;上述算法描述是最简单的红外壁障算法,如果有一定的速度需求, 则在以上算法上进行改进。

使用特权

评论回复
5
4c1l|  楼主 | 2022-8-29 23:04 | 只看该作者
壁障模块的安装调试步骤 :

将2路探头呈一行布置在智能车前方,探头朝前面, 可以采用铜柱+螺丝方式固定; 将中控板固定在车身上; 正确连接中控板和探头的杜邦线; 正确连接控制主板; 将小车放到地面上,前方10CM处放物体,调节电位器, 保证某探头在经过物体时,LED的状态不同。 若无论怎么调节电位器,LED状态都不变化,则应该 是杜邦线接触不好,要更换。

使用特权

评论回复
6
4c1l|  楼主 | 2022-8-29 23:05 | 只看该作者
简单源码分析—IO口定义


使用特权

评论回复
7
4c1l|  楼主 | 2022-8-29 23:31 | 只看该作者
简单源码分析—算法分析

使用特权

评论回复
8
4c1l|  楼主 | 2022-8-29 23:32 | 只看该作者
主程序:

#include "stm32f10x.h"
#include "interface.h"
#include "LCD1602.h"
#include "IRCtrol.h"
#include "motor.h"
#include "UltrasonicCtrol.h"
#include "redvoid.h"

//全局变量定义
unsigned int speed_count=0;//占空比计数器 50次一周期
char front_left_speed_duty=SPEED_DUTY;
char front_right_speed_duty=SPEED_DUTY;
char behind_left_speed_duty=SPEED_DUTY;
char behind_right_speed_duty=SPEED_DUTY;

unsigned char tick_5ms = 0;//5ms计数器,作为主函数的基本周期
unsigned char tick_1ms = 0;//1ms计数器,作为电机的基本计数器
unsigned char tick_200ms = 0;//刷新显示

char ctrl_comm = COMM_STOP;//控制指令
char ctrl_comm_last = COMM_STOP;//上一次的指令
unsigned char continue_time=0;

int main(void)
{
        delay_init();
        GPIOCLKInit();
        UserLEDInit();
//        LCD1602Init();
//        IRCtrolInit();
        TIM2_Init();
        MotorInit();
        //UltraSoundInit();
        RedRayInit();
        ServoInit();

while(1)
{         
                         if(tick_5ms >= 5)
                {
                        tick_5ms = 0;
                        tick_200ms++;
                        if(tick_200ms >= 40)
                        {
                                tick_200ms = 0;
                                LEDToggle(LED_PIN);
                        }

                        VoidRun();

                }
               
}
}


使用特权

评论回复
9
4c1l|  楼主 | 2022-8-29 23:32 | 只看该作者
串口部分:
#include "uart.h"
#include "interface.h"

//UART function
//UART1 TxD GPIOA9   RxD GPIOA10
void USART1Conf(u32 baudRate)
{
        USART_InitTypeDef USART_InitSturct;//定义串口1的初始化结构体

        GPIO_InitTypeDef GPIO_InitStruct;//定义串口对应管脚的结构体

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA , ENABLE);//打开串口管脚时钟
        //USART1_Tx_Pin Configure
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//输出引脚
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;//设置最高速度50MHz
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用输出
        GPIO_Init(GPIOA , &GPIO_InitStruct);//将初始化好的结构体装入寄存器

//USART1_Rx_Pin Configure
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//GPIO模式悬浮输入
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;//输入引脚
  GPIO_Init(GPIOA, &GPIO_InitStruct);//将初始化好的结构体装入寄存器

//USART1 Configure       
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);//时钟使能
        USART_InitSturct.USART_BaudRate = baudRate;//波特率19200
        USART_InitSturct.USART_WordLength = USART_WordLength_8b;//数据宽度8位
        USART_InitSturct.USART_StopBits = USART_StopBits_1;//一个停止位
        USART_InitSturct.USART_Parity = USART_Parity_No;//无奇偶校验
        USART_InitSturct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitSturct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//使能发送与接收
        USART_Init(USART1 , &USART_InitSturct);//将初始化好的结构体装入寄存器       
        //USART1_INT Configure
        USART_ITConfig(USART1 , USART_IT_RXNE , ENABLE);//使能接收中断
//        USART_ITConfig(USART1 , USART_IT_TXE , ENABLE);
        USART_Cmd(USART1 , ENABLE);//打开串口
        USART_ClearFlag(USART1 , USART_FLAG_TC);//解决第一个数据发送失败的问题
}

void PutChar(u8 Data)
{
        USART_SendData(USART1 , Data);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待发送完毕
}
void PutStr(char *str)//发送一个字符串
{
        while(*str != '\0')
        {
                USART_SendData(USART1 , *str++);
                while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待发送完毕
        }
}

void PutNChar(u8 *buf , u16 size)
{
  u8 i;
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //防止第一字节丢失
        for(i=0;i<size;i++)
        {
                 USART_SendData(USART1 , buf[i]);
                 while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待发送完毕
        }
}




使用特权

评论回复
10
4c1l|  楼主 | 2022-8-29 23:33 | 只看该作者
电机模块:
#include "motor.h"
#include "interface.h"
#include "stm32f10x.h"

//GPIO配置函数
void MotorGPIO_Configuration(void)
{               
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Pin = FRONT_LEFT_F_PIN;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        
        GPIO_Init(FRONT_LEFT_F_GPIO, &GPIO_InitStructure);   
       
        GPIO_InitStructure.GPIO_Pin = FRONT_LEFT_B_PIN;       
        GPIO_Init(FRONT_LEFT_B_GPIO, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = FRONT_RIGHT_F_PIN;       
        GPIO_Init(FRONT_RIGHT_F_GPIO, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = FRONT_RIGHT_B_PIN;       
        GPIO_Init(FRONT_RIGHT_B_GPIO, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = BEHIND_LEFT_F_PIN;       
        GPIO_Init(BEHIND_LEFT_F_GPIO, &GPIO_InitStructure);  
       
        GPIO_InitStructure.GPIO_Pin = BEHIND_LEFT_B_PIN;       
        GPIO_Init(BEHIND_LEFT_B_GPIO, &GPIO_InitStructure);  
       
        GPIO_InitStructure.GPIO_Pin = BEHIND_RIGHT_F_PIN;       
        GPIO_Init(BEHIND_RIGHT_F_GPIO, &GPIO_InitStructure);  
       
        GPIO_InitStructure.GPIO_Pin = BEHIND_RIGHT_B_PIN;       
        GPIO_Init(BEHIND_RIGHT_B_GPIO, &GPIO_InitStructure);  
       
}

//根据占空比驱动电机转动
void CarMove(void)
{   
       
         BEHIND_RIGHT_EN;
       
/* //左前轮
        if(front_left_speed_duty > 0)//向前
        {
                if(speed_count < front_left_speed_duty)
                {
                        FRONT_LEFT_GO;
                }else
                {
                        FRONT_LEFT_STOP;
                }
        }
        else if(front_left_speed_duty < 0)//向后
        {
                if(speed_count < (-1)*front_left_speed_duty)
                {
                        FRONT_LEFT_BACK;
                }else
                {
                        FRONT_LEFT_STOP;
                }
        }
        else                //停止
        {
                FRONT_LEFT_STOP;
        }*/
       
                //右前轮
        if(front_right_speed_duty > 0)//向前
        {
                if(speed_count < front_right_speed_duty)
                {
                        FRONT_RIGHT_GO;
                }else                //停止
                {
                        FRONT_RIGHT_STOP;
                }
        }
        else if(front_right_speed_duty < 0)//向后
        {
                if(speed_count < (-1)*front_right_speed_duty)
                {
                        FRONT_RIGHT_BACK;
                }else                //停止
                {
                        FRONT_RIGHT_STOP;
                }
        }
        else                //停止
        {
                FRONT_RIGHT_STOP;
        }
       
        //左后轮
        if(behind_left_speed_duty > 0)//向前
        {
                if(speed_count < behind_left_speed_duty)
                {
                        BEHIND_LEFT_GO;
                }        else                //停止
                {
                        BEHIND_LEFT_STOP;
                }
        }
        else if(behind_left_speed_duty < 0)//向后
        {
                if(speed_count < (-1)*behind_left_speed_duty)
                {
                        BEHIND_LEFT_BACK;
                }        else                //停止
                {
                        BEHIND_LEFT_STOP;
                }
        }
        else                //停止
        {
                BEHIND_LEFT_STOP;
        }
       
/*                //右后轮
        if(behind_right_speed_duty > 0)//向前
        {
                if(speed_count < behind_right_speed_duty)
                {
                        BEHIND_RIGHT_GO;
                }        else                //停止
                {
                        BEHIND_RIGHT_STOP;
                }
        }
        else if(behind_right_speed_duty < 0)//向后
        {
                if(speed_count < (-1)*behind_right_speed_duty)
                {
                        BEHIND_RIGHT_BACK;
                }        else                //停止
                {
                        BEHIND_RIGHT_STOP;
                }
        }
        else                //停止
        {
                BEHIND_RIGHT_STOP;
        }*/
}

//向前
void CarGo(void)
{
        front_left_speed_duty=SPEED_DUTY;
        front_right_speed_duty=SPEED_DUTY;
        behind_left_speed_duty=SPEED_DUTY;
        behind_right_speed_duty=SPEED_DUTY;
}

//后退
void CarBack(void)
{
        front_left_speed_duty=-SPEED_DUTY;
        front_right_speed_duty=-SPEED_DUTY;
        behind_left_speed_duty=-SPEED_DUTY;
        behind_right_speed_duty=-SPEED_DUTY;
}

//向左
void CarLeft(void)
{
        front_left_speed_duty=-20;
        front_right_speed_duty=SPEED_DUTY;
        behind_left_speed_duty=-20;
        behind_right_speed_duty=SPEED_DUTY+10;//增加后轮驱动力
}

//向右
void CarRight(void)
{
        front_left_speed_duty=SPEED_DUTY;
        front_right_speed_duty=-20;
        behind_left_speed_duty=SPEED_DUTY+10;//增加后轮驱动力
        behind_right_speed_duty=-20;
}

//停止
void CarStop(void)
{
        front_left_speed_duty=0;
        front_right_speed_duty=0;
        behind_left_speed_duty=0;
        behind_right_speed_duty=0;
}

void MotorInit(void)
{
        MotorGPIO_Configuration();
        CarStop();
}


使用特权

评论回复
11
4c1l|  楼主 | 2022-8-29 23:34 | 只看该作者
红外遥控配置:
#include "IRCtrol.h"
#include "interface.h"

unsigned char ir_rec_flag=0;//接收数据标志位 1 有新数据 0 没有
unsigned char IRCOM[4];

//use time3 realize delay systick已经在main函数中使用了,在中断中不能重复使用
void Time3Init(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    TIM_TimeBaseStructure.TIM_Period = 1;
    TIM_TimeBaseStructure.TIM_Prescaler = (72 - 1);//72M / 72 = 1us
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
}

//1us 延时
void DelayUs(vu32 nCount)
{
  u16 TIMCounter = nCount;
  TIM_Cmd(TIM3, ENABLE);
  TIM_SetCounter(TIM3, TIMCounter);
  while (TIMCounter>1)
  {
    TIMCounter = TIM_GetCounter(TIM3);
  }
  TIM_Cmd(TIM3, DISABLE);
}

//外部中断配置 红外遥控配置
void IRCtrolInit(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        EXTI_InitTypeDef         EXTI_InitStructure;//定义一个外部中断相关的结构体
        NVIC_InitTypeDef NVIC_InitStructure; //定义一个中断的结构体
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);
        GPIO_InitStructure.GPIO_Pin = IRIN_PIN;//配置使能GPIO管脚
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度
        GPIO_Init(IRIN_GPIO , &GPIO_InitStructure);
               
        GPIO_EXTILineConfig(IRIN_PORTSOURCE , IRIN_PINSOURCE);
        EXTI_InitStructure.EXTI_Line = IRIN_EXITLINE;//将对应的GPIO口连接到中断线上
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//中断事件类型,下降沿
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//选择模式,中断型
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能该中断
        EXTI_Init(&EXTI_InitStructure);//将配置好的参数写入寄存器
                       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);         //阶级为0,不可嵌套
        NVIC_InitStructure.NVIC_IRQChannel =         IRIN_IRQCH;//打开PINA_8的外部中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//主优先级0,最高
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //子优先级,最低
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //使能该模块中断
        NVIC_Init(&NVIC_InitStructure);        //中断初始化,将结构体定义的数据执行
       
        Time3Init();
}

/*******************************************************************************
* 函 数 名 :DelayIr
* 函数功能 :0.14MS 延时
* 输    入 :无
* 输    出 :无
*******************************************************************************/
void DelayIr(unsigned char x)  
{
  while(x--)
{
  DelayUs(140);
}
}

void IRIntIsr(void)
{
  unsigned char j,k,N=0;
         DelayIr(15);
         if (IRIN==1)
     {
           return;
          }
                 continue_time = 40;//连发信号,表示指令持续 40*5 = 200ms 无指令停车
                           //确认IR信号出现
  while (!IRIN)            //等IR变为高电平,跳过9ms的前导低电平信号。
    {DelayIr(1);}

for (j=0;j<4;j++)         //收集四组数据
{
  for (k=0;k<8;k++)        //每组数据有8位
  {
   while (IRIN)            //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
     {DelayIr(1);}
    while (!IRIN)          //等 IR 变为高电平
     {DelayIr(1);}
     while (IRIN)           //计算IR高电平时长
      {
    DelayIr(1);
    N++;           
    if (N>=30)
         {
         return;}                  //0.14ms计数过长自动离开。
      }                        //高电平计数完毕               
     IRCOM[j]=IRCOM[j] >> 1;                  //数据最高位补“0”
     if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;}  //数据最高位补“1”
     N=0;
  }//end for k
}//end for j
   
        k = ~IRCOM[3];
   if (IRCOM[2] != k)
   {
     return; }
         
                 //指令转换
                 
                 switch(IRCOM[2])
                 {
                         case 0x46: ctrl_comm = COMM_UP;break;
                         case 0x15: ctrl_comm = COMM_DOWN;break;
                         case 0x44: ctrl_comm = COMM_LEFT;break;
                         case 0x43: ctrl_comm = COMM_RIGHT;break;
                         case 0x40: ctrl_comm = COMM_STOP;break;
                         default :  return;
                 }
                 ir_rec_flag = 1;
       
}

使用特权

评论回复
12
4c1l|  楼主 | 2022-8-29 23:35 | 只看该作者
红外避障模块:
#include "redvoid.h"
#include "interface.h"
#include "motor.h"

extern char ctrl_comm;

//获取红外避障模块状态
char GetVoidStatus(void)
{
        char left=0,right=0;
        char count;
        if(VOID_L_IO == BARRIER_Y)
        {
                count = 2;
                while(--count)//10ms 采集2次均要采集到前面障碍物信息,滤波
                {
                        if(VOID_L_IO == BARRIER_N)
                                break;
                        Delayms(1);
                }
                if(count == 0) left = 1;
        }
       
        if(VOID_R_IO == BARRIER_Y)
        {
                count = 2;
                while(--count)//10ms 采集2次均要采集到前面障碍物信息,滤波
                {
                        if(VOID_R_IO == BARRIER_N)
                                break;
                        Delayms(1);
                }
                if(count == 0) right = 2;
        }
       
        return left + right;
}

//延时的同时检测红外,一旦发生障碍物,就停止并跳出延时
void DelayCheck(int ms)
{
        while(ms--)
        {
                Delayms(1);
                if(VOID_NONE != GetVoidStatus())
                {
                        CarStop();
                        return;
                }
        }
}

//红外避障处理
//处理方式:左边检测到  后退500ms 右转500ms
//                        右边检测到  后退500ms 左转500ms
//                        两边检测到  后退700ms 右转500ms
//          没检测到    直行
void VoidRun(void)
{
        char status;
        status = GetVoidStatus();
       
        switch(status)
        {
                case VOID_LEFT:
                        ctrl_comm = COMM_RIGHT;CarBack(); Delayms(500); CarRight(); DelayCheck(500);
                        break;
                case VOID_RIGHT:
                        ctrl_comm = COMM_LEFT;CarBack(); Delayms(500); CarLeft(); DelayCheck(500);       
                        break;
                case VOID_BOTH:
                        ctrl_comm = COMM_RIGHT;CarBack(); Delayms(700); CarRight(); DelayCheck(500);
                        break;
                case VOID_NONE:
                        ctrl_comm = COMM_UP;CarGo();
                        break;
                default: break;
        }
}


使用特权

评论回复
13
zerorobert| | 2022-9-7 20:44 | 只看该作者
这个能检测小车的姿态吗

使用特权

评论回复
14
lzmm| | 2022-9-7 21:02 | 只看该作者
平衡车的算法和资料

使用特权

评论回复
15
Stahan| | 2022-9-7 22:03 | 只看该作者
这个能检测小车的姿态吗

使用特权

评论回复
16
earlmax| | 2022-9-8 10:01 | 只看该作者
这个小车的工程文件有吗

使用特权

评论回复
17
uiint| | 2022-9-8 13:12 | 只看该作者
如何调整小车的速度呢?

使用特权

评论回复
18
match007| | 2022-9-8 20:42 | 只看该作者
成品什么样?能展示么

使用特权

评论回复
19
myiclife| | 2022-9-11 15:43 | 只看该作者
没有完整的设计吗

使用特权

评论回复
20
primojones| | 2022-9-11 20:37 | 只看该作者
stm32的驱动代码怎么写

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

59

主题

600

帖子

2

粉丝