Thursday, 17 March 2016

Pi Communication

Team : ESD
Name: Ian Murphy
Section: Pi Communication


For this sprint it was my responsibility to get the Pis to be able to communicate with each other as the design called for the separation of different tasks across different Pis which would require the passing of data from one pi to another bidirectionally. To set this up it was first necessary to have the Pis connected to each other and then to implement the actual communication in software using threads by implementing Kamil's thread and communication design.

Connecting Together


The first approach taken was to try and set the Pis up in an ah-hoc network which allows the pis to connect to each other without the use of a wireless router as an intermediary. However, reading various articles/blogs on this subject it was discovered that the wireless dongle that we were using didn't support being used in ad-hoc mode due to the driver. With spending so much time trying to configure both the Pis to work in ad-hoc mode the decision was made to park the idea with the possibility to returning to it later after finding a blog that had some success with the dongles we are using being used in ad-hoc mode.


The approach taken after trying to implement the ad-hoc solution was to set the Pis up to connect to each other through a router, this would allow the Pis to communicate and also allow easier connection of a laptop to the network for easier transfer of files during development work as it would allow an FTP connection to be established. 
To set the wireless up to work with the router it was necessary to edit a configuration file on the Pi.

To do this, enter the following into a terminal on the pi:

And add the following to it, making sure any other reference to "wlan0" is deleted.
The dhcp here tells the Pi that the router will automatically issue it with an IP address once it's connected, this can cause issues by giving the Pis a different address when the lease of the IP expires, it can be simply resolved however by going into the router's settings and reserving the IP addresses of both the Pis so that they are fixed and won't be changed.

Sending and Receiving Data

To actually send data between the two Pis, the way to send the data was to use sockets. One Pi would act as a server, the base Pi and the other as the client. The server would set up a socket that would be constantly listening for the client socket to connect to it. Once the client then connected the client would go through it's list of objects in the shared memory of Kamil's design that needed to be sent and then send them.

Server Code:

Code here sets up a socket on port 1245, there is no need for a host address on the server as it is only listening for other sockets that trying to connect to it. There's then a number of options to set up, the 'SO_REUSEADDR' option makes it so that if there's any issues on closing the socket connection that it will reuse the address without waiting for a timeout to occur. The 'TCP_NODELAY' option is meant to make sure that whenever a socket sends something there is little to no delay in sending the message.

Inside the first loop is where the server will wait until it detects a connection coming in form another client, s.accept() returns a tuple where 'c' in the code above is a new socket object that is going to be used to send and receive the data on the connection. 

The data can only be sent over the network as a string or byte array, to accomplish this the data object is parsed into JSON before being sent. This can be seen occurring in the client code. Before finally being sent though, there is also a send_one_message() function that calculates the length of the data being sent and then sends this information before the actual data string is sent.

Once the socket connection is established it goes into another where the data exchange will occur. Once there is data in the received buffer, the 'recv_one_message(c)' is a helper function that extracts the data from the buffer due to the way in which data is packed. The object at this stage is a string so the call 'jsonpickle.decode(data)' takes the sent string and returns the parsed JSON as an object. Using this object then it is then added to the shared memory of the 2nd pi.

The client code shows how the data is sent, the loop goes through all the objects to be sent on the client pi, for testing purposes its just simply "facePos1" and "facePos2", which are added on each iteration of the While loop. This won't happen in the full program as there will be a list of object in shared memory that other module designers have come up with. The main thing is the loop through the list, for each of the tags in the list the loop will grab that object from memory where it is then wrapped into a dict along with the tag name. It is then encoded into JSON as already mentioned, bytes are sent over the network and not objects. 

The send_one_message() then takes over in sending the message by first calculating the length of the string being sent, it then sends the length of the string being sent so that the server can grab the right amount of bytes from its received buffer. After the length has been sent then the actual data is sent. And then the loop repeats, going through all the tags that the system needs to send.


The terminal on the left shows the server code running and the right terminal is the client, both are running as separate processes on a PC and connect to each other using 'localhost'. The outputs on the left show that the data has been successfully sent from the client, parsed correctly and then placed in the shared memory of the process that is running the server.


There is an issue however, the speed at which the server is receiving the data is very slow. The 'TCP_NODELAY' option helped a bit but the delay is still going to cause problems.

Again the left shows the server, right the client. While the left shows that server has correctly received the first object with 8007 as x and y the client shows that it is about to send the object with 8011 for x and y. 

There is a couple of things that could cause this, one is using TCP instead of UDP as the transmission protocol. TCP is a streaming protocol and might not be best suited for this application. UDP has drawbacks though, TCP ensures delivery of packets but UDP does not. This may not be an issue however as if one packet gets lost here it may not cause too much of an issue. Or it may be something that I haven't yet thought about. For the next sprint my focus will be on the solving of the speed issue.


No comments:

Post a Comment