- 2024-10-14
-
回复了主题帖:
【2024 DigiKey 创意大赛】Dodging Rover 避障小车
四、作品源码 基于ESP32采用Arduino开发,编译通过。
下载代码如下 https://download.eeworld.com.cn/detail/%E5%8C%97%E6%96%B9/634565
五、作品功能演示视频
[localvideo]adbb1bc4f0e9bcf0e4275759edd18af6[/localvideo]
补充:
本次提交的涉及文档doc格式如下
-
上传了资料:
Dodging Rover视频
- 2024-10-10
-
上传了资料:
DodgingRover
- 2024-09-30
-
发表了主题帖:
【2024 DigiKey 创意大赛】Dodging Rover 避障小车
Dodging Rover 避障小车
一、作品简介
DodgingRover是室内避障小车,通过60GHz微波雷达探测周边的障碍并作出探测和转向的选择。扩展周围气体环境条件的采集实现智能提示。
物料清单:
ESP32-C6-DevKitC-1 是一款入门级开发板,使用带有 8 MB SPI flash 的通用型模组 ESP32-C6-WROOM-1(U)。该款开发板具备完整的 Wi-Fi、低功耗蓝牙、Zigbee 及 Thread 功能;
60GHz雷达传感器 60GHz mmWave Sensor;
气体传感器Adafruit SGP30 TVOC/eCO2 Gas Sensor;
电机控制拓展板MKR Motor Carrier;
5V电池仓;
直流电机控制运动平台。
二、系统框图
直流电机控制运动平台。DodgingRover通过多样的传感器数据采集,实现高精度的距离采样,动态控制低成本直流电机实现良好的动力控制。
灵活的软件开发平台可以使用Arduino实现快速部署和开发。
硬件以ESP32C6为核心,实现UART和I2C数据的通讯实现多样数据采集,并实现实时控制。框图如下。
三、各部分功能说明
核心ESP32C6实现数据采集,避障策略,以及电机控制的综合性能。见图。
周边传感器,包括60GHz雷达传感器和气体传感器实现数据采集。
以下实现雷达读取心率和呼吸频率,使用UART1串口1实现,连接4和5引脚,
SG30气体质量传感器的读数,使用I2C读取引脚,连接22和23引脚
直流电机控制运动平台,实现运动平台的前后左右移动。这个电机驱动板使用MKR motor carrier扩展版,是通过i2c进行命令传输和控制的。可以按照上面的逻辑框图综合实现。
四、作品源码
https://download.eeworld.com.cn/detail/%E5%8C%97%E6%96%B9/634565
五、作品功能演示视频
见帖子补充内容
六、项目总结
雷达传感器的引入,可以使得避障小车具有更好的视野和控制平台,这样给室内定位和避障提供了更多的可能性和实现效果。
七、其他
本项目预留视觉识别避障的扩展,可以实现雷达组合视觉摄像头的方案。
补充内容 (2024-10-10 16:38): 四、作品源码 基于ESP32采用Arduino开发,编译通过。下载代码如下 https://download.eeworld.com.cn/detail/%E5%8C%97%E6%96%B9/634565 补充内容 (2024-10-14 09:01): 五、作品功能演示视频 https://download.eeworld.com.cn/detail/%E5%8C%97%E6%96%B9/634580 已经按照压缩格式上传到下载中心 补充内容 (2024-10-14 09:11): 五、作品功能演示视频 [localvideo]adbb1bc4f0e9bcf0e4275759edd18af6[/localvideo] 补充: 本次提交的涉及文档doc格式如下
- 2024-08-08
-
发表了主题帖:
【2024 DigiKey 创意大赛】ESP32-C6和雷达传感器,气体传感器开箱
1.感谢EEWORLD和Digikey能够入选”2024 DigiKey 创意大赛“。下订单后光速到货,打开标准包装纸箱,三个选中的物料并排如下
2 拆开包装箱和密封袋,物料如下,依次为ESP32-C6,气体传感器和雷达传感器
ESP32-C6,如下。参考资料为ESP32-C6-DevKitC-1 v1.1 - - — esp-dev-kits latest documentation (espressif.com) ESP32-C6-DevKitC-1 v1.2 - - — esp-dev-kits latest 文档 (espressif.com)
ESP32-C6-DevKitC-1 是一款入门级开发板,使用带有 8 MB SPI flash 的通用型模组 ESP32-C6-WROOM-1(U)。该款开发板具备完整的 Wi-Fi、低功耗蓝牙、Zigbee 及 Thread 功能。
板上模组大部分管脚均已引出至两侧排针,开发人员可根据实际需求,轻松通过跳线连接多种外围设备,同时也可将开发板插在面包板上使用。
气体传感器SGP30 Overview | Adafruit SGP30 TVOC/eCO2 Gas Sensor | Adafruit Learning System 通过i2c接口访问数据
和60GHz雷达传感器 60GHz mmWave Static Breathing and Heartbeat | Seeed Studio Wiki
3 后续围绕这个开发工具,进行项目开发
- 2024-08-06
-
回复了主题帖:
锁相环
TTTQ10 发表于 2024-8-6 13:42
并网逆变器中使用的dq锁相环
alpha,beta和dq变换有关,和PLL关系不大。
旋转角变换成静止角度,使用sin cos具有对称性,使用atan只是理论上可行。
-
回复了主题帖:
锁相环
确定是在电子设计中用的PLL吗?
用在并网逆变器等高压的设计中的,和电子电路设计没什么直接关系。
猜测和d-q变换的原理有关更多一些
- 2024-07-23
-
回复了主题帖:
【EEWorld邀你来拆解】正昀电池管理系统解析
freebsder 发表于 2024-6-21 09:53
为何?现在的理念是怎样的可否介绍下?
more compact and less parts
- 2024-07-15
-
回复了主题帖:
EEWorld邀你来拆解——汽车激光雷达拆起来
激光雷达的核心是算法,包括激光测距的算法,以及多线雷达的点云构建模式。
北醒雷达是典型的后期之秀,把众多前浪拍在沙滩上,还给拍死的那种。
本次继续申请拆解,内容应该是以介绍和文献说明为主,结构设计以及电气设计应该都不会很复杂。
- 2024-06-17
-
发表了主题帖:
【EEWorld邀你来拆解】正昀电池管理系统解析
本帖最后由 北方 于 2024-6-20 11:16 编辑
1 对照学习BMS
电池管理系统的主要功能就是电池检测和电压均衡,这个拆解的BMS系统,功能比较全,应该是一个主控板,包括了物联网,电压管理,CAN通讯等多种功能,采用的芯片均为TI和ADI大厂产品。看来那时候国产芯片替代还没有上规模了。对比TI的这BQ756506和BQ79616的功能逻辑图,这个也是类似的逻辑
因为在BQ7xxxx芯片内部完成了ADC采样和内置电压均衡,所以MCU的工作就简单很多了。但是,这个正昀电池管理系统基本上都是功能独立的元件,那么主要的控制逻辑就在MCU中实现了。所以,其中的软件管理是非常重要的,也具有很大难度的。单从硬件拆解看,仅仅能猜测其功能和逻辑设计。
前一个帖子说明了因为绝缘漆基本上不能看清楚芯片的丝印。不过,因为同类型芯片比较多,因为PCB表面不平整,所以,就有绝缘漆层不厚的情况,大多数都查出来了。
这样就可以看看这个2015年出厂的BMS是如何设计的。
2 主控芯片
主控芯片是NXP LPC1178.LPC1778FBD144_ARM Cortex-M3_32位MCU | NXP 半导体
LPC1778是一种适合嵌入式应用的Cortex-M3微控制器,具有高集成度和低功耗的特点,运行频率为120 MHz。功能包括512 kB闪存、96 kB数据存储器、以太网、USB 2.0设备/主机/OTG、8通道DMA控制器、5个UART、2个CAN通道、3个SSP/SPI、3个I2C、I2S、8通道12位ADC、10位DAC、QEI、SD/MMC、电机控制PWM、4个通用定时器、6输出通用PWM、带独立电池供电的超低功耗实时时钟以及最多109个通用I/O引脚。
这个芯片可以独立引出109个引脚,所以这里基本上都用到了,实现了UART连接, CAN通讯,ADC采样,电池均压电路管理等功能。
这个芯片最早在2016年就已经批量生产了,现在看来还在正常供货,也是一个长寿产品了。
3 SIM800A无线网卡
SIM800A是芯讯通的2G GSM/GPRS模组,SIM800A工作频率为GSM/GPRS 900/1800MHz,可以低功耗实现语音、SMS和数据信息的传输。SIM800A尺寸为24*24*3mm,能适用于各种紧凑型产品设计需求。现在很多地方,2G已经停止服务了。数据参数如下,也就是最大14.4kbps的数据通道。
•GPRS class 12:最大85.6 kbps(下行速率)
•支持PBCCH
•Coding schemes CS 1, 2, 3, 4
•PPP-stack
•CSD达14.4 kbps
•USSD
•非透传
这个管理比较简单,就是通过标准的AT指令实现。具体参考SIM800A (simcom.com)。
而且直接采用PCB天线,现在应该有更多的选择,并且支持到4G,甚至5G模块也已经出境了。
4 CAN控制器MCP2515 | Microchip Technology和数据隔离器ADUM1201数据手册和产品信息 | Analog Devices
这个BMS有一个重要的功能就是CAN通讯接口。CAN协议通常在工业中尤其是汽车上,广泛应用,各个设备都在CAN总线上,自动识别哪个设备发送,管理简单可靠。这个芯片是SPI控制的CAN控制器。上面提到的LPC1778已经自动有两路CAN可以直接控制传输了,只是增加数据隔离和电平转换就可以了。但是这个方案还是采用了SPI控制的CAN控制器,应该是可以多提供一个CAN接口。在上述的端口可以看到,有CAN1,CAN2,CAN3至少3组CAN通道,所以增加一个CAN控制器是可以理解的。控制逻辑图如下
连接在CAN网络的每个设备都在侦听网路,发送和接受对应的传输信息
对应于CAN总线,工作电压是在很大的范围波动的,想想一下汽车启动时车内灯都突然暗一下的场景吧。使用数字隔离器ADUM1201。ADuM1201是采用1/1通道方向性的双通道数字隔离器,其基于ADI公司iCoupler®技术。 这些隔离器件将高速CMOS与单芯片变压器技术融为一体,具有优于光耦合器等替代器件的出色性能特征。适合用在
尺寸至关重要的多通道隔离
SPI接口/数据转换器隔离
RS-232/RS-422/RS-485收发器隔离
数字现场总线隔离
混合动力汽车、电池监控器和电机驱动
逻辑图如下
5 BMS平衡电阻的控制LM5110 数据表、产品信息和支持 | 德州仪器 TI.com.cn和AO4482 datasheet(1/6 Pages) AOSMD | 100V N-Channel MOSFET (alldatasheet.com)
在不均衡电池充电电压下,驱动电池和电压进行对应的BMS控制,使用TI LM510驱动器,实现双通道驱动,根据官网,这个产品已经被更新的规格替代了。
驱动控制的时AO4482的100V MOSFET
6 模拟采样ADUC7039数据手册和产品信息 | Analog Devices和数据采样ADUM2401数据手册和产品信息 | Analog Devices,SN74LVC07A 数据表、产品信息和支持 | 德州仪器 TI.com.cn
根据这个BMS标识,还包括电池电流Ibat的采样,和DI数字输入的功能。其中数字放大器时用于车用电池的专用芯片,功能如下
高精度ADC
双通道、同步采样、16位Σ-Δ型 ADC
可编程ADC吞吐量:10 Hz至1 kHz
片内5 ppm/°C基准电压源
电流通道
全差分、缓冲输入
可编程增益
ADC输入范围:−200 mV至+300 mV
数字比较器,内置电流累加器功能
这个用来捕捉电池的电流,
对于数据输入,先使用数据隔离器ADUM2401,保证点评稳定,然后使用数据缓冲器SN74LVC07A,准确记录输入的数据,定定期从内存读取。
7 其他
这个产品; 还有专门的电路板供电回路的DC/DC直流变换器,使用的是UCC2813,但是现在已经升级到UCC3813。参加UCCx813-x Low-Power Economy BiCMOS Current-Mode PWM datasheet (Rev. F) (ti.com.cn)
整个开发板从现在的角度看,而是使用了大量的国际大厂的产品,而且,近10年了,这些产品多数仍然还在供应。保持了 极强的供货能力和生命周期。
另外,整个电路板使用了大量的电感和信号变压器,绕线均匀。绝缘封闭封闭很好,也是品质优良的产品。
这样,从现在的角度看,这个电路板的集成能力,以及设计理念已经落后了。
但是从制造工艺和软件开发能力看,确实hai是有一定水平的。
不过,现在已经有了摩托车,那么谁还会去自行车。
- 2024-06-14
-
发表了主题帖:
【EEWorld邀你来拆解】正昀电池管理系统
本帖最后由 北方 于 2024-6-14 21:18 编辑
【EEWorld邀你来拆解】正昀电池管理系统
1 概述
再次入选EEWorld邀你来拆解——好久不见,咱们继续拆起来! - 电源技术 - 电子工程世界-论坛,这次拆解的是BMS电池管理系统。
按说,BMS本身是一个持续的概念,对于电池均衡充电的需求一直存在。这个是因为无论任何蓄电池,单体电压都是很低的。这个数据是由于电化学反应中,电极不同元素之间的能级决定的。以铅酸电池为例,单体电压在2.0V这个数量级,对于220V直流就需要100个左右的单体电池。提高电压唯一的办法就是串联,而串联的最大问题就是柿子专拣软的捏,耐压最差的那个单体承受的压力最大,这样单个单元的损坏,就意味者整体的报废。
这个问题在以前不突出,是因为围绕汽车的电池管理是从12V开始的,这样单体数少。但是,现在这个数值不断提升,现在我朝的电动车卷王们的最新的目标是800V,那么BMS就是核心竞争力。
2 BMS概念和正昀电池管理系统
这次拆解的BMS正昀电池管理系统是已经使用过的,应该不是最新的技术,但是原理大差不差,都是一样的。具体前面已经有大拿科普过BMS了,主要的功能分两部分,主动管理,就是及时发现串联电池单元串的不均衡端电压,采取措施均衡起来。这个措施比较多,最直接的就是并一串均压电阻,选择性接入电路,还有设置一次性熔断器单元,当这个电池单元不行了,直接短路,这样虽然少了一个,但是因为电池数量大,每个新增的电压增量不大,可以持续运行。还有被动管理,就是涉及过压保护,过流保护,超温保护等等。
摘抄一小段:
BMS(battery management system),是电动汽车不可或缺的重要部件,是管理和监控动力电池的中枢,管理、维护、监控电池各个模块,肩负着防止电池过充过放电、延长电池使用寿命、帮助电池正常运行的重任。电池管理系统(BMS)是连接车载电池和电动车的重要纽带,它主要的功能包括:电池物理参数实时监测、电池状态估计、在线诊断与预警、充放电与预充控制均衡管理、热管理等等。以上哪个功能实现不好,都会让电池出现致命的危害。
详细参考一下CSDN,认知BMS电池管理系统,看这一篇就够了!_大三电与小三电分别是什么-CSDN博客
正昀新能源sunevtech没有找到公司网站,看起来像是闷头干活挣钱的。所以,没有参考资料,只好盲拆。
3 边拆边解
3.1 外壳拆解
整体是全金属外壳,厚度大概0.8mm,足够强度,也够分量,看来是给汽车配套的,不搞轻量化设计。标注清晰规范。
标准的产品还包括一个可以拆的射频天线,粘在顶部正中,
两侧各有2个螺丝,再加上顶部一个,拆下来就可以
外观有三组插接头,规格不大一样,而且最右侧的没有全部引出引脚,
拆开的天线,原来直接用的一个倒U型的PCB板,应该是MHz级别的频率。
3.2 内部PCB拆一下
移去顶盖,这个由两部分组成,顶部一个看起来是射频板,下面的是主板,
移去上部射频板的螺丝,拆了,
侧面还有一个3x2插针,用导热硅胶封住了,应该是固定粘接的作用,稍微用力可以拔下来,
移去顶部射频板
露出主板,
注意到这里的螺丝都是带弹簧的防脱螺丝,
移去主板,下面还衬着绝缘纸,因为外壳是金属的,这样也是双保险
3.3 射频板
射频板的背面很简洁,就是一些测试点
正面可以发现有物联网SIM卡固定槽,按着黄色的俺就就可以弹出,
这个SIM800A模块是一个标准的GSM/GPRS模组,IM800A工作频率为GSM/GPRS 900/1800MHz,可以低功耗实现语音、SMS和数据信息的传输。SIM800A尺寸为24*24*3mm,能适用于各种紧凑型产品设计需求。这个是用AT命令,通过串口控制。具体参数参见SIM800A (simcom.com)
3.4 主板
主控板制版时整体涂了绝缘漆,所以,基本上绝缘漆涂上的地方,就完全看不清丝印,这样拆解分析就完全靠猜了。
核心主控芯片的漆层薄,大致看出来是NXP LPC系列产品,这个是通用型MCU,如果是用在汽车上。那么不得不说,这个还是省料了。因为车规主要有两点,一个是工作温度提高了大致105度的样子,另一个是内核设计会有防误考虑,如双核自动切换等,最主要的是需要交费通过车规试验。所以车规MCU一定是贵了不少的。
比较有意思的是这个电容,看起来是超级电容,通常是用在掉电保持的情况下,一般坚持数十秒,这个应该是提升性能和安全性来用的
比较考验质量的是功率元件,这几个功率电感应该是共轭电感和变压器,线径粗绕线均匀,应该是品质比较高的产品。这个在BMS性能上是有很大助力的。
主控板的反面,基本上是正面排不下的元件,分一部分到反面来,功能应该统一起来分析。
4 小结和后续计划
从这个拆解看,做工很好,而且用料实在,应该工作环境是振动环境,所以采取了相应的措施。
因为不少元器件的丝印看不清楚,所以分析电路就需要沿线猜元件,随后继续分析。整体看起来还是采用了电阻均压的原理,用通用MCU来实现BMS软件的算法。
现在,已经有专门的BMS芯片,可以支持不少于48串电池的BMS管理,可以明显简化编程,简化电路设计。这个主控板还有CAN接口,应该是纳入车联网中,实现高级数据采样和控制。
不过,这个设计中没有发现热管理的设计,这样BMS的发热是确定的,这个设计采用的是自然通风散热的模式,应该总体功率不能很大,应该是早期电动车EV的配套产品。
-
回复了主题帖:
【AI挑战营第三站】在Luckfox Pico上部署MNIST数字识别
Jacktang 发表于 2024-6-14 07:20
会不会因为模型的大小和复杂性有硬件限制?
确实是这样的。
通常工业化的模型最小的要4-5M左右,如谷歌的mobileNet v2,这样的数据吞吐和计算量很大,因此需要压缩。
通常是把参数的浮点数改为整数,这样能压缩2-4倍,其他的结构优化等需要更强大的优化能力。
这个MNIST效果不错,能达到20fps,精度下降很多,在40%-50%左右,但是已经能够识别出来了。
就是很成功了
- 2024-06-12
-
发表了主题帖:
【AI挑战营第三站】在Luckfox Pico上部署MNIST数字识别
本帖最后由 北方 于 2024-6-12 22:25 编辑
在Luckfox Pico上部署MNIST数字识别
1 概述
在完成第一站和第二站的任务后,具备在Luckfox上部署AI模型的条件了。参考,
#AI挑战营第一站#Pytorch 安装和MNIST识别 - Linux与安卓 - 电子工程世界-论坛 (eeworld.com.cn)
【AI挑战营第二站】MNIST转RKNN格式并算法工程化部署打包成SDK - Linux与安卓 - 电子工程世界-论坛 (eeworld.com.cn)
2 更新firmware
在刚拿到开发板的时候,就可以用adb连接,并读取文件系统,但是连接CSI摄像头后,无法按照手册的说明读取视频。根据下述wiki的资料可知,
CSI Camera | LUCKFOX WIKI
出厂的是一个测试版映像,只能测试开发板的正常工作,具体实现什么功能都需要自行编译系统。可选的有buildroot和ubuntu,其中ubuntu会更大些,需要在SD卡上加载,而buildroot精简很多,可以适用menuconfig定义,然后自行编译,所以,选择用buildroot来实现,直接写入SPI内存中。
根据手册,需要从github上clone源代码,配置交叉编译工具,使用脚本编译。因为gitee也同步了源码,所以,从gitee上可以快速搞定,避免了github的长久期待。
因为交叉编译工具只是适用于Linux系统,所以,直接在ubuntu上做这个步骤更便捷,否则就需要WSL或者虚拟机了。
下面是编译的过程,在一个老爷笔记本上,大概搞了4个小时,整个过程只是出现一些warning,非常顺畅。丝滑。
编译成果如下图,并提示build输出的路径。
进入目录,生成下述文件,其中需要写入的只有一个文件,就是uboot.img
其实,通过云盘也提供了一个可以直接写入的映像,可以下载后解压,看如下,和上面的其实是一回事
按着Boot键加电,就可以找到这个开发板,如Fuzhou Rockchip.... 所示,
然后适用upgrade_tool这个工具下载到Luchfox开发板上,upgrade_tool也是需要下载安装的,只适合Linux系统
升级成功
这时搜索一下连接的网口,发现用172.32.0.93,连不上这个开发板了。
这个花了很长时间,最后发现这个是Luchfox pico pro,网口被配置成另一个192.168.10.x起手的网址了。需要用RNDS来连接usb口虚拟的网口,才可以继续用这个网址连接。
虽然没有实际适用,在windows实现上述功能需要使用另一个工具,
不再重复,直接查上面的wiki就可以。
3 实现视频流捕捉
连接好视频摄像头,注意luchfox pico pro的连接和普通pico是不同的,使用可以直接捕捉视频流的VLC,
选择rtsp://172.32.0.93的第0个通道的实时视频,显示如下,花花草草
另外可以用用ssh连接,用户名root,密码luckfox,使用MobaXterm可以用GUI模式,这样直观很多,
上传文件,也可以用scp命令行命令,
同样,adb也可以,先搜索设备,只有一个就用adb shell就可以。这个adb是android device连接工具,如果装了android studio就自带,否则就需要单独下载后解压使用,
在这个目录中找到rkipc.ini,这个是CSI摄像头连接成功的意思,原来的出厂测试版是没有的
使用adb push可以上传文件
这样具备了视频识别MNIST的条件了。
4 调用SDK实现基于视频流的MNIST数字识别
4.1如前所述,首先需要训练除自己的AI模型,然后转换成公用ONNX格式,再用专业工具压缩后转换成rknn格式,这个压缩后参数都整数化,识别精度都有一定的损失。
这个代码是用c语言编写的,视频的数据读取是实用的opencv库,这里实用lib的方式编译的
void *data = RK_MPI_MB_Handle2VirAddr(stVpssFrame.stVFrame.pMbBlk);
cv::Mat frame(height,width,CV_8UC3,data);
读取的mat矩阵数据,在推理命令下读取输出,这个就是前面编译的sdk
inference_mnist_model(&rknn_app_ctx, sub_pics[i], detect_results);
总体来说,上面的推理命令,就是实用自带的AI数据处理API实现对应的高强度卷积计算,输出结果,对照选择数字的结果。
这个是基于yolo8范例代码更改的,其他的模型,都还是用这个开发的编程顺序实现的,不同的是采用的model模型参数。
这样,通过对于不同模型的计算,代码变化几乎不大,但是通过分离训练的模型,就可以实现多种功能。
4.2 编译后直接使用可执行文件,结果文件中断了,
这是需要用RkLunch-stop.,sh先停止启动的自动调用摄像头,注意其中的小写和大写字母,
再启动代码,就显示连续识别的输出命令行,
输出效果可以看到,不够标准的2识别为3
不够标准的3识别为5,
这次识别正确,手写比较规范的3,字体模糊一些也没有关系。而且识别速度很快,可以达到21fps,就是连续视频30fps,基本上不太讲究的话,可以实时识别数据。
5 小结
经过这个过程,可以发现MNIST可以比较实用地实现数字识别功能,速度也很可以。中间需要注意,MNIST模型一般是需要经过压缩的,识别率明显不如测试的时候,普遍置信度再50%作业,而训练时已经超过90%,在第一站的训练,实际是99%。看起来数据很差,但是比较规范的书写是可以完美读出。
这个是一个偏向实用的,均衡性价比和功耗的平衡选择。
- 2024-06-06
-
回复了主题帖:
【名单公布】EEWord邀你来拆解——汽车BMS(好久不见,咱们继续拆起来!)
已确认
- 2024-05-30
-
回复了主题帖:
EEWorld邀你来拆解——好久不见,咱们继续拆起来!
报名拆解:任意BMS系统
理由:
BMS系统在原来航电模型3C充电器中就一直使用,对每个3.7V的电池包均衡充电,最终输出电压11.4V。
这次的BMS系统拆解更准确的是不是应该理解为针对48V以上电动汽车充电桩的BMS管理系统,这个BMS系统加上AC/DC变换系统就构成了充电桩的主体。设计均衡充电和电池保护两大功能,TI及ADI等都有专门的集成BMS系统,最高支持到48V,12个电池串接。这次拆解都是回收的产品,那么大致应该就是定位到底采用的是哪个大厂的BMS方案,估计新出的BMS系统国产的应该快上位了。
- 2024-05-16
-
回复了主题帖:
【AI挑战营第二站】MNIST转RKNN格式并算法工程化部署打包成SDK
freebsder 发表于 2024-5-11 17:26
load_onnx,看来也是用onnx做交换了。
是的,都是先弄成onnx,这个比较方便了。
- 2024-05-10
-
发表了主题帖:
【AI挑战营第二站】MNIST转RKNN格式并算法工程化部署打包成SDK
1 RKNN简述
RKNN内部逻辑应该是纯数理原理,对于开发者来说,简单理解,就是压缩深度学习的模型,并剪裁后,适配到开发板。这个过程并不容易,需要强大的开发工具支持,并且,必然会遇到各种兼容问题。
解决的方法就是设置一个虚拟环境,如果搞砸了直接重新删除,再来一次。本帖子所花时间远大于第一站。
2 安装环境
首先还是要创建虚拟环境,这里没有用conda,那个太大了,用venv就足够的。
python -m venv mnist
然后就是直接下载开发代码库,需要两个,使用git命令就好了
git clone https://github.com/airockchip/rknn-toolkit2.git --depth 1
git clone https://github.com/airockchip/rknn_model_zoo.git --depth 1
然后,进去第一个库中,找到适合python版本的先安装关联的库,这时候要进入虚拟环境,在ubuntu中用source 命令
这个时间相当的长,问什么呢?打开文件就知道了,
# base deps
protobuf==3.20.3
# utils
psutil>=5.9.0
ruamel.yaml>=0.17.21
scipy>=1.9.3
tqdm>=4.64.1
opencv-python>=4.5.5.64
fast-histogram>=0.11
# base
onnx==1.14.1
onnxoptimizer==0.3.8
onnxruntime==1.16.0
torch>=1.13.1,<=2.1.0
tensorflow==2.8.0
其中torch最新版本已经2.3.0了,因为没有测试过,所以不要追求新鲜感了,然后安装对应的wheel库,这次就非常快了
成功安装。
3 转换RKNN并打包SDK
事先采用jupyter试了一下,还是没有调试好环境变量,所以没有启动成功,这个代码简单,就直接在python的交互页面就可以完成,主要可以参考以下代码。
import sys
from rknn.api import RKNN
DATASET_PATH = '../../../datasets/COCO/coco_subset_20.txt'
DEFAULT_RKNN_PATH = '../model/yolov5.rknn'
DEFAULT_QUANT = True
def parse_arg():
if len(sys.argv) < 3:
print("Usage: python3 {} onnx_model_path [platform] [dtype(optional)] [output_rknn_path(optional)]".format(sys.argv[0]))
print(" platform choose from [rk3562,rk3566,rk3568,rk3588,rk1808,rv1109,rv1126]")
print(" dtype choose from [i8, fp] for [rk3562,rk3566,rk3568,rk3588]")
print(" dtype choose from [u8, fp] for [rk1808,rv1109,rv1126]")
exit(1)
model_path = sys.argv[1]
platform = sys.argv[2]
do_quant = DEFAULT_QUANT
if len(sys.argv) > 3:
model_type = sys.argv[3]
if model_type not in ['i8', 'u8', 'fp']:
print("ERROR: Invalid model type: {}".format(model_type))
exit(1)
elif model_type in ['i8', 'u8']:
do_quant = True
else:
do_quant = False
if len(sys.argv) > 4:
output_path = sys.argv[4]
else:
output_path = DEFAULT_RKNN_PATH
return model_path, platform, do_quant, output_path
if __name__ == '__main__':
model_path, platform, do_quant, output_path = parse_arg()
# Create RKNN object
rknn = RKNN(verbose=False)
# Pre-process config
print('--> Config model')
rknn.config(mean_values=[[0, 0, 0]], std_values=[
[255, 255, 255]], target_platform=platform)
print('done')
# Load model
print('--> Loading model')
ret = rknn.load_onnx(model=model_path)
if ret != 0:
print('Load model failed!')
exit(ret)
print('done')
# Build model
print('--> Building model')
ret = rknn.build(do_quantization=do_quant, dataset=DATASET_PATH)
if ret != 0:
print('Build model failed!')
exit(ret)
print('done')
# Export rknn model
print('--> Export rknn model')
ret = rknn.export_rknn(output_path)
if ret != 0:
print('Export rknn model failed!')
exit(ret)
print('done')
# Release
rknn.release()
如下图,输出rknn的转换模型了
参见附件
逐句说明
-首先导入开发包
from rknn.api import RKNN
-其次创建实例rknn
>>> rknn = RKNN()
I rknn-toolkit2 version: 2.0.0b0+9bab5682
- 导入前面从pytorch转换出来的onnx文件,导入成功,但是提示版本不大对,
>>> ret = rknn.load_onnx(model='mnist_cnn.onnx')
I It is recommended onnx opset 19, but your onnx model opset is 17!
I Model converted from pytorch, 'opset_version' should be set 19 in torch.onnx.export for successful convert!
E load_onnx: Please call rknn.config first!
- 这个命令失败,因为首先需要选择硬件平台,这个很关键,因为这个SDK是需要和硬件相匹配的,不是共用的,所以如果不熟悉硬件,没选对那是不行的。
>>> rknn.config(mean_values=[[128]], std_values=[[128]])
E config: The 'target_platform' has not been set yet, valid values are ['rk3566', 'rk3568', 'rk3588', 'rv1103', 'rv1106', 'rk3562', 'rk3576', 'rv1103b', 'rk2118'],
Please set it according to the actual platform!
- 这次选择rv1103,选择,没有问题,但是,这个在后面的build过程,提示必须要提供源数据,不能不量化,意思是,这个内存资源紧张,必须压缩才行。
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform='rv1103')
0
- 中间忽略一万头羊陀,选择rk3588,这个是当下的王牌,一定没有问题。后面在开发板到了以后,安装开发板的型号和规格选择,如rv1106,到手后小改即可,
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform='rk3588')
0
- 开始build,显然非常成功
>>> ret = rknn.build(do_quantization=False)
I rknn building ...
I rknn buiding done.
- 然后输出文件,并释放资源。
>>> ret = rknn.export_rknn('opt_model_rk3588.rknn')
>>> rknn.release()
4 小结
虽然本文不长,但是都是干货,时间锤炼的结果,按照这个过此必成。
其中,源代码中有两个隐形的坑,首先要定义platform平台,然后才能加载,然后是是否量化需要结合硬件来选择,不能想当然。
随后的sdk如何使用,虽然板子没到,可以剧透一下。
首先要用adb来连接,然后启动硬件的rknn server,这个模型就可以直接下载到开发板部署,然后直接用c++或者python来调用,在本地计算机的测试,本质还是用来形成onnx文件,进行调用和使用了。
这里面也提供了非常全面的范例,应该是不会缺资料。
第二站任务完成。
5 附件。
这个是在转换rknn的踩坑地图,贴在后面供大家批判一下。
(mnist) north@north-Lenovo-Product:~/Desktop/mnist$ python
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from rknn.api import RKNN
>>> rknn = RKNN()
I rknn-toolkit2 version: 2.0.0b0+9bab5682
>>> ret = rknn.load_onnx(model='mnist_cnn.onnx')
I It is recommended onnx opset 19, but your onnx model opset is 17!
I Model converted from pytorch, 'opset_version' should be set 19 in torch.onnx.export for successful convert!
E load_onnx: Please call rknn.config first!
I ===================== WARN(0) =====================
E rknn-toolkit2 version: 2.0.0b0+9bab5682
E load_onnx: Catch exception when loading onnx model: /home/north/Desktop/mnist/mnist_cnn.onnx!
E load_onnx: Traceback (most recent call last):
E load_onnx: File "rknn/api/rknn_base.py", line 1546, in rknn.api.rknn_base.RKNNBase.load_onnx
E load_onnx: File "rknn/api/rknn_base.py", line 653, in rknn.api.rknn_base.RKNNBase._create_ir_and_inputs_meta
E load_onnx: File "rknn/api/rknn_log.py", line 92, in rknn.api.rknn_log.RKNNLog.e
E load_onnx: ValueError: Please call rknn.config first!
W If you can't handle this error, please try updating to the latest version of the toolkit2 and runtime from:
https://console.zbox.filez.com/l/I00fc3 (Pwd: rknn) Path: RKNPU2_SDK / 2.X.X / develop /
If the error still exists in the latest version, please collect the corresponding error logs and the model,
convert script, and input data that can reproduce the problem, and then submit an issue on:
https://redmine.rock-chips.com (Please consult our sales or FAE for the redmine account)
>>> rknn.config(mean_values=[[128]], std_values=[[128]])
E config: The 'target_platform' has not been set yet, valid values are ['rk3566', 'rk3568', 'rk3588', 'rv1103', 'rv1106', 'rk3562', 'rk3576', 'rv1103b', 'rk2118'],
Please set it according to the actual platform!
W config: ===================== WARN(1) =====================
E rknn-toolkit2 version: 2.0.0b0+9bab5682
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/north/Desktop/mnist/lib/python3.10/site-packages/rknn/api/rknn.py", line 128, in config
return self.rknn_base.config(args)
File "rknn/api/rknn_base.py", line 944, in rknn.api.rknn_base.RKNNBase.config
File "rknn/api/rknn_log.py", line 92, in rknn.api.rknn_log.RKNNLog.e
ValueError: The 'target_platform' has not been set yet, valid values are ['rk3566', 'rk3568', 'rk3588', 'rv1103', 'rv1106', 'rk3562', 'rk3576', 'rv1103b', 'rk2118'],
Please set it according to the actual platform!
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform=['rv1103])
File "<stdin>", line 1
rknn.config(mean_values=[[128]], std_values=[[128]],target_platform=['rv1103])
^
SyntaxError: unterminated string literal (detected at line 1)
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform=['rv1103'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/north/Desktop/mnist/lib/python3.10/site-packages/rknn/api/rknn.py", line 128, in config
return self.rknn_base.config(args)
File "rknn/api/rknn_base.py", line 946, in rknn.api.rknn_base.RKNNBase.config
AttributeError: 'list' object has no attribute 'lower'
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform=[[rv1103]])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'rv1103' is not defined
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform=[['rv1103']])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/north/Desktop/mnist/lib/python3.10/site-packages/rknn/api/rknn.py", line 128, in config
return self.rknn_base.config(args)
File "rknn/api/rknn_base.py", line 946, in rknn.api.rknn_base.RKNNBase.config
AttributeError: 'list' object has no attribute 'lower'
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform='rv1103')
0
>>> ret = rknn.load_onnx(model='mnist_cnn.onnx')
I It is recommended onnx opset 19, but your onnx model opset is 17!
I Model converted from pytorch, 'opset_version' should be set 19 in torch.onnx.export for successful convert!
I Loading : 100%|███████████████████████████████████████████████████| 8/8 [00:00<00:00, 2251.52it/s]
>>> ret = rknn.build(do_quantization=False)
E build: Current target_platform(rv1103) not support do_quantization = False!
>>> ret = rknn.build(do_quantization=True)
E build: If set do_quantization = True, dataset file need be provided. But it`s value is None!
>>> ret = rknn.build()
E build: If set do_quantization = True, dataset file need be provided. But it`s value is None!
>>> ret = rknn.build(do_quantization=False)
E build: Current target_platform(rv1103) not support do_quantization = False!
>>> ret = rknn.build(do_quantization=False,dataset='./data/MNIST/raw/train-labels-idx1-ubyte')
E build: Current target_platform(rv1103) not support do_quantization = False!
>>> ret = rknn.build(do_quantization=True,dataset='./data/MNIST/raw/train-labels-idx1-ubyte')
E build: Catch exception when building RKNN model!
E build: Traceback (most recent call last):
E build: File "rknn/api/rknn_base.py", line 1998, in rknn.api.rknn_base.RKNNBase.build
E build: File "rknn/api/graph_optimizer.py", line 2109, in rknn.api.graph_optimizer.GraphOptimizer.sparse_weight
E build: File "rknn/api/sparse_weight.py", line 528, in rknn.api.sparse_weight.sparse_weight
E build: File "rknn/api/sparse_weight.py", line 55, in rknn.api.sparse_weight._range_input
E build: File "/usr/lib/python3.10/codecs.py", line 322, in decode
E build: (result, consumed) = self._buffer_decode(data, self.errors, final)
E build: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xea in position 6: invalid continuation byte
W If you can't handle this error, please try updating to the latest version of the toolkit2 and runtime from:
https://console.zbox.filez.com/l/I00fc3 (Pwd: rknn) Path: RKNPU2_SDK / 2.X.X / develop /
If the error still exists in the latest version, please collect the corresponding error logs and the model,
convert script, and input data that can reproduce the problem, and then submit an issue on:
https://redmine.rock-chips.com (Please consult our sales or FAE for the redmine account)
>>> rknn.config(mean_values=[[128]], std_values=[[128]],target_platform='rk3588')
0
>>> ret = rknn.build(do_quantization=False)
I rknn building ...
I rknn buiding done.
>>> ret = rknn.export_rknn('opt_model_rk3588.rknn')
>>> rknn.release()
>>>
- 2024-05-09
-
回复了主题帖:
入围名单公布:嵌入式工程师AI挑战营(初阶),获RV1106 Linux 板+摄像头的名单
个人信息已确认,领取板卡
- 2024-04-12
-
回复了主题帖:
免费申请:幸狐 RV1106 Linux 开发板(带摄像头),助力AI挑战营应用落地
#AI挑战营第一站#Pytorch 安装和MNIST识别 - Linux与安卓 - 电子工程世界-论坛 (eeworld.com.cn)
-
发表了主题帖:
#AI挑战营第一站#Pytorch 安装和MNIST识别
本帖最后由 北方 于 2024-4-12 16:57 编辑
1 概述
AI挑战营第一站的任务就是尝试一下pytorch,通常大家都是在用tensorflow,那么用一下torch,大同小异,而且还更方便。
2 安装环境
首先创建虚拟环境,python -m venv mnist
然后安装torch和torchvision
为了使用方便,装一个jupyter,pip install jupyter
3 训练模型
3.1 启动jupyter notebook
进入环境,创建一个notebook文件
写入以下代码,仔细调试,就可以直接输出训练结果了,这个电脑没有显卡,只用cpu,这样14个循环就搞了1个小时,如果用cuda,应该是2-3分钟的事情
from __future__ import print_function
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.optim.lr_scheduler import StepLR
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.dropout1 = nn.Dropout(0.25)
self.dropout2 = nn.Dropout(0.5)
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = self.dropout1(x)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = F.relu(x)
x = self.dropout2(x)
x = self.fc2(x)
output = F.log_softmax(x, dim=1)
return output
def train(args, model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % args.log_interval == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
if args.dry_run:
break
def test(model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
if True:
parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
parser.add_argument('--batch-size', type=int, default=64, metavar='N',
help='input batch size for training (default: 64)')
parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
help='input batch size for testing (default: 1000)')
parser.add_argument('--epochs', type=int, default=14, metavar='N',
help='number of epochs to train (default: 14)')
parser.add_argument('--lr', type=float, default=1.0, metavar='LR',
help='learning rate (default: 1.0)')
parser.add_argument('--gamma', type=float, default=0.7, metavar='M',
help='Learning rate step gamma (default: 0.7)')
parser.add_argument('--no-cuda', action='store_true', default=False,
help='disables CUDA training')
parser.add_argument('--no-mps', action='store_true', default=False,
help='disables macOS GPU training')
parser.add_argument('--dry-run', action='store_true', default=False,
help='quickly check a single pass')
parser.add_argument('--seed', type=int, default=1, metavar='S',
help='random seed (default: 1)')
parser.add_argument('--log-interval', type=int, default=10, metavar='N',
help='how many batches to wait before logging training status')
parser.add_argument('--save-model', action='store_true', default=False,
help='For Saving the current Model')
args = parser.parse_known_args()[0]
use_cuda = not args.no_cuda and torch.cuda.is_available()
use_mps = not args.no_mps and torch.backends.mps.is_available()
if use_cuda:
device = torch.device("cuda")
elif use_mps:
device = torch.device("mps")
else:
device = torch.device("cpu")
torch.manual_seed(args.seed)
train_kwargs = {'batch_size': args.batch_size}
test_kwargs = {'batch_size': args.test_batch_size}
'''
if use_cuda:
cuda_kwargs = {'num_workers': 1,
'pin_memory': True,
'shuffle': True}
train_kwargs.update(cuda_kwargs)
test_kwargs.update(cuda_kwargs)
'''
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
dataset1 = datasets.MNIST('../data', train=True, download=True,
transform=transform)
dataset2 = datasets.MNIST('../data', train=False,
transform=transform)
train_loader = torch.utils.data.DataLoader(dataset1,**train_kwargs)
test_loader = torch.utils.data.DataLoader(dataset2, **test_kwargs)
model = Net().to(device)
optimizer = optim.Adadelta(model.parameters(), lr=args.lr)
scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma)
for epoch in range(1, args.epochs + 1):
train(args, model, device, train_loader, optimizer, epoch)
test(model, device, test_loader)
scheduler.step()
if args.save_model:
torch.save(model.state_dict(), "mnist_cnn.pt")
输出模型用下述代码
if args.save_model:
torch.save(model.state_dict(), "mnist_cnn.pt")
这里上传notebook的文件
和模型文件用mnist_cnn.pt如下,
训练精度还是可以的