注意:写着写着发现要讲的实在太多了,实在没精力了,后面就只会提重点了,可能显得虎头蛇尾,但本文只是提点入门,最重要的还是自己去琢磨,不可能一篇博客就包教会。还有学之前先学会C++。
Veins是一款用于车载移动环境下无线通信仿真的开源框架,其对于车载无线网的底层结构,如物理层、MAC层等基于802.11p协议已基本开发完善,因此在此基础上进行二次开发,如改进MAC层协议或者路由协议等研究都是非常便携的。甚至如果是进行应用层上的研究,如车联网环境下的车辆自动驾驶、编队行驶、路径规划、信号灯区域协调等则更加方便,因为底层的结构可以直接使用,不必再浪费时间精力在这些并不是需要主要研究但却又对仿真结果影响重大的部分。
Veins的好处很多,一旦掌握可以节省大量的开发时间,得到更加准确的仿真实验结果,为自己的理论提供更加权威可靠的支持。但是Veins的相关教程却寥寥无几,除了官网上的一份运行其内置示例的教程外很难再寻找到其他相关教程,因此很多人打开Veins后面对密密麻麻的C++
代码难以下手,望而却步。博主因为学业所需对其进行过一段时间的研究,真是万分痛苦!在此将自己的研究经验经过整理得到一份入门级教程奉献给大家,愿大家都能早日脱离苦海。
看教程之前先确定自己已经把官网上的内置示例的教程运行成功了。
首先在OMNeT++的IDE左侧有如下图所示的窗口,打开veins的项目(博主拿二次开发过的程序在讲解,可能会比纯净版多出一些文件,大家不要在意),veins内置的示例就在文件夹examples内:
<root>
<AnalogueModels>
<AnalogueModel type="SimplePathlossModel">
<parameter name="alpha" type="double" value="2.0"/>
<parameter name="carrierFrequency" type="double" value="5.890e+9"/>
AnalogueModel>
<AnalogueModel type="SimpleObstacleShadowing">
<parameter name="carrierFrequency" type="double" value="5.890e+9"/>
<obstacles>
<type id="building" db-per-cut="9" db-per-meter="0.4" />
obstacles>
AnalogueModel>
AnalogueModels>
<Decider type="Decider80211p">
<parameter name="centerFrequency" type="double" value="5.890e9"/>
Decider>
root>
<root>
<AnalogueModels>
<AnalogueModel type="SimplePathlossModel">
<parameter name="alpha" type="double" value="2.0"/>
<parameter name="carrierFrequency" type="double" value="5.890e+9"/>
AnalogueModel>
AnalogueModels>
<Decider type="Decider80211p">
<parameter name="centerFrequency" type="double" value="5.890e9"/>
Decider>
root>
OMNeT++运行文件,后文重点讲解;
[General]
cmdenv-express-mode = true
cmdenv-autoflush = true
cmdenv-status-frequency = 1s
**.cmdenv-log-level = info
ned-path = .
image-path = ../../images
network = RSUExampleScenario
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 SETTINGS #
# #
# #
##########################################################
*.rsu[0].mobility.x = 2000
*.rsu[0].mobility.y = 2000
*.rsu[0].mobility.z = 3
*.rsu[*].applType = "TraCIDemoRSU11p"
*.rsu[*].appl.headerLength = 80 bit
*.rsu[*].appl.sendBeacons = true
*.rsu[*].appl.dataOnSch = false
*.rsu[*].appl.beaconInterval = 1s
*.rsu[*].appl.beaconUserPriority = 7
*.rsu[*].appl.dataUserPriority = 5
##########################################################
# 11p specific parameters #
# #
# NIC-Settings #
##########################################################
*.connectionManager.sendDirect = true
*.connectionManager.maxInterfDist = 2600m
*.connectionManager.drawMaxIntfDist = false
*.**.nic.mac1609_4.useServiceChannel = false
*.**.nic.mac1609_4.txPower = 20mW
*.**.nic.mac1609_4.bitrate = 6Mbps
*.**.nic.phy80211p.sensitivity = -89dBm
*.**.nic.phy80211p.useThermalNoise = true
*.**.nic.phy80211p.thermalNoise = -110dBm
*.**.nic.phy80211p.decider = xmldoc("config.xml")
*.**.nic.phy80211p.analogueModels = xmldoc("config.xml")
*.**.nic.phy80211p.usePropagationDelay = true
*.**.nic.phy80211p.antenna = xmldoc("antenna.xml", "/root/Antenna[@id='monopole']")
##########################################################
# WaveAppLayer #
##########################################################
*.node[*].applType = "TraCIDemo11p"
*.node[*].appl.headerLength = 80 bit
*.node[*].appl.sendBeacons = true
*.node[*].appl.dataOnSch = false
*.node[*].appl.beaconInterval = 1s
##########################################################
# Mobility #
##########################################################
*.node[*].veinsmobilityType.debug = true
*.node[*].veinsmobility.x = 0
*.node[*].veinsmobility.y = 0
*.node[*].veinsmobility.z = 1.895
*.node[*0].veinsmobility.accidentCount = 1
*.node[*0].veinsmobility.accidentStart = 75s
*.node[*0].veinsmobility.accidentDuration = 50s
这里只挑最重要的讲,其余的自己看ned文件的import、extends往上慢慢捋就行。
看代码可以发现RSUExampleScnario内加入了一个RSU单元。
import org.car2x.veins.nodes.RSU;
import org.car2x.veins.nodes.Scenario;
network RSUExampleScenario extends Scenario
{
submodules:
rsu[1]: RSU {
@display("p=150,140;i=veins/sign/yellowdiamond;is=vs");
}
}
其实是通过TraCIScenarioManagerLaunchd.ned这个模块加入的
package org.car2x.veins.modules.mobility.traci;
//
// Extends the TraCIScenarioManager for use with sumo-launchd.py and SUMO.
//
// Connects to a running instance of the sumo-launchd.py script
// to automatically launch/kill SUMO when the simulation starts/ends.
//
// All other functionality is provided by the TraCIScenarioManager.
simple TraCIScenarioManagerLaunchd
{
parameters:
@display("i=block/network2");
@class(Veins::TraCIScenarioManagerLaunchd);
bool debug = default(false); // emit debug messages?
double connectAt @unit("s") = default(0s); // when to connect to TraCI server (must be the initial timestep of the server)
double firstStepAt @unit("s") = default(-1s); // when to start synchronizing with the TraCI server (-1: immediately after connecting)
double updateInterval @unit("s") = default(1s); // time interval of hosts' position updates
string moduleType = default("org.car2x.veins.nodes.Car"); // module type to be used in the simulation for each managed vehicle
string moduleName = default("node"); // module name to be used in the simulation for each managed vehicle
// module displayString to be used in the simulation for each managed vehicle
// display strings key-value pairs needs to be protected with single quotes, as they use an = sign as the type mappings. For example
//
// *.manager.moduleDisplayString = "'i=block/process'"
// *.manager.moduleDisplayString = "a='i=block/process' b='i=misc/sun'"
//
//
// moduleDisplayString can also be left empty:
//
// *.manager.moduleDisplayString = ""
//
string moduleDisplayString = default("*='i=veins/node/car;is=vs'");
string host = default("localhost"); // sumo-launchd.py server hostname
int port = default(9999); // sumo-launchd.py server port
xml launchConfig; // launch configuration to send to sumo-launchd.py
int seed = default(-1); // seed value to set in launch configuration, if missing (-1: current run number)
bool autoShutdown = default(true); // Shutdown module as soon as no more vehicles are in the simulation
int margin = default(25); // margin to add to all received vehicle positions
string roiRoads = default(""); // which roads (e.g. "hwy1 hwy2") are considered to consitute the region of interest, if not empty
string roiRects = default(""); // which rectangles (e.g. "0,0-10,10 20,20-30,30) are considered to consitute the region of interest, if not empty. Note that these rectangles have to use TraCI (SUMO) coordinates and not OMNeT++. They can be easily read from sumo-gui.
double penetrationRate = default(1); //the probability of a vehicle being equipped with Car2X technology
int numVehicles = default(0);
bool useRouteDistributions = default(false);
int vehicleRngIndex = default(0); // index of the RNG stream to be used, all random numbers concerning the managed vehicles
}
其中下面一行代码定义了RSUExampleScnario.ned这个network中加入的移动节点。往上一层层捋就很容易发现,RSUExampleScnario继承自Scnario,Scnario又import了TraCIScenarioManagerLaunchd。
string moduleType = default("org.car2x.veins.nodes.Car");
到此为止,入门结束,剩下的具体功能实现请进入src/veins/nodes文件夹,仔细琢磨其中的ned文件并一层层往上捋即可。最后再啰嗦一句,ned定义结构,同名C++文件定义功能,明白这一点其实就没问题了。