
1. 为什么我要折腾RTK数据转发这件事搞高精度定位的朋友对RTKLIB这个开源库肯定不陌生。它是一套完整的GNSS数据处理工具集从单点定位到载波相位差分从静态后处理到实时动态解算几乎覆盖了厘米级定位的所有环节。但很多人卡在第一步数据怎么从基准站流到流动站尤其是当你手头只有一台普通电脑、一个GNSS模块、一张4G上网卡的时候怎么把基准站的观测数据实时推给几公里外的流动站这就是str2str工具要解决的问题。它是RTKLIB自带的一个命令行程序专门负责数据流的转换和转发。你可以把它理解成一个“数据搬运工”——从串口读、往TCP写从NTRIP客户端拉、往本地文件存各种协议之间的桥接它都能干。我最初接触str2str是因为一个无人机测绘项目基准站架在已知点上流动站装在无人机上两者之间隔着几百米到几公里的距离必须通过无线链路把差分数据传过去。商用RTK电台一套下来大几千块而用str2str配合4G网络成本可以压到几百块。这篇文章适合谁看如果你正在搭建自己的RTK系统手头有GNSS板卡或模块需要把基准站数据转发给流动站又不想花大价钱买成品数传电台那str2str就是你的菜。我会从整体设计思路讲起然后拆解str2str的核心参数接着给出完整的实操配置最后分享我在实际项目中踩过的坑和排查技巧。整个过程不需要你精通C语言或者GNSS底层协议只要能看懂命令行参数、会改配置文件就行。2. 整体设计思路与方案选型2.1 为什么选str2str而不是其他方案搭建RTK数据转发服务器市面上常见的方案有这么几种商用数传电台、NTRIP Caster自建、MQTT转发、以及str2str直接转发。我逐一分析一下各自的适用场景。商用数传电台的优势是稳定、延迟低、不依赖公网但缺点也很明显一对电台动辄三四千传输距离受功率和天线限制而且只能点对点。NTRIP Caster方案适合多用户场景一个基准站可以同时服务多个流动站但需要公网服务器和固定IP维护成本高。MQTT转发灵活性强但需要自己写中间件对不熟悉编程的用户不友好。str2str的方案介于两者之间它可以直接把串口数据转成TCP流也可以作为NTRIP客户端从Caster拉数据再转发还可以把数据同时写到多个目标。最关键的是它不需要额外的服务器软件一台能上网的电脑或者树莓派就能跑起来。对于个人用户和小型项目来说这是性价比最高的选择。我实测下来用str2str配合4G路由器基准站到流动站的端到端延迟可以控制在200毫秒以内对于无人机航测、农机自动驾驶这类应用完全够用。而且str2str支持多路输出你可以同时把数据推给流动站、存到本地文件、再转发给另一个NTRIP Caster一份数据多处使用。2.2 数据流转的核心逻辑在动手配置之前先把数据流转的路径理清楚。一个典型的RTK数据转发链路是这样的基准站GNSS模块通过串口输出RTCM差分数据格式通常是RTCM 3.x。str2str从串口读取这些数据然后通过TCP协议发送到流动站所在的网络地址。流动站端的str2str或者RTKNAVI从TCP端口接收数据再通过串口送给流动站的GNSS模块。流动站模块结合自身的观测数据和基准站的差分数据解算出厘米级的位置。这里有几个关键点需要注意。第一基准站输出的必须是RTCM格式不能是NMEA或者原始观测数据因为流动站需要的是差分改正数。第二串口参数必须匹配波特率、数据位、停止位、校验位一个都不能错。第三TCP连接需要保证双方网络可达如果是公网转发基准站端需要有公网IP或者做端口映射。str2str在这个链路中扮演的是“协议转换数据分发”的角色。它不关心数据内容是什么只负责把字节流从A搬到B。这种设计的好处是通用性强任何符合串口或网络协议的数据都能转发坏处是它不做数据校验和纠错如果网络不稳定丢包会直接影响RTK固定率。2.3 硬件选型的几个考量虽然标题说的是“低成本”但硬件选型还是有一些底线要守住。基准站端的GNSS模块建议选支持多系统多频点的板卡比如常见的F9P、UM980、或者Mosaic系列。单频模块虽然也能用但固定速度慢、抗干扰能力差实际体验会打折扣。主机方面树莓派Zero 2 W或者二手迷你PC都行关键是功耗要低、要能稳定运行。我用过树莓派4B和一台老旧的Atom工控机两者都能跑str2str但树莓派的功耗只有几瓦更适合野外太阳能供电的场景。网络部分4G路由器选工业级的别用那种几十块的随身WiFi夏天高温容易死机。天线要选带增益的放在高处确保信号稳定。如果基准站和流动站距离不远也可以用无线网桥替代4G延迟更低。流动站端的硬件取决于你的应用。无人机上一般用轻量化的GNSS模块加数传链路农机上可以用平板电脑加4G网卡。不管哪种流动站端也需要跑str2str或者兼容的NTRIP客户端来接收数据。3. str2str核心参数拆解与配置详解3.1 命令行参数的基本结构str2str的命令行格式遵循一个固定的模式str2str -in [输入源] -out [输出目标] [选项]。输入源和输出目标可以是串口、TCP客户端、TCP服务端、NTRIP客户端、文件等。选项用来控制超时、重连、数据格式转换等行为。先看一个最简单的例子str2str -in serial://ttyUSB0:115200:8:n:1 -out tcpcli://192.168.1.100:5000这条命令的意思是从/dev/ttyUSB0串口读取数据波特率1152008位数据位无校验1位停止位然后通过TCP客户端连接到192.168.1.100的5000端口把数据发过去。参数看起来简单但实际配置时有很多细节要注意。比如串口路径在Linux下是/dev/ttyUSB0或/dev/ttyACM0在Windows下是COM3这样的格式。TCP客户端模式下如果目标地址不可达str2str会一直重试但重试间隔和超时时间需要根据网络状况调整。3.2 输入源配置串口、TCP、NTRIP怎么选输入源的选择取决于你的基准站数据从哪里来。如果GNSS模块直接连在运行str2str的电脑上用串口输入最直接。串口配置的完整格式是serial://port:rate:data:parity:stop其中rate是波特率data是数据位通常7或8parity是校验位n表示无校验e表示偶校验o表示奇校验stop是停止位1或2。如果基准站数据已经在网络上比如你从另一个NTRIP Caster获取差分数据那就用NTRIP客户端模式str2str -in ntripcli://user:passcaster.example.com:2101/MOUNTPOINT这里的user和pass是NTRIP账号密码caster.example.com是Caster地址2101是端口MOUNTPOINT是挂载点名称。注意NTRIP的挂载点通常以大写字母开头具体名称要问服务提供方。还有一种情况是基准站端已经有一个TCP服务在输出数据str2str作为客户端去连接它str2str -in tcpcli://192.168.1.50:9000这三种输入模式我都在项目里用过。串口模式最稳定延迟最低但受线缆长度限制。NTRIP模式适合跨地域的场景但依赖Caster的稳定性。TCP客户端模式适合局域网内转发配置简单。3.3 输出目标配置一份数据多处分发str2str的输出配置比输入灵活得多因为它支持多路输出。你可以在一条命令里写多个-out参数每个输出目标独立配置。比如str2str -in serial://ttyUSB0:115200:8:n:1 \ -out tcpcli://192.168.1.100:5000 \ -out tcpcli://192.168.1.101:5000 \ -out file:///home/pi/rtcm_log.rtcm这条命令把串口数据同时发给两个TCP客户端并保存到本地文件。实际项目中我经常用这种方式做数据备份和远程监控。TCP服务端模式也很常用特别是在基准站有公网IP的情况下str2str -in serial://ttyUSB0:115200:8:n:1 -out tcpsvr://:5000注意tcpsvr://后面的冒号前面是空的表示监听所有网络接口的5000端口。如果有多个网卡可以指定IP地址比如tcpsvr://192.168.1.50:5000。NTRIP服务端模式适合把本地基准站数据推送到公共Casterstr2str -in serial://ttyUSB0:115200:8:n:1 \ -out ntripsvr://user:passcaster.example.com:2101/MOUNTPOINT这里str2str作为NTRIP Server主动把数据推给Caster。注意NTRIP Server模式需要Caster端配置好挂载点和账号权限。3.4 关键选项参数超时、重连、缓冲str2str的选项参数决定了它在异常情况下的行为。最常用的几个选项包括-t超时时间单位秒。如果输入源在指定时间内没有数据str2str会认为连接断开并尝试重连。默认值是0表示不超时。实际使用中建议设为5到10秒。-r重连间隔单位秒。连接断开后等待多久重新连接。默认是10秒网络不稳定的场景可以设短一点比如3秒。-b缓冲区大小单位字节。默认是32768。如果数据量大或者网络延迟高可以适当增大。-p延迟启动时间单位秒。str2str启动后等待指定时间再开始转发用于等待GNSS模块初始化完成。-msg指定要转发的消息类型。比如-msg 1004,1012,1033只转发这些类型的RTCM消息。这个选项在带宽受限的场景下很有用。我一般会加上-t 5 -r 3这两个参数让str2str在数据中断时快速重连。如果网络特别差还会加上-b 65536增大缓冲区减少丢包。还有一个隐藏技巧-n选项可以指定线程数。默认是1如果同时转发多路数据可以增加到2或4提高并发处理能力。不过实测下来对于RTCM数据这种低带宽场景单线程完全够用。4. 完整实操从零搭建RTK转发服务器4.1 环境准备与RTKLIB安装先搞定运行环境。我以树莓派4B为例系统是Raspberry Pi OS Lite 64位。其他Linux发行版步骤类似Windows下需要编译或者下载预编译的二进制文件。第一步更新系统并安装必要的依赖sudo apt update sudo apt upgrade -y sudo apt install -y build-essential gcc g make libncurses5-dev第二步下载RTKLIB源码。官方仓库在GitHub上但国内访问可能不稳定可以用镜像源或者直接下载release包。我一般用2.4.3 b34版本这个版本比较稳定。wget https://github.com/tomojitakasu/RTKLIB/archive/refs/tags/b34.tar.gz tar -xzf b34.tar.gz cd RTKLIB-b34第三步编译。RTKLIB的编译很简单进入src目录直接makecd src make编译完成后str2str可执行文件会出现在src目录下。你可以把它复制到/usr/local/bin方便调用sudo cp str2str /usr/local/bin/验证一下是否安装成功str2str -h如果看到帮助信息说明安装没问题。注意编译过程中如果报错找不到ncurses.h说明缺少开发库执行sudo apt install libncurses5-dev即可。另外树莓派上编译可能需要十几分钟耐心等待。4.2 基准站端配置串口读取与TCP转发假设你的GNSS模块通过USB转串口线连在树莓派上设备节点是/dev/ttyUSB0波特率115200。基准站需要输出RTCM 3.x格式的差分数据具体配置方法取决于你的模块型号一般用厂商提供的配置工具设置。先确认串口能正常读到数据sudo cat /dev/ttyUSB0 | xxd | head如果看到以D3开头的十六进制数据说明RTCM输出正常。如果没有数据检查模块配置和接线。接下来写一个启动脚本放在/home/pi/start_base.sh#!/bin/bash sleep 10 str2str -in serial://ttyUSB0:115200:8:n:1 \ -out tcpsvr://:5000 \ -out file:///home/pi/rtcm_$(date %Y%m%d_%H%M%S).rtcm \ -t 5 -r 3 -b 65536这个脚本做了几件事等待10秒让GNSS模块初始化从串口读数据在5000端口开TCP服务同时把数据保存到带时间戳的文件超时5秒重连间隔3秒缓冲区64KB。给脚本加执行权限chmod x /home/pi/start_base.sh然后配置开机自启。编辑/etc/rc.local在exit 0之前加上su - pi -c /home/pi/start_base.sh 或者用systemd服务更规范一些。创建/etc/systemd/system/str2str-base.service[Unit] Descriptionstr2str Base Station Forwarder Afternetwork.target [Service] Typesimple Userpi ExecStart/usr/local/bin/str2str -in serial://ttyUSB0:115200:8:n:1 -out tcpsvr://:5000 -t 5 -r 3 -b 65536 Restartalways RestartSec10 [Install] WantedBymulti-user.target启用服务sudo systemctl daemon-reload sudo systemctl enable str2str-base sudo systemctl start str2str-base检查状态sudo systemctl status str2str-base如果看到active (running)说明基准站端配置成功。4.3 流动站端配置TCP客户端接收与串口输出流动站端可以是另一台树莓派、一台笔记本电脑、或者无人机上的机载电脑。假设流动站的GNSS模块连在/dev/ttyUSB0上波特率115200我们需要把从基准站收到的RTCM数据通过串口送给它。流动站端的str2str命令str2str -in tcpcli://基准站IP:5000 \ -out serial://ttyUSB0:115200:8:n:1 \ -t 5 -r 3这里基准站IP替换成实际的公网IP或者局域网IP。如果基准站在内网需要做端口映射或者用内网穿透工具注意这里说的是合法的内网穿透服务用于远程访问自己的设备不涉及任何违规用途。流动站端也建议用systemd管理[Unit] Descriptionstr2str Rover Receiver Afternetwork.target [Service] Typesimple Userpi ExecStart/usr/local/bin/str2str -in tcpcli://203.0.113.10:5000 -out serial://ttyUSB0:115200:8:n:1 -t 5 -r 3 Restartalways RestartSec10 [Install] WantedBymulti-user.target配置完成后流动站的GNSS模块应该能收到差分数据。你可以用RTKNAVI或者RTKPOST查看定位状态如果看到FIX或者Float说明差分链路通了。4.4 验证数据链路是否正常配置完成后怎么确认数据真的在流动有几个方法。方法一在基准站端用tcpdump抓包看5000端口有没有数据发出sudo tcpdump -i any port 5000 -c 10方法二在流动站端用nc测试TCP连接nc -v 基准站IP 5000 | xxd | head如果看到RTCM数据说明网络链路正常。方法三用RTKNAVI的Monitor功能查看差分龄期。差分龄期是指流动站当前时间与最近一次收到差分数据的时间差正常应该在1到2秒以内。如果超过5秒说明链路延迟太大或者丢包严重。我一般会同时用这三种方法交叉验证确保每个环节都没问题。5. 常见问题与排查技巧实录5.1 串口读不到数据怎么办这是最常见的问题。先检查硬件USB转串口线是否插紧GNSS模块是否上电天线是否接好。然后检查软件串口设备节点是否正确波特率是否匹配权限是否足够。Linux下串口权限问题很常见。默认情况下/dev/ttyUSB0属于dialout组普通用户没有读写权限。解决方法有两种把用户加入dialout组或者用sudo运行str2str。sudo usermod -a -G dialout pi改完需要重新登录才生效。如果不想改用户组可以在udev规则里给串口设备加权限echo KERNELttyUSB*, MODE0666 | sudo tee /etc/udev/rules.d/99-usb-serial.rules sudo udevadm control --reload-rules还有一个坑有些GNSS模块上电后需要发送配置命令才会输出RTCM数据。这种情况下你需要先用厂商工具配置好模块让它自动输出或者用str2str的-p选项延迟启动等配置完成后再开始转发。5.2 TCP连接不稳定怎么优化TCP连接不稳定的表现是频繁断连、数据断断续续、RTK固定率低。排查思路从网络层开始。先看基准站和流动站之间的网络延迟和丢包率。用ping测试ping -c 100 基准站IP如果丢包率超过5%说明网络质量有问题。4G网络在信号弱的地方丢包很正常可以尝试换位置、加天线、或者换运营商。如果网络本身没问题检查str2str的参数。-t超时时间设得太短会导致频繁重连设得太长会导致数据中断后不能及时恢复。我一般设5秒实测比较平衡。-r重连间隔设3秒既能快速恢复又不会因为频繁重连加重网络负担。还有一个容易被忽略的点TCP的Nagle算法。str2str默认可能启用了Nagle算法导致小数据包被合并发送增加延迟。可以在系统层面禁用echo 1 | sudo tee /proc/sys/net/ipv4/tcp_low_latency不过这个设置是全局的会影响所有TCP连接。如果不想全局修改可以在str2str层面看有没有相关选项或者用setsockopt在代码里设置。实测下来RTCM数据包本身就不大Nagle算法的影响有限不是主要瓶颈。5.3 RTK固定率低的排查思路RTK固定率低的原因很多差分链路只是其中之一。排查时按照从易到难的顺序来。先看差分龄期。如果龄期经常超过3秒说明差分数据到达不及时问题在链路。检查网络延迟、str2str是否在正常运行、基准站是否在持续输出数据。如果差分龄期正常但固定率还是低检查基准站和流动站的卫星观测条件。基准站天线要放在开阔处周围不能有高大建筑物或树木遮挡。流动站同理。另外基准站和流动站最好能观测到相同的卫星如果两者相距太远共视卫星数量不足固定率也会下降。还有一个常见原因是多路径效应。基准站天线附近如果有金属物体或者水面反射信号会干扰观测。解决方法是在天线下面加一个扼流圈或者金属底板抑制多路径。最后检查RTCM消息类型。有些基准站默认只输出部分类型的RTCM消息比如只有1004没有1012导致流动站无法解算。建议基准站输出完整的MSM消息比如MSM4或MSM7包含所有频点的观测数据。5.4 常见问题速查表问题现象可能原因排查方法解决方案串口无数据设备节点错误ls /dev/ttyUSB*确认设备节点检查驱动串口无数据波特率不匹配查看模块手册修改str2str波特率参数串口无数据权限不足ls -l /dev/ttyUSB0加入dialout组或改udev规则TCP连接失败防火墙拦截telnet IP 端口开放端口或关闭防火墙TCP连接失败端口映射错误检查路由器配置重新配置端口映射数据断断续续网络丢包ping -c 100 IP改善网络环境或换链路数据断断续续超时设置不当查看str2str日志调整-t和-r参数RTK固定率低差分龄期大RTKNAVI查看龄期优化链路延迟RTK固定率低共视卫星少查看卫星分布调整基准站位置RTK固定率低多路径干扰观察信噪比加扼流圈或换位置提示排查问题时建议在基准站和流动站两端同时开日志。str2str本身没有日志功能但可以用tee命令把输出保存下来或者用tcpdump抓包分析。5.5 几个我踩过的坑第一个坑树莓派USB供电不足。我用树莓派Zero 2 W带一个4G网卡和一个GNSS模块刚开始一切正常但运行几个小时后str2str频繁崩溃。查了半天发现是USB口供电不足4G网卡峰值电流超过500mA把电压拉低了。换了一个带独立供电的USB Hub才解决。第二个坑串口线太长导致数据错误。基准站天线离主机有十几米我用了一根普通的USB延长线结果串口数据经常出现校验错误。后来换成带屏蔽的工业级USB线问题消失。所以线材不能省尤其是野外环境。第三个坑str2str的-msg选项用错了。我想只转发1004和1012消息写了-msg 1004,1012结果发现流动站收不到数据。后来查文档才知道-msg选项的语法是-msg type1,type2但有些版本的str2str不支持这个选项或者需要配合其他参数使用。最后我干脆不筛选全量转发反正RTCM数据量不大。第四个坑NTRIP账号密码里有特殊字符。我用了一个包含符号的密码结果str2str解析URL时出错。解决方法是用URL编码把换成%40。这个坑很隐蔽因为错误信息不会直接提示密码问题。6. 进阶玩法多路转发与远程管理6.1 一份数据同时推给多个流动站str2str的多路输出能力在团队作业时特别有用。比如一个基准站同时服务三台流动站只需要在基准站端启动一个str2str实例配置三个-out参数str2str -in serial://ttyUSB0:115200:8:n:1 \ -out tcpcli://192.168.1.101:5000 \ -out tcpcli://192.168.1.102:5000 \ -out tcpcli://192.168.1.103:5000 \ -t 5 -r 3每个流动站独立连接互不影响。如果某个流动站断线str2str会单独重连那一路不会影响其他流动站。不过要注意TCP客户端模式下如果目标地址不可达str2str会阻塞等待。如果三个流动站中有一个网络有问题可能会拖慢整体转发效率。解决办法是用tcpsvr模式让流动站主动来连基准站这样基准站不需要维护每个连接的状态。6.2 用NTRIP Caster做中转如果流动站数量多、分布广直接TCP转发就不太合适了。这时候可以用NTRIP Caster做中转。基准站把数据推给Caster流动站从Caster拉数据Caster负责分发。基准站端配置str2str -in serial://ttyUSB0:115200:8:n:1 \ -out ntripsvr://user:passcaster.example.com:2101/BASE01 \ -t 5 -r 3流动站端配置str2str -in ntripcli://user:passcaster.example.com:2101/BASE01 \ -out serial://ttyUSB0:115200:8:n:1 \ -t 5 -r 3这种架构的好处是扩展性强加流动站只需要在Caster端加账号基准站端不用改配置。缺点是依赖Caster的稳定性而且多了一跳网络延迟。我实测下来自建NTRIP Caster的端到端延迟比直接TCP转发多50到100毫秒。对于大多数RTK应用来说这个延迟可以接受。但如果你的应用对延迟特别敏感比如高速无人机避障还是直接TCP转发更合适。6.3 远程监控与自动重启野外部署最怕设备死机。我的做法是写一个监控脚本定期检查str2str进程是否在运行如果不在就自动重启。脚本放在/home/pi/watchdog.sh#!/bin/bash while true; do if ! pgrep -x str2str /dev/null; then echo $(date): str2str not running, restarting... /home/pi/watchdog.log /usr/local/bin/str2str -in serial://ttyUSB0:115200:8:n:1 -out tcpsvr://:5000 -t 5 -r 3 fi sleep 30 done这个脚本每30秒检查一次如果str2str不在运行就重新启动。配合systemd的Restartalways基本上可以做到无人值守。远程监控方面我一般用SSH隧道加网页监控。在基准站上跑一个简单的HTTP服务用Python的http.server模块展示当前状态python3 -m http.server 8080然后写一个CGI脚本输出str2str的运行状态和差分龄期。这样在手机浏览器上就能看到基准站是否正常。注意远程访问自己的设备时务必使用强密码和密钥认证不要用默认端口定期更新系统补丁。安全无小事尤其是暴露在公网上的设备。6.4 低成本硬件的性能边界最后说说低成本方案的性能边界。我用树莓派4B加F9P模块做过压力测试连续运行72小时str2str的CPU占用率不到5%内存占用稳定在10MB左右。数据转发延迟平均150毫秒最大不超过300毫秒。这个性能对于1Hz的RTK输出完全够用甚至10Hz也扛得住。但如果你的应用需要20Hz以上的更新率或者同时转发多路高带宽数据树莓派的USB总线和网络带宽可能会成为瓶颈。这时候可以考虑换x86工控机或者用有线网络替代4G。另外4G网络的延迟波动比较大市区可能50毫秒郊区可能200毫秒偏远地区可能500毫秒以上。如果对延迟要求高建议用有线网络或者无线网桥。我做过对比测试同样的硬件配置有线网络的RTK固定率比4G高15%左右固定时间快3到5秒。这个方案后续还可以扩展。比如加一个Web界面来动态修改str2str参数或者用MQTT把状态数据推送到手机App。再比如结合RTKLIB的rnx2rtkp做后处理把原始观测数据存下来事后做高精度解算。这些玩法我都在逐步尝试有机会再单独写文章分享。