Wiki
開發問題與排查
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.開發問題與排查
1.1.SSH 連線 ysu.local 時解析到 MID360 網口地址
1.1.1.原因
現象是:電腦與工控機連線同一個 Wi-Fi,直接 ping 工控機的 Wi-Fi 地址 192.168.2.183 正常,也能通過這個地址 SSH 登入;但使用 ssh ysu@ysu.local 時,主機名卻解析到 192.168.1.50,提示 Connection closed by 192.168.1.50 port 22。
此前拔掉 MID360 網線並重啟工控機後,主機名又能解析到 Wi-Fi 地址,但保留兩張網絡卡時問題再次出現。
工控機同時使用 Wi-Fi 和有線網口,兩張網絡卡的用途不同:
| 介面或裝置 | 本次地址 | 用途 |
|---|---|---|
工控機 Wi-Fi wlp4s0 |
192.168.2.183/24 |
SSH、區域網通訊和聯網,地址由 DHCP 分配 |
工控機雷達有線口 enp3s0 |
192.168.1.50/24 |
接收 MID360 點雲和 IMU 資料 |
| MID360 | 192.168.1.107 |
向配置的上位機地址傳送資料 |
**192.168.1.50 是雷達資料的接收端地址,不是 MID360 的預設閘道器。
**該地址填寫在驅動配置的 host_net_info 中,雷達自身地址填寫在 lidar_configs 中。
Wi-Fi 和雷達使用不同的 /24 網段,本次故障不是這兩個網段重疊造成的。
2026-10-19 保留兩張網絡卡復現後,抓包和程序跟蹤確認:工控機上的 NoMachine 9.7.3 在 Wi-Fi 上錯誤釋出了 ysu.local → 192.168.1.50,與 Avahi 釋出的正確地址衝突。
| 釋出程序 | 在 Wi-Fi 上返回的 A 記錄 | 記錄有效期 TTL |
|---|---|---|
avahi-daemon,PID 735 |
ysu.local → 192.168.2.183 |
120 秒 |
nxserver.bin,PID 3955,傳送執行緒 4400 |
ysu.local → 192.168.1.50 |
600 秒 |
在工控機 wlp4s0 上抓到的響應均來自 192.168.2.183:5353,但記錄內容分別為 .183 和 .50。進一步跟蹤系統呼叫,確認 NoMachine 的傳送執行緒將包含 .50 的記錄從 Wi-Fi socket 發出,而 Avahi 發出的是 .183。因此不是單憑“哪個程序監聽了 5353 埠”推測原因,已經定位到錯誤記錄的實際傳送程序。
兩個服務使用同一個主機名給出不同的地址,電腦收到並快取錯誤記錄後,就會把 SSH 發往雷達網段。
600 秒錶示記錄有效期,並不是地址優先順序;實際解析結果還受響應先後和快取更新影響,所以會出現有時正常、有時指向 .50 的現象。
本次電腦去往 .50 的實際路由還進入了 FlClash TUN,去往 .183 則直接經過 Wi-Fi。
錯誤地址來自工控機 NoMachine 的 mDNS 釋出;FlClash 接管去往錯誤地址的連線,是後續路徑問題。
不能僅憑 Connection closed 判斷工控機的 SSH 服務故障。
Avahi 當時已正確回答 Wi-Fi 地址,systemd-resolved 的 mDNS 未啟用,兩端檢查的 hosts 檔案中也沒有靜態配置 ysu.local → .50。先關閉 NoMachine 自帶的區域網發現後,主機名立即恢復正常,驗證了故障來源;單獨重啟 Avahi 或限制其介面,無法阻止 NoMachine 繼續傳送錯誤記錄。隨後進一步通過 NoMachine 自身的 NXDListenAddress 配置繫結 Wi-Fi 地址,恢復原生自動發現,並補上 DHCP 地址變化時的同步。下面先記錄臨時方案,再說明本機最終採用的完整修復。
1.1.2.臨時方案:關閉 NoMachine 自動發現
1. 臨時連線:使用工控機當前的 Wi-Fi 地址。(前提是你得知道它的 IP 地址)
以下命令在電腦端執行,本次地址為:
ssh ysu@192.168.2.183
Wi-Fi 地址可能隨 DHCP 租約變化,可以在工控機本地或路由器客戶端列表中查詢。工控機上也可以執行:
nmcli -f DEVICE,TYPE,STATE,CONNECTION device status
ip -br -4 addr
本次工控機 Wi-Fi 介面為 wlp4s0,雷達有線介面為 enp3s0。排查其他機器時,以實際輸出為準。

