加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入

基于STM32F103CBT6的AGV(自动导引车)安全距离检测系统

05/15 10:02
1450
服务支持:
技术交流群

完成交易后在“购买成功”页面扫码入群,即可与技术大咖们分享疑惑和经验、收获成长和认同、领取优惠和红包等。

虚拟商品不可退

当前内容为数字版权作品,购买后不支持退换且无法转移使用。

加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论
放大
实物图(3)
相关方案
  • 方案介绍
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

前段时间一直在做超声波的调试,很多模拟量的问题没有解决这段时间降模拟量和通信做了调整,目前完成了Modbus-RTU数据通信以及超声波测距的工作,整体的项目进展目前已经基本完成了,所以这里来和大家做一下汇报,分享一下自己的成果,首先从整体的项目规划以及框图开始说起,可能会比较繁琐一点,但是我还是觉得尽量详细的介绍我们现在的东西,也许会对大家带来一些启发。

1 项目介绍

AGV在现在物流运输和分拣中起到了重要作用,通常情况下是由上级电脑完成系统路径的规划,然后车辆按照分配路线将物流包裹配送到对应的区域内,从而完成大量包裹的分拣的工作,节约了很多人力成本,也避免了由于人为操作失误造成物流停滞、延迟的负面影响。因此AGV在物流分拣的重要性可想而知。在AGV的整体路径规划中,AGV的智能性也将起到至关重要的作用,其中最主要的一点就是安全距离检测,可以判断对于障碍物的判断,以及车辆急停、车辆会根据障碍物距离做出相应的减速、停止、转向等动作。

2 硬件方案

整体的硬件方案是STM32F103CBT6作为主控,通过分时复用完成多多个超声波探头的然后通过RS485或者CAN总线完成数据的传输,通常情况下,RS485和CAN总线在实时性上是有一些距离的。目前的话只做了RS485这块,支持Modbus_RTU的协议。整体还配备了温度采集传感器,可以通过温度来进行声音测距的温度补偿,计算出当前温度的声速,从而对测量距离进行修正。

2.1 硬件原理图

整体的原理图如上图,采用八个国内的超声波测距芯片,然后使用DCDC,完成12V到3.3V的电压转换,通过两个8通道的选择开关完成对每个传感器的数据选择和读取,通过TTL串口实现数的采集。软件内配置状态机,可以正常的完成采集。

整体的电路板如上图。每个传感器都有自己的驱动芯片

3 软件流程图

3.1 状态机切换机制

状态机是在控制最常用的一种机制,可以避免阻塞,完成程序的流畅运行,同样避免了不必要的程序运行占用资源。目前我使用的状态机一共设置了几个状态,每个状态有对应状态的工作任务。
目前一共分为:空闲状态、命令发送状态、回复等待状态、超时状态、异常状态。

3.2 代码展示

3.2.1 状态机代码

void get_Data(struct CSB_Get  *CSB_Struct)
{
        int i=0;
  unsigned int Status=CSB_Struct->Stttus;
        unsigned int Data=0;
        if(CSB_Struct->Channel_Count>CSB_Struct->Channel_MAX)
                {
                                CSB_Struct->Channel_Count=0;/*-- 如果当前通道计数大于 最大通道--那么这次就作废---*/
                                return ;
                }
        else
                {
                                switch(Status)
                                {
                                        
                                        /*--------*/
                                        case Status_Ideal:/*--数据采集之前的数据初始化工作 ---*/
                                        {   
                                                        for(i=0;i<CSB_Struct->Channel_MAX;i++)
                                                        {
                                                                CSB_Struct->CSB_Data_Stable[i]=CSB_Struct->CSB_Curent_Data[i];
                                                                SysTemInfo.Sys_Data.CSB_Data[i]=CSB_Struct->CSB_Curent_Data[i]/1000;
                                                        }
                                                        select(CSB_Struct->Channel_Count);                    /*-- 选择发送通道 --*/                              
                                                        CSB_Struct->TimeOut_Flag=0;                           /*-- 超时标志清零--*/
                                                        CSB_Struct->UART_GetData_Flag=0;                      /*-- 串口接收数据标志清零--*/
                                                        CSB_Struct->Uart_GetData_Count=0;                     /*-- 串口接收数量计数清零 ---*/
                                                        CSB_Struct->CSB_Curent_Data[CSB_Struct->Channel_Count]=0;/*当前通道长度清零--*/
                                                  CSB_Struct->TimeStart_Flag=1;
                                                  CSB_Struct->TimeOutCount=0;
                                                        CSB_Struct->Uart_Data[0]=0;
                                                        CSB_Struct->Uart_Data[1]=0;
                                                        CSB_Struct->Uart_Data[2]=0;
                                                  CSB_Struct->Stttus=Status_SendCND;

                                                
                                        }break;
                                        case Status_SendCND:
                                        {   
                                                        select(CSB_Struct->Channel_Count);                    /*-- 选择发送通道 --*/
                                                  Send_Cmd();                                           /*-- 发送超声波的数据采集命令 --*/
              timer_enable(TIMER1);                                 /*-- 开启定时器  -------*/
                                                        CSB_Struct->Uart_Data[2]=0;
                                                CSB_Struct->Stttus=Status_WaitReply;
                                                
                                        }break;
                                        case Status_WaitReply :
                                        {
                                          if(CSB_Struct->UART_GetData_Flag==1)
                                                {
                                                        Data  =(Data|(CSB_Struct->Uart_Data[0]<<16) |(CSB_Struct->Uart_Data[1]<<8)|(CSB_Struct->Uart_Data[2]));
                                                        CSB_Struct->CSB_Curent_Data[CSB_Struct->Channel_Count]=Data;
                                                        CSB_Struct->Channel_Count++;
                                                        CSB_Struct->Stttus=Status_Ideal;
                                                }
                                                /*-- 如果超时 --*/
                                                if(CSB_Struct->TimeOut_Flag==1)
                                                {
                                                   CSB_Struct->Stttus=Status_TimeOut;
                                                }
                                        
                                        
                                        }break;
                                        case Status_TimeOut:  /*-- 直接跳转到空闲模式,继续下一个通道的测量 ----*/
                                        {
                                                
                                                CSB_Struct->Channel_Count++;
                                                CSB_Struct->TimeStart_Flag=0;
                                                CSB_Struct->TimeOutCount=0;
                                                timer_disable(TIMER1);                                 /*-- 开启定时器  -------*/
                                          CSB_Struct->Stttus=Status_Ideal;
                                        }break;
                                        /*--------*/
                                        default:
                                        {
                                                        CSB_Struct->TimeOut_Flag=0;                           /*-- 超时标志清零--*/
                                                        CSB_Struct->UART_GetData_Flag=0;                      /*-- 串口接收数据标志清零--*/
                                                        CSB_Struct->Uart_GetData_Count=0;                     /*-- 串口接收数量计数清零 ---*/
                                                        CSB_Struct->Uart_Data[0]=0;
                                                        CSB_Struct->Uart_Data[1]=0;
                                                        CSB_Struct->Uart_Data[2]=0;
                                                  CSB_Struct->Channel_Count=0;
                                                  CSB_Struct->TimeStart_Flag=0;
                                                  timer_disable(TIMER1);                                 /*-- 开启定时器  -------*/
                                        }
                                }
    }

}

