omnet++,veins车辆间消息的传输、车辆运动信息获取

目录

1、定义自己的消息内容:

1.1、定义.msg文件:

1.2、Bulid Project生成Beacon_m.h和Beacon_m.cc文件:

 1.3引用:

2、消息的发送:

2.1、定义自消息:

2.2、消息内容的设置及消息的发送:

3、消息的接收:

3.1消息从哪里接收

3.2接收消息和处理:

4、总结


  本文介绍V2X消息的传输和事件的安排及调度。

1、定义自己的消息内容:

1.1、定义.msg文件:

加入自己需要传递的信息,以我之前的实验内容中的beacon为例:

cplusplus{{
#import "veins/base/utils/Coord.h"
#import "veins/modules/utility/Consts80211p.h"
}};

// namespace Veins;

class noncobject Coord;

packet Beacon {
	//id of the originator
	int vehicleId = 0;
	//id of the sender. relayerId == vehicleId on first hope
	double v = 0;
	double a= 0;
	double x = 0;
	double y = 0;
	double l = 0;
	//double speedX = 0;
	//double speedY = 0;
	double ang = 0;
	double speed[100];
	double acceleration[100];
	Coord position[100];
	double angle[100];
    double beaconrate[100];
    double cp[100];  //collision probability
    Coord slotpos;
    simtime_t timestamp = 0;
}

1.2、Bulid Project生成Beacon_m.h和Beacon_m.cc文件:

生成的类提供了获取消息内容的接口,即get和set函数,和.msg中的内容是对应的,如:

 1.3引用:

在头文件中引用消息的类Beacon_m.h:

#include "veins/modules/messages/Beacon_m.h"

2、消息的发送:

2.1、定义自消息:

在你需要实现发送和接收的层的实现类中定义自消息并完成Beacon消息发送的安排。如我需要在应用层发送和接收beacon消息,使用的实现类是veins提供的MyVeinsApp。

首先在头文件中声明自消息,如:

cMessage* sendBeacon; 

然后在.cc中initialize的stage == 0(也可以在该自消息被调度之前)中初始化自消息:

sendBeacon = new cMessage("send Beacon");

接着,在initialize的stage == 1中调度自消息,在给定的时间执行给定的自消息:

if(strcmp(this->getParentModule()->getName(),"human") == 0){
    scheduleAt(SimTime(5),sendBeacon);
}

上面表示名为human的车辆在模拟时间第5s执行sendBeacon这个自消息。

2.2、消息内容的设置及消息的发送:

在开始之前说一下,MyVeinsApp.cc这个类重写了父类的handleSelfMsg,(所有重写的函数都需要实现,否则报错)。所有schedule的自消息都在给定的时间在handleSelfMsg这个函数里实现如:

  • 首先,我相信最常用的信息是车辆的动力学信息,如何获取它:
cModule* vehicle = getParentModule();
Veins::TraCIMobility* traci = dynamic_cast<Veins::TraCIMobility*>(vehicle->getSubmodule("veinsmobility", 0));
Veins::TraCICommandInterface::Vehicle* traciVehicle = traci->getVehicleCommandInterface();

第一行获取了车辆的模型,因为app层所属是车辆,如果是mac层或者phy层,所属nic,nic所属车辆,需要:

cModule* vehicle = getParentModule()->getParentModule();

 NOTE1,如果你想通过场景模块获取其他车辆的信息(不推荐这样做,因为这样通信就没有意义了,现实中也不可能,确实遇到困难才这么做,或者为了方便),直接车辆模块getParentModule()就是场景模块,场景的子模块当然有所有车辆和RSU:

/*检测车辆数量*/
int Mac1609_4::getCarNumber(){
    int num = 0;
    int i=0;
    cModule* nic = getParentModule();
    cModule* car = nic->getParentModule();
    const char* name = car->getName();
    cModule* scenario = car->getParentModule();

    while(scenario->findSubmodule("node",i)!=-1){
        num++;
        cModule* vehicle = scenario->getSubmodule("node",i);
        Veins::TraCIMobility* traci = dynamic_cast<Veins::TraCIMobility*>(vehicle->getSubmodule("veinsmobility", 0));
        Veins::TraCICommandInterface::Vehicle* traciVehicle = traci->getVehicleCommandInterface();
        //DBG_MAC <<"car index is :" << vehicle->getIndex() << " and lane is :" << traciVehicle->getLaneIndex() << std::endl;

        lanesHasVehicle[traciVehicle->getLaneIndex()] = true;

        /*存储车辆车道信息和行驶方向信息*/
        vehicleLanes[i] = traciVehicle->getLaneIndex();
        vehicleAngles[i] = traci->getAngleRad();
        i++;
    }
}

