ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Python AttributeError occurs when running on ROS Noetic

asked 2020-08-30 13:10:37 -0500

Swaffles_Waffles gravatar image

updated 2020-09-18 13:33:37 -0500

sloretz gravatar image

Hello firends, I have a python code that I have successfully had running on a ROS melodic installation for some time. Now that we've decided to switch over to the new ROS Noetic (since joy got added recently) any time I try to kick off this python node I get:

Traceback (most recent call last):
  File "/home/casey/mqs_control/devel/lib/xbee/mqs_xbee.py", line 15, in <module>
    exec(compile(fh.read(), python_script, 'exec'), context)
  File "/home/casey/mqs_control/src/xbee/scripts/mqs_xbee.py", line 39, in <module>
    xbee = XBee.XBee("/dev/ttyUSB0")
AttributeError: module 'XBee' has no attribute 'XBee'

I was certain that this code works for both python 2.7 and 3, and have tried all manner of file renaming, permissions, different import calls to no avail. Any help would be greatly appreciated!

Thanks in advance, M

mqs_xbee.py:

'''#!/usr/bin/env python'''
import rospy
import XBee
from time import sleep
from xbee.msg import cmd_ctrl
from rospy.numpy_msg import numpy_msg

''' 
This node subscribes for data being changed on cmd_ctrl
 and publishes it to the XBEE. Data is coming in as
 a properly ordered bytearray in cmd_ctrl.msg
'''
def callback(cmds):
    rospy.loginfo("Rx: %s", cmds)
    rospy.loginfo(type(cmds))

''' sends data over the xbee'''
def xbee_send(cmds):
    # sends the data on the 16 channels
    channels_byte = bytearray()
    channels_byte.extend(cmds.cmds)
    # sent=xbee.Send(bytearray(channels_byte))
    xbee.Send(bytearray(channels_byte))

def mqs_xbee():
    rospy.init_node('mqs_xbee', anonymous=True)
    # subscribe to cmd_ctrl
    rospy.Subscriber("cmds", numpy_msg(cmd_ctrl), xbee_send)
    # for debugging
    rospy.Subscriber("cmds", numpy_msg(cmd_ctrl), callback) 

    rospy.spin()

if __name__ == "__main__":
    xbee = XBee.XBee("/dev/ttyUSB0")
    mqs_xbee()'

XBee.py

import serial
from collections import deque


class XBee:
    RxBuff = bytearray()
    RxMessages = deque()

    def __init__(self, serialport, baudrate=115200):
        self.serial = serial.Serial(port=serialport, baudrate=baudrate)

    def Receive(self):
        """
            Recieves data from serial and checks buffer for potential messages/
            Returns the next message in the queue if available
        """
        remaining = self.serial.inWaiting()
        while remaining:
            chunk = self.serial.read(remaining)
            remaining -= len(chunk)
            self.RxBuff.extend(chunk)

            msgs = self.RxBuff.split(bytes(b'\x7E'))
            for msg in msgs[:-1]:
                self.validate(msg)

            self.RxBuff = (bytearray() if self.Validate(msgs[-1]) else msgs[-1])

            if self.RxMessages:
                return self.RxMessages.popleft()
            else:
                return None

    def Validate(self, msg):
        """
        Parses a byte or bytearray object to verify the contents are a properly formatted XBee message.

        Inputs: An incoming XBee message

        Outputs: True or False, indicating message validity
        """
        # 9 bytes is Minimum length to be a valid Rx frame
        # LSB, MSB,Type, Source Address(2), RSSI, Options, 1 byte data, checksum
        if (len(msg) - msg.count(bytes(b'0x7D'))) < 9:
            return False

        # All bytes in message must be unescaped before validating content
        frame = self.Unescape(msg)

        LSB = frame[1]
        # Frame (minus checksum) must contain at least length equal to LSB
        if LSB > (len(frame[2:]) - 1):
            return False

        # Validate checksum
        if (sum(frame[2:3 + LSB]) & 0xFF) != 0xFF:
            return False

        print("Rx: " + self.format(bytearray(b'\x7E') + msg))
        self.RxMessages.append ...
(more)
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2020-08-31 11:24:16 -0500

sloretz gravatar image

updated 2020-09-18 13:43:54 -0500

Edit Thanks for posting the CMakeLists.txt output!

It seems mqs_xbee.py expects to be able to import XBee.py installed adjacent to it, which is an assumption that doesn't hold in all circumstances in ROS Noetic. catkin_install_python() is for installing scripts that are meant to be run directly, not imported. I would recommend solving this by installing the code in XBee.py as a python package.

This means adding catkin_python_setup() to your CMakeLists.txt, a setup.py, and maybe making a folder with an __init__.py. See the catkin documentation for more info.

For a practical example of a package that has both Python scripts and modules check out urdf_parser_py.

Original answer below


AttributeError: module 'XBee' has no attribute 'XBee'

This error says import XBee succeeded, but Python didn't find anything in that module called XBee. This is strange because the XBee.py file you posted definitely has a class XBee. I would try debugging this by adding print statements to see what module was imported.

if __name__ == "__main__":
    # Figure out what file python imported for the XBee module
    import inspect
    print(inspect.getsourcefile(XBee))

    # Print the attributes that are available on the XBee module
    print(dir(XBee))

    # xbee = XBee.XBee("/dev/ttyUSB0")
    # mqs_xbee()

That will give useful info for debugging the issue.

edit flag offensive delete link more

Comments

Hi Sloretz, This is what I get after running the inspect:

~/mqs_control/devel/lib/xbee/XBee.py directories available: ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'context', 'fh', 'python_script']

To my eye it looks like it's not looking in the correct directory for XBee.py. I checked my working melodic version and it does not have an XBee.py or even an xbee folder located in ~/mqs_control/devel/lib. Furthermore, the melodic version does successfully import the XBee module as well as serial and deque as shown below.

output from running same code on melodic version:

Attributes available: ['XBee','__builtins__', '__doc__', '__file__', '__name__', '__package__', 'deque', 'serial']

edit: Xbee.py exists in ~/mqs_control/devel/lib from the CMakeLists.txt where the python scrpts are included under the install section.

Swaffles_Waffles gravatar image Swaffles_Waffles  ( 2020-08-31 12:03:49 -0500 )edit

Mind updating your original question with the content of ~/mqs_control/devel/lib/xbee/XBee.py? That would help understand what it is. Also, mind posting the part of the CMakeLists.txt of the install section you mentioned?

sloretz gravatar image sloretz  ( 2020-08-31 12:30:17 -0500 )edit

Updates are posted as well as the changes I made to the package.xml for this xbee specific ros package

Swaffles_Waffles gravatar image Swaffles_Waffles  ( 2020-08-31 14:23:58 -0500 )edit

Updated answer with possible solution

sloretz gravatar image sloretz  ( 2020-09-18 13:44:09 -0500 )edit

Question Tools

2 followers

Stats

Asked: 2020-08-30 13:10:37 -0500

Seen: 1,243 times

Last updated: Sep 18 '20