警告

您正在閱讀已達到生命週期結束(end-of-life,EOL)版本的 ROS 2 文件,該版本不再正式受支援。如果您想獲取最新資訊,請參見 Lyrical

DDS 調校資訊

本頁面提供一些參數調校的指引,這些調校是針對在實際情況中於 Linux 上使用各種 DDS 實作時所遇到的問題。我們在 Linux 上或使用某個供應商時發現的問題,也可能發生在其他未在此記錄的平台和供應商上。

以下建議是調校的起點;它們在特定系統和環境中有效,但調校可能因多種因素而異。在除錯時,您可能需要根據訊息大小、網路拓撲等因素來增加或減少數值。

重要的是要認識到,調校參數可能會消耗資源,並可能影響系統中超出預期改進範圍的部分。對於每個案例,應權衡提升可靠性的好處與其帶來的任何不利影響。

跨供應商調校

問題: 透過有損(通常是 WiFi)連線傳送資料時,若某些 IP 片段被丟棄,可能會導致接收端的內核緩衝區被填滿。

當一個 UDP 封包缺少至少一個 IP 片段時,其餘已接收的片段會填滿內核緩衝區。預設情況下,Linux 內核在嘗試重組封包片段 30 秒後會逾時。由於此時內核緩衝區已滿(預設大小為 256KB),無法再接收新的片段,因此連線會看似「掛起」很長一段時間。

此問題在所有 DDS 供應商中普遍存在,因此解決方案涉及調整內核參數。

解決方案: 使用盡力而為(best-effort)的 QoS 設定,而非可靠(reliable)模式。

盡力而為設定可減少網路流量,因為 DDS 實作不需要承擔可靠通訊的額外負擔——在可靠模式下,發布者需要針對發送給訂閱者的訊息獲取確認,且必須重新發送未被正確接收的樣本。

不過,如果 IP 片段的內核緩衝區已滿,症狀仍然相同(阻塞 30 秒)。此解決方案應能在無需調整參數的情況下某種程度地改善問題。

解決方案: 降低 ipfrag_time 參數的值。

``net.ipv4.ipfrag_time / /proc/sys/net/ipv4/ipfrag_time``(預設 30 秒):在記憶體中保留 IP 片段的時間(秒)。

透過執行以下指令將值降低,例如降至 3 秒:

sudo sysctl net.ipv4.ipfrag_time=3

Reducing this parameter’s value also reduces the window of time where no fragments are received. The parameter is global for all incoming fragments, so the feasibility of reducing its value needs to be considered for every environment.

解決方案: 提高 ipfrag_high_thresh 參數的值。

``net.ipv4.ipfrag_high_thresh / /proc/sys/net/ipv4/ipfrag_high_thresh``(預設:262144 位元組):用於重組 IP 片段的最大記憶體。

透過執行以下指令提高值,例如提高到 128MB:

sudo sysctl net.ipv4.ipfrag_high_thresh=134217728     # (128 MB)

Significantly increasing this parameter’s value is an attempt to ensure that the buffer never becomes completely full. However, the value would likely have to be significantly high to hold all data received during the time window of ipfrag_time, assuming every UDP packet lacks one fragment.

議題: 發送包含大型可變大小陣列的非原始類型自訂訊息會導致高序列化/反序列化開銷和 CPU 負載。這可能導致發布者因在 publish() 中花費過多時間而停滯,並且像 ros2 topic hz 這樣的工具會低估接收到的訊息實際頻率。請注意,例如 builtin_interfaces/Time 也被視為非原始類型,會產生較高的序列化開銷。由於序列化開銷增加,在從 ROS 1 單純地轉移自訂訊息類型到 ROS 2 時,可能會觀察到嚴重的效能下降。

解決方法: 使用多個原始類型陣列,而非單一自訂類型陣列;或者像 PointCloud2 訊息那樣打包成位元組陣列。例如,不要將 FooArray 訊息定義為:

Foo[] my_large_array

其中 Foo 定義為:

uint64 foo_1
uint32 foo_2

而是將 FooArray 定義為:

uint64[] foo_1_array
uint32[] foo_2_array

Fast RTPS 調校

問題: Fast RTPS 在透過 WiFi 運作時,會以大量資料或快速發布的資料淹沒網路。

請參閱 跨供應商調校 下的解決方案。

Cyclone DDS 調校

問題: Cyclone DDS 即使使用可靠設定並透過有線網路傳輸,仍無法可靠地傳遞大型訊息。

This issue should be addressed soon. Until then, we’ve come up with the following solution (debugged using this test program):

解決方案: 增加 Linux 內核的最大接收緩衝區大小和 Cyclone 使用的最小 socket 接收緩衝區大小。

解決 9MB 訊息的調整:

透過執行以下指令設定最大接收緩衝區大小 rmem_max

sudo sysctl -w net.core.rmem_max=2147483647

或者透過編輯 /etc/sysctl.d/10-cyclone-max.conf 檔案將其永久設定為包含以下內容:

net.core.rmem_max=2147483647

接下來,若要設定 Cyclone 請求的最小 socket 接收緩衝區大小,請編寫一個供 Cyclone 在啟動時使用的組態檔,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://cdds.io/config
https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd">
    <Domain id="any">
        <Internal>
            <MinimumSocketReceiveBufferSize>10MB</MinimumSocketReceiveBufferSize>
        </Internal>
    </Domain>
</CycloneDDS>

然後,每當您要執行節點時,請設定以下環境變數:

CYCLONEDDS_URI=file:///absolute/path/to/config_file.xml

RTI Connext 調校

問題: Connext 即使使用可靠設定並透過有線網路傳輸,仍無法可靠地傳遞大型訊息。

解決方案: 使用此 Connext QoS 設定檔,並提高 rmem_max 參數。

透過執行以下指令設定最大接收緩衝區大小 rmem_max

sudo sysctl -w net.core.rmem_max=4194304

透過將 Linux 內核中的 net.core.rmem_max 調校至 4MB,QoS 設定檔可實現真正可靠的行為。

此組態已證明可透過 SHMEM|UDPv4 以及在單台機器上僅使用 UDPv4 可靠地傳遞訊息。也在多機器組態下進行了測試,rmem_max 設為 4MB 和 20MB(兩台機器透過 1Gbps 乙太網路連接),結果沒有訊息丟失,平均訊息傳遞時間分別為 700 毫秒和 371 毫秒。

Without configuring the kernel’s rmem_max, the same Connext QoS profile took up to 12 seconds for the data to be delivered. However, it always at least managed to complete the delivery.

解決方案: 使用 Connext QoS 設定檔*無需*調整 rmem_max

The ROS2TEST_QOS_PROFILES.xml file was configured using RTI’s documentation on configuring flow controllers. It has slow, medium and fast flow controllers (seen in the Connext QoS profile link).

中速流量控制器在我們的情況下產生了最佳結果。然而,控制器仍需要根據其運行的特定機器/網路/環境進行調校。Connext 流量控制器可用於調整頻寬及其發送資料的積極程度,但一旦超過特定設定的頻寬,效能就會開始下降。