《自动驾驶编程原理与应用》课件 第3、4章Autoware编程基础、高精地图创建与加载_第1页
《自动驾驶编程原理与应用》课件 第3、4章Autoware编程基础、高精地图创建与加载_第2页
《自动驾驶编程原理与应用》课件 第3、4章Autoware编程基础、高精地图创建与加载_第3页
《自动驾驶编程原理与应用》课件 第3、4章Autoware编程基础、高精地图创建与加载_第4页
《自动驾驶编程原理与应用》课件 第3、4章Autoware编程基础、高精地图创建与加载_第5页
已阅读5页,还剩307页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1自动驾驶编程原理与应用2第三章Autoware编程基础知识点:了解Autoware与ROS之间的联系;掌握基于C++语言的ROS编程基本概念和方法。重点:重点掌握ROS编程常用命令行工具、工作空间与功能包、发布/订阅话题消息以及客服端请求与服务端应答相关定义和使用方法。难点:模块化设计思想以及发布订阅模式。自动驾驶编程原理与应用3本章节目录3.1C++编程基础IO库复合类型变量迭代语句条件语句类模板3.2ROS编程基础文件系统与通讯机制常用命令行工具工作空间编译话题发布与订阅编程话题消息定义与使用服务请求与应答编程服务数据定义与使用43.1C++编程基础53.1C++编程基础由于Autoware是基于ROS搭建的,且其源码为C++语言,所以基于Autoware平台学习搭建自动驾驶系统就必须具备一定C++和ROS编程基础。63.1C++编程基础C++是一门高效、灵活且功能强大的通用编程语言,由丹麦计算机科学家BjarneStroustrup于1983年在贝尔实验室设计开发。作为C语言的超集(Superset),它不仅继承了C语言在高性能计算和底层系统控制方面的优势,还通过引入面向对象编程和泛型编程等特性,大幅提升了代码的可重用性、可扩展性和可维护性。73.1C++编程基础C++的标准模板库(STL,StandardTemplateLibrary)提供了一系列高效、泛型化的容器和算法,显著简化了常见数据结构和算法的实现流程,使开发者能够更专注于业务逻辑而非底层细节。在Autoware系统的开发实践中,C++的诸多核心特性发挥着关键作用。下面就Autoware系统编程中涉及的IO库、复合类型变量、迭代语句、条件语句、类及模板等C++编程基础内容逐一展开介绍。83.1C++编程基础IO库C++语言本身并未定义任何用于输入输出(IO)操作的语句,而是通过一个功能丰富的标准库(standardlibrary)来提供IO功能。本节示例主要使用标准库中的组件iostream库,该库包含istream(输入流)和ostream(输出流)两个基础类型。其中,术语流(stream)表示从IO设备读取或写入的字符序列,其概念强调字符是随时间推移按顺序生成或消耗的。iostream库定义了4个IO对象,其中包括用于处理输入的istream类型对象cin(标准输入)和用于处理输出的ostream类型对象cout(标准输出)。93.1C++编程基础IO库使用iostream库需要在#include指令后方尖括号中指出头文件(header),该示例中头文件为iostream。#include指令一般位于源文件的开始位置,且必须出现在所有函数之外。#include<iostream>

intmain(){std::cout<<"Entertwonumbers:"<<std::endl;inta=0,b=0;std::cin>>a>>b;std::cout<<"Thesumof"<<a<<"and"<<b<<"is"<<a+b<<std::endl;return0;}示例103.1C++编程基础IO库该示例主函数(main函数)中的第一条语句执行了一个表达式(通常是由运算对象和运算符组成),该表达式使用了两次输出运算符<<在标准输出cout上打印消息。#include<iostream>

intmain(){std::cout<<"Entertwonumbers:"<<std::endl;inta=0,b=0;std::cin>>a>>b;std::cout<<"Thesumof"<<a<<"and"<<b<<"is"<<a+b<<std::endl;return0;}示例输出113.1C++编程基础IO库在该表达式中,第一个输出运算符<<左侧的运算对象为ostream类型对象,输出运算符<<右侧的运算对象为打印的消息,而第一个输出运算符<<的运算结果成为了第二输出运算符<<左侧的运算对象,如此一来便可将打印消息连接起来。#include<iostream>

