Ask Your Question
0

Service return array of arrays

asked 2020-08-01 20:12:07 -0500

sisko gravatar image

updated 2020-08-03 03:59:41 -0500

UPDATED AFTER VERY HELPFUL RESPONSE FROM Weasfas:

I have created a service which I want to return and array which contains array elements of the following structure:

[
    ['/turtle1/color_sensor', 'turtlesim/Color'],
    ['/client_count', 'std_msgs/Int32'],
    ['/rosout', 'rosgraph_msgs/Log'], 
]

To achieve the structure, I created the following message type, Topic.msg :

string name 
string type

And in my FetchTopics.srv file I defined the request, response of my service as follows:

---
Topic[] topics

Catkin_make executes successfully. When I call my service I get the following error:

ERROR: service [/fetch_topics] responded with an error: error processing request: Invalid number of arguments, args should be ['topics'] args are(['/turtle1/color_sensor', 'turtlesim/Color'], ['/client_count', 'std_msgs/Int32'], ['/rosout', 'rosgraph_msgs/Log'])

Here is the code in my topics_server.py:

from topics_lister.srv import FetchTopics, FetchTopicsResponse
import rospy
from topics_lister.msg import Topic

def sendTopics(request):
    # print("%s" %request)
    print("_________________________")

    return FetchTopicsResponse(
        ['/turtle1/color_sensor', 'turtlesim/Color'],
        ['/client_count', 'std_msgs/Int32'],
        ['/rosout', 'rosgraph_msgs/Log'],
    )

rospy.init_node('fetch_topics_server')
s = rospy.Service('fetch_topics', FetchTopics, sendTopics)
print ("Serving topics ...")
rospy.spin()

Can someone tell me if my approach is correct and if it is, how do I solve the error above ?

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
1

answered 2020-08-02 07:16:37 -0500

Weasfas gravatar image

updated 2020-08-04 05:08:24 -0500

Hi @sisko,

You cannot do that since the definition is not well formed. As well as you cannot do string[][] topic since only one dimension is supported in msg definition. What you can do to achieve what you want can split into several approaches:

  • Either you define a custom message containing a String array:

StringArray.msg

string[] topic

And then use it in your srv file like:

TopicList.srv

StringArray topic
---
StringArray[] topics

List item

  • Or just implement a custom msg Multiarray like Float32Multiarray but StringMultiarray that let you declare a multi dimensional variable. It would be something like:

StringMultiarray.msg

std_msgs/MultiArrayLayout layout
string[] data

and TopicList.srv

string[] topic
---
StringMultiArray topics

Hope that can help you solving the problem.

Regards.

EDIT:

@sisko, I had implemented a client and service nodes to test your set up and I was able to make it work without errors. I used the follosing code:

For the server_node:

#!/usr/bin/env python

from topics_lister.srv import FetchTopics, FetchTopicsResponse
from topics_lister.msg import Topic
import rospy

def sendTopics(request):
    print("_________________________")
    msg_topic_1 = Topic('/turtle1/color_sensor', 'turtlesim/Color')
    msg_topic_2 = Topic('/client_count', 'std_msgs/Int32')

    response = FetchTopicsResponse()
    response.topics = [msg_topic_1, msg_topic_2]

    return response


def fetch_topics_server():
    rospy.init_node('fetch_topics_server')
    s = rospy.Service('fetch_topics', FetchTopics, sendTopics)
    print ("Serving topics ...")
    rospy.spin()

if __name__ == "__main__":
    fetch_topics_server()

And for the client_node:

#!/usr/bin/env python

import sys
import rospy
from topics_lister.srv import *
from topics_lister.msg import *

def fetch_topic_client(data):
    rospy.wait_for_service('fetch_topics')
    try:
        fetch_topics = rospy.ServiceProxy('fetch_topics', FetchTopics)
        resp1 = fetch_topics(data)
        return resp1.topics
    except rospy.ServiceException as e:
        print("Service call failed: %s"%e)

def usage():
    return "%s [data]"%sys.argv[0]

if __name__ == "__main__":
    if len(sys.argv) == 2:
        data = sys.argv[1]
    else:
        print(usage())
        sys.exit(1)
    print("Requesting topics...")
    print(fetch_topic_client("place_holder"))

Since yu only provided the response of the srv I assume the full definition is:

string req_data
---
Topic[] topics

But you can change that easily.

edit flag offensive delete link more

Comments

Hello.

Thank you very much for your answer. It was very helpful and I used it to correct my approach. Unfortunately, I still encountered problems.

I have amended my question with my updated approach and I would really appreciate your input.

Thanks again

sisko gravatar image sisko  ( 2020-08-03 04:02:54 -0500 )edit

Correct me if I am mistaken but as your definition says you need a Topic array, that means that you will need first to declare you Topic variables and then add those to the topics array. It would be something like:

msg_topic_1 = Topic(name = '/turtle1/color_sensor', type =  'turtlesim/Color')
msg_topic_2 = Topic(name = '/client_count', type = 'std_msgs/Int32')
msg_topic_3 = Topic(name = '/rosout', type = 'rosgraph_msgs/Log')

response = FetchTopics()
response.topics = [msg_topic_1 , msg_topic_2 , msg_topic_3 ]

I have not tested this code but it would be something like that.

Weasfas gravatar image Weasfas  ( 2020-08-03 12:10:56 -0500 )edit

Hello again @Weasfas

You are quite correct. I suspect your code should work and I will try it later when I return to working on the ROS side of my project.

I have been trying to find a solution that would allow my to provide the output of the rospy.get_published_topics() as an argument and have the array indexes be separate Topics. The function returns multiple array indexes in the format: [ [topic, type] ...... [topic, type] ]

sisko gravatar image sisko  ( 2020-08-03 12:22:30 -0500 )edit

Your code makes sense but FetchTopics() seems to be inaccurate. I replaced it with FetchTopicsResponse(), but correct me if I'm wrong. In fact, why not just share my code:

from topics_lister.srv import FetchTopics, FetchTopicsResponse
import rospy
from topics_lister.msg import Topic

def sendTopics(request):
    print("_________________________")
    msg_topic_1 = Topic('/turtle1/color_sensor', 'turtlesim/Color')

    response = FetchTopicsResponse()
    response.topics = [msg_topic_1]

    return response

rospy.init_node('fetch_topics_server')
s = rospy.Service('fetch_topics', FetchTopics, sendTopics)
print ("Serving topics ...")
rospy.spin()

Then:

catkin_make && clear && rosrun topics_lister topics_server

and:

clear && rosservice call /fetch_topics

I get the following error:

ERROR: service [/fetch_topics] responded with an error: error processing request: 'list' object has no attribute 'name'
sisko gravatar image sisko  ( 2020-08-04 02:07:26 -0500 )edit

@sisko I have edited my answer with a working solution.

Weasfas gravatar image Weasfas  ( 2020-08-04 05:06:43 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2020-08-01 20:12:07 -0500

Seen: 519 times

Last updated: Aug 04 '20