pythonrossensor-fusion

Python callback attribute error


I have written a python ROS node to subscribe to two different topics and uses the ApproximateTimeSynchroniser to basically to match the messages via their timestamp and bundle these messages into one callback routine. If I use the callback to simply print out the two messages received it works fine.

However, I would like to populate a geometry_msgs/Pose message using the x and y positions from the received Pose 2D data in the callback routine.Using the code below, I have done this by making an empty Pose object in the callback routine:

  #!/usr/bin/env python


import message_filters
import rospy
from laser_line_extraction.msg import LineSegmentList
from geometry_msgs.msg import Pose,  Pose2D
from std_msgs.msg import Int32, Float32

rospy.init_node('simul-subscriber')

def callback(Pose2D, LineSegmentList): 
 pose = Pose()
 pose.position.x =  Pose2D.position.x 
 pose.position.y =  Pose2D.position.y 
 pose.position.z = 0
 #print(Pose2D,  LineSegmentList, pose)
 print(pose)
 print(LineSegmentList)

line_segment_sub = message_filters.Subscriber('/line_segments', LineSegmentList)
pose_2D_sub = message_filters.Subscriber('/pose2D',Pose2D)

ts = message_filters.ApproximateTimeSynchronizer([line_segment_sub, pose_2D_sub], 10, 0.1, allow_headerless=True)
ts.registerCallback(callback)

rospy.spin()

Unfortunately, this gives a weird error when running this node:

[ERROR] [1535552711.709928, 1381.743000]: bad callback: <bound method Subscriber.callback of <message_filters.Subscriber object at 0x7f7af3cee9d0>>
Traceback (most recent call last):
  File "/opt/ros/kinetic/lib/python2.7/dist-packages/rospy/topics.py", line 750, in _invoke_callback
    cb(msg)
  File "/opt/ros/kinetic/lib/python2.7/dist-packages/message_filters/__init__.py", line 75, in callback
    self.signalMessage(msg)
  File "/opt/ros/kinetic/lib/python2.7/dist-packages/message_filters/__init__.py", line 57, in signalMessage
    cb(*(msg + args))
  File "/opt/ros/kinetic/lib/python2.7/dist-packages/message_filters/__init__.py", line 287, in add
    self.signalMessage(*msgs)
  File "/opt/ros/kinetic/lib/python2.7/dist-packages/message_filters/__init__.py", line 57, in signalMessage
    cb(*(msg + args))
  File "/home/elisabeth/catkin_ws/src/hector_quadrotor/hector_quadrotor_demo/python_scripts/simul-subscriber.py", line 14, in callback
    pose.position.x =  Pose2D.position.x
AttributeError: 'LineSegmentList' object has no attribute 'position'

This is odd as the position attribute is only referenced for the Pose 2D and not the LineSegmentList msg. I suspect this is most a python issue than a ROS issue, any help somebody could give would be much appreciated!

I am following the example found at http://wiki.ros.org/message_filters where they took two different topics image and cameraInfo and passed them into the callback function

  1 import message_filters
   2 from sensor_msgs.msg import Image, CameraInfo
   3 
   4 def callback(image, camera_info):
   5   # Solve all of perception here...
   6 
   7 image_sub = message_filters.Subscriber('image', Image)
   8 info_sub = message_filters.Subscriber('camera_info', CameraInfo)
   9 
  10 ts = message_filters.TimeSynchronizer([image_sub, info_sub], 10)
  11 ts.registerCallback(callback)
  12 rospy.spin()

Solution

  • You confuse class names with object names. The fix to your program should be straight forward. I've changed Pose2D to pose2d, and LineSegmentList to linesegmentlist where it was necessary and comented it with # --- Change ...:

    #!/usr/bin/env python
    import message_filters
    import rospy
    from laser_line_extraction.msg import LineSegmentList
    from geometry_msgs.msg import Pose,  Pose2D
    from std_msgs.msg import Int32, Float32
    
    rospy.init_node('simul-subscriber')
    
    # --- CHANGE: using proper object names instread of class names
    def callback(pose2d, linesegmentlist): 
     pose = Pose()
     # --- CHANGE: using the object
     pose.position.x =  pose2d.position.x 
     pose.position.y =  pose2d.position.y 
     pose.position.z = 0
     #print(pose2d,  linesegmentlist, pose)
     print(pose)
     print(linesegmentlist)
    
    line_segment_sub = message_filters.Subscriber('/line_segments', LineSegmentList)
    pose_2D_sub = message_filters.Subscriber('/pose2D',Pose2D)
    
    ts = message_filters.ApproximateTimeSynchronizer([line_segment_sub, pose_2D_sub], 10, 0.1, allow_headerless=True)
    ts.registerCallback(callback)
    
    rospy.spin()