The Platooning Extension for Veins.

Plexe Examples - Adding non-platooning vehicles and changing transmit power

Note: This tutorial assumes you already cloned the git repositories for running Example 1.

Step 0. Building Plexe

If you built the code for Example 1 you are ready to go. Be careful that the code for this example is not yet officially release, so you will find it in the plexe-dev branch of the plexe-veins repository.

Adding a human-driven vehicle:

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:

  • Adding a new vehicle type: with respect to the SUMO configuration files in 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):
  • <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/veins/modules/application/platooning/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/veins/modules/application/platooning/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 4 modules:
    1. HumanInterferingProtocol: the module that generates interfering packets;
    2. UnicastProtocol: as used by platooning vehicles, on top of the 802.11p NIC;
    3. Nic80211p: the 802.11p NIC;
    4. TraCIMobility: the module that takes care of moving the OMNeT++ node to match the vehicle in SUMO.
    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:
    1. In the original file you find
      *.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. In the modified version, you find
      *.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 Carmodule, 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
      *.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.
    2. We change the traffic manager and use the new one, so we change
      **.traffic_type = "PlatoonsTrafficManager"
      **.traffic_type = "PlatoonsPlusHumanTraffic"
    3. We then configure the traffic manager and tell it to inject only one human-driven vehicle:
      **.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.
    4. We set the height of the antenna, in case you are using the two ray ground model:
      *.human[*].mobility.x = 0
      *.human[*].mobility.y = 0
      *.human[*].mobility.z = 1.895
    5. Finally, we configure some parameters of the beaconing protocol of the human-driven vehicle:
      *.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.

Changing transmit power and bitrate:

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

Mac1609_4 *mac = FindModule::findSubModule(getParentModule());
Then, you can change the default transmit power and MCS by invoking
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

UnicastMessage *unicast = new UnicastMessage("", INTERFERENCE_TYPE);

InterferingBeacon *pkt = new InterferingBeacon();

PhyControlMessage *ctrl = new PhyControlMessage();
ctrl->setMcs(getMCS(bitrate, BW_OFDM_10_MHZ));

First, we create a UnicastMessage 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.