intmain(){std::cout<<"Entertwonumbers:"<<std::endl;inta=0,b=0;std::cin>>a>>b;std::cout<<"Thesumof"<<a<<"and"<<b<<"is"<<a+b<<std::endl;return0;}示例输出123.1C++编程基础IO库需要说明的是,该示例主函数第一条语句中的第二输出运算符用于打印endl,这是一种操纵符的特殊值,其表示结束当前行。此外,该示例主函数第一条语句中使用的是std::cout和std::endl,而非直接使用cout和endl,前缀std::表明cout和endl定义在名为std的命名空间(namespace),命名空间机制能够有效避免同名冲突。#include<iostream>

intmain(){std::cout<<"Entertwonumbers:"<<std::endl;inta=0,b=0;std::cin>>a>>b;std::cout<<"Thesumof"<<a<<"and"<<b<<"is"<<a+b<<std::endl;return0;}示例输出133.1C++编程基础IO库该示例主函数第二条语句中定义两个int类型(整型)变量a和b来存储输入内容,并对其进行初始化。#include<iostream>

intmain(){std::cout<<"Entertwonumbers:"<<std::endl;inta=0,b=0;std::cin>>a>>b;std::cout<<"Thesumof"<<a<<"and"<<b<<"is"<<a+b<<std::endl;return0;}示例143.1C++编程基础IO库该示例主函数第三条语句中使用输入运算符>>,输入运算符>>左侧的运算对象为istream类型对象,输入运算符>>右侧的运算对象为存入对象,输入运算符>>返回其左侧运算对象作为其运算结果。#include<iostream>

intmain(){std::cout<<"Entertwonumbers:"<<std::endl;inta=0,b=0;std::cin>>a>>b;std::cout<<"Thesumof"<<a<<"and"<<b<<"is"<<a+b<<std::endl;return0;}示例输入153.1C++编程基础IO库最后,打印运算结果,包括字符串字面值常量(如“Thesumof”,“and”,“is”)、int值(如a,b,a+b)等。#include<iostream>

