在仓储系统中,为了提高人工拣选的效率,许多企业在仓库中增加了亮灯拣选功能,即在已有货架上增加灯光指引,操作员根据灯光在对应货架上拣选物料。现在市面上的安装在库位上的亮灯指引标识一般都是专门做的设备,功能上完全满足要求,但售价一般比较高。结合现在市面上WS2812灯带应用普及,用WS2812做亮灯拣选指引,功能上满足要求,效果上比现有更好,成本却比现在的更低。
1:系统框图
核心控制器选用stm32系列的单片机,后续可更换为国产单片机。
通信,为了适应多种场景,目前实现的支持485通信,232通信和网口通信。
灯带选择WS2812B灯芯的灯带,灯带长度根据实际库位确定,控制器支持的长度可以自由设定。
供电,考虑到现场实施的便捷,设备供电范围从5V~24V。
2:通信协议及程序处理
通信协议用自有协议,在硬件层确定好硬件接口后,WMS系统需要按该协议格式发送数据,控制器收到数据后,检验正常,反馈同帧数据给WMS系统,同时开始执行亮灯;检验异常,在异常位置设置对应的异常编码,然后反馈给WMS系统,不执行亮灯。
通信协议定义如下
从通信接口给主控板发送如下指令
该指令含义如下:
AA :表示帧开始
00 15 : 从21个灯开始
00 05:亮5个灯
00 :等待命令灭灯
00 00 30 :灯色蓝色30
00 00 00 :灭灯色
00 :正常帧
00 00 : crc检验,本帧为方便测试,为左校验。
BB:帧结束
实际测试板子功能测试中,使用串口进行测试,从串口中发送的数据如图
在这个图中,发送过三次亮灯指引帧,实际的指引亮灯如下图:
第一帧命令:从1号灯开始5个灯亮绿色;
第二帧命令:从11号灯开始5个灯亮红色;
第三帧命令:从21号灯开始5个灯亮蓝色。
控制板串口通信接收数据是在串口中断中执行的,每收到一个字符都做分析,接收程序如下
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
if(huart == &huart1)
{
//接收状态标识,0:等待协议头;1:协议接收中;2:协议接收完成,待处理。
switch(recv_flag)
{
case 0:
recv_overtime:
if(recv == 0xAA){
recv_delay = RECV_DELAY;
recv_flag = 1;
recv_length = 0;
recv_buff[recv_length]=recv;
recv_length ++;
}
break;
case 1:
if(RECV_DELAY == 0){
//接收字符间延迟超时
recv_flag = 0;
goto recv_overtime;
}
recv_delay = RECV_DELAY;
recv_buff[recv_length]=recv;
recv_length ++;
if(recv_length == 16){
if(recv == 0xBB){
recv_flag = 2;
}else{
recv_flag = 0;
}
}
break;
default:
break;
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&recv, 1);
}
}
接收后在主程序中处理数据,程序如下:
//协议中超时后取消显示功能
WS_ClearWHLED();
//接收到数据,待处理
if(recv_flag == 2)
{
//RC522_Test(recv_flag);
if(spisend_flag == 0)
{
//显示数据分析处理
WS_CreateWHLED();
HAL_IWDG_Refresh(&hiwdg);
//接收到的数据在回复给发送方
for(i = 0; i < 16; i++)
{
send_buff[i]= recv_buff[i];
}
HAL_UART_Transmit(&huart1,send_buff,16,0xFFFF);
recv_flag = 0;
}
}
具体的数据处理
void WS_CreateWHLED()
{
int i;
U16 pt, len;
//超时自动取消显示
if(recv_buff[5] != 0)
{
led_flag = 1;
led_delay1s = recv_buff[5] + 1;
}
else
led_flag = 0;
pt = (recv_buff[1] << 8) + recv_buff[2] - 1;
len = (recv_buff[3] << 8) + recv_buff[4];
if((0 <= pt) && (pt < LEDNUMB))
{
if((pt + len) > LEDNUMB)
len = LEDNUMB - pt;
for(i = 0; i < len; i++)
{
ledGRB[3*pt + 3*i] = recv_buff[6];
ledGRB[3*pt + 3*i + 1] = recv_buff[7];
ledGRB[3*pt + 3*i + 2] = recv_buff[8];
}
}
//WS2812B显示
WS_led();
}
void WS_ClearWHLED()
{
int i;
I16 pt;
U16 len;
if(led_flag == 1)
{
if(led_delay1s == 0)
{
led_flag = 0;
pt = (recv_buff[1] << 8) + recv_buff[2] - 1;
len = (recv_buff[3] << 8) + recv_buff[4];
if((0 <= pt) && (pt < LEDNUMB))
{
if((pt + len) > LEDNUMB)
len = LEDNUMB - pt;
for(i = 0; i < len; i++)
{
ledGRB[3*pt + 3*i] = recv_buff[9];
ledGRB[3*pt + 3*i + 1] = recv_buff[10];
ledGRB[3*pt + 3*i + 2] = recv_buff[11];
}
}
WS_led();
}
}
}
3:WS2812B数据显示
WS2812B数据传输波形可以参考手册,本程序中用SPI + DMA中断方式来实现该接口。WS2812的一个位用spi的一个byte模拟。
参数配置如下
WS2812位取值1是SPI对应的byte取值0XF8,位为0是对应的取值0XC0。
WS2812由位转换程spi的函数
U8 WS_code[2] = {0XC0, 0XF8};
void WS_GetData(U8 *data, U16 len)
{
int i, j, k = 0;
for(i = 0; i < len; i++)
{
for(j = 7; j >= 0; j--)
{
senddata[k] = WS_code[(data[i] >> j) & 0x01];
k ++;
}
}
}
void WS_led()
{
WS_GetData(ledGRB, GRBNUMB);
//SPI_Send(senddata, SENDLen);
//SPI_Send_IT(senddata, SENDLen);
SPI_SendDMA_IT(senddata, SENDLen);
}
void SPI_SendDMA_IT(U8 *pData, U16 Size)
{
spisend_flag = 1;
HAL_SPI_Transmit_DMA(&hspi1, senddata, SENDLen);
}
//spi发送完毕中断
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
UNUSED(hspi);
if(hspi == &hspi1)
{
spisend_flag = 0;
HAL_SPI_DMAStop(hspi);
}
}
至此,完成了从数据接收到亮灯的功能。
最后,安装实施和用效果看,该方案在亮灯指示方面优于市面上现有的专用设备;不足就是操作人员分拣完毕后,反馈完毕结果,专用设备直接拍灯(按键)反馈,该方案需要在PDA上反馈。