项目实战-外卖自提柜 1.项目介绍、协议制定

2023-05-16

项目实战-外卖自提柜 1.项目介绍、协议制定
项目实战-外卖自提柜 2. CubeMX + FreeRTOS入门
项目实战-外卖自提柜 3. FreeRTOS主要API的应用
项目实战-外卖自提柜 4. FreeRTOS 堆栈分配、调试技巧
项目实战-外卖自提柜 5. ESP8266 01S配置与掉线处理
项目实战-外卖自提柜 6. 硬件工作与测试(原理图、PCB绘制、测试视频)

项目介绍

外卖自提柜,类似蜂巢之类的快递柜。
工作流程:

  • 外卖员通过手机APP扫描柜体上面的固定二维码,在APP中输入客户的手机号

  • 完成后,服务器向对应手机号发送含有取货密码的短信

  • 同时自动分配一个空柜子,向设备端发送一个开柜指令,内容包括,柜号、开柜密码等

  • 设备端收到开柜指令后开柜

  • 客户收到短信后凭密码取外卖,取完后设备端上报服务器取货成功的信息。

基本功能包括与服务器通信,控制开柜,显示信息,声音提示,验证码输入等等。

服务器和APP是别人做的,我做设备端,柜体用下面这种。
在这里插入图片描述

方案选型

方案:
MCU + WIFI模块 + GPRS模块 + 显示屏 + 键盘
选型:
stm32f103rbt6 + esp8266 + sim800 + lcd彩屏 + 矩阵键盘

一开始觉得这个项目so easy 烂大街 ,乍一看确实,这选型也太烂大街了(笑),如果说这是一道电赛题,几天也能弄出来,但做它却花了近两个月…至于原因嘛,做的时候是当一个产品 亲儿子 来做(虽然也不知道产品标准是啥),从系统稳定性、工程/代码规范来讲,很认真在做的。

工作流程

设备端主要工作流程如下:

  1. 硬件开机后与服务器连接,连接成功后,硬件自动向服务器发送注册指令, 包含本机的Id,服务器收到后会将该机器注册进来,进行监管。

  2. 当有客户想要存放时,会扫描硬件二维码获取机器Id,然后在App上打开某个格子,服务器会向该机器发送存货指令 , 包含要打开的机器Id,格子Id,存放模式,取货验证码等等,同时服务器会向取货的客户发送6位验证码短信。

  3. 机器接收到存柜存货指令后,尝试打开相应格子,并保存验证码,若打开成功,则发回给服务器开柜成功指令表示成功。否则返回开柜失败指令表示失败。

  4. 客户来取物品时,在机器上输入相应的六位密码,响应密码的格子就会自动打开,然后向服务器发送取货指令,报告格子被打开。

  5. 持续工作,设备需要每30s发送一次心跳指令

协议制定

协议部分雏形是做服务器的同学定的,这部分直接导致系统从裸奔变成跑FreeRTOS,也是个人认为整个项目最费劲的地方。

下面直接把跟做服务器同学的部分讨论贴上来
(聊天记录自己读了好几遍,相当给劲)

首次确定格式 帧头+数据长度+数据+校验和

Ta:帧头+长度+数据+校验和 的形式可以吗。帧头标志数据开始,长度标识了信息结束的位置,其实也可以看作是帧头作为不同信息的分隔符
——————————
:可以
——————————
Ta:还有一种情况是信息内部出现帧头格式,怎么识别。数据丢失也可能发生在头部和尾部
——————————
:只要不是单字节非ASCII数据,就不会连续四字节的0x0a,咱们数据都用short类型(两字节),帧头就用四个连续的0x0a就可以避免上面的情况了

到这时候,我依然打算裸奔(不跑RTOS),直到后面出现一个个问题:

