omnet++,veins,plexe模块介绍与实现

    本文是在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每帧的信标间隔,好像也有:

没了,写的很乱,感谢您有耐心看到最后,希望对你有帮助!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 13
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值