
刚入坑交通仿真或者准备用SUMO做实验的同学十有八九都会卡在第一步软件装好了文档翻了几页却不知道从哪下手开始建一个能跑起来的仿真。SUMOSimulation of Urban Mobility是目前最常用的开源微观交通仿真工具没有商业授权限制能逐辆车模拟跟驰、变道、信号控制还能配合Python通过TraCI接口做在线交互。这篇教程是我自己从零摸爬滚打总结出来的第一篇主要解决三件事为什么要选SUMO、怎么正确装好环境、以及怎么从一张空白路网跑到第一个仿真动画。内容面向零基础尽量说人话每个步骤你照着做就能出结果。1. 为什么偏偏是SUMO1.1 微观仿真里它到底能干什么交通仿真软件分宏观、中观、微观三个层级SUMO属于微观仿真。什么意思就是每一辆车都是独立个体有独立的加速度、期望速度、车长、反应时间车跟车之间会互相影响。宏观仿真只给个流量密度关系曲线微观仿真则能回答“如果我把这个路口改成左转专用道排队长度会怎么变化”这类具体问题。SUMO里经常被忽略的是它背后的学术积累。它源自德国宇航中心里面内置了多种跟驰模型和换道模型比如经典的Krauss模型、IDM模型你可以通过配置文件直接切换。这意味着你在论文里写的“基于IDM模型开展仿真”不是嘴上说说而是真的能在SUMO里选到这个模型。除了模型SUMO还自带一套完整的工具链netedit画路网netconvert转换OpenStreetMap等外部路网duarouter做路径分配randomTrips生成随机出行请求TraCI做在线控制。这些工具单独拎出来都能干活组合起来就是一条完整流程。1.2 和VISSIM这类商业软件怎么选我经常被问一个问题既然有VISSIM为什么还要用SUMO我的回答是看你的场景和预算。VISSIM在三维可视化、信号配时细节上确实做得成熟接口也很齐全但一套License不便宜。如果你只是课程设计、毕业论文、算法验证或者要给交通信号控制算法做个快速原型验证SUMO完全够用。它最大的优势是免费、开源、脚本化。免费意味着你可以随便装很多台机器做大规模批量仿真不心疼。开源意味着你能看到仿真内部逻辑甚至修改源码这在学术审稿时是一个重要的可复现性加分项。另外一个实际对比是二次开发效率。VISSIM提供COM接口需要用C或Python写脚本去驱动编译和调试周期相对长。SUMO的TraCI接口直接用Python就能连代码量少调试方便而且社区有大量现成示例。我自己在两个平台都写过信号控制实验同样的实验用SUMO大概能省一半时间。1.3 什么样的人适合先从SUMO入门如果你属于下面任何一类SUMO都值得认真学交通工程专业的学生需要用仿真验证课程设计做自动驾驶或车路协同相关研究的人需要模拟车辆和路侧设备交互做算法的人需要一套可编程的交通环境来验证信号控制、路径规划、车速引导等策略以及单纯对城市交通系统感兴趣、想亲手“造一座城”的爱好者。反过来讲如果你的需求只是给甲方做漂亮的三维汇报动画SUMO的视觉表现力比不上商业软件建议我还是推荐你考虑商业方案。SUMO默认的二维界面比较朴素虽然能换视角和着色方案但跟游戏级的画面还是有差距。工具选型只有适合不适合没有绝对的好坏。2. 安装与运行环境准备不同系统的正确姿势2.1 Windows下的安装细节与Path配置Windows是SUMO用户最多、教程最多的平台安装本身没什么难度但是有几个细节值得注意。去官网下载页面sumo.dlr.de找到Windows安装包注意区分64位和32位现在主流机器都选64位。安装路径尽量不要带中文和空格我见过太多因为路径问题导致的莫名其妙报错比如装了默认的C盘Program Files目录导致脚本读取配置失败。建议直接装到D:\SUMO这种纯英文目录。安装完成后最关键的一步是配置环境变量。虽然安装程序一般会自动把sumo命令加入Path但很多情况下配置不完整。打开“系统属性—环境变量”把D:\SUMO\bin加进Path同时新建一个环境变量SUMO_HOME值设置为SUMO的安装根目录比如D:\SUMO。这个环境变量非常重要因为SUMO运行时需要定位自身的辅助文件比如类型定义文件和转换模板如果找不到就有各种奇怪的错误。配置完后打开命令行输入sumo --version验证安装。如果显示出版本号说明安装成功。再输入sumo-gui --version确认图形界面也可用。2.2 macOS和Linux安装要点macOS用户可以直接用Homebrewbrew install sumo装完需要检查Python绑定的路径因为Homebrew安装的SUMO可能不会自动配置Python库。你可以在终端里运行python -c import sys; print(sys.path)如果后续使用traci或sumolib报ModuleNotFoundError基本是Python环境变量问题。我一般建议加上环境变量export SUMO_HOME/opt/homebrew/share/sumo/$(brew list sumo | grep share/sumo | head -1 | xargs basename)Linux发行版用apt或yum装很方便但要注意版本往往偏旧。Ubuntu软件源里的SUMO可能比官网最新版本落后一年甚至更多有些新功能和网络格式不兼容。如果你要用到新特性比如新的信号控制或车道功能我建议直接从GitHub Release下载源码编译或者下载预编译版本。验证方式相同执行sumo --version如果不想把安装目录疯狂填到环境变量里Linux用户可以把export SUMO_HOME...写进~/.bashrc。2.3 安装过程中的高频坑第一个坑是版本过旧。很多教程基于很老版本的SUMO界面和文件格式跟新版有差异。如果你看的教程是“NetEdit里点某个按钮”但新版界面里根本找不到先检查版本而不是怀疑自己。第二个坑是Python库不匹配。SUMO的TraCI和sumolib需要通过Python导入而Python版本有可能不一致。建议创建虚拟环境用pip install sumo确认pip能找到正确的包路径然后测试导入import traci import sumolib第三个坑是防火墙或杀毒软件误拦截。SUMO运行时开启TraCI需要在本地端口默认8813上通信某些安全软件会拦截导致连接不上。3. SUMO核心概念四个文件和一个大脑3.1 少不了的三大核心文件我花了不少时间才想明白SUMO的文件体系这里给你一个最直观的类比一次仿真就像拍一部戏路网文件.net.xml是舞台出行需求文件.rou.xml是演员表配置文件.sumocfg是导演。路网文件描述道路怎么连接有几条车道限速多少信号灯在哪连接关系是什么。后缀通常是.net.xml。出行需求文件定义车辆从哪里出发、到哪里去、什么时候出发、最大速度多少。后缀通常是.rou.xml但实际可以是任意名字。配置文件把路网和需求关联起来并指定仿真时间步长、开始/结束时间、输出文件等。后缀是.sumocfg。当你运行sumo-gui your_config.sumocfg时SUMO读取配置加载路网然后让车辆按需求文件出现在路网上逐秒推进仿真。3.2 工具链全家桶谁负责干什么SUMO的bin目录下有很多可执行文件新手容易被吓到其实真正入门先记住这几个就够sumo命令行模式的仿真引擎不弹界面适合批量跑实验。sumo-gui带图形界面的仿真引擎能实时看到车辆移动。netedit图形化路网编辑器支持画路网、设置信号灯、检查器属性。netconvert把外部路网OpenStreetMap、Shapefile等转换成SUMO格式。randomTrips.py在路网上生成随机出行需求的Python脚本。duarouter根据出发地和目的地计算车辆路径输出实际行驶路线文件。polyconvert导入背景多边形建筑、水域等主要用于可视化。traciPython接口允许你在仿真运行过程中实时获取或修改仿真状态。可以这样理解netedit和netconvert是解决“路网从哪来”的问题randomTrips和duarouter是解决“车从哪来”的问题sumo是解决“车子怎么动起来”的问题TraCI是解决“我怎么控制整个过程”的问题。3.3 XML文件的基本结构和注意事项SUMO的配置和数据格式是XML所以稍微懂一点XML基础会更好上手。一个路网文件大致是这个样子net version1.6 junctionCornerDetail5 ... edge idedge1 fromnode1 tonode2 numLanes2 speed13.89/ edge idedge2 fromnode2 tonode3 numLanes1 speed11.11/ junction idnode1 typedead_end x0.0 y0.0 incLanesedge1_0 intLanes shape0.0,0.0 10.0,0.0/ /net这里edge就是一段路junction就是端点。注意SUMO中用edge表示两个节点之间的路段每个edge可以有多条车道车道编号从0开始方向从起始节点指向终止节点。如果你直接手写这种文件语法稍有不对仿真就会报错或加载失败。所以我的建议是优先用netedit或netconvert生成路网不要手写路网XML。手写的路网还要保证内部连接结构正确对新人不友好。4. 完整实操从空白路网到跑通第一个仿真4.1 用Netedit创建一条简单路网打开sumo-gui和netedit之前建议先在命令行里测试一下netedit能不能启动。能启动我们就开始画路网。第一步在netedit中创建节点和路段。打开netedit后默认处于“编辑网络”模式。在空白处单击放置节点连续单击两个节点两节点之间会自动生成一条路段。我建议从最简单的“十字路口”开始练手画四个方向的节点然后用十字交叉连接形成一个最简单的环岛形的路网原型。第二步检查路段属性。选中一条路段在左侧属性面板能看到numLanes、speed、id等字段。如果你是给城市道路做仿真车速默认单位是m/s不是km/h。一个常见的错误是把“60”理解为60km/h直接填进去结果仿真里车速直接飙到60m/s。注意换算关系1 m/s 3.6 km/h城市道路限速40km/h就填大约11.11限速60km/h就填16.67。第三步设置节点类型和连接关系。在默认情况下两个路段相交的节点是优先规则right-before-left而不是信号灯控制。后面如果你想配信号灯可以在节点上添加信号机构我留到后面教程细说本篇先保证能跑。第四步保存网络文件。使用“保存网络”功能把文件存成比如myNet.net.xml。保存时会弹出一个对话框建议勾选“保存时自动修复网络”这样SUMO会帮你补全一些缺失的连接信息。4.2 用randomTrips生成车辆需求路网有了还需要车。最简单的方式是使用SUMO自带的randomTrips.py脚本。在命令行中进入刚才保存路网文件的目录执行python D:\SUMO\tools\trip\randomTrips.py -n myNet.net.xml -r trips.rou.xml -e 100 -p 2参数说明-n net.xml指定路网文件。-r trips.rou.xml输出车辆路由文件。-e 100仿真结束时间为100秒。-p 2每2秒生成一辆车。--edges-file如果只想在特定道路生成车辆可以用这个参数指定一个包含edge id的文本文件。执行完后目录下会生成trips.rou.xml里面包含很多trip元素就是一个出行需求清单。但是注意randomTrips.py生成的只是“出行需求”还没确定走哪条路。所以我们需要调用duarouter来为每个出行计算具体路径duarouter -n myNet.net.xml -r trips.rou.xml -o routes.rou.xmlroutes.rou.xml才是最终可用的车辆路由文件里面每个vehicle包含一条具体行驶路线。这里有必要讲一下两段式的逻辑SUMO把“我想从这个路口到那个路口”和“具体怎么走”分成两层。同一个需求如果路网发生变化路径会重新计算这样你不需要重抄需求文件只需要重新运行duarouter这对后续研究信号控制或路网拓扑变化非常方便。4.3 编写sumocfg配置文件配置文件就是把路网、车辆路由串起来的主控文件。新建一个文本文件demo.sumocfg内容如下configuration input net-file valuemyNet.net.xml/ route-files valueroutes.rou.xml/ /input time begin value0/ end value100/ step-length value0.1/ /time /configurationstep-length是时间步长单位是秒默认是0.01秒也就是仿真引擎每0.01秒迭代一次。对于大多数宏观实验0.1秒甚至0.2秒就足够调大能加快仿真速度。但如果你在做车联网通信或超车细节研究可能需要更小的步长来捕捉瞬时变化。4.4 运行仿真并查看结果在命令行里执行sumo-gui demo.sumocfg如果一切正常你会看到一个窗口弹出地图上会出现路网车辆沿着路段行驶。如果点击“开始”按钮没有车辆出现多半是路网文件或者路由文件里的edge id对不上。仿真运行中你可以做什么第一用鼠标滚轮缩放地图按住鼠标中键拖动视角。第二点击一辆车右侧信息栏会显示它的速度、加速度、所在车道、目标路线等。第三通过左侧的“车辆选择”面板查看当前路上的每辆车。第四设置断点让仿真在某一时刻暂停方便观察。一个非常实用的调试技巧在sumo-gui里开启“车辆路线显示”模式在右侧图层选项里找到“车辆路线”这样每辆车会沿道路画出一条色带你可以直观看到车辆的完整路径规划。4.5 Netconvert从OpenStreetMap导入真实地图有人会问我想仿真一个真实的城区难道要自己一笔一笔画路网完全不用。SUMO支持从OpenStreetMap直接下载地图数据并转换。步骤很简单在OpenStreetMap网站上框选目标区域导出得到.osm文件。执行转换命令netconvert --osm-files map.osm -o map.net.xml如果原文件里有一些复杂的交叉口和转向限制转换后的路网可能连接不完整需要加参数netconvert --osm-files map.osm -o map.net.xml --osm.skip-turnabout我实测下来OpenStreetMap转换对普通城市道路效果不错但高速公路匝道有时会有连接混乱的问题。建议先用小范围区域试一次确认没问题再扩大到整个城市。还需要提醒一点OpenStreetMap转换得到的地图可能规模巨大直接跑仿真会非常卡。我通常会用netedit打开后手动删除一些不重要的支路或者用netconvert的裁剪参数按边界框切割地图。5. 跑通之后必踩的坑和排查技巧5.1 报错信息怎么看SUMO的报错一般比较直白但也容易吓到新人。最常见的报错有Error: The geometry of edge ... is not fully contained in its start/end junction这是路网几何问题通常出现在手写或转换后的路网里。解决办法是用netedit重新保存一下网络让SUMO自动修正几何大多数情况下能解决。Error: Vehicle ... has no route表示某辆车没有成功计算出路径。原因可能是路网不连通或者出发地和目的地之间没有可用路径。在netedit里开启连通性检查Check for disconnected edges能看到哪些路段是孤岛。Error: Cannot allocate vehicle ...车辆出发时间重叠或车辆数量过多导致同一时间大量车辆被生成。解决办法是增大车辆生成间隔或减少车辆数量。TraCI connection closedTraCI端口连接被意外断开多半是仿真已经结束或者被强制关闭。排查思路很重要——先看错误行号再打开对应的XML文件定位如果是路网问题优先使用netedit检查如果是需求问题把routes.rou.xml里出错的那条vehicle删掉再重新运行看是否还有问题。5.2 仿真性能很卡怎么办做了大范围路网仿真的同学都会遇到卡顿。这时候不要急着换电脑先从这几方面优化。第一调大时间步长。把step-length从0.1调到0.2甚至0.5会影响仿真精度但很多实验对精度要求没那么苛刻图像画面会流畅很多。注意如果你用TraCI实时读取每辆车的精确位置大步长会让数据变得粗糙需要平衡。第二减少仿真时间范围。如果你只是验证晚高峰1小时不要设置end为24小时控制仿真时长能明显减少计算量。第三关闭不必要的输出和可视化。在sumo-gui里关掉车辆路线显示、关闭背景多边形甚至可以在运行仿真时切换到“快速模式”让界面不实时渲染性能提升非常显著。第四采用sumo命令行模式而不是图形界面。如果只是做数据实验sumo -c demo.sumocfg没有图形渲染速度能快好几倍。5.3 为什么车总是在某个路口绕圈或堵住不动很多新手第一次跑复杂路网时会发现车在一个路口绕圈或者明明前方没车却不动了。这种现象通常有三个原因。第一个原因是路径规划不合理。duarouter默认是根据最短路径或用户设定的权值计算路径如果你的路网里某些边是单向的车可能绕远路。这时用netedit检查路段方向确认单向箭头是否设置正确。第二个原因是优先规则。SUMO默认是“右侧优先”如果两条路交叉且都没有信号灯车辆会按交通规则让行。如果你的路网不符合这个规则就会自然出现拥堵。解决办法是给关键节点配置信号灯或取消优先规则。第三个原因是路网连接错误。比如两条车道虽然看着相连但实际连接关系是断的。这种情况在OpenStreetMap转换后经常出现排查方法是让某辆车在可疑路线上走一遍观察它是否能顺利通过。5.4 Python环境与TraCI连接的坑我最后说一下TraCI这是SUMO里最值的深入的功能但也是坑最多的地方。一个常见的错误是顺序搞不对。标准流程是先启动SUMO的TraCI服务再让Python脚本连接。比如import traci traci.start([sumo-gui, -c, demo.sumocfg]) step 0 while step 100: traci.simulationStep() step 1 traci.close()如果你的Python报错ModuleNotFoundError: No module named traci先确认SUMO_HOME是否设置正确然后可以用import os import sys sys.path.append(os.path.join(os.environ[SUMO_HOME], tools)) import traci还有一个坑是端口占用。TraCI默认使用端口8813如果有其他程序占用启动时会报错。可以在traci.start里指定其他端口traci.start([sumo-gui, -c, demo.sumocfg], port8815)5.5 把自己的实验固化下来项目目录的组织习惯最后分享一个我从多次教训里总结出来的习惯一个仿真实验尽量固定在一个目录里目录下分net、route、config、output四个子目录命名规则统一。demo_project/ ├── net/ │ └── myNet.net.xml ├── route/ │ └── routes.rou.xml ├── config/ │ └── demo.sumocfg └── output/ └── results.xml这样做的好处非常直接——当你跑了几十组仿真之后不会找不到哪个文件对应哪次实验也不会因为文件全是final_final_2.xml这种命名而崩溃。配置文件里所有路径都建议写相对路径避免换机器或迁移项目时路径失效。还有一个小技巧对每轮实验把用的sumocfg复制一份到output目录里作为实验记录的一部分。这样即使过了一个月你翻到一组results.xml时依然能知道当时用的是哪组路网、哪份需求文件、什么参数跑的。写在最后的一点个人建议我从第一次装好SUMO到真正跑通一个带信号灯的路口仿真中间大概折腾了两天大部分时间都花在理解文件关系上。回头看不难难的是跨过“文件之间怎么联系”这道坎。所以你如果卡在某个环节别怀疑自己多半只是某个小细节没对上。建议先严格按这篇教程把“一个十字路口”的仿真跑通再去折腾真实地图和复杂路网。下一篇我准备写TraCI的在线控制实战包括如何用Python实时修改信号灯、如何采集车辆轨迹数据如果到时候你发现这篇基础篇打牢了后面会很顺畅。