All notable changes to the Smart Drone System project.
A multi-node drone simulation system on Fedora 44 with ROS 2 Lyrical demonstrating:
- 5 Python nodes communicating over topics, services, and actions
- Custom message/service/action definitions (drone_interfaces package)
- Simulated sensor data, state machine, waypoint navigation, CLI command tool
- Full integration verified: sensors -> state machine -> controller -> ground station
sensor_node ──/drone/sensors──► state_machine_node
──/drone/state──► ground_station_node
command_node ──takeoff/land──► state_machine_node
──goto──────────► controller_node ──/drone/cmd_waypoint──► (action)
- All Python: C++ compilation failed due to missing transitive include directories in Lyrical COPR packages (
type_description_interfaces, etc.). Convertedstate_machine_nodefrom C++ to Python to unblock progress. - ament_python for drone_system: Used
setup.pywithentry_pointsinstead of CMake.drone_interfacesremains ament_cmake (CMake is required for rosidl code generation). - Wrapper scripts: Created shell wrappers in
install/<pkg>/lib/<pkg>/to makeros2 runwork (see Core Issues below).
The ament_cmake package in this Lyrical build removed ament_target_dependencies(). Any CMakeLists.txt using it fails at configure time.
Solution: Use target_link_libraries() or avoid C++ entirely. All drone_system nodes are Python.
COPR packages don't export transitive include paths for interfaces like type_description_interfaces, unique_identifier_msgs, etc. This means any C++ node that depends on custom messages won't compile.
Solution: Rewrote state_machine_node in Python. No C++ code remains in drone_system.
The ament_python package is not available in the Lyrical COPR. Without it, colcon build for ament_python packages does not create the lib/<package_name>/ directory that ros2 run searches for executables.
Solution: Created build.sh which generates shell wrapper scripts:
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
exec python3 "$SCRIPT_DIR/../python3.14/site-packages/drone_system/<node>.py" "$@"These wrappers are placed in install/drone_system/lib/drone_system/ where ros2 run expects them.
Limitation: Wrappers are lost on each colcon build. Must run build.sh or manually recreate them after building.
The ros2 launch extension is not included in the Lyrical ros2cli package. Running ros2 launch gives:
error: argument Call `ros2 <command> -h` for more detailed usage.:
invalid choice: 'launch'
Solution: Run nodes individually in separate terminals. Launch files are included for reference and future use when the extension becomes available.
In Lyrical, RcutilsLogger.warn() was removed. Must use self.get_logger().warning() instead.
Solution: Replaced all .warn( calls with .warning( in state_machine_node.py.
src/
├── drone_interfaces/ # Custom .msg, .srv, .action (ament_cmake)
│ ├── msg/SensorData.msg
│ ├── msg/DroneState.msg
│ ├── srv/Takeoff.srv
│ ├── srv/Land.srv
│ ├── srv/EmergencyStop.srv
│ └── action/GoToWaypoint.action
└── drone_system/ # All nodes (ament_python)
├── drone_system/
│ ├── sensor_node.py
│ ├── state_machine_node.py
│ ├── controller_node.py
│ ├── ground_station_node.py
│ └── command_node.py
├── launch/ # Launch files (for future use)
├── config/params.yaml
├── setup.py
└── package.xml
# Build
source /opt/ros/lyrical/setup.bash
colcon build --packages-select drone_interfaces
source install/setup.bash
colcon build --packages-select drone_system
source install/setup.bash
# Create ros2 run wrappers (required after each build)
./build.sh
# Run nodes
ros2 run drone_system sensor_node
ros2 run drone_system state_machine_node
ros2 run drone_system controller_node
ros2 run drone_system ground_station_node
ros2 run drone_system command_node takeoff 10.0sudo dnf install ros-lyrical-ros-desktop
sudo dnf install ros-lyrical-rosidl-default-generators ros-lyrical-rosidl-default-runtime