Search code examples
pythonimportroscatkincmakelists-options

Importing python files/functions from the same directory in ROS (as simple as it sounds!)


I've managed to run in an incredible issue that me and my friend just are not able to solve. Luckily, we managed to replicate the issue in the example talker.py and listener.py. My issue is that I cannot seem to import any function from another python file, even when these files are located in the same folder as the talker.py file.

Here is the code (you just need talker.py for this):

#!/usr/bin/env python

import rospy
from sum import Sum
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    print(Sum(1,2))
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

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

the sum.py:

#!/usr/bin/env python

def Sum(a,b):
     return a + b

And what I have added to the CMakeLists.txt file:

catkin_install_python(PROGRAMS
  scripts/talker.py scripts/listener.py scripts/sum.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

after doing catkin_make, source devel/setup.bash, and rosrun test talker.py I get the output:

Traceback (most recent call last):
  File "/home/-/catkin_ws/devel/lib/test/talker.py", line 15, in <module>
    exec(compile(fh.read(), python_script, 'exec'), context)
  File "/home/-/catkin_ws/src/test/scripts/talker.py", line 40, in <module>
    from sum import Sum
ImportError: cannot import name 'Sum' from 'sum' (/home/-/catkin_ws/devel/lib/test/sum.py)

where test is the name that I gave the package (not the smartest name, but it doesn't conflict right now). Things I have tried (to no avail):

  1. add import rospy to the sum.py file
  2. use catkin build test instead of catkin_make
  3. use the setup.py file
  4. use a blank init.py file (per another answer on StackOverflow)

I'm quite frankly at a loss on what to do. It seems like such a fundamental thing to do, that I'm afraid I'm missing something extremely obvious. However, after a lot of search engine work, it seems that no one has had such as simple problem before (most of what I find relates to importing functions/files/modules from different packages, etc.)

Any help or hints would be really appreciated!


Solution

  • I appreciate Andrei and John's help. Hopefully, this answer can help someone that stumbles upon the same importing issue.

    I'm not quite sure what the underlying problem is, yet allow me to show the structure that removes the error:

    CMakeLists.xtx:

    cmake_minimum_required(VERSION 3.0.2)
    project(test_package)
    
    ## Find catkin macros and libraries
    ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
    ## is used, also find other catkin packages
    find_package(catkin REQUIRED COMPONENTS
      message_generation
      rospy
      std_msgs
    )
    
    catkin_package(
    #  INCLUDE_DIRS include
    #  LIBRARIES test
    #  CATKIN_DEPENDS rospy std_msgs message_runtime
    #  DEPENDS system_lib
    )
    
    ## Specify additional locations of header files
    ## Your package locations should be listed before other locations
    include_directories(
    # include
      ${catkin_INCLUDE_DIRS}
    )
    
    ## Mark executable scripts (Python etc.) for installation
    ## in contrast to setup.py, you can choose the destination
    catkin_install_python(PROGRAMS
      src/talker.py 
      src/listener.py #src/test_package/sum.py
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )
    

    package.xml

    <?xml version="1.0"?>
    <package format="2">
      <name>test_package</name>
      <version>0.0.0</version>
      <description>The test package</description>
    
      <maintainer email="[email protected]">anon</maintainer>
    
      <license>TODO</license>
    
      <buildtool_depend>catkin</buildtool_depend>
    
      <build_depend>message_generation</build_depend>
      <build_depend>rospy</build_depend>
      <build_depend>std_msgs</build_depend>
    
      <build_export_depend>rospy</build_export_depend>
      <build_export_depend>std_msgs</build_export_depend>
    
      <exec_depend>rospy</exec_depend>
      <exec_depend>std_msgs</exec_depend>
    
      <export>
    
      </export>
    </package>
    

    setup.py

    ## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
    from distutils.core import setup
    from catkin_pkg.python_setup import generate_distutils_setup
    # fetch values from package.xml
    setup_args = generate_distutils_setup(
    packages=['test_package'],
    package_dir={'': 'src'},
    )
    setup(**setup_args)
    

    talker.py

    #!/usr/bin/env python
    
    import rospy
    from test_package.sum import Sum
    from std_msgs.msg import String
    
    def talker():
        pub = rospy.Publisher('chatter', String, queue_size=10)
        print(Sum(1,2))
        rospy.init_node('talker', anonymous=True)
        rate = rospy.Rate(10) # 10hz
        while not rospy.is_shutdown():
            hello_str = "hello world %s" % rospy.get_time()
            rospy.loginfo(hello_str)
            pub.publish(hello_str)
            rate.sleep()
    
    if __name__ == '__main__':
        try:
            talker()
        except rospy.ROSInterruptException:
            pass
    

    And most importantly, the file structure:

    catkin_ws/src/test_package
        /src
            /test_package
                __init__.py
                sum.py
            talker.py
            listener.py
        CmakeLists.txt
        package.xml
        setup.py
    

    where I build with catkin build, then source devel/setup.bash and rosrun test_package talker.py after running an instance of roscore. Given the location of the __init__.py and the setup.py file, I suspect something went wrong there initially.