草庐IT

2021年电赛F题智能送药小车(国二)开源分享

苏幕遮不遮 2023-04-19 原文

文章目录


题目任务

设计并制作智能送药小车,模拟完成在医院药房与病房间药品的送取作业。 院区结构示意如图1所示。院区走廊两侧的墙体由黑实线表示。走廊地面上画有 居中的红实线,并放置标识病房号的黑色数字可移动纸张。药房和近端病房号(1、2 号)如图1所示位置固定不变,中部病房和远端病房号(3-8号)测试时随机设定。
工作过程:参赛者手动将小车摆放在药房处(车头投影在门口区域内,面向 病房),手持数字标号纸张由小车识别病房号,将约 200g 药品一次性装载到送药小车上;小车检测到药品装载完成后自动开始运送;小车根据走廊上的标识信 息自动识别、寻径将药品送到指定病房(车头投影在门口区域内),点亮红色指示灯,等待卸载药品;病房处人工卸载药品后,小车自动熄灭红色指示灯,开始返回;小车自动返回到药房(车头投影在门口区域内,面向药房)后,点亮绿色指示灯。


前言(闲话)

这次比赛因为疫情延期了,给了我们更多的准备(摸鱼)时间,比赛四天三夜,占用了有课的周五(刚好碰上了实习,打铁贼累 还得熬夜。。。)
因为太过摸鱼本以为能那个省三就不错了,没想到冲了个国二,圆梦电赛了,打破了学校十年的记录。所以说竞赛这方面还得坚持,万一破纪录了呢。
我本人是负责视觉方面的,将详细写实现方法,保姆级教程,包括神经网络训练。


一、团队分工介绍

由队长赵嘉辉(电控编程)、队员陈为骞(视觉识别)和吴金颖(机械设计)组成,其中两个大四,一个大三。

//两位光电专业、一位机械的hhh

二、题目分析、破题

1.要点分析

任务可简单分为3个:
(1)巡线移动。完成最基础的移动功能,是所有功能的基础。本作品采用灰度传感器循迹步进电机的巡线移动方案。
(2)识别病房号数字。可采用openmv、k210、树莓派等视觉单片机识别。由于没有提前准备k210,且树莓派大小、功耗较大,因此采用最常见的openmv。为保证性能足够,采用openmv4plus
(3)双机通信。本作品采用蓝牙双机通信,实现数据共享。
完成以上3个任务后,就是对小车代码逻辑的构思和想法。后面的就是多调试代码,修bug即可。

2.系统方案

  • 1、单片机选择

    采用ArduinoMEGA2560单片机作主控。由于其代码开源性,代码简易,适合新手使用。强大的库函数能极大减少开发时间。且对于该题目,运算速度足够,因此采用。

  • 2、运动系统

    采用42步进电机。该款电机转动精确度高,扭力大,额定电流2A以下,且控制简单,不会因为不同驱动的电压而导致转动步数的偏差,无需使用闭环控制即能走出非常好的直线,不易走歪,短距离内可精准控制运动位移。驱动采用TB6600 H桥双极恒相流驱动。驱动及电机采用淘宝成品套件,设置驱动细分数为800。由于驱动体积较大,且42步进电机运行时电流较小,因此可以拆除该驱动模块的金属外壳(散热器),从而达到极大缩小体积和重量。

    前轮采用牛眼轮进行支撑。牛眼轮的选择最好选摩擦力小的。本作品用的牛眼轮摩擦力较大,使得电机的速度不能提得太高,否则摩擦力会将车的运动姿态扰乱,走起来一抖一抖的。

  • 3、循迹系统

    采用八路灰度传感器(实际只用了4路)。调节好阈值,能精准分辨红白色。推荐使用下图的灰度传感器。用非常简单的数字逻辑检测循迹代码即能完成循迹功能。

  • 4、视觉系统

    手持病房号采用模板匹配识别,原因是手持病房号可动态调整远近、角度,模板匹配也能很快识别成功。

    地面上的病房号数字采用OpenMV4 H7 Plus神经网络方法识别。对比模板匹配,识别成功率极高,高达90%以上。由于性能受限,运行时图像仅有2~3帧,需要在病房号前停下零点几秒让其图像稳定下来识别数字。

  • 5、通信系统

    采用HM-10蓝牙模块进行双机通信。主蓝牙仅能接收从蓝牙的信息,不能传信息给从蓝牙。因此从蓝牙接1号车,主蓝牙接2号车。2号车只需要接收1号车指令即可完成所有任务。注意:需提前AT指令设置主从模式和自动连接蓝牙的操作。

  • 6、其他

    采用了oled屏幕显示本次读取病房号是否成功,及实时显示一些小车运行状态,方便调试。设置红绿黄指示灯、蜂鸣器提示等功能。

    采用双边自复位按钮作复位键。由于主控单片机和OpenMV工作电平不一致,复位引脚不能接入同一按键上,因此使用此按键可一键复位两个单片机。

    药物检测采用简单的红外避障模块检测高低电平即可。

