|
| 1 | +--- |
| 2 | +date: 2025-04-29 |
| 3 | +title: Building an iOS App for ROS 2 Integration |
| 4 | +--- |
| 5 | + |
| 6 | +This document provides a detailed, step-by-step guide on building an iOS application integrated with ROS 2 using the SwiftROS2 framework. In this guide, you will learn how to set up the project, configure ROS 2 nodes, implement publishers and subscribers to exchange messages via DDS, and build a SwiftUI-based user interface for operating ROS 2 functionality. In addition, this guide offers an in-depth explanation of the dependency packages and how the DDS mechanism is implemented to support ROS 2 communication. This guide assumes you have a basic understanding of Swift and iOS development. By the end, you will be able to create and run an iOS app that seamlessly interacts with ROS 2 nodes. |
| 7 | + |
| 8 | +The complete code can be found at <https://github.com/LiaoChiawen/ROS2iOSApp>. |
| 9 | + |
| 10 | +## Table of Contents |
| 11 | +- [Introduction](#introduction) |
| 12 | +- [Background and Key Concepts](#background-and-key-concepts) |
| 13 | +- [Step-by-Step Tutorial: Building an iOS App for ROS 2](#step-by-step-tutorial-building-an-ios-app-for-ros-2) |
| 14 | + - [1. Project Setup and Dependencies](#1-project-setup-and-dependencies) |
| 15 | + - [2. Creating the ROS 2 Node](#2-creating-the-ros-2-node) |
| 16 | + - [3. Implementing Publishers and Subscribers](#3-implementing-publishers-and-subscribers) |
| 17 | + - [4. Building the User Interface](#4-building-the-user-interface) |
| 18 | + - [5. Running and Testing the App](#5-running-and-testing-the-app) |
| 19 | +- [Detailed Explanation of Dependencies](#detailed-explanation-of-dependencies) |
| 20 | + - [swift-ros2](#swift-ros2) |
| 21 | + - [FastRTPSSwift](#fastrtpsswift) |
| 22 | + - [ros2msg](#ros2msg) |
| 23 | +- [Understanding the DDS Mechanism](#understanding-the-dds-mechanism) |
| 24 | +- [Usage Instructions](#usage-instructions) |
| 25 | +- [Summary](#summary) |
| 26 | +- [See Also](#see-also) |
| 27 | +- [Further Reading](#further-reading) |
| 28 | +- [References](#references) |
| 29 | + |
| 30 | +## Introduction |
| 31 | +This tutorial explains how to build an iOS app that leverages ROS 2 capabilities using the SwiftROS2 framework. In this guide you will learn to initialize a ROS 2 node, set up publishers and subscribers via a DDS-based system, and construct a simple user interface with SwiftUI to operate core functionalities including initialization, message publishing, and node shutdown. |
| 32 | + |
| 33 | +## Background and Key Concepts |
| 34 | +Before diving into the code, it is useful to understand these key concepts: |
| 35 | +- **ROS 2 (Robot Operating System 2):** A set of libraries and tools for building robot applications, which employs nodes, topics, and messaging to facilitate robust communication. |
| 36 | +- **DDS (Data Distribution Service):** A middleware protocol used in ROS 2 for real-time, scalable, and high-performance data exchange. It allows configuration of Quality of Service (QoS) parameters such as reliability and latency. |
| 37 | +- **Nodes:** The computational executables in ROS 2 that handle processing and communication. |
| 38 | +- **Publishers and Subscribers:** Mechanisms for sending (publishing) and receiving (subscribing) messages across nodes. |
| 39 | +- **SwiftROS2:** A simulated Swift library that provides interfaces to create ROS 2 nodes, publishers, and subscribers. |
| 40 | +- **iOS Development using SwiftUI:** SwiftUI is utilized for building modern, responsive user interfaces on iOS. |
| 41 | + |
| 42 | +## Step-by-Step Tutorial: Building an iOS App for ROS 2 |
| 43 | + |
| 44 | +### 1. Project Setup and Dependencies |
| 45 | +1. **Clone the Repository:** |
| 46 | + Begin by cloning the codebase. Your repository key directories are: |
| 47 | + - `/ROS2iOS`: Contains the main source code. |
| 48 | + - `/ROS2iOSAppTests`: Holds unit tests. |
| 49 | + - `/Preview Content`: Contains sample packages and resources. |
| 50 | + |
| 51 | +2. **Install Dependencies:** |
| 52 | + This project uses Swift Package Manager. Open your Xcode workspace (e.g. `ROS2iOS.xcodeproj`) and ensure the following packages are correctly resolved: |
| 53 | + - [swift-ros2](https://github.com/LiaoChiawen/swift-ros2) |
| 54 | + - [FastRTPSSwift](https://github.com/kabirkedia/FastRTPSSwift) |
| 55 | + - [ros2msg](https://github.com/LiaoChiawen/ros2msg) |
| 56 | + |
| 57 | + Verify that your `Package.resolved` file lists the correct versions. |
| 58 | + |
| 59 | +3. **Configure Xcode:** |
| 60 | + In Xcode, set the deployment target to iOS 17.0 and ensure proper code signing configurations. |
| 61 | + |
| 62 | +### 2. Creating the ROS 2 Node |
| 63 | +The heart of the app is the ROS 2 node. The `CentralNode` class encapsulates ROS 2 functionalities including initialization and resource management. |
| 64 | + |
| 65 | +- **Initialization:** |
| 66 | + In `ContentView.swift`, the `initialize()` function performs the following: |
| 67 | + - Retrieves the device IP using `getWiFiIPv4Address()`. |
| 68 | + - Creates a new `CentralNode` instance with a domain ID and IP address. |
| 69 | + - Calls asynchronous initialization on the node and associated publishers. |
| 70 | + |
| 71 | +```swift |
| 72 | +// Example snippet from ContentView.swift: |
| 73 | +func initialize(){ |
| 74 | + Task { |
| 75 | + configViewIP = getWiFiIPv4Address() ?? "127.0.0.1" |
| 76 | + observableCentralNode.centralNode = CentralNode( |
| 77 | + domainID: 0, |
| 78 | + ipAddress: configViewIP |
| 79 | + ) |
| 80 | + |
| 81 | + guard let cn = observableCentralNode.centralNode else { |
| 82 | + logger.error("Central Node is not ready/available. Cannot initialize.") |
| 83 | + return |
| 84 | + } |
| 85 | + await cn.initialize() |
| 86 | + await publisherModel.initialize(centralNode: cn) |
| 87 | + } |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +### 3. Implementing Publishers |
| 92 | +Communication between nodes is achieved by creating both publishers and subscribers. |
| 93 | + |
| 94 | +- **Publishing:** |
| 95 | + The `PublisherModel.swift` file demonstrates setting up a publisher. |
| 96 | + |
| 97 | +```swift |
| 98 | +// Excerpt from PublisherModel.swift: |
| 99 | +public func sendString() { |
| 100 | + guard let publisher = self.publisher else { |
| 101 | + logger.error("Publisher is not initialized.") |
| 102 | + return |
| 103 | + } |
| 104 | + |
| 105 | + let ros2str = ROS2String() |
| 106 | + ros2str.data = "Hello World!" |
| 107 | + |
| 108 | + let ddsMsg = DDSString(val: ros2str) |
| 109 | + |
| 110 | + Task { |
| 111 | + await publisher.publish(ddsMsg) |
| 112 | + logger.info("Published \(ros2str.data)") |
| 113 | + } |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | + |
| 118 | +### 4. Building the User Interface |
| 119 | +The UI is built using SwiftUI and consists of three main buttons: |
| 120 | +- **Initialize:** Sets up the ROS 2 node and publishers. |
| 121 | +- **Publish Message:** Sends a test message. |
| 122 | +- **Destroy Node:** Tears down the node and cleans up. |
| 123 | + |
| 124 | +```swift |
| 125 | +// Example snippet from ContentView.swift: |
| 126 | +var body: some View { |
| 127 | + VStack(spacing: 20) { |
| 128 | + Button("Initialize") { |
| 129 | + initialize() |
| 130 | + } |
| 131 | + .font(.headline) |
| 132 | + .frame(width: 140, height: 44) |
| 133 | + .padding() |
| 134 | + .background(Color.orange) |
| 135 | + .foregroundColor(.white) |
| 136 | + .cornerRadius(8) |
| 137 | + |
| 138 | + Button("Publish Message") { |
| 139 | + publisherModel.sendString() |
| 140 | + } |
| 141 | + .font(.headline) |
| 142 | + .frame(width: 140, height: 44) |
| 143 | + .padding() |
| 144 | + .background(Color.blue) |
| 145 | + .foregroundColor(.white) |
| 146 | + .cornerRadius(8) |
| 147 | + |
| 148 | + Button("Destroy Node") { |
| 149 | + destroyNode() |
| 150 | + } |
| 151 | + .font(.headline) |
| 152 | + .frame(width: 140, height: 44) |
| 153 | + .padding() |
| 154 | + .background(Color.red) |
| 155 | + .foregroundColor(.white) |
| 156 | + .cornerRadius(8) |
| 157 | + } |
| 158 | + .padding() |
| 159 | +} |
| 160 | +``` |
| 161 | + |
| 162 | +### 5. Running and Testing the App |
| 163 | +- **Build the Project:** |
| 164 | + Use Xcode to build the project ensuring that all dependencies are properly integrated. |
| 165 | +- **Run on Simulator or Device:** |
| 166 | + Launch the app on an iOS device or Simulator. Use the buttons to initialize the ROS 2 node, publish a message, and destroy the node. |
| 167 | +- **Testing:** |
| 168 | + Verify the functionality by checking Xcode console logs and running unit tests located in `/ROS2iOSAppTests`. |
| 169 | + |
| 170 | +## Detailed Explanation of Dependencies |
| 171 | + |
| 172 | +### swift-ros2 |
| 173 | +- **Purpose:** |
| 174 | + Provides a high-level Swift interface to interact with ROS 2, allowing creation of nodes, publishers, and subscribers. |
| 175 | +- **Usage:** |
| 176 | + Classes such as `CentralNode` use this package to encapsulate ROS 2 operations and expose easy-to-use methods to initialize nodes and create communication channels. |
| 177 | +- **Implementation:** |
| 178 | + Utilizes Swift’s async/await for asynchronous operations and error-handling mechanisms for reliable integration with ROS 2 middleware. |
| 179 | + |
| 180 | +### FastRTPSSwift |
| 181 | +- **Purpose:** |
| 182 | + Bridges ROS 2 DDS functionalities by leveraging the Fast RTPS (Real-Time Publish-Subscribe) protocol. |
| 183 | +- **Usage:** |
| 184 | + Manages low-level DDS operations such as registering writers (publishers) and readers (subscribers) and handles QoS settings (e.g., reliability, durability). |
| 185 | +- **Implementation:** |
| 186 | + Wraps the native C/C++ Fast RTPS libraries into Swift-friendly APIs, abstracting the complexity involved in direct DDS communications. |
| 187 | + |
| 188 | +### ros2msg |
| 189 | +- **Purpose:** |
| 190 | + Defines message types and data structures used in ROS 2 communications. |
| 191 | +- **Usage:** |
| 192 | + Provides message models like `ROS2String` to package data and ensure proper serialization and deserialization using Swift’s Codable protocol. |
| 193 | +- **Implementation:** |
| 194 | + Structures messages in a way that aligns with ROS 2 standards, facilitating seamless interaction between different nodes and platforms. |
| 195 | + |
| 196 | +## Understanding the DDS Mechanism |
| 197 | +DDS (Data Distribution Service) underpins the efficient and reliable exchange of data between ROS 2 nodes. Key points include: |
| 198 | +- **DDS Communication Model:** |
| 199 | + Uses a publish/subscribe model where publishers send messages to topics and subscribers receive them based on topic subscriptions. |
| 200 | +- **Quality of Service (QoS):** |
| 201 | + DDS allows customization of parameters (e.g., reliability, durability, latency) ensuring high-performance communication even in real-time applications. |
| 202 | +- **Fast RTPS Integration:** |
| 203 | + The FastRTPSSwift package bridges the Fast RTPS library with SwiftROS2, managing: |
| 204 | + - **Participant Creation:** The ROS 2 node (CentralNode) acts as a participant joining a DDS domain. |
| 205 | + - **Writer and Reader Registration:** Publishers (writers) and subscribers (readers) are registered with the DDS participant. |
| 206 | + - **Message Routing:** DDS middleware routes messages efficiently between registered writers and readers, applying QoS policies. |
| 207 | +- **Abstraction in SwiftROS2:** |
| 208 | + SwiftROS2 simplifies these complex operations into easy-to-use Swift classes and methods, allowing developers to focus on application logic rather than low-level protocol details. |
| 209 | + |
| 210 | +## Usage Instructions |
| 211 | +1. **Clone and Open the Project:** |
| 212 | + Clone the repository and open `ROS2iOS.xcodeproj` with Xcode. |
| 213 | +2. **Resolve Dependencies:** |
| 214 | + Ensure that the Swift packages (swift-ros2, FastRTPSSwift, ros2msg) are downloaded and configured. |
| 215 | +3. **Build and Run:** |
| 216 | + Build the project and run the app on the desired iOS simulator or device. |
| 217 | +4. **Interact with the App:** |
| 218 | + - Tap **Initialize** to set up the ROS 2 node. |
| 219 | + - Tap **Publish Message** to send a test ROS 2 message. |
| 220 | + - Tap **Destroy Node** to gracefully shut down the ROS 2 node. |
| 221 | +5. **Review Logs:** |
| 222 | + Monitor the Xcode console for log messages confirming successful node initialization, message publishing, and node destruction. |
| 223 | + |
| 224 | +## Summary |
| 225 | +This guide provided a comprehensive walkthrough for building an iOS app integrated with ROS 2: |
| 226 | +- Project setup, dependency resolution, and Xcode configuration. |
| 227 | +- Initializing a ROS 2 node with `CentralNode` and configuring communication via DDS. |
| 228 | +- Implementing publishers and subscribers to exchange messages. |
| 229 | +- Designing a user interface with SwiftUI and testing the functionality. |
| 230 | +- Detailed insights into the core dependency packages and DDS integration research. |
| 231 | + |
| 232 | +## See Also |
| 233 | +- [ROS 2 Official Documentation](https://docs.ros.org/) |
| 234 | +- [Fast RTPS Documentation](https://fast-dds.docs.eprosima.com/en/latest/) |
| 235 | +- [Swift Package Manager Documentation](https://swift.org/package-manager/) |
| 236 | +- [SwiftUI Tutorials](https://developer.apple.com/tutorials/swiftui) |
| 237 | + |
| 238 | +## Further Reading |
| 239 | +- Advanced DDS configuration and Quality of Service (QoS) settings. |
| 240 | +- Detailed tutorials on integrating C/C++ libraries with Swift. |
| 241 | +- Comprehensive studies of ROS 2 communication patterns and best practices. |
| 242 | + |
| 243 | +## References |
| 244 | +1. Y. Hu, "swift-ros2 – ROS2-like node that supports subscription and publication of DDS messages in ROS2 message format," GitHub Repository, <https://github.com/strapsai/swift-ros2>. |
| 245 | +2. ROS Documentation, "Getting Started with ROS 2," available at <https://docs.ros.org/>. |
| 246 | +3. Fast RTPS Documentation, available at <https://fast-dds.docs.eprosima.com/en/latest/>. |
| 247 | +4. Apple Developer Documentation, "SwiftUI," available at <https://developer.apple.com/documentation/swiftui>. |
0 commit comments