Applicable Versions
StandardPro


Applicable Releases
v13.0v13.1
v14.0


This article explains an example of online coupling between NetSim and SUMO, that allows for the adaptation of drivers’ behavior during simulation runtime. The mobility pattern of the vehicles is therefore not pre-established from fixed trajectory (also called trace) files. Instead the road traffic and NetSim is connected in real time using TraCI thus enabling the control of mobility arrtibutes of each simulated vehicle. 


The parameters associated with vehicles in SUMO, such as vehicle speed, vehicle direction, and vehicle position can be set by using TraCI API's. In this example, we show to modify the vehicle speed in run time from NetSim using the TraCI APIs. 


1. Open the SumoRun.py file present in the <NetSim_Install_Directory>/bin path, perform the changes highlighted below:


v13.1/v14.0


# Import Sumo Libraries

import traci, string

import traci.constants as tc


traci.init(PORT)


print(" Running Sumo Simulation...")


traci.simulationStep() #skip the fist step to avoid termination

while traci.simulation.getMinExpectedNumber() > 0:

    garbage= "hello".encode()                #Send Garbage

    win32file.WriteFile(p1, garbage)

    jk =win32file.ReadFile(p1, 4096)    #Read vehicle from Netsim

    cmd=win32file.ReadFile(p1, 4096)    #Read command from Netsim

    vehicle_from_Netsim=jk[1].lower()[:-1]    #convert to lower case

    vehicle_from_Netsim = vehicle_from_Netsim.decode("utf-8")

    command_from_Netsim=cmd[1].lower()[:-1]    #convert to lower case

    command_from_Netsim = command_from_Netsim.decode("utf-8")

    k=0                                    #Flag if vehicle found

    k5=traci.vehicle.getIDList()

    for i in k5:

        if i.lower() == vehicle_from_Netsim:        #If vehicle found in sumo

            k=1                        #Turn on flag

    #command processing

            if "speed" in command_from_Netsim:        

                print("command from NetSim "+command_from_Netsim+"\n")

                print("speed is "+command_from_Netsim[6:]+" m/s\n")

                speed=float(command_from_Netsim[6:])

                traci.vehicle.setSpeed(i,speed)

            elif "continue" in command_from_Netsim:

                print("continuing simulation\n")

            break;

    if k==1:

        win32file.WriteFile(p1, 'c'.encode())            #The vehicle was found, being sent to Netsim for Connection('c' for confirmation)

        #get coordinates

        position_x = str(abs(traci.vehicle.getPosition(i)[0]))

        position_y= str(abs(traci.vehicle.getPosition(i)[1]))

        #send to Netsim

        win32file.WriteFile(p1, position_x.encode())

        win32file.WriteFile(p1, position_y.encode())

        #time.sleep(0.5)

        speed = str(abs(traci.vehicle.getSpeed(i)))

        angle = str(abs(traci.vehicle.getAngle(i)))

        time_stamp = str(abs(traci.simulation.getTime()))

        win32file.WriteFile(p1, speed.encode())

        win32file.WriteFile(p1, angle.encode())

        win32file.WriteFile(p1, time_stamp.encode())

        if i == k5[0]:                            #For every first vehicle present in list of vehicles, simulate

            traci.simulationStep()

    else :

        win32file.WriteFile(p1, 'f'.encode())                #Send not found to Netsim ('f' for denial of connection)

traci.close()

p1.close()


v13.0

# Import Sumo Libraries

import traci, string

import traci.constants as tc


traci.init(PORT)


print(" Running Sumo Simulation...")


