浅谈无人机飞控操作系统层
操作系统向下进行硬件资源管理,向上提供任务调度和通信接口。当前Ubuntu(一款Linux发行版)+ROS(Robot Operating System)已经成为机器人运行环境的事实标准,而对于无人机飞控,我们期望操作系统是实时的且高度可剪裁配置、可扩展。主流飞控的嵌入式实时内核依据软件架构、接口标准兼容性等划分为两大类:类Unix如NuttX等,微内核类如FreeRTOS和uCOSii等。其中实时主要是指具备高优先级任务抢占低优先级任务的能力,调度延迟以系统时钟量级来计。上述两类操作系统都满足实时要求,类Unix、微核本质是调度器,由一些线性数据结构实现对任务线程的管理;而ROS本质是多进程Socket通信中间件。
一、类Unix操作系统
PC端Unix操作系统启动之后呈现出进程树和文件系统树,进程树表达所有进程之间都具有亲缘关系,而文件系统树表达文件系统路径之间的挂载关系。
NuttX是类Unix嵌入式实时操作系统,因为处理器架构不同,又限于资源压力,相比于Linux,它对机制实现做了一些简化。麻雀虽小,五脏俱全,NuttX支持8bit到64bit微处理器环境,支持POSIX/ANSI标准的任务控制、命名管道,计数信号量,信号,互斥量以及文件系统等机制,下面是NuttX架构图:
NuttX架构图
首先, NuttX支持用户线程和内核线程,而不具有Linux意义下的进程概念。取而代之的是NuttX线程组,包括一个主任务线程和由主线程创建的pthreads,线程组线程彼此共享资源如环境变量、文件描述符、文件流、sockets等。另外,在NuttX上有task的概念,task是一种特殊的pthread,和pthread资源共享程度相比,task有一定独立度。对于线程/任务控制,NuttX提供了VxWorks与POSIX风格的API,实现最大程度兼容性。对于内核线程,他们相比于用户态有内核资源访问权限。
默认情况下,NuttX按照优先级调度,高优任务在阻塞之前独占CPU,同优先级任务按下来先调度顺序执行,NuttX任务或线程可以通过选项配置round-robin或sporadic方式调度。
除了线程与任务之外,NuttX还有一种任务执行方案,work queue:work queue是一系列需要执行的工作加入到队列中,由一些线程来消费执行。NuttX支持三种类型work queue,包括高优内核work queue:一般用于处理中断句柄中的延迟任务,也可用于驱动底层处理工作,因为这些任务通常是高优快速运行的;还有低优内核work queue:低优先级工作队列更适合于处理面向应用层的工作,比如文件系统清理,内存垃圾回收,异步IO操作等;还有用户模式work queue:同样面向应用层,但是访问内核资源需要系统调用增加开销,用户自行结合实际情况选取。
在任务同步、通信,资源互斥保护方面,NuttX支持命名管道,计数信号量,信号,共享内存等。父子关系的线程或任务之间可以用waitpid等同步,非父子关系可以用其他如命名管道等方式做同步,PX4中的uORB就是基于命名管道实现的,命名管道支持POSIX标准文件系统操作,如下介绍:
NuttX符合“一切皆文件”的哲学,接口上对外暴露Open、Close、Read、Write、Ioctl以及Poll。如设备驱动,又如命名管道。NuttX伪根文件系统是全内存的,其他或真实文件系统可以挂载到根下。NuttX设备驱动包括字符设备驱动,如常见串口驱动,模数驱动,PWM驱动,CAN驱动,正交编码器,定时器驱动,RTC驱动,FOC(Field Oriented Control)控制交流电机驱动等。除了最常见的字符设备驱动之外,还有字符设备驱动,它们以块为单位读写访问,以及一些特殊设备驱动:SYSLOG,RAM LOG等。PX4中传感器驱动是对字符设备的进一步开发,放在PX4-Autopilotsrcdrivers路径中,读者可以自行查看调用关系。
二、微内核
与类Unix相比,微核的调度、通信等机制都是独立实现,不遵守接口标准,因此更轻量。相比于裸机编程,使用微内核,业务被模块化可以使架构更清楚,开发者对调度和通信的实现无需过多关注。微内核代表产品包括FreeRTOS、uCOSii,以及国产RT-thread,我们以FreeRTOS为例介绍一下:
FreeRTOS支持消息队列,用于任务间通信,本质是一段对各个任务可见的共享内存。也支持二值信号量(或互斥信号量)做资源互斥保护以及多值信号量做同步,他们的本质也是共享内存空间以及有PV语义的接口。
对中断的响应和处理也是嵌入式编程需要关注的一个特性,在FreeRTOS中,中断事件可以与常规task进行通信和同步。此外,微核支持临界区来关闭调度和中断,临界区逻辑需要尽可能短小,以保证实时性。
内存管理方面,与NuttX一样,对于没有MMU的STM32F4处理器, TCB(Task Control Block)与各自的栈链表形式保存在扁平内存中,内存布局可以类比下图:
微核内存管理示意图
总地来说,对于类Unix和微核,应该没有程序运行效率上差别,类Unix操作系统遵守协议标准,对Linux特性熟悉的可以很容易上手开发,同时可以使用KConfig剪裁配置系统功能;微核优势在于轻量级,系统代码占用几K空间,比较受到国内MCU开发者青睐。当然也有裸机编程的,自己开发定时器中断回调,完成周期任务执行,但是显然,这样的开发方式只适用于小规模项目。
三、ROS
ROS(Robot Operating System)从2007年诞生至今已经成为机器人操作系统事实标准,经历过两个主要版本ROS1和ROS2。虽然被叫做操作系统,但是ROS本质只是一个中间件,不具备原生调度硬件的能力,更不满足实时性要求。
下面是ROS发行版与Ubuntu版本匹配情况:
下面简单介绍一些ROS概念和用法:
包是项目的功能单元和发布单元,工作空间是包开发和运行的路径范围。ROS提供catkin基础包帮助用户做开发包的构建管理,catkin本质是CMake与一些python脚本实现的,此外,ROS也提供了一些包管理的命令行工具。
包中可以包含一个或多个可运行二进制,称为节点。运行中的节点彼此存在消息流交互,构成图,在ROS1中,由master节点提供名称索引服务与消息通讯,由参数服务器提供系统参数增删改查服务。节点之间通信采用SOCKET。ROS2干掉了master概念,节点可消息直传,系统更鲁棒。另外,ROS2构建于 Data Distribution Service(DDS)之上,因其支持多种传输模式,因此更适合于实时性更好的操作系统。
ROS架构 来源:《Exploring the performance of ROS2》
此外,ROS有着丰富的辅助开发工具,包括可视化工具Rviz,仿真工具gazebo。此外,ROS也有着庞大的开发者基础,支持的功能包也涵盖优化,控制,导航,视觉,AI等领域。如果有机会,我们后面会选取SOTA成果,对包做测评。
这篇只是简单聊聊这两类操作系统,并没有事无巨细介绍,因为我还是觉得操作系统实现或开发,实操效果会更好,可以研究研究嵌入式操作系统的调度特性,内存管理,文件系统,以及ROS包开发,功能包评测来加深理解。