2. 工控機:確認 NoMachine 也在使用 mDNS。
以下操作在工控機上執行,不是在用於遠端連線的電腦上執行:
sudo ss -ulpn 'sport = :5353'
sudo /etc/NX/nxserver --version
修復前,5353 UDP 埠同時由 avahi-daemon 和 nxserver.bin 使用。本次 NoMachine 版本為 9.7.3。多個程序監聽同一埠本身不代表一定故障,應結合實際回答的地址判斷;本次已通過抓包和程序跟蹤確認 NoMachine 釋出錯誤記錄。
3. 工控機:關閉 NoMachine 的區域網自動發現。
先備份配置。下面的備份檔名用於本次排查;再次操作時換一個檔名,保留已有備份:
sudo cp -a /usr/NX/etc/server.cfg /usr/NX/etc/server.cfg.before-mdns-fix-20261019
sudoedit /usr/NX/etc/server.cfg
找到本次安裝版本中的配置項:
#EnableLocalNetworkBroadcast 1
去掉開頭的 # 並改為:
EnableLocalNetworkBroadcast 0
這會關閉 NoMachine 的區域網自動發現,其他電腦不再通過它的廣播自動發現該工控機;仍可通過 IP 或能夠正常解析的主機名手動連線 NoMachine。 無需解除安裝 NoMachine,也無需停掉 Avahi。NoMachine 官方埠與配置說明
不同版本的配置項可能不同,舊資料中還會出現 EnableNetworkBroadcast。應以安裝版本的 server.cfg 註釋和對應文件為準,不能把舊名稱直接新增到本次 9.7.3 的配置中。
4. 工控機:重啟 NoMachine,使配置生效。
先結束正在使用的 NoMachine 遠端桌面會話,再執行;重啟會暫時中斷該服務:
sudo /etc/NX/nxserver --restart
sudo /etc/NX/nxserver --status
隨後檢查:
sudo ss -ulpn 'sport = :5353'
sudo ss -ltnp 'sport = :4000'
臨時方案生效後,5353 埠只剩 Avahi,NoMachine 的 nxserver、nxnode 和 nxd 服務恢復執行,4000 TCP 埠繼續監聽。配置儲存在檔案中,系統重啟後仍會讀取;本次沒有修改 Avahi 配置,也沒有修改 Wi-Fi、雷達 IP 或路由。
5. 電腦端:驗證主機名和 SSH。
getent ahostsv4 ysu.local
avahi-resolve-host-name -4 ysu.local
ssh ysu@ysu.local
預期解析到工控機當前的 Wi-Fi 地址,本次為 192.168.2.183,並且可以正常登入。已經快取的錯誤記錄可能需要等待過期或被正確記錄更新;若仍返回 .50,應繼續抓包確認是否還有錯誤釋出源,不能僅憑服務狀態認定修復完成。
如需抓包,在工控機執行以下命令,將介面名換成實際 Wi-Fi 介面:
sudo tcpdump -ni wlp4s0 -vv 'udp port 5353'
觀察 ysu.local 的 A 記錄內容,而不只是資料包的源 IP。本次錯誤響應的資料包源 IP 也是 .183,真正錯誤的是其中的 A 記錄指向了 .50。
1.1.3.臨時方案驗證結果
2026-10-19 完成上述修改並重啟 NoMachine 後:
| 檢查專案 | 結果 |
|---|---|
| 電腦端三次名稱查詢 | 均得到 192.168.2.183 |
| 工控機 Wi-Fi 上的三次 mDNS 查詢響應 | 均為 Avahi 返回的 .183,該輪抓包未再出現 .50 |
ssh ysu@ysu.local |
密碼登入成功,遠端 hostname 返回 ysu |
| NoMachine 狀態 | 服務正常,4000 TCP 埠繼續監聽 |
| 電腦斷開並重新連線原 Wi-Fi 後 | 主機名仍解析到 .183 |
臨時方案只將 /usr/NX/etc/server.cfg 中的 EnableLocalNetworkBroadcast 設為 0,原配置備份在同目錄的 server.cfg.before-mdns-fix-20261019。後續已恢復自動發現,最終狀態以下面的完整修復為準。
1.1.4.完整修復:讓 NoMachine 自動跟隨 Wi-Fi 當前 IP
這裡固定的是用於遠端連線的 Wi-Fi 介面,不是某一個 IP。NXDListenAddress 本身需要填寫具體地址,不能靠寫一行配置就自動追蹤 DHCP。動態效果來自下面的同步程式:每次讀取 Wi-Fi 當前地址,再把它寫入 NoMachine 配置。
例如當前地址為 .183,程式就寫入 .183;以後 DHCP 分配了其他地址,程式會用新地址替換它。不要手動把 NXDListenAddress 永久寫成 192.168.2.183,也不要把 ysu.local 填進這個欄位來解析自己;電腦端連線時才使用 ysu.local。NoMachine 監聽和廣播地址配置說明
本機已完成下面的部署,現有工控機無需重複安裝。下面給出完整步驟,方便在其他機器複用;首次部署會重啟 NoMachine,應先結束正在使用的遠端桌面會話。
1. 工控機:確認需要跟隨的 Wi-Fi 介面。
nmcli -f DEVICE,TYPE,STATE,CONNECTION device status
ip -br -4 addr
本機 Wi-Fi 為 wlp4s0,雷達網口為 enp3s0。後面的 Python 指令碼和 NetworkManager 事件指令碼中各有一處介面設定,其他機器應把兩處 wlp4s0 都換成實際 Wi-Fi 介面名。Wi-Fi 繼續使用 DHCP,無需固定 IP,也無需修改雷達網口。
2. 工控機:安裝讀取當前 IP 的同步程式。
建立檔案:
sudoedit /usr/local/sbin/nomachine-wifi-sync
填入下面的內容。指令碼中只指定介面名 INTERFACE,沒有寫死 Wi-Fi IP;PORT 對應本機 NoMachine 預設的 4000 埠。
#!/usr/bin/python3
"""Keep NoMachine bound to the robot's management Wi-Fi IPv4 address."""
import fcntl
import json
import os
from pathlib import Path
import re
import stat
import subprocess
import tempfile
INTERFACE = "wlp4s0"
CONFIG = Path("/usr/NX/etc/server.cfg")
PORT = 4000
def run(*args):
return subprocess.check_output(args, text=True, timeout=10)
def replace_config(content):
metadata = CONFIG.stat()
temporary = None
try:
with tempfile.NamedTemporaryFile(mode="w", dir=CONFIG.parent, delete=False) as output:
temporary = Path(output.name)
output.write(content)
output.flush()
os.fchown(output.fileno(), metadata.st_uid, metadata.st_gid)
os.fchmod(output.fileno(), stat.S_IMODE(metadata.st_mode))
os.fsync(output.fileno())
os.replace(temporary, CONFIG)
finally:
if temporary is not None and temporary.exists():
temporary.unlink()
def main():
with open("/run/nomachine-wifi-sync.lock", "w") as lock:
fcntl.flock(lock, fcntl.LOCK_EX)
interfaces = json.loads(run("/usr/sbin/ip", "-j", "-4", "address", "show", "dev", INTERFACE))
addresses = [
address["local"]
for interface in interfaces
for address in interface.get("addr_info", [])
if address.get("scope") == "global" and address.get("valid_life_time") != 0
]
if not addresses:
print(f"{INTERFACE} has no IPv4 address; leaving configuration unchanged.", flush=True)
return
if len(addresses) != 1:
raise RuntimeError(f"Expected one Wi-Fi IPv4 address; got {addresses!r}")
address = addresses[0]
old = CONFIG.read_text()
updated, count = re.subn(
r"(?m)^[ \t]*#?NXDListenAddress[^\S\n]+[^\n]*$",
f'NXDListenAddress "{address}"',
old,
)
if count != 1:
raise RuntimeError(f"Expected one NXDListenAddress entry; got {count}")
listeners = run("/usr/bin/ss", "-H", "-ltn", f"sport = :{PORT}")
bound = any(line.split()[3] == f"{address}:{PORT}" for line in listeners.splitlines())
if updated == old and bound:
print(f"NoMachine already bound to {INTERFACE} {address}:{PORT}; no restart.", flush=True)
return
if updated != old:
replace_config(updated)
print(f"Synchronizing NoMachine to {INTERFACE} {address}:{PORT}.", flush=True)
subprocess.run(["/etc/NX/nxserver", "--restart"], check=True, timeout=75)
listeners = run("/usr/bin/ss", "-H", "-ltn", f"sport = :{PORT}")
if not any(line.split()[3] == f"{address}:{PORT}" for line in listeners.splitlines()):
raise RuntimeError(f"NoMachine is not listening on {address}:{PORT} after restart")
print(f"Verified NoMachine listener {address}:{PORT}.", flush=True)
if __name__ == "__main__":
main()
這個程式讀取介面當前的唯一全域性 IPv4,更新現有的 NXDListenAddress 配置項。當前地址和監聽都正確時直接退出;地址改變或監聽未恢復時,才重啟 NoMachine 並檢查結果。介面暫時沒有 IPv4 時不修改配置,存在多個 IPv4 時明確報錯,避免隨意選擇地址。
3. 工控機:設定開機同步和網路變化觸發。
建立一次性同步服務:
sudoedit /etc/systemd/system/nomachine-wifi-sync.service
填入:
[Unit]
Description=Bind NoMachine to the current management Wi-Fi IPv4 address
Wants=network-online.target
After=network-online.target nxserver.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/nomachine-wifi-sync
TimeoutStartSec=100
[Install]
WantedBy=multi-user.target
再建立 NetworkManager 事件指令碼:
sudoedit /etc/NetworkManager/dispatcher.d/90-nomachine-wifi
填入:
#!/bin/sh
# NetworkManager runs this as root after connection/address changes.
case "${1:-}:${2:-}" in
wlp4s0:up|wlp4s0:dhcp4-change|wlp4s0:reapply)
/usr/bin/systemctl --no-block start nomachine-wifi-sync.service
;;
esac
設定檔案所有者和執行許可權:
sudo chown root:root /usr/local/sbin/nomachine-wifi-sync /etc/systemd/system/nomachine-wifi-sync.service /etc/NetworkManager/dispatcher.d/90-nomachine-wifi
sudo chmod 755 /usr/local/sbin/nomachine-wifi-sync /etc/NetworkManager/dispatcher.d/90-nomachine-wifi
sudo chmod 644 /etc/systemd/system/nomachine-wifi-sync.service
這樣,Wi-Fi 連線、DHCPv4 租約變化或重新應用連線配置時,系統都會觸發同步。NetworkManager 官方事件說明
上述三個檔案是本次部署的輔助配置,不是 NoMachine 自帶功能;只修改 server.cfg、沒有安裝事件指令碼,地址就不會自動跟隨 DHCP。
4. 工控機:啟用同步,再恢復 NoMachine 自動發現。
先載入並啟用同步服務,讓程式根據當前 Wi-Fi 地址生成 NXDListenAddress:
sudo systemctl daemon-reload
sudo systemctl enable --now nomachine-wifi-sync.service
然後編輯 NoMachine 配置:
sudoedit /usr/NX/etc/server.cfg
將區域網自動發現配置項改為:
EnableLocalNetworkBroadcast 1
**NXDListenAddress 這一行交給同步程式維護,不手動填寫 .183。**首次開啟自動發現後,重啟 NoMachine,使該開關生效:
sudo /etc/NX/nxserver --restart
後續 IP 變化由同步服務自動處理,無需再手動修改配置或重啟;地址發生變化時的服務重啟會中斷原有 NoMachine 會話。
可以檢查程式生成的地址和日誌:
sudo grep '^NXDListenAddress' /usr/NX/etc/server.cfg
systemctl is-enabled nomachine-wifi-sync.service
sudo journalctl -u nomachine-wifi-sync.service -n 30 --no-pager
這裡看到的是程式最後一次同步的具體地址,應與 wlp4s0 當前 IPv4 一致,不代表給網絡卡設定了靜態 IP。服務是一次性任務,執行成功後顯示 inactive 屬於正常情況,應看日誌和 Result,不要求它一直處於 active。
需要手動重新同步時執行:
sudo systemctl start nomachine-wifi-sync.service
NoMachine 恢復自動發現後仍會使用 5353 UDP 埠。此時不能把“看到 nxserver.bin 監聽 5353”直接當作故障,應檢查它釋出的地址是否與當前 Wi-Fi IP 一致。
5. 電腦端:始終使用主機名連線。
avahi-browse -rt _nomachine._tcp
getent ahostsv4 ysu.local
ssh ysu@ysu.local
自動發現的 A 記錄和 TXT 中的 ip= 應等於工控機此時的 Wi-Fi IPv4,而不是永遠等於本次排查時的 .183。本次 NoMachine 的 SRV 記錄埠為 0,實際 NX 連線埠由 TXT 中的 service=nx:4000 給出,不能據此誤判服務沒有監聽。
手動建立 NoMachine 連線時使用主機名:
协议:NX
主机:ysu.local
端口:4000
用户名:ysu
電腦仍需與工控機處於能夠進行區域網發現和互訪的網路中。IP 變化時,由 Avahi 更新主機名記錄、同步程式更新 NoMachine 繫結地址,電腦端繼續使用 ysu.local。
1.1.5.完整修複驗證結果
| 檢查專案 | 結果 |
|---|---|
| 原生 NoMachine 自動發現 | 已恢復,能發現 ysu,A 記錄和 TXT 的 IP 均為 .183 |
| Wi-Fi 抓包 | Avahi 和 NoMachine 都回答 .183,該輪未再出現 .50 |
| 4000 TCP 埠 | 繫結 192.168.2.183:4000,電腦端實際 TCP 連線成功 |
| SSH 主機名連線 | ssh ysu@ysu.local hostname 密碼登入成功,返回 ysu |
| 配置殘留舊 IP 的模擬 | 將儲存地址臨時改成 .254 後觸發 DHCP 變化處理,同步任務自動恢復 .183、重啟服務並驗證監聽成功 |
| 地址未變化的事件 | 同步任務直接退出,不重啟 NoMachine |
| 開機同步 | 服務已啟用 |
完整修復前的配置備份為 /usr/NX/etc/server.cfg.before-wifi-binding-20261019。本次沒有改變工控機實際 Wi-Fi IP,也沒有做整機重啟或圖形桌面登入測試;模擬舊配置驗證了同步處理流程,真實換 IP 和完整圖形會話仍應在實際使用時確認。
1.2.ROS 2 遠端檢視 MID360 點雲導致降頻、延遲和 RViz 不顯示
1.2.1.原因
現象是:電腦通過 Wi-Fi 開啟 RViz,或者僅執行遠端 ros2 topic hz,工控機上的 MID360 點雲和 IMU 就明顯降頻,連工控機本地測頻也受到影響;關閉遠端訂閱後恢復。切換手機熱點和其他 Wi-Fi 都未直接解決問題。
本次排查發現了兩個獨立問題:
-
電腦端 DDS 公佈了不適合本次跨機通訊的地址。
電腦端 DDS 同時公佈了 Wi-Fi 地址、Docker 網橋地址
172.17.0.1和 Clash TUN 虛擬網絡卡地址198.20.0.1。工控機根據這些地址傳送資料,其中發往 Clash TUN 地址的資料被路由到雷達網口的閘道器192.168.1.1,鄰居解析未完成。實測部分 UDP 傳送呼叫阻塞約 250~330 毫秒,傳送阻塞拖慢釋出,點雲和 IMU 出現積壓。本次定位到的明顯阻塞與 Clash TUN 地址有關,沒有單獨驗證 Docker 地址是否造成同樣阻塞。不過,電腦 Docker 網橋地址也不適合作為本次跨機接收地址,應一併排除。選擇介面的原則是:只使用 ROS 對端實際可達、並且本次通訊確實需要的介面。
-
電腦端 UDP 接收緩衝不足以承受本次點雲突發流量。
修正介面並重建電腦端 daemon 後,工控機已恢復點雲約 20 Hz、IMU 約 200 Hz,但電腦端點雲仍只有約 12.8 Hz,接收 socket 仍有緩衝丟包。此時預設接收緩衝約為 208 KiB;將請求值增大到 4 MiB 後,電腦端點雲恢復約 20 Hz,測試期間該 socket 的緩衝丟包計數為零。
因此,緩衝丟包不能全部歸因於選錯網絡卡。大點雲的分片集中到達、接收執行緒短暫來不及處理時,正確介面也可能出現緩衝溢位。增大接收緩衝是按資料量選擇的最佳化;本次 MID360 接收環境有實測依據,建議保留 4 MiB。Fast DDS 大數據傳輸說明
ros2 topic hz 會訂閱完整訊息來統計頻率,同樣需要接收整幀點雲,因此僅開啟遠端測頻也可能觸發上述問題。ROS 2 Humble 測頻實現
點雲延遲到十幾秒甚至幾十秒後,點雲時間戳可能早於 RViz 儲存的 TF 歷史。即使 TF 樹連通、最新變換正常,RViz 仍無法完成點雲時間戳對應的座標變換,表現為不顯示點雲。本次將 Fixed Frame 臨時改為點雲自身的 front_mid360 後出現點雲,驗證了這個方向;解決傳輸積壓後,就可以使用正常的顯示座標系。
1.2.2.解決方法
1. 工控機:建議保留非同步釋出。
在實際執行 ROS 的使用者的 ~/.bashrc 中加入。
export RMW_FASTRTPS_PUBLICATION_MODE=ASYNCHRONOUS
修改後執行:
source ~/.bashrc
然後在載入了該環境的終端中重新啟動 MID360 驅動,使新程序繼承設定。
非同步釋出將實際傳送交給後臺執行緒,可以減輕網路傳送對驅動釋出執行緒的直接影響;單獨設定它未能解決本次問題,仍需配合下面的電腦端配置。Fast DDS 在 ROS 2 Humble 中的釋出模式說明
2. 電腦端:通過 source 載入工程內的 dds_env.bash。
先查詢自己網路網絡卡:
ip -br -4 addr
看ip就能看出來,只有10.xx.xx.xx和192.168.xx.xx這種才是NAT4下發的ip。
所以這個wlp0s20f3才是你和ROS用於區域網通訊的網絡卡。

