nknk的博客

nknk的博客

技术交流与分享

多单片机的盲人辅助系统

目前使用了三种不同类型的单片机进行实验,之后准备把他们全部画到一个板子上处理。 供电部分:两节18650电池,3.7v一个,串联应该是7.4v,得到分压后的5v电压对模块进行供电。 传感器部分:1.ESP32-CAM 提供图像检测,这个是网上买的现成的。2.3个超声波传感器 一个用于测量前方障碍物,2个朝向下方并呈现一定的角度,用于测量当前坡度(这里就有个坑,使用者要必须保持水平、这也是这个项目比较扯淡的地方)。 显示部分:用一块OLED显示短信内容。由于我们使用了4G模块,理论上只要是有4G信号覆盖的地方,我就能建立TCP连接,然后直接往OLED上发消息就行了。不过只能显示英文和数字。我使用的是STM32C6T6,中文字符库太占地方了,这种板子根本放不下。 语音部分:使用的是ASR-PRO,语音编程,设计好逻辑即可,并不复杂。 通信部分:三块单片机之前需要通信,ESP-CAM和STM32使用IO口进行通信,STM32和ASR-PRO通过UART进行通信。模块与云端服务器需要通信,通过AT指令控制YED-780G,它不仅可以获取GPS信号,还能进行4G通信。于是我可以通过4G
2 min read

基于cpu+gpu的图像拼接、识别

单纯的拼接实现逻辑如下图所示: 运行环境:通过docker进行部署,nvidia driver为535,cuda12.2,ffmpeg为6.1.1。 docker通过阿里云进行托管,名字是stitch_env,目前版本已更新到v1.3.8。 拼接:为了减少工作量,我们采用了ffmpeg库。里面有有关编码以及解码的各种封装,并且也有现成的RTSP推流/拉流库,可以直接进行使用。于是可以把主要的工作量放在实现拼接代码上。与CPU拼接不同的是,在GPU上拼接似乎可借助的开源库比较少一些(反正没找到),所以我们只好自己写拼接代码。为了工程上可以进行实时拼接(目前是5×4K@20fps),我们目前采取的方法仅仅是进行简单的裁剪,目前GPU损耗大概3G左右的内存,CPU除了跑了几个线程以及推拉流,实际负载非常低。 目前的问题: 1.拼接有缝:因为在GPU上,我们目前还没有找到特别好的开源库进行用,比如在opencv上,我们可以使用H矩阵进行运算,如果在GPU上把这个代码实现出来,难度还是比较大的。 2.编码大小受限:按照正常拼接完的话,最终的图片大小可能接近15000*2160,
3 min read
stm32

基于特征提取的指纹识别系统

1.FPC1020 fpc1020芯片是一款比较老旧的芯片,并且资料非常少,在经过多次尝试,并且通过以下的文档,最终可以驱动了,文档主要是看的下面这个。 通过网盘分享的文件:710-FPC1020_PB3_Product-Specification.pdf 链接: https://pan.baidu.com/s/1NeSne8U8_KJQg86acrk9Vw 提取码: tn94 在github上参考了一些代码之后,成功在STM32F407上驱动了FPC1020芯片(文档的内容还是太少了,github上的很多初始化寄存器,文档里都没写,这个给了我很大的困扰)。下图红点是为了防止指纹信息泄露。 最后参考了一个俄罗斯人写的基于特征识别的算法库,但是个人认为算法库写的有点烂了,有大概率会匹配错误。 通过UART将stm32中读到的数据传输给电脑,电脑对数据进行分析,上位机如下图所示: 下位机实际如下图所示:
1 min read
小项目

基于yolov5的元器件识别

基于yolov5的元器件识别/封装识别,目前部署版本已经放在kaggle中,点击即可运行,封装识别放在了华为云上,因为华为云上对数据集打标签比较方便。 数据集: 1.元器件识别:2000多张图片,训练集和测试集按8:2进行分开。内有8种不同的元器件。 2.封装识别:600多张图片,网上找不到开源库(开源的一些都比较烂),在嘉立创商城保存的图片,在华为云上打的标签,训练集和测试集按7.5:2.5进行分开。内有10中不同的封装类型。 神经网络模型:yolov5。 训练环境:线上 元器件识别的训练结果: CPU 规格:Intel(R) Xeon(R) CPU GPU 规格:NVIDIA Tesla GPU P100 下面列出训练了100轮,batch-size设为32的一次训练结果,其他选项均为默认。 封装识别的训练结果: 部署模型:个人笔记本(Y9000P
3 min read
python

python的前向引用

在之前看python代码时,发现了一个很有意思的现象,有些python函数是下面这个状态: def copyRandomList(self, head: Optional[Node]) -> Optional[Node]: 这种好说,理解起来还是很简单的,就是为了方便阅读嘛,所以事先把类型写再后面。但是下面这个,就感到很费解: def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]': 他居然把类型外面加了一层''?但是按以前的学习中,''包裹的都是字符串啊,这样写居然也不会报错。 询问了chatgpt我才明白咋回事。加上''主要是为了延迟解析。 想象一下下面这个场景. from typing import
1 min read

