├── 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
--------------------------------------------------------------------------------