opp_env Workspace Layout and Your First VANET Project

Video CompanionUpdated July 7, 2026

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

  1. Select File → New → OMNeT++ Project
  2. Keep "Use default location" checked
  3. 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.0 and veins-5.3.1 to 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.