概述
本文是在Plexe框架上实验并做的总结,plexe是Veins框架的拓展,实现了队列的相关功能,做相关应用的大佬们可以去了解一下:http://plexe.car2x.org/
实际上,plexe并没有在veins的基础上变化很多,只是多了与队列有关的模块,比如positionHelper类提供了获取队列ID和队列中所在位置等服务。
(如果你也在用plexe,且正在了解这方面的内容,可以把这篇当作一个简单的教程来看。如果您只是在用veins,可能有些地方有些差距,不过也没关系,毕竟用plexe的人也不多,我会多放些代码,希望可以帮助大家理解。)
1、车辆模块结构
1.1首先我们来看一下plexe默认的车辆结构:
src/veins/modules/application/platooning/PlatoonCar.ned:
package org.car2x.veins.modules.application.platooning;
import org.car2x.veins.base.modules.IBaseApplLayer;
import org.car2x.veins.modules.application.platooning.utilities.BasePositionHelper;
import org.car2x.veins.modules.application.platooning.scenarios.BaseScenario;
import org.car2x.veins.modules.application.platooning.protocols.BaseProtocol;
import org.car2x.veins.modules.application.platooning.apps.BaseApp;
import org.car2x.veins.modules.application.platooning.UnicastProtocol;
import org.car2x.veins.modules.mobility.traci.TraCIMobility;
import org.car2x.veins.modules.nic.Nic80211p;
module PlatoonCar
{
parameters:
string scenario_type;
string helper_type;
string appl_type;
string protocol_type;
gates:
input radioIn; // gate for sendDirect
submodules:
helper: <helper_type> like BasePositionHelper {
parameters:
@display("p=84,100");
}
scenario: <scenario_type> like BaseScenario {
parameters:
@display("p=139,100");
}
appl: <appl_type> like BaseApp {
parameters:
@display("p=31,100");
}
prot: <protocol_type> like BaseProtocol {
parameters:
@display("p=60,200");
}
unicast: UnicastProtocol {
parameters:
@display("p=60,300");
}
nic: Nic80211p {
parameters:
@display("p=60,400");
}
mobility: TraCIMobility {
parameters:
@display("p=130,172;i=block/cogwheel");
}
connections allowunconnected:
unicast.upperControlIn <-- prot.lowerControlOut;
unicast.upperControlOut --> prot.lowerControlIn;
unicast.upperLayerIn <-- prot.lowerLayerOut;
unicast.upperLayerOut --> prot.lowerLayerIn;
nic.upperLayerIn <-- unicast.lowerLayerOut;
nic.upperLayerOut --> unicast.lowerLayerIn;
radioIn --> nic.radioIn;
}
这个模块和veins的Car.ned有些差距,多了unicast模块和上面三个模块(应用层单独放在了上面。)其中:
unicast: UnicastProtocol:这是一个单播层,在veins.modules.application.platooning.UnicastProtocol.h中定义。考虑到veins中Mac层只涉及到广播,所以设计了一个更高层的单播协议层,在发送消息时需要指定目标地址(广播地址为-1),另外提供了超时判断,重播等服务。(veins现在也支持单播了)。UnicastProtocol.cc中的代码还是比较好理解的,可以自己看一下。
helper: <helper_type> like BasePositionHelper:这是队列控制的类,可以获取队列相关信息,<helper_type>指的是你可以自己在omnetpp.ini配置文件中指定具体的类,但是必须是BasePositionHelper的衍生类,PositionHelper.cc的代码。你还可以丰富它的功能,例如判断自己是不是最后一个车辆:
bool BasePositionHelper::isLast() const
{
return getPosition() + 1 == platoonSize;
}
appl和prot层下面会详细讲,从代码中看也是可以在配置文件中指定相应实现类的。
1.2我们自己定义的车辆模块:
(本来写的是一个令牌环的实验,改了个动态信标的,问题不大,/笑。完整的项目代码后续可能上传到哪里再说吧。)
package org.car2x.veins.modules.application.platooning;
import ned.DatarateChannel;
import org.car2x.veins.base.modules.IBaseApplLayer;
import org.car2x.veins.modules.application.platooning.utilities.BasePositionHelper;
import org.car2x.veins.modules.application.platooning.scenarios.BaseScenario;
import org.car2x.veins.modules.application.platooning.protocols.BaseProtocol;
import org.car2x.veins.modules.application.platooning.protocols.BBaseProtocol;
import org.car2x.veins.modules.application.platooning.protocols.TokenProtocol;
import org.car2x.veins.modules.application.platooning.protocols.NegotiateProtocol;
import org.car2x.veins.modules.application.platooning.protocols.MutiPlatoonAdaptBeaconing;
import org.car2x.veins.modules.application.platooning.apps.BaseApp;
import org.car2x.veins.modules.application.platooning.apps.TokenApp;
import org.car2x.veins.modules.application.platooning.apps.MutiPlatoonAdaptBeaconApp;
import org.car2x.veins.modules.application.platooning.UnicastProtocol;
import org.car2x.veins.modules.application.platooning.unicast.TokenUnicast;
import org.car2x.veins.modules.mobility.traci.TraCIMobility;
import org.car2x.veins.modules.nic.Nic80211p;
module MyPlatoonCar
{
parameters:
string scenario_type;
string helper_type;
string appl_type;
string protocol_type;
gates:
input radioIn; // gate for sendDirect
input radioIn2;
submodules:
helper: <helper_type> like BasePositionHelper {
parameters:
@display("p=99,44");
}
scenario: <scenario_type> like BaseScenario {
parameters:
@display("p=52,44");
}
// appl: <appl_type> like BaseApp {
// parameters:
// @display("p=91,119");
// }
tokenApp: MutiPlatoonAdaptBeaconApp { //TokenApp MutiPlatoonAdaptBeaconApp
parameters:
@display("p=99,125");
}
prot: <protocol_type> like BaseProtocol {
parameters:
@display("p=60,212");
}
unicast: UnicastProtocol {
parameters:
@display("p=60,300");
}
nic: Nic80211p {
parameters:
@display("p=60,400");
}
mobility: TraCIMobility {
parameters:
@display("p=154,44;i=block/cogwheel");
}
nic2: Nic80211p {
@display("p=147,400");
}
negotiateUnicast: TokenUnicast { //TokenUnicast MutiPlatoonAdaptBeaconing
@display("p=147,300");
}
negotiateProtocol: TokenProtocol {//TokenProtocol MutiPlatoonAdaptBeaconing BaseProtocol
@display("p=147,212");
}
connections allowunconnected:
unicast.upperControlIn <-- prot.lowerControlOut;
unicast.upperControlOut --> prot.lowerControlIn;
unicast.upperLayerIn <-- prot.lowerLayerOut;
unicast.upperLayerOut --> prot.lowerLayerIn;
nic.upperLayerIn <-- unicast.lowerLayerOut;
nic.upperLayerOut --> unicast.lowerLayerIn;
radioIn --> nic.radioIn;
nic2.upperControlOut --> negotiateUnicast.lowerControlIn;
nic2.upperLayerOut --> negotiateUnicast.lowerLayerIn;
negotiateUnicast.lowerControlOut --> nic2.upperControlIn;
negotiateUnicast.lowerLayerOut --> nic2.upperLayerIn;
//radioIn2 --> nic2.radioIn;
negotiateUnicast.upperControlOut --> negotiateProtocol.lowerControlIn;
negotiateUnicast.upperLayerOut --> negotiateProtocol.lowerLayerIn;
negotiateProtocol.lowerControlOut --> negotiateUnicast.upperControlIn;
negotiateProtocol.lowerLayerOut --> negotiateUnicast.upperLayerIn;
// prot.upperControlOut[0] --> appl.lowerControlIn;
// prot.upperLayerOut[0] --> appl.lowerLayerIn;
// appl.lowerControlOut --> prot.upperControlIn[0];
// appl.lowerLayerOut --> prot.upperLayerIn[0];
prot.upperControlOut[0] --> tokenApp.lowerControlIn[0];
prot.upperLayerOut[0] --> tokenApp.lowerLayerIn[0];
tokenApp.lowerControlOut[0] --> prot.upperControlIn[0];
tokenApp.lowerLayerOut[0] --> prot.upperLayerIn[0];
negotiateProtocol.upperControlOut[0] --> tokenApp.lowerControlIn++;
negotiateProtocol.upperLayerOut[0] --> tokenApp.lowerLayerIn++;
tokenApp.lowerControlOut++ --> negotiateProtocol.upperControlIn[0];
tokenApp.lowerLayerOut++ --> negotiateProtocol.upperLayerIn[0];
}
上面两种实现的指定方式都用到了,用<*_type>是为了可以更加方便的在.ini中指定实现的类,但是其实在配置文件中更改和直接在.ned文件中改我觉得差不多:
prot: <protocol_type> like BaseProtocol
negotiateProtocol: TokenProtocol
最重要的我认为是:在上面的图中可以看到tokenApp层向下需要连接两个协议层(因为用到两张nic卡,分别用CCH和SCH),但是veins中没有这样多进多出的模块供继承,所以需要自己写一个:
package org.car2x.veins.modules.application.platooning.apps;
network TokenApp
{
parameters:
int headerLength @unit("bit") = default(0 bit);
@display("i=block/app2");
@class(TokenApp);
gates:
input lowerLayerIn[2];
output lowerLayerOut[2];
input lowerControlIn[2];
output lowerControlOut[2];
}
TokenApp类的代码就不贴出来了,在本文后面的实现中也没有用到TokenApp提供的功能。重要的是两个协议层,内容如下。
2、模块的创建与实现
在这之前,需要在.ini文件中指定不同车辆的模块、显示名称、显示图片:
*.manager.moduleType = "vtypeauto=org.car2x.veins.modules.application.platooning.MyPlatoonCar vtypehuman=org.car2x.veins.modules.application.platooning.HumanCar"
*.manager.moduleName = "vtypeauto=node vtypehuman=human"
*.manager.moduleDisplayString = ""
human模块第三节简单讲一下,先说MyPlatoonCar中的几个模块。
prot: <protocol_type> like BaseProtocol:
- 首先在配置文件中指定实现的类:
*.node[*].protocol_type = "MutiPlatoonAdaptBeaconing"
这里的protocol_type就是上面车辆.ned中的<protocol_type>,记得吗,在实例化车辆模块时(SUMO负责生成车辆,Veins负责对每个车辆实例化一个模型)会从配置文件中获取这些参数。
- 然后你需要创造这个MutiPlatoonAdaptBeaconing模块(.ned文件)
package org.car2x.veins.modules.application.platooning.protocols;
import org.car2x.veins.modules.application.platooning.UnicastProtocol;
import org.car2x.veins.modules.application.platooning.protocols.BBaseProtocol;
//
// TODO auto-generated type
//
simple MutiPlatoonAdaptBeaconing extends BBaseProtocol
{
@display("i=block/network2");
@class(MutiPlatoonAdaptBeaconing);
}
这个模块继承自BBaseProtocol,@class(MutiPlatoonAdaptBeaconing)表示实现这个模块功能的类就是MutiPlatoonAdaptBeaconing。
- 接着你需要定义这个MutiPlatoonAdaptBeaconing类:
#ifndef SRC_VEINS_MODULES_APPLICATION_PLATOONING_PROTOCOLS_MUTIPLATOONADAPTBEACONING_H_
#define SRC_VEINS_MODULES_APPLICATION_PLATOONING_PROTOCOLS_MUTIPLATOONADAPTBEACONING_H_
#include "BaseProtocol.h"
#include "veins/modules/application/platooning/myMessages/Beacon_m.h"
#include "veins/modules/application/platooning/utilities/PositionHelper.h"
class MutiPlatoonAdaptBeaconing : public BaseProtocol {
protected:
virtual void handleMessage(cMessage* msg) override;
virtual void handleSelfMsg(cMessage* msg) override;
virtual void handleUpperMsg(cMessage* msg) override;
virtual void handleLowerMsg(cMessage* msg) override;
virtual void finish();
bool needBeaconInThisFrame(SimTime lastBeaconTime , SimTime intralBeaconInterval);
SimTime getFrameStart();
PositionHelper* positionHelper;
protected:
cMessage* sendBeaconMsg;
cMessage* changeBeaconRateMsg;
double intralBeaconRate = 0;
SimTime intralBeaconInterval = SimTime(0);
SimTime baseBeaconInterval = SimTime(0);
int slotNum = 100;
SimTime lastBeaconTime;
SimTime lastreceiceBeacon;
SimTime changeBeaconFlagTime = SimTime(0);
SimTime lastBusyTimeInMac=0;
SimTime busyTimeInMac=0;
void sendBeacon();
void changeBeaconSlot();//to simu contact or join
void changeBeaconSlotBack();//to simu contact or join
void changeBeaconRate();
cMessage*recordMPABeaconingData;
int totalreceivedBeacon;
cOutVector totalreceivedBeaconOut;
int totalsendBeacon;
cOutVector totalsendBeaconOut;
simtime_t interval;
cOutVector intervalOut;
public:
MutiPlatoonAdaptBeaconing();
virtual ~MutiPlatoonAdaptBeaconing();
virtual void initialize(int stage);
};
#endif /* SRC_VEINS_MODULES_APPLICATION_PLATOONING_PROTOCOLS_MUTIPLATOONADAPTBEACONING_H_ */
#include "MutiPlatoonAdaptBeaconing.h"
#include "veins/modules/mac/ieee80211p/Mac1609_4.h"
using namespace Veins;
Define_Module(MutiPlatoonAdaptBeaconing)
void MutiPlatoonAdaptBeaconing::initialize(int stage)
{
BaseProtocol::initialize(stage);
if (stage == 0){
EV << "MutiPlatoonAdaptBeaconing : initialize stage = 0" << endl;
recordMPABeaconingData = new cMessage("recordMPABeaconingData");
changeBeaconRateMsg = new cMessage("changeBeaconRateMsg");
totalreceivedBeaconOut.setName("totalreceivedBeacon");
totalsendBeaconOut.setName("totalsendBeacon");
intervalOut.setName("interval");
totalreceivedBeacon = 0;
totalsendBeacon = 0;
interval = 0;
SimTime rounded = SimTime(floor((simTime()+9).dbl() * 1000 + 100), SIMTIME_MS);
scheduleAt(rounded, recordMPABeaconingData);
}
if (stage == 1) {
EV << "MutiPlatoonAdaptBeaconing : initialize stage = 1" << endl;
mobility = Veins::TraCIMobilityAccess().get(getParentModule());
positionHelper = FindModule<PositionHelper*>::findSubModule(getParentModule());
traci = mobility->getCommandInterface();
traciVehicle = mobility->getVehicleCommandInterface();
int positionInPlatoon = positionHelper->getPosition();
// one beacon interval is divided into 'platoonSize' slots
intralBeaconRate = 10;
baseBeaconInterval = SimTime(1) / intralBeaconRate;
intralBeaconInterval = baseBeaconInterval;
lastBeaconTime = SimTime(0);
slotNum = 100;
SimTime slotDur = intralBeaconInterval/slotNum;
sendBeaconMsg = new cMessage("ssendBeaconMsg");
//double seed = (positionHelper->getPosition())/10;
SimTime beginTime = slotDur * positionHelper->getPosition();
SimTime sendTime = SimTime(10.312) + beginTime;
//SimTime sendTime = SimTime(10.3) +SimTime(uniform(0,beaconingInterval));
scheduleAt(sendTime, sendBeaconMsg);
scheduleAt(SimTime(11.0999), changeBeaconRateMsg);
//scheduleAt(SimTime(11) , sendBeaconMsg);
}
}
void MutiPlatoonAdaptBeaconing::handleMessage(cMessage* msg)
{
if (msg->isSelfMessage()) {
handleSelfMsg(msg);
return ;
}
EV << "MutiPlatoonAdaptBeaconing : handleMessage , gate:" << msg->getArrivalGate()->getName() << endl;
EV << "platoonID :" << positionHelper->getPlatoonId() << " and index : " << positionHelper->getPosition() << endl;
if(strcmp(msg->getArrivalGate()->getName() , "upperLayerIn") == 0){
handleUpperMsg(msg);
return ;
}
else if(strcmp(msg->getArrivalGate()->getName() , "lowerLayerIn") == 0){
handleLowerMsg(msg);
return ;
}
else if (msg->getArrivalGateId() >= minUpperControlId && msg->getArrivalGateId() <= maxUpperControlId)
handleUpperControl(msg);
else
handleMessage(msg);
}
void MutiPlatoonAdaptBeaconing::handleSelfMsg(cMessage* msg)
{
EV << "MutiPlatoonAdaptBeaconing::handleSelfMsg : time now is:" << simTime() << endl;
EV << "msg name :" << msg->getName() << endl;
EV << "position=" << positionHelper->getPosition() << endl;
Veins::Mac1609_4* mac = dynamic_cast<Veins::Mac1609_4 *>(getParentModule()->getSubmodule("nic")->getSubmodule("mac1609_4"));
EV << mac << endl;
EV << "busyTime = " << mac->getStatsTotalBusyTime() <<endl;
busyTimeInMac = mac->getStatsTotalBusyTime()-lastBusyTimeInMac;
lastBusyTimeInMac = mac->getStatsTotalBusyTime();
//double busyRatio = busyTimeInMac/SimTime(0.1);
if(busyTimeInMac>0)
intralBeaconInterval = (baseBeaconInterval/SimTime(1))*(1+(busyTimeInMac/0.005 - 1 )*3);//ms
EV << "busyRatio = " << busyTimeInMac/0.005 << endl;
EV << "intralBeaconInterval = " << intralBeaconInterval << endl;
if(intralBeaconInterval>1 || intralBeaconInterval<0)
intralBeaconInterval = baseBeaconInterval;
if(msg == recordMPABeaconingData){
//if(positionHelper->getPlatoonId() == 0){
EV << "lastreceiceBeacon=" << lastreceiceBeacon << endl;
EV<< "lastBeaconTime=" << lastBeaconTime << endl;
totalreceivedBeaconOut.record(totalreceivedBeacon);
totalreceivedBeacon = 0;
//lastreceiceBeacon = SimTime(0);
totalsendBeaconOut.record(totalsendBeacon);
totalsendBeacon = 0;
interval= intralBeaconInterval;
intervalOut.record(interval);
interval = 0;
scheduleAt(simTime() + SimTime(100, SIMTIME_MS), recordMPABeaconingData);
}
else if(msg == sendBeaconMsg){
EV << "handleSelfMsg->sendbeaconMsg" << lastreceiceBeacon << endl;
sendBeacon();
scheduleAt(simTime() + intralBeaconInterval, sendBeaconMsg);
/*test for simuing contact*/
/* if(positionHelper->getPlatoonId() == 0){
if(SimTime()>=15.5 && SimTime()<15.6)
changeBeaconSlot();
if(SimTime()>=18.5 && SimTime()<18.6)
changeBeaconSlotBack();
}*/
}
else if(msg = changeBeaconRateMsg){
changeBeaconRate();
}
}
void MutiPlatoonAdaptBeaconing::changeBeaconSlot(){
if(sendBeaconMsg->isScheduled())
cancelEvent(sendBeaconMsg);
baseBeaconInterval = 0.1;
scheduleAt(getFrameStart() + 0.1 + 0.09 +0.001*positionHelper->getPosition(), sendBeaconMsg);
}
void MutiPlatoonAdaptBeaconing::changeBeaconSlotBack(){
if(sendBeaconMsg->isScheduled())
cancelEvent(sendBeaconMsg);
baseBeaconInterval = 0.1;
scheduleAt(getFrameStart() + 0.001*positionHelper->getPosition(), sendBeaconMsg);
}
void MutiPlatoonAdaptBeaconing::changeBeaconRate(){
changeBeaconFlagTime = simTime();
if(int((simTime().raw()*10)/SimTime(1).raw())%100 == 10 || int((simTime().raw()*10)/SimTime(1).raw())%100 == 60){
intralBeaconRate = 10;
scheduleAt(simTime() +0.5 , changeBeaconRateMsg);
}
else if(int((simTime().raw()*10)/SimTime(1).raw())%100 == 15 || int((simTime().raw()*10)/SimTime(1).raw())%100 == 65){
intralBeaconRate = 5;
scheduleAt(simTime() + 1 , changeBeaconRateMsg);
}
else if(int((simTime().raw()*10)/SimTime(1).raw())%100 == 25 || int((simTime().raw()*10)/SimTime(1).raw())%100 == 75){
intralBeaconRate = 2.5;
scheduleAt(simTime() + 2, changeBeaconRateMsg);
}
else if(int((simTime().raw()*10)/SimTime(1).raw())%100 == 45 || int((simTime().raw()*10)/SimTime(1).raw())%100 == 95){
intralBeaconRate = 5;
scheduleAt(simTime() + 1, changeBeaconRateMsg);
}
else if(int((simTime().raw()*10)/SimTime(1).raw())%100 == 55 || int((simTime().raw()*10)/SimTime(1).raw())%100 == 5){
intralBeaconRate = 10;
scheduleAt(simTime() + 0.5, changeBeaconRateMsg);
}
baseBeaconInterval = SimTime(1) / intralBeaconRate;
intralBeaconInterval = baseBeaconInterval;
}
void MutiPlatoonAdaptBeaconing::sendBeacon()
{
Plexe::VEHICLE_DATA data;
// get information about the vehicle via traci
traciVehicle->getVehicleData(&data);
Beacon* beacon = new Beacon();
beacon->setName("beacon");
beacon->setVehicleId(this->getParentModule()->getId());
beacon->setPlatoonId(positionHelper->getPlatoonId());
beacon->setControllerAcceleration(data.u);
beacon->setAcceleration(data.acceleration);
beacon->setSpeed(data.speed);
beacon->setPositionX(data.positionX);
beacon->setPositionY(data.positionY);
beacon->setLength(data.length);
beacon->setSpeedX(data.speedX);
beacon->setSpeedY(data.speedY);
beacon->setAngle(data.angle);
beacon->setIsLeader(positionHelper->isLeader());
beacon->setIsLast(positionHelper->isLast());
beacon->setMyL3Addr(myApplAddr());
UnicastMessage* unicast = new UnicastMessage();
unicast->setDestination(-1);
unicast->encapsulate(beacon);
unicast->setName("beacon");
send(unicast,lowerLayerOut);
lastBeaconTime = simTime();
totalsendBeacon ++;
EV<< "MutiPlatoonAdaptBeaconing : send beacon down." << endl;
EV<< "lastBeaconTime=" << lastBeaconTime << endl;
}
void MutiPlatoonAdaptBeaconing::handleUpperMsg(cMessage* msg){
EV << "MutiPlatoonAdaptBeaconing Beaconing : handleUpperMsg : " << msg->getName() << endl;
UnicastMessage * unicast = check_and_cast<UnicastMessage*>(msg);
cPacket * pkt = new cPacket();
pkt = unicast->getEncapsulatedPacket();
BaseProtocol::handleUpperMsg(msg);
}
void MutiPlatoonAdaptBeaconing::handleLowerMsg(cMessage* msg){
/*handle BeaconNotify*/
UnicastMessage * unicast = check_and_cast<UnicastMessage*>(msg);
if(strcmp(msg->getName() , "beacon") == 0){
EV << "MutiPlatoonAdaptBeaconing : receive a msg , name:" << msg->getName() << endl;
cPacket* enc = unicast->getEncapsulatedPacket();
Beacon * beacon = dynamic_cast<Beacon*>(enc);
if(beacon->getPlatoonId() != positionHelper->getPlatoonId()){
EV << "Beacon from different platoon , delete msg." << endl;
delete(msg);
return ;
}
else{
EV << "Beacon from same platoon , id:" << beacon->getVehicleId() << endl;
EV << "vehicle ApplAddr:" << beacon->getMyL3Addr() << endl;
totalreceivedBeacon ++;
EV << "totalreceivedBeacon=" << totalreceivedBeacon << endl;
EV << "lastreceiceBeacon=" << lastreceiceBeacon << endl;
lastreceiceBeacon = simTime();
EV << "lastreceiceBeacon=" << lastreceiceBeacon << endl;
}
return ;
}
}
SimTime MutiPlatoonAdaptBeaconing::getFrameStart(){
SimTime t = simTime();
SimTime pointOne = SimTime((double)1/10);
SimTime frameStart = SimTime((double)((int)(t.raw()/pointOne.raw()))/10);
return frameStart;
}
/*Since different platoon has different beaconRate , decide whether platoon need to beacon in this frame */
bool MutiPlatoonAdaptBeaconing::needBeaconInThisFrame(SimTime lastBeaconTime , SimTime intralBeaconInterval){
SimTime t = simTime();
SimTime pointOne = SimTime((double)1/10);
SimTime frameStart = SimTime((double)((int)(t.raw()/pointOne.raw()))/10);
SimTime bt = lastBeaconTime + intralBeaconInterval;
EV << "lastBeaconTime=" << lastBeaconTime << " frameStart=" << frameStart <<endl;
if(lastBeaconTime > frameStart){
EV << "I have send a beacon in this frame , do not send again." << endl;
return false;
}
EV << "lastBeaconTime=" << lastBeaconTime << " intralBeaconInterval=" << intralBeaconInterval << endl;
if(bt < frameStart + 0.1){
EV << "bt < frameStart + 0.1s , beacon in this frame." << endl;
return true;
}
else{
EV << "do not beacon in this frame." << endl;
return false;
}
}
void MutiPlatoonAdaptBeaconing::finish(){
//recordScalar("totalReceivedBeacon", totalReceivedBeacon);
//recordScalar("aveTokenTransTime", totalTokenTransTime.dbl() / tokenReceiveTimes);
}
MutiPlatoonAdaptBeaconing::MutiPlatoonAdaptBeaconing() {
// TODO Auto-generated constructor stub
}
MutiPlatoonAdaptBeaconing::~MutiPlatoonAdaptBeaconing() {
// TODO Auto-generated destructor stub
}
代码应该不复杂,主要实现几个功能:
1)按照TDMA的思想,队列内车辆按照自己在队列中的位置(第几辆车)决定发送消息的时间:
SimTime beginTime = slotDur * positionHelper->getPosition();
SimTime sendTime = SimTime(10.312) + beginTime;
scheduleAt(sendTime, sendBeaconMsg);
SimTime MutiPlatoonAdaptBeaconing::getFrameStart(){...}方法确定帧开始时间。
2)车辆根据自己MAC层的信道忙时间决定消息发送间隔(公式不科学,不要在意):
if(busyTimeInMac>0)
intralBeaconInterval = (baseBeaconInterval/SimTime(1))*(1+(busyTimeInMac/0.005 - 1 )*3);//ms
3)车辆定期调整自己的通信频率:
void MutiPlatoonAdaptBeaconing::changeBeaconRate()
4)模拟车辆所在环境信道质量的变化,给车辆在一个帧内重新指定一个较好的时间通信:
void MutiPlatoonAdaptBeaconing::changeBeaconSlot(){
if(sendBeaconMsg->isScheduled())
cancelEvent(sendBeaconMsg);
baseBeaconInterval = 0.1;
scheduleAt(getFrameStart() + 0.1 + 0.09 +0.001*positionHelper->getPosition(), sendBeaconMsg);
}
void MutiPlatoonAdaptBeaconing::changeBeaconSlotBack(){
if(sendBeaconMsg->isScheduled())
cancelEvent(sendBeaconMsg);
baseBeaconInterval = 0.1;
scheduleAt(getFrameStart() + 0.001*positionHelper->getPosition(), sendBeaconMsg);
}
需要注意的有几点:
1).h文件中所有override结尾声明的函数都需要重写,否则报错。
2).cc文件开头须说明这个类实现的是哪个模块:
Define_Module(MutiPlatoonAdaptBeaconing)
3)重写的函数可能需要父函数的功能(也可能不需要),重写时不能忘记父函数,如:
BaseProtocol::initialize(stage);
4)这是协议层,车辆中的其他模块你可以这样获得:
//MAC层
Veins::Mac1609_4* mac = dynamic_cast<Veins::Mac1609_4 *>(getParentModule()->getSubmodule("nic")->getSubmodule("mac1609_4"));
//TraCIMobility
mobility = Veins::TraCIMobilityAccess().get(getParentModule());
positionHelper = FindModule<PositionHelper*>::findSubModule(getParentModule());
traci = mobility->getCommandInterface();
traciVehicle = mobility->getVehicleCommandInterface();
5)SimTime是一个模拟时间的类,其中表示时间的成员类型是int64_t,如果你想获得我们熟悉的时间(/s),你需要这样(相当于消掉单位):
intralBeaconRate = 10;
baseBeaconInterval = SimTime(1) / intralBeaconRate;
//消掉单位
baseBeaconInterval/SimTime(1))
6)关于应用层,对于多进多出的模块,也许通过gate判别消息类型的方法会出错,你可以使用更简单暴力的方法:
if(strcmp(msg->getArrivalGate()->getName() , "upperLayerIn") == 0){...}
//通过消息名字
if(strcmp(msg->getName() , "beacon") == 0){...}
MyPlatoonCar中的其他模块也一样,你可以自己定义模块并定义类来实现它,就不多说了。
3、干扰车辆实现
在我上一篇文章说了多应用层的问题,这里详细说一下MyPlatoonCar之外,human的定义。
- 第二节开头已经为两种车辆指定了两种模型,其中human模型为HumanCar,他比默认的PlatoonCar还要简单,只有一个协议层负责发送干扰信息:
package org.car2x.veins.modules.application.platooning;
import org.car2x.veins.base.modules.IBaseApplLayer;
import org.car2x.veins.modules.application.platooning.protocols.HumanInterferingProtocol;
import org.car2x.veins.modules.application.platooning.unicast.HumanInterferingUnicast;
import org.car2x.veins.modules.application.platooning.UnicastProtocol;
import org.car2x.veins.modules.mobility.traci.TraCIMobility;
import org.car2x.veins.modules.nic.Nic80211p;
module HumanCar
{
gates:
input radioIn; // gate for sendDirect
submodules:
prot: HumanInterferingProtocol {
parameters:
@display("p=60,200");
}
unicast: UnicastProtocol {
parameters:
@display("p=60,300");
}
nic2: Nic80211p {
parameters:
@display("p=60,400");
}
mobility: TraCIMobility {
parameters:
@display("p=130,172;i=block/cogwheel");
}
connections allowunconnected:
unicast.upperControlIn <-- prot.lowerControlOut;
unicast.upperControlOut --> prot.lowerControlIn;
unicast.upperLayerIn <-- prot.lowerLayerOut;
unicast.upperLayerOut --> prot.lowerLayerIn;
nic2.upperLayerIn <-- unicast.lowerLayerOut;
nic2.upperLayerOut --> unicast.lowerLayerIn;
radioIn --> nic2.radioIn;
}
- prot: HumanInterferingProtocol: 协议层使用HumanInterferingProtocol类实现,来看一下这个类的代码:
#ifndef HUMANINTERFERINGPROTOCOL_H_
#define HUMANINTERFERINGPROTOCOL_H_
#include "veins/base/modules/BaseApplLayer.h"
#include "veins/modules/application/platooning/UnicastProtocol.h"
#include "veins/modules/application/platooning/messages/PlatooningBeacon_m.h"
#include "veins/modules/mobility/traci/TraCIMobility.h"
#include "veins/modules/application/platooning/utilities/BasePositionHelper.h"
#include "veins/modules/mac/ieee80211p/Mac1609_4.h"
class HumanInterferingProtocol : public Veins::BaseApplLayer {
private:
// beacon interval
SimTime beaconingInterval;
// access category
int priority;
// packet size
int packetSize;
// transmit power in mW
double txPower;
// bit rate in bps
int bitrate;
protected:
// traci mobility. used for getting/setting info about the car
Veins::TraCIMobility* mobility;
Veins::TraCICommandInterface* traci;
Veins::TraCICommandInterface::Vehicle* traciVehicle;
// pointer to the mac layer
Veins::Mac1609_4* mac;
// messages for scheduleAt
cMessage* sendBeacon;
SimTime lastInterferTime =SimTime(0);
cMessage* recordHumanAppData;
cOutVector interferTimesOut;
int interferTimes = 0;
virtual void handleSelfMsg(cMessage* msg);
virtual void handleLowerMsg(cMessage* msg);
/**
* Sends an interfering packet
*/
void sendInterferingMessage();
public:
// id for beacon message
static const int INTERFERENCE_TYPE = 12349;
HumanInterferingProtocol()
{
sendBeacon = nullptr;
}
virtual ~HumanInterferingProtocol();
virtual void initialize(int stage);
};
#endif
#include "veins/modules/application/platooning/protocols/HumanInterferingProtocol.h"
#include "veins/modules/application/platooning/messages/InterferingBeacon_m.h"
#include "veins/modules/messages/PhyControlMessage_m.h"
#include "veins/modules/application/platooning/protocols/SlottedBeaconing.h"
using namespace Veins;
Define_Module(HumanInterferingProtocol)
void HumanInterferingProtocol::initialize(int stage)
{
BaseApplLayer::initialize(stage);
if (stage == 0) {
// init class variables
sendBeacon = 0;
// get gates
lowerLayerIn = findGate("lowerLayerIn");
lowerLayerOut = findGate("lowerLayerOut");
// get traci interface
mobility = Veins::TraCIMobilityAccess().get(getParentModule());
traci = mobility->getCommandInterface();
traciVehicle = mobility->getVehicleCommandInterface();
// get pointer to mac
mac = FindModule<Mac1609_4*>::findSubModule(getParentModule());
// tell the unicast protocol below which mac address to use via control message
UnicastProtocolControlMessage* setMacAddress = new UnicastProtocolControlMessage("");
setMacAddress->setControlCommand(SET_MAC_ADDRESS);
// set a mac address not interfering with platooning vehicles
setMacAddress->setCommandValue(getParentModule()->getIndex() + 1e6);
send(setMacAddress, lowerControlOut);
// beaconing interval in seconds
beaconingInterval = SimTime(par("beaconingInterval").doubleValue());
// platooning message packet size
packetSize = par("packetSize").longValue();
// priority of platooning message
priority = par("priority").longValue();
ASSERT2(priority >= 0 && priority <= 7, "priority value must be between 0 and 7");
// tx power
txPower = par("txPower").doubleValue();
// bit rate
bitrate = par("bitrate").doubleValue();
// init messages for scheduleAt
sendBeacon = new cMessage("sendBeacon");
recordHumanAppData = new cMessage("recordHumanAppData");
interferTimesOut.setName("interferTimes");
interferTimes = 0;
//interferTimesOut.record(interferTimes);
SimTime rounded = SimTime(floor((simTime()+9).dbl() * 1000 + 100), SIMTIME_MS);
scheduleAt(rounded, recordHumanAppData);
}
if (stage == 1) {
// METHOD 1: setting tx power and bitrate for all frames sent
// call this method at stage 1 otherwise the MAC might overwrite the
// values with the ones loaded from omn
mac->setTxPower(txPower);
mac->setMCS(getMCS(bitrate, BW_OFDM_10_MHZ));
double seed = ((this->getParentModule()->getIndex()-63)*5 + 10)/100;
SimTime beginTime = beaconingInterval* seed;
SimTime sendTime = SimTime(10.3) + beginTime + SimTime(0.055555555555);
//SimTime sendTime = SimTime(10.3) +SimTime(uniform(0,beaconingInterval));
scheduleAt(sendTime, sendBeacon);
EV << "next sendBeacon Time = " << sendTime << "##########" << endl;
}
}
HumanInterferingProtocol::~HumanInterferingProtocol()
{
cancelAndDelete(sendBeacon);
sendBeacon = nullptr;
}
void HumanInterferingProtocol::handleSelfMsg(cMessage* msg)
{
EV << "HumanInterferingProtocol::handleSelfMsg"<< endl;
if(msg == recordHumanAppData){
//isDNOut.record(isDN);
//EV<< "isDN = " << isDN << endl;
EV<<"lastInterferTime="<< lastInterferTime << endl;
interferTimesOut.record(interferTimes);
interferTimes = 0;
scheduleAt(simTime() + SimTime(100, SIMTIME_MS), recordHumanAppData);
}
else if (msg == sendBeacon) {
lastInterferTime = simTime();
interferTimes++;
HumanInterferingProtocol::sendInterferingMessage();
scheduleAt(simTime() + beaconingInterval, sendBeacon);
}
else
BaseApplLayer::handleSelfMsg(msg);
}
void HumanInterferingProtocol::sendInterferingMessage()
{
// create and send beacon
UnicastMessage* unicast = new UnicastMessage("interferenceBeacon", INTERFERENCE_TYPE);
unicast->setDestination(-1);
unicast->setPriority(priority);
unicast->setChannel(Channels::CCH);
// create platooning beacon with data about the car
InterferingBeacon* pkt = new InterferingBeacon("interferenceBeacon");
pkt->setKind(INTERFERENCE_TYPE);
pkt->setByteLength(packetSize);
// METHOD 2: setting tx power and bitrate on a per frame basis
PhyControlMessage* ctrl = new PhyControlMessage();
ctrl->setTxPower_mW(txPower);
ctrl->setMcs(getMCS(bitrate, BW_OFDM_10_MHZ));
pkt->setControlInfo(ctrl);
// put platooning beacon into the message for the UnicastProtocol
unicast->encapsulate(pkt);
sendDown(unicast);
EV << "succeed to send interferencc beacon down."<< endl;
}
void HumanInterferingProtocol::handleLowerMsg(cMessage* msg)
{
delete msg;
}
这个类只有一个基本的功能就是按照固定的时间间隔发送干扰消息,你可以在initialize函数中指定发送时间和频率等。
4、模拟结果
每帧车辆0接收来自本队列车辆的消息总数,好像有频率变化吧(/应该)(因为设了频率变化,还记得吗:changeBeaconRate()):
车辆0每帧的信标间隔,好像也有:
没了,写的很乱,感谢您有耐心看到最后,希望对你有帮助!
最后
以上就是慈祥高山为你收集整理的omnet++,veins,plexe模块介绍与实现1、车辆模块结构2、模块的创建与实现3、干扰车辆实现4、模拟结果的全部内容,希望文章能够帮你解决omnet++,veins,plexe模块介绍与实现1、车辆模块结构2、模块的创建与实现3、干扰车辆实现4、模拟结果所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复