big_uncle
big_uncle
你好,我参照你的代码实现CH341的模拟,目前已经成功枚举,串口调试软件也能成功打开串口,但打开串口之后电脑不断请求设备状态,也就是下面: ```c int ch341_get_status(struct usb_device *dev) { char *buffer; int r = -ENOMEM; const unsigned size = 8; dbg("ch341_get_status()"); buffer = kmalloc(size, GFP_KERNEL); if (!buffer) goto out; r = ch341_control_in(dev,...
演示页面
# Gitblog 一个简单的页面功能展示。 # 文章发表支持Markdown语法: # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 ## 表格绘制 |header1|header2| |:--:|:--:| |content1|content2| ## 图片插入  ## 引用 > A:嚯!厉害 >>...
感谢您关注并使用本项目,因个人经费有限,不再续费云服务器,若未自己搭建服务端,则博客的登录评论功能会受影响。
随着代码结构的完善,越来越希望代码更加智能化,调参的步骤越少越好,要是啥也不用调就更好了。。。 回忆起以往看过的代码,感觉智能化第一步就是搞定flash读写。有了flash之后,一切都变得很方便了。 比如每辆车的电机安装方式不一样,那么云台中间位置就不一样,如果有了flash,直接运行校准程序,云台左右分别碰到限位开关,自动计算出中间位置,pitch轴直接用手扶正,靠陀螺仪判断是否水平,水平的时候就记下当前位置,写入flash中,不用再慢吞吞地进调试,手动记录中间位置了。 又比如现在都流行自己搞上位机,上位机校准的关键一点就是单片机需要存储上位机的信息,下次上电就可以直接使用了。 所以flash多好啊。 # flash 首先我们需要了解一个内存映射:  stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同。 RAM起始地址是0x2000 0000,结束地址是0x2000 0000加上芯片的RAM大小。不同的芯片RAM也不同。 Flash中的内容一般用来存储代码和一些定义为const的数据,断电不丢失, RAM可以理解为内存,用来存储代码运行时的数据,变量等等。掉电数据丢失。 STM32将外设等都映射为地址的形式,对地址的操作就是对外设的操作。 STM32的外设地址从0x4000 0000开始,可以看到在库文件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的。 一般情况下,程序文件是从 0x0800 0000 地址写入,这个是STM32开始执行的地方,0x0800 0004是STM32的中断向量表的起始地址。 在使用keil进行编写程序时,其编程地址的设置一般是这样的:  程序的写入地址从0x08000000(数好零的个数)开始的,其大小为0x100000也就是1024K的空间,换句话说就是告诉编译器flash的空间是从0x08000000-0x08100000。这与STM32的内存地址映射关系是对应的。 ##...
之前写过一篇使用STM32虚拟串口功能的文章:[实现USB CDC通信](https://imuncle.github.io/content.html?id=59),但是这个有个很大的问题,它的Windows驱动的数字签名过期了,我在我的电脑里搜索了一下,发现有两个驱动:  不过很可惜,这两个驱动都过期了:  这就直接导致在Windows上使用ST自己的虚拟串口需要强制跳过数字签名这一步,而每次电脑重启之后Windows就会恢复默认设置,最麻烦的是每次还必须通过重启设置,不过Linux下倒没这个问题,因为数字签名是Windows自己搞出来的东西。 但还是很烦,所以我决定抛弃ST官方的虚拟串口驱动,正好我找到了别人用STM32模拟CH341的代码:[blackmiaool/STM32_USB_CH341 ](https://github.com/blackmiaool/STM32_USB_CH341),但这已经是五六年前的代码了,当时还是标准库,所以我决定把它用HAL库实现。 踩了一些坑,这玩意儿花了我三天时间,主要还是对USB协议不太熟悉,下面就按照我踩坑的时间顺序记录。 # 第一天:让电脑识别为CH340 这一步很简单,只需要改变设备描述符就行了,具体更改如下: ## 使用STM32CubeMX生成代码  这里修改以下PID和VID,然后字符串名称就随便写,点击生成代码。 ## 修改设备描述符 在`usbd_desc.c`里面,修改`USBD_FS_DeviceDesc`变量: ```c __ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = { 0x12, /* bLength */...
该算法在论文《Automatic camera and range sensor calibration using a single shot》中被提出,同时作者还给出了角点检测部分的MATLAB源代码。这篇文章的工作主要是使用OpenCV和C++复现MATLAB的代码效果,同时梳理一下角点检测的过程。 复现的代码见https://github.com/imuncle/camera_calibration 算法分为三个部分:角点提取、角点亚像素化、棋盘生长。 # 角点提取 角点提取部分采取的是类似Harris特征的检测方法。它设置的角点特征如下图所示:  这里有两组特征,如果角点的旋转角度不大,则由第一组特征检测,如果角点旋转角度大,则由第二组特征检测。 使用这些特征作为卷积核对图像进行卷积。对于每一个像素i,它经过一组特征的四个卷积核的卷积后会得到四个值`f_A` `f_B` `f_C` `f_D`,其最后的卷积结果c的定义如下:  最后每个像素由不同大小、不同类型的卷积核卷积后取各个卷积结果的最大值,其得到角点似然域,如下图右图所示:  最后对角点似然域进行非极大值抑制即可得到像素精度的角点值。 # 角点亚像素化 该方法是根据角点所对应的两条线的角度来对角点坐标进行优化,同时也优化了两条线的角度(后文以角点的方向代指)。 首先使用Sobel算子对图像进行横向和纵向的滤波,滤波卷积核如下图所示: ...
在驱动步进电机成功之后(可看[这篇文章](https://imuncle.github.io/content.html?id=27)了解详情),剩下的就是读取编码器的值了。 编码器使用的是多摩川(Tamagawa)的39位高精度编码器(23位单圈精度+16位多圈精度),支持RS485通信,波特率为2.5Mbps,数据长度为八位。型号为TS5700N8401,属于SA48系列编码器。 使用起来很简单,只要数据手册正确以及模块能满足功能。。。这里就记录一下我这一周所踩的坑。 # RS485通信 RS485通信是从RS232中衍生出来的,解决了RS232不能联网通信的痛点。 RS485与串口通信非常相似,也是两根线,但它可以像CAN通信一样,一条总线上搭载多个设备,实现联网通信。两根线分别为A线和B线,这里就说说我踩的第一个坑: 编码器的说明书里把两个数据线写作:  这我怎么知道哪根是A线哪根是B线啊,百度也百度不到,拿头来接吗。。 没办法,只能试错法,结果一次“成功”,我成功收到了数据。结果后来仔细一看这数据是我自己的发出去的,当时就自闭了,`为啥我会收到我自己发的数据?`。 后来的某个晚上我突然开窍,原来是`接反了`,A、B两线反接就跟TX和RX短接一样,RX的信号立马被TX捕获,造成了接收到编码器数据的假象。 # USART低位优先 搞懂了这一点后我把线反接回来,但这下一点反馈信息都没有了,编码器就像死了一样。没办法,看通信协议哪里写错了吧。 *(这里又要吐槽一下,这编码器的数据手册是真的难找,淘宝店家给的和公司网站找到的都只有编码器的性能参数和接线方法,死活没有通信协议,后来我从CSDN上才找到一个型号很相近的TS5700N8501编码器的数据手册,这下才开工)* *下载地址:* https://download.csdn.net/download/ppl002/10787122 读了数据手册才知道编码器可以读取绝对值角度数据,也可以读写数据到内置的EEPROM中,当然我这里只需要读取绝对值角度数据就行了。 通信协议如下:     我先读取编码器的单圈数值吧,所以我要请求`DATA_ID_0`。 ## 起始位&停止位 手册里写的是CF由10bits,但众所周知**USART**一次只能发送8bits的数据,而这里显然是不能分两次发送的。 后来我才领悟到原来这里的起始位和停止位并不需要手动发送,因为USART的通信协议中就自带了起始位和停止位。所以这里我只需要发送`0100 0000`就行了,也就是`0x40`。...
博客搭建过程
最近正值期末考试,今天刚考完一门,昨晚上实在是不想复习了,正想着怎么办的时候,突然想把复习的考点放在自己的博客上,正好我半年前搭建了一个博客,打开一看发现只有最开始搭建的时候的一篇博客,感觉很失败。 之前的这篇博客采用的是Hexo+NexT框架搭建的,但是我的电脑几经改装,系统也重装了几次,node.js早就没了,想要继续维护这个博客有些麻烦,索性全删了,从头手写一个博客。 首先明确目标,我对博客要求不高,能发文章就行了,所以博客的功能就两点:发文章、读文章。当然,最基本的文章分类是必须的。 然后开始找模板,因为我个人的UI设计能力实在堪忧,只有借鉴别人的设计。我仍然选择在[NexT主题](https://hexo.io/themes)中寻找,很快我找到了一个[不错的博客样式](http://lalala.lol)。然后我就使用自卑鄙的手段,按下`F12`查找元素的样式,顺手把图也扒了下来,基本上还原了博客的样式。 ## 渐变动画 博客里有**内容渐变动画**和**菜单动画**,我使用了css+Jquery实现,就拿我的博客的头像来进行说明吧。 头像的部分css样式如下: ```css .head { display: inline-block; width: 130px; height: 130px; border-radius: 50%; padding: 3px; background: #fff; box-shadow: 0 0 5px #95a5a6; position: relative;...
鱼眼镜头因其较大的畸变而难以标定,对鱼眼镜头的畸变建模也是多种多样,相机模型的一些重要时间节点如下: 1. 透视模型:于2000年,Zhang贡献(编码为RTCM=Radial Tangential Camera Model)。 2. 开创理论:于2000年,Geyer和Daniilidis提出UCM(Unified Camera Model)成像模型,可用于建模平面、抛物、椭圆及双曲反射相机。 3. 完善理论:于2001年,Barreto和Araujo优化UCM成像模型,从而简化了标定算法的开发。 4. 理论向工程过渡:于2006年,Scaramuzza和Martinelli及Siegwart基于泰勒展开式提出用多项式来近似所有成像模型。 5. 等距模型:于2006年,Kannala和Brandt贡献(编码为KBCM)。 6. 开创工程:于2007年,Mei和Rives融合径向切向畸变到UCM成像模型(编码为MUCM),解决UCM建模鱼眼镜头差的问题。 7. 优化工程:于2013年,Heng和Li及Pollefeys。 8. 完善工程:于2016年,Khomutenko和Garcia及Martinet提出EUCM(Extended Unified Camera Model)成像模型,解决了UCM径向畸变和建模鱼眼镜头差的问题及MUCM非闭环解问题。 9. 完善工程:于2018年,Usenko和Demmel及Cremers提出DSCM(Double Sphere Camera Model)成像模型,相对于EUCM、MUCM、KBCM等算法,在精度和速度上取得了折中。...
MPU9250六轴算法
前段时间我研究了MPU9250的数据读取和九轴姿态解析算法,效果还不错,详情点[这里](https://imuncle.github.io/content.html?id=39)。 但是今天发现九轴算法得出来的角度有两个问题,一个是波动较大,一个是会出现下图所示的斜坡。  后来我发现,应该是陀螺仪积分出来的角度和磁力计加速度计坐标转换过来的角度不一致,导致被缓慢纠正,进一步发现pitch轴和roll轴没有这个问题,只有yaw轴有,所以是磁力计的问题。 磁力计这东西吧,问题还真挺多,到了一个新地方还要重新校准一下,而且特别容易受到干扰。我采集了一段数据后发现,加速度、角速度、磁场强度,就磁场数据波动最大,这也是角度波动大的罪魁祸首。 我尝试对磁力计进行低通滤波或者均值滤波,但效果都不是很好,最后角度数值稳定下来了,但是那个斜坡还是无法消除。 没办法,暂时抛下磁力计试试六轴算法,也就是说只使用MPU9250里面的MPU6050。 # 六轴算法 我参考了正点原子的飞控代码,在正式总结之前先说一声`正点原子牛逼!` ## 陀螺仪数据 六轴算法中最重要的就是陀螺仪数据的处理,因为陀螺仪数据是四元数更新的根本依据。加速度能纠正pitch轴和roll轴,所以yaw轴的稳定全靠陀螺仪数据的准确。 这里主要是采集一段陀螺仪静止的数据,找到三轴数据的静差。我采集了1024个数据,先计算他们的方差,如果方差大于阈值,则表明陀螺仪不是静止的,则不进行校准,当方差满足要求时,计算样本数据的平均值,当做陀螺仪的静差。 处理过后,才静止情况下三轴的陀螺仪数据小数点后两位都是0,效果还不错。 实现代码如下,函数较多: ```c #define SENSORS_NBR_OF_BIAS_SAMPLES 1024 /*计算方差的采样样本个数 */ #define GYRO_VARIANCE_BASE 4000 /* 陀螺仪零偏方差阈值 */ /*计算方差和平均值*/ static...