Ros2 package
Claude Code skills for ROS 2 Jazzy — establish the unknowns first, verify against the installed system, prove the result ran.
npx -y skills add Leehyunbin0131/claude-ros2-skills --skill ros2-packageAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 14 days oldThe repository was created 14 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 12 stars12 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Package & build wiring: ros2 pkg create, package.xml, ament_cmake CMakeLists, ament_python setup.py, colcon build/source, installing launch & config, custom .msg/.srv interface packages.
SKILL.md
6.1 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it
ROS 2 Package Creation & Build Wiring (Ubuntu 24.04 LTS & ROS 2 Jazzy)
Most "it built fine but doesn't run" bugs are wiring, not code. This skill covers the seams between a source file and a runnable node.
1. Documentation Entry Points
| For | Entry point |
|---|---|
| ament_cmake reference (install, exports, testing hooks) | https://docs.ros.org/en/jazzy/How-To-Guides/Ament-CMake-Documentation.html |
| Package creation, custom interfaces, colcon tutorials | https://docs.ros.org/en/jazzy/Tutorials/ |
Ground truth beats both: read a working installed package under
/opt/ros/jazzy/share/<pkg>/ and copy its structure.
2. Scaffolding
ros2 pkg create --build-type ament_cmake --license Apache-2.0 --node-name my_node my_package
ros2 pkg create --build-type ament_python --license Apache-2.0 --node-name my_node my_package
Created: ament_cmake → CMakeLists.txt, package.xml, src/, include/my_package/.
ament_python → setup.py, setup.cfg, package.xml, resource/my_package, my_package/.
Never hand-roll this layout — resource/<pkg> and the ament index registration are
easy to omit and the package then silently fails to be discovered.
3. The Wiring That Makes a Node Runnable
ament_cmake
find_package(rclcpp REQUIRED)
add_executable(my_node src/my_node.cpp)
ament_target_dependencies(my_node rclcpp) # links deps AND their headers
install(TARGETS my_node
DESTINATION lib/${PROJECT_NAME}) # exact path — ros2 run looks only here
install(DIRECTORY launch params
DESTINATION share/${PROJECT_NAME}) # launch/config are NOT installed by default
ament_package() # last call, exactly once per package
The lib/${PROJECT_NAME} destination is not a convention you may vary — the ament
guide states it "must be followed exactly for the rest of the ROS tooling to find it."
target_link_libraries with namespaced targets (Eigen3::Eigen) is the accepted
alternative to ament_target_dependencies.
ament_python
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
# add launch/config explicitly, e.g.:
# (os.path.join('share', package_name, 'launch'), glob('launch/*launch.py')),
],
entry_points={
'console_scripts': [
'my_node = my_package.my_node:main', # <exe name> = <module path>:<function>
],
},
A Python node with no console_scripts line builds cleanly and is invisible to ros2 run.
4. Custom Interfaces (.msg / .srv)
Interfaces require an ament_cmake package — they cannot live in an ament_python
package. Standard practice is a dedicated <project>_interfaces package that your
node packages depend on.
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME} # first arg must start with the package name
"msg/Num.msg"
"srv/AddThreeInts.srv"
DEPENDENCIES geometry_msgs
)
<buildtool_depend>rosidl_default_generators</buildtool_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
Verify the result with ros2 interface show my_pkg/msg/Num — if that fails, the
generation never ran.
5. Build & Source Loop
colcon build --symlink-install --packages-select my_package
source install/setup.bash # every new shell, and after adding any new file
--symlink-install links Python sources and installed data instead of copying, so
edits take effect without rebuilding. C++ still needs a rebuild.
6. Symptom -> Root Cause -> Action
| Symptom | Likely root cause | Action |
|---|---|---|
Build succeeds, ros2 run <pkg> <exe> says no executable found | install(TARGETS ...) missing, or DESTINATION isn't lib/${PROJECT_NAME} | Add/fix the install rule; confirm the binary landed in install/<pkg>/lib/<pkg>/ |
Same, but package is ament_python | No matching console_scripts entry in setup.py | Add '<exe> = <pkg>.<module>:main'; rebuild (entry points are generated at install time) |
ros2 launch reports the launch file doesn't exist, though it's in the source tree | launch/ never installed | ament_cmake: install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}); ament_python: add it to data_files |
| Edited a Python node, behavior unchanged | Built without --symlink-install, so ros2 run executes the stale installed copy | Rebuild with --symlink-install, then re-source |
colcon build doesn't see the package at all | Not under the workspace src/, or package.xml missing/malformed | Check location; colcon list shows what colcon actually discovers |
Package builds but ros2 pkg list omits it; imports fail | Shell was sourced before the build, or overlay never sourced | source install/setup.bash again in that shell |
Custom message: ModuleNotFoundError / no type support at runtime | Interfaces declared in an ament_python package, or member_of_group tag missing | Move interfaces to a dedicated ament_cmake package with all three package.xml tags |
C++ link fails: undefined reference to rclcpp::... | find_package present but the target never linked | Add ament_target_dependencies(<target> rclcpp ...) for every dependency used |
| A dependent package can't find your headers | include/ not installed / target not exported | install(DIRECTORY include/ DESTINATION include/${PROJECT_NAME}) plus the export calls in the ament_cmake guide |
7. Strict Rules
- Declare every dependency in
package.xml— a build that works only because a sibling package happened to pull the dependency in will break on a clean machine. - One concern per package; keep interfaces in their own
ament_cmakepackage. - After adding any new file, directory, or entry point: rebuild and re-source before concluding something is broken.