while True:

    garbage= "hello".encode()                #Send Garbage

    win32file.WriteFile(p1, garbage)


    jk =win32file.ReadFile(p1, 4096)    #Read vehicle from Netsim

    cmd=win32file.ReadFile(p1, 4096)    #Read command from Netsim


    vehicle_from_Netsim=jk[1].lower()[:-1]    #convert to lower case

    vehicle_from_Netsim = vehicle_from_Netsim.decode("utf-8")   


    command_from_Netsim=cmd[1].lower()[:-1]    #convert to lower case

    command_from_Netsim = command_from_Netsim.decode("utf-8")



    k=0                                    #Flag if vehicle found

    k5=traci.vehicle.getIDList()


    if len(k5)==0:                        #No vehicle present, let the simulation continue

        traci.simulationStep()


    for i in k5:

        if i.lower() == vehicle_from_Netsim:        #If vehicle found in sumo

            k=1                                        #Turn on flag

            #command processing

            if "speed" in command_from_Netsim:        

                print("command from NetSim "+command_from_Netsim+"\n")

                print("speed is "+command_from_Netsim[6:]+" m/s\n")

                speed=float(command_from_Netsim[6:])

                traci.vehicle.setSpeed(i,speed)

            elif "continue" in command_from_Netsim:

                print("continuing simulation\n")

            

            break;


    if k==1:

        if i == k5[0]:                            #For every 1st vehicle present in list of vehicles, simulate

            traci.simulationStep()


        win32file.WriteFile(p1, 'c'.encode())            #The vehicle was found, being sent to Netsim for Connection('c' for confirmation)


        #get coordinates

        position_x = str(abs(traci.vehicle.getPosition(i)[0]))

        position_y= str(abs(traci.vehicle.getPosition(i)[1]))

        #print position_x,position_y,'\n'


        #send to Netsim

        win32file.WriteFile(p1, position_x.encode())

        win32file.WriteFile(p1, position_y.encode())

        #time.sleep(0.5)

        speed = str(abs(traci.vehicle.getSpeed(i)))

        angle = str(abs(traci.vehicle.getAngle(i)))

        time_stamp = str(abs(traci.simulation.getTime()))

        win32file.WriteFile(p1, speed.encode())

        win32file.WriteFile(p1, angle.encode())

        win32file.WriteFile(p1, time_stamp.encode())


    else :

        win32file.WriteFile(p1, 'f'.encode())                #Send not found to Netsim ('f' for denial of connection)


traci.close()

p1.close()


2. Open NetSim source codes in Visual Studio and add the lines of code highlighted below, in the Mobility.h file which is part of the Mobility source code project:

struct stru_NetSim_MobilityVar

    {        

        double dPauseTime; ///< To store the pause time.        

        double dVelocity; ///< To store the velocity.        

        unsigned long ulSeed1; ///< Used to generate random point.        

        unsigned long ulSeed2; ///< Used to generate random point        

        double dLastTime; ///< Represent the devices last move time.

        NETSIM_ID nGroupId; ///< To store group id of device.

        double dCalculationInterval;

        //Sumo

        char* sumoFileName;

        double step_size;

        double speed;

        double time;

        double X;

        double Y;

        //Pedestrain

        double Max_Speed;

        double Min_Speed;

        double Stop_Probability;

        double Stop_Duration;

        double Pedestrain_Speed;

        double angel;

    };

 

3. Go to the Sumo_interface.c file which is part of the Mobility source code project, and add the following function above the existing corr() function:

bool set_vehicle_speed(NETSIM_ID devid,double *speed)

{

    MOBILITY_VAR* var = (MOBILITY_VAR*)DEVICE_MOBILITY(devid)->pstruMobVar;

    if (var->speed < 5.5)

    {

        *speed = 5.5;

        return true;

    }    

    else

    return false;

}


4. In the same file modify the existing sumo_run() function as highlighted below:

    if (pstruMobilityVar->dLastTime + pstruMobilityVar->dPauseTime * 1000000 < pstruEventDetails->dEventTime + 1000000)    //Everytime Mobility being called

    {

        double* coordinates;        // Pointer for array of X and Y coordinates

        coordinates = corr(DEVICE_NAME(pstruEventDetails->nDeviceId));    //Get coordinates from python

        if (coordinates != NULL)

        {

            MOBILITY_VAR* var = (MOBILITY_VAR*)DEVICE_MOBILITY(pstruEventDetails->nDeviceId)->pstruMobVar;

            var->X = coordinates[0];

            var->Y = coordinates[1];

            var->speed = coordinates[2];

            var->time = coordinates[3];

            NETWORK->ppstruDeviceList[pstruEventDetails->nDeviceId - 1]->pstruDeviceMobility->pstruNextPosition->X = coordinates[0];    // Update the coordinates in Network stack

            NETWORK->ppstruDeviceList[pstruEventDetails->nDeviceId - 1]->pstruDeviceMobility->pstruNextPosition->Y = coordinates[1];

            free(coordinates);            // Free memory of pointer

        }


        //store the last time

        pstruMobilityVar->dLastTime = pstruEventDetails->dEventTime + 1000000 * step_size;            // Update Last time since we want to match timings with SUMO

    }