论文导读:Cam4DOcc

论文链接: 论文结构 摘要 纯视觉的端到端自动驾驶方案。 首先说传统的3D空间只有当前时刻的物体空间,但是没有考虑时间轴,即未来的物体状态。(所以说Cam4DOcc代表的就是三维空间加一维时间)。 为了对未来的研究建立一个全面的基准,引入了四种模型,分别是静态世界占用模型,点云预测的体素化处理(体素化(Voxelization) 是一种将三维空间中的几何对象转换为规则的三维网格(体素)的过程。),基于2D-3D实例的预测(是指一种从二维数据(例如图像)预测三维结构的技术方法,这种预测是基于具体实例的,即每个单独的对象或实例都被单独处理。)和,Cam4DOcc(本文的方法) 在文章最后,还设计了多个任务,对模型做了评估。 1.介绍 这本书的主要贡献有如下几点(摘要扩写了一遍): (1)提出本模型,方便未来的基于相机的四维空间占用预测。 (2)利用该领域已有的数据集进行训练,并为适配该模型提出了新的数据格式。 (3)提出四种基准方案,其中三种方案是已有的,最后一种是这个Cam4DOcc。 (4)提出了一种标准的评估协议,用于评估模型质量。
3 min read
小项目

基于嵌入式的智能农业物联网系统

本项目是基于STM32F407芯片构建而成的程序,除此之外,还有YED-780G,为减轻工作量,使用的是其中的DTU固件。该程序可以做到本地自动运行,也可以接受控制指令,通过WAKE_UP键来选择手动模式和自动模式,在自动模式下,远程控制无效。 STM32芯片中采取了FREERTOS,里面主要是5个函数,并行运行(一开始是想分成7个,但是最后任务太多了导致任务执行缓慢。)。5个函数优先级是一致的,所以这五个函数本质上还是“顺序的”,并没有使用“抢占”这一特性。 ECS使用的是阿里云服务器,本博客也是建立在该服务器之上。服务器与STM32的连接使用的是8133端口,采取的是TCP通信的方式。在8132端口,服务器开启了http协议,各种上位机均可通过此端口对STM32进行控制。 由于本项目是采用正点原子的探索者芯片,因此包括操作系统移植、传感器驱动的编写均有范例可以参考,故而比较方便。 在本项目中,主要学习了freertos任务的调度以及尝试在一个程序中开启两个端口,分别对两种不同的接入分别处理,这在以前还没有试过。这次的项目,更多的尝试了使用别人已经写好的库,提高了编写效率,把
2 min read
论文

论文导读:UniPAD

论文链接:UniPAD: A Universal Pre-training Paradigm for Autonomous Driving 论文结构 摘要 在自动驾驶领域中,有效的特征学习至关重要。尽管传统的3D自监督预训练方法取得了广泛成功,但大多数方法仍沿用最初为2D图像设计的思路。在这篇论文中,我们提出了一种名为 UniPAD 的新颖自监督学习范式,它采用了3D体素可微渲染技术。 1.介绍 在这篇论文中,主要提出了一种针对三维空间的预训练范式,这不仅消除了对复杂正/负样本分配(这是啥意思)的需求,而且还隐含地提供了连续的监督信号(是指录一段的意思吗)来学习三维形状结构。 2.相关工作(介绍他人的工作) 1.点云中的自监督学习 2.图像中的表示学习 3.自动驾驶的神经渲染 3.方法 1.Modal-specific Encoder 即对输入进行译码,在本论文中,输入为激光雷达和多视角的图片,因此会有两种不同的译码器分为point encoder和image
2 min read
算法

将有序数组转换为二叉搜索树-迭代做法

