开源路径规划引擎

OSRM (开源路径规划引擎) 是一款适用于开放街道地图(OSM)道路网络的超快路径规划引擎。在之前的教程中,我们讲解了如何搭建自托管的开放街道地图 瓦片服务器。本教程将向您展示如何使用OSRM为开放街道地图添加导航功能。

1. 从源代码构建OSRM

安装依赖包。

sudo apt update
sudo apt install build-essential git cmake pkg-config doxygen libboost-all-dev libtbb-dev lua5.2 liblua5.2-dev libluabind-dev libstxxl-dev libstxxl1v5 libxml2 libxml2-dev libosmpbf-dev libbz2-dev libzip-dev libprotobuf-dev

创建osrm 用户。(该用户无需设置密码。)

sudo useradd -d /srv/osrm -s /bin/bash -m osrm

授予您自己的用户账户权限。请将此处的username替换为您的实际Linux用户名。

sudo apt install acl
sudo setfacl -R -m u:username:rwx /srv/osrm/

切换到/srv/osrm/目录。

cd /srv/osrm/

从Github仓库下载OSRM源代码。

git clone --branch v5.27.1 https://github.com/Project-OSRM/osrm-backend.git

您也可以先将代码克隆到本地机器,然后将其压缩,再上传到服务器并解压缩:

scp -i osrmOpen osrm-backend.zip yourusername@[2a01:4ff:f0:7b77::1]:/srv/osrm/
sudo apt install unzip
unzip osrm-backend.zip

创建build目录。

mkdir build

在 Debian 12 上,编译时可能会出现以下错误:

cc1plus: 所有警告均被视为错误 make[2]: *** [CMakeFiles/EXTRACTOR.dir/build.make:328: CMakeFiles/EXTRACTOR.dir/src/extractor/scripting_environment_lua.cpp.o] 错误 1

为了避免该错误,您需要修改/srv/osrm/osrm-backend文件夹中的CMakeLists.txt文件。 注释掉这一行(第 339 行)

# include(cmake/warnings.cmake)

除此之外,我还必须对第 442 行和第 443 行进行注释:

# target_no_warning(MICROTAR unused-variable)
# target_no_warning(MICROTAR format)

在 Ubuntu 20.04 和 22.04 上,您可以跳过注释这些行。切换到build目录并配置编译环境。

cd build
cmake /srv/osrm/osrm-backend/ -Wno-dev

编译源代码。(如果看到TBB警告:已弃用信息,可以忽略。)

编译过程需要很长时间,因此您可以使用 screen 命令来保持进程持续运行。

make

