UCOSIII编写无人机飞控程序——第一篇

       

研究无人机飞控已经接近两年,作为一个业余的兴趣爱好。兴趣源于看到国外大神Raffaello D'Andrea在TED做的无人机演讲和展示,感觉无人机很像工程师所施展的魔法,给一向给人苦逼印象的工程师一种清新脱俗且高大上的感觉。此后一发不可收拾,有时间就学习飞控,甚至忘记了自己曾痴迷的各种PC游戏。之前一直研读一些国内外的开源飞控,去年根据这些开源代码,写了一个没有实时操作系统的工程,功能相对完整,添加了国内开源飞控一直没有开放的导航算法,对所有控制部分也重点做了优化。遗憾的是由于不会编写地面站,一直不能添加航点,不过想来能够做到遥控信号丢失后按预定航线自动返航,航点飞行控制也应该不是问题。 最近想到作为一名控制软件开发工程师,精通嵌入式实施操作系统是门必修课,索性把之前的裸机飞控程序用UCOSIII组织一下。这样一个庞大的工程下来,想估计RTOS想不精通都难了。这也是后面一年我这一系列博客的主题,通过把自己在编写过程中的想法和问题记录下来,加深对着部分知识的理解,也想听听其他大牛的意见,避免闭门造车。  

上重点。。。。  

通过UCOSIII组织飞控程序,遇到的第一个问题是如何架构程序。我的硬件平台是stm32f405,前段时间学习了stm32f4cubemx,所以很多底层底层程序打算放弃标准库,利用cube生成的HAL库,估计很多软件工程师很烦它,确实变化很大、很多冗余,甚至部分细节处存在BUG,不过这毕竟是趋势,所以还是硬着头皮用。在这个基础上,的想到的程序架构如下。

UCOSIII编写无人机飞控程序——第一篇_第1张图片

这个架构主要解决几个问题:(1)将大的工程项目分层处理,将代码拆解为两个大的部分,一部分是底层程序,这些代码是开发平台自动生成的,不需花经历开发,另外一部分是应用程序,需要花时间编写或者优化;(2)将应用程序部分又分为两部分,一部分为底层和硬件如MCU外设操作、传感器驱动等直接相关的程序,将这部分程序都封装起来,形成统一的API函数,这样后期修改硬件后只需修改这部分即可,另外一部分为和硬件无关的程序,这部分直接调用封装起来的API编写具体应用程序;(3)考虑后期程序功能扩展的兼容性,比如后期想添加固定翼或者直升机程序等,在架构中对应顶层配置文件。在顶层配置文件中添加配置项,在具体任务中采用条件编译的方式编写应用代码即可;(4)梳理具体的任务,明确各任务的具体职能。

顺便给出cubemx引脚配置页,确实很直观也很方便。

UCOSIII编写无人机飞控程序——第一篇_第2张图片  

程序架构中的一个难点问题是如何实现任务间通讯。整个五一假期都在思考任务间通讯的问题。国外Crazyfile和PX4等开源程序提供了很好的借鉴,比如Crazyfile采用的是FreeRTOS,不过其关键代码都集中在了stabilizerTask()这个单一的任务中,任务间通讯对它来说并不是太大的问题,我看到了对于一些关键的变量,他采用结构体和全局变量的方式存储。PX4的方法显然更为恰当,它采用Nuttx中uORB通讯方式使任务间通讯非常方便,这或许也是当初选择这个操作系统的原因之一。  

UCOSIII没有uORB这样强大的通讯方式,只有信号量、消息队列、事件标志组和等待多个内核对象。我又不想全部通过全局变量实现任务间资源共享和通讯,因为这样的话也就失去了使用RTOS的意义。所以最后还是打算综合运用UCOSIII给出的通讯方式。在程序框架依赖外部通讯最多的任务是Motor_Control任务,计划在该任务中实现姿态、位置、高度的控制,并将最后控制变量输出至电机。在该职能定位下,Motor_Control需要大量其他任务发送的相关信息,如Remote_ Command给出的各通道控制量,Data_Acquisition给出的Gyro、Acc、Attitude等状态信息,Ground_Station_Communication给出的PID整定量、螺旋桨方向、目标高度等信息,NAV给出的在Roll、Pitch、Yaw的控制输入等。  

这里的难点在于Motor_Control任务需要固定的周期循环执行,而如果采用Pend消息队列的方式触发任务,则很难保证任务执行的周期性。最后抱着邵贝贝翻译的《嵌入式实时操作系统μC/OSIII》学习很久决定采用等待多个内核对对象+事件标志组的方式实现与其他任务的通讯与同步。具体为通过Data_Acquisition()任务周期发送消息队列的方式实现Motor_Control对ESC控制输出的严格周期性,也通过其他任务发送的消息队列接收相关的数据信息,通过事件标志组接收Remote_ Command和Ground_Station_Communication发出的飞行模式、上锁信息等。这里一个学习很久才学到的技巧是时间标志组可以配置为不阻塞任务,在不满足预设条件下仍然去执行任务后续程序,而不是像信号量、消息队列那样直接退出任务。  

想清楚了Motor_Control这个任务的通讯和同步方式,其他任务的问题也就相对简单了,不再赘述。目前已经导出了底层程序,移植了UCOSIII系统,下一周第二版飞控硬件回来,所以先要把底层的驱动程序编写出来,快速验证硬件的正确性。下一周会在博客里更新几个跟通讯、传感器相关任务的编写。  

期待有类似开发经验的同学或同行多给出些建议和意见,软件这东西多分享和交流才会进步。  

这里感谢http://blog.sina.com.cn/s/blog_632136f9010133jx.html这篇博客,转载的一篇关于事件标志组的说明,比书中描述的要透彻,给了我很大启发。

你可能感兴趣的:(第二代飞控开发)