5. In the corr() function which is part of the Sumo_interface.c file, add the following lines of code that are highlighted:


   

double* corr(char* id)

{

    BOOL   fSuccess;                                //If reading/writing successfil or not

    DWORD  cbRead, cbToWrite, cbWritten;            // For Pipes

    CHAR  chBuf[BUFSIZ]; //For reading messages from pipes


    double xcor1, ycor1;     // x and y coordinates to be received from sumo

    double* coordinates;

    double speed; //speed of vehicle to be received from sumo

    double direction; //direction of vehicle to be received from sumo

    double time_stamp = 0; //Simulation time from sumo


    do

    {

        // Read Garbage from the pipe. 


        fSuccess = ReadFile

        (

            hPipe,    // pipe handle 

            chBuf,    // buffer to receive reply 

            BUFSIZ * sizeof(CHAR),  // size of buffer 

            &cbRead,  // number of bytes read 

            NULL        // not overlapped 

        );


        if (!fSuccess && GetLastError() != ERROR_MORE_DATA)

            break;

        chBuf[cbRead] = 0;

    } while (!fSuccess);  // repeat loop if ERROR_MORE_DATA 



    //Send Vehicle Name to Python 


    cbToWrite = (DWORD)strlen(id) + 1;

    fSuccess = WriteFile

    (

        hPipe,                  // pipe handle 

        id,             // message 

        cbToWrite,              // message length 

        &cbWritten,             // bytes written 

        NULL                    // not overlapped 

    );


    double new_speed = 0;

    char cmd[BUFSIZ];

    if (set_vehicle_speed(fn_NetSim_Stack_GetDeviceId_asName(id), &new_speed))

    {

        //Send new speed for Vehicle Name to Python 

        sprintf(cmd, "speed=%lf", new_speed);

        cbToWrite = (DWORD)strlen(id) + 1;

        fSuccess = WriteFile

        (

            hPipe,                  // pipe handle 

            cmd,             // message 

            cbToWrite,              // message length 

            &cbWritten,             // bytes written 

            NULL                    // not overlapped 

        );

    }

    else

    {

        //Send continue to Python 


        cbToWrite = (DWORD)strlen(id) + 1;

        fSuccess = WriteFile

        (

            hPipe,                  // pipe handle 

            "continue",             // message 

            cbToWrite,              // message length 

            &cbWritten,             // bytes written 

            NULL                    // not overlapped 

        );

    }


    // Read acknowledgment for vehicle ids

    do

    {


        fSuccess = ReadFile

        (

            hPipe,    // pipe handle 

            chBuf,    // buffer to receive reply 

            BUFSIZ * sizeof(CHAR),  // size of buffer 

            &cbRead,  // number of bytes read 

            NULL    // not overlapped 

        );


        if (!fSuccess && GetLastError() != ERROR_MORE_DATA)

            break;

        chBuf[cbRead] = 0;


    } while (!fSuccess);  // repeat loop if ERROR_MORE_DATA 




    if (chBuf[0] == 'c')  // If the vehicle is present ('c' for confirmation)

    {

        xcor1 = 0; ycor1 = 0;

        do

        {

            // Read X coordinate 

            fSuccess = ReadFile

            (

                hPipe,    // pipe handle 

                chBuf,    // buffer to receive reply 

                BUFSIZ * sizeof(CHAR),  // size of buffer 

                &cbRead,  // number of bytes read 

                NULL    // not overlapped 

            );


            if (!fSuccess && GetLastError() != ERROR_MORE_DATA)

                break;


        } while (!fSuccess);  // repeat loop if ERROR_MORE_DATA 


        xcor1 = atof(chBuf);

        if (xcor1 < 0)

            xcor1 = 0;


        do

        {

            // Read Y coordinate


            fSuccess = ReadFile

            (

                hPipe,    // pipe handle 

                chBuf,    // buffer to receive reply 

                BUFSIZ * sizeof(CHAR),  // size of buffer 

                &cbRead,  // number of bytes read 

                NULL        // not overlapped     

            );


            if (!fSuccess && GetLastError() != ERROR_MORE_DATA)

                break;

            chBuf[cbRead] = 0;


        } while (!fSuccess);  // repeat loop if ERROR_MORE_DATA 


        ycor1 = atof(chBuf);

        if (ycor1 < 0)

            ycor1 = 0;


        do


        {


            // Read vehicle speed


            fSuccess = ReadFile


            (


                hPipe, // pipe handle


                chBuf, // buffer to receive reply


                BUFSIZ * sizeof(CHAR), // size of buffer


                &cbRead, // number of bytes read


                NULL// not overlapped


            );


            if (!fSuccess && GetLastError() != ERROR_MORE_DATA)


                break;


            chBuf[cbRead] = 0;


        } while (!fSuccess); // repeat loop if ERROR_MORE_DATA


        speed = atof(chBuf);




        do


        {


            // Read vehicle direction


            fSuccess = ReadFile


            (


                hPipe, // pipe handle


                chBuf, // buffer to receive reply


                BUFSIZ * sizeof(CHAR), // size of buffer


                &cbRead, // number of bytes read


                NULL// not overlapped


            );


            if (!fSuccess && GetLastError() != ERROR_MORE_DATA)


                break;


            chBuf[cbRead] = 0;


        } while (!fSuccess); // repeat loop if ERROR_MORE_DATA


        direction = atof(chBuf);


        do


        {


            // Read time stamp


            fSuccess = ReadFile


            (


                hPipe, // pipe handle


                chBuf, // buffer to receive reply


                BUFSIZ * sizeof(CHAR), // size of buffer


                &cbRead, // number of bytes read


                NULL// not overlapped


            );


            if (!fSuccess && GetLastError() != ERROR_MORE_DATA)


                break;


            chBuf[cbRead] = 0;


        } while (!fSuccess); // repeat loop if ERROR_MORE_DATA


        time_stamp = atof(chBuf);


        coordinates = (double*)malloc(4 * sizeof * coordinates);

        coordinates[0] = xcor1;

        coordinates[1] = ycor1;

        coordinates[2] = speed;

        coordinates[3] = time_stamp;

        return (coordinates);                //Return X Y Coordinates  

    }


    else

    {

        return(NULL);        // If vehicle not found, return NULL

    }


}