3.2.2 通信代码展示 这里仅展示部分代码

     case ReadMultRegister :    //--功能码:03   -- 读多个寄存器----
                                                                {
                                                                           MB->ProtocalStr.MB_DataNum=MB->MB_RxData[MB_DataNum]<<8|MB->MB_RxData[MB_DataNum+1];
                                                                           MB->ProtocalStr.CRCData=MB->MB_RxData[MB->MB_RxData_Len-1]<<8|MB->MB_RxData[MB->MB_RxData_Len-2];//--填入CRC数值--
                                                                                        
                                                                                        //--进入这里,说明地址和功能码都满足了,现在需要做的事判断输出数量是否在规定范围内--
                                                                            //--IO数量的计算应当从起始地址+数量来计算--如果起始地址加上数量之后大于IO的点数,
                                                                            //--此时应当报错处理--
                                                                        DataLimit=MB->ProtocalStr.MB_StartAddr + MB->ProtocalStr.MB_DataNum;//--起始地址+读取数量---
                                                                        if((DataLimit>=1)&&(DataLimit<MaxiunReadREG_Data))
                                                                        {
                                                                                MB->MB_TxData[TX_MB_Addr]=MB->MB_RxData[MB_Addr];//--填充站号---
                                                                                MB->MB_TxData[TX_MB_FunCode]=MB->MB_RxData[MB_FunCode];//--填充功能码--
                                                                                //--读取线圈的函数----unsigned short        ReadMultReg_03(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
                                                                                RTN_DataLen=ReadMultReg_03(&MB->MB_TxData[TX_MB_DataBase],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
                                                                                //--填充字节数--
                                                                                MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字节数--
                                                                                //--开始填充数据--
                                                                                //计算CRC---校验和----校验是按照从包头开始 -- 一直到数据结束---
                                                                                CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+3 );//--计算CRC的数值
                                                        
                                                                                RTN_DataLen=RTN_DataLen+5;  //--这里是包含了CRC校验的----站号 +功能码 +数量+CRCData*2=5
                                                                                MB->MB_TxData_Len=RTN_DataLen;//--传入带发送的字节长度--
                                                                                MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff);  //--CRC-H
                                                                                MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff);  //--CRC-L
                                                                                //        完成数据包的组包
                                                                                //--        发送标志----
                                                                                MB->SendFlag=1;
                                                                        }
                                                                        else/*--说明--超出范围了---应当返回异常码------  --*/
                                                                        {
                                                                                  MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站号--
                                                          MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能码--错误码--                
                                                                                  MB->MB_TxData_Len=2;
                                                                                  MB->SendFlag=1;
                                                                        }
                                                                }
                                                                break ;
                                                                //--
                                                case ReadinputRegister :   //--功能码:04   -- 读输入寄存器----
                                                                {
                                                                           MB->ProtocalStr.MB_DataNum=MB->MB_RxData[MB_DataNum]<<8|MB->MB_RxData[MB_DataNum+1];
                                                                           MB->ProtocalStr.CRCData=MB->MB_RxData[MB->MB_RxData_Len-1]<<8|MB->MB_RxData[MB->MB_RxData_Len-2];//--填入CRC数值--
                                                                                DataLimit=MB->ProtocalStr.MB_StartAddr + MB->ProtocalStr.MB_DataNum;//--起始地址+读取数量---
                                                                                        if((DataLimit>=1)&&(DataLimit<MaxiunReadREG_Data))
                                                                                        {
                                                                                         
                                                                                                                MB->MB_TxData[TX_MB_Addr]=MB->MB_RxData[MB_Addr];//--填充站号---
                                                                                                                MB->MB_TxData[TX_MB_FunCode]=MB->MB_RxData[MB_FunCode];//--填充功能码--
                                                                                                                //--读取线圈的函数----unsigned short        ReadMultReg_03(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
                                                                                                                RTN_DataLen=ReadInputReg_04(&MB->MB_TxData[TX_MB_DataBase],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
                                                                                                                //--填充字节数--
                                                                                                                MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字节数--
                                                                                                                //--开始填充数据--
                                                                                                                //计算CRC---校验和----校验是按照从包头开始 -- 一直到数据结束---
                                                                                                                CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+3 );//--计算CRC的数值
                                                                                        
                                                                                                                RTN_DataLen=RTN_DataLen+5;  //--这里是包含了CRC校验的----站号 +功能码 +数量+CRCData*2=5
                                                                                                    MB->MB_TxData_Len=RTN_DataLen;//--传入带发送的字节长度--
                                                                                                                MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff);  //--CRC-H
                                                                                                                MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff);  //--CRC-L
                                                                                                                //        完成数据包的组包
                                                                                                                //--        发送标志----
                                                                                                                MB->SendFlag=1;
                                                                                        }
                                                                                else/*--说明--超出范围了---应当返回异常码------  --*/
                                                                                        {
                                                                                                  MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站号--
                          MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能码--错误码--                
                                                                                                  MB->MB_TxData_Len=2;
                                                                                                  MB->SendFlag=1;
                                                                                        }
                                                                 }
                                                                break ;

                 //----
                                                case WriteSingelRegister : //--功能码:06   -- 写单个寄存器----
                                                                {
                                                                 MB->ProtocalStr.MB_DataNum=1;
                                                                                        //--站号-功能码-起始地址 - 数量  字节计数-- 寄存器数值--
                                                          DataLimit=MB->ProtocalStr.MB_StartAddr+MB->ProtocalStr.MB_DataNum;
                                                                //--进入这里,说明地址和功能码都满足了,现在需要做的事判断输出数量是否在规定范围内--
                                                                if((MB->ProtocalStr.MB_DataNum>=1)&&(MB->ProtocalStr.MB_DataNum<=0x07D0))
                                                                {
                                                                        //--站号-功能码-寄存器地址- 寄存器值
                                                                        for(i=0;i<6;i++)
                                                                          MB->MB_TxData[i]=MB->MB_RxData[i];
                                                                        //--写多个寄存器的函数----unsigned short        WriteMultRegister_16(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
                                                                        RTN_DataLen=WriteSingelReg_06(&MB->MB_RxData[4],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
                                                                  //--填充字节数--
//                                                                        MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字节数--
                                                                        //--开始填充数据--
                                                                        //计算CRC---校验和----校验是按照从包头开始 -- 一直到数据结束---
                                                                        CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+6 );//--计算CRC的数值
                                                
                                                                        RTN_DataLen=RTN_DataLen+8;  //--这里是包含了CRC校验的----站号 +功能码 +数量+CRCData*2=5
                                                                        MB->MB_TxData_Len=RTN_DataLen;//--传入带发送的字节长度--
                                                                        MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff);  //--CRC-H
                                                                        MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff);  //--CRC-L
                                                                        //        完成数据包的组包
                                                                        //--        发送标志----
                                                                        MB->SendFlag=1;
                                                                }
                                                                else/*--说明--超出范围了---应当返回异常码------  --*/
                                                                {
                                                                    MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站号--
                                                                                MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能码--错误码--                
                                                                                MB->MB_TxData_Len=2;
                                                                                MB->SendFlag=1;
                                                                }
                                                                
                                                                }
                                                                break ;                

4 实物测试图

由于电路没有处理好,所以目前可以稳定测试的距离在40cm以内,下面是Modbus-RTU 的测试界面。

 

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
74HC245D,653 1 Nexperia 74HC245; 74HCT245 - Octal bus transceiver; 3-state@en-us SOP 20-Pin

ECAD模型

下载ECAD模型
$0.61 查看
SN74LVC2G74DCURE4 1 Texas Instruments Single Positive-Edge-Triggered D-Type Flip-Flop with Clear and Preset 8-VSSOP -40 to 125

ECAD模型

下载ECAD模型
$0.62 查看
SN74HC595DWR 1 Texas Instruments 8-bit shift registers with 3-state output registers 16-SOIC -40 to 85

ECAD模型

下载ECAD模型
$0.87 查看

相关推荐

电子产业图谱