Ta
因为数据传输可能出现两种情况,第一种是出错,第二种是丢失。不论哪种情况都需要数据重传,所以对于不管是出错还是丢失的数据都采取丢弃不响应的措施。而正确收到的数据需要返回一个回复帧用以响应
然后在自己这里设置一个定时器,如果超过一定时间没有收到响应就认为这个数据丢失或者出错了,就进行重传。重传三次以上都没有响应就关闭链接。
—————————————————————————————————
但加入重传就导致另一个问题,就是由于网络问题,回复帧丢失或者是回复帧传输较慢,发送端认为接收端未收到,但实际接收端收到了。发送端就会又进行重传,这时我们需要判断这条指令我们有没有执行过,不能重复执行。
所以如果要进行严格的数据安全保证: 第一个是定时检查,重传未响应数据 第二个是对于响应丢失或延迟,识别并排除重复指令
所以在我们这里实现就是,识别每一个指令,保存发送过的指令,超时重传处理,每个指令都要有回复帧。客户端和服务器端都需要实现这些功能,因为相互传输过程中都有可能出现出错,丢失
————————————————————————————————
我:
为解决上面的问题,我们增加一个计数值,我们双方每成功通信一次,计数加1,对于发送方来说,收到正确的应答算一次成功通信;对于接收方来说,收到的数据没有错误算一次成功通讯。
把这个计数值附加在每条指令的最后(校验和之前),这样发送者的计数值应该和接收者的计数值相同。如果出现了上面的那种情况,比如设备端已经收到数据,而由于回复帧有延时导致服务器误判断为超时,重发本条指令。这时设备端计数值已经加1了,而服务器的计数值未增加(此时设备端计数值=服务器计数值+1),则设备端判断为重复指令,忽略此次指令对应的执行动作,但照常回复
—————————————————————————————————
Ta:ok我觉得可行,我再想一下细节,明天同步完善一下
—————————————————————————————————
Ta:我昨天想了一下,计数值可能会出现问题。因为通信消息的发送并不是顺序进行的
比如,当前计数值为10,表示已经通信10次了。现在服务器向你发送多条开柜消息(多人在使用柜子),由于前面发送的还没收到应答消息,所以计数值还是10,那这些消息的消息的计数值就都=10+1=11。
另一种情况是,服务器发送开柜消息,通信号为11,在这段发送时间里,你那里也发送开柜信号,通信号也是11。因为咱俩计数值是一致的=10,我这里发送一条新消息11,你那里也是11
—————————————————————————————————
:我的理解是,虽然会同时使用柜子,但发送指令还是按顺序来的,服务器发完指令阻塞等待设备回复,这期间不对该设备发送指令,进行一次成功通讯后(收到成功应答信号),再进行下一次通讯
—————————————————————————————————
Ta:实际上并不是这样的,netty框架本身是异步的,当然也可以同步阻塞,但是阻塞的话,一个客户发送消息,如果消息丢了,需要超时重传,响应丢了需要超时重传,这个过程一直阻塞的话,其他人的手机界面一直转圈圈等待,效率太低了。netty就是为高效而生,如果每进行一步都要阻塞等待,那用最简单传统的socket通信就可以了。所以通信不能阻塞,通信必须可以并发
————————————————————————————————
Ta:假如我们设置一分钟的超时时间+四五位客户存东西+线路传送时间,那么最后一位存东西的不一直在等吗,相当于在排队
我们要的效果是,如果第一位存的消息没到达但是干扰不了第五位存的,第五位顺利到达了,第五位正常存取,第一位自己在等待
————————————————————————————
:懂了,这样的话,计数值不行。主要原因是计数值总在收到回复后才自增,导致后面数据的必须阻塞才能保证计数正确。
那另一种方案,计数值在每发送一个新数据时自增(新数据不包括错误重发的数据),这样计数值相当于一个数据帧的唯一ID,开一个数组/链表,内容为正在等待接收方回复的数据帧的ID,如果某数据帧收到正确的回复,那么将该数据帧对应的ID从数组/链表中移出。
当然这里需要判断这条回复帧是回复哪条数据帧的,所以回复帧中,需要增加数据帧ID的信息。
这样,发送端在每发送一个数据帧时,将该数据帧的ID计入数组/链表,同时开一个属于该数据帧的定时器,做超时判断。
————————————————————————————————
Ta:这样,如果服务器和客户端公用一个计数值,不好保证同步。服务器自己用一个计数器,从服务器发送出去的数据帧从0开始计数,客户端同理,使用自己的计数器。每发送一个指令就自增,保证自己发送的数据id在自己发送里是唯一的。同理我发送给你的数据指令id在你的接收里也是唯一的。

这一段讨论,增加了一个头疼的需求:

要保证当设备发送一条指令时,等待该条指令被应答的时间内,不影响新的指令的发送

我还是以系统裸奔为前提,来寻找解决办法:

每发送一条指令,我需要为该条指令创建一个独立的的软件定时器,用以等待接收方对该条指令的回复,同时不能阻塞系统的运行。

软件定时器是可行的,但我只能提前在程序里创建好规定数量的定时器,这样软件定时器的个数是确定的,而极端恶劣环境下(有N多条指令要等待发送),那至少从理论上,这种方法不是最优解。
(最优解是:只要单片机的RAM还富裕,我就可以一直创建,直到榨干)