三、电控部分

电控部分已在立创开源平台发布!比赛准备的全部工程都有!点这里!!
也可以访问:https://oshwhub.com/AngleLeon/gong-ke-sai-xin-hao-zheng-ge-ban_copy
电控代码也在里面。

1、主控拓展电路

  • (1)单片机及其引脚外接

    其中arduino的D2-D5作为IO口接入电机驱动模块,驱动两个步进电机(每个步进电机由DIR和PUL控制),D23-D37的其中一些引脚接灰度传感器的8个数字信号口。

  • (2)电源输入、输出

    12V从圆孔DC5.5系列接口输入,一路直出给步进电机驱动和步进电机供电,领一路经过5V稳压模块给单片机等其他模块供电。引出8组5V电源接口,方便扩展。

  • (3)其他
    其他多余的接口没有特别定义,只是单纯引出,备用。

2、步进电机驱动信号整合板

两个步进电机需要两个驱动板,需要较多信号线和电源线,会导致接线较乱、易松。为了稳定性更好,制作了这块信号整合板,并使用了XH2.54红白排插线,连接不易松,且易拔插。

  • (1)原理图

    分为12V电源输入输出,布线配合单片机扩展板的IO分布。

  • (2)PCB及仿真图

    印丝层加入了对应的IO口数字号,标注了步进电机驱动细分数对应的拨码器状态。且该pcb孔位、大小完全适配拆了散热外壳后的步进电机驱动模块,能直接安装在驱动上,省空间。

PCB设计分析

由于主要难度在电控编程上,因此对于PCB的布线难度较小,有一定基础即可,没有需要特别注意的地方。

四、视觉部分

很多人觉得视觉难,是因为没办法搭建深度学习的训练环境,巧合的是,本人主持的大创项目正好的关于视觉神经网络的,对于懂的人识别数字十分简单,但是要在嵌入式上载入模型,对于小白来说还是有难度的。我这里只介绍一种极简方法,不需要懂神经网络内涵,手把手小白入门教学。
本人比赛使用的是OpenMv4 Plus,这是支持神经网络最低配的一款,当然K210、树莓派等都可以吊打Openmv,但是由于比赛没有准备其他两款,只能选择普普通通的Openmv了。
先上结果:

神经网络的训练:

//大神请忽略此部分~~~
在线端训练网站:https://studio.edgeimpulse.com

  • 1、使用Opemv采集数据

    打开 工具-数据集编辑器-新数据集

    创建相应数字的文件夹

    通过helloworld.py例程来采集图像,需要把画质改为QQVGA
    多加sensor.set_windowing(20,76,40,40) #框选位置,左右都需要

import sensor, image, time

sensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.GRAYSCALE) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)   # Set frame size to QVGA (320x240)
sensor.set_windowing(20,76,40,40)   #框选位置自己修改成合适的
sensor.skip_frames(time = 2000)     # Wait for settings take effect.
clock = time.clock()                # Create a clock object to track the FPS.

while(True):
    clock.tick()                    # Update the FPS clock.
    img = sensor.snapshot()         # Take a picture and return the image.
    print(clock.fps())              # Note: OpenMV Cam runs about half as fast when connected
                                    # to the IDE. The FPS should increase once disconnected.

然后开始采集,将数字放在左右两边,两边都要采集大概几十到一百张。

  • 2、在网站导入图像(Create impulse)

    从openmv IDE通过API密匙上传采集到的数据集。

  • 3、调整图像(Image)

    按默认设置就好了。

  • 4、迁移学习(Transfer learning)

    参数也是按默认就行。

  • 5、保存模型(Versioning)

    及时做好备份,这是云端的,防止多次采集训练后效果还没以前某一次好。

  • 6、导出模型

下载神经网络后解压导入Openmv,完成。

运行代码:

下面是Openmv端运行代码,代码含模板匹配,移步星瞳官网文档,写得比我好。
Openmv端程序框图:

主程序:

import time, sensor, image,os,tf
from image import SEARCH_EX, SEARCH_DS
from pyb import UART
#从imgae模块引入SEARCH_EX和SEARCH_DS。使用from import仅仅引入SEARCH_EX,
#SEARCH_DS两个需要的部分,而不把image模块全部引入。
uart = UART(3, 9600)
# Reset sensor
sensor.reset()

# Set sensor settings
# Max resolution for template matching with SEARCH_EX is QQVGA
sensor.set_framesize(sensor.QQVGA) #推荐QQVGA,能提高识别速度

# You can set windowing to reduce the search image.
#sensor.set_windowing(((640-80)//2, (480-60)//2, 80, 60))
sensor.set_pixformat(sensor.GRAYSCALE)

net = "trained.tflite"                                      #导入神经网络
labels = [line.rstrip('\n') for line in open("labels.txt")] #导入模板

# Load template.
# Template should be a small (eg. 32x32 pixels) grayscale image.
template1 = ["/1.pgm"]
template2 = ["/2.pgm"]
template3 = ["/3.pgm","/3a.pgm","/3b.pgm"]
template4 = ["/4.pgm","/4a.pgm","/4b.pgm"]
template5 = ["/5.pgm","/5a.pgm","/5b.pgm"]
template6 = ["/6.pgm","/6a.pgm","/6b.pgm"]
template7 = ["/7.pgm","/7a.pgm","/7b.pgm"]
template8 = ["/8.pgm","/8a.pgm","/8b.pgm"]

A0=1
A9=1
B0=1
A1=0
A2=0
A3=0
A4=0
A5=0
A6=0
A7=0
A8=0
B0=1
C0=1
C1=0
C2=1
D0=1
D1=1


#加载模板图片

clock = time.clock()

