OpenMV数字识别进而控制直流电机转速【小白篇】

这篇具有很好参考价值的文章主要介绍了OpenMV数字识别进而控制直流电机转速【小白篇】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

第一次接触OpenMV也是第一次将理论用于实践,是老师让我实现的一个小测验,这几天完成后决定写下完整的过程。本文主要是当缝合怪,借鉴和参考了其他人的代码再根据我个人设备进行了一定的调整,此外还包括了我自身实践过程中的一些小意外。
!!!一定要根据个人器件型号和个人设备来参考


一、数字识别的模型训练

1.下载训练集

研究期间,我发现大部分人以及官网教程采用的都是自己拍摄照片再进行网络训练,存在的缺陷就是数据集较小不全面、操作繁琐。个人认为如果是对标准的数字进行识别,自己手动拍取照片进行识别足够了。但想要应用于更广泛的情况,应该寻找更大的数据集,所以我找到了国外手写数字的数据集MNIST。建议四个文件都下载
数据链接:MINIST数据集

2.对数据进行调整

2.1 将ubyte格式转为jpg格式

代码参考链接:python将ubyte格式的MNIST数据集转成jpg图片格式并保存

import numpy as np
import cv2
import os
import struct
 
def trans(image, label, save):#image位置,label位置和转换后的数据保存位置
    if 'train' in os.path.basename(image):
        prefix = 'train'
    else:
        prefix = 'test'
 
    labelIndex = 0
    imageIndex = 0
    i = 0
    lbdata = open(label, 'rb').read()
    magic, nums = struct.unpack_from(">II", lbdata, labelIndex)
    labelIndex += struct.calcsize('>II')
 
    imgdata = open(image, "rb").read()
    magic, nums, numRows, numColumns = struct.unpack_from('>IIII', imgdata, imageIndex)
    imageIndex += struct.calcsize('>IIII')
 
    for i in range(nums):
        label = struct.unpack_from('>B', lbdata, labelIndex)[0]
        labelIndex += struct.calcsize('>B')
        im = struct.unpack_from('>784B', imgdata, imageIndex)
        imageIndex += struct.calcsize('>784B')
        im = np.array(im, dtype='uint8')
        img = im.reshape(28, 28)
        save_name = os.path.join(save, '{}_{}_{}.jpg'.format(prefix, i, label))
        cv2.imwrite(save_name, img)
 
if __name__ == '__main__':
    #需要更改的文件路径!!!!!!
    #此处是原始数据集位置
    train_images = 'C:/Users/ASUS/Desktop/train-images.idx3.ubyte'
    train_labels = 'C:/Users/ASUS/Desktop/train-labels.idx1.ubyte'
    test_images ='C:/Users/ASUS/Desktop/t10k-images.idx3.ubyte'
    test_labels = 'C:/Users/ASUS/Desktop/t10k-labels.idx1.ubyte'
    #此处是我们将转化后的数据集保存的位置
    save_train ='C:/Users/ASUS/Desktop/MNIST/train_images/'
    save_test ='C:/Users/ASUS/Desktop/MNIST/test_images/'
    
    if not os.path.exists(save_train):
        os.makedirs(save_train)
    if not os.path.exists(save_test):
        os.makedirs(save_test)
 
    trans(test_images, test_labels, save_test)
    trans(train_images, train_labels, save_train)

2.2 将图片按照标签分类到具体文件夹

文章参考链接:python实现根据文件名自动分类转移至不同的文件夹
注意:为了适合这个数据集和我的win11系统对代码进行了一点调整,由于数据很多如果只需要部分数据一定要将那些数据单独放在一个文件夹。

# 导入库
import os
import shutil

# 当前文件夹所在的路径,使用时需要进行修改
current_path = 'C:/Users/ASUS/Desktop/MNIST/test'
print('当前文件夹为:' + current_path)

# 读取该路径下的文件
filename_list = os.listdir(current_path)

# 建立文件夹并且进行转移
# 假设原图片名称 test_001_2.jpg
for filename in filename_list:
    name1, name2, name3 = filename.split('_')   # name1 = test  name2 = 001  name3 = 2.jpg
    name4, name5 = name3.split('.')             # name4 = 2  name5 = jpg
    if name5 == 'jpg' or name5 == 'png':
        try:
            os.mkdir(current_path+'/'+name4)
            print('成功建立文件夹:'+name4)
        except:
        	pass
        try:
            shutil.move(current_path+'/'+filename, current_path+'/'+name4[:])
            print(filename+'转移成功!')
        except Exception as e:
            print('文件 %s 转移失败' % filename)
            print('转移错误原因:' + e)

print('整理完毕!')

2.3 数据存在的缺陷

  1. 数据集内的图片数量很多,由于后面介绍的云端训练的限制,只能采用部分数据(本人采用的是1000张,大家可以自行增减数目)。

  2. 数据集为国外的数据集,很多数字写的跟我们不一样。如果想要更好的适用于我们国内的场景,可以对数据集进行手动的筛选。下面是他们写的数字2:

