Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,11 @@ CM11_proj/tmp.obj
/tests/Applications/Eco_Fixed_Timming/Experiments/

TODO.md

# User-provided proprietary scenarios - track folder structure but ignore contents
/tests/UserScenarios/*
!/tests/UserScenarios/.gitkeep
!/tests/UserScenarios/README.md

# Active debug configuration (per-worktree, for VS debugging)
/TrafficLayer/.active_config
144 changes: 144 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Real-Sim FIXS (Flexible Interface for XIL Simulation) is a multi-resolution X-in-the-loop (XIL) simulation framework for connected and automated vehicle testing. It provides transparent connections between traffic simulators (VISSIM, SUMO), vehicle dynamics tools (CarMaker, Simulink), and virtual environments (Carla).

**Current Software Versions**: CarMaker 13.1.2, Carla 0.9.15, VISSIM 2022, SUMO 1.21, dSPACE/Matlab 2024a

## Architecture

### Core Components

- **TrafficLayer**: Main interface executable that orchestrates connections between traffic simulators and other components. Entry point: [TrafficLayer/TrafficLayer/mainTrafficLayer.cpp](TrafficLayer/TrafficLayer/mainTrafficLayer.cpp)
- **ControlLayer**: Application-level controllers (e.g., CoordMerge for coordinated merging)
- **VehicleClient**: Dummy clients for testing (numbered 1-20 for multi-vehicle scenarios)
- **VirtualEnvironment**: Interface to virtual environments like Carla
- **CommonLib**: Shared libraries and helpers used across all components

### Key Helper Classes

- **ConfigHelper**: Parses config.yaml files and manages simulation setup ([CommonLib/ConfigHelper.h](CommonLib/ConfigHelper.h))
- **SocketHelper**: Handles TCP socket communication between components ([CommonLib/SocketHelper.h](CommonLib/SocketHelper.h))
- **TrafficHelper**: Manages connections to VISSIM/SUMO traffic simulators ([CommonLib/TrafficHelper.h](CommonLib/TrafficHelper.h))
- **MsgHelper**: Message serialization/deserialization for vehicle data ([CommonLib/MsgHelper.h](CommonLib/MsgHelper.h))

### Communication Architecture

The system uses a client-server socket architecture:
- TrafficLayer acts as central hub, connecting to traffic simulators (VISSIM via DLL, SUMO via libsumo)
- Applications/XIL systems connect to TrafficLayer as clients
- Messages contain vehicle state data defined in [CommonLib/VehDataMsgDefs.h](CommonLib/VehDataMsgDefs.h)
- Configuration driven by config.yaml files (see test directories for examples)

### Simulator-Specific Implementations

- **VISSIM**: Uses driver model DLL ([ProprietaryFiles/VISSIMserver](ProprietaryFiles/VISSIMserver)) that hooks into VISSIM's driver model API
- **SUMO**: Uses libsumo embedded library ([CommonLib/libsumo](CommonLib/libsumo)) for in-process communication
- **CarMaker**: Uses custom HIL integration with Simulink ([CarMaker](CarMaker) utilities)

## Build System

### Prerequisites

External libraries must be compiled first using:
```
compileExternalLibraries.bat
```

This builds:
- libevent (event-driven socket library) in [CommonLib/libevent](CommonLib/libevent)
- yaml-cpp (YAML parser) in [CommonLib/yaml-cpp](CommonLib/yaml-cpp)

Both libraries use CMake with Visual Studio 16 2019 generator and build both Release and Debug configurations.

### Building Components

Build all components:
```
cd tests
compileCodes.bat
```

This builds (in order):
1. TrafficLayer.exe
2. CoordMerge.exe (control layer)
3. DriverModel_RealSim.dll and DriverModel_RealSim_v2021.dll (VISSIM interface)
4. VirtualEnvironment.exe
5. CarMaker projects (CM9, CM10, CM11)

All builds use msbuild with Release configuration. The msbuild command must be in PATH (typically `%ProgramFiles(x86)%\Microsoft Visual Studio\2019\<EDITION>\MSBuild\Current\Bin`).

### Release Dispatch

Create a distributable release build:
```
dispatch.bat
```

Requires:
- Conda environment named `realsimdev` with Python >= 3.8
- Runs [dispatchRealSim.py](dispatchRealSim.py) which compiles all components and copies executables/libraries to `build/` folder

## Configuration

### config.yaml Structure

All simulations are configured via YAML files with these main sections:

- **SimulationSetup**: Core settings including which simulator (VISSIM/SUMO), IP/ports, message fields to exchange, synchronization mode
- **ApplicationSetup**: Application layer subscriptions for vehicle/detector/signal data
- **XilSetup**: XIL system configuration (Simulink, CarMaker)
- **VirtualEnvironmentSetup**: Virtual environment (Carla) settings

Key configuration parameters:
- `SelectedTrafficSimulator`: 'VISSIM' or 'SUMO'
- `EnableExternalDynamics`: Allow external control of vehicle dynamics (SUMO)
- `VehicleMessageField`: Array of fields to exchange (see [README.md](README.md) Appendix for full field list)
- `SimulationMode`: Bitfield controlling sync behavior (0=sync at start, 1=wait for ego entry, 4=wait for specified time)

### Simulation Modes

SimulationMode is a bitfield:
- 0 (binary 000): Sync from simulation start
- 1 (binary 001): Wait mode until ego vehicle enters network, then sync
- 4 (binary 100): Wait mode until SimulationModeParameter seconds, then sync

## Running Tests

Test scenarios are in [tests](tests) directory, each with .bat files to run:

Example test execution:
```
cd tests/CoordMerge
runCoordMergeSUMO.bat
```

Tests are organized by scenario (CoordMerge, DelayedConnection, Elevation, etc.) and typically include:
- config.yaml for that scenario
- Batch files to launch simulation
- Network files for VISSIM/SUMO
- Simulink models if applicable

## Development Workflow

1. **Modifying simulator interfaces**: Edit TrafficHelper or simulator-specific code in CommonLib
2. **Adding message fields**: Update VehDataMsgDefs.h and corresponding pack/unpack logic in MsgHelper
3. **Creating new controllers**: Add to ControlLayer following CoordMerge pattern
4. **Testing changes**: Use existing test scenarios or create new one with config.yaml

## Important Notes

- **Error logs**: TrafficLayer.exe writes errors to TrafficLayer.err in its directory
- **VISSIM logs**: DriverModelError.txt and DriverModelLog.txt appear in VISSIM network directory
- **Verbose logging**: Enable with `EnableVerboseLog: true` in config.yaml for debugging
- **Multi-vehicle numbering**: Client/controller components numbered 1-20 for running multiple instances
- **Platform**: Windows-only (uses WinSock, VISSIM is Windows-only)

## Documentation

- VISSIM-specific: [doc/VISSIMdoc.md](doc/VISSIMdoc.md)
- SUMO-specific: [doc/SUMOdoc.md](doc/SUMOdoc.md)
- CarMaker-specific: [doc/CarMakerDoc.md](doc/CarMakerDoc.md)
3 changes: 0 additions & 3 deletions TrafficLayer/TrafficLayer/TrafficLayer.vcxproj.user
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>-f ..\..\RealSimRelease\config_SUMO_ACM.yaml</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>-f C:\src_git\Debug_Project\tests\UAtest\RS_config_release.yaml</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerEnvironment>PATH=%PATH%;..\..\CommonLib\libsumo;</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>-f ..\..\tests\Applications\Eco_Fixed_Timming\Experiments_Sumo\Debug\0%_1Hz_E\ecodriving_config_Sumo_wo_dyno.yaml</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
121 changes: 120 additions & 1 deletion TrafficLayer/TrafficLayer/mainTrafficLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,84 @@ static void show_usage(std::string name)
<< std::endl;
}

#ifdef WIN32
// Find all YAML files in a directory recursively (Windows implementation)
void findYamlFilesRecursive(const std::string& directory, std::vector<std::string>& yamlFiles) {
WIN32_FIND_DATAA findData;
std::string searchPath = directory + "\\*";
HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData);

if (hFind == INVALID_HANDLE_VALUE) {
return;
}

do {
std::string fileName = findData.cFileName;
if (fileName == "." || fileName == "..") continue;

std::string fullPath = directory + "\\" + fileName;

if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// Recursively search subdirectories
findYamlFilesRecursive(fullPath, yamlFiles);
}
else {
// Check if file has .yaml or .yml extension
size_t dotPos = fileName.find_last_of('.');
if (dotPos != std::string::npos) {
std::string ext = fileName.substr(dotPos);
if (ext == ".yaml" || ext == ".yml") {
yamlFiles.push_back(fullPath);
}
}
}
} while (FindNextFileA(hFind, &findData));

FindClose(hFind);
}
#else
// Find all YAML files in a directory recursively (POSIX implementation)
#include <dirent.h>
#include <sys/stat.h>
void findYamlFilesRecursive(const std::string& directory, std::vector<std::string>& yamlFiles) {
DIR* dir = opendir(directory.c_str());
if (!dir) return;

struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
std::string fileName = entry->d_name;
if (fileName == "." || fileName == "..") continue;

std::string fullPath = directory + "/" + fileName;

struct stat statbuf;
if (stat(fullPath.c_str(), &statbuf) == 0) {
if (S_ISDIR(statbuf.st_mode)) {
// Recursively search subdirectories
findYamlFilesRecursive(fullPath, yamlFiles);
}
else if (S_ISREG(statbuf.st_mode)) {
// Check if file has .yaml or .yml extension
size_t dotPos = fileName.find_last_of('.');
if (dotPos != std::string::npos) {
std::string ext = fileName.substr(dotPos);
if (ext == ".yaml" || ext == ".yml") {
yamlFiles.push_back(fullPath);
}
}
}
}
}
closedir(dir);
}
#endif

std::vector<std::string> findYamlFiles(const std::string& directory) {
std::vector<std::string> yamlFiles;
findYamlFilesRecursive(directory, yamlFiles);
return yamlFiles;
}

int main(int argc, char* argv[]) {

printf("==================================================\n");
Expand Down Expand Up @@ -365,7 +443,10 @@ int main(int argc, char* argv[]) {
}
}

string configPath = ".\\ecodrivingConfig.yaml";
string configPath;
bool configSpecified = false;

// Parse command-line arguments
for (int i = 1; i < argc; i++) {
string arg = argv[i];
if (arg == "-h" || arg == "--help") {
Expand All @@ -375,6 +456,7 @@ int main(int argc, char* argv[]) {
else if (arg == "-f" || arg == "--file") {
if (i + 1 < argc) {
configPath = argv[++i];
configSpecified = true;
}
else {
std::cerr << "--path option requires one argument." << std::endl;
Expand All @@ -388,6 +470,43 @@ int main(int argc, char* argv[]) {
}
}

// Auto-discover config if not specified
if (!configSpecified) {
// First, check for TrafficLayer/.active_config file
std::ifstream activeConfigFile("TrafficLayer/.active_config");
if (activeConfigFile.good()) {
std::getline(activeConfigFile, configPath);
activeConfigFile.close();
printf("Using config from TrafficLayer/.active_config: %s\n", configPath.c_str());
}
else {
// Auto-discover in tests/UserScenarios/
std::vector<std::string> yamlFiles = findYamlFiles("tests/UserScenarios");

if (yamlFiles.empty()) {
printf("ERROR: No configuration specified and no YAML found in tests/UserScenarios/\n");
printf("Options:\n");
printf(" - Use: -f path/to/config.yaml\n");
printf(" - Add scenario to tests/UserScenarios/\n");
printf(" - Create TrafficLayer/.active_config with path to your config\n");
return -1;
}
else if (yamlFiles.size() == 1) {
configPath = yamlFiles[0];
printf("Auto-discovered config: %s\n", configPath.c_str());
}
else {
printf("ERROR: Multiple YAML files found in tests/UserScenarios/\n");
printf("Please create TrafficLayer/.active_config file with one of these paths:\n");
for (const auto& yaml : yamlFiles) {
printf(" - %s\n", yaml.c_str());
}
printf("\nExample: echo tests/UserScenarios/issue_85/config.yaml > TrafficLayer/.active_config\n");
return -1;
}
}
}

// ===========================================================================
// READ Config File
// ===========================================================================
Expand Down
Loading