diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index eee652d2..e380311c 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -4,9 +4,9 @@ on: push: branches: - rolling - #schedule: - ## Run every morning to detect flakiness and broken dependencies - #- cron: '28 6 * * *' + schedule: + # Run every morning to detect flakiness and broken dependencies + - cron: '28 6 * * *' jobs: ci_binary: @@ -20,7 +20,6 @@ jobs: env: UPSTREAM_WORKSPACE: ros_team_workspace.repos steps: - - run: sudo apt-get update -qq && sudo apt-get upgrade - uses: actions/checkout@v1 - uses: 'ros-industrial/industrial_ci@master' env: ${{matrix.env}} diff --git a/.github/workflows/docs-sphinx-build-check.yml b/.github/workflows/docs-sphinx-build-check.yml index d592bc30..430bd51f 100644 --- a/.github/workflows/docs-sphinx-build-check.yml +++ b/.github/workflows/docs-sphinx-build-check.yml @@ -16,3 +16,4 @@ jobs: - uses: ammaraskar/sphinx-action@master with: docs-folder: 'docs/' + pre-build-command: "apt-get update -y && apt-get install -y python3-pip && pip3 install sphinx_rtd_theme" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..46d1af33 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,68 @@ +# Contributing Guidelines +Thank you for your interest in contributing to `ros_team_workspace`. +Whether it's a bug report, new feature, correction, or additional +documentation, we greatly value feedback and contributions from our community. + +Please read through this document before submitting any issues or pull requests to ensure we have all the necessary +information to effectively respond to your bug report or contribution. + + +## Reporting Bugs/Feature Requests +We welcome you to use the GitHub issue tracker to report bugs or suggest features. + +When filing an issue, please check [existing open][issues], or [recently closed][closed-issues], issues to make sure + somebody else hasn't already reported the issue. +Please try to include as much information as you can. Details like these are incredibly useful: + +* A reproducible test case or series of steps +* The version of our code being used +* Any modifications you've made relevant to the bug +* Anything unusual about your environment or deployment + + +## Contributing via Pull Requests +Contributions via pull requests are much appreciated. +Before sending us a pull request, please ensure that: + +1. You are working against the latest source on the *master* branch. +2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. +3. You open an issue to discuss any significant work - we would hate for your time to be wasted. + +To send us a pull request, please: + +1. Fork the repository. +2. Modify the source; please focus on the specific change you are contributing. + If you also reformat all the code, it will be hard for us to focus on your change. +3. Ensure local tests pass. +4. Commit to your fork using clear commit messages. +5. Send a pull request, answering any default questions in the pull request interface. +6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. + +GitHub provides additional documentation on [forking a repository](https://help.github.com/articles/fork-a-repo/) and +[creating a pull request](https://help.github.com/articles/creating-a-pull-request/). + + +## Finding contributions to work on +Looking at the existing issues is a great way to find something to contribute on. +As this project, by default, uses the default GitHub issue labels + (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'][help-wanted] issues + is a great place to start. + + +## Licensing +Any contribution that you make to this repository will be under the Apache 2 License, as dictated by that [license]: + +~~~ +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +~~~ + +[issues]: https://github.com/StoglRobotics/ros_team_workspace/issues +[closed-issues]: https://github.com/StoglRobotics/ros_team_workspace/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20 +[help-wanted]: https://github.com/StoglRobotics/ros_team_workspace/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22 +[license]: http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/docs/guidelines/package_structure.rst b/docs/guidelines/package_structure.rst index 86f220d8..6ec28f31 100644 --- a/docs/guidelines/package_structure.rst +++ b/docs/guidelines/package_structure.rst @@ -17,34 +17,46 @@ Here proposed architecture try to split the robot's files to minimize per-packag ├── [_[_]|_manipulators]/ # Meta-package of the robot │ ├── CMakeLists.txt │ └── package.xml - ├── _bringup/ # Launch and config files of the robot - │ ├── [CMakeLists.txt] + ├── _bringup/ # Launch and config files for starting the robot using ros2_control + │ ├── [CMakeLists.txt] # if ament_cmake is used (recommended) │ ├── package.xml - │ ├── [setup.py] + │ ├── [setup.py] # if amend_python is used + │ ├── [setup.cfg] # if amend_python is used │ ├── config/ - │ │ └── .yaml + │ │ ├── _controllers.yaml # Controllers' configuraiton for ros2_control + │ │ ├── _forward_position_publisher.yaml # Setup test publisher for forward position controller + │ │ └── _joint_trajectory_publisher.yaml # Setup test publisher for joint trajectory controller │ └── launch/ - │ └── .launch.py - ├── _description/ # Robot's description files - │ ├── [CMakeLists.txt] + │ ├── .launch.py # Robot's default launch file + │ ├── test_forward_position_controller.launch.py # Start test publisher for forward position controller + │ └── test_joint_trajectory_controller.launch.py # Start test publisher for joint trajectory controller + ├── _description/ # Robot's description files + │ ├── [CMakeLists.txt] # if ament_cmake is used (recommended) │ ├── package.xml - │ ├── [setup.py] - │ ├── config/ - │ │ └── - │ ├── meshes/ - │ │ └── collision - │ │ ├── .stl - │ │ └── ... + │ ├── [setup.py] # if amend_python is used + │ ├── [setup.cfg] # if amend_python is used + │ ├── config/ # general YAML files for a robot + │ │ └── _.yaml + │ ├── launch/ # launch files related to testing robots' description + │ │ └── test__description.launch.py + │ ├── meshes/ # meshes used in _macro.urdf.xacro + │ │ ├── collision + │ │ │ └── # meshes are sorted by robot name or model + │ │ │ ├── .stl + │ │ │ └── ... │ │ └── visual - │ │ ├── .dae - │ │ └── ... - │ ├── rviz/ + │ │ └── + │ │ ├── .dae + │ │ └── ... + │ ├── rviz/ # rviz display configurations │ │ └── _default.rviz - │ └── urdf/ - │ ├── .urdf.xacro - │ ├── _macro.ros2_control.xacro - │ └── _macro.xacro - └── _hardware_interface/ # Implementation of the ros2_control interface + │ └── urdf/ # URDF file for the robot + │ ├── common.xacro # Common XACRO definitions + │ ├── .urdf.xacro # Main URDF for a robot - loads macro and other files + │ └── + │ ├── _macro.xacro # Macro file of the robot - can add prefix, define origin, etc. + │ └── _macro.ros2_control.xacro # URDF-part used to configure ros2_control + └── _hardware_interface/ # Implementation of the ros2_control interface │ ├── CMakeLists.txt │ ├── package.xml │ ├── include/ diff --git a/docs/use-cases/create_setup_workspace.rst b/docs/use-cases/create_setup_workspace.rst index 1bd678fa..ca76aca1 100644 --- a/docs/use-cases/create_setup_workspace.rst +++ b/docs/use-cases/create_setup_workspace.rst @@ -1,4 +1,26 @@ -======================== -Create Setup Workspace -======================== +=========================== +Setup a new Workspace +=========================== +.. _uc-setup-workspace: + +This use-case describes how to setup a new ROS workspace using scripts from the ROS Team Workspace (RosTeamWS) framework. + +.. contents:: Table of Contents + :depth: 2 + + +Script for Creating Workspace +============================== + +`setup-ros-workspace.bash` accepts ros distro name workspace suffix and workspace folder as parameters. +All three parameters are optional. + +.. code-block:: bash + :caption: Usage of the script for setting up a new ROS workspace. + :name: setup-workspace + + setup-ros-workspace.bash ROS_DISTRO WS_SUFFIX WS_FOLDER + +The script creates... + diff --git a/docs/use-cases/setup_robot_bringup_package.rst b/docs/use-cases/setup_robot_bringup_package.rst new file mode 100644 index 00000000..856f35d3 --- /dev/null +++ b/docs/use-cases/setup_robot_bringup_package.rst @@ -0,0 +1,30 @@ +========================================== +Setup robot bringup +========================================== +.. _uc-setup-robot-bringup: + +This use-case describes how to set up a robot bringup package using scripts from ROS Team Workspace (RosTeamWS) framework. +The package follows as far as possible best practices for `robot support packages `_ from ROS-Industrial consortia. (**This has to be verified!**) + +.. contents:: Table of Contents + :depth: 2 + +Script for Setting up Description Package +============================================ + +``setup-robot-bringup.bash`` script accepts the robot name and, optionally, the package name. +If the package name is not set, it is guessed from the current path using the folder's name. +The script **has to be executed** from the folder where the bringup should be generated. + +**Note**: it is recomended to setup your package using :ref:`set-new-package.bash ` scritpt. + +The scripts copies template files from the ``templates/robot_bringup`` folder, rename the files, and replaces the placeholders. + +.. code-block:: bash + :caption: Usage of script for setting up the robot bringup. + :name: setup-robot-bringup + + setup-robot-bringup.bash ROBOT_NAME [PKG_NAME] + + +After all files are copied and placeholders set, a commit is automatically created. diff --git a/docs/use-cases/setup_robot_ros2_control_hardware.rst b/docs/use-cases/setup_robot_ros2_control_hardware.rst new file mode 100644 index 00000000..e28f2dec --- /dev/null +++ b/docs/use-cases/setup_robot_ros2_control_hardware.rst @@ -0,0 +1,33 @@ +======================================================= +Setup robot's ros2_control hardware package +======================================================= +.. _uc-setup-ros2-control-hardware: + +This use-case describes how to set up a robot's hardware interface for the ros2_control framework using scripts from ROS Team Workspace (RosTeamWS) framework. + +.. contents:: Table of Contents + :depth: 2 + +Script for Setting up ros2_control hardware package +==================================================== + +``setup-robot-ros2-control-hardware.bash`` script accepts the file name of the robot's hardware interfacea and, optionally, class name and the package name. +The file name should use standard ROS format . +A ``.cpp`` and ``.hpp`` files will added using this name. +If the class name is not set, it is guessed by camel-casing the file name. +If the package name is not set, it is guessed from the current path using the folder's name. +The script **has to be executed** from the folder where the package should be generated. + +**Note**: it is recomended to setup your package using :ref:`set-new-package.bash ` scritpt. + +The scripts copies template files from the ``templates/ros2_control/hardware`` folder, rename the files, and replaces the placeholders. +The scripts adds also a plugin description and simple test checking if the plugin can be loaded. + +.. code-block:: bash + :caption: Usage of script for setting up the robot bringup. + :name: setup-ros2-control-hardware + + setup-robot-ros2-control-hardware.bash FILE_NAME [CLASS_NAME] [PKG_NAME] + + +After all files are copied and placeholders set, a commit is automatically created. diff --git a/ros_team_workspace.repos b/ros_team_workspace.repos new file mode 100644 index 00000000..56f46b6f --- /dev/null +++ b/ros_team_workspace.repos @@ -0,0 +1 @@ +repositories: diff --git a/scripts/_RosTeamWs_Defines.bash b/scripts/_RosTeamWs_Defines.bash index 62ce5c44..24b67e59 100755 --- a/scripts/_RosTeamWs_Defines.bash +++ b/scripts/_RosTeamWs_Defines.bash @@ -40,8 +40,19 @@ setup_ros2_exports () { setup_ros2_aliases () { - alias cba="colcon build --symlink-install" - alias cbap="colcon build --symlink-install --packages-select" + alias cb="colcon build --symlink-install" + alias cbp="colcon build --symlink-install --packages-select" + alias cbup="colcon build --symlink-install --packages-up-to" + alias cbar="colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release" + + alias ct="colcon test" + alias ctp="colcon test --packages-select" + alias ctup="colcon test --packages-up-to" + + alias ctr="colcon test-result" + +# cbap ros2_control_test_assets hardware_interface fake_components && colcon test --packages-select hardware_interface ^Cke_components && colcon test-result + #colcon_build() #{ # local pkg=\$1 @@ -65,15 +76,21 @@ setup_ros2_aliases () { ## BEGIN: Framework functions +print_and_exit() { + message=$1 + echo "" + echo "$message !!Exiting..." + exit +} framework_default_paths () { - ros_distro=$1 + ros_distro=$1 - FRAMEWORK_NAME="ros_team_workspace" - FRAMEWORK_BASE_PATH="/opt/RosTeamWS" - FRAMEWORK_REPO_PATH="$FRAMEWORK_BASE_PATH/ros_ws_$ros_distro" - FRAMEWORK_PACKAGE_PATH="$FRAMEWORK_BASE_PATH/ros_ws_$ros_distro/src/ros_team_workspace" - #TODO: remove this in the future + FRAMEWORK_NAME="ros_team_workspace" + FRAMEWORK_BASE_PATH="/opt/RosTeamWS" + FRAMEWORK_REPO_PATH="$FRAMEWORK_BASE_PATH/ros_ws_$ros_distro" + FRAMEWORK_PACKAGE_PATH="$FRAMEWORK_BASE_PATH/ros_ws_$ros_distro/src/ros_team_workspace" + #TODO: remove this in the future # REMOTE_FRAMEWORK_BASE_PATH="/vol64_remote/IPR-Framework" # REMOTE_FRAMEWORK_PATH="$REMOTE_FRAMEWORK_BASE_PATH/IPR_ros_ws_$ros_distro" # #TODO: use this in the future @@ -84,37 +101,68 @@ framework_default_paths () { # fi # FRAMEWORK_REPO_PATH="$REMOTE_FRAMEWORK_PATH/src/ros_team_workspace/scripts" - # Script-specific variables - PACKAGE_TEMPLATES="$FRAMEWORK_PACKAGE_PATH/templates/package" - ROBOT_DESCRIPTION_TEMPLATES="$FRAMEWORK_PACKAGE_PATH/templates/robot_description" + # Script-specific variables + PACKAGE_TEMPLATES="$FRAMEWORK_PACKAGE_PATH/templates/package" + ROBOT_DESCRIPTION_TEMPLATES="$FRAMEWORK_PACKAGE_PATH/templates/robot_description" + ROS2_CONTROL_TEMPLATES="$FRAMEWORK_PACKAGE_PATH/templates/ros2_control" + ROS2_CONTROL_HW_ITF_TEMPLATES="$FRAMEWORK_PACKAGE_PATH/templates/ros2_control/hardware" + LICENSE_TEMPLATES="$FRAMEWORK_PACKAGE_PATH/templates/licenses" } check_ros_distro () { - ros_distro=$1 - if [ -z "$1" ]; then - ros_distro=$DEFAULT_ROS_DISTRO - echo "No ros_distro defined. Using default: '$ros_distro'" - if [ ! -d "/opt/ros/$ros_distro" ]; then - echo "FATAL: ROS '$ros_distro' not installed on this computer! Exiting..." - exit - fi - echo "Press to continue or +C to exit." - read - fi - + ros_distro=$1 + if [ -z "$1" ]; then + ros_distro=$DEFAULT_ROS_DISTRO + echo "No ros_distro defined. Using default: '$ros_distro'" if [ ! -d "/opt/ros/$ros_distro" ]; then - echo "FATAL: ROS '$ros_distro' not installed on this computer! Exiting..." - exit - fi - - ros_version=$DEFAULT_ROS_VERSION - if [[ $ros_distro == "foxy" ]]; then - ros_version=2 - elif [[ $ros_distro == "noetic" ]]; then - ros_version=1 + print_and_exit "FATAL: ROS '$ros_distro' not installed on this computer! Exiting..." +# echo "FATAL: ROS '$ros_distro' not installed on this computer! Exiting..." +# exit fi + read -p "Press to continue or +C to exit." + fi + + if [ ! -d "/opt/ros/$ros_distro" ]; then + print_and_exit "FATAL: ROS '$ros_distro' not installed on this computer! Exiting..." +# echo "FATAL: ROS '$ros_distro' not installed on this computer! Exiting..." +# exit + fi + + ros_version=$DEFAULT_ROS_VERSION + if [[ $ros_distro == "foxy" ]]; then + ros_version=2 + elif [[ $ros_distro == "noetic" ]]; then + ros_version=1 + fi + + framework_default_paths $ros_distro +} - framework_default_paths $ros_distro +# first param is package name, second (yes/no) for executing tests +compile_and_source_package() { + pkg_name=$1 + if [ -z "$1" ]; then + print_and_exit "No package to compile provided. Exiting..." + fi + test=$2 + if [ -z "$2" ]; then + test="no" + fi + bn=`basename "$PWD"` + path=$bn + while [[ "$bn" != "src" ]]; do + cd .. + bn=`basename "$PWD"` + path="$bn/$path" + done + cd .. + colcon build --symlink-install --packages-select $pkg_name + source install/setup.bash + if [[ "$test" == "yes" ]]; then + colcon test --packages-select $pkg_name + colcon test-result | grep $pkg_name + fi + cd $path } # END: Framework functions diff --git a/scripts/environment/setup.bash b/scripts/environment/setup.bash index 86248bd3..c8eb56fe 100644 --- a/scripts/environment/setup.bash +++ b/scripts/environment/setup.bash @@ -9,7 +9,7 @@ source $script_own_dir/../_RosTeamWs_Defines.bash check_ros_distro $1 ws_suffix=$2 -if [ -z "$2" ]; then +if [[ "$2" == "-" ]]; then ws_suffix="" else ws_suffix="_$2" @@ -35,5 +35,20 @@ elif [[ $ros_version == 2 ]]; then /opt/rti.com/rti_connext_dds-5.3.1/setenv_ros2rti.bash # export LANG=de_DE.UTF-8 - source ~/$ws_folder/ros_ws_$ros_distro$ws_suffix/install/setup.bash + WS_FOLDER="" + WS_FOLDER_1="$HOME/$ws_folder/ros_ws_$ros_distro$ws_suffix" + WS_FOLDER_2="$HOME/$ws_folder/ros2_ws_$ros_distro$ws_suffix" + if [ -d "$WS_FOLDER_1" ]; then + WS_FOLDER=$WS_FOLDER_1 + elif [ -d "$WS_FOLDER_2" ]; then + WS_FOLDER=$WS_FOLDER_2 + else + print_and_exit "Neither '$WS_FOLDER_1' nor 'WS_FOLDER_2' exist. Can not find ROS workspace!" + fi + + export COLCON_WS=$WS_FOLDER + source "$WS_FOLDER/install/setup.bash" + + echo "" + echo "RosTeamWS: Sourced file: $WS_FOLDER/install/setup.bash" fi diff --git a/scripts/setup-new-package.bash b/scripts/setup-new-package.bash index 61696187..8efc7703 100755 --- a/scripts/setup-new-package.bash +++ b/scripts/setup-new-package.bash @@ -150,6 +150,8 @@ case "$choice" in fi + ## Move this from here into setup-repository.bash script + # Add package to CI append_to_string=" #package-name:" sed -i "s/$append_to_string/$append_to_string\\n #${PKG_NAME}/g" .github/workflows/ci-build.yml @@ -163,6 +165,9 @@ case "$choice" in append_to_string='### Packages in `'"${META_NAME}"'` metapackage' sed -i "s/$append_to_string/$append_to_string\\n* **${PKG_NAME}** - ${PKG_DESCRIPTION}/g" README.md + # Setup also subpackage README.md + head -4 $PACKAGE_TEMPLATES/README.md.github >> ${PKG_NAME}/README.md + git add . git commit -m "RosTeamWS: Created sub-package $PKG_NAME." diff --git a/scripts/setup-repository.bash b/scripts/setup-repository.bash index a4aa7e93..e1cba7a0 100755 --- a/scripts/setup-repository.bash +++ b/scripts/setup-repository.bash @@ -87,25 +87,39 @@ case "$choice" in exit 0 esac +# This functionality is not provided in all framework versions +if [[ -f "$PACKAGE_TEMPLATES/_append_to_README_ROS_Intro.md" ]]; then + # Ask if add How-to-use and ROS-Intro + read -p "Do you want to append description on 'How-to-use and ROS-Intro' to the README? (y/n) [n]" choice + choice=${choice="n"} + + case "$choice" in + "y") + cat $PACKAGE_TEMPLATES/_append_to_README_ROS_Intro.md >> README.md + echo "Descrption is appended." + "n") + echo "Description not appended." + esac +fi + read -p "Enter namespace of the repository [default: $PKG_NAME]: " NAMESPACE NAMESPACE=${NAMESPACE:=$PKG_NAME} license_web="${LICENSE// /%20}" sed -i 's/\$NAME\$/'${PKG_NAME}'/g' README.md sed -i 's/\$ROS_DISTRO\$/'${ros_distro}'/g' README.md +sed -i 's/\$Ros_distro\$/'${ros_distro^}'/g' README.md sed -i 's/\$DESCRIPTION\$/'"${PKG_DESCRIPTION}"'/g' README.md sed -i 's/\$LICENSE\$/'${license_web}'/g' README.md sed -i 's/\$NAMESPACE\$/'${NAMESPACE}'/g' README.md # Check if it is metapackage if [[ ! -f "package.xml" ]]; then - -echo "" >> README.md -echo "" >> README.md -echo "### Packages in \`${PKG_NAME}\` metapackage" >> README.md -echo "" >> README.md -echo "" >> README.md - + echo "" >> README.md + echo "" >> README.md + echo "### Packages in \`${PKG_NAME}\` metapackage" >> README.md + echo "" >> README.md + echo "" >> README.md fi git add . @@ -122,6 +136,8 @@ case "$open_source" in echo "Adding 'LICENSE' file for '$license' license." # TODO: maybe use "-i, --input-file=DATEI in lokaler oder externer DATEI" option? wget -O LICENSE https://www.apache.org/licenses/LICENSE-2.0.txt + # TODO: Add contributing file +# OS-Apache-CONTRIBUTING.md ;; "n") echo "Not open source repository" diff --git a/scripts/setup-robot-description.bash b/scripts/setup-robot-description.bash index dd889173..3afad70e 100755 --- a/scripts/setup-robot-description.bash +++ b/scripts/setup-robot-description.bash @@ -18,9 +18,9 @@ usage="setup-robot-description.bash ROBOT_NAME [PKG_NAME]" -echo "" -echo "Your path is `pwd`. Is this your package folder where to setup robot's description?" -read -p "If so press otherise +C and start the script again from the description folder." +# echo "" +# echo "Your path is `pwd`. Is this your package folder where to setup robot's description?" +# read -p "If so press otherise +C and start the script again from the description folder." # Load Framework defines script_own_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" @@ -29,7 +29,7 @@ check_ros_distro ${ROS_DISTRO} ROBOT_NAME=$1 if [ -z "$1" ]; then - echo "You should provide package description!" + echo "You should provide robot name!" exit 0 fi @@ -37,11 +37,14 @@ PKG_NAME=$2 if [ -z "$2" ]; then current=`pwd` PKG_NAME=$(basename "$current") - echo "Package name guessed from the current path is '$PKG_NAME' is this correct?" - echo "If so press otherise +C and start the script with the package name as second parameter." - read + echo "Package name guessed from the current path is '$PKG_NAME' is this correct? If not provide it as second paramter." fi +echo "" +echo "ATTENTION: Setting up description configuration for robot '$ROBOT_NAME' in package '$PKG_NAME' in folder '`pwd`'." +echo "" +read -p "If correct press , otherwise +C and start the script again from the package folder and/or with correct robot name." + # Create folders for meshes F_NAME="meshes/${ROBOT_NAME}/visual" mkdir -p $F_NAME @@ -59,22 +62,19 @@ mkdir -p $F_NAME ROBOT_URDF_XACRO="urdf/${ROBOT_NAME}.urdf.xacro" ROBOT_MACRO="urdf/${ROBOT_NAME}/${ROBOT_NAME}_macro.xacro" ROBOT_MACRO_ROS2_CONTROL="urdf/${ROBOT_NAME}/${ROBOT_NAME}_macro.ros2_control.xacro" - cp -n $ROBOT_DESCRIPTION_TEMPLATES/common.xacro urdf/common.xacro cp -n $ROBOT_DESCRIPTION_TEMPLATES/robot.urdf.xacro $ROBOT_URDF_XACRO cp -n $ROBOT_DESCRIPTION_TEMPLATES/robot_macro.xacro $ROBOT_MACRO cp -n $ROBOT_DESCRIPTION_TEMPLATES/robot_macro.ros2_control.xacro $ROBOT_MACRO_ROS2_CONTROL # Copy launch.py file for testing the description -# TODO: Add here ros2_control launch file mkdir -p launch TEST_ROBOT_DESCRIPTION_LAUNCH="launch/test_${ROBOT_NAME}_description.launch.py" cp -n $ROBOT_DESCRIPTION_TEMPLATES/test_robot_description.launch.py $TEST_ROBOT_DESCRIPTION_LAUNCH # Copy YAML files mkdir -p config -ROBOT_CONTROLLERS_YAML="config/${ROBOT_NAME}_controllers.yaml" -cp -n $ROBOT_DESCRIPTION_TEMPLATES/robot_controllers.yaml $ROBOT_CONTROLLERS_YAML +touch config/.gitkeep # Copy rviz files mkdir -p rviz @@ -90,7 +90,7 @@ for SED_FILE in "${FILES_TO_SED[@]}"; do done # Add dependencies if they not exist -DEP_PKGS=("joint_state_publisher_gui" "robot_state_publisher" "rviz2") +DEP_PKGS=("xacro" "rviz2" "robot_state_publisher" "joint_state_publisher_gui") for DEP_PKG in "${DEP_PKGS[@]}"; do if `grep -q $DEP_PKG package.xml`; then @@ -105,22 +105,20 @@ done preppend_to_string="if(BUILD_TESTING)" sed -i "s/$preppend_to_string/install\(\\n DIRECTORY config launch\/ meshes rviz urdf\\n DESTINATION share\/\$\{PROJECT_NAME\}\\n\)\\n\\n$preppend_to_string/g" CMakeLists.txt +# extend README with general instructions +if [ -f README.md ]; then + cat $ROBOT_DESCRIPTION_TEMPLATES/append_to_README.md >> README.md + sed -i "s/\\\$PKG_NAME\\\$/${PKG_NAME}/g" README.md + sed -i "s/\\\$ROBOT_NAME\\\$/${ROBOT_NAME}/g" README.md +fi + +#TODO: Set license + git add . git commit -m "RosTeamWS: Description files for $ROBOT_NAME generated." -# TODO: move this into separate, helper function # Compile and add new package the to the path -bn=`basename "$PWD"` -path=$bn -while [[ "$bn" != "src" ]]; do - cd .. - bn=`basename "$PWD"` - path="$bn/$path" -done -cd .. -colcon build --symlink-install --packages-select $PKG_NAME -source install/setup.bash -cd $path +compile_and_source_package $PKG_NAME echo "" echo "FINISHED: You can test the configuration by executing 'ros2 launch $PKG_NAME test_${ROBOT_NAME}_description.launch.py'" diff --git a/scripts/setup-robot-ros2-control-hardware.bash b/scripts/setup-robot-ros2-control-hardware.bash new file mode 100755 index 00000000..b2d3eca4 --- /dev/null +++ b/scripts/setup-robot-ros2-control-hardware.bash @@ -0,0 +1,350 @@ +#!/bin/bash +# +# Copyright 2021 Stogl Denis Stogl (Stogl Robotics Consulting) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +usage="setup-robot-ros2-control-hardware.bash FILE_NAME [CLASS_NAME] [PKG_NAME]" + +# echo "" +# echo "Your path is `pwd`. Is this your package folder where to setup robot's bringup?" +# read -p "If so press otherise +C and start the script again from the bringup folder." + +# Load Framework defines +script_own_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" +source $script_own_dir/_RosTeamWs_Defines.bash +check_ros_distro ${ROS_DISTRO} + +FILE_NAME=$1 +if [ -z "$1" ]; then + print_and_exit "ERROR: You should provide the file name!" +fi +if [ -f src/$FILE_NAME.cpp ]; then + print_and_exit "ERROR:The file '$FILE_NAME' alread exist!" +fi + +CLASS_NAME=$2 +if [ -z "$2" ]; then + delimiter='_' + s="$FILE_NAME$delimiter" + CLASS_NAME="" + while [[ $s ]]; do + part="${s%%"$delimiter"*}" + s=${s#*"$delimiter"} + CLASS_NAME="$CLASS_NAME${part^}" + done + echo "ClassName guessed from the '$FILE_NAME': '$CLASS_NAME'. Is this correct? If not provide it as the second parameter." +fi + +PKG_NAME=$3 +if [ -z "$3" ]; then + current=`pwd` + PKG_NAME=$(basename "$current") + echo "Package name guessed from the current path is '$PKG_NAME'. Is this correct? If not provide it as the third parameter." +fi + +echo "Which type of ros2_control hardware interface you want to extend? [0]" +echo "(0) system" +echo "(1) sensor" +echo "(2) actuator" +read choice +choice=${choice="0"} + +INTERFACE_TYPE="system" +case "$choice" in +"1") + INTERFACE_TYPE="sensor" + ;; +"2") + INTERFACE_TYPE="actuator" +esac + +echo "Which license-header do you want to use? [1]" +echo "(0) None" +echo "(1) Apache 2.0 License" +echo "(2) Propiatery" +read choice +choice=${choice:="1"} + +if [ "$choice" != 0 ]; then + read -p "Insert your company or personal name (copyright): " NAME_ON_LICENSE + NAME_ON_LICENSE=${NAME_ON_LICENSE=""} + YEAR_ON_LICENSE=`date +%Y` +fi + +LICENSE_HEADER="" +case "$choice" in +"1") + LICENSE_HEADER="$LICENSE_TEMPLATES/default_cpp.txt" + ;; +"2") + LICENSE_HEADER="$LICENSE_TEMPLATES/propriatery_company_cpp.txt" +esac + +echo "" +echo "ATTENTION: Setting up ros2_control hardware interface files with following parameters: file name '$FILE_NAME', class '$CLASS_NAME', package/namespace '$PKG_NAME' for interface type '$INTERFACE_TYPE'. Those will be placed in folder '`pwd`'." +echo "" +read -p "If correct press , otherwise +C and start the script again from the package folder and/or with correct robot name." + +# Add folders if deleted +ADD_FOLDERS=("include/$PKG_NAME" "src" "test") + +for FOLDER in "${ADD_FOLDERS[@]}"; do + mkdir -p $FOLDER +done + +# Set file constants +VC_H="include/$PKG_NAME/visibility_control.h" +HW_ITF_HPP="include/$PKG_NAME/$FILE_NAME.hpp" +HW_ITF_CPP="src/$FILE_NAME.cpp" +PLUGIN_XML="$PKG_NAME.xml" +TEST_CPP="test/test_$FILE_NAME.cpp" + +# Copy files +cp -n $ROS2_CONTROL_HW_ITF_TEMPLATES/visibility_control.h $VC_H +cp -n $ROS2_CONTROL_HW_ITF_TEMPLATES/robot_hardware_interface.hpp $HW_ITF_HPP +cp -n $ROS2_CONTROL_HW_ITF_TEMPLATES/robot_hardware_interface.cpp $HW_ITF_CPP +cp -n $ROS2_CONTROL_HW_ITF_TEMPLATES/robot_pluginlib.xml $PLUGIN_XML +cp -n $ROS2_CONTROL_HW_ITF_TEMPLATES/test_robot_hardware_interface.cpp $TEST_CPP + +echo "Template files copied." + +# Add license header to the files +# TODO: When Propiatery then add the follwing before ament_lint_auto_find_test_dependencies() +# list(APPEND AMENT_LINT_AUTO_EXCLUDE +# ament_cmake_copyright +# ) +FILES_TO_LICENSE=($VC_H $HW_ITF_HPP $HW_ITF_CPP $TEST_CPP) +TMP_FILE=".f_tmp" +if [[ "$LICENSE_HEADER" != "" ]]; then + touch $TMP_FILE + for FILE_TO_LIC in "${FILES_TO_LICENSE[@]}"; do + cat $LICENSE_HEADER > $TMP_FILE + cat $FILE_TO_LIC >> $TMP_FILE + sed -i "/\\\$LICENSE\\\$/d" $TMP_FILE + mv $TMP_FILE $FILE_TO_LIC + sed -i "s/\\\$YEAR\\\$/${YEAR_ON_LICENSE}/g" $FILE_TO_LIC + sed -i "s/\\\$NAME_ON_LICENSE\\\$/${NAME_ON_LICENSE}/g" $FILE_TO_LIC + done +# echo "Licence header added to files: ("`declare -p FILES_TO_LICENSE`")" +fi + +FILES_TO_SED=("${FILES_TO_LICENSE[@]}") +# sed all needed files +FILES_TO_SED+=("$PLUGIN_XML") +# declare -p FILES_TO_SED + +for SED_FILE in "${FILES_TO_SED[@]}"; do + sed -i "s/\\\$PACKAGE_NAME\\\$/${PKG_NAME^^}/g" $SED_FILE + sed -i "s/\\\$package_name\\\$/${PKG_NAME}/g" $SED_FILE + sed -i "s/\\\$file_name\\\$/${FILE_NAME}/g" $SED_FILE + sed -i "s/\\\$FILE_NAME\\\$/${FILE_NAME^^}/g" $SED_FILE + sed -i "s/\\\$ClassName\\\$/${CLASS_NAME}/g" $SED_FILE + sed -i "s/\\\$interface_type\\\$/${INTERFACE_TYPE}/g" $SED_FILE + sed -i "s/\\\$Interface_Type\\\$/${INTERFACE_TYPE^}/g" $SED_FILE +done + + +# CMakeLists.txt: Remove comments if there any and add library +DEL_STRINGS=("# uncomment the following" "# further" "# find_package(") + +for DEL_STR in "${DEL_STRINGS[@]}"; do + sed -i "/$DEL_STR/d" CMakeLists.txt +done + +TMP_FILE=".f_tmp" +touch $TMP_FILE + +# Get line with if(BUILD_TESTING) +TEST_LINE=`awk '$1 == "if(BUILD_TESTING)" { print NR }' CMakeLists.txt` +let CUT_LINE=$TEST_LINE-1 +head -$CUT_LINE CMakeLists.txt >> $TMP_FILE + +# Add Plugin library stuff inside +echo "add_library(" >> $TMP_FILE +echo " $PKG_NAME" >> $TMP_FILE +echo " SHARED" >> $TMP_FILE +echo " $HW_ITF_CPP" >> $TMP_FILE +echo ")" >> $TMP_FILE + +echo "target_include_directories(" >> $TMP_FILE +echo " $PKG_NAME" >> $TMP_FILE +echo " PUBLIC" >> $TMP_FILE +echo " include" >> $TMP_FILE +echo ")" >> $TMP_FILE + +echo "ament_target_dependencies(" >> $TMP_FILE +echo " $PKG_NAME" >> $TMP_FILE +echo " hardware_interface" >> $TMP_FILE +echo " rclcpp" >> $TMP_FILE +echo ")" >> $TMP_FILE + +# TODO(anyone): Delete after Foxy!!! +echo "# prevent pluginlib from using boost" >> $TMP_FILE +echo "target_compile_definitions($PKG_NAME PUBLIC \"PLUGINLIB__DISABLE_BOOST_FUNCTIONS\")" >> $TMP_FILE + +echo "" >> $TMP_FILE +echo "pluginlib_export_plugin_description_file(" >> $TMP_FILE +echo " hardware_interface $PLUGIN_XML)" >> $TMP_FILE + +## Add install directives +echo "" >> $TMP_FILE +echo "install(" >> $TMP_FILE +echo " TARGETS" >> $TMP_FILE +echo " $PKG_NAME" >> $TMP_FILE +echo " RUNTIME DESTINATION bin" >> $TMP_FILE +echo " ARCHIVE DESTINATION lib" >> $TMP_FILE +echo " LIBRARY DESTINATION lib" >> $TMP_FILE +echo ")" >> $TMP_FILE + +if [[ ! `grep -q "DIRECTORY include/" $TMP_FILE` ]]; then + echo "" >> $TMP_FILE + echo "install(" >> $TMP_FILE + echo " DIRECTORY include/" >> $TMP_FILE + echo " DESTINATION include" >> $TMP_FILE + echo ")" >> $TMP_FILE +fi + +echo "" >> $TMP_FILE + +END_TEST_LINE=`tail -n +$TEST_LINE CMakeLists.txt | awk '$1 == "endif()" { print NR }'` +let CUT_LINE=$END_TEST_LINE-1 +tail -n +$TEST_LINE CMakeLists.txt | head -$CUT_LINE >> $TMP_FILE + +echo "" >> $TMP_FILE +echo " ament_add_gmock(test_$FILE_NAME $TEST_CPP)" >> $TMP_FILE +echo " target_include_directories(test_$FILE_NAME PRIVATE include)" >> $TMP_FILE +echo " ament_target_dependencies(" >> $TMP_FILE +echo " test_$FILE_NAME" >> $TMP_FILE +echo " hardware_interface" >> $TMP_FILE +echo " pluginlib" >> $TMP_FILE +echo " ros2_control_test_assets" >> $TMP_FILE +echo " )" >> $TMP_FILE +echo "" + +# Add export definitions +tail -n +$TEST_LINE CMakeLists.txt | head -$END_TEST_LINE | tail -1 >> $TMP_FILE + +echo "" >> $TMP_FILE +echo "ament_export_include_directories(" >> $TMP_FILE +echo " include" >> $TMP_FILE +echo ")" >> $TMP_FILE + +echo "ament_export_libraries(" >> $TMP_FILE +echo " $PKG_NAME" >> $TMP_FILE +echo ")" >> $TMP_FILE + +echo "ament_export_dependencies(" >> $TMP_FILE +echo " hardware_interface" >> $TMP_FILE +echo " pluginlib" >> $TMP_FILE +echo " rclcpp" >> $TMP_FILE +echo ")" >> $TMP_FILE + +# Add last part +let CUT_LINE=$END_TEST_LINE+1 +tail -n +$TEST_LINE CMakeLists.txt | tail -n +$CUT_LINE >> $TMP_FILE + +mv $TMP_FILE CMakeLists.txt + +# CMakeLists.txt & package.xml: Add dependencies if they not exist +DEP_PKGS=("rclcpp" "pluginlib" "hardware_interface") + +for DEP_PKG in "${DEP_PKGS[@]}"; do + + # CMakeLists.txt + if `grep -q "find_package(${DEP_PKG} REQUIRED)" CMakeLists.txt`; then + echo "'$DEP_PKG' is already dependency in CMakeLists.txt" + else + append_to_string="find_package(ament_cmake REQUIRED)" + sed -i "s/$append_to_string/$append_to_string\\nfind_package(${DEP_PKG} REQUIRED)/g" CMakeLists.txt + fi + + # package.xml + if `grep -q "${DEP_PKG}" package.xml`; then + echo "'$DEP_PKG' is already listed in package.xml" + else + append_to_string="ament_cmake<\/buildtool_depend>" + sed -i "s/$append_to_string/$append_to_string\\n\\n ${DEP_PKG}<\/depend>/g" package.xml + fi + +done + +# CMakeLists.txt & package.xml: Add test dependencies if they not exist +TEST_DEP_PKGS=("ros2_control_test_assets" "ament_cmake_gmock") + +for DEP_PKG in "${TEST_DEP_PKGS[@]}"; do + + # CMakeLists.txt + if `grep -q " find_package(${DEP_PKG} REQUIRED)" CMakeLists.txt`; then + echo "'$DEP_PKG' is already listed in CMakeLists.txt" + else + append_to_string="ament_lint_auto_find_test_dependencies()" + sed -i "s/$append_to_string/$append_to_string\\n find_package(${DEP_PKG} REQUIRED)/g" CMakeLists.txt + fi + + # package.xml + if `grep -q "${DEP_PKG}" package.xml`; then + echo "'$DEP_PKG' is already listed in package.xml" + else + append_to_string="ament_lint_common<\/test_depend>" + sed -i "s/$append_to_string/$append_to_string\\n ${DEP_PKG}<\/test_depend>/g" package.xml + fi +done + +# extend README with general instructions +if [ -f README.md ]; then + + echo "" >> README.md + echo "Pluginlib-Library: $PKG_NAME" >> README.md + echo "Plugin: $PKG_NAME/${CLASS_NAME} (hardware_interface::${INTERFACE_TYPE^}Interface)" >> README.md + +fi + +git add . +# git commit -m "RosTeamWS: ros2_control skeleton files for $ROBOT_NAME generated." + +# Compile and add new package the to the path +compile_and_source_package $PKG_NAME "yes" + +echo "" +echo "FINISHED: Your package is set and the tests should be finished without any errors." + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/setup-ros-workspace.bash b/scripts/setup-ros-workspace.bash index fb4045d9..e5e43dfc 100755 --- a/scripts/setup-ros-workspace.bash +++ b/scripts/setup-ros-workspace.bash @@ -2,7 +2,7 @@ # workspace folder is relative to your home -usage='Usage: ./setup-ros-workspace.bash "ros_distro" "ros_ws_suffix" "workspace_folder"' +usage='Usage: setup-ros-workspace.bash ROS_DISTRO WS_SUFFIX WS_FOLDER' # Load Framework defines script_own_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" @@ -26,22 +26,21 @@ fi # TODO: Write this automatically from the user's definitions echo "Please choose which workspace should be basis for yours:" echo "(0) " -echo "(1) Industrial" -echo "(2) Mobile" +# echo "(1) Industrial" +# echo "(2) Mobile" read choice if [ -z "$choice" ]; then - echo "No workspace is chosen! Exiting..." - exit + print_and_exit "No workspace is chosen!" fi case "$choice" in -"1") - base_ws=Industrial - ;; -"2") - base_ws=Mobile - ;; +# "1") +# base_ws=Industrial +# ;; +# "2") +# base_ws=Mobile +# ;; "0") base_ws="" ;; @@ -51,8 +50,8 @@ case "$choice" in esac # TODO: Add here output of the WS -echo "Creating a new workspace in folder '$ws_folder' for ROS '$ros_distro' (ROS$ros_version) with suffix '$ros_ws_suffix' using '$base_ws' as base workspace. Press to continue..." -read +echo "" +read -p "ATTENTION: Creating a new workspace in folder '$ws_folder' for ROS '$ros_distro' (ROS$ros_version) with suffix '$ros_ws_suffix' using '$base_ws' as base workspace. Press to continue..." # Create and initalise ROS-Workspace if [[ $base_ws != "" ]]; then @@ -77,7 +76,14 @@ fi cd -fun_name="RosTeamWS_setup_ros$ros_version" +alias_name=_ros${ros_version} +if [ -z "$ros_ws_suffix" ]; then + fun_name="RosTeamWS_setup_ros$ros_version" + ros_ws_suffix="-" +else + fun_name="RosTeamWS_setup_ros${ros_version}_$ros_ws_suffix" + alias_name=${alias_name}_$ros_ws_suffix +fi cp ~/.bashrc ~/.bashrc.bkp # Comment out the old configuration is such exists - this is hard if using functions... @@ -92,15 +98,17 @@ echo " RosTeamWS_WS_FOLDER=$ws_folder" >> ~/.bashrc echo " RosTeamWS_WS_SUFFIX=$ros_ws_suffix" >> ~/.bashrc echo " source $FRAMEWORK_BASE_PATH/ros_ws_\$RosTeamWS_DISTRO/src/$FRAMEWORK_NAME/scripts/environment/setup.bash \$RosTeamWS_DISTRO \$RosTeamWS_WS_SUFFIX \$RosTeamWS_WS_FOLDER" >> ~/.bashrc echo "}" >> ~/.bashrc -echo "alias st_ros$ros_version=$fun_name" >> ~/.bashrc +echo "alias $alias_name=$fun_name" >> ~/.bashrc # Setup new workspace source ~/.bashrc +# Update rosdep definitions +rosdep update + if [[ $ros_version == 1 ]]; then - rosdep update rospack profile fi echo "------------------------------------------------------" -echo "Fnished: Please open new terminal and execute 'st_ros$ros_version'" +echo "Fnished: Please open a new terminal and execute '$alias_name'" diff --git a/templates/licenses/default_cpp.txt b/templates/licenses/default_cpp.txt new file mode 100644 index 00000000..39c80167 --- /dev/null +++ b/templates/licenses/default_cpp.txt @@ -0,0 +1,14 @@ +// Copyright (c) $YEAR$, $NAME_ON_LICENSE$ +// Copyright (c) $YEAR$, Stogl Robotics Consulting (template) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/templates/licenses/default_py.txt b/templates/licenses/default_py.txt new file mode 100644 index 00000000..f623a597 --- /dev/null +++ b/templates/licenses/default_py.txt @@ -0,0 +1,14 @@ +# Copyright (c) $YEAR$, $NAME_ON_LICENSE$ +# Copyright (c) $YEAR$, Stogl Robotics Consulting (template) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/templates/licenses/propriatery_company_cpp.txt b/templates/licenses/propriatery_company_cpp.txt new file mode 100644 index 00000000..e7038712 --- /dev/null +++ b/templates/licenses/propriatery_company_cpp.txt @@ -0,0 +1,7 @@ +// Copyright (c) $YEAR$, $NAME_ON_LICENSE$ +// All rights reserved. +// +// Proprietary License +// +// Unauthorized copying of this file, via any medium is strictly prohibited. +// The file is considered confidential. diff --git a/templates/licenses/propriatery_company_py.txt b/templates/licenses/propriatery_company_py.txt new file mode 100644 index 00000000..89fffcd0 --- /dev/null +++ b/templates/licenses/propriatery_company_py.txt @@ -0,0 +1,7 @@ +# Copyright (c) $YEAR$, $NAME_ON_LICENSE$ +# All rights reserved. +# +# Proprietary License +# +# Unauthorized copying of this file, via any medium is strictly prohibited. +# The file is considered confidential. diff --git a/templates/package/CI-github_docs-sphinx-build-check.yml b/templates/package/CI-github_docs-sphinx-build-check.yml index 3a39cc57..7e89a8e9 100644 --- a/templates/package/CI-github_docs-sphinx-build-check.yml +++ b/templates/package/CI-github_docs-sphinx-build-check.yml @@ -16,3 +16,4 @@ jobs: - uses: ammaraskar/sphinx-action@master with: docs-folder: '$DOCS_FOLDER$' + pre-build-command: "apt-get update -y && apt-get install -y python3-pip && pip3 install sphinx_rtd_theme" diff --git a/templates/package/OS-Apache-CONTRIBUTING.md b/templates/package/OS-Apache-CONTRIBUTING.md new file mode 100644 index 00000000..bf70893d --- /dev/null +++ b/templates/package/OS-Apache-CONTRIBUTING.md @@ -0,0 +1,68 @@ +# Contributing Guidelines +Thank you for your interest in contributing to `$NAME$`. +Whether it's a bug report, new feature, correction, or additional +documentation, we greatly value feedback and contributions from our community. + +Please read through this document before submitting any issues or pull requests to ensure we have all the necessary +information to effectively respond to your bug report or contribution. + + +## Reporting Bugs/Feature Requests +We welcome you to use the GitHub issue tracker to report bugs or suggest features. + +When filing an issue, please check [existing open][issues], or [recently closed][closed-issues], issues to make sure + somebody else hasn't already reported the issue. +Please try to include as much information as you can. Details like these are incredibly useful: + +* A reproducible test case or series of steps +* The version of our code being used +* Any modifications you've made relevant to the bug +* Anything unusual about your environment or deployment + + +## Contributing via Pull Requests +Contributions via pull requests are much appreciated. +Before sending us a pull request, please ensure that: + +1. You are working against the latest source on the *master* branch. +2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. +3. You open an issue to discuss any significant work - we would hate for your time to be wasted. + +To send us a pull request, please: + +1. Fork the repository. +2. Modify the source; please focus on the specific change you are contributing. + If you also reformat all the code, it will be hard for us to focus on your change. +3. Ensure local tests pass. (`colcon test`) +4. Commit to your fork using clear commit messages. +5. Send a pull request, answering any default questions in the pull request interface. +6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. + +GitHub provides additional documentation on [forking a repository](https://help.github.com/articles/fork-a-repo/) and +[creating a pull request](https://help.github.com/articles/creating-a-pull-request/). + + +## Finding contributions to work on +Looking at the existing issues is a great way to find something to contribute on. +As this project, by default, uses the default GitHub issue labels + (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'][help-wanted] issues + is a great place to start. + + +## Licensing +Any contribution that you make to this repository will be under the Apache 2 License, as dictated by that [license]: + +~~~ +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +~~~ + +[issues]: https://github.com/$NAMESPACE$/$NAME$/issues +[closed-issues]: https://github.com/$NAMESPACE$/$NAME$/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20 +[help-wanted]: https://github.com/$NAMESPACE$/$NAME$/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22 +[license]: http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/templates/package/pkg_name.repos b/templates/package/pkg_name.repos index 56f46b6f..1b3910e7 100644 --- a/templates/package/pkg_name.repos +++ b/templates/package/pkg_name.repos @@ -1 +1,6 @@ repositories: + ## EXAMPLE DEPENDENCY +# : +# type: git +# url: git@github.com:/.git +# version: master diff --git a/templates/robot_description/append_to_README.md b/templates/robot_description/append_to_README.md new file mode 100644 index 00000000..f8fe1b75 --- /dev/null +++ b/templates/robot_description/append_to_README.md @@ -0,0 +1,49 @@ + + +## General details about robot description packages + +This description package follows, as much as possible, the recommendations from [ROS-Industrial Consortium about robot support packages](https://wiki.ros.org/Industrial/Tutorials/WorkingWithRosIndustrialRobotSupportPackages). +The general package structure is the following: + +``` +_description/ # Robot's description files +├── [CMakeLists.txt] # if ament_cmake is used (recommended) +├── package.xml +├── [setup.py] # if amend_python is used +├── [setup.cfg] # if amend_python is used +├── config/ # general YAML files for a robot +│ └── _.yaml +├── launch/ # launch files related to testing robots' description +│ └── test__description.launch.py +├── meshes/ # meshes used in _macro.urdf.xacro +│ ├── collision +│ │ └── # meshes are sorted by robot name or model +│ │ ├── .stl +│ │ └── ... +│ └── visual +│ └── +│ ├── .dae +│ └── ... +├── rviz/ # rviz display configurations +│ └── _default.rviz +└── urdf/ # URDF file for the robot + ├── common.xacro # Common XACRO definitions + ├── .urdf.xacro # Main URDF for a robot - loads macro and other files + └── + ├── _macro.xacro # Macro file of the robot - can add prefix, define origin, etc. + └── _macro.ros2_control.xacro # URDF-part used to configure ros2_control + +``` + +### Testing the validity of robot description + +1. Go to the root of your workspace folder (there where `src`, `build`, `install` and `log` files are). +2. Install the package by calling `colcon build --symlink-install --packages-select $PKG_NAME$` +3. (Re-)Source environemnt `source install/setup.bash` +4. Launch description test: + ``` + ros2 launch $PKG_NAME$ test_$ROBOT_NAME$_description.launch.py + ``` + +If there are no issues with the description, two windows are opened: `rviz2` and `Joint State Publisher`. +Rviz2 visualizes the robot's state and Joint state Publisher to changes joint values using sliders or generates random but valid configurations. diff --git a/templates/robot_description/robot.urdf.xacro b/templates/robot_description/robot.urdf.xacro index 00822c64..dedda34d 100644 --- a/templates/robot_description/robot.urdf.xacro +++ b/templates/robot_description/robot.urdf.xacro @@ -2,7 +2,8 @@ - + + @@ -19,6 +20,7 @@ + use_fake_hardware="$(arg use_fake_hardware)" + fake_sensor_commands="$(arg fake_sensor_commands)" /> diff --git a/templates/robot_description/robot_macro.ros2_control.xacro b/templates/robot_description/robot_macro.ros2_control.xacro index 23692b12..27c714b3 100644 --- a/templates/robot_description/robot_macro.ros2_control.xacro +++ b/templates/robot_description/robot_macro.ros2_control.xacro @@ -1,14 +1,19 @@ - + - fake_components/GenericRobot - ${example_param} + + fake_components/GenericRobot + ${fake_sensor_commands} + + + robot_hardware_inteface/RobotHardwareInteface + - + -1 1 @@ -16,8 +21,9 @@ + 0.0 - + -1 1 @@ -25,8 +31,9 @@ + 0.0 - + -1 1 @@ -34,8 +41,9 @@ + 0.0 - + -1 1 @@ -43,8 +51,9 @@ + 0.0 - + -1 1 @@ -52,8 +61,9 @@ + 0.0 - + -1 1 @@ -61,6 +71,7 @@ + 0.0 diff --git a/templates/robot_description/robot_macro.xacro b/templates/robot_description/robot_macro.xacro index 6251f924..41267a52 100644 --- a/templates/robot_description/robot_macro.xacro +++ b/templates/robot_description/robot_macro.xacro @@ -26,7 +26,7 @@ - + @@ -34,19 +34,19 @@ - + - + - + @@ -54,19 +54,19 @@ - + - + - + @@ -74,19 +74,19 @@ - + - + - + @@ -94,19 +94,19 @@ - + - + - + @@ -114,19 +114,19 @@ - + - + - + @@ -134,14 +134,14 @@ - + - + @@ -168,57 +168,57 @@ - + - + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - + + diff --git a/templates/robot_description/test_robot_description.launch.py b/templates/robot_description/test_robot_description.launch.py index b0de05e0..b19a5517 100644 --- a/templates/robot_description/test_robot_description.launch.py +++ b/templates/robot_description/test_robot_description.launch.py @@ -1,16 +1,4 @@ -# Copyright 2021 Stogl Denis Stogl (Stogl Robotics Consulting) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +$LICENSE$ import os @@ -30,7 +18,7 @@ def generate_launch_description(): 'urdf', '$ROBOT_NAME$.urdf.xacro') robot_description_config = xacro.process_file(robot_description_path, - mappings={'example_arg': 'test1'}) + mappings={'fake_sensor_commands': 'true'}) robot_description = {'robot_description': robot_description_config.toxml()} rviz_config_file = os.path.join( diff --git a/templates/ros2_control/append_to_README.md b/templates/ros2_control/append_to_README.md new file mode 100644 index 00000000..238c2070 --- /dev/null +++ b/templates/ros2_control/append_to_README.md @@ -0,0 +1,178 @@ + + +## General details about robot bringup packages + +A bringup package holds config und launch files for starting different scenarios with a robot. + +The general package structure is the following: + +``` +_bringup/ # Launch and config files for starting the robot using ros2_control +├── [CMakeLists.txt] # if ament_cmake is used (recommended) +├── package.xml +├── [setup.py] # if amend_python is used +├── [setup.cfg] # if amend_python is used +├── config/ +│ ├── _controllers.yaml # Controllers' configuraiton for ros2_control +│ ├── _forward_position_publisher.yaml # Setup test publisher for forward position controller +│ └── _joint_trajectory_publisher.yaml # Setup test publisher for joint trajectory controller +└── launch/ + ├── .launch.py # Robot's default launch file + ├── test_forward_position_controller.launch.py # Start test publisher for forward position controller + └── test_joint_trajectory_controller.launch.py # Start test publisher for joint trajectory controller + +``` + +**NOTE**: Most of the following steps are equivalent to the description in [ros2_control_demos](https://github.com/ros-controls/ros2_control_demos) repository. +Consult the repository and [ros2_control documentation](https://ros-controls.github.io/control.ros.org/) for more details. + + +## Testing the *fake* robot using ros2_control-framework + +**ATTENTION**: if the package is not build and sourced do this first + +1. Start robot's hardware and load controllers (default configuration starts fake hardware) + ``` + ros2 launch $PKG_NAME$ $ROBOT_NAME$.launch.py + ``` + +2. Open another terminal and check if your hardware is loaded properly: + ``` + ros2 control list_hardware_interfaces + ``` + You should see list of *command*- and *state* interfaces for your hardware. + +3. Now you should load controllers as described in [loading controllers](#loading-controllers) section. + +4. Check the result as described in the [result](#result) section. + + +## Testing the real robot using ros2_control-framework + +**TBD** + + +## Loading Controllers + +To move the robot you should load and start contorllers. +To get feedback about robot's state `JointStateController` is used. +to send command to the robot `ForwardCommandController` (direct goals) or `JointTrajectoryController` (interpolates trajectory). +The sections below describe their usage. + +### Joint State Controller +Joint state Controllers provides output of robot's internal states to `/joint_states` and `/dynamic_joint_states` ROS2-topics. + +In a new terminal with sourced ROS2 environement load, configure and start `joint_state_controller`: + ``` + ros2 control load_start_controller joint_state_controller + ``` +Check if controller is loaded properly: + ``` + ros2 control list_controllers + ``` +You should get similar response to: + ``` + joint_state_controller[joint_state_controller/JointStateController] active + ``` + +Now you should also see your robot represented correctly in the `rviz2`. + +### Using Forward Command Controllers + +1. If you want to test hardware with `ForwardCommandController` first load and configure it. Controller types are e.g., "position", "velocity", and depend on configured names in the [`config/$ROBOT_NAME$_controllers.yaml`](config/$ROBOT_NAME$_controllers.yaml): + ``` + ros2 control load_configure_controller forward__controller + ``` + Check if controller is loaded properly: + ``` + ros2 control list_controllers + ``` + You should get the response: + ``` + joint_state_controller[joint_state_controller/JointStateController] active + forward__controller[forward_command_controller/ForwardCommandController] inactive + ``` + +2. Now start the controller: + ``` + ros2 control switch_controllers --start-controllers forward__controller + ``` + Check if controllers are activated: + ``` + ros2 control list_controllers + ``` + You should get `active` in the response: + ``` + joint_state_controller[joint_state_controller/JointStateController] active + forward__controller[forward_command_controller/ForwardCommandController] active + ``` + +**NOTE**: You can do this in only one step by using `load_start_controller` verb instead of `load_configure_controller`. + +3. Send command to the controller, either: + + a. Manually using ros2 cli interface: + ``` + ros2 topic pub /forward__controller/commands std_msgs/msg/Float64MultiArray "data: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5" + ``` + b. Or you can start demo node which sends two goals every 5 seconds in a loop (**Only with position controller!**): + ``` + ros2 launch $PKG_NAME$ test_forward_position_controller.launch.py + ``` + +### Using JointTrajectoryController (**Not working yet!**) + +1. If a `ForwardCommandController` is started you should stop it first by using: + ``` + ros2 control switch_controllers --stop-controllers forward__controller + ``` + Check if controllers are activated: + ``` + ros2 control list_controllers + ``` + You should get `active` in the response: + ``` + joint_state_controller[joint_state_controller/JointStateController] active + forward__controller[forward_command_controller/ForwardCommandController] inactive + ``` + +2. If you want to test hardware with `JointTrajectoryController` first load, configure and start it: + ``` + ros2 control load_start_controller joint_trajectory_controller + ``` + Check if controllers are activated: + ``` + ros2 control list_controllers + ``` + You should get `active` in the response: + ``` + joint_state_controller[joint_state_controller/JointStateController] active + joint_trajectory_controller[joint_trajectory_controller/JointTrajectoryController] active + ``` + +3. Send command to the controller using test node: + ``` + ros2 launch ros2_control_demo_robot test_joint_trajectory_controller.launch.py + ``` + +**NOTE**: You can swith contorllers (step 1 and 2) also with one command: +``` +ros2 control switch_controllers --stop-controllers forward__controller --start-controllers joint_trajectory_controller +``` + + +## Result + +1. If you echo the `/joint_states` or `/dynamic_joint_states` topics you should changing values when the robot is moving values. + ``` + ros2 topic echo /joint_states + ros2 topic echo /dynamic_joint_states + ``` + +3. The robot should also move in `rviz2`. diff --git a/templates/ros2_control/hardware/robot_hardware_interface.cpp b/templates/ros2_control/hardware/robot_hardware_interface.cpp new file mode 100644 index 00000000..a26c3090 --- /dev/null +++ b/templates/ros2_control/hardware/robot_hardware_interface.cpp @@ -0,0 +1,97 @@ +$LICENSE$ + +#include "$package_name$/$file_name$.hpp" + +#include +#include + +#include "hardware_interface/types/hardware_interface_type_values.hpp" +#include "rclcpp/rclcpp.hpp" + +namespace $package_name$ +{ + +return_type $ClassName$::configure( + const hardware_interface::HardwareInfo & info) +{ + if (configure_default(info) != return_type::OK) { + return return_type::ERROR; + } + + // TODO(anyone): read parameters and initialize the hardware + hw_states_.resize(info_.joints.size(), std::numeric_limits::quiet_NaN()); + hw_commands_.resize(info_.joints.size(), std::numeric_limits::quiet_NaN()); + + status_ = hardware_interface::status::CONFIGURED; + return return_type::OK; +} + +std::vector +$ClassName$::export_state_interfaces() +{ + std::vector state_interfaces; + for (uint i = 0; i < info_.joints.size(); i++) { + state_interfaces.emplace_back( + hardware_interface::StateInterface( + // TODO(anyone): insert correct interfaces + info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_states_[i])); + } + + return state_interfaces; +} + +std::vector +$ClassName$::export_command_interfaces() +{ + std::vector command_interfaces; + for (uint i = 0; i < info_.joints.size(); i++) { + command_interfaces.emplace_back( + hardware_interface::CommandInterface( + // TODO(anyone): insert correct interfaces + info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_commands_[i])); + } + + return command_interfaces; +} + + +return_type $ClassName$::start() +{ + // TODO(anyone): prepare the robot to receive commands + + status_ = hardware_interface::status::STARTED; + + return return_type::OK; +} + +return_type $ClassName$::stop() +{ + // TODO(anyone): prepare the robot to stop receiving commands + + status_ = hardware_interface::status::STOPPED; + + return return_type::OK; +} + +hardware_interface::return_type $ClassName$::read() +{ + // TODO(anyone): read robot states + + return return_type::OK; +} + +hardware_interface::return_type $ClassName$::write() +{ + // TODO(anyone): write robot's commands' + + return return_type::OK; +} + +} // namespace $package_name$ + +#include "pluginlib/class_list_macros.hpp" + +PLUGINLIB_EXPORT_CLASS( + $package_name$::$ClassName$, + hardware_interface::$Interface_Type$Interface +) diff --git a/templates/ros2_control/hardware/robot_hardware_interface.hpp b/templates/ros2_control/hardware/robot_hardware_interface.hpp new file mode 100644 index 00000000..b17d314f --- /dev/null +++ b/templates/ros2_control/hardware/robot_hardware_interface.hpp @@ -0,0 +1,58 @@ +$LICENSE$ + + +#ifndef $PACKAGE_NAME$__$FILE_NAME$_HPP_ +#define $PACKAGE_NAME$__$FILE_NAME$_HPP_ + +#include +#include + +#include "rclcpp/macros.hpp" + +#include "hardware_interface/base_interface.hpp" +#include "hardware_interface/$interface_type$_interface.hpp" +#include "hardware_interface/handle.hpp" +#include "hardware_interface/hardware_info.hpp" +#include "hardware_interface/types/hardware_interface_return_values.hpp" +#include "hardware_interface/types/hardware_interface_status_values.hpp" +#include "$package_name$/visibility_control.h" + +using hardware_interface::return_type; + +namespace $package_name$ +{ +class $ClassName$ : public + hardware_interface::BaseInterface +{ +public: + RCLCPP_SHARED_PTR_DEFINITIONS($ClassName$); + + $PACKAGE_NAME$_PUBLIC + return_type configure(const hardware_interface::HardwareInfo & info) override; + + $PACKAGE_NAME$_PUBLIC + std::vector export_state_interfaces() override; + + $PACKAGE_NAME$_PUBLIC + std::vector export_command_interfaces() override; + + $PACKAGE_NAME$_PUBLIC + return_type start() override; + + $PACKAGE_NAME$_PUBLIC + return_type stop() override; + + $PACKAGE_NAME$_PUBLIC + return_type read() override; + + $PACKAGE_NAME$_PUBLIC + return_type write() override; + +private: + std::vector hw_commands_; + std::vector hw_states_; +}; + +} // namespace $package_name$ + +#endif // $PACKAGE_NAME$__$FILE_NAME$_HPP_ diff --git a/templates/ros2_control/hardware/robot_pluginlib.xml b/templates/ros2_control/hardware/robot_pluginlib.xml new file mode 100644 index 00000000..e9ac18a7 --- /dev/null +++ b/templates/ros2_control/hardware/robot_pluginlib.xml @@ -0,0 +1,10 @@ + + + + ros2_control hardware interface. + + + + diff --git a/templates/ros2_control/hardware/test_robot_hardware_interface.cpp b/templates/ros2_control/hardware/test_robot_hardware_interface.cpp new file mode 100644 index 00000000..ea5f9ca7 --- /dev/null +++ b/templates/ros2_control/hardware/test_robot_hardware_interface.cpp @@ -0,0 +1,44 @@ +$LICENSE$ + +#include +#include + +#include "hardware_interface/resource_manager.hpp" +#include "ros2_control_test_assets/descriptions.hpp" +#include "ros2_control_test_assets/components_urdfs.hpp" + +class TestGenericSystem : public ::testing::Test +{ +protected: + void SetUp() override + { + // TODO(anyone): Extend this description to your robot + $file_name$_2dof_ = + R"( + + + $package_name$/$ClassName$ + + + + + 1.57 + + + + + 0.7854 + + +)"; + } + + std::string $file_name$_2dof_; +}; + +TEST_F(TestGenericSystem, load_$file_name$_2dof) { + auto urdf = + ros2_control_test_assets::urdf_head + $file_name$_2dof_ + + ros2_control_test_assets::urdf_tail; + ASSERT_NO_THROW(hardware_interface::ResourceManager rm(urdf)); +} diff --git a/templates/ros2_control/hardware/visibility_control.h b/templates/ros2_control/hardware/visibility_control.h new file mode 100644 index 00000000..9ba82d0b --- /dev/null +++ b/templates/ros2_control/hardware/visibility_control.h @@ -0,0 +1,37 @@ +$LICENSE$ + +#ifndef $PACKAGE_NAME$__VISIBILITY_CONTROL_H_ +#define $PACKAGE_NAME$__VISIBILITY_CONTROL_H_ + +// This logic was borrowed (then namespaced) from the examples on the gcc wiki: +// https://gcc.gnu.org/wiki/Visibility + +#if defined _WIN32 || defined __CYGWIN__ +#ifdef __GNUC__ +#define $PACKAGE_NAME$_EXPORT __attribute__((dllexport)) +#define $PACKAGE_NAME$_IMPORT __attribute__((dllimport)) +#else +#define $PACKAGE_NAME$_EXPORT __declspec(dllexport) +#define $PACKAGE_NAME$_IMPORT __declspec(dllimport) +#endif +#ifdef $PACKAGE_NAME$_BUILDING_DLL +#define $PACKAGE_NAME$_PUBLIC $PACKAGE_NAME$_EXPORT +#else +#define $PACKAGE_NAME$_PUBLIC $PACKAGE_NAME$_IMPORT +#endif +#define $PACKAGE_NAME$_PUBLIC_TYPE $PACKAGE_NAME$_PUBLIC +#define $PACKAGE_NAME$_LOCAL +#else +#define $PACKAGE_NAME$_EXPORT __attribute__((visibility("default"))) +#define $PACKAGE_NAME$_IMPORT +#if __GNUC__ >= 4 +#define $PACKAGE_NAME$_PUBLIC __attribute__((visibility("default"))) +#define $PACKAGE_NAME$_LOCAL __attribute__((visibility("hidden"))) +#else +#define $PACKAGE_NAME$_PUBLIC +#define $PACKAGE_NAME$_LOCAL +#endif +#define $PACKAGE_NAME$_PUBLIC_TYPE +#endif + +#endif // $PACKAGE_NAME$__VISIBILITY_CONTROL_H_ diff --git a/templates/robot_description/robot_controllers.yaml b/templates/ros2_control/robot_controllers.yaml similarity index 54% rename from templates/robot_description/robot_controllers.yaml rename to templates/ros2_control/robot_controllers.yaml index 4bb5acb1..d91ef86f 100644 --- a/templates/robot_description/robot_controllers.yaml +++ b/templates/ros2_control/robot_controllers.yaml @@ -5,13 +5,16 @@ controller_manager: joint_state_controller: type: joint_state_controller/JointStateController - forward_position_controller: + forward_position_controller: # delete entry if controller is not applicable type: forward_command_controller/ForwardCommandController - position_trajectory_controller: + forward_velocity_controller: # delete entry if controller is not applicable + type: forward_command_controller/ForwardCommandController + + joint_trajectory_controller: # delete entry if controller is not applicable type: joint_trajectory_controller/JointTrajectoryController -forward_position_controller: +forward_position_controller: # delete entry if controller is not applicable ros__parameters: joints: - joint1 @@ -22,7 +25,18 @@ forward_position_controller: - joint6 interface_name: position -position_trajectory_controller: +forward_velocity_controller: # delete entry if controller is not applicable + ros__parameters: + joints: + - joint1 + - joint2 + - joint3 + - joint4 + - joint5 + - joint6 + interface_name: velocity + +joint_trajectory_controller: ros__parameters: joints: - joint1 diff --git a/templates/ros2_control/robot_forward_position_publisher.yaml b/templates/ros2_control/robot_forward_position_publisher.yaml new file mode 100644 index 00000000..e12fead7 --- /dev/null +++ b/templates/ros2_control/robot_forward_position_publisher.yaml @@ -0,0 +1,11 @@ +publisher_forward_position_controller: + ros__parameters: + + controller_name: "forward_position_controller" + wait_sec_between_publish: 5 + + goal_names: ["pos1", "pos2", "pos3", "pos4"] + pos1: [0.785, 0.785, 0.785, 0.785, 0.785, 0.785] + pos2: [0, 0, 0, 0, 0, 0] + pos3: [-0.785, -0.785, -0.785, -0.785, -0.785, -0.785] + pos4: [0, 0, 0, 0, 0, 0] diff --git a/templates/ros2_control/robot_joint_trajectory_publisher.yaml b/templates/ros2_control/robot_joint_trajectory_publisher.yaml new file mode 100644 index 00000000..f46ad24a --- /dev/null +++ b/templates/ros2_control/robot_joint_trajectory_publisher.yaml @@ -0,0 +1,19 @@ +publisher_joint_trajectory_controller: + ros__parameters: + + controller_name: "joint_trajectory_controller" + wait_sec_between_publish: 6 + + goal_names: ["pos1", "pos2", "pos3", "pos4"] + pos1: [0.785, 0.785, 0.785, 0.785, 0.785, 0.785] + pos2: [0, 0, 0, 0, 0, 0] + pos3: [-0.785, -0.785, -0.785, -0.785, -0.785, -0.785] + pos4: [0, 0, 0, 0, 0, 0] + + joints: + - joint1 + - joint2 + - joint3 + - joint4 + - joint5 + - joint6 diff --git a/templates/ros2_control/robot_ros2_control.launch.py b/templates/ros2_control/robot_ros2_control.launch.py new file mode 100644 index 00000000..2701a4b5 --- /dev/null +++ b/templates/ros2_control/robot_ros2_control.launch.py @@ -0,0 +1,65 @@ +$LICENSE$ + +import os + +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch_ros.actions import Node + +import xacro + + +def generate_launch_description(): + + # Get URDF via xacro + robot_description_path = os.path.join( + get_package_share_directory('$DESCR_PKG_NAME$'), + 'urdf', + '$ROBOT_NAME$.urdf.xacro') + robot_description_config = xacro.process_file(robot_description_path, + mappings={ + 'use_fake_hardware': 'true', + 'fake_sensor_commands': 'true' + }) + robot_description = {'robot_description': robot_description_config.toxml()} + + robot_controllers = os.path.join( + get_package_share_directory('$PKG_NAME$'), + 'config', + '$ROBOT_NAME$_controllers.yaml' + ) + rviz_config_file = os.path.join( + get_package_share_directory('$DESCR_PKG_NAME$'), + 'rviz', + '$ROBOT_NAME$.rviz' + ) + + control_node = Node( + package='controller_manager', + executable='ros2_control_node', + parameters=[robot_description, robot_controllers], + output={ + 'stdout': 'screen', + 'stderr': 'screen', + }, + ) + robot_state_pub_node = Node( + package='robot_state_publisher', + executable='robot_state_publisher', + output='both', + parameters=[robot_description] + ) + rviz_node = Node( + package='rviz2', + executable='rviz2', + name='rviz2', + output='log', + arguments=['-d', rviz_config_file], + ) + + return LaunchDescription([ + control_node, + robot_state_pub_node, + rviz_node, + ]) diff --git a/templates/ros2_control/test_forward_position_controller.launch.py b/templates/ros2_control/test_forward_position_controller.launch.py new file mode 100644 index 00000000..abba3d71 --- /dev/null +++ b/templates/ros2_control/test_forward_position_controller.launch.py @@ -0,0 +1,30 @@ +$LICENSE$ + +import os + +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch_ros.actions import Node + + +def generate_launch_description(): + + position_goals = os.path.join( + get_package_share_directory('$PKG_NAME$'), + 'config', + '$ROBOT_NAME$_forward_position_publisher.yaml' + ) + + return LaunchDescription([ + Node( + package='ros2_control_test_nodes', + executable='publisher_forward_position_controller', + parameters=[position_goals], + output={ + 'stdout': 'screen', + 'stderr': 'screen', + }, + ) + + ]) diff --git a/templates/ros2_control/test_joint_trajectory_controller.launch.py b/templates/ros2_control/test_joint_trajectory_controller.launch.py new file mode 100644 index 00000000..dfc5fb0a --- /dev/null +++ b/templates/ros2_control/test_joint_trajectory_controller.launch.py @@ -0,0 +1,30 @@ +$LICENSE$ + +import os + +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch_ros.actions import Node + + +def generate_launch_description(): + + position_goals = os.path.join( + get_package_share_directory('$PKG_NAME$'), + 'config', + '$ROBOT_NAME$_joint_trajectory_publisher.yaml' + ) + + return LaunchDescription([ + Node( + package='ros2_control_test_nodes', + executable='publisher_joint_trajectory_controller', + parameters=[position_goals], + output={ + 'stdout': 'screen', + 'stderr': 'screen', + }, + ) + + ])