openmv控制电机,嵌入式硬件,python 可以看出跟我们的不一样,不过数据集中仍然存在跟常规书写的一样的,我们需要进行人为的筛选。

2.4 优化建议(核心)

分析发现,部分数字精度不高的原因主要是国外手写很随意,我们可以通过调整网络参数(如下)、人为筛选数据(如上)、增大数据集等方式进行优化。


二、模型训练

主要参考文章:通过云端自动生成openmv的神经网络模型,进行目标检测
!!!唯一不同的点是我图像参数设置的是灰度而不是上述文章的RGB。
下面是我模型训练时的参数设置(仅供参考):
openmv控制电机,嵌入式硬件,python
通过混淆矩阵可以看出,主要的错误在于数字2、6、8。我们可以通过查看识别错误的数字来分析可能的原因。


三、项目实现

!!!我们需要先将上述步骤中导出文件中的所有内容复制粘贴带OpenMV中自带的U盘中。然后将其中的.py文件名称改为main

1. 代码实现

本人修改后的完整代码展示如下,使用的是OpenMV IDE(官网下载):

# 数字识别后控制直流电机转速
from pyb import Pin, Timer
import sensor, image, time, os, tf, math, random, lcd, uos, gc

# 根据识别的数字输出不同占比的PWM波
def run(number):
    if inverse == True:
        ain1.low()
        ain2.high()
    else:
        ain1.high()
        ain2.low()
    ch1.pulse_width_percent(abs(number*10))

# 具体参数调整自行搜索
sensor.reset()                         # 初始化感光元件
sensor.set_pixformat(sensor.GRAYSCALE) # set_pixformat : 设置像素模式(GRAYSCALSE : 灰色; RGB565 : 彩色)
sensor.set_framesize(sensor.QQVGA2)    # set_framesize : 设置处理图像的大小
sensor.set_windowing((128, 160))       # set_windowing : 设置提取区域大小
sensor.skip_frames(time = 2000)        # skip_frames :跳过2000ms再读取图像
lcd.init()                             # 初始化lcd屏幕。


inverse = False                        # True : 电机反转  False : 电机正转
ain1 =  Pin('P1', Pin.OUT_PP)          # 引脚P1作为输出
ain2 =  Pin('P4', Pin.OUT_PP)          # 引脚P4作为输出
ain1.low()                             # P1初始化低电平
ain2.low()                             # P4初始化低电平
tim = Timer(2, freq = 1000)            # 采用定时器2,频率为1000Hz
ch1 = tim.channel(4, Timer.PWM, pin = Pin('P5'), pulse_width_percent = 100) # 输出通道1 配置PWM模式下的定时器(高电平有效) 端口为P5 初始占空比为100%
clock = time.clock()                   # 设置一个时钟用于追踪FPS

# 加载模型
try:
    net = tf.load("trained.tflite", load_to_fb=uos.stat('trained.tflite')[6] > (gc.mem_free() - (64*1024)))
except Exception as e:
    print(e)
    raise Exception('Failed to load "trained.tflite", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')')

# 加载标签
try:
    labels = [line.rstrip('\n') for line in open("labels.txt")]
except Exception as e:
    raise Exception('Failed to load "labels.txt", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')')

# 不断的进行运行
while(True):
    clock.tick()                                    # 更新时钟
    img = sensor.snapshot().binary([(0,64)])        # 抓取一张图像以灰度图显示
    lcd.display(img)                                # 拍照并显示图像
    for obj in net.classify(img, min_scale=1.0, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5):
        # 初始化最大值和标签
        max_num = -1
        max_index = -1
        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]))
            if predictions_list[i][1] > max_num:
                max_num =  predictions_list[i][1]
                max_index = int(predictions_list[i][0])
    run(max_index)
    print('该数字预测为:%d' % max_index)
    print('FPS为:', clock.fps())
    print('PWM波占空比为: %d%%' % (max_index*10))

2. 采用器件

使用的器件为OpenMV4 H7 Plus和L298N以及常用的直流电机关键是找到器件的引脚图,再进行简单的连线即可。
参考文章:【L298N驱动模块学习笔记】–openmv驱动
参考文章:【openmv】原理图 引脚图

2. 注意事项

上述代码中我用到了lcd屏幕,主要是为了方便离机操作。使用过程中,OpenMV的lcd初始化时会重置端口,所有我们在输出PWM波的时候一定不要发生引脚冲突。我们可以在OpenMV官网查看lcd用到的端口:
openmv控制电机,嵌入式硬件,python
可以看到上述用到的是P0、P2、P3、P6、P7和P8。所有我们输出PWM波时要避开这些端口。下面是OpenMV的PWM资源:
openmv控制电机,嵌入式硬件,python