6. Go to the BSM.c file which is part of the Application source code project and include the mobility header file in the beginning as shown below:


#include "Application.h"

#include "../Mobility/Mobility.h"


 7. Add a function copy_bsm_payload() above the already existing add_sae_j2735_payload() function as shown below:


void copy_bsm_payload(UINT8 real[], NetSim_PACKET* packet, unsigned int* payload, ptrAPPLICATION_INFO info)

{

    u_short i;

    uint32_t key = 16;

    char custom_data[BUFSIZ];

    MOBILITY_VAR* var = (MOBILITY_VAR*)DEVICE_MOBILITY(packet->nSourceId)->pstruMobVar;

    double speed = var->speed;

    double X = var->X;

    double Y = var->Y;

    double time_stamp = var->time;


    sprintf(custom_data,"time=%lf,x=%lf,y=%lf,speed=%lf",

        time_stamp,X,Y,speed);

    if (payload)

    {

        size_t custom_data_len = strlen(custom_data);

        for (i = 0; i < custom_data_len; i++)

        {

            if (info->encryption == Encryption_XOR)

                real[i] = xor_encrypt(custom_data[i], 16);

            else

                real[i] = custom_data[i];

        }

        if (info->encryption == Encryption_TEA)

            encryptBlock(real, payload, &key);

        else if (info->encryption == Encryption_AES)

            aes256(real, payload);

        else if (info->encryption == Encryption_DES)

            des(real, payload);

    }

}


