├── .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 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------