Skip to content
This repository has been archived by the owner on Jul 3, 2019. It is now read-only.

PUB/SUB Interface #3

Closed
jpas opened this issue Jul 24, 2017 · 3 comments
Closed

PUB/SUB Interface #3

jpas opened this issue Jul 24, 2017 · 3 comments

Comments

@jpas
Copy link
Contributor

jpas commented Jul 24, 2017

To allow for easier subscription to 0MQ sockets.

The publish/subscribe model should be used for metrics and sensor data.

I propose using a Uniform Resource Identifier (URI) scheme for our published messages which will allow for easy identification of where information is coming from. In addition to this, all messages should be able to be serialized to JSON.

I will be using the following hypothetical publishers as an example:

  • A temperature sensor

    • Bound to the socket tcp://10.0.0.1:5000
    • Publishes the current temperature in Celsius and Fahrenheit.
      • tcp://10.0.0.1:5000/temperature/celsius
      • tcp://10.0.0.1:5000/temperature/fahrenheit
  • A GPS receiver

    • Bound to the socket tcp://10.0.0.2:6000
    • Publishes the current GPS position
      • tcp://10.0.0.2:6000/gps/location

I propose an API that could conform to the following code. The code in this issue is pseudo-python.

# temperature publisher
pub = Publisher('tcp://10.0.0.1:5000/temperature')
while True:
    c = read_temperature()
    pub.publish('celcius', {'unit': 'celcius', 'value': c})
    f = c * (9/5) + 32
    pub.publish('fahrenheit', {'unit': 'fahrenheit', 'value': f})
# gps publisher
pub = Publisher('tcp://10.0.0.2:6000/gps')
while True:
    lat, lon = get_gps()
    pub.publish('location', {'latitude': lat, 'longitude': lon})
# subscriber
sub = Subscriber()

# callback to print function
sub.subscribe('tcp://10.0.0.1:5000/temperature', print)

last_gps = {'latitude': 0, 'longitude': 0}
def on_gps(from, message):
    distance = calculate_distance(message, last_gps)
    print(distance)

# callback to on_gps
sub.subscribe('tcp://10.0.0.2:6000/gps/location', on_gps)

# sleep indefinitely
while True:
    sleep(1)

The output of the subscriber will look something like this:

tcp://10.0.0.1:5000/temperature/celcius {'unit': 'celcius', 'value': 20}
tcp://10.0.0.1:5000/temperature/fahrenheit {'unit': 'fahrenheit', 'value': 68}
100
0
tcp://10.0.0.1:5000/temperature/celcius {'unit': 'celcius', 'value': 20}
tcp://10.0.0.1:5000/temperature/fahrenheit {'unit': 'fahrenheit', 'value': 68}
0
2
@ottopasuuna
Copy link
Member

Sounds great! One thing that would be nice is to avoid having to specify the ip address and port; that should be configured automatically somehow, probably by asking the process manager or something. I think I saw functions in zeromq for using random port numbers, so there may be some level of automation build into zmq already. Idealy we can just use the hostname of the machine its running on.
So creating a publisher would look like
pub = Publisher('gps').
Creating a subscriber like this might be trickier, but it would be nice if you could just do sub.subscribe('gps', on_gps)
and the system would figure out where things are.
Or sub.subscribe('NavPi/gps', on_gps)

@climathosphere
Copy link
Contributor

climathosphere commented Aug 9, 2017

Carl,

I found on the ZeroMQ documentation that they use a '*' as a wildcard operator for the publisher's socket (but not for the subscription's connection to the publisher's socket). We can check to see by experimentation if we can use the same wildcard operator for the subscription's connection. I read their example on getting the message out:
http://zguide.zeromq.org/py:all#Getting-the-Message-Out

For randomly specifying the IP address, I haven't found anything in their guide that would allow us to generate random sockets. However, it could be possible if we use proxies and create IPs buy generating random numbers on our own.
http://zguide.zeromq.org/py:all#Intermediaries-and-Proxies

Other than that, I don't mind using IP addresses to specify the sockets for each device. I'm guessing that if we were to exclude the IP addresses, it may defeat the purpose of decentralization (which is going against the purpose of ZeroMQ).

@ottopasuuna
Copy link
Member

The IP addresses would be configured either by a physical router using DHCP or manually assigned static IPs, so all we should need is a proxy to do all the routing. I was thinking one of the functional components of the process manager would be this proxy. Although it may become a bottle neck at some point, that is a backend problem that can be changed without effecting rover modules themselves.
The main point I want to make about hiding IP addresses and ports, is that in order for the application layer to be easy to configure and scalable, you should only have to think about communicating between processes, not which machine the process is running on. I wasn't on the team when this happened, but the first year the USST did the rover, everything was running on separate raspberry pi's but I don't think there was any standard communication layer like what we are trying to do now. Apparently it was a bit of a disaster when Pi's and SD cards got fried from ESD and it was difficult to get everything communicating properly. We'll need to make sure we don't end making the same mistakes (which is trickey when we don't know exacly what those mistakes were).

@wjtan360-git have you tried using the * wildcard on the subscribers socket? I suspect it won't work as that is saying "listen to every IP address on the internet", but ZeroMQ does many fancy things under the hood so I could be wrong.

@jpas jpas mentioned this issue Oct 15, 2017
7 tasks
@ottopasuuna ottopasuuna added this to the IDR2017 milestone Oct 26, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants