SGM
SGM

Reputation: 151

How to publish/subscribe a python “list of list” as topic in ROS

I am new to ROS and rospy, and I am not familiar with non-simple data type as topic.

I want to build a ROS node as both a subscriber and publisher: it receives a topic (a list of two float64), and uses a function (say my_function) which returns a list of lists of float64, then publish this list of list as a topic.

To do this, I built a node as following:

from pymongo import MongoClient
from myfile import my_function
import rospy
import numpy as np

pub = None
sub = None

def callback(req):
    client = MongoClient()
    db = client.block
    lon = np.float64(req.b)
    lat = np.float64(req.a)
    point_list = my_function(lon, lat, db)
    pub.publish(point_list)

def calculator():
    global sub, pub
    rospy.init_node('calculator', anonymous=True)
    pub = rospy.Publisher('output_data', list)
    # Listen
    sub = rospy.Subscriber('input_data', list, callback)
    print "Calculation finished. \n"
    ros.spin()

if __name__ == '__main__':
    try:
        calculator()
    except rospy.ROSInterruptException:
        pass

I know clearly that list in Subscriber and Publisher is not a message data, but I cannot figure out how to fix it since it is not an integer nor list of integer.

Upvotes: 6

Views: 10809

Answers (3)

Maciek Woźniak
Maciek Woźniak

Reputation: 455

I agree with the solution, I thought about organizing it a bit more

  1. Create a file FloatArray.msg in your catkin_ws in the src folder where you have all your other message files.

  2. Build your env using catkin_make or catkin build.

  3. In your script (e.g. Python script) import the message type and use it in the subscriber e.g.

    joint_state_publisher_Unity = rospy.Publisher("/joint_state_unity", FloatArray , queue_size = 10)

specific case (bonus :)): if you are using Unity and ROS# build the message in Unity

Upvotes: 0

adamconkey
adamconkey

Reputation: 4745

This post on the ROS forums gives you most of what you need. This is also useful. You can define a new message type FloatList.msg with the following specification:

float64[] elements

And then a second message type FloatArray.msg defined as:

FloatList[] lists

Then your function could look like:

def callback(req):
    client = MongoClient()
    db = client.block
    lon = np.float64(req.b)
    lat = np.float64(req.a)
    point_list = my_function(lon, lat, db)
    float_array = FloatArray()
    for i in range(len(point_list)):
        float_list = FloatList()
        float_list.elements = point_list[i]
        float_array.lists[i] = float_list
    pub.publish(float_array)

And then you can unpack it with:

def unpack_callback(float_array_msg):
    for lst in float_array_msg.lists:
        for e in lst.elements:
            print "Here is an element: %f" % e

In general, it is recommended you put ROS related questions on the ROS Forums since you are way more likely to get an answer to your question there.

Upvotes: 5

You can complicate yourself by defining a new ros Type in the msg OR use the default and easy to implement std_msgs Type, maybe will be useful to use a json module, so you serialize the data before publishing and deserialize it back on the other side after receiving...

the rest Pub/Sub , topic and handlers remain the same :)

Upvotes: 1

Related Questions