[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/assert.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/conditional_restrictions.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/coordinate.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/coordinate_calculation.cpp.o
[  0%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/exception.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/fingerprint.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/geojson_debug_policies.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/guidance/bearing_class.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/guidance/entry_class.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/guidance/turn_lanes.cpp.o
[  4%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/log.cpp.o
[  8%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/opening_hours.cpp.o
[  8%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/timed_historgram.cpp.o
[  8%] 正在构建 CXX 对象 CMakeFiles/UTIL.dir/src/util/timezones.cpp.o
从 /usr/include/boost/math/tools/cxx03_warn.hpp:9 包含的文件,
                 来自 /usr/include/boost/math/constants/constants.hpp:11,
                 来自 /usr/include/boost/geometry/util/math.hpp:29,
                 来自 /usr/include/boost/geometry/core/radian_access.hpp:33,
                 来自 /usr/include/boost/geometry/geometry.hpp:51,
                 来自 /usr/include/boost/geometry.hpp:17,
                 来自 /srv/osrm/osrm-backend/include/util/timezones.hpp:7,
                 来自 /srv/osrm/osrm-backend/src/util/timezones.cpp:1:
/usr/include/boost/function_output_iterator.hpp:14:1: 注意:‘#pragma message: 此头文件已弃用。 
请改用 <boost/iterator/function_output_iterator.hpp>。’
   14 | BOOST_HEADER_DEPRECATED(“<boost/iterator/function_output_iterator.hpp>”
      | ^~~~~~~~~~~~~~~~~~~~~~~
13% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/extractor.cpp.o
在包含自 /usr/include/boost/smart_ptr/detail/sp_thread_sleep.hpp:22 的文件中,
                                                          yield_k.hpp:23,
                                                          spinlock_gcc_atomic.hpp:14,
                                                          spinlock.hpp:42
……

21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/raster_source.cpp.o
21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/restriction_graph.cpp.o
21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/restriction_parser.cpp.o
21% 正在构建 CXX 对象 CMakeFiles/EXTRACTOR.dir/src/extractor/scripting_environment_lua.cpp.o
在包含自 /usr/include/boost/smart_ptr/detail/sp_thread_sleep.hpp:22 的文件中,
                 来自 /usr/include/boost/smart_ptr/detail/yield_k.hpp:23,
                 来自 /usr/include/boost/smart_ptr/detail/spinlock_gcc_atomic.hpp:14,
                 来自 /usr/include/boost/smart_ptr/detail/spinlock.hpp:42,
                 来自 /usr/include/boost/smart_ptr/detail/spinlock_pool.hpp:25,
                 来自 /usr/include/boost/smart_ptr/shared_ptr.hpp:29,
                 来自 /usr/include/boost/shared_ptr.hpp:17,
                 来自 /usr/include/boost/format/alt_sstream.hpp:22,
                 来自 /usr/include/boost/format/internals.hpp:24,
                 来自 /usr/include/boost/format.hpp:38,
                 来自 /srv/osrm/osrm-backend/include/util/exception.hpp:38,
                 来自 /srv/osrm/osrm-backend/include/extractor/extraction_relation.hpp:4,
                来自 /srv/osrm/osrm-backend/include/extractor/scripting_environment_lua.hpp:4,
                来自 /srv/osrm/osrm-backend/src/extractor/scripting_environment_lua.cpp:1:
/usr/include/boost/detail/no_exceptions_support.hpp:17:1: 注意: ‘#pragma message: 此头文件已弃用。
请改用 <boost/core/no_exceptions_support.hpp>。’
   17 | BOOST_HEADER_DEPRECATED(“<boost/core/no_exceptions_support.hpp>”)
      | ^~~~~~~~~~~~~~~~~~~~~~~
……  
        

安装二进制文件。

sudo make install

将安装以下二进制文件:

2. 生成OSRM路径数据

现在我们需要下载开放街道地图数据并使其可用于路径规划。运行以下命令以PBF (ProtoBufBinary)格式下载马里兰数据(195MB)。

wget -c https://download.geofabrik.de/north-america/us/maryland-latest.osm.pbf -P /srv/osrm/osrm-backend

如果您想要某个国家/州/省/市,请访问 http://download.geofabrik.de

请确保您位于 /srv/osrm/osrm-backend/ 目录中。

cd /srv/osrm/osrm-backend/

从开放街道地图中提取图表。

osrm-extract maryland-latest.osm.pbf --threads=2

默认情况下,它将使用 car.lua 配置文件。
        [2025-11-12T22:53:01.882265254] [信息] 已解析 0 个位置相关要素,包含 0 个 GeoJSON 多边形
        [2025-11-12T22:53:01.882323182] [信息] 使用脚本 profiles/car.lua
        [2025-11-12T22:53:01.882464286] [信息] 输入文件:maryland-latest.osm.pbf
        [2025-11-12T22:53:01.882479645] [信息] 配置文件:car.lua
        [2025-11-12T22:53:01.882483904] [信息] 线程数:2
        [2025-11-12T22:53:01.882600652] [信息] 解析进行中..
        [2025-11-12T22:53:01.882825334] [信息] 输入文件由 osmium/1.14.0 生成
        [2025-11-12T22:53:01.882957983] [信息] 时间戳:2025-11-11T21:21:30Z
        [2025-11-12T22:53:01.887276358] [信息] 使用 profile api 版本 4
        [2025-11-12T22:53:01.887601177] [信息] 发现 3 个转弯限制标签:
        [2025-11-12T22:53:01.887618260] [信息]   机动车
        [2025-11-12T22:53:01.887625644] [信息]   汽车
        [2025-11-12T22:53:01.887630432] [信息]   车辆
        [2025-11-12T22:53:01.887681568] [信息] 解析关系...
        [2025-11-12T22:53:02.982318280] [信息] 解析路径和节点...
        [2025-11-12T22:53:02.986341461] [信息] 使用 profile api 版本 4

这个过程非常消耗资源。在我的服务器上,它占用了1.6GB 内存,CPU 负载高达2。我用的是马里兰地图。

完成后,会生成文件名相同但是扩展名不同的文件,包括一个 .osrm 扩展名的文件。运行以下命令,将此图递归分割成单元格。

osrm-partition maryland-latest.osrm

[2025-11-12T22:58:39.621128018] [信息] 计算递归二分
[2025-11-12T22:58:39.717910677] [信息] 已加载压缩的基于节点的图:2702344 条边,4742031 个节点
[2025-11-12T22:58:39.777106776] [信息]  运行分区: 128 1.2 0.25 10 1000 # 最大单元格尺寸 平衡 边界 切割 小组件尺寸
[2025-11-12T22:58:40.046057205] [信息] 发现 3629476 个 SCC(1 个大型,3629475 个小型)
[2025-11-12T22:58:40.046097070] [信息] SCC 运行耗时:0.264543 秒
[2025-11-12T22:59:04.718396464] [信息] 完全二分法完成,耗时 24.2568 秒
[2025-11-12T22:59:04.743987817] [信息] 已加载基于节点的图到基于边的图的映射
[2025-11-12T22:59:05.759426757] [信息] 已加载基于边的图,用于映射分区 ID:9654934 条边,2582414 个节点
[2025-11-12T22:59:06.138803527] [信息] 修复了 324 个未连接的节点
[2025-11-12T22:59:06.138843462] [信息] 基于边的图注释:
[2025-11-12T22:59:06.138847310] [信息]   级别 1 单元格数 13114 位大小 14
[2025-11-12T22:59:06.139257279] [信息]   级别 2 单元格数 952 位大小 10
[2025-11-12T22:59:06.139263691] [信息]   级别 3 单元格数 62 位大小 6
[2025-11-12T22:59:06.139267058] [信息]   级别 4 单元格 3 位大小 2
[2025-11-12T22:59:08.820778825] [信息] 数据重新编号耗时 2.6815 秒
[2025-11-12T22:59:08.982056204] [信息] 多级分区构建完成,耗时 0.161123 秒
[2025-11-12T22:59:09.153941236] [信息] CellStorage 构建完成,耗时 0.171819 秒
[2025-11-12T22:59:09.354557698] [信息] MLD 数据写入耗时 0.20055 秒
[2025-11-12T22:59:09.354605156] [信息] 每级单元格统计信息
[2025-11-12T22:59:09.364573010] [信息] 1 级 #单元格 13114 #边界节点 172268,源:平均 8,目标:平均 12,
条目数:1930000(15440000 字节)
[2025-11-12T22:59:09.365717067] [信息] 2 级 #单元格 952 #边界节点 27201,源:平均 19,目标:平均 26,
条目数:610424(4883392 字节)
[2025-11-12T22:59:09.365904549] [信息] 3 级 #单元格 62 #边界节点 4170,源:平均 45,目标:平均 59,
条目数:210994(1687952 字节)
[2025-11-12T22:59:09.365918586] [信息] 4 级 #单元格 3 #边界节点 137,源:平均 30,目标:平均 35,
条目数:4949(39592 字节)
[2025-11-12T22:59:09.368547702] [信息] 二分法耗时 29.7473 秒。
[2025-11-12T22:59:09.368564684] [信息] RAM:峰值使用字节数:702300160
        

通过计算所有单元格的路径规划权重来自定义单元格。

osrm-customize maryland-latest.osrm

[2025-11-12T23:04:58.781401701] [信息] 已加载基于边的图:9654934 条边,2582414 个节点
[2025-11-12T23:04:58.791836400] [信息] 加载分区数据耗时 1.30856 秒
[2025-11-12T23:05:05.533197032] [信息] 单元格自定义耗时 6.7413 秒
[2025-11-12T23:05:05.533251512] [信息] 各级别单元格统计
[2025-11-12T23:05:05.540293802] [信息] 1级 #单元格 13114 #边界节点 172268,源:平均 8,目标:平均 12,
条目数:1930000(15440000 字节)
[2025-11-12T23:05:05.541446640] [信息] 2级 #单元格 952 #边界节点 27201,源:平均 19,目标:平均 26,
条目数:610424(4883392 字节)
[2025-11-12T23:05:05.541637581] [信息] 3级 #单元格 62 #边界节点 4170,源:平均 45,目标:平均 59,
条目数:210994(1687952 字节)
[2025-11-12T23:05:05.541657729] [信息] 4级 #单元格 3 #边界节点 137,源:平均 30,目标:平均 35,
条目数:4949(39592 字节)
[2025-11-12T23:05:05.541665612] [信息] 各级别不可达节点统计信息
[2025-11-12T23:05:05.543776411] [警告] 每个小区1级不可达边界节点数:0.000915053 个源节点,0.000991307 个目标节点
[2025-11-12T23:05:05.544257676] [警告] 每个小区内2级不可达边界节点数:0.00735294 个源节点,0 个目标节点
[2025-11-12T23:05:05.544410427] [警告] 每个小区内3级不可达边界节点数:0.016129个源节点,0个目标节点
[2025-11-12T23:05:05.544431485] [警告] 每个小区内4级不可达边界节点数:0.333333 个源节点,0 个目标节点
[2025-11-12T23:05:05.544443177] [信息] 各级别不可达节点统计信息
[2025-11-12T23:05:05.546622921] [警告] 每个小区1级不可达边界节点数:0.00831173 个源节点,0.00541406 个目标节点
[2025-11-12T23:05:05.547096652] [警告] 每个小区内2级不可达边界节点数:0.0682773 个源节点,0.0336134 个目标节点
[2025-11-12T23:05:05.547244193] [警告] 每个小区内3级不可达边界节点数:0.516129 个源节点,0.258065 个目标节点
[2025-11-12T23:05:05.547264450] [警告] 每个小区内4级不可达边界节点数:0.666667 个源节点,0.333333 个目标节点
[2025-11-12T23:05:05.547276041] [信息] 各级别不可达节点统计信息
[2025-11-12T23:05:05.549399302] [警告] 每个小区1级不可达边界节点数:0.122693 个源节点,0.0758731 个目标节点
[2025-11-12T23:05:05.549933655] [警告] 每个小区内2级不可达边界节点数:0.951681 个源节点,0.536765 个目标节点
[2025-11-12T23:05:05.550101904] [警告] 每个小区内3级不可达边界节点:4.5 个源节点,2.67742 个目标节点
[2025-11-12T23:05:05.550122572] [警告] 每个小区内4级不可达边界节点数:5.66667 个源节点,3.33333 个目标节点
[2025-11-12T23:05:05.550133623] [信息] 各级别不可达节点统计信息
[2025-11-12T23:05:05.552152973] [警告] 每个小区1级不可达边界节点数:0.00106756 个源节点,0.00114382 个目标节点
[2025-11-12T23:05:05.552614811] [警告] 每个小区内2级不可达边界节点数:0.00840336 个源节点,0.00105042 个目标节点
[2025-11-12T23:05:05.552736184] [警告] 每个小区内3级不可达边界节点数:0.016129 个源节点,0 个目标节点
[2025-11-12T23:05:05.552755129] [警告] 每个小区内 4 级不可达边界节点数:0.333333 个源节点,0 个目标节点
[2025-11-12T23:05:05.637747306] [信息] MLD 自定义写入耗时 0.084966 秒
[2025-11-12T23:05:05.781055707] [信息] 图写入耗时 0.14326 秒
[2025-11-12T23:05:05.783944224] [信息] RAM:峰值使用字节数:658309120
        

现在可以启动路径引擎了。

osrm-routed --algorithm=MLD maryland-latest.osrm

xtao@tile:/srv/osrm/osrm-backend$ osrm-routed --algorithm=MLD maryland-latest.osrm
[2025-11-12T23:09:46.324878731] [信息] 正在启动引擎,版本 5.27.1
[2025-11-12T23:09:46.325791452] [信息] 线程数:2
[2025-11-12T23:09:46.325800418] [信息] IP 地址:0.0.0.0
[2025-11-12T23:09:46.325803835] [信息] IP 端口:5000
[2025-11-12T23:09:46.614771989] [信息] http 1.1 压缩由 zlib 版本 1.2.13 处理
[2025-11-12T23:09:46.614973181] [信息] 正在监听:0.0.0.0:5000
[2025-11-12T23:09:46.615263620] [信息] 正在运行并等待请求
        

如您所见,它监听的是TCP端口 5000。

3. 创建 systemd 服务

我们可以使用手动方式运行OSRM 路径规划引擎: osrm-routed --algorithm=MLD maryland-latest.osrm,但更方便的做法是在后台以系统守护进程运行 osrm-routed。

按下 Ctrl+C 停止当前进程,并使用以下命令为 osrm-routed 创建一个系统守护进程。

sudo vi /etc/systemd/system/osrm-routed.service

将以下几行内容添加到文件中。

[Unit]
Description=Open Source Routing Machine
Wants=network-online.target
After=network.target network-online.target

[Service]
ExecStart=/usr/local/bin/osrm-routed --algorithm=MLD /srv/osrm/osrm-backend/maryland-latest.osrm
User=osrm
Group=osrm
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

保存并关闭文件。更改 /srv/osrm/osrm-backend/ 目录的所有权。

sudo chown osrm:osrm /srv/osrm/osrm-backend/ -R

现在我们可以启动并启用 osrm-routed 系统守护进程了。

sudo systemctl start osrm-routed
sudo systemctl enable osrm-routed

查看状态。

systemctl status osrm-routed

xtao@tile:/srv/osrm/osrm-backend$ systemctl status osrm-routed
● osrm-routed.service - 开源路径规划
      已加载:已加载(/etc/systemd/system/osrm-routed.service; 已启用; 预设: 已启用)
    活动状态:自2025年11月12日星期三 23:20:15 UTC 起处于活动(运行中); 24s ago
   主进程 ID:6489 (osrm-routed)
      任务数: 4 (上限:2250)
        内存:529.5M
        CPU: 184毫秒
     CGroup: /system.slice/osrm-routed.service
             └─6489 /usr/local/bin/osrm-routed --algorithm=MLD /srv/osrm/osrm-backend/maryland-latest.osrm
        

4. 设置反向代理

我们可以将Apache 网络服务器配置为 osrm-routed 服务的反向代理,这样我们就可以使用域名来访问路径规划服务,并启用 HTTPS 加密。 安装Apache网络服务器。

sudo apt install apache2

要使用 Apache 作为反向代理,我们需要启用proxy、proxy_http 和 rewrite 模块。

sudo a2enmod proxy proxy_http rewrite

然后为 OSRM 创建虚拟主机文件。

sudo vi /etc/apache2/sites-available/osrm.conf

将以下文本添加到文件中。将 osrm.your-domain.com 替换为您的实际域名,并且不要忘记为其创建 DNS A 记录。

<VirtualHost *:80>
ServerName osrm.your-domain.com
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
</VirtualHost>

保存并关闭文件。然后启用此虚拟主机。

sudo a2ensite osrm.conf

请重新加载 Apache 以使更改生效。

sudo systemctl reload apache2

现在您可以通过在浏览器地址栏中输入域名 (osrm.your-domain.com) 来访问 OSRM。

5. 启用 HTTPS

我们可以通过安装 Let’s Encrypt 颁发的免费TLS证书来启用 HTTPS。在 瓦片服务器搭建 中,我们已经安装了 Let’s Encrypt 客户端 (certbot)。因此,我们只需要运行以下命令来获取并安装 TLS 证书。

sudo certbot --apache --agree-tos --email your-account@example.com -d osrm.your-domain.com

调试日志已保存至 /var/log/letsencrypt/letsencrypt.log
正在为 osrm.umd.me.uk 申请证书

已成功收到证书。
证书保存在: /etc/letsencrypt/live/osrm.umd.me.uk/fullchain.pem
密钥保存在:         /etc/letsencrypt/live/osrm.umd.me.uk/privkey.pem
此证书将于 2026 年 2 月 10 日到期。
证书续期时,这些文件将会更新。
Certbot 已设置定时任务,在后台自动续订此证书。

部署证书
已成功将 osrm.umd.me.uk 的证书部署到 /etc/apache2/sites-available/osrm-le-ssl.conf
恭喜!您已成功在 https://osrm.umd.me.uk 上启用 HTTPS。
        

默认情况下,Let's Encrypt 会将 HTTP 请求重定向到 HTTPS。如果您想保留 HTTP,可以删除 osrm.conf 文件中自动生成的重写规则,然后重新加载系统中的 apache2 服务。

6. 将 OSRM 与滑动地图集成

我假设您的滑动地图是用 Leaflet JavaScript 库显示的。

要将OSRM与滑动地图集成,我们可以使用名为 Leaflet Routing Machine 的插件。首先,将 Leaflet routing machine 的 JavaScript 和 CSS 文件添加到您的滑动地图中。请注意,它们应该放在 Leaflet 主 JavaScript 文件之后。

下载 leaflet-routing-machine.css、 leaflet-routing-machine.min.js、 leaflet.routing.icons.png 和 routing-icon.png 到 dist 文件夹。

sudo mkdir /var/www/html/dist
cd /var/www/html/dist
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.css
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.js
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet.routing.icons.png
sudo wget https://unpkg.com/leaflet-routing-machine@latest/dist/routing-icon.png

        <html>
          <head>
             ....
             ....
             <link rel="stylesheet" href="dist/leaflet-routing-machine.css" />
             <script src="dist/leaflet-routing-machine.js"></script>
         </head>
         <body>
         ....
         ....
         </body>
        </html>
        
        

接下来,将以下几行代码添加到 <script>...</script> HTML 正文中的代码片段中。

    end = [38.985978, -76.942564]; // 马里兰大学
    start = [38.99883, -76.90663]; // 目标超市
    L.Routing.control({
        serviceUrl: 'https://osrm.your-domain.com/route/v1',
        waypoints: [
            L.latLng(start[0], start[1]),
            L.latLng(end[0], end[1])
        ],
        routeWhileDragging: true
    }).addTo(map);

        
像这样:
        <html>
          <head>
             ....
             ....
             <link rel="stylesheet" href="dist/leaflet-routing-machine.css" />
             <script src="dist/leaflet-routing-machine.js"></script>
         </head>
         <body>
           <div id="map"></div>
             <script>
             ....
             ....
             end = [38.985978, -76.942564]; // 马里兰大学
             start = [38.99883, -76.90663]; // 目标超市
             L.Routing.control({
                serviceUrl: https://'osrm.your-domain.com/route/v1',
                waypoints: [
                    L.latLng(start[0], start[1]),
                    L.latLng(end[0], end[1])
                ],
                routeWhileDragging: true
             }).addTo(map);
             </script>

         </body>
        </html>
        

保存并关闭文件。 然后在浏览器中重新加载地图,你应该会在右上角看到一个控制面板,您可以与路径交互。

您可以拖动地图上的航点, OSRM 将自动重新计算路线。

导航语言默认是英语,如果您想转换为中文,可以把leaflet-routing-machine.js另存为leaflet-routing-machines.js。中文导航已经在15137到15629行之间定义。我删除了冗余的“个”字。

        "arrive": {
            "default": {
                "default": "您已经到达您的{nth}目的地",
                "upcoming": "您即将到达您的{nth}目的地",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name}"
            },
            "left": {
                "default": "您已经到达您的{nth}目的地,目的地在道路左侧",
                "upcoming": "您即将到达您的{nth}目的地,目的地在道路左侧",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name},目的地在您左边。"
            },
            "right": {
                "default": "您已经到达您的{nth}目的地,目的地在道路右侧",
                "upcoming": "您即将到达您的{nth}目的地,目的地在道路右侧",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name},目的地在您右边。"
            },
            "sharp left": {
                "default": "您已经到达您的{nth}目的地,目的地在道路左侧",
                "upcoming": "您即将到达您的{nth}目的地,目的地在道路左侧",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name},目的地在您左边。"
            },
            "sharp right": {
                "default": "您已经到达您的{nth}目的地,目的地在道路右侧",
                "upcoming": "您即将到达您的{nth}目的地,目的地在道路右侧",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name},目的地在您右边。"
            },
            "slight right": {
                "default": "您已经到达您的{nth}目的地,目的地在道路左侧",
                "upcoming": "您即将到达您的{nth}目的地,目的地在道路左侧",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name},目的地在您右边。"
            },
            "slight left": {
                "default": "您已经到达您的{nth}目的地,目的地在道路右侧",
                "upcoming": "您即将到达您的{nth}目的地,目的地在道路右侧",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name},目的地在您左边。"
            },
            "straight": {
                "default": "您已经到达您的{nth}目的地,目的地在您正前方",
                "upcoming": "您即将到达您的{nth}目的地,目的地在您正前方",
                "short": "已到达目的地",
                "short-upcoming": "即将到达目的地",
                "named": "您已到达{waypoint_name},目的地在您前方。"
            }
        },
        ......
        

