From b411cc5f55d85f0859de57f923f0675acded3394 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 9 May 2025 09:40:58 +0200 Subject: [PATCH 1/8] check_links: Use lychee instead of custom script --- .github/helpers/check_urls.sh | 67 ------------------------------- .github/workflows/check_links.yml | 24 ++++++++--- .gitignore | 1 + 3 files changed, 19 insertions(+), 73 deletions(-) delete mode 100755 .github/helpers/check_urls.sh diff --git a/.github/helpers/check_urls.sh b/.github/helpers/check_urls.sh deleted file mode 100755 index f7222d115..000000000 --- a/.github/helpers/check_urls.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash - -set -e - -IGNORE_FILES="" -IGNORE_PATTERNS="" - -while getopts ":f:d:p:" opt; do - case "${opt}" in - f) - IGNORE_FILES="${OPTARG}";; - d) - IGNORE_DIRS="${OPTARG}";; - p) - IGNORE_PATTERNS="${OPTARG}";; - \?) - echo "Invalid option -$OPTARG" - exit;; - esac -done - -read -r -a ignore_files <<<"$IGNORE_FILES" -read -r -a ignore_dirs <<<"$IGNORE_DIRS" -read -r -a ignore_patterns <<<"$IGNORE_PATTERNS" - -IGNORE_FILES_ARG="" -for item in "${ignore_files[@]}"; do - IGNORE_FILES_ARG="$IGNORE_FILES_ARG --exclude=$item" -done -IGNORE_DIRS_ARG="" -for item in "${ignore_dirs[@]}"; do - IGNORE_DIRS_ARG="$IGNORE_DIRS_ARG --exclude-dir=$item" -done - -#Find URLs in code: -urls=$(grep -oP '(http|ftp|https):\/\/([a-zA-Z0-9_-]+(?:(?:\.[a-zA-Z0-9_-]+)+))([a-zA-Z0-9_.,@?^=%&:\/~+#-]*[a-zA-Z0-9_@?^=%&\/~+#-])?' -rI $IGNORE_FILES_ARG $IGNORE_DIRS_ARG) - -fail_counter=0 - -FAILED_LINKS=() -for item in $urls; do -# echo $item - skip=0 - for pattern in "${ignore_patterns[@]}"; do - [[ "$item" =~ $pattern ]] && skip=1 - done - - if [[ $skip == 1 ]]; then - echo "SKIPPING $item" - continue - fi - - filename=$(echo "$item" | cut -d':' -f1) - url=$(echo "$item" | cut -d':' -f2-) - echo -n "Checking $url from file $filename" - if ! curl --head --silent --fail "$url" 2>&1 > /dev/null; then - echo -e " \033[0;31mNOT FOUND\033[32m\n" - FAILED_LINKS+=("$url from file $filename") - ((fail_counter=fail_counter+1)) - else - printf " \033[32mok\033[0m\n" - fi -done - -echo "Failed files:" -printf '%s\n' "${FAILED_LINKS[@]}" -exit $fail_counter diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml index 4e2c4c8b0..c7f3357bb 100644 --- a/.github/workflows/check_links.yml +++ b/.github/workflows/check_links.yml @@ -11,9 +11,21 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Check URLs - run: | - .github/helpers/check_urls.sh \ - -d ".git build CMakeModules debian" \ - -f "package.xml ursim_docker.rst architecture_coarse.svg" \ - -p "vnc\.html opensource\.org\/licenses\/BSD-3-Clause" + - name: Restore lychee cache + uses: actions/cache@v4 + with: + path: .lycheecache + key: cache-lychee + restore-keys: cache-lychee + - name: Link Checker + id: lychee + uses: lycheeverse/lychee-action@v2 + with: + fail: true + args: > + --verbose + --no-progress + --cache + --cache-exclude-status 429 + --max-cache-age 2d + './**/*.md' './**/*.html' './**/*.rst' './**/*.cpp' './**/*.h' './**/*.py' diff --git a/.gitignore b/.gitignore index 141947570..729969e30 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ docs_output docs_build cross_reference ur_robot_driver/doc/generated +.lycheecache From a1bcb7e590c4ef972d48b3868e051677ffd9c8a8 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 9 May 2025 09:47:25 +0200 Subject: [PATCH 2/8] Fix links to removed ROS_INTERFACES.md file --- ur_robot_driver/README.md | 49 +++++++-------------------------------- 1 file changed, 9 insertions(+), 40 deletions(-) diff --git a/ur_robot_driver/README.md b/ur_robot_driver/README.md index 32b9f58b4..8ffcbf2d2 100644 --- a/ur_robot_driver/README.md +++ b/ur_robot_driver/README.md @@ -4,8 +4,6 @@ This package contains the actual driver for UR robots. It is part of the *univer repository and requires other packages from that repository. Also, see the [main repository's README](../README.md) for information on how to install and startup this driver. -## ROS-API -The ROS API is documented in a [standalone document](doc/ROS_INTERFACE.rst). ## Technical details The following image shows a very coarse overview of the driver's architecture. @@ -41,7 +39,7 @@ The robot won't accept script code from a remote source unless the robot is put *remote_control-mode*. However, if put into *remote_control-mode*, the program containing the **External Control** program node can't be started from the panel. For this purpose, please use the **dashboard** services to load, start and stop the main program -running on the robot. See the [ROS-API documentation](doc/ROS_INTERFACE.rst) for details on the +running on the robot. See the [Dashboard client documentation](doc/dashboard_client.rst) for details on the dashboard services. For using the **tool communication interface** on e-Series robots, a `socat` script is prepared to @@ -55,42 +53,13 @@ recommend using the controllers from the `ur_controllers` package. See it's available using the controllers from `ur_controllers`** ## A note about modes -The term **mode** is used in different meanings inside this driver. - -### Remote control mode -On the e-series the robot itself can operate in different command modes: It can be either in **local control -mode** where the teach pendant is the single point of command or in **remote control mode**, where -motions from the TP, starting & loading programs from the TP activating the freedrive mode are -blocked. Note that the **remote control mode** has to be explicitly enabled in the robot's settings -under **Settings** -> **System** -> **Remote Control**. See the robot's manual for details. - -The **remote control mode** is needed for many aspects of this driver such as - * headless mode (see below) - * sending script code to the robot - * many dashboard functionalities such as - * restarting the robot after protective / EM-Stop - * powering on the robot and do brake release - * loading and starting programs - * the `set_mode` action, as it uses the dashboard calls mentioned above - -### Headless mode -Inside this driver, there's the **headless** mode, which can be either enabled or not. When the -[headless mode](./doc/ROS_INTERFACE.rst#headless_mode-default-false) is activated, required script -code for external control will be sent to the robot directly when the driver starts. As soon as -other script code is sent to the robot either by sending it directly through this driver or by -pressing any motion-related button on the teach pendant, the script will be overwritten by this -action and has to be restarted by using the -[resend_robot_program](./doc/ROS_INTERFACE.rst#resend_robot_program-std_srvstrigger) service. If this -is necessary, you will see the output `Connection to robot dropped, waiting for new connection.` -from the driver. Note that pressing "play" on the TP won't start the external control again, but -whatever program is currently loaded on the controller. This mode doesn't require the "External -Control" URCap being installed on the robot as the program is sent to the robot directly. However, -we recommend to use the non-headless mode and leverage the `set_mode` action to start program -execution without the teach pendant. The **headless** mode might be removed in future releases. - -**Note for the e-Series:** In order to leverage the **headless** mode on the e-Series the robot must -be in **remote_control_mode** as explained above. +The term **mode** is used in different meanings inside this driver. See [Operation +Modes](doc/operation_modes.rst) for details. ## controller_stopper -A small helper node that stops and restarts ROS controllers based on a boolean status topic. When the status goes to `false`, all running controllers except a set of predefined *consistent_controllers* gets stopped. If status returns to `true` the stopped controllers are restarted. -This is done by Subscribing to a robot's running state topic. Ideally this topic is latched and only publishes on changes. However, this node only reacts on state changes, so a state published each cycle would also be fine. +A small helper node that stops and restarts ROS controllers based on a boolean status topic. When +the status goes to `false`, all running controllers except a set of predefined +*consistent_controllers* gets stopped. If status returns to `true` the stopped controllers are +restarted. This is done by Subscribing to a robot's running state topic. Ideally this topic is +latched and only publishes on changes. However, this node only reacts on state changes, so a state +published each cycle would also be fine. From d3501c227dcf1a0d7b156f981010e2820f63cbd2 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 9 May 2025 10:00:26 +0200 Subject: [PATCH 3/8] Always safe cache also on failed check --- .github/workflows/check_links.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml index c7f3357bb..9ce03e596 100644 --- a/.github/workflows/check_links.yml +++ b/.github/workflows/check_links.yml @@ -12,7 +12,8 @@ jobs: steps: - uses: actions/checkout@v4 - name: Restore lychee cache - uses: actions/cache@v4 + id: restore-cache + uses: actions/cache/restore@v4 with: path: .lycheecache key: cache-lychee @@ -29,3 +30,9 @@ jobs: --cache-exclude-status 429 --max-cache-age 2d './**/*.md' './**/*.html' './**/*.rst' './**/*.cpp' './**/*.h' './**/*.py' + - name: Save lychee cache + uses: actions/cache/save@v4 + if: always() + with: + path: .lycheecache + key: ${{ steps.restore-cache.outputs.cache-primary-key }} From e09da5da73c72bbdb0c969a2e6cc98eabbb0364b Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 9 May 2025 10:04:52 +0200 Subject: [PATCH 4/8] Ignore local IP from documentation --- .github/workflows/check_links.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml index 9ce03e596..5d43d31bb 100644 --- a/.github/workflows/check_links.yml +++ b/.github/workflows/check_links.yml @@ -30,6 +30,7 @@ jobs: --cache-exclude-status 429 --max-cache-age 2d './**/*.md' './**/*.html' './**/*.rst' './**/*.cpp' './**/*.h' './**/*.py' + --exclude '^http://192\.168\.56\.101' - name: Save lychee cache uses: actions/cache/save@v4 if: always() From 50e4adf9aa8cc4e8508d56aed4cf8f2a4aeacab4 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 9 May 2025 10:15:40 +0200 Subject: [PATCH 5/8] Use specific caches to make sure we update it on a re-run --- .github/workflows/check_links.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml index 5d43d31bb..4a1c3892f 100644 --- a/.github/workflows/check_links.yml +++ b/.github/workflows/check_links.yml @@ -16,7 +16,7 @@ jobs: uses: actions/cache/restore@v4 with: path: .lycheecache - key: cache-lychee + key: cache-lychee-${{ github.run_id }}-${{ github.run_attempt }} restore-keys: cache-lychee - name: Link Checker id: lychee From 2c99a952c17988ed4bd3545cc1821fd8f55cd0e3 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 9 May 2025 10:19:54 +0200 Subject: [PATCH 6/8] update cache restore key --- .github/workflows/check_links.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml index 4a1c3892f..c4d6c0d65 100644 --- a/.github/workflows/check_links.yml +++ b/.github/workflows/check_links.yml @@ -17,7 +17,7 @@ jobs: with: path: .lycheecache key: cache-lychee-${{ github.run_id }}-${{ github.run_attempt }} - restore-keys: cache-lychee + restore-keys: cache-lychee- - name: Link Checker id: lychee uses: lycheeverse/lychee-action@v2 From bb7ea4876c0cde373d36f0920bb7ce29aebb4230 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Fri, 9 May 2025 10:22:22 +0200 Subject: [PATCH 7/8] Use 1 thread to avoid rate limits --- .github/workflows/check_links.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml index c4d6c0d65..852784438 100644 --- a/.github/workflows/check_links.yml +++ b/.github/workflows/check_links.yml @@ -31,6 +31,7 @@ jobs: --max-cache-age 2d './**/*.md' './**/*.html' './**/*.rst' './**/*.cpp' './**/*.h' './**/*.py' --exclude '^http://192\.168\.56\.101' + --threads 1 - name: Save lychee cache uses: actions/cache/save@v4 if: always() From b7aa5c9ceac351ea9aa11a9fe9ca262d08f9f3fc Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Mon, 12 May 2025 15:47:26 +0200 Subject: [PATCH 8/8] Make sure the file globs are the last argument of the lychee call --- .github/workflows/check_links.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml index 852784438..1444d175d 100644 --- a/.github/workflows/check_links.yml +++ b/.github/workflows/check_links.yml @@ -29,9 +29,9 @@ jobs: --cache --cache-exclude-status 429 --max-cache-age 2d - './**/*.md' './**/*.html' './**/*.rst' './**/*.cpp' './**/*.h' './**/*.py' --exclude '^http://192\.168\.56\.101' - --threads 1 + --max-concurrency 1 + './**/*.md' './**/*.html' './**/*.rst' './**/*.cpp' './**/*.h' './**/*.py' - name: Save lychee cache uses: actions/cache/save@v4 if: always()