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

2.4k Views Asked by At

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!

2

There are 2 best solutions below

0
J.V. On BEST ANSWER

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.

0
Andrei Vukolov On

The source directory of your package should be added to PYTHONPATH list.

The best way to do this is described here in the ROS documentation. Create setup.py file in the root directory of the package containing delisted src directory:

setup_args = generate_distutils_setup(
    packages=['package'],
    package_dir={'': 'src'},
)

Then use catkin_python_setup() function in CMakeLists.txt to list your src directory in the PYTHONPATH for the sourced workspace.