Search code examples
python-2.7rospublishersubscriber

Python global variables not available in function


I am using the following code to read sensor data, process it and publish some feedback to a different topic, /scans_freespace.

#!/usr/bin/env python

import rospy
from rospy.core import is_shutdown
from sensor_msgs.msg import LaserScan
from sweep_bot.msg import Space
from sweep_bot.msg import SpaceArray

class FreeSpace :

    def __init__(self) :
        rospy.loginfo('starting')
        self.scans = ()
        self.regions = {}
        self.publisher = self.subscriber = ''
        
    def callbackScans(self, data) :
        self.scans = data.ranges
        self.regions = {
            'starboard_aft' : self.scans[0:135],
            'starboard_abeam_aft' : self.scans[136:271],
            'starboard_abeam_bow' : self.scans[272:407],
            'starboard_bow' : self.scans[408:543],
            'port_aft' : self.scans[949:1084],
            'port_abeam_aft' : self.scans[814:949],
            'port_abeam_bow' : self.scans[679:814],
            'port_bow' : self.scans[544:679],
        }

    def publish(self) :
        self.getSomeData('port_bow')

    def getSomeData(self, region) :
        rospy.loginfo("Checking region: %s", region)
        rospy.loginfo("Checking scans: %s", self.scans)

        return self.scans[region]
        
    
if __name__ == '__main__' :
    rospy.init_node('space_identifier')
    rate = rospy.Rate(10)
    spacer = FreeSpace()

    subscriber = rospy.Subscriber("scans", LaserScan, spacer.callbackScans)
    publisher  = rospy.Publisher("scans_freespace", SpaceArray, queue_size=10)

    while not rospy.is_shutdown() :
        spacer.publish()
        rate.sleep()

As the code shows, I am calling the getSomeData() function from my publish() function passing a single string argument. getSomeData() receives the argument as expected but the global variables which are populated from the callbackScan() function are empty.

The output from the script is as follow:

[INFO] [1629830370.246796, 0.000000]: starting
[INFO] [1629830370.253719, 0.000000]: Checking region: port_bow
[INFO] [1629830370.256151, 0.000000]: Checking scans: ()
Traceback (most recent call last):
  File "/home/sisko/catkin_ws/src/sweepbot/Sweeper/sweep_bot/src/freespace.py", line 49, in <module>
    spacer.publish()
  File "/home/sisko/catkin_ws/src/sweepbot/Sweeper/sweep_bot/src/freespace.py", line 31, in publish
    self.getSomeData('port_bow')
  File "/home/sisko/catkin_ws/src/sweepbot/Sweeper/sweep_bot/src/freespace.py", line 37, in getSomeData
    return self.scans[region]
TypeError: tuple indices must be integers, not str

Ironically, the code did work until I attempted to update my output.

What am I missing?


Solution

  • There are a few things wrong here. However, your error is because you do not properly initialize your message fields. This in turn causes issue when publish() is called before a LaserScan message is received. As well, ranges is a std_msg/Float32[] so even if it was assigned correctly in the callback you'd have another error when trying to index a float list with a string. It is a little unclear as to what you want to do, but looking at the key names getSomeData() should look something more like this:

    def getSomeData(self, region) :
        rospy.loginfo("Checking region: %s", region)
        rospy.loginfo("Checking scans: %s", self.scans)
    
        return self.regions[region] if region in self.regions else None
    

    Another point to make is if you're hoping to publish the results of this function out via the publish() function, you need to actually define a publisher inside your class with the correct type.