├── LICENSE
├── README.md
├── build
├── .built_by
├── COLCON_IGNORE
└── my_robot_navigation
│ ├── build
│ └── lib
│ │ └── my_robot_navigation
│ │ ├── __init__.py
│ │ └── obstacle_avoidance.py
│ ├── colcon_build.rc
│ ├── colcon_command_prefix_setup_py.sh
│ ├── colcon_command_prefix_setup_py.sh.env
│ ├── install.log
│ ├── my_robot_navigation.egg-info
│ ├── PKG-INFO
│ ├── SOURCES.txt
│ ├── dependency_links.txt
│ ├── entry_points.txt
│ ├── requires.txt
│ ├── top_level.txt
│ └── zip-safe
│ └── prefix_override
│ ├── __pycache__
│ └── sitecustomize.cpython-310.pyc
│ └── sitecustomize.py
├── images
├── animation.png
├── cmd_vel.png
└── logs.png
├── install
├── .colcon_install_layout
├── COLCON_IGNORE
├── _local_setup_util_ps1.py
├── _local_setup_util_sh.py
├── local_setup.bash
├── local_setup.ps1
├── local_setup.sh
├── local_setup.zsh
├── my_robot_navigation
│ ├── lib
│ │ ├── my_robot_navigation
│ │ │ └── obstacle_avoidance
│ │ └── python3.10
│ │ │ └── site-packages
│ │ │ ├── my_robot_navigation-0.0.0-py3.10.egg-info
│ │ │ ├── PKG-INFO
│ │ │ ├── SOURCES.txt
│ │ │ ├── dependency_links.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── requires.txt
│ │ │ ├── top_level.txt
│ │ │ └── zip-safe
│ │ │ └── my_robot_navigation
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ ├── __init__.cpython-310.pyc
│ │ │ └── obstacle_avoidance.cpython-310.pyc
│ │ │ └── obstacle_avoidance.py
│ └── share
│ │ ├── ament_index
│ │ └── resource_index
│ │ │ └── packages
│ │ │ └── my_robot_navigation
│ │ ├── colcon-core
│ │ └── packages
│ │ │ └── my_robot_navigation
│ │ └── my_robot_navigation
│ │ ├── __pycache__
│ │ └── robot_navigation.launch.cpython-310.pyc
│ │ ├── hook
│ │ ├── ament_prefix_path.dsv
│ │ ├── ament_prefix_path.ps1
│ │ ├── ament_prefix_path.sh
│ │ ├── pythonpath.dsv
│ │ ├── pythonpath.ps1
│ │ └── pythonpath.sh
│ │ ├── package.bash
│ │ ├── package.dsv
│ │ ├── package.ps1
│ │ ├── package.sh
│ │ ├── package.xml
│ │ ├── package.zsh
│ │ └── robot_navigation.launch.py
├── setup.bash
├── setup.ps1
├── setup.sh
└── setup.zsh
└── src
└── my_robot_navigation
├── launch
└── robot_navigation.launch.py
├── my_robot_navigation
├── __init__.py
└── obstacle_avoidance.py
├── package.xml
├── resource
└── my_robot_navigation
├── setup.cfg
├── setup.py
└── test
├── test_copyright.py
├── test_flake8.py
└── test_pep257.py
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Anson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo
2 | This repository contains the implementation of an autonomous navigation and obstacle avoidance robot simulated using ROS2 (Humble) and Gazebo. The project features a TurtleBot3 Burger robot navigating a custom hexagonal obstacle course, utilizing LIDAR data for real-time obstacle detection and avoidance.
3 |
4 | ---
5 |
6 | ## Project Overview
7 |
8 | The robot autonomously navigates a Gazebo-simulated environment, avoiding obstacles with a custom ROS2 Python node that processes LIDAR data and publishes velocity commands. The system integrates mechanical simulation, sensor processing, and control algorithms, making it a practical example for mechatronics and robotics applications.
9 |
10 | ## Screenshots
11 |
12 | ### Gazebo Simulation
13 | 
14 | *The TurtleBot3 navigating a hexagonal obstacle course with LIDAR data visualized.*
15 |
16 | ### Velocity Commands (/cmd_vel)
17 | 
18 | *Sample output from `ros2 topic echo /cmd_vel`, showing velocity commands (e.g., `angular.z: 0.5` for turning).*
19 |
20 | ### Obstacle Avoidance Logs
21 | 
22 | *Terminal logs demonstrating real-time obstacle detection and movement adjustments.*
23 |
24 | ---
25 | ### Key Features
26 | - **Obstacle Avoidance**: Detects obstacles within 0.5 meters using LIDAR and adjusts movement (turns right or moves forward).
27 | - **Real-Time Simulation**: Runs in Gazebo with ROS2 Humble, visualized via RViz.
28 | - **Custom Node**: A Python-based ROS2 node (`obstacle_avoidance.py`) handles sensor data and control logic.
29 | - **Documentation**: Includes setup instructions, usage, and troubleshooting for reproducibility.
30 |
31 | ---
32 |
33 | ## Prerequisites
34 |
35 | ### Software
36 | - **Ubuntu 22.04** (recommended for ROS2 Humble).
37 | - **ROS2 Humble** (install via [official guide](https://docs.ros.org/en/humble/Installation.html)).
38 | - **Gazebo** (included with ROS2 Humble).
39 | - **TurtleBot3 Packages**:
40 | ```bash
41 | sudo apt install ros-humble-turtlebot3 ros-humble-turtlebot3-gazebo
42 | ```
43 | - **Python 3.10** (system Python, avoid Conda to prevent version conflicts).
44 | - **pip** (for installing `lxml`):
45 | ```bash
46 | pip3 install lxml
47 | ```
48 |
49 | ### Hardware
50 | - A computer with at least 8GB RAM to run Gazebo and ROS2 smoothly.
51 |
52 | ---
53 |
54 | ## Installation
55 |
56 | 1. **Clone the Repository**
57 | ```bash
58 | git clone https://github.com/anson10/Obstacle-Avoidance-Robot-in-Gazebo-with-ROS2
59 |
60 | cd Obstacle-Avoidance-Robot-in-Gazebo-with-ROS2
61 | ```
62 |
63 | 2. **Set Up the Workspace**
64 | - Create a ROS2 workspace:
65 | ```bash
66 | mkdir -p ~/ros2_ws/src
67 | cd ~/ros2_ws/src
68 | ```
69 | - Copy the repository contents into `~/ros2_ws/src/my_robot_navigation`.
70 |
71 | 3. **Install Dependencies**
72 | - Ensure `lxml` is installed for Gazebo model spawning:
73 | ```bash
74 | pip3 install lxml
75 | ```
76 | - Deactivate any Conda environment to use system Python 3.10:
77 | ```bash
78 | conda deactivate
79 | ```
80 |
81 | 4. **Build the Workspace**
82 | ```bash
83 | cd ~/ros2_ws
84 | colcon build
85 | source install/setup.bash
86 | ```
87 |
88 | 5. **Set Environment Variable**
89 | - Export the TurtleBot3 model:
90 | ```bash
91 | export TURTLEBOT3_MODEL=burger
92 | ```
93 | - (Optional) Add to `~/.bashrc` for persistence:
94 | ```bash
95 | echo "export TURTLEBOT3_MODEL=burger" >> ~/.bashrc
96 | source ~/.bashrc
97 | ```
98 |
99 | ---
100 |
101 | ## Usage
102 |
103 | 1. **Launch the Simulation**
104 | - Start the project with the launch file:
105 | ```bash
106 | ros2 launch my_robot_navigation robot_navigation.launch.py
107 | ```
108 | - This opens Gazebo with the TurtleBot3 and runs the obstacle avoidance node.
109 |
110 | 2. **Visualize in RViz (Optional)**
111 | - Open a new terminal and launch RViz:
112 | ```bash
113 | ros2 run rviz2 rviz2
114 | ```
115 | - Configure RViz:
116 | - Set "Fixed Frame" to `odom`.
117 | - Add "LaserScan" display for `/scan`.
118 | - Add "RobotModel" display for the TurtleBot3.
119 |
120 | 3. **Monitor Topics**
121 | - List available topics:
122 | ```bash
123 | ros2 topic list
124 | ```
125 | - View LIDAR data or velocity commands:
126 | ```bash
127 | ros2 topic echo /scan
128 | ros2 topic echo /cmd_vel
129 | ```
130 |
131 | 4. **Expected Behavior**
132 | - Logs indicate "Path clear, moving forward" when no obstacles are near.
133 | - Logs show "Obstacle detected X.XXm ahead, turning!" when avoiding obstacles (see screenshots).
134 |
135 | ---
136 |
137 |
138 |
139 | ## Code Structure
140 |
141 | - **`my_robot_navigation/`**:
142 | - **`launch/robot_navigation.launch.py`**: Launches Gazebo and the obstacle avoidance node.
143 | - **`obstacle_avoidance.py`**: Python script for LIDAR processing and velocity control.
144 | - **`setup.py`**: Configures the ROS2 package and executable.
145 |
146 | ## Customization
147 |
148 | - **Adjust Parameters**: Modify `min_distance` (e.g., `0.5` to `1.0`) or velocities (`linear.x`, `angular.z`) in `obstacle_avoidance.py`.
149 | - **Enhance Algorithm**: Integrate Navigation2 for path planning or add sensor fusion with IMU data.
150 | - **Custom World**: Edit the Gazebo world file to design new obstacle layouts.
151 |
152 | ## Contributing
153 |
154 | Contributions are welcome! Please fork the repository and submit pull requests for:
155 | - Bug fixes or performance improvements.
156 | - Advanced features (e.g., SLAM, machine learning for navigation).
157 | - Documentation enhancements.
158 |
159 | ## License
160 |
161 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
162 |
--------------------------------------------------------------------------------
/build/.built_by:
--------------------------------------------------------------------------------
1 | colcon
2 |
--------------------------------------------------------------------------------
/build/COLCON_IGNORE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/build/COLCON_IGNORE
--------------------------------------------------------------------------------
/build/my_robot_navigation/build/lib/my_robot_navigation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/build/my_robot_navigation/build/lib/my_robot_navigation/__init__.py
--------------------------------------------------------------------------------
/build/my_robot_navigation/build/lib/my_robot_navigation/obstacle_avoidance.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import rclpy
4 | from rclpy.node import Node
5 | from sensor_msgs.msg import LaserScan
6 | from geometry_msgs.msg import Twist
7 |
8 | class ObstacleAvoidanceNode(Node):
9 | def __init__(self):
10 | super().__init__('obstacle_avoidance_node')
11 | # Subscriber to LIDAR data
12 | self.subscription = self.create_subscription(
13 | LaserScan,
14 | '/scan', # TurtleBot3 LIDAR topic
15 | self.lidar_callback,
16 | 10
17 | )
18 | # Publisher for velocity commands
19 | self.publisher = self.create_publisher(
20 | Twist,
21 | '/cmd_vel', # TurtleBot3 velocity topic
22 | 10
23 | )
24 | self.get_logger().info("Obstacle Avoidance Node Started")
25 |
26 | def lidar_callback(self, msg):
27 | # Process LIDAR data (360 degrees, 0 = front, 180 = rear)
28 | ranges = msg.ranges
29 | min_distance = min(ranges[0:60] + ranges[300:360]) # Check front 120 degrees
30 | twist = Twist()
31 |
32 | if min_distance < 0.5: # If obstacle closer than 0.5m
33 | twist.linear.x = 0.0
34 | twist.angular.z = 0.5 # Turn right
35 | self.get_logger().info(f"Obstacle detected {min_distance:.2f}m ahead, turning!")
36 | else:
37 | twist.linear.x = 0.2 # Move forward
38 | twist.angular.z = 0.0
39 | self.get_logger().info("Path clear, moving forward")
40 |
41 | self.publisher.publish(twist)
42 |
43 | def main(args=None):
44 | rclpy.init(args=args)
45 | node = ObstacleAvoidanceNode()
46 | try:
47 | rclpy.spin(node)
48 | except KeyboardInterrupt:
49 | node.get_logger().info("Shutting down")
50 | finally:
51 | node.destroy_node()
52 | rclpy.shutdown()
53 |
54 | if __name__ == '__main__':
55 | main()
56 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/colcon_build.rc:
--------------------------------------------------------------------------------
1 | 0
2 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/colcon_command_prefix_setup_py.sh:
--------------------------------------------------------------------------------
1 | # generated from colcon_core/shell/template/command_prefix.sh.em
2 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/colcon_command_prefix_setup_py.sh.env:
--------------------------------------------------------------------------------
1 | AMENT_PREFIX_PATH=/home/anson/ros2_ws/install/my_robot_navigation:/opt/ros/humble
2 | COLCON=1
3 | COLCON_PREFIX_PATH=/home/anson/ros2_ws/install
4 | CONDA_EXE=/home/anson/miniconda3/bin/conda
5 | CONDA_PYTHON_EXE=/home/anson/miniconda3/bin/python
6 | CONDA_SHLVL=0
7 | DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
8 | DISPLAY=:0
9 | ENVMAN_LOAD=loaded
10 | GAZEBO_MODEL_PATH=/usr/share/gazebo-11/models
11 | GAZEBO_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/gazebo-11/plugins
12 | GAZEBO_RESOURCE_PATH=/usr/share/gazebo-11
13 | HOME=/home/anson
14 | HOSTTYPE=x86_64
15 | LANG=C.UTF-8
16 | LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/gazebo-11/plugins:/opt/ros/humble/opt/rviz_ogre_vendor/lib:/opt/ros/humble/lib/x86_64-linux-gnu:/opt/ros/humble/lib
17 | LESSCLOSE=/usr/bin/lesspipe %s %s
18 | LESSOPEN=| /usr/bin/lesspipe %s
19 | LOGNAME=anson
20 | LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
21 | NAME=Anson
22 | NVM_BIN=/home/anson/.nvm/versions/node/v20.18.0/bin
23 | NVM_CD_FLAGS=
24 | NVM_DIR=/home/anson/.nvm
25 | NVM_INC=/home/anson/.nvm/versions/node/v20.18.0/include/node
26 | OLDPWD=/home/anson/ros2_ws
27 | PATH=/home/anson/.local/bin:/opt/ros/humble/bin:/home/anson/.local/bin:/home/anson/go/bin:/home/anson/.local/opt/go/bin:/home/anson/.nvm/versions/node/v20.18.0/bin:/home/anson/miniconda3/condabin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/mnt/c/Program Files/WindowsApps/MicrosoftCorporationII.WindowsSubsystemForLinux_2.3.26.0_x64__8wekyb3d8bbwe:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0:/mnt/c/WINDOWS/System32/OpenSSH:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA NvDLISR:/mnt/c/Program Files/dotnet:/mnt/c/Program Files/Microsoft SQL Server/150/Tools/Binn:/mnt/c/Program Files/Microsoft SQL Server/Client SDK/ODBC/170/Tools/Binn:/mnt/c/Program Files (x86)/Windows Kits/10/Windows Performance Toolkit:/mnt/c/Users/sanso/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/sanso/AppData/Local/Programs/Microsoft VS Code/bin:/mnt/c/Users/sanso/.dotnet/tools:/mnt/c/Program Files/gnuplot/bin:/snap/bin:/usr/local/cuda/bin:/usr/bin
28 | PULSE_SERVER=unix:/mnt/wslg/PulseServer
29 | PWD=/home/anson/ros2_ws/build/my_robot_navigation
30 | PYTHONPATH=/home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages:/opt/ros/humble/lib/python3.10/site-packages:/opt/ros/humble/local/lib/python3.10/dist-packages
31 | ROS_DISTRO=humble
32 | ROS_LOCALHOST_ONLY=0
33 | ROS_PYTHON_VERSION=3
34 | ROS_VERSION=2
35 | SHELL=/bin/bash
36 | SHLVL=1
37 | TERM=xterm-256color
38 | TURTLEBOT3_MODEL=burger
39 | USER=anson
40 | WAYLAND_DISPLAY=wayland-0
41 | WSL2_GUI_APPS_ENABLED=1
42 | WSLENV=
43 | WSL_DISTRO_NAME=Ubuntu-22.04
44 | WSL_INTEROP=/run/WSL/304_interop
45 | XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
46 | XDG_RUNTIME_DIR=/run/user/1000/
47 | _=/usr/bin/colcon
48 | _CE_CONDA=
49 | _CE_M=
50 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/install.log:
--------------------------------------------------------------------------------
1 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/obstacle_avoidance.py
2 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__init__.py
3 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__pycache__/obstacle_avoidance.cpython-310.pyc
4 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__pycache__/__init__.cpython-310.pyc
5 | /home/anson/ros2_ws/install/my_robot_navigation/share/ament_index/resource_index/packages/my_robot_navigation
6 | /home/anson/ros2_ws/install/my_robot_navigation/share/my_robot_navigation/package.xml
7 | /home/anson/ros2_ws/install/my_robot_navigation/share/my_robot_navigation/robot_navigation.launch.py
8 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/top_level.txt
9 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/entry_points.txt
10 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/PKG-INFO
11 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/requires.txt
12 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/SOURCES.txt
13 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/zip-safe
14 | /home/anson/ros2_ws/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/dependency_links.txt
15 | /home/anson/ros2_ws/install/my_robot_navigation/lib/my_robot_navigation/obstacle_avoidance
16 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/my_robot_navigation.egg-info/PKG-INFO:
--------------------------------------------------------------------------------
1 | Metadata-Version: 2.1
2 | Name: my-robot-navigation
3 | Version: 0.0.0
4 | Summary: Obstacle avoidance robot with ROS2 and Gazebo
5 | Home-page: UNKNOWN
6 | Maintainer: anson
7 | Maintainer-email: sansonmsa@gmail.com
8 | License: Apache License 2.0
9 | Platform: UNKNOWN
10 |
11 | UNKNOWN
12 |
13 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/my_robot_navigation.egg-info/SOURCES.txt:
--------------------------------------------------------------------------------
1 | package.xml
2 | setup.cfg
3 | setup.py
4 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/PKG-INFO
5 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/SOURCES.txt
6 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/dependency_links.txt
7 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/entry_points.txt
8 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/requires.txt
9 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/top_level.txt
10 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/zip-safe
11 | launch/robot_navigation.launch.py
12 | my_robot_navigation/__init__.py
13 | my_robot_navigation/obstacle_avoidance.py
14 | resource/my_robot_navigation
15 | test/test_copyright.py
16 | test/test_flake8.py
17 | test/test_pep257.py
--------------------------------------------------------------------------------
/build/my_robot_navigation/my_robot_navigation.egg-info/dependency_links.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/my_robot_navigation.egg-info/entry_points.txt:
--------------------------------------------------------------------------------
1 | [console_scripts]
2 | obstacle_avoidance = my_robot_navigation.obstacle_avoidance:main
3 |
4 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/my_robot_navigation.egg-info/requires.txt:
--------------------------------------------------------------------------------
1 | setuptools
2 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/my_robot_navigation.egg-info/top_level.txt:
--------------------------------------------------------------------------------
1 | my_robot_navigation
2 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/my_robot_navigation.egg-info/zip-safe:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/build/my_robot_navigation/prefix_override/__pycache__/sitecustomize.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/build/my_robot_navigation/prefix_override/__pycache__/sitecustomize.cpython-310.pyc
--------------------------------------------------------------------------------
/build/my_robot_navigation/prefix_override/sitecustomize.py:
--------------------------------------------------------------------------------
1 | import sys
2 | if sys.prefix == '/usr':
3 | sys.real_prefix = sys.prefix
4 | sys.prefix = sys.exec_prefix = '/home/anson/ros2_ws/install/my_robot_navigation'
5 |
--------------------------------------------------------------------------------
/images/animation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/images/animation.png
--------------------------------------------------------------------------------
/images/cmd_vel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/images/cmd_vel.png
--------------------------------------------------------------------------------
/images/logs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/images/logs.png
--------------------------------------------------------------------------------
/install/.colcon_install_layout:
--------------------------------------------------------------------------------
1 | isolated
2 |
--------------------------------------------------------------------------------
/install/COLCON_IGNORE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/install/COLCON_IGNORE
--------------------------------------------------------------------------------
/install/_local_setup_util_ps1.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016-2019 Dirk Thomas
2 | # Licensed under the Apache License, Version 2.0
3 |
4 | import argparse
5 | from collections import OrderedDict
6 | import os
7 | from pathlib import Path
8 | import sys
9 |
10 |
11 | FORMAT_STR_COMMENT_LINE = '# {comment}'
12 | FORMAT_STR_SET_ENV_VAR = 'Set-Item -Path "Env:{name}" -Value "{value}"'
13 | FORMAT_STR_USE_ENV_VAR = '$env:{name}'
14 | FORMAT_STR_INVOKE_SCRIPT = '_colcon_prefix_powershell_source_script "{script_path}"' # noqa: E501
15 | FORMAT_STR_REMOVE_LEADING_SEPARATOR = '' # noqa: E501
16 | FORMAT_STR_REMOVE_TRAILING_SEPARATOR = '' # noqa: E501
17 |
18 | DSV_TYPE_APPEND_NON_DUPLICATE = 'append-non-duplicate'
19 | DSV_TYPE_PREPEND_NON_DUPLICATE = 'prepend-non-duplicate'
20 | DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS = 'prepend-non-duplicate-if-exists'
21 | DSV_TYPE_SET = 'set'
22 | DSV_TYPE_SET_IF_UNSET = 'set-if-unset'
23 | DSV_TYPE_SOURCE = 'source'
24 |
25 |
26 | def main(argv=sys.argv[1:]): # noqa: D103
27 | parser = argparse.ArgumentParser(
28 | description='Output shell commands for the packages in topological '
29 | 'order')
30 | parser.add_argument(
31 | 'primary_extension',
32 | help='The file extension of the primary shell')
33 | parser.add_argument(
34 | 'additional_extension', nargs='?',
35 | help='The additional file extension to be considered')
36 | parser.add_argument(
37 | '--merged-install', action='store_true',
38 | help='All install prefixes are merged into a single location')
39 | args = parser.parse_args(argv)
40 |
41 | packages = get_packages(Path(__file__).parent, args.merged_install)
42 |
43 | ordered_packages = order_packages(packages)
44 | for pkg_name in ordered_packages:
45 | if _include_comments():
46 | print(
47 | FORMAT_STR_COMMENT_LINE.format_map(
48 | {'comment': 'Package: ' + pkg_name}))
49 | prefix = os.path.abspath(os.path.dirname(__file__))
50 | if not args.merged_install:
51 | prefix = os.path.join(prefix, pkg_name)
52 | for line in get_commands(
53 | pkg_name, prefix, args.primary_extension,
54 | args.additional_extension
55 | ):
56 | print(line)
57 |
58 | for line in _remove_ending_separators():
59 | print(line)
60 |
61 |
62 | def get_packages(prefix_path, merged_install):
63 | """
64 | Find packages based on colcon-specific files created during installation.
65 |
66 | :param Path prefix_path: The install prefix path of all packages
67 | :param bool merged_install: The flag if the packages are all installed
68 | directly in the prefix or if each package is installed in a subdirectory
69 | named after the package
70 | :returns: A mapping from the package name to the set of runtime
71 | dependencies
72 | :rtype: dict
73 | """
74 | packages = {}
75 | # since importing colcon_core isn't feasible here the following constant
76 | # must match colcon_core.location.get_relative_package_index_path()
77 | subdirectory = 'share/colcon-core/packages'
78 | if merged_install:
79 | # return if workspace is empty
80 | if not (prefix_path / subdirectory).is_dir():
81 | return packages
82 | # find all files in the subdirectory
83 | for p in (prefix_path / subdirectory).iterdir():
84 | if not p.is_file():
85 | continue
86 | if p.name.startswith('.'):
87 | continue
88 | add_package_runtime_dependencies(p, packages)
89 | else:
90 | # for each subdirectory look for the package specific file
91 | for p in prefix_path.iterdir():
92 | if not p.is_dir():
93 | continue
94 | if p.name.startswith('.'):
95 | continue
96 | p = p / subdirectory / p.name
97 | if p.is_file():
98 | add_package_runtime_dependencies(p, packages)
99 |
100 | # remove unknown dependencies
101 | pkg_names = set(packages.keys())
102 | for k in packages.keys():
103 | packages[k] = {d for d in packages[k] if d in pkg_names}
104 |
105 | return packages
106 |
107 |
108 | def add_package_runtime_dependencies(path, packages):
109 | """
110 | Check the path and if it exists extract the packages runtime dependencies.
111 |
112 | :param Path path: The resource file containing the runtime dependencies
113 | :param dict packages: A mapping from package names to the sets of runtime
114 | dependencies to add to
115 | """
116 | content = path.read_text()
117 | dependencies = set(content.split(os.pathsep) if content else [])
118 | packages[path.name] = dependencies
119 |
120 |
121 | def order_packages(packages):
122 | """
123 | Order packages topologically.
124 |
125 | :param dict packages: A mapping from package name to the set of runtime
126 | dependencies
127 | :returns: The package names
128 | :rtype: list
129 | """
130 | # select packages with no dependencies in alphabetical order
131 | to_be_ordered = list(packages.keys())
132 | ordered = []
133 | while to_be_ordered:
134 | pkg_names_without_deps = [
135 | name for name in to_be_ordered if not packages[name]]
136 | if not pkg_names_without_deps:
137 | reduce_cycle_set(packages)
138 | raise RuntimeError(
139 | 'Circular dependency between: ' + ', '.join(sorted(packages)))
140 | pkg_names_without_deps.sort()
141 | pkg_name = pkg_names_without_deps[0]
142 | to_be_ordered.remove(pkg_name)
143 | ordered.append(pkg_name)
144 | # remove item from dependency lists
145 | for k in list(packages.keys()):
146 | if pkg_name in packages[k]:
147 | packages[k].remove(pkg_name)
148 | return ordered
149 |
150 |
151 | def reduce_cycle_set(packages):
152 | """
153 | Reduce the set of packages to the ones part of the circular dependency.
154 |
155 | :param dict packages: A mapping from package name to the set of runtime
156 | dependencies which is modified in place
157 | """
158 | last_depended = None
159 | while len(packages) > 0:
160 | # get all remaining dependencies
161 | depended = set()
162 | for pkg_name, dependencies in packages.items():
163 | depended = depended.union(dependencies)
164 | # remove all packages which are not dependent on
165 | for name in list(packages.keys()):
166 | if name not in depended:
167 | del packages[name]
168 | if last_depended:
169 | # if remaining packages haven't changed return them
170 | if last_depended == depended:
171 | return packages.keys()
172 | # otherwise reduce again
173 | last_depended = depended
174 |
175 |
176 | def _include_comments():
177 | # skipping comment lines when COLCON_TRACE is not set speeds up the
178 | # processing especially on Windows
179 | return bool(os.environ.get('COLCON_TRACE'))
180 |
181 |
182 | def get_commands(pkg_name, prefix, primary_extension, additional_extension):
183 | commands = []
184 | package_dsv_path = os.path.join(prefix, 'share', pkg_name, 'package.dsv')
185 | if os.path.exists(package_dsv_path):
186 | commands += process_dsv_file(
187 | package_dsv_path, prefix, primary_extension, additional_extension)
188 | return commands
189 |
190 |
191 | def process_dsv_file(
192 | dsv_path, prefix, primary_extension=None, additional_extension=None
193 | ):
194 | commands = []
195 | if _include_comments():
196 | commands.append(FORMAT_STR_COMMENT_LINE.format_map({'comment': dsv_path}))
197 | with open(dsv_path, 'r') as h:
198 | content = h.read()
199 | lines = content.splitlines()
200 |
201 | basenames = OrderedDict()
202 | for i, line in enumerate(lines):
203 | # skip over empty or whitespace-only lines
204 | if not line.strip():
205 | continue
206 | # skip over comments
207 | if line.startswith('#'):
208 | continue
209 | try:
210 | type_, remainder = line.split(';', 1)
211 | except ValueError:
212 | raise RuntimeError(
213 | "Line %d in '%s' doesn't contain a semicolon separating the "
214 | 'type from the arguments' % (i + 1, dsv_path))
215 | if type_ != DSV_TYPE_SOURCE:
216 | # handle non-source lines
217 | try:
218 | commands += handle_dsv_types_except_source(
219 | type_, remainder, prefix)
220 | except RuntimeError as e:
221 | raise RuntimeError(
222 | "Line %d in '%s' %s" % (i + 1, dsv_path, e)) from e
223 | else:
224 | # group remaining source lines by basename
225 | path_without_ext, ext = os.path.splitext(remainder)
226 | if path_without_ext not in basenames:
227 | basenames[path_without_ext] = set()
228 | assert ext.startswith('.')
229 | ext = ext[1:]
230 | if ext in (primary_extension, additional_extension):
231 | basenames[path_without_ext].add(ext)
232 |
233 | # add the dsv extension to each basename if the file exists
234 | for basename, extensions in basenames.items():
235 | if not os.path.isabs(basename):
236 | basename = os.path.join(prefix, basename)
237 | if os.path.exists(basename + '.dsv'):
238 | extensions.add('dsv')
239 |
240 | for basename, extensions in basenames.items():
241 | if not os.path.isabs(basename):
242 | basename = os.path.join(prefix, basename)
243 | if 'dsv' in extensions:
244 | # process dsv files recursively
245 | commands += process_dsv_file(
246 | basename + '.dsv', prefix, primary_extension=primary_extension,
247 | additional_extension=additional_extension)
248 | elif primary_extension in extensions and len(extensions) == 1:
249 | # source primary-only files
250 | commands += [
251 | FORMAT_STR_INVOKE_SCRIPT.format_map({
252 | 'prefix': prefix,
253 | 'script_path': basename + '.' + primary_extension})]
254 | elif additional_extension in extensions:
255 | # source non-primary files
256 | commands += [
257 | FORMAT_STR_INVOKE_SCRIPT.format_map({
258 | 'prefix': prefix,
259 | 'script_path': basename + '.' + additional_extension})]
260 |
261 | return commands
262 |
263 |
264 | def handle_dsv_types_except_source(type_, remainder, prefix):
265 | commands = []
266 | if type_ in (DSV_TYPE_SET, DSV_TYPE_SET_IF_UNSET):
267 | try:
268 | env_name, value = remainder.split(';', 1)
269 | except ValueError:
270 | raise RuntimeError(
271 | "doesn't contain a semicolon separating the environment name "
272 | 'from the value')
273 | try_prefixed_value = os.path.join(prefix, value) if value else prefix
274 | if os.path.exists(try_prefixed_value):
275 | value = try_prefixed_value
276 | if type_ == DSV_TYPE_SET:
277 | commands += _set(env_name, value)
278 | elif type_ == DSV_TYPE_SET_IF_UNSET:
279 | commands += _set_if_unset(env_name, value)
280 | else:
281 | assert False
282 | elif type_ in (
283 | DSV_TYPE_APPEND_NON_DUPLICATE,
284 | DSV_TYPE_PREPEND_NON_DUPLICATE,
285 | DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS
286 | ):
287 | try:
288 | env_name_and_values = remainder.split(';')
289 | except ValueError:
290 | raise RuntimeError(
291 | "doesn't contain a semicolon separating the environment name "
292 | 'from the values')
293 | env_name = env_name_and_values[0]
294 | values = env_name_and_values[1:]
295 | for value in values:
296 | if not value:
297 | value = prefix
298 | elif not os.path.isabs(value):
299 | value = os.path.join(prefix, value)
300 | if (
301 | type_ == DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS and
302 | not os.path.exists(value)
303 | ):
304 | comment = f'skip extending {env_name} with not existing ' \
305 | f'path: {value}'
306 | if _include_comments():
307 | commands.append(
308 | FORMAT_STR_COMMENT_LINE.format_map({'comment': comment}))
309 | elif type_ == DSV_TYPE_APPEND_NON_DUPLICATE:
310 | commands += _append_unique_value(env_name, value)
311 | else:
312 | commands += _prepend_unique_value(env_name, value)
313 | else:
314 | raise RuntimeError(
315 | 'contains an unknown environment hook type: ' + type_)
316 | return commands
317 |
318 |
319 | env_state = {}
320 |
321 |
322 | def _append_unique_value(name, value):
323 | global env_state
324 | if name not in env_state:
325 | if os.environ.get(name):
326 | env_state[name] = set(os.environ[name].split(os.pathsep))
327 | else:
328 | env_state[name] = set()
329 | # append even if the variable has not been set yet, in case a shell script sets the
330 | # same variable without the knowledge of this Python script.
331 | # later _remove_ending_separators() will cleanup any unintentional leading separator
332 | extend = FORMAT_STR_USE_ENV_VAR.format_map({'name': name}) + os.pathsep
333 | line = FORMAT_STR_SET_ENV_VAR.format_map(
334 | {'name': name, 'value': extend + value})
335 | if value not in env_state[name]:
336 | env_state[name].add(value)
337 | else:
338 | if not _include_comments():
339 | return []
340 | line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
341 | return [line]
342 |
343 |
344 | def _prepend_unique_value(name, value):
345 | global env_state
346 | if name not in env_state:
347 | if os.environ.get(name):
348 | env_state[name] = set(os.environ[name].split(os.pathsep))
349 | else:
350 | env_state[name] = set()
351 | # prepend even if the variable has not been set yet, in case a shell script sets the
352 | # same variable without the knowledge of this Python script.
353 | # later _remove_ending_separators() will cleanup any unintentional trailing separator
354 | extend = os.pathsep + FORMAT_STR_USE_ENV_VAR.format_map({'name': name})
355 | line = FORMAT_STR_SET_ENV_VAR.format_map(
356 | {'name': name, 'value': value + extend})
357 | if value not in env_state[name]:
358 | env_state[name].add(value)
359 | else:
360 | if not _include_comments():
361 | return []
362 | line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
363 | return [line]
364 |
365 |
366 | # generate commands for removing prepended underscores
367 | def _remove_ending_separators():
368 | # do nothing if the shell extension does not implement the logic
369 | if FORMAT_STR_REMOVE_TRAILING_SEPARATOR is None:
370 | return []
371 |
372 | global env_state
373 | commands = []
374 | for name in env_state:
375 | # skip variables that already had values before this script started prepending
376 | if name in os.environ:
377 | continue
378 | commands += [
379 | FORMAT_STR_REMOVE_LEADING_SEPARATOR.format_map({'name': name}),
380 | FORMAT_STR_REMOVE_TRAILING_SEPARATOR.format_map({'name': name})]
381 | return commands
382 |
383 |
384 | def _set(name, value):
385 | global env_state
386 | env_state[name] = value
387 | line = FORMAT_STR_SET_ENV_VAR.format_map(
388 | {'name': name, 'value': value})
389 | return [line]
390 |
391 |
392 | def _set_if_unset(name, value):
393 | global env_state
394 | line = FORMAT_STR_SET_ENV_VAR.format_map(
395 | {'name': name, 'value': value})
396 | if env_state.get(name, os.environ.get(name)):
397 | line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
398 | return [line]
399 |
400 |
401 | if __name__ == '__main__': # pragma: no cover
402 | try:
403 | rc = main()
404 | except RuntimeError as e:
405 | print(str(e), file=sys.stderr)
406 | rc = 1
407 | sys.exit(rc)
408 |
--------------------------------------------------------------------------------
/install/_local_setup_util_sh.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016-2019 Dirk Thomas
2 | # Licensed under the Apache License, Version 2.0
3 |
4 | import argparse
5 | from collections import OrderedDict
6 | import os
7 | from pathlib import Path
8 | import sys
9 |
10 |
11 | FORMAT_STR_COMMENT_LINE = '# {comment}'
12 | FORMAT_STR_SET_ENV_VAR = 'export {name}="{value}"'
13 | FORMAT_STR_USE_ENV_VAR = '${name}'
14 | FORMAT_STR_INVOKE_SCRIPT = 'COLCON_CURRENT_PREFIX="{prefix}" _colcon_prefix_sh_source_script "{script_path}"' # noqa: E501
15 | FORMAT_STR_REMOVE_LEADING_SEPARATOR = 'if [ "$(echo -n ${name} | head -c 1)" = ":" ]; then export {name}=${{{name}#?}} ; fi' # noqa: E501
16 | FORMAT_STR_REMOVE_TRAILING_SEPARATOR = 'if [ "$(echo -n ${name} | tail -c 1)" = ":" ]; then export {name}=${{{name}%?}} ; fi' # noqa: E501
17 |
18 | DSV_TYPE_APPEND_NON_DUPLICATE = 'append-non-duplicate'
19 | DSV_TYPE_PREPEND_NON_DUPLICATE = 'prepend-non-duplicate'
20 | DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS = 'prepend-non-duplicate-if-exists'
21 | DSV_TYPE_SET = 'set'
22 | DSV_TYPE_SET_IF_UNSET = 'set-if-unset'
23 | DSV_TYPE_SOURCE = 'source'
24 |
25 |
26 | def main(argv=sys.argv[1:]): # noqa: D103
27 | parser = argparse.ArgumentParser(
28 | description='Output shell commands for the packages in topological '
29 | 'order')
30 | parser.add_argument(
31 | 'primary_extension',
32 | help='The file extension of the primary shell')
33 | parser.add_argument(
34 | 'additional_extension', nargs='?',
35 | help='The additional file extension to be considered')
36 | parser.add_argument(
37 | '--merged-install', action='store_true',
38 | help='All install prefixes are merged into a single location')
39 | args = parser.parse_args(argv)
40 |
41 | packages = get_packages(Path(__file__).parent, args.merged_install)
42 |
43 | ordered_packages = order_packages(packages)
44 | for pkg_name in ordered_packages:
45 | if _include_comments():
46 | print(
47 | FORMAT_STR_COMMENT_LINE.format_map(
48 | {'comment': 'Package: ' + pkg_name}))
49 | prefix = os.path.abspath(os.path.dirname(__file__))
50 | if not args.merged_install:
51 | prefix = os.path.join(prefix, pkg_name)
52 | for line in get_commands(
53 | pkg_name, prefix, args.primary_extension,
54 | args.additional_extension
55 | ):
56 | print(line)
57 |
58 | for line in _remove_ending_separators():
59 | print(line)
60 |
61 |
62 | def get_packages(prefix_path, merged_install):
63 | """
64 | Find packages based on colcon-specific files created during installation.
65 |
66 | :param Path prefix_path: The install prefix path of all packages
67 | :param bool merged_install: The flag if the packages are all installed
68 | directly in the prefix or if each package is installed in a subdirectory
69 | named after the package
70 | :returns: A mapping from the package name to the set of runtime
71 | dependencies
72 | :rtype: dict
73 | """
74 | packages = {}
75 | # since importing colcon_core isn't feasible here the following constant
76 | # must match colcon_core.location.get_relative_package_index_path()
77 | subdirectory = 'share/colcon-core/packages'
78 | if merged_install:
79 | # return if workspace is empty
80 | if not (prefix_path / subdirectory).is_dir():
81 | return packages
82 | # find all files in the subdirectory
83 | for p in (prefix_path / subdirectory).iterdir():
84 | if not p.is_file():
85 | continue
86 | if p.name.startswith('.'):
87 | continue
88 | add_package_runtime_dependencies(p, packages)
89 | else:
90 | # for each subdirectory look for the package specific file
91 | for p in prefix_path.iterdir():
92 | if not p.is_dir():
93 | continue
94 | if p.name.startswith('.'):
95 | continue
96 | p = p / subdirectory / p.name
97 | if p.is_file():
98 | add_package_runtime_dependencies(p, packages)
99 |
100 | # remove unknown dependencies
101 | pkg_names = set(packages.keys())
102 | for k in packages.keys():
103 | packages[k] = {d for d in packages[k] if d in pkg_names}
104 |
105 | return packages
106 |
107 |
108 | def add_package_runtime_dependencies(path, packages):
109 | """
110 | Check the path and if it exists extract the packages runtime dependencies.
111 |
112 | :param Path path: The resource file containing the runtime dependencies
113 | :param dict packages: A mapping from package names to the sets of runtime
114 | dependencies to add to
115 | """
116 | content = path.read_text()
117 | dependencies = set(content.split(os.pathsep) if content else [])
118 | packages[path.name] = dependencies
119 |
120 |
121 | def order_packages(packages):
122 | """
123 | Order packages topologically.
124 |
125 | :param dict packages: A mapping from package name to the set of runtime
126 | dependencies
127 | :returns: The package names
128 | :rtype: list
129 | """
130 | # select packages with no dependencies in alphabetical order
131 | to_be_ordered = list(packages.keys())
132 | ordered = []
133 | while to_be_ordered:
134 | pkg_names_without_deps = [
135 | name for name in to_be_ordered if not packages[name]]
136 | if not pkg_names_without_deps:
137 | reduce_cycle_set(packages)
138 | raise RuntimeError(
139 | 'Circular dependency between: ' + ', '.join(sorted(packages)))
140 | pkg_names_without_deps.sort()
141 | pkg_name = pkg_names_without_deps[0]
142 | to_be_ordered.remove(pkg_name)
143 | ordered.append(pkg_name)
144 | # remove item from dependency lists
145 | for k in list(packages.keys()):
146 | if pkg_name in packages[k]:
147 | packages[k].remove(pkg_name)
148 | return ordered
149 |
150 |
151 | def reduce_cycle_set(packages):
152 | """
153 | Reduce the set of packages to the ones part of the circular dependency.
154 |
155 | :param dict packages: A mapping from package name to the set of runtime
156 | dependencies which is modified in place
157 | """
158 | last_depended = None
159 | while len(packages) > 0:
160 | # get all remaining dependencies
161 | depended = set()
162 | for pkg_name, dependencies in packages.items():
163 | depended = depended.union(dependencies)
164 | # remove all packages which are not dependent on
165 | for name in list(packages.keys()):
166 | if name not in depended:
167 | del packages[name]
168 | if last_depended:
169 | # if remaining packages haven't changed return them
170 | if last_depended == depended:
171 | return packages.keys()
172 | # otherwise reduce again
173 | last_depended = depended
174 |
175 |
176 | def _include_comments():
177 | # skipping comment lines when COLCON_TRACE is not set speeds up the
178 | # processing especially on Windows
179 | return bool(os.environ.get('COLCON_TRACE'))
180 |
181 |
182 | def get_commands(pkg_name, prefix, primary_extension, additional_extension):
183 | commands = []
184 | package_dsv_path = os.path.join(prefix, 'share', pkg_name, 'package.dsv')
185 | if os.path.exists(package_dsv_path):
186 | commands += process_dsv_file(
187 | package_dsv_path, prefix, primary_extension, additional_extension)
188 | return commands
189 |
190 |
191 | def process_dsv_file(
192 | dsv_path, prefix, primary_extension=None, additional_extension=None
193 | ):
194 | commands = []
195 | if _include_comments():
196 | commands.append(FORMAT_STR_COMMENT_LINE.format_map({'comment': dsv_path}))
197 | with open(dsv_path, 'r') as h:
198 | content = h.read()
199 | lines = content.splitlines()
200 |
201 | basenames = OrderedDict()
202 | for i, line in enumerate(lines):
203 | # skip over empty or whitespace-only lines
204 | if not line.strip():
205 | continue
206 | # skip over comments
207 | if line.startswith('#'):
208 | continue
209 | try:
210 | type_, remainder = line.split(';', 1)
211 | except ValueError:
212 | raise RuntimeError(
213 | "Line %d in '%s' doesn't contain a semicolon separating the "
214 | 'type from the arguments' % (i + 1, dsv_path))
215 | if type_ != DSV_TYPE_SOURCE:
216 | # handle non-source lines
217 | try:
218 | commands += handle_dsv_types_except_source(
219 | type_, remainder, prefix)
220 | except RuntimeError as e:
221 | raise RuntimeError(
222 | "Line %d in '%s' %s" % (i + 1, dsv_path, e)) from e
223 | else:
224 | # group remaining source lines by basename
225 | path_without_ext, ext = os.path.splitext(remainder)
226 | if path_without_ext not in basenames:
227 | basenames[path_without_ext] = set()
228 | assert ext.startswith('.')
229 | ext = ext[1:]
230 | if ext in (primary_extension, additional_extension):
231 | basenames[path_without_ext].add(ext)
232 |
233 | # add the dsv extension to each basename if the file exists
234 | for basename, extensions in basenames.items():
235 | if not os.path.isabs(basename):
236 | basename = os.path.join(prefix, basename)
237 | if os.path.exists(basename + '.dsv'):
238 | extensions.add('dsv')
239 |
240 | for basename, extensions in basenames.items():
241 | if not os.path.isabs(basename):
242 | basename = os.path.join(prefix, basename)
243 | if 'dsv' in extensions:
244 | # process dsv files recursively
245 | commands += process_dsv_file(
246 | basename + '.dsv', prefix, primary_extension=primary_extension,
247 | additional_extension=additional_extension)
248 | elif primary_extension in extensions and len(extensions) == 1:
249 | # source primary-only files
250 | commands += [
251 | FORMAT_STR_INVOKE_SCRIPT.format_map({
252 | 'prefix': prefix,
253 | 'script_path': basename + '.' + primary_extension})]
254 | elif additional_extension in extensions:
255 | # source non-primary files
256 | commands += [
257 | FORMAT_STR_INVOKE_SCRIPT.format_map({
258 | 'prefix': prefix,
259 | 'script_path': basename + '.' + additional_extension})]
260 |
261 | return commands
262 |
263 |
264 | def handle_dsv_types_except_source(type_, remainder, prefix):
265 | commands = []
266 | if type_ in (DSV_TYPE_SET, DSV_TYPE_SET_IF_UNSET):
267 | try:
268 | env_name, value = remainder.split(';', 1)
269 | except ValueError:
270 | raise RuntimeError(
271 | "doesn't contain a semicolon separating the environment name "
272 | 'from the value')
273 | try_prefixed_value = os.path.join(prefix, value) if value else prefix
274 | if os.path.exists(try_prefixed_value):
275 | value = try_prefixed_value
276 | if type_ == DSV_TYPE_SET:
277 | commands += _set(env_name, value)
278 | elif type_ == DSV_TYPE_SET_IF_UNSET:
279 | commands += _set_if_unset(env_name, value)
280 | else:
281 | assert False
282 | elif type_ in (
283 | DSV_TYPE_APPEND_NON_DUPLICATE,
284 | DSV_TYPE_PREPEND_NON_DUPLICATE,
285 | DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS
286 | ):
287 | try:
288 | env_name_and_values = remainder.split(';')
289 | except ValueError:
290 | raise RuntimeError(
291 | "doesn't contain a semicolon separating the environment name "
292 | 'from the values')
293 | env_name = env_name_and_values[0]
294 | values = env_name_and_values[1:]
295 | for value in values:
296 | if not value:
297 | value = prefix
298 | elif not os.path.isabs(value):
299 | value = os.path.join(prefix, value)
300 | if (
301 | type_ == DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS and
302 | not os.path.exists(value)
303 | ):
304 | comment = f'skip extending {env_name} with not existing ' \
305 | f'path: {value}'
306 | if _include_comments():
307 | commands.append(
308 | FORMAT_STR_COMMENT_LINE.format_map({'comment': comment}))
309 | elif type_ == DSV_TYPE_APPEND_NON_DUPLICATE:
310 | commands += _append_unique_value(env_name, value)
311 | else:
312 | commands += _prepend_unique_value(env_name, value)
313 | else:
314 | raise RuntimeError(
315 | 'contains an unknown environment hook type: ' + type_)
316 | return commands
317 |
318 |
319 | env_state = {}
320 |
321 |
322 | def _append_unique_value(name, value):
323 | global env_state
324 | if name not in env_state:
325 | if os.environ.get(name):
326 | env_state[name] = set(os.environ[name].split(os.pathsep))
327 | else:
328 | env_state[name] = set()
329 | # append even if the variable has not been set yet, in case a shell script sets the
330 | # same variable without the knowledge of this Python script.
331 | # later _remove_ending_separators() will cleanup any unintentional leading separator
332 | extend = FORMAT_STR_USE_ENV_VAR.format_map({'name': name}) + os.pathsep
333 | line = FORMAT_STR_SET_ENV_VAR.format_map(
334 | {'name': name, 'value': extend + value})
335 | if value not in env_state[name]:
336 | env_state[name].add(value)
337 | else:
338 | if not _include_comments():
339 | return []
340 | line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
341 | return [line]
342 |
343 |
344 | def _prepend_unique_value(name, value):
345 | global env_state
346 | if name not in env_state:
347 | if os.environ.get(name):
348 | env_state[name] = set(os.environ[name].split(os.pathsep))
349 | else:
350 | env_state[name] = set()
351 | # prepend even if the variable has not been set yet, in case a shell script sets the
352 | # same variable without the knowledge of this Python script.
353 | # later _remove_ending_separators() will cleanup any unintentional trailing separator
354 | extend = os.pathsep + FORMAT_STR_USE_ENV_VAR.format_map({'name': name})
355 | line = FORMAT_STR_SET_ENV_VAR.format_map(
356 | {'name': name, 'value': value + extend})
357 | if value not in env_state[name]:
358 | env_state[name].add(value)
359 | else:
360 | if not _include_comments():
361 | return []
362 | line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
363 | return [line]
364 |
365 |
366 | # generate commands for removing prepended underscores
367 | def _remove_ending_separators():
368 | # do nothing if the shell extension does not implement the logic
369 | if FORMAT_STR_REMOVE_TRAILING_SEPARATOR is None:
370 | return []
371 |
372 | global env_state
373 | commands = []
374 | for name in env_state:
375 | # skip variables that already had values before this script started prepending
376 | if name in os.environ:
377 | continue
378 | commands += [
379 | FORMAT_STR_REMOVE_LEADING_SEPARATOR.format_map({'name': name}),
380 | FORMAT_STR_REMOVE_TRAILING_SEPARATOR.format_map({'name': name})]
381 | return commands
382 |
383 |
384 | def _set(name, value):
385 | global env_state
386 | env_state[name] = value
387 | line = FORMAT_STR_SET_ENV_VAR.format_map(
388 | {'name': name, 'value': value})
389 | return [line]
390 |
391 |
392 | def _set_if_unset(name, value):
393 | global env_state
394 | line = FORMAT_STR_SET_ENV_VAR.format_map(
395 | {'name': name, 'value': value})
396 | if env_state.get(name, os.environ.get(name)):
397 | line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
398 | return [line]
399 |
400 |
401 | if __name__ == '__main__': # pragma: no cover
402 | try:
403 | rc = main()
404 | except RuntimeError as e:
405 | print(str(e), file=sys.stderr)
406 | rc = 1
407 | sys.exit(rc)
408 |
--------------------------------------------------------------------------------
/install/local_setup.bash:
--------------------------------------------------------------------------------
1 | # generated from colcon_bash/shell/template/prefix.bash.em
2 |
3 | # This script extends the environment with all packages contained in this
4 | # prefix path.
5 |
6 | # a bash script is able to determine its own path if necessary
7 | if [ -z "$COLCON_CURRENT_PREFIX" ]; then
8 | _colcon_prefix_bash_COLCON_CURRENT_PREFIX="$(builtin cd "`dirname "${BASH_SOURCE[0]}"`" > /dev/null && pwd)"
9 | else
10 | _colcon_prefix_bash_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
11 | fi
12 |
13 | # function to prepend a value to a variable
14 | # which uses colons as separators
15 | # duplicates as well as trailing separators are avoided
16 | # first argument: the name of the result variable
17 | # second argument: the value to be prepended
18 | _colcon_prefix_bash_prepend_unique_value() {
19 | # arguments
20 | _listname="$1"
21 | _value="$2"
22 |
23 | # get values from variable
24 | eval _values=\"\$$_listname\"
25 | # backup the field separator
26 | _colcon_prefix_bash_prepend_unique_value_IFS="$IFS"
27 | IFS=":"
28 | # start with the new value
29 | _all_values="$_value"
30 | _contained_value=""
31 | # iterate over existing values in the variable
32 | for _item in $_values; do
33 | # ignore empty strings
34 | if [ -z "$_item" ]; then
35 | continue
36 | fi
37 | # ignore duplicates of _value
38 | if [ "$_item" = "$_value" ]; then
39 | _contained_value=1
40 | continue
41 | fi
42 | # keep non-duplicate values
43 | _all_values="$_all_values:$_item"
44 | done
45 | unset _item
46 | if [ -z "$_contained_value" ]; then
47 | if [ -n "$COLCON_TRACE" ]; then
48 | if [ "$_all_values" = "$_value" ]; then
49 | echo "export $_listname=$_value"
50 | else
51 | echo "export $_listname=$_value:\$$_listname"
52 | fi
53 | fi
54 | fi
55 | unset _contained_value
56 | # restore the field separator
57 | IFS="$_colcon_prefix_bash_prepend_unique_value_IFS"
58 | unset _colcon_prefix_bash_prepend_unique_value_IFS
59 | # export the updated variable
60 | eval export $_listname=\"$_all_values\"
61 | unset _all_values
62 | unset _values
63 |
64 | unset _value
65 | unset _listname
66 | }
67 |
68 | # add this prefix to the COLCON_PREFIX_PATH
69 | _colcon_prefix_bash_prepend_unique_value COLCON_PREFIX_PATH "$_colcon_prefix_bash_COLCON_CURRENT_PREFIX"
70 | unset _colcon_prefix_bash_prepend_unique_value
71 |
72 | # check environment variable for custom Python executable
73 | if [ -n "$COLCON_PYTHON_EXECUTABLE" ]; then
74 | if [ ! -f "$COLCON_PYTHON_EXECUTABLE" ]; then
75 | echo "error: COLCON_PYTHON_EXECUTABLE '$COLCON_PYTHON_EXECUTABLE' doesn't exist"
76 | return 1
77 | fi
78 | _colcon_python_executable="$COLCON_PYTHON_EXECUTABLE"
79 | else
80 | # try the Python executable known at configure time
81 | _colcon_python_executable="/usr/bin/python3"
82 | # if it doesn't exist try a fall back
83 | if [ ! -f "$_colcon_python_executable" ]; then
84 | if ! /usr/bin/env python3 --version > /dev/null 2> /dev/null; then
85 | echo "error: unable to find python3 executable"
86 | return 1
87 | fi
88 | _colcon_python_executable=`/usr/bin/env python3 -c "import sys; print(sys.executable)"`
89 | fi
90 | fi
91 |
92 | # function to source another script with conditional trace output
93 | # first argument: the path of the script
94 | _colcon_prefix_sh_source_script() {
95 | if [ -f "$1" ]; then
96 | if [ -n "$COLCON_TRACE" ]; then
97 | echo "# . \"$1\""
98 | fi
99 | . "$1"
100 | else
101 | echo "not found: \"$1\"" 1>&2
102 | fi
103 | }
104 |
105 | # get all commands in topological order
106 | _colcon_ordered_commands="$($_colcon_python_executable "$_colcon_prefix_bash_COLCON_CURRENT_PREFIX/_local_setup_util_sh.py" sh bash)"
107 | unset _colcon_python_executable
108 | if [ -n "$COLCON_TRACE" ]; then
109 | echo "$(declare -f _colcon_prefix_sh_source_script)"
110 | echo "# Execute generated script:"
111 | echo "# <<<"
112 | echo "${_colcon_ordered_commands}"
113 | echo "# >>>"
114 | echo "unset _colcon_prefix_sh_source_script"
115 | fi
116 | eval "${_colcon_ordered_commands}"
117 | unset _colcon_ordered_commands
118 |
119 | unset _colcon_prefix_sh_source_script
120 |
121 | unset _colcon_prefix_bash_COLCON_CURRENT_PREFIX
122 |
--------------------------------------------------------------------------------
/install/local_setup.ps1:
--------------------------------------------------------------------------------
1 | # generated from colcon_powershell/shell/template/prefix.ps1.em
2 |
3 | # This script extends the environment with all packages contained in this
4 | # prefix path.
5 |
6 | # check environment variable for custom Python executable
7 | if ($env:COLCON_PYTHON_EXECUTABLE) {
8 | if (!(Test-Path "$env:COLCON_PYTHON_EXECUTABLE" -PathType Leaf)) {
9 | echo "error: COLCON_PYTHON_EXECUTABLE '$env:COLCON_PYTHON_EXECUTABLE' doesn't exist"
10 | exit 1
11 | }
12 | $_colcon_python_executable="$env:COLCON_PYTHON_EXECUTABLE"
13 | } else {
14 | # use the Python executable known at configure time
15 | $_colcon_python_executable="/usr/bin/python3"
16 | # if it doesn't exist try a fall back
17 | if (!(Test-Path "$_colcon_python_executable" -PathType Leaf)) {
18 | if (!(Get-Command "python3" -ErrorAction SilentlyContinue)) {
19 | echo "error: unable to find python3 executable"
20 | exit 1
21 | }
22 | $_colcon_python_executable="python3"
23 | }
24 | }
25 |
26 | # function to source another script with conditional trace output
27 | # first argument: the path of the script
28 | function _colcon_prefix_powershell_source_script {
29 | param (
30 | $_colcon_prefix_powershell_source_script_param
31 | )
32 | # source script with conditional trace output
33 | if (Test-Path $_colcon_prefix_powershell_source_script_param) {
34 | if ($env:COLCON_TRACE) {
35 | echo ". '$_colcon_prefix_powershell_source_script_param'"
36 | }
37 | . "$_colcon_prefix_powershell_source_script_param"
38 | } else {
39 | Write-Error "not found: '$_colcon_prefix_powershell_source_script_param'"
40 | }
41 | }
42 |
43 | # get all commands in topological order
44 | $_colcon_ordered_commands = & "$_colcon_python_executable" "$(Split-Path $PSCommandPath -Parent)/_local_setup_util_ps1.py" ps1
45 |
46 | # execute all commands in topological order
47 | if ($env:COLCON_TRACE) {
48 | echo "Execute generated script:"
49 | echo "<<<"
50 | $_colcon_ordered_commands.Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries) | Write-Output
51 | echo ">>>"
52 | }
53 | if ($_colcon_ordered_commands) {
54 | $_colcon_ordered_commands.Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries) | Invoke-Expression
55 | }
56 |
--------------------------------------------------------------------------------
/install/local_setup.sh:
--------------------------------------------------------------------------------
1 | # generated from colcon_core/shell/template/prefix.sh.em
2 |
3 | # This script extends the environment with all packages contained in this
4 | # prefix path.
5 |
6 | # since a plain shell script can't determine its own path when being sourced
7 | # either use the provided COLCON_CURRENT_PREFIX
8 | # or fall back to the build time prefix (if it exists)
9 | _colcon_prefix_sh_COLCON_CURRENT_PREFIX="/home/anson/ros2_ws/install"
10 | if [ -z "$COLCON_CURRENT_PREFIX" ]; then
11 | if [ ! -d "$_colcon_prefix_sh_COLCON_CURRENT_PREFIX" ]; then
12 | echo "The build time path \"$_colcon_prefix_sh_COLCON_CURRENT_PREFIX\" doesn't exist. Either source a script for a different shell or set the environment variable \"COLCON_CURRENT_PREFIX\" explicitly." 1>&2
13 | unset _colcon_prefix_sh_COLCON_CURRENT_PREFIX
14 | return 1
15 | fi
16 | else
17 | _colcon_prefix_sh_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
18 | fi
19 |
20 | # function to prepend a value to a variable
21 | # which uses colons as separators
22 | # duplicates as well as trailing separators are avoided
23 | # first argument: the name of the result variable
24 | # second argument: the value to be prepended
25 | _colcon_prefix_sh_prepend_unique_value() {
26 | # arguments
27 | _listname="$1"
28 | _value="$2"
29 |
30 | # get values from variable
31 | eval _values=\"\$$_listname\"
32 | # backup the field separator
33 | _colcon_prefix_sh_prepend_unique_value_IFS="$IFS"
34 | IFS=":"
35 | # start with the new value
36 | _all_values="$_value"
37 | _contained_value=""
38 | # iterate over existing values in the variable
39 | for _item in $_values; do
40 | # ignore empty strings
41 | if [ -z "$_item" ]; then
42 | continue
43 | fi
44 | # ignore duplicates of _value
45 | if [ "$_item" = "$_value" ]; then
46 | _contained_value=1
47 | continue
48 | fi
49 | # keep non-duplicate values
50 | _all_values="$_all_values:$_item"
51 | done
52 | unset _item
53 | if [ -z "$_contained_value" ]; then
54 | if [ -n "$COLCON_TRACE" ]; then
55 | if [ "$_all_values" = "$_value" ]; then
56 | echo "export $_listname=$_value"
57 | else
58 | echo "export $_listname=$_value:\$$_listname"
59 | fi
60 | fi
61 | fi
62 | unset _contained_value
63 | # restore the field separator
64 | IFS="$_colcon_prefix_sh_prepend_unique_value_IFS"
65 | unset _colcon_prefix_sh_prepend_unique_value_IFS
66 | # export the updated variable
67 | eval export $_listname=\"$_all_values\"
68 | unset _all_values
69 | unset _values
70 |
71 | unset _value
72 | unset _listname
73 | }
74 |
75 | # add this prefix to the COLCON_PREFIX_PATH
76 | _colcon_prefix_sh_prepend_unique_value COLCON_PREFIX_PATH "$_colcon_prefix_sh_COLCON_CURRENT_PREFIX"
77 | unset _colcon_prefix_sh_prepend_unique_value
78 |
79 | # check environment variable for custom Python executable
80 | if [ -n "$COLCON_PYTHON_EXECUTABLE" ]; then
81 | if [ ! -f "$COLCON_PYTHON_EXECUTABLE" ]; then
82 | echo "error: COLCON_PYTHON_EXECUTABLE '$COLCON_PYTHON_EXECUTABLE' doesn't exist"
83 | return 1
84 | fi
85 | _colcon_python_executable="$COLCON_PYTHON_EXECUTABLE"
86 | else
87 | # try the Python executable known at configure time
88 | _colcon_python_executable="/usr/bin/python3"
89 | # if it doesn't exist try a fall back
90 | if [ ! -f "$_colcon_python_executable" ]; then
91 | if ! /usr/bin/env python3 --version > /dev/null 2> /dev/null; then
92 | echo "error: unable to find python3 executable"
93 | return 1
94 | fi
95 | _colcon_python_executable=`/usr/bin/env python3 -c "import sys; print(sys.executable)"`
96 | fi
97 | fi
98 |
99 | # function to source another script with conditional trace output
100 | # first argument: the path of the script
101 | _colcon_prefix_sh_source_script() {
102 | if [ -f "$1" ]; then
103 | if [ -n "$COLCON_TRACE" ]; then
104 | echo "# . \"$1\""
105 | fi
106 | . "$1"
107 | else
108 | echo "not found: \"$1\"" 1>&2
109 | fi
110 | }
111 |
112 | # get all commands in topological order
113 | _colcon_ordered_commands="$($_colcon_python_executable "$_colcon_prefix_sh_COLCON_CURRENT_PREFIX/_local_setup_util_sh.py" sh)"
114 | unset _colcon_python_executable
115 | if [ -n "$COLCON_TRACE" ]; then
116 | echo "_colcon_prefix_sh_source_script() {
117 | if [ -f \"\$1\" ]; then
118 | if [ -n \"\$COLCON_TRACE\" ]; then
119 | echo \"# . \\\"\$1\\\"\"
120 | fi
121 | . \"\$1\"
122 | else
123 | echo \"not found: \\\"\$1\\\"\" 1>&2
124 | fi
125 | }"
126 | echo "# Execute generated script:"
127 | echo "# <<<"
128 | echo "${_colcon_ordered_commands}"
129 | echo "# >>>"
130 | echo "unset _colcon_prefix_sh_source_script"
131 | fi
132 | eval "${_colcon_ordered_commands}"
133 | unset _colcon_ordered_commands
134 |
135 | unset _colcon_prefix_sh_source_script
136 |
137 | unset _colcon_prefix_sh_COLCON_CURRENT_PREFIX
138 |
--------------------------------------------------------------------------------
/install/local_setup.zsh:
--------------------------------------------------------------------------------
1 | # generated from colcon_zsh/shell/template/prefix.zsh.em
2 |
3 | # This script extends the environment with all packages contained in this
4 | # prefix path.
5 |
6 | # a zsh script is able to determine its own path if necessary
7 | if [ -z "$COLCON_CURRENT_PREFIX" ]; then
8 | _colcon_prefix_zsh_COLCON_CURRENT_PREFIX="$(builtin cd -q "`dirname "${(%):-%N}"`" > /dev/null && pwd)"
9 | else
10 | _colcon_prefix_zsh_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
11 | fi
12 |
13 | # function to convert array-like strings into arrays
14 | # to workaround SH_WORD_SPLIT not being set
15 | _colcon_prefix_zsh_convert_to_array() {
16 | local _listname=$1
17 | local _dollar="$"
18 | local _split="{="
19 | local _to_array="(\"$_dollar$_split$_listname}\")"
20 | eval $_listname=$_to_array
21 | }
22 |
23 | # function to prepend a value to a variable
24 | # which uses colons as separators
25 | # duplicates as well as trailing separators are avoided
26 | # first argument: the name of the result variable
27 | # second argument: the value to be prepended
28 | _colcon_prefix_zsh_prepend_unique_value() {
29 | # arguments
30 | _listname="$1"
31 | _value="$2"
32 |
33 | # get values from variable
34 | eval _values=\"\$$_listname\"
35 | # backup the field separator
36 | _colcon_prefix_zsh_prepend_unique_value_IFS="$IFS"
37 | IFS=":"
38 | # start with the new value
39 | _all_values="$_value"
40 | _contained_value=""
41 | # workaround SH_WORD_SPLIT not being set
42 | _colcon_prefix_zsh_convert_to_array _values
43 | # iterate over existing values in the variable
44 | for _item in $_values; do
45 | # ignore empty strings
46 | if [ -z "$_item" ]; then
47 | continue
48 | fi
49 | # ignore duplicates of _value
50 | if [ "$_item" = "$_value" ]; then
51 | _contained_value=1
52 | continue
53 | fi
54 | # keep non-duplicate values
55 | _all_values="$_all_values:$_item"
56 | done
57 | unset _item
58 | if [ -z "$_contained_value" ]; then
59 | if [ -n "$COLCON_TRACE" ]; then
60 | if [ "$_all_values" = "$_value" ]; then
61 | echo "export $_listname=$_value"
62 | else
63 | echo "export $_listname=$_value:\$$_listname"
64 | fi
65 | fi
66 | fi
67 | unset _contained_value
68 | # restore the field separator
69 | IFS="$_colcon_prefix_zsh_prepend_unique_value_IFS"
70 | unset _colcon_prefix_zsh_prepend_unique_value_IFS
71 | # export the updated variable
72 | eval export $_listname=\"$_all_values\"
73 | unset _all_values
74 | unset _values
75 |
76 | unset _value
77 | unset _listname
78 | }
79 |
80 | # add this prefix to the COLCON_PREFIX_PATH
81 | _colcon_prefix_zsh_prepend_unique_value COLCON_PREFIX_PATH "$_colcon_prefix_zsh_COLCON_CURRENT_PREFIX"
82 | unset _colcon_prefix_zsh_prepend_unique_value
83 | unset _colcon_prefix_zsh_convert_to_array
84 |
85 | # check environment variable for custom Python executable
86 | if [ -n "$COLCON_PYTHON_EXECUTABLE" ]; then
87 | if [ ! -f "$COLCON_PYTHON_EXECUTABLE" ]; then
88 | echo "error: COLCON_PYTHON_EXECUTABLE '$COLCON_PYTHON_EXECUTABLE' doesn't exist"
89 | return 1
90 | fi
91 | _colcon_python_executable="$COLCON_PYTHON_EXECUTABLE"
92 | else
93 | # try the Python executable known at configure time
94 | _colcon_python_executable="/usr/bin/python3"
95 | # if it doesn't exist try a fall back
96 | if [ ! -f "$_colcon_python_executable" ]; then
97 | if ! /usr/bin/env python3 --version > /dev/null 2> /dev/null; then
98 | echo "error: unable to find python3 executable"
99 | return 1
100 | fi
101 | _colcon_python_executable=`/usr/bin/env python3 -c "import sys; print(sys.executable)"`
102 | fi
103 | fi
104 |
105 | # function to source another script with conditional trace output
106 | # first argument: the path of the script
107 | _colcon_prefix_sh_source_script() {
108 | if [ -f "$1" ]; then
109 | if [ -n "$COLCON_TRACE" ]; then
110 | echo "# . \"$1\""
111 | fi
112 | . "$1"
113 | else
114 | echo "not found: \"$1\"" 1>&2
115 | fi
116 | }
117 |
118 | # get all commands in topological order
119 | _colcon_ordered_commands="$($_colcon_python_executable "$_colcon_prefix_zsh_COLCON_CURRENT_PREFIX/_local_setup_util_sh.py" sh zsh)"
120 | unset _colcon_python_executable
121 | if [ -n "$COLCON_TRACE" ]; then
122 | echo "$(declare -f _colcon_prefix_sh_source_script)"
123 | echo "# Execute generated script:"
124 | echo "# <<<"
125 | echo "${_colcon_ordered_commands}"
126 | echo "# >>>"
127 | echo "unset _colcon_prefix_sh_source_script"
128 | fi
129 | eval "${_colcon_ordered_commands}"
130 | unset _colcon_ordered_commands
131 |
132 | unset _colcon_prefix_sh_source_script
133 |
134 | unset _colcon_prefix_zsh_COLCON_CURRENT_PREFIX
135 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/my_robot_navigation/obstacle_avoidance:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # EASY-INSTALL-ENTRY-SCRIPT: 'my-robot-navigation==0.0.0','console_scripts','obstacle_avoidance'
3 | import re
4 | import sys
5 |
6 | # for compatibility with easy_install; see #2198
7 | __requires__ = 'my-robot-navigation==0.0.0'
8 |
9 | try:
10 | from importlib.metadata import distribution
11 | except ImportError:
12 | try:
13 | from importlib_metadata import distribution
14 | except ImportError:
15 | from pkg_resources import load_entry_point
16 |
17 |
18 | def importlib_load_entry_point(spec, group, name):
19 | dist_name, _, _ = spec.partition('==')
20 | matches = (
21 | entry_point
22 | for entry_point in distribution(dist_name).entry_points
23 | if entry_point.group == group and entry_point.name == name
24 | )
25 | return next(matches).load()
26 |
27 |
28 | globals().setdefault('load_entry_point', importlib_load_entry_point)
29 |
30 |
31 | if __name__ == '__main__':
32 | sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
33 | sys.exit(load_entry_point('my-robot-navigation==0.0.0', 'console_scripts', 'obstacle_avoidance')())
34 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/PKG-INFO:
--------------------------------------------------------------------------------
1 | Metadata-Version: 2.1
2 | Name: my-robot-navigation
3 | Version: 0.0.0
4 | Summary: Obstacle avoidance robot with ROS2 and Gazebo
5 | Home-page: UNKNOWN
6 | Maintainer: anson
7 | Maintainer-email: sansonmsa@gmail.com
8 | License: Apache License 2.0
9 | Platform: UNKNOWN
10 |
11 | UNKNOWN
12 |
13 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/SOURCES.txt:
--------------------------------------------------------------------------------
1 | package.xml
2 | setup.cfg
3 | setup.py
4 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/PKG-INFO
5 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/SOURCES.txt
6 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/dependency_links.txt
7 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/entry_points.txt
8 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/requires.txt
9 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/top_level.txt
10 | ../../build/my_robot_navigation/my_robot_navigation.egg-info/zip-safe
11 | launch/robot_navigation.launch.py
12 | my_robot_navigation/__init__.py
13 | my_robot_navigation/obstacle_avoidance.py
14 | resource/my_robot_navigation
15 | test/test_copyright.py
16 | test/test_flake8.py
17 | test/test_pep257.py
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/dependency_links.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/entry_points.txt:
--------------------------------------------------------------------------------
1 | [console_scripts]
2 | obstacle_avoidance = my_robot_navigation.obstacle_avoidance:main
3 |
4 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/requires.txt:
--------------------------------------------------------------------------------
1 | setuptools
2 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/top_level.txt:
--------------------------------------------------------------------------------
1 | my_robot_navigation
2 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation-0.0.0-py3.10.egg-info/zip-safe:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__init__.py
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__pycache__/__init__.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__pycache__/__init__.cpython-310.pyc
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__pycache__/obstacle_avoidance.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/__pycache__/obstacle_avoidance.cpython-310.pyc
--------------------------------------------------------------------------------
/install/my_robot_navigation/lib/python3.10/site-packages/my_robot_navigation/obstacle_avoidance.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import rclpy
4 | from rclpy.node import Node
5 | from sensor_msgs.msg import LaserScan
6 | from geometry_msgs.msg import Twist
7 |
8 | class ObstacleAvoidanceNode(Node):
9 | def __init__(self):
10 | super().__init__('obstacle_avoidance_node')
11 | # Subscriber to LIDAR data
12 | self.subscription = self.create_subscription(
13 | LaserScan,
14 | '/scan', # TurtleBot3 LIDAR topic
15 | self.lidar_callback,
16 | 10
17 | )
18 | # Publisher for velocity commands
19 | self.publisher = self.create_publisher(
20 | Twist,
21 | '/cmd_vel', # TurtleBot3 velocity topic
22 | 10
23 | )
24 | self.get_logger().info("Obstacle Avoidance Node Started")
25 |
26 | def lidar_callback(self, msg):
27 | # Process LIDAR data (360 degrees, 0 = front, 180 = rear)
28 | ranges = msg.ranges
29 | min_distance = min(ranges[0:60] + ranges[300:360]) # Check front 120 degrees
30 | twist = Twist()
31 |
32 | if min_distance < 0.5: # If obstacle closer than 0.5m
33 | twist.linear.x = 0.0
34 | twist.angular.z = 0.5 # Turn right
35 | self.get_logger().info(f"Obstacle detected {min_distance:.2f}m ahead, turning!")
36 | else:
37 | twist.linear.x = 0.2 # Move forward
38 | twist.angular.z = 0.0
39 | self.get_logger().info("Path clear, moving forward")
40 |
41 | self.publisher.publish(twist)
42 |
43 | def main(args=None):
44 | rclpy.init(args=args)
45 | node = ObstacleAvoidanceNode()
46 | try:
47 | rclpy.spin(node)
48 | except KeyboardInterrupt:
49 | node.get_logger().info("Shutting down")
50 | finally:
51 | node.destroy_node()
52 | rclpy.shutdown()
53 |
54 | if __name__ == '__main__':
55 | main()
56 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/ament_index/resource_index/packages/my_robot_navigation:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/install/my_robot_navigation/share/ament_index/resource_index/packages/my_robot_navigation
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/colcon-core/packages/my_robot_navigation:
--------------------------------------------------------------------------------
1 | geometry_msgs:rclcpp:sensor_msgs
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/__pycache__/robot_navigation.launch.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/install/my_robot_navigation/share/my_robot_navigation/__pycache__/robot_navigation.launch.cpython-310.pyc
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/hook/ament_prefix_path.dsv:
--------------------------------------------------------------------------------
1 | prepend-non-duplicate;AMENT_PREFIX_PATH;
2 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/hook/ament_prefix_path.ps1:
--------------------------------------------------------------------------------
1 | # generated from colcon_powershell/shell/template/hook_prepend_value.ps1.em
2 |
3 | colcon_prepend_unique_value AMENT_PREFIX_PATH "$env:COLCON_CURRENT_PREFIX"
4 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/hook/ament_prefix_path.sh:
--------------------------------------------------------------------------------
1 | # generated from colcon_core/shell/template/hook_prepend_value.sh.em
2 |
3 | _colcon_prepend_unique_value AMENT_PREFIX_PATH "$COLCON_CURRENT_PREFIX"
4 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/hook/pythonpath.dsv:
--------------------------------------------------------------------------------
1 | prepend-non-duplicate;PYTHONPATH;lib/python3.10/site-packages
2 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/hook/pythonpath.ps1:
--------------------------------------------------------------------------------
1 | # generated from colcon_powershell/shell/template/hook_prepend_value.ps1.em
2 |
3 | colcon_prepend_unique_value PYTHONPATH "$env:COLCON_CURRENT_PREFIX\lib/python3.10/site-packages"
4 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/hook/pythonpath.sh:
--------------------------------------------------------------------------------
1 | # generated from colcon_core/shell/template/hook_prepend_value.sh.em
2 |
3 | _colcon_prepend_unique_value PYTHONPATH "$COLCON_CURRENT_PREFIX/lib/python3.10/site-packages"
4 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/package.bash:
--------------------------------------------------------------------------------
1 | # generated from colcon_bash/shell/template/package.bash.em
2 |
3 | # This script extends the environment for this package.
4 |
5 | # a bash script is able to determine its own path if necessary
6 | if [ -z "$COLCON_CURRENT_PREFIX" ]; then
7 | # the prefix is two levels up from the package specific share directory
8 | _colcon_package_bash_COLCON_CURRENT_PREFIX="$(builtin cd "`dirname "${BASH_SOURCE[0]}"`/../.." > /dev/null && pwd)"
9 | else
10 | _colcon_package_bash_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
11 | fi
12 |
13 | # function to source another script with conditional trace output
14 | # first argument: the path of the script
15 | # additional arguments: arguments to the script
16 | _colcon_package_bash_source_script() {
17 | if [ -f "$1" ]; then
18 | if [ -n "$COLCON_TRACE" ]; then
19 | echo "# . \"$1\""
20 | fi
21 | . "$@"
22 | else
23 | echo "not found: \"$1\"" 1>&2
24 | fi
25 | }
26 |
27 | # source sh script of this package
28 | _colcon_package_bash_source_script "$_colcon_package_bash_COLCON_CURRENT_PREFIX/share/my_robot_navigation/package.sh"
29 |
30 | unset _colcon_package_bash_source_script
31 | unset _colcon_package_bash_COLCON_CURRENT_PREFIX
32 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/package.dsv:
--------------------------------------------------------------------------------
1 | source;share/my_robot_navigation/hook/pythonpath.ps1
2 | source;share/my_robot_navigation/hook/pythonpath.dsv
3 | source;share/my_robot_navigation/hook/pythonpath.sh
4 | source;share/my_robot_navigation/hook/ament_prefix_path.ps1
5 | source;share/my_robot_navigation/hook/ament_prefix_path.dsv
6 | source;share/my_robot_navigation/hook/ament_prefix_path.sh
7 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/package.ps1:
--------------------------------------------------------------------------------
1 | # generated from colcon_powershell/shell/template/package.ps1.em
2 |
3 | # function to append a value to a variable
4 | # which uses colons as separators
5 | # duplicates as well as leading separators are avoided
6 | # first argument: the name of the result variable
7 | # second argument: the value to be prepended
8 | function colcon_append_unique_value {
9 | param (
10 | $_listname,
11 | $_value
12 | )
13 |
14 | # get values from variable
15 | if (Test-Path Env:$_listname) {
16 | $_values=(Get-Item env:$_listname).Value
17 | } else {
18 | $_values=""
19 | }
20 | $_duplicate=""
21 | # start with no values
22 | $_all_values=""
23 | # iterate over existing values in the variable
24 | if ($_values) {
25 | $_values.Split(";") | ForEach {
26 | # not an empty string
27 | if ($_) {
28 | # not a duplicate of _value
29 | if ($_ -eq $_value) {
30 | $_duplicate="1"
31 | }
32 | if ($_all_values) {
33 | $_all_values="${_all_values};$_"
34 | } else {
35 | $_all_values="$_"
36 | }
37 | }
38 | }
39 | }
40 | # append only non-duplicates
41 | if (!$_duplicate) {
42 | # avoid leading separator
43 | if ($_all_values) {
44 | $_all_values="${_all_values};${_value}"
45 | } else {
46 | $_all_values="${_value}"
47 | }
48 | }
49 |
50 | # export the updated variable
51 | Set-Item env:\$_listname -Value "$_all_values"
52 | }
53 |
54 | # function to prepend a value to a variable
55 | # which uses colons as separators
56 | # duplicates as well as trailing separators are avoided
57 | # first argument: the name of the result variable
58 | # second argument: the value to be prepended
59 | function colcon_prepend_unique_value {
60 | param (
61 | $_listname,
62 | $_value
63 | )
64 |
65 | # get values from variable
66 | if (Test-Path Env:$_listname) {
67 | $_values=(Get-Item env:$_listname).Value
68 | } else {
69 | $_values=""
70 | }
71 | # start with the new value
72 | $_all_values="$_value"
73 | # iterate over existing values in the variable
74 | if ($_values) {
75 | $_values.Split(";") | ForEach {
76 | # not an empty string
77 | if ($_) {
78 | # not a duplicate of _value
79 | if ($_ -ne $_value) {
80 | # keep non-duplicate values
81 | $_all_values="${_all_values};$_"
82 | }
83 | }
84 | }
85 | }
86 | # export the updated variable
87 | Set-Item env:\$_listname -Value "$_all_values"
88 | }
89 |
90 | # function to source another script with conditional trace output
91 | # first argument: the path of the script
92 | # additional arguments: arguments to the script
93 | function colcon_package_source_powershell_script {
94 | param (
95 | $_colcon_package_source_powershell_script
96 | )
97 | # source script with conditional trace output
98 | if (Test-Path $_colcon_package_source_powershell_script) {
99 | if ($env:COLCON_TRACE) {
100 | echo ". '$_colcon_package_source_powershell_script'"
101 | }
102 | . "$_colcon_package_source_powershell_script"
103 | } else {
104 | Write-Error "not found: '$_colcon_package_source_powershell_script'"
105 | }
106 | }
107 |
108 |
109 | # a powershell script is able to determine its own path
110 | # the prefix is two levels up from the package specific share directory
111 | $env:COLCON_CURRENT_PREFIX=(Get-Item $PSCommandPath).Directory.Parent.Parent.FullName
112 |
113 | colcon_package_source_powershell_script "$env:COLCON_CURRENT_PREFIX\share/my_robot_navigation/hook/pythonpath.ps1"
114 | colcon_package_source_powershell_script "$env:COLCON_CURRENT_PREFIX\share/my_robot_navigation/hook/ament_prefix_path.ps1"
115 |
116 | Remove-Item Env:\COLCON_CURRENT_PREFIX
117 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/package.sh:
--------------------------------------------------------------------------------
1 | # generated from colcon_core/shell/template/package.sh.em
2 |
3 | # This script extends the environment for this package.
4 |
5 | # function to prepend a value to a variable
6 | # which uses colons as separators
7 | # duplicates as well as trailing separators are avoided
8 | # first argument: the name of the result variable
9 | # second argument: the value to be prepended
10 | _colcon_prepend_unique_value() {
11 | # arguments
12 | _listname="$1"
13 | _value="$2"
14 |
15 | # get values from variable
16 | eval _values=\"\$$_listname\"
17 | # backup the field separator
18 | _colcon_prepend_unique_value_IFS=$IFS
19 | IFS=":"
20 | # start with the new value
21 | _all_values="$_value"
22 | # workaround SH_WORD_SPLIT not being set in zsh
23 | if [ "$(command -v colcon_zsh_convert_to_array)" ]; then
24 | colcon_zsh_convert_to_array _values
25 | fi
26 | # iterate over existing values in the variable
27 | for _item in $_values; do
28 | # ignore empty strings
29 | if [ -z "$_item" ]; then
30 | continue
31 | fi
32 | # ignore duplicates of _value
33 | if [ "$_item" = "$_value" ]; then
34 | continue
35 | fi
36 | # keep non-duplicate values
37 | _all_values="$_all_values:$_item"
38 | done
39 | unset _item
40 | # restore the field separator
41 | IFS=$_colcon_prepend_unique_value_IFS
42 | unset _colcon_prepend_unique_value_IFS
43 | # export the updated variable
44 | eval export $_listname=\"$_all_values\"
45 | unset _all_values
46 | unset _values
47 |
48 | unset _value
49 | unset _listname
50 | }
51 |
52 | # since a plain shell script can't determine its own path when being sourced
53 | # either use the provided COLCON_CURRENT_PREFIX
54 | # or fall back to the build time prefix (if it exists)
55 | _colcon_package_sh_COLCON_CURRENT_PREFIX="/home/anson/ros2_ws/install/my_robot_navigation"
56 | if [ -z "$COLCON_CURRENT_PREFIX" ]; then
57 | if [ ! -d "$_colcon_package_sh_COLCON_CURRENT_PREFIX" ]; then
58 | echo "The build time path \"$_colcon_package_sh_COLCON_CURRENT_PREFIX\" doesn't exist. Either source a script for a different shell or set the environment variable \"COLCON_CURRENT_PREFIX\" explicitly." 1>&2
59 | unset _colcon_package_sh_COLCON_CURRENT_PREFIX
60 | return 1
61 | fi
62 | COLCON_CURRENT_PREFIX="$_colcon_package_sh_COLCON_CURRENT_PREFIX"
63 | fi
64 | unset _colcon_package_sh_COLCON_CURRENT_PREFIX
65 |
66 | # function to source another script with conditional trace output
67 | # first argument: the path of the script
68 | # additional arguments: arguments to the script
69 | _colcon_package_sh_source_script() {
70 | if [ -f "$1" ]; then
71 | if [ -n "$COLCON_TRACE" ]; then
72 | echo "# . \"$1\""
73 | fi
74 | . "$@"
75 | else
76 | echo "not found: \"$1\"" 1>&2
77 | fi
78 | }
79 |
80 | # source sh hooks
81 | _colcon_package_sh_source_script "$COLCON_CURRENT_PREFIX/share/my_robot_navigation/hook/pythonpath.sh"
82 | _colcon_package_sh_source_script "$COLCON_CURRENT_PREFIX/share/my_robot_navigation/hook/ament_prefix_path.sh"
83 |
84 | unset _colcon_package_sh_source_script
85 | unset COLCON_CURRENT_PREFIX
86 |
87 | # do not unset _colcon_prepend_unique_value since it might be used by non-primary shell hooks
88 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | my_robot_navigation
5 | 0.0.0
6 | TODO: Package description
7 | anson
8 | TODO: License declaration
9 |
10 | rclcpp
11 | sensor_msgs
12 | geometry_msgs
13 |
14 | ament_copyright
15 | ament_flake8
16 | ament_pep257
17 | python3-pytest
18 |
19 |
20 | ament_python
21 |
22 |
23 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/package.zsh:
--------------------------------------------------------------------------------
1 | # generated from colcon_zsh/shell/template/package.zsh.em
2 |
3 | # This script extends the environment for this package.
4 |
5 | # a zsh script is able to determine its own path if necessary
6 | if [ -z "$COLCON_CURRENT_PREFIX" ]; then
7 | # the prefix is two levels up from the package specific share directory
8 | _colcon_package_zsh_COLCON_CURRENT_PREFIX="$(builtin cd -q "`dirname "${(%):-%N}"`/../.." > /dev/null && pwd)"
9 | else
10 | _colcon_package_zsh_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
11 | fi
12 |
13 | # function to source another script with conditional trace output
14 | # first argument: the path of the script
15 | # additional arguments: arguments to the script
16 | _colcon_package_zsh_source_script() {
17 | if [ -f "$1" ]; then
18 | if [ -n "$COLCON_TRACE" ]; then
19 | echo "# . \"$1\""
20 | fi
21 | . "$@"
22 | else
23 | echo "not found: \"$1\"" 1>&2
24 | fi
25 | }
26 |
27 | # function to convert array-like strings into arrays
28 | # to workaround SH_WORD_SPLIT not being set
29 | colcon_zsh_convert_to_array() {
30 | local _listname=$1
31 | local _dollar="$"
32 | local _split="{="
33 | local _to_array="(\"$_dollar$_split$_listname}\")"
34 | eval $_listname=$_to_array
35 | }
36 |
37 | # source sh script of this package
38 | _colcon_package_zsh_source_script "$_colcon_package_zsh_COLCON_CURRENT_PREFIX/share/my_robot_navigation/package.sh"
39 | unset convert_zsh_to_array
40 |
41 | unset _colcon_package_zsh_source_script
42 | unset _colcon_package_zsh_COLCON_CURRENT_PREFIX
43 |
--------------------------------------------------------------------------------
/install/my_robot_navigation/share/my_robot_navigation/robot_navigation.launch.py:
--------------------------------------------------------------------------------
1 | from launch import LaunchDescription
2 | from launch_ros.actions import Node
3 | from launch.actions import ExecuteProcess
4 | from launch.substitutions import LaunchConfiguration
5 | from launch.actions import SetEnvironmentVariable
6 |
7 | def generate_launch_description():
8 | return LaunchDescription([
9 | # Set the TURTLEBOT3_MODEL environment variable
10 | SetEnvironmentVariable('TURTLEBOT3_MODEL', 'burger'),
11 | # Launch Gazebo with TurtleBot3
12 | ExecuteProcess(
13 | cmd=['ros2', 'launch', 'turtlebot3_gazebo', 'turtlebot3_world.launch.py'],
14 | output='screen'
15 | ),
16 | # Launch the obstacle avoidance node
17 | Node(
18 | package='my_robot_navigation',
19 | executable='obstacle_avoidance',
20 | name='obstacle_avoidance_node',
21 | output='screen'
22 | )
23 | ])
24 |
--------------------------------------------------------------------------------
/install/setup.bash:
--------------------------------------------------------------------------------
1 | # generated from colcon_bash/shell/template/prefix_chain.bash.em
2 |
3 | # This script extends the environment with the environment of other prefix
4 | # paths which were sourced when this file was generated as well as all packages
5 | # contained in this prefix path.
6 |
7 | # function to source another script with conditional trace output
8 | # first argument: the path of the script
9 | _colcon_prefix_chain_bash_source_script() {
10 | if [ -f "$1" ]; then
11 | if [ -n "$COLCON_TRACE" ]; then
12 | echo "# . \"$1\""
13 | fi
14 | . "$1"
15 | else
16 | echo "not found: \"$1\"" 1>&2
17 | fi
18 | }
19 |
20 | # source chained prefixes
21 | # setting COLCON_CURRENT_PREFIX avoids determining the prefix in the sourced script
22 | COLCON_CURRENT_PREFIX="/opt/ros/humble"
23 | _colcon_prefix_chain_bash_source_script "$COLCON_CURRENT_PREFIX/local_setup.bash"
24 |
25 | # source this prefix
26 | # setting COLCON_CURRENT_PREFIX avoids determining the prefix in the sourced script
27 | COLCON_CURRENT_PREFIX="$(builtin cd "`dirname "${BASH_SOURCE[0]}"`" > /dev/null && pwd)"
28 | _colcon_prefix_chain_bash_source_script "$COLCON_CURRENT_PREFIX/local_setup.bash"
29 |
30 | unset COLCON_CURRENT_PREFIX
31 | unset _colcon_prefix_chain_bash_source_script
32 |
--------------------------------------------------------------------------------
/install/setup.ps1:
--------------------------------------------------------------------------------
1 | # generated from colcon_powershell/shell/template/prefix_chain.ps1.em
2 |
3 | # This script extends the environment with the environment of other prefix
4 | # paths which were sourced when this file was generated as well as all packages
5 | # contained in this prefix path.
6 |
7 | # function to source another script with conditional trace output
8 | # first argument: the path of the script
9 | function _colcon_prefix_chain_powershell_source_script {
10 | param (
11 | $_colcon_prefix_chain_powershell_source_script_param
12 | )
13 | # source script with conditional trace output
14 | if (Test-Path $_colcon_prefix_chain_powershell_source_script_param) {
15 | if ($env:COLCON_TRACE) {
16 | echo ". '$_colcon_prefix_chain_powershell_source_script_param'"
17 | }
18 | . "$_colcon_prefix_chain_powershell_source_script_param"
19 | } else {
20 | Write-Error "not found: '$_colcon_prefix_chain_powershell_source_script_param'"
21 | }
22 | }
23 |
24 | # source chained prefixes
25 | _colcon_prefix_chain_powershell_source_script "/opt/ros/humble\local_setup.ps1"
26 |
27 | # source this prefix
28 | $env:COLCON_CURRENT_PREFIX=(Split-Path $PSCommandPath -Parent)
29 | _colcon_prefix_chain_powershell_source_script "$env:COLCON_CURRENT_PREFIX\local_setup.ps1"
30 |
--------------------------------------------------------------------------------
/install/setup.sh:
--------------------------------------------------------------------------------
1 | # generated from colcon_core/shell/template/prefix_chain.sh.em
2 |
3 | # This script extends the environment with the environment of other prefix
4 | # paths which were sourced when this file was generated as well as all packages
5 | # contained in this prefix path.
6 |
7 | # since a plain shell script can't determine its own path when being sourced
8 | # either use the provided COLCON_CURRENT_PREFIX
9 | # or fall back to the build time prefix (if it exists)
10 | _colcon_prefix_chain_sh_COLCON_CURRENT_PREFIX=/home/anson/ros2_ws/install
11 | if [ ! -z "$COLCON_CURRENT_PREFIX" ]; then
12 | _colcon_prefix_chain_sh_COLCON_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
13 | elif [ ! -d "$_colcon_prefix_chain_sh_COLCON_CURRENT_PREFIX" ]; then
14 | echo "The build time path \"$_colcon_prefix_chain_sh_COLCON_CURRENT_PREFIX\" doesn't exist. Either source a script for a different shell or set the environment variable \"COLCON_CURRENT_PREFIX\" explicitly." 1>&2
15 | unset _colcon_prefix_chain_sh_COLCON_CURRENT_PREFIX
16 | return 1
17 | fi
18 |
19 | # function to source another script with conditional trace output
20 | # first argument: the path of the script
21 | _colcon_prefix_chain_sh_source_script() {
22 | if [ -f "$1" ]; then
23 | if [ -n "$COLCON_TRACE" ]; then
24 | echo "# . \"$1\""
25 | fi
26 | . "$1"
27 | else
28 | echo "not found: \"$1\"" 1>&2
29 | fi
30 | }
31 |
32 | # source chained prefixes
33 | # setting COLCON_CURRENT_PREFIX avoids relying on the build time prefix of the sourced script
34 | COLCON_CURRENT_PREFIX="/opt/ros/humble"
35 | _colcon_prefix_chain_sh_source_script "$COLCON_CURRENT_PREFIX/local_setup.sh"
36 |
37 |
38 | # source this prefix
39 | # setting COLCON_CURRENT_PREFIX avoids relying on the build time prefix of the sourced script
40 | COLCON_CURRENT_PREFIX="$_colcon_prefix_chain_sh_COLCON_CURRENT_PREFIX"
41 | _colcon_prefix_chain_sh_source_script "$COLCON_CURRENT_PREFIX/local_setup.sh"
42 |
43 | unset _colcon_prefix_chain_sh_COLCON_CURRENT_PREFIX
44 | unset _colcon_prefix_chain_sh_source_script
45 | unset COLCON_CURRENT_PREFIX
46 |
--------------------------------------------------------------------------------
/install/setup.zsh:
--------------------------------------------------------------------------------
1 | # generated from colcon_zsh/shell/template/prefix_chain.zsh.em
2 |
3 | # This script extends the environment with the environment of other prefix
4 | # paths which were sourced when this file was generated as well as all packages
5 | # contained in this prefix path.
6 |
7 | # function to source another script with conditional trace output
8 | # first argument: the path of the script
9 | _colcon_prefix_chain_zsh_source_script() {
10 | if [ -f "$1" ]; then
11 | if [ -n "$COLCON_TRACE" ]; then
12 | echo "# . \"$1\""
13 | fi
14 | . "$1"
15 | else
16 | echo "not found: \"$1\"" 1>&2
17 | fi
18 | }
19 |
20 | # source chained prefixes
21 | # setting COLCON_CURRENT_PREFIX avoids determining the prefix in the sourced script
22 | COLCON_CURRENT_PREFIX="/opt/ros/humble"
23 | _colcon_prefix_chain_zsh_source_script "$COLCON_CURRENT_PREFIX/local_setup.zsh"
24 |
25 | # source this prefix
26 | # setting COLCON_CURRENT_PREFIX avoids determining the prefix in the sourced script
27 | COLCON_CURRENT_PREFIX="$(builtin cd -q "`dirname "${(%):-%N}"`" > /dev/null && pwd)"
28 | _colcon_prefix_chain_zsh_source_script "$COLCON_CURRENT_PREFIX/local_setup.zsh"
29 |
30 | unset COLCON_CURRENT_PREFIX
31 | unset _colcon_prefix_chain_zsh_source_script
32 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/launch/robot_navigation.launch.py:
--------------------------------------------------------------------------------
1 | from launch import LaunchDescription
2 | from launch_ros.actions import Node
3 | from launch.actions import ExecuteProcess
4 | from launch.substitutions import LaunchConfiguration
5 | from launch.actions import SetEnvironmentVariable
6 |
7 | def generate_launch_description():
8 | return LaunchDescription([
9 | # Set the TURTLEBOT3_MODEL environment variable
10 | SetEnvironmentVariable('TURTLEBOT3_MODEL', 'burger'),
11 | # Launch Gazebo with TurtleBot3
12 | ExecuteProcess(
13 | cmd=['ros2', 'launch', 'turtlebot3_gazebo', 'turtlebot3_world.launch.py'],
14 | output='screen'
15 | ),
16 | # Launch the obstacle avoidance node
17 | Node(
18 | package='my_robot_navigation',
19 | executable='obstacle_avoidance',
20 | name='obstacle_avoidance_node',
21 | output='screen'
22 | )
23 | ])
24 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/my_robot_navigation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/src/my_robot_navigation/my_robot_navigation/__init__.py
--------------------------------------------------------------------------------
/src/my_robot_navigation/my_robot_navigation/obstacle_avoidance.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import rclpy
4 | from rclpy.node import Node
5 | from sensor_msgs.msg import LaserScan
6 | from geometry_msgs.msg import Twist
7 |
8 | class ObstacleAvoidanceNode(Node):
9 | def __init__(self):
10 | super().__init__('obstacle_avoidance_node')
11 | # Subscriber to LIDAR data
12 | self.subscription = self.create_subscription(
13 | LaserScan,
14 | '/scan', # TurtleBot3 LIDAR topic
15 | self.lidar_callback,
16 | 10
17 | )
18 | # Publisher for velocity commands
19 | self.publisher = self.create_publisher(
20 | Twist,
21 | '/cmd_vel', # TurtleBot3 velocity topic
22 | 10
23 | )
24 | self.get_logger().info("Obstacle Avoidance Node Started")
25 |
26 | def lidar_callback(self, msg):
27 | # Process LIDAR data (360 degrees, 0 = front, 180 = rear)
28 | ranges = msg.ranges
29 | min_distance = min(ranges[0:60] + ranges[300:360]) # Check front 120 degrees
30 | twist = Twist()
31 |
32 | if min_distance < 0.5: # If obstacle closer than 0.5m
33 | twist.linear.x = 0.0
34 | twist.angular.z = 0.5 # Turn right
35 | self.get_logger().info(f"Obstacle detected {min_distance:.2f}m ahead, turning!")
36 | else:
37 | twist.linear.x = 0.2 # Move forward
38 | twist.angular.z = 0.0
39 | self.get_logger().info("Path clear, moving forward")
40 |
41 | self.publisher.publish(twist)
42 |
43 | def main(args=None):
44 | rclpy.init(args=args)
45 | node = ObstacleAvoidanceNode()
46 | try:
47 | rclpy.spin(node)
48 | except KeyboardInterrupt:
49 | node.get_logger().info("Shutting down")
50 | finally:
51 | node.destroy_node()
52 | rclpy.shutdown()
53 |
54 | if __name__ == '__main__':
55 | main()
56 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | my_robot_navigation
5 | 0.0.0
6 | TODO: Package description
7 | anson
8 | TODO: License declaration
9 |
10 | rclcpp
11 | sensor_msgs
12 | geometry_msgs
13 |
14 | ament_copyright
15 | ament_flake8
16 | ament_pep257
17 | python3-pytest
18 |
19 |
20 | ament_python
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/resource/my_robot_navigation:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/anson10/Autonomous-Robot-Navigation-and-Obstacle-Avoidance-Using-ROS2-and-Gazebo/1734feacfc11f11ac6af202adf24a75c49924c93/src/my_robot_navigation/resource/my_robot_navigation
--------------------------------------------------------------------------------
/src/my_robot_navigation/setup.cfg:
--------------------------------------------------------------------------------
1 | [develop]
2 | script_dir=$base/lib/my_robot_navigation
3 | [install]
4 | install_scripts=$base/lib/my_robot_navigation
5 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | import os
3 | from glob import glob
4 |
5 | package_name = 'my_robot_navigation'
6 |
7 | setup(
8 | name=package_name,
9 | version='0.0.0',
10 | packages=[package_name],
11 | data_files=[
12 | ('share/ament_index/resource_index/packages', ['resource/' + package_name]),
13 | ('share/' + package_name, ['package.xml']),
14 | (os.path.join('share', package_name), glob('launch/*.launch.py')),
15 | ],
16 | install_requires=['setuptools'],
17 | zip_safe=True,
18 | maintainer='anson',
19 | maintainer_email='sansonmsa@gmail.com',
20 | description='Obstacle avoidance robot with ROS2 and Gazebo',
21 | license='Apache License 2.0',
22 | tests_require=['pytest'],
23 | entry_points={
24 | 'console_scripts': [
25 | 'obstacle_avoidance = my_robot_navigation.obstacle_avoidance:main',
26 | ],
27 | },
28 | )
29 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/test/test_copyright.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Open Source Robotics Foundation, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from ament_copyright.main import main
16 | import pytest
17 |
18 |
19 | # Remove the `skip` decorator once the source file(s) have a copyright header
20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.')
21 | @pytest.mark.copyright
22 | @pytest.mark.linter
23 | def test_copyright():
24 | rc = main(argv=['.', 'test'])
25 | assert rc == 0, 'Found errors'
26 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/test/test_flake8.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 Open Source Robotics Foundation, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from ament_flake8.main import main_with_errors
16 | import pytest
17 |
18 |
19 | @pytest.mark.flake8
20 | @pytest.mark.linter
21 | def test_flake8():
22 | rc, errors = main_with_errors(argv=[])
23 | assert rc == 0, \
24 | 'Found %d code style errors / warnings:\n' % len(errors) + \
25 | '\n'.join(errors)
26 |
--------------------------------------------------------------------------------
/src/my_robot_navigation/test/test_pep257.py:
--------------------------------------------------------------------------------
1 | # Copyright 2015 Open Source Robotics Foundation, Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from ament_pep257.main import main
16 | import pytest
17 |
18 |
19 | @pytest.mark.linter
20 | @pytest.mark.pep257
21 | def test_pep257():
22 | rc = main(argv=['.', 'test'])
23 | assert rc == 0, 'Found code style errors / warnings'
24 |
--------------------------------------------------------------------------------