├── Client_Data_Interfaces ├── ClientInterfaces_Primary.pdf └── ClientInterfaces_Realtime.pdf ├── LICENSE ├── README.md ├── UR_TCPip_RW_Console_app └── Program.cs ├── UR_TCPip_Stream_Data_app └── Program.cs └── images ├── cb_1.PNG ├── communication_scheme.png └── e_1.PNG /Client_Data_Interfaces/ClientInterfaces_Primary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rparak/UR_Robot_data_processing/a297664f66e1c34563878def22519bb13f08f084/Client_Data_Interfaces/ClientInterfaces_Primary.pdf -------------------------------------------------------------------------------- /Client_Data_Interfaces/ClientInterfaces_Realtime.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rparak/UR_Robot_data_processing/a297664f66e1c34563878def22519bb13f08f084/Client_Data_Interfaces/ClientInterfaces_Realtime.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Roman Parak 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TCP/IP Communication between Universal Robots UR3 (Server) and simple Client (C#) 2 | 3 | ## Requirements: 4 | 5 | **Software:** 6 | ```bash 7 | Universal Robots Polyscope, Visual Studio (or something similar) 8 | ``` 9 | 10 | | Software/Package | Link | 11 | | -------------------------- | ------------------------------------------------------------------------------------- | 12 | | Universal Robots Polyscope | https://www.universal-robots.com/download/ | 13 | | Visual Studio | https://visualstudio.microsoft.com/downloads/ | 14 | 15 | **Programming Language:** 16 | ```bash 17 | C#, Another Language (Python, C/C++ -> similar implementation as C#) 18 | ``` 19 | 20 | **Packages:** 21 | ```bash 22 | C# (.NET Framework 4.6.1) 23 | ``` 24 | 25 | ## Project Description: 26 | 27 | The project is focused on a simple demonstration of client-server communication via TCP / IP. In this case, it is a collaborative robot Universal Robots UR3 / UR3e (server), which communicates with the client via the C# application. An example of an application is reading (Joint / Cartesian position) and writing data (movement -> linear, joint interpolation, etc.). The application was tested on each of the robot types (UR3 -> real hardware + simulation, UR5, UR10, etc.) E and CB series (simulation using VMware <-> UR Polyscope in Windows). 28 | 29 | Writing data is really simple, just create a variable of type STRING in accordance with certain principles, transform the data into a BYTE and send this command to the Server. Data is read using packets on the server (see the file for a description of the packet -> /Client_Data_Interfaces/). 30 | 31 | Further information can be found at: 32 | [REMOTE CONTROL VIA TCP/IP](https://www.universal-robots.com/articles/ur/interface-communication/remote-control-via-tcpip/) 33 | 34 | The application uses performance optimization using multi-threaded programming. Communication (C# application) can be used in Unity3D for digital twins / augmented reality or in other relevant applications. 35 | 36 | Sample application in the Unity3D program (Digital-Twin): 37 | 38 | [Universal Robots UR3 - Unity3D Robotics](https://github.com/rparak/Unity3D_Robotics_UR) 39 | 40 | The project was realized at the Institute of Automation and Computer Science, Brno University of Technology, Faculty of Mechanical Engineering (NETME Centre - Cybernetics and Robotics Division). 41 | 42 |

43 | 44 |

45 | 46 | ## Project Hierarchy: 47 | 48 | **Client (C#) - Repositary [/UR_Robot_data_processing/UR_TCPip_RW_Console_app/]:** 49 | 50 | ```bash 51 | [ Main Program (Read / Write Data) ] /Program.cs/ 52 | ``` 53 | 54 | **Client (C#) - Repositary [/UR_Robot_data_processing/UR_TCPip_Stream_Data_app/]:** 55 | 56 | ```bash 57 | [ Main Program (Collecting data and saving to file) ] /Program.cs/ 58 | ``` 59 | 60 | **Data Interfaces - Repositary [UR_Robot_data_processing/Client_Data_Interfaces/]:** 61 | 62 | ```bash 63 | [ Datasheet ] /Client_InterfacesV3.14andV5.9.xlsx/ 64 | ``` 65 | 66 | ## Example of reading the position of a joint from different series of Universal Robots UR3: 67 | 68 |

69 | 70 | 71 |

72 | 73 | ## Contact Info: 74 | Roman.Parak@outlook.com 75 | 76 | ## Citation (BibTex) 77 | ```bash 78 | @misc{RomanParak_DT_UR, 79 | author = {Roman Parak}, 80 | title = {Data collection from the Universal Robots control unit using the TCP/IP communication protocol}, 81 | year = {2020-2021}, 82 | publisher = {GitHub}, 83 | journal = {GitHub repository}, 84 | howpublished = {\url{https://github.com/rparak/UR_Robot_data_processing/}} 85 | } 86 | ``` 87 | 88 | ## License 89 | [MIT](https://choosealicense.com/licenses/mit/) 90 | -------------------------------------------------------------------------------- /UR_TCPip_RW_Console_app/Program.cs: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | MIT License 3 | Copyright(c) 2020 Roman Parak 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | ***************************************************************************** 20 | Author : Roman Parak 21 | Email : Roman.Parak @outlook.com 22 | Github : https://github.com/rparak 23 | File Name: Program.cs 24 | ****************************************************************************/ 25 | 26 | // System Lib. 27 | using System; 28 | using System.Text; 29 | using System.Net.Sockets; 30 | using System.Threading; 31 | using System.Diagnostics; 32 | using System.Collections.Generic; 33 | 34 | namespace UR_TCPip_RW_Console_app 35 | { 36 | public static class UR_Stream_Data 37 | { 38 | // IP Port Number and IP Address 39 | public static string ip_address; 40 | // Real-time (Read Only) 41 | public const ushort port_number = 30013; 42 | // Comunication Speed (ms) 43 | public static int time_step; 44 | // Joint Space: 45 | // Orientation {J1 .. J6} (rad) 46 | public static double[] J_Orientation = new double[6]; 47 | // Cartesian Space: 48 | // Position {X, Y, Z} (mm) 49 | public static double[] C_Position = new double[3]; 50 | // Orientation {Euler Angles} (rad): 51 | public static double[] C_Orientation = new double[3]; 52 | } 53 | 54 | public static class UR_Control_Data 55 | { 56 | // IP Port Number and IP Address 57 | public static string ip_address; 58 | // Real-time (Read/Write) 59 | public const ushort port_number = 30003; 60 | // Comunication Speed (ms) 61 | public static int time_step; 62 | // Home Parameters UR3/UR3e: 63 | // Joint Space: 64 | // Orientation {J1 .. J6} (rad) 65 | public static double[] J_Orientation = new double[6] { -1.6, -1.7, -2.2, -0.8, 1.59, -0.03 }; 66 | // Cartesian Space: 67 | // Position {X, Y, Z} (mm) 68 | public static double[] C_Position = new double[3] { -0.11, -0.26, 0.15 }; 69 | // Orientation {Euler Angles} (rad): 70 | public static double[] C_Orientation = new double[3] { 0.0, 3.11, 0.0 }; 71 | // Move Parameters: Velocity, Acceleration 72 | public static string velocity = "1.0"; 73 | public static string acceleration = "1.0"; 74 | } 75 | 76 | class Program 77 | { 78 | static void Main(string[] args) 79 | { 80 | // Initialization {TCP/IP Universal Robots} 81 | // Read Data: 82 | UR_Stream_Data.ip_address = "192.168.230.133"; 83 | // Communication speed: CB-Series 125 Hz (8 ms), E-Series 500 Hz (2 ms) 84 | UR_Stream_Data.time_step = 8; 85 | // Write Data: 86 | UR_Control_Data.ip_address = "192.168.230.133"; 87 | // Communication speed: CB-Series 125 Hz (8 ms), E-Series 500 Hz (2 ms) 88 | UR_Control_Data.time_step = 8; 89 | 90 | // Start Stream {Universal Robots TCP/IP} 91 | UR_Stream ur_stream_robot = new UR_Stream(); 92 | ur_stream_robot.Start(); 93 | 94 | // Start Control {Universal Robots TCP/IP} 95 | UR_Control ur_ctrl_robot = new UR_Control(); 96 | ur_ctrl_robot.Start(); 97 | 98 | Console.WriteLine("[INFO] Stop (y):"); 99 | // Stop communication 100 | string stop_rs = Convert.ToString(Console.ReadLine()); 101 | 102 | if (stop_rs == "y") 103 | { 104 | Console.WriteLine("Joint Space: Orientation (radian)"); 105 | Console.WriteLine("J1: {0} | J2: {1} | J3: {2} | J4: {3} | J5: {4} | J6: {5}", 106 | UR_Stream_Data.J_Orientation[0], UR_Stream_Data.J_Orientation[1], UR_Stream_Data.J_Orientation[2], 107 | UR_Stream_Data.J_Orientation[3], UR_Stream_Data.J_Orientation[4], UR_Stream_Data.J_Orientation[5]); 108 | 109 | Console.WriteLine("Cartesian Space: Position (metres), Orientation (radian):"); 110 | Console.WriteLine("X: {0} | Y: {1} | Z: {2} | RX: {3} | RY: {4} | RZ: {5}", 111 | UR_Stream_Data.C_Position[0], UR_Stream_Data.C_Position[1], UR_Stream_Data.C_Position[2], 112 | UR_Stream_Data.C_Orientation[0], UR_Stream_Data.C_Orientation[1], UR_Stream_Data.C_Orientation[2]); 113 | 114 | // Destroy UR {Control / Stream} 115 | ur_stream_robot.Destroy(); 116 | ur_ctrl_robot.Destroy(); 117 | 118 | // Application quit 119 | Environment.Exit(0); 120 | } 121 | } 122 | } 123 | 124 | class UR_Stream 125 | { 126 | // Initialization of Class variables 127 | // Thread 128 | private Thread robot_thread = null; 129 | private bool exit_thread = false; 130 | // TCP/IP Communication 131 | private TcpClient tcp_client = new TcpClient(); 132 | private NetworkStream network_stream = null; 133 | // Packet Buffer (Read) 134 | private byte[] packet = new byte[1116]; 135 | // Main state machine 136 | private int state_id = 0; 137 | 138 | // Offset: 139 | // Size of first packet in bytes (Integer) 140 | private const byte first_packet_size = 4; 141 | // Size of other packets in bytes (Double) 142 | private const byte offset = 8; 143 | 144 | // Total message length in bytes 145 | private static List msg_length_list = new List(); 146 | private static UInt32 total_msg_length = 0; 147 | 148 | public void UR_Stream_Thread() 149 | { 150 | try 151 | { 152 | if (tcp_client.Connected == false) 153 | { 154 | // Connect to controller -> if the controller is disconnected 155 | tcp_client.Connect(UR_Stream_Data.ip_address, UR_Stream_Data.port_number); 156 | } 157 | 158 | // Initialization TCP/IP Communication (Stream) 159 | network_stream = tcp_client.GetStream(); 160 | 161 | // Initialization timer 162 | var t = new Stopwatch(); 163 | 164 | while (exit_thread == false) 165 | { 166 | switch (state_id) 167 | { 168 | case 0: 169 | { 170 | // Getting the total message length from several runs of reading data 171 | if (network_stream.Read(packet, 0, packet.Length) != 0) 172 | { 173 | if (msg_length_list.Count == 10) 174 | { 175 | msg_length_list.Sort(); 176 | total_msg_length = msg_length_list[msg_length_list.Count - 1]; 177 | state_id = 1; 178 | } 179 | else 180 | { 181 | msg_length_list.Add(BitConverter.ToUInt32(packet, first_packet_size - 4)); 182 | } 183 | } 184 | 185 | } 186 | break; 187 | 188 | case 1: 189 | { 190 | // Get the data from the robot 191 | if (network_stream.Read(packet, 0, packet.Length) != 0) 192 | { 193 | if (BitConverter.ToUInt32(packet, first_packet_size - 4) == total_msg_length) 194 | { 195 | // t_{0}: Timer start. 196 | t.Start(); 197 | 198 | // Reverses the order of elements in a one-dimensional array or part of an array. 199 | Array.Reverse(packet); 200 | 201 | // Note: 202 | // For more information on values 32... 37, etc., see the UR Client Interface document. 203 | // Read Joint Values in radians 204 | UR_Stream_Data.J_Orientation[0] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (32 * offset)); 205 | UR_Stream_Data.J_Orientation[1] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (33 * offset)); 206 | UR_Stream_Data.J_Orientation[2] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (34 * offset)); 207 | UR_Stream_Data.J_Orientation[3] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (35 * offset)); 208 | UR_Stream_Data.J_Orientation[4] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (36 * offset)); 209 | UR_Stream_Data.J_Orientation[5] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (37 * offset)); 210 | // Read Cartesian (Positon) Values in metres 211 | UR_Stream_Data.C_Position[0] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (56 * offset)); 212 | UR_Stream_Data.C_Position[1] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (57 * offset)); 213 | UR_Stream_Data.C_Position[2] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (58 * offset)); 214 | // Read Cartesian (Orientation) Values in metres 215 | UR_Stream_Data.C_Orientation[0] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (59 * offset)); 216 | UR_Stream_Data.C_Orientation[1] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (60 * offset)); 217 | UR_Stream_Data.C_Orientation[2] = BitConverter.ToDouble(packet, packet.Length - first_packet_size - (61 * offset)); 218 | 219 | // t_{1}: Timer stop. 220 | t.Stop(); 221 | 222 | // Recalculate the time: t = t_{1} - t_{0} -> Elapsed Time in milliseconds 223 | if (t.ElapsedMilliseconds < UR_Stream_Data.time_step) 224 | { 225 | Thread.Sleep(UR_Stream_Data.time_step - (int)t.ElapsedMilliseconds); 226 | } 227 | 228 | // Reset (Restart) timer. 229 | t.Restart(); 230 | } 231 | } 232 | } 233 | break; 234 | } 235 | } 236 | } 237 | catch (SocketException e) 238 | { 239 | Console.WriteLine("SocketException: {0}", e); 240 | } 241 | } 242 | 243 | public void Start() 244 | { 245 | exit_thread = false; 246 | // Start a thread to control Universal Robots (UR) 247 | robot_thread = new Thread(new ThreadStart(UR_Stream_Thread)); 248 | robot_thread.IsBackground = true; 249 | robot_thread.Start(); 250 | } 251 | public void Stop() 252 | { 253 | exit_thread = true; 254 | // Stop a thread 255 | Thread.Sleep(100); 256 | } 257 | public void Destroy() 258 | { 259 | // Start a thread and disconnect tcp/ip communication 260 | Stop(); 261 | if (tcp_client.Connected == true) 262 | { 263 | network_stream.Dispose(); 264 | tcp_client.Close(); 265 | } 266 | Thread.Sleep(100); 267 | } 268 | } 269 | 270 | class UR_Control 271 | { 272 | // Initialization of Class variables 273 | // Thread 274 | private Thread robot_thread = null; 275 | private bool exit_thread = false; 276 | // TCP/IP Communication 277 | private TcpClient tcp_client = new TcpClient(); 278 | private NetworkStream network_stream = null; 279 | // Packet Buffer (Write) 280 | private byte[] packet_cmd; 281 | // Encoding 282 | private UTF8Encoding utf8 = new UTF8Encoding(); 283 | 284 | public void UR_Control_Thread() 285 | { 286 | try 287 | { 288 | if (tcp_client.Connected == false) 289 | { 290 | // Connect to controller -> if the controller is disconnected 291 | tcp_client.Connect(UR_Control_Data.ip_address, UR_Control_Data.port_number); 292 | } 293 | 294 | // Initialization TCP/IP Communication (Stream) 295 | network_stream = tcp_client.GetStream(); 296 | 297 | while (exit_thread == false) 298 | { 299 | // Note: 300 | // For more information about commands, see the URScript Programming Language document 301 | 302 | // Instruction 1 (Home Position): Joint Input Command, Move Joint Interpolation 303 | // Get Bytes from String 304 | packet_cmd = utf8.GetBytes("movej([" + UR_Control_Data.J_Orientation[0].ToString() + "," + UR_Control_Data.J_Orientation[1].ToString() + "," + UR_Control_Data.J_Orientation[2].ToString() + "," 305 | + UR_Control_Data.J_Orientation[3].ToString() + "," + UR_Control_Data.J_Orientation[4].ToString() + "," + UR_Control_Data.J_Orientation[5].ToString() + "]," 306 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")" + "\n"); 307 | // Send command to the robot 308 | network_stream.Write(packet_cmd, 0, packet_cmd.Length); 309 | // Wait Time (5 seconds) 310 | Thread.Sleep(5000); 311 | 312 | // Instruction 2 (Multiple Positions): Cartesian Input Command, Move Linear Interpolation 313 | // Get Bytes from String 314 | packet_cmd = utf8.GetBytes("[movel(p[" + UR_Control_Data.C_Position[0].ToString() + "," + UR_Control_Data.C_Position[1].ToString() + "," + (UR_Control_Data.C_Position[2] - 0.1).ToString() + "," 315 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 316 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")," + 317 | "movel(p[" + (UR_Control_Data.C_Position[0] - 0.1).ToString() + ", " + UR_Control_Data.C_Position[1].ToString() + ", " + (UR_Control_Data.C_Position[2] - 0.1).ToString() + ", " 318 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 319 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")," + 320 | "movel(p[" + (UR_Control_Data.C_Position[0] - 0.1).ToString() + ", " + UR_Control_Data.C_Position[1].ToString() + ", " + UR_Control_Data.C_Position[2].ToString() + ", " 321 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 322 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")," + 323 | "movel(p[" + UR_Control_Data.C_Position[0].ToString() + ", " + UR_Control_Data.C_Position[1].ToString() + ", " + (UR_Control_Data.C_Position[2]).ToString() + ", " 324 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 325 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")]" + "\n"); 326 | // Send command to the robot 327 | network_stream.Write(packet_cmd, 0, packet_cmd.Length); 328 | // Wait Time (5 seconds) 329 | Thread.Sleep(5000); 330 | 331 | // Instruction 3 (Multiple Positions): Cartesian Input Command, Move Joint Interpolation 332 | // Get Bytes from String 333 | packet_cmd = utf8.GetBytes("[movej(p[" + UR_Control_Data.C_Position[0].ToString() + "," + UR_Control_Data.C_Position[1].ToString() + "," + (UR_Control_Data.C_Position[2] - 0.1).ToString() + "," 334 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 335 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")," + 336 | "movej(p[" + (UR_Control_Data.C_Position[0] - 0.1).ToString() + ", " + UR_Control_Data.C_Position[1].ToString() + ", " + (UR_Control_Data.C_Position[2] - 0.1).ToString() + ", " 337 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 338 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")," + 339 | "movej(p[" + (UR_Control_Data.C_Position[0] - 0.1).ToString() + ", " + UR_Control_Data.C_Position[1].ToString() + ", " + UR_Control_Data.C_Position[2].ToString() + ", " 340 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 341 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")," + 342 | "movej(p[" + UR_Control_Data.C_Position[0].ToString() + ", " + UR_Control_Data.C_Position[1].ToString() + ", " + (UR_Control_Data.C_Position[2]).ToString() + ", " 343 | + UR_Control_Data.C_Orientation[0].ToString() + "," + UR_Control_Data.C_Orientation[1].ToString() + "," + UR_Control_Data.C_Orientation[2].ToString() + "]," 344 | + "a=" + UR_Control_Data.acceleration + ", v=" + UR_Control_Data.velocity + ")]" + "\n"); 345 | // Send command to the robot 346 | network_stream.Write(packet_cmd, 0, packet_cmd.Length); 347 | // Wait Time (5 seconds) 348 | Thread.Sleep(5000); 349 | } 350 | } 351 | catch (SocketException e) 352 | { 353 | Console.WriteLine("SocketException: {0}", e); 354 | } 355 | } 356 | public void Start() 357 | { 358 | exit_thread = false; 359 | // Start a thread to control Universal Robots (UR) 360 | robot_thread = new Thread(new ThreadStart(UR_Control_Thread)); 361 | robot_thread.IsBackground = true; 362 | robot_thread.Start(); 363 | } 364 | public void Stop() 365 | { 366 | exit_thread = true; 367 | // Stop a thread 368 | Thread.Sleep(100); 369 | } 370 | public void Destroy() 371 | { 372 | // Start a thread and disconnect tcp/ip communication 373 | Stop(); 374 | if (tcp_client.Connected == true) 375 | { 376 | network_stream.Dispose(); 377 | tcp_client.Close(); 378 | } 379 | Thread.Sleep(100); 380 | } 381 | } 382 | } 383 | -------------------------------------------------------------------------------- /UR_TCPip_Stream_Data_app/Program.cs: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | MIT License 3 | Copyright(c) 2021 Roman Parak 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | ***************************************************************************** 20 | Author : Roman Parak 21 | Email : Roman.Parak @outlook.com 22 | Github : https://github.com/rparak 23 | File Name: Program.cs 24 | ****************************************************************************/ 25 | 26 | // System Lib. 27 | using System; 28 | using System.Net.Sockets; 29 | using System.Threading; 30 | using System.Diagnostics; 31 | using System.Collections.Generic; 32 | 33 | namespace UR_TCPip_Stream_Data_app 34 | { 35 | public static class UR_Stream_Data 36 | { 37 | // IP Port Number and IP Address 38 | public static string ip_address; 39 | // Real-time (Read Only) 40 | public const ushort port_number = 30013; 41 | // Comunication Speed (ms) 42 | public static int time_step; 43 | // Joint Space: 44 | // Orientation {J1 .. J6} (rad) 45 | public static List J_Orientation_1 = new List(); 46 | public static List J_Orientation_2 = new List(); 47 | public static List J_Orientation_3 = new List(); 48 | public static List J_Orientation_4 = new List(); 49 | public static List J_Orientation_5 = new List(); 50 | public static List J_Orientation_6 = new List(); 51 | } 52 | 53 | class Program 54 | { 55 | static void Main(string[] args) 56 | { 57 | // Variable used to save data to a file from the UR robot. 58 | bool save_data = true; 59 | 60 | // Initialization {TCP/IP Universal Robots} 61 | // Read Data: 62 | UR_Stream_Data.ip_address = "192.168.230.132"; 63 | // Communication speed: CB-Series 125 Hz (8 ms), E-Series 500 Hz (2 ms) 64 | UR_Stream_Data.time_step = 8; 65 | 66 | // Start Stream {Universal Robots TCP/IP} 67 | UR_Stream ur_stream_robot = new UR_Stream(); 68 | ur_stream_robot.Start(); 69 | 70 | Console.WriteLine("[INFO] Stop (y):"); 71 | // Stop communication 72 | string stop_rs = Convert.ToString(Console.ReadLine()); 73 | 74 | if (stop_rs == "y") 75 | { 76 | if (save_data == true) 77 | { 78 | // Write Data to file (.txt) 79 | Write_Data(UR_Stream_Data.J_Orientation_1, UR_Stream_Data.J_Orientation_2, UR_Stream_Data.J_Orientation_3, 80 | UR_Stream_Data.J_Orientation_4, UR_Stream_Data.J_Orientation_5, UR_Stream_Data.J_Orientation_6, 81 | "D:\\UR10e_Stream_Data_Example.txt"); 82 | 83 | Console.WriteLine("[INFO] File saved successfully!"); 84 | } 85 | 86 | // Destroy UR {Control / Stream} 87 | ur_stream_robot.Destroy(); 88 | 89 | // Application quit 90 | Environment.Exit(0); 91 | } 92 | } 93 | public static void Write_Data(List Joint_1, List Joint_2, List Joint_3, 94 | List Joint_4, List Joint_5, List Joint_6, 95 | string file_path) 96 | { 97 | try 98 | { 99 | using (System.IO.StreamWriter file = new System.IO.StreamWriter(@file_path, true)) 100 | { 101 | for (int i = 0; i < Joint_1.Count; ++i) 102 | { 103 | file.WriteLine(Joint_1[i].ToString() + "," + Joint_2[i].ToString() + "," + Joint_3[i].ToString() + "," + 104 | Joint_4[i].ToString() + "," + Joint_5[i].ToString() + "," + Joint_6[i].ToString()); 105 | } 106 | } 107 | } 108 | catch (Exception ex) 109 | { 110 | throw new ApplicationException("Error: ", ex); 111 | } 112 | } 113 | } 114 | 115 | class UR_Stream 116 | { 117 | // Initialization of Class variables 118 | // Thread 119 | private Thread robot_thread = null; 120 | private bool exit_thread = false; 121 | // TCP/IP Communication 122 | private TcpClient tcp_client = new TcpClient(); 123 | private NetworkStream network_stream = null; 124 | // Packet Buffer (Read) 125 | private byte[] packet = new byte[1116]; 126 | // Main state machine 127 | private int state_id = 0; 128 | 129 | // Offset: 130 | // Size of first packet in bytes (Integer) 131 | private const byte first_packet_size = 4; 132 | // Size of other packets in bytes (Double) 133 | private const byte offset = 8; 134 | 135 | // Total message length in bytes 136 | private static List msg_length_list = new List(); 137 | private static UInt32 total_msg_length = 0; 138 | 139 | public void UR_Stream_Thread() 140 | { 141 | try 142 | { 143 | if (tcp_client.Connected == false) 144 | { 145 | // Connect to controller -> if the controller is disconnected 146 | tcp_client.Connect(UR_Stream_Data.ip_address, UR_Stream_Data.port_number); 147 | } 148 | 149 | // Initialization TCP/IP Communication (Stream) 150 | network_stream = tcp_client.GetStream(); 151 | 152 | // Initialization timer 153 | var t = new Stopwatch(); 154 | 155 | while (exit_thread == false) 156 | { 157 | switch (state_id) 158 | { 159 | case 0: 160 | { 161 | // Getting the total message length from several runs of reading data 162 | if (network_stream.Read(packet, 0, packet.Length) != 0) 163 | { 164 | if (msg_length_list.Count == 10) 165 | { 166 | msg_length_list.Sort(); 167 | total_msg_length = msg_length_list[msg_length_list.Count - 1]; 168 | state_id = 1; 169 | } 170 | else 171 | { 172 | msg_length_list.Add(BitConverter.ToUInt32(packet, first_packet_size - 4)); 173 | } 174 | } 175 | 176 | } 177 | break; 178 | 179 | case 1: 180 | { 181 | // Get the data from the robot 182 | if (network_stream.Read(packet, 0, packet.Length) != 0) 183 | { 184 | if (BitConverter.ToUInt32(packet, first_packet_size - 4) == total_msg_length) 185 | { 186 | // t_{0}: Timer start. 187 | t.Start(); 188 | 189 | // Reverses the order of elements in a one-dimensional array or part of an array. 190 | Array.Reverse(packet); 191 | 192 | // Note: 193 | // For more information on values 32... 37, etc., see the UR Client Interface document. 194 | // Read Joint Values in radians 195 | UR_Stream_Data.J_Orientation_1.Add(BitConverter.ToDouble(packet, packet.Length - first_packet_size - (32 * offset))); 196 | UR_Stream_Data.J_Orientation_2.Add(BitConverter.ToDouble(packet, packet.Length - first_packet_size - (33 * offset))); 197 | UR_Stream_Data.J_Orientation_3.Add(BitConverter.ToDouble(packet, packet.Length - first_packet_size - (34 * offset))); 198 | UR_Stream_Data.J_Orientation_4.Add(BitConverter.ToDouble(packet, packet.Length - first_packet_size - (35 * offset))); 199 | UR_Stream_Data.J_Orientation_5.Add(BitConverter.ToDouble(packet, packet.Length - first_packet_size - (36 * offset))); 200 | UR_Stream_Data.J_Orientation_6.Add(BitConverter.ToDouble(packet, packet.Length - first_packet_size - (37 * offset))); 201 | 202 | // t_{1}: Timer stop. 203 | t.Stop(); 204 | 205 | // Recalculate the time: t = t_{1} - t_{0} -> Elapsed Time in milliseconds 206 | if (t.ElapsedMilliseconds < UR_Stream_Data.time_step) 207 | { 208 | Thread.Sleep(UR_Stream_Data.time_step - (int)t.ElapsedMilliseconds); 209 | } 210 | 211 | // Reset (Restart) timer. 212 | t.Restart(); 213 | } 214 | } 215 | } 216 | break; 217 | } 218 | } 219 | } 220 | catch (SocketException e) 221 | { 222 | Console.WriteLine("SocketException: {0}", e); 223 | } 224 | } 225 | 226 | public void Start() 227 | { 228 | exit_thread = false; 229 | // Start a thread to control Universal Robots (UR) 230 | robot_thread = new Thread(new ThreadStart(UR_Stream_Thread)); 231 | robot_thread.IsBackground = true; 232 | robot_thread.Start(); 233 | } 234 | public void Stop() 235 | { 236 | exit_thread = true; 237 | // Stop a thread 238 | Thread.Sleep(100); 239 | } 240 | public void Destroy() 241 | { 242 | // Start a thread and disconnect tcp/ip communication 243 | Stop(); 244 | if (tcp_client.Connected == true) 245 | { 246 | network_stream.Dispose(); 247 | tcp_client.Close(); 248 | } 249 | Thread.Sleep(100); 250 | } 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /images/cb_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rparak/UR_Robot_data_processing/a297664f66e1c34563878def22519bb13f08f084/images/cb_1.PNG -------------------------------------------------------------------------------- /images/communication_scheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rparak/UR_Robot_data_processing/a297664f66e1c34563878def22519bb13f08f084/images/communication_scheme.png -------------------------------------------------------------------------------- /images/e_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rparak/UR_Robot_data_processing/a297664f66e1c34563878def22519bb13f08f084/images/e_1.PNG --------------------------------------------------------------------------------