intmain(){std::cout<<"Entertwonumbers:"<<std::endl;inta=0,b=0;std::cin>>a>>b;std::cout<<"Thesumof"<<a<<"and"<<b<<"is"<<a+b<<std::endl;return0;}示例163.1C++编程基础复合类型变量在C++中,对象通常也被称为变量。变量是程序中具有名称的可操作存储空间,其内存占用大小、布局方式、数值范围以及支持的运算均由其数据类型决定。数据类型可分为算术类型和void类型。常见的算术类型有字符char、整型int、布尔类型bool、单精度浮点数float及双精度浮点数double等,其中布尔类型bool的取值为真(true)或假(false)。void类型没有关联具体的值,最常见的就是使用void类型作为无返回值函数的返回类型。173.1C++编程基础复合类型变量引用是C++中为已存在的对象创建的别名,它本身并不是独立的对象,而是绑定到另一个已存在对象的标识符。引用类型通过将声明符写成&refVal的形式来定义引用类型,其中refVal表示声明的变量名称,第二条语句表示refVal指向ival,即refVal是ival的别名。intival=1024;int&refVal=ival;示例引用183.1C++编程基础复合类型变量通常,当我们初始化变量时,会将初始值的副本存入新创建的对象中。而对于引用的定义,我们并非复制初始值,而是将引用直接绑定到初始化对象上。引用一旦完成初始化,就会永久绑定其初始对象,无法重新绑定到其他对象。正因如此,引用必须在定义时进行初始化,这一点与指针有所不同。intival=1024;int&refVal=ival;示例引用193.1C++编程基础复合类型变量指针是C++中另一种常见的复合类型,它和引用一样可用于间接访问对象,但在本质上存在显著差异。作为独立对象,指针支持赋值和拷贝操作,并可在生命周期内改变所指向的对象。与引用必须初始化的特性不同,指针允许延迟初始化,若在块作用域内定义的指针未初始化,其值将处于未定义状态,这点与其他内置类型一样。指针stringstr="astring",*pt=&str;autonum=str.size();num=(*pt).size();num=pt->size();示例203.1C++编程基础复合类型变量指针类型通过将声明符写成*pt的形式来定义引用类型,其中pt表示声明的变量名称,第一条语句表示pt是指向变量str的指针,即pt存放着变量str的地址。需要说明的是,指针使用操作符&是作为取址符出现在表达式中,而引用使用操作符&则是作为声明的一部分紧随类型名出现。指针stringstr="astring",*pt=&str;autonum=str.size();num=(*pt).size();num=pt->size();示例用途:如遍历数组213.1C++编程基础复合类型变量第二条语句运行string对象str的size成员并赋值给auto类型变量num。指针stringstr="astring",*pt=&str;autonum=str.size();num=(*pt).size();num=pt->size();示例223.1C++编程基础复合类型变量第三条语句运行pt所指对象的size成员。指针stringstr="astring",*pt=&str;autonum=str.size();num=(*pt).size();num=pt->size();示例233.1C++编程基础复合类型变量第四条语句中表达式pt->size()等价于第三条语句中表达式(*pt).size()。指针stringstr="astring",*pt=&str;autonum=str.size();num=(*pt).size();num=pt->size();示例243.1C++编程基础迭代语句迭代语句通常称为循环,用于在条件为真时重复执行操作。C++提供了多种循环结构,其中while和for是最常用的两种。这两种循环均采用先判断条件后执行的方式:while循环在条件持续为真时重复执行语句,而for循环则通过初始化、条件判断和迭代更新三个部分提供更紧凑的循环控制结构。它们适用于不同的场景,如while适合不确定迭代次数的情况(如读取输入),而for更适合已知或需要精确控制循环次数的任务(如遍历数组)。253.1C++编程基础迭代语句以计算输入数字之和为例。在源文件的开始位置使用using声明则不用添加std::形式便可访问命名空间std里的成员(如主函数中的第二条语句可直接使用cin,无须写成std::cin的形式,读取输入数字num)。while#include<iostream>usingnamespacestd;

intmain(){intnum,sum=0;cin>>num;while(num!=0){sum+=num;cin>>num;}return0;}示例263.1C++编程基础迭代语句主函数中的第三条语句中使用了while语句,表示只要num不等于0,循环就会继续执行。while语句在条件持续为真时重复执行目标语句,首次条件为假则跳过循环,且条件不可为空(通常为表达式或已初始化变量声明)。while#include<iostream>usingnamespacestd;

intmain(){intnum,sum=0;cin>>num;while(num!=0){sum+=num;cin>>num;}return0;}示例273.1C++编程基础迭代语句通过主函数中的第四条语句将每次输入的数字num累加到变量sum中。while#include<iostream>usingnamespacestd;

intmain(){intnum,sum=0;cin>>num;while(num!=0){sum+=num;cin>>num;}return0;}示例283.1C++编程基础迭代语句在循环内部读取下一个输入,直至输入0跳过循环。while#include<iostream>usingnamespacestd;

intmain(){intnum,sum=0;cin>>num;while(num!=0){sum+=num;cin>>num;}return0;}示例迭代语句for语句头初始化部分一般情况下只初始化一个值,这个值会随着循环的进行而改变。条件判断部分作为循环控制的条件,当判断语句为真时,则执行循环体,当判断语句为假时,则终止循环。迭代更新部分负责在每次循环后对初始部分中的变量进行修改。#include<iostream>#include<vector>usingnamespacestd;

intmain(){vector<int>num;for(inti=1;i<=5;i++){num.push_back(i*i);}return0;}293.1C++编程基础for示例初始化部分条件判断部分迭代更新部分迭代语句以计算1到5的整数平方为例。主函数中的第一条语句中创建一个空的vector对象num,用于存储整型元素。#include<iostream>#include<vector>usingnamespacestd;

