opp_env Workspace Layout and Your First VANET Project
What opp_env installs, how to wire a project to it, and a minimal Veins scenario that actually sends and receives. This is the companion piece to the video — a reference document for setting up a VANET project with OMNeT++.
What opp_env actually installs
A single command creates three directories:
inet-4.6.0/omnetpp-6.3.0/veins-5.3.1/
INET is included as a dependency since Veins uses some of its channel and mobility models. Verify dependencies with opp_env info veins-latest.
Entering the workspace
All installed components only function within the opp_env shell:
opp_env shell
omnetpp
The IDE automatically configures the workspace root.
Creating a project
- Select File → New → OMNeT++ Project
- Keep "Use default location" checked
- Maintain standard structure:
src/for C++ modules,simulations/for network definitions
Two distinct configuration steps are required:
- Project References (right-click project → Properties → Project References): check
inet-4.6.0andveins-5.3.1to resolve NED types - Makemake settings (Properties → OMNeT++ → Makemake → select
src→ Options → Compile tab): separately confirm veins is checked to resolve C++ includes
Missing the second one is the most common failure at this stage.
A minimal SUMO network
All files remain flat inside simulations/ without subfolders.
Generate a grid network:
netgenerate --grid --grid.number=2 -o simple.net.xml
Route file (simple.rou.xml):
<routes>
<vType id="car" accel="2.6" decel="4.5" length="5" maxSpeed="20"/>
<route id="route0" edges="A0A1 A1B1"/>
<vehicle id="veh0" type="car" route="route0" depart="0"/>
<vehicle id="veh1" type="car" route="route0" depart="5"/>
</routes>
SUMO configuration (simple.sumo.cfg):
<configuration>
<input>
<net-file value="simple.net.xml"/>
<route-files value="simple.rou.xml"/>
</input>
</configuration>
Launch configuration (simple.launchd.xml):
<launch>
<copy file="simple.net.xml" />
<copy file="simple.rou.xml" />
<copy file="simple.sumo.cfg" type="config" />
</launch>
Copy config.xml and antenna.xml from bundled Veins examples rather than writing custom files for radio physics parameters.
A custom app layer
PingApp.h:
#pragma once
#include "veins/modules/application/ieee80211p/DemoBaseApplLayer.h"
using namespace veins;
class PingApp : public DemoBaseApplLayer {
protected:
void initialize(int stage) override;
void handleSelfMsg(cMessage* msg) override;
void onWSM(BaseFrame1609_4* wsm) override;
};
PingApp.ned:
simple PingApp extends org.car2x.veins.modules.application.ieee80211p.DemoBaseApplLayer
{
parameters:
@class(PingApp);
}
The @class directive is mandatory. Without it, the NED type inherits the parent class binding and attempts to instantiate the base class directly, which cannot run independently.
PingApp.cc:
#include "PingApp.h"
Define_Module(PingApp);
void PingApp::initialize(int stage)
{
DemoBaseApplLayer::initialize(stage);
if (stage == 0) {
scheduleAt(simTime() + 2, new cMessage("sendPing"));
}
}
void PingApp::handleSelfMsg(cMessage* msg)
{
if (strcmp(msg->getName(), "sendPing") == 0) {
BaseFrame1609_4* wsm = new BaseFrame1609_4();
populateWSM(wsm);
sendDown(wsm);
delete msg;
}
else {
DemoBaseApplLayer::handleSelfMsg(msg);
}
}
void PingApp::onWSM(BaseFrame1609_4* wsm)
{
EV << "Received a message at " << simTime() << "\n";
}
Each vehicle sends a message after 2 seconds. Receiving vehicles process it through onWSM. This approach deliberately avoids the built-in beacon mechanism and uses onWSM instead of onBSM.
The network
PingNetwork.ned:
package vanet_scenarios.simulations;
import org.car2x.veins.nodes.Scenario;
network PingNetwork extends Scenario
{
}
No car submodule is declared. TraCIScenarioManager creates vehicles at runtime as SUMO reports them and automatically wires radio gates into the connection manager.
The full ini
[General]
cmdenv-express-mode = true
cmdenv-autoflush = true
cmdenv-status-frequency = 1s
**.cmdenv-log-level = info
network = PingNetwork
sim-time-limit = 30s
**.scalar-recording = true
**.vector-recording = true
*.playgroundSizeX = 200m
*.playgroundSizeY = 200m
*.playgroundSizeZ = 50m
*.annotations.draw = true
*.manager.updateInterval = 1s
*.manager.host = "localhost"
*.manager.port = 9999
*.manager.autoShutdown = true
*.manager.launchConfig = xmldoc("simple.launchd.xml")
*.connectionManager.sendDirect = true
*.connectionManager.maxInterfDist = 2600m
*.connectionManager.drawMaxIntfDist = false
*.**.nic.mac1609_4.useServiceChannel = false
*.**.nic.mac1609_4.txPower = 20mW
*.**.nic.mac1609_4.bitrate = 6Mbps
*.**.nic.phy80211p.minPowerLevel = -110dBm
*.**.nic.phy80211p.useNoiseFloor = true
*.**.nic.phy80211p.noiseFloor = -98dBm
*.**.nic.phy80211p.decider = xmldoc("config.xml")
*.**.nic.phy80211p.analogueModels = xmldoc("config.xml")
*.**.nic.phy80211p.usePropagationDelay = true
*.**.nic.phy80211p.antenna = xmldoc("antenna.xml", "/root/Antenna[@id='monopole']")
*.node[*].nic.phy80211p.antennaOffsetY = 0 m
*.node[*].nic.phy80211p.antennaOffsetZ = 1.895 m
*.node[*].applType = "PingApp"
*.node[*].appl.headerLength = 80 bit
*.node[*].appl.sendBeacons = false
*.node[*].appl.dataOnSch = false
*.node[*].veinsmobility.x = 0
*.node[*].veinsmobility.y = 0
*.node[*].veinsmobility.z = 0
*.node[*].veinsmobility.setHostSpeed = false
What this proves, and what it doesn't
The example demonstrates the complete chain: vehicle movement under TraCI control, scheduled message transmission, and reception through Veins in custom code. It does not address realistic road networks, traffic density, or practical application logic — that's covered next.
Next up
A follow-up covering real VANET scenarios using OpenStreetMap road data, roadside units, and measurable results.