总结

本人第一次自己做东西也是第一次使用python,所以代码和项目写的都很粗糙,只是简单的识别数字控制直流电机。我也是四处借鉴修改后写下的大小,这篇文章主要是为了给那些像我一样的小白们提供一点帮助,减少大家查找资料的时间。模型的缺陷以及改进方法上述中已经说明,如果我有写错或者大家有更好的方法欢迎大家告诉我,大家一起进步!文章来源地址https://www.toymoban.com/news/detail-621228.html

到了这里,关于OpenMV数字识别进而控制直流电机转速【小白篇】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32控制直流电机转向

    一、所需硬件模块 1.主控芯片:STM32F103C8T6 2.程序下载器:STLINK 3.电机:直流电机 4.电机驱动模块:L298N 二、模块介绍 1、主控芯片采用的是STM32系列的最小系统板,通过控制其引脚的输出进而实现对电机的控制; 2、STLINK下载器是用于烧录程序,其中的SWCLK、SWDLO、GND、3.3V引脚

    2024年02月07日
    浏览(35)
  • STM32PWM控制直流电机

    PWM介绍 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用 微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽 度的控制 PWM的原理: 假定定时器工作在向上计数 PWM 模式,且当 CNT=CCRx 时输出 1。那么就可以

    2024年02月08日
    浏览(47)
  • 【Arduino32】PWM控制直流电机速度

    震动传感器:1个 红黄绿LED灯:各一个 旋钮电位器:1个 直流电机:1个 1K电阻:1个 220欧电阻:3个 杜邦线:若干

    2024年02月07日
    浏览(37)
  • 单片机控制直流电机(风扇)电路详解

    单片机引脚为什么无法直接控制电机或风扇?         我们在使用单片机去控制+5V的直流电机或者散热风扇时,可能会有一种疑惑,51单片机的引脚电压为+5V,为什么不直接用单片机引脚去驱动电机或者风扇?         实际上单片机的控制引脚,不管是51单片机或者s

    2024年01月16日
    浏览(88)
  • 基于单片机串口控制直流电机调速

    一、系统方案 (2)本设计采用STC89C5单片机作为主控器,串口控制直流电机调速,串口助手发送1-8,改变电机速度,数码管显示对应速度。 二、硬件设计 原理图如下: 三、单片机软件设计 1、首先是系统初始化 TMOD=0x21;//定时器0工作方式1 ET1=0; SM0=0; SM1=1; REN=1; EA=1; ES=1; 2、数码管

    2024年02月12日
    浏览(46)
  • STM32第八课:PWM控制直流电机

            TB6612FNG是一款新型驱动器件,能独立双向控制2个直流电机,它具有很高的集成度,同时能提供足够的输出能力,运行性能和能耗方面也具有优势因此在集成化、小型化的电机控制系统中,它可以作为理想的电机驱动器件。                           

    2024年03月24日
    浏览(50)
  • 基于stm32的减速直流电机PID算法控制

    本例程采用了HAL库进行项目开发(主要使用软件CubexMX和keil5),文章末尾会有代码开源,欢迎各位对文章进行指正和探讨。         硬件组成:stm32f103c8t6最小系统板;0.96寸LED12864(I2C通讯模式);智能小车12v移动电源;25GA370直流减速电机(带霍尔编码器);JDY-31蓝牙模块

    2024年02月20日
    浏览(43)
  • STM32-微项目03-pwm控制直流电机运行

    一,项目目标 实现利用STM32F103C8T6+TB6612,输出不同占空比输出的PWM波,从而实现电机不同转速的运行、正反转的功能;    二、硬件涉及 1,STM32核心板 2,TB6612直流电机驱动模块 3,直流电机  三、硬件接线涉及 1,先看TB6612直流电机驱动模块: ①驱动模块是具备两路PWM输入

    2024年02月04日
    浏览(48)
  • 【正点原子】STM32电机应用控制学习笔记——2.直流无刷电机基础知识

    没有电刷,无换向器的电机,也称为无换向器电机。 主要是定子和转子,而直流有刷电机多的是换向器和电刷。 而直流有刷的定子是N和S的永磁体,而无刷是三个线圈饶阻。 直流有刷是定子是饶阻,无刷的定子是N和S的永磁体。两者的转子和定子恰好是相反的。也是他们最大

    2024年02月03日
    浏览(68)
  • 【 使用 Arduino 和 L293D 电机驱动器 IC 控制直流电机】

    如果你打算用直流电机建造一个机器人,那么你最终会了解到,如果你想让它朝某个方向移动,你需要同时控制电机的速度和方向。最好的方法之一是使用 L293D 电机驱动器 IC,因为它便宜、易于使用,并且有一点 PWM 支持,它可以控制速度和方向。这就是为什么在本教程中我

    2024年02月15日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包