背景介绍:
以前写过一篇《arducopter 最新代码姿态环的 29 个参数》
同样的 PID 在定高控制上也有使用,所以计划写一篇定高控制相关的,兼有“控制框图”、“代码分析”和“数据分析”的推文。
在这之前先推一篇关于“模式”的文章,对模式的关键代码先有个认识。
目的是为写定高模式打个基础,同时重点讲讲 C++ 相关知识。
白话讲“C++多态”
主要从非编程角度说说多态咋理解、有啥用。
1、传承(理解多态)
科学技术的发展离不开传承。一代新人换旧人,旧人要把已经获得的成果传承给新人,新人继续努力:一面实现旧人的愿望,一面去改善旧人的成果使之更合实际需要。这就引出了“多态”的意思,下面进一步说说生活中多态是啥样。
举个栗子说说“实现旧人的愿望”型的多态就是著名的“哥德巴赫猜想”,这类事属于前人想干啥事交待下来了,但不知道咋干,后人要在咋干成这事儿上下功夫。
举个栗子说“改善旧人成果”型的多态就是手机,这玩儿艺就是最早的人说“想要跟千里之外的人讲话”,结果弄出个“大哥大”,被后来人搞成了“小灵通”,再后来成了“彩屏手机”,直到发展成现在你正拿着看推文的手机。
“多态”就是前人开了个任务,起了个名,后来人要么去实现要么去完善。
2、可持续发展(多态有啥用)
通过上面的表述,不难知道多态就是发展。没有多态也能发展,但有多态就能可持续发展。因为多态除了发展之外,还包含统一、分类、整理。
以“通话”为例,不妨起个神奇的名子叫“千里传音”,历史上人类曾借助固话、无绳电话、移动电话来实现这个功能。倒过来说,不管借助啥实现这个功能,功能名都叫“千里传音”,这就是统一。固话有线,无绳电话有线转无线,移动电话就是无线,这就是分类。随着发展,固话和移动电话在不同应用场合留存下来,而无绳电话几近灭绝(或者说已经灭绝),这就是整理。
这种多形态的千里传音,使“千里传音”这个功能以可持续发展的方式留下了最合适时代潮流的媒介。
以模式为例说说 ArduCopter 的 C++ 多态
1、C++ 多态必须的 virtual 关键字
上面讲到了“传承”,C++里相应的有“继承”的概念。想让子类继承于父类的函数实现有效(就是实现多态的意思),父类里必须在准备让子类重新实现的函数前加上 virtual 关键字。
2、虚函数与纯虚函数
父类里有实现的 virtual 函数是虚函数,父类里在函数声明时加 “=0;” 的是纯虚函数。
纯虚函数必须在子类里实现,而虚函数若子类不实现则使用父类的实现。
3、用父类的指针指向子类的对象。
更多有关 C++ 多态的解释可以参见如下链接(好文推荐):
https://m.runoob.com/cplusplus/cpp-polymorphism.html
ArduCopter模式管理下的两个重要的虚函数
init() 和 run()。
同时说说 Sugar 对于 ArduCopter 在模式上多态的感悟。
1、看下 ArduCopter 里模式相关类的继承关系
很明显,众多类都是从父类 Mode 派生出来的(换个同样意思的说法是:都是继承于父类 Mode 的)。
2、以定高为例,看下定高模式两个重点函数的实现是啥样。
图没截全,主要想表达一下这两个函数是各个模式最大的不同。
3、Sugar 对代码结构的感悟
(1) 模式统一管理
不同的飞行模式差异很大,涉及不同的传感器和控制方法。差别这么大,要想统一管理,必须把规则统一。这个“统一规则”的需求就由 C++ 的多态来实现。
模式管理层规则:进入某个模式时先初始化,通过初始化后才能进入该模式运行。
基于这个统一的规则,模式管理层只需用父类的指针 flightmode 调用 init() 和 run(),而不用管各个模式具体怎么实现(论服从的重要性)。
这样写模式管理层代码时,就可以集中精力解决“怎么管”,而不用分心看实现。写具体某个模式代的码时,也只管怎么搞定这个模式的实现,压根儿不用操心这个模式怎么管理。
(2) run() 是纯虚函数的必要性
试想如果飞机飞在天上,切入一个模式,而这个模式的 run() 是个空实现会怎么样?聪明的你一定会想到:那肯定掉下来呀!
不同模式的飞行方式不同,父类没法实现这个 run(),但出于安全考虑,又不能只加个{}空实现。
必须强制要求子类实现 run() 函数,基于这个需求 run() 必须是纯虚函数。
关于 ArduCopter 的模式管理
Sugar 不确定写这个推文的受众会有多大,如果收到的需求人数满百,Sugar 会着手写这个推文。
关注作者
欢迎扫码关注我的公众号MultiMCU EDU
。
提示:在公众号“关于我”页面可加作者微信好友。
喜欢本文求点赞,有打赏我会更有动力。
请我喝杯咖啡如何?
微信 支付宝