├── insert_sdf.txt ├── arm_description.zip ├── arm_description ├── meshes │ ├── link1.STL │ ├── link2.STL │ ├── link3.STL │ ├── link4.STL │ ├── link5.STL │ ├── link6.STL │ ├── link7.STL │ ├── link8.STL │ └── base_link.STL ├── config │ └── joint_names_arm_description.yaml ├── CMakeLists.txt ├── launch │ ├── display.launch │ └── gazebo.launch ├── package.xml └── urdf │ ├── arm_description.csv │ └── arm_description.urdf ├── assets ├── image-20241221170805196.png ├── image-20241221170940960.png ├── image-20241221171227422.png ├── image-20241221171539556.png └── image-20241221172237859.png ├── insert_urdf.txt ├── LICENSE ├── README_CN.md ├── README.md └── dir_ros2.py /insert_sdf.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /arm_description.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description.zip -------------------------------------------------------------------------------- /arm_description/meshes/link1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link1.STL -------------------------------------------------------------------------------- /arm_description/meshes/link2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link2.STL -------------------------------------------------------------------------------- /arm_description/meshes/link3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link3.STL -------------------------------------------------------------------------------- /arm_description/meshes/link4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link4.STL -------------------------------------------------------------------------------- /arm_description/meshes/link5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link5.STL -------------------------------------------------------------------------------- /arm_description/meshes/link6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link6.STL -------------------------------------------------------------------------------- /arm_description/meshes/link7.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link7.STL -------------------------------------------------------------------------------- /arm_description/meshes/link8.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/link8.STL -------------------------------------------------------------------------------- /assets/image-20241221170805196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/assets/image-20241221170805196.png -------------------------------------------------------------------------------- /assets/image-20241221170940960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/assets/image-20241221170940960.png -------------------------------------------------------------------------------- /assets/image-20241221171227422.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/assets/image-20241221171227422.png -------------------------------------------------------------------------------- /assets/image-20241221171539556.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/assets/image-20241221171539556.png -------------------------------------------------------------------------------- /assets/image-20241221172237859.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/assets/image-20241221172237859.png -------------------------------------------------------------------------------- /arm_description/meshes/base_link.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fish1sheep/sw2urdf_ROS2/HEAD/arm_description/meshes/base_link.STL -------------------------------------------------------------------------------- /arm_description/config/joint_names_arm_description.yaml: -------------------------------------------------------------------------------- 1 | controller_joint_names: ['', 'joint1', 'joint2', 'joint3', 'joint4', 'joint5', 'joint6', 'joint7', 'joint8', ] 2 | -------------------------------------------------------------------------------- /insert_urdf.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /arm_description/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | 3 | project(arm_description) 4 | 5 | find_package(catkin REQUIRED) 6 | 7 | catkin_package() 8 | 9 | find_package(roslaunch) 10 | 11 | foreach(dir config launch meshes urdf) 12 | install(DIRECTORY ${dir}/ 13 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/${dir}) 14 | endforeach(dir) 15 | -------------------------------------------------------------------------------- /arm_description/launch/display.launch: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 11 | 15 | 20 | -------------------------------------------------------------------------------- /arm_description/launch/gazebo.launch: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 15 | 20 | -------------------------------------------------------------------------------- /arm_description/package.xml: -------------------------------------------------------------------------------- 1 | 2 | arm_description 3 | 1.0.0 4 | 5 |

URDF Description package for arm_description

6 |

This package contains configuration data, 3D models and launch files 7 | for arm_description robot