intmain(){vector<int>num;for(inti=1;i<=5;i++){num.push_back(i*i);}return0;}303.1C++编程基础for示例迭代语句主函数中的第二条语句使用for语句头初始化整型变量i,通过判断i是否小于等于5决定是否执行循环体,每次循环后对变量i的值进行修改。313.1C++编程基础#include<iostream>#include<vector>usingnamespacestd;

intmain(){vector<int>num;for(inti=1;i<=5;i++){num.push_back(i*i);}return0;}for示例迭代语句循环体中使用命名空间vector中的成员函数push_back,将i的平方(i*i)添加到vector对象num的末尾。当判断语句i<=5不为真时,则终止循环。323.1C++编程基础#include<iostream>#include<vector>usingnamespacestd;

intmain(){vector<int>num;for(inti=1;i<=5;i++){num.push_back(i*i);}return0;}for示例333.1C++编程基础条件语句C++提供了if和switch两种条件执行语句,分别适用于不同的分支控制场景。其中if语句主要根据布尔条件决定控制流,可嵌套使用;而switch语句则是根据整型表达式结果选择执行路径,通过case标签实现多路分支,通常需要配合break使用。条件语句if语句的作用是判断一个指定的条件是否为真,根据判断结果决定程序执行路径。当判断语句为真时,则执行对应的语句;当判断语句为假时,则跳过对应的语句。343.1C++编程基础ifif(grade<60)lettergrade=scores[0];else{lettergrade=scores[(grade-50)/10];if(grade!=100)if(grade%10>7)lettergrade+='+';elseif(grade%10<3)lettergrade+='-';}示例条件语句以给等级制考核合格成绩(等级制与百分制成绩转换按:90-100分计优秀,80-89分计良好,70-79分计中等,60-69分计及格,<60计不及格)后面添加加减号为例,第一条语句用于判断百分制成绩grade的值是否小于60。353.1C++编程基础ifif(grade<60)lettergrade=scores[0];else{lettergrade=scores[(grade-50)/10];if(grade!=100)if(grade%10>7)lettergrade+='+';elseif(grade%10<3)lettergrade+='-';}示例条件语句当判断语句为真时,则执行第二条语句将scores[0]赋值给等级制成绩lettergrade;363.1C++编程基础ifif(grade<60)lettergrade=scores[0];else{lettergrade=scores[(grade-50)/10];if(grade!=100)if(grade%10>7)lettergrade+='+';elseif(grade%10<3)lettergrade+='-';}示例条件语句否则,执行第四条语句将scores[(grade-50)/10]赋值给lettergrade。373.1C++编程基础ifif(grade<60)lettergrade=scores[0];else{lettergrade=scores[(grade-50)/10];if(grade!=100)if(grade%10>7)lettergrade+='+';elseif(grade%10<3)lettergrade+='-';}示例条件语句然后,判断grade的值是否不等于100。383.1C++编程基础ifif(grade<60)lettergrade=scores[0];else{lettergrade=scores[(grade-50)/10];if(grade!=100)if(grade%10>7)lettergrade+='+';elseif(grade%10<3)lettergrade+='-';}示例条件语句当判断语句为真时,则根据算术运算符%求取余数,判断余数大于7还是小于3决定添加加号“+”还是减号“-”。393.1C++编程基础ifif(grade<60)lettergrade=scores[0];else{lettergrade=scores[(grade-50)/10];if(grade!=100)if(grade%10>7)lettergrade+='+';elseif(grade%10<3)lettergrade+='-';}示例#include<iostream>usingnamespacestd;

intmain(){intaCount=0,eCount=0,iCount=0,oCount=0,uCount=0;charch;while(cin.get(ch)){switch(ch){case'a':++aCount;break;case'e':++eCount;break;case'i':++iCount;break;case'o':++oCount;break;case'u':++uCount;break;}}return0;}条件语句403.1C++编程基础示例switch语句提供了一种便捷的方式来从多个固定选项中选择执行路径。switch#include<iostream>usingnamespacestd;

