├── .gitignore ├── LICENSE ├── README.md └── src ├── mobRobURDF_control ├── CMakeLists.txt ├── config │ ├── drive │ │ ├── gazebo_controller_diffDrive_2wd_caster.yaml │ │ ├── gazebo_controller_diffDrive_4wd.yaml │ │ └── gazebo_controller_mecDrive.yaml │ ├── gazebo_controller_tricycle.yaml │ └── steer │ │ ├── gazebo_controller_ackerSteer.yaml │ │ └── gazebo_controller_triSteer.yaml └── package.xml ├── mobRobURDF_description ├── CMakeLists.txt ├── package.xml └── urdf │ ├── gazebo_files │ ├── control │ │ ├── gazebo_ros2_control_2wc_diff.xacro │ │ ├── gazebo_ros2_control_3w_triSteer.xacro │ │ ├── gazebo_ros2_control_3w_tricycle.xacro │ │ ├── gazebo_ros2_control_4w_acker.xacro │ │ ├── gazebo_ros2_control_4w_diff.xacro │ │ └── gazebo_ros2_control_4w_mec.xacro │ ├── gazebo_properties.xacro │ └── gazebo_sensors.xacro │ ├── macros │ ├── inertial_macros.xacro │ └── material_macros.xacro │ ├── mobRob.urdf │ ├── mobRob.urdf.xacro │ └── submodules │ ├── 2_wheeled_caster │ ├── base.xacro │ ├── mobRob_2wc_diff.xacro │ ├── sensors.xacro │ └── wheels.xacro │ ├── 3_wheeled │ ├── base.xacro │ ├── mobRob_3w_triSteer.xacro │ ├── mobRob_3w_tricycle.xacro │ ├── sensors.xacro │ └── wheels.xacro │ └── 4_wheeled │ ├── ackermann │ ├── base.xacro │ ├── mobRob_4w_acker.xacro │ ├── sensors.xacro │ └── wheels.xacro │ ├── base.xacro │ ├── mobRob_4w_diff.xacro │ ├── mobRob_4w_mec.xacro │ ├── sensors.xacro │ └── wheels.xacro ├── mobRobURDF_gazebo ├── config │ └── gz_bridge.yaml ├── mobRobURDF_gazebo │ └── __init__.py ├── models │ └── FYI.txt ├── package.xml ├── resource │ └── mobRobURDF_gazebo ├── setup.cfg ├── setup.py ├── test │ ├── test_copyright.py │ ├── test_flake8.py │ └── test_pep257.py └── worlds │ ├── empty_world.sdf │ └── warehouse_world.sdf ├── mobRobURDF_launch ├── launch │ ├── gazebo_test.launch.py │ └── urdf_test.launch.py ├── mobRobURDF_launch │ └── __init__.py ├── package.xml ├── resource │ └── mobRobURDF_launch ├── rviz │ ├── rviz_gazebo_test.rviz │ └── rviz_test.rviz ├── setup.cfg ├── setup.py └── test │ ├── test_copyright.py │ ├── test_flake8.py │ └── test_pep257.py └── mobRobURDF_wizard ├── images ├── control_types │ ├── ackermann.png │ ├── diff_2wc.png │ ├── diff_4w.png │ ├── mecanum.png │ ├── triSteer.png │ └── tricycle.png ├── future_features │ ├── control.png │ ├── gazebo.png │ ├── navigation.png │ ├── object_tracking.png │ └── slam.png ├── robot_types │ ├── 2wc_preview.png │ ├── 3w_preview.png │ └── 4w_preview.png └── welcome.gif ├── mobRobURDF_wizard ├── RobotWizard.py ├── __init__.py ├── classes │ ├── OpenGLWidget.py │ ├── URDFManager.py │ └── pages │ │ ├── ConfigurationPage.py │ │ ├── ControlConfigurationPage.py │ │ ├── FutureFeaturesPage.py │ │ ├── RobotTypeSelectionPage.py │ │ └── WelcomePage.py └── utils │ └── utils.py ├── package.xml ├── resource └── mobRobURDF_wizard ├── setup.cfg ├── setup.py └── test ├── test_copyright.py ├── test_flake8.py └── test_pep257.py /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore install directory 2 | install/ 3 | 4 | # ignore log directory 5 | log/ 6 | 7 | # ignore build directory 8 | build/ 9 | 10 | # ignore pycache files 11 | src/mobRobURDF_wizard/mobRobURDF_wizard/__pycache__/ 12 | src/mobRobURDF_wizard/mobRobURDF_wizard/classes/__pycache__/ 13 | src/mobRobURDF_wizard/mobRobURDF_wizard/utils/__pycache__/ 14 | src/mobRobURDF_wizard/mobRobURDF_wizard/classes/pages/__pycache__/ 15 | 16 | # ignore finally creaded mobRob.urdf file 17 | #src/mobRobURDF_description/urdf/mobRob.urdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Ali Pahlevani 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mobile_Robot_URDF_Maker (v3) 2 | 3 | **Automate** the process of making a **URDF** for your **mobile robot** using this "**Wizard**" 4 | 5 | ![Preview_Image](https://github.com/user-attachments/assets/f117642b-6f3c-4057-a417-f05a30a2baa8) 6 | 7 | - You can now easily choose any **controller** you want for your selected mobile robot. A **new page** has been added to the wizard which let's you choose one of the **six available controllers**. 8 | - Based on the type of your robot, you may choose one these controllers: 9 | - **2-Wheeled** Robot with a **Caster Wheel**: 10 | + **Differential-Drive** Controller 11 | - **3-Wheeled** Robot (**Tricycle**): 12 | + **Tricycle** Controller 13 | + **Tricycle-Steering** Controller 14 | - **4-Wheeled** Robot: 15 | + **Differential-Drive** Controller (Skid-Steering) 16 | + **Ackermann-Steering** Controller 17 | + **Mecanum-Drive** Controller 18 | - After choosing the controller type and setting the parameters of the robot, the corresponding values for the controller will be set in the specific config file of that controller type (config files can be found at: **/mobRobURDF_control/config/**). 19 | 20 | ![Controller_List](https://github.com/user-attachments/assets/945a5620-d423-44a1-b807-2aa61d8e1d83) 21 | 22 | - Other good news is that now you can **simulate your robot** in **Modern Gazebo** (since the *Gazebo Classic* has reached its *EOL*). In order to do that, a **new launch file** has been added. By launching this launch file, *robot*, *Gazebo world*, and all the *controllers* will be spawned. Also, *Rviz2* window will open up as well; so, please *build* the workspace, *source* it, and finally *run* the following command: 23 | 24 | ```bash 25 | ros2 launch mobRobURDF_launch gazebo_test.launch.py 26 | ``` 27 | ![Gazebo_Scene](https://github.com/user-attachments/assets/2abbf489-6c52-4d09-b639-26b8e7e7771c) 28 | 29 | --- 30 | 31 | - It should be mentioned that for now, all the *twist commands* are **unstamped**; however, the **stamped versions** are on the way. For now, in order to control the robot in gazebo *teleoperately*, please run one of the following lines in **another terminal** based on your *controller type*: 32 | 33 | **Differential-Drive** Controller: 34 | ```bash 35 | ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/diffDrive_controller/cmd_vel_unstamped 36 | ``` 37 | 38 | **Tricycle Controller**: 39 | ```bash 40 | ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/tricycle_controller/cmd_vel 41 | ``` 42 | 43 | **Tricycle-Steering** Controller: 44 | ```bash 45 | ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/triSteer_controller/reference_unstamped 46 | ``` 47 | 48 | **Differential-Drive** Controller (Skid-Steering): 49 | ```bash 50 | ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/diffDrive_controller/cmd_vel_unstamped 51 | ``` 52 | 53 | **Ackermann-Steering** Controller: 54 | ```bash 55 | ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/ackerSteer_controller/reference_unstamped 56 | ``` 57 | 58 | **Mecanum-Drive** Controller: 59 | ```bash 60 | ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/mecDrive_controller/reference_unstamped 61 | ``` 62 | 63 | ![Rviz2](https://github.com/user-attachments/assets/e21d173e-c43c-43de-a6be-9f3a55366c62) 64 | 65 | --- 66 | 67 | - One more thing to mention is that **some** of the controllers **don't** publish **odom->base_link tf** by themselves. For those ones, you'll need to run a **separate node** for publishing *odom->base_link tf* and *odometry topic*. Soon, **I'll add** those necessary nodes as well, so that you won't need to do anything at all. 68 | 69 | - Finally, you can modify the **Gazebo physical properties** for your simulation in the following file: **/mobRobURDF_description/urdf/gazebo_files/gazebo_properties.xacro**. Also, you may add a *new world* (based on your needs) in the following directory: **/mobRobURDF_gazebo/worlds/** (and then modify the launch file). 70 | 71 | - I almost forgot it. Another good news is that now, by *generating the URDF* for your robot, not only a **.urdf** file is created, also a **.urdf.xacro** file is created as well (**/mobRobURDF_description/urdf/mobRob.urdf** and **/mobRobURDF_description/urdf/mobRob.urdf.xacro**), so that you can easily modify the parameters after closing the wizard. 72 | 73 | - Finally, one **minor fix** is that in this version, the *caster wheel* (for the *2WC* robot type) has **3-DOF** for *free motion* (instead of its previous *fixed joint*). 74 | 75 | --- 76 | 77 | ## Just like the previous version, the path to run the wizard is as simple as you can see: 78 | 79 | In order to run the **Wizard**, first you need to **clone** the workspace: 80 | 81 | ```bash 82 | git clone https://github.com/ali-pahlevani/Mobile_Robot_URDF_Maker.git 83 | cd Mobile_Robot_URDF_Maker 84 | ``` 85 | 86 | For the next step, you'll need to install the **dependencies**: 87 | 88 | ```bash 89 | sudo apt update 90 | rosdep install --from-paths src --ignore-src -r -y 91 | sudo apt install python3-pyqt5 python3-pyqt5.qtopengl 92 | pip install PyOpenGL PyOpenGL_accelerate 93 | pip install ruamel.yaml 94 | ``` 95 | 96 | After that, you should **build** the workspace and **source** the installation: 97 | 98 | ```bash 99 | colcon build --symlink-install 100 | source install/setup.bash 101 | ``` 102 | 103 | Finally, you can easily run the following line in your **terminal**: 104 | 105 | ```bash 106 | ros2 run mobRobURDF_wizard mobRobURDF_wizard 107 | ``` 108 | --- 109 | 110 | In order to launch the **new launch file** (Gazebo + Rviz2), you can run the following line in your **terminal**: 111 | 112 | ```bash 113 | ros2 launch mobRobURDF_launch gazebo_test.launch.py 114 | ``` 115 | 116 | --- 117 | 118 | If you have any questions, please let me know: **a.pahlevani1998@gmail.com** 119 | 120 | + Also, please don't forget to check out our **website** at: **https://www.SLAMbotics.org** 121 | 122 | ## Please stay tuned for the next versions of the app. 123 | 124 | --- 125 | --- 126 | --- 127 | 128 | ## Version 2 129 | 130 | **Automate** the process of making a **URDF** for your **mobile robot** using this "**Wizard**" 131 | 132 | - Now, you don't have only 1 option (4-wheeled robot). In version 2, you'll have **3 options** to choose from (in the next version, I'll introduce **specific controllers** for each of these types, so that you can make **ros2_control config files** for each of these types of **kinematics**): 133 | - **4-Wheeled** Robot 134 | - **3-Wheeled** Robot (**Tricycle**) 135 | - **2-Wheeled** Robot with a **Caster Wheel** 136 | 137 | - You can easily choose the type of robot you need to work with, build its URDF **automatically** (based on the parameters you choose), and get your built URDF file. 138 | - In this version, when you hit the save button, first a **copy of the URDF file** is **saved automatically** in a specific place for the launch file; so that **launch file** will recognize it automatically when you launch it (for **testing** purposes). 139 | - Other than that, you can also save **another copy** of it to any **directory you want** (or simply close the saving window if you **don't need** it!). 140 | 141 | - As it be seen, the overall structure of the wizard has been enhanced and organized, so that not only you can **navigate to different pages** using **Navigation Bar**, also at the last page of the wizard (in this version), you can see the **upcoming updates** for the wizard in the next releases (adding *Gazebo* files, *SLAM* and *Navigation* capability, setting up *Controllers*, etc.). 142 | 143 | --- 144 | 145 | ## Just like the previous version, the path to run the wizard is as simple as you can see: 146 | 147 | In order to run the **Wizard**, first you need to **clone** the workspace: 148 | 149 | ```bash 150 | git clone https://github.com/ali-pahlevani/Mobile_Robot_URDF_Maker.git 151 | cd Mobile_Robot_URDF_Maker 152 | ``` 153 | 154 | For the next step, you'll need to install the **dependencies**: 155 | 156 | ```bash 157 | sudo apt update 158 | rosdep install --from-paths src --ignore-src -r -y 159 | sudo apt install python3-pyqt5 python3-pyqt5.qtopengl 160 | ``` 161 | 162 | After that, you should **build** the workspace and **source** the installation: 163 | 164 | ```bash 165 | colcon build --symlink-install 166 | source install/setup.bash 167 | ``` 168 | 169 | Finally, you can easily run the following line in your **terminal**: 170 | 171 | ```bash 172 | ros2 run mobRobURDF_wizard mobRobURDF_wizard 173 | ``` 174 | --- 175 | 176 | In order to run the launch file, you can run the following line in your **terminal**: 177 | 178 | ```bash 179 | ros2 launch mobRobURDF_launch urdf_test.launch.py 180 | ``` 181 | 182 | --- 183 | 184 | If you have any question, please let me know: **a.pahlevani1998@gmail.com** 185 | 186 | ## Please stay tuned for the next versions of the app. 187 | 188 | --- 189 | --- 190 | --- 191 | 192 | ## Version 1 193 | 194 | **Automate** the process of making a **URDF** for your **4-wheeled mobile robot** using this "**Wizard**" 195 | 196 | --- 197 | 198 | This workspace has 3 **ROS2** packages (up to now. I have plan for adding other packages as well for **Gazebo**, **Control**, **Navigation**, etc.): 199 | 200 | 1. ### mobRobURDF_description: 201 | - This package includes all the **template Xacro** files necessary for creating the **final URDF** file. The *sub-directories* in this directory are: 202 | - **submodules:** containing **base.xacro** (*chassis*), **wheels.xacro** (*4 wheels*), and **sensors.xacro** (*2D-Lidar* + *RGB Camera*) files, 203 | - **macros:** containing **inertial_macros.xacro**, and **material.xacro** (*colors*) files, 204 | - **gazebo_files:** containing **gazebo_sensors.xacro** file for now (in the future, when the Gazebo package is added, not only this file will be used in the final URDF file, also other Xacro files for Gazebo will be added as well (e.g., **gazebo_properties.xacro** file)). 205 | - Finally, all the Xacro files are imported into the *main Xacro file* (**mobRob.xacro**), so that it can be converted to **mobRob.urdf** file. 206 | - Good news is that not only you can use the Wizard to make the URDF file you need, but also you have **access** to all the Xacro files. If you ever wanted to **change** any of them and adapt them to your specific case, you're free to go. 207 | 208 | --- 209 | 210 | 2. ### mobRobURDF_wizard: 211 | - This is the *main package* of the workspace. This package contains the **source codes** of the Wizard. The codebase is composed of different classes and some utility functions, all imported into the main file **robot_wizard.py**. This package used to be a standalone codebase; however, now its a **ROS2 node**. 212 | - In the Wizard window, you can apply your changes step by step, with no pressure. You can even fill only *some of the fields* and only apply those changes. Finally, you can **save your created URDF file** to any directory you want. Additionally, for your convenience, you'll have **3-DOF camera rotation**, plus **zooming capability** in the preview window. 213 | - **Attention:** If you want to use the launch file (that is provided for **testing purposes** (check the next part)), you'll need to **save** the created **URDF** file in the following location: **/mobRobURDF_description/urdf/mobRob.urdf** 214 | 215 | - In order to run the **Wizard**, first you need to **clone** the workspace: 216 | 217 | ```bash 218 | git clone https://github.com/ali-pahlevani/Mobile_Robot_URDF_Maker.git 219 | cd Mobile_Robot_URDF_Maker 220 | ``` 221 | 222 | - For the next step, you'll need to install the **dependencies**: 223 | 224 | ```bash 225 | sudo apt update 226 | rosdep install --from-paths src --ignore-src -r -y 227 | sudo apt install python3-pyqt5 python3-pyqt5.qtopengl 228 | ``` 229 | 230 | - After that, you should **build** the workspace and **source** the installation: 231 | 232 | ```bash 233 | colcon build --symlink-install 234 | source install/setup.bash 235 | ``` 236 | 237 | - Finally, you can easily run the following line in your **terminal**: 238 | 239 | ```bash 240 | ros2 run mobRobURDF_wizard mobRobURDF_wizard 241 | ``` 242 | 243 | --- 244 | 245 | 3. ### mobRobURDF_launch: 246 | - This package includes 2 main directories: 247 | - **launch:** containing only one launch file (for now) for testing purposes (**urdf_test.launch.py**). By launching this launch file, 3 nodes will be launched: 248 | - **robot_state_publisher** 249 | - **joint_state_publisher_gui** 250 | - **rviz2** 251 | Using these nodes, everyone would be able to **test** the performance of the final URDF file (**visual check** + **testing the joints**) 252 | - **rviz:** containing only one *rviz2 config file* (**rviz_test.rviz**). This is the rviz2 config file that is loaded into the discussed launch file. 253 | 254 | - In order to run the launch file, you can run the following line in your **terminal**: 255 | 256 | ```bash 257 | ros2 launch mobRobURDF_launch urdf_test.launch.py 258 | ``` 259 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(mobRobURDF_control) 3 | 4 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 5 | add_compile_options(-Wall -Wextra -Wpedantic) 6 | endif() 7 | 8 | # Find dependencies 9 | find_package(ament_cmake REQUIRED) 10 | find_package(xacro REQUIRED) 11 | find_package(rclpy REQUIRED) 12 | find_package(geometry_msgs REQUIRED) 13 | find_package(std_msgs REQUIRED) 14 | 15 | # Install config files 16 | install( 17 | DIRECTORY config 18 | DESTINATION share/${PROJECT_NAME} 19 | ) 20 | 21 | # Export the package 22 | ament_package() 23 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/config/drive/gazebo_controller_diffDrive_2wd_caster.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 50 4 | use_sim_time: true 5 | 6 | diffDrive_controller: 7 | type: diff_drive_controller/DiffDriveController 8 | 9 | joint_state_broadcaster: 10 | type: joint_state_broadcaster/JointStateBroadcaster 11 | 12 | diffDrive_controller: 13 | ros__parameters: 14 | 15 | publish_rate: 50.0 16 | 17 | base_frame_id: base_link 18 | odom_frame_id: odom 19 | enable_odom_tf: true 20 | 21 | left_wheel_names: ["left_joint"] 22 | right_wheel_names: ["right_joint"] 23 | 24 | wheel_separation: 0.92 25 | wheel_radius: 0.22 26 | 27 | use_stamped_vel: false 28 | 29 | #wheel_separation_multiplier: 1.0 30 | #left_wheel_radius_multiplier: 1.0 31 | #right_wheel_radius_multiplier: 1.0 32 | 33 | pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 34 | twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 35 | 36 | #position_feedback: false 37 | #open_loop: true 38 | 39 | #cmd_vel_timeout: 0.5 # seconds 40 | #publish_limited_velocity: true 41 | #velocity_rolling_window_size: 10 42 | 43 | # Velocity limits 44 | #linear.x.max_velocity: 1.0 45 | #linear.x.min_velocity: -1.0 46 | #linear.x.max_acceleration: 0.5 47 | #linear.x.max_deceleration: 0.5 48 | #linear.x.max_acceleration_reverse: 0.5 49 | #linear.x.max_deceleration_reverse: 0.5 50 | #linear.x.max_jerk: 1.0 51 | #linear.x.min_jerk: -1.0 52 | 53 | #angular.z.max_velocity: 1.0 54 | #angular.z.min_velocity: -1.0 55 | #angular.z.max_acceleration: 0.5 56 | #angular.z.max_deceleration: 0.5 57 | #angular.z.max_acceleration_reverse: 0.5 58 | #angular.z.max_deceleration_reverse: 0.5 59 | #angular.z.max_jerk: 1.0 60 | #angular.z.min_jerk: -1.0 61 | 62 | joint_state_broadcaster: 63 | ros__parameters: 64 | joints: 65 | - left_joint 66 | - right_joint 67 | - free-rotating_x_joint 68 | - free-rotating_y_joint 69 | - front_caster_joint 70 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/config/drive/gazebo_controller_diffDrive_4wd.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 50 4 | use_sim_time: true 5 | 6 | diffDrive_controller: 7 | type: diff_drive_controller/DiffDriveController 8 | 9 | joint_state_broadcaster: 10 | type: joint_state_broadcaster/JointStateBroadcaster 11 | 12 | diffDrive_controller: 13 | ros__parameters: 14 | 15 | publish_rate: 50.0 16 | 17 | base_frame_id: base_link 18 | odom_frame_id: odom 19 | enable_odom_tf: true 20 | 21 | left_wheel_names: ["front_left_joint", "rear_left_joint"] 22 | right_wheel_names: ["front_right_joint", "rear_right_joint"] 23 | 24 | wheel_separation: 0.92 25 | wheel_radius: 0.22 26 | 27 | use_stamped_vel: false 28 | 29 | #wheel_separation_multiplier: 1.0 30 | #left_wheel_radius_multiplier: 1.0 31 | #right_wheel_radius_multiplier: 1.0 32 | 33 | pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 34 | twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 35 | 36 | #position_feedback: false 37 | #open_loop: true 38 | 39 | #cmd_vel_timeout: 0.5 # seconds 40 | #publish_limited_velocity: true 41 | #velocity_rolling_window_size: 10 42 | 43 | # Velocity limits 44 | #linear.x.max_velocity: 1.0 45 | #linear.x.min_velocity: -1.0 46 | #linear.x.max_acceleration: 0.5 47 | #linear.x.max_deceleration: 0.5 48 | #linear.x.max_acceleration_reverse: 0.5 49 | #linear.x.max_deceleration_reverse: 0.5 50 | #linear.x.max_jerk: 1.0 51 | #inear.x.min_jerk: -1.0 52 | 53 | #angular.z.max_velocity: 1.0 54 | #angular.z.min_velocity: -1.0 55 | #angular.z.max_acceleration: 0.5 56 | #angular.z.max_deceleration: 0.5 57 | #angular.z.max_acceleration_reverse: 0.5 58 | #angular.z.max_deceleration_reverse: 0.5 59 | #angular.z.max_jerk: 1.0 60 | #angular.z.min_jerk: -1.0 61 | 62 | joint_state_broadcaster: 63 | ros__parameters: 64 | joints: 65 | - front_left_joint 66 | - front_right_joint 67 | - rear_left_joint 68 | - rear_right_joint 69 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/config/drive/gazebo_controller_mecDrive.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 50 4 | use_sim_time: true 5 | 6 | mecDrive_controller: 7 | type: mecanum_drive_controller/MecanumDriveController 8 | 9 | joint_state_broadcaster: 10 | type: joint_state_broadcaster/JointStateBroadcaster 11 | 12 | mecDrive_controller: 13 | ros__parameters: 14 | 15 | publish_rate: 50.0 16 | 17 | base_frame_id: base_link 18 | odom_frame_id: odom 19 | enable_odom_tf: true 20 | 21 | #reference_timeout: 0.9 22 | 23 | front_left_wheel_command_joint_name: "front_left_joint" 24 | front_right_wheel_command_joint_name: "front_right_joint" 25 | rear_right_wheel_command_joint_name: "rear_right_joint" 26 | rear_left_wheel_command_joint_name: "rear_left_joint" 27 | 28 | kinematics: 29 | base_frame_offset: {x: 0.0, y: 0.0, theta: 0.0} 30 | wheels_radius: 0.22 31 | sum_of_robot_center_projection_on_X_Y_axis: 2.0 32 | 33 | twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 34 | pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 35 | 36 | use_stamped_vel: false 37 | 38 | joint_state_broadcaster: 39 | ros__parameters: 40 | joints: 41 | - front_left_joint 42 | - front_right_joint 43 | - rear_left_joint 44 | - rear_right_joint 45 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/config/gazebo_controller_tricycle.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 50 4 | use_sim_time: true 5 | 6 | tricycle_controller: 7 | type: tricycle_controller/TricycleController 8 | 9 | joint_state_broadcaster: 10 | type: joint_state_broadcaster/JointStateBroadcaster 11 | 12 | tricycle_controller: 13 | ros__parameters: 14 | 15 | publish_rate: 50.0 16 | 17 | base_frame_id: base_link 18 | odom_frame_id: odom 19 | enable_odom_tf: true 20 | 21 | traction_joint_name: front_joint 22 | steering_joint_name: chassis_to_front_steering 23 | wheel_radius: 0.22 24 | wheelbase: 1.2 25 | 26 | use_stamped_vel: false 27 | open_loop: false 28 | 29 | pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 30 | twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] 31 | #odom_only_twist: true 32 | #publish_ackermann_command: true 33 | #traction: 34 | # max_acceleration: 1.0 35 | # max_deceleration: 1.0 36 | #steering: 37 | # max_position: 0.785 # pi/4 38 | # max_velocity: 1.0 39 | 40 | joint_state_broadcaster: 41 | ros__parameters: 42 | joints: 43 | - chassis_to_front_steering 44 | - front_joint 45 | - rear_left_joint 46 | - rear_right_joint 47 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/config/steer/gazebo_controller_ackerSteer.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 50 4 | use_sim_time: true 5 | 6 | ackerSteer_controller: 7 | type: ackermann_steering_controller/AckermannSteeringController 8 | 9 | joint_state_broadcaster: 10 | type: joint_state_broadcaster/JointStateBroadcaster 11 | 12 | ackerSteer_controller: 13 | ros__parameters: 14 | 15 | publish_rate: 50.0 16 | 17 | base_frame_id: base_link 18 | odom_frame_id: odom 19 | enable_odom_tf: true 20 | 21 | front_steering: true 22 | 23 | front_wheel_track: 0.8 24 | rear_wheel_track: 0.8 25 | front_wheels_radius: 0.22 26 | rear_wheels_radius: 0.22 27 | wheelbase: 1.2 28 | 29 | #reference_timeout: 2.0 30 | #open_loop: false 31 | #velocity_rolling_window_size: 10 32 | #position_feedback: false 33 | rear_wheels_names: [rear_right_joint, rear_left_joint] 34 | front_wheels_names: [chassis_to_front_right_steering, chassis_to_front_left_steering] 35 | 36 | use_stamped_vel: false 37 | 38 | traction_track_width: 0.8 39 | traction_wheels_radius: 0.22 40 | joint_state_broadcaster: 41 | ros__parameters: 42 | joints: 43 | - front_left_joint 44 | - front_right_joint 45 | - rear_left_joint 46 | - rear_right_joint 47 | - chassis_to_front_left_steering 48 | - chassis_to_front_right_steering 49 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/config/steer/gazebo_controller_triSteer.yaml: -------------------------------------------------------------------------------- 1 | controller_manager: 2 | ros__parameters: 3 | update_rate: 50 4 | use_sim_time: true 5 | 6 | triSteer_controller: 7 | type: tricycle_steering_controller/TricycleSteeringController 8 | 9 | joint_state_broadcaster: 10 | type: joint_state_broadcaster/JointStateBroadcaster 11 | 12 | triSteer_controller: 13 | ros__parameters: 14 | 15 | publish_rate: 50.0 16 | 17 | base_frame_id: base_link 18 | odom_frame_id: odom 19 | enable_odom_tf: true 20 | 21 | #reference_timeout: 2.0 22 | front_steering: true 23 | #open_loop: false 24 | #velocity_rolling_window_size: 10 25 | position_feedback: true 26 | use_stamped_vel: false 27 | 28 | rear_wheels_names: [rear_right_joint, rear_left_joint] 29 | front_wheels_names: [chassis_to_front_steering] 30 | 31 | wheelbase: 1.2 32 | wheel_track: 0.8 33 | front_wheels_radius: 0.22 34 | rear_wheels_radius: 0.22 35 | 36 | joint_state_broadcaster: 37 | ros__parameters: 38 | joints: 39 | - chassis_to_front_steering 40 | - front_joint 41 | - rear_left_joint 42 | - rear_right_joint 43 | -------------------------------------------------------------------------------- /src/mobRobURDF_control/package.xml: -------------------------------------------------------------------------------- 1 | 2 | mobRobURDF_control 3 | 0.0.1 4 | Package for containing control config files 5 | 6 | Ali Pahlevani 7 | MIT 8 | 9 | ament_cmake 10 | 11 | ament_index_cpp 12 | rclcpp 13 | rclpy 14 | geometry_msgs 15 | std_msgs 16 | xacro 17 | 18 | 19 | ament_cmake 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(mobRobURDF_description) 3 | 4 | # Find dependencies 5 | find_package(ament_cmake REQUIRED) 6 | find_package(xacro REQUIRED) 7 | 8 | # Install URDF and Mesh files 9 | install( 10 | DIRECTORY urdf 11 | DESTINATION share/${PROJECT_NAME} 12 | ) 13 | 14 | # Export the package 15 | ament_package() 16 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/package.xml: -------------------------------------------------------------------------------- 1 | 2 | mobRobURDF_description 3 | 0.0.1 4 | Package for containing Xacro URDF files 5 | 6 | Ali Pahlevani 7 | MIT 8 | 9 | ament_cmake 10 | 11 | ament_index_cpp 12 | rclcpp 13 | xacro 14 | 15 | 16 | ament_cmake 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/control/gazebo_ros2_control_2wc_diff.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gz_ros2_control/GazeboSimSystem 7 | 8 | 9 | 10 | 11 | -50 12 | 50 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -50 21 | 50 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 | $(find mobRobURDF_control)/config/drive/gazebo_controller_diffDrive_2wd_caster.yaml 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/control/gazebo_ros2_control_3w_triSteer.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gz_ros2_control/GazeboSimSystem 7 | 8 | 9 | 10 | 11 | -50 12 | 50 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -50 21 | 50 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -0.785 30 | 0.785 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | $(find mobRobURDF_control)/config/steer/gazebo_controller_triSteer.yaml 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/control/gazebo_ros2_control_3w_tricycle.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gz_ros2_control/GazeboSimSystem 7 | 8 | 9 | 10 | 11 | -50 12 | 50 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -0.785 21 | 0.785 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 | $(find mobRobURDF_control)/config/gazebo_controller_tricycle.yaml 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/control/gazebo_ros2_control_4w_acker.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gz_ros2_control/GazeboSimSystem 7 | 8 | 9 | 10 | 11 | -50 12 | 50 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -50 21 | 50 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -0.785 30 | 0.785 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -0.785 39 | 0.785 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 | $(find mobRobURDF_control)/config/steer/gazebo_controller_ackerSteer.yaml 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/control/gazebo_ros2_control_4w_diff.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gz_ros2_control/GazeboSimSystem 7 | 8 | 9 | 10 | 11 | -50 12 | 50 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -50 21 | 50 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -50 30 | 50 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -50 39 | 50 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | $(find mobRobURDF_control)/config/drive/gazebo_controller_diffDrive_4wd.yaml 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/control/gazebo_ros2_control_4w_mec.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gz_ros2_control/GazeboSimSystem 7 | 8 | 9 | 10 | 11 | -50 12 | 50 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -50 21 | 50 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -50 30 | 50 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -50 39 | 50 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | $(find mobRobURDF_control)/config/drive/gazebo_controller_mecDrive.yaml 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/gazebo_properties.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 0.8 19 | 0.8 20 | 21 | 22 | 23 | 1e6 24 | 1.0 25 | 0.1 26 | 0.001 27 | 28 | 29 | 0.0 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 1.0 45 | 1.0 46 | 47 | 48 | 49 | 1e6 50 | 1.0 51 | 0.1 52 | 0.001 53 | 54 | 55 | 0.0 56 | 57 | 58 | 59 | 60 | 61 | 0.1 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 0.1 74 | 0.1 75 | 76 | 77 | 78 | 1e6 79 | 1.0 80 | 0.1 81 | 0.001 82 | 83 | 84 | 0.0 85 | 86 | 87 | 88 | 89 | 90 | 0.01 91 | 92 | 93 | 0.01 94 | 95 | 96 | 0.01 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 1.0 109 | 1.0 110 | 111 | 112 | 113 | 1e6 114 | 1.0 115 | 0.1 116 | 0.001 117 | 118 | 119 | 0.0 120 | 121 | 122 | 123 | 124 | 125 | 0.1 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 1.2 143 | 1.2 144 | 145 | 146 | 147 | 1e6 148 | 1.0 149 | 0.1 150 | 0.001 151 | 152 | 153 | 0.0 154 | 155 | 156 | 157 | 158 | 159 | 0.15 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 1.0 177 | 1.0 178 | 179 | 180 | 181 | 1e6 182 | 1.0 183 | 0.1 184 | 0.001 185 | 186 | 187 | 0.0 188 | 189 | 190 | 191 | 192 | 193 | 0.1 194 | 195 | 196 | 197 | 198 | 0.01 199 | 0.3 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 0.8 210 | 0.8 211 | 212 | 213 | 214 | 1e6 215 | 1.0 216 | 0.1 217 | 0.001 218 | 219 | 220 | 0.0 221 | 222 | 223 | 224 | 225 | 226 | 0.05 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 1.0 242 | 1.0 243 | 244 | 245 | 246 | 1e6 247 | 1.0 248 | 0.1 249 | 0.001 250 | 251 | 252 | 0.0 253 | 254 | 255 | 256 | 257 | 258 | 0.1 259 | 260 | 261 | 262 | 263 | 0.02 264 | 0.3 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 0.8 275 | 0.8 276 | 277 | 278 | 279 | 1e6 280 | 1.0 281 | 0.1 282 | 0.001 283 | 284 | 285 | 0.0 286 | 287 | 288 | 289 | 290 | 291 | 0.05 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 1.0 308 | 1.0 309 | 310 | 311 | 312 | 1e6 313 | 1.0 314 | 0.1 315 | 0.001 316 | 317 | 318 | 0.0 319 | 320 | 321 | 322 | 323 | 324 | 0.1 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 0.01 333 | 0.3 334 | 335 | 336 | 0.01 337 | 0.3 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 0.8 348 | 0.8 349 | 350 | 351 | 352 | 1e6 353 | 1.0 354 | 0.1 355 | 0.001 356 | 357 | 358 | 0.0 359 | 360 | 361 | 362 | 363 | 364 | 0.05 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/gazebo_files/gazebo_sensors.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Gazebo/Black 6 | 7 | 0 0 0 0 0 0 8 | true 9 | 10 10 | 11 | 12 | 13 | 360 14 | -3.14 15 | 3.14 16 | 17 | 18 | 19 | 0.3 20 | 12 21 | 22 | 23 | scan 24 | laser_frame 25 | 26 | 27 | 28 | 29 | 30 | Gazebo/Black 31 | 32 | 0 0 0 0 0 0 33 | true 34 | 10 35 | 36 | camera/camera_info 37 | 1.089 38 | 39 | R8G8B8 40 | 640 41 | 480 42 | 43 | 44 | 0.05 45 | 8.0 46 | 47 | 48 | camera/image_raw 49 | camera_link_optical 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/macros/inertial_macros.xacro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/macros/material_macros.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/mobRob.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 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/2_wheeled_caster/base.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/2_wheeled_caster/mobRob_2wc_diff.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 | 34 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/2_wheeled_caster/sensors.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 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/2_wheeled_caster/wheels.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 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/3_wheeled/base.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/3_wheeled/mobRob_3w_triSteer.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 | 34 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/3_wheeled/mobRob_3w_tricycle.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 | 34 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/3_wheeled/sensors.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 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/3_wheeled/wheels.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/ackermann/base.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/ackermann/mobRob_4w_acker.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 | 35 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/ackermann/sensors.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 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/ackermann/wheels.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/base.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/mobRob_4w_diff.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 | 35 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/mobRob_4w_mec.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 | 35 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/sensors.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 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/mobRobURDF_description/urdf/submodules/4_wheeled/wheels.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 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/config/gz_bridge.yaml: -------------------------------------------------------------------------------- 1 | - ros_topic_name: "clock" 2 | gz_topic_name: "clock" 3 | ros_type_name: "rosgraph_msgs/msg/Clock" 4 | gz_type_name: "gz.msgs.Clock" 5 | direction: GZ_TO_ROS 6 | 7 | # gz topic published by Sensors plugin 8 | - ros_topic_name: "scan" 9 | gz_topic_name: "scan" 10 | ros_type_name: "sensor_msgs/msg/LaserScan" 11 | gz_type_name: "gz.msgs.LaserScan" 12 | direction: GZ_TO_ROS 13 | 14 | # gz topic published by Sensors plugin (Camera) 15 | - ros_topic_name: "camera/camera_info" 16 | gz_topic_name: "camera/camera_info" 17 | ros_type_name: "sensor_msgs/msg/CameraInfo" 18 | gz_type_name: "gz.msgs.CameraInfo" 19 | direction: GZ_TO_ROS -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/mobRobURDF_gazebo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_gazebo/mobRobURDF_gazebo/__init__.py -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/models/FYI.txt: -------------------------------------------------------------------------------- 1 | This is where you can put the model(s) you'll use in your world(s). -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mobRobURDF_gazebo 5 | 0.0.1 6 | Package for creating gazebo worlds 7 | Ali Pahlevani 8 | MIT 9 | 10 | 11 | ament_copyright 12 | ament_flake8 13 | ament_pep257 14 | python3-pytest 15 | 16 | 17 | ament_python 18 | 19 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/resource/mobRobURDF_gazebo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_gazebo/resource/mobRobURDF_gazebo -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/mobRobURDF_gazebo 3 | [install] 4 | install_scripts=$base/lib/mobRobURDF_gazebo 5 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import find_packages, setup 2 | 3 | package_name = 'mobRobURDF_gazebo' 4 | 5 | setup( 6 | name=package_name, 7 | version='0.0.0', 8 | packages=find_packages(exclude=['test']), 9 | data_files=[ 10 | ('share/ament_index/resource_index/packages', ['resource/' + package_name]), 11 | ('share/' + package_name, ['package.xml']), 12 | ('share/' + package_name + '/worlds', ['worlds/warehouse_world.sdf']), 13 | ('share/' + package_name + '/worlds', ['worlds/empty_world.sdf']), 14 | ('share/' + package_name + '/config', ['config/gz_bridge.yaml']), 15 | ], 16 | install_requires=['setuptools'], 17 | zip_safe=True, 18 | maintainer='Ali Pahlevani', 19 | maintainer_email='a.pahlevani1998@gmail.com', 20 | description='Package for creating gazebo worlds', 21 | license='MIT', 22 | tests_require=['pytest'], 23 | entry_points={ 24 | 'console_scripts': [], 25 | }, 26 | ) 27 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/worlds/empty_world.sdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.001 5 | 1.0 6 | 7 | 10 | 11 | 14 | 15 | 18 | 19 | 22 | ogre2 23 | 24 | 27 | 28 | 29 | 30 | true 31 | 0 0 10 0 0 0 32 | 0.8 0.8 0.8 1 33 | 0.2 0.2 0.2 1 34 | 35 | 1000 36 | 0.9 37 | 0.01 38 | 0.001 39 | 40 | -0.5 0.1 -0.9 41 | 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 0 0 1 50 | 100 100 51 | 52 | 53 | 54 | 55 | 56 | 57 | 0 0 1 58 | 100 100 59 | 60 | 61 | 62 | 0.8 0.8 0.8 1 63 | 0.8 0.8 0.8 1 64 | 0.8 0.8 0.8 1 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/mobRobURDF_gazebo/worlds/warehouse_world.sdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 0 -9.8 4 | 5 | 0.01 6 | 1 7 | 10 8 | 1000 9 | 10 | 11 | 12 | 13 | 14 | 15 | ogre2 16 | 17 | 18 | 19 | 20 | 3D View 21 | false 22 | docked 23 | 24 | ogre2 25 | scene 26 | 0.4 0.4 0.4 27 | 0.8 0.8 0.8 28 | 13.4 -6.1 2.23 0 0.4 -1.83 29 | 30 | 31 | 32 | World control 33 | false 34 | false 35 | 72 36 | 121 37 | 1 38 | floating 39 | 40 | 41 | 42 | 43 | 44 | true 45 | true 46 | true 47 | 48 | 49 | 50 | World stats 51 | false 52 | false 53 | 110 54 | 290 55 | 1 56 | floating 57 | 58 | 59 | 60 | 61 | 62 | true 63 | true 64 | true 65 | true 66 | 67 | 68 | 69 | false 70 | 0 71 | 0 72 | 250 73 | 50 74 | floating 75 | #666666 76 | 77 | 78 | 79 | 80 | false 81 | 250 82 | 0 83 | 150 84 | 50 85 | floating 86 | #666666 87 | 88 | 89 | 90 | 91 | false 92 | 400 93 | 0 94 | 50 95 | 50 96 | floating 97 | #666666 98 | 99 | 100 | 101 | 102 | 0 103 | 0 104 | 400 105 | 375 106 | docked_collapsed 107 | 108 | 109 | 110 | 111 | 0 112 | 0 113 | 400 114 | 375 115 | docked_collapsed 116 | 117 | 118 | 119 | 120 | 1 1 1 1 121 | 0.3 0.7 0.9 1 122 | false 123 | false 124 | 125 | 6e-06 2.3e-05 -4.2e-05 126 | 127 | 128 | true 129 | 130 | 131 | 132 | 133 | 0 0 1 134 | 1 1 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 0 0 0 0 -0 0 146 | 147 | 0 0 0 0 -0 0 148 | 1 149 | 150 | 1 151 | 0 152 | 0 153 | 1 154 | 0 155 | 1 156 | 157 | 158 | false 159 | 160 | 0 0 0 0 -0 0 161 | false 162 | 163 | 164 | https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Warehouse 165 | warehouse 166 | 0 0 -0.09 0 -0 0 167 | 168 | 169 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/Tugbot-charging-station 170 | charging_station 171 | 14.7 -10.6 -0.04 0 -0 0 172 | 173 | 174 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/cart_model_2 175 | cart1 176 | -5.73 15 0.25 0 -0 0 177 | 178 | 179 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf_big 180 | shelf_big_0 181 | -9.34177 -13.5598 0 0 -0 0 182 | 183 | 184 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 185 | shelf 186 | -4.41528 -0.690987 0 0 -0 0 187 | 188 | 189 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 190 | shelf_0 191 | -4.41528 2.30697 0 0 -0 0 192 | 193 | 194 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 195 | shelf_1 196 | -4.41528 5.30708 0 0 -0 0 197 | 198 | 199 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 200 | shelf_2 201 | -4.41528 8.34352 0 0 -0 0 202 | 203 | 204 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 205 | shelf_3 206 | 5.60144 8.34352 0 0 -0 0 207 | 208 | 209 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 210 | shelf_4 211 | 5.60144 5.30708 0 0 -0 0 212 | 213 | 214 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 215 | shelf_5 216 | 5.60144 -0.690987 0 0 -0 0 217 | 218 | 219 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 220 | shelf_6 221 | 5.60144 2.30697 0 0 -0 0 222 | 223 | 224 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/pallet_box_mobile 225 | pallet_box_mobile 226 | 4.4161 14.6952 0.01 0 -0 0 227 | 228 | 229 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/pallet_box_mobile 230 | pallet_box_mobile_0 231 | 4.45415 13.6212 0.01 0 -0 0 232 | 233 | 234 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/pallet_box_mobile 235 | pallet_box_mobile_1 236 | 4.4468 12.229 0.01 0 -0 0 237 | 238 | 239 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/pallet_box_mobile 240 | pallet_box 241 | -6.11913 13.7079 0.01 0 -0 0 242 | 243 | 244 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf_big 245 | shelf_big_1 246 | 13.9821 15.319 0 0 -0 0 247 | 248 | 249 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf_big 250 | shelf_big_2 251 | 6.19777 -12.9647 0 0 -0 0 252 | 253 | 254 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf_big 255 | shelf_big_3 256 | 0.594376 -12.9647 0 0 -0 0 257 | 258 | 259 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf_big 260 | shelf_big_4 261 | -5.36284 -12.9647 0 0 -0 0 262 | 263 | 264 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 265 | shelf_7 266 | 13.3818 -21.2416 0 0 -0 0 267 | 268 | 269 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 270 | shelf_8 271 | 13.3818 -19.0028 0 0 -0 0 272 | 273 | 274 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 275 | shelf_9 276 | 13.3818 -16.4478 0 0 -0 0 277 | 278 | 279 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/shelf 280 | shelf_10 281 | 13.3818 -14.1028 0 0 -0 0 282 | 283 | 284 | https://fuel.ignitionrobotics.org/1.0/MovAi/models/pallet_box_mobile 285 | pallet_box_0 286 | 14.0222 -24.335 0.01 0 -0 0 287 | 288 | 289 | -5 -3 10 0 -0 0 290 | false 291 | 1 292 | 0 0 -1 293 | 1 1 1 1 294 | 1 1 1 1 295 | 296 | 10 297 | 1 298 | 1 299 | 0 300 | 301 | 302 | 0 303 | 0 304 | 0 305 | 306 | 307 | 308 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/launch/gazebo_test.launch.py: -------------------------------------------------------------------------------- 1 | from launch import LaunchDescription 2 | from launch_ros.actions import Node 3 | from launch.substitutions import PathJoinSubstitution, LaunchConfiguration 4 | import xacro 5 | from ament_index_python.packages import get_package_share_directory 6 | from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument 7 | from launch.launch_description_sources import PythonLaunchDescriptionSource 8 | import os 9 | 10 | def generate_launch_description(): 11 | 12 | urdf_path = get_package_share_directory('mobRobURDF_description') + '/urdf/mobRob.urdf.xacro' 13 | 14 | processed_urdf = xacro.process_file(urdf_path).toxml() 15 | 16 | rviz_config_path = PathJoinSubstitution([ 17 | get_package_share_directory('mobRobURDF_launch'), 18 | 'rviz', 19 | 'rviz_gazebo_test.rviz' 20 | ]) 21 | 22 | default_world = os.path.join( 23 | get_package_share_directory('mobRobURDF_gazebo'), 24 | 'worlds', 25 | 'warehouse_world.sdf' 26 | ) 27 | 28 | world = LaunchConfiguration('world') 29 | 30 | world_arg = DeclareLaunchArgument( 31 | 'world', 32 | default_value=default_world, 33 | description='World to load' 34 | ) 35 | 36 | gazebo = IncludeLaunchDescription( 37 | PythonLaunchDescriptionSource([os.path.join( 38 | get_package_share_directory('ros_gz_sim'), 'launch', 'gz_sim.launch.py')]), 39 | launch_arguments={'gz_args': ['-r -v4 ', world], 'on_exit_shutdown': 'true'}.items() 40 | ) 41 | 42 | node_robot_state_publisher = Node( 43 | package='robot_state_publisher', 44 | executable='robot_state_publisher', 45 | name='robot_state_publisher', 46 | output='screen', 47 | parameters=[{ 48 | 'robot_description': processed_urdf, 49 | 'use_sim_time': True 50 | }] 51 | ) 52 | 53 | spawn_entity = Node( 54 | package='ros_gz_sim', 55 | executable='create', 56 | arguments=['-topic', 'robot_description', '-name', 'mobRobURDF', '-z', '0.5'], 57 | output='screen' 58 | ) 59 | 60 | controllers = Node( 61 | package="controller_manager", 62 | executable="spawner", 63 | arguments=["diffDrive_controller"], 64 | ) 65 | 66 | joint_state_broadcaster = Node( 67 | package="controller_manager", 68 | executable="spawner", 69 | arguments=["joint_state_broadcaster"], 70 | ) 71 | 72 | bridge_params = os.path.join(get_package_share_directory('mobRobURDF_gazebo'),'config','gz_bridge.yaml') 73 | 74 | ros_gz_bridge = Node( 75 | package="ros_gz_bridge", 76 | executable="parameter_bridge", 77 | arguments=[ 78 | '--ros-args', 79 | '-p', 80 | f'config_file:={bridge_params}', 81 | ] 82 | ) 83 | 84 | ros_gz_image_bridge = Node( 85 | package="ros_gz_image", 86 | executable="image_bridge", 87 | arguments=["/camera/image_raw"] 88 | ) 89 | 90 | rviz = Node( 91 | package='rviz2', 92 | executable='rviz2', 93 | name='rviz2', 94 | output='screen', 95 | arguments=['-d', rviz_config_path] 96 | ) 97 | 98 | return LaunchDescription([ 99 | node_robot_state_publisher, 100 | world_arg, 101 | gazebo, 102 | spawn_entity, 103 | controllers, 104 | joint_state_broadcaster, 105 | ros_gz_bridge, 106 | ros_gz_image_bridge, 107 | rviz 108 | ]) -------------------------------------------------------------------------------- /src/mobRobURDF_launch/launch/urdf_test.launch.py: -------------------------------------------------------------------------------- 1 | import os 2 | import launch 3 | import launch_ros.actions 4 | from ament_index_python.packages import get_package_share_directory 5 | from launch import LaunchDescription 6 | from launch.actions import DeclareLaunchArgument 7 | from launch.substitutions import LaunchConfiguration 8 | 9 | 10 | def generate_launch_description(): 11 | # File paths for URDF and RViz configuration 12 | urdf_file = os.path.join(get_package_share_directory('mobRobURDF_description'), 'urdf', 'mobRob.urdf') 13 | rviz_config_file = os.path.join(get_package_share_directory('mobRobURDF_launch'), 'rviz', 'rviz_test.rviz') 14 | 15 | # Declare the launch argument for GUI visibility 16 | use_gui_arg = DeclareLaunchArgument('use_gui', default_value='True', description='Use joint state publisher GUI') 17 | 18 | # Joint State Publisher (GUI) node 19 | joint_state_publisher_gui_node = launch_ros.actions.Node( 20 | package='joint_state_publisher_gui', 21 | executable='joint_state_publisher_gui', 22 | name='joint_state_publisher_gui', 23 | condition=launch.conditions.IfCondition(LaunchConfiguration('use_gui')) 24 | ) 25 | 26 | # Robot State Publisher node 27 | robot_state_publisher_node = launch_ros.actions.Node( 28 | package='robot_state_publisher', 29 | executable='robot_state_publisher', 30 | name='robot_state_publisher', 31 | parameters=[{'robot_description': open(urdf_file).read()}] 32 | ) 33 | 34 | # RViz2 node with configuration file 35 | rviz2_node = launch_ros.actions.Node( 36 | package='rviz2', 37 | executable='rviz2', 38 | name='rviz2', 39 | output='screen', 40 | arguments=['-d', rviz_config_file] 41 | ) 42 | 43 | # Return the launch description with all the nodes and the launch argument 44 | return LaunchDescription([ 45 | use_gui_arg, 46 | joint_state_publisher_gui_node, 47 | robot_state_publisher_node, 48 | rviz2_node, 49 | ]) 50 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/mobRobURDF_launch/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_launch/mobRobURDF_launch/__init__.py -------------------------------------------------------------------------------- /src/mobRobURDF_launch/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mobRobURDF_launch 5 | 0.0.1 6 | Package for creating launch file for testing the generated URDF 7 | Ali Pahlevani 8 | MIT 9 | 10 | 11 | ament_copyright 12 | ament_flake8 13 | ament_pep257 14 | python3-pytest 15 | 16 | 17 | ament_python 18 | 19 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/resource/mobRobURDF_launch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_launch/resource/mobRobURDF_launch -------------------------------------------------------------------------------- /src/mobRobURDF_launch/rviz/rviz_gazebo_test.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz_common/Displays 3 | Help Height: 0 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | Splitter Ratio: 0.5 9 | Tree Height: 463 10 | - Class: rviz_common/Selection 11 | Name: Selection 12 | - Class: rviz_common/Tool Properties 13 | Expanded: 14 | - /2D Goal Pose1 15 | - /Publish Point1 16 | Name: Tool Properties 17 | Splitter Ratio: 0.5886790156364441 18 | - Class: rviz_common/Views 19 | Expanded: 20 | - /Current View1 21 | Name: Views 22 | Splitter Ratio: 0.5 23 | - Class: rviz_common/Time 24 | Experimental: false 25 | Name: Time 26 | SyncMode: 0 27 | SyncSource: "" 28 | Visualization Manager: 29 | Class: "" 30 | Displays: 31 | - Alpha: 0.5 32 | Cell Size: 1 33 | Class: rviz_default_plugins/Grid 34 | Color: 160; 160; 164 35 | Enabled: true 36 | Line Style: 37 | Line Width: 0.029999999329447746 38 | Value: Lines 39 | Name: Grid 40 | Normal Cell Count: 0 41 | Offset: 42 | X: 0 43 | Y: 0 44 | Z: 0 45 | Plane: XY 46 | Plane Cell Count: 10 47 | Reference Frame: 48 | Value: true 49 | - Alpha: 0.800000011920929 50 | Class: rviz_default_plugins/RobotModel 51 | Collision Enabled: false 52 | Description File: "" 53 | Description Source: Topic 54 | Description Topic: 55 | Depth: 5 56 | Durability Policy: Volatile 57 | History Policy: Keep Last 58 | Reliability Policy: Reliable 59 | Value: /robot_description 60 | Enabled: true 61 | Links: 62 | All Links Enabled: true 63 | Expand Joint Details: false 64 | Expand Link Details: false 65 | Expand Tree: false 66 | Link Tree Style: Links in Alphabetic Order 67 | base_link: 68 | Alpha: 1 69 | Show Axes: false 70 | Show Trail: false 71 | camera: 72 | Alpha: 1 73 | Show Axes: false 74 | Show Trail: false 75 | Value: true 76 | camera_optical: 77 | Alpha: 1 78 | Show Axes: false 79 | Show Trail: false 80 | chassis: 81 | Alpha: 1 82 | Show Axes: false 83 | Show Trail: false 84 | Value: true 85 | front_left_wheel: 86 | Alpha: 1 87 | Show Axes: false 88 | Show Trail: false 89 | Value: true 90 | front_right_wheel: 91 | Alpha: 1 92 | Show Axes: false 93 | Show Trail: false 94 | Value: true 95 | lidar: 96 | Alpha: 1 97 | Show Axes: false 98 | Show Trail: false 99 | Value: true 100 | rear_left_wheel: 101 | Alpha: 1 102 | Show Axes: false 103 | Show Trail: false 104 | Value: true 105 | rear_right_wheel: 106 | Alpha: 1 107 | Show Axes: false 108 | Show Trail: false 109 | Value: true 110 | Mass Properties: 111 | Inertia: false 112 | Mass: false 113 | Name: RobotModel 114 | TF Prefix: "" 115 | Update Interval: 0 116 | Value: true 117 | Visual Enabled: true 118 | - Class: rviz_default_plugins/TF 119 | Enabled: true 120 | Frame Timeout: 15 121 | Frames: 122 | All Enabled: false 123 | base_link: 124 | Value: true 125 | camera: 126 | Value: false 127 | camera_optical: 128 | Value: true 129 | chassis: 130 | Value: true 131 | front_left_wheel: 132 | Value: true 133 | front_right_wheel: 134 | Value: true 135 | lidar: 136 | Value: true 137 | odom: 138 | Value: true 139 | rear_left_wheel: 140 | Value: true 141 | rear_right_wheel: 142 | Value: true 143 | Marker Scale: 2.5 144 | Name: TF 145 | Show Arrows: true 146 | Show Axes: true 147 | Show Names: false 148 | Tree: 149 | odom: 150 | base_link: 151 | chassis: 152 | camera: 153 | camera_optical: 154 | {} 155 | front_left_wheel: 156 | {} 157 | front_right_wheel: 158 | {} 159 | lidar: 160 | {} 161 | rear_left_wheel: 162 | {} 163 | rear_right_wheel: 164 | {} 165 | Update Interval: 0 166 | Value: true 167 | - Class: rviz_default_plugins/Image 168 | Enabled: true 169 | Max Value: 1 170 | Median window: 5 171 | Min Value: 0 172 | Name: Image 173 | Normalize Range: true 174 | Topic: 175 | Depth: 5 176 | Durability Policy: Volatile 177 | History Policy: Keep Last 178 | Reliability Policy: Reliable 179 | Value: /camera/image_raw 180 | Value: true 181 | - Alpha: 1 182 | Autocompute Intensity Bounds: true 183 | Autocompute Value Bounds: 184 | Max Value: 10 185 | Min Value: -10 186 | Value: true 187 | Axis: Z 188 | Channel Name: intensity 189 | Class: rviz_default_plugins/LaserScan 190 | Color: 255; 255; 255 191 | Color Transformer: "" 192 | Decay Time: 0 193 | Enabled: true 194 | Invert Rainbow: false 195 | Max Color: 255; 255; 255 196 | Max Intensity: 4096 197 | Min Color: 0; 0; 0 198 | Min Intensity: 0 199 | Name: LaserScan 200 | Position Transformer: "" 201 | Selectable: true 202 | Size (Pixels): 3 203 | Size (m): 0.009999999776482582 204 | Style: Flat Squares 205 | Topic: 206 | Depth: 5 207 | Durability Policy: Volatile 208 | Filter size: 10 209 | History Policy: Keep Last 210 | Reliability Policy: Reliable 211 | Value: /scan 212 | Use Fixed Frame: true 213 | Use rainbow: true 214 | Value: true 215 | Enabled: true 216 | Global Options: 217 | Background Color: 48; 48; 48 218 | Fixed Frame: odom 219 | Frame Rate: 30 220 | Name: root 221 | Tools: 222 | - Class: rviz_default_plugins/Interact 223 | Hide Inactive Objects: true 224 | - Class: rviz_default_plugins/MoveCamera 225 | - Class: rviz_default_plugins/Select 226 | - Class: rviz_default_plugins/FocusCamera 227 | - Class: rviz_default_plugins/Measure 228 | Line color: 128; 128; 0 229 | - Class: rviz_default_plugins/SetInitialPose 230 | Covariance x: 0.25 231 | Covariance y: 0.25 232 | Covariance yaw: 0.06853891909122467 233 | Topic: 234 | Depth: 5 235 | Durability Policy: Volatile 236 | History Policy: Keep Last 237 | Reliability Policy: Reliable 238 | Value: /initialpose 239 | - Class: rviz_default_plugins/SetGoal 240 | Topic: 241 | Depth: 5 242 | Durability Policy: Volatile 243 | History Policy: Keep Last 244 | Reliability Policy: Reliable 245 | Value: /goal_pose 246 | - Class: rviz_default_plugins/PublishPoint 247 | Single click: true 248 | Topic: 249 | Depth: 5 250 | Durability Policy: Volatile 251 | History Policy: Keep Last 252 | Reliability Policy: Reliable 253 | Value: /clicked_point 254 | Transformation: 255 | Current: 256 | Class: rviz_default_plugins/TF 257 | Value: true 258 | Views: 259 | Current: 260 | Class: rviz_default_plugins/Orbit 261 | Distance: 6.349802017211914 262 | Enable Stereo Rendering: 263 | Stereo Eye Separation: 0.05999999865889549 264 | Stereo Focal Distance: 1 265 | Swap Stereo Eyes: false 266 | Value: false 267 | Focal Point: 268 | X: 0.11272592842578888 269 | Y: 0.029559344053268433 270 | Z: 0.07974841445684433 271 | Focal Shape Fixed Size: true 272 | Focal Shape Size: 0.05000000074505806 273 | Invert Z Axis: false 274 | Name: Current View 275 | Near Clip Distance: 0.009999999776482582 276 | Pitch: 0.4947950839996338 277 | Target Frame: 278 | Value: Orbit (rviz) 279 | Yaw: 2.6054012775421143 280 | Saved: ~ 281 | Window Geometry: 282 | Displays: 283 | collapsed: false 284 | Height: 1016 285 | Hide Left Dock: false 286 | Hide Right Dock: true 287 | Image: 288 | collapsed: false 289 | QMainWindow State: 000000ff00000000fd0000000400000000000001940000035afc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d0000020c000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d006100670065010000024f000001480000002800ffffff000000010000010f0000035afc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d0000035a000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073a0000003efc0100000002fb0000000800540069006d006501000000000000073a000002fb00fffffffb0000000800540069006d00650100000000000004500000000000000000000005a00000035a00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 290 | Selection: 291 | collapsed: false 292 | Time: 293 | collapsed: false 294 | Tool Properties: 295 | collapsed: false 296 | Views: 297 | collapsed: true 298 | Width: 1850 299 | X: 70 300 | Y: 27 301 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/rviz/rviz_test.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 | - /RobotModel1 10 | - /TF1 11 | Splitter Ratio: 0.5 12 | Tree Height: 696 13 | - Class: rviz_common/Selection 14 | Name: Selection 15 | - Class: rviz_common/Tool Properties 16 | Expanded: 17 | - /2D Goal Pose1 18 | - /Publish Point1 19 | Name: Tool Properties 20 | Splitter Ratio: 0.5886790156364441 21 | - Class: rviz_common/Views 22 | Expanded: 23 | - /Current View1 24 | Name: Views 25 | Splitter Ratio: 0.5 26 | - Class: rviz_common/Time 27 | Experimental: false 28 | Name: Time 29 | SyncMode: 0 30 | SyncSource: "" 31 | Visualization Manager: 32 | Class: "" 33 | Displays: 34 | - Alpha: 0.5 35 | Cell Size: 1 36 | Class: rviz_default_plugins/Grid 37 | Color: 160; 160; 164 38 | Enabled: true 39 | Line Style: 40 | Line Width: 0.029999999329447746 41 | Value: Lines 42 | Name: Grid 43 | Normal Cell Count: 0 44 | Offset: 45 | X: 0 46 | Y: 0 47 | Z: 0 48 | Plane: XY 49 | Plane Cell Count: 10 50 | Reference Frame: 51 | Value: true 52 | - Alpha: 0.800000011920929 53 | Class: rviz_default_plugins/RobotModel 54 | Collision Enabled: false 55 | Description File: "" 56 | Description Source: Topic 57 | Description Topic: 58 | Depth: 5 59 | Durability Policy: Volatile 60 | History Policy: Keep Last 61 | Reliability Policy: Reliable 62 | Value: /robot_description 63 | Enabled: true 64 | Links: 65 | All Links Enabled: true 66 | Expand Joint Details: false 67 | Expand Link Details: false 68 | Expand Tree: false 69 | Link Tree Style: Links in Alphabetic Order 70 | base_link: 71 | Alpha: 1 72 | Show Axes: false 73 | Show Trail: false 74 | camera: 75 | Alpha: 1 76 | Show Axes: false 77 | Show Trail: false 78 | Value: true 79 | camera_optical: 80 | Alpha: 1 81 | Show Axes: false 82 | Show Trail: false 83 | chassis: 84 | Alpha: 1 85 | Show Axes: false 86 | Show Trail: false 87 | Value: true 88 | front_left_wheel: 89 | Alpha: 1 90 | Show Axes: false 91 | Show Trail: false 92 | Value: true 93 | front_right_wheel: 94 | Alpha: 1 95 | Show Axes: false 96 | Show Trail: false 97 | Value: true 98 | lidar: 99 | Alpha: 1 100 | Show Axes: false 101 | Show Trail: false 102 | Value: true 103 | rear_left_wheel: 104 | Alpha: 1 105 | Show Axes: false 106 | Show Trail: false 107 | Value: true 108 | rear_right_wheel: 109 | Alpha: 1 110 | Show Axes: false 111 | Show Trail: false 112 | Value: true 113 | Mass Properties: 114 | Inertia: false 115 | Mass: false 116 | Name: RobotModel 117 | TF Prefix: "" 118 | Update Interval: 0 119 | Value: true 120 | Visual Enabled: true 121 | - Class: rviz_default_plugins/TF 122 | Enabled: true 123 | Frame Timeout: 15 124 | Frames: 125 | All Enabled: false 126 | base_link: 127 | Value: true 128 | camera: 129 | Value: false 130 | camera_optical: 131 | Value: true 132 | chassis: 133 | Value: true 134 | front_left_wheel: 135 | Value: true 136 | front_right_wheel: 137 | Value: true 138 | lidar: 139 | Value: true 140 | rear_left_wheel: 141 | Value: true 142 | rear_right_wheel: 143 | Value: true 144 | Marker Scale: 1 145 | Name: TF 146 | Show Arrows: true 147 | Show Axes: true 148 | Show Names: false 149 | Tree: 150 | base_link: 151 | chassis: 152 | camera: 153 | camera_optical: 154 | {} 155 | front_left_wheel: 156 | {} 157 | front_right_wheel: 158 | {} 159 | lidar: 160 | {} 161 | rear_left_wheel: 162 | {} 163 | rear_right_wheel: 164 | {} 165 | Update Interval: 0 166 | Value: true 167 | Enabled: true 168 | Global Options: 169 | Background Color: 48; 48; 48 170 | Fixed Frame: base_link 171 | Frame Rate: 30 172 | Name: root 173 | Tools: 174 | - Class: rviz_default_plugins/Interact 175 | Hide Inactive Objects: true 176 | - Class: rviz_default_plugins/MoveCamera 177 | - Class: rviz_default_plugins/Select 178 | - Class: rviz_default_plugins/FocusCamera 179 | - Class: rviz_default_plugins/Measure 180 | Line color: 128; 128; 0 181 | - Class: rviz_default_plugins/SetInitialPose 182 | Covariance x: 0.25 183 | Covariance y: 0.25 184 | Covariance yaw: 0.06853891909122467 185 | Topic: 186 | Depth: 5 187 | Durability Policy: Volatile 188 | History Policy: Keep Last 189 | Reliability Policy: Reliable 190 | Value: /initialpose 191 | - Class: rviz_default_plugins/SetGoal 192 | Topic: 193 | Depth: 5 194 | Durability Policy: Volatile 195 | History Policy: Keep Last 196 | Reliability Policy: Reliable 197 | Value: /goal_pose 198 | - Class: rviz_default_plugins/PublishPoint 199 | Single click: true 200 | Topic: 201 | Depth: 5 202 | Durability Policy: Volatile 203 | History Policy: Keep Last 204 | Reliability Policy: Reliable 205 | Value: /clicked_point 206 | Transformation: 207 | Current: 208 | Class: rviz_default_plugins/TF 209 | Value: true 210 | Views: 211 | Current: 212 | Class: rviz_default_plugins/Orbit 213 | Distance: 2.7399492263793945 214 | Enable Stereo Rendering: 215 | Stereo Eye Separation: 0.05999999865889549 216 | Stereo Focal Distance: 1 217 | Swap Stereo Eyes: false 218 | Value: false 219 | Focal Point: 220 | X: 0.08230569958686829 221 | Y: -0.04210767149925232 222 | Z: -0.10552318394184113 223 | Focal Shape Fixed Size: true 224 | Focal Shape Size: 0.05000000074505806 225 | Invert Z Axis: false 226 | Name: Current View 227 | Near Clip Distance: 0.009999999776482582 228 | Pitch: 0.4997950792312622 229 | Target Frame: 230 | Value: Orbit (rviz) 231 | Yaw: 1.1653926372528076 232 | Saved: ~ 233 | Window Geometry: 234 | Displays: 235 | collapsed: false 236 | Height: 987 237 | Hide Left Dock: false 238 | Hide Right Dock: false 239 | QMainWindow State: 000000ff00000000fd00000004000000000000015600000341fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b00000341000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000341fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b00000341000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007740000003efc0100000002fb0000000800540069006d00650100000000000007740000025300fffffffb0000000800540069006d00650100000000000004500000000000000000000005030000034100000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 240 | Selection: 241 | collapsed: false 242 | Time: 243 | collapsed: false 244 | Tool Properties: 245 | collapsed: false 246 | Views: 247 | collapsed: false 248 | Width: 1908 249 | X: 0 250 | Y: 0 251 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/mobRobURDF_launch 3 | [install] 4 | install_scripts=$base/lib/mobRobURDF_launch 5 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import find_packages, setup 2 | 3 | package_name = 'mobRobURDF_launch' 4 | 5 | setup( 6 | name=package_name, 7 | version='0.0.0', 8 | packages=find_packages(exclude=['test']), 9 | data_files=[ 10 | ('share/ament_index/resource_index/packages', ['resource/' + package_name]), 11 | ('share/' + package_name, ['package.xml']), 12 | ('share/' + package_name + '/launch', ['launch/gazebo_test.launch.py']), 13 | ('share/' + package_name + '/launch', ['launch/urdf_test.launch.py']), 14 | ('share/' + package_name + '/rviz', ['rviz/rviz_gazebo_test.rviz']), 15 | ('share/' + package_name + '/rviz', ['rviz/rviz_test.rviz']), 16 | ], 17 | install_requires=['setuptools'], 18 | zip_safe=True, 19 | maintainer='Ali Pahlevani', 20 | maintainer_email='a.pahlevani1998@gmail.com', 21 | description='Package for creating launch file for testing the generated URDF', 22 | license='MIT', 23 | tests_require=['pytest'], 24 | entry_points={ 25 | 'console_scripts': [], 26 | }, 27 | ) 28 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /src/mobRobURDF_launch/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/control_types/ackermann.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/control_types/ackermann.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/control_types/diff_2wc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/control_types/diff_2wc.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/control_types/diff_4w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/control_types/diff_4w.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/control_types/mecanum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/control_types/mecanum.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/control_types/triSteer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/control_types/triSteer.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/control_types/tricycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/control_types/tricycle.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/future_features/control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/future_features/control.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/future_features/gazebo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/future_features/gazebo.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/future_features/navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/future_features/navigation.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/future_features/object_tracking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/future_features/object_tracking.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/future_features/slam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/future_features/slam.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/robot_types/2wc_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/robot_types/2wc_preview.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/robot_types/3w_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/robot_types/3w_preview.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/robot_types/4w_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/robot_types/4w_preview.png -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/images/welcome.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/images/welcome.gif -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/RobotWizard.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import logging 5 | from PyQt5.QtWidgets import (QVBoxLayout, QHBoxLayout, QWidget, QApplication, QWizard, QListWidget) 6 | from PyQt5.QtGui import QFont 7 | from PyQt5.QtCore import Qt 8 | from OpenGL.GL import * 9 | from OpenGL.GLUT import * 10 | from OpenGL.GLU import * 11 | 12 | # Custom page classes 13 | try: 14 | from mobRobURDF_wizard.classes.pages.WelcomePage import WelcomePage 15 | from mobRobURDF_wizard.classes.pages.RobotTypeSelectionPage import RobotTypeSelectionPage 16 | from mobRobURDF_wizard.classes.pages.ControlConfigurationPage import ControlConfigurationPage 17 | from mobRobURDF_wizard.classes.pages.ConfigurationPage import ConfigurationPage 18 | from mobRobURDF_wizard.classes.pages.FutureFeaturesPage import FutureFeaturesPage 19 | from mobRobURDF_wizard.classes.URDFManager import URDFManager 20 | except ImportError as e: 21 | print(f"Error importing modules: {e}") 22 | sys.exit(1) 23 | 24 | class RobotWizard(QWizard): 25 | def __init__(self): 26 | super().__init__() 27 | self.setWindowFlags(Qt.Window | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint) 28 | self.setWindowTitle("Mobile Robot URDF Maker Wizard (v3)") 29 | self.setFixedSize(1800, 900) 30 | 31 | try: 32 | self.urdf_manager = URDFManager() 33 | except Exception as e: 34 | #logging.error(f"Failed to initialize URDFManager: {e}") 35 | raise 36 | 37 | self.nav_list = QListWidget() 38 | self.nav_list.addItems(["Welcome", "Select Robot Type", "Select Controller", "Configure Parameters", "Future Features"]) 39 | self.nav_list.setFixedWidth(270) 40 | self.nav_list.setFixedHeight(500) 41 | self.nav_list.setStyleSheet(""" 42 | QListWidget { 43 | background-color: #2E2E2E; 44 | color: #FFFFFF; 45 | border: 1px solid #555555; 46 | padding: 5px; 47 | } 48 | QListWidget::item { 49 | padding: 10px; 50 | font-size: 16pt; 51 | font-weight: bold; 52 | } 53 | QListWidget::item:selected { 54 | background-color: #4A90E2; 55 | color: #FFFFFF; 56 | } 57 | QListWidget::item:hover { 58 | background-color: #666666; 59 | } 60 | """) 61 | font = QFont("Arial", 16, QFont.Bold) 62 | self.nav_list.setFont(font) 63 | self.nav_list.setCurrentRow(0) 64 | 65 | self.nav_list.itemClicked.connect(self.navigate_to_page) 66 | 67 | try: 68 | self.addPage(WelcomePage()) 69 | self.addPage(RobotTypeSelectionPage()) 70 | self.addPage(ControlConfigurationPage()) 71 | self.addPage(ConfigurationPage(self.urdf_manager)) 72 | self.addPage(FutureFeaturesPage()) 73 | except Exception as e: 74 | #logging.error(f"Failed to add pages: {e}") 75 | raise 76 | 77 | main_widget = QWidget() 78 | main_layout = QHBoxLayout() 79 | nav_layout = QVBoxLayout() 80 | nav_layout.addWidget(self.nav_list) 81 | nav_layout.addStretch() 82 | main_layout.addLayout(nav_layout) 83 | main_layout.addStretch() 84 | main_widget.setLayout(main_layout) 85 | self.setSideWidget(main_widget) 86 | 87 | self.currentIdChanged.connect(self.update_navigation) 88 | #logging.debug("RobotWizard initialized") 89 | 90 | def update_navigation(self, page_id): 91 | page_index = self.pageIds().index(page_id) 92 | if self.nav_list.currentRow() != page_index: 93 | self.nav_list.setCurrentRow(page_index) 94 | #logging.debug(f"Page ID changed to: {page_id}") 95 | 96 | def navigate_to_page(self, item): 97 | page_names = ["Welcome", "Select Robot Type", "Select Controller", "Configure Parameters", "Future Features"] 98 | target_index = page_names.index(item.text()) 99 | current_index = self.pageIds().index(self.currentId()) 100 | 101 | while current_index < target_index: 102 | self.next() 103 | current_index += 1 104 | while current_index > target_index: 105 | self.back() 106 | current_index -= 1 107 | 108 | #logging.debug(f"Navigated to page: {item.text()} (Index: {target_index})") 109 | 110 | def main(): 111 | glutInit(sys.argv) 112 | #logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") 113 | app = QApplication(sys.argv) 114 | wizard = RobotWizard() 115 | wizard.show() 116 | sys.exit(app.exec_()) 117 | 118 | if __name__ == '__main__': 119 | main() -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/mobRobURDF_wizard/__init__.py -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/classes/OpenGLWidget.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * 2 | from OpenGL.GLUT import * 3 | from OpenGL.GLU import * 4 | import numpy as np 5 | from PyQt5.QtOpenGL import QGLWidget 6 | from PyQt5.QtCore import Qt 7 | import logging 8 | 9 | # Class for 3D Preview 10 | class OpenGLWidget(QGLWidget): 11 | def __init__(self, parent=None): 12 | super(OpenGLWidget, self).__init__(parent) 13 | self.setFocusPolicy(Qt.StrongFocus) 14 | self.setMouseTracking(True) 15 | self.zoom = -5 16 | self.rotation = np.identity(4, dtype=np.float32) 17 | self.lastPos3D = None 18 | self.L, self.W, self.H = 1.2, 0.8, 0.3 19 | self.wheel_radius, self.wheel_width = 0.22, 0.12 20 | self.lidar_radius, self.lidar_height = 0.1, 0.08 21 | self.camera_size = (0.08, 0.2, 0.08) 22 | self.chassis_color = (0.5, 0.5, 0.5) 23 | self.wheel_color = (0.0, 0.0, 0.0) 24 | self.lidar_color = (1.0, 0.0, 0.0) 25 | self.camera_color = (0.0, 0.0, 1.0) 26 | self.robot_type = "4_wheeled" # Default 27 | #logging.debug("OpenGLWidget initialized") 28 | 29 | def initializeGL(self): 30 | glEnable(GL_DEPTH_TEST) 31 | glClearColor(0.7, 0.7, 0.7, 1.0) 32 | #logging.debug("OpenGL initialized") 33 | 34 | def resizeGL(self, w, h): 35 | glViewport(0, 0, w, h) 36 | glMatrixMode(GL_PROJECTION) 37 | glLoadIdentity() 38 | gluPerspective(45, w / h if h != 0 else 1, 0.1, 100.0) 39 | glMatrixMode(GL_MODELVIEW) 40 | 41 | def paintGL(self): 42 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 43 | glLoadIdentity() 44 | glTranslatef(0.0, 0.0, self.zoom) 45 | glMultMatrixf(self.rotation.T) 46 | 47 | # Draw chassis 48 | glPushMatrix() 49 | glColor3f(*self.chassis_color) 50 | glScalef(self.L, self.W, self.H) 51 | glutSolidCube(1.0) 52 | glPopMatrix() 53 | 54 | # Draw wheels based on robot type 55 | glColor3f(*self.wheel_color) 56 | if self.robot_type == "4_wheeled": 57 | wheel_positions = [ 58 | (self.L / 2 - self.wheel_radius / 1.5, self.W / 2 + self.wheel_width / 2, -self.H / 2), # Front left 59 | (self.L / 2 - self.wheel_radius / 1.5, -self.W / 2 - self.wheel_width / 2, -self.H / 2), # Front right 60 | (-self.L / 2 + self.wheel_radius / 1.5, self.W / 2 + self.wheel_width / 2, -self.H / 2), # Rear left 61 | (-self.L / 2 + self.wheel_radius / 1.5, -self.W / 2 - self.wheel_width / 2, -self.H / 2), # Rear right 62 | ] 63 | for pos in wheel_positions: 64 | glPushMatrix() 65 | glTranslatef(*pos) 66 | glRotatef(90, 1, 0, 0) 67 | glTranslatef(0, 0, -self.wheel_width / 2) 68 | glutSolidCylinder(self.wheel_radius, self.wheel_width, 20, 20) 69 | glPopMatrix() 70 | elif self.robot_type == "3_wheeled": 71 | wheel_positions = [ 72 | (self.L / 2, 0, -self.H / 2), # Front wheel (centered) 73 | (-self.L / 2 + self.wheel_radius / 1.5, self.W / 2 + self.wheel_width / 2, -self.H / 2), # Rear left 74 | (-self.L / 2 + self.wheel_radius / 1.5, -self.W / 2 - self.wheel_width / 2, -self.H / 2), # Rear right 75 | ] 76 | for pos in wheel_positions: 77 | glPushMatrix() 78 | glTranslatef(*pos) 79 | glRotatef(90, 1, 0, 0) 80 | glTranslatef(0, 0, -self.wheel_width / 2) 81 | glutSolidCylinder(self.wheel_radius, self.wheel_width, 20, 20) 82 | glPopMatrix() 83 | elif self.robot_type == "2_wheeled_caster": 84 | wheel_positions = [ 85 | (-self.L / 4, self.W / 2 + self.wheel_width / 2, -self.H / 2), # Left wheel 86 | (-self.L / 4, -self.W / 2 - self.wheel_width / 2, -self.H / 2), # Right wheel 87 | ] 88 | for pos in wheel_positions: 89 | glPushMatrix() 90 | glTranslatef(*pos) 91 | glRotatef(90, 1, 0, 0) 92 | glTranslatef(0, 0, -self.wheel_width / 2) 93 | glutSolidCylinder(self.wheel_radius, self.wheel_width, 20, 20) 94 | glPopMatrix() 95 | # Caster wheel as a sphere, using wheel_radius 96 | glPushMatrix() 97 | glTranslatef(self.L / 2 - self.wheel_radius, 0, -self.H / 2) 98 | glutSolidSphere(self.wheel_radius, 20, 20) # Changed to wheel_radius 99 | glPopMatrix() 100 | 101 | # Draw lidar 102 | glColor3f(*self.lidar_color) 103 | glPushMatrix() 104 | glTranslatef(0.0, 0.0, self.H / 2) 105 | glutSolidCylinder(self.lidar_radius, self.lidar_height, 20, 20) 106 | glPopMatrix() 107 | 108 | # Draw camera 109 | glColor3f(*self.camera_color) 110 | glPushMatrix() 111 | 112 | if self.robot_type == "3_wheeled": 113 | glTranslatef(self.L / 2 + self.camera_size[0] / 2, 0.0, self.H / 2 - self.camera_size[2] / 2) 114 | else: 115 | glTranslatef(self.L / 2 + self.camera_size[0] / 2, 0.0, 0.0) 116 | 117 | glScalef(*self.camera_size) 118 | glutSolidCube(1.0) 119 | glPopMatrix() 120 | 121 | def _map_to_sphere(self, x, y): 122 | width, height = self.width(), self.height() 123 | if width <= 0 or height <= 0: 124 | return np.array([0.0, 0.0, 0.0], dtype=np.float32) 125 | nx = (2.0 * x - width) / width 126 | ny = (height - 2.0 * y) / height 127 | length2 = nx * nx + ny * ny 128 | if length2 > 1.0: 129 | norm = 1.0 / np.sqrt(length2) 130 | return np.array([nx * norm, ny * norm, 0.0], dtype=np.float32) 131 | return np.array([nx, ny, np.sqrt(1.0 - length2)], dtype=np.float32) 132 | 133 | def mousePressEvent(self, event): 134 | self.lastPos3D = self._map_to_sphere(event.x(), event.y()) 135 | 136 | def mouseMoveEvent(self, event): 137 | if not (event.buttons() & Qt.LeftButton): 138 | return 139 | currentPos3D = self._map_to_sphere(event.x(), event.y()) 140 | if self.lastPos3D is None or np.array(self.lastPos3D).size != 3: 141 | self.lastPos3D = currentPos3D 142 | return 143 | axis = np.cross(self.lastPos3D, currentPos3D) 144 | dot = np.clip(np.dot(self.lastPos3D, currentPos3D), -1.0, 1.0) 145 | angle = np.arccos(dot) 146 | if np.linalg.norm(axis) > 1e-5: 147 | axis /= np.linalg.norm(axis) 148 | c, s = np.cos(angle), np.sin(angle) 149 | t = 1 - c 150 | ax, ay, az = axis 151 | R = np.array([ 152 | [t*ax*ax + c, t*ax*ay - s*az, t*ax*az + s*ay, 0], 153 | [t*ax*ay + s*az, t*ay*ay + c, t*ay*az - s*ax, 0], 154 | [t*ax*az - s*ay, t*ay*az + s*ax, t*az*az + c, 0], 155 | [0, 0, 0, 1] 156 | ], dtype=np.float32) 157 | self.rotation = R @ self.rotation 158 | self.lastPos3D = currentPos3D 159 | self.update() 160 | 161 | def wheelEvent(self, event): 162 | self.zoom += event.angleDelta().y() / 120 * 0.5 163 | self.update() 164 | 165 | def updateRobotModel(self, L, W, H, wheel_radius, wheel_width, lidar_radius, lidar_height, camera_size, 166 | chassis_color, wheel_color, lidar_color, camera_color, robot_type="4_wheeled", caster_radius=None): 167 | try: 168 | self.L, self.W, self.H = L, W, H 169 | self.wheel_radius = float(wheel_radius) 170 | self.wheel_width = float(wheel_width) 171 | self.lidar_radius = float(lidar_radius) 172 | self.lidar_height = float(lidar_height) 173 | self.camera_size = tuple(map(float, camera_size.split())) 174 | self.chassis_color = chassis_color 175 | self.wheel_color = wheel_color 176 | self.lidar_color = lidar_color 177 | self.camera_color = camera_color 178 | self.robot_type = robot_type 179 | # Caster radius defaults to wheel_radius for consistency 180 | self.caster_radius = self.wheel_radius if robot_type == "2_wheeled_caster" else float(caster_radius) if caster_radius is not None else self.wheel_radius 181 | #logging.debug(f"Updated robot model: type={self.robot_type}, wheel_radius={self.wheel_radius}, caster_radius={self.caster_radius}") 182 | self.update() 183 | except ValueError as e: 184 | logging.error(f"Error updating robot model parameters: {str(e)}") -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/classes/pages/ControlConfigurationPage.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from PyQt5.QtWidgets import (QWizardPage, QPushButton, QLabel, QHBoxLayout, QVBoxLayout, QFrame, QWidget) 4 | from PyQt5.QtCore import Qt, pyqtSignal 5 | from PyQt5.QtGui import QPixmap 6 | from ament_index_python.packages import get_package_share_directory 7 | 8 | class ControlConfigurationPage(QWizardPage): 9 | controllerTypeChanged = pyqtSignal() 10 | 11 | def __init__(self, parent=None): 12 | super().__init__(parent) 13 | self.setTitle("Select Controller Type") 14 | self.registerField("controllerType*", self, property="controllerType", changedSignal=self.controllerTypeChanged) 15 | self._controller_type = None 16 | self._robot_type = None 17 | 18 | self.image_dir = os.path.join(get_package_share_directory("mobRobURDF_wizard"), "images", "control_types") 19 | #logging.debug(f"Control image directory set to: {self.image_dir}") 20 | 21 | self.controllers = [ 22 | ("Differential (2WC)", "diff_2wc", "2_wheeled_caster"), 23 | ("Tricycle", "tricycle", "3_wheeled"), 24 | ("Tricycle Steer", "triSteer", "3_wheeled"), 25 | ("Differential (4W)", "diff_4w", "4_wheeled"), 26 | ("Mecanum", "mecanum", "4_wheeled"), 27 | ("Ackermann", "ackermann", "4_wheeled"), 28 | ] 29 | 30 | self.buttons = {} 31 | self.labels = {} 32 | self.base_button_style = """ 33 | QPushButton { 34 | background-color: #4A90E2; 35 | color: white; 36 | font-size: 14pt; 37 | font-weight: bold; 38 | font-family: "Segoe UI"; 39 | padding: 8px; 40 | border-radius: 6px; 41 | border: 2px solid #357ABD; 42 | } 43 | QPushButton:hover { 44 | background-color: #66B3FF; 45 | } 46 | QPushButton:pressed { 47 | background-color: #2E7DB2; 48 | } 49 | """ 50 | self.selected_button_style = """ 51 | QPushButton { 52 | background-color: #28A745; 53 | color: white; 54 | font-size: 16pt; 55 | font-weight: bold; 56 | font-family: "Segoe UI"; 57 | padding: 8px; 58 | border-radius: 6px; 59 | border: 2px solid #218838; 60 | } 61 | QPushButton:hover { 62 | background-color: #34C759; 63 | } 64 | QPushButton:pressed { 65 | background-color: #1E7E34; 66 | } 67 | """ 68 | self.disabled_button_style = """ 69 | QPushButton { 70 | background-color: #666666; 71 | color: #AAAAAA; 72 | font-size: 14pt; 73 | font-weight: bold; 74 | font-family: "Segoe UI"; 75 | padding: 8px; 76 | border-radius: 6px; 77 | border: 2px solid #555555; 78 | } 79 | """ 80 | self.image_style = """ 81 | QLabel { 82 | border: 1px solid #CCCCCC; 83 | border-radius: 5px; 84 | background-color: #F5F5F5; 85 | padding: 5px; 86 | } 87 | """ 88 | self.disabled_image_style = """ 89 | QLabel { 90 | border: 1px solid #999999; 91 | border-radius: 5px; 92 | background-color: #D3D3D3; 93 | padding: 5px; 94 | opacity: 0.5; 95 | } 96 | """ 97 | 98 | main_layout = QVBoxLayout() 99 | row1_layout = QHBoxLayout() 100 | row2_layout = QHBoxLayout() 101 | 102 | for i, (name, controller_id, robot_type) in enumerate(self.controllers): 103 | btn = QPushButton(name) 104 | self.buttons[controller_id] = btn 105 | btn.setStyleSheet(self.base_button_style) 106 | label = QLabel() 107 | label.setFixedSize(200, 250) 108 | self.load_image(label, os.path.join(self.image_dir, f"{controller_id}.png")) 109 | label.setStyleSheet(self.image_style) 110 | self.labels[controller_id] = label 111 | 112 | section_layout = QVBoxLayout() 113 | section_layout.addStretch(1) 114 | section_layout.addWidget(btn, alignment=Qt.AlignCenter) 115 | section_layout.addSpacing(30) 116 | section_layout.addWidget(label, alignment=Qt.AlignCenter) 117 | section_layout.addStretch(1) 118 | 119 | frame = QFrame() 120 | frame.setLayout(section_layout) 121 | frame.setStyleSheet("QFrame { background-color: #FFFFFF; border: 1px solid #E0E0E0; border-radius: 10px; padding: 32px; }") 122 | 123 | if i < 3: 124 | row1_layout.addWidget(frame) 125 | else: 126 | row2_layout.addWidget(frame) 127 | 128 | btn.clicked.connect(lambda _, cid=controller_id: self.set_controller_type(cid)) 129 | 130 | row1_layout.setSpacing(20) 131 | row2_layout.setSpacing(20) 132 | main_layout.addLayout(row1_layout) 133 | main_layout.addLayout(row2_layout) 134 | main_layout.addStretch() 135 | 136 | main_widget = QWidget() 137 | main_widget.setLayout(main_layout) 138 | main_widget.setStyleSheet("background-color: #F0F4F8;") 139 | self.setLayout(QVBoxLayout()) 140 | self.layout().addWidget(main_widget) 141 | 142 | def initializePage(self): 143 | self._robot_type = self.field("robotType") 144 | value = self.field("controllerType") 145 | if value is not None and value != self._controller_type: 146 | self._controller_type = value 147 | self.set_controller_type(value) # Update button styles 148 | #logging.debug(f"ControlConfigurationPage initialized with robotType: {self._robot_type}, controllerType: {self._controller_type}") 149 | self.update_controller_availability() 150 | 151 | def update_controller_availability(self): 152 | for controller_id, btn in self.buttons.items(): 153 | controller_robot_type = next(c[2] for c in self.controllers if c[1] == controller_id) 154 | is_enabled = controller_robot_type == self._robot_type 155 | btn.setEnabled(is_enabled) 156 | btn.setStyleSheet(self.disabled_button_style if not is_enabled else self.base_button_style) 157 | self.labels[controller_id].setStyleSheet(self.disabled_image_style if not is_enabled else self.image_style) 158 | 159 | def set_controller_type(self, value): 160 | if not self.buttons[value].isEnabled(): 161 | return 162 | self.setField("controllerType", value) 163 | self._controller_type = value 164 | self.controllerTypeChanged.emit() 165 | if self._controller_type != value: 166 | self.completeChanged.emit() # Update Next button state only if changed 167 | #logging.debug(f"Set controllerType to: {self.field('controllerType')}") 168 | 169 | for controller_id, btn in self.buttons.items(): 170 | if btn.isEnabled(): 171 | btn.setStyleSheet(self.base_button_style if controller_id != value else self.selected_button_style) 172 | else: 173 | btn.setStyleSheet(self.disabled_button_style) 174 | 175 | def controllerType(self): 176 | return self._controller_type 177 | 178 | def setControllerType(self, value): 179 | #logging.debug(f"QWizard setting controllerType to: {value}") 180 | self._controller_type = value 181 | self.controllerTypeChanged.emit() 182 | 183 | def load_image(self, label, image_path): 184 | pixmap = QPixmap(image_path) 185 | if not pixmap.isNull(): 186 | label.setPixmap(pixmap.scaled(label.size(), Qt.KeepAspectRatio)) 187 | #logging.debug(f"Loaded control image: {image_path}") 188 | else: 189 | label.setText("Image Not Found") 190 | #logging.warning(f"Failed to load control image: {image_path}") 191 | 192 | def isComplete(self): 193 | return self._controller_type is not None -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/classes/pages/FutureFeaturesPage.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from PyQt5.QtWidgets import (QWizardPage, QVBoxLayout, QHBoxLayout, QLabel, QWidget) 4 | from PyQt5.QtCore import Qt 5 | from PyQt5.QtGui import QPixmap 6 | from ament_index_python.packages import get_package_share_directory 7 | 8 | # Future Features Page 9 | class FutureFeaturesPage(QWizardPage): 10 | def __init__(self, parent=None): 11 | super().__init__(parent) 12 | self.setTitle("Future Features") 13 | 14 | self.image_dir = os.path.join(get_package_share_directory("mobRobURDF_wizard"), "images", "future_features") 15 | #logging.debug(f"Image directory set to: {self.image_dir}") 16 | 17 | features = [ 18 | #("Gazebo", os.path.join(self.image_dir, "gazebo.png")), 19 | #("Control", os.path.join(self.image_dir, "control.png")), 20 | ("SLAM", os.path.join(self.image_dir, "slam.png")), 21 | ("Navigation", os.path.join(self.image_dir, "navigation.png")), 22 | ("Obj. Tracking", os.path.join(self.image_dir, "object_tracking.png")), 23 | ] 24 | 25 | # Main layout: Vertical stack of feature rows 26 | main_layout = QVBoxLayout() 27 | main_layout.setSpacing(140) # Space between rows (prev: 40) 28 | 29 | for feature_name, image_path in features: 30 | # Feature name label (centered text) 31 | feature_label = QLabel(feature_name) 32 | feature_label.setStyleSheet(""" 33 | font-size: 36pt; 34 | font-weight: bold; 35 | font-family: "Segoe UI"; 36 | color: #8B0000; 37 | padding: 10px; 38 | background-color: #FFFFFF; 39 | border: 1px solid #E0E0E0; 40 | border-radius: 5px; 41 | """) 42 | feature_label.setFixedWidth(500) #(prev: 240) 43 | feature_label.setAlignment(Qt.AlignCenter) # Center text horizontally and vertically 44 | 45 | # Image label 46 | image_label = QLabel() 47 | pixmap = QPixmap(image_path) 48 | if not pixmap.isNull(): 49 | image_label.setPixmap(pixmap.scaled(900, 150)) # Qt.KeepAspectRatio 50 | #logging.debug(f"Loaded image for {feature_name}: {image_path}") 51 | else: 52 | image_label.setText(f"{feature_name} Image Not Found") 53 | #logging.warning(f"Failed to load image for {feature_name}: {image_path}") 54 | image_label.setStyleSheet(""" 55 | border: 2px solid #4A90E2; 56 | border-radius: 10px; 57 | background-color: #F5F5F5; 58 | padding: 5px; 59 | """) 60 | 61 | # Row layout: Name at start, image centered exactly 62 | feature_row = QHBoxLayout() 63 | feature_row.addWidget(feature_label) # Name at the start (left) 64 | feature_row.addStretch(2) # Stretch to push image toward center 65 | feature_row.addWidget(image_label, alignment=Qt.AlignCenter) # Image centered 66 | feature_row.addStretch(2) # Stretch to balance centering 67 | feature_row.setSpacing(15) # Space between name and image 68 | 69 | # Wrap row in a widget for styling 70 | row_widget = QWidget() 71 | row_widget.setLayout(feature_row) 72 | row_widget.setStyleSheet(""" 73 | background-color: #FFFFFF; 74 | border: 1px solid #E0E0E0; 75 | border-radius: 8px; 76 | padding: 10px; 77 | """) 78 | # Hover effect 79 | row_widget.setProperty("class", "feature-row") 80 | row_widget.setStyleSheet(row_widget.styleSheet() + """ 81 | .feature-row:hover { 82 | background-color: #F0F4F8; 83 | border: 1px solid #4A90E2; 84 | } 85 | """) 86 | 87 | main_layout.addWidget(row_widget) 88 | 89 | main_layout.addStretch() # Center the rows vertically 90 | self.setLayout(main_layout) 91 | self.setStyleSheet("background-color: #F0F4F8;") # Light blue-gray page background 92 | #logging.debug("FutureFeaturesPage initialized") -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/classes/pages/RobotTypeSelectionPage.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from PyQt5.QtWidgets import (QWizardPage, QPushButton, QLabel, QHBoxLayout, QVBoxLayout, QFrame, QWidget) 4 | from ament_index_python.packages import get_package_share_directory 5 | from PyQt5.QtCore import Qt, pyqtSignal 6 | from PyQt5.QtGui import QPixmap 7 | 8 | class RobotTypeSelectionPage(QWizardPage): 9 | robotTypeChanged = pyqtSignal() # Define the custom signal 10 | 11 | def __init__(self, parent=None): 12 | super().__init__(parent) 13 | self.setTitle("Select Robot Type") 14 | 15 | # Register the field with a property and signal 16 | self.registerField("robotType*", self, property="robotType", changedSignal=self.robotTypeChanged) 17 | self._robot_type = None # Internal storage for the field 18 | 19 | # Image directory 20 | self.image_dir = os.path.join(get_package_share_directory("mobRobURDF_wizard"), "images", "robot_types") 21 | #logging.debug(f"Image directory set to: {self.image_dir}") 22 | 23 | # Define the three robot options with styled buttons 24 | self.btn_4w = QPushButton("4-Wheeled Robot") 25 | self.btn_3w = QPushButton("3-Wheeled Robot (Tricycle)") 26 | self.btn_2wc = QPushButton("2-Wheeled Robot with Caster") 27 | 28 | # Base button style (unselected state) 29 | self.base_button_style = """ 30 | QPushButton { 31 | background-color: #4A90E2; /* Bright blue */ 32 | color: white; 33 | font-size: 16pt; 34 | font-weight: bold; 35 | font-family: "Segoe UI"; 36 | padding: 10px; 37 | border-radius: 8px; 38 | border: 2px solid #357ABD; /* Darker blue border */ 39 | } 40 | QPushButton:hover { 41 | background-color: #66B3FF; /* Lighter blue on hover */ 42 | } 43 | QPushButton:pressed { 44 | background-color: #2E7DB2; /* Darker blue when pressed */ 45 | } 46 | """ 47 | # Selected button style (green) 48 | self.selected_button_style = """ 49 | QPushButton { 50 | background-color: #28A745; /* Green */ 51 | color: white; 52 | font-size: 18pt; 53 | font-weight: bold; 54 | font-family: "Segoe UI"; 55 | padding: 10px; 56 | border-radius: 8px; 57 | border: 2px solid #218838; /* Darker green border */ 58 | } 59 | QPushButton:hover { 60 | background-color: #34C759; /* Lighter green on hover */ 61 | } 62 | QPushButton:pressed { 63 | background-color: #1E7E34; /* Darker green when pressed */ 64 | } 65 | """ 66 | 67 | # Apply initial base style to all buttons 68 | self.btn_4w.setStyleSheet(self.base_button_style) 69 | self.btn_3w.setStyleSheet(self.base_button_style) 70 | self.btn_2wc.setStyleSheet(self.base_button_style) 71 | 72 | # Create framed labels for each robot type's image 73 | self.label_4w = QLabel() 74 | self.label_4w.setFixedSize(420, 400) 75 | self.load_image(self.label_4w, os.path.join(self.image_dir, "4w_preview.png")) 76 | 77 | self.label_3w = QLabel() 78 | self.label_3w.setFixedSize(420, 400) 79 | self.load_image(self.label_3w, os.path.join(self.image_dir, "3w_preview.png")) 80 | 81 | self.label_2wc = QLabel() 82 | self.label_2wc.setFixedSize(420, 400) 83 | self.load_image(self.label_2wc, os.path.join(self.image_dir, "2wc_preview.png")) 84 | 85 | # Style image labels with a subtle frame 86 | image_style = """ 87 | QLabel { 88 | border: 1px solid #CCCCCC; /* Light gray border */ 89 | border-radius: 5px; /* Slightly rounded */ 90 | background-color: #F5F5F5; /* Light gray background */ 91 | padding: 5px; /* Inner padding for frame effect */ 92 | } 93 | """ 94 | self.label_4w.setStyleSheet(image_style) 95 | self.label_3w.setStyleSheet(image_style) 96 | self.label_2wc.setStyleSheet(image_style) 97 | 98 | # Connect buttons to set robot type 99 | self.btn_4w.clicked.connect(lambda: self.set_robot_type("4_wheeled")) 100 | self.btn_3w.clicked.connect(lambda: self.set_robot_type("3_wheeled")) 101 | self.btn_2wc.clicked.connect(lambda: self.set_robot_type("2_wheeled_caster")) 102 | 103 | # Main layout: Three horizontal sections with frames 104 | main_layout = QHBoxLayout() 105 | main_layout.setSpacing(20) # Space between sections 106 | 107 | # Section 1: 4-Wheeled Robot 108 | section_4w = QVBoxLayout() 109 | section_4w.addStretch(1) # Stretch above to center content vertically 110 | section_4w.addWidget(self.btn_4w, alignment=Qt.AlignCenter) 111 | section_4w.addSpacing(80) # Adjustable distance between name and image 112 | section_4w.addWidget(self.label_4w, alignment=Qt.AlignCenter) 113 | section_4w.addStretch(1) # Stretch below to center content vertically 114 | 115 | frame_4w = QFrame() 116 | frame_4w.setLayout(section_4w) 117 | frame_4w.setStyleSheet("QFrame { background-color: #FFFFFF; border: 1px solid #E0E0E0; border-radius: 10px; padding: 10px; }") 118 | main_layout.addWidget(frame_4w) 119 | 120 | # Section 2: 3-Wheeled Robot (Tricycle) 121 | section_3w = QVBoxLayout() 122 | section_3w.addStretch(1) 123 | section_3w.addWidget(self.btn_3w, alignment=Qt.AlignCenter) 124 | section_3w.addSpacing(80) 125 | section_3w.addWidget(self.label_3w, alignment=Qt.AlignCenter) 126 | section_3w.addStretch(1) 127 | 128 | frame_3w = QFrame() 129 | frame_3w.setLayout(section_3w) 130 | frame_3w.setStyleSheet("QFrame { background-color: #FFFFFF; border: 1px solid #E0E0E0; border-radius: 10px; padding: 10px; }") 131 | main_layout.addWidget(frame_3w) 132 | 133 | # Section 3: 2-Wheeled Robot with Caster 134 | section_2wc = QVBoxLayout() 135 | section_2wc.addStretch(1) 136 | section_2wc.addWidget(self.btn_2wc, alignment=Qt.AlignCenter) 137 | section_2wc.addSpacing(80) 138 | section_2wc.addWidget(self.label_2wc, alignment=Qt.AlignCenter) 139 | section_2wc.addStretch(1) 140 | 141 | frame_2wc = QFrame() 142 | frame_2wc.setLayout(section_2wc) 143 | frame_2wc.setStyleSheet("QFrame { background-color: #FFFFFF; border: 1px solid #E0E0E0; border-radius: 10px; padding: 10px; }") 144 | main_layout.addWidget(frame_2wc) 145 | 146 | # Set the main layout with background styling 147 | main_widget = QWidget() 148 | main_widget.setLayout(main_layout) 149 | main_widget.setStyleSheet("background-color: #F0F4F8;") # Light blue-gray background for the page 150 | self.setLayout(QVBoxLayout()) 151 | self.layout().addWidget(main_widget) 152 | 153 | def initializePage(self): 154 | value = self.field("robotType") 155 | if value is not None and value != self._robot_type: 156 | self._robot_type = value 157 | self.set_robot_type(value) # Update button styles 158 | #logging.debug(f"RobotTypeSelectionPage initialized with robotType: {self._robot_type}") 159 | 160 | def set_robot_type(self, value): 161 | """Set the robot type and update button styles.""" 162 | self.setField("robotType", value) # Update the wizard's field 163 | self._robot_type = value # Sync local variable 164 | self.robotTypeChanged.emit() # Emit custom signal 165 | if self._robot_type != value: 166 | self.completeChanged.emit() # Update Next button state only if changed 167 | #logging.debug(f"Set robotType to: {self.field('robotType')}") 168 | 169 | # Reset all buttons to base style 170 | self.btn_4w.setStyleSheet(self.base_button_style) 171 | self.btn_3w.setStyleSheet(self.base_button_style) 172 | self.btn_2wc.setStyleSheet(self.base_button_style) 173 | 174 | # Set the selected button to green 175 | if value == "4_wheeled": 176 | self.btn_4w.setStyleSheet(self.selected_button_style) 177 | elif value == "3_wheeled": 178 | self.btn_3w.setStyleSheet(self.selected_button_style) 179 | elif value == "2_wheeled_caster": 180 | self.btn_2wc.setStyleSheet(self.selected_button_style) 181 | 182 | def robotType(self): 183 | return self._robot_type 184 | 185 | def setRobotType(self, value): 186 | #logging.debug(f"QWizard setting robotType to: {value}") 187 | self._robot_type = value 188 | self.robotTypeChanged.emit() 189 | 190 | def load_image(self, label, image_path): 191 | """Load an image into a QLabel with error handling.""" 192 | pixmap = QPixmap(image_path) 193 | if not pixmap.isNull(): 194 | label.setPixmap(pixmap.scaled(label.size(), Qt.KeepAspectRatio)) 195 | #logging.debug(f"Loaded image: {image_path}") 196 | else: 197 | label.setText("Image Not Found") 198 | #logging.warning(f"Failed to load image: {image_path}") 199 | 200 | def isComplete(self): 201 | return self._robot_type is not None -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/classes/pages/WelcomePage.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from PyQt5.QtWidgets import (QWizardPage, QVBoxLayout, QLabel) 4 | from ament_index_python.packages import get_package_share_directory 5 | from PyQt5.QtCore import Qt 6 | from PyQt5.QtGui import QMovie, QFont 7 | 8 | # Welcome Page 9 | class WelcomePage(QWizardPage): 10 | def __init__(self, parent=None): 11 | super().__init__(parent) 12 | self.setTitle("") 13 | 14 | # Title label 15 | title_label = QLabel("Welcome to the 'Mobile Robot URDF Maker' Wizard!") 16 | title_label.setStyleSheet(""" 17 | font-size: 28pt; /* Larger font size */ 18 | font-weight: bold; /* Bold text */ 19 | color: #DC143C; /* Dark gray color */ 20 | """) 21 | title_label.setFont(QFont("Segoe UI", 28, QFont.Bold)) 22 | title_label.setAlignment(Qt.AlignCenter) # Center horizontally 23 | 24 | # GIF label: No fixed size, adapts to window 25 | self.gif_label = QLabel(self) 26 | 27 | self.image_dir = os.path.join(get_package_share_directory("mobRobURDF_wizard"), "images") 28 | gif_path = os.path.join(self.image_dir, "welcome.gif") 29 | #logging.debug(f"Attempting to load GIF from: {gif_path}") 30 | 31 | self.movie = QMovie(gif_path) 32 | if self.movie.isValid(): 33 | self.gif_label.setMovie(self.movie) 34 | self.movie.start() 35 | self.gif_label.setAlignment(Qt.AlignCenter) # Center GIF horizontally 36 | self.gif_label.setScaledContents(True) # Allow scaling with widget size 37 | #logging.debug("GIF loaded and animation started") 38 | else: 39 | self.gif_label.setText("Welcome GIF not found") 40 | self.gif_label.setAlignment(Qt.AlignCenter) 41 | #logging.warning(f"Failed to load welcome.gif from {gif_path}") 42 | 43 | # Layout: Stack title and GIF vertically, centered 44 | layout = QVBoxLayout() 45 | layout.addStretch(1) # Push content toward the middle 46 | layout.addWidget(title_label, alignment=Qt.AlignHCenter) # Center title horizontally 47 | layout.addWidget(self.gif_label, alignment=Qt.AlignHCenter) # Center GIF horizontally 48 | layout.addStretch(1) # Balance with stretch below to center vertically 49 | 50 | # Page background styling 51 | self.setStyleSheet("background-color: #F0F4F8;") # Light blue-gray background 52 | 53 | self.setLayout(layout) 54 | 55 | def resizeEvent(self, event): 56 | """Adjust GIF size dynamically when the window is resized.""" 57 | super().resizeEvent(event) 58 | if self.movie.isValid(): 59 | # Scale GIF to fit the full smaller dimension of the window 60 | max_size = int(min(self.width(), self.height()) * 1.6) # Use 160% of smaller dimension 61 | original_size = self.movie.currentPixmap().size() # Get size of current frame 62 | scaled_size = original_size.scaled(max_size, max_size, Qt.KeepAspectRatio) 63 | self.movie.setScaledSize(scaled_size) 64 | self.gif_label.adjustSize() 65 | #logging.debug(f"Window resized to {self.width()}x{self.height()}, GIF adjusted") -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/mobRobURDF_wizard/utils/utils.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from string import Template 3 | import logging 4 | 5 | def render_template(template_path, params): 6 | """Render a template file with given parameters.""" 7 | try: 8 | with open(template_path, 'r') as f: 9 | tmpl = Template(f.read()) 10 | rendered = tmpl.safe_substitute(params) 11 | #logging.debug(f"Rendered template: {template_path}") 12 | return rendered 13 | except FileNotFoundError: 14 | #logging.error(f"Template file not found: {template_path}") 15 | return f"Error: Template file not found: {template_path}" 16 | except Exception as e: 17 | #logging.error(f"Error rendering template {template_path}: {str(e)}") 18 | return f"Error rendering template: {str(e)}" 19 | 20 | def generate_urdf(xacro_file): 21 | """Generate a URDF from a Xacro file using the xacro command.""" 22 | try: 23 | result = subprocess.run(['xacro', xacro_file], 24 | stdout=subprocess.PIPE, 25 | stderr=subprocess.PIPE, 26 | check=True, 27 | text=True) 28 | logging.debug(f"Generated URDF from: {xacro_file}") 29 | return result.stdout 30 | except subprocess.CalledProcessError as e: 31 | error_msg = f"Error generating URDF from {xacro_file}:\n{e.stderr}" 32 | #logging.error(error_msg) 33 | return error_msg 34 | except FileNotFoundError: 35 | error_msg = "Error: 'xacro' command not found. Ensure xacro is installed." 36 | #logging.error(error_msg) 37 | return error_msg 38 | except Exception as e: 39 | error_msg = f"Unexpected error generating URDF from {xacro_file}: {str(e)}" 40 | #logging.error(error_msg) 41 | return error_msg 42 | 43 | def get_color(color_name): 44 | """Map a color name to an RGB tuple.""" 45 | colors = { 46 | "Gray": (0.5, 0.5, 0.5), 47 | "Black": (0.0, 0.0, 0.0), 48 | "Red": (1.0, 0.0, 0.0), 49 | "Blue": (0.0, 0.0, 1.0), 50 | "Green": (0.0, 1.0, 0.0), 51 | "White": (1.0, 1.0, 1.0), 52 | } 53 | color = colors.get(color_name.capitalize(), (0.5, 0.5, 0.5)) 54 | #logging.debug(f"Color mapped: {color_name} -> {color}") 55 | return color -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mobRobURDF_wizard 5 | 0.0.1 6 | Package for generating URDF files with a GUI wizard 7 | Ali Pahlevani 8 | MIT 9 | 10 | 11 | ament_copyright 12 | ament_flake8 13 | ament_pep257 14 | python3-pytest 15 | 16 | 17 | ament_python 18 | 19 | -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/resource/mobRobURDF_wizard: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ali-pahlevani/Mobile_Robot_URDF_Maker/f276320e936e00fe8a7ea54fdc91e86a12f785d3/src/mobRobURDF_wizard/resource/mobRobURDF_wizard -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/setup.cfg: -------------------------------------------------------------------------------- 1 | [develop] 2 | script_dir=$base/lib/mobRobURDF_wizard 3 | [install] 4 | install_scripts=$base/lib/mobRobURDF_wizard 5 | -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import os 3 | from glob import glob 4 | 5 | package_name = 'mobRobURDF_wizard' 6 | 7 | setup( 8 | name=package_name, 9 | version='0.0.0', 10 | packages=[package_name], 11 | data_files=[ 12 | (os.path.join('share', 'ament_index', 'resource_index', 'packages'), [os.path.join('resource', package_name)]), 13 | (os.path.join('share', package_name), ['package.xml']), 14 | (os.path.join('share', package_name, 'images', 'future_features'), glob('images/future_features/*.png')), 15 | (os.path.join('share', package_name, 'images', 'robot_types'), glob('images/robot_types/*.png')), 16 | (os.path.join('share', package_name, 'images', 'control_types'), glob('images/control_types/*.png')), 17 | (os.path.join('share', package_name, 'images'), glob('images/*.gif')), 18 | ], 19 | install_requires=['setuptools'], 20 | zip_safe=True, 21 | maintainer='Ali Pahlevani', 22 | maintainer_email='a.pahlevani1998@gmail.com', 23 | description='Package for generating URDF files with a GUI wizard.', 24 | license='MIT', 25 | tests_require=['pytest'], 26 | entry_points={ 27 | 'console_scripts': [ 28 | 'mobRobURDF_wizard = mobRobURDF_wizard.RobotWizard:main', 29 | ], 30 | }, 31 | ) -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/test/test_copyright.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_copyright.main import main 16 | import pytest 17 | 18 | 19 | # Remove the `skip` decorator once the source file(s) have a copyright header 20 | @pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') 21 | @pytest.mark.copyright 22 | @pytest.mark.linter 23 | def test_copyright(): 24 | rc = main(argv=['.', 'test']) 25 | assert rc == 0, 'Found errors' 26 | -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/test/test_flake8.py: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_flake8.main import main_with_errors 16 | import pytest 17 | 18 | 19 | @pytest.mark.flake8 20 | @pytest.mark.linter 21 | def test_flake8(): 22 | rc, errors = main_with_errors(argv=[]) 23 | assert rc == 0, \ 24 | 'Found %d code style errors / warnings:\n' % len(errors) + \ 25 | '\n'.join(errors) 26 | -------------------------------------------------------------------------------- /src/mobRobURDF_wizard/test/test_pep257.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Open Source Robotics Foundation, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from ament_pep257.main import main 16 | import pytest 17 | 18 | 19 | @pytest.mark.linter 20 | @pytest.mark.pep257 21 | def test_pep257(): 22 | rc = main(argv=['.', 'test']) 23 | assert rc == 0, 'Found code style errors / warnings' 24 | --------------------------------------------------------------------------------