Problem: 108. 将有序数组转换为二叉搜索树 解题过程 使用迭代方法解决题目 复杂度 * 时间复杂度: O(n) * 空间复杂度: O(n) Code /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right)
1 min read
杂项

ESP32C3和ESP8266通过u8g2库使用0.96寸OLED对比

在淘宝上买了一款ESP32C3 mini板,想用它显示OLED屏幕,但却发现显示帧率太低了,此时ESP32C3 mini板的cpu频率为160mhz。 void MenuShow(U8G2_SSD1306_128X64_NONAME_F_SW_I2C& myoled){ myoled.clearBuffer(); myoled.setCursor(50,20); myoled.printf("%d",millis()-t); t = millis(); myoled.sendBuffer(); } 最后发现一帧屏幕居然要花费450ms!一开始我还以为是软件问题,在网上没有找到答案。最后想着是不是硬件问题,于是我把一摸一样的代码烧进了esp8266中,发现速度提高了很多。 在cpu频率为80mhz时,屏幕刷新频率为185ms左右。 于是我又尝试把cpu频率提高到160mhz,屏幕刷新频率为115ms左右。 最后,初步排除是软件的问题,但是还是不明白为什么esp32c3迷你板在执行相同代码时,要比esp8266慢这么多。
1 min read
python

python语法分析器(parser)源码阅读(三)

关于结构体tok_state以及结构体parser_state 这两个结构体主要出现在parsetok.c以及tokenizer.c文件中,对于这两个结构体,它们之间的关系应该是承上启下的关系即先生成tok_state然后再生成相应的parser_state. 下图是通过sizeof取得的两个结构体的大小。 可以看出,这两个结构体都比较大,再加上结构体内指针指向的地址空间,结构体包含的实际信息量要更大。其中结构体内部的具体信息在源码里都有详细描述,这里不再写。 先看一下tok_state,通过我的观察,这个主要用在PyTokenizer_Get(struct tok_state *tok, char **p_start, char **p_end)这个函数上,位于tokenizer.c文件中第1838行,通过这个函数,主要用于获取输入的字符串。然后信息通过tok_state保存下来。 这里出现了一个我一直想不通的问题,为啥tok_state使用时必须在前面加一个struct,不加就会报错。 再看一下parser_state,它集中出现在parser.c文件中,这个文件中主要
3 min read
python

python语法分析器(parser)源码阅读(二)

每次打开python编译器,映入眼帘的总是那一块黑框框,像这样。  作为一个初学者,我很想知道这个编译器是怎么把我输入的字符串进行转化,然后一步步分析,最后让程序执行起来的。看了好几天后,我把目光锁定在了myreadline.c这个文件上 现在就去看看这个文件里都有什么。 首先,通过调试,先找到了程序调用的系统API---ReadConsoleW 通过这个函数,我们成功把写入的字符串读取了出来。 之后我们再看一下文件中的其它函数 _PyOS_WindowsConsoleReadline---line 102 ReadConsoleW的第一层封装,所做的工作是将读出的字符串转化为utf-8格式。 PyOS_StdioReadline---line 217 第二层封装,在_PyOS_WindowsConsoleReadline函数前面加入了fflush函数,该函数的作用是将缓冲区中的内容强制写入指定位置(stdin:输入端|stdout:输出端|stderr:错误输出端)。然后直接返回_PyOS_WindowsConsoleReadline的值。注意到,在return后面
2 min read
python

python语法分析器(parser)源码阅读(一)

从官方网站上下载了python3.7.9的源代码,准备这几天看一下python的语法分析器。 本来我以为会有很多东西,没想到打开了parser这个文件夹之后,发现才有14个文件(c语言的文件),其中有2个头文件,12个源文件。 注:阅读这一部分的源码,搭配《编译原理》更佳。 我准备从自顶向下的顺序进行分析: 文件包含关系 1.头文件 * parser.h                定义了几个语法分析器有关的数据结构,以栈的形式存储语法分析器 * tokenizer.h           里面主要写了一个结构体tok_state ,记录着源代码(你写的python代码)的很多东西 2.源文件 * acceler.c               语法分析器加速模块 * bitset.c                  被解析器使用的bitset原语 * firstsets.c              FIRST集的代码实现(详见《编译原理》4.4.2)    * grammar.c            语法实现 * grammar1.
2 min read
算法

二叉树的层序遍历-迭代解法

题目要求 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 解题思路 这里给出迭代解法。 代码 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: vector<vector<int>> levelOrderBottom(TreeNode* root) { vector<TreeNode*>
1 min read