ROS TCP
ROS2 is often seen as the robot’s brain, while Unity serves as the eyes and environment. To simulate realistic robotics behavior, we need a bridge between them. That bridge is the ROS-TCP Endpoint/Connector. By connecting both, we can test navigation, visualization, and SLAM in a controlled environment before deploying to real hardware.
Understanding the Basics
ROS TCP Endpoint/Connector

- Def: A ROS node that enables message passing over TCP between ROS2 and external systems like Unity
- Purpose: : Facilitates real-time communication for robotics simulations and visualizations
- Example: A ROS node sends robot position data to Unity, which renders the robot in a 3D environment
ROS-Unity Communication

Image Source: MDPI
- Def: The broader process of how ROS 2 and Unity interact, using the TCP Endpoint/Connector to exchange data via topics, services, or actions.
- Example: Unity subscribes to a ROS topic (/robot_color) to change a robot’s color, or ROS responds to a Unity service request with a robot’s pose.
SLAM (Simultaneous Localization & Mapping)

Image Source: LASER_Scanning and KODIFLY
- Def: A method for robots to build a map of an unknown environment while tracking their location within it.
- Applications: Autonomous navigation, 3D map reconstruction, obstacle avoidance.
- Example: A robot uses LIDAR to create a 2D occupancy grid in RViz, visualized in Unity.
Materials
-
Github
-
ROS (I used Ubuntu 22.04 with ROS2 Humble)
-
Unity v.2020.2+
-
Visual Studio (for C#)
-
RViz (for visualization in ROS)
Tutorial
Since I used ROS2, this tutorial is written based on ROS2 (especially ROS2 Humble).
Setup
ROS

- Download ROS TCP Endpoint
- In your src folder of ROS TCP Endpoint, navigate to your Colcon worspace and run the following commands:
source install/setup.bashcolcon buildsource install/setup.bash- In your Colcon workspace, run the following command, replacing
<your IP address>with your ROS machine’s IP or hostname.
ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=192.168.0.5- If you’re running ROS in a Docker container, 0.0.0.0 is a valid incoming address, so you can write
ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=0.0.0.0 - On Linux you can find out your IP address with the command
hostname -I - On MacOS you can find out your IP address with
ipconfig getifaddr en0
Once the server_endpoint has started, it will print something similar to [INFO] [1603488341.950794]: Starting server on 192.168.50.149:10000.
(Alternative) If you need the server to listen on a port that’s different from the default 10000, here’s the command line to also set the ROS_TCP_PORT parameter:
ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=127.0.0.1 -p ROS_TCP_PORT:=10000Unity
- Open the Package Manager (
Window > Package Manager) - Click the + button in the upper lefthand corner of the window. Select Add
package from git URL... - Enter the git URL for the package.
- For the ROS-TCP-Connector, enter
https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.ros-tcp-connector.
- (not necessary)For Visualizations, enter
https://github.com/Unity-Technologies/ROS-TCP-Connector.git?path=/com.unity.robotics.visualizations.
- Click
Add. - open Robotics/ROS Settings from the Unity menu bar, and set the ROS IP Address variable to the IP you set earlier. (If you’re using Docker, leave it as the default 127.0.0.1.)
- in the ROS Settings window, ROS2 users should switch the protocol to ROS2 now.
ROS Unity Integration
Publisher
Unity publishes data (e.g., robot position coordinates) to a ROS 2 topic, which a ROS subscriber receives.
Concept: Unity can act as a Publisher, sending data continuously to a ROS topic. Typical Use Case: Streaming an object’s position, velocity, or any sensor-like data from Unity to ROS. Unity Side: You use the ROSConnection component to define the topic and message type, then call Publish() inside a Unity script. ROS Side: A ROS node subscribes to the same topic to consume Unity’s data.
Subscriber
ROS2 publishes a topic to change the color, and Unity subscribes to that topic to update it.
Concept: Unity can also subscribe to ROS topics and react when messages arrive.
Typical Use Case: ROS publishes sensor data or control commands, and Unity updates its simulation accordingly (e.g., changing color, triggering animations).
Unity Side: In Unity, you register a callback for a topic using Subscribe
Service

Unity (Service Client) request an object’s pose in Unity. ROS (Service Server) calculates its pose and responds to Unity.
Concept: Unlike Publishers/Subscribers, a Service works as a request–response pattern. Typical Use Case: When Unity needs a precise answer at a specific moment. Unity as Service Client: Unity sends a request, e.g., “What’s the pose of this object?” ROS as Service Server: ROS computes the answer and returns it.
Service Call
1. Start at current position 2. Move toward destination 3. Near target → Request update from ROS 4. Get new destination 5. RepeatConcept: A Service Call can be repeated in sequence to drive a process step by step. Typical Use Case: Unity moves an object toward a goal. Once near the target, Unity requests a new goal from ROS, receives it, and continues.
Note: While Publisher and Subscriber cover most real-time data flows, Services shine when you need precise, one-off information. The Service Call tutorial illustrates how even a simple request–response can orchestrate dynamic behavior when chained together.
In practice, you’ll often combine these: Publishers for streaming state, Subscribers for reacting to commands, and Services for exact queries. The key is to choose the right communication model for the task at hand.
Robotics Nav2 SLAM Example
Running
- Clone the Nav2 SLAM Example and run:
git clone https://github.com/Unity-Technologies/Robotics-Nav2-SLAM-Example.gitcd Robotics-Nav2-SLAM-Example/ros2_docker/colcon_ws➡️ Expected Output: A 2D occupancy grid in RViz showing the robot’s map, with real-time updates as it navigates. You can extend this with custom visualization (e.g., battery status, camera feeds).
Visualization & Custom Visualizer
DefaultVisualizationSuite includes:
- GoalPose → Robot position (topic-based).
- OccupancyGridVisualizer → SLAM map.
- LaserScanSensor → LiDAR scan.
You also need to add the following code in your Unity.
using System;using System.Collections.Generic;using RosMessageTypes.Geometry; // Generated message classesusing Unity.Robotics.Visualizations; // Visualizationsusing Unity.Robotics.ROSTCPConnector.ROSGeometry; // Coordinate space utilitiesusing UnityEngine;
public class PoseTrailVisualizer : HistoryDrawingVisualizer<PoseStampedMsg>{ [SerializeField] Color m_Color = Color.white; [SerializeField] float m_Thickness = 0.1f; [SerializeField] string m_Label = "";
public override Action CreateGUI(IEnumerable<Tuple<PoseStampedMsg, MessageMetadata>> messages) { return () => { var count = 0; foreach (var (message, meta) in messages) { GUILayout.Label($"Goal #{count}:"); message.pose.GUI(); count++; } }; }
public override void Draw(Drawing3d drawing, IEnumerable<Tuple<PoseStampedMsg, MessageMetadata>> messages) { var firstPass = true; var prevPoint = Vector3.zero; var color = Color.white; var label = "";
foreach (var (msg, meta) in messages) { var point = msg.pose.position.From<FLU>(); if (firstPass) { color = VisualizationUtils.SelectColor(m_Color, meta); label = VisualizationUtils.SelectLabel(m_Label, meta); firstPass = false; } else { drawing.DrawLine(prevPoint, point, color, m_Thickness); }
prevPoint = point; }
drawing.DrawLabel(label, prevPoint, color); }}Errors
ROS Error
Colcon Build
- Wrong package name: ROS-TCP-Endpoint-main → ros_tcp_endpoint
- Wrong build location: colcon build inside Robotics-Nav2-SLAM-Example → Robotics-Nav2-SLAM-Example/ros2_docker/colcon_ws
Not Connected to Unity
- Wrong Wi-Fi
- Wrong ROS IP Address
Unity Error
DeserializationException: Cannot deserialize message
- Rebuild msg files