当然我可以动态 申请/释放 内存来 创建/删除 软件定时器,不过这个点子是我决定使用FreeRTOS之后才想到的,当然这就像自己去造轮子,毕竟RTOS实现多任务也通过动态管理内存。

一直在搬砖的我选择继续搬…

相比之前,增加了FrameId,每一帧都有自己唯一的FrameId,用以辨识重复的指令。

嘿,至此,数据格式完全确定了:

帧头 + Length + CmdId + DevId + Content + FrameId + 校验和

  • 帧头:0x0a 0x0a 0x0a 0x0a
  • Length :指令字节数总长度,包括其本身和校验和,两个字节的无符号short类型,顺序为 [低字节,高字节]
  • CmdId: 指令的Id , 一个字节的无符号byte类型
  • DevId: 目标设备的Id,两个字节的无符号short类型,顺序为 [低字节,高字节]
  • Content : 该条指令包含的详细信息
  • FrameId:每一帧的唯一Id,两字节无符号short类型,顺序为[低字节,高字节]
  • 校验和:一字节有符号byte类型

不同指令的Content不同:

  1. 注册帧000:设备向服务器发送的认证信息,在服务器上注册该设备
    Content为空

  2. 回复帧001:回复数据正确
    Content为空

  3. 心跳帧002:心跳保持
    Content为空

  4. 存货开柜帧003:服务器向设备发送存货开柜指令
    Content内容包含:
    -CellId:机器格子的编号,要开启的格子。两个字节的无符号short类型,顺序为 [低字节,高字节]
    -Mode:代表存储的模式(常温,保温,制冷),一个字节的无符号byte
    -PassWord:表示存储密码,六个字节的char字符串,顺序即为密码顺序
    -SendAddress:表示存件者的id,11个字节的电话号码,char字符串,顺序即为号码顺序
    -ReceiveAddress:表示取件者的id,含义同上

  5. 开柜成功帧004:设备开柜成功
    Content内容与指令003相同

  6. 开柜失败帧005:设备开柜失败
    Content包含:
    -SendAddress : 表示存件者的id,11个字节的电话号码,char字符串,顺序即为号码顺序

  7. 取货帧006:客户取货成功
    Content包含:
    -CellId:机器格子的编号,要开启的格子。两个字节的无符号short类型,顺序为 [低字节,高字节]

前期工作完成了,开始写程序。

项目实战-外卖自提柜 1.项目介绍、协议制定
项目实战-外卖自提柜 2. CubeMX + FreeRTOS入门
项目实战-外卖自提柜 3. FreeRTOS主要API的应用
项目实战-外卖自提柜 4. FreeRTOS 堆栈分配、调试技巧
项目实战-外卖自提柜 5. ESP8266 01S配置与掉线处理
项目实战-外卖自提柜 6. 硬件工作与测试(原理图、PCB绘制、测试视频)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

