1、今日主题

背景:
曾经在大三参加2017全国大学生电子设计竞赛,当时做的是四旋翼自主飞行器探测跟踪的题目,我是负责主控这一块的,中后期整个过程主要都是调试,在调试的过程中,我们需要将飞行器的各类数据上传至地面站上位机来观测飞行器的姿态,通过波形判断控制算法的鲁棒性,以便更好的调节控制参数。地面站有固定的的数据传输协议,根据协议进行编程,通过串口蓝牙无线传输,在电脑上就可以看到波形了。

问题:
由于各数据的数据类型不太一致,个数有一样的也有不一样的针对每一次的调试就需要定义不同的函数,这可怎么办呢?用C语言编程思维惯性,第一反应当然就是根据需求定义多个不同的函数,粘贴复制,增加参数,粘贴复制,修改…,搞定!写完之后发现函数名要取得不一致,或者有的干脆用同一个函数名加数字123进行区别,调用的时候用哪个函数、要确定好每一个参数,一一对应,搞着搞着人都搞蒙了…

思考:
那要怎么解决这个问题呢?有没有什么办法能够进行优化的呢?

实践演练

解决思路:

1、学了C++自然就想到了C++支持函数重载,通过重载,对一个函数名赋予新的含义,让一个函数名可以多用。

1.1、于是将数据传输的函数名都定义为一样的:DataSendToUSART1();解决了定义多个函数名混淆不清的情况;

1.2、然后根据不同的需求定义不同的函数,实现不同的数据传输;例如:

// 传输三维姿态角
void DataSendToUSART1(float roll,float pitch,float yaw)
{unsigned char i = 0;unsigned char cnt = 0, sum = 0;unsigned int mTemp;unsigned char dataToSend[50];dataToSend[cnt++]=0xAA;dataToSend[cnt++]=0xAA;dataToSend[cnt++]=0x01;dataToSend[cnt++]=0;mTemp = (int)(roll*100);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);mTemp = (int)(pitch*100);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);mTemp = (int)(yaw*100);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);dataToSend[3] = cnt-4;/* 和校验 */for(i = 0; i < cnt; i++)sum+= dataToSend[i];dataToSend[cnt++] = sum;/* 串口发送数据 */for(i = 0; i < cnt; i++)printf("%c", dataToSend[i]);}
// 传输X ,Y,方向速度PID输出,高度
void DataSendToUSART1(int speed_X_PID,int speed_Y_PID,uint16_t height)
{unsigned char i = 0;unsigned char cnt = 0, sum = 0;unsigned int mTemp;unsigned char dataToSend[50];dataToSend[cnt++]=0xAA;dataToSend[cnt++]=0xAA;dataToSend[cnt++]=0xF1;dataToSend[cnt++]=0;mTemp = (int)(speed_X_PID);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);mTemp = (int)(speed_Y_PID);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);mTemp = (uint16_t)(height);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);dataToSend[3] = cnt-4;/* 和校验 */for(i = 0; i < cnt; i++)sum+= dataToSend[i];dataToSend[cnt++] = sum;/* 串口发送数据 */for(i = 0; i < cnt; i++)printf("%c", dataToSend[i]);}

在调用函数时,系统会根据给出的信息找到与之匹配的函数,然后进行调用。写完之后发现真的太棒了,这样我就不用一一去找什么时候用哪个函数了,只要直接调用就可以了

2、名字的问题是解决了,但是我的函数还是那么多个呀,程序还是很多重复的,不够精简,看起来还是很头疼啊,怎么办呢?

2.1、这时候我就根据传输的数据进行分类,我发现,有一些函数只是形参的类型不同,而函数的参数个数以及函数体(传输数据的程序)是一致的,于是想能不能定义一个通用的函数,这样就可以将只是形参类型不同的函数统一,大大的精简程序代码。

2.2、这时候,就到了C++的函数模板出场的时候了,通过定义一个通用的函数,函数的类型和形参类型不具体指定,用一个虚拟的类型来代表。例如:

template <typename T>
void DataSendToUSART1(T a,T b,T c)
{unsigned char i = 0;unsigned char cnt = 0, sum = 0;unsigned int mTemp;unsigned char dataToSend[50];dataToSend[cnt++]=0xAA;dataToSend[cnt++]=0xAA;dataToSend[cnt++]=0x01;dataToSend[cnt++]=0;mTemp = (int)(a*100);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);mTemp = (int)(b*100);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);mTemp = (int)(c*100);dataToSend[cnt++] = BYTE1(mTemp);dataToSend[cnt++] = BYTE0(mTemp);dataToSend[3] = cnt-4;/* 和校验 */for(i = 0; i < cnt; i++)sum+= dataToSend[i];dataToSend[cnt++] = sum;/* 串口发送数据 */for(i = 0; i < cnt; i++)printf("%c", dataToSend[i]);
}int main()
{float roll = 1.0f,float pitch = 2.0f,float yaw = 3.0f;DataSendToUSART1(roll,pitch,yaw);// 调用模板函数,此时T被float 取代return 0;
}

只需在模板中定义一次,我们就可以用模板来代替所有函数体相同的函数。调用函数时,系统根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。

2.3、上述函数的类型参数都是一致的,但如果我要同时传输不同类型的数据呢,函数模板同样可以搞定,类型参数可以不止一个,可以根据功能需求确定个数:如:

template <typename T1, typename T2, typename T3>
至此,发现这功能简直不要太好用了吧,直接将发送数据的函数分为几类,对应哪一类就用那个函数模板就可以了。

小结

1、函数重载

