The Platooning Extension for Veins.
This quick tutorial assumes that you already have installed Plexe and all the required software following the instruction inside the building section. After doing so, please set up the environmental variables by running the following
1
2 cd ~/src/plexe
. ./setenv
One of the design features of Plexe is the possibility of including non-platooning vehicles in the simulation.
So far, using this feature was not trivial, as it required to know very very well some of the core principles of both OMNeT++ and Veins.
To help you understanding how to do something like this, we prepared this tutorial.
The simulation runs an 8-car platoon as in the first example, but this time it also adds an additional human driven vehicle which generates network interference by periodically sending IEEE 802.11p frames.
The example is located in the examples/human
folder under the Plexe-Veins source folder.
To implement this scenario, we do the following steps:
examples/platooning/sumocfg
, we simply add a new vehicle type to the freeway.rou.xml
file.
This will be our human-driven vehicle type.
For this vehicle, we do not use the CC car following model, as the vehicle will simply use a human-behavioral model.
We also give it a blue color, so we will be able to distinguish it from platooning vehicles (red):1 <vType id="vtypehuman" accel="2.5" decel="6.0" sigma="0.5" length="4" minGap="0" maxSpeed="27.77778" color="0,0,1" probability="1"></vType>
Create a beaconing protocol: the OMNeT++ module instance for the human-driven vehicle will be different from a platooning vehicle.
Such a vehicle will not use the beaconing protocols used by platooning vehicles.
One reason is that, in reality, a vehicle might run a different application and thus a different protocol.
In addition, this will keep the code nice and clean, as we will not mix platooning and non-platooning vehicles code.
The sample protocol is located under src/plexe/protocols
and it is called HumanInterferingProtocol
.
Its code is very simple and it does only send periodic beacons.
The only important thing that it does is to define a different ID for its sent beacons, so that platooning vehicles will simply ignore packets received from human-driven vehicles.
As the beacon ID for platooning vehicles is 12345
we simply choose a different one for human-driven vehicle, i.e., 12349
.
Create a new traffic manager: the standard traffic injection class (PlatoonsTrafficManager
) only injects platooning vehicles.
We can either modify it to inject our human-driven vehicle, or create a new one.
To keep things separated, we created a new one, called PlatoonsPlusHumanTraffic
, which is located under src/plexe/traffic
.
Create a new vehicle module: we create a new vehicle OMNeT++ compound module that will be the instance of our human-driven vehicle.
In examples/human
we create HumanCar.ned
, which is very similar to Car.ned
(the OMNeT++ instance for a platooning vehicle) but only uses the HumanInterferingProtocol
we defined.
If you look inside the file, you will see that it only uses 3 modules:
All the other modules in Car.ned
are not needed.
Edit omnetpp.ini: the omnetpp.ini
in the human
example folder is a copy of the one in the platooning
example folder, with some changes.
Let’s go through those changes:
In the original file you find
1
2 *.manager.moduleType = "Car"
*.manager.moduleName = "node"
which says that every vehicle in SUMO should be instantiated as a Car module in OMNeT++, and that for configuring the parameters of that module, node
should be used as a name (e.g., *.node[*].mobility.z = 1.895
.
1
2 *.manager.moduleType = "vtypeauto=Car vtypehuman=HumanCar"
*.manager.moduleName = "vtypeauto=node vtypehuman=human"
which tells Veins that every vehicle with SUMO vehicle type vtypeauto
should be instantiated as a Car
module, while the vehicle type vtypehuman
should be instantiated as a HumanCar
module.
In addition, we will use the name human
to set the parameters of the latter within the omnetpp.ini
file.
If you want a SUMO vehicle not to be an OMNeT++ node, meaning that it will be a simple, non-communicating vehicle, you can change the previous configuration to
1
2 *.manager.moduleType = "vtypeauto=Car vtypehuman=0"
*.manager.moduleName = "vtypeauto=node vtypehuman=0"
This way, there will be a vehicle in your SUMO scenario, but no corresponding OMNeT++ node. If you don’t need some vehicles to communicate, this can speed up your simulation.
1 **.traffic_type = "PlatoonsTrafficManager"
into
1 **.traffic_type = "PlatoonsPlusHumanTraffic"
1
2
3
4
5 **.numberOfHumanCars = ${humanCars = 1}
**.numberOfHumanLanes = ${humanLanes = 1}
**.traffic.humanCars = ${humanCars}
**.traffic.humanLanes = ${humanLanes}
**.traffic.humanVType = "vtypehuman"
In the last line, we are telling which SUMO vehicle type the traffic manager should use to create the human-driven vehicle.
1
2
3 *.human[*].mobility.x = 0
*.human[*].mobility.y = 0
*.human[*].mobility.z = 1.895
1
2
3
4
5 *.human[*].prot.beaconingInterval = 0.1 s
*.human[*].prot.priority = 2
*.human[*].prot.packetSize = 200
*.human[*].prot.txPower = 100 mW
*.human[*].prot.bitrate = 3 Mbps
The parameters include the beacon interval, the access category (priority), the packet size in bytes, the transmit power, and the physical layer bitrate. In the next part of the tutorial, we are going to see how to set transmit power and physical layer bitrate within the code.
One feature that you might need in your simulation is to change the transmit power and the modulation and coding scheme (MCS) of a particular vehicle within your code.
This is not always the case, but usually parameters set within the omnetpp.ini
file are general, meaning that they affect all vehicles.
By looking into the code of the HumanInterferingProtocol
class, you will find two methods to change such parameters from the code.
One way is to set the transmit power and/or the MCS by calling two specific methods of the MAC layer.
This will change the default transmit power and the MCS for all the frames sent by that vehicle.
This first thing to do within your module is to retrieve the instance of you MAC layer, which is done through
1 Mac1609_4 *mac = FindModule<Mac1609_4 *>::findSubModule(getParentModule());
Then, you can change the default transmit power and MCS by invoking
1
2 mac->setTxPower(txPower);
mac->setMCS(getMCS(bitrate, BW_OFDM_10_MHZ));
where txPower
is the transmit power in mW, while bitrate
is the bitrate in bps.
So to use 3 Mbps, you will need to pass 3 000 000 to the getMCS
function.
Be careful to call those functions in the second initialization stage (see the code).
By invoking them in the first initialization stage, if your module is initialized before the MAC module, the MAC initialization might overwrite the values you just set with the values take from the omnetpp.ini
file.
The second method permits to choose transmit power and MCS on a per packet basis, i.e., you can tell the MAC to use a certain transmit power for a frame and another value for another frame.
To do so, you will need to attach some control information to your beacon.
The code of the sendInterferingBeacon
method looks as follows
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 BaseFrame1609_4* frame = new BaseFrame1609_4("", INTERFERENCE_TYPE);
frame->setRecipientAddress(LAddress::L2BROADCAST());
frame->setUserPriority(priority);
frame->setChannelNumber(static_cast<int>(Channel::cch));
InterferingBeacon* pkt = new InterferingBeacon();
pkt->setKind(INTERFERENCE_TYPE);
pkt->setByteLength(packetSize);
PhyControlMessage* ctrl = new PhyControlMessage();
ctrl->setTxPower_mW(txPower);
ctrl->setMcs(static_cast<int>(getMCS(bitrate, Bandwidth::ofdm_10_mhz)));
pkt->setControlInfo(ctrl);
frame->encapsulate(pkt);
sendDown(frame);
First, we create a BaseFrame1609_4
in which we encapsulate our InterferingBeacon
.
To set the transmit power and the MCS for this beacon, we create a PhyControlMessage
, set the desired values, and add it to the beacon as control information.
The control information will be then taken by the MAC layer and used for setting the transmit power and the MCS.