intmain(){intaCount=0,eCount=0,iCount=0,oCount=0,uCount=0;charch;while(cin.get(ch)){switch(ch){case'a':++aCount;break;case'e':++eCount;break;case'i':++iCount;break;case'o':++oCount;break;case'u':++uCount;break;}}return0;}条件语句413.1C++编程基础switch示例以文本片段中五个元音字母('a'、'e'、'i'、'o'、'u')各自出现的次数为例。主函数中的第三条语句使用while语句循环读取输入的每个字符。#include<iostream>usingnamespacestd;

intmain(){intaCount=0,eCount=0,iCount=0,oCount=0,uCount=0;charch;while(cin.get(ch)){switch(ch){case'a':++aCount;break;case'e':++eCount;break;case'i':++iCount;break;case'o':++oCount;break;case'u':++uCount;break;}}return0;}条件语句423.1C++编程基础switch示例主函数中的第四条语句利用switch语句匹配不同ch的值对应的case(该示例中case标签为五个元音字母)。#include<iostream>usingnamespacestd;

intmain(){intaCount=0,eCount=0,iCount=0,oCount=0,uCount=0;charch;while(cin.get(ch)){switch(ch){case'a':++aCount;break;case'e':++eCount;break;case'i':++iCount;break;case'o':++oCount;break;case'u':++uCount;break;}}return0;}条件语句433.1C++编程基础switch示例执行与元音匹配的case分支代码,将该元音对应的计数值(aCount、eCount、iCount、oCount、uCount)加1。#include<iostream>usingnamespacestd;

intmain(){intaCount=0,eCount=0,iCount=0,oCount=0,uCount=0;charch;while(cin.get(ch)){switch(ch){case'a':++aCount;break;case'e':++eCount;break;case'i':++iCount;break;case'o':++oCount;break;case'u':++uCount;break;}}return0;}条件语句443.1C++编程基础switch示例case分支以break语句结尾跳出,将控制权转移到while语句循环中。453.1C++编程基础类在C++中,类(Class)是一种用户自定义的数据类型,用于封装数据(成员变量)和操作数据的方法(成员函数)。类的主要目的是提高代码的模块化、可重用性和安全性。作为面向对象编程的核心概念,类具有封装和继承的特性:封装是指将数据和操作隐藏在一个单元中,通过访问控制保护内部状态,用户只能使用接口而无法访问实现部分;继承是指允许派生类继承基类的成员,实现代码复用。463.1C++编程基础类通常使用访问说明符public或private控制类中成员(变量和函数)的可见性和访问权限:定义在public说明符之后的成员在整个程序内可被访问(public成员定义类的接口对外提供功能)。定义在private说明符之后的成员可被类的成员访问,但是不能被使用该类的代码访问(private封装了类的实现细节)。类473.1C++编程基础#include<iostream>#include<string>usingnamespacestd;

classStudent{private:stringname;intage;

public:voidsetName(stringn){name=n;}voidsetAge(inta){age=a;}voiddisplay(){cout<<"姓名:"<<name<<",年龄:"<<age<<endl;}};

intmain(){Studentstu;stu.setName("张三");stu.setAge(20);stu.display();

return0;}示例以定义和使用一个简单的Student类为例。定义一个Student类,通过private说明符指定外部无法直接访问成员name和age。类483.1C++编程基础#include<iostream>#include<string>usingnamespacestd;

classStudent{private:stringname;intage;

public:voidsetName(stringn){name=n;}voidsetAge(inta){age=a;}voiddisplay(){cout<<"姓名:"<<name<<",年龄:"<<age<<endl;}};

intmain(){Studentstu;stu.setName("张三");stu.setAge(20);stu.display();

return0;}示例再者通过public说明符指定成员setName、setAge和display作为可被外部访问的接口。类493.1C++编程基础#include<iostream>#include<string>usingnamespacestd;

classStudent{private:stringname;intage;

public:voidsetName(stringn){name=n;}voidsetAge(inta){age=a;}voiddisplay(){cout<<"姓名:"<<name<<",年龄:"<<age<<endl;}};

intmain(){Studentstu;stu.setName("张三");stu.setAge(20);stu.display();

return0;}示例主函数中的第一条语句创建Student类型对象stu。类503.1C++编程基础#include<iostream>#include<string>usingnamespacestd;

