回答

收藏

《2023 DigiKey 汽车应用创意挑战赛》-AGV安全距离检测系统

#竞赛 #竞赛 2209 人阅读 | 0 人回复 | 2024-01-04




AGV安全距离检测系统



前段时间一直在做超声波的调试,很多模拟量的问题没有解决这段时间降模拟量和通信做了调整,目前完成了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 状态机代码

  1. void get_Data(struct CSB_Get  *CSB_Struct)
  2. {
  3.         int i=0;
  4.   unsigned int Status=CSB_Struct->Stttus;
  5.         unsigned int Data=0;
  6.         if(CSB_Struct->Channel_Count>CSB_Struct->Channel_MAX)
  7.                 {
  8.                                 CSB_Struct->Channel_Count=0;/*-- 如果当前通道计数大于 最大通道--那么这次就作废---*/
  9.                                 return ;
  10.                 }
  11.         else
  12.                 {
  13.                                 switch(Status)
  14.                                 {
  15.                                        
  16.                                         /*--------*/
  17.                                         case Status_Ideal:/*--数据采集之前的数据初始化工作 ---*/
  18.                                         {   
  19.                                                         for(i=0;i<CSB_Struct->Channel_MAX;i++)
  20.                                                         {
  21.                                                                 CSB_Struct->CSB_Data_Stable[i]=CSB_Struct->CSB_Curent_Data[i];
  22.                                                                 SysTemInfo.Sys_Data.CSB_Data[i]=CSB_Struct->CSB_Curent_Data[i]/1000;
  23.                                                         }
  24.                                                         select(CSB_Struct->Channel_Count);                    /*-- 选择发送通道 --*/                              
  25.                                                         CSB_Struct->TimeOut_Flag=0;                           /*-- 超时标志清零--*/
  26.                                                         CSB_Struct->UART_GetData_Flag=0;                      /*-- 串口接收数据标志清零--*/
  27.                                                         CSB_Struct->Uart_GetData_Count=0;                     /*-- 串口接收数量计数清零 ---*/
  28.                                                         CSB_Struct->CSB_Curent_Data[CSB_Struct->Channel_Count]=0;/*当前通道长度清零--*/
  29.                                                   CSB_Struct->TimeStart_Flag=1;
  30.                                                   CSB_Struct->TimeOutCount=0;
  31.                                                         CSB_Struct->Uart_Data[0]=0;
  32.                                                         CSB_Struct->Uart_Data[1]=0;
  33.                                                         CSB_Struct->Uart_Data[2]=0;
  34.                                                   CSB_Struct->Stttus=Status_SendCND;

  35.                                                
  36.                                         }break;
  37.                                         case Status_SendCND:
  38.                                         {   
  39.                                                         select(CSB_Struct->Channel_Count);                    /*-- 选择发送通道 --*/
  40.                                                   Send_Cmd();                                           /*-- 发送超声波的数据采集命令 --*/
  41.               timer_enable(TIMER1);                                 /*-- 开启定时器  -------*/
  42.                                                         CSB_Struct->Uart_Data[2]=0;
  43.                                                 CSB_Struct->Stttus=Status_WaitReply;
  44.                                                
  45.                                         }break;
  46.                                         case Status_WaitReply :
  47.                                         {
  48.                                           if(CSB_Struct->UART_GetData_Flag==1)
  49.                                                 {
  50.                                                         Data  =(Data|(CSB_Struct->Uart_Data[0]<<16) |(CSB_Struct->Uart_Data[1]<<8)|(CSB_Struct->Uart_Data[2]));
  51.                                                         CSB_Struct->CSB_Curent_Data[CSB_Struct->Channel_Count]=Data;
  52.                                                         CSB_Struct->Channel_Count++;
  53.                                                         CSB_Struct->Stttus=Status_Ideal;
  54.                                                 }
  55.                                                 /*-- 如果超时 --*/
  56.                                                 if(CSB_Struct->TimeOut_Flag==1)
  57.                                                 {
  58.                                                    CSB_Struct->Stttus=Status_TimeOut;
  59.                                                 }
  60.                                        
  61.                                        
  62.                                         }break;
  63.                                         case Status_TimeOut:  /*-- 直接跳转到空闲模式,继续下一个通道的测量 ----*/
  64.                                         {
  65.                                                
  66.                                                 CSB_Struct->Channel_Count++;
  67.                                                 CSB_Struct->TimeStart_Flag=0;
  68.                                                 CSB_Struct->TimeOutCount=0;
  69.                                                 timer_disable(TIMER1);                                 /*-- 开启定时器  -------*/
  70.                                           CSB_Struct->Stttus=Status_Ideal;
  71.                                         }break;
  72.                                         /*--------*/
  73.                                         default:
  74.                                         {
  75.                                                         CSB_Struct->TimeOut_Flag=0;                           /*-- 超时标志清零--*/
  76.                                                         CSB_Struct->UART_GetData_Flag=0;                      /*-- 串口接收数据标志清零--*/
  77.                                                         CSB_Struct->Uart_GetData_Count=0;                     /*-- 串口接收数量计数清零 ---*/
  78.                                                         CSB_Struct->Uart_Data[0]=0;
  79.                                                         CSB_Struct->Uart_Data[1]=0;
  80.                                                         CSB_Struct->Uart_Data[2]=0;
  81.                                                   CSB_Struct->Channel_Count=0;
  82.                                                   CSB_Struct->TimeStart_Flag=0;
  83.                                                   timer_disable(TIMER1);                                 /*-- 开启定时器  -------*/
  84.                                         }
  85.                                 }
  86.     }

  87. }
