imuncle.github.io
imuncle.github.io copied to clipboard
大叔的个人小站
刚接触惯性导航传感器的时候,被求解姿态角的一系列操作秀了一脸,虽然研究了一两天,但最后还是浅尝辄止,只了解了个大概,当时把MPU9250的算法逻辑捋了个大概思路,原文见:[MPU9250姿态解析](https://imuncle.github.io/content.html?id=39)、[MPU9250六轴算法](https://imuncle.github.io/content.html?id=44)。这其中最不理解的就是四元数的那一部分,为什么四元数可以这样求解出来?为什么四元数与欧拉角之间的转换关系式这样的?四元数到底有什么几何或者物理意义? 可惜的是普遍的讲解姿态解析的文章都是直接给出了最后的公式,并没有讲解为什么。最近又因为想做四足机器人,需要实现惯导的室内定位功能,正好趁此机会好好研究一下四元数。 以下内容绝大部分参考自《惯性导航》(作者 秦永元)一书。 # 什么是四元数 ## 四元数的定义 顾名思义,四元数是由四个元构成的数,它是一个超复数,具有一个实部和三个虚部,也可以看成是一个四维空间中的一个向量。  ## 四元数的运算法则 四元数的运算也有加减乘除四种,加减就很简单了,这里看看乘法和除法。 不过既然四元数是一个四维向量,那么它的运算法则就完全符合向量的运算法则,换句话说,符合矩阵的运算法则。 ### 四元数的乘法 乘法分为一个四元数和一个常数相乘以及两个四元数相乘两种情况,第一种情况太简单了,就看第二种乘法运算:     ### 四元数的除法 矩阵的除法可以转换成逆矩阵相乘,所以除法的关键是四元数的逆的求解。  四元数就了解到这里,接下来就研究四元数与欧拉角之间的关系。 # 四元数与姿态阵间的关系 首先看下图模型: ...
昨天刚搞定STM32模拟CH340,今天就实现了ROS的串口通信,果然还是硬件让人头秃,软件开发的资料太丰富了,随便百度就能找到答案。 下面进入正题。 ROS要和STM32通信首先要确定通信协议。我的协议很简单,单片机上有两个LED,如果接收到命令'0x01',就改变1号LED的亮灭状态,如果收到`0x02`,就改变2号LED的亮灭状态。另外STM32会返回本次接受到的数据第一位和数据长度。 我的思路是ROS读取键盘输入,然后将键盘的输入以键盘码(不是字符串ASCII码)的形式发送给STM32,同时监听STM32的消息。 # 实现串口通信 这里参考的是这篇博客:[ROS使用官方包进行串口通信](https://blog.csdn.net/qq_25254777/article/details/81364716) 我的代码如下: ```cpp int main(int argc, char **argv) { ros::init(argc, argv, "serial_read_node"); ros::NodeHandle n; ros::Subscriber write_sub = n.subscribe("keyboard", 1000, write_callback); try { //设置串口属性,并打开串口 ser.setPort("/dev/ttyUSB0");...
不经意间刷到了一篇知乎问答:[没有磁强计的陀螺仪能算出偏航角(Yaw)吗?](https://www.zhihu.com/question/68156189/answer/900276549),赞同数最高的答案中提到了两种姿态解算算法,`MadgwickAHRS`和`MahonyAHRS`,其中`MohonyAHRS`算法就是我之前一直在使用的姿态解析算法,可以参考这几篇: * [MPU9250姿态解析](https://imuncle.github.io/content.html?id=39) * [MPU9250六轴算法](https://imuncle.github.io/content.html?id=44) `MadgwickAHRS`算法还没看太懂,等之后搞懂了再补充。下面的链接里有这两种算法的**C代码**、**C#代码**、**MATLAB代码**以及相关论文等: [Open source IMU and AHRS algorithms](https://x-io.co.uk/open-source-imu-and-ahrs-algorithms/) 我这里把两种算法的C语言版本贴出来,方便以后直接复制使用。 ## MadgwickAHRS ```c //===================================================================================================== // MadgwickAHRS.c //===================================================================================================== // // Implementation of Madgwick's IMU and AHRS algorithms. //...
# CMakeLists配置 ```cmake cmake_minimum_required (VERSION 2.8) include_directories(${OpenCV_INCLUDE_DIRS}) #OpenCV的include文件夹 set(OpenCV_DIR /usr/local/lib) #OpenCV的lib文件夹 find_package(OpenCV REQUIRED) add_executable(程序名 主函数所在cpp) target_link_libraries(程序名 ${OpenCV_LIBS}) ``` # 显示图像 ```cpp #include using namespace cv; void main() { Mat src...
之前有一篇写如何制作CMSIS-DAP下载器的文章:[自制CMSIS-DAP下载器](https://imuncle.github.io/content.html?id=83),就在昨晚,我搞定了它的无线版本,也就是可以实现无线下载程序和调试程序。 # 代码修改 就直接在上一篇文章建立的工程上修改。其实可以看出来,这份代码可以分为两部分,一部分是用于和PC端通信的USB HID,另一部分是和单片机调试内核通信的DAP,要实现无线通信,意味着要制作一个发射端和一个接收端,发射端主要实现USB HID,接收端主要实现DAP,两者之间的信息交互通过无线模块实现。 整份CMSIS-DAP代码最关键的部分就是在`DAP_Thread()`函数中的 ```c DAP_ExecuteCommand(USB_Request[USB_RequestIndexO], USB_Response[USB_ResponseIndexI]); ``` 从函数名就可以看出来,这个函数是将USB HID的命令`USB_Request[USB_RequestIndexO]`传给DAP处理函数`DAP_ExecuteCommand`,同时返回一个单片机的响应`USB_Response[USB_ResponseIndexI])`,那么对于发射端,我就直接把DAP的那五个核心代码都删除,只留下USB HID的代码,然后把上面这行代码修改如下: ```c HAL_UART_Transmit(&huart1, USB_Request[USB_RequestIndexO], 64, 500); HAL_UART_Receive_DMA(&huart1, USB_Response[USB_ResponseIndexI], 64); while(__HAL_DMA_GET_COUNTER(huart1.hdmarx) > 0){} ``` 因为我选用的无线串口模块,所以这里使用的是串口发送和接收。 对应的从机部分则只保留DAP部分,删除USB HID部分,代码执行靠串口接收中断推动,关键性代码如下: ```c...
之前有提到一个想使用Windows批处理脚本模拟CMake的想法,具体见[gcc编译带资源的Win32程序](https://imuncle.github.io/content.html?id=91),正当我还在纠结怎么使用batch比较文件修改时间的时候,VBScript进入了我的视野,只因一句话,我就震惊了: ```vb Msgbox "Hello World" ``` 将它保存为`hello.vbs`,然后双击运行:  一个Message Box就这样产生了!这也太简洁了吧。而且VB是深度嵌入进Windows系统的,也就是说这是真正的随便一个Windows都可以运行的代码,并且因为是脚本文件,运行时是一行一行解析运行的,所以这还省去了编译的步骤,这也太帅了吧。 后续进一步了解发现,原来VBScript曾经是和JavaScript一争高下的脚本语言,可惜VBScript只支持IE,而后者则是所有浏览器都支持,自然被搞下台。现在基本上网页开发里已经看不到它的身影了。 鉴于VBScript的API接口多很多,所以我打算使用它来模拟CMake,以实现我的“自动化编译”。 我的工程文件如下:  VBScript代码如下: ```vb Set objFSO = CreateObject("Scripting.FileSystemObject") Set obj = createobject("wscript.shell") Const targetFile = "poppad" '判断是否存在build文件夹,若不存在则创建 if...
两天前我突然回想自己当初是为什么想学编程的。 大约是高三毕业的那个暑假,我第一次尝试学习编程,当时也就听说过C语言,就上网百度,结果因为对编程一点概念都没有,直接点进了一个图形化编程的教学网站,最后也没学到啥东西,这网站现在好像已经找不到了。 后来大一的时候又决定学一次C语言,这次学乖了,下载了网上的C语言入门书籍的PDF(说实话那是我第一次知道还有PDF这种格式,之前我的脑子里就只有txt,excel,word和ppt),算是正式入门C语言了吧,在学习线性代数的时候因为不想手算矩阵,还用C语言写了一个矩阵计算器,但依旧是停留在命令行的交互阶段。 我其实一直想写出像Windows其他应用程序一样的东西,拥有窗口界面,用户鼠标点点点就行,人机交互良好,尤其喜欢那种单独一个exe执行文件,无需安装,无需解压,随表找台装有Windows系统的电脑,双击就能运行,体积也不大,可能也就2~3MB,特别喜欢这种小软件,比如我日常开发就用到一款类似的小软件`XCOM.exe`,是正点原子开发的。 再后来我接触了Qt,开发起来确实很方便,但是使用过后发现,我只是实现一个很简单的功能,但是打包出来的工程还需要带很多dll库文件,给其他人使用非常不方便,最最关键的是那些dll库体积真的很大,工程本身只有一百多KB,dll库文件加起来有几百MB,这谁顶得住啊,Debug版本和Release版本都是差不多的样子。 于是两天前我想,自己已经写代码两年有余了,如果连最初的目标都实现不了的话,还算什么程序员。 所以我把手伸向了Win32开发,使用最原生的Windows API,追求简洁小巧高效率,写自己的小工具,做一个自由软件开发者。另外我还要拜托IDE的束缚,直接使用文本编辑器写代码,这会让我对程序有更深入的认识,也带来更多的成就感。 直接贴上我的第一份代码吧: ```c #include int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MessageBox(NULL, TEXT("Hello World!"), TEXT("大叔的第一个窗口程序"), MB_OK); return 0...
电控基础知识
# 写在最前 本网页将我这一年(2018年)的电控经历积累下来的知识和经验,以及下半年进行的两次培训的内容和要点做了一个综合总结。 上半年我一直用的是标准库进行编程,但自从国庆期间用上**HAL库**之后,我被HAL库的便捷深深打动,自此基本放弃了标准库,所以本总结的内容是基于HAL库的,并结合**STM32CubeMX**软件(因为过程有些繁琐,截图很麻烦,所以本总结并不会贴出STM32CubeMX上的相关配置过程)。 # GPIO GPIO外设一共有八种模式,我比较熟悉的是这三种:**上拉输入**、**下拉输入**、**推挽输出**。上拉输入和下拉输入一般都和**外部中断**联系在一起,最典型的的应用就是读取按键的输入。推挽输出的功能是控制IO口的输出电平的高低,最常见的应用就是控制LED灯的亮灭。GPIO涉及的基本函数有以三个: ## GPIO简介 ```c HAL_GPIO_WritePin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); //直接指定引脚的电平输出,用于推挽输出 HAL_GPIO_TogglePin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin); //直接翻转引脚的电平输出,无需指定输出电平,用于推挽输出 HAL_GPIO_ReadPin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin); //读取指定引脚当前的电平高低...
# 资源简介 对于Microsoft Windows程序来说,图标、光标、菜单等都是Windows“资源”的类型。资源是数据,它们通常被保存在一个程序的`.exe`文件中,但它们不在可执行程序的数据区,换句话说,资源不能再程序代码中用变量直接寻址,相反,Windows提供了函数来显示或隐式地把程序资源加载到内存中以供使用。 使用资源的一个好处是可以把程序的很多组建都绑定到程序的`.exe`文件中,如果没有资源的概念,一个诸如图标图像的二进制文件将不得不作为一个单独的文件来保存,`.exe`文件需要将该文件读入内存再能使用。或者,图标需要在程序中定义为一个字节的数组(这会使得我们难以将实际图标图像可视化),而作为一种资源,图标在开发者的机器上被存为一个单独的可编辑文件,然后在程序编译的过程中被绑定到`.exe`文件内。 # 遇到的问题 不管是什么教程,基本都是通过IDE来添加资源,并且教程中都强烈建议不要修改IDE自动生成的`resource.h`和`resource.rc`文件,编译也是通过IDE自动将资源和代码文件链接起来,目前的教程里基本都是基于Visual Studio的,更老一点的教程可能基于Visual C++ Developer Studio,而我追求的是去IDE化,想使用命令行直接编译。 我的工程文件有: * menudemo.c * menudemo.rc * resource.h 代码里实现的是一个顶部菜单栏,具体的菜单选项在`menudemo.rc`里面。我按照之前的编译方法编译: ```bash gcc -mwindows menudemo.c -o menudemo.exe ``` 然而生成出来的可执行文件里并没有顶部菜单,说明编译时并没有将资源文件包含进来,这让我一度很困惑。 # 编译资源文件...
要实现嵌入式视觉开发,首先得把最强大最经典的OpenCV学会。 我参考的是毛星云主编的《OpenCV3编程入门》,过了一遍,记录了我比较关注的内容。学习时编写的源码如下: ```cpp #include using namespace cv; using namespace std; const int g_nMaxAlphaValue = 100; //Alpha值的最大值 int g_nAlphaValueSlider; //滑动条对应的变量 double g_dAlphaValue; double g_bBetaValue; Mat g_srcImage1; Mat g_srcImage2; Mat g_srcImage; Rect...