默认情况下,中文不受支持,您可以写一份类似英文导航(在17183和17242之间定义)的中文导航。我在17855和17914行之间添加如下行:

        'zh-Hans': {
            directions: {
                N: '北',
                NE: '东北',
                E: '东',
                SE: '东南',
                S: '南',
                SW: '西南',
                W: '西',
                NW: '西北',
                SlightRight: '稍向右',
                Right: '向右',
                SharpRight: '急向右',
                SlightLeft: '稍向左',
                Left: '向左',
                SharpLeft: '急向左',
                Uturn: '调头'
            },
            instructions: {
                // 指示,如果道路有名称,则添加后缀
                'Head':
                    [' 在 {road}', '向 {dir}'],
                'Continue':
                    ['继续 {dir}'],
                'TurnAround':
                    ['调头'],
                'WaypointReached':
                    ['到达目的地'],
                'Roundabout':
                    ['从环岛 {exitStr} 出口驶出', ',进入 {road}'],
                'DestinationReached':
                    ['您已到达目的地'],
                'Fork': ['在岔路口, 转 {modifier}', ' 进入 {road}'],
                'Merge': ['并入 {modifier}', ' 进入 {road}'],
                'OnRamp': ['在匝道上 {modifier} 转', ' 进入 {road}'],
                'OffRamp': ['在匝道上转 {modifier}', ' 进入 {road}'],
                'EndOfRoad': ['在路尽头转 {modifier}', ' 进入 {road}'],
                'Onto': '到达 {road}'
            },
            formatOrder: function(n) {
                var i = n % 10 - 1,
                suffix = ['st', 'nd', 'rd'];

                return suffix[i] ? n + suffix[i] : n + 'th';
            },
            ui: {
                startPlaceholder: '起点',
                viaPlaceholder: '途经 {viaNumber}',
                endPlaceholder: '终点'
            },
            units: {
                meters: '米',
                kilometers: '公里',
                yards: '码',
                miles: '迈',
                hours: '小时',
                minutes: '分钟',
                seconds: '秒'
            }
        }
        

最后在您的网页文件中serviceUrl之后添加如下行,以及把外部JavaScript文件改为leaflet-routing-machines.js:

language: 'zh-Hans',

下一步

希望这篇教程能帮助您在 Debian 12 上搭建开源路径规划引擎。如果您使用的是 Debian 11 服务器,或者您更喜欢使用 nginx,请参考在 Debian 11 上设置开源路径规划引擎。您也可以考虑设置带有网页界面的地理编码服务器来提供搜索功能。