针对实现同一类功能的函数,只是细节上有所不同,可以通过函数重载用同一函数名定义多个函数,这些函数的参数个数和类型、函数体都可以不同。

注意:参数个数、参数类型、参数顺序必须至少有一种不同。

2、函数模板

  • 函数模板能够根据实参对参数类型进行推导
  • 函数模板支持显示的指定参数类型
  • 函数模板是C++中重要的代码复用方式
  • 函数模板通过具体类型产生不同的函数
  • 函数模板可以定义任意多个不同的类型参数
  • 函数模板中的返回值类型必须显示指定
  • 函数模板可以像普通函数一样重载

相关小知识

四轴飞行器调试的过程中有一个很重复的问题就是需要进行反复的参数调试,以求达到最好的控制参数,在这期间我们不可能调试一遍就修改一次程序进行烧录再调试,这样太浪费时间,同时我们需要观测相关数据曲线以判断控制过程的好坏,以此调节作为调节参数的依据。

我们当时的做法就是通过串口蓝牙将数据传送到匿名地面站上进行观测,同时通过自制遥控器进行参数调节,使用的是2.4G通讯,这样的好处是方便在电脑上观测飞行数据曲线,同时能够便捷的调试参数。

函数重载、函数模板在四轴飞行器中的实际应用相关推荐

  1. 函数重载函数的引用算重载吗_了解C ++中的函数重载

    函数重载函数的引用算重载吗 介绍 (Introduction) Today in this tutorial, we are going to understand the concept of Fu ...

  2. C++笔记函数重载函数模板

    #include <iostream>using namespace std;class Student { private:int num;int score; public:void ...

  3. java的函数重载函数_Java函数重载和重写

    版权声明:转载原创文章请以超链接形式请注明原文章出处,尊重作者,尊重原创! 恰饭广告 函数也称为方法! 函数重载:在同一个类中存在多个函数,函数名称相同但参数列表不同.这就是函数的重载. 注意事项: ...

  4. C++中函数重载是如何实现

    函数重载的重要性不言而明,但是你知道C++中函数重载是如何实现的呢(虽然本文谈的是C++中函数重载的实现,但我想其它语言也是类似的)?这个可以分解为下面两个问题 1.声明/定义重载函数时,是如何解决命 ...

  5. 【C++深度剖析教程7】C++之类中的函数重载

    函数重载的回顾(接上一篇文章): 函数重载的本质为相互独立的不同的函数 C++中通过函数名和函数参数确定函数调用 无法直接通过函数名得到重载函数的入口地址 函数重载必然发生在同一个作用域中 类中的成员 ...

  6. TS中的方法重载,函数重载,构造器重载

    什么叫重载 名字相同 ,参数类型不同 方法重载 方法重载在类中定义多个同名的方法,但是每一个同名的方法要求不同数据类型和不同参数 下面来实现一个方法重载 以ArrayList 为例 可以查看数据 可以 ...

  7. C++深度解析 类中的函数重载 -- 全局函数,普通成员函数,静态成员函数(28)

    C++深度解析 类中的函数重载 -- 全局函数,普通成员函数,静态成员函数(28) 函数重载的回顾 函数重载的本质为相互独立的不同函数 C++中通过函数名和函数参数确定函数调用 无法直接通过函数名得到 ...

  8. 浅谈C++的函数重载

    转自:微点阅读(www.weidianyuedu.com)微点阅读 - 范文大全 - 免费学习网站 导语: 函数重载的重要性不言而明,但是你知道C++中函数重载是如何实现的呢(虽然本文谈的是C++中函 ...

  9. c++学习笔记内联函数,函数重载,默认参数

    c++学习笔记内联函数,函数重载,默认参数 1 inline内联函数 C++中的const常量可以替代宏常数定义,如: const int A = 3;  #define A 3 C++中是否有解决 ...

最新文章

  1. 重磅!《2021中国开源发展蓝皮书》发布
  2. Git 简易食用指南 v2.0
  3. 5、Python函数
  4. word使用技巧(不定时更新)
  5. php无法调用shell脚本文件,php调用shell脚本--126错误
  6. Unity3D研究院之2D游戏开发制作原理(二十一) 【转】
  7. java 的权限表_JAVA权限表
  8. 《伪化生:修罗战场》写给那些在读伪化生专业的
  9. python线性链表
  10. ES6 模板字符串基本用法
  11. 远程控制工具哪个好?向日葵VS ToDesk,安卓移动设备远程操控哪个更好用?
  12. SAP中货架寿命控制功能的简单测试分析
  13. 运筹说 第55期丨整数规划先驱——Ralph Gomory
  14. python 01列表异或_【快速跟水】图像隐写的python实现
  15. Windwos磁盘管理工具diskpart
  16. 魔性!Python生成全网爆火的“蚂蚁呀嘿”
  17. 服务器inetpub是什么文件夹,处理inetpub文件夹在win10中的问题
  18. 关于安装anaconda错误:failed to create anaconda menus
  19. Chrome OS 与 Android 的生死爱欲
  20. 《软件工程与实践》 |(九)软件工程新技术及体系 知识梳理

热门文章

  1. 用HTML5新增canvas标签实现个性时钟效果
  2. mysql体系结构及四种部署方式
  3. 系列解读SMC-R:透明无感提升云上 TCP 应用网络性能(一)| 龙蜥技术
  4. 科学与计算机作文,科技与生活的作文4篇
  5. 简单工厂模式学习笔记
  6. Android Screen_ON Screen_OFF广播的接收
  7. idea修改子模块名
  8. 又一个改写MBR的病毒(TDSS TDL4)
  9. 硬盘与硬盘对拷如何操作
  10. 修改jupyter网页字体的设置