第二行找到mobility子模块;

第三行使用mobility提供的traci接口;

NOTE2:上面的traci只能获取速度等信息,而traciVehicle可以设置车辆的速度等。

  • 定义消息、设置内容并发送:
if (msg == sendBeacon) {
    Beacon* beacon = new Beacon();
    beacon->setVehicleId(this->getParentModule()->getIndex());
    beacon->setV(traci->getSpeed());
    beacon->setX(traci->getPositionAt(simTime()).x);
    beacon->setY(traci->getPositionAt(simTime()).y);
    THSposition[this->getParentModule()->getIndex()] = traci->getPositionAt(simTime());
    THSangle[this->getParentModule()->getIndex()] = traci->getAngleRad();
    THSspeed[this->getParentModule()->getIndex()] = traci->getSpeed();
    THSacceleration[this->getParentModule()->getIndex()] = acceleration;
    //加速度可以通过保存前一时刻速度来计算:
    acceleration = ( traci->getSpeed() - speedBefore ) * 1;//renew acc every 1s
    speedBefore = traci->getSpeed();

    beacon->setA(acceleration);
    for (int i = 0;i < 100;i++){
        beacon->setBeaconrate(i,THSbeaconrate[i]);
        beacon->setCp(i, THScp[i]);
        beacon->setSpeed(i,THSspeed[i]);
        beacon->setAcceleration(i, THSacceleration[i]);
        beacon->setPosition(i, THSposition[i]);
        beacon->setAngle(i, THSangle[i]);
    }

    //新建WSM,这是应用层和MAC层通信的消息
    WaveShortMessage* WSM = new WaveShortMessage();
    //把beacon封装在WSM中
    WSM->encapsulate(beacon);
    //设置WSM的基本信息
    populateWSM(WSM);
    //将WSM从应用层的向下接口发送出去
    send(WSM,lowerLayerOut);
    return;
}

NOTE3:如果要设置一个数组的所有信息,需要通过循环使用这样的方法:

beacon->setBeaconrate(i,THSbeaconrate[i]);

NOTE4:如果需要循环发送,如实现TDMA可以在return之前,循环调度这个自消息:

scheduleAt(simTime() + frameLength,sendBeacon);

其他的一些信息如源目地址可以这样设置:

//自身应用层的ID:
beacon->setMyL3Addr(myApplAddr());
//设置目标地址,不设置就是-1广播地址:
//如果你使用plexe,可以使用UnicastMessage类的方法:
unicastMsg->setDestination(1);
//如果你是用Veins,可以使用WSM类的方法:
wsmMsg->setRecipientAddress(1);

 NOTE5:值得注意的是即使设置了目标地址,Veins在过程上还是将消息广播出去,其他车辆接收时在MAC层判断目标地址是否和自己一致,如果一致,将这个消息传递到上层,不一致则丢弃这个消息:

 

 类似这个方法,我们也可以在自己定义的消息(如上面的Beacon)中加入源目成员,发送时设置源目信息,在接收时,可以直接在应用层判断目标地址。

3、消息的接收:

3.1消息从哪里接收

首先我们应该大体知道消息的传递方式如下图(灵魂画手),A给B发消息,最后会从B的Mac层upperLayerOut传到App层的LowerLayerIn接口:

3.2接收消息和处理:

MyVeinsApp.cc没有重写handleLowerMsg函数,需要在头文件中添加:

virtual void handleLowerMsg(cMessage* msg);

并在MyVeinsApp.cc中实现:

void MyVeinsApp::handleLowerMsg(cMessage* msg) {
    //消息传换成WSM
    WaveShortMessage* WSM = check_and_cast<WaveShortMessage*>(msg);
    //从WSM中解封数据包
    cPacket* enc = WSM->getEncapsulatedPacket();
    //数据包转换成Beacon
    Beacon* bc = dynamic_cast<Beacon*>(enc);
    cModule* vehicle = getParentModule();
    Veins::TraCIMobility* traci = dynamic_cast<Veins::TraCIMobility*>(vehicle->getSubmodule("veinsmobility", 0));
    EV << "current position = " <<traci->getPositionAt(simTime())<<endl;
    for (int i = 0;i < 100;i++){
        THSbeaconrate[i] = bc->getBeaconrate(i) ;
        THSspeed[i] = bc->getSpeed(i) ;
        THSacceleration[i] = bc->getAcceleration(i) ;
        THSposition[i] = bc->getPosition(i) ;
        THSangle[i] = bc->getAngle(i) ;
        THScp[i] = bc->getCp(i) ;

    //    EV << "received beaconrate = " <<bc->getBeaconrate(i)<<endl;    //get THSbeaconrate ???
    //    EV << "received speed = " <<bc->getSpeed(i)<<endl;
    //    EV << "received acceleration = " <<bc->getAcceleration(i)<<endl;
    //    EV << "received position = " <<bc->getPosition(i)<<endl;
    //    EV << "received angle = " <<bc->getAngle(i)<<endl;
    }
    for (int i = 0;i < (int)bc->getBeaconrate(bc->getVehicleId());i++ ){
        int k = i*(int)(10/bc->getBeaconrate(bc->getVehicleId())) ;
        if(bc->getSlotpos().x+k < 10){
        THSslotnum[(int)bc->getSlotpos().x+k][(int)bc->getSlotpos().y] = 1 ;
        }
    }
    THSbeaconrate[bc->getVehicleId()] = bc->getBeaconrate(bc->getVehicleId());
    THSspeed[bc->getVehicleId()] = bc->getSpeed(bc->getVehicleId()) ;
    THSacceleration[bc->getVehicleId()] = bc->getAcceleration(bc->getVehicleId()) ;
    THSposition[bc->getVehicleId()] = bc->getPosition(bc->getVehicleId()) ;
    THSangle[bc->getVehicleId()] = bc->getAngle(bc->getVehicleId()) ;

    EV << "Receive successfully !!!!!!!!!!!" << endl;

}

设置消息和接收消息的两处内容可能有偏差,不是大问题。

NOTE6:handleLowerMsg重写了父类BaseWaveApplLayer的handleLowerMsg,为了避免覆盖父类的实现,可以在该方法最后加上下面一行代码,对于handleSelfMsg或Mac、phy层的handleUpperMsg也可以加上这样的代码:

BaseWaveApplLayer::handlLowerfMsg(msg);

4、总结

到此一次完整的消息传输过程就结束了,容易出错的地方总结如下:

1、消息的封装和解封

//封装:
    //新建WSM,这是应用层和MAC层通信的消息
    WaveShortMessage* WSM = new WaveShortMessage();
    //把beacon封装在WSM中
    WSM->encapsulate(beacon);
    //设置WSM的基本信息
    populateWSM(WSM);
    //将WSM从应用层的向下接口发送出去
    send(WSM,lowerLayerOut);
//解封:
    //消息传换成WSM
    WaveShortMessage* WSM = check_and_cast<WaveShortMessage*>(msg);
    //从WSM中解封数据包
    cPacket* enc = WSM->getEncapsulatedPacket();
    //数据包转换成Beacon
    Beacon* bc = dynamic_cast<Beacon*>(enc);

2、消息中数组的使用:

//setter:
    for (int i = 0;i < 100;i++){
        beacon->setBeaconrate(i,THSbeaconrate[i]);
        beacon->setCp(i, THScp[i]);
        beacon->setSpeed(i,THSspeed[i]);
        beacon->setAcceleration(i, THSacceleration[i]);
        beacon->setPosition(i, THSposition[i]);
        beacon->setAngle(i, THSangle[i]);
    }
//getter:
    for (int i = 0;i < 100;i++){
        THSbeaconrate[i] = bc->getBeaconrate(i) ;
        THSspeed[i] = bc->getSpeed(i) ;
        THSacceleration[i] = bc->getAcceleration(i) ;
        THSposition[i] = bc->getPosition(i) ;
        THSangle[i] = bc->getAngle(i) ;
        THScp[i] = bc->getCp(i) ;
    }

3、消息调度错误常见有两种情况

(1)调度的时间是过去时间,如在8s时scheduleAt(SimTime(5),sendBeacon);出错;

(2)被调度的自消息已经被调度并且还没执行,如在5s时scheduleAt(SimTime(8),sendBeacon),在6s时又scheduleAt(SimTime(8),sendBeacon),这种情况下可以先取消再调度:

if (sendBeacon->isScheduled()) {
    cancelEvent(sendBeacon);
}
scheduleAt(SimTime(8),sendBeacon);

以上!希望对大家有帮助,也感谢大家支持。关于veins应用方面如果大家还有想了解的内容可以私信我,我会尽力去学习。再次感谢。

  • 22
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 31
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值