一、任务要求
设计并制作智能送药小车,模拟完成在医院药房与病房间药品的送取作业。 院区结构示意如图1所示。院区走廊两侧的墙体由黑实线表示。走廊地面上画有 居中的红实线,并放置标识病房号的黑色数字可移动纸张。药房和近端病房号(1、2 号)如图1所示位置固定不变,中部病房和远端病房号(3-8号)测试时随机设定。
工作过程:参赛者手动将小车摆放在药房处(车头投影在门口区域内,面向 病房),手持数字标号纸张由小车识别病房号,将约 200g 药品一次性装载到送药小车上;小车检测到药品装载完成后自动开始运送;小车根据走廊上的标识信 息自动识别、寻径将药品送到指定病房(车头投影在门口区域内),点亮红色指示灯,等待卸载药品;病房处人工卸载药品后,小车自动熄灭红色指示灯,开始返回;小车自动返回到药房(车头投影在门口区域内,面向药房)后,点亮绿色指示灯。
![](https://img-blog.csdnimg.cn/img_convert/dc2b1b235ca012970e3a3707b3cd1abf.png)
二、视觉部分实现
1.K210简介
K210全称为堪智K210,是嘉楠科技自主研发的一款采用RISC-V处理器架构,具备视听一体、自主IP内核与可编程能力强三大特点,支持机器视觉与机器听觉多模态识别,可广泛应用于智能家居、智能园区、智能能耗和智能农场等场景。
![](https://img-blog.csdnimg.cn/img_convert/fd5138dc69565007e2a685f51f27f64c.png)
我们采用的是DOCK板
![](https://img-blog.csdnimg.cn/img_convert/cc02408272cd8ccf57ea1531a3936c78.png)
开发环境及语言
MicroPython 是基于 Python3 的语法做的一款解析器,包含了 Python3 的大多数基础语法, 主要运行在性能和内存有限的嵌入式芯片上。(注意 Micropython 不包含 Python3 的所有语法)
编译器
![](https://img-blog.csdnimg.cn/img_convert/665f175c647a5b1ee129dec265903995.png)
详细配置及教程参考官方文档
MaixPy 文档简介 - Sipeed Wiki
2.数字识别实现
最初尝试模型库中手写数字识别,效果不太好,于是我们决定自己制作数据集,上传到Maixhub训练模型。
采用目标检测方法训练yolo模型, 使用K210采集数字照片,按照数字“1”到“8”进行数据集标注和打包后,上传数据集并创建训练任务。
1) 数据集制作
(这是21年做的 当时官网训练模型要求数据集的格式如下(旧版本))
![](https://img-blog.csdnimg.cn/img_convert/5eb10476af314e43a2b1e005ee3ea2ac.png)
![](https://img-blog.csdnimg.cn/img_convert/e4027904c6454ca1992ae3b94d55b1fe.png)
现在新版已经可以支持在线导入图片、进行标注。
也可以本地导入上传压缩包(这里和旧版略有不同)。
文章是maixhub新版的本地上传的方法,最近试了试之前的格式不能用了。大家可以尝试在线导入图片、标注,比较便捷。
2)数据集的格式
![](https://img-blog.csdnimg.cn/img_convert/ad0264a8abd84e5687146263450e94ba.png)
按如上格式分别制作1~8 ,8个压缩包
例:"1"文件夹
![](https://img-blog.csdnimg.cn/img_convert/6e869ac536c24cd9b9866c486d8bb52f.png)
![](https://img-blog.csdnimg.cn/img_convert/fe5a34cc6c254357bb96bdec8031a196.png)
images文件夹
存放照片 注意大小224×224
![](https://img-blog.csdnimg.cn/img_convert/65b4e9f75b8645dcb24f97899f13c61b.png)
xml文件夹
数据标注
存放每个照片对应的xml文件(即标注完的照片)
![](https://img-blog.csdnimg.cn/img_convert/010ce44e7f50420097bceedf5db24e5d.png)
标注软件
![](https://img-blog.csdnimg.cn/img_convert/ccd4b00c103cba325955285287402e52.png)
数据集标注
![](https://img-blog.csdnimg.cn/img_convert/ea314f7bc1bd438c9ad64826dc5087e4.png)
最后压缩
![](https://img-blog.csdnimg.cn/img_convert/4f675edeaf94489db2bda0c173ca1e8a.png)
按相同步骤制作2~8,最后有8个压缩包
这个标注操作不熟练,可以在上传完图片之后官网在线标注,非常便捷。
![](https://img-blog.csdnimg.cn/img_convert/0fd7d3d17505450ba00c412167395c97.png)
3)训练模型
MaixHub 训练模型网址
创建项目
![](https://img-blog.csdnimg.cn/img_convert/bc4a07e0081f48ccb484285fa60099f2.png)
项目类型是图像检测
![](https://img-blog.csdnimg.cn/img_convert/00b3c8e7df0343e0aa8da36f315e7cf3.png)
创建数据集
![](https://img-blog.csdnimg.cn/img_convert/c102d3da4d9740d4a04d8603ba83916c.png)
选择从本地上传数据集
![](https://img-blog.csdnimg.cn/img_convert/d930fc924e4f4a99af85b17e1bf156ea.png)
批量选择一部分放到验证集,也可以不放
![](https://img-blog.csdnimg.cn/img_convert/19a1b0bed0cd42e1b5937c3ee61e8a15.png)
官网给出的介绍
创建任务
![](https://img-blog.csdnimg.cn/img_convert/0369dba6ab05433b8af3e15a848c72e6.png)
最后部署模型,手动部署即可
这里是我训练完的,可以下载
源码即模型下载 K210数字识别模型含代码
三、K210与STM32通信代码
将识别到的数字传送到32端
import sensor, image, lcd, time
import KPU as kpu
import gc, sys
from machine import UART
from fpioa_manager import fm
fm.register(8, fm.fpioa.UART1_RX, force=True) #串口
fm.register(9, fm.fpioa.UART1_TX, force=True) #串口
uart = UART(UART.UART1, 115200, read_buf_len=4096)
def lcd_show_except(e):
import uio
err_str = uio.StringIO()
sys.print_exception(e, err_str)
err_str = err_str.getvalue()
img = image.Image(size=(224,224))
img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))
lcd.display(img)
def main(anchors, labels = None, model_addr="/sd/m.kmodel", sensor_window=(224, 224), lcd_rotation=0, sensor_hmirror=True, sensor_vflip=True):
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing(sensor_window)
sensor.set_hmirror(sensor_hmirror)
sensor.set_vflip(sensor_vflip)
sensor.run(1)
lcd.init(type=1)
lcd.rotation(lcd_rotation)
lcd.clear(lcd.WHITE)
if not labels:
with open('labels.txt','r') as f:
exec(f.read())
if not labels:
print("no labels.txt")
img = image.Image(size=(320, 240))
img.draw_string(90, 110, "no labels.txt", color=(255, 0, 0), scale=2)
lcd.display(img)
return 1
try:
img = image.Image("startup.jpg")
lcd.display(img)
except Exception:
img = image.Image(size=(320, 240))
img.draw_string(90, 110, "loading model...", color=(255, 255, 255), scale=2)
lcd.display(img)
try:
task = None
task = kpu.load(model_addr)
kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) # threshold:[0,1], nms_value: [0, 1]
while(True):
img = sensor.snapshot()
t = time.ticks_ms()
objects = kpu.run_yolo2(task, img)
t = time.ticks_ms() - t
if objects:
for obj in objects:
pos = obj.rect() #返回一个坐标元组x y w h
if obj.value() >0.7:#识别到的概率大于0.7才判断,提高准确度
img.draw_rectangle(pos) #把图片框起来
img.draw_string(pos[0], pos[1], "%s : %.2f" %(labels[obj.classid()], obj.value()), scale=2, color=(255, 0, 0) #lcd上打上标签
uart.write(labels[obj.classid()]+'\r\n')
#print(c,pic_posy)
img.draw_string(0, 200, "t:%dms" %(t), scale=2, color=(255, 0, 0))
lcd.display(img)
except Exception as e:
raise e
finally:
if not task is None:
kpu.deinit(task)
if __name__ == "__main__":
try:
labels = ["1", "2", "3", "4", "5", "6", "7", "8"]
anchors = [2.53125, 3.5625, 2.125, 3.03125, 2.9375, 4.0, 3.75, 5.375, 4.6875, 6.09375]
# main(anchors = anchors, labels=labels, model_addr=0x300000, lcd_rotation=0)
main(anchors = anchors, labels=labels, model_addr="/sd/m.kmodel")
except Exception as e:
sys.print_exception(e)
lcd_show_except(e)
finally:
gc.collect()