项目实战-外卖自提柜 1.项目介绍、协议制定 的相关文章

  • Linux驱动开发经典面试简答题

    1 Linux设备中字符设备与设备有什么主要的区别 xff1f 请分别举例一些实际的设备说出它们是哪一类设备 字符设备 xff1a 字符设备是个能够像字节流 xff08 类似文件 xff09 一样被访问的设备 xff0c 由字符设备驱动程序
  • CMake中cmake_host_system_information的使用

    CMake中的cmake host system information命令用于查询各种主机系统信息 xff0c 其格式如下 xff1a cmake host system information RESULT lt variable gt
  • 一文知晓嵌入式Linux

    嵌入式Linux是什么 嵌入式Linux跟桌面Linux一样 xff0c 是一个操作系统 从单片机走过来的童鞋往往习惯于直接控制寄存器 xff0c 事必躬亲 xff0c 从零开始实现想要的功能 而在嵌入式Linux的世界里 xff0c 我们
  • 修改i.mx6ull Linux内核 启动logo

    1 制作Linux内核需要的开机logo xff08 ppm格式 xff09 1 1在Ubuntu系统上安装netpdm工具 命令如下 xff1a span class token macro property sudo apt get i
  • keil5编译错误error: #5: cannot open source input file “core_cm3.h“: No such file or directory

    用Keil vision5编译时出现 xff1a error 5 cannot open source input file core cm3 h No such file or directory 可能是MDK版本太新了 xff0c 我装
  • IPv6基础详解

    IPv6 由于internet规模的扩大 xff0c IPv4地址空间已经消耗殆尽 xff0c IETF在90年代提出了下一代互联网协议IPv6 xff0c IPv6支持几乎无限的地址空间 xff0c 并且配置更加简单 xff0c IPv6
  • Pycharm中debug使用学习

    1 运行环境 1 1 运行 xff1a 先确认项目运行环境 点击右下角python查看 向任务中添加环境 xff0c 一般加入anaconda的环境 xff0c 配置方便 切换到自己所需环境 添加运行环境 初次搭建 xff0c 哔哩哔哩中新
  • 对项目的梳理、流程和总结

    过程 我在制作 中国汽车技术研究中心 的一个演讲PPT前 xff0c 也已经有第一版的基础了 xff0c 不过 xff0c 第一版的PPT客户并不满意 xff0c 因为这个风格不是客户想要的 xff0c 所以客户对第一版的PPT并不是很满意
  • 【ROS】xxx is neither a launch file in package xxx nor is xxx a launch file name……解决

    在ros中新增加一个功能包时 xff0c 如果没有处理得当的话 xff0c 在执行时很有可能报如下错误 xff1a xxx is neither a launch file in package xxx nor is xxx a launc
  • FreeRTOS——流和消息缓冲区

    FreeRTOS 基础系列文章 基本对象 FreeRTOS 任务 FreeRTOS 队列 FreeRTOS 信号量 FreeRTOS 互斥量 FreeRTOS 任务通知 FreeRTOS 流和消息缓冲区 FreeRTOS 软件定时器 Fre
  • FreeRTOS——静态与动态内存分配

    FreeRTOS 基础系列文章 基本对象 FreeRTOS 任务 FreeRTOS 队列 FreeRTOS 信号量 FreeRTOS 互斥量 FreeRTOS 任务通知 FreeRTOS 流和消息缓冲区 FreeRTOS 软件定时器 Fre
  • CAS 6.5.5项目初始化搭建运行

    一 项目背景介绍 公司项目重构 xff0c 决定使用CAS中央认证系统 在GitHub上找到最新的稳定版本6 5 5 CAS项目在5 x版本的运行环境是jdk8 xff0c 使用maven做的项目管理 6 x使用的是jdk11作为运行环境
  • GoogleTest中gMock的使用

    GoogleTest中的gMock是一个库 xff0c 用于创建mock类并使用它们 当你编写原型或测试 prototype or test 时 xff0c 完全依赖真实对象通常是不可行或不明智的 not feasible or wise
  • 基于Autoware制作高精地图(一)

    基于Autoware制作高精地图 xff08 一 xff09 开始进入正题 xff0c 也是最近在忙的一件事 xff0c 制作高精地图 高精地图的制作大概分为以下四个流程 xff08 不一定完全正确 xff09 xff1a 1 构建点云地图
  • Ubuntu sh文件编写,开多终端,自动读取密码

    Ubuntu sh文件编写 xff0c 开多终端 xff0c 自动读取密码 开启多个终端自动读取密码 在最近的项目调试中经常需要开多个终端启动多个launch xff0c 这样的操作多了难免会感到烦躁并且时间一长再回去使用一些功能包的时候就
  • 控制理论——自动控制原理若干概念

    1 对自动控制系统的基本要求 稳定性 被控量因扰动偏离期望值后 xff0c 经过过渡过程可以恢复到原来的期望值状态 快速性 包含两方面 xff1a 过渡过程的时间 最大超调量 xff08 震荡幅度 xff09 准确性 指稳态误差 xff1a
  • Optitrack下通过mavros实现offbord控制

    参考文章 xff1a 树莓派通过MAVROS与Pixhawk PX4通信 PX4使用Optitrack进行室内定位 通过optitrack与妙算连接在同一局域网下 xff0c 关闭防火墙 xff0c 并设置刚体发布 vrpn安装 cd ca
  • 【场景图生成】Unbiased Scene Graph Generation from Biased Training

    文章下载地址 xff1a https arxiv org pdf 2002 11949 pdf 代码地址 xff1a GitHub KaihuaTang Scene Graph Benchmark pytorch 发表地点 xff1a CV
  • 【场景图生成】Graphical Contrastive Losses for Scene Graph Parsing

    文章下载地址 xff1a Graphical Contrastive Losses for Scene Graph Parsing 代码地址 xff1a https github com NVIDIA ContrastiveLosses4V
  • jquery无法获取到textarea中的值详解

    问题描述 xff1a 今天在springboot中jquery读取前端的值通过jquery打包为json传入后端 xff0c 发现其中textarea区域中的内容无法获取 解决办法 xff1a 首先看你的textarea中是否有 name属

随机推荐