├── LICENSE
├── DDS_Optimizer.py
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 DGIST CSI LAB
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/DDS_Optimizer.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import sys
3 | import math
4 |
5 | def parse_args(args):
6 | """Parse command line arguments"""
7 | params = {}
8 | for arg in args:
9 | if '=' in arg:
10 | key, val = arg.split('=')
11 | params[key.strip()] = float(val.strip())
12 | return params
13 |
14 | def compute_parameters(params):
15 | """Compute QoS parameters"""
16 | r = params.get("r", 10)
17 | u = params.get("u", 100000)
18 | T = params.get("T", 1e8)
19 | w = params.get("w", 0.5)
20 |
21 | retrans_ns = int(1e9 / (2 * r))
22 | history_cache = math.floor(T / u)
23 |
24 | return {
25 | "r": int(r),
26 | "u": int(u),
27 | "T": int(T),
28 | "w": w,
29 | "retrans_ns": retrans_ns,
30 | "history_cache": history_cache
31 | }
32 |
33 | def generate_publisher_xml(params, output_file):
34 | """Generate Publisher XML"""
35 | xml_content = f"""
36 |
37 |
38 |
39 |
40 | udp_transport
41 | UDPv4
42 | 1472
43 |
44 |
45 |
46 |
47 |
48 | udp_transport
49 |
50 | false
51 |
52 |
53 |
54 |
55 |
56 | KEEP_ALL
57 |
58 |
59 | {params['history_cache']}
60 | 10
61 | {params['history_cache']}
62 |
63 |
64 |
65 | true
66 |
67 | RELIABLE
68 |
69 | 1000
70 |
71 |
72 |
73 |
74 |
75 | 0
76 |
77 |
78 | 0
79 | {params['retrans_ns']}
80 |
81 |
82 | 0
83 |
84 |
85 | 0
86 |
87 |
88 |
89 |
90 |
91 | """
92 | with open(output_file, "w") as f:
93 | f.write(xml_content)
94 | print(f"[INFO] Publisher XML: {output_file}")
95 |
96 | def generate_subscriber_xml(params, output_file):
97 | """Generate Subscriber XML"""
98 | xml_content = f"""
99 |
100 |
101 |
102 |
103 | udp_transport
104 | UDPv4
105 | 1472
106 |
107 |
108 |
109 |
110 |
111 | udp_transport
112 |
113 | false
114 |
115 |
116 |
117 |
118 |
119 | {params['history_cache']}
120 | 10
121 | {params['history_cache']}
122 |
123 |
124 |
125 |
126 | AUTOMATIC
127 |
128 | DURATION_INFINITY
129 |
130 |
131 | DURATION_INFINITY
132 |
133 |
134 |
135 |
136 |
137 | 0
138 | 0
139 |
140 |
141 | 0
142 | 0
143 |
144 |
145 |
146 |
147 |
148 | """
149 | with open(output_file, "w") as f:
150 | f.write(xml_content)
151 | print(f"[INFO] Subscriber XML: {output_file}")
152 |
153 | def main():
154 | required_keys = {"r", "u", "T", "w"}
155 |
156 | if len(sys.argv) < 2:
157 | print("Usage: python3 DDS_Optimizer.py r=30 u=330000 T=90000000 w=0.6")
158 | sys.exit(1)
159 |
160 | args = parse_args(sys.argv[1:])
161 | if not required_keys.issubset(args.keys()):
162 | print("Usage: python3 DDS_Optimizer.py r=30 u=330000 T=90000000 w=0.6")
163 | sys.exit(1)
164 |
165 | qos = compute_parameters(args)
166 | pub_filename = "Optimized_profile_pub.xml"
167 | sub_filename = "Optimized_profile_sub.xml"
168 |
169 | generate_publisher_xml(qos, pub_filename)
170 | generate_subscriber_xml(qos, sub_filename)
171 |
172 | print(f"[INFO] HistoryCache_size = {qos['history_cache']} | Retransmission_ns = {qos['retrans_ns']}")
173 |
174 | if __name__ == "__main__":
175 | main()
176 |
177 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DDS Optimizer for Wirelss Large Payload Transfer
2 |
3 |
4 |
5 |
6 |
7 |
8 | ## 📝 Paper Summary
9 | ROS 2 uses a DDS-based communication stack, but suffers from severe performance degradation when transmitting large payloads over wireless networks. The key root causes are identified as IP fragmentation, inefficient retransmission timing, and buffer bursts. To address these issues, the paper proposes a lightweight optimization framework that leverages only XML-based QoS configuration without modifying the DDS protocol. The optimization consists of: (i) setting the RTPS message size to 1472 B, (ii) configuring the retransmission rate as *n* = *2r*, and (iii) adjusting the HistoryCache size based on payload size *u* and link bandwidth. All improvements are fully compatible with existing ROS 2 applications and require no changes to application logic or middleware internals. Experiments were conducted on ROS 2 Humble using Fast DDS 2.6.9 version over IEEE 802.11ac wireless links. Test scenarios included different packet error rates (1%, 20%), temporary link outages, and varying payload sizes (32–512 KB). Default DDS and LARGE_DATA mode failed to maintain performance under high loss, while the proposed optimization remained stable up to 512 KB. The effectiveness of HistoryCache tuning was particularly evident in link outage recovery scenarios. Overall, this work demonstrates that practical, protocol-compliant DDS tuning enables robust and real-time wireless communication in ROS 2.
10 |
11 | ## Essential QoS Settings for Topic Communication
12 | | QoS Policy| QoS Value | Function |
13 | |------|---------|---------|
14 | | **history** | **KEEP_ALL** | To store all data without loss |
15 | | **reliability** | **RELIABLE** | To ensure that every message sample is delivered without loss |
16 | | **reliability.max_blocking_time** | **A sufficiently large value** | To prevent publisher blocking or data loss |
17 |
18 | ## About DDS Optimizer
19 | Our forthcoming paper introduces an optimizer for configuring parameters to efficiently transmit large payloads.
20 |
21 | > **Input**: Publish rate *r*, payload size *u*, link-layer throughput *T*OS→Link, link utilization 𝜔
22 | > **Step 1**: **Prevents IP fragmentation** Set RTPS maxMessageSize = 1472 B
23 | > **Step 2**: **Minimize Retransmission Jitter** Set retransmission rate *n* = *2r*
24 | > **Step 3**: **Prevent Buffer Burst** Set HistoryCache size as
25 | > **Output**: Optimized ROS 2 XML QoS profile
26 |
27 | ### XML Configuration Details
28 |
29 | Each optimization step is implemented through specific XML configurations:
30 |
31 | **Step 1: Prevents IP fragmentation**
32 |
33 | > **XML Configuration:**
34 | > ```xml
35 | >
36 | > udp_transport
37 | > UDPv4
38 | > 1472
39 | >
40 | > ```
41 |
42 | This setting limits the RTPS message size to 1472 bytes to prevent IP fragmentation over wireless networks.
43 |
44 | **Step 2: Minimize Retransmission Jitter**
45 |
46 | > **XML Configuration:**
47 | > ```xml
48 | >
49 | > 0
50 | > [Optimized Value]
51 | >
52 | > ```
53 |
54 | The heartbeat rate is optimized to `n = 2r` where `r` is the publish rate, reducing retransmission jitter and improving control traffic efficiency.
55 |
56 | **Step 3: Prevent Buffer Burst**
57 |
58 | > **XML Configuration:**
59 | > ```xml
60 | >
61 | > [Optimized Value]
62 | > 10
63 | > [Optimized Value]
64 | >
65 | > ```
66 |
67 | The HistoryCache size is calculated as `⌊T × ω / u⌋` where:
68 | - `T` is the link-layer throughput
69 | - `ω` is the link utilization (default: 0.6-0.7, reduce for congested links)
70 | - `u` is the payload size
71 |
72 | This prevents buffer overflow and ensures stable data transmission by considering actual available bandwidth.
73 |
74 |
75 | ## 💡 How to run it from the terminal
76 |
77 | ### Step-by-Step Guide
78 |
79 | #### 1. Navigate to your ROS 2 package directory
80 | ```bash
81 | # Example: Navigate to ROS 2 package on Ubuntu
82 | cd ~/ros2_ws/src/your_package_name
83 | ```
84 |
85 | #### 2. Verify that your code satisfies the Essential QoS Settings
86 |
87 | **Python version (rclpy):**
88 | ```python
89 | qos = QoSProfile(
90 | history=HistoryPolicy.KEEP_ALL,
91 | reliability=ReliabilityPolicy.RELIABLE
92 | )
93 | # Publisher
94 | publisher = node.create_publisher(String, 'topic_name', qos)
95 |
96 | # Subscriber
97 | subscriber = node.create_subscription(String, 'topic_name', callback, qos)
98 | ```
99 |
100 | **C++ version (rclcpp):**
101 | ```cpp
102 | auto qos = rclcpp::QoS(10)
103 | .keep_all()
104 | .reliable();
105 |
106 | // Publisher
107 | auto publisher = node->create_publisher("topic_name", qos);
108 |
109 | // Subscriber
110 | auto subscriber = node->create_subscription(
111 | "topic_name", qos, callback);
112 | ```
113 |
114 | #### 3. Clone DDS Optimizer and navigate to the optimizer directory
115 | ```bash
116 | git clone https://github.com/anonymous-ld/large-data-optimization.git
117 | cd large-data-optimization
118 | ```
119 |
120 | #### 4. Run DDS_Optimizer.py
121 | ```bash
122 | # Basic usage
123 | python3 DDS_Optimizer.py r={publish rate} u={payload size} T={link-layer throughput} w={link utilization}
124 |
125 | # Example: [publish rate = 30 Hz], [payload size = 330 KB], [link-layer throughput = 90 Mb/s], [link utilization = 0.6]
126 | python3 DDS_Optimizer.py r=30 u=330000 T=90000000 w=0.6
127 | ```
128 |
129 | **Output example:**
130 | ```
131 | [INFO] Publisher XML: Optimized_profile_pub.xml
132 | [INFO] Subscriber XML: Optimized_profile_sub.xml
133 | [INFO] HistoryCache_size = 309 | Retransmission_ns = 16666666
134 | ```
135 |
136 | #### 5. Apply the generated XML to your pub and sub
137 |
138 | **5-1. Set as default XML using environment variables (Recommended)**
139 | ```bash
140 | # Linux/macOS
141 | export FASTRTPS_DEFAULT_PROFILES_FILE=/path/to/generated_pub.xml
142 | ```
143 |
144 | **5-2. Set the generated XML as default XML in your code**
145 | ```python
146 | # Set environment variable in Python
147 | import os
148 | os.environ['FASTRTPS_DEFAULT_PROFILES_FILE'] = '/path/to/generated_pub.xml'
149 | ```
150 |
151 | ```cpp
152 | // Set environment variable in C++
153 | #include
154 | setenv("FASTRTPS_DEFAULT_PROFILES_FILE", "/path/to/generated_pub.xml", 1);
155 | ```
156 |
157 | ## Performance Comparision
158 |
159 |

160 |
161 |
162 |
163 | ## 📢 Notice
164 | This project is currently compatible with ROS 2 Humble using Fast DDS 2.6.9.
165 | Support for other DDS vendors such as Cyclone DDS and OpenDDS is planned in future updates.
166 |
167 | ### Contact & Collaboration
168 | If you have any issues or questions about using this tool, please feel free to contact us anytime.
169 |
170 | **Email**: [leesh2913@dgist.ac.kr](mailto:leesh2913@dgist.ac.kr)
171 | **Homepage**: [hun0130.github.io](https://hun0130.github.io/)
172 |
173 | Research collaborations and industry-academia partnerships are also welcome!
174 |
175 |
--------------------------------------------------------------------------------