ROS Subscriber not updating values with callback data
Hi,
I am trying to write a subscriber which subscribes to the /cf<id>/pose
topic (of the Crazyswarm ROS package) to retrieve the pose of my Crazyflie quadcopter, where <id>
is the index of the Crazyflie, which is 1 in my case since I am testing it with only one quadcopter for now. However, only the variable initialization (np.ones(3)
; np.ones(4)
) gets returned and not the updated value from the callback function. I have tried checking the contents of the topic's message with rostopic echo /cf<id>/pose
, and seem to be getting the correct real-time position of the robot. I have also tried using the global keyword within the callback function with no luck. Plus, initializing p
and theta
with None
returns the error:
TypeError: 'NoneType' object is not subscriptable.
What could I be doing wrong? I have pored over robotics.stackexchange and ROS Answers and tried every solution I could find, and am still getting the same results, so there is definitely something wrong with my code.
Here's my code:
import numpy as np
import math
import rospy
from geometry_msgs.msg import Pose
import tf
p = np.ones(3)
theta = np.ones(4)
def allPoseCallback(data):
global p
global theta
p = np.array(data.position)
theta = np.array(data.orientation)
def cfPoseSubscriber():
rospy.Subscriber('/cf1/pose', Pose, allPoseCallback)
allcfpose = {} #Initialize empty dictionary
allcfrpy = np.zeros((1,3)) #Array to hold roll pitch yaw values of one CF
if __name__ == '__main__':
rospy.init_node('cflistener', anonymous=True)
k = 0
while not rospy.is_shutdown():
cfPoseSubscriber()
allcfrpy[k,:] = np.array(tf.transformations.euler_from_quaternion(theta)) #Populate allcfrpy using rpy angles
allcfpose[f'cf{k+1}'] = np.array(p) #Populate dictionary using pose data
# k+=1
print(allcfpose)
print('\n----------------------------------\n')
print(allcfrpy)
Any help will be appreciated. Many thanks.
Asked by cenwerem on 2022-06-23 14:39:51 UTC
Answers
Your while loop has problems:
- Do not keep re-subscribing every time through the loop. Do it once before you enter the loop.
- You must sleep() inside the while loop. Use rospy.sleep(n), or use a rospy.Rate object.
To get started, try n = 0.250
Asked by Mike Scheutzow on 2022-06-23 19:15:36 UTC
Comments
Thank you for your response. I have effected the changes you highlighted, but I am still getting the same behavior; higher or lower values of the sleep period also do not change the result. I have also tried using empty arrays and can confirm that the callback isn't being called, because I get the empty arrays back exactly. I should also add that defining the variables, subscriber, and callback within a class yields similar results. Perhaps, there is some other way of initializing the p
and theta
variables other than None
or empty arrays that just might work. Thanks for your time and help.
Asked by cenwerem on 2022-06-23 22:15:55 UTC
I could not get this to work, but in the meantime, I've had to use the position()
method of the Crazyflie
class, which returns the real-time position of the Crazyflie. There isn't one for the attitude, but I only need the position currently and can just assume that all the robots are in a hover state for now.
Asked by cenwerem on 2022-06-24 10:47:30 UTC
If you add a try/except around the code in your subscribe callback, and print any exception that is thrown, you will likely discover what is wrong. I'm skeptical that np.array(data.position)
is valid code.
Asked by Mike Scheutzow on 2022-06-24 10:59:43 UTC
Yeah, I did take out the np.array
part in a later version of the code and left it just as data.position
, but still got empty values. Thanks, I didn't think of the try/except part. I'll add a try/except block in my callback to see if I can catch the error. Thank you.
Asked by cenwerem on 2022-06-24 18:38:32 UTC
I have this in the callback now, but the except block doesn't print anything. Is this implementation right? Thanks.
p = []
theta = []
def allPoseCallback(data):
try:
global p
global theta
p = data.position
theta = data.orientation
except len(p) == 0:
print("Callback didn't run!")
Asked by cenwerem on 2022-06-24 18:44:02 UTC
No, not right: position
is not an array. data
is a geometry_msgs/Pose
object, so position
is a geometry_msgs/Position
object. You can use rosmsg
terminal command to quickly see the structure:
rosmsg info geometry_msgs/Pose
Also, the except
keyword has to be followed by an Exception class type. Do an internet search for this.
Asked by Mike Scheutzow on 2022-06-25 08:32:06 UTC
Got it. Thanks.
Asked by cenwerem on 2022-06-25 10:17:34 UTC
I just wanted to add that the problem was because I was listening for the wrong message type in my subscriber function. The message type should have been PoseStamped
and not Pose
. Thanks to everyone for the help!
Asked by cenwerem on 2022-07-10 18:36:54 UTC
Comments
Since you have a main function it makes sense that all your global variables be defined under main, dont define anything outside it or it will be a confusion.
Asked by Ammar Albakri on 2022-06-24 03:19:17 UTC
Thanks, I've shifted the variables around, but usually run into a scoping problem outside the main environment. I've had to use a built-in method from the Crazyswarm package for my needs temporarily. See my comment below. Thank you for the help.
Asked by cenwerem on 2022-06-24 10:55:42 UTC