I tested both foxy and humble on Ubuntu 20.04, 22.04 and got the same error.
When I build my package and type the source command, source /home/ws/ros2_ws/install/setup.bash
, I get the following error.
$> ros2 launch
Failed to load entry point 'launch': No module named 'launch.launch_description_sources'
Traceback (most recent call last):
File "/opt/ros/foxy/bin/ros2", line 11, in <module>
load_entry_point('ros2cli==0.9.13', 'console_scripts', 'ros2')()
File "/opt/ros/foxy/lib/python3.8/site-packages/ros2cli/cli.py", line 39, in main
add_subparsers_on_demand(
File "/opt/ros/foxy/lib/python3.8/site-packages/ros2cli/command/__init__.py", line 237, in add_subparsers_on_demand
extension = command_extensions[name]
KeyError: 'launch'
The only solution I've found so far is to delete the launch folder. What could be the problem?
├── config
│ └── params_app.yaml
├── face_pose_estimation
│ ├── app_for_1.py
│ ├── components
│ │ ├── main_component.py
│ │ ├── __init__.py
│ │ └── utils
│ │ ├── common.py
│ │ ├── __init__.py
│ │ └── play_voice.py
│ ├── __init__.py
│ └── save_service_server.py
├── launch
│ ├── __init__.py
│ └── app_1.launch.py
├── log
│ └── 20241011_1114.txt
├── package.xml
├── README.md
├── resource
│ ├── ros_app.service
│ └── weights
├── script
│ ├── all.sh
│ ├── micro_ros.sh
│ └── usbcam_open.sh
├── setup.cfg
├── setup.py
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
import os
def generate_launch_description():
package_share_dir = get_package_share_directory("my_package")
cam_params_file = os.path.join(package_share_dir, "config", "params_usbcam.yaml")
app_params_file = os.path.join(package_share_dir, "config", "params_app.yaml")
return LaunchDescription(
[
# Node(
# package="micro_ros_agent",
# execuable="micro_ros_agent",
# name="micro_ros",
# arguments=[
# "serial",
# "--dev",
# "/dev/ttyUSB0",
# "-b",
# "115200",
# ],
# ),
Node(
package="usb_cam",
executable="usb_cam_node_exe",
name="app_cam",
# parameters=[cam_params_file],
),
Node(
package="my_package",
executable="app_for_1",
name="app",
parameters=[app_params_file],
),
]
import os
from setuptools import setup, find_packages
package_name = "my_package"
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:
if filename == "__init__.py":
continue
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
def copy_weights_to_home():
home_dir = os.path.expanduser("~")
dest_dir = os.path.join(home_dir, ".temp", "weights")
os.makedirs(dest_dir, exist_ok=True)
src_dir = os.path.abspath(
os.path.join(os.path.dirname(__file__), "resource", "weights")
)
for path, directories, filenames in os.walk(src_dir):
for filename in filenames:
src_file = os.path.join(path, filename)
dest_file = os.path.join(dest_dir, filename)
if not os.path.exists(dest_file):
os.symlink(src_file, dest_file)
elif os.path.islink(dest_file) and os.readlink(dest_file) != src_file:
os.remove(dest_file)
os.symlink(src_file, dest_file)
setup(
name=package_name,
version="0.0.0",
packages=find_packages(exclude=["test"]),
data_files=package_files(data_files, ["launch", "config", "resource"]),
install_requires=["setuptools"],
zip_safe=True,
maintainer="foo",
maintainer_email="[email protected]",
description="TODO: Package description",
license="TODO: License declaration",
tests_require=["pytest"],
entry_points={
"console_scripts": [
"app_for_1 = my_package.app_for_1:main",
],
},
)
copy_weights_to_home()
package.xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>my_package</name>
<version>0.0.0</version>
<description>ROS package</description>
<maintainer email="[email protected]">foo</maintainer>
<license>TODO: License declaration</license>
<buildtool_depend>ament_python</buildtool_depend>
<exec_depend>rclpy</exec_depend>
<exec_depend>launch</exec_depend>
<exec_depend>launch_ros</exec_depend>
<depend>std_msgs</depend>
<depend>sensor_msgs</depend>
<depend>cv_bridge</depend>
<depend>usb_cam</depend>
<depend>v4l-utils</depend>
<depend>ffmpeg</depend>
<depend>ament_index_python</depend>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
You might want to check out: RoboticsBackend - Create a Python Package
Launch files
Create a
launch/
folder at the root of your package. You’ll put all your launch files inside this folder.$ cd ~/ros2_ws/src/my_python_pkg/
$ mkdir launch
Now, to install those launch files, you need to modify setup.py.
import os from glob import glob from setuptools import setup ... data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), (os.path.join('share', package_name, 'launch'), glob('launch/*.launch.py')), ], ...
For our example, with package name “my_python_pkg”, this will install all launch files from the launch/ folder, into ~/ros2_ws/install/my_python_pkg/share/my_python_pkg/launch/.
Note: you only need to modify setup.py once. After that, every time you add a launch file you’ll just need to compile your package so that the file is installed, that’s it.
Then, to start a launch file:
ros2 launch package_name launch_file_name