平面图标
送货到
更新(08 / 12 / 2025): 我们所有产品都有大量库存,也可以在    立即购买

如何设置 Node-RED 服务器以远程接收 NMEA

GNSS RTK技术的应用范围很广,通常情况下,你会进行一些测量,然后将其导出到计算机进行分析。这是最常见的情况。
但对于某些应用程序,您可能需要实时将 GNSS RTK 数据发送到您的计算机/服务器,这样您就可以立即采取行动,而无需等待几个小时来处理数据。

需要将实时位置发送到服务器的流行应用包括:车队管理和物流、叫车和公共交通、资产跟踪、野生动物监测……

在本教程中,我们将解释如何使用 Node-RED(一种流行的可视化编程工具)设置服务器,以便您可以启动自己的项目,我们还将介绍如何配置您的 GNSS 接收器和插件以将数据发送到该服务器。

所需硬件

所需软件

  • GNSS Master Android的应用程序

Node-RED 的安装

远程 Linux 服务器

在我们的例子中,我们使用 AlmaLinux 发行版。
打开服务器的终端并运行以下命令:

sudo dnf module reset -y nodejs
sudo dnf module enable -y nodejs:20
sudo dnf install -y nodejs npm gcc-c++ make
# then:
sudo npm i -g --unsafe-perm node-red

您可以通过输入以下命令检查安装是否成功:
/usr/local/bin/node-red --version

如果一切正常,您将看到终端上显示的版本。

其他设备/操作系统

您可以在 Node-RED 官方项目页面上找到有关 不同的系统.

在服务器上打开 TCP 端口

这可能并不总是必要的,但您可能需要打开 TCP 端口以允许传入连接。
在本例中我们将使用 TCP 端口 2222,您应该在服务器终端上输入:
iptables -A INPUT -p tcp --dport 2222 -j ACCEPT

运行 Node-RED

输入以下命令:
 /usr/local/bin/node-red &

转到浏览器并输入:
172.123.123.123:1880
其中 172.123.123.123 必须是您的服务器的 IP 地址。
如果一切正常,您应该会看到类似这样的内容:

准备您的第一个流程

在 Node-RED 中,项目被称为流。
我们将准备一个新的流程来监听传入的 TCP 连接并将接收到的任何内容打印到调试窗口中。

在左侧面板上搜索名为 TCP 输入,将其拖放到流程画布上。
还搜索 调试 节点并将它们连接在一起,如下所示:

在 Node-RED 中,项目被称为流。
我们将准备一个新的流程来监听传入的 TCP 连接并将接收到的任何内容打印到调试窗口中。

在左侧面板上搜索名为 TCP 输入,将其拖放到流程画布上。
还搜索 调试 节点并将它们连接在一起,如下所示:

双击节点中的 tcp 并设置您想要监听的 TCP 端口,在此示例中为:2222。
还设置为以 \r\n 分隔的流字符串。

这样做之后 点击部署按钮 在屏幕的右上方。
此按钮将在任何修改后运行块。

将您的 GNSS 接收器连接到 Node-RED

RTK Portable Bluetooth Kit 使用 Android 设备

  1. 通过 BT 将您的便携式蓝牙套件连接到您的 Android 设备。
  2. 可选 GNSS Master 应用程序,连接到 GNSS 接收器连接中的 BT 模块。
  3. 如果需要,设置校正输入
  4. 在“接收器数据输出”中,选择“TCP 客户端”,并在“TCP 地址”中输入服务器的 IP 地址,在“TCP 端口”中输入 2222。点击“连接”。
  5. 就这样,如果你双击 Node-RED 中的调试窗口,你应该会看到类似这样的内容,其中所有数据都被接收了:

其他带有 4G、WiFi 或以太网插件的 GNSS 接收器

如果您有不同的 GNSS 接收器,即使没有 Android 设备,您也可以获得相同的结果。
确保将要发送到服务器的消息输出到 XBee 插件 COM 端口,通常至少要发送 NMEA GGA。

然后,配置您的 4G、WiFi 或 Ethernet NTRIP Master 使用与之前相同的参数,为插件添加 TCP 客户端功能,TCP 服务器是您的服务器 IP 地址,TCP 端口是 2222。

就这么简单 🙂

对数据进行处理

好吧,到目前为止还不是很令人兴奋,对吧?
在您的服务器上查看实时 NMEA 流是可以的,但我们想看看 Node-RED 的一些功能。
在下一个示例中,我们将向您展示如何解析输入流以获取纬度和经度,并且我们将在地图上绘制实时位置,并用显示旧位置的轨迹。

首先,删除您当前的流程。
点击右上角菜单 > 管理调色板 > 安装 > 搜索 node-red-contrib-web-worldmap 并安装它。

