本项目旨在分享开源交通仿真软件 SUMO 的 C++ 二次开发实践经验,填补当前中文互联网中关于 SUMO C++ 开发资料的空白。项目中整理了完整的开发编译流程、关键接口说明以及实际应用示例,帮助开发者快速上手并灵活拓展 SUMO 的功能。
同时,也诚挚推荐国产优秀的交通仿真平台 TESS NG,希望通过项目推广推动国产仿真技术的发展与应用!
- 支持将 Python TraCI 脚本迁移为 C++ 的 libtraci 实现,显著提升运行效率,满足科研与工程对性能的更高要求。
- 支持动态创建与管理车辆对象,适用于交通管理与交通控制相关科研场景。
- 支持多类型交通流混合干扰建模,便于对国产交通仿真软件功能是否可替代 SUMO 进行深入对比研究。
SumoCoSimuWithTessng
├── /include ->项目头文件
├── /lib ->项目三方静态库
├── /src ->项目源文件
├── /SumoDependence ->sumo cpp开发依赖(动态库、头文件、静态库)
│ ├── /bin/ ->可执行文件依赖的dll动态库
│ │ ├── libtracicpp.dll
│ │ ├── ...
│ │ ├── xxx.dll
│ ├── /include/ ->项目依赖的相关头文件
│ │ ├── /libsumo/
│ │ │ ├── Simulation.h
│ │ │ ├── ...
│ │ │ ├── xxx.h
│ ├── /lib/ ->编译时所需的lib静态库
│ │ ├── libsumocpp.lib
│ │ ├── libtracicpp.lib
├── /TESSNG.zip ->TESSNG可执行文件zip压缩包
├── /maps ->sumo仿真路网文件
│ ├── /Crossing8/
│ │ ├── Crossing8Course.net.xml
│ │ ├── Crossing8Course.sumocfg
│ │ ├── Crossing8Course.xodr
│ │ └── routes.rou.xml
├── CMakeLists.txt -> CMake文件
├── config.json ->项目运行配置文件
├── main.cpp ->主程序
├── README.md ->README
├── LICENSE.txt ->开源证书
项目基于Windows平台开发,且只支持release模式。需要安装visual studio以及cmake。
- [visual studio](微软集成开发环境)
https://learn.microsoft.com/zh-cn/cpp/build/vscpp-step-0-installation?view=msvc-170
- [cmake](开源跨平台自动构建系统)
https://blog.csdn.net/zhouzhiwengang/article/details/133430457
-
[grpc - 谷歌开源rpc通信库] (https://github.com/grpc/grpc)
-
[TESS NG - 济达交通国产交通微观仿真软件] (https://www.jidatraffic.com/#/home)
1、下载代码后,文件夹内新建build文件夹。
2、cmake-gui打开文件夹。CMAKE_INSTALL_PREFIX的Value填写为第一步创建的build文件夹绝对路径(作者的build文件夹绝对路径为 "F:\Projects\Sumo\Sumo\build")。点击左下角的Configure按钮,等待提示框中出现Configuring done。
3、Configuring done后点击Generate按钮,等待提示框中出现Generating done。
4、双击新建的build文件夹,再双击SumoCoSimuWithTessng.sln打开visual studio解决方案。
5、双击sln文件,打开visual studio项目。
6、右键ALL_BUILD点击生成,开始编译项目。
7、生成完毕后,visual studio会在build文件夹下生成Release文件夹,Release文件夹下的SumoCoSimuWithT essng.exe为编译后的可执行文件。参考《文件目录说明》,将SumoCoSimuWithTessng/SumoDependence/ bin下的dll文件;SumoCoSimuWithTessng/maps文件夹;SumoCoSimuWithTessng/config.json全部拷贝到build/Release目录下。
8、运行可执行文件。会打开config.json中配置的默认路网Crossing8Course.sumocfg.
项目中用到libtraci相关接口的部分代码。
1、SimControl.cpp
void SimControl::SumoSimulation::paintSumoVehicle(const std::string &vehID){
if (vehID.compare(0, 6, "extern") == 0){
return;
}
libtraci::Vehicle::setColor(vehID, libsumo::TraCIColor(0, 255, 255));
}
std::string SimControl::SumoSimulation::addSumoVehicle(const CoSimulation::TessngVehicleProto& externVehicle, const std::vector<std::string>& vehicleIdList, const std::vector<std::string>& edgeIdList){
std::stringstream vehicleId;
vehicleId << "extern_" << externVehicle.id();
std::string vehicleIdStr = vehicleId.str();
// 如果包含这个对象,则直接pass
if (alreadyAddedExternVehicleIdSet.contains(vehicleIdStr)){
std::cout << "exist pass " << vehicleIdStr << std::endl;
return "";
}
std::vector<std::string> myRouteEdgeList {edgeIdList.at(0)};
libtraci::Vehicle::add(vehicleIdStr, "");
// 创建成功插入集合
if (!alreadyAddedExternVehicleIdSet.contains(vehicleIdStr)){
alreadyAddedExternVehicleIdSet.insert(vehicleIdStr);
std::cout << "add success! " << vehicleIdStr << std::endl;
}
return vehicleIdStr;
}
void SimControl::SumoSimulation::moveSumoVehicle(const std::string &vehID, const CoSimulation::TessngVehicleProto& externVehicle, const std::vector<std::string>& vehicleIdList){
std::stringstream vehicleId;
vehicleId << "extern_" << externVehicle.id();
std::string vehicleIdStr = vehicleId.str();
// 如果这个车不是我创建的,直接pass
if (!alreadyAddedExternVehicleIdSet.contains(vehicleIdStr)){
return;
}
// 如果这个车已经被sumo系统移除,则同步移除alreadyAddedExternVehicleIdSet中的id
if (!(std::find(vehicleIdList.begin(), vehicleIdList.end(), vehicleIdStr) != vehicleIdList.end())){
return;
}
// 设置颜色和速度
libtraci::Vehicle::moveToXY(vehicleIdStr, "", -1, externVehicle.position().x(), externVehicle.position().y(), externVehicle.heading().yaw(), 2);
libtraci::Vehicle::setSpeed(vehicleIdStr, 0);
libtraci::Vehicle::setSpeedMode(vehicleIdStr, 0);
libtraci::Vehicle::setRoutingMode(vehicleIdStr, 0);
// 设置颜色和尺寸
libtraci::Vehicle::setColor(vehicleIdStr, libsumo::TraCIColor(255, 0, 0));
libtraci::Vehicle::setLength(vehicleIdStr, 5);
libtraci::Vehicle::setWidth(vehicleIdStr, 2);
}
PublicStruct::SumoVehicle* SimControl::SumoSimulation::getVehicleInfo(const std::string &vehID) {
auto* vehicle = new PublicStruct::SumoVehicle();
vehicle->vehicleId = vehID;
vehicle->speed = libtraci::Vehicle::getSpeed(vehID);
vehicle->type = "sumo";
vehicle->size.length = libtraci::Vehicle::getLength(vehID);
vehicle->size.width = libtraci::Vehicle::getWidth(vehID);
vehicle->size.height = libtraci::Vehicle::getHeight(vehID);
PublicStruct::Rotation rotation{};
double yaw = libtraci::Vehicle::getAngle(vehID);
double pitch = libtraci::Vehicle::getSlope(vehID);
rotation.yaw = yaw;
rotation.pitch = pitch;
rotation.roll = 0;
vehicle->rotation = rotation;
PublicStruct::Position myPosition{};
libsumo::TraCIPosition position3D = libtraci::Vehicle::getPosition3D(vehID);
myPosition.x = position3D.x;
myPosition.y = position3D.y;
myPosition.z = position3D.z;
vehicle->position = myPosition;
auto now = std::chrono::system_clock::now();
auto seconds_since_epoch = std::chrono::duration_cast<std::chrono::duration<double>>(now.time_since_epoch());
auto timestamp_in_seconds = static_cast<double>(seconds_since_epoch.count());
vehicle->timestamp = timestamp_in_seconds;
return vehicle;
}
2、GuiControl.cpp
void GuiControl::SumoGui::startSumoGui() const {
if (SumoGuiPath.empty() || SumoCfgPath.empty()){
return;
}
// 指定50001端口
try{
libtraci::Simulation::start({SumoGuiPath[0], "-c", SumoCfgPath, "--step-length", OnceStepSecond}, 50001);
}catch (const std::exception& e){
std::cerr << e.what() << std::endl;
}
}
github:https://github.com/zhuabaguai
该项目签署了MIT 授权许可,详情请参阅 [LICENSE.txt]