8. Modify the function add_sae_j2735_payload() as highlighted below:


bool add_sae_j2735_payload(NetSim_PACKET* packet, ptrAPPLICATION_INFO info)

{

    // Add the payload based on SAE J2735 or any other standard

    // return true after adding.

    

    while (packet)

    {

        if (!packet->szPayload &&

            packet->pstruAppData &&

            packet->pstruAppData->dPacketSize &&

            packet->pstruAppData->nAppType != TRAFFIC_EMULATION /* Don't set payload in emulation */)

        {

            unsigned int size = (unsigned int)packet->pstruAppData->dPacketSize;

            packet->szPayload = (PPACKET_INFO)calloc(1, sizeof * packet->szPayload);

            copy_bsm_payload(packet->szPayload->packet, packet, &size, info);

            packet->szPayload->packet_len = size;

            packet->pstruAppData->dPacketSize = (double)size;

        }

        packet = packet->pstruNextPacket;

    }


    return true;

}


9. In the same file add the function definition for process_saej2735_packet() function as shown below:


void process_saej2735_packet(NetSim_PACKET* packet)

{

    //Add the code to process the SAE J2735 packet.

    //This function is called in Application_IN event.

    double speed = 0,time=0,x=0,y=0;

    char payload[BUFSIZ];

    char* parameters[4];

    char* tmp;

    int param_counter = 0;

    strcpy(payload, packet->szPayload->packet);

    char* token = strtok(payload, ",");


    // Keep printing tokens while one of the

    // delimiters present in str[].

    while (token != NULL) {

        parameters[param_counter] = token;

        //fprintf(stderr, "\n%s\n", token);

        token = strtok(NULL, ",");

        param_counter++;

    }


    for (int i = 0; i < param_counter; i++)

    {

        token = strtok(parameters[i], ",");

        if (strstr(token, "time"))

        {

            tmp = strtok(token, "=");

            while (token != NULL)

            {

                tmp = token;

                //fprintf(stderr, "\n%s\n", token);

                token = strtok(NULL, "=");

            }

            time = atof(tmp);

        }

        else if (strstr(token, "x"))

        {

            tmp = strtok(token, "=");

            while (token != NULL)

            {

                tmp = token;

                //fprintf(stderr, "\n%s\n", token);

                token = strtok(NULL, "=");

            }

            x = atof(tmp);

        }

        else if (strstr(token, "y"))

        {

            tmp = strtok(token, "=");

            while (token != NULL)

            {

                tmp = token;

                //fprintf(stderr, "\n%s\n", token);

                token = strtok(NULL, "=");

            }

            y = atof(tmp);

        }

        else if (strstr(token, "speed"))

        {

            tmp = strtok(token, "=");

            while (token != NULL)

            {

                tmp = token;

                //fprintf(stderr, "\n%s\n", token);

                token = strtok(NULL, "=");

            }

            speed = atof(tmp);

        }

    }

    

    fprintf(stderr, "\nPHY_IN Parameters of %s: time=%lf,x=%lf,y=%lf,speed=%lf\n", DEVICE_NAME(packet->nSourceId),time,x,y,speed);    


}


10. Save all changes and rebuild the Application and Mobility source code projects. 


11. Now run any simulations in VANET that involves SUMO mobility with Wireshark set to online/offline in the nodes that are either source/destination of BSM traffic.


12. During the simulation you can see the various parameters such as time, x, y, and speed associated with vehicles in SUMO retrieved printed to console and part of the Wireshark packet payload. 


Note: Ensure that the packet size is set to 50 Bytes or higher, in order to store the vehicle parameters.


10. The set_vehicle_speed() function defined in the Sumo_interface.c file can be modified suitably to set vehicle speed in SUMO based on certain calculations done in NetSim.