├── CMakeLists.txt ├── LICENSE ├── LICENSE.previous.md ├── Package_Installation_Instruction.md ├── README.md ├── Tips_and_Troubleshooting.md ├── config ├── controller.yaml ├── controller_gz_sim.yaml ├── empty.yaml ├── gz_params.yaml ├── joystick_params.yaml ├── mapper_params_localization.yaml ├── mapper_params_online_async.yaml ├── minibot_config.rviz ├── minibot_display.rviz ├── nav2_params.yaml ├── sim_config.rviz └── twist_mux.yaml ├── demo_publisher_node └── velocity_publisher.cpp ├── description ├── camera.xacro ├── depth_camera.xacro ├── gz_diff_drive_control.xacro ├── inertial_macros.xacro ├── lidar.xacro ├── robot.urdf.xacro ├── robot_main.xacro └── ros2_control.xacro ├── launch ├── joystick_teleop.launch.py ├── robot.launch.py ├── robot_remote_station.launch.py ├── sim.launch.py └── sim_control_station.launch.py ├── maps ├── map_01.pgm ├── map_01.yaml ├── map_01_serial.data ├── map_01_serial.posegraph ├── sample_map.pgm ├── sample_map.yaml ├── sample_map_serial.data └── sample_map_serial.posegraph ├── package.xml ├── visual_demos ├── Nav2_demostration-ezgif.com-video-to-gif-converter.gif ├── SLAM_demostration-ezgif.com-video-to-gif-converter.gif ├── robot_hardware.jpg └── robot_visual.jpg └── worlds ├── empty.sdf └── playground.sdf /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(minibot) 3 | 4 | # Default to C99 5 | if(NOT CMAKE_C_STANDARD) 6 | set(CMAKE_C_STANDARD 99) 7 | endif() 8 | 9 | # Default to C++14 10 | if(NOT CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 14) 12 | endif() 13 | 14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 15 | add_compile_options(-Wall -Wextra -Wpedantic) 16 | endif() 17 | 18 | # find dependencies 19 | find_package(ament_cmake REQUIRED) 20 | find_package(rclcpp REQUIRED) 21 | find_package(geometry_msgs REQUIRED) 22 | # uncomment the following section in order to fill in 23 | # further dependencies manually. 24 | # find_package( REQUIRED) 25 | 26 | if(BUILD_TESTING) 27 | find_package(ament_lint_auto REQUIRED) 28 | # the following line skips the linter which checks for copyrights 29 | # uncomment the line when a copyright and license is not present in all source files 30 | #set(ament_cmake_copyright_FOUND TRUE) 31 | # the following line skips cpplint (only works in a git repo) 32 | # uncomment the line when this package is not in a git repo 33 | #set(ament_cmake_cpplint_FOUND TRUE) 34 | ament_lint_auto_find_test_dependencies() 35 | endif() 36 | 37 | add_executable(velocity_publisher demo_publisher_node/velocity_publisher.cpp) 38 | ament_target_dependencies(velocity_publisher 39 | rclcpp 40 | geometry_msgs 41 | ) 42 | 43 | install(TARGETS 44 | velocity_publisher 45 | DESTINATION lib/${PROJECT_NAME} 46 | ) 47 | 48 | install( 49 | DIRECTORY config description launch worlds demo_publisher_node maps visual_demos 50 | DESTINATION share/${PROJECT_NAME} 51 | ) 52 | 53 | ament_package() 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 YJ0528 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 | -------------------------------------------------------------------------------- /LICENSE.previous.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Package_Installation_Instruction.md: -------------------------------------------------------------------------------- 1 | ### List of Content: 2 | * [Introduction](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#introduction) 3 | * [Install ROS 2 Packages](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#install-ros-2-package) 4 | * [Install and Flash Microcontroller Driver code](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#install-and-flash-microcontroller-driver-code) 5 | 6 | ## Introduction 7 | There are 2 ways to install ROS2 package, either via binary installation or build from source. Most of the stable-released standard ROS2 package can be installed via binary, while building the package from source allows more flexibility in modifying the package(s) content, or to install additional third-party package(s). 8 | 9 | For more information, see: 10 | * [Explaination on ROS 2 Packages](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#explanation-on-ros-2-packages) 11 | * [Configuring your ROS 2 environment](https://docs.ros.org/en/eloquent/Tutorials/Configuring-ROS2-Environment.html#background) 12 | 13 | At the time I started this project, the ROS2 Jazzy Jalilsco only released several months, some of the packages were still not fully ported to Jazzy yet. Therefore, I will have to install from source or look up for pull request. 14 | 15 | Since then some packages has received a more refined updates. Therefore I will include both options if possible in the subesequent sections. However, binary installation are usually preferred if possible. 16 | 17 |
18 | 19 | # Install ROS 2 Package: 20 | The directory for the instruction to install required packages are listed below: 21 | 22 | **For simulation only:** 23 | * [ros_gz](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#ros_gz) 24 | * [ros2_control](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#ros2_control) 25 | * [nav2 stack](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#nav2) 26 | * [twist_mux](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#twist_mux) 27 | * [twist_stamper](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#twist_stamper) 28 | 29 | **For driver and hardware interface (in addition to the file listed for simulation, except `ros_gz`):** 30 | * [diffdrive_arduino](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#diffdrive_arduino) 31 | * [serial](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#serial) 32 | * [sllidar_ros2](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#sllidar_ros2) 33 | 34 | ### Third-party Packages Repository 35 | Among the above listed packages, the following are third-party packages: 36 | * [twist_stamper](https://github.com/joshnewans/twist_stamper.git) 37 | * [diffdrive_arduino](https://github.com/YJ0528/diffdrive_arduino ) (forked from [here](https://github.com/joshnewans/diffdrive_arduino)) 38 | * [serial](https://github.com/joshnewans/serial.git) 39 | * [sllidar_ros2](https://github.com/Slamtec/sllidar_ros2.git) 40 | 41 |
42 | 43 | ## ros_gz 44 | ROS2 Jazzy Jalisco supports Gazebo Harmonic (LTS), see [Summary of Compatible ROS and Gazebo Combinations](https://gazebosim.org/docs/harmonic/ros_installation/#summary-of-compatible-ros-and-gazebo-combinations). 45 | 46 | ### Binary Installation 47 | * Install the **default gazebo/ROS pairing** by following the instruction given [Installing the Default Gazebo/ROS Pairing](https://gazebosim.org/docs/harmonic/ros_installation/#installing-the-default-gazebo-ros-pairing). 48 | 49 | sudo apt-get install ros-${ROS_DISTRO}-ros-gz 50 | ### Build from source 51 | * Install the required **gazebo packages** by following the instruction given [here](https://github.com/gazebosim/ros_gz/tree/jazzy?tab=readme-ov-file#install) (optional, if create node is not available) . 52 | 53 | In order to build ros_gz from source, sufficient RAM is essential to avoid the machine from getting crashed. 54 | If the machine consist of 8GB RAM or less, expanding the virtual RAM with the instruction [How to Increase Virtual Memory](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#how-to-increase-virtual-memory). 55 | 56 |
57 | 58 | ## ros2_control 59 | ### Binary Installation 60 | * Install ros2_control for Jazzy Jalisco using: 61 | 62 | sudo apt install ros-jazzy-ros2-control 63 | ### Build from source 64 | * Install ros2_control from source following the instruction [here](https://control.ros.org/jazzy/doc/getting_started/getting_started.html#building-from-source) (optional, in case the spawner.py is not found). 65 | 66 |
67 | 68 | ## nav2 69 | ### Binary Installation 70 | * Install nav2 stack for Jazzy Jalisco using: 71 | 72 | sudo apt install ros-jazzy-navigation2 ros-jazzy-nav2-bringup 73 | 74 |
75 | 76 | ## twist_mux 77 | ### Binary installation 78 | The recently updated version (4.4.0) supports stamped cmd_vel, which can be installed directly: 79 | 80 | sudo apt install ros-jazzy-twist-mux 81 | **The following version is not tested yet so the parameter name could be different.** 82 | * To check the parameter name, see [Useful Tips: Check node parameter name in command line](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#how-to-check-ros-2-node-parameter-name-using-command-line) 83 | 84 | ### Build from source 85 | Alternatively, if user wish to build from source: 86 | 1. Go the the workspace src: 87 | 88 | ##Example: 89 | cd ros_ws/ 90 | cd src/ 91 | 2. Clone the package from github: 92 | 93 | https://github.com/YJ0528/twist_mux.git 94 | * I have created a fork for the pr_52, which provides the stamped cmd_vel option. 95 | * Alternatively, user can still convert unstamped cmd_vel to stamped using [twist_stamper](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#twist_stamper). 96 | 3. Build the package: 97 | 98 | ##Remove <--packages-select twist_stamper> to build all other packages 99 | colcon build --symlink-install --packages-select twist_mux 100 | 101 |
102 | 103 | ## twist_stamper 104 | twist_stamper is a third-party package contributed by [Josh Newans](https://github.com/joshnewans), [niemsoen](https://github.com/niemsoen), and [Rick-v-E](https://github.com/Rick-v-E). Since it is not an official ROS 2 package, it can only build from source. 105 | 106 | #### Build from source 107 | 1. Go the the workspace src: 108 | 109 | ##Example: 110 | cd ros_ws/ 111 | cd src/ 112 | 2. Clone the package from github: 113 | 114 | git clone https://github.com/joshnewans/twist_stamper.git 115 | 3. Build the package: 116 | 117 | ##Remove <--packages-select twist_stamper> to build all other packages 118 | colcon build --symlink-install --packages-select twist_stamper 119 | 120 |
121 | 122 | ## diffdrive_arduino 123 | #### Build from source 124 | 1. Go the the workspace src: 125 | 126 | ##Example: 127 | cd ros_ws/ 128 | cd src/ 129 | 2. Clone the package from github: 130 | 131 | git clone https://github.com/YJ0528/diffdrive_arduino.git 132 | * I have created a fork with the Humble branch so it could be cloned directly. 133 | * The pacakages works with Jazzy version although it is built for Humble. 134 | 3. Build the package: 135 | 136 | ##Remove <--packages-select twist_stamper> to build all other packages 137 | colcon build --symlink-install --packages-select diffdrive_arduino 138 | 139 |
140 | 141 | ## serial 142 | #### Build from source 143 | 1. Go the the workspace src: 144 | 145 | ##Example: 146 | cd ros_ws/ 147 | cd src/ 148 | 2. Clone the package from github: 149 | 150 | git clone https://github.com/joshnewans/serial 151 | * I have created a fork with the Humble branch so it could be cloned directly. 152 | * The pacakages works with Jazzy version although it is built for Humble. 153 | 3. Build the package: 154 | 155 | ##Remove <--packages-select twist_stamper> to build all other packages 156 | colcon build --symlink-install --packages-select serial 157 | 158 |
159 | 160 | ## sllidar_ros2 161 | * Build the `sllidar_ros2` package from source following the instruction [here](https://github.com/Slamtec/sllidar_ros2?tab=readme-ov-file#how-to-create-a-ros2-workspace). 162 | 163 |
164 | 165 | # Install and Flash Microcontroller Driver Code 166 | The arduino driver code repository can be found at here: [ros_arduino_bridge](https://github.com/YJ0528/ros_arduino_bridge.git), in which compatibility for ESP32 and Cytron MDD3A motor driver is implemented. 167 | ### A. Install Arduino IDE and Required Libraries 168 | 1. Make sure you have arduino installed in the machine, otherwise see [Arduino IDE 1 Installation (Linux)](https://docs.arduino.cc/software/ide-v1/tutorials/Linux/). 169 | 2. Open the Arduino IDE, install the ESP32 add-on in Arduino IDE, see [Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, Linux)](https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/) 170 | 3. In the Arduino IDE, install the following libraries via Tools -> Manage Libraries... 171 | * ESP32Encoder version 0.11.7, repository: https://github.com/madhephaestus/ESP32Encoder.git 172 | * Cytron Motor Drivers Library version 1.0.1, repository: https://github.com/CytronTechnologies/CytronMotorDriver 173 | ### B. Flashing the Driver code 174 | 1. clone the driver code to local: 175 | 176 | git clone https://github.com/YJ0528/ros_arduino_bridge.git 177 | * Can place the code in any directory, as long as it can be open by the IDE. 178 | 179 | 2. In Arduino IDE, open the cloned sketch: ros_arduino_bridge/RosArduinoBridge/[RosArduinoBridge.ino](https://github.com/YJ0528/ros_arduino_bridge/blob/main/ROSArduinoBridge/ROSArduinoBridge.ino). 180 | 3. Ensure the ESP32 serial is connected and accessible to the machine,set the port number to the ESP32 dev/ttyUSB0 and flash 181 | 4. The default port number starts from `dev/ttyUSB0`, `dev/ttyUSB0`..., check serial port using 182 | 183 | ls -l /dev/ttyUSB* 184 | 6. If the ESP32 is plugged into the serial port but the it is not recognized by the IDE, see [RPI5: Add USB Access for Raspberry Pi](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#rpi5-add-usb-access-for-raspberry-pi). 185 | 7. run python miniterm with echo and set serial port, and baud rate as following (assume serial port= /dev/ttyUSB0): 186 | 187 | python3 -m serial.tools.miniterm -e /dev/ttyUSB0 115200 188 | 189 | ## TODO (maybe): 190 | * Include guide to use arduinon extension in vscode 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## License 2 | This project is licensed under MIT License. 3 | For previous licensing history, see [LICENSE.previous.md](https://github.com/YJ0528/minibot/blob/main/LICENSE.previous.md) 4 | 5 |
6 | 7 |
8 | 9 |
10 |

Differential Drive Robot using ROS 2 Jazzy Jalisco

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

