Veins入門教程——教你如何下手研究
目錄
注意:寫着寫着發現要講的實在太多了,實在沒精力了,後面就只會提重點了,可能顯得虎頭蛇尾,但本文只是提點入門,最重要的還是自己去琢磨,不可能一篇博客就包教會。還有學之前先學會C++。
Veins是一款用於車載移動環境下無線通信仿真的開源框架,其對於車載無線網的底層結構,如物理層、MAC層等基於802.11p協議已基本開發完善,因此在此基礎上進行二次開發,如改進MAC層協議或者路由協議等研究都是非常便攜的。甚至如果是進行應用層上的研究,如車聯網環境下的車輛自動駕駛、編隊行駛、路徑規劃、信號燈區域協調等則更加方便,因爲底層的結構可以直接使用,不必再浪費時間精力在這些並不是需要主要研究但卻又對仿真結果影響重大的部分。
Veins的好處很多,一旦掌握可以節省大量的開發時間,得到更加準確的仿真實驗結果,爲自己的理論提供更加權威可靠的支持。但是Veins的相關教程卻寥寥無幾,除了官網上的一份運行其內置示例的教程外很難再尋找到其他相關教程,因此很多人打開Veins後面對密密麻麻的C++
代碼難以下手,望而卻步。博主因爲學業所需對其進行過一段時間的研究,真是萬分痛苦!在此將自己的研究經驗經過整理得到一份入門級教程奉獻給大家,願大家都能早日脫離苦海。
看教程之前先確定自己已經把官網上的內置示例的教程運行成功了。
廢話少說!
首先在OMNeT++的IDE左側有如下圖所示的窗口,打開veins的項目(博主拿二次開發過的程序在講解,可能會比純淨版多出一些文件,大家不要在意),veins內置的示例就在文件夾examples內:
- antenna.xml:對車輛天線做出配置,不用管;
- config.xml:配置物理層無線電傳播相關參數,如示例中將信號路徑衰落的模型配置爲“SmiplePathlossModel”,障礙物引起的信號衰落模型設置爲“SimpleObstacleShadowing”,一般使用默認的即可;
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- The center frequency on which the phy listens-->
<parameter name="centerFrequency" type="double" value="5.890e9"/>
</Decider>
</root>
- debug:調試信息,不用管;
- erlangen.launchd.xml:建立與SUMO的通信,不能更改;
- erlangen.net.xml: SUMO路網文件,跑自己的仿真時需要替換,至於如何生成請參考SUMO官網文檔;
- erlangen.poly.xml:如果SUMO路網文件是由地圖轉化而來的,如從OpenStreetMap導入的,則路網文件中還將包含所選地區的建築物的信息,通過SUMO提供的OpenStreetMap Web接口便可生成記錄這些建築物形狀、大小和位置信息的配置文件,作爲config.xml內信號衰落模型的輸入;如果不考慮建築物對於信號傳播的影響則無需此文件,當然config.xml內的信號衰落模型的配置也要刪去;
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- The center frequency on which the phy listens-->
<parameter name="centerFrequency" type="double" value="5.890e9"/>
</Decider>
</root>
- erlangen.rou.xml:交通流文件,如何生成也請查閱SUMO官網文檔,不再贅述;
- erlangen.sumo.cfg: SUMO運行文件,可對運行時長等運行參數進行配置;
- omnetpp.ini:
OMNeT++運行文件,後文重點講解;
- RSUExampleScnario.ned: OMNeT++類似於積木,一個工程項目是由多個ned文件互相嵌套組合而成的。veins作爲一個基於OMNeT++的框架,其便是由層次分明的ned文件組合而成的,如果學過面向對象編程的話可能會容易理解一些,這些ned文件就類似一個個類。但是OMNeT++中更爲特殊,因爲ned文件只是定義了組件的結構,比如定義一輛車,ned只是描述了它包含幾個對外通信的接口,這些接口的參數之類的,具體的功能還需要與ned文件同名的C++文件進行定義,比如用這些接口選擇與誰進行通信,專業點就叫路由。對於OMNet++獨特的ned網絡語言大家還是踏踏實實看OMNeT++官方手冊學習吧。一開始可能找不到頭緒,所以建議大家去聽聽這個OMNeT++基礎講解的視頻課程(要學的東西是不是很多?是不是很煩?)。這裏的RSUExampleScnario.ned定義了OMNeT++中最大的結構——網絡(network),可以看到在omnetpp.ini中的[General]部分對於本次仿真所運行的網絡定義爲RSUExampleScenario;
[General]
cmdenv-express-mode = true
cmdenv-autoflush = true
cmdenv-status-frequency = 1s
**.cmdenv-log-level = info
ned-path = .
image-path = ../../images
network = RSUExampleScenario
講解omnetpp.ini!(挑關鍵的)
- 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 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:對MAC層ned(nic)相關參數做出設置,nic包含兩個子ned(mac1609_4和phy80211p)。至於connectionManager基本保持不變,如果要研究信號傳播範圍的影響的話,需要改變maxInterfDist;
##########################################################
# 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: 對移動節點(車輛)的應用層做出設置,和RSU一個道理;
##########################################################
# WaveAppLayer #
##########################################################
*.node[*].applType = "TraCIDemo11p"
*.node[*].appl.headerLength = 80 bit
*.node[*].appl.sendBeacons = true
*.node[*].appl.dataOnSch = false
*.node[*].appl.beaconInterval = 1s
- Mobility: 對移動節點的移動模塊做出設置。其中accidentCount、accidentStart、accidentDuration這三個參數是對移動節點發生事故的事件做出設置,這是veins的examples演示的功能(事故預警消息的傳播),我們用不到直接令accidentCount=0即可。
##########################################################
# 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
講解RSUExampleScnario.ned!
這裏只挑最重要的講,其餘的自己看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
// <pre>
// *.manager.moduleDisplayString = "'i=block/process'"
// *.manager.moduleDisplayString = "a='i=block/process' b='i=misc/sun'"
// </pre>
//
// moduleDisplayString can also be left empty:
// <pre>
// *.manager.moduleDisplayString = ""
// </pre>
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++文件定義功能,明白這一點其實就沒問題了。