8 |
9 | TODO 10 | 11 | BSD 12 | catkin 13 | roslaunch 14 | robot_state_publisher 15 | rviz 16 | joint_state_publisher_gui 17 | gazebo 18 | 19 | 20 | 21 |
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2025, Rob0tsheep 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # SW2URDF ROS2 2 | 3 | ## 环境配置 4 | 5 | 1. Ubuntu 6 | 3. ROS2 7 | 4. Gazebo11 8 | 5. gazebo_ros 9 | 6. robot_state_publisher 10 | 7. joint_state_publisher 11 | 12 | ## 安装依赖 13 | 14 | ```bash 15 | # install Gazebo and gazebo_ros 16 | sudo apt install gazebo && sudo apt install ros-$ROS_DISTRO-gazebo-ros-pkgs 17 | ``` 18 | 19 | 20 | 21 | ```bash 22 | # install robot_state_publisher and joint_state_publisher 23 | sudo apt install ros-$ROS_DISTRO-robot-state-publisher && sudo apt install ros-$ROS_DISTRO-joint-state-publisher 24 | ``` 25 | 26 | ## 工具说明 27 | 28 | 运行dir_ros2.py选择sw2urdf生成的目录,自动转化sw2urdf生成的目录为ROS2可用的功能包。 29 | 30 | 此功能包可以在**rviz2,gazebo**中显示模型。 31 | 32 | ## 必要设置 33 | 34 | 在insert_urdf.txt里设置base_footprint和base_link的几何关系 35 | 36 | ```xml 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | ``` 45 | 46 | ## 运行测试 47 | 48 | ### 转化目录 49 | 50 | 1. 运行dir_ros2.py 51 | 52 | ![image-20241221170805196](./assets/image-20241221170805196.png) 53 | 54 | 2. 选择你的sw2urdf生成的原始目录,注意先压缩一份备份,防止失败。 55 | 56 | ![image-20241221170940960](./assets/image-20241221170940960.png) 57 | 58 | 3. 要点进去这个目录,然后点击OK,等待完成即可。 59 | 60 | ![image-20241221171227422](./assets/image-20241221171227422.png) 61 | 62 | 4. 把转化后的目录放到ROS2工作空间的src目录下,colcon build然后source工作空间。 63 | 64 | ### rviz2 65 | 66 | 运行 **display.launch.py** launch文件 67 | 68 | > 注:arm_description目录为测试目标 69 | 70 | ```bash 71 | ros2 launch arm_description display.launch.py 72 | ``` 73 | 74 | 注意 75 | **fix_frame**选择 **base_footprint** 76 | 77 | **Description Topic**选择 **/robot_description** 78 | ![image-20241221171539556](./assets/image-20241221171539556.png) 79 | 80 | ### Gazebo 81 | 运行 **gazebo.launch.py** launch文件 82 | 83 | > 注:arm_description目录为测试目标 84 | 85 | ```bash 86 | ros2 launch arm_description gazebo.launch.py 87 | ``` 88 | 89 | ![image-20241221172237859](./assets/image-20241221172237859.png) 90 | 91 | 这里的效果是因为我没加控制器,但是模型加载没有问题 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SW2URDF ROS2 2 | **If you want to export ROS2 function packages directly in solidworks, please see this project https://github.com/fish1sheep/solidworks_urdf_exporter** (**But No Gazebo launch**) 3 | ## Environment Setup 4 | 5 | 1. Ubuntu 6 | 2. ROS2 7 | 3. Gazebo11 8 | 4. gazebo_ros 9 | 5. robot_state_publisher 10 | 6. joint_state_publisher 11 | 12 | ## Install Dependencies 13 | 14 | ```bash 15 | # Install Gazebo and gazebo_ros 16 | sudo apt install gazebo && sudo apt install ros-$ROS_DISTRO-gazebo-ros-pkgs 17 | ``` 18 | 19 | ```bash 20 | # Install robot_state_publisher and joint_state_publisher 21 | sudo apt install ros-$ROS_DISTRO-robot-state-publisher && sudo apt install ros-$ROS_DISTRO-joint-state-publisher 22 | ``` 23 | 24 | ## Tool Description 25 | 26 | Run `dir_ros2.py` to select the directory generated by sw2urdf. This will automatically convert the sw2urdf output directory into a ROS2-compatible package. 27 | 28 | The package can be visualized in **rviz2** and **gazebo**. 29 | 30 | ## Necessary Configuration 31 | 32 | Set the geometric relationship between `base_footprint` and `base_link` in the `insert_urdf.txt` file: 33 | 34 | ```xml 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ``` 43 | 44 | ## Running Test 45 | 46 | ### Convert Directory 47 | 48 | 1. Run `dir_ros2.py`. 49 | 50 | ![image-20241221170805196](./assets/image-20241221170805196.png) 51 | 52 | 1. Select the directory where sw2urdf was generated. Remember to back up the original directory before proceeding, in case of any issues. 53 | 54 | ![image-20241221170940960](./assets/image-20241221170940960.png) 55 | 56 | 1. Go into the directory, then click OK and wait for the conversion to complete. 57 | 58 | ![image-20241221171227422](./assets/image-20241221171227422.png) 59 | 60 | 1. Move the converted directory to the `src` folder of your ROS2 workspace. Run `colcon build` and source the workspace. 61 | 62 | ### rviz2 63 | 64 | Run the **display.launch.py** launch file 65 | 66 | > Note: The `arm_description` directory is used as an example. 67 | 68 | ```bash 69 | ros2 launch arm_description display.launch.py 70 | ``` 71 | 72 | Make sure to set the following: 73 | 74 | - **Fixed Frame**: Choose **base_footprint**. 75 | - **Description Topic**: Choose **/robot_description**. 76 | 77 | ![image-20241221171539556](./assets/image-20241221171539556.png) 78 | 79 | ### Gazebo 80 | 81 | Run the **gazebo.launch.py** launch file 82 | 83 | > Note: The `arm_description` directory is used as an example. 84 | 85 | ```bash 86 | ros2 launch arm_description gazebo.launch.py 87 | ``` 88 | 89 | ![image-20241221172237859](./assets/image-20241221172237859.png) 90 | 91 | In this case, the model is loaded correctly, but no controllers were added, so the behavior shown is due to the absence of control mechanisms. 92 | -------------------------------------------------------------------------------- /arm_description/urdf/arm_description.csv: -------------------------------------------------------------------------------- 1 | Link Name,Center of Mass X,Center of Mass Y,Center of Mass Z,Center of Mass Roll,Center of Mass Pitch,Center of Mass Yaw,Mass,Moment Ixx,Moment Ixy,Moment Ixz,Moment Iyy,Moment Iyz,Moment Izz,Visual X,Visual Y,Visual Z,Visual Roll,Visual Pitch,Visual Yaw,Mesh Filename,Color Red,Color Green,Color Blue,Color Alpha,Collision X,Collision Y,Collision Z,Collision Roll,Collision Pitch,Collision Yaw,Collision Mesh Filename,Material Name,SW Components,Coordinate System,Axis Name,Joint Name,Joint Type,Joint Origin X,Joint Origin Y,Joint Origin Z,Joint Origin Roll,Joint Origin Pitch,Joint Origin Yaw,Parent,Joint Axis X,Joint Axis Y,Joint Axis Z,Limit Effort,Limit Velocity,Limit Lower,Limit Upper,Calibration rising,Calibration falling,Dynamics Damping,Dynamics Friction,Safety Soft Upper,Safety Soft Lower,Safety K Position,Safety K Velocity 2 | base_link,0.00143969137250427,0.00143969137250421,0.00438777280701788,0,0,0,44.9190588648697,0.286002598339597,0.00628467784877577,-0.000280541255882245,0.286002598339597,-0.000280541255882233,0.522166428473919,0,0,0,0,0,0,package://arm_description/meshes/base_link.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/base_link.STL,,p1-1,Origin_global,,,,0,0,0,0,0,0,,0,0,0,,,,,,,,,,,, 3 | link1,-0.057075524192337,0.0829029144921835,0.00277681134891594,0,0,0,18.1477609595778,0.093812441089824,0.0713439095373798,0.00373913324318502,0.127557254087219,-0.00327157523451793,0.186836265570095,0,0,0,0,0,0,package://arm_description/meshes/link1.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link1.STL,,p2-1,Origin_joint1,Axis_joint1,joint1,continuous,0,0,0.05,1.5707963267949,0,-0.106786316106193,base_link,0,1,0,,,,,,,,,,,, 4 | link2,-0.140026146825609,0.0352923616875173,0.00812609460372782,0,0,0,7.18324748071002,0.00478738563697837,-0.000656938778811113,0.00136729920819372,0.140060678405665,0.000243185688554337,0.137440098674691,0,0,0,0,0,0,package://arm_description/meshes/link2.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link2.STL,,p3-1,Origin_joint2,Axis_joint2,joint2,continuous,-0.15,0.16,0,-1.5707963267949,0,-1.69396353495007,link1,0,1,0,,,,,,,,,,,, 5 | link3,0.0339570442163462,0.0385141208523814,-0.026153403400337,0,0,0,10.1219655479422,0.013852442854189,-0.00222927417346809,0.000634652869064411,0.0479561386819704,0.000970994342187811,0.0510153448606204,0,0,0,0,0,0,package://arm_description/meshes/link3.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link3.STL,,p4-1,Origin_joint3,Axis_joint3,joint3,continuous,-0.35,0,0,1.57079632678933,-1.44762911863972,-3.14159265358416,link2,0,0,1,,,,,,,,,,,, 6 | link4,-0.107629273657781,-1.96725968848455E-11,-3.96261912172235E-10,0,0,0,4.6846328248742,0.00425222907051563,-1.15223954333504E-12,-1.17247842077589E-10,0.0166762626633217,1.32397646512377E-09,0.0154642820527334,0,0,0,0,0,0,package://arm_description/meshes/link4.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link4.STL,,p5-2,Origin_joint4,Axis_joint4,joint4,continuous,0.191733844433853,0.0450000000000266,-0.0279999999997629,-3.14159265358975,0,-3.14159265358961,link3,1,0,0,,,,,,,,,,,, 7 | link5,-1.06137321154165E-13,-5.99520433297585E-15,0.0593911348979121,0,0,0,2.67314149540547,0.00301316183579177,3.55380738182177E-17,-4.47233396150271E-19,0.00299472549560383,1.24416924629023E-16,0.00178277119167584,0,0,0,0,0,0,package://arm_description/meshes/link5.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link5.STL,,p6-2,Origin_joint5,Axis_joint5,joint5,continuous,-0.166266155566159,0,0,3.1124527982526,1.57079630572147,-0.0291398553370043,link4,1,0,0,,,,,,,,,,,, 8 | link6,0.0254645564837129,-2.55351295663786E-15,0,0,0,0,0.599488074004664,0.000318150978567396,-2.04830878322425E-18,1.79570984817912E-19,0.000298478621868992,-1.81199056464057E-19,0.000248329231235005,0,0,0,0,0,0,package://arm_description/meshes/link6.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link6.STL,,P7-2,Origin_joint6,Axis_joint6,joint6,continuous,0,0,0.0947144555394169,3.14159265358979,-1.5707963267949,0,link5,1,0,0,,,,,,,,,,,, 9 | link7,7.12545567160827E-06,-0.0529959306902813,-0.0242856512691401,0,0,0,0.310349624397085,0.000423122555917328,2.95995593893583E-08,2.4103351774309E-08,6.53431315833532E-05,-0.000112596773524812,0.000373533620298053,0,0,0,0,0,0,package://arm_description/meshes/link7.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link7.STL,,p8-13,Origin_joint7,Axis_joint7,joint7,continuous,0.0425044303195282,0,0.0408095110958686,0.106786316106193,0,1.5707963267948,link6,1,0,0,,,,,,,,,,,, 10 | link8,7.12545567183032E-06,-0.0529959306902812,-0.0242856512691401,0,0,0,0.310349624397084,0.000423122555917325,2.9599559391305E-08,2.41033517749469E-08,6.53431315833555E-05,-0.000112596773524815,0.000373533620298048,0,0,0,0,0,0,package://arm_description/meshes/link8.STL,0.650980392156863,0.619607843137255,0.588235294117647,1,0,0,0,0,0,0,package://arm_description/meshes/link8.STL,,p8-14,Origin_joint8,Axis_joint8,joint8,continuous,0.0425044303195284,0,-0.0408095110958682,3.0348063374836,0,-1.570796326795,link6,1,0,0,,,,,,,,,,,, 11 | -------------------------------------------------------------------------------- /arm_description/urdf/arm_description.urdf: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 9 | 10 | 13 | 15 | 22 | 23 | 24 | 27 | 28 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 41 | 42 | 44 | 45 | 46 | 47 | 49 | 50 | 53 | 55 | 62 | 63 | 64 | 67 | 68 | 70 | 71 | 73 | 75 | 76 | 77 | 78 | 81 | 82 | 84 | 85 | 86 | 87 | 90 | 93 | 95 | 97 | 99 | 100 | 102 | 103 | 106 | 108 | 115 | 116 | 117 | 120 | 121 | 123 | 124 | 126 | 128 | 129 | 130 | 131 | 134 | 135 | 137 | 138 | 139 | 140 | 143 | 146 | 148 | 150 | 152 | 153 | 155 | 156 | 159 | 161 | 168 | 169 | 170 | 173 | 174 | 176 | 177 | 179 | 181 | 182 | 183 | 184 | 187 | 188 | 190 | 191 | 192 | 193 | 196 | 199 | 201 | 203 | 205 | 206 | 208 | 209 | 212 | 214 | 221 | 222 | 223 | 226 | 227 | 229 | 230 | 232 | 234 | 235 | 236 | 237 | 240 | 241 | 243 | 244 | 245 | 246 | 249 | 252 | 254 | 256 | 258 | 259 | 261 | 262 | 265 | 267 | 274 | 275 | 276 | 279 | 280 | 282 | 283 | 285 | 287 | 288 | 289 | 290 | 293 | 294 | 296 | 297 | 298 | 299 | 302 | 305 | 307 | 309 | 311 | 312 | 314 | 315 | 318 | 320 | 327 | 328 | 329 | 332 | 333 | 335 | 336 | 338 | 340 | 341 | 342 | 343 | 346 | 347 | 349 | 350 | 351 | 352 | 355 | 358 | 360 | 362 | 364 | 365 | 367 | 368 | 371 | 373 | 380 | 381 | 382 | 385 | 386 | 388 | 389 | 391 | 393 | 394 | 395 | 396 | 399 | 400 | 402 | 403 | 404 | 405 | 408 | 411 | 413 | 415 | 417 | 418 | 420 | 421 | 424 | 426 | 433 | 434 | 435 | 438 | 439 | 441 | 442 | 444 | 446 | 447 | 448 | 449 | 452 | 453 | 455 | 456 | 457 | 458 | 461 | 464 | 466 | 468 | 470 | 471 | -------------------------------------------------------------------------------- /dir_ros2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import tkinter as tk 4 | from tkinter import filedialog 5 | import subprocess 6 | 7 | # 1. Create tkinter root window 8 | root = tk.Tk() 9 | root.withdraw() # Hide the main window 10 | 11 | # 2. Open folder selection dialog to choose the target directory 12 | target_directory = filedialog.askdirectory(title="Select Target Directory") 13 | # Check if the selected directory is valid 14 | if not target_directory: 15 | print("No valid directory selected.") 16 | else: 17 | print(f"Selected directory: {target_directory}") 18 | 19 | # 3. Delete the 'launch' folder if it exists 20 | launch_folder = os.path.join(target_directory, 'launch') 21 | if os.path.exists(launch_folder) and os.path.isdir(launch_folder): 22 | try: 23 | shutil.rmtree(launch_folder) 24 | print("Successfully deleted the 'launch' folder.") 25 | except Exception as e: 26 | print(f"Error deleting 'launch' folder: {e}") 27 | else: 28 | print("'launch' folder does not exist.") 29 | 30 | # 4. Delete 'CMakeLists.txt' file if it exists 31 | cmake_file = os.path.join(target_directory, 'CMakeLists.txt') 32 | if os.path.exists(cmake_file) and os.path.isfile(cmake_file): 33 | try: 34 | os.remove(cmake_file) 35 | print("Successfully deleted the 'CMakeLists.txt' file.") 36 | except Exception as e: 37 | print(f"Error deleting 'CMakeLists.txt' file: {e}") 38 | else: 39 | print("'CMakeLists.txt' file does not exist.") 40 | 41 | # 5. Delete 'package.xml' file if it exists 42 | package_file = os.path.join(target_directory, 'package.xml') 43 | if os.path.exists(package_file) and os.path.isfile(package_file): 44 | try: 45 | os.remove(package_file) 46 | print("Successfully deleted the 'package.xml' file.") 47 | except Exception as e: 48 | print(f"Error deleting 'package.xml' file: {e}") 49 | else: 50 | print("'package.xml' file does not exist.") 51 | 52 | # 6. Create an empty 'launch' folder 53 | try: 54 | os.makedirs(launch_folder, exist_ok=True) 55 | print("Successfully created an empty 'launch' folder.") 56 | except Exception as e: 57 | print(f"Error creating 'launch' folder: {e}") 58 | 59 | # Get package_name (the name of the target directory) 60 | package_name = os.path.basename(target_directory) 61 | 62 | # 7. Create display.launch.py file content 63 | launch_content = f"""import os 64 | from launch import LaunchDescription 65 | from launch.actions import DeclareLaunchArgument 66 | from launch_ros.actions import Node 67 | from ament_index_python.packages import get_package_share_directory 68 | 69 | 70 | def generate_launch_description(): 71 | package_dir = get_package_share_directory('{package_name}') 72 | 73 | # URDF file path 74 | urdf_file = os.path.join(package_dir, 'urdf', '{package_name}.urdf') 75 | 76 | # Read URDF file content 77 | with open(urdf_file, 'r') as file: 78 | robot_description = file.read() 79 | 80 | # Create LaunchDescription 81 | return LaunchDescription([ 82 | 83 | # Declare urdf_file argument to allow external input 84 | DeclareLaunchArgument('urdf_file', default_value=urdf_file), 85 | 86 | # Launch joint_state_publisher_gui node 87 | Node( 88 | package='joint_state_publisher_gui', 89 | executable='joint_state_publisher_gui', 90 | name='joint_state_publisher_gui', 91 | output='screen' 92 | ), 93 | 94 | # Launch robot_state_publisher node with robot_description parameter 95 | Node( 96 | package='robot_state_publisher', 97 | executable='robot_state_publisher', 98 | name='robot_state_publisher', 99 | output='screen', 100 | parameters=[{{'robot_description': robot_description}}] 101 | ), 102 | 103 | # Launch rviz2 node with robot_description parameter 104 | Node( 105 | package='rviz2', 106 | executable='rviz2', 107 | name='rviz2', 108 | output='screen', 109 | parameters=[{{'robot_description': robot_description}}] 110 | ), 111 | ]) 112 | """ 113 | 114 | # Target file path: display.launch.py 115 | file_path = os.path.join(launch_folder, 'display.launch.py') 116 | 117 | # Write content to display.launch.py file 118 | try: 119 | with open(file_path, 'w', encoding='utf-8') as file: 120 | file.write(launch_content) 121 | print(f"Successfully saved 'display.launch.py' as: {file_path}") 122 | except Exception as e: 123 | print(f"Error writing to file: {e}") 124 | 125 | # 8. Create CMakeLists.txt file content 126 | cmake_content = f"""cmake_minimum_required(VERSION 3.8) 127 | project({package_name}) 128 | 129 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 130 | add_compile_options(-Wall -Wextra -Wpedantic) 131 | endif() 132 | 133 | # Find dependencies 134 | find_package(ament_cmake REQUIRED) 135 | find_package(rclcpp REQUIRED) 136 | find_package(robot_state_publisher REQUIRED) 137 | find_package(rviz2 REQUIRED) 138 | find_package(gazebo_ros REQUIRED) 139 | 140 | install(DIRECTORY launch config meshes urdf 141 | DESTINATION share/${{PROJECT_NAME}}) 142 | 143 | if(BUILD_TESTING) 144 | find_package(ament_lint_auto REQUIRED) 145 | # The following line skips the linter which checks for copyrights 146 | # Comment the line when a copyright and license is added to all source files 147 | set(ament_cmake_copyright_FOUND TRUE) 148 | # The following line skips cpplint (only works in a git repo) 149 | # Comment the line when this package is in a git repo and when 150 | # a copyright and license is added to all source files 151 | set(ament_cmake_cpplint_FOUND TRUE) 152 | ament_lint_auto_find_test_dependencies() 153 | endif() 154 | 155 | ament_package() 156 | """ 157 | 158 | # Target file path: CMakeLists.txt 159 | cmake_file_path = os.path.join(target_directory, 'CMakeLists.txt') 160 | 161 | # Write content to CMakeLists.txt file 162 | try: 163 | with open(cmake_file_path, 'w', encoding='utf-8') as file: 164 | file.write(cmake_content) 165 | print(f"Successfully saved 'CMakeLists.txt' as: {cmake_file_path}") 166 | except Exception as e: 167 | print(f"Error writing to file: {e}") 168 | 169 | # 9. Create package.xml file content 170 | xml_content = f""" 171 | 172 | 173 | {package_name} 174 | 0.0.0 175 | TODO: Package description 176 | robotsheep 177 | Apache-2.0 178 | 179 | ament_cmake 180 | 181 | rclcpp 182 | robot_state_publisher 183 | rviz2 184 | gazebo_ros 185 | 186 | ament_lint_auto 187 | ament_lint_common 188 | 189 | 190 | ament_cmake 191 | 192 | 193 | """ 194 | 195 | # Target file path: package.xml 196 | xml_file_path = os.path.join(target_directory, 'package.xml') 197 | 198 | # Write content to package.xml file 199 | try: 200 | with open(xml_file_path, 'w', encoding='utf-8') as file: 201 | file.write(xml_content) 202 | print(f"Successfully saved 'package.xml' as: {xml_file_path}") 203 | except Exception as e: 204 | print(f"Error writing to file: {e}") 205 | 206 | def insert_content_at_line(source_file, target_file, line_number): 207 | # Read content from source file 208 | with open(source_file, 'r', encoding='utf-8') as src: 209 | source_content = src.read() 210 | 211 | # Read target file content 212 | with open(target_file, 'r', encoding='utf-8') as tgt: 213 | target_lines = tgt.readlines() # Read lines from target file 214 | 215 | # Insert source content at the specified line 216 | # If the line number exceeds the number of lines in the target file, append the content to the end 217 | if line_number > len(target_lines): 218 | line_number = len(target_lines) 219 | 220 | target_lines.insert(line_number - 1, source_content + '\n') 221 | 222 | # Write modified content back to target file 223 | with open(target_file, 'w', encoding='utf-8') as tgt: 224 | tgt.writelines(target_lines) 225 | 226 | print( 227 | f"Content successfully inserted into {target_file} at line {line_number}") 228 | 229 | source_file = 'insert_urdf.txt' 230 | target_file = target_directory + '/urdf/' + \ 231 | os.path.basename(target_directory)+".urdf" 232 | line_number = 7 233 | 234 | insert_content_at_line(source_file, target_file, line_number) 235 | 236 | # File path 237 | file_path = target_file 238 | 239 | # Content to replace 240 | new_first_line = '''''' 241 | 242 | # Open the file for reading 243 | with open(file_path, 'r', encoding='utf-8') as file: 244 | lines = file.readlines() 245 | 246 | if lines: 247 | lines[0] = new_first_line + '\n' # Ensure newline is added 248 | 249 | # Write the modified content back to the file 250 | with open(file_path, 'w', encoding='utf-8') as file: 251 | file.writelines(lines) 252 | 253 | urdf_folder = os.path.join(target_directory, "urdf") 254 | command = f"gz sdf -p {target_file} > {urdf_folder}/model.sdf" 255 | subprocess.run(command, shell=True, check=True) 256 | 257 | source_file = 'insert_sdf.txt' 258 | target_file = target_directory + '/urdf/' + "model.sdf" 259 | line_number = 1 260 | 261 | insert_content_at_line(source_file, target_file, line_number) 262 | 263 | # Define file and target directory paths 264 | source_sdf_file = target_directory + '/urdf/' + "model.sdf" 265 | target_sdf_directory = os.path.join(os.path.expanduser( 266 | "~"), ".gazebo", "models", f"{os.path.basename(target_directory)}") 267 | 268 | # Check if target directory exists 269 | if not os.path.exists(target_sdf_directory): 270 | # If the directory does not exist, create it 271 | os.makedirs(target_sdf_directory) 272 | print(f"Directory {target_sdf_directory} created.") 273 | else: 274 | print(f"Directory {target_sdf_directory} already exists.") 275 | 276 | # Perform file copy operation 277 | target_path = os.path.join( 278 | target_sdf_directory, os.path.basename(source_sdf_file)) 279 | shutil.copy(source_sdf_file, target_sdf_directory) 280 | print(f"File {source_sdf_file} successfully copied to {target_sdf_directory}.") 281 | 282 | model_config_content = f""" 283 | 284 | 285 | {os.path.basename(target_directory)} 286 | 1.0 287 | model.sdf 288 | 289 | 290 | todo 291 | todo@todo.todo/email> 292 | 293 | 294 | 295 | sw2urdf ROS2 for gazebo11 296 | 297 | 298 | """ 299 | 300 | model_config_path = target_sdf_directory 301 | file_name = "model.config" 302 | file_path = os.path.join(model_config_path, file_name) 303 | try: 304 | with open(file_path, 'w', encoding='utf-8') as file: 305 | file.write(model_config_content) 306 | print(f"Successfully saved 'sdf.config' as: {model_config_path}") 307 | except Exception as e: 308 | print(f"Error writing to file: {e}") 309 | 310 | source_directory = target_directory+"/meshes" 311 | destination_directory = target_sdf_directory+"/meshes" 312 | 313 | if os.path.exists(destination_directory): 314 | print(f"Target directory {destination_directory} already exists!") 315 | else: 316 | shutil.copytree(source_directory, destination_directory) 317 | print(f"Directory {source_directory} successfully copied to {destination_directory}") 318 | 319 | source_directory = target_directory+"/textures" 320 | destination_directory = target_sdf_directory+"/materials/textures" 321 | 322 | if os.path.exists(destination_directory): 323 | print(f"Target directory {destination_directory} already exists!") 324 | else: 325 | shutil.copytree(source_directory, destination_directory) 326 | print(f"Directory {source_directory} successfully copied to {destination_directory}") 327 | 328 | file_path = os.path.join(target_directory, "urdf", "model.sdf") 329 | 330 | try: 331 | os.remove(file_path) # Delete file 332 | print(f"File {file_path} successfully deleted.") 333 | except FileNotFoundError: 334 | print(f"File {file_path} does not exist.") 335 | except PermissionError: 336 | print(f"No permission to delete file {file_path}.") 337 | except Exception as e: 338 | print(f"Error deleting file: {e}") 339 | 340 | # Gazebo launch file content 341 | gazebo_launch_content = f"""import launch 342 | import launch_ros 343 | from ament_index_python.packages import get_package_share_directory 344 | from launch.launch_description_sources import PythonLaunchDescriptionSource 345 | import os 346 | 347 | 348 | def generate_launch_description(): 349 | # Get default path 350 | robot_name_in_model = "{package_name}" 351 | urdf_tutorial_path = get_package_share_directory('{package_name}') 352 | default_model_path = os.path.join( 353 | urdf_tutorial_path, 'urdf', '{package_name}.urdf') 354 | 355 | # Read URDF file content 356 | with open(default_model_path, 'r') as urdf_file: 357 | robot_description = urdf_file.read() 358 | 359 | robot_state_publisher_node = launch_ros.actions.Node( 360 | package='robot_state_publisher', 361 | executable='robot_state_publisher', 362 | parameters=[{{'robot_description': robot_description}}] 363 | ) 364 | 365 | # Include another launch file for Gazebo 366 | launch_gazebo = launch.actions.IncludeLaunchDescription( 367 | PythonLaunchDescriptionSource([get_package_share_directory( 368 | 'gazebo_ros'), '/launch', '/gazebo.launch.py']), 369 | ) 370 | 371 | # Request Gazebo to spawn the robot 372 | spawn_entity_node = launch_ros.actions.Node( 373 | package='gazebo_ros', 374 | executable='spawn_entity.py', 375 | arguments=['-topic', '/robot_description', 376 | '-entity', robot_name_in_model]) 377 | 378 | return launch.LaunchDescription([ 379 | robot_state_publisher_node, 380 | launch_gazebo, 381 | spawn_entity_node 382 | ]) 383 | """ 384 | 385 | file_path = os.path.join(launch_folder, 'gazebo.launch.py') 386 | 387 | try: 388 | with open(file_path, 'w', encoding='utf-8') as file: 389 | file.write(gazebo_launch_content) 390 | print(f"Successfully saved 'gazebo.launch.py' as: {file_path}") 391 | except Exception as e: 392 | print(f"Error writing to file: {e}") 393 | --------------------------------------------------------------------------------