也可以點選WIFI按鈕確認一下ip,和上方說的一模一樣:

當前指令碼位於工程根目錄:
/ysu2026_rm_sentry_nav/dds_env.bash
現在初始化當前終端後即可正常使用 rviz2 和 ros2 命令。
這份配置應首先載入到電腦端,因為接收地址由電腦 DDS 公佈,接收緩衝也屬於電腦上的接收程序。工控機使用電腦公佈的地址傳送點雲;增大工控機的接收緩衝不能替代電腦端設定。
指令碼讀取所選介面當前的 IPv4,生成 XML,並匯出 FASTRTPS_DEFAULT_PROFILES_FILE。UDP 使用所選地址和本機迴環地址 127.0.0.1,同時保留本機 SHM 通訊。XML 儲存在工程根目錄,檔名為 .dds-env-<用户ID>-<配置摘要>.xml,已加入 Git 忽略規則。Fast DDS 介面白名單
以下命令在電腦的 ROS 終端執行。兩端 ROS_DOMAIN_ID 必須一致,本次為 6;網絡卡名 wlp0s20f3 應按實際介面修改:
source /opt/ros/humble/setup.bash
export ROS_DOMAIN_ID=6
export DDS_INTERFACE=wlp0s20f3
export DDS_RECV_BUFFER=4MiB
source /你的存放工程的路径/ysu2026_rm_sentry_nav/dds_env.bash
比如:source /home/tungchiahui/UserFolder/MySource/ysu2026_rm_sentry/ysu2026_rm_sentry_nav/dds_env.bash
兩個引數可以分別配置:
| 引數 | 用法 |
|---|---|
DDS_INTERFACE |
指定網絡卡名稱,支援逗號分隔的多個介面;未設定時自動選擇唯一處於 UP 狀態且有 IPv4 的物理網絡卡,多個候選時返回錯誤,要求明確選擇 |
DDS_RECV_BUFFER |
不設定或 0 表示系統預設;純整數表示位元組;支援 B、KB、MB、GB、KiB、MiB、GiB 單位,數值須為非負整數 |
4MiB 等於 4194304 位元組,4MB 等於 4000000 位元組。緩衝引數是指令碼定義的選項,最終會轉換為位元組寫入 Fast DDS XML。本次接收 MID360 點雲建議使用已驗證有效的 4MiB。請求值還受系統 net.core.rmem_max 上限約束,超出上限時指令碼會提示,但不會自動修改系統引數。
指令碼成功載入時不列印,出錯或系統上限不足時給出提示。它僅配置 Fast DDS,不改變 ROS_DOMAIN_ID、訊息 QoS 或當前 shell 的選項。
我電腦容器使用 host 網路,可以訪問宿主 Wi-Fi 介面。其他 Docker 網路模式應選擇容器實際可見且對端可達的介面;
介面白名單不能替代 bridge 網路所需的 NAT 或發現配置。跨容器使用 SHM 還取決於 IPC 配置。(一勞永逸,直接host即可)
3. 首次啟用或切換網路後,重建電腦端 daemon。
先關閉舊的 RViz 和遠端測頻程序,在已載入上述 DDS 配置的終端執行:
ros2 daemon stop
ros2 daemon start
daemon 本身也會建立 DDS Participant,應繼承相同的介面配置,避免保留原先的虛擬網絡卡地址。本次排查中,重建 daemon 是恢復正常通訊的一步;不必每次測頻都重啟它。
4. 直接開啟 RViz 和測頻。
在已載入配置的電腦終端中開啟 RViz:
rviz2
另一個終端也先載入第 2 步相同的 ROS 和 DDS 環境,再執行:
ros2 topic hz /livox/lidar/pointcloud --window 40
--window 40 只是縮短統計視窗,方便觀察近期變化;真正起作用的是網絡卡白名單和接收緩衝設定。
5. 日常使用:可加入電腦 ROS 使用者的 .bashrc。
將以下三行放在已有 ROS 環境載入語句之後。當前電腦容器使用 root,對應 /root/.bashrc:
export DDS_INTERFACE=wlp0s20f3
export DDS_RECV_BUFFER=4MiB
source /你的存放工程的路径/ysu2026_rm_sentry_nav/dds_env.bash
比如:source /home/tungchiahui/UserFolder/MySource/ysu2026_rm_sentry/ysu2026_rm_sentry_nav/dds_env.bash
這樣,新開啟並讀取 .bashrc 的終端會自動初始化 DDS。通過服務或非互動方式啟動的 ROS 程式,需要在其啟動環境中主動載入配置。指令碼位於個人工程中,載入現有 /opt/ros/humble/setup.bash 不會修改 ROS 安裝檔案。
切換 Wi-Fi、改變所選介面或接收緩衝後,應重新 source 指令碼,重建 daemon,並重新啟動相關 ROS 程式;已經執行的程序不會自動讀取新的環境變數或 XML。指令碼本身不會重啟這些程序。
1.2.3.本次驗證結果
完成介面限制、daemon 重建和 4 MiB 接收緩衝配置後的現場遠端實測結果如下:
| 測量位置 | 點雲頻率 | IMU 頻率 |
|---|---|---|
| 工控機本地 | 約 20 Hz | 約 200 Hz |
| 電腦端 | 約 20 Hz | 約 197~199 Hz |
放大緩衝後的測試節點接收緩衝丟包計數為零。開啟 RViz 後,工控機仍保持正常頻率,點雲持續顯示,延遲不再增長到幾十秒。這是本次測試期間的結果。
上表來自整理新指令碼之前的現場遠端測試。後續新增 dds_env.bash,在 ysu_ros_humble 中驗證了 XML 載入、接收緩衝生效、本機約 262 KB 點雲接收 20/20 幀,以及單位轉換、靜默載入和引數錯誤時保留原環境。新版指令碼的驗證範圍包含這些專案;上述遠端頻率仍引用此前現場實測。
配置整理在工程中新增了 DDS 環境指令碼和生成 XML 的 Git 忽略規則;本次排查未修改 MID360 驅動、SLAM 或控制節點的業務程式碼。
1.3.點雲和 TF 正常但二維地圖不更新
1.3.1.現象與排查入口
2026-10-20,工控機 ysu.local 在容器 ysu_rm_ros_humble 中進行實車建圖,啟動引數包含 slam:=True use_sim_time:=False。現場表現為點雲持續重新整理,odom 到底盤的 TF 和位姿輸出正常,但二維地圖沒有繼續生成。
當前二維建圖鏈路為:
Point-LIO → cloud_registered
→ loam_interface → registered_scan(odom系点云)
→ 地形分析 → terrain_map_ext
→ pointcloud_to_laserscan → obstacle_scan
→ slam_toolbox → /map
先檢查點雲有沒有變成二維掃描,再檢查掃描有沒有進入地圖。 點雲重新整理只說明三維處理鏈有輸出;ros2 node list 能看到轉換節點、ros2 topic list 能看到話題,也不代表該節點正在釋出有效資料。
以下檢查在工控機實際執行建圖的 ROS 容器內執行,先載入對應環境。工程路徑和 ROS_DOMAIN_ID 按現場修改,本次為:
source /opt/ros/humble/setup.bash
source /home/ysu/robomaster/ysu2026_rm_sentry/install/setup.bash
export ROS_DOMAIN_ID=6
# 分别观察二维转换的直接输入和输出,每项最多运行10秒。
timeout 10s ros2 topic hz /terrain_map_ext --window 40
timeout 10s ros2 topic hz /obstacle_scan --window 40
# 查看是否有发布端和订阅端;有连接仍需结合实际收帧判断。
ros2 topic info /obstacle_scan --verbose
上面的 timeout 到時結束屬於預期行為;在沒有訊息時,測頻命令可能一直沒有頻率輸出。本次已存在 slam_toolbox 訂閱,轉換節點仍然沒有輸出,不能解釋為“沒人訂閱,所以節點沒有接收點雲”。
1.3.2.現場證據
本次在工控機本地連續訂閱取樣 10 秒,結果如下:
| 話題 | 接收數量 | 說明 |
|---|---|---|
/cloud_registered |
199 | Point-LIO 點雲持續更新 |
/registered_scan |
197 | 轉到 odom 系的點雲持續更新 |
/terrain_map |
199 | 近場地形持續更新 |
/terrain_map_ext |
195 | 二維轉換的直接輸入持續更新,約20 Hz |
/odometry |
196 | 位姿輸出持續更新 |
/obstacle_scan |
0 | 二維轉換的輸出斷流 |
/map |
20 | 仍在釋出舊地圖,訊息時間約落後405秒 |
/terrain_map_ext 最後一幀有 2700 個點,其中 1204 個點滿足配置的 intensity=[0.1,2.0] 門檻。這裡的 intensity 是地形節點計算的相對地面高差,單位為 m。該結果說明輸入並非全部被這項門檻篩掉,但其他幾何條件仍需單獨檢查;本次確定死鎖依靠下面的執行緒和鎖證據。
slam_toolbox 的引數服務正常返回,use_sim_time=false,scan_topic=obstacle_scan;轉換節點的引數請求在取樣期間沒有返回。這與轉換節點的主執行執行緒被阻塞相符。
單獨看到 /map 的時間戳較舊,不能直接斷言死鎖:機器人靜止或新掃描未達到入圖門檻時,地圖內容也可能不變。本次同時確認了輸入持續更新、輸出完全斷流、引數請求不返回,以及兩個執行緒互相等待鎖。
1.3.3.原因:轉換節點內部的 TF 等待死鎖
現場安裝版本為:
ros-humble-tf2 0.25.23-1jammy.20260907.213559
ros-humble-tf2-ros 0.25.23-1jammy.20260907.224752
ros-humble-tf2-sensor-msgs 0.25.23-1jammy.20260907.225802
轉換節點使用 tf2_ros::MessageFilter,等待把 odom 系地形點雲轉換到 base_footprint 所需的 TF。這個版本的非同步等待路徑存在鎖順序反轉:點雲處理執行緒先持有一把鎖、再等另一把鎖,TF 接收執行緒按相反順序持鎖,可能形成永久的相互等待。Humble 上游修復說明
本次轉換節點容器 PID 為 2902,抓取執行緒堆疊後立即脫離。兩條關鍵呼叫鏈為:
主线程2902:
pthread_mutex_lock(0x5dad8dbf3840)
→ tf2::BufferCore::addTransformableRequest
→ tf2_ros::Buffer::waitForTransform
→ tf2_ros::MessageFilter<PointCloud2>::add
TF接收线程3006:
pthread_mutex_lock(0x5dad8dbf38f0)
→ tf2_ros::Buffer的transform-ready回调
→ tf2::BufferCore::testTransformableRequests
→ tf2::BufferCore::setTransformImpl
→ tf2_ros::TransformListener::subscription_callback
讀取兩把鎖的所有者,得到:
| 鎖地址 | 持有該鎖的執行緒 | 等待該鎖的執行緒 |
|---|---|---|
0x5dad8dbf3840 |
3006 | 2902 |
0x5dad8dbf38f0 |
2902 | 3006 |
執行緒2902和3006各持有對方需要的鎖,已經形成死鎖。這裡的執行緒編號和地址只描述本次現場,重新啟動後會變化。
外部 TF 正常與這個死鎖可以同時存在。 每個轉換程序有自己的 TF Buffer 和處理執行緒;本次卡住的是二維轉換程序內部的等待路徑,其他節點仍能接收 TF、處理點雲和輸出位姿。轉換節點程序保持存在,卻停止處理新點雲,slam_toolbox 收不到新的 obstacle_scan,於是只能繼續釋出舊地圖。相同版本與呼叫鏈的上游報告 #992
1.3.4.修復版本與時間
Humble 已有對應修復:
| 日期 | 上游進展 |
|---|---|
| 2026-09-10 | 修復鎖順序反轉的補丁合入 Humble 分支,見PR #990 |
| 2026-09-15 | tf2/tf2_ros 0.25.24 的版本記錄列出這項死鎖修復,見tf2版本記錄、tf2_ros版本記錄 |
2026-10-20 直接檢查工控機所配置的清華 ROS 軟體源線上索引,確認已有以下 amd64 包:
ros-humble-tf2 0.25.24-1jammy.20260915.203746
ros-humble-tf2-ros 0.25.24-1jammy.20260915.204410
但容器當時的 apt-cache policy 仍把 0.25.23 列為候選,本地 ROS 軟體源索引停在2026-10-02。因此需要先重新整理索引,再檢查候選版本;“上游有修復”“本地安裝了修復版”“執行中的程序已經載入修復版”是三個不同狀態。
1.3.5.處理方法
以下為修復操作步驟,本次診斷時尚未執行。
1. 在執行建圖的 ROS 容器內重新整理索引,核對候選版本。
以下以容器中的 root 使用者為例;普通使用者執行軟體包管理命令時需使用 sudo:
apt update
apt-cache policy ros-humble-tf2 ros-humble-tf2-ros
確認兩個包的 Candidate 均為 0.25.24 或包含該修復的後續 Humble 版本。如果仍為 0.25.23,先檢查索引重新整理是否成功及映象是否同步,再進行升級。
2. 結束本輪建圖,升級相關包並核對安裝結果。
apt install --only-upgrade ros-humble-tf2 ros-humble-tf2-ros
dpkg-query -W -f='${Package} ${Version}\n' ros-humble-tf2 ros-humble-tf2-ros
由包管理器處理依賴,檢查命令是否成功以及實際安裝版本。單獨重啟轉換節點有機會暫時恢復,但繼續使用 0.25.23 仍可能再次觸發死鎖。
3. 重新啟動建圖,檢查掃描與地圖恢復。
使用原來的實車建圖啟動方式重新執行,隨後檢查:
/terrain_map_ext持續輸入,/obstacle_scan恢復連續輸出,且掃描中存在有效距離值。- 轉換節點的引數請求能夠正常返回。
- 在滿足掃描入圖條件的實際移動後,
/map內容繼續更新。不要只憑靜止時地圖不變判斷修復失敗。
升級磁碟上的庫不會解除舊程序已經形成的死鎖,必須重啟使用舊庫的建圖程序。修改高度、強度、TF容差或RViz顯示引數,也無法解除這次已經形成的鎖等待環。
1.3.6.本次驗證狀態
已完成: 現場話題取樣、引數服務檢查、執行緒堆疊和鎖所有者核對;確認二維轉換節點死鎖;核實上游修復版本及當前配置映象中修復包可用。
待完成: 容器軟體包升級、建圖重啟,以及升級後二維掃描與地圖恢復的實車驗證。截至2026-10-20本次記錄,尚未執行這些修復操作,不能將上游修復結論寫成已經完成本機恢復驗證。