返回菜单 > 导入 > 剪贴板并粘贴以下代码:

				
					[
  {
    "id": "tab1",
    "type": "tab",
    "label": "GNSS Live Map + Track",
    "disabled": false,
    "info": ""
  },
  {
    "id": "tcpInNmea2222",
    "type": "tcp in",
    "z": "tab1",
    "name": "NMEA TCP 2222",
    "server": "server",
    "host": "",
    "port": "2222",
    "datamode": "stream",
    "datatype": "utf8",
    "newline": "\\r\\n",
    "topic": "",
    "base64": false,
    "x": 150,
    "y": 140,
    "wires": [
      [
        "fnGGA"
      ]
    ]
  },
  {
    "id": "fnGGA",
    "type": "function",
    "z": "tab1",
    "name": "Filter GGA → {lat,lon}",
    "func": "// Allman style\nfunction nmeaToDecimal(raw, hemi)\n{\n    if (!raw || !hemi)\n    {\n        return null;\n    }\n    const isLat = (hemi === 'N' || hemi === 'S');\n    const degDigits = isLat ? 2 : 3;\n    const deg = parseInt(raw.slice(0, degDigits), 10);\n    const min = parseFloat(raw.slice(degDigits));\n    if (Number.isNaN(deg) || Number.isNaN(min))\n    {\n        return null;\n    }\n    let dec = deg + (min / 60.0);\n    if (hemi === 'S' || hemi === 'W')\n    {\n        dec = -dec;\n    }\n    return dec;\n}\n\nif (typeof msg.payload !== 'string')\n{\n    return null;\n}\n\nconst line = msg.payload.trim();\nif (!line.startsWith('$') || line.indexOf('GGA,') === -1)\n{\n    return null;\n}\n\nconst f = line.split(',');\nconst lat = nmeaToDecimal(f[2], f[3]);\nconst lon = nmeaToDecimal(f[4], f[5]);\nif (lat == null || lon == null)\n{\n    return null;\n}\n\nmsg.payload = { lat, lon };\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 410,
    "y": 140,
    "wires": [
      [
        "fnToWorldmap"
      ]
    ]
  },
  {
    "id": "fnToWorldmap",
    "type": "function",
    "z": "tab1",
    "name": "Marker + Track",
    "func": "// Input: msg.payload={lat,lon}\n// Output1 → worldmap marker\n// Output2 → worldmap-tracks polyline (then wired into worldmap)\n\nif (!msg.payload || msg.payload.lat == null || msg.payload.lon == null)\n{\n    return null;\n}\n\nconst lat = Number(msg.payload.lat);\nconst lon = Number(msg.payload.lon);\nconst name = \"GPS-1\"; // keep constant per device\nconst now = Date.now();\n\nconst base =\n{\n    name: name,\n    lat: lat,\n    lon: lon,\n    layer: \"GNSS\",\n    time: now, // helps pruning\n    icon: \"fa-location-arrow\",\n    popup: `Lat: ${lat.toFixed(6)}<br>Lon: ${lon.toFixed(6)}<br>UTC: ${new Date(now).toISOString()}`\n};\n\nreturn [ { payload: base }, { payload: base } ];",
    "outputs": 2,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 650,
    "y": 140,
    "wires": [
      [
        "worldmap",
        "dbgMarker"
      ],
      [
        "tracks"
      ]
    ]
  },
  {
    "id": "tracks",
    "type": "worldmap-tracks",
    "z": "tab1",
    "name": "Track GNSS (layer GNSS)",
    "depth": "1000",
    "layer": "GNSS",
    "doors": "",
    "x": 930,
    "y": 180,
    "wires": [
      [
        "worldmap"
      ]
    ]
  },
  {
    "id": "worldmap",
    "type": "worldmap",
    "z": "tab1",
    "name": "Live Map (/worldmap)",
    "lat": "0",
    "lon": "0",
    "zoom": "2",
    "layer": "OSM",
    "cluster": "",
    "maxage": "",
    "usermenu": "show",
    "layers": "show",
    "panit": "false",
    "panlock": "false",
    "zoomlock": "false",
    "hiderightclick": "false",
    "coords": "none",
    "showgrid": "false",
    "showruler": "false",
    "showlayer": "true",
    "showmenu": "true",
    "path": "/worldmap",
    "overlist": "DR,CO,RA,DN,HM",
    "maplist": "OSM,Esri Terrain,Esri Satellite",
    "mapname": "",
    "mapurl": "",
    "mapopt": "",
    "kmlurl": "",
    "devicelabel": "name",
    "layercontrol": "false",
    "x": 930,
    "y": 120,
    "wires": []
  },
  {
    "id": "dbgMarker",
    "type": "debug",
    "z": "tab1",
    "name": "Marker payload",
    "active": false,
    "tosidebar": true,
    "console": false,
    "tostatus": false,
    "complete": "payload",
    "statusVal": "",
    "statusType": "auto",
    "x": 930,
    "y": 220,
    "wires": []
  },
  {
    "id": "hint",
    "type": "comment",
    "z": "tab1",
    "name": "Send NMEA (\\r\\n delimited) to TCP 2222. Open http://<host>:1880/worldmap",
    "info": "",
    "x": 330,
    "y": 90,
    "wires": []
  }
]

				
			

你应该看到这样的东西:

双击世界地图节点。
在地图列表下拉菜单中,选择 OpenStreetMap 或其他图层,单击完成:

按 部署 按钮。
您可以通过浏览器访问此处的实时地图:
172.123.123.123:1880/世界地图/
其中 IP 地址必须与您的服务器的 IP 地址相同。

您将看到一张带有标记的地图,显示您的 GNSS 接收器位置,实时更新,您可以随意放大/缩小。

我们建议您查看流程中的每个节点,以便更好地了解它们的作用、修改它们并查看有什么变化。

如果您想做一些更高级的事情,您会发现大量的教程和 AI 工具也会为您提供帮助。

玩得开心!

如果您想关闭 Node-RED,请执行以下操作:
iptables -A INPUT -p tcp --dport 2222 -j REJECT

类型 ps aux | grep node ,找到节点进程并通过以下方式终止该进程:
kill NODE_PROCESS_ID

如果你喜欢这个内容,你可以关注我们 Twitter, YouTube, Facebook or LinkedIn 保持更新这样的内容。

有任何问题或要求吗?
联系我们!我们将在 24 小时内回复!

图标
联系我们 ArduSimple
关闭

想了解更多关于 GPS/RTK 的信息吗?

1. 我们的工程团队会联系您解决任何问题
2.我们会及时通知您促销和新产品发布
3.只有当我们有重要新闻时您才会收到我们的消息,我们不会向您发送垃圾邮件