This document explains the necessary configurations for building, running, and including files in a ROS 2 package's [setup.py](<http://setup.py>)
file. It covers the data_files
and entry_points
variables, which are used to include additional files in the package build and declare package scripts as nodes, respectively. It also provides code examples for adding files and shortcuts for including all files within a specific directory and its subfolders.
The setup.py
file in your ROS 2 package includes the necessary configurations for building, running, and including files in your robot application. A freshly created package will have a setup.py
like below:
<aside>
💡 The package_name
variable will have the name of your specific ROS 2 package.
</aside>
from setuptools import setup
package_name = 'example_package'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='yourname',
maintainer_email='[email protected]',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'example_package = example_package.example_package:main'
],
},
)
The first lines of code are used to import the required packages for the setup.py file. A freshly made package will only have one import, but as the package grows, it may have many more.
from setuptools import setup
After the imports is a space to declare global variables or function definitions to be used in the setup()
tag.
package_name = 'example_pacakge'
Within the setup tag are the necessary configurations for your ROS 2 package. All variables have a purpose, but the most important ones to understand are the data_files
and entry_points
.
The data_files
tag has some standard inclusions that all Python packages need.
data_files = [
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
When adding additional files to be included in your package build, ensure that these base package files are still included. To add recognizable files (like .launch.py
, .urdf
, and .yaml
) to your ROS package, the file paths have to be added to the data_files
array. Adding a singular folder or file can be done by adding the following lines:
data_files = [
(share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
#To add a singular file, use:
(os.path.join('share',package_name,'config','controller.yaml')),
#To add all files in a /launch/ folder with the .launch.py file tag, use:
(os,path.join('share',package_name,'launch'), glob(os.path.join('launch','*.launch.py'))),
The first line additions add a controller.yaml
file from the config
folder to the ROS package. The second line additions add the package subfolder launch
and includes all contained files with the suffix .launch.py
.
Using this method, including multiple different file types, or a subfolder within the included folder would be tedious. A useful shortcut to include all files within a specific directory and its subfolders is shown below.
import os
data_files = [
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
]
def package_files(data_files, directory_list):
paths_dict = {}
for directory in directory_list:
for (path, directories, filenames) in os.walk(directory):
for filename in filenames:
file_path = os.path.join(path, filename)
install_path = os.path.join('share', package_name, path)
if install_path in paths_dict.keys():
paths_dict[install_path].append(file_path)
else:
paths_dict[install_path] = [file_path]
for key in paths_dict.keys():
data_files.append((key, paths_dict[key]))
return data_files
[...]
data_files=package_files(data_files, ['launch/','models/', [...]]),
Add all folders to include into an array in the package_files
function call to include them and all contained files to the setup.py
declaration.