classStudent{private:stringname;intage;

public:voidsetName(stringn){name=n;}voidsetAge(inta){age=a;}voiddisplay(){cout<<"姓名:"<<name<<",年龄:"<<age<<endl;}};

intmain(){Studentstu;stu.setName("张三");stu.setAge(20);stu.display();

return0;}示例主函数中的第二、三条语句调用函数setName和setAge分别设置private成员name和age。类513.1C++编程基础#include<iostream>#include<string>usingnamespacestd;

classStudent{private:stringname;intage;

public:voidsetName(stringn){name=n;}voidsetAge(inta){age=a;}voiddisplay(){cout<<"姓名:"<<name<<",年龄:"<<age<<endl;}};

intmain(){Studentstu;stu.setName("张三");stu.setAge(20);stu.display();

return0;}示例主函数中的第四条语句调用函数display输出“姓名:张三,年龄:20”。523.1C++编程基础模板模板是一种泛型编程工具,它允许开发者编写与数据类型无关的通用代码。通过定义函数模板和类模板,可以实现同一套逻辑适用于多种数据类型,有效避免重复编写相似代码。函数模板用于创建处理不同数据类型的通用函数。类模板则用于构建处理不同数据类型的通用类。通常模板定义以关键字template开始,后跟模板参数列表,模板参数列表不能为空,表中的模板参数用于表示在类或函数定义中用到的类型或值,类型参数前一般使用关键字class或typename(两个关键字的含义相同,可以互换使用)。533.1C++编程基础模板模板本身并不是具体的类或函数,而是编译器生成具体代码的蓝图。只有当提供具体的模板参数时(这个过程称为实例化),编译器才会根据模板生成实际的类或函数。模板543.1C++编程基础以交换两个变量的值为例。定义一个函数模板用于实现交换两个变量的值的功能。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板模板553.1C++编程基础函数swapValues声明了一个名为T的类型参数(T是占位符,其实际表示的类型则在编译时根据swapValues的使用情况来定)。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板模板563.1C++编程基础主函数中分别调用函数swapValues对两组不同类型变量进行处理。主函数中的第一条语句中定义两个int类型变量x和y来存储输入内容,并对其进行赋值。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板模板573.1C++编程基础主函数中的第二条语句中调用函数swapValues交换两个int类型变量的值。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板模板583.1C++编程基础主函数中的第三条语句输出“x=20,y=10”。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板模板593.1C++编程基础而主函数中的第四条语句中则是定义两个double类型变量m和n来存储输入内容,并对其进行赋值。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板模板603.1C++编程基础主函数中的第五条语句中调用函数swapValues交换两个double类型变量的值。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板模板613.1C++编程基础主函数中的第六条语句输出“m=2.5,n=1.5”。#include<iostream>usingnamespacestd;

template<typenameT>voidswapValues(T&a,T&b){Ttemp=a;a=b;b=temp;}