21 |
22 | 23 | Hi everyone! Today I would like to share my project implementing a fundamental differential drive robot using **ROS2 Jazzy Jalisco** and **Raspberry Pi 5**, with features including Gazebo simulation, ros2_control, teleoperation, SLAM, and Navigation2. 24 | 25 | This project also represents my learning journey following tutorials from [Articulated Robotics](https://articulatedrobotics.xyz/): 26 | 27 | * Forum: https://articulatedrobotics.xyz/tutorials/mobile-robot/project-overview/ 28 | * Tutorial playlist: https://youtube.com/playlist?list=PLunhqkrRNRhYAffV8JDiFOatQXuU-NnxT&si=1N9GNN6gRnet5heK 29 | 30 | You can see the demo [here](https://github.com/YJ0528/minibot/blob/main/README.md#demo) 31 | 32 |
33 | 34 | ## Getting Started 35 | Before we start, make sure you are using [Ubuntu 24.04](https://ubuntu.com/tutorials/install-ubuntu-desktop#1-overview) and have [ROS 2 Jazzy Jalisco](https://docs.ros.org/en/jazzy/index.html) installed in your server machine (which is your desktop or laptop). 36 | 37 | Make sure to install git: 38 | 39 | sudo apt install git ros-dev-tools -y 40 | 41 | Make sure VScode is installed, it can be found in Ubuntu App Center. Some extensions that I have installed are listed below: 42 | * C/C++ Extension Pack (Microsoft) 43 | * Python (Microsoft) 44 | * ROS (Microsoft) 45 | * YAML (Red Hat) 46 | * Remote - SSH (Microsoft) 47 | 48 | Additionally, consider to install [Terminator](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#terminator), which is a useful tool to use with ROS 2. 49 | 50 |
51 | 52 | ## Setting Up ROS 2 Workspace and Installed Requied Packages 53 | Before we start, see [ROS 2 Packages: A Brief Introduction](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#introduction) for the differences between the **binary installation** and **build from source** 54 | 55 | ### Creating a Workspace `ros_ws` 56 | 1. Open a terminal using `ctrl + alt + t`, create a workspace named `ros_ws` with a folder named `src`: 57 | 58 | mkdir -p ~/ros_ws/src 59 | * Replace `ros_ws` with the name you want to put as your workspace name. 60 | 61 | 3. Follow to the insturction at [**Install ROS 2 Packages**](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#install-ros-2-package) to install all the necessary packages. 62 | * Although only the listed items under **For simulation only** are required for simulation, it is recommanded to install all of them. 63 | 64 |
65 | 66 | ## Launch Simulation 67 | 1. Once Everything is set, go to `your_workspace` and source the workspace: 68 | 69 | cd ros_ws/ 70 | . install/setup.bash 71 | * When a new terminal is opened, ensure that terminal sourced the workspace also: 72 | 73 | 2. Launch the simulation: 74 | 75 | ros2 launch minibot sim.launch.py 76 | * This will launch the `robot description`, `gazebo`, `rviz2`, `ros2_control` etc. 77 | 78 | 3. Launch Simulation Control and SLAM 79 | 80 | The `sim_control_station.launch.py` will launch all control features for the simulation, inclduing `teleop`, `slam_toolbox`, `nav2 stack`. 81 | 82 | * To run the control with `online_async_slam` from `slam_toolbox`, open a new terminal, source the local workspace and enter: 83 | 84 | ros2 launch minibot sim_control_station.launch.py use_slam_option:=online_async_slam 85 | * For `mapper_params_localization` from `slam_toolbox`: 86 | 87 | ros2 launch minibot sim_control_station.launch.py use_slam_option:=mapper_params_localization 88 | * To change the map to load, open the params file at [`./src/minibot/config/mapper_params_localization.yaml`](https://github.com/YJ0528/minibot/blob/aa18371856751b270af9280b53b87c7f5f3a6bcf/config/mapper_params_localization.yaml#L18), replace the value corresponding `map_file_name` with the desired directory. 89 | * For `AMCL` from `nav2`: 90 | 91 | ros2 launch minibot sim_control_station.launch.py use_slam_option:=amcl map:=./src/minibot/maps/sample_map.yaml 92 | * To change the map to load, replace the default value corresponding to [`map`](https://github.com/YJ0528/minibot/blob/aa18371856751b270af9280b53b87c7f5f3a6bcf/launch/sim_control_station.launch.py#L27) with the desired directory. 93 | 94 | 5. Alternatively, we can just run the teleoperation only using: 95 | 96 | ros2 launch minibot joystick_teleop.launch.py 97 | ### Additional Notes: 98 | Refer to: 99 | * [ros_gz_bridge](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#ros_gz_bridge) if a topic could not be send or recived between ROS 2 and Gazebo. 100 | * [How a ROS 2 Topic Is Received By a Node](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#how-a-ros-2-topic-is-received-by-a-node) if you suspect topics are not being published or subscribed to properly 101 | * [How to Check ROS 2 Node Parameter Name using Command Line](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#how-to-check-ros-2-node-parameter-name-using-command-line) if you want to check if the parameters from `.yaml` file is loaded to the node properly. 102 | 103 |
104 |
105 | 106 | 107 |
108 |

Setting Up the Robot

109 | 110 |

Robot Hardware and Circuit Connection Setup

111 |
112 | 113 | ***IMPORTANT:** Please exercise the proper safety for lipo battery, I have included some precautions at [Lipo Battery Safety Precautions](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#lipo-battery-safety-precautions). 114 | 115 | ## Lisf of Hardwares: 116 | * Raspberry Pi 5 117 | * RPLIDAR C1 118 | * ESP32-vroom-32 development board 119 | * ESP32 expansion board (be award whether the pinout match the ESP32 dev board) 120 | * Cytron MDD3A motor driver 121 | * 3S lipo battery 122 | * Step down converter ([DFRobot DRF0205](https://www.dfrobot.com/product-752.html) for example) 123 | 124 | I only listed down the main electronics that I used, for more information, refer to [Build a Mobile Robot with ROS: Bill of Materials](https://articulatedrobotics.xyz/tutorials/mobile-robot/project-overview/#bill-of-materials) by [Articulated Robotics](https://articulatedrobotics.xyz/) 125 | 126 | see also: [Recommanded Components for Wiring and Robot Chasis (Optional)](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#recommanded-components-for-wiring-and-robot-chasis-optional). 127 | 128 |
129 | 130 | ## Configuring the Raspberry Pi: 131 | Make sure you are using [Ubuntu 24.04](https://ubuntu.com/tutorials/install-ubuntu-desktop#1-overview) and have [ROS 2 Jazzy Jalisco](https://docs.ros.org/en/jazzy/index.html) installed in the Raspberry Pi. 132 | 133 | **Install Ubuntu in Raspberry PI using rpi-imager** 134 | * Make sure you have a Micro SD Card with at least 32GB, but a Micro SD with **64GB or more** is recommanded. 135 | * The system has occupied about 24GB of my SD Card, including all everything needed to run the robot. 136 | * If you never install Ubuntu 24.04 using rpi-imager before, see: [RPI5: Flash Ubuntu to SD Card](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#rpi5-flash-ubuntu-to-sd-card). 137 | 138 | **Install ROS 2 in Raspberry PI** 139 | * For ROS 2 installation, you can select `ROS-Base Install` instead of `Desktop Install`. 140 | * If you wish to run `RViz` in Raspberry Pi, consider `Desktop Install` or binary install via bash using `sudo apt install ros-jazzy-rviz2`. 141 | 142 |
143 | 144 | ## Installing Packages for Raspberry Pi and Flashing Code to ESP32 145 | 146 | **Creating a Workspace `robot_ws` in Your SBC (Raspberry Pi)** 147 | 1. Open a terminal using `ctrl + alt + t`, create a workspace named `robot_ws` with a folder named `src`: 148 | 149 | mkdir -p ~/robot_ws/src 150 | * Replace `robot_ws` with the name you want to put as your workspace name. 151 | 152 | 2. Follow to the insturction at [**Install ROS 2 Packages**](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#install-ros-2-package) to install all the necessary packages in Raspberry Pi. 153 | * You need to install all the packages listed except `ros_gz`. 154 | 155 | **Flashing Code to ESP32** 156 | 157 | In addition, you need to Flash the driver code to your ESP32, see [Install and Flash Microcontroller Driver code](https://github.com/YJ0528/minibot/blob/main/Package_Installation_Instruction.md#install-and-flash-microcontroller-driver-code) 158 | 159 |
160 | 161 | ## Operating the Robot 162 | 163 | 1. Ensure the Raspberry Pi USB device port number matched the value declared: 164 | 165 | * `/dev/ttyUSB0` for the lidar serial; located at [`./src/minibot/launch/robot.launch.py/declare_lidar_serial_port`](https://github.com/YJ0528/minibot/blob/aa18371856751b270af9280b53b87c7f5f3a6bcf/launch/robot.launch.py#L53). 166 | * `/dev/ttyUSB1` for the ESP32; located at [`./src/minibot/description/ros2_control.xacro/RobotSystem/device`](https://github.com/YJ0528/minibot/blob/aa18371856751b270af9280b53b87c7f5f3a6bcf/description/ros2_control.xacro#L11). 167 | * To check or troubleshoot the USB connection in Raspberry Pi, see [RPI5: Add USB Access for Raspberry Pi](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#rpi5-add-usb-access-for-raspberry-pi). 168 | 169 | 2. Connects to the Raspberry Pi from your server machine using `openssh-server`. Open a terminal in the server machine, enter: 170 | 171 | ssh @ 172 | * If you never install or use `openssh-server` before,see [SSH Access to Remote Machine- Connect Remote Machine via Terminal](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#connecting-to-the-remote-machine-in-terminal). 173 | 174 | 3. In order to let the nodes to be discoverable between the server and the remote machine, We need to set `ROS_DOMAIN_ID` to the same for both of the machine: 175 | 176 | # The ID is 0 by default, but can be any number between 0 between 101 177 | export ROS_DOMAIN_ID=1 178 | * For the Raspberry Pi, we can add `export ROS_DOMAIN_ID = 1` to the `.bashrc` file instead using: 179 | 180 | echo "export ROS_DOMAIN_ID=1" >> ~/.bashrc 181 | * To check the `ROS_DOMAIN_ID` set, enter `echo ${ROS_DOMAIN_ID}` in terminal. 182 | 183 | 4. Once Everything is set, go to `your_workspace` and source the workspace: 184 | 185 | cd ros_ws/ 186 | . install/setup.bash 187 | * When a new terminal is opened, ensure that terminal sourced the workspace also: 188 | 189 | 5. Run the robot: 190 | 191 | ros2 launch minibot robot.launch.py 192 | * This will launch `robot description`,`ros2_control`, `sllidar_c1_launch` etc. 193 | 194 | 6. Launch Robot Control with SLAM or Localization 195 | 196 | The `robot_remote_station.launch.py` will launch all control features for the robot, inclduing `teleop`, `slam_toolbox`, `nav2 stack`. 197 | 198 | * To run the control with `online_async_slam` from `slam_toolbox`, open a new terminal in your server machine, source the local workspace and enter: 199 | 200 | ros2 launch minibot robot_remote_station.launch.py use_slam_option:=online_async_slam 201 | * For `mapper_params_localization` from `slam_toolbox`: 202 | 203 | ros2 launch minibot robot_remote_station.launch.py use_slam_option:=mapper_params_localization 204 | * To change the map to load, open the params file at [`./src/minibot/config/mapper_params_localization.yaml`](https://github.com/YJ0528/minibot/blob/aa18371856751b270af9280b53b87c7f5f3a6bcf/config/mapper_params_localization.yaml#L18), replace the value in `map_file_name` with the desired directory. 205 | * For `AMCL` from `nav2`: 206 | 207 | ros2 launch minibot robot_remote_station.launch.py use_slam_option:=amcl map:=./src/minibot/maps/sample_map.yaml 208 | * To change the map to load, replace the default value of [`map`](https://github.com/YJ0528/minibot/blob/aa18371856751b270af9280b53b87c7f5f3a6bcf/launch/robot_remote_station.launch.py#L27) with the desired directory. 209 | 7. Alternatively, we can just run the teleoperation only using: 210 | 211 | ros2 launch minibot joystick_teleop.launch.py 212 | 213 |
214 | 215 | ## Demo: 216 | Some visual demostration: 217 |
218 |

SLAM with Joystick Teleoperation (5x speed with defualt parameter)

219 | 220 |

221 |

Nav2 Navigation using SLAM Toolbox Localization (5x speed)

222 | 223 |
224 | 225 |                 `global_costmap/global_costmap/ros__parameters/inflation_layer/cost_scaling_factor`= 1.0 226 | 227 |                 `global_costmap/global_costmap/ros__parameters/inflation_layer/inflation_radius`= 0.05 228 | 229 | 230 | ## TO DO (maybe): 231 | * Implement the hardware interface within this package instead. 232 | * Explore the `slam_toolbox` and `nav2`, or any equivalent. 233 | * Implement 3D slam at least in simulation using depth camera, if possible. 234 | 235 | -------------------------------------------------------------------------------- /Tips_and_Troubleshooting.md: -------------------------------------------------------------------------------- 1 | This file consists of some concept to handle ROS 2 batter and some implementation suggestion for reference and troubleshooting. 2 | ### List of Content: 3 | * [Explanation on ROS 2 Packages](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#explanation-on-ros-2-packages) 4 | * [How a ROS 2 Topic Is Received By a Node](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#how-a-ros-2-topic-is-received-by-a-node) 5 | * [How to Check ROS 2 Node Parameter Name using Command Line](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#how-to-check-ros-2-node-parameter-name-using-command-line) 6 | * [How to Increase Virtual Memory](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#how-to-increase-virtual-memory) 7 | * [Lipo Battery Safety Precautions](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#lipo-battery-safety-precautions) 8 | * [Recommanded Components for Wiring and Robot Chasis (Optional)](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#recommanded-components-for-wiring-and-robot-chasis-optional) 9 | * [ros_gz_bridge](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#ros_gz_bridge) 10 | * [RPI5: Add USB Access for Raspberry Pi](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#rpi5-add-usb-access-for-raspberry-pi) 11 | * [RPI5: Flash Ubuntu to SD Card](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#rpi5-flash-ubuntu-to-sd-card) 12 | * [SSH Access to Remote Machine](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#ssh-access-to-remote-machine) 13 | * [Terminator](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#terminator) 14 |
15 | 16 | ## Explanation on ROS 2 Packages 17 | ROS 2 installed its packages mainly in 2 types of location, which recognize as workspace: 18 | 19 | * A **core workspace** located at `/opt/ros/` 20 | 21 | * **Local workspaces**, which can be create freely using: 22 | 23 | mkdir -p ~//src 24 | The differences between core workspace and local workspaces are listed below: 25 | 26 | | Feature | Core Workspace | Local workspaces | 27 | |-----|----|----| 28 | | Role | contain all the essential libraries and packages. | space we use to develop our robot system; provide felxibility to experiment any packages we want. | 29 | | Workspace layer | Underlay workspace, all local workspace can access here when needed. | Overlay workspace, Content in local workspaces will not share between each other. | 30 | | Package included | only official-released ROS 2 packages | mainly packages under development or third-party packages | 31 | | Workspace number(s) | normally only one for each distro | can be multiple | 32 | | Folder location(s) | located at `/opt/ros/` | can be create freely using mkdir `-p ~//src` | 33 | | Installation method | Binary Installation using `sudo apt install ros-jazzy-` | Build from source using `colcon build...` at the root of local workspace, see [here](https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html#tasks). | 34 | | Installation difficulty | simple, the system itself will choose the suitable version | can be more difficult, version incompatible could happen; some understanding towrads the package is required | 35 | | Package reliability | Reliability is guaranteed, tested before release | reliability might varies, some packages might not available for newer version. | 36 | | Package priority | lower | higher | 37 | | Documentation | Usually comes with official documentation | Mainly included in README.md | 38 | | Sourcing the workspace | `source /opt/ros/jazzy/setup.bash `; add to shell startup scrip using: `echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc` | In local's root workspace, `source install/setup.bash` | 39 |
40 | 41 | ## How a ROS 2 Topic Is Received By a Node 42 | In ROS 2, for a topic to be received by a subscriber node, the following have to match each other: 43 | * **Topic name** 44 | * **Topic message type**, defines the message format and content 45 | A topic can have multiple message type, but the value will not share between the message types. 46 | 47 | ### Manually Identify the Message Type in ROS 2 Core Package. 48 | We can imagine topic message type as the **directory towards the hearder file** that included all the necessary implementation information (counting from `/opt/ros/jazzy/include` onwards). 49 | 50 | To check the message type, we can: 51 | 1. Locate to `/opt/ros/jazzy/include` 52 | 2. **Most (not all)** message type will suffixed with `_msgs` at the first directory, or `msg` in the subsequent path. 53 | 3. For example,topic cmd_vel has a message type `geometry_msgs/msg/TwistStamped`, hence its header file is located at `/opt/ros/jazzy/include/geometry_msgs/msg` 54 | 55 | ### Checking the Topic and Topic Message Type using Command Line 56 | In the terminal: 57 | 58 | To list all available ROS 2 topics: 59 | 60 | ros2 topic list 61 | To check if ROS 2 topic is publishing message: 62 | 63 | ros2 topic echo /topic_name 64 | To check ROS 2 topic message type: 65 | 66 | ros2 topic type /topic_name 67 | To list all available gazebo topics: 68 | 69 | gz topic -l 70 | To check if gazebo topic is publishing message: 71 | 72 | gz topic -t /topic_name -i 73 | To check gazebo topic message type: 74 | 75 | gz topic -e /topic_name 76 |
77 | 78 | ## How to Check ROS 2 Node Parameter Name using Command Line 79 | 80 | 1. launch the node (e.g. twist_mux node) using configuration in .yaml file: 81 | 82 | ##Example: 83 | ros2 run twist_mux twist_mux --params-file src/minibot/config/joystick_params.yaml 84 | 2. In another terminal, list out all availabe nodes to check the name: 85 | 86 | ros2 node list 87 | which return: 88 | 89 | /twist_mux 90 | 3. Check the paramter of the node /twist_mux using: 91 | 92 | ros2 param dump /twist_mux 93 | which return (for example): 94 | 95 | twist_mux: 96 | ros__parameters: 97 | diagnostic_updater: 98 | period: 1.0 99 | use_fqn: false 100 | output_stamped: true 101 | qos_overrides: 102 | /parameter_events: 103 | publisher: 104 | depth: 1000 105 | durability: volatile 106 | history: keep_last 107 | reliability: reliable 108 | start_type_description_service: true 109 | use_sim_time: false 110 | * In this case, the parameter name to publish stamped cmd_vel is `/output_stamped` 111 |
112 | 113 | ## How to Increase Virtual Memory 114 | Some packages such as Gazebo or Moveit2 required decent amount of memory when building the packages from source, having an insufficient RAM(e.g. 8GB) may risk the machine to stop responding and subsequently fail the build. 115 | 116 | Such risk can be reduced by increasing the virtual memory. In Ubuntu, virtual memory is stored in term of swap space. 117 | 118 | Following method to increase the swap space is extracted from [askUbuntu: How to increase swap space?](https://askubuntu.com/questions/178712/how-to-increase-swap-space). 119 | 120 | 1. Firstly, open the terminal and input the following: 121 | 122 | dd if=/dev/zero of=/media/fasthdd/swapfile.img bs=1024 count=1M 123 | * This will create a swap file containing 1GiB virtual memory named `swapfile.img` 124 | * To change the swap size to 4GiB, replace `count=1M` to `count=4M` 125 | 2. Bake the swap file using: 126 | 127 | mkswap /media/fasthdd/swapfile.img 128 | 3. To activate the swap space during boot, add the following to `dev/fstab`: 129 | 130 | /media/fasthdd/swapfile.img swap swap sw 0 0 131 | 4. Reboot or enter the following command in terminal to activate the swap space: 132 | 133 | swapon /media/fasthdd/swapfile.img 134 | 5. To check if the swap space is available: 135 | 136 | cat /proc/swaps 137 | * If the swap space is avaialble, you should see the name of the swapfile and the size in `byte`. 138 | 139 |
140 | 141 | ## Lipo Battery Safety Precautions 142 | Lipo battery is highly volatile especially due to its high discharge rate. It can causes a fire if being handled properly. 143 | 144 | *** **IMPORTANT** *** **Please do not hesitate to spend money on the accessories.** 145 | * Do not leave the charging battery unsupervised. 146 | * Get a battery charger with **balance charge** and **storage charge**. 147 | * Balance charge if possible. 148 | * Consider getting a [bat-safe charging box](https://hobbyking.com/en_us/bat-safe-lipo-battery-charging-safe-box.html?utm_source=youtube&utm_medium=social&utm_campaign=woolysheep_032021&___store=en_us) or a lipo bag at least. 149 | * Ensure no combustable material nearby. 150 | * Storage charge the battery asap once received, especially when not planning to use it immediately. 151 | * Discharge (or use) a charged battery within 3 days, possibly use it the next day. 152 | * Keep track of each of the battery voltage using battery checker. 153 | 154 | ### Imbalanced Voltage Value Across Batteries 155 | Given a 3S battery for example, the battery consists of 3 serially-connected lipo batteries, with a voltage reading between 3.20V to 4.20V for each of them. Normally each of the batteries will have a voltage value that is close to each other. 156 | 157 | An imbalance voltage value across each of the batteries could indicate an its unhealthy state, and should be aware of since the battery voltage could drop below the low limit (3.20V) although the total voltage value is still above the limit (3.20 x3 = 9.60V, but also 3.00 + 3.30 x 2 = 9.60V), resulting a one-sided puffing battry for example. 158 | 159 | If the voltage imbalance is observed, check the battery voltage more frequently using a bettery checker when discharging the battery. 160 | 161 |
162 | 163 | ## Recommanded Components for Wiring and Robot Chasis (Optional) 164 | Item listed below are some recommandation for building the wire connection and the robot chasis: 165 | * Wire ferrule/ double wire ferrule 166 | * XT60 connector or T-plug to connect the lipo battery 167 | * Terminal strips 168 | * Terminal block 169 | * USB to terminal block connector 170 | * 3.6v/4.8V screwdriver 171 | * 12V screwdriver for drilling 172 | * hot air gun 173 | * multimeter 174 | * wire crimper 175 | * heat shrink tube 176 | * molex connecter and pin 177 | * screw set 178 | 179 |
180 | 181 | ## ros_gz_bridge 182 | Starting from ROS 2 Jazzy, plugins are no longer supported in connecting gazebo and ROS 2 topics. Instead ros_gz_bridge is used for this purpose, see: [Use ROS 2 to interact with Gazebo](https://gazebosim.org/docs/harmonic/ros2_integration/#use-ros-2-to-interact-with-gazebo). 183 | 184 | An example implementation in launch file are as follow: 185 | 186 | node_gz_bridge = Node( 187 | package='ros_gz_bridge', 188 | executable='parameter_bridge', 189 | arguments=[ 190 | # Gazebo_Control 191 | '/cmd_vel@geometry_msgs/msg/Twist]gz.msgs.Twist', 192 | ], 193 | output='screen' 194 | ) 195 | * This will send the topic message named cmd_vel from ROS 2 to gazebo. 196 | * Replace `]` with `@` to established a connection in both direction, and `[` to send topic message from Gazebo to ROS. 197 | 198 | ### ROS-Gazebo message type conversion 199 | **In most case (not all)**, gazebo message type will be `gz.msg.`. 200 | 201 | Given the topic `cmd_vel` type name in ROS 2 is `/cmd_vel@geometry_msgs/msg/Twist`, its message type in gazebo will be `gz.msgs.Twist` 202 | 203 | To retrive the values directly from command line, see: [Checking the Topic and Topic Message Type using Command Line](https://github.com/YJ0528/minibot/blob/main/Tips_and_Troubleshooting.md#checking-the-topic-and-topic-message-type-using-command-line) 204 | 205 |
206 | 207 | ## RPI5: Add USB Access for Raspberry Pi 208 | First, we check if the serial port is found in /dev using: 209 | 210 | ls -l /dev/ttyUSB* 211 | * If serial port is conencted it should return `/dev/ttyUSB0`, `/dev/ttyUSB1`... 212 | 213 | If the issue presist, it could indicate that raspberry pi is preventing the user from accessing the device. 214 | 215 | To resolve this: 216 | 217 | **A. Add user to diaout group:** 218 | 219 | sudo usermod -a -G dialout $USER 220 | * Logout and login again for the change to take effect. 221 | 222 | **B. Create a udev rule:** 223 | 224 | *** **IMPORTANT** *** **I got this fix from Claude and logically I did not actually understand how it works, so it might not work as expected, please implement with caution.** 225 | 226 | 1. Create a udev rule: 227 | 228 | sudo nano /etc/udev/rules.d/99-sllidar.rules 229 | 2. Add the following line to the file: 230 | 231 | # SLLIDAR rule 232 | SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="4466c1d8fee5ed118b4bd0a80b2af5ab", SYMLINK+="ttyLIDAR", MODE="0666" 233 | 234 | # ESP32 rule 235 | SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="0001", SYMLINK+="ttyESP32", MODE="0666" 236 | 237 | # Rule to ignore both devices in ModemManager 238 | SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ENV{ID_MM_DEVICE_IGNORE}="1" 239 | * exit `ctrl + x` and save (press `y` followed by `enter` ) the file using command: 240 | 4. Reload the udev rules: 241 | 242 | sudo udevadm control --reload-rules && sudo udevadm trigger 243 |
244 | 245 | ## RPI5: Flash Ubuntu to SD Card 246 | 247 | ### Note: 248 | As of the lastest update according to the 249 | [Ubuntu MATE 24.04 LTS Release Notes](https://ubuntu-mate.org/blog/ubuntu-mate-noble-numbat-release-notes/), and 250 | [Ubuntu MATE 24.10 Release Notes](https://ubuntu-mate.org/blog/ubuntu-mate-oracular-oriole-release-notes/), 251 | the Ubuntu mate is not available for Raspberry Pi yet. Hence, this section will install `Ubuntu desktop 24.04` instead. 252 | 253 | ### Instruction 254 | 1. Install rpi-imager from Ubuntu App Center. 255 | * Alternatively, install rpi-imager from bash: 256 | 257 | sudo apt update && sudo apt install rpi-imager 258 | 259 | 2. Insert your SD card to the computer, open the imager, choose the Raspberry Pi device that your are using. 260 | 3. Select the desired OS. 261 | * For Ubuntu OS, it should located at `Other general-purpose OS/Ubuntu`, select the desktop version. 262 | 4. Select your SD card as the storage and flash the OS. 263 | 5. Once done, insert the flashed SD card into the Raspberry Pi and the it is ready to run. 264 | 265 |
266 | 267 | ## SSH Access to Remote Machine 268 | ### Connect Remote Machine via Terminal 269 | OpenSSH server allows our computer to remotely control networked machine (server) such as Raspberry Pi as a client. 270 | 271 | **To Connect to remote using OpenSSH server:** 272 | 1. Install OpenSSH server: 273 | 274 | sudo apt install openssh-server 275 | 2. Connect the Raspberry Pi (aka the server machine) to a monitor, open a terminal and enter: 276 | 277 | whoami 278 | ip addr 279 | * `whoami`: will return your remote machine's `username` 280 | * `ip addr`: will return a long chain of information, including something like `inet 192.168.1.100/24`, in which the ip address will be `192.168.1.100` 281 | 282 | 3. In our client machine, or a computer, open a terminal and enter: 283 | 284 | ssh @ 285 | ### VScode Remote - SSH extension 286 | The extension allows the dev machine access the remote machine's files and folder in VScode. To set up the connection, see: [ Connect to a Remote Server with SSH in VS Code -- Step-by-Step Tutorial ](https://www.youtube.com/watch?v=qZwGyfN8X5A). 287 |
288 | 289 | ## Terminator 290 | Terminator allows multiple terminal to be open in the same window, see: [Terminator](https://innovativeinnovation.github.io/ubuntu-setup/terminals/terminator.html) 291 | 292 |
293 | 294 |
295 | source: Terminator 296 |

297 |
298 | 299 | To install Terminator in Ubuntu: 300 |
301 |
302 | 303 | sudo apt install terminator 304 | Shortcut keys: 305 | * `ctrl + o`: Open an new terminal below the current terminal. 306 | * `ctrl + e`: Open an new terminal at the right of the current terminal. 307 | * `ctrl + shift + t`: Open an new tab. 308 | * `ctrl + w`: Close the current terminal. 309 | * `ctrl + shift + arrow_key`: Move current terminal border. 310 | 311 | -------------------------------------------------------------------------------- /config/controller.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 30 # Hz 4 | # use_sim_time: true 5 | 6 | joint_state_broadcaster: 7 | type: joint_state_broadcaster/JointStateBroadcaster 8 | 9 | diff_drive_controller: 10 | ros__parameters: 11 | type: diff_drive_controller/DiffDriveController 12 | left_wheel_names: ["left_wheel_joint"] 13 | right_wheel_names: ["right_wheel_joint"] 14 | 15 | wheel_separation: 0.266 16 | # wheels_per_side: 1 # actually 2, but both are controlled by 1 signal 17 | wheel_radius: 0.034 18 | 19 | wheel_separation_multiplier: 1.0 20 | left_wheel_radius_multiplier: 1.0 21 | right_wheel_radius_multiplier: 1.0 22 | 23 | publish_rate: 30.0 24 | odom_frame_id: odom 25 | base_frame_id: base_link 26 | pose_covariance_diagonal : [0.001, 0.001, 0.001, 0.001, 0.001, 0.01] 27 | twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.01] 28 | 29 | open_loop: true 30 | enable_odom_tf: true 31 | 32 | cmd_vel_timeout: 0.5 33 | # publish_limited_velocity: true 34 | use_stamped_vel: false 35 | # velocity_rolling_window_size: 10 36 | 37 | # Velocity and acceleration limits 38 | # Whenever a min_* is unspecified, default to -max_* 39 | linear.x.has_velocity_limits: true 40 | linear.x.has_acceleration_limits: true 41 | linear.x.has_jerk_limits: false 42 | linear.x.max_velocity: 1.0 43 | linear.x.min_velocity: -1.0 44 | linear.x.max_acceleration: 1.0 45 | linear.x.max_jerk: 0.0 46 | linear.x.min_jerk: 0.0 47 | 48 | angular.z.has_velocity_limits: true 49 | angular.z.has_acceleration_limits: true 50 | angular.z.has_jerk_limits: false 51 | angular.z.max_velocity: 1.0 52 | angular.z.min_velocity: -1.0 53 | angular.z.max_acceleration: 1.0 54 | angular.z.min_acceleration: -1.0 55 | angular.z.max_jerk: 0.0 56 | angular.z.min_jerk: 0.0 -------------------------------------------------------------------------------- /config/controller_gz_sim.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 30 # Hz 4 | use_sim_time: true 5 | 6 | joint_state_broadcaster: 7 | type: joint_state_broadcaster/JointStateBroadcaster 8 | 9 | diff_drive_controller: 10 | ros__parameters: 11 | type: diff_drive_controller/DiffDriveController 12 | left_wheel_names: ["left_wheel_joint"] 13 | right_wheel_names: ["right_wheel_joint"] 14 | 15 | wheel_separation: 0.266 16 | # wheels_per_side: 1 # actually 2, but both are controlled by 1 signal 17 | wheel_radius: 0.034 18 | 19 | wheel_separation_multiplier: 1.0 20 | left_wheel_radius_multiplier: 1.0 21 | right_wheel_radius_multiplier: 1.0 22 | 23 | publish_rate: 30.0 24 | odom_frame_id: odom 25 | base_frame_id: base_link 26 | pose_covariance_diagonal : [0.001, 0.001, 0.001, 0.001, 0.001, 0.01] 27 | twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.01] 28 | 29 | open_loop: true 30 | enable_odom_tf: true 31 | 32 | cmd_vel_timeout: 0.5 33 | # publish_limited_velocity: true 34 | use_stamped_vel: false 35 | # velocity_rolling_window_size: 10 36 | 37 | # Velocity and acceleration limits 38 | # Whenever a min_* is unspecified, default to -max_* 39 | linear.x.has_velocity_limits: true 40 | linear.x.has_acceleration_limits: true 41 | linear.x.has_jerk_limits: false 42 | linear.x.max_velocity: 1.0 43 | linear.x.min_velocity: -1.0 44 | linear.x.max_acceleration: 1.0 45 | linear.x.max_jerk: 0.0 46 | linear.x.min_jerk: 0.0 47 | 48 | angular.z.has_velocity_limits: true 49 | angular.z.has_acceleration_limits: true 50 | angular.z.has_jerk_limits: false 51 | angular.z.max_velocity: 1.0 52 | angular.z.min_velocity: -1.0 53 | angular.z.max_acceleration: 1.0 54 | angular.z.min_acceleration: -1.0 55 | angular.z.max_jerk: 0.0 56 | angular.z.min_jerk: 0.0 -------------------------------------------------------------------------------- /config/empty.yaml: -------------------------------------------------------------------------------- 1 | # This is an empty file, so that git commits the folder correctly -------------------------------------------------------------------------------- /config/gz_params.yaml: -------------------------------------------------------------------------------- 1 | gazebo: 2 | ros__parameters: 3 | publish_rate: 500.0 -------------------------------------------------------------------------------- /config/joystick_params.yaml: -------------------------------------------------------------------------------- 1 | joy_node: 2 | ros__parameters: 3 | device_id: 0 4 | deadzone: 0.05 5 | autorepeat_rate: 20.0 6 | 7 | teleop_node: 8 | ros__parameters: 9 | axis_linear: 10 | x: 1 11 | scale_linear: 12 | x: -0.5 13 | scale_linear_turbo: 14 | x: -1.0 15 | 16 | axis_angular: 17 | yaw: 0 18 | scale_angular: 19 | yaw: 0.5 20 | scale_angular_turbo: 21 | yaw: 1.0 22 | 23 | enable_button: 0 24 | enable_turbo_button: 1 25 | require_enable_button: true 26 | 27 | use_sim_time: true 28 | inverted_reverse: true 29 | 30 | publish_stamped_twist: true 31 | frame: teleop_twist_joy 32 | -------------------------------------------------------------------------------- /config/mapper_params_localization.yaml: -------------------------------------------------------------------------------- 1 | slam_toolbox: 2 | ros__parameters: 3 | solver_plugin: solver_plugins::CeresSolver 4 | ceres_linear_solver: SPARSE_NORMAL_CHOLESKY 5 | ceres_preconditioner: SCHUR_JACOBI 6 | ceres_trust_strategy: LEVENBERG_MARQUARDT 7 | ceres_dogleg_type: TRADITIONAL_DOGLEG 8 | ceres_loss_function: None 9 | 10 | # ROS Parameters 11 | odom_frame: odom 12 | map_frame: map 13 | base_frame: base_footprint 14 | scan_topic: /scan 15 | mode: localization 16 | 17 | # if you'd like to start localizing on bringup in a map and pose 18 | map_file_name: ./src/minibot/maps/sample_map_serial 19 | #map_start_pose: [5.0, 1.0, 0.0] 20 | 21 | debug_logging: false 22 | throttle_scans: 1 23 | transform_publish_period: 0.02 #if 0 never publishes odometry 24 | map_update_interval: 5.0 25 | resolution: 0.05 26 | max_laser_range: 20.0 #for rastering images 27 | minimum_time_interval: 0.5 28 | transform_timeout: 0.2 29 | tf_buffer_duration: 30. 30 | stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps 31 | 32 | # General Parameters 33 | use_scan_matching: true 34 | use_scan_barycenter: true 35 | minimum_travel_distance: 0.5 36 | minimum_travel_heading: 0.5 37 | scan_buffer_size: 3 38 | scan_buffer_maximum_scan_distance: 10.0 39 | link_match_minimum_response_fine: 0.1 40 | link_scan_maximum_distance: 1.5 41 | do_loop_closing: true 42 | loop_match_minimum_chain_size: 3 43 | loop_match_maximum_variance_coarse: 3.0 44 | loop_match_minimum_response_coarse: 0.35 45 | loop_match_minimum_response_fine: 0.45 46 | 47 | # Correlation Parameters - Correlation Parameters 48 | correlation_search_space_dimension: 0.5 49 | correlation_search_space_resolution: 0.01 50 | correlation_search_space_smear_deviation: 0.1 51 | 52 | # Correlation Parameters - Loop Closure Parameters 53 | loop_search_space_dimension: 8.0 54 | loop_search_space_resolution: 0.05 55 | loop_search_space_smear_deviation: 0.03 56 | loop_search_maximum_distance: 3.0 57 | 58 | # Scan Matcher Parameters 59 | distance_variance_penalty: 0.5 60 | angle_variance_penalty: 1.0 61 | 62 | fine_search_angle_offset: 0.00349 63 | coarse_search_angle_offset: 0.349 64 | coarse_angle_resolution: 0.0349 65 | minimum_angle_penalty: 0.9 66 | minimum_distance_penalty: 0.5 67 | use_response_expansion: true 68 | -------------------------------------------------------------------------------- /config/mapper_params_online_async.yaml: -------------------------------------------------------------------------------- 1 | slam_toolbox: 2 | ros__parameters: 3 | 4 | # Plugin params 5 | solver_plugin: solver_plugins::CeresSolver 6 | ceres_linear_solver: SPARSE_NORMAL_CHOLESKY 7 | ceres_preconditioner: SCHUR_JACOBI 8 | ceres_trust_strategy: LEVENBERG_MARQUARDT 9 | ceres_dogleg_type: TRADITIONAL_DOGLEG 10 | ceres_loss_function: None 11 | 12 | # ROS Parameters 13 | odom_frame: odom 14 | map_frame: map 15 | base_frame: base_footprint 16 | scan_topic: /scan 17 | use_map_saver: true 18 | mode: mapping 19 | 20 | # if you'd like to immediately start continuing a map at a given pose 21 | # or at the dock, but they are mutually exclusive, if pose is given 22 | # will use pose 23 | # map_file_name: 24 | # map_start_pose: [0.0, 0.0, 0.0] 25 | map_start_at_dock: true 26 | 27 | debug_logging: false 28 | throttle_scans: 1 29 | transform_publish_period: 0.02 #if 0 never publishes odometry 30 | map_update_interval: 1.0 31 | resolution: 0.05 32 | max_laser_range: 10.0 #for rastering images 33 | minimum_time_interval: 0.5 34 | transform_timeout: 0.2 35 | tf_buffer_duration: 30.0 36 | stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps 37 | enable_interactive_mode: true 38 | 39 | # General Parameters 40 | use_scan_matching: true 41 | use_scan_barycenter: true 42 | minimum_travel_distance: 0.5 43 | minimum_travel_heading: 0.5 44 | scan_buffer_size: 10 45 | scan_buffer_maximum_scan_distance: 10.0 46 | link_match_minimum_response_fine: 0.1 47 | link_scan_maximum_distance: 1.5 48 | loop_search_maximum_distance: 3.0 49 | do_loop_closing: true 50 | loop_match_minimum_chain_size: 10 51 | loop_match_maximum_variance_coarse: 3.0 52 | loop_match_minimum_response_coarse: 0.35 53 | loop_match_minimum_response_fine: 0.45 54 | 55 | # Correlation Parameters - Correlation Parameters 56 | correlation_search_space_dimension: 0.5 57 | correlation_search_space_resolution: 0.01 58 | correlation_search_space_smear_deviation: 0.1 59 | 60 | # Correlation Parameters - Loop Closure Parameters 61 | loop_search_space_dimension: 8.0 62 | loop_search_space_resolution: 0.05 63 | loop_search_space_smear_deviation: 0.03 64 | 65 | # Scan Matcher Parameters 66 | distance_variance_penalty: 0.5 67 | angle_variance_penalty: 1.0 68 | 69 | fine_search_angle_offset: 0.00349 70 | coarse_search_angle_offset: 0.349 71 | coarse_angle_resolution: 0.0349 72 | minimum_angle_penalty: 0.9 73 | minimum_distance_penalty: 0.5 74 | use_response_expansion: true 75 | -------------------------------------------------------------------------------- /config/minibot_config.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz_common/Displays 3 | Help Height: 78 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | Splitter Ratio: 0.5029411911964417 10 | Tree Height: 707 11 | - Class: rviz_common/Selection 12 | Name: Selection 13 | - Class: rviz_common/Tool Properties 14 | Expanded: 15 | - /2D Goal Pose1 16 | - /Publish Point1 17 | Name: Tool Properties 18 | Splitter Ratio: 0.5886790156364441 19 | - Class: rviz_common/Views 20 | Expanded: 21 | - /Current View1 22 | Name: Views 23 | Splitter Ratio: 0.5 24 | - Class: rviz_common/Time 25 | Experimental: false 26 | Name: Time 27 | SyncMode: 0 28 | SyncSource: LaserScan 29 | Visualization Manager: 30 | Class: "" 31 | Displays: 32 | - Alpha: 0.5 33 | Cell Size: 1 34 | Class: rviz_default_plugins/Grid 35 | Color: 160; 160; 164 36 | Enabled: true 37 | Line Style: 38 | Line Width: 0.029999999329447746 39 | Value: Lines 40 | Name: Grid 41 | Normal Cell Count: 0 42 | Offset: 43 | X: 0 44 | Y: 0 45 | Z: 0 46 | Plane: XY 47 | Plane Cell Count: 10 48 | Reference Frame: 49 | Value: true 50 | - Class: rviz_default_plugins/TF 51 | Enabled: true 52 | Filter (blacklist): "" 53 | Filter (whitelist): "" 54 | Frame Timeout: 15 55 | Frames: 56 | All Enabled: true 57 | base_footprint: 58 | Value: true 59 | base_link: 60 | Value: true 61 | camera_link: 62 | Value: true 63 | camera_link_optical: 64 | Value: true 65 | caster_wheel: 66 | Value: true 67 | chasis: 68 | Value: true 69 | left_wheel: 70 | Value: true 71 | lidar_frame: 72 | Value: true 73 | map: 74 | Value: true 75 | odom: 76 | Value: true 77 | right_wheel: 78 | Value: true 79 | Marker Scale: 1 80 | Name: TF 81 | Show Arrows: true 82 | Show Axes: true 83 | Show Names: false 84 | Tree: 85 | map: 86 | odom: 87 | base_link: 88 | base_footprint: 89 | {} 90 | chasis: 91 | camera_link: 92 | camera_link_optical: 93 | {} 94 | caster_wheel: 95 | {} 96 | lidar_frame: 97 | {} 98 | left_wheel: 99 | {} 100 | right_wheel: 101 | {} 102 | Update Interval: 0 103 | Value: true 104 | - Alpha: 1 105 | Class: rviz_default_plugins/RobotModel 106 | Collision Enabled: false 107 | Description File: "" 108 | Description Source: Topic 109 | Description Topic: 110 | Depth: 5 111 | Durability Policy: Volatile 112 | History Policy: Keep Last 113 | Reliability Policy: Reliable 114 | Value: /robot_description 115 | Enabled: true 116 | Links: 117 | All Links Enabled: true 118 | Expand Joint Details: false 119 | Expand Link Details: false 120 | Expand Tree: false 121 | Link Tree Style: Links in Alphabetic Order 122 | base_footprint: 123 | Alpha: 1 124 | Show Axes: false 125 | Show Trail: false 126 | base_link: 127 | Alpha: 1 128 | Show Axes: false 129 | Show Trail: false 130 | camera_link: 131 | Alpha: 1 132 | Show Axes: false 133 | Show Trail: false 134 | Value: true 135 | camera_link_optical: 136 | Alpha: 1 137 | Show Axes: false 138 | Show Trail: false 139 | caster_wheel: 140 | Alpha: 1 141 | Show Axes: false 142 | Show Trail: false 143 | Value: true 144 | chasis: 145 | Alpha: 1 146 | Show Axes: false 147 | Show Trail: false 148 | Value: true 149 | left_wheel: 150 | Alpha: 1 151 | Show Axes: false 152 | Show Trail: false 153 | Value: true 154 | lidar_frame: 155 | Alpha: 1 156 | Show Axes: false 157 | Show Trail: false 158 | Value: true 159 | right_wheel: 160 | Alpha: 1 161 | Show Axes: false 162 | Show Trail: false 163 | Value: true 164 | Mass Properties: 165 | Inertia: false 166 | Mass: false 167 | Name: RobotModel 168 | TF Prefix: "" 169 | Update Interval: 0 170 | Value: true 171 | Visual Enabled: true 172 | - Alpha: 1 173 | Autocompute Intensity Bounds: true 174 | Autocompute Value Bounds: 175 | Max Value: 10 176 | Min Value: -10 177 | Value: true 178 | Axis: Z 179 | Channel Name: intensity 180 | Class: rviz_default_plugins/LaserScan 181 | Color: 255; 255; 255 182 | Color Transformer: Intensity 183 | Decay Time: 0 184 | Enabled: true 185 | Invert Rainbow: false 186 | Max Color: 255; 255; 255 187 | Max Intensity: 56 188 | Min Color: 0; 0; 0 189 | Min Intensity: 5 190 | Name: LaserScan 191 | Position Transformer: XYZ 192 | Selectable: true 193 | Size (Pixels): 3 194 | Size (m): 0.03999999910593033 195 | Style: Flat Squares 196 | Topic: 197 | Depth: 5 198 | Durability Policy: Volatile 199 | Filter size: 10 200 | History Policy: Keep Last 201 | Reliability Policy: Reliable 202 | Value: /scan 203 | Use Fixed Frame: true 204 | Use rainbow: true 205 | Value: true 206 | - Alpha: 0.699999988079071 207 | Binary representation: false 208 | Binary threshold: 100 209 | Class: rviz_default_plugins/Map 210 | Color Scheme: map 211 | Draw Behind: false 212 | Enabled: false 213 | Name: Map 214 | Topic: 215 | Depth: 5 216 | Durability Policy: Volatile 217 | Filter size: 10 218 | History Policy: Keep Last 219 | Reliability Policy: Reliable 220 | Value: /map 221 | Update Topic: 222 | Depth: 5 223 | Durability Policy: Volatile 224 | History Policy: Keep Last 225 | Reliability Policy: Reliable 226 | Value: /map_updates 227 | Use Timestamp: false 228 | Value: false 229 | - Alpha: 0.699999988079071 230 | Binary representation: false 231 | Binary threshold: 100 232 | Class: rviz_default_plugins/Map 233 | Color Scheme: costmap 234 | Draw Behind: false 235 | Enabled: true 236 | Name: Map 237 | Topic: 238 | Depth: 5 239 | Durability Policy: Volatile 240 | Filter size: 10 241 | History Policy: Keep Last 242 | Reliability Policy: Reliable 243 | Value: /global_costmap/costmap 244 | Update Topic: 245 | Depth: 5 246 | Durability Policy: Volatile 247 | History Policy: Keep Last 248 | Reliability Policy: Reliable 249 | Value: /global_costmap/costmap_updates 250 | Use Timestamp: false 251 | Value: true 252 | Enabled: true 253 | Global Options: 254 | Background Color: 48; 48; 48 255 | Fixed Frame: map 256 | Frame Rate: 30 257 | Name: root 258 | Tools: 259 | - Class: rviz_default_plugins/Interact 260 | Hide Inactive Objects: true 261 | - Class: rviz_default_plugins/MoveCamera 262 | - Class: rviz_default_plugins/Select 263 | - Class: rviz_default_plugins/FocusCamera 264 | - Class: rviz_default_plugins/Measure 265 | Line color: 128; 128; 0 266 | - Class: rviz_default_plugins/SetInitialPose 267 | Covariance x: 0.25 268 | Covariance y: 0.25 269 | Covariance yaw: 0.06853891909122467 270 | Topic: 271 | Depth: 5 272 | Durability Policy: Volatile 273 | History Policy: Keep Last 274 | Reliability Policy: Reliable 275 | Value: /initialpose 276 | - Class: rviz_default_plugins/SetGoal 277 | Topic: 278 | Depth: 5 279 | Durability Policy: Volatile 280 | History Policy: Keep Last 281 | Reliability Policy: Reliable 282 | Value: /goal_pose 283 | - Class: rviz_default_plugins/PublishPoint 284 | Single click: true 285 | Topic: 286 | Depth: 5 287 | Durability Policy: Volatile 288 | History Policy: Keep Last 289 | Reliability Policy: Reliable 290 | Value: /clicked_point 291 | Transformation: 292 | Current: 293 | Class: rviz_default_plugins/TF 294 | Value: true 295 | Views: 296 | Current: 297 | Angle: -1.5749999284744263 298 | Class: rviz_default_plugins/TopDownOrtho 299 | Enable Stereo Rendering: 300 | Stereo Eye Separation: 0.05999999865889549 301 | Stereo Focal Distance: 1 302 | Swap Stereo Eyes: false 303 | Value: false 304 | Invert Z Axis: false 305 | Name: Current View 306 | Near Clip Distance: 0.009999999776482582 307 | Scale: 196.64593505859375 308 | Target Frame: 309 | Value: TopDownOrtho (rviz_default_plugins) 310 | X: 1.166335940361023 311 | Y: 1.3729205131530762 312 | Saved: ~ 313 | Window Geometry: 314 | Displays: 315 | collapsed: false 316 | Height: 1011 317 | Hide Left Dock: false 318 | Hide Right Dock: false 319 | QMainWindow State: 000000ff00000000fd00000004000000000000015600000351fc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005d00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003f00000351000000cc00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000c00430061006d00650072006101000002a6000000ea0000000000000000000000010000010f00000351fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003f00000351000000a900fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073e0000003efc0100000002fb0000000800540069006d006501000000000000073e0000026f00fffffffb0000000800540069006d00650100000000000004500000000000000000000004cd0000035100000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 320 | Selection: 321 | collapsed: false 322 | Time: 323 | collapsed: false 324 | Tool Properties: 325 | collapsed: false 326 | Views: 327 | collapsed: false 328 | Width: 1854 329 | X: 66 330 | Y: 32 331 | -------------------------------------------------------------------------------- /config/minibot_display.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz_common/Displays 3 | Help Height: 78 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | Splitter Ratio: 0.5 10 | Tree Height: 542 11 | - Class: rviz_common/Selection 12 | Name: Selection 13 | - Class: rviz_common/Tool Properties 14 | Expanded: 15 | - /2D Goal Pose1 16 | - /Publish Point1 17 | Name: Tool Properties 18 | Splitter Ratio: 0.5886790156364441 19 | - Class: rviz_common/Views 20 | Expanded: 21 | - /Current View1 22 | Name: Views 23 | Splitter Ratio: 0.5 24 | - Class: rviz_common/Time 25 | Experimental: false 26 | Name: Time 27 | SyncMode: 0 28 | SyncSource: "" 29 | Visualization Manager: 30 | Class: "" 31 | Displays: 32 | - Alpha: 0.5 33 | Cell Size: 1 34 | Class: rviz_default_plugins/Grid 35 | Color: 160; 160; 164 36 | Enabled: true 37 | Line Style: 38 | Line Width: 0.029999999329447746 39 | Value: Lines 40 | Name: Grid 41 | Normal Cell Count: 0 42 | Offset: 43 | X: 0 44 | Y: 0 45 | Z: 0 46 | Plane: XY 47 | Plane Cell Count: 10 48 | Reference Frame: 49 | Value: true 50 | - Class: rviz_default_plugins/TF 51 | Enabled: true 52 | Filter (blacklist): "" 53 | Filter (whitelist): "" 54 | Frame Timeout: 15 55 | Frames: 56 | All Enabled: true 57 | base_link: 58 | Value: true 59 | caster_wheel: 60 | Value: true 61 | chasis: 62 | Value: true 63 | left_wheel: 64 | Value: true 65 | right_wheel: 66 | Value: true 67 | Marker Scale: 1 68 | Name: TF 69 | Show Arrows: true 70 | Show Axes: true 71 | Show Names: false 72 | Tree: 73 | base_link: 74 | chasis: 75 | caster_wheel: 76 | {} 77 | left_wheel: 78 | {} 79 | right_wheel: 80 | {} 81 | Update Interval: 0 82 | Value: true 83 | - Alpha: 1 84 | Class: rviz_default_plugins/RobotModel 85 | Collision Enabled: false 86 | Description File: "" 87 | Description Source: Topic 88 | Description Topic: 89 | Depth: 5 90 | Durability Policy: Volatile 91 | History Policy: Keep Last 92 | Reliability Policy: Reliable 93 | Value: /robot_description 94 | Enabled: true 95 | Links: 96 | All Links Enabled: true 97 | Expand Joint Details: false 98 | Expand Link Details: false 99 | Expand Tree: false 100 | Link Tree Style: Links in Alphabetic Order 101 | base_link: 102 | Alpha: 1 103 | Show Axes: false 104 | Show Trail: false 105 | caster_wheel: 106 | Alpha: 1 107 | Show Axes: false 108 | Show Trail: false 109 | Value: true 110 | chasis: 111 | Alpha: 1 112 | Show Axes: false 113 | Show Trail: false 114 | Value: true 115 | left_wheel: 116 | Alpha: 1 117 | Show Axes: false 118 | Show Trail: false 119 | Value: true 120 | right_wheel: 121 | Alpha: 1 122 | Show Axes: false 123 | Show Trail: false 124 | Value: true 125 | Mass Properties: 126 | Inertia: false 127 | Mass: false 128 | Name: RobotModel 129 | TF Prefix: "" 130 | Update Interval: 0 131 | Value: true 132 | Visual Enabled: true 133 | Enabled: true 134 | Global Options: 135 | Background Color: 48; 48; 48 136 | Fixed Frame: base_link 137 | Frame Rate: 30 138 | Name: root 139 | Tools: 140 | - Class: rviz_default_plugins/Interact 141 | Hide Inactive Objects: true 142 | - Class: rviz_default_plugins/MoveCamera 143 | - Class: rviz_default_plugins/Select 144 | - Class: rviz_default_plugins/FocusCamera 145 | - Class: rviz_default_plugins/Measure 146 | Line color: 128; 128; 0 147 | - Class: rviz_default_plugins/SetInitialPose 148 | Covariance x: 0.25 149 | Covariance y: 0.25 150 | Covariance yaw: 0.06853891909122467 151 | Topic: 152 | Depth: 5 153 | Durability Policy: Volatile 154 | History Policy: Keep Last 155 | Reliability Policy: Reliable 156 | Value: /initialpose 157 | - Class: rviz_default_plugins/SetGoal 158 | Topic: 159 | Depth: 5 160 | Durability Policy: Volatile 161 | History Policy: Keep Last 162 | Reliability Policy: Reliable 163 | Value: /goal_pose 164 | - Class: rviz_default_plugins/PublishPoint 165 | Single click: true 166 | Topic: 167 | Depth: 5 168 | Durability Policy: Volatile 169 | History Policy: Keep Last 170 | Reliability Policy: Reliable 171 | Value: /clicked_point 172 | Transformation: 173 | Current: 174 | Class: rviz_default_plugins/TF 175 | Value: true 176 | Views: 177 | Current: 178 | Class: rviz_default_plugins/Orbit 179 | Distance: 2.6215710639953613 180 | Enable Stereo Rendering: 181 | Stereo Eye Separation: 0.05999999865889549 182 | Stereo Focal Distance: 1 183 | Swap Stereo Eyes: false 184 | Value: false 185 | Focal Point: 186 | X: 0 187 | Y: 0 188 | Z: 0 189 | Focal Shape Fixed Size: true 190 | Focal Shape Size: 0.05000000074505806 191 | Invert Z Axis: false 192 | Name: Current View 193 | Near Clip Distance: 0.009999999776482582 194 | Pitch: 0.4197966456413269 195 | Target Frame: 196 | Value: Orbit (rviz) 197 | Yaw: 0.9004007577896118 198 | Saved: ~ 199 | Window Geometry: 200 | Displays: 201 | collapsed: false 202 | Height: 846 203 | Hide Left Dock: false 204 | Hide Right Dock: false 205 | QMainWindow State: 000000ff00000000fd000000040000000000000156000002acfc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005d00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003f000002ac000000cc00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002acfc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003f000002ac000000a900fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b00000026f00fffffffb0000000800540069006d006501000000000000045000000000000000000000023f000002ac00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 206 | Selection: 207 | collapsed: false 208 | Time: 209 | collapsed: false 210 | Tool Properties: 211 | collapsed: false 212 | Views: 213 | collapsed: false 214 | Width: 1200 215 | X: 66 216 | Y: 60 217 | -------------------------------------------------------------------------------- /config/nav2_params.yaml: -------------------------------------------------------------------------------- 1 | amcl: 2 | ros__parameters: 3 | alpha1: 0.2 4 | alpha2: 0.2 5 | alpha3: 0.2 6 | alpha4: 0.2 7 | alpha5: 0.2 8 | base_frame_id: "base_footprint" 9 | beam_skip_distance: 0.5 10 | beam_skip_error_threshold: 0.9 11 | beam_skip_threshold: 0.3 12 | do_beamskip: false 13 | global_frame_id: "map" 14 | lambda_short: 0.1 15 | laser_likelihood_max_dist: 2.0 16 | laser_max_range: 100.0 17 | laser_min_range: -1.0 18 | laser_model_type: "likelihood_field" 19 | max_beams: 60 20 | max_particles: 2000 21 | min_particles: 500 22 | odom_frame_id: "odom" 23 | pf_err: 0.05 24 | pf_z: 0.99 25 | recovery_alpha_fast: 0.0 26 | recovery_alpha_slow: 0.0 27 | resample_interval: 1 28 | robot_model_type: "nav2_amcl::DifferentialMotionModel" 29 | save_pose_rate: 0.5 30 | sigma_hit: 0.2 31 | tf_broadcast: true 32 | transform_tolerance: 1.0 33 | update_min_a: 0.2 34 | update_min_d: 0.25 35 | z_hit: 0.5 36 | z_max: 0.05 37 | z_rand: 0.5 38 | z_short: 0.05 39 | scan_topic: scan 40 | 41 | bt_navigator: 42 | ros__parameters: 43 | global_frame: map 44 | robot_base_frame: base_link 45 | odom_topic: /odom 46 | bt_loop_duration: 10 47 | default_server_timeout: 20 48 | wait_for_service_timeout: 1000 49 | action_server_result_timeout: 900.0 50 | navigators: ["navigate_to_pose", "navigate_through_poses"] 51 | navigate_to_pose: 52 | plugin: "nav2_bt_navigator::NavigateToPoseNavigator" 53 | navigate_through_poses: 54 | plugin: "nav2_bt_navigator::NavigateThroughPosesNavigator" 55 | # 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are use defaults: 56 | # nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml 57 | # nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml 58 | # They can be set here or via a RewrittenYaml remap from a parent launch file to Nav2. 59 | 60 | # plugin_lib_names is used to add custom BT plugins to the executor (vector of strings). 61 | # Built-in plugins are added automatically 62 | # plugin_lib_names: [] 63 | 64 | error_code_names: 65 | - compute_path_error_code 66 | - follow_path_error_code 67 | 68 | controller_server: 69 | ros__parameters: 70 | controller_frequency: 20.0 71 | min_x_velocity_threshold: 0.001 72 | min_y_velocity_threshold: 0.5 73 | min_theta_velocity_threshold: 0.001 74 | failure_tolerance: 0.3 75 | progress_checker_plugins: ["progress_checker"] 76 | goal_checker_plugins: ["general_goal_checker"] # "precise_goal_checker" 77 | controller_plugins: ["FollowPath"] 78 | use_realtime_priority: false 79 | 80 | # Progress checker parameters 81 | progress_checker: 82 | plugin: "nav2_controller::SimpleProgressChecker" 83 | required_movement_radius: 0.5 84 | movement_time_allowance: 10.0 85 | # Goal checker parameters 86 | #precise_goal_checker: 87 | # plugin: "nav2_controller::SimpleGoalChecker" 88 | # xy_goal_tolerance: 0.25 89 | # yaw_goal_tolerance: 0.25 90 | # stateful: True 91 | general_goal_checker: 92 | stateful: True 93 | plugin: "nav2_controller::SimpleGoalChecker" 94 | xy_goal_tolerance: 0.25 95 | yaw_goal_tolerance: 0.25 96 | FollowPath: 97 | plugin: "nav2_mppi_controller::MPPIController" 98 | time_steps: 56 99 | model_dt: 0.05 100 | batch_size: 2000 101 | ax_max: 3.0 102 | ax_min: -3.0 103 | ay_max: 3.0 104 | az_max: 3.5 105 | vx_std: 0.2 106 | vy_std: 0.2 107 | wz_std: 0.4 108 | vx_max: 0.5 109 | vx_min: -0.35 110 | vy_max: 0.5 111 | wz_max: 1.9 112 | iteration_count: 1 113 | prune_distance: 1.7 114 | transform_tolerance: 0.1 115 | temperature: 0.3 116 | gamma: 0.015 117 | motion_model: "DiffDrive" 118 | visualize: true 119 | regenerate_noises: true 120 | TrajectoryVisualizer: 121 | trajectory_step: 5 122 | time_step: 3 123 | AckermannConstraints: 124 | min_turning_r: 0.2 125 | critics: [ 126 | "ConstraintCritic", "CostCritic", "GoalCritic", 127 | "GoalAngleCritic", "PathAlignCritic", "PathFollowCritic", 128 | "PathAngleCritic", "PreferForwardCritic"] 129 | ConstraintCritic: 130 | enabled: true 131 | cost_power: 1 132 | cost_weight: 4.0 133 | GoalCritic: 134 | enabled: true 135 | cost_power: 1 136 | cost_weight: 5.0 137 | threshold_to_consider: 1.4 138 | GoalAngleCritic: 139 | enabled: true 140 | cost_power: 1 141 | cost_weight: 3.0 142 | threshold_to_consider: 0.5 143 | PreferForwardCritic: 144 | enabled: true 145 | cost_power: 1 146 | cost_weight: 5.0 147 | threshold_to_consider: 0.5 148 | CostCritic: 149 | enabled: true 150 | cost_power: 1 151 | cost_weight: 3.81 152 | critical_cost: 300.0 153 | consider_footprint: true 154 | collision_cost: 1000000.0 155 | near_goal_distance: 1.0 156 | trajectory_point_step: 2 157 | PathAlignCritic: 158 | enabled: true 159 | cost_power: 1 160 | cost_weight: 14.0 161 | max_path_occupancy_ratio: 0.05 162 | trajectory_point_step: 4 163 | threshold_to_consider: 0.5 164 | offset_from_furthest: 20 165 | use_path_orientations: false 166 | PathFollowCritic: 167 | enabled: true 168 | cost_power: 1 169 | cost_weight: 5.0 170 | offset_from_furthest: 5 171 | threshold_to_consider: 1.4 172 | PathAngleCritic: 173 | enabled: true 174 | cost_power: 1 175 | cost_weight: 2.0 176 | offset_from_furthest: 4 177 | threshold_to_consider: 0.5 178 | max_angle_to_furthest: 1.0 179 | mode: 0 180 | # TwirlingCritic: 181 | # enabled: true 182 | # twirling_cost_power: 1 183 | # twirling_cost_weight: 10.0 184 | 185 | local_costmap: 186 | local_costmap: 187 | ros__parameters: 188 | update_frequency: 5.0 189 | publish_frequency: 2.0 190 | global_frame: odom 191 | robot_base_frame: base_link 192 | rolling_window: true 193 | width: 3 194 | height: 3 195 | resolution: 0.05 196 | robot_radius: 0.22 197 | plugins: ["voxel_layer", "inflation_layer"] 198 | inflation_layer: 199 | plugin: "nav2_costmap_2d::InflationLayer" 200 | cost_scaling_factor: 3.0 201 | inflation_radius: 0.70 202 | voxel_layer: 203 | plugin: "nav2_costmap_2d::VoxelLayer" 204 | enabled: True 205 | publish_voxel_map: True 206 | origin_z: 0.0 207 | z_resolution: 0.05 208 | z_voxels: 16 209 | max_obstacle_height: 2.0 210 | mark_threshold: 0 211 | observation_sources: scan 212 | scan: 213 | topic: /scan 214 | max_obstacle_height: 2.0 215 | clearing: True 216 | marking: True 217 | data_type: "LaserScan" 218 | raytrace_max_range: 3.0 219 | raytrace_min_range: 0.0 220 | obstacle_max_range: 2.5 221 | obstacle_min_range: 0.0 222 | static_layer: 223 | plugin: "nav2_costmap_2d::StaticLayer" 224 | map_subscribe_transient_local: True 225 | always_send_full_costmap: True 226 | 227 | global_costmap: 228 | global_costmap: 229 | ros__parameters: 230 | update_frequency: 1.0 231 | publish_frequency: 1.0 232 | global_frame: map 233 | robot_base_frame: base_link 234 | robot_radius: 0.22 235 | resolution: 0.05 236 | track_unknown_space: true 237 | plugins: ["static_layer", "obstacle_layer", "inflation_layer"] 238 | obstacle_layer: 239 | plugin: "nav2_costmap_2d::ObstacleLayer" 240 | enabled: True 241 | observation_sources: scan 242 | scan: 243 | topic: /scan 244 | max_obstacle_height: 2.0 245 | clearing: True 246 | marking: True 247 | data_type: "LaserScan" 248 | raytrace_max_range: 3.0 249 | raytrace_min_range: 0.0 250 | obstacle_max_range: 2.5 251 | obstacle_min_range: 0.0 252 | static_layer: 253 | plugin: "nav2_costmap_2d::StaticLayer" 254 | map_subscribe_transient_local: True 255 | inflation_layer: 256 | plugin: "nav2_costmap_2d::InflationLayer" 257 | cost_scaling_factor: 1.0 258 | inflation_radius: 0.05 259 | always_send_full_costmap: True 260 | 261 | # The yaml_filename does not need to be specified since it going to be set by defaults in launch. 262 | # If you'd rather set it in the yaml, remove the default "map" value in the tb3_simulation_launch.py 263 | # file & provide full path to map below. If CLI map configuration or launch default is provided, that will be used. 264 | # map_server: 265 | # ros__parameters: 266 | # yaml_filename: "" 267 | 268 | map_saver: 269 | ros__parameters: 270 | save_map_timeout: 5.0 271 | free_thresh_default: 0.25 272 | occupied_thresh_default: 0.65 273 | map_subscribe_transient_local: True 274 | 275 | planner_server: 276 | ros__parameters: 277 | expected_planner_frequency: 20.0 278 | planner_plugins: ["GridBased"] 279 | GridBased: 280 | plugin: "nav2_navfn_planner::NavfnPlanner" 281 | tolerance: 0.5 282 | use_astar: false 283 | allow_unknown: true 284 | 285 | smoother_server: 286 | ros__parameters: 287 | smoother_plugins: ["simple_smoother"] 288 | simple_smoother: 289 | plugin: "nav2_smoother::SimpleSmoother" 290 | tolerance: 1.0e-10 291 | max_its: 1000 292 | do_refinement: True 293 | 294 | behavior_server: 295 | ros__parameters: 296 | local_costmap_topic: local_costmap/costmap_raw 297 | global_costmap_topic: global_costmap/costmap_raw 298 | local_footprint_topic: local_costmap/published_footprint 299 | global_footprint_topic: global_costmap/published_footprint 300 | cycle_frequency: 10.0 301 | behavior_plugins: ["spin", "backup", "drive_on_heading", "assisted_teleop", "wait"] 302 | spin: 303 | plugin: "nav2_behaviors::Spin" 304 | backup: 305 | plugin: "nav2_behaviors::BackUp" 306 | drive_on_heading: 307 | plugin: "nav2_behaviors::DriveOnHeading" 308 | wait: 309 | plugin: "nav2_behaviors::Wait" 310 | assisted_teleop: 311 | plugin: "nav2_behaviors::AssistedTeleop" 312 | local_frame: odom 313 | global_frame: map 314 | robot_base_frame: base_link 315 | transform_tolerance: 0.1 316 | simulate_ahead_time: 2.0 317 | max_rotational_vel: 1.0 318 | min_rotational_vel: 0.4 319 | rotational_acc_lim: 3.2 320 | 321 | waypoint_follower: 322 | ros__parameters: 323 | loop_rate: 20 324 | stop_on_failure: false 325 | action_server_result_timeout: 900.0 326 | waypoint_task_executor_plugin: "wait_at_waypoint" 327 | wait_at_waypoint: 328 | plugin: "nav2_waypoint_follower::WaitAtWaypoint" 329 | enabled: True 330 | waypoint_pause_duration: 200 331 | 332 | velocity_smoother: 333 | ros__parameters: 334 | smoothing_frequency: 20.0 335 | scale_velocities: False 336 | feedback: "OPEN_LOOP" 337 | max_velocity: [0.5, 0.0, 2.0] 338 | min_velocity: [-0.5, 0.0, -2.0] 339 | max_accel: [2.5, 0.0, 3.2] 340 | max_decel: [-2.5, 0.0, -3.2] 341 | odom_topic: "odom" 342 | odom_duration: 0.1 343 | deadband_velocity: [0.0, 0.0, 0.0] 344 | velocity_timeout: 1.0 345 | 346 | collision_monitor: 347 | ros__parameters: 348 | base_frame_id: "base_footprint" 349 | odom_frame_id: "odom" 350 | cmd_vel_in_topic: "cmd_vel_smoothed" 351 | cmd_vel_out_topic: "cmd_vel" 352 | state_topic: "collision_monitor_state" 353 | transform_tolerance: 0.2 354 | source_timeout: 1.0 355 | base_shift_correction: True 356 | stop_pub_timeout: 2.0 357 | # Polygons represent zone around the robot for "stop", "slowdown" and "limit" action types, 358 | # and robot footprint for "approach" action type. 359 | polygons: ["FootprintApproach"] 360 | FootprintApproach: 361 | type: "polygon" 362 | action_type: "approach" 363 | footprint_topic: "/local_costmap/published_footprint" 364 | time_before_collision: 1.2 365 | simulation_time_step: 0.1 366 | min_points: 6 367 | visualize: False 368 | enabled: True 369 | observation_sources: ["scan"] 370 | scan: 371 | type: "scan" 372 | topic: "scan" 373 | min_height: 0.15 374 | max_height: 2.0 375 | enabled: True 376 | 377 | docking_server: 378 | ros__parameters: 379 | controller_frequency: 50.0 380 | initial_perception_timeout: 5.0 381 | wait_charge_timeout: 5.0 382 | dock_approach_timeout: 30.0 383 | undock_linear_tolerance: 0.05 384 | undock_angular_tolerance: 0.1 385 | max_retries: 3 386 | base_frame: "base_link" 387 | fixed_frame: "odom" 388 | dock_backwards: false 389 | dock_prestaging_tolerance: 0.5 390 | 391 | # Types of docks 392 | dock_plugins: ['simple_charging_dock'] 393 | simple_charging_dock: 394 | plugin: 'opennav_docking::SimpleChargingDock' 395 | docking_threshold: 0.05 396 | staging_x_offset: -0.7 397 | use_external_detection_pose: true 398 | use_battery_status: false # true 399 | use_stall_detection: false # true 400 | 401 | external_detection_timeout: 1.0 402 | external_detection_translation_x: -0.18 403 | external_detection_translation_y: 0.0 404 | external_detection_rotation_roll: -1.57 405 | external_detection_rotation_pitch: -1.57 406 | external_detection_rotation_yaw: 0.0 407 | filter_coef: 0.1 408 | 409 | # Dock instances 410 | # The following example illustrates configuring dock instances. 411 | # docks: ['home_dock'] # Input your docks here 412 | # home_dock: 413 | # type: 'simple_charging_dock' 414 | # frame: map 415 | # pose: [0.0, 0.0, 0.0] 416 | 417 | controller: 418 | k_phi: 3.0 419 | k_delta: 2.0 420 | v_linear_min: 0.15 421 | v_linear_max: 0.15 422 | 423 | loopback_simulator: 424 | ros__parameters: 425 | base_frame_id: "base_footprint" 426 | odom_frame_id: "odom" 427 | map_frame_id: "map" 428 | scan_frame_id: "base_scan" # tb4_loopback_simulator.launch.py remaps to 'rplidar_link' 429 | update_duration: 0.02 430 | -------------------------------------------------------------------------------- /config/sim_config.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz_common/Displays 3 | Help Height: 78 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | Splitter Ratio: 0.5029411911964417 10 | Tree Height: 467 11 | - Class: rviz_common/Selection 12 | Name: Selection 13 | - Class: rviz_common/Tool Properties 14 | Expanded: 15 | - /2D Goal Pose1 16 | - /Publish Point1 17 | Name: Tool Properties 18 | Splitter Ratio: 0.5886790156364441 19 | - Class: rviz_common/Views 20 | Expanded: 21 | - /Current View1 22 | Name: Views 23 | Splitter Ratio: 0.5 24 | - Class: rviz_common/Time 25 | Experimental: false 26 | Name: Time 27 | SyncMode: 0 28 | SyncSource: LaserScan 29 | Visualization Manager: 30 | Class: "" 31 | Displays: 32 | - Alpha: 0.5 33 | Cell Size: 1 34 | Class: rviz_default_plugins/Grid 35 | Color: 160; 160; 164 36 | Enabled: true 37 | Line Style: 38 | Line Width: 0.029999999329447746 39 | Value: Lines 40 | Name: Grid 41 | Normal Cell Count: 0 42 | Offset: 43 | X: 0 44 | Y: 0 45 | Z: 0 46 | Plane: XY 47 | Plane Cell Count: 10 48 | Reference Frame: 49 | Value: true 50 | - Class: rviz_default_plugins/TF 51 | Enabled: true 52 | Filter (blacklist): "" 53 | Filter (whitelist): "" 54 | Frame Timeout: 15 55 | Frames: 56 | All Enabled: true 57 | base_footprint: 58 | Value: true 59 | base_link: 60 | Value: true 61 | camera_link: 62 | Value: true 63 | camera_link_optical: 64 | Value: true 65 | caster_wheel: 66 | Value: true 67 | chasis: 68 | Value: true 69 | left_wheel: 70 | Value: true 71 | lidar_frame: 72 | Value: true 73 | map: 74 | Value: true 75 | odom: 76 | Value: true 77 | right_wheel: 78 | Value: true 79 | Marker Scale: 1 80 | Name: TF 81 | Show Arrows: true 82 | Show Axes: true 83 | Show Names: false 84 | Tree: 85 | map: 86 | {} 87 | odom: 88 | base_link: 89 | base_footprint: 90 | {} 91 | chasis: 92 | camera_link: 93 | camera_link_optical: 94 | {} 95 | caster_wheel: 96 | {} 97 | lidar_frame: 98 | {} 99 | left_wheel: 100 | {} 101 | right_wheel: 102 | {} 103 | Update Interval: 0 104 | Value: true 105 | - Alpha: 1 106 | Class: rviz_default_plugins/RobotModel 107 | Collision Enabled: false 108 | Description File: "" 109 | Description Source: Topic 110 | Description Topic: 111 | Depth: 5 112 | Durability Policy: Volatile 113 | History Policy: Keep Last 114 | Reliability Policy: Reliable 115 | Value: /robot_description 116 | Enabled: true 117 | Links: 118 | All Links Enabled: true 119 | Expand Joint Details: false 120 | Expand Link Details: false 121 | Expand Tree: false 122 | Link Tree Style: Links in Alphabetic Order 123 | base_footprint: 124 | Alpha: 1 125 | Show Axes: false 126 | Show Trail: false 127 | base_link: 128 | Alpha: 1 129 | Show Axes: false 130 | Show Trail: false 131 | camera_link: 132 | Alpha: 1 133 | Show Axes: false 134 | Show Trail: false 135 | Value: true 136 | camera_link_optical: 137 | Alpha: 1 138 | Show Axes: false 139 | Show Trail: false 140 | caster_wheel: 141 | Alpha: 1 142 | Show Axes: false 143 | Show Trail: false 144 | Value: true 145 | chasis: 146 | Alpha: 1 147 | Show Axes: false 148 | Show Trail: false 149 | Value: true 150 | left_wheel: 151 | Alpha: 1 152 | Show Axes: false 153 | Show Trail: false 154 | Value: true 155 | lidar_frame: 156 | Alpha: 1 157 | Show Axes: false 158 | Show Trail: false 159 | Value: true 160 | right_wheel: 161 | Alpha: 1 162 | Show Axes: false 163 | Show Trail: false 164 | Value: true 165 | Mass Properties: 166 | Inertia: false 167 | Mass: false 168 | Name: RobotModel 169 | TF Prefix: "" 170 | Update Interval: 0 171 | Value: true 172 | Visual Enabled: true 173 | - Alpha: 1 174 | Autocompute Intensity Bounds: true 175 | Autocompute Value Bounds: 176 | Max Value: 10 177 | Min Value: -10 178 | Value: true 179 | Axis: Z 180 | Channel Name: intensity 181 | Class: rviz_default_plugins/LaserScan 182 | Color: 255; 255; 255 183 | Color Transformer: Intensity 184 | Decay Time: 0 185 | Enabled: true 186 | Invert Rainbow: false 187 | Max Color: 255; 255; 255 188 | Max Intensity: 0 189 | Min Color: 0; 0; 0 190 | Min Intensity: 0 191 | Name: LaserScan 192 | Position Transformer: XYZ 193 | Selectable: true 194 | Size (Pixels): 3 195 | Size (m): 0.03999999910593033 196 | Style: Flat Squares 197 | Topic: 198 | Depth: 5 199 | Durability Policy: Volatile 200 | Filter size: 10 201 | History Policy: Keep Last 202 | Reliability Policy: Reliable 203 | Value: /scan 204 | Use Fixed Frame: true 205 | Use rainbow: true 206 | Value: true 207 | - Class: rviz_default_plugins/Camera 208 | Enabled: true 209 | Far Plane Distance: 100 210 | Image Rendering: background and overlay 211 | Name: Camera 212 | Overlay Alpha: 0.5 213 | Topic: 214 | Depth: 5 215 | Durability Policy: Volatile 216 | History Policy: Keep Last 217 | Reliability Policy: Reliable 218 | Value: /camera/depth/image_raw/image 219 | Value: true 220 | Visibility: 221 | Grid: true 222 | LaserScan: true 223 | Map: true 224 | PointCloud2: true 225 | RobotModel: false 226 | TF: false 227 | Value: true 228 | Zoom Factor: 1 229 | - Alpha: 1 230 | Autocompute Intensity Bounds: true 231 | Autocompute Value Bounds: 232 | Max Value: 10 233 | Min Value: -10 234 | Value: true 235 | Axis: Z 236 | Channel Name: intensity 237 | Class: rviz_default_plugins/PointCloud2 238 | Color: 255; 255; 255 239 | Color Transformer: RGB8 240 | Decay Time: 0 241 | Enabled: false 242 | Invert Rainbow: false 243 | Max Color: 255; 255; 255 244 | Max Intensity: 4096 245 | Min Color: 0; 0; 0 246 | Min Intensity: 0 247 | Name: PointCloud2 248 | Position Transformer: XYZ 249 | Selectable: true 250 | Size (Pixels): 3 251 | Size (m): 0.009999999776482582 252 | Style: Flat Squares 253 | Topic: 254 | Depth: 5 255 | Durability Policy: Volatile 256 | History Policy: Keep Last 257 | Reliability Policy: Reliable 258 | Value: /camera/depth/image_raw/points 259 | Use Fixed Frame: true 260 | Use rainbow: true 261 | Value: false 262 | - Alpha: 0.699999988079071 263 | Binary representation: false 264 | Binary threshold: 100 265 | Class: rviz_default_plugins/Map 266 | Color Scheme: map 267 | Draw Behind: false 268 | Enabled: false 269 | Name: Map 270 | Topic: 271 | Depth: 5 272 | Durability Policy: Volatile 273 | Filter size: 10 274 | History Policy: Keep Last 275 | Reliability Policy: Reliable 276 | Value: /map 277 | Update Topic: 278 | Depth: 5 279 | Durability Policy: Volatile 280 | History Policy: Keep Last 281 | Reliability Policy: Reliable 282 | Value: /map_updates 283 | Use Timestamp: false 284 | Value: false 285 | - Alpha: 0.699999988079071 286 | Binary representation: false 287 | Binary threshold: 100 288 | Class: rviz_default_plugins/Map 289 | Color Scheme: costmap 290 | Draw Behind: false 291 | Enabled: true 292 | Name: Map 293 | Topic: 294 | Depth: 5 295 | Durability Policy: Volatile 296 | Filter size: 10 297 | History Policy: Keep Last 298 | Reliability Policy: Reliable 299 | Value: /global_costmap/costmap 300 | Update Topic: 301 | Depth: 5 302 | Durability Policy: Volatile 303 | History Policy: Keep Last 304 | Reliability Policy: Reliable 305 | Value: /global_costmap/costmap_updates 306 | Use Timestamp: false 307 | Value: true 308 | Enabled: true 309 | Global Options: 310 | Background Color: 48; 48; 48 311 | Fixed Frame: odom 312 | Frame Rate: 30 313 | Name: root 314 | Tools: 315 | - Class: rviz_default_plugins/Interact 316 | Hide Inactive Objects: true 317 | - Class: rviz_default_plugins/MoveCamera 318 | - Class: rviz_default_plugins/Select 319 | - Class: rviz_default_plugins/FocusCamera 320 | - Class: rviz_default_plugins/Measure 321 | Line color: 128; 128; 0 322 | - Class: rviz_default_plugins/SetInitialPose 323 | Covariance x: 0.25 324 | Covariance y: 0.25 325 | Covariance yaw: 0.06853891909122467 326 | Topic: 327 | Depth: 5 328 | Durability Policy: Volatile 329 | History Policy: Keep Last 330 | Reliability Policy: Reliable 331 | Value: /initialpose 332 | - Class: rviz_default_plugins/SetGoal 333 | Topic: 334 | Depth: 5 335 | Durability Policy: Volatile 336 | History Policy: Keep Last 337 | Reliability Policy: Reliable 338 | Value: /goal_pose 339 | - Class: rviz_default_plugins/PublishPoint 340 | Single click: true 341 | Topic: 342 | Depth: 5 343 | Durability Policy: Volatile 344 | History Policy: Keep Last 345 | Reliability Policy: Reliable 346 | Value: /clicked_point 347 | Transformation: 348 | Current: 349 | Class: rviz_default_plugins/TF 350 | Value: true 351 | Views: 352 | Current: 353 | Angle: -1.5749999284744263 354 | Class: rviz_default_plugins/TopDownOrtho 355 | Enable Stereo Rendering: 356 | Stereo Eye Separation: 0.05999999865889549 357 | Stereo Focal Distance: 1 358 | Swap Stereo Eyes: false 359 | Value: false 360 | Invert Z Axis: false 361 | Name: Current View 362 | Near Clip Distance: 0.009999999776482582 363 | Scale: 60.9480094909668 364 | Target Frame: 365 | Value: TopDownOrtho (rviz_default_plugins) 366 | X: 1.920721173286438 367 | Y: 0.09565046429634094 368 | Saved: ~ 369 | Window Geometry: 370 | Camera: 371 | collapsed: false 372 | Displays: 373 | collapsed: false 374 | Height: 1011 375 | Hide Left Dock: false 376 | Hide Right Dock: false 377 | QMainWindow State: 000000ff00000000fd00000004000000000000015600000351fc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005d00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003f00000261000000cc00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000c00430061006d00650072006101000002a6000000ea0000001700ffffff000000010000010f00000351fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003f00000351000000a900fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073e0000003efc0100000002fb0000000800540069006d006501000000000000073e0000026f00fffffffb0000000800540069006d00650100000000000004500000000000000000000004cd0000035100000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 378 | Selection: 379 | collapsed: false 380 | Time: 381 | collapsed: false 382 | Tool Properties: 383 | collapsed: false 384 | Views: 385 | collapsed: false 386 | Width: 1854 387 | X: 66 388 | Y: 32 389 | -------------------------------------------------------------------------------- /config/twist_mux.yaml: -------------------------------------------------------------------------------- 1 | twist_mux: 2 | ros__parameters: 3 | topics: 4 | navigation: 5 | topic : nav_vel 6 | timeout : 0.5 7 | priority: 10 8 | stamped : true 9 | 10 | joystick: 11 | topic : joy_vel 12 | timeout : 0.5 13 | priority: 100 14 | stamped : true -------------------------------------------------------------------------------- /demo_publisher_node/velocity_publisher.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 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 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | using namespace std::chrono_literals; 22 | 23 | int main(int argc, char * argv[]) 24 | { 25 | rclcpp::init(argc, argv); 26 | 27 | std::shared_ptr node = 28 | std::make_shared("diff_drive_control_input"); 29 | 30 | auto publisher = node->create_publisher( 31 | "/diff_drive_controller/cmd_vel", 10); 32 | 33 | RCLCPP_INFO(node->get_logger(), "node created"); 34 | 35 | geometry_msgs::msg::TwistStamped command; 36 | 37 | command.twist.linear.x = 0.0; 38 | command.twist.linear.y = 0.0; 39 | command.twist.linear.z = 0.0; 40 | 41 | command.twist.angular.x = 0.0; 42 | command.twist.angular.y = 0.0; 43 | command.twist.angular.z = 0.15; 44 | 45 | while (1) { 46 | command.header.stamp = node->now(); 47 | command.header.frame_id = "odom"; 48 | publisher->publish(command); 49 | std::this_thread::sleep_for(50ms); 50 | rclcpp::spin_some(node); 51 | } 52 | rclcpp::shutdown(); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /description/camera.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | camera_link_optical 40 | 0 0 0 0 0 0 41 | camera/image_raw 42 | 30 43 | 1 44 | true 45 | 46 | 47 | 1.089 48 | 49 | R8G8B8 50 | 640 51 | 480 52 | 53 | 54 | 0.05 55 | 8.0 56 | 57 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /description/depth_camera.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | camera_link 40 | camera_link_optical 41 | 0 0 0 0 0 0 42 | camera/depth/image_raw 43 | 10 44 | 1 45 | true 46 | 47 | 48 | 2.0944 49 | 50 | R8G8B8 51 | 640 52 | 480 53 | 54 | 55 | 0.05 56 | 12.0 57 | 58 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /description/gz_diff_drive_control.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | left_wheel_joint 10 | right_wheel_joint 11 | 0.266 12 | 0.034 13 | 14 | 15 | 200 16 | 10.0 17 | 18 | 19 | cmd_vel 20 | odom 21 | world 22 | 30 23 | tf 24 | 25 | 26 | odom 27 | base_link 28 | 29 | 30 | true 31 | true 32 | true 33 | true 34 | 35 | 36 | 37 | 39 | 40 | 41 | joint_states 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /description/inertial_macros.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /description/lidar.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | lidar_frame 38 | 0 0 0 0 0 0 39 | scan 40 | 10 41 | 1 42 | true 43 | 44 | 45 | 46 | 47 | 360 48 | 1 49 | -3.14159 50 | 3.14159 51 | 52 | 53 | 1 54 | 0.1 55 | 0. 56 | 0. 57 | 58 | 59 | 60 | 0.08 61 | 10.0 62 | 0.01 63 | 64 | 65 | gaussian 66 | 0.0 67 | 0.01 68 | 69 | 70 | 71 | 73 | ogre2 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /description/robot.urdf.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /description/robot_main.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Gazebo/Black 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | Gazebo/Orange 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | Gazebo/Orange 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | Gazebo/Orange 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /description/ros2_control.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | diffdrive_arduino/DiffDriveArduinoHardware 8 | left_wheel_joint 9 | right_wheel_joint 10 | 30 11 | /dev/ttyUSB1 12 | 115200 13 | 1000 14 | 616 15 | 16 | 17 | 18 | -10 19 | 10 20 | 21 | 22 | 23 | 24 | 25 | 26 | -10 27 | 10 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | gz_ros2_control/GazeboSimSystem 39 | 40 | 41 | 42 | -10 43 | 10 44 | 45 | 46 | 47 | 48 | 49 | 50 | -10 51 | 10 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | 62 | $(find minibot)/config/controller_gz_sim.yaml 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /launch/joystick_teleop.launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ament_index_python.packages import get_package_share_directory 3 | from launch import LaunchDescription 4 | from launch_ros.actions import Node 5 | 6 | def generate_launch_description(): 7 | 8 | package_name= 'minibot' 9 | 10 | # Declare the path to files 11 | joy_params_file = os.path.join( 12 | get_package_share_directory(package_name), 13 | 'config', 14 | 'joystick_params.yaml' 15 | ) 16 | 17 | # joy node 18 | joy_node = Node( 19 | package='joy', 20 | executable='joy_node', 21 | parameters=[joy_params_file] 22 | ) 23 | 24 | # teleop node 25 | teleop_node = Node( 26 | package='teleop_twist_joy', 27 | executable='teleop_node', 28 | name= 'teleop_node', 29 | parameters=[joy_params_file], 30 | remappings=[('/cmd_vel','joy_vel')] 31 | ) 32 | 33 | # Create the launch description and populate 34 | ld = LaunchDescription() 35 | 36 | # Add the nodes to the launch description 37 | ld.add_action(joy_node) 38 | ld.add_action(teleop_node) 39 | 40 | # Generate the launch description and 41 | return ld 42 | 43 | -------------------------------------------------------------------------------- /launch/robot.launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from ament_index_python.packages import get_package_share_directory 4 | 5 | from launch import LaunchDescription 6 | from launch.actions import RegisterEventHandler, DeclareLaunchArgument, IncludeLaunchDescription 7 | from launch.event_handlers import OnProcessStart 8 | from launch.launch_description_sources import PythonLaunchDescriptionSource 9 | from launch_ros.actions import Node 10 | from launch_ros.parameter_descriptions import ParameterValue 11 | from launch.substitutions import LaunchConfiguration, Command 12 | 13 | 14 | # Image Transport Republishers 15 | # terminal command example: ros2 run image_transport republish raw compressed --ros-args -r in:=/camera/image_raw -r out/compressed:=/camera/image_raw/compressed 16 | def image_transport_republisher(transport, camera_topics): 17 | base_topic = camera_topics.split('/')[-1] 18 | 19 | return Node( 20 | package='image_transport', 21 | executable='republish', 22 | name=f'image_transport_republish_{transport}_{base_topic}', 23 | arguments=['raw', transport], 24 | remappings=[ 25 | ('in', f'/camera/{camera_topics}'), 26 | (f'out/{transport}', f'/camera/{camera_topics}/{transport}'), 27 | ], 28 | ) 29 | 30 | def generate_launch_description(): 31 | 32 | package_name= 'minibot' 33 | package_dir= get_package_share_directory(package_name) 34 | 35 | use_sim_time = LaunchConfiguration('use_sim_time') 36 | use_ros2_control = LaunchConfiguration('use_ros2_control') 37 | lidar_serial_port = LaunchConfiguration('lidar_serial_port') 38 | 39 | declare_use_sim_time= DeclareLaunchArgument( 40 | 'use_sim_time', 41 | default_value='false', 42 | description='If true, use simulated clock' 43 | ) 44 | 45 | declare_use_ros2_control = DeclareLaunchArgument( 46 | 'use_ros2_control', 47 | default_value='true', 48 | description='If true, use ros2_control' 49 | ) 50 | 51 | declare_lidar_serial_port = DeclareLaunchArgument( 52 | 'lidar_serial_port', 53 | default_value='/dev/ttyUSB0', 54 | description='Specifying usb port to connected lidar' 55 | ) 56 | 57 | # Declare the path to files 58 | robot_description_xacro_file = os.path.join( 59 | package_dir, 60 | 'description', 61 | 'robot.urdf.xacro' 62 | ) 63 | 64 | rviz_config_file_dir = os.path.join( 65 | package_dir, 66 | 'config', 67 | 'minibot_config.rviz' 68 | ) 69 | 70 | robot_controllers_file_dir = os.path.join( 71 | package_dir, 72 | 'config', 73 | 'controller.yaml' 74 | ) 75 | 76 | 77 | twist_mux_params_file = os.path.join( 78 | package_dir, 79 | 'config', 80 | 'twist_mux.yaml' 81 | ) 82 | 83 | # robot_state_publisher setup 84 | robot_description_config = Command ([ 85 | 'xacro ', 86 | robot_description_xacro_file, 87 | ' use_ros2_control:=', 88 | use_ros2_control 89 | ]) 90 | 91 | params = { 92 | 'robot_description': ParameterValue(robot_description_config, value_type=str), 93 | 'use_sim_time': use_sim_time, 94 | 'use_ros2_control': use_ros2_control 95 | } 96 | 97 | # robot_state_publisher node 98 | node_robot_state_publisher = Node( 99 | package='robot_state_publisher', 100 | executable='robot_state_publisher', 101 | output='screen', 102 | parameters=[params] 103 | 104 | ) 105 | 106 | # Image Transport Republishers Node 107 | camera = 'image_raw' 108 | depth_camera = 'depth/image_raw' 109 | image_transports = ['compressed','compressedDepth', 'theora', 'zstd' ] 110 | node_image_republishers = [image_transport_republisher(transport, depth_camera) 111 | for transport in image_transports] 112 | 113 | # controller spawn 114 | node_ros2_control = Node( 115 | package="controller_manager", 116 | executable="ros2_control_node", 117 | parameters=[params, 118 | robot_controllers_file_dir 119 | ], 120 | ) 121 | 122 | joint_state_broadcaster_spawner = Node( 123 | package="controller_manager", 124 | executable="spawner", 125 | arguments=["joint_state_broadcaster"], 126 | ) 127 | 128 | diff_drive_controller_spawner = Node( 129 | package="controller_manager", 130 | executable="spawner", 131 | arguments=["diff_drive_controller", 132 | "--param-file", 133 | robot_controllers_file_dir 134 | ], 135 | ) 136 | 137 | node_twist_mux = Node( 138 | package="twist_mux", 139 | executable="twist_mux", 140 | name='twist_mux', 141 | output='screen', 142 | parameters=[ 143 | twist_mux_params_file, 144 | {'use_stamped': True}, 145 | ], 146 | remappings=[ 147 | ('cmd_vel_out', 148 | 'diff_drive_controller/cmd_vel'), 149 | ], 150 | ) 151 | 152 | node_twist_stamper = Node( 153 | package="twist_stamper", 154 | executable="twist_stamper", 155 | name='twist_stamper', 156 | output='screen', 157 | remappings=[ 158 | ('cmd_vel_in', 'cmd_vel_smoothed'), 159 | ('cmd_vel_out', 'nav_vel'), 160 | ], 161 | ) 162 | 163 | register_node_ros2_control = RegisterEventHandler( 164 | event_handler=OnProcessStart( 165 | target_action= node_robot_state_publisher, 166 | on_start= [node_ros2_control], 167 | ) 168 | ) 169 | 170 | register_joint_state_broadcaster_spawner = RegisterEventHandler( 171 | event_handler=OnProcessStart( 172 | target_action= node_ros2_control, 173 | on_start=[joint_state_broadcaster_spawner], 174 | ) 175 | ) 176 | 177 | register_diff_drive_controller_spawner = RegisterEventHandler( 178 | event_handler=OnProcessStart( 179 | target_action= joint_state_broadcaster_spawner, 180 | on_start=[diff_drive_controller_spawner], 181 | ) 182 | ) 183 | 184 | node_rplidar_drive = IncludeLaunchDescription( 185 | PythonLaunchDescriptionSource([os.path.join( 186 | get_package_share_directory('sllidar_ros2'), 187 | 'launch', 188 | 'sllidar_c1_launch.py' 189 | )]), 190 | launch_arguments={ 191 | 'serial_port': lidar_serial_port, 192 | 'frame_id': 'lidar_frame' 193 | }.items() 194 | ) 195 | 196 | # Create the launch description and populate 197 | ld = LaunchDescription() 198 | 199 | # Add the nodes to the launch description 200 | ld.add_action(declare_use_sim_time) 201 | ld.add_action(declare_use_ros2_control) 202 | ld.add_action(declare_lidar_serial_port) 203 | 204 | ld.add_action(register_node_ros2_control) 205 | ld.add_action(register_joint_state_broadcaster_spawner) 206 | ld.add_action(register_diff_drive_controller_spawner) 207 | 208 | ld.add_action(node_robot_state_publisher) 209 | ld.add_action(node_twist_mux) 210 | ld.add_action(node_twist_stamper) 211 | for node_republisher in node_image_republishers: 212 | ld.add_action(node_republisher) 213 | ld.add_action(node_rplidar_drive) 214 | 215 | # Generate the launch description 216 | return ld 217 | 218 | -------------------------------------------------------------------------------- /launch/robot_remote_station.launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ament_index_python.packages import get_package_share_directory 3 | from launch import LaunchDescription 4 | from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument 5 | from launch.launch_description_sources import PythonLaunchDescriptionSource 6 | from launch_ros.actions import Node 7 | from launch.substitutions import LaunchConfiguration, PythonExpression 8 | from launch.conditions import IfCondition 9 | 10 | def generate_launch_description(): 11 | 12 | package_name= 'minibot' 13 | package_dir= get_package_share_directory(package_name) 14 | 15 | use_sim_time = LaunchConfiguration('use_sim_time') 16 | map = LaunchConfiguration('map') 17 | use_slam_option = LaunchConfiguration('use_slam_option') 18 | 19 | declare_use_sim_time= DeclareLaunchArgument( 20 | 'use_sim_time', 21 | default_value='false', 22 | description='If true, use simulated clock' 23 | ) 24 | 25 | declare_map= DeclareLaunchArgument( 26 | 'map', 27 | default_value='./src/minibot/maps/map_01.yaml', 28 | description='If true, use simulated clock' 29 | ) 30 | 31 | declare_use_slam_option = DeclareLaunchArgument( 32 | 'use_slam_option', 33 | default_value='mapper_params_localization', 34 | description='Choose SLAM option: amcl, mapper_params_localization, or online_async_slam' 35 | ) 36 | 37 | # Declare the path to files 38 | joy_params_file = os.path.join( 39 | get_package_share_directory(package_name), 40 | 'config', 41 | 'joystick_params.yaml' 42 | ) 43 | 44 | rviz_config_file = os.path.join( 45 | get_package_share_directory(package_name), 46 | 'config', 47 | 'minibot_config.rviz' 48 | ) 49 | 50 | mapper_params_online_async_file = os.path.join( 51 | package_dir, 52 | 'config', 53 | 'mapper_params_online_async.yaml' 54 | ) 55 | 56 | mapper_params_localization_file = os.path.join( 57 | package_dir, 58 | 'config', 59 | 'mapper_params_localization.yaml' 60 | ) 61 | 62 | nav2_params_file = os.path.join( 63 | package_dir, 64 | 'config', 65 | 'nav2_params.yaml' 66 | ) 67 | 68 | # joy node 69 | joy_node = Node( 70 | package='joy', 71 | executable='joy_node', 72 | parameters=[joy_params_file] 73 | ) 74 | 75 | # teleop node 76 | teleop_node = Node( 77 | package='teleop_twist_joy', 78 | executable='teleop_node', 79 | name= 'teleop_node', 80 | parameters=[joy_params_file], 81 | remappings=[('/cmd_vel','joy_vel')] 82 | ) 83 | 84 | # rviz2 node 85 | node_rviz2 = Node( 86 | package='rviz2', 87 | executable='rviz2', 88 | name='rviz2', 89 | arguments=['-d', rviz_config_file], 90 | parameters=[{'use_sim_time': False}], 91 | output='both' 92 | ) 93 | 94 | # online_async_slam launch 95 | online_async_slam = IncludeLaunchDescription( 96 | PythonLaunchDescriptionSource([os.path.join( 97 | get_package_share_directory('slam_toolbox'), 98 | 'launch', 99 | 'online_async_launch.py' 100 | )]), 101 | launch_arguments={ 102 | 'slam_params_file': mapper_params_online_async_file, 103 | 'use_sim_time': use_sim_time 104 | }.items(), 105 | condition=IfCondition(PythonExpression(["'", use_slam_option, "' == 'online_async_slam'"])) 106 | ) 107 | 108 | # nav2_nmapper_params_localization launch 109 | mapper_params_localization = IncludeLaunchDescription( 110 | PythonLaunchDescriptionSource([os.path.join( 111 | get_package_share_directory('slam_toolbox'), 112 | 'launch', 113 | 'localization_launch.py' 114 | )]), 115 | launch_arguments={ 116 | 'slam_params_file': mapper_params_localization_file, 117 | 'use_sim_time': use_sim_time 118 | }.items(), 119 | condition=IfCondition(PythonExpression(["'", use_slam_option, "' == 'mapper_params_localization'"])) 120 | ) 121 | 122 | # amcl launch 123 | amcl = IncludeLaunchDescription( 124 | PythonLaunchDescriptionSource([os.path.join( 125 | get_package_share_directory('nav2_bringup'), 126 | 'launch', 127 | 'localization_launch.py' 128 | )]), 129 | launch_arguments={ 130 | 'map': map, 131 | 'use_sim_time': use_sim_time 132 | }.items(), 133 | condition=IfCondition(PythonExpression(["'", use_slam_option, "' == 'amcl'"])) 134 | ) 135 | 136 | # nav2_navigation launch 137 | navigation = IncludeLaunchDescription( 138 | PythonLaunchDescriptionSource([os.path.join( 139 | get_package_share_directory('nav2_bringup'), 140 | 'launch', 141 | 'navigation_launch.py' 142 | )]), 143 | launch_arguments={ 144 | 'params_file': nav2_params_file, 145 | 'use_sim_time': use_sim_time 146 | }.items() 147 | ) 148 | 149 | 150 | 151 | # Create the launch description and populate 152 | ld = LaunchDescription() 153 | 154 | # Add the launch arguments 155 | ld.add_action(declare_use_sim_time) 156 | ld.add_action(declare_map) 157 | ld.add_action(declare_use_slam_option) 158 | 159 | # Add the nodes to the launch description 160 | ld.add_action(joy_node) 161 | ld.add_action(teleop_node) 162 | ld.add_action(node_rviz2) 163 | 164 | # Add SLAM options 165 | ld.add_action(online_async_slam) 166 | ld.add_action(mapper_params_localization) 167 | ld.add_action(amcl) 168 | 169 | # # Add navigation 170 | ld.add_action(navigation) 171 | 172 | # Generate the launch description and 173 | return ld 174 | 175 | -------------------------------------------------------------------------------- /launch/sim.launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from ament_index_python.packages import get_package_share_directory 4 | 5 | from launch import LaunchDescription 6 | from launch.actions import IncludeLaunchDescription, GroupAction, RegisterEventHandler, DeclareLaunchArgument 7 | from launch.event_handlers import OnProcessStart 8 | from launch.launch_description_sources import PythonLaunchDescriptionSource 9 | from launch_ros.actions import Node 10 | from launch_ros.parameter_descriptions import ParameterValue 11 | from launch.substitutions import LaunchConfiguration, Command 12 | 13 | 14 | # Image Transport Republishers 15 | # terminal command example: ros2 run image_transport republish raw compressed --ros-args -r in:=/camera/image_raw -r out/compressed:=/camera/image_raw/compressed 16 | def image_transport_republisher(transport, camera_topics): 17 | base_topic = camera_topics.split('/')[-1] 18 | 19 | return Node( 20 | package='image_transport', 21 | executable='republish', 22 | name=f'image_transport_republish_{transport}_{base_topic}', 23 | arguments=['raw', transport], 24 | remappings=[ 25 | ('in', f'/camera/{camera_topics}'), 26 | (f'out/{transport}', f'/camera/{camera_topics}/{transport}'), 27 | ], 28 | ) 29 | 30 | def generate_launch_description(): 31 | 32 | package_name= 'minibot' 33 | package_dir= get_package_share_directory(package_name) 34 | 35 | # Add launch configurations 36 | use_sim_time = LaunchConfiguration('use_sim_time') 37 | use_ros2_control = LaunchConfiguration('use_ros2_control') 38 | use_ros2_control_gz_sim = LaunchConfiguration('use_ros2_control_gz_sim') 39 | 40 | # Declare launch arguments 41 | declare_use_sim_time= DeclareLaunchArgument( 42 | 'use_sim_time', 43 | default_value='true', 44 | description='If true, use simulated clock' 45 | ) 46 | 47 | declare_use_ros2_control = DeclareLaunchArgument( 48 | 'use_ros2_control', 49 | default_value='true', 50 | description='If true, use ros2_control' 51 | ) 52 | 53 | declare_use_ros2_control_gz_sim = DeclareLaunchArgument( 54 | 'use_ros2_control_gz_sim', 55 | default_value='true', 56 | description='If true, use ros2_control in gz_sim' 57 | ) 58 | 59 | # Declare the path to files 60 | robot_description_xacro_file = os.path.join( 61 | package_dir, 62 | 'description', 63 | 'robot.urdf.xacro' 64 | ) 65 | 66 | world_file_path = os.path.join( 67 | package_dir, 68 | 'worlds', 69 | 'playground.sdf' 70 | ) 71 | 72 | rviz_config_file = os.path.join( 73 | package_dir, 74 | 'config', 75 | 'sim_config.rviz' 76 | ) 77 | 78 | robot_controllers_file = os.path.join( 79 | package_dir, 80 | 'config', 81 | 'controller_gz_sim.yaml' 82 | ) 83 | 84 | gazebo_params_file = os.path.join( 85 | package_dir, 86 | 'config', 87 | 'gz_params.yaml' 88 | ) 89 | 90 | twist_mux_params_file = os.path.join( 91 | package_dir, 92 | 'config', 93 | 'twist_mux.yaml' 94 | ) 95 | 96 | # robot_state_publisher setup 97 | robot_description_config = Command ([ 98 | 'xacro ', 99 | robot_description_xacro_file, 100 | ' use_ros2_control:=', 101 | use_ros2_control, 102 | ' use_ros2_control_gz_sim:=', 103 | use_ros2_control_gz_sim, 104 | ]) 105 | 106 | params = { 107 | 'robot_description': ParameterValue(robot_description_config, value_type=str), 108 | 'use_sim_time': use_sim_time, 109 | } 110 | 111 | # robot_state_publisher node 112 | node_robot_state_publisher = Node( 113 | package='robot_state_publisher', 114 | executable='robot_state_publisher', 115 | output='screen', 116 | parameters=[params] 117 | ) 118 | 119 | # gz_bridge node 120 | # format: '@/[/]@/[/]', 121 | # ros2 topic type to check topi type_name in ros2 122 | # gz topic -t -i to check topic type_name in gazebo 123 | node_gz_bridge = Node( 124 | package='ros_gz_bridge', 125 | executable='parameter_bridge', 126 | arguments=[ 127 | 128 | # General 129 | '/clock@rosgraph_msgs/msg/Clock[gz.msgs.Clock', 130 | 131 | # Gazebo_Control 132 | '/cmd_vel@geometry_msgs/msg/Twist]gz.msgs.Twist', 133 | '/odom@nav_msgs/msg/Odometry[gz.msgs.Odometry', 134 | '/joint_states@sensor_msgs/msg/JointState[gz.msgs.Model', 135 | '/tf@tf2_msgs/msg/TFMessage[gz.msgs.Pose_V', 136 | 137 | # Lidar 138 | '/scan@sensor_msgs/msg/LaserScan[gz.msgs.LaserScan', 139 | '/scan/points@sensor_msgs/msg/PointCloud2[gz.msgs.PointCloudPacked', 140 | 141 | # Camera 142 | # '/camera/image_raw@sensor_msgs/msg/Image[gz.msgs.Image', 143 | # '/camera/camera_info@sensor_msgs/msg/CameraInfo[gz.msgs.CameraInfo', 144 | 145 | # RGBD Camera 146 | '/camera/depth/image_raw/camera_info@sensor_msgs/msg/CameraInfo[gz.msgs.CameraInfo', 147 | '/camera/depth/image_raw/depth_image@sensor_msgs/msg/Image[gz.msgs.Image', 148 | '/camera/depth/image_raw/image@sensor_msgs/msg/Image[gz.msgs.Image', 149 | '/camera/depth/image_raw/points@sensor_msgs/msg/PointCloud2[gz.msgs.PointCloudPacked', 150 | ], 151 | output='screen' 152 | ) 153 | 154 | # Image Transport Republishers Node 155 | camera = 'image_raw' 156 | depth_camera = 'depth/image_raw' 157 | image_transports = ['compressed','compressedDepth', 'theora', 'zstd' ] 158 | node_image_republishers = [image_transport_republisher(transport, depth_camera) 159 | for transport in image_transports] 160 | 161 | # gz launch world 162 | gazebo = IncludeLaunchDescription( 163 | PythonLaunchDescriptionSource([os.path.join( 164 | get_package_share_directory('ros_gz_sim'), 165 | 'launch', 166 | 'gz_sim.launch.py' 167 | )]), 168 | launch_arguments= 169 | {'gz_args': f'-r -v 4 {world_file_path}', 170 | 'extra_gazebo_args': '--ros-args --params-file' + gazebo_params_file}.items() 171 | ) 172 | 173 | # gz spawn robot entity 174 | node_gz_spawn_entity = Node( 175 | package='ros_gz_sim', 176 | executable='create', 177 | output='screen', 178 | arguments=['-topic', 'robot_description', 179 | '-name', 'minibot', 180 | '-allow_renaming', 'true', 181 | '-z', '0.1'], 182 | ) 183 | 184 | # rviz2 node 185 | node_rviz2 = Node( 186 | package='rviz2', 187 | executable='rviz2', 188 | name='rviz2', 189 | arguments=['-d', rviz_config_file], 190 | parameters=[{'use_sim_time': True}], 191 | output='both' 192 | ) 193 | 194 | # controller spawn 195 | joint_state_broadcaster_spawner = Node( 196 | package="controller_manager", 197 | executable="spawner", 198 | arguments=["joint_state_broadcaster"], 199 | ) 200 | 201 | diff_drive_controller_spawner = Node( 202 | package="controller_manager", 203 | executable="spawner", 204 | arguments=["diff_drive_controller", 205 | "--param-file", 206 | robot_controllers_file 207 | ], 208 | ) 209 | 210 | node_twist_mux = Node( 211 | package="twist_mux", 212 | executable="twist_mux", 213 | name='twist_mux', 214 | output='screen', 215 | parameters=[ 216 | twist_mux_params_file, 217 | {'use_stamped': True}, 218 | ], 219 | remappings=[ 220 | ('cmd_vel_out', 221 | 'diff_drive_controller/cmd_vel'), 222 | ], 223 | ) 224 | 225 | node_twist_stamper = Node( 226 | package="twist_stamper", 227 | executable="twist_stamper", 228 | name='twist_stamper', 229 | output='screen', 230 | remappings=[ 231 | ('cmd_vel_in', 'cmd_vel_smoothed'), 232 | ('cmd_vel_out', 'nav_vel'), 233 | ], 234 | ) 235 | 236 | register_joint_state_broadcaster_spawner = RegisterEventHandler( 237 | event_handler=OnProcessStart( 238 | target_action= node_gz_spawn_entity, 239 | on_start= [joint_state_broadcaster_spawner], 240 | ) 241 | ) 242 | 243 | register_diff_drive_controller_spawner = RegisterEventHandler( 244 | event_handler=OnProcessStart( 245 | target_action= joint_state_broadcaster_spawner, 246 | on_start= [diff_drive_controller_spawner], 247 | ) 248 | ) 249 | 250 | group_spawn_gz= GroupAction( 251 | [gazebo, 252 | node_gz_spawn_entity, 253 | ] 254 | ) 255 | 256 | 257 | # Create the launch description and populate 258 | ld = LaunchDescription() 259 | 260 | # Add the nodes to the launch description 261 | ld.add_action(declare_use_sim_time) 262 | ld.add_action(declare_use_ros2_control) 263 | ld.add_action(declare_use_ros2_control_gz_sim) 264 | 265 | ld.add_action(register_joint_state_broadcaster_spawner) 266 | ld.add_action(register_diff_drive_controller_spawner) 267 | 268 | ld.add_action(node_robot_state_publisher) 269 | ld.add_action(node_twist_mux) 270 | ld.add_action(node_twist_stamper) 271 | ld.add_action(node_gz_bridge) 272 | for node_republisher in node_image_republishers: 273 | ld.add_action(node_republisher) 274 | ld.add_action(group_spawn_gz) 275 | ld.add_action(node_rviz2) 276 | 277 | # Generate the launch description 278 | return ld 279 | 280 | -------------------------------------------------------------------------------- /launch/sim_control_station.launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ament_index_python.packages import get_package_share_directory 3 | from launch import LaunchDescription 4 | from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument 5 | from launch.launch_description_sources import PythonLaunchDescriptionSource 6 | from launch_ros.actions import Node 7 | from launch.substitutions import LaunchConfiguration, PythonExpression 8 | from launch.conditions import IfCondition 9 | 10 | def generate_launch_description(): 11 | 12 | package_name= 'minibot' 13 | package_dir= get_package_share_directory(package_name) 14 | 15 | use_sim_time = LaunchConfiguration('use_sim_time') 16 | map = LaunchConfiguration('map') 17 | use_slam_option = LaunchConfiguration('use_slam_option') 18 | 19 | declare_use_sim_time= DeclareLaunchArgument( 20 | 'use_sim_time', 21 | default_value='true', 22 | description='If true, use simulated clock' 23 | ) 24 | 25 | declare_map= DeclareLaunchArgument( 26 | 'map', 27 | default_value='./src/minibot/maps/sample_map.yaml', 28 | description='If true, use simulated clock' 29 | ) 30 | 31 | declare_use_slam_option = DeclareLaunchArgument( 32 | 'use_slam_option', 33 | default_value='online_async_slam', 34 | description='Choose SLAM option: amcl, mapper_params_localization, or online_async_slam' 35 | ) 36 | 37 | # Declare the path to files 38 | joy_params_file = os.path.join( 39 | get_package_share_directory(package_name), 40 | 'config', 41 | 'joystick_params.yaml' 42 | ) 43 | 44 | mapper_params_online_async_file = os.path.join( 45 | package_dir, 46 | 'config', 47 | 'mapper_params_online_async.yaml' 48 | ) 49 | 50 | mapper_params_localization_file = os.path.join( 51 | package_dir, 52 | 'config', 53 | 'mapper_params_localization.yaml' 54 | ) 55 | 56 | nav2_params_file = os.path.join( 57 | package_dir, 58 | 'config', 59 | 'nav2_params.yaml' 60 | ) 61 | 62 | # joy node 63 | joy_node = Node( 64 | package='joy', 65 | executable='joy_node', 66 | parameters=[joy_params_file] 67 | ) 68 | 69 | # teleop node 70 | teleop_node = Node( 71 | package='teleop_twist_joy', 72 | executable='teleop_node', 73 | name= 'teleop_node', 74 | parameters=[joy_params_file], 75 | remappings=[('/cmd_vel','joy_vel')] 76 | ) 77 | 78 | # online_async_slam launch 79 | online_async_slam = IncludeLaunchDescription( 80 | PythonLaunchDescriptionSource([os.path.join( 81 | get_package_share_directory('slam_toolbox'), 82 | 'launch', 83 | 'online_async_launch.py' 84 | )]), 85 | launch_arguments={ 86 | 'slam_params_file': mapper_params_online_async_file, 87 | 'use_sim_time': use_sim_time 88 | }.items(), 89 | condition=IfCondition(PythonExpression(["'", use_slam_option, "' == 'online_async_slam'"])) 90 | ) 91 | 92 | # nav2_nmapper_params_localization launch 93 | mapper_params_localization = IncludeLaunchDescription( 94 | PythonLaunchDescriptionSource([os.path.join( 95 | get_package_share_directory('slam_toolbox'), 96 | 'launch', 97 | 'localization_launch.py' 98 | )]), 99 | launch_arguments={ 100 | 'slam_params_file': mapper_params_localization_file, 101 | 'use_sim_time': use_sim_time 102 | }.items(), 103 | condition=IfCondition(PythonExpression(["'", use_slam_option, "' == 'mapper_params_localization'"])) 104 | ) 105 | 106 | # amcl launch 107 | amcl = IncludeLaunchDescription( 108 | PythonLaunchDescriptionSource([os.path.join( 109 | get_package_share_directory('nav2_bringup'), 110 | 'launch', 111 | 'localization_launch.py' 112 | )]), 113 | launch_arguments={ 114 | 'map': map, 115 | 'use_sim_time': use_sim_time 116 | }.items(), 117 | condition=IfCondition(PythonExpression(["'", use_slam_option, "' == 'amcl'"])) 118 | ) 119 | 120 | # nav2_navigation launch 121 | navigation = IncludeLaunchDescription( 122 | PythonLaunchDescriptionSource([os.path.join( 123 | get_package_share_directory('nav2_bringup'), 124 | 'launch', 125 | 'navigation_launch.py' 126 | )]), 127 | launch_arguments={ 128 | 'params_file': nav2_params_file, 129 | 'use_sim_time': use_sim_time 130 | }.items() 131 | ) 132 | 133 | 134 | 135 | # Create the launch description and populate 136 | ld = LaunchDescription() 137 | 138 | # Add the launch arguments 139 | ld.add_action(declare_use_sim_time) 140 | ld.add_action(declare_map) 141 | ld.add_action(declare_use_slam_option) 142 | 143 | # Add the nodes to the launch description 144 | ld.add_action(joy_node) 145 | ld.add_action(teleop_node) 146 | 147 | # Add SLAM options 148 | ld.add_action(online_async_slam) 149 | ld.add_action(mapper_params_localization) 150 | ld.add_action(amcl) 151 | 152 | # Add navigation 153 | ld.add_action(navigation) 154 | 155 | # Generate the launch description and 156 | return ld 157 | 158 | -------------------------------------------------------------------------------- /maps/map_01.pgm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/maps/map_01.pgm -------------------------------------------------------------------------------- /maps/map_01.yaml: -------------------------------------------------------------------------------- 1 | image: map_01.pgm 2 | mode: trinary 3 | resolution: 0.05 4 | origin: [-0.225, -0.699, 0] 5 | negate: 0 6 | occupied_thresh: 0.65 7 | free_thresh: 0.25 -------------------------------------------------------------------------------- /maps/map_01_serial.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/maps/map_01_serial.data -------------------------------------------------------------------------------- /maps/map_01_serial.posegraph: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/maps/map_01_serial.posegraph -------------------------------------------------------------------------------- /maps/sample_map.pgm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/maps/sample_map.pgm -------------------------------------------------------------------------------- /maps/sample_map.yaml: -------------------------------------------------------------------------------- 1 | image: sample_map.pgm 2 | mode: trinary 3 | resolution: 0.05 4 | origin: [-3.1, -5.6, 0] 5 | negate: 0 6 | occupied_thresh: 0.65 7 | free_thresh: 0.25 -------------------------------------------------------------------------------- /maps/sample_map_serial.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/maps/sample_map_serial.data -------------------------------------------------------------------------------- /maps/sample_map_serial.posegraph: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/maps/sample_map_serial.posegraph -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | minibot 5 | 1.0.0 6 | Differerntial drive robot system using Jazzy Jalisco 7 | yj0528 8 | Apache-2.0 9 | 10 | ament_cmake 11 | rclcpp 12 | geometry_msgs 13 | ament_lint_auto 14 | ament_lint_common 15 | 16 | 17 | ament_cmake 18 | 19 | 20 | -------------------------------------------------------------------------------- /visual_demos/Nav2_demostration-ezgif.com-video-to-gif-converter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/visual_demos/Nav2_demostration-ezgif.com-video-to-gif-converter.gif -------------------------------------------------------------------------------- /visual_demos/SLAM_demostration-ezgif.com-video-to-gif-converter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/visual_demos/SLAM_demostration-ezgif.com-video-to-gif-converter.gif -------------------------------------------------------------------------------- /visual_demos/robot_hardware.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/visual_demos/robot_hardware.jpg -------------------------------------------------------------------------------- /visual_demos/robot_visual.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YJ0528/minibot/349140cfcdfd9b79d6a6c96f9aa2ac924f9f5378/visual_demos/robot_visual.jpg -------------------------------------------------------------------------------- /worlds/empty.sdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.001 5 | 1 6 | 1000 7 | 8 | 9 | 10 | 11 | 12 | 0 0 -9.8000000000000007 13 | 5.5644999999999998e-06 2.2875799999999999e-05 -4.2388400000000002e-05 14 | 15 | 16 | 0.400000006 0.400000006 0.400000006 1 17 | 0.699999988 0.699999988 0.699999988 1 18 | true 19 | 20 | 21 | true 22 | 23 | 24 | 25 | 26 | 0 0 1 27 | 100 100 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 0 0 1 42 | 100 100 43 | 44 | 45 | 46 | 0.800000012 0.800000012 0.800000012 1 47 | 0.800000012 0.800000012 0.800000012 1 48 | 0.800000012 0.800000012 0.800000012 1 49 | 50 | 51 | 0 0 0 0 0 0 52 | 53 | 0 0 0 0 0 0 54 | 1 55 | 56 | 1 57 | 0 58 | 0 59 | 1 60 | 0 61 | 1 62 | 63 | 64 | false 65 | 66 | 0 0 0 0 0 0 67 | false 68 | 69 | 70 | 0 0 10 0 0 0 71 | true 72 | 1 73 | -0.5 0.10000000000000001 -0.90000000000000002 74 | 0.800000012 0.800000012 0.800000012 1 75 | 0.200000003 0.200000003 0.200000003 1 76 | 77 | 1000 78 | 0.01 79 | 0.90000000000000002 80 | 0.001 81 | 82 | 83 | 0 84 | 0 85 | 0 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /worlds/playground.sdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.001 5 | 1 6 | 1000 7 | 8 | 9 | 10 | 11 | 12 | 0 0 -9.8000000000000007 13 | 5.5644999999999998e-06 2.2875799999999999e-05 -4.2388400000000002e-05 14 | 15 | 16 | 0.400000006 0.400000006 0.400000006 1 17 | 0.699999988 0.699999988 0.699999988 1 18 | true 19 | 20 | 21 | true 22 | 23 | 24 | 25 | 26 | 0 0 1 27 | 100 100 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 0 0 1 42 | 100 100 43 | 44 | 45 | 46 | 0.800000012 0.800000012 0.800000012 1 47 | 0.800000012 0.800000012 0.800000012 1 48 | 0.800000012 0.800000012 0.800000012 1 49 | 50 | 51 | 0 0 0 0 0 0 52 | 53 | 0 0 0 0 0 0 54 | 1 55 | 56 | 1 57 | 0 58 | 0 59 | 1 60 | 0 61 | 1 62 | 63 | 64 | false 65 | 66 | 0 0 0 0 0 0 67 | false 68 | 69 | 70 | 0 0 10 0 0 0 71 | true 72 | 1 73 | -0.5 0.10000000000000001 -0.90000000000000002 74 | 0.800000012 0.800000012 0.800000012 1 75 | 0.200000003 0.200000003 0.200000003 1 76 | 77 | 1000 78 | 0.01 79 | 0.90000000000000002 80 | 0.001 81 | 82 | 83 | 0 84 | 0 85 | 0 86 | 87 | 88 | 89 | 90 | 0 0 0 0 0 1.57 91 | 92 | https://fuel.gazebosim.org/1.0/OpenRobotics/models/Playground 93 | 94 | 95 | 96 | 97 | 98 | --------------------------------------------------------------------------------