0
$\begingroup$

Rosanswers logo

Hello everyone,

I am trying to publish a Float64MultiArray using python, this is what I have so far.

Code:

import rospy
from std_msgs.msg import Float64MultiArray    

TOPIC_NAME = 'waypoints'
NODE_NAME = 'waypoints_publisher'

def post_coordinates():
    pub = rospy.Publisher('waypoints', Float64MultiArray, queue_size=10) # TOPIC
    rospy.init_node('waypoints_publisher', anonymous=True)
    rate = rospy.Rate(1) # 10hz

while not rospy.is_shutdown():
    my_msg = Float64MultiArray()
    d=[[1.2354567, 99.7890, 67.654236], [67.875, 90.6543, 76.5689], [65.3452, 45.873, 67.8956]]
    my_msg.data = d
    pub.publish(my_msg)

    rospy.loginfo('SEND DATA: \n%s', my_msg)
    rate.sleep()

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

I get the following error when trying to run the code:

 Traceback (most recent call last):
 File "/opt/ros/noetic/lib/python3/dist-packages/std_msgs/msg/_Float64MultiArray.py", line 112, in serialize
    buff.write(struct.Struct(pattern).pack(*self.data))
struct.error: required argument is not a float



During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 882, in publish
    self.impl.publish(data)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 1066, in publish
    serialize_message(b, self.seq, message)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/msg.py", line 152, in serialize_message
    msg.serialize(b)
  File "/opt/ros/noetic/lib/python3/dist-packages/std_msgs/msg/_Float64MultiArray.py", line 113, in serialize
    except struct.error as se: self._check_types(struct.error("%s: '%s' when writing '%s'" % (type(se), str(se), 
str(locals().get('_x', self)))))
  File "/opt/ros/noetic/lib/python3/dist-packages/genpy/message.py", line 393, in _check_types
    check_type(n, t, getattr(self, n))
  File "/opt/ros/noetic/lib/python3/dist-packages/genpy/message.py", line 314, in check_type
    check_type(field_name + '[]', base_type, v)
  File "/opt/ros/noetic/lib/python3/dist-packages/genpy/message.py", line 273, in check_type
    raise SerializationError('field %s must be float type' % field_name)
genpy.message.SerializationError: field data[] must be float type

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/ubuntu/catkin_ws/devel/lib/robotics_demo/waypoint_publisher.py", line 15, in <module>
    exec(compile(fh.read(), python_script, 'exec'), context)
  File "/home/ubuntu/catkin_ws/src/robotics_demo/scripts/waypoint_publisher.py", line 25, in <module>
   post_coordinates()
  File "/home/ubuntu/catkin_ws/src/robotics_demo/scripts/waypoint_publisher.py", line 18, in post_coordinates
   pub.publish(my_msg)
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 886, in publish
    raise ROSSerializationException(str(e))
rospy.exceptions.ROSSerializationException: field data[] must be float type

I already tried adding this:

d=[[float(d[i][j]) for j in range(len(d))] for i in range(len(d[0]))]

exactly before :

 my_msg.data = d

the error remains the same. What am I doing wrong?

This is my endpoint.py

#!/usr/bin/env python

import rospy

from ros_tcp_endpoint import TcpServer, RosSubscriber
from std_msgs.msg import Float64MultiArray


def main():
    ros_node_name = rospy.get_param("/TCP_NODE_NAME", 'TCPServer')
    buffer_size = rospy.get_param("/TCP_BUFFER_SIZE", 1024)
    connections = rospy.get_param("/TCP_CONNECTIONS", 10)
    tcp_server = TcpServer(ros_node_name, buffer_size, connections)
    rospy.init_node(ros_node_name, anonymous=True)

    tcp_server.start({
        'waypoints': RosSubscriber('waypoints', Float64MultiArray, tcp_server),
    })

    rospy.spin()


if __name__ == "__main__":
    main()

Originally posted by panserzap on ROS Answers with karma: 3 on 2021-06-23

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

You try to assign a list of lists to my_msg.data. my_msg.data is, however, a list of floats only. How you order the single values needs to be specified in the MultiArrayLayout part my_msg.layout.


EDIT

Not quire sure what the ros_tcp_endpoint expects and if it can handle arbitrary msgs.

If it can handle arbitrary messages, I'd go for something more descriptive for a waypoint, then a FloatMultiArray. You could use e.g. a nav_msgs/Path or a geometry_msgs/PoseArray. Or even create your own Waypoint message, e.g. as a list of geometry_msgs/Point.

If, for some reason, you are limited to use a FloatMultiArray, I'd do something along the lines of (rough sketch, so no guarantee that it works, but you should get the idea)

p1 = [x,y,z] # create all the points until pn
my_msgs.data = [*p1, ..., *pn]
my_msgs.layout.data_offset =  0 # no padding
dim = []
dim.append(MultiArrayDimension("points", n, 3*n))
dim.append(MultiArrayDimenstion("coords", 3, 1))
my_msgs.layout.dim = dim

Originally posted by mgruhler with karma: 12390 on 2021-06-23

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by panserzap on 2021-06-23:
Thank you for the guidance. I now understand what I am doing wrong. I have already read the documentation though, but I haven't been able to fully understand it. Could you give me an example either to my specific case or to a similar one?

EDIT

I believe "Or even create your own Waypoint message, e.g. as a list of geometry_msgs/Point." is the best choice for me. Since it is currently working after following your example I will keep it as it is for now. Thank you for the fast and detailed answer. Wunsche einen schönen Tag!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.