ELF2开发板(飞凌嵌入式)部署yolov5s的自定义模型

ELF2开发板(飞凌嵌入式)部署yolov5s的自定义模型

本人将零基础教学自己训练的yolov5s模型部署于飞凌的elf2开发板,利用RKNN-Toolkit2对模型进行转化为rknn模型,在开发板上进行推理。

获得自定义训练得到的yolov5s pt模型

准备自定义数据集(博主用的是VOC数据集)

  • 数据集目录结构如下:
└─VOC2028:		自定义数据集
    ├─Annotations	存放的是数据集标签文件,xml格式
    ├─ImageSets		数据集的划分文件
    │  └─Main
    ├─JPEGImages	存放的是数据集图片
  • 分割数据集

在split_train_val.py文件路径下执行python3 split_train_val.py会得到一下目录结构:

└─VOC2028:		自定义数据集
    ├─Annotations	存放的是数据集标签文件,xml格式
    ├─ImageSets		数据集的划分文件
    │  └─Main test.txt
          └─test.txt
          └─train.txt
          └─val.txt
    ├─JPEGImages	存放的是数据集图片
    ├─split_train_val.py	分割数据集的py文件

split_train_val.py文件代码如下

# -*- coding: utf-8 -*-
"""
Author:dragonforward
简介:分训练集、验证集和测试集,按照 8:1:1 的比例来分,训练集8,验证集1,测试集1
"""
import os
import random
import argparse

parser = argparse.ArgumentParser()
# xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下
parser.add_argument('--xml_path', default='Annotations/', type=str, help='input xml label path')
# 数据集的划分,地址选择自己数据下的ImageSets/Main
parser.add_argument('--txt_path', default='ImageSets/Main/', type=str, help='output txt label path')
opt = parser.parse_args()

train_percent = 0.8  # 训练集所占比例
val_percent = 0.1    # 验证集所占比例
test_persent = 0.1   # 测试集所占比例

xmlfilepath = opt.xml_path
txtsavepath = opt.txt_path
total_xml = os.listdir(xmlfilepath)

if not os.path.exists(txtsavepath):
    os.makedirs(txtsavepath)

num = len(total_xml)  
list = list(range(num))

t_train = int(num * train_percent)  
t_val = int(num * val_percent)

train = random.sample(list, t_train)
num1 = len(train)
for i in range(num1):
    list.remove(train[i])


val_test = [i for i in list if not i in train]
val = random.sample(val_test, t_val)
num2 = len(val)
for i in range(num2):
    list.remove(val[i])


file_train = open(txtsavepath + '/train.txt', 'w')
file_val = open(txtsavepath + '/val.txt', 'w')
file_test = open(txtsavepath + '/test.txt', 'w')

for i in train:
    name = total_xml[i][:-4] + '\n'
    file_train.write(name)

for i in val:
    name = total_xml[i][:-4] + '\n'
    file_val.write(name)    

for i in list:
    name = total_xml[i][:-4] + '\n'
    file_test.write(name)
    
    
file_train.close()
file_val.close()
file_test.close()
  • voc转label得到label文件

目录结构如下:

└─VOC2028:		自定义数据集
    ├─Annotations	存放的是数据集标签文件,xml格式
    ├─ImageSets		数据集的划分文件
    │  └─Main
    ├─JPEGImages	存放的是数据集图片
    └─labels		yolov5将此文件夹当作训练的标注文件夹
└─voc_label.py

voc_label.py文件代码如下

# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os

sets = ['train', 'val', 'test']  # 如果你的Main文件夹没有test.txt,就删掉'test'
classes = ["hat", "people"]   # 改成自己的类别,VOC数据集有以下20类别
# classes = ["brickwork", "coil","rebar"]   # 改成自己的类别,VOC数据集有以下20类别
# classes = ["aeroplane", 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog',
#            'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']  # class names
# abs_path = os.getcwd() /root/yolov5/data/voc_label.py 
abs_path = '/root/yolov5/data/'

def convert(size, box):
    dw = 1. / (size[0])
    dh = 1. / (size[1])
    x = (box[0] + box[1]) / 2.0 - 1
    y = (box[2] + box[3]) / 2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return x, y, w, h


