arduino 伸缩轨道_M5Train 视觉识别轨道小火车头
本帖最后由 沧海笑1122 于 2020-1-13 21:45 编辑
【M5Train 视觉识别轨道小火车头】
【故事】
front_s.jpg (183.22 KB, 下载次数: 4)
2020-1-13 21:10 上传
玩具轨道电动小火车历史悠久,是孩子们常见喜爱的玩具。米兔小火车轨道兼容宜家的轨道,孩子们百玩不厌。但是,毕竟电动小火车头只有一个车速,小火车头拖动着车厢匀速前进,时间长了,难免枯燥。如何增进趣味呢?
M5stack(明栈科技)出品了基于K210的视觉识别core-M5stickV。我们利用http://v-training.m5stack.com/这个友好的训练服务,训练自己的模型并且上传至服务器,将得到返回的训练模型。这样就为小火车装上了一双能识别交通标志的聪明眼睛。
本项目一共训练了七个交通标志。我尝试将其用于米兔轨道小火车,用M5stickC作为执行元件,构成了一个基于视觉识别的,好玩的轨道小火车。
icon1.jpg (124.27 KB, 下载次数: 5)
2020-1-13 21:10 上传
我们先一起看看视频吧,在视频中,小火车头拖着一节车厢,从始发站出发,经过了限速、注意火车、解除限速、亮灯、鸣笛以及停车等七个动作。小火车头变身可以识别交通标志的AI小火车,根据交通标志完成了变速、闪灯、各种音效鸣笛以及起步停车等动作。为儿童玩具增加了更多的趣味。
【硬件】编号内容型号或性能配置备注
1电动火车头配置标称1200MAH的1.2V可充电电池以及管理模块,一套单电机及齿轮传动系统来自闲鱼,这是一个兼容宜家、米兔的可充电电动火车头
2视觉识别装置M5stickV/K210芯片,具有视觉识别、模型自主训练等功能鸣笛及火车音效、亮灯等通过M5stickV完成
3执行装置M5stickC/esp32,接收来自m5stcikV的识别结果并且转换为相应动作,发送至电机驱动板驱动电机的相关动作,有C完成
4电机驱动板L298N双路电机驱动板本项目火车头仅有一个电机,因此仅用一路;
5小火车头动力部分改装锂电池充电控制板、5V/750MA充电器以及14500电池构成。外置的锂电池充电装置,代替了原有小火车内部的1.2V电池以及充电管理模块,14500电池(850MAH/3.7V)具有良好的动力性能,而且可以与L298N模块匹配
6配件自保持开关、铜芯导线若干
vc.jpg (83.63 KB, 下载次数: 6)
2020-1-13 21:10 上传
【软件】编号内容出品及版本备注
1M5sitckV固件M5出品/V1022-beta
2M5StickC固件M5出品/V1.4.3固件基于UIFLOW
3UIFLOW开发环境M5出品/V1.4.3
4Thonny IDEThonny.org /v3.2.6优秀的micropython开发环境
5Vscode+m5stack插件Microsoft出品优秀的通用代码开发环境
【制作过程】
第一步:购买并且改装小火车头
火车头1_s.jpg (83.4 KB, 下载次数: 3)
2020-1-13 21:10 上传
在闲鱼上购买了一只黑红相间的漂亮扎实的小火车头,当时是看中了它具有充电以及车灯功能。到货拆解后,发现其设计比较紧凑合理,做工精良,使用内三角螺丝紧固。小火车头的动力系统包括一节标称1200MAH的1.2V可充电电池+单电机以及齿轮系统+电池充电管理模块。
但是发现存在三个问题:一是动力不足,1200mah的容量几乎可以肯定是虚标;二是电池1.2V的输出电压无法与L298N电机驱动板匹配,也就是难以完成调速、停车、正反转等功能。三是前车灯非常黯淡,可以肯定串接了一个高阻。使用M5sitckC测试后,输出亮度难以满意。
所以我们需要对小火车头进行改装。
(1)改装其动力系统,原有的1.2V电池以及充电管理模块忍痛去除,代之以850MAH/3.7V可充电电池14500,这颗电池的尺寸和原电池一致,所以很容易装配到原位置,我用热熔胶进行了较为严实的固定,将电池的充电系统外置,不再安装在火车内部,把腾出来的位置用于安装L298N电机驱动板。
(2)在车厢顶部开孔(M3)用于安装M5sitckV。
(3)将内部空间里面的原有拨动开关拆除,将内部的塑料结构用电磨进行拆除,空间用于电机驱动板以及布置铜芯导线。
(4)增设一节车厢,用于承载M5sitckC。这样,把小火车的动力部分、电机驱动部分以及视觉识别元件(M5sitckV)放在火车头,而电源开关以及执行元件(M5sitckC)装在一节单独的车厢,两者通过磁性连接件以及排线连接。
old_s.jpg (159.58 KB, 下载次数: 7)
2020-1-13 21:10 上传
第二步:代码设计
代码设计部分其实比较简单,我们一起来看看吧。
(1)M5sitckV部分
一是训练模型
使用M5sitckV的训练程序,将七个交通标志各拍摄100张以上的照片(合计700+照片),发送至http://v-training.m5stack.com/,如果你的训练是符合要求的,计算结果将收敛,这样大约在半小时左右,你会收到一份带有下载链接的邮件。下载后,你将得到一份自主训练的模型库,一个boot.py的demo代码,不要小看这个demo,我们会很容易移植到主程序中。注意:训练时尽可能将模型放入取景框且尝试不同的光线条件。
二是设计代码
这部分主要是将识别的结果发送至M5sitckC,所以uart的发送编程是主要内容,另外,由于M5sitckV带有喇叭,所以我们这个项目的火车音效就靠M5sitckV实现,前文说到的火车头车灯不亮,而M5sitckV本身就带有一个非常亮的全彩LED,这个亮灯的任务也交给M5sitckV吧。
[mw_shl_code=python,true]import audio
import gc
import image
import lcd
import sensor
import sys
import time
import uos
import os
import KPU as kpu
from fpioa_manager import *
from Maix import I2S, GPIO
from machine import I2C
from board import board_info
from pmu import axp192
pmu = axp192()
pmu.enablePMICSleepMode(True)
fm.register(board_info.SPK_SD, fm.fpioa.GPIO0)
spk_sd=GPIO(GPIO.GPIO0, GPIO.OUT)
spk_sd.value(1)
fm.register(board_info.SPK_DIN,fm.fpioa.I2S0_OUT_D1)
fm.register(board_info.SPK_BCLK,fm.fpioa.I2S0_SCLK)
fm.register(board_info.SPK_LRCLK,fm.fpioa.I2S0_WS)
wav_dev = I2S(I2S.DEVICE_0)
from machine import UART
fm.register(board_info.CONNEXT_B,fm.fpioa.UART1_TX)
fm.register(board_info.CONNEXT_A,fm.fpioa.UART1_RX)
uart_A = UART(UART.UART1, 115200, 8, None, 1, timeout=1000, read_buf_len=4096)
fm.register(board_info.LED_W, fm.fpioa.GPIO3)
led_w = GPIO(GPIO.GPIO3, GPIO.OUT)
led_w.value(1)
passlable=''
global v_state
v_state='no'
lcd.init()
lcd.rotation(2)
try:
img = image.Image("/sd/startup.jpg")
lcd.display(img)
except:
lcd.draw_string(lcd.width()//2-100,lcd.height()//2-4, "Error: Cannot find start.jpg", lcd.WHITE, lcd.RED)
task = kpu.load("/sd/3f758421b4b1db32_mbnet10_quant.kmodel")
labels=["1","2","3","4","5","6","7"]
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
sensor.run(1)
lcd.clear()
def play_sound(filename):
try:
player = audio.Audio(path = filename)
player.volume(30)
wav_info = player.play_process(wav_dev)
wav_dev.channel_config(wav_dev.CHANNEL_1, I2S.TRANSMITTER,resolution = I2S.RESOLUTION_16_BIT, align_mode = I2S.STANDARD_MODE)
wav_dev.set_sample_rate(wav_info[1])
spk_sd.value(1)
while True:
ret = player.play()
if ret == None:
break
elif ret==0:
break
player.finish()
spk_sd.value(0)
except:
pass
while(True):
img = sensor.snapshot()
fmap = kpu.forward(task, img)
plist=fmap[:]
pmax=max(plist)
max_index=plist.index(pmax)
a = lcd.display(img)
if pmax>0.99:
lcd.draw_string(40, 60, "Accu:%.2f Type:%s"%(pmax, labels[max_index].strip()))
passlable=str(labels[max_index])
if passlable==v_state:
pass
else:
v_state=passlable
uart_A.write(passlable)
if v_state=='1':
led_w.value(0)
time.sleep_ms(2000)
led_w.value(1)
elif v_state=='2':
play_sound("/sd/whistle3.wav")
time.sleep_ms(200)
elif v_state=='3':
play_sound("/sd/train.wav")
time.sleep_ms(200)
else:
pass
else:
pass
a = kpu.deinit(task)
uart_A.deinit()
[/mw_shl_code]
(1)M5sitckC部分
M5sitckC的代码比较简单,从uart接收到识别特征字以后,通过一系列判断语句,将动作行为发送至L298N即可。
(a)在设计M5sitckC的代码时,我用UIFLOW作为UI设计以及框架搭建,然后将生成的代码用thonny进行调试,玩家看到这里可能会问两个问题:一是为什么不是用uiflow继续调试呢?Uiflow毕竟有一定局限性,而thonny在调试esp32时可以得到非常全面的调试和错误信息;二是为什么调试M5sitckC时,不用vscode+m5插件这种方式呢?因为M5sitckC的屏幕很小,在vscode+m5插件调试时,得不到具体的出错信息。所以根据我的体会,在调试M5sitckC时,比较适合我的办法就是UIFLOW+thonny.
(b)在M5sitckC的屏幕上,我设计了三个参数,一是电池的电压(C的续航能力较弱,实时显示电池电压非常重要,否则调试中会走很多弯路),二是显示从v获取的识别特征码,三是现实C的动作行为(如stop/go/......)便于与V联调时,对识别情况的把握。
stop1s.jpg (130.1 KB, 下载次数: 3)
2020-1-13 21:10 上传
[mw_shl_code=python,true]#2020-01-03
#C侧的火车控制程序v0.11
#
from m5stack import *
from m5ui import *
from uiflow import *
import machine
import time
#UI
setScreenColor(0x111111)
title0 = M5Title(title="Train0108", x=3 , fgcolor=0xFFFFFF, bgcolor=0x0000FF)
label0 = M5TextBox(31, 45, "Ready", lcd.FONT_Default,0xFFFFFF, rotate=0) #显示火车状态
label1 = M5TextBox(33, 89, "Inbox", lcd.FONT_Default,0xFFFFFF, rotate=0) #显示接收到的指令情况
circle0 = M5Circle(17, 52, 3, 0xFFFFFF, 0xFFFFFF)
circle1 = M5Circle(17, 97, 3, 0xFFFFFF, 0xFFFFFF)
#lcd setup
axp.setLDO2Volt(2.7)
title0.setTitle(str(axp.getBatVoltage()))
#setup
#===uart
uart = None
uart = machine.UART(1, tx=32, rx=33)
uart.init(115200, bits=8, parity=None, stop=1)
#===GPI0 SETUP
#pin1 = machine.Pin(5, mode=machine.Pin.OUT, pull=machine.Pin.PULL_UP)
pin0 = machine.Pin(0, mode=machine.Pin.OUT, pull=machine.Pin.PULL_UP)
PWM1 = machine.PWM(26, freq=10000, duty=0, timer=0)
PWM1.resume()
wait(1)
#===Train Action
def go(): #normal
pin0.value(0)
PWM1.duty(60) #speed=60
label0.setText('Go')
label1.setText('no')
def light(): #light of train
#light on m5stickV
label0.setText('Light')
label1.setText('1')
pin0.value(0)
PWM1.duty(50) #speed=50
def train(): #Train comming
# Train sound play on m5stickV
label0.setText('Train')
label1.setText('2')
pin0.value(1)
PWM1.duty(100) #IN1=1 IN2=1 停车3S后正常速度,相当于等待火车通过
time.sleep_ms(3000)
pin0.value(0)
PWM1.duty(50) #3S为speed=50
def whistle(): #whistle
# whistle play on m5stickV
label0.setText('Whistle')
label1.setText('3')
pin0.value(0)
PWM1.duty(50) #speed=50
def limit(): #train limit 5KM/h
pin0.value(0)
PWM1.duty(45) #speed=45
label0.setText('Limit')
label1.setText('4')
def nolimit(): #train no limit 5KM/h
pin0.value(0)
PWM1.duty(75) #speed=75
label0.setText('NoLmt')
label1.setText('5')
time.sleep_ms(2000)
pin0.value(0)
PWM1.duty(50) #2S后降速为speed=50
def stop():#train stop
pin0.value(1)
PWM1.duty(100) #IN1=1 IN2=1
label0.setText('Stop')
label1.setText('6')
def greenlight(): #train Go
pin0.value(0)
PWM1.duty(50) # speed=50
label0.setText('GLight')
label1.setText('7')
#=====Loop
while True:
title0.setTitle(str(axp.getBatVoltage()))
if uart.any():
bin_data = uart.readline(1)
decode_bin_data=bin_data.decode()
wait_ms(200)
if decode_bin_data=='1': #如果识别到1开灯
light()
time.sleep_ms(200)
elif decode_bin_data=='2':#如果识别到2===火车通过
train()
time.sleep_ms(200)
elif decode_bin_data=='3':#如果识别到3===鸣笛
whistle()
time.sleep_ms(200)
elif decode_bin_data=='4':#如果识别到4===限速
limit()
time.sleep_ms(200)
elif decode_bin_data=='5':#如果识别到5===解除限速
nolimit()
time.sleep_ms(200)
elif decode_bin_data=='6':#如果识别到6===停车
stop()
time.sleep_ms(200)
elif decode_bin_data=='7':#如果识别到7===绿灯
greenlight()
time.sleep_ms(200)
else: #其他数据正常前进即可
go()
else:
pass
[/mw_shl_code]
第三步:L298N电机驱动板调试
L298N电机驱动板的控制真值表:
l298n2.jpg (79.57 KB, 下载次数: 6)
2020-1-13 21:10 上传
联调的接线很简单,见下图:
l298n_s.jpg (142.61 KB, 下载次数: 4)
2020-1-13 21:10 上传
在联调时,我用了一个小技巧,将一个测试用的电机,其输入线端焊接了两个杜邦线的母头,而L298N的输出输入的铜芯导线端部,都焊接了排针并且进行了热缩处理。这样非常方便地讲L298N与电池、电机以及M5sitckC连接起来。而在正式部署时,只需要将铜芯导线截断至合适长度即可。这样的小技巧可以大大缩短调试时间,并且增加调试的可靠性。L298N的调试目的就是测试各个控制行为以及根据电机实际情况得到PWM的参数(这个参数在装配小火车头电机后,还会进行一些修正)。
第四步:组装M5sitckV+M5sitckC以及小火车系统并且联调
将M5sitckV+M5sitckC以及小火车系统安装好,其中M5sitckC用扎带固定在车厢上,M5sitckV用M3螺丝以及M5提供的专用L型支架固定在火车头的车厢顶部。火车头的电机与调试后的L298N连接起来。
联调的过程比较简单,注意把火车头翻过来,车轮朝上,这样就不会在调试中,面对不停动弹的火车头手忙脚乱。然后把七个标志一一由V识别,观察C上面的接收情况。
注意:如果您是第一次调试M5sitckV,您需要增加一个步骤,就是M5sitckV与PC的串口助手要先行进行调试,确保M5sitckV识别到的特征码能够准确地传送至uart,我因为在M5sitckV模拟小超市中已经进行过类似调试,积累了很好的经验,所以不需要此步骤。
charge1_s.jpg (106.03 KB, 下载次数: 5)
2020-1-13 21:10 上传
第五步:组装轨道以及路测
接下来就是比较有趣的部分了,也是亲子活动时间,和孩子一起组装一个环形轨道,然后把七个交通标志布置在你希望出现的地方,就可以开始路测了,路测时注意几个问题:
一是M5sitckC/V需要有足够充电,否则因电压不稳的重启会让你的路测不连续。
二是M5sitckV的摄像头角度需要在路测时不断调整。
三是电机的PWM参数需要在路测中不断进行微调,因为每个人小火车头的电机参数都会略有不同,轨道的弯度也需要进行一些调整,有一些过急的弯道可能会造成脱轨,需要进行一些修正。
allmap_s_1.jpg (137.07 KB, 下载次数: 10)
2020-1-13 21:25 上传
这个调试过程总体是很有趣的,看着小火车头拖动着M5sitckC的车厢,在环形轨道上做出种种识别动作,欢声笑语使得前面的辛苦工作,都显得那么物有所值。
【鸣谢】
感谢m5stack.com以及arduino.cn社区,提供这样好的硬件以及交流平台。
感谢社区多位师兄给我的帮助和鼓励,如“滚筒洗衣机”师兄(抱歉您的ID的确如此)对动力系统的指导,笑笑以及jimmy、小华师兄对我的指导和鼓励。
感谢我的孩子能够欣赏我这个小小的项目,并且和我一起测试。
这个小项目抛砖引玉,希望更多玩家做出更有趣的尝试。
新春将至,春天的脚步更近了,祝福各位师兄新春大吉,诸事顺意。
沧海抱拳。
upload_m5train00.zip
(363.28 KB, 下载次数: 5)
2020-1-13 21:21 上传
点击文件名下载附件
2020-1-13 21:21 上传
点击文件名下载附件
2020-1-13 21:21 上传
点击文件名下载附件
2020-1-13 21:21 上传
点击文件名下载附件
由于论坛附件size限制,请下载四个附件后,进行文件名修改,然后解压,我分享了code\model\wav。
原文件名更改为
upload_m5train00.zipupload_m5train.zip
upload_m5train01.zipupload_m5train.z01
upload_m5train02.zipupload_m5train.z02
upload_m5train03.zipupload_m5train.z03
arduino 伸缩轨道_M5Train 视觉识别轨道小火车头相关推荐
- Unity - Timeline 自定义剪辑,轨道,混合轨道,Inspector属性显示(使用Default Playables辅助工具)
Timeline中,可以通过脚本扩展自定义的剪辑,轨道,混合轨道,Inspector属性显示器. 我这里参考了官方的 Default Playables的一个节点扩展方式,它也提供了一个辅助工具,非常 ...
- MATLAB与STK互联44:生成太阳同步轨道、地球同步轨道、闪电轨道等特殊轨道
在进行仿真任务时,我们经常会用到太阳同步轨道.地球同步轨道.闪电轨道等一系列特殊的轨道.在设计这些轨道时,参数往往都有内在相关性或一定的约束,所以轨道参数并不是随意设置.在过去博文中,设置卫星参数都很 ...
- Timeline以及自定义轨道(对话轨道)
目录 创建Timeline 添加Track 添加Animation Track 添加Activation Track 添加Audio Track 添加对话轨道(自定义轨道) 可以同时操作多个模型的动画 ...
- arduino 伸缩轨道_基于Arduino的多轨道Midi音序器的实现
基于 Arduino 的多轨道 Midi 音序器的实现 陈业欣,丰大军,张 蓓 [摘 要] 我国对于专业电声设备的研究相对落后,当今专业电声产品无一例外 均来自日本及欧美国家.通过对使用音乐合成器时声 ...
- 小行星轨道 matlab,小行星轨道问题的建模与求解数学建模论文.doc
您所在位置:网站首页 > 海量文档  > 学术论文 > 自然科学论文 小行星轨道问题的建模与求解数学建模论文.doc6 ...
- Unity学习笔记 解决Cinemachine AutoDolly的虚拟相机在轨道上不按轨道前进方向运动的问题
问题 在使用Cinemachine提供的Tracked Dolly来做路径运动时,若绘制的轨道有交错或者相对接近的地方,可能会出现摄像机没有按照轨道前进的方向实时移动而跳回到了原来的轨道上的情况. 解 ...
- 【BLE MIDI】MIDI 文件格式分析 ( MIDI 轨道分析 | MIDI 轨道头 | MIDI 轨道长度 | delta-time 间隔 )
文章目录 前言 一.MIDI 轨道分析 二.MIDI 轨道头 三.MIDI 轨道长度 四.delta-time 间隔 前言 上一篇博客 [BLE MIDI]MIDI 文件格式分析 ( MIDI 文件头 ...
- css 轨道,html-当其他轨道增加时,CSS网格的轨道不会缩...
由于行和列定义中都包含1fr,因此水平和垂直空间受到限制-因此网格项目将平均共享它们.尝试将其更改为自动用于行和列,您可以看到一切正常,但还不完美-请注意,悬停的网格项周围存在空格: .grid--c ...
- 人工智能轨道交通行业周刊-第8期(2022.8.1-8.7)
0 前言 昨天可可满月了,人虽不在老家,但亲人们都跑到北京来给可可过生日,甚为感动.也来了很多好朋友,让我跟可可妈妈感受到了在他乡的人间温暖,感谢大家! 与可可相处有一个月的时间了,每天最幸福的事莫过 ...
最新文章
- js 对动态添加的table 排序
- 学习笔记98—从矩阵坐标转换至MNI坐标
- Linux下百度网盘一直进入不了登陆界面的解决方案
- 分析 C# 2.0 新特性 -- 空类型(Nullable Types)
- redis远程链接(NOAUTH Authentication required)
- setInterval定时连接后台防止session失效
- 1、Fiddler 打断点 bpu
- Mybatis简介、环境搭建和详解
- 一份工作一年半的java开发个人简历,欢迎拍砖
- java视频教程哪个好?
- activity劫持反劫持
- solidity 重入攻击测试
- 深圳学位锁定怎么计算机,【实用】如何查询深圳房子学位是否锁定?(附操作步骤)...
- 投资学实务-郑商所比赛-交易记录7
- Openwrt Kernel panic - not syncing: Fatal exception 解决方案
- Pandas 数据预处理
- 4864: [BeiJing 2017 Wc]神秘物质
- 电路分析——学习笔记(1.1)
- Eclipse 安装ADT
- 计算机工作原理 课件,计算机的基本结构和工作原理ppt课件.ppt
热门文章
- 单差、双差和三差测量方程
- oracle 配置mysql_Oracle 入门之EM配置
- 期货交易入门流程(期货交易入门书籍)
- 浅析 Vue 的两个版本
- 做自媒体,有哪些好用的工具和软件,这6大自媒体工具,力荐!
- ScalingLayout
- 如何手动启动消防广播_奥瑞那消防主机手册 如何手动启动消防广播
- IDEA打包或者build时报错Failure to find XXX in http://maven.aliyun.com/nexus
- 网站主题包怎么上传到服务器,WordPress网站主题(模板)上传安装
- python dfs算法_算法工程师技术路线图