intmain(){intx=10,y=20;swapValues(x,y);cout<<"x="<<x<<",y="<<y<<endl;

doublem=1.5,n=2.5;swapValues(m,n);//T为doublecout<<"m="<<m<<",n="<<n<<endl;}示例函数模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板623.1C++编程基础以通用数组类为例。定义一个类模板(以关键字template和参数列表开始,后跟关键字class定义一个GenericArray类)。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板633.1C++编程基础通过private说明符指定外部无法直接访问含有size个元素的泛型数组arr。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板643.1C++编程基础通过public说明符指定函数set和get作为可被外部访问的接口。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板653.1C++编程基础主函数中分别调用GenericArray类对两组含有不同类型元素的数组进行处理。主函数中的第一条语句中定义GenericArray类型对象intArray存储含有5个元素的int类型数组。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板663.1C++编程基础主函数中的第二条语句中调用函数set对数组中第一个元素赋值100。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板673.1C++编程基础主函数中的第三条语句中调用函数get输出数组中第一个元素“100”。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板683.1C++编程基础而主函数中的第四条语句中则是定义GenericArray类型对象strArray存储含有3个元素的string类型数组。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板693.1C++编程基础主函数中的第五条语句中调用函数set对数组中第二个元素赋字符串“Hello”。示例类模板#include<iostream>usingnamespacestd;

template<typenameT,intsize>classGenericArray{private:Tarr[size];public:voidset(intindex,Tvalue){arr[index]=value;}Tget(intindex){returnarr[index];}};

intmain(){GenericArray<int,5>intArray;intArray.set(0,100);cout<<intArray.get(0)<<endl;

GenericArray<string,3>strArray;strArray.set(1,"Hello");cout<<strArray.get(1)<<endl;}模板703.1C++编程基础主函数中的第六条语句中调用函数get输出数组中第二个元素“Hello”。示例类模板713.2ROS编程基础723.2ROS编程基础ROS(RobotOperatingSystem)是专为机器人系统开发设计的分布式计算框架和开源中间件平台。自2007年由斯坦福大学人工智能实验室和WillowGarage公司联合研发以来,现已成为全球机器人领域的事实标准。其优势在于:其去中心化的点对点通信机制实现了高效的节点间直接交互;基于接口定义语言(IDL)的设计支持C++、Python、Java等多语言的无缝协同开发;模块化的开源生态系统完整覆盖了从环境感知、决策规划到运动控制的全流程功能链。733.2ROS编程基础在工具支持方面,ROS提供了Rviz三维可视化工具、Gazebo高保真仿真环境和ROSbag数据记录回放等全周期开发套件。其微内核架构专注于消息传递、软件包管理和硬件抽象等核心服务,通过Catkin构建系统实现了功能模块的松耦合集成。目前,ROS已广泛应用于学术研究、工业自动化、服务机器人等多个领域。下面将从文件系统与通信机制、常用命令行工具、创建工作空间与功能包、发布/订阅话题消息、话题消息的定义和使用、客服端请求与服务端应答、服务数据的定义与使用等方面分节介绍ROS编程相关基础要点。743.2ROS编程基础文件系统与通信机制(1)文件系统文件系统是ROS框架中组织和存储代码、配置文件、消息定义等资源的标准化结构。ROS通过层次化的工作空间(catkin_workspace)架构实现机器人开发的模块化管理。工作空间主要由src(开发者维护的源代码)、build(catkin自动管理的编译缓存)和devel(生成的可执行文件及开发环境)三个核心目录构成,其中build和devel目录由系统自动维护,开发者只需专注于src目录下的代码开发。753.2ROS编程基础文件系统与通信机制(1)文件系统763.2ROS编程基础文件系统与通信机制(1)文件系统autoware.aisrcbuildlindar_localizercore_perceptionnodesautowareMetapackageMetapackagePackage773.2ROS编程基础文件系统与通信机制(1)文件系统功能包(Package)是ROS软件中的基本单元,在功能包内可以编写实现某功能的节点程序,添加节点运行依赖的库、配置文件和数据集等。一组相关的功能包可以打包成一个元功能包(MetaPackage)。每个功能包包含两个核心文件(CMakeLists.txt和package.xml)以及若干标准目录(包含include文件夹、launch文件夹、src文件夹、config文件夹、msg文件夹和srv文件夹)。783.2ROS编程基础文件系统与通信机制(1)文件系统CmakeList文件为功能包的编译文件,ROS下的catkin编译系统对工作空间进行编译是对所有功能包进行编译,编译完成后生成build和devel两个文件夹。package.xml文件为功能包清单,用于记录该功能包的基本信息,包含名称、版本、描述、许可信息、依赖选项等。核心文件793.2ROS编程基础文件系统与通信机制(1)文件系统include文件夹中的.h文件为实现C++文件功能所需的头文件。launch文件夹主要用于存放可执行文件的启动文件(.launch文件)。src文件夹用于存放实现该功能包功能的C++代码文件(.cpp文件)。标准目录803.2ROS编程基础文件系统与通信机制(1)文件系统config文件夹用于存在该功能包所需的所有配置文件(.yaml文件),由用户进行创建。srv和msg两个文件夹分别用于存放服务与消息的描述文件:.srv文件用于定义ROS中服务请求和应答的数据结构。.msg文件则是用于定义ROS中发送消息的数据结构。标准目录813.2ROS编程基础文件系统与通信机制(2)通信机制ROS采用分布式通信机制实现多节点(Node)间的交互,其中节点是执行具体任务的独立进程或可执行文件。每个节点必须具有唯一名称,支持不同编程语言开发,并可以分布式部署在不同主机上运行。ROS提供两种核心通信方式:话题通信机制服务通信机制823.2ROS编程基础文件系统与通信机制(2)通信机制话题通信机制基于发布/订阅模型实现单向异步数据传输,适用于传感器数据传输等高频场景;服务通信机制采用客户端/服务端模型实现双向同步交互,适合低频的指令控制等任务。这两种机制虽然都基于TCP连接,但在通信模型、缓冲机制等方面存在显著差异。使用场景不同833.2ROS编程基础文件系统与通信机制(2)通信机制话题通信采用松耦合的发布/订阅模式,消息通过话题(Topic)进行异步传输,适用于持续性的数据流传输;服务通信通过服务(Service)建立紧密的客户端和服务端关系,实现请求-应答的同步交互,更适合离散式的任务调用。二者使用的接口定义文件(msg文件与srv文件)及适用场景也各不相同,开发者需要根据具体需求选择合适的通信方式。843.2ROS编程基础文件系统与通信机制(2)通信机制话题通信与服务通信在多个维度呈现明显区别。.特性话题服务通信模型发布/订阅服务端/客户端通信方式单向异步通信双向同步通信缓冲区有缓冲无缓冲节点关系多对多一对多消息类型定义文件.msg文件.srv文件适用场景高频数据传输低频任务处理853.2ROS编程基础文件系统与通信机制(2)通信机制话题通信863.2ROS编程基础文件系统与通信机制(2)通信机制发布者(Publisher)和订阅者(Subscriber)两个节点启动后,将分别向节点管理器(ROSMaster)注册各自信息。节点管理器不仅用于为节点提供注册服务,还会根据订阅者的订阅信息从注册列表中查找匹配的发布者。如果没有找到匹配的发布者,则等待发布者加入;如果有找到匹配的发布者,则向订阅者发送匹配的发布者信息。订阅者根据节点管理器发回的发布者信息,向发布者发送连接请求。话题通信873.2ROS编程基础文件系统与通信机制(2)通信机制订阅者在收到发布者发回的确认消息后了,与发布者建立TCP网络连接。成功建立连接后,发布者便可向订阅者发送话题消息数据。消息(Message)由msg文件定义,该文件支持ROS标准类型和用户自定义类型,在编译时会自动生成对应的代码文件,为话题通信提供统一的数据交互规范。话题通信883.2ROS编程基础文件系统与通信机制(2)通信机制服务通信893.2ROS编程基础文件系统与通信机制(2)通信机制服务端(Server)和客户端(Client)两个节点启动后,将分别向节点管理器注册各自信息。节点管理器不仅用于为节点提供注册服务,还会根据客户端需要的服务信息从注册列表中查找匹配的服务端。如果没有找到匹配的服务端,则等待服务端加入;如果有找到匹配的服务端,则向客户端发送匹配的服务端信息。客户端根据节点管理器发回的服务端信息,向服务端发送连接请求。服务通信903.2ROS编程基础文件系统与通信机制(2)通信机制客户端在收到服务端发回的确认消息后了,与服务端建立TCP网络连接。成功建立连接后,客户端向服务端发送服务请求。服务端收到服务请求后,开始执行相应功能,执行完成后便向客户端发送应答数据。服务(Service)由srv文件定义,该文件在编译时会自动生成对应的代码文件,为服务通信提供标准化的请求-应答数据交互规范。服务通信913.2ROS编程基础文件系统与通信机制(2)通信机制ROS参数管理机制通过参数服务器(ParameterServer)提供一种可通过网络访问的全局共享参数存储系统,允许节点存储和访问静态配置数据,其支持整型、浮点、布尔、字符串、列表等数据类型。参数服务器独立于节点通信,适合存储硬件参数、算法超参数等非动态数据,节点可通过rosparam命令行工具或编程接口(如rospy.get_par

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论