复制代码



3.2.2 通信代码展示 这里仅展示部分代码
  1.      case ReadMultRegister :    //--功能码:03   -- 读多个寄存器----
  2.                                                                 {
  3.                                                                            MB->ProtocalStr.MB_DataNum=MB->MB_RxData[MB_DataNum]<<8|MB->MB_RxData[MB_DataNum+1];
  4.                                                                            MB->ProtocalStr.CRCData=MB->MB_RxData[MB->MB_RxData_Len-1]<<8|MB->MB_RxData[MB->MB_RxData_Len-2];//--填入CRC数值--
  5.                                                                                        
  6.                                                                                         //--进入这里,说明地址和功能码都满足了,现在需要做的事判断输出数量是否在规定范围内--
  7.                                                                             //--IO数量的计算应当从起始地址+数量来计算--如果起始地址加上数量之后大于IO的点数,
  8.                                                                             //--此时应当报错处理--
  9.                                                                         DataLimit=MB->ProtocalStr.MB_StartAddr + MB->ProtocalStr.MB_DataNum;//--起始地址+读取数量---
  10.                                                                         if((DataLimit>=1)&&(DataLimit<MaxiunReadREG_Data))
  11.                                                                         {
  12.                                                                                 MB->MB_TxData[TX_MB_Addr]=MB->MB_RxData[MB_Addr];//--填充站号---
  13.                                                                                 MB->MB_TxData[TX_MB_FunCode]=MB->MB_RxData[MB_FunCode];//--填充功能码--
  14.                                                                                 //--读取线圈的函数----unsigned short        ReadMultReg_03(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
  15.                                                                                 RTN_DataLen=ReadMultReg_03(&MB->MB_TxData[TX_MB_DataBase],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
  16.                                                                                 //--填充字节数--
  17.                                                                                 MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字节数--
  18.                                                                                 //--开始填充数据--
  19.                                                                                 //计算CRC---校验和----校验是按照从包头开始 -- 一直到数据结束---
  20.                                                                                 CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+3 );//--计算CRC的数值
  21.                                                        
  22.                                                                                 RTN_DataLen=RTN_DataLen+5;  //--这里是包含了CRC校验的----站号 +功能码 +数量+CRCData*2=5
  23.                                                                                 MB->MB_TxData_Len=RTN_DataLen;//--传入带发送的字节长度--
  24.                                                                                 MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff);  //--CRC-H
  25.                                                                                 MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff);  //--CRC-L
  26.                                                                                 //        完成数据包的组包
  27.                                                                                 //--        发送标志----
  28.                                                                                 MB->SendFlag=1;
  29.                                                                         }
  30.                                                                         else/*--说明--超出范围了---应当返回异常码------  --*/
  31.                                                                         {
  32.                                                                                   MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站号--
  33.                                                           MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能码--错误码--               
  34.                                                                                   MB->MB_TxData_Len=2;
  35.                                                                                   MB->SendFlag=1;
  36.                                                                         }
  37.                                                                 }
  38.                                                                 break ;
  39.                                                                 //--
  40.                                                 case ReadinputRegister :   //--功能码:04   -- 读输入寄存器----
  41.                                                                 {
  42.                                                                            MB->ProtocalStr.MB_DataNum=MB->MB_RxData[MB_DataNum]<<8|MB->MB_RxData[MB_DataNum+1];
  43.                                                                            MB->ProtocalStr.CRCData=MB->MB_RxData[MB->MB_RxData_Len-1]<<8|MB->MB_RxData[MB->MB_RxData_Len-2];//--填入CRC数值--
  44.                                                                                 DataLimit=MB->ProtocalStr.MB_StartAddr + MB->ProtocalStr.MB_DataNum;//--起始地址+读取数量---
  45.                                                                                         if((DataLimit>=1)&&(DataLimit<MaxiunReadREG_Data))
  46.                                                                                         {
  47.                                                                                          
  48.                                                                                                                 MB->MB_TxData[TX_MB_Addr]=MB->MB_RxData[MB_Addr];//--填充站号---
  49.                                                                                                                 MB->MB_TxData[TX_MB_FunCode]=MB->MB_RxData[MB_FunCode];//--填充功能码--
  50.                                                                                                                 //--读取线圈的函数----unsigned short        ReadMultReg_03(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
  51.                                                                                                                 RTN_DataLen=ReadInputReg_04(&MB->MB_TxData[TX_MB_DataBase],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
  52.                                                                                                                 //--填充字节数--
  53.                                                                                                                 MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字节数--
  54.                                                                                                                 //--开始填充数据--
  55.                                                                                                                 //计算CRC---校验和----校验是按照从包头开始 -- 一直到数据结束---
  56.                                                                                                                 CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+3 );//--计算CRC的数值
  57.                                                                                        
  58.                                                                                                                 RTN_DataLen=RTN_DataLen+5;  //--这里是包含了CRC校验的----站号 +功能码 +数量+CRCData*2=5
  59.                                                                                                     MB->MB_TxData_Len=RTN_DataLen;//--传入带发送的字节长度--
  60.                                                                                                                 MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff);  //--CRC-H
  61.                                                                                                                 MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff);  //--CRC-L
  62.                                                                                                                 //        完成数据包的组包
  63.                                                                                                                 //--        发送标志----
  64.                                                                                                                 MB->SendFlag=1;
  65.                                                                                         }
  66.                                                                                 else/*--说明--超出范围了---应当返回异常码------  --*/
  67.                                                                                         {
  68.                                                                                                   MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站号--
  69.                           MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能码--错误码--               
  70.                                                                                                   MB->MB_TxData_Len=2;
  71.                                                                                                   MB->SendFlag=1;
  72.                                                                                         }
  73.                                                                  }
  74.                                                                 break ;

  75.                  //----
  76.                                                 case WriteSingelRegister : //--功能码:06   -- 写单个寄存器----
  77.                                                                 {
  78.                                                                  MB->ProtocalStr.MB_DataNum=1;
  79.                                                                                         //--站号-功能码-起始地址 - 数量  字节计数-- 寄存器数值--
  80.                                                           DataLimit=MB->ProtocalStr.MB_StartAddr+MB->ProtocalStr.MB_DataNum;
  81.                                                                 //--进入这里,说明地址和功能码都满足了,现在需要做的事判断输出数量是否在规定范围内--
  82.                                                                 if((MB->ProtocalStr.MB_DataNum>=1)&&(MB->ProtocalStr.MB_DataNum<=0x07D0))
  83.                                                                 {
  84.                                                                         //--站号-功能码-寄存器地址- 寄存器值
  85.                                                                         for(i=0;i<6;i++)
  86.                                                                           MB->MB_TxData[i]=MB->MB_RxData[i];
  87.                                                                         //--写多个寄存器的函数----unsigned short        WriteMultRegister_16(unsigned char *Buffer,unsigned short StartAddr,unsigned short Length)
  88.                                                                         RTN_DataLen=WriteSingelReg_06(&MB->MB_RxData[4],MB->ProtocalStr.MB_StartAddr,MB->ProtocalStr.MB_DataNum);
  89.                                                                   //--填充字节数--
  90. //                                                                        MB->MB_TxData[TX_MB_TxNum]=(unsigned char )(RTN_DataLen&0xff); //--填充字节数--
  91.                                                                         //--开始填充数据--
  92.                                                                         //计算CRC---校验和----校验是按照从包头开始 -- 一直到数据结束---
  93.                                                                         CRC_Data=usMBCRC16( MB->MB_TxData, RTN_DataLen+6 );//--计算CRC的数值
  94.                                                
  95.                                                                         RTN_DataLen=RTN_DataLen+8;  //--这里是包含了CRC校验的----站号 +功能码 +数量+CRCData*2=5
  96.                                                                         MB->MB_TxData_Len=RTN_DataLen;//--传入带发送的字节长度--
  97.                                                                         MB->MB_TxData[RTN_DataLen-2]=(CRC_Data&0xff);  //--CRC-H
  98.                                                                         MB->MB_TxData[RTN_DataLen-1]=((CRC_Data>>8)&0xff);  //--CRC-L
  99.                                                                         //        完成数据包的组包
  100.                                                                         //--        发送标志----
  101.                                                                         MB->SendFlag=1;
  102.                                                                 }
  103.                                                                 else/*--说明--超出范围了---应当返回异常码------  --*/
  104.                                                                 {
  105.                                                                     MB->MB_TxData[MB_Addr]=(0x80+ MB->MB_RxData[MB_FunCode]);//--填充站号--
  106.                                                                                 MB->MB_TxData[MB_FunCode]=MB_ERR_Output_Outof_RangeNum;//--填充功能码--错误码--               
  107.                                                                                 MB->MB_TxData_Len=2;
  108.                                                                                 MB->SendFlag=1;
  109.                                                                 }
  110.                                                                
  111.                                                                 }
  112.                                                                 break ;               
复制代码



4 实物测试图






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







分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条