How to setup ROS with Python 3

While working on ROS package for Anki Vector I had no choice but to use Python 3.6 as Anki’s Python SDK was specifically built for that version. Doing so I found that setting up ROS with Python 3 isn’t such a trivial task. It’s also not extremely complex, but there is no single guide that says exactly how to do it properly — so I decided to write one. This guide was written for ROS Melodic but a lot of it applies also for Kinetic.

In case you just started to build your Python 3 package and you want to make sure you’ve fixed all of the issues we're going to discuss beforehand, you can use a small ROS Package I wrote to reproduce them and see.

Also— ROS works best with Python 2 (as you probably know if you’re reading this), ROS2, on the other hand, was built with Python 3 in mind. So if you don’t need ROS(1) specifically but rather simply interested in developing for ROS using Python 3 you should consider moving to ROS2. Otherwise, follow these steps:

1. Basic Setup

  • Once you try to execute some script with python 3 shebang line(#!/usr/bin/env python3) you are going the get the following screaming error about some missing yaml library:
Traceback (most recent call last):
File "/catkin_ws/src/ros_python3_issues/src/issue_yaml.py", line 3, in <module>
import rospy
File "/opt/ros/melodic/lib/python2.7/dist-packages/rospy/__init__.py", line 47, in <module>
from std_msgs.msg import Header
File "/opt/ros/melodic/lib/python2.7/dist-packages/std_msgs/msg/__init__.py", line 1, in <module>
from ._Bool import *
File "/opt/ros/melodic/lib/python2.7/dist-packages/std_msgs/msg/_Bool.py", line 5, in <module>
import genpy
File "/opt/ros/melodic/lib/python2.7/dist-packages/genpy/__init__.py", line 34, in <module>
from . message import Message, SerializationError, DeserializationError, MessageException, struct_I
File "/opt/ros/melodic/lib/python2.7/dist-packages/genpy/message.py", line 44, in <module>
import yaml
ModuleNotFoundError: No module named 'yaml'
  • Don’t worry, open bash and install the following missing libraries:
sudo apt-get install python3-pip python3-yaml
sudo pip3 install rospkg catkin_pkg
  • And that’s it! now try executing your script again…

2. cv_bridge Issue

  • If you’ll try to use cv_bridge for OpenCV you are most likely to get the following exception:
Traceback (most recent call last):
File "/catkin_ws/src/ros_python3_issues/src/issue_cv_bridge.py", line 23, in <module>
ros_image = bridge.cv2_to_imgmsg(numpy.asarray(empty_image), encoding="rgb8") # convert PIL image to ROS image
File "/opt/ros/melodic/lib/python2.7/dist-packages/cv_bridge/core.py", line 259, in cv2_to_imgmsg
if self.cvtype_to_name[self.encoding_to_cvtype2(encoding)] != cv_type:
File "/opt/ros/melodic/lib/python2.7/dist-packages/cv_bridge/core.py", line 91, in encoding_to_cvtype2
from cv_bridge.boost.cv_bridge_boost import getCvType
ImportError: dynamic module does not define module export function (PyInit_cv_bridge_boost)
  • The issue is that cv_bridge is built only for python 2.7 so our python 3 interpreter is trying to use cv_bridge for 2.7 and fails, lets built it for Python 3:
  • First, let's install some tools we’ll need for the build process
sudo apt-get install python-catkin-tools python3-dev python3-numpy
  • Now, create new catkin_build_ws to avoid any future problems with catkin_make(assuming you are using it) and config catkin to use your python 3(3.6 in my case) when building packages:
mkdir ~/catkin_build_ws && cd ~/catkin_build_ws
catkin config -DPYTHON_EXECUTABLE=/usr/bin/python3 -DPYTHON_INCLUDE_DIR=/usr/include/python3.6m -DPYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.6m.so
catkin config --install
  • clone official vision_opencv repo:
mkdir src
cd src
git clone -b melodic https://github.com/ros-perception/vision_opencv.git
  • finally, let’s build and source the package:
cd ~/catkin_build_ws
catkin build cv_bridge
source install/setup.bash --extend
  • That’s it! now you can use cv_bridge from Python 3!

3. rostest Issue

... logging to /root/.ros/log/rostest-477a6ee2f64d-4170.log
[ROSUNIT] Outputting test results to /root/.ros/test_results/ros_python3_issues/rostest-test_test_issue_rosunit.xml
Traceback (most recent call last):
File "/catkin_ws/src/ros_python3_issues/test/issue_rosunit.py", line 18, in <module>
rostest.rosrun('ros_python3_issues', 'issue_rosunit', TestROSUnitIssue)
File "/opt/ros/melodic/lib/python2.7/dist-packages/rostest/__init__.py", line 146, in rosrun
result = rosunit.create_xml_runner(package, test_name, result_file).run(suite)
File "/opt/ros/melodic/lib/python2.7/dist-packages/rosunit/xmlrunner.py", line 275, in run
result.print_report(stream, time_taken, out_s, err_s)
File "/opt/ros/melodic/lib/python2.7/dist-packages/rosunit/xmlrunner.py", line 202, in print_report
stream.write(ET.tostring(self.xml(time_taken, out, err).getroot(), encoding='utf-8', method='xml'))
TypeError: write() argument must be str, not bytes
[Testcase: testissue_rosunit] ... ok
[ROSTEST]-----------------------------------------------------------------------SUMMARY
* RESULT: SUCCESS
* TESTS: 0
* ERRORS: 0
* FAILURES: 0
  • This issue was actually already solved but for some reason, it is not yet available on the apt repository so we’ll simply install it from source:
cd ~/catkin_ws/src
git clone https://github.com/ros/ros
cd ..
catkin_make_isolated --install --pkg rosunit -DCMAKE_BUILD_TYPE=Release --install-space /opt/ros/melodic
  • That’s it!

Found any other issue with ROS running Python 3 that I didn’t mention? Please, DM or email(beta_b0t@yahoo.com) me and I will update this post(with credits of course 😉).

References:

  1. https://answers.ros.org/question/237613/how-to-define-ros-kinetic-to-use-python3-instead-of-python27/
  2. https://github.com/OTL/cozmo_driver#super-hack-to-run-rospy-from-python3
  3. https://stackoverflow.com/questions/49221565/unable-to-use-cv-bridge-with-ros-kinetic-and-python3
  4. https://github.com/ros/ros/issues/158

@beta_b0t | betab0t.io

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store