准备条件
假如你是一个小白,先找到相关的参考资料(已根据上一篇博客安装好Veins),主要是官方文档和相关的博客,官方提供了一个example,我找到的资料如下:
- Frequently Asked Questions (FAQ)
- OMNeT++ Documentation
博客:
Frank-Veins教程
ZhengKX-Veins入门教程
Questions tagged [veins]
AI助手:
Chatgpt
给他一个角色扮演,Veins网络仿真专家,不懂的代码随时扔给它。
代码架构
antenna.xml #车辆天线配置文件
config.xml #物理层无线电传播相关参数。默认的配置是信号穿过建筑有衰减,如示例中将信号路径衰落的模型配置为“SmiplePathlossModel”,障碍物引起的信号衰落模型设置为“SimpleObstacleShadowing”,一般使用默认的即可;前期如果不需要这个配置,可以将db-per-cut和db-per-meter都改成0。
erlangen.launched.xml #启动sumo的配置文件,不更改
erlangen.net.xml # SUMO路网文件,跑自己的仿真时需要替换
erlangen.png #一张地图图片
erlangen.poly.xml:如果SUMO路网文件是由地图转化而来的,如从OpenStreetMap导入的,则路网文件中还将包含所选地区的建筑物的信息,通过SUMO提供的OpenStreetMap Web接口便可生成记录这些建筑物形状、大小和位置信息的配置文件,作为config.xml内信号衰落模型的输入;如果不考虑建筑物对于信号传播的影响则无需此文件,当然config.xml内的信号衰落模型的配置也要删去;简而言之:记录地图中建筑信息的文件
erlangen.rou.xml:交通流文件(大概是生成的小车往哪里走,规划行驶路线)
erlangen.sumo.cfg: SUMO运行文件,可对运行时长等运行参数进行配置;
omnetpp.ini: OMNeT++运行文件,后文重点讲解;点击左下角的Source就看到源码,默认是Form。
RSUExampleScnario.ned: OMNeT++类似于积木,一个工程项目是由多个ned文件互相嵌套组合而成的。veins作为一个基于OMNeT++的框架,其便是由层次分明的ned文件组合而成的,如果学过面向对象编程的话可能会容易理解一些,这些ned文件就类似一个个类。但是OMNeT++中更为特殊,因为ned文件只是定义了组件的结构,比如定义一辆车,ned只是描述了它包含几个对外通信的接口,这些接口的参数之类的,具体的功能还需要与ned文件同名的C++文件进行定义,比如用这些接口选择与谁进行通信,专业点就叫路由。这里的RSUExampleScnario.ned定义了OMNeT++中最大的结构——网络(network),可以看到在omnetpp.ini中的[General]部分对于本次仿真所运行的网络定义为RSUExampleScenario;
OMNet++独特的ned网络语言需要结合官方文档和相关视频博客开始学习,我将找到的相关资料整理在这:
OMNeT++ Technical Articles- TicToc Tutorial
Simulation Manual (pdf)
视频:
协议森林主页
OMNet++初学-进阶-精进历程分享
当然github上也有一个教程及Youtube视频,英文的:VANETTutorials,视频搬到b站了VANET和OMNET++、INET、Veins和SUMO仿真模拟教程。b站也有一些其他的视频,自行搜索。
omnetpp.ini
好了,到这网上讲的就不多了,有的是挑关键的讲一讲,这个时候就可以上GPT了,代码一顿喂饱,让它来详细解释一下这段代码:
General Section:
cmdenv-express-mode, cmdenv-autoflush, cmdenv-status-frequency, **.cmdenv-log-level:
这些配置项是有关OMNeT++运行环境的设置,如日志级别、自动刷新等。
image-path:
设置了图像文件的路径,通常用于地图等图形可视化。
network:
定义了仿真中使用的网络场景。在这里,网络场景是"RSUExampleScenario",这可能是一个您自定义的场景名称。
Simulation Parameters:
4. debug-on-errors, print-undisposed, sim-time-limit:
这些参数控制了仿真的调试行为、是否打印未释放的对象以及仿真的时间限制。
**.scalar-recording, **.vector-recording:
启用了标量和矢量数据的记录,以便在仿真运行后进行分析。
*.playgroundSizeX, *.playgroundSizeY, *.playgroundSizeZ:
定义了仿真场景的大小,包括X、Y和Z方向。
Annotation Parameters:
7. *.annotations.draw:
控制是否绘制注释信息。通常在可视化仿真结果时使用。
Obstacle Parameters:
8. *.obstacles.obstacles:
使用xmldoc函数引用了一个XML配置文件,该文件定义了障碍物的位置和特性。这些障碍物可以影响通信和车辆移动。
TraCIScenarioManager Parameters:
9. 该部分包括了有关TraCI(交通控制接口)的参数,用于与仿真管理器进行通信。
RSU Settings:
10. 这一部分设置了RSU的参数,包括位置坐标、应用程序类型、通信参数等。这定义了RSU的行为和通信方式。
11p Specific Parameters:
11. 这部分包括了与IEEE 802.11p通信标准相关的参数,如发送距离、发射功率、信噪比等。
App Layer:
12. 这一部分设置了应用层的参数,包括应用程序类型、数据传输设置等。
Mobility:
13. 这一部分定义了车辆的移动行为,包括位置坐标、速度等。还包括了车辆事故的设置。
Config Default and Other Configurations:
14. 最后,提供了一些配置块,用于定义不同的仿真配置。例如,"Config WithBeaconing"启用了RSU和车辆发送信标。
这段配置文件定义了Veins仿真的各种设置,从基本的仿真参数到车辆和RSU的通信参数,以及特定的应用层和移动行为设置。
network:非常关键的参数,需要替换成自己的network级ned文件;
sim-time-limit: 网络仿真时间限制,注意与SUMO生成的交通流运行时长对应;
RSU SETTINGS: 对RSUExampleScnario.ned中的路侧单元ned中的参数做出设置。其中最重要的就是applType,它指定了RSU的应用层,也就是RSU会做什么。其实RSU也是一个ned文件,比network级低,它是由另外几个更低级的ned组成的,包括作为应用层的ned(appl),作为MAC层的ned(nic),作为移动驱动的ned(mobility)。applType指定的就是应用层的ned,而应用层ned的功能又由其同名且在同一个文件夹的C++文件定义,这样RSU的功能也就确定了,做应用层研究的要改变的就是这个应用层的ned与对应的C++文件。至于后面那些参数都是对于应用层ned中的一些参数做出设置,比如.rsu[*].appl.beaconUserPriority = 7就是令所有RSU应用层的信标优先级为7。
RSU的ned文件
这段代码定义了一个Veins仿真中的RSU(Roadside Unit)模块,模块名为"RSU"。让我为您逐行解释这段代码的含义:
package org.car2x.veins.nodes;:
这行代码指定了模块所在的Java包(package)。该模块位于org.car2x.veins.nodes包中。
import org.car2x.veins.base.modules.*; 和 import org.car2x.veins.modules.nic.Nic80211p;:
这些是Java的import语句,用于引入所需的Java类和模块。
module RSU:
这行代码定义了一个RSU模块。
parameters::
这个部分用于定义模块的参数,包括applType和nicType。
string applType;:
这个参数定义了应用层的类型(applType)。在Veins中,应用层类型通常用于定义RSU的应用程序行为。
string nicType = default("Nic80211p");:
这个参数定义了网络接口卡的类型(nicType)。默认情况下,它被设置为"Nic80211p",这是IEEE 802.11p标准的网络接口卡类型。
gates::
这个部分用于定义模块的输入和输出门(gates)。在这里,定义了一个输入门veinsradioIn,用于sendDirect。
submodules::
这个部分用于定义模块的子模块。在这里,定义了三个子模块:appl、nic和mobility。
appl: <applType> like org.car2x.veins.base.modules.IBaseApplLayer:
这行代码定义了appl子模块,其类型是根据applType参数动态选择的应用层类型。这种方式允许根据仿真配置选择不同的应用层实现。
nic: <nicType> like org.car2x.veins.modules.nic.INic80211p:
这行代码定义了nic子模块,其类型是根据nicType参数动态选择的网络接口卡类型。同样,这种方式允许根据仿真配置选择不同的网络接口卡实现。
mobility: BaseMobility:
这行代码定义了mobility子模块,它是基本移动性模块。
connections::
这个部分用于定义模块之间的连接。在这里,定义了一系列连接,将nic和appl模块之间的输入输出连接起来,以及将veinsradioIn连接到nic模块的radioIn门。
这段代码定义了一个RSU模块,其中包括应用层、网络接口卡和移动性模块。模块的类型和连接方式可以根据参数(如applType和nicType)进行动态配置,使得Veins仿真更加灵活和可定制。这是Veins中定义模块的一种典型方式。
11p specific parameters NIC-Settings:对MAC层ned(nic)相关参数做出设置,nic包含两个子ned(mac1609_4和phy80211p)。至于connectionManager基本保持不变,如果要研究信号传播范围的影响的话,需要改变maxInterfDist;
package org.car2x.veins.modules.nic;
import org.car2x.veins.modules.phy.PhyLayer80211p;
import org.car2x.veins.modules.mac.ieee80211p.Mac1609_4;
//
// This NIC implements an 802.11p network interface card.
//
// @author David Eckhoff
//
// @see DemoBaseApplLayer
// @see Mac1609_4
// @see PhyLayer80211p
//
module Nic80211p like INic80211p
{
parameters:
string connectionManagerName = default("connectionManager");
gates:
input upperLayerIn; // to upper layers
output upperLayerOut; // from upper layers
output upperControlOut; // control information
input upperControlIn; // control information
input radioIn; // radioIn gate for sendDirect
submodules:
phy80211p: PhyLayer80211p {
@display("p=69,218;i=block/process_s");
}
mac1609_4: Mac1609_4 {
@display("p=69,82");
}
connections:
radioIn --> phy80211p.radioIn;
mac1609_4.lowerControlOut --> phy80211p.upperControlIn;
mac1609_4.lowerLayerOut --> phy80211p.upperLayerIn;
phy80211p.upperLayerOut --> mac1609_4.lowerLayerIn;
phy80211p.upperControlOut --> mac1609_4.lowerControlIn;
mac1609_4.upperControlIn <-- upperControlIn;
mac1609_4.upperLayerIn <-- upperLayerIn;
mac1609_4.upperLayerOut --> upperLayerOut;
mac1609_4.upperControlOut --> upperControlOut;
}
这段代码定义了一个名为Nic80211p的Veins仿真模块,它是一个实现了IEEE 802.11p网络接口卡(NIC)的模块。让我为您逐行解释这段代码的含义:
package org.car2x.veins.modules.nic;:
这行代码指定了模块所在的Java包(package),这个模块位于org.car2x.veins.modules.nic包中。
import org.car2x.veins.modules.phy.PhyLayer80211p; 和 import org.car2x.veins.modules.mac.ieee80211p.Mac1609_4;:
这些是Java的import语句,用于引入所需的Java类和模块。
module Nic80211p like INic80211p:
这行代码定义了一个Veins仿真模块,名称为Nic80211p,并指定它实现了INic80211p接口。这意味着Nic80211p模块应该包括了符合802.11p标准的NIC功能。
parameters::
这个部分用于定义模块的参数,包括connectionManagerName。
string connectionManagerName = default("connectionManager");:
这个参数定义了连接管理器的名称,默认为"connectionManager"。
gates::
这个部分用于定义模块的输入和输出门(gates)。在这里,定义了输入门upperLayerIn、输出门upperLayerOut、输出门upperControlOut、输入门upperControlIn和输入门radioIn。
submodules::
这个部分用于定义模块的子模块。在这里,定义了两个子模块:phy80211p和mac1609_4。
phy80211p: PhyLayer80211p:
这行代码定义了phy80211p子模块,它表示802.11p物理层。
mac1609_4: Mac1609_4:
这行代码定义了mac1609_4子模块,它表示802.11p MAC层(Mac1609_4)。
connections::
这个部分用于定义模块之间的连接关系。连接包括将radioIn连接到phy80211p模块的radioIn门,以及将mac1609_4和phy80211p模块之间的输入和输出连接起来,以实现数据和控制信息的传输。
总的来说,这段代码定义了一个802.11p网络接口卡(NIC)模块,它包括了物理层(PhyLayer80211p)和MAC层(Mac1609_4)子模块。这种模块结构反映了802.11p标准中NIC的组成部分。这个NIC模块可以在Veins仿真中用于模拟车辆之间的通信和数据传输。 Veins允许用户根据具体仿真需求自定义NIC模块,以适应不同的研究场景。
App Layer: 对移动节点(车辆)的应用层做出设置,和RSU一个道理;
Mobility: 对移动节点的移动模块做出设置。其中accidentCount、accidentStart、accidentDuration这三个参数是对移动节点发生事故的事件做出设置,这是veins的examples演示的功能(事故预警消息的传播),我们用不到直接令accidentCount=0即可。
最后一个RSUExampleScnario.ned
看ned文件的import、extends往上慢慢捋就行。
看代码可以发现RSUExampleScnario内加入了一个RSU单元。
ned定义结构,同名C++文件定义功能。
从新啰嗦一遍,梳理一下:
从RSUExampleScenario.ned开始逐级往上,读懂代码并了解其用法。
点开RSUExampleScenario.ned可知网络主要继承于Scenario
除了继承的Scenario,RSUExampleScenario还定义了一个RSU,分别从这两个方向往上逐级深入:
Annotations
标注注解,暂不深入
World
提供一些整个项目可用的函数,暂不深入
Scenario
Scenario提供预制的Annotations,World,Manager,Obstacles,ConnectionManager和Node模块。其中Node就是车辆模块。
这段代码定义了一个名为"Scenario"的Veins仿真网络。这个网络表示一个仿真场景,其中包括了道路、车辆、通信和可视化等元素。我将逐行解释这段代码的含义:
package org.car2x.veins.nodes;:
这行代码指定了模块所在的Java包(package),这个模块位于org.car2x.veins.nodes包中。
import org.car2x.veins.base.connectionManager.ConnectionManager; 和其他import语句:
这些是Java的import语句,用于引入所需的Java类和模块。
network Scenario:
这行代码定义了一个名为"Scenario"的Veins仿真网络。
parameters::
这个部分用于定义网络的参数,包括仿真区域的大小(playgroundSizeX、playgroundSizeY、playgroundSizeZ)以及显示设置。
double playgroundSizeX @unit(m);:
定义了仿真区域的X轴尺寸,单位是米。
double playgroundSizeY @unit(m);:
定义了仿真区域的Y轴尺寸,单位是米。
double playgroundSizeZ @unit(m);:
定义了仿真区域的Z轴尺寸,单位是米。通常,这代表仿真场景的高度。
@display("bgb=$playgroundSizeX,$playgroundSizeY");:
这行代码通过@display注解定义了仿真区域的显示设置,使用了playgroundSizeX和playgroundSizeY参数来确定显示的边界框。
submodules::
这个部分用于定义网络中的子模块。
obstacles: ObstacleControl:
定义了一个名为obstacles的子模块,它是用于控制障碍物的模块。这些障碍物可以影响车辆的移动和通信。
annotations: AnnotationManager:
定义了一个名为annotations的子模块,用于管理注释信息,通常在仿真可视化中使用。
connectionManager: ConnectionManager:
定义了一个名为connectionManager的子模块,用于管理仿真中的连接和通信。
world: BaseWorldUtility:
定义了一个名为world的子模块,它表示仿真中的世界,包括地图和其他环境元素。
manager: TraCIScenarioManagerLaunchd:
定义了一个名为manager的子模块,它是TraCI(交通控制接口)场景管理器的启动模块,用于与外部TraCI客户端通信。
roadsCanvasVisualizer: RoadsCanvasVisualizer:
定义了一个名为roadsCanvasVisualizer的子模块,用于可视化仿真中的道路和车辆。
node[0]: Car:
定义了一个名为node[0]的节点,类型为Car。这是仿真中的一个车辆节点。
connections allowunconnected::
这个部分用于定义模块之间的连接关系,允许未连接的连接。
总的来说,这段代码定义了一个包含了多个子模块的Veins仿真网络,用于模拟车辆通信、移动和可视化等行为。这个仿真场景可以根据参数进行配置,包括仿真区域的大小和显示设置。 Veins允许用户创建复杂的仿真场景,以研究车辆通信和智能交通系统的各种方面。
Manager
这个是与sumo-launchd.py脚本交互的类,实现与SUMO通信。主要是对小车的仿真。主要的的函数实现在src/veins/modules/mobility/traci/TraCICommandInterface.cc文件内;与SUMO交互的接口函数在同目录下的TraCIConnection.cc内。
Obstacles
ObstacleControl即障碍的控制类。障碍会阻碍信号传播,均为多边形(polygon)。相关类文件在src/veins/modules/obstacle/内,障碍的位置通过前文提到的erlangen.poly.xml定义。
config.xml中的obstacles标签下定义了信号传输的衰减,默认的设置会导致信号穿过建筑后衰减为0,这解释了为什么前文运行例子的时候有些小车没有及时收到信息。
Node (Car)
Node是一个元素类型为Car的数组,也就是仿真需要的所有车辆。
Car有三个模块分别是
appl 应用层
nic MAC层
veinsmobility 移动驱动层
其中nic定义了上下层的接口,可以不作修改
而veinsmobility定义了底层,包括位置速度参数等,定义函数比如获取速度,前往下一个坐标等,可以修改/替换,至少需要实现IMobility这个接口
例子中的apply应用层是TraCIDemo11p.cc只是定义了几个简单的消息处理函数,开发中需要自己添加其他功能
这段代码定义了一个Veins仿真中的车辆模块,模块名为"Car"。让我为您逐行解释这段代码的含义:
package org.car2x.veins.nodes;:
这行代码指定了模块所在的Java包(package),这个模块位于org.car2x.veins.nodes包中。
import org.car2x.veins.base.modules.*; 和 import org.car2x.veins.modules.nic.Nic80211p;:
这些是Java的import语句,用于引入所需的Java类和模块。
module Car:
这行代码定义了一个车辆模块,模块名为"Car"。
parameters::
这个部分用于定义模块的参数,包括applType、nicType和veinsmobilityType。
string applType;:
这个参数定义了应用层的类型(applType)。在Veins中,应用层类型通常用于定义车辆的应用程序行为。
string nicType = default("Nic80211p");:
这个参数定义了网络接口卡的类型(nicType)。默认情况下,它被设置为"Nic80211p",这是IEEE 802.11p标准的网络接口卡类型。
string veinsmobilityType = default("org.car2x.veins.modules.mobility.traci.TraCIMobility");:
这个参数定义了车辆移动性模块的类型(veinsmobilityType)。默认情况下,它被设置为TraCIMobility,这是基于TraCI的移动性模块。
gates::
这个部分用于定义模块的输入和输出门(gates)。在这里,定义了一个输入门veinsradioIn,用于sendDirect。
submodules::
这个部分用于定义模块的子模块。在这里,定义了三个子模块:appl、nic和veinsmobility。
appl: <applType> like org.car2x.veins.base.modules.IBaseApplLayer:
这行代码定义了appl子模块,其类型是根据applType参数动态选择的应用层类型。这种方式允许根据仿真配置选择不同的应用层实现。
nic: <nicType> like org.car2x.veins.modules.nic.INic80211p:
这行代码定义了nic子模块,其类型是根据nicType参数动态选择的网络接口卡类型。同样,这种方式允许根据仿真配置选择不同的网络接口卡实现。
veinsmobility: <veinsmobilityType> like org.car2x.veins.base.modules.IMobility:
这行代码定义了veinsmobility子模块,其类型是根据veinsmobilityType参数动态选择的移动性模块类型。
connections::
这个部分用于定义模块之间的连接。连接包括将veinsradioIn连接到nic模块的radioIn门,以及将nic和appl模块之间的输入输出连接起来,以实现数据和控制信息的传输。
总的来说,这段代码定义了一个车辆模块,包括了应用层、网络接口卡和移动性模块。模块的类型和连接方式可以根据参数(如applType、nicType和veinsmobilityType)进行动态配置,使得Veins仿真更加灵活和可定制。这是Veins中定义模块的一种典型方式。