def convert_annotation(image_id):
    in_file = open(abs_path + '/VOC2028/Annotations/%s.xml' % (image_id), encoding='UTF-8')
    out_file = open(abs_path + '/VOC2028/labels/%s.txt' % (image_id), 'w')
    tree = ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)
    for obj in root.iter('object'):
        difficult = obj.find('difficult').text
        # difficult = obj.find('Difficult').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult) == 1:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
             float(xmlbox.find('ymax').text))
        b1, b2, b3, b4 = b
        # 标注越界修正
        if b2 > w:
            b2 = w
        if b4 > h:
            b4 = h
        b = (b1, b2, b3, b4)
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')


for image_set in sets:
    if not os.path.exists(abs_path + '/VOC2028/labels/'):
        os.makedirs(abs_path + '/VOC2028/labels/')

    image_ids = open(abs_path + '/VOC2028/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
    list_file = open(abs_path + '/VOC2028/%s.txt' % (image_set), 'w')
    for image_id in image_ids:
        list_file.write(abs_path + '/VOC2028/JPEGImages/%s.jpg\n' % (image_id))  # 要么自己补全路径,只写一半可能会报错
        convert_annotation(image_id)
    list_file.close()


picture 1

图1 文件列表图

训练模型

  • 配置环境
git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt
pip install onnx
  • 下载预训练权重(博主尝试了v7.0的和v6.0的pt都可以)
https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt

picture 0

图2 官方模型pt图
  • 训练(博主使用的是学校的集群进行训练)
python3 train.py --weights weights/yolov5s.pt --cfg models/yolov5s.yaml --data data/safthat.yaml --epochs 150 --batch-size 16 --multi-scale --device 0 

picture 2

图3 模型训练
python3 detect.py --source /root/yolov5/data/images/000000.jpg --weights /root/yolov5/runs/train/exp13/weights/best.pt --conf-thres 0.25

picture 3

图4 安全帽模型测试

自定义yolov5s pt模型进行转换(干货)

下载瑞芯微官方修改过的yolov5以及环境搭建

本人使用的是conda进行的处理,首先先拉取仓库,然后安装conda(可以参考该文章),我使用的是python3.8。

具体执行:

git clone https://github.com/airockchip/yolov5.git
(www) C:\Users\wxw>cd C:\Users\wxw\PycharmProjects\yolov5
在conda终端配置镜像源
conda config --remove-key channels
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/cloud/pytorch/
conda config --set show_channel_urls yes
pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/web/simple
(www) C:\Users\wxw\PycharmProjects\yolov5>pip install -r requirements.txt

输出结果成功安装:

Looking in indexes: https://mirrors.ustc.edu.cn/pypi/web/simple
Collecting gitpython (from -r requirements.txt (line 5))
  Using cached https://mirrors.ustc.edu.cn/pypi/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl (207 kB)
Collecting ipython (from -r requirements.txt (line 6))
  Using cached https://mirrors.ustc.edu.cn/pypi/packages/8d/97/8fe103906cd81bc42d3b0175b5534a9f67dccae47d6451131cf8d0d70bb2/ipython-8.12.3-py3-none-any.whl (798 kB)
Collecting matplotlib>=3.2.2 (from -r requirements.txt (line 7))
  Using cached https://mirrors.ustc.edu.cn/pypi/packages/16/51/58b0b9de42fe1e665736d9286f88b5f1556a0e22bed8a71f468231761083/matplotlib-3.7.5-cp38-cp38-win_amd64.whl (7.5 MB)
<think>好的,用户想用ELF2开发板控制直流电机,需要相关的教程、示例代码和硬件连接信息。首先,我需要确认ELF2开发板的具体型号和功能,是否有相关的官方文档或者社区支持。根据提供的引用,用户之前可能接触过BLDC电机控制,比如esp_sensorless_bldc_control方案和MCSPTE1AK344套件,但这次是直流电机,可能需要不同的控制方法。 直流电机通常使用PWM信号控制速度,方向则需要H桥电路。所以硬件连接部分可能需要电机驱动模块如L298N或TB6612ELF2的GPIO输出PWM,同时控制方向引脚。软件方面需要配置PWM模块,编写控制逻辑。 用户提到的ELF2开发板,可能基于某个微控制器,比如ESP32或者STM32,需要确定具体型号以查找对应的库和示例代码。假设ELF2使用ESP32,那么可以使用Arduino IDE或ESP-IDF来开发。示例代码可能包括设置PWM参数,控制GPIO高低电平来改变电机方向。 另外,需要确保用户了解安全措施,比如添加保护二极管、避免电源反接、使用独立电源为电机供电,防止电流倒灌损坏开发板。还可能涉及电流检测和过流保护,但基础控制可能不需要这些。 用户可能需要基础教程,所以步骤需要详细,从硬件连接到代码编写,再到测试。可能的问题包括电机不转、转速不稳定,需要排查电路连接和代码配置。 最后,生成相关问题,帮助用户深入,比如如何调速、控制多个电机、加入传感器反馈等。确保回答结构清晰,分步骤说明,引用相关参考资料,但根据用户提供的引用,可能没有直接相关的,所以主要依赖通用知识和假设ELF2的功能。</think>### ELF2开发板控制直流电机技术指南 ### 一、硬件连接 1. **核心组件** - ELF2开发板 - 直流电机(额定电压需匹配开发板输出) - 电机驱动模块(推荐L298N或TB6612FNG H桥驱动) - 外部独立电源(建议电压与电机额定电压一致) 2. **接线步骤** ```text ELF2 GPIO口 → 驱动模块控制端 │ │ PWM引脚 → 驱动模块ENA/ENB(速度控制) │方向引脚 → 驱动模块IN1/IN2(正反转控制) │ └─驱动模块输出端 → 直流电机两极 ``` > 注意:电机电源必须与开发板电源隔离,建议使用独立供电方案 ### 二、软件配置 1. **开发环境** - 推荐使用Arduino IDE或PlatformIO - 安装对应硬件支持包(如ESP32开发包) 2. **基础控制代码示例** ```cpp // 引脚定义 #define MOTOR_PWM GPIO_NUM_12 #define MOTOR_IN1 GPIO_NUM_14 #define MOTOR_IN2 GPIO_NUM_27 // PWM参数配置 const int freq = 5000; const int resolution = 8; void setup() { // 初始化GPIO pinMode(MOTOR_IN1, OUTPUT); pinMode(MOTOR_IN2, OUTPUT); // 配置PWM通道 ledcSetup(0, freq, resolution); ledcAttachPin(MOTOR_PWM, 0); } void setMotor(int speed, bool direction) { digitalWrite(MOTOR_IN1, direction); digitalWrite(MOTOR_IN2, !direction); ledcWrite(0, abs(speed)); // 速度范围0-255 } void loop() { // 正向50%转速 setMotor(128, true); delay(2000); // 停止 setMotor(0, true); delay(1000); // 反向75%转速 setMotor(191, false); delay(2000); } ``` ### 三、进阶功能实现 1. **闭环控制** - 集成编码器反馈: ```cpp // 编码器脉冲计数 volatile long encoderCount = 0; void IRAM_ATTR encoderISR() { encoderCount++; } ``` - PID调速算法: $$u(t) = K_p e(t) + K_i \int_0^t e(\tau)d\tau + K_d \frac{de(t)}{dt}$$ 2. **保护机制** - 过流检测:通过ADC采样电流传感器信号 - 软件限流:限制PWM占空比最大值 - 温度监控:读取板载温度传感器数据 ### 四、关键参数配置表 | 参数项 | 推荐值 | 作用说明 | |----------------|-------------|-----------------------| | PWM频率 | 5-20kHz | 平衡噪声与效率 | | 死区时间 | 1-2μs | 防止H桥直通短路 | | 采样周期 | 10ms | 闭环控制更新频率 | | 最大占空比 | 80% | 电机安全运行范围 | ### 五、调试技巧 1. **基础验证步骤** - 先测试GPIO电平输出是否正常 - 用万用表验证PWM波形 - 空载测试电机响应 2. **常见问题处理** - 电机抖动:检查电源功率是否充足 - 转速不稳:增加滤波电容(推荐100-470μF) - 方向异常:检查IN1/IN2逻辑组合
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖小新新

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值