Veins教程08 - Veins魔改应用层2

这篇教程优化Report Message。基于”Version 2”,即以RSU为主控,轮询小车的模式。效果图在最后。

Real Map

首先参考SUMOVeins将地图替换成真实地图。

Config.xml

由于本例中RSU放置于路口,原则上是可以与所有方向道路上的小车通信。为了减少调试RSU的位置,可以将config.xml中的的信号衰减率调低或设为零,这样RSU不用精准的放在路口中心,也能辐射范围内所有小车。

<type id="building" db-per-cut="0" db-per-meter="0" />

Limit Broadcast Range

在现实中,V2V和V2I有最大广播范围的限制,例如V2V一般不超过300米。在本例中,由于需要小车和RSU双向通讯,最好将小车和RSU通讯范围设置相同,比如200米。

好在Veins提供了预制的范围设置,暂时也不需要魔改。

可以通过如下修改omnetpp.ini中的配置修改最大通讯范围。

1
*.connectionManager.maxInterfDist = 200m

Improve Display

Message in Qtenv

上一个教程已经证实小车和RSU可以互相通信,因此我们不再需要显式的查看仿真中的消息传递。

开始仿真后,可以在弹出的Qtenv中点击File - Preferences - Animation, 取消勾选Animate messages。

Display Range

Veins提供预制的范围显示开关。

1
*.connectionManager.drawMaxIntfDist = true

开启范围显示之后,仿真,会发现所有小车周围也会显示范围,会让整个网络非常混乱。

分析之后可以发现实现范围显示的代码在base/connectionManager/BaseConnectionManager.cc中的registerNic函数,这是一个注册mac层使之由ConnectionManager管理的函数,会在节点被initialize的时候调用。

其中具体负责绘制的代码为最后的

1
2
3
if (drawMIR) {
nic->getParentModule()->getDisplayString().setTagArg("r", 0, maxInterferenceDistance);
}

简便起见我们可以直接在这里做修改。如果以后有需要,比如小车和RSU通信范围不同等,可以重写参数的分配,将绘制范围的任务分给各自的mac层,这里暂不深入研究。

提供以下一种写法,通过getParentModule()->getName()获取父模块(即所在node)的模块名来判断是否是RSU:

1
2
3
if (drawMIR && strcmp(nic->getParentModule()->getName(), "rsu") == 0) {
nic->getParentModule()->getDisplayString().setTagArg("r", 0, maxInterferenceDistance);
}

编译运行,现在只有RSU会显示通信范围。

Optimize Code

RSU

之前的教程中,我们简单使用了一个set来统计RSU连接的小车。这个方法可行的前提是通信范围无限(默认是2600米),可连接小车数量只增不减。而本例中调整了辐射范围,因此小车如果超过范围RSU应该移除该实例。

Set在本例中不太适用,可以改用Map,key是id,value是上次汇报reportMsg的时间。

RSU依旧每两秒钟轮询一次;如果小车超过三秒钟没有汇报ReportMessage则认为其断开连接了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// TraCIDemoRSU11p.h
// add a member
std::map<LAddress::L2Type, simtime_t> connectedNodes;

// TraCIDemoRSU11p.cc
void TraCIDemoRSU11p::onRM(ReportMessage* frame)
{
ReportMessage* rm = check_and_cast<ReportMessage*>(frame);
LAddress::L2Type sender = rm->getSenderAddress();
simtime_t time = simTime();
std::map<LAddress::L2Type, simtime_t>::iterator it;
it = connectedNodes.find(sender);

if(it == connectedNodes.end()) {
// if not exist, insert
connectedNodes.insert(std::make_pair(sender, time));
}
else {
// exist, update time
it->second = time;
}

// display a textbox above the RSU icon in the map showing the number of connected nodes
findHost()->getDisplayString().setTagArg("t", 0, connectedNodes.size());
}

// TraCIDemoRSU11p.cc
void TraCIDemoRSU11p::handleSelfMsg(cMessage* msg)
{
ReportMessage* rm = dynamic_cast<ReportMessage*>(msg);
scheduleAt(simTime() + 2, rm);
sendDown(rm->dup());

std::map<LAddress::L2Type, simtime_t>::iterator it;

// checking disconnected nodes by iterating the map
for(it = connectedNodes.begin(); it != connectedNodes.end(); it++) {
// if the last report time of a specific node is 3 seconds ago, assume it's disconnected
if (simTime() - it->second >= 3) {
connectedNodes.erase(it++);
if (it == connectedNodes.end()) {
break;
}
}
}
}

Car

小车方面,为了增加直观显示,减少Debug,我们可以设置小车收到RSU轮询消息后变为绿色,超过三秒没有收到任何轮询消息则判断没有可连接RSU,并切换回白色,实现如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// TraCIDemo11p.h
// add a member
simtime_t lastReceiveAt;

// TraCIDemo11p.cc
void TraCIDemo11p::onRM(ReportMessage* rm)
{
if (rm->getSenderType() == 0) {

lastReceiveAt = simTime();
// alter the color of the component by editing the display string
findHost()->getDisplayString().setTagArg("i", 1, "green");

ReportMessage* newRM = new ReportMessage();
populateWSM(newRM);
newRM->setSenderAddress(myId);
newRM->setSenderType(1);
scheduleAt(simTime() + uniform(0.01, 0.2), newRM->dup());
delete newRM;
}
}

// TraCIDemo11p.cc
void TraCIDemo11p::handlePositionUpdate(cObject* obj)
{
DemoBaseApplLayer::handlePositionUpdate(obj);

if (simTime() - lastReceiveAt >= 3) {
// alter the color of the component by editing the display string
findHost()->getDisplayString().setTagArg("i", 1, "white");
}
}

关于display string, 可以参看官方手册的8.4节和附录F。

Result

代码Repo

效果展示

效果图

评论