TCP/IP communication with C++

Hello all,

I have made a vision program that produces the X,Y,Z coordinate of an object.
I want to transfer this X,Y,Z coordinate to our UR5 robot.
The idea is to do this with a Ethernet cable and a TCP/IP protocol (however if there is a better way feel free to suggest it).
I have written my vision application in C++ and this is pretty much the only programming language I have experience with.
I have found a bunch of python and C# examples but I’m having trouble implementing these in c++.
This is my first application using a UR5, so sorry if this is quite basic.

Could one of you maybe help me with this or point me in the right direction?

Yours sincerely,
Bart

In your c++ program implement a XMLRPC server then in your program you can instantiate an XMLRPC factory and then you can use that to transfer data back and forth. You would host the methods on the server and then program calls those methods using dot notation and can send any required parameters along with the call. This is a very fast way to send data between the robot and another application.

A quick google search this morning returned a lot of hits for c XML-RPC Server.

1 Like

Hi,

Modbus TCP is also a simple solution.

Libraries are availlable libmodbus/modbus-tcp.c at master · stephane/libmodbus · GitHub
but also at others places such as GitHub - fz-lyu/modbuspp: A C++ Library for Modbus TCP Client Protocol

Values can be send in mrad (modbus word are 16 bits unsigned integers … or specific treatments should be done) such as the UR leaves access to position in mrad and velocity in mrad/s

See https://www.universal-robots.com/articles/ur-articles/modbus-server/ for registers addresses.

Bye

1 Like

Bart,

Create a program on your machine that acts as a TCP/IP server. Write a program on the UR5, using script, that opens a socket connection to the PC. Let the PC send the values in a “(%lf,%lf,%lf)” format. Let the UR read the float values from the socket. Again using script. There’s no need for anything else.

1 Like

Hello mvrooij,

I have setup a simple TCP/IP server and am currently testing with a tool called: SocketTest v 3.0.0.
I’m having a little trouble with the second half of your answer and sending float values in the first place.
I have a server that sends a float (for testing purpose I did just 1 number).
When I run my code I don’t get to see that number in the SocketTest program. See picture below

Could you help me with this?
This is the first time I’m writing a network program.

Ideally I want to send a number or word from the robot to the pc which I can use to re-loop my vision software.
This outputs a X,Y,Z that I send to to robot, which after going to that coordinate sends a signal back to the pc.
like in this example :Ethernet socket communication via URScript - 15678
But then in C++ and using 1 point only

Hello,

You’re sending the number as a binary number, the raw bytes that make up the number, that’s why it looks “garbled” on SocketTest. You need to convert it to ASCII first:

#include

char buf[123]

double number = ;