# Run template matching
while (True):
        clock.tick()
        img = sensor.snapshot()
        while(A0):                          #开始模板匹配识别手持数字
            clock.tick()
            img = sensor.snapshot()
            t1 = image.Image(template1[0])
            r1 = img.find_template(t1, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r1:
                img.draw_rectangle(r1)
                A1=1
                A0=0
            t2 = image.Image(template2[0])
            r2 = img.find_template(t2, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r2:
                img.draw_rectangle(r2)
                A2=1
                A0=0
            t3 = image.Image(template3[0])
            r3 = img.find_template(t3, 0.85, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r3:
                img.draw_rectangle(r3)
                print('3') #打印模板名字
                A3=1
                A0=0
            t4 = image.Image(template4[0])
            r4 = img.find_template(t4, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r4:
                img.draw_rectangle(r4)
                print('4') #打印模板名字
                A4=1
                A0=0
            t5 = image.Image(template5[0])
            r5 = img.find_template(t5, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r5:
                img.draw_rectangle(r5)
                print('5') #打印模板名字
                A5=1
                A0=0
            t6 = image.Image(template6[0])
            r6 = img.find_template(t6, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r6:
                img.draw_rectangle(r6)
                print('6') #打印模板名字
                A6=1
                A0=0
            t7 = image.Image(template7[0])
            r7 = img.find_template(t7, 0.80, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r7:
                img.draw_rectangle(r7)
                print('7') #打印模板名字
                A7=1
                A0=0
            t8 = image.Image(template8[0])
            r8 = img.find_template(t8, 0.85, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
            if r8:
                img.draw_rectangle(r8)
                print('8') #打印模板名字
                A8=1
                A0=0

        while(A9):                            #识别到数字,发送指令给主控
            if A1==1:
                uart.write('1')
                print('1') #打印模板名字
                num=1
                A9=0
            if A2==1:
                uart.write('2')
                print('2') #打印模板名字
                num=2
                A9=0
            if A3==1:
                uart.write('3')
                print('3')
                num=3
                A9=0
            if A4==1:
                uart.write('4')
                print('4')
                num=4
                A9=0
            if A5==1:
                uart.write('5')
                print('5')
                num=5
                A9=0
            if A6==1:
                uart.write('6')
                print('6')
                num=6
                A9=0
            if A7==1:
                uart.write('7')
                print('7')
                num=7
                A9=0
            if A8==1:
                uart.write('8')
                print('8')
                num=8
                A9=0

        while(True):                        #接受到主控指令,可以进行识别数字
            while(B0):
                    if (uart.any()):
                        B = uart.read()
                        print(B)
                        if B==b'1':
                            print("1")
                            B0=0
                            C0=1
            while(C0):
                img = sensor.snapshot()         #神经网络识别右边数字
                roiL=(20,76,40,40)
                for obj in tf.classify(net, img, roiL,min_scale=1, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5):
                    print("**********\nPredictions at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())
                    img.draw_rectangle(obj.rect())
                    predictions_list = list(zip(labels, obj.output()))
                for i in range(len(predictions_list)):
                    print("%s = %f" % (predictions_list[i][0], predictions_list[i][1]))
                    num1=ord(predictions_list[i][0])-48
                    if predictions_list[i][1]>0.7 and num1==num:
                        uart.write('1')
                        print('11')
                        C1=1
                        C0=0
                roiR=(89,77,40,40)              #神经网络识别左边数字
                for obj in tf.classify(net, img, roiR,min_scale=1, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5):
                    print("**********\nPredictions2 at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())
                    img.draw_rectangle(obj.rect())
                    predictions_list2 = list(zip(labels, obj.output()))
                for p in range(len(predictions_list2)):
                    print("%s = %f" % (predictions_list2[p][0], predictions_list2[p][1]))
                    num2=ord(predictions_list2[p][0])-48
                    if predictions_list2[p][1]>0.7 and num2 == num:
                        uart.write('2')
                        print("22")
                        C1=1
                        C0=0
                if C1==0:
                    uart.write('0')
                    print("00")
            print(clock.fps(), "fps")

五、机械部分

  • 1、整车模型

    如图为小车机械结构3D图。前轮采用两个牛眼轮进行辅助支撑,后轮为步进电机驱动的动力轮。长21cm、宽19.5cm、高24.5cm。

    图中1为牛眼轮,2为八路灰度传感器模块,3为小车底板,4为六角铜柱,5为单片机和PCB扩展板,6为摄像头支架固定底座,7为OpenMV摄像头,8为药品,9为药仓,10为红外对射模块,11为步进电机驱动板,12为普通轮子,13为步进电机,14为12V锂电池,15为支撑座。

  • 2、车底盘图

如图为车底盘CAD图,使用激光切割亚克力制成。厚度4mm左右。

最终成品图:

总结

1.选择自己最擅长的方案。不要去尝试其他不熟悉的方案,因为4天3页时间真的很紧急。打算做控制类一定要把通用代码准备好,如PID,视觉双机通信等。

2.作为队长要根据每个队员的优势长处设定任务,队长要担任起进度规划的重任,经常是“单核多线程”工作。每个队员都要有强烈的责任感,在选队员上是关键。例如我们队伍有一个机械,负责车组装和3d建模打印等操作,效率极高,半天时间就设计完,一天不到就组装出第一台车,为我们队伍节省了非常多宝贵的调试时间。

3.运气也是实力的一部分。本次比赛的题目非常符合我们队伍阵容,车控电控、神经网络、机械,完美适配我们三人的优势,也许这些都是命中注定。

4.颁奖典礼时听王越院士说到:建议电赛以后的题目越来越多的人工智能,现在机器学习、深度学习实在太火了,掌握深度学习这项技能十分重要,如果不懂视觉,这次的电赛可能就没办法打了。

附件

B站演示视频:https://www.bilibili.com/video/BV1Qb4y1i7Sn/

主控电路工程:https://oshwhub.com/AngleLeon/gong-ke-sai-xin-hao-zheng-ge-ban_copy#P5

主控代码:https://download.csdn.net/download/weixin_45902201/76727241

Openmv端代码:https://download.csdn.net/download/weixin_45902201/76727631

想白嫖代码请访问立创开源平台,不想麻烦可以直接下载

有关2021年电赛F题智能送药小车(国二)开源分享的更多相关文章

  1. 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一) - 2

    前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型

  2. 智能客服 | 浅谈人工智能聊天机器人ChatGPT - 2

    2022年底,OpenAI的预训练模型ChatGPT给人工智能领域的爱好者和研究人员留下了深刻的印象和启发,他展现的惊人能力将人工智能的研究和应用热度推向高潮,网上也充斥着和ChatGPT的各种聊天,他可以作诗、写小说、写代码、讨论疫情问题等。下面就是一些他的神回复:人命关天的坑: 写歌,留给词作者的机会不多了。。。 回答人类怎么样面对人工智能: 什么是ChatGPT?借用网上的一段介绍,ChatGPT是由人工智能研究实验室OpenAI在2022年11月30日发布的全新聊天机器人模型,一款人工智能技术驱动的自然语言处理工具。它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动

  3. python - 开源 Twitter 克隆(在 Ruby/Python 中) - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭6年前。Improvethisquestion是否有任何用Ruby或Python编写的生产就绪的开源Twitter克隆?我对功能丰富的实现更感兴趣,而不仅仅是简单的Twitter消息(例如:API、FBconnect、通知等)谢谢!

  4. Gradle 自动化构建开源工具 - 2

    文章目录写在前面1、下载与安装(windows)1.1、idea中配置gradle2、基础知识(Gradle6.9为例)2.1、Gradle脚本语法2.1.1、dependsOn2.1.2、创建动态任务2.1.3、增加任务行为2.1.4、参数2.1.5、Ant任务2.1.6、方法2.1.7、默认任务2.1.6、依赖任务的不同输出3、java项目中使用3.1、在已有项目中构建gradle3.2、在新建项目时构建gradle(idea)3.3、gradle项目目录结构3.4、build.gradle3.4.1、plugins3.4.2、repositories3.4.3、dependencies3

  5. 连续3天3场分享,KubeVela@KubeCon EU 2023 抢鲜看! - 2

    自从2019年OpenApplicationModel诞生以来,KubeVela已经经历了几十个版本的变化,并向现代应用程序交付先进功能的方向不断发展。最近,KubeVela完成了向CNCF孵化项目的晋升,标志着社区的发展来到一个新的里程碑。今天,KubeVela社区内活跃着大量来自全球的开发者,共同推动KubeVela项目的落地和发展。在即将开幕的KubeCon+CloudNatvieConEurope2023上,我们惊喜地发现,连续3天,KubeVela项目的贡献者、企业用户和来自阿里云的核心维护者,将从不同角度展对KubeVela项目的分享。让我们先睹为快!🎙️BuildingaPlat

  6. 停车系统源码-基于springboot+uniapp开源项目 - 2

    Iparking停车收费管理系统-可商用介绍Iparking是一款基于springBoot的停车收费管理系统,支持封闭车场和路边车场,支持微信支付宝多种支付渠道,支持多种硬件,涵盖了停车场管理系统的所有基础功能。技术栈Springboot,MybatisPlus,Beetl,Mysql,Redis,RabbitMQ,UniApp功能云端功能序号模块功能描述1系统管理菜单管理配置系统菜单2系统管理组织管理管理组织机构3系统管理角色管理配置系统角色,包含数据权限和功能权限配置4系统管理用户管理管理后台用户5系统管理租户管理多租户管理6系统管理公众号配置租户公众号配置7系统管理操作日志审计日志8系统

  7. 基于python的短视频智能推荐/django的影视网站/视频推荐系统 - 2

    摘要本论文主要论述了如何使用Python技术开发一个短视频智能推荐,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述短视频智能推荐的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程,对系统进行各个阶段分析设计。 短视频智能推荐的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、热门视频管理、用户上传管理、系统管理,用户:首页、个人中心、用户上传管理、我的收藏管理,前台首页;首页、热门视频、用户上传、公告信息、个人中心、后台管理等功能。由于本网站的功能模块设计比较全面,所以使得整个短视频智能推荐信

  8. ruby-on-rails - 在 Facebook、转推等上分享直接 Ruby gem 中的按钮? - 2

    注意http://techcrunch.com/2010/04/04/he-even-makes-coldplay-sound-fun/顶部的那些按钮在社交网络上分享网址?我想为我正在构建的网站做一些非常相似的事情。ShareThis提供了一个可以做同样事情的小部件,但它是品牌化的和外部的。我正在寻找纯Ruby解决方案。包含可包含在RailsApplicationHelper类中的模块的gem将是完美的。在我重新发明轮子之前,感谢您的建议!想象一下: 最佳答案 我能找到的最好的是:http://www.addthis.com/这里有

  9. ruby-on-rails - 有没有很好的引用(开源)Rails NoSQL应用程序? - 2

    我有兴趣了解使用nosql将如何影响rails应用程序的架构/设计/代码。有人知道使用nosql持久性的开源rails应用程序的一个好例子吗?谢谢 最佳答案 看看这些项目:卡桑德拉用法atDigg。卡桑德拉用法atTwitter。Friendly用法atFetLife(nsfw)。最后,MyNoSQL是一个提供nosql相关信息的好网站。 关于ruby-on-rails-有没有很好的引用(开源)RailsNoSQL应用程序?,我们在StackOverflow上找到一个类似的问题:

  10. 《ChatGPT实用指南》(精编版)重磅发布,全网免费分享,快上车,别掉队 - 2

    文/高扬(微信公众号:量子论)据上次3月18号发布的V1.8版,已经过去十天,这期间AI领域发生了很多重大变化。因此,我们对《ChatGPT实用指南》进行了重大改版,增加了大量实用的操作和详细的讲解,保证小白可以轻松上手,快速驾驭ChatGPT。V2.0版本亮点:1、结构更合理。分为基础篇、进阶篇、高级篇,从易到难,由浅入深,符合学习规律。2、内容更充实。扩充了27页的内容,尽量看图说话,将操作步骤一步步地展示出来。3、排版更美观。按图书出版的规范制作,便于知识点查阅。后记:2022年11月底,我们在HackerNews上看到了关于ChatGPT的新闻报道后,开始意识到,人工智能的春天来了,这

随机推荐