Applicable Versions | Standard | Pro |
Applicable Releases | v13.0 | v13.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.
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);
}
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.