std::sprintf(buf,"(%lf)”,number);

size_t buf_len = std::strlen(buf);

Now send buf.

The () are needed for the robot. When it receives () it treats it as a list of numbers. It’s a comma separated value list, e.g. sending 4 numbers would look like:

(12.4,456,900.87,6)

The robot will then receive 5 numbers. The first being the total numbers in the list, followed by the actual numbers.

1 Like

Ok, thanks again for your feedback,

I have tried your suggestion, I do get a decimal number now but not the whole string of numbers only the last number. see picture below:

Would you happen to know what would be the correct way to send the string of numbers?
I’ve tried changing sprintf_s(buf, "(%lf)",number); to sprintf_s(buf, "(%lf,%lf,%lf,%lf)",number); but this gave the result below:


I will maybe have time to test it on our UR5 today, otherwise it will probably be Wednesday.

And again I’m sorry if these are basic questions, I’m trying to learn by doing and by asking lot’s and lot’s of questions

Ok, you’re close

double number1 = 12.4;

double number2 = 456;

double number3 = 900.87;

double number4 = 6;

sprintf_s(buf,”(%lf,%lf,%lf,%lf)”,number1,number2,number3,number4);

The %lf means take a double and convert it to ASCII. You need it 4x because you have 4 numbers to convert.

1 Like

It is currently working on the pc with my little testing tool!

Maybe I will have some time today to test it with the UR5. I will keep you updated.

Thank you for the help.

Hello all I just had some time to try a few things.
Sadly I’m hitting a wall really early on, I can’t find how I would open a socket on the UR5 side.

I think In general I’m going to need some more help on the UR5 side as well.
I’m sorry for asking but this is the first time ourcompany is working with connection between the UR5 and a PC.

Can someone help me with this?

Hi Bart,

You can download the URScript Manual (which contains all the functions that can be run by one of our robots; it includes examples) from our Support Site here.

As for opening a socket you can see an example below on how to set one up. This one shows how to open a socket, send a string to the server, wait for a response from a server, and saving that response into 3 separate variables. The reason we use the “loop” with the socket open is to ensure that the connection through the socket is established otherwise it may not connect and you wouldn’t be able to perform further communication. For the “Loop data[0] != 3” this is due to the function “socket_read_ascii_float(3)” which returns 4 values in a list: [3, 1, 2, 3] where the first number is the number of values that were sent from the Server. So if you want to return 1 value from the Server the “data” list would need two list spaces: [0, 0] and you would wait until data[0] is equal to 1.

For what you’re trying to do the example listed is probably pretty close to what you need as it’s accepting 3 values from the Server and then placing those 3 values (using indexing) into “x”, “y”, and “rz”. In your case the last could be put in a “z” variable and then incorporate that with a pose to enable robot motion.

image

1 Like

Thank you for your response,

I denefinetely think this will get me started with my applicatie, I will try to test this today.
Do you maby have a link or laction where the sample picture comes from, it is just a little to small for me, I’m heaving difficulty reading it.

Oh, and one of the issue’s I had was that the command’s socket_open and socket_read_ascii_float don’t show up in the functions dropdown menu in the assign command.

Thank you in advance,
Bart

Hello again,

I have tried the sample you suggested.
However the code seems to be stuck in the comm != false loop.
And I get the following error: Not able to open socket (see pictures below as well)

I’m not really sure whats going wrong here, I think I might have selected the wrong IP-address, I found the current one by using ipconfig and selecting the IPv4 under ethernet adapter.

So I’m really sorry for bothering you all again but I think I need some help.

Just FYI, my shift ends in about 5 hours so If I don’t react after that you will probably get a reaction on monday.

Hi Bart,

Sorry for the late response, I messaged at the end of my workday.
The picture comes from our training slides. Unfortunately they’re not available online.

Regarding the loop getting stuck the issue is that your variable comm isn’t changing. You need to change var_1 to comm in order to break out of the loop and continue with the rest of your program. You also need to setup a data variable in the before start. I recommend putting data=[0, 0, 0, 0] otherwise you’ll get a missing variable error. I’ve attached just a picture Polyscope below, hopefully it’s easier to read.

image

Are you connecting to a physical robot via ethernet? If so (and you’re on a Windows computer) on your PC open “Network & Internet Settings”, click “Change adapter options”, right click on “Ethernet” and select properties. Look at IPv4 and change it to static and choose an IP Address.

You then need to change the IP Address on the robot under the settings (click the hamburger menu top right). Make sure the IP Address of your computer and the IP Address of the robot are the same except for the last digits (for instance if on your PC you choose “192.168.7.10” on the robot you could put “192.168.7.15”). Below I’ve included the script function for socket_open() that can be seen in the Script Manual.

image

You need to make sure you start the socket server on your PC side in your program or you won’t connect. It’s been awhile since I’ve used C++ so I’m sure how to do this but you should be able to google it.

1 Like

Hello,

I’ve tried your suggested changes.
I’ve changed Var_1 to com, and set an initial data variable.
I did set the IPv4 to static and changed it to 192.168.1.10.

Sadly the code still get’s stuck in the first loop.

I really don’t know what the problem is at the moment, hopefully you guys can help me further.

I’ve attached some picture below of my settings and put my server code underneath it.
UR5 program:

The error given:

UR Network settings:

Computer network settings:

My code:
#include
#include <WS2tcpip.h>

#pragma comment (lib, "ws2_32.lib")

using namespace std;

void main()
{

	//initialize winsock (sockets)
	WSADATA wsData;
	WORD ver = MAKEWORD(2, 2);

	int wsOk = WSAStartup(ver, &wsData);
	if (wsOk != 0)
	{
		cerr << "Can't initialize winsock! quitting" << endl;
		return;
	}

	//create a socket
	SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
	if (listening == INVALID_SOCKET)
	{
		cerr << "Can't create a socket! quitting" << endl;
		return;
	}

	//bind the ip to a socket address and port
	sockaddr_in hint;
	hint.sin_family = AF_INET;
	hint.sin_port = htons(1701);
	hint.sin_addr.S_un.S_addr = INADDR_ANY; //could also use inet_pton

	bind(listening, (sockaddr*)&hint, sizeof(hint));

	//tell winsock the socket is for listening
	listen(listening, SOMAXCONN);

	//wait for a connection
	sockaddr_in client;
	int clientSize = sizeof(client);

	SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
	if (clientSocket == INVALID_SOCKET)
	{
		cerr << "Can't make connection! quitting" << endl;
		return;
	}

	char host[NI_MAXHOST];		//client's remote name
	char service[NI_MAXSERV];	//service (i.e. port) the client is connect on

	ZeroMemory(host, NI_MAXHOST);
	ZeroMemory(service, NI_MAXSERV);

	if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
	{
		cout << host << " connected on port " << service << endl;
	}
	else
	{
		inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
		cout << host << " connected on port " <<
			ntohs(client.sin_port) << endl;
	}

	//close listening socket
	closesocket(listening);
	
	char buf[4096];

	while (true) //this part of the code will be used to send and receive data
	{
		ZeroMemory(buf, 4096);
		float X = 12.4;
		float Y = 456;
		float Z = 900.87;

		sprintf_s(buf, "(%lf,%lf,%lf)",X,Y,Z);
		size_t buf_len = strlen(buf);
		
		send(clientSocket, buf, buf_len, 0);


		
		
		int bytesReceived = recv(clientSocket, buf, 4096, 0);
	}

	//close the socket(s)
	closesocket(clientSocket);

	//shutdown/cleanup winsock (sockets)
	WSACleanup();

}

Check your windows firewall, it often blocks .exe if they open sockets (back door threat)

1 Like

Thank you,

This solved the issue for me.

I want to thank all of you for helping me this much, thank you.

With kind regards,
Bart

Hello - I have been following this thread and have a question. I got this to work but I only get the updated data after I stop the program.

I have my socket open connection in a thread. After the connection is made, I then send the ready message to my connected pc, then the pc sends the 4 values in Data[]. but if I look at the Data[] in the variables on the pendant, while running the program, they don’t update until I stop the program.

Am I not allowed to run the socket in a thread? Do I need to continually open and then close the socket for each data exchange or can I keep it open until the program ends?

Here is the program If you don’t mind taking a look.

I am also writing a C-based PC program that sends the string of data to the UR10e.

Thanks for your help.

Hello, I’ve read your issue,

Sadly I’m affraid I’m to much a biginner to help you with this.
I will leave my working code down here, so you can see how my working code looks:

IMG_20200515_131653

When a socket closes, any pending data is flushed to the receiving application. The reason why you won’t get is sooner is because you didn’t complete the data packet from the PC side. Missing ) perhaps?