今天来聊一聊minimosd。Osd的全称是on-screen display,指在屏幕视频之上叠加数据,相信每一个使用apm或者pix做飞行控制器的人都多少与osd打过交道。 目前市面所有的飞控osd模块都是起源于google上的minimosd项目。
该项目版本截止于12年的2.0。其硬件解决方案是采用atmega328芯片作为主控,配置相当于arduino nano,具有32kb的flash,2kb的sram以及1kb的eeprom;同时采用7456作为字符叠加芯片,7456可以存储256个字符,针对pal或者ntsc信号完成字符叠加。在软件方面,minimosd遵从mavlink协议,从串口获取封装为该协议的飞行数据,显示在视频之上,同时具有桌面配置程序,支持用户配置显示信息的内容与风格。
在minimosd2.0版本的基础之上,全球范围内出现了若干分支版本,其中比较著名的是托管在github上的minimosd-extra 2.4(https://github.com/diydrones/MinimOSD-Extra/wiki), 该版本在原版基础上扩展对mavlink传递信息的支持,可以显示更多的飞行数据,并且具备了简单的飞行统计功能,还改进了osd显示方案的切换方式。在此之外,也流传着一批针对国内用户的中文版osd固件,基本上都是基于minimosd-extra进行了简单改造。而杭州的playuav则大胆的对osd体系结构进行了改进,彻底改变了osd硬件架构,做出了一些很有新意的osd尝试(https://github.com/PlayUAV/)。
作为一个源码解析类的专题,下面我们以google上的项目minimosd-2.0源码为基础,来进一步了解minimosd的程序语言。
Minimosd源码分为三个部分,分别是osd功能固件ArduCam_Osd;配套库libraries以及osd的桌面配置工具OSD_Config。我们主要研读的代码是ArduCam_OSD,是烧录到osd片子上的主要功能代码。
ArduCam工程的主要功能文件包括两个头文件:OSD_Vars.h,OSD_Config.h以及三个源码定义文件ArduCAM_osd.ion,OSD_Panels.ino,MAVLink.ino。
OSD_Vars.h中定义的变量储存了从mavlink协议获取的飞行数据,这些飞行数据被解析后,保存在运行时内存sram中。
OSD_Config.h则负责与eeprom打交道,定义了配置信息在eeprom中的保存位置,便于minimosd启动后,从eeprom读取用户配置信息。
ArduCAM_osd.ino是minimosd的程序入口点,是整个程序的骨架。
OSD_Panels.ino是具体的绘制功能,每一帧视频,都有这些功能,将飞行器信息绘制到视频之上。
MavLink.ino则是用于对mavlink协议的解析,将收到的数据包按照mavlink协议解析,解析成功后将数据储存在ODS_Vars.h中定义的变量中。
整个minimosd的程序流程非常简单,如下图所示
在minimosd通电启动后,首先调用到Setup()入口函数,实现如下流程。
1.初始化mavlink,设置了与飞控连接的串口波特率以及端口号
然后向飞控发送数据请求,osd需要如下飞行数据
2.初始化7456,设置7456通信的spi端口,并且激活7456
3.读取eeprom设置,OSD_Config.h中记录了不同的设置信息在eeprom中的存储位置,在这里逐次读取,如:
这里要说一下minimosd中的panel结构,minimosd中设计了4组,每组8个,共32个数据槽位,每个槽位分别对应于需要显示的一种飞行数据。针对每个槽位,可以开启或者关闭显示,亦可以设置该槽位在屏幕上的显示位置(x,y坐标)。对于上述的32组槽位设置,minimosd支持两种方案,所以放到一个长度为2的数组中进行管理 。
下述代码是每个槽位是否显示的变量结构,每组8个槽位的1或者0正好对应于一个byte数据类型,因为有两套显示方案,所以每组都是一个长度为2的byte数组
下述代码是槽位显示位置的变量结构,x和y坐标分别用byte来存储。同样,都可以应对两套显示方案。
4.启动loop循环,无更多细节。
通电后,minimosd完成Setup中的所有功能,便进入了一个周而复始的循环工作过程,不断的调用Loop()函数,而每个loop循环,则执行如下函数:
1.获取mavlink数据.根据mavlink的msgid,获知数据类型,后分别调用mavlink库中的函数对数据包进行解析,存储到变量中。
2.字符绘制,这是osd的核心功能,针对允许显示的飞行数据,调用绘制该数据的函数
我们以绘制电池电量panBatt_A为例,该函数代码如下:
其中,osd.setPanel()函数是7456提供的开发接口,设置当前要绘制字符的位置。
Osd.printf()函数类似于标准c++的printf,是向7456当前的位置输出字符。在上述代码中,在eeprom读出的屏幕位置,绘制了从mavlink协议获取的osd_vbat_A变量的值。
这里需要注意到的是,7456字符叠加器内部存储了256种不同的字符图标,正好对应了char类型的取值范围,可以通过MAX7456Charwizard.jar编辑相应的图标,大家使用的中文版osd,也就是这样制作出来的,仅仅将用到的中文画成了图标,而并不是支持所有的中文字库。
上述是osd的功能性代码的简单介绍,希望可以对大家有所帮助。
最后给大家留一个思考题。我们可以看到minimosd的功能非常简单,仅仅解析了mavlink4到5类数据包,存储其中32种飞行数据,但是,大家可以尝试看看代码中对于显示槽位相关的储存结构,十分的晦涩难懂。那么,请大家思考一下,为什么minimosd代码功能如此简单,却动用了天书一般的数据结构来实现?
apm、pix咨询、定制开发与服务,欢迎大家联系博主.