Service return array of arrays
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 ?
Asked by sisko on 2020-08-01 20:12:07 UTC
Answers
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.
Asked by Weasfas on 2020-08-02 07:16:37 UTC
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
Asked by sisko on 2020-08-03 04:02:54 UTC
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.
Asked by Weasfas on 2020-08-03 12:10:56 UTC
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] ]
Asked by sisko on 2020-08-03 12:22:30 UTC
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'
Asked by sisko on 2020-08-04 02:07:26 UTC
@sisko I have edited my answer with a working solution.
Asked by Weasfas on 2020-08-04 05:06:43 UTC
Comments