From 77a35cdb9b3c12f6012f503787eb4bfe6160fb4f Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Tue, 18 Aug 2026 13:04:03 +0200 Subject: [PATCH 01/14] Support loading robot in remote control mode --- .github/workflows/ci.yml | 12 ++- scripts/start_ursim.sh | 18 ++++- tests/CMakeLists.txt | 5 -- .../dockerursim/citadelDB/000001.sst | Bin 0 -> 462 bytes .../dockerursim/citadelDB/000001.vlog | Bin 0 -> 20 bytes tests/resources/dockerursim/citadelDB/DISCARD | Bin 0 -> 1048576 bytes .../dockerursim/citadelDB/KEYREGISTRY | 1 + .../resources/dockerursim/citadelDB/MANIFEST | Bin 0 -> 30 bytes .../polyscopex/10.13.0/ur7e/.id-counters.json | 4 + .../polyscopex/10.13.0/ur7e/00000000000.xd | Bin 0 -> 24995 bytes .../polyscopex/10.13.0/ur7e/blobs/4.blob | 1 + .../polyscopex/10.13.0/ur7e/blobs/7.blob | 1 + .../polyscopex/10.13.0/ur7e/blobs/version | Bin 0 -> 4 bytes .../programs/polyscopex/10.13.0/ur7e/xd.lck | 70 ++++++++++++++++++ tests/test_dashboard_client_x.cpp | 10 +-- 15 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 tests/resources/dockerursim/citadelDB/000001.sst create mode 100644 tests/resources/dockerursim/citadelDB/000001.vlog create mode 100644 tests/resources/dockerursim/citadelDB/DISCARD create mode 100644 tests/resources/dockerursim/citadelDB/KEYREGISTRY create mode 100644 tests/resources/dockerursim/citadelDB/MANIFEST create mode 100644 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/.id-counters.json create mode 100644 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/00000000000.xd create mode 100644 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/4.blob create mode 100644 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/7.blob create mode 100644 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/version create mode 100644 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3870b11e..45f3e7e12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,18 +75,25 @@ jobs: PROGRAM_FOLDER: 'tests/resources/dockerursim/programs/polyscopex' - ROBOT_MODEL: 'ur7e' URSIM_VERSION: '10.13.0' - PROGRAM_FOLDER: 'tests/resources/dockerursim/programs/polyscopex' + PROGRAM_FOLDER: 'tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e' + POLYSCOPE_X_WITH_REMOTE_CONTROL: 'true' + CITADEL_DB_FOLDER: 'tests/resources/dockerursim/citadelDB' steps: - uses: actions/checkout@v7 - name: start ursim run: | - scripts/start_ursim.sh -m $ROBOT_MODEL -v $URSIM_VERSION -p $PROGRAM_FOLDER -d -f DISABLED + CITADEL_DB_ARG="" + if [ -n "$CITADEL_DB_FOLDER" ]; then + CITADEL_DB_ARG="-c $CITADEL_DB_FOLDER" + fi + scripts/start_ursim.sh -m $ROBOT_MODEL -v $URSIM_VERSION -p $PROGRAM_FOLDER $CITADEL_DB_ARG -d -f DISABLED env: DOCKER_RUN_OPTS: --network ursim_net ROBOT_MODEL: ${{matrix.env.ROBOT_MODEL}} URSIM_VERSION: ${{matrix.env.URSIM_VERSION}} PROGRAM_FOLDER: ${{matrix.env.PROGRAM_FOLDER}} + CITADEL_DB_FOLDER: ${{matrix.env.CITADEL_DB_FOLDER || ''}} - id: check_polyscopex run: | if [[ "${{matrix.env.URSIM_VERSION}}" == "10."* ]]; then @@ -115,6 +122,7 @@ jobs: run: cd build && ctest --output-on-failure --output-junit junit.xml env: URSIM_VERSION: ${{matrix.env.URSIM_VERSION}} + POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL: ${{matrix.env.POLYSCOPE_X_WITH_REMOTE_CONTROL || ''}} - name: Upload test results to Codecov uses: codecov/codecov-action@v7 with: diff --git a/scripts/start_ursim.sh b/scripts/start_ursim.sh index bd9bafa56..f24508555 100755 --- a/scripts/start_ursim.sh +++ b/scripts/start_ursim.sh @@ -49,6 +49,10 @@ help() for available versions. Defaults to 'latest'" echo " -p Location from which programs are read / to which programs are written. If not specified, will fallback to ${PERSISTENT_BASE}/${ROBOT_SERIES}/${ROBOT_MODEL}/programs" + echo " -c Location of the citadelDB to mount into the URSim container. + Only used for PolyScope X. Enables persisting settings such as + remote-control mode across container restarts. + If not specified, no citadelDB volume is mounted." echo " -u Location from which URCaps are read / to which URCaps are written. If not specified, will fallback to ${PERSISTENT_BASE}/${ROBOT_SERIES}/urcaps" echo " -n Name of the docker container. Defaults to '$CONTAINER_NAME'" @@ -64,6 +68,7 @@ ROBOT_SERIES="" URSIM_VERSION=latest PORT_FORWARDING="" PROGRAM_STORAGE_ARG="" +CITADEL_DB_STORAGE_ARG="" URCAP_STORAGE_ARG="" DETACHED=false @@ -351,7 +356,7 @@ post_setup_polyscopex() } parse_arguments(){ - while getopts ":hm:v:p:u:i:f:n:dt" option; do + while getopts ":hm:v:p:c:u:i:f:n:dt" option; do case $option in h) # display Help help @@ -365,6 +370,9 @@ parse_arguments(){ p) # program_folder PROGRAM_STORAGE_ARG=${OPTARG} ;; + c) # citadel_db_folder + CITADEL_DB_STORAGE_ARG=${OPTARG} + ;; u) # urcaps_folder URCAP_STORAGE_ARG=${OPTARG} ;; @@ -492,12 +500,20 @@ main() { mkdir -p "${PROGRAM_STORAGE}" PROGRAM_STORAGE=$(realpath "$PROGRAM_STORAGE") + CITADEL_DB_MOUNT="" + if [ -n "$CITADEL_DB_STORAGE_ARG" ]; then + mkdir -p "$CITADEL_DB_STORAGE_ARG" + CITADEL_DB_STORAGE=$(realpath "$CITADEL_DB_STORAGE_ARG") + CITADEL_DB_MOUNT="-v ${CITADEL_DB_STORAGE}:/citadelDB" + fi + ROBOT_MODEL_CONTROLLER_FLAG="" verlte "10.7.0" "$URSIM_VERSION" && verlte "$URSIM_VERSION" "10.8.0" && ROBOT_MODEL_CONTROLLER_FLAG="-e ROBOT_TYPE_CONTROLLER=${ROBOT_MODEL}" docker_cmd="docker run --rm -d \ --net ursim_net --ip $IP_ADDRESS \ -v ${PROGRAM_STORAGE}:/ur/bin/backend/applications \ + $CITADEL_DB_MOUNT \ -e ROBOT_TYPE=${ROBOT_MODEL} \ $ROBOT_MODEL_CONTROLLER_FLAG \ $PORT_FORWARDING \ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6c473e454..072139e5d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,7 +23,6 @@ target_link_libraries(fake_primary_server PRIVATE ur_client_library::urcl) include(GoogleTest) option(INTEGRATION_TESTS "Build the integration tests that require a running robot / URSim" OFF) -option(POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL "Run Polyscope X tests that require remote control" OFF) option(CHECK_RTDE_DOCS_RECIPE "Fetch the RTDE documentation to auto-generate a recipe containing all output fields and check that with the RTDE client. Requires python3 and pandas and an internet connection." OFF) set(INTEGRATION_TESTS_ROBOT_IP "" CACHE STRING "If set, override the default robot IP (192.168.56.101) compiled into each integration test main() by passing --robot_ip to every ctest-registered integration test.") # Build Tests @@ -36,10 +35,6 @@ if (INTEGRATION_TESTS) set(INTEGRATION_TESTS_ROBOT_IP_ARG --robot_ip ${INTEGRATION_TESTS_ROBOT_IP}) endif() - if(POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL) - add_compile_definitions(POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL=1 ) - endif() - add_executable(rtde_tests test_rtde_client.cpp fake_rtde_server.cpp) target_link_libraries(rtde_tests PRIVATE ur_client_library::urcl GTest::gmock_main) gtest_add_tests(TARGET rtde_tests diff --git a/tests/resources/dockerursim/citadelDB/000001.sst b/tests/resources/dockerursim/citadelDB/000001.sst new file mode 100644 index 0000000000000000000000000000000000000000..fbb4c6409633f12d54430135b54e869284a0ba48 GIT binary patch literal 462 zcmZXR%SyvQ6o&t3TN-bqVx`d*w6sW}YK;}#2!bvIUAPeiDIwaljkK9EiF6|f>cS@| zF2q-G<4O>G1Hm`YC-8o+;~8=1fp5-X&VT-4W<>ik5Cf~*u32Z?H@W4OZBM95sx=F& z7gVT-^x{M5P37~G+38$%Y9epMflobd#DK5vm=OiOmFPkN=m)oJ%(q83nd@^_RT^0# z#63Bctg2^kB!P!LTHf{Kd<>jock!OGxgOYwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ T0|pEjFkrxd0RsjM82APT0Pp|- literal 0 HcmV?d00001 diff --git a/tests/resources/dockerursim/citadelDB/KEYREGISTRY b/tests/resources/dockerursim/citadelDB/KEYREGISTRY new file mode 100644 index 000000000..fbbdbb7b8 --- /dev/null +++ b/tests/resources/dockerursim/citadelDB/KEYREGISTRY @@ -0,0 +1 @@ +„x^ùQÅ`‚O0á¹ýHello Badger \ No newline at end of file diff --git a/tests/resources/dockerursim/citadelDB/MANIFEST b/tests/resources/dockerursim/citadelDB/MANIFEST new file mode 100644 index 0000000000000000000000000000000000000000..4683694ac4fc3c96686aa8ef69a60762d45e6c47 GIT binary patch literal 30 dcmZ=tNiSkxVBi2^7+`yQRO%lW3kRbCBLGA<1fT!_ literal 0 HcmV?d00001 diff --git a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/.id-counters.json b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/.id-counters.json new file mode 100644 index 000000000..b631f1db1 --- /dev/null +++ b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/.id-counters.json @@ -0,0 +1,4 @@ +{ + "application": 0, + "program": 0 +} \ No newline at end of file diff --git a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/00000000000.xd b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/00000000000.xd new file mode 100644 index 0000000000000000000000000000000000000000..723c12e82bf78ff3a52791d8f57775a184c03fa7 GIT binary patch literal 24995 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 KIJ4ts b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper"},"ur-application-variables":{"type":"ur-application-variables","version":"0.0.1","variables":{}},"universal-robots-external-control-external-control-application":{"type":"universal-robots-external-control-external-control-application","version":"1.0.0","port":50002,"robotIP":"192.168.56.1"}},"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{}},"sourcesNodes":{"robot":{"groupId":"robot","version":"1.0.0.","sources":[{"sourceID":"ur-wired-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"},{"signalID":"AO 0","direction":"OUT","valueType":"FLOAT"},{"signalID":"AO 1","direction":"OUT","valueType":"FLOAT"}],"webSocketURL":"/sources/wired-io"},{"sourceID":"ur-tool-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"}],"webSocketURL":"/sources/tool-io"}],"isDynamic":false},"ur-modbus":{"groupId":"ur-modbus","isDynamic":true,"version":"1.0.0","sources":[]},"ur-robot-io":{"type":"ur-robot-io","groupId":"ur-robot-io","isDynamic":false,"version":"1.0.2","sources":[{"sourceID":"ur-robot-wired-io","name":"Wired I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 0","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 1","valueType":"FLOAT"}]},{"sourceID":"ur-robot-tool-io","name":"Tool I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"}]}],"parameters":{"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{},"toolOutput":{"dualPinPower":false,"voltage":{"value":0,"unit":"V"},"powerOutput":{"DO 0":1,"DO 1":1}}},"migrateSourceConfigDone":true}}},"safety":{"settings":{"io":{"automaticModeSafeguardResetInput":{"name":"automaticModeSafeguardResetInput","valueA":255,"valueB":255},"automaticModeSafeguardStopInput":{"name":"automaticModeSafeguardStopInput","valueA":255,"valueB":255},"emergencyStopInput":{"name":"emergencyStopInput","valueA":255,"valueB":255},"notReducedModeOutput":{"name":"notReducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"operationalModeInput":{"name":"operationalModeInput","valueA":255,"valueB":255},"reducedModeInput":{"name":"reducedModeInput","valueA":255,"valueB":255},"reducedModeOutput":{"name":"reducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotMovingOutput":{"name":"robotMovingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotNotStoppingOutput":{"name":"robotNotStoppingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeHomeOutput":{"name":"safeHomeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeguardResetInput":{"name":"safeguardResetInput","valueA":0,"valueB":1},"systemEmergencyStoppedOutput":{"name":"systemEmergencyStoppedOutput","ossdEnabled":false,"valueA":255,"valueB":255},"threePositionSwitchInput":{"name":"threePositionSwitchInput","valueA":255,"valueB":255},"freedriveEnabledInput":{"name":"freedriveEnabledInput","valueA":255,"valueB":255},"threePositionEnablingStopOutput":{"name":"threePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255},"notThreePositionEnablingStopOutput":{"name":"notThreePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255}},"major":5,"minor":14,"normalJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"normalJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"normalRobotLimits":{"elbowForce":150,"elbowSpeed":1.5,"momentum":25,"power":300,"stoppingDistance":0.5,"stoppingTime":0.4,"toolForce":150,"toolSpeed":1.5},"reducedJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"reducedJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"reducedRobotLimits":{"elbowForce":120,"elbowSpeed":0.75,"momentum":10,"power":200,"stoppingDistance":0.3,"stoppingTime":0.3,"toolForce":120,"toolSpeed":0.75},"safetyHardware":{"injectionMoldingMachineInterface":"NONE","teachPendant":"NORMAL"},"safetyPlanes":{"planes":[{"id":"c7314701-34ec-1674-a33d-a226b1cd34bc","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"ed4d303b-25c3-9ef0-867d-5dd3d70201f9","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"79ace36e-a147-044d-c436-583abde29c09","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"52d5930b-4200-b2c2-ff14-ca60642554cd","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e1554217-d3da-bc37-57cc-d8e868766608","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"643c8131-1f1d-db3f-6447-d062bd6a41da","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"b531cb99-8f5b-2ecd-0da6-8b0009840661","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e367d34e-fba3-5a65-f9ed-0c4925240d21","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"}],"ioSafetyPlanes":[{"id":"dcbb3122-97a6-3196-c6fd-c234fc103963","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a1554adb-2b98-f7ec-a7d7-9877ebe7939c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"fb53caf6-eb68-bab8-bddc-4ccb8dd42f25","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"79c00e8d-7415-4510-1e40-6742240e86ff","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"70f45544-4998-52f8-5a91-adaf39459678","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a8678cc2-fd26-4c10-a10c-4904469c6e08","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"e6225a34-0085-7027-2f23-9cedb6cb3688","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"32d5f884-e587-e9fe-8970-456fff173c7f","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"}]},"safetySafeHome":{"base":-1,"elbow":-1,"shoulder":-1,"wrist1":-1,"wrist2":-1,"wrist3":-1,"enabled":false},"safetyAPIParameters":{"numberOfClients":0,"clients":[]},"safetyFieldbusses":{"enablePROFIsafe":false,"sourceAddressPROFIsafe":0,"destAddressPROFIsafe":0,"modeControlPROFIsafe":false},"threePosition":{"allowManualHighSpeed":true,"useTeachPendantAs3PE":false},"toolDirection":{"limitDeviation":6.2831855,"limitDirection":{"x":0,"y":0,"z":1},"limitRestriction":"DISABLED","tcp":{"id":"toolFlangeTcpId","name":"Tool_flange"},"toolPan":0,"toolTilt":0,"limitTilt":0,"limitRotation":0},"toolPositions":{"toolPositions":[{"name":"Tool Flange","center":{"x":0,"y":0,"z":0},"radius":0,"definition":2},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0}]},"normalWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"},"reducedWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"}},"crc":"2850523693","confirmed":true},"operatorScreens":[{"type":"ur-operator-screen-default","version":"0.0.2","parameters":{"status":[],"configuration":[]}}],"sidebarItems":[{"type":"ur-global-variables","version":"1.0.0","disabled":{"master":false,"automaticMode":false,"remoteMode":true}},{"type":"ur-log-messages-sidebar","version":"0.0.1","disabled":{"master":false,"automaticMode":false,"remoteMode":true}}],"activeOperatorScreen":"ur-operator-screen-default","smartSkills":[{"name":"Align to Plane","enabled":true,"type":"ur-align-to-plane","parameters":{"radius":0.05,"push_force":20,"n_plane_points":3,"max_distance":0.25,"velocity_slow":0.001,"velocity_search":0.035,"velocity_move":0.1,"acceleration":0.1}},{"name":"Align Z to Nearest Axis","enabled":true,"type":"ur-align-z-to-nearest-axis"},{"name":"Center","enabled":true,"type":"ur-center","parameters":{"push_force":10,"velocity_move":0.05,"acc_move":0.2,"max_radius_search":0.05,"num_fingers":3}},{"name":"Freedrive","enabled":true,"type":"ur-freedrive","version":"1.0.0","recordingFrequency":50,"recordingSignals":["timestamp","target_q","actual_TCP_pose","tcp_offset"]},{"name":"Move into Contact","enabled":true,"type":"ur-move-into-contact","parameters":{"force":10,"velocity":0.05,"acceleration":0.2,"max_distance":0.25,"retract":0}},{"name":"Retract","enabled":true,"type":"ur-retract","parameters":{"distance":-0.1,"acceleration":0.4,"velocity":0.1}},{"name":"Put into Box","enabled":false,"type":"ur-put-in-box","version":"1.0.0"},{"name":"Custom","enabled":false,"type":"ur-custom-smart-skill","parameters":{"includePreamble":true,"includeModules":false},"version":"1.0.0"},{"name":"Home","enabled":true,"type":"ur-position","version":"1.1.2","parameters":{"actualWaypoint":{"frame":"base","pose":{"position":[-1.8246917738038495E-9,-0.2329000001676105,1.0793999999522315],"orientation":[3.987257497300885E-9,2.2214414675120993,-2.221441467056474]},"qNear":{"base":0,"shoulder":-1.5707963249999999,"elbow":0,"wrist1":-1.5707963249999999,"wrist2":0,"wrist3":0}},"variable":{"name":"Home","reference":false,"type":"$$Variable","valueType":"waypoint","id":"8dbe361a-a570-5719-3461-20743ddc9310","_IDENTIFIER":"VariableDeclaration"}}}]},"script":{"script":"set_safety_mode_transition_hardness(1)\nreset_world_model()\nset_input_actions_to_default()\nset_analog_outputdomain(0,0)\nset_analog_outputdomain(1,0)\nset_standard_analog_input_domain(0,0)\nset_standard_analog_input_domain(1,0)\nset_tool_output_mode(0)\nset_tool_voltage(0)\nset_tool_digital_output_mode(0,1)\nset_tool_digital_output_mode(1,1)\nset_tool_analog_input_domain(0,0)\nset_tool_analog_input_domain(1,0)\nset_gravity([0, 0, 9.82])\nlocal existingBaseParent = get_frame_parent(\"base\")\nlocal basePose = get_pose(\"base\", existingBaseParent)\nbasePose[3] = 0\nbasePose[4] = 0\nbasePose[5] = 0\nmove_frame(\"base\", basePose, existingBaseParent)\nglobal base = \"base\"\nglobal tcp = \"tcp\"\nglobal world = \"world\"\nglobal flange = \"flange\"\nset_target_payload(0, [0, 0, 0], [0, 0, 0, 0, 0, 0])\nset_tcp(p[0, 0, 0, 0, 0, 0], \"Tool_flange\")\n# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper\n# Waypoint variable for Home smart skill\nglobal Home = struct(p=p[-1.8246917738038495e-9, -0.2329000001676105, 1.0793999999522315, 3.987257497300885e-9, 2.2214414675120993, -2.221441467056474], frame=\"base\", q=[0, -1.5707963249999999, 0, -1.5707963249999999, 0, 0])\n# Start of Align to Plane\n###\n# Align to plane will touch up a plane by moving the robot into contact with the table or part in several locations to determine its orientation. Afterwards the robot will orient its tool to the plane.\n# @param radius number Radius [m] of the circle within the plane will be touched up\n# @param push_force number How hard to robot pushed against the plane\n# @param n_plane_points number Number of points that the robot uses to compute the plane\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_slow number Velocity when pressing downwards\n# @param velocity_search number Velocity used when approaching the touch up point\n# @param velocity_move number Velocity used in freespace\n# @param acceleration number Acceleration of the robot\n# @param direction array 3D vector determining the direction of the TCP for touching up the plane\n###\ndef ur_align_to_plane(radius = 0.05, push_force = 20, n_plane_points = 3, max_distance = 0.25, velocity_slow = 0.001, velocity_search = 0.035, velocity_move = 0.10, acceleration = 0.1, direction = [0, 0, 1]):\n local angle = 2 * PI / n_plane_points\n local start_pos = get_target_tcp_pose()\n local retract_distance = -0.015\n ur_move_tcp_direction(retract_distance, direction, velocity_move, acceleration, 0)\n sleep(0.25)\n zero_ftsensor()\n local cnt = 0\n local t_base_target = get_target_tcp_pose()\n local mean_point = [0.0, 0.0, 0.0]\n local A = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]\n local b = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n while cnt < n_plane_points:\n local new_pos = pose_trans(t_base_target, p[cos(angle * cnt) * radius, sin(angle * cnt) * radius, 0.0, 0.0, 0.0, 0.0])\n local blend_radius = norm(point_dist(get_actual_tcp_pose(), new_pos))/5\n movel(new_pos, a = acceleration, v = velocity_move, r = blend_radius)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_search, acceleration, push_force)\n local movement = normalize(direction * -1) * 0.0005\n local target_pose = pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose)\n sleep(0.2)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_slow, acceleration, push_force)\n sleep(0.2)\n while (not is_steady()):\n sync()\n end\n local poked_point = get_target_tcp_pose()\n poked_point = pose_trans(inv(t_base_target), poked_point)\n A[cnt, 0] = poked_point[0]\n A[cnt, 1] = poked_point[1]\n A[cnt, 2] = 1.0\n b[cnt] = poked_point[2]\n mean_point = mean_point + [poked_point[0], poked_point[1], poked_point[2]]\n movel(new_pos, a = 0.2, v = velocity_move, r = blend_radius)\n cnt = cnt + 1\n end\n mean_point = mean_point / n_plane_points\n cnt = 0\n while cnt < n_plane_points:\n local cntj = 0\n while cntj < 2:\n A[cnt, cntj] = A[cnt, cntj] - mean_point[cntj]\n cntj = cntj + 1\n end\n b[cnt] = b[cnt] - mean_point[2]\n cnt = cnt + 1\n end\n local x1 = inv(transpose(A) * A) * transpose(A) * b\n local x = normalize([x1[0], x1[1], -1])\n local d = dot(mean_point, x)\n local dval = dot(direction, x)\n if dval < 0:\n x = -x\n dval = -dval\n end\n local eaa = [0.0, 0.0, 0.0]\n local EPSILON = 1e-10\n if norm(dval - 1) < EPSILON:\n # if the projection is close to 1 then the angle between the vectors are almost 0 and we cannot\n # reliably determine the perpendicular axis.\n # A good approximation is therefore just to set the EAA equal to 0.\n eaa = [0.0, 0.0, 0.0]\n else:\n local axis = cross(direction, x)\n local eaa = normalize(axis) * acos(dval)\n end\n local t_base_target_aligned = pose_trans(t_base_target, p[0, 0, 0, eaa[0], eaa[1], eaa[2]])\n movel(t_base_target_aligned, a = 0.2, v = velocity_move)\nend\n# End of Align to Plane\n# Start of Align Z to Nearest Axis\n###\n# Aligns the TCP Z axis to the nearest axis of the given frame\n# @param frame_id string frame_id to lookup frame\n###\ndef ur_align_z_to_nearest_axis(frame_id = \"world\"):\n ###\n # Given a reference frame as input this function returns a struct with the nearest\n # pose which aligns the z-axis of the robot TCP with the z-axis of the given reference frame.\n # The pose is in the reference of the given frame.\n # @param frame bool frame\n # @returns struct pose, distance, referencePose\n ###\n def get_aligned_z_pose(frame):\n local actualPose = get_actual_tcp_pose()\n local actualPoseInFrame = pose_trans(pose_inv(frame), actualPose)\n # Create rotation vector and convert that to RPY representation\n local actualRotInFrame = [actualPoseInFrame[3], actualPoseInFrame[4], actualPoseInFrame[5]]\n local actRPY = rotvec2rpy(actualRotInFrame)\n # Set RX and RY to 0 and convert back to rotation vector\n local alignedRot = rpy2rotvec([0, 0, actRPY[2]])\n local alignedRotFlipped = rpy2rotvec([PI, 0, actRPY[2]])\n local zUpPose = actualPoseInFrame\n zUpPose[3] = alignedRot[0]\n zUpPose[4] = alignedRot[1]\n zUpPose[5] = alignedRot[2]\n zUpStruct = struct(pose = zUpPose, distance=pose_dist(actualPoseInFrame, zUpPose), referencePose=frame)\n local zDownPose = actualPoseInFrame\n zDownPose[3] = alignedRotFlipped[0]\n zDownPose[4] = alignedRotFlipped[1]\n zDownPose[5] = alignedRotFlipped[2]\n local zDownStruct = struct(pose = zDownPose, distance=pose_dist(actualPoseInFrame, zDownPose), referencePose=frame)\n # Return the solution which is closer to the current robot pose\n if (zDownStruct.distance > zUpStruct.distance):\n return zUpStruct\n else:\n return zDownStruct\n end\n end\n local frame = get_pose(frame_id)\n # Rotate the given frame so that Z can be align to X-Y-Z respectively \n local rotZtoX = rpy2rotvec([0,0.5*PI,0])\n local rotZtoY = rpy2rotvec([0.5*PI,0,0])\n local rotZtoZ = rpy2rotvec([0,0,0])\n # Get aligned poses for each of the rotated frames\n local structAlignedToX = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoX[0],rotZtoX[1],rotZtoX[2]]))\n structAlignedToY = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoY[0],rotZtoY[1],rotZtoY[2]]))\n structAlignedToZ = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoZ[0],rotZtoZ[1],rotZtoZ[2]]))\n # Find the nearest alignement\n local structAligned = structAlignedToZ\n if(structAligned.distance > structAlignedToX.distance):\n structAligned = structAlignedToX \n end\n if(structAligned.distance > structAlignedToY.distance):\n structAligned = structAlignedToY \n end\n # Move the robot to the aligned pose\n movel(pose_trans(get_actual_tcp_pose(), p[0,0,0.00001,0,0,0]), v = 0.1)\n movel(pose_trans(structAligned.referencePose, structAligned.pose ), v = 0.1)\nend\n# End of Align Z to Nearest Axis\n# Start of Center to Object\n###\n# Centers to an object by touching the externals of it. It works well for fixtured or heavy parts.\n# @param push_force number Force the robot uses to determine if a contact has been achieved\n# @param velocity_move number Velocity in freespace\n# @param velocity_search number First move is used then search\n# @param acc_move number Acceleration in freespace\n# @param max_radius_search number Maximum search radius\n# @param num_fingers number Number of fingers that the gripper has\n###\ndef ur_center_to_object(push_force = 10, velocity_move = 0.10, velocity_search = 0.01, acc_move = 0.2, max_radius_search = 0.05, num_fingers = 3):\n def compute_circle_center(p_list):\n # Compute the circle center by circular regression\n # Source: https://math.stackexchange.com/questions/2898295/how-to-quickly-fit-a-circle-by-given-random-arc-points\n local itr = 0\n local x = 0\n local y = 1\n \n local m1 = [[0,0,0],[0,0,0],[0,0,0]]\n local m2 = [[0,0],[0,0],[0,0]]\n local m3 = [[0],[0],[0]]\n \n while(itr < get_list_length(p_list)):\n local p = p_list[itr]\n \n if(p_list[itr] == p[0,0,0,0,0,0]):\n break\n end\n \n m1[0,0] = m1[0,0] + (p[x]*p[x])\n m1[0,1] = m1[0,1] + (p[x]*p[y])\n m1[0,2] = m1[0,2] + (p[x])\n \n m1[1,0] = m1[1,0] + (p[x]*p[y])\n m1[1,1] = m1[1,1] + (p[y]*p[y])\n m1[1,2] = m1[1,2] + (p[y])\n \n m1[2,0] = m1[2,0] + (p[x])\n m1[2,1] = m1[2,1] + (p[y])\n \n m2[0,0] = m2[0,0] + (pow(p[x], 3))\n m2[0,1] = m2[0,1] + (p[x] * pow(p[y], 2))\n \n m2[1,0] = m2[1,0] + (pow(p[y], 3))\n m2[1,1] = m2[1,1] + (pow(p[x], 2) * p[y])\n \n m2[2,0] = m2[2,0] + (pow(p[x], 2))\n m2[2,1] = m2[2,1] + (pow(p[y], 2))\n \n itr = itr +1\n end\n \n if(itr < 2):\n return p[0,0,0,0,0,0]\n elif(itr > get_list_length(p_list)):\n return p[0,0,0,0,0,0]\n end\n \n m1[0,0] = 2 * m1[0,0]\n m1[0,1] = 2 * m1[0,1]\n m1[1,0] = 2 * m1[1,0]\n m1[1,1] = 2 * m1[1,1]\n m1[2,0] = 2 * m1[2,0]\n m1[2,1] = 2 * m1[2,1]\n m1[2,2] = itr\n m3[0,0] = m2[0,0] + m2[0,1]\n m3[1,0] = m2[1,0] + m2[1,1]\n m3[2,0] = m2[2,0] + m2[2,1]\n \n local center = inv(m1) * m3\n \n return p[center[0,0], center[1,0],0,0,0,0]\n end\n \n def sanity_checked_move(p_org, p_new, max_diff, acc, vel):\n if (pose_dist(p_org, p_new) > max_diff):\n movel(p_org, a = acc, v = vel)\n popup(\"New pose is too far away from original. Returning to original\", title = \"Failed\", warning = False, error = True, blocking = True)\n else:\n movel(p_new, a = acc, v = vel)\n end\n end\n # Start by zeroing the FT sensor\n sleep(0.25)\n zero_ftsensor()\n local p_start = get_actual_tcp_pose()\n local p0 = p[0,0,0,0,0,0]\n local DIR_X = [1, 0, 0]\n if (num_fingers == 2):\n local dir_list = [DIR_X, -DIR_X, DIR_X, -DIR_X]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0]\n elif (num_fingers == 3):\n local DIR_P1 = DIR_X\n local DIR_P2 = [-1 / 2, sqrt(3.0) / 2.0, 0]\n local DIR_P3 = [-1 / 2, -sqrt(3.0) / 2.0, 0]\n local dir_list = [DIR_P1, DIR_P2, DIR_P3, DIR_P1, DIR_P2, DIR_P3]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0, p0, p0]\n else:\n popup(\"Number of fingers not supported\")\n halt\n end\n # Loop through directions\n local it = 0\n local dir_list_size = size(dir_list)\n local dir_list_length = dir_list_size[0]\n while(it < dir_list_length):\n # Move to starting position if more than 3 positions is stored then calculate a new starting position\n if(it < 3):\n movel(pose_trans(p_start, start_offset[it]), a = acc_move, v = velocity_move)\n else:\n local p_start_temp = pose_trans(pose_trans(p_start, compute_circle_center(p_list)), start_offset[it])\n local p_start_w_offset = pose_trans(p_start, start_offset[it])\n sanity_checked_move(p_start_w_offset, p_start_temp, max_radius_search, acc_move, velocity_move)\n end\n local p_start_temp = get_actual_tcp_pose()\n # Move into contact and store contact point\n sleep(0.1)\n local contact_point = ur_move_until_force(distance = max_radius_search, direction = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]], velocity = velocity_search, acceleration = acc_move, stop_force = push_force)\n \n local dir = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]]\n dir = normalize(dir) * 0.05\n contact_point = pose_trans(contact_point, p[dir[0], dir[1], dir[2], 0, 0, 0])\n p_list[it] = pose_trans(pose_inv(p_start), contact_point)\n # Move out of contact\n movel(p_start_temp, a = acc_move, v = velocity_move)\n it = it + 1\n end\n # Find circle center based on n stored points\n local center_offset_xy = compute_circle_center(p_list)\n local p_center = pose_trans(p_start, center_offset_xy)\n \n # Move the robot to the center if it can\n sanity_checked_move(p_start, p_center, max_radius_search, acc_move, velocity_move)\nend\n# End of Center to Object\n# Start of Move Into Contact\n###\n# Moves the robot into contact in the TCP direction set\n# @param force number Force that determines when a contact has been achieved\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_search number velocity_search\n# @param retract number Retract distance after a contact has been found\n# @param move_tcp_dir array TCP direction (3D vector)\n# @param zero_ft_on_start bool Determines if the force-torque sensor should be zeroed on start\n###\ndef ur_move_into_contact(force = 10, velocity = 0.05, acceleration = 0.1, max_distance = 0.25, retract = 0.0, move_tcp_dir = [0, 0, 1], zero_ft_on_start = True):\n # Zero the force torque sensor\n if (zero_ft_on_start):\n sleep(0.25)\n zero_ftsensor()\n end\n # Move the robot\n ur_move_until_force(max_distance, move_tcp_dir, velocity, acceleration, force)\n # If a retract distance is set, move the robot back to that position\n if (retract != 0):\n # Compute position offset from TCP direction and retract distance\n local position = normalize(move_tcp_dir) * retract\n movel(pose_trans(get_actual_tcp_pose(), p[position[0], position[1], position[2], 0, 0, 0]))\n end\nend\n# End of Move Into Contact\n# Start of Retract\n###\n# Retract in the TCP direction set\n# @param distance number Retraction distance\n# @param direction array TCP direction to move in (3D vector)\n# @param acceleration number Acceleration used by the robot\n# @param velocity number Velocity used by the robot\n###\ndef ur_retract(distance = -0.1, direction = [0, 0, 1], acceleration = 0.4, velocity = 0.1):\n local movement = normalize(direction) * distance\n movel(pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0]), a = acceleration, v = velocity)\nend\n# End of Retract","nodeIDList":[]}} \ No newline at end of file diff --git a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/7.blob b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/7.blob new file mode 100644 index 000000000..b47e7520f --- /dev/null +++ b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/7.blob @@ -0,0 +1 @@ +{"jsonContent":{"applicationContributions":{"ur-mounting":{"type":"ur-mounting","version":"0.0.1","mounting":{"baseAngle":{"value":0,"unit":"deg"},"tiltAngle":{"value":0,"unit":"deg"}}},"ur-frames":{"type":"ur-frames","version":"0.0.7","framesList":[{"name":"base","nameVariable":{"name":"base","reference":false,"type":"$$Variable","valueType":"frame","id":"17c5e7dd-f5a3-ef14-19fb-881f12fb655a","_IDENTIFIER":"VariableDeclaration"},"parent":"world","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"tcp","nameVariable":{"name":"tcp","reference":false,"type":"$$Variable","valueType":"frame","id":"d96aa509-ec33-3065-09fe-4a23a9dabd7e","_IDENTIFIER":"VariableDeclaration"},"parent":"flange","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"world","nameVariable":{"name":"world","reference":false,"type":"$$Variable","valueType":"frame","id":"2b2fe453-df5f-d8b9-f496-673d978f005a","_IDENTIFIER":"VariableDeclaration"},"pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"flange","nameVariable":{"name":"flange","reference":false,"type":"$$Variable","valueType":"frame","id":"2e6d33a2-5ee3-b61d-e217-481053c1e028","_IDENTIFIER":"VariableDeclaration"},"parent":"base","pose":{"position":[0,0,0],"orientation":[0,0,0]}}]},"ur-grid-pattern":{"type":"ur-grid-pattern","version":"0.0.3","grids":[{"grid":{"name":"grid","reference":false,"type":"$$Variable","valueType":"grid","id":"48df2b01-e230-53d6-7907-915e1d764eac","_IDENTIFIER":"VariableDeclaration"},"waypoint":{"name":"grid_iterator","reference":false,"type":"$$Variable","valueType":"waypoint","id":"b93685a1-ba10-44ac-a2e5-22003cff5c6d","_IDENTIFIER":"VariableDeclaration"},"corners":[null,null,null,null],"numRows":4,"numColumns":5}]},"ur-end-effector":{"type":"ur-end-effector","version":"0.0.2","endEffectors":[{"id":"2e7f4047-a637-aa1f-d957-30b7358a50a6","name":"Robot","payload":{"weight":{"value":0,"unit":"kg"}},"cog":{"cx":{"value":0,"unit":"m"},"cy":{"value":0,"unit":"m"},"cz":{"value":0,"unit":"m"}},"inertia":{"Ixx":{"value":0,"unit":"kg*m^2"},"Iyy":{"value":0,"unit":"kg*m^2"},"Izz":{"value":0,"unit":"kg*m^2"},"Ixy":{"value":0,"unit":"kg*m^2"},"Ixz":{"value":0,"unit":"kg*m^2"},"Iyz":{"value":0,"unit":"kg*m^2"}},"useCustomInertia":false,"tcps":[{"id":"c2f98e6f-a449-4e6a-a701-9f8a54e67ef4","name":"Tool_flange","x":{"value":0,"unit":"m"},"y":{"value":0,"unit":"m"},"z":{"value":0,"unit":"m"},"rx":{"value":0,"unit":"rad"},"ry":{"value":0,"unit":"rad"},"rz":{"value":0,"unit":"rad"}}]}],"defaultTcp":{"endEffectorId":"2e7f4047-a637-aa1f-d957-30b7358a50a6","tcpId":"c2f98e6f-a449-4e6a-a701-9f8a54e67ef4"}},"ur-motion-profiles":{"type":"ur-motion-profiles","version":"0.0.1","moveProfiles":{"joint":[{"isDefault":false,"profile":{"name":"Joint_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"0ef8f8e8-cde2-9d57-cc5b-c7208c9fe3c2","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Joint_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"5346fd60-6b3d-e0a9-cfaa-3c2658924408","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"linear":[{"isDefault":false,"profile":{"name":"Linear_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"7c2febc9-1491-589e-1501-42442cc6893c","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Linear_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"8b590dc2-ec8b-3637-004c-9a57e7e84276","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"process":[{"isDefault":true,"profile":{"name":"Process","reference":false,"type":"$$Variable","valueType":"profile","id":"1e798479-1637-e766-859b-7040d73ebaf7","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"Classic","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2}}}]}},"ur-smart-skills":{"type":"ur-smart-skills","version":"0.0.3","preamble":"# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper"},"ur-application-variables":{"type":"ur-application-variables","version":"0.0.1","variables":{}},"universal-robots-external-control-external-control-application":{"type":"universal-robots-external-control-external-control-application","version":"1.0.0","port":50002,"robotIP":"192.168.56.1"}},"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{}},"sourcesNodes":{"robot":{"groupId":"robot","version":"1.0.0.","sources":[{"sourceID":"ur-wired-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"},{"signalID":"AO 0","direction":"OUT","valueType":"FLOAT"},{"signalID":"AO 1","direction":"OUT","valueType":"FLOAT"}],"webSocketURL":"/sources/wired-io"},{"sourceID":"ur-tool-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"}],"webSocketURL":"/sources/tool-io"}],"isDynamic":false},"ur-modbus":{"groupId":"ur-modbus","isDynamic":true,"version":"1.0.0","sources":[]},"ur-robot-io":{"type":"ur-robot-io","groupId":"ur-robot-io","isDynamic":false,"version":"1.0.2","sources":[{"sourceID":"ur-robot-wired-io","name":"Wired I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 0","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 1","valueType":"FLOAT"}]},{"sourceID":"ur-robot-tool-io","name":"Tool I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"}]}],"parameters":{"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{},"toolOutput":{"dualPinPower":false,"voltage":{"value":0,"unit":"V"},"powerOutput":{"DO 0":1,"DO 1":1}}},"migrateSourceConfigDone":true}}},"safety":{"settings":{"io":{"automaticModeSafeguardResetInput":{"name":"automaticModeSafeguardResetInput","valueA":255,"valueB":255},"automaticModeSafeguardStopInput":{"name":"automaticModeSafeguardStopInput","valueA":255,"valueB":255},"emergencyStopInput":{"name":"emergencyStopInput","valueA":255,"valueB":255},"notReducedModeOutput":{"name":"notReducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"operationalModeInput":{"name":"operationalModeInput","valueA":255,"valueB":255},"reducedModeInput":{"name":"reducedModeInput","valueA":255,"valueB":255},"reducedModeOutput":{"name":"reducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotMovingOutput":{"name":"robotMovingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotNotStoppingOutput":{"name":"robotNotStoppingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeHomeOutput":{"name":"safeHomeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeguardResetInput":{"name":"safeguardResetInput","valueA":0,"valueB":1},"systemEmergencyStoppedOutput":{"name":"systemEmergencyStoppedOutput","ossdEnabled":false,"valueA":255,"valueB":255},"threePositionSwitchInput":{"name":"threePositionSwitchInput","valueA":255,"valueB":255},"freedriveEnabledInput":{"name":"freedriveEnabledInput","valueA":255,"valueB":255},"threePositionEnablingStopOutput":{"name":"threePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255},"notThreePositionEnablingStopOutput":{"name":"notThreePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255}},"major":5,"minor":14,"normalJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"normalJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"normalRobotLimits":{"elbowForce":150,"elbowSpeed":1.5,"momentum":25,"power":300,"stoppingDistance":0.5,"stoppingTime":0.4,"toolForce":150,"toolSpeed":1.5},"reducedJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"reducedJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"reducedRobotLimits":{"elbowForce":120,"elbowSpeed":0.75,"momentum":10,"power":200,"stoppingDistance":0.3,"stoppingTime":0.3,"toolForce":120,"toolSpeed":0.75},"safetyHardware":{"injectionMoldingMachineInterface":"NONE","teachPendant":"NORMAL"},"safetyPlanes":{"planes":[{"id":"c7314701-34ec-1674-a33d-a226b1cd34bc","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"ed4d303b-25c3-9ef0-867d-5dd3d70201f9","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"79ace36e-a147-044d-c436-583abde29c09","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"52d5930b-4200-b2c2-ff14-ca60642554cd","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e1554217-d3da-bc37-57cc-d8e868766608","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"643c8131-1f1d-db3f-6447-d062bd6a41da","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"b531cb99-8f5b-2ecd-0da6-8b0009840661","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e367d34e-fba3-5a65-f9ed-0c4925240d21","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"}],"ioSafetyPlanes":[{"id":"dcbb3122-97a6-3196-c6fd-c234fc103963","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a1554adb-2b98-f7ec-a7d7-9877ebe7939c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"fb53caf6-eb68-bab8-bddc-4ccb8dd42f25","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"79c00e8d-7415-4510-1e40-6742240e86ff","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"70f45544-4998-52f8-5a91-adaf39459678","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a8678cc2-fd26-4c10-a10c-4904469c6e08","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"e6225a34-0085-7027-2f23-9cedb6cb3688","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"32d5f884-e587-e9fe-8970-456fff173c7f","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"}]},"safetySafeHome":{"base":-1,"elbow":-1,"shoulder":-1,"wrist1":-1,"wrist2":-1,"wrist3":-1,"enabled":false},"safetyAPIParameters":{"numberOfClients":0,"clients":[]},"safetyFieldbusses":{"enablePROFIsafe":false,"sourceAddressPROFIsafe":0,"destAddressPROFIsafe":0,"modeControlPROFIsafe":false},"threePosition":{"allowManualHighSpeed":true,"useTeachPendantAs3PE":false},"toolDirection":{"limitDeviation":6.2831855,"limitDirection":{"x":0,"y":0,"z":1},"limitRestriction":"DISABLED","tcp":{"id":"toolFlangeTcpId","name":"Tool_flange"},"toolPan":0,"toolTilt":0,"limitTilt":0,"limitRotation":0},"toolPositions":{"toolPositions":[{"name":"Tool Flange","center":{"x":0,"y":0,"z":0},"radius":0,"definition":2},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0}]},"normalWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"},"reducedWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"}},"crc":"2850523693","confirmed":true},"operatorScreens":[{"type":"ur-operator-screen-default","version":"0.0.2","parameters":{"status":[],"configuration":[]}}],"sidebarItems":[{"type":"ur-global-variables","version":"1.0.0","disabled":{"master":false,"automaticMode":false,"remoteMode":true}},{"type":"ur-log-messages-sidebar","version":"0.0.1","disabled":{"master":false,"automaticMode":false,"remoteMode":true}}],"activeOperatorScreen":"ur-operator-screen-default","smartSkills":[{"name":"Align to Plane","enabled":true,"type":"ur-align-to-plane","parameters":{"radius":0.05,"push_force":20,"n_plane_points":3,"max_distance":0.25,"velocity_slow":0.001,"velocity_search":0.035,"velocity_move":0.1,"acceleration":0.1}},{"name":"Align Z to Nearest Axis","enabled":true,"type":"ur-align-z-to-nearest-axis"},{"name":"Center","enabled":true,"type":"ur-center","parameters":{"push_force":10,"velocity_move":0.05,"acc_move":0.2,"max_radius_search":0.05,"num_fingers":3}},{"name":"Freedrive","enabled":true,"type":"ur-freedrive","version":"1.0.0","recordingFrequency":50,"recordingSignals":["timestamp","target_q","actual_TCP_pose","tcp_offset"]},{"name":"Move into Contact","enabled":true,"type":"ur-move-into-contact","parameters":{"force":10,"velocity":0.05,"acceleration":0.2,"max_distance":0.25,"retract":0}},{"name":"Retract","enabled":true,"type":"ur-retract","parameters":{"distance":-0.1,"acceleration":0.4,"velocity":0.1}},{"name":"Put into Box","enabled":false,"type":"ur-put-in-box","version":"1.0.0"},{"name":"Custom","enabled":false,"type":"ur-custom-smart-skill","parameters":{"includePreamble":true,"includeModules":false},"version":"1.0.0"},{"name":"Home","enabled":true,"type":"ur-position","version":"1.1.2","parameters":{"actualWaypoint":{"frame":"base","pose":{"position":[-1.8246917738038495E-9,-0.2329000001676105,1.0793999999522315],"orientation":[3.987257497300885E-9,2.2214414675120993,-2.221441467056474]},"qNear":{"base":0,"shoulder":-1.5707963249999999,"elbow":0,"wrist1":-1.5707963249999999,"wrist2":0,"wrist3":0}},"variable":{"name":"Home","reference":false,"type":"$$Variable","valueType":"waypoint","id":"8dbe361a-a570-5719-3461-20743ddc9310","_IDENTIFIER":"VariableDeclaration"}}}]},"script":{"script":"set_safety_mode_transition_hardness(1)\nreset_world_model()\nset_input_actions_to_default()\nset_analog_outputdomain(0,0)\nset_analog_outputdomain(1,0)\nset_standard_analog_input_domain(0,0)\nset_standard_analog_input_domain(1,0)\nset_tool_output_mode(0)\nset_tool_voltage(0)\nset_tool_digital_output_mode(0,1)\nset_tool_digital_output_mode(1,1)\nset_tool_analog_input_domain(0,0)\nset_tool_analog_input_domain(1,0)\nset_gravity([0, 0, 9.82])\nlocal existingBaseParent = get_frame_parent(\"base\")\nlocal basePose = get_pose(\"base\", existingBaseParent)\nbasePose[3] = 0\nbasePose[4] = 0\nbasePose[5] = 0\nmove_frame(\"base\", basePose, existingBaseParent)\nglobal base = \"base\"\nglobal tcp = \"tcp\"\nglobal world = \"world\"\nglobal flange = \"flange\"\nset_target_payload(0, [0, 0, 0], [0, 0, 0, 0, 0, 0])\nset_tcp(p[0, 0, 0, 0, 0, 0], \"Tool_flange\")\n# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper\n# Waypoint variable for Home smart skill\nglobal Home = struct(p=p[-1.8246917738038495e-9, -0.2329000001676105, 1.0793999999522315, 3.987257497300885e-9, 2.2214414675120993, -2.221441467056474], frame=\"base\", q=[0, -1.5707963249999999, 0, -1.5707963249999999, 0, 0])\n# Start of Align to Plane\n###\n# Align to plane will touch up a plane by moving the robot into contact with the table or part in several locations to determine its orientation. Afterwards the robot will orient its tool to the plane.\n# @param radius number Radius [m] of the circle within the plane will be touched up\n# @param push_force number How hard to robot pushed against the plane\n# @param n_plane_points number Number of points that the robot uses to compute the plane\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_slow number Velocity when pressing downwards\n# @param velocity_search number Velocity used when approaching the touch up point\n# @param velocity_move number Velocity used in freespace\n# @param acceleration number Acceleration of the robot\n# @param direction array 3D vector determining the direction of the TCP for touching up the plane\n###\ndef ur_align_to_plane(radius = 0.05, push_force = 20, n_plane_points = 3, max_distance = 0.25, velocity_slow = 0.001, velocity_search = 0.035, velocity_move = 0.10, acceleration = 0.1, direction = [0, 0, 1]):\n local angle = 2 * PI / n_plane_points\n local start_pos = get_target_tcp_pose()\n local retract_distance = -0.015\n ur_move_tcp_direction(retract_distance, direction, velocity_move, acceleration, 0)\n sleep(0.25)\n zero_ftsensor()\n local cnt = 0\n local t_base_target = get_target_tcp_pose()\n local mean_point = [0.0, 0.0, 0.0]\n local A = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]\n local b = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n while cnt < n_plane_points:\n local new_pos = pose_trans(t_base_target, p[cos(angle * cnt) * radius, sin(angle * cnt) * radius, 0.0, 0.0, 0.0, 0.0])\n local blend_radius = norm(point_dist(get_actual_tcp_pose(), new_pos))/5\n movel(new_pos, a = acceleration, v = velocity_move, r = blend_radius)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_search, acceleration, push_force)\n local movement = normalize(direction * -1) * 0.0005\n local target_pose = pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose)\n sleep(0.2)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_slow, acceleration, push_force)\n sleep(0.2)\n while (not is_steady()):\n sync()\n end\n local poked_point = get_target_tcp_pose()\n poked_point = pose_trans(inv(t_base_target), poked_point)\n A[cnt, 0] = poked_point[0]\n A[cnt, 1] = poked_point[1]\n A[cnt, 2] = 1.0\n b[cnt] = poked_point[2]\n mean_point = mean_point + [poked_point[0], poked_point[1], poked_point[2]]\n movel(new_pos, a = 0.2, v = velocity_move, r = blend_radius)\n cnt = cnt + 1\n end\n mean_point = mean_point / n_plane_points\n cnt = 0\n while cnt < n_plane_points:\n local cntj = 0\n while cntj < 2:\n A[cnt, cntj] = A[cnt, cntj] - mean_point[cntj]\n cntj = cntj + 1\n end\n b[cnt] = b[cnt] - mean_point[2]\n cnt = cnt + 1\n end\n local x1 = inv(transpose(A) * A) * transpose(A) * b\n local x = normalize([x1[0], x1[1], -1])\n local d = dot(mean_point, x)\n local dval = dot(direction, x)\n if dval < 0:\n x = -x\n dval = -dval\n end\n local eaa = [0.0, 0.0, 0.0]\n local EPSILON = 1e-10\n if norm(dval - 1) < EPSILON:\n # if the projection is close to 1 then the angle between the vectors are almost 0 and we cannot\n # reliably determine the perpendicular axis.\n # A good approximation is therefore just to set the EAA equal to 0.\n eaa = [0.0, 0.0, 0.0]\n else:\n local axis = cross(direction, x)\n local eaa = normalize(axis) * acos(dval)\n end\n local t_base_target_aligned = pose_trans(t_base_target, p[0, 0, 0, eaa[0], eaa[1], eaa[2]])\n movel(t_base_target_aligned, a = 0.2, v = velocity_move)\nend\n# End of Align to Plane\n# Start of Align Z to Nearest Axis\n###\n# Aligns the TCP Z axis to the nearest axis of the given frame\n# @param frame_id string frame_id to lookup frame\n###\ndef ur_align_z_to_nearest_axis(frame_id = \"world\"):\n ###\n # Given a reference frame as input this function returns a struct with the nearest\n # pose which aligns the z-axis of the robot TCP with the z-axis of the given reference frame.\n # The pose is in the reference of the given frame.\n # @param frame bool frame\n # @returns struct pose, distance, referencePose\n ###\n def get_aligned_z_pose(frame):\n local actualPose = get_actual_tcp_pose()\n local actualPoseInFrame = pose_trans(pose_inv(frame), actualPose)\n # Create rotation vector and convert that to RPY representation\n local actualRotInFrame = [actualPoseInFrame[3], actualPoseInFrame[4], actualPoseInFrame[5]]\n local actRPY = rotvec2rpy(actualRotInFrame)\n # Set RX and RY to 0 and convert back to rotation vector\n local alignedRot = rpy2rotvec([0, 0, actRPY[2]])\n local alignedRotFlipped = rpy2rotvec([PI, 0, actRPY[2]])\n local zUpPose = actualPoseInFrame\n zUpPose[3] = alignedRot[0]\n zUpPose[4] = alignedRot[1]\n zUpPose[5] = alignedRot[2]\n zUpStruct = struct(pose = zUpPose, distance=pose_dist(actualPoseInFrame, zUpPose), referencePose=frame)\n local zDownPose = actualPoseInFrame\n zDownPose[3] = alignedRotFlipped[0]\n zDownPose[4] = alignedRotFlipped[1]\n zDownPose[5] = alignedRotFlipped[2]\n local zDownStruct = struct(pose = zDownPose, distance=pose_dist(actualPoseInFrame, zDownPose), referencePose=frame)\n # Return the solution which is closer to the current robot pose\n if (zDownStruct.distance > zUpStruct.distance):\n return zUpStruct\n else:\n return zDownStruct\n end\n end\n local frame = get_pose(frame_id)\n # Rotate the given frame so that Z can be align to X-Y-Z respectively \n local rotZtoX = rpy2rotvec([0,0.5*PI,0])\n local rotZtoY = rpy2rotvec([0.5*PI,0,0])\n local rotZtoZ = rpy2rotvec([0,0,0])\n # Get aligned poses for each of the rotated frames\n local structAlignedToX = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoX[0],rotZtoX[1],rotZtoX[2]]))\n structAlignedToY = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoY[0],rotZtoY[1],rotZtoY[2]]))\n structAlignedToZ = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoZ[0],rotZtoZ[1],rotZtoZ[2]]))\n # Find the nearest alignement\n local structAligned = structAlignedToZ\n if(structAligned.distance > structAlignedToX.distance):\n structAligned = structAlignedToX \n end\n if(structAligned.distance > structAlignedToY.distance):\n structAligned = structAlignedToY \n end\n # Move the robot to the aligned pose\n movel(pose_trans(get_actual_tcp_pose(), p[0,0,0.00001,0,0,0]), v = 0.1)\n movel(pose_trans(structAligned.referencePose, structAligned.pose ), v = 0.1)\nend\n# End of Align Z to Nearest Axis\n# Start of Center to Object\n###\n# Centers to an object by touching the externals of it. It works well for fixtured or heavy parts.\n# @param push_force number Force the robot uses to determine if a contact has been achieved\n# @param velocity_move number Velocity in freespace\n# @param velocity_search number First move is used then search\n# @param acc_move number Acceleration in freespace\n# @param max_radius_search number Maximum search radius\n# @param num_fingers number Number of fingers that the gripper has\n###\ndef ur_center_to_object(push_force = 10, velocity_move = 0.10, velocity_search = 0.01, acc_move = 0.2, max_radius_search = 0.05, num_fingers = 3):\n def compute_circle_center(p_list):\n # Compute the circle center by circular regression\n # Source: https://math.stackexchange.com/questions/2898295/how-to-quickly-fit-a-circle-by-given-random-arc-points\n local itr = 0\n local x = 0\n local y = 1\n \n local m1 = [[0,0,0],[0,0,0],[0,0,0]]\n local m2 = [[0,0],[0,0],[0,0]]\n local m3 = [[0],[0],[0]]\n \n while(itr < get_list_length(p_list)):\n local p = p_list[itr]\n \n if(p_list[itr] == p[0,0,0,0,0,0]):\n break\n end\n \n m1[0,0] = m1[0,0] + (p[x]*p[x])\n m1[0,1] = m1[0,1] + (p[x]*p[y])\n m1[0,2] = m1[0,2] + (p[x])\n \n m1[1,0] = m1[1,0] + (p[x]*p[y])\n m1[1,1] = m1[1,1] + (p[y]*p[y])\n m1[1,2] = m1[1,2] + (p[y])\n \n m1[2,0] = m1[2,0] + (p[x])\n m1[2,1] = m1[2,1] + (p[y])\n \n m2[0,0] = m2[0,0] + (pow(p[x], 3))\n m2[0,1] = m2[0,1] + (p[x] * pow(p[y], 2))\n \n m2[1,0] = m2[1,0] + (pow(p[y], 3))\n m2[1,1] = m2[1,1] + (pow(p[x], 2) * p[y])\n \n m2[2,0] = m2[2,0] + (pow(p[x], 2))\n m2[2,1] = m2[2,1] + (pow(p[y], 2))\n \n itr = itr +1\n end\n \n if(itr < 2):\n return p[0,0,0,0,0,0]\n elif(itr > get_list_length(p_list)):\n return p[0,0,0,0,0,0]\n end\n \n m1[0,0] = 2 * m1[0,0]\n m1[0,1] = 2 * m1[0,1]\n m1[1,0] = 2 * m1[1,0]\n m1[1,1] = 2 * m1[1,1]\n m1[2,0] = 2 * m1[2,0]\n m1[2,1] = 2 * m1[2,1]\n m1[2,2] = itr\n m3[0,0] = m2[0,0] + m2[0,1]\n m3[1,0] = m2[1,0] + m2[1,1]\n m3[2,0] = m2[2,0] + m2[2,1]\n \n local center = inv(m1) * m3\n \n return p[center[0,0], center[1,0],0,0,0,0]\n end\n \n def sanity_checked_move(p_org, p_new, max_diff, acc, vel):\n if (pose_dist(p_org, p_new) > max_diff):\n movel(p_org, a = acc, v = vel)\n popup(\"New pose is too far away from original. Returning to original\", title = \"Failed\", warning = False, error = True, blocking = True)\n else:\n movel(p_new, a = acc, v = vel)\n end\n end\n # Start by zeroing the FT sensor\n sleep(0.25)\n zero_ftsensor()\n local p_start = get_actual_tcp_pose()\n local p0 = p[0,0,0,0,0,0]\n local DIR_X = [1, 0, 0]\n if (num_fingers == 2):\n local dir_list = [DIR_X, -DIR_X, DIR_X, -DIR_X]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0]\n elif (num_fingers == 3):\n local DIR_P1 = DIR_X\n local DIR_P2 = [-1 / 2, sqrt(3.0) / 2.0, 0]\n local DIR_P3 = [-1 / 2, -sqrt(3.0) / 2.0, 0]\n local dir_list = [DIR_P1, DIR_P2, DIR_P3, DIR_P1, DIR_P2, DIR_P3]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0, p0, p0]\n else:\n popup(\"Number of fingers not supported\")\n halt\n end\n # Loop through directions\n local it = 0\n local dir_list_size = size(dir_list)\n local dir_list_length = dir_list_size[0]\n while(it < dir_list_length):\n # Move to starting position if more than 3 positions is stored then calculate a new starting position\n if(it < 3):\n movel(pose_trans(p_start, start_offset[it]), a = acc_move, v = velocity_move)\n else:\n local p_start_temp = pose_trans(pose_trans(p_start, compute_circle_center(p_list)), start_offset[it])\n local p_start_w_offset = pose_trans(p_start, start_offset[it])\n sanity_checked_move(p_start_w_offset, p_start_temp, max_radius_search, acc_move, velocity_move)\n end\n local p_start_temp = get_actual_tcp_pose()\n # Move into contact and store contact point\n sleep(0.1)\n local contact_point = ur_move_until_force(distance = max_radius_search, direction = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]], velocity = velocity_search, acceleration = acc_move, stop_force = push_force)\n \n local dir = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]]\n dir = normalize(dir) * 0.05\n contact_point = pose_trans(contact_point, p[dir[0], dir[1], dir[2], 0, 0, 0])\n p_list[it] = pose_trans(pose_inv(p_start), contact_point)\n # Move out of contact\n movel(p_start_temp, a = acc_move, v = velocity_move)\n it = it + 1\n end\n # Find circle center based on n stored points\n local center_offset_xy = compute_circle_center(p_list)\n local p_center = pose_trans(p_start, center_offset_xy)\n \n # Move the robot to the center if it can\n sanity_checked_move(p_start, p_center, max_radius_search, acc_move, velocity_move)\nend\n# End of Center to Object\n# Start of Move Into Contact\n###\n# Moves the robot into contact in the TCP direction set\n# @param force number Force that determines when a contact has been achieved\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_search number velocity_search\n# @param retract number Retract distance after a contact has been found\n# @param move_tcp_dir array TCP direction (3D vector)\n# @param zero_ft_on_start bool Determines if the force-torque sensor should be zeroed on start\n###\ndef ur_move_into_contact(force = 10, velocity = 0.05, acceleration = 0.1, max_distance = 0.25, retract = 0.0, move_tcp_dir = [0, 0, 1], zero_ft_on_start = True):\n # Zero the force torque sensor\n if (zero_ft_on_start):\n sleep(0.25)\n zero_ftsensor()\n end\n # Move the robot\n ur_move_until_force(max_distance, move_tcp_dir, velocity, acceleration, force)\n # If a retract distance is set, move the robot back to that position\n if (retract != 0):\n # Compute position offset from TCP direction and retract distance\n local position = normalize(move_tcp_dir) * retract\n movel(pose_trans(get_actual_tcp_pose(), p[position[0], position[1], position[2], 0, 0, 0]))\n end\nend\n# End of Move Into Contact\n# Start of Retract\n###\n# Retract in the TCP direction set\n# @param distance number Retraction distance\n# @param direction array TCP direction to move in (3D vector)\n# @param acceleration number Acceleration used by the robot\n# @param velocity number Velocity used by the robot\n###\ndef ur_retract(distance = -0.1, direction = [0, 0, 1], acceleration = 0.4, velocity = 0.1):\n local movement = normalize(direction) * distance\n movel(pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0]), a = acceleration, v = velocity)\nend\n# End of Retract","nodeIDList":[]}} \ No newline at end of file diff --git a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/version b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/version new file mode 100644 index 0000000000000000000000000000000000000000..720d64f4baafc33efdf971f02084aca5f25b34a5 GIT binary patch literal 4 LcmZQzU|<9Q00jU7 literal 0 HcmV?d00001 diff --git a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck new file mode 100644 index 000000000..bdb8261a3 --- /dev/null +++ b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck @@ -0,0 +1,70 @@ +Private property of Exodus: 7@bcc1ff5ec5af + +jetbrains.exodus.io.LockingManager.lock(LockingManager.kt:88) +jetbrains.exodus.io.LockingManager.lock(LockingManager.kt:39) +jetbrains.exodus.io.FileDataWriter.lock(FileDataWriter.kt:70) +jetbrains.exodus.log.Log.tryLock(Log.kt:804) +jetbrains.exodus.log.Log.(Log.kt:117) +jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:117) +jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:81) +jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:77) +jetbrains.exodus.env.Environments$newInstance$4.invoke(Environments.kt:46) +jetbrains.exodus.env.Environments$newInstance$4.invoke(Environments.kt:46) +jetbrains.exodus.env.Environments.prepare(Environments.kt:120) +jetbrains.exodus.env.Environments.newInstance(Environments.kt:46) +jetbrains.exodus.entitystore.PersistentEntityStores.newInstance(PersistentEntityStores.java:64) +jetbrains.exodus.entitystore.PersistentEntityStores.newInstance(PersistentEntityStores.java:70) +com.ur.web.application.service.internal.PersistentEntityStoreFactory.initializeStorage(PersistentEntityStoreFactory.java:90) +com.ur.web.application.service.internal.PersistentEntityStoreFactory.instance(PersistentEntityStoreFactory.java:72) +com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.doCreate(Unknown Source) +com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.create(Unknown Source) +com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.create(Unknown Source) +io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119) +io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38) +io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35) +io.quarkus.arc.impl.LazyValue.get(LazyValue.java:32) +io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69) +io.quarkus.arc.impl.ComputingCacheContextInstances.computeIfAbsent(ComputingCacheContextInstances.java:19) +io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35) +com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.get(Unknown Source) +com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.get(Unknown Source) +com.ur.web.application.service.internal.XodusProgramDataSource_Bean.doCreate(Unknown Source) +com.ur.web.application.service.internal.XodusProgramDataSource_Bean.create(Unknown Source) +com.ur.web.application.service.internal.XodusProgramDataSource_Bean.create(Unknown Source) +io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119) +io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38) +io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35) +io.quarkus.arc.impl.LazyValue.get(LazyValue.java:32) +io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69) +io.quarkus.arc.impl.ComputingCacheContextInstances.computeIfAbsent(ComputingCacheContextInstances.java:19) +io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35) +com.ur.web.application.service.internal.XodusProgramDataSource_Bean.get(Unknown Source) +com.ur.web.application.service.internal.XodusProgramDataSource_Bean.get(Unknown Source) +com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.doCreate(Unknown Source) +com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.create(Unknown Source) +com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.create(Unknown Source) +io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119) +io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38) +io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35) +io.quarkus.arc.impl.LazyValue.get(LazyValue.java:32) +io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69) +io.quarkus.arc.impl.ComputingCacheContextInstances.computeIfAbsent(ComputingCacheContextInstances.java:19) +io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35) +com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.get(Unknown Source) +com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.get(Unknown Source) +com.ur.web.application.service.internal.PersistentEntityStoreFactory_Observer_startup_K9EA9CTXa_UuSGId5mYynBPXgFA.notify(Unknown Source) +io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:365) +io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:347) +io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:81) +io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:163) +io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:114) +io.quarkus.runner.recorded.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source) +io.quarkus.runner.recorded.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source) +io.quarkus.runner.ApplicationImpl.doStart(Unknown Source) +io.quarkus.runtime.Application.start(Application.java:101) +io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:119) +io.quarkus.runtime.Quarkus.run(Quarkus.java:80) +io.quarkus.runtime.Quarkus.run(Quarkus.java:51) +com.ur.web.robot.service.impl.internal.Activator.main(Activator.java:100) +io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:69) +io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:37) diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index 83432fd70..53d63e1fa 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "gtest/gtest.h" #include "test_utils.h" @@ -64,11 +65,10 @@ class DashboardClientTestX : public ::testing::Test protected: void SetUp() { -#ifdef POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL -# if POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL == 1 - skip_remote_control_tests = false; -# endif -#endif + if (std::getenv("POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL") != nullptr) + { + skip_remote_control_tests = false; + } urcl::comm::INotifier notifier; primary_client_.reset(new urcl::primary_interface::PrimaryClient(g_ROBOT_IP, notifier)); primary_client_->start(); From 174e2fc66958c496f71676f76177e5582fff0add Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Tue, 18 Aug 2026 17:55:56 +0200 Subject: [PATCH 02/14] Updating citadelDB for robot to be in remote control mode --- tests/resources/dockerursim/citadelDB/000002.sst | Bin 0 -> 283 bytes tests/resources/dockerursim/citadelDB/000002.vlog | 3 +++ tests/resources/dockerursim/citadelDB/MANIFEST | Bin 30 -> 44 bytes tests/test_dashboard_client_x.cpp | 5 ++++- 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/resources/dockerursim/citadelDB/000002.sst create mode 100644 tests/resources/dockerursim/citadelDB/000002.vlog diff --git a/tests/resources/dockerursim/citadelDB/000002.sst b/tests/resources/dockerursim/citadelDB/000002.sst new file mode 100644 index 0000000000000000000000000000000000000000..a57527ad467458d2a3dba74a8c55916116cc8581 GIT binary patch literal 283 zcmZ{fK?=e!6hx<3iWZd?M2fgjaO)kq_7V~_qEH)YQry~w(1jktD|i9%KBC@0C$(Dx z!wmWF5B$P;AAmkGxm89^7b-QGN5(hDlAIcrU- oN3|%YL>$5Ix;9gG5AfMxDVGU2R>_`Y2y4w=(3;3c+hX4Qo literal 0 HcmV?d00001 diff --git a/tests/resources/dockerursim/citadelDB/000002.vlog b/tests/resources/dockerursim/citadelDB/000002.vlog new file mode 100644 index 000000000..74fbbb8b8 --- /dev/null +++ b/tests/resources/dockerursim/citadelDB/000002.vlog @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c6bbe3c850de9acc56951c528dfc83197d6d4e1dab56d715a34c29f49327139 +size 20 diff --git a/tests/resources/dockerursim/citadelDB/MANIFEST b/tests/resources/dockerursim/citadelDB/MANIFEST index 4683694ac4fc3c96686aa8ef69a60762d45e6c47..20fe60bc7357cb5361f3d195940a1bec15c3b857 100644 GIT binary patch delta 19 acmb2snIOl Date: Tue, 18 Aug 2026 20:27:54 +0200 Subject: [PATCH 03/14] Take screenshots on failed tests --- .github/workflows/ci.yml | 11 ++++++++++- tests/test_dashboard_client_x.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45f3e7e12..44f52e506 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,7 +110,7 @@ jobs: - name: Extract CMake build directory run: tar -xzf build.tar.gz - name: Create folder for test artifacts - run: mkdir -p test_artifacts + run: mkdir -p test_artifacts/screenshots - name: Access PolyScope if: ${{ steps.check_polyscopex.outputs.is_polyscopex == 'true' }} run: chrome --no-sandbox --disable-settuid-sandbox --headless=new 192.168.56.101 & @@ -123,6 +123,7 @@ jobs: env: URSIM_VERSION: ${{matrix.env.URSIM_VERSION}} POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL: ${{matrix.env.POLYSCOPE_X_WITH_REMOTE_CONTROL || ''}} + POLYSCOPE_X_SCREENSHOT_DIR: ${{github.workspace}}/test_artifacts/screenshots - name: Upload test results to Codecov uses: codecov/codecov-action@v7 with: @@ -176,6 +177,14 @@ jobs: path: test_artifacts if-no-files-found: error retention-days: 10 + - name: Upload PolyScope X screenshots + uses: actions/upload-artifact@v7 + if: ${{ failure() && steps.check_polyscopex.outputs.is_polyscopex == 'true' }} + with: + name: ${{matrix.env.ROBOT_MODEL}}_${{matrix.env.URSIM_VERSION}}_screenshots + path: test_artifacts/screenshots + if-no-files-found: ignore + retention-days: 10 - name: Upload generated scripts uses: actions/upload-artifact@v6 if: ${{ always() }} diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index f7023ee32..5db589e69 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "gtest/gtest.h" #include "test_utils.h" @@ -510,6 +511,30 @@ TEST_F(DashboardClientTestX, microsecond_receive_timeout_makes_connect_fail) EXPECT_FALSE(dashboard_client_->connect()); } +class PolyScopeScreenshotListener : public ::testing::EmptyTestEventListener +{ +public: + void OnTestEnd(const ::testing::TestInfo& test_info) override + { + if (!test_info.result()->Failed()) + { + return; + } + + const char* dir_env = std::getenv("POLYSCOPE_X_SCREENSHOT_DIR"); + std::filesystem::path screenshot_dir = dir_env ? dir_env : "test_artifacts/screenshots"; + std::filesystem::create_directories(screenshot_dir); + + std::string filename = + (screenshot_dir / (std::string(test_info.test_suite_name()) + "." + test_info.name() + ".png")).string(); + std::string cmd = "chrome --headless=new --no-sandbox --disable-settuid-sandbox" + " --window-size=1920,1080" + " --screenshot=" + + filename + " http://" + g_ROBOT_IP + " 2>/dev/null || true"; + [[maybe_unused]] int ret = std::system(cmd.c_str()); + } +}; + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); @@ -523,5 +548,7 @@ int main(int argc, char* argv[]) } } + ::testing::UnitTest::GetInstance()->listeners().Append(new PolyScopeScreenshotListener()); + return RUN_ALL_TESTS(); } From 0c3347f1c1dd251c2d00e920ef35326101b803a7 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Tue, 18 Aug 2026 20:30:01 +0200 Subject: [PATCH 04/14] Fix boolean check --- tests/test_dashboard_client_x.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index 5db589e69..e9389891f 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -68,7 +68,8 @@ class DashboardClientTestX : public ::testing::Test { if (std::getenv("POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL") != nullptr) { - if (parseBoolean(std::getenv("POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL"))) + std::string env_var = std::getenv("POLYSCOPE_X_TESTS_WITH_REMOTE_CONTROL"); + if (env_var != "" && parseBoolean(env_var)) { skip_remote_control_tests = false; } From 021b42892c23117b7b6782d2d813425528444136 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Wed, 19 Aug 2026 09:30:58 +0200 Subject: [PATCH 05/14] Use playwright to take screenshots This way we can delay taking the screenshot --- .github/workflows/ci.yml | 14 ++++++++++++ tests/resources/polyscopex_screenshot.py | 28 ++++++++++++++++++++++++ tests/test_dashboard_client_x.cpp | 7 +++--- 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 tests/resources/polyscopex_screenshot.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 44f52e506..12e5611c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,6 +116,9 @@ jobs: run: chrome --no-sandbox --disable-settuid-sandbox --headless=new 192.168.56.101 & - name: Install Python dependencies run: sudo apt-get update && sudo apt-get install -y python3-pandas python3-lxml + - name: Install Playwright for PolyScope X screenshots + if: ${{ steps.check_polyscopex.outputs.is_polyscopex == 'true' }} + run: pip install playwright && playwright install chromium - name: Generate rtde outputs lists run: python3 tests/resources/generate_rtde_outputs.py - name: test @@ -177,6 +180,17 @@ jobs: path: test_artifacts if-no-files-found: error retention-days: 10 + - name: Capture PolyScope X URSim logs + if: ${{ always() && steps.check_polyscopex.outputs.is_polyscopex == 'true' }} + run: docker logs ursim > test_artifacts/ursim_docker.log 2>&1 + - name: Upload PolyScope X URSim logs + uses: actions/upload-artifact@v7 + if: ${{ always() && steps.check_polyscopex.outputs.is_polyscopex == 'true' }} + with: + name: ${{matrix.env.ROBOT_MODEL}}_${{matrix.env.URSIM_VERSION}}_URSim_Logs + path: test_artifacts/ursim_docker.log + if-no-files-found: error + retention-days: 10 - name: Upload PolyScope X screenshots uses: actions/upload-artifact@v7 if: ${{ failure() && steps.check_polyscopex.outputs.is_polyscopex == 'true' }} diff --git a/tests/resources/polyscopex_screenshot.py b/tests/resources/polyscopex_screenshot.py new file mode 100644 index 000000000..f02bc1a9d --- /dev/null +++ b/tests/resources/polyscopex_screenshot.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +"""Take a screenshot of the PolyScope X UI with a real post-load delay for SPA rendering. + +Usage: polyscopex_screenshot.py +""" +import sys + +from playwright.sync_api import sync_playwright + + +def main(): + if len(sys.argv) != 4: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + url, output_file, delay_ms = sys.argv[1], sys.argv[2], int(sys.argv[3]) + + with sync_playwright() as p: + browser = p.chromium.launch(args=["--no-sandbox", "--disable-setuid-sandbox"]) + page = browser.new_page(viewport={"width": 1920, "height": 1080}) + page.goto(url, wait_until="load") + page.wait_for_timeout(delay_ms) + page.screenshot(path=output_file) + browser.close() + + +if __name__ == "__main__": + main() diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index e9389891f..55a330394 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -528,10 +528,9 @@ class PolyScopeScreenshotListener : public ::testing::EmptyTestEventListener std::string filename = (screenshot_dir / (std::string(test_info.test_suite_name()) + "." + test_info.name() + ".png")).string(); - std::string cmd = "chrome --headless=new --no-sandbox --disable-settuid-sandbox" - " --window-size=1920,1080" - " --screenshot=" + - filename + " http://" + g_ROBOT_IP + " 2>/dev/null || true"; + std::string cmd = "python3 ../tests/resources/polyscopex_screenshot.py" + " http://" + + g_ROBOT_IP + " " + filename + " 3000 2>/dev/null || true"; [[maybe_unused]] int ret = std::system(cmd.c_str()); } }; From 103ffe7ecfbefa7902dbabc442c3ea939b91c554 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Wed, 19 Aug 2026 14:33:59 +0200 Subject: [PATCH 06/14] Update volumes --- .../dockerursim/citadelDB/000001.sst | Bin 462 -> 455 bytes .../dockerursim/citadelDB/000001.vlog | Bin 20 -> 20 bytes .../dockerursim/citadelDB/000002.sst | Bin 283 -> 0 bytes .../dockerursim/citadelDB/000002.vlog | 3 - .../dockerursim/citadelDB/KEYREGISTRY | 2 +- .../resources/dockerursim/citadelDB/MANIFEST | Bin 44 -> 30 bytes .../polyscopex/10.13.0/ur7e/.allow-empty | 0 .../polyscopex/10.13.0/ur7e/00000000000.xd | Bin 24995 -> 34803 bytes .../polyscopex/10.13.0/ur7e/blobs/4.blob | 2 +- .../10.13.0/ur7e/blobs/{7.blob => 5.blob} | 2 +- .../programs/polyscopex/10.13.0/ur7e/xd.lck | 70 ------------------ 11 files changed, 3 insertions(+), 76 deletions(-) delete mode 100644 tests/resources/dockerursim/citadelDB/000002.sst delete mode 100644 tests/resources/dockerursim/citadelDB/000002.vlog create mode 100755 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/.allow-empty rename tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/{7.blob => 5.blob} (74%) delete mode 100644 tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck diff --git a/tests/resources/dockerursim/citadelDB/000001.sst b/tests/resources/dockerursim/citadelDB/000001.sst index fbb4c6409633f12d54430135b54e869284a0ba48..98f21568a0a223989c65fa806852d42a989d3e28 100644 GIT binary patch delta 360 zcmXZX&r1S990l+H=oA%H6m8#?20qN2nKuJ-@4NG{QHL$GmU9_RD`uART0sTA6}1op zenPQA6!>M)ts`Itw$b3iSS)i(*u2h8)2{2jt^>ku8plZ_z9?7qx?`~6ip`x;g*SB5 zDmg+IhBU;dlG>ex+)pog1Z9OjWskrrQrcZ4!kSzmo*>>V3q6>lU$H%G9(XVk^veyBL%ysl@#UYFqZ55|NsA^0|P@^Voq^tk`e>MrzRlrQ&P!Af}tqCI6fsmH!(9W zzPKc@B$YLdbvAa20>PJy=e># zpCzXOnbY)S85q7u%6@QWU{GXWV6X+^P$13%;u;{H2gC<}_z@7ZF)}dd191cp*8}k! zAO-?HfgkI)%;5tm0D1@v1Q-+;WEdvfGxF&j04f5>{fE*Zc@7{3DFumhwulHgFw9_J eX=Y;bW|>^gD8*K7{jGcpHh literal 20 XcmZQzfPe+kb=#iW`v1{C8_)v)C-(+5 diff --git a/tests/resources/dockerursim/citadelDB/000002.sst b/tests/resources/dockerursim/citadelDB/000002.sst deleted file mode 100644 index a57527ad467458d2a3dba74a8c55916116cc8581..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 283 zcmZ{fK?=e!6hx<3iWZd?M2fgjaO)kq_7V~_qEH)YQry~w(1jktD|i9%KBC@0C$(Dx z!wmWF5B$P;AAmkGxm89^7b-QGN5(hDlAIcrU- oN3|%YL>$5Ix;9gG5AfMxDVGU2R>_`Y2y4w=(3;3c+hX4Qo diff --git a/tests/resources/dockerursim/citadelDB/000002.vlog b/tests/resources/dockerursim/citadelDB/000002.vlog deleted file mode 100644 index 74fbbb8b8..000000000 --- a/tests/resources/dockerursim/citadelDB/000002.vlog +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c6bbe3c850de9acc56951c528dfc83197d6d4e1dab56d715a34c29f49327139 -size 20 diff --git a/tests/resources/dockerursim/citadelDB/KEYREGISTRY b/tests/resources/dockerursim/citadelDB/KEYREGISTRY index fbbdbb7b8..7aeb4b5c6 100644 --- a/tests/resources/dockerursim/citadelDB/KEYREGISTRY +++ b/tests/resources/dockerursim/citadelDB/KEYREGISTRY @@ -1 +1 @@ -„x^ùQÅ`‚O0á¹ýHello Badger \ No newline at end of file +¼ò%¬{.AØGé„ÛƒzHello Badger \ No newline at end of file diff --git a/tests/resources/dockerursim/citadelDB/MANIFEST b/tests/resources/dockerursim/citadelDB/MANIFEST index 20fe60bc7357cb5361f3d195940a1bec15c3b857..4683694ac4fc3c96686aa8ef69a60762d45e6c47 100644 GIT binary patch delta 4 LcmdOqn;-`O0!#q; delta 19 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 KIJ4ts b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper"},"ur-application-variables":{"type":"ur-application-variables","version":"0.0.1","variables":{}},"universal-robots-external-control-external-control-application":{"type":"universal-robots-external-control-external-control-application","version":"1.0.0","port":50002,"robotIP":"192.168.56.1"}},"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{}},"sourcesNodes":{"robot":{"groupId":"robot","version":"1.0.0.","sources":[{"sourceID":"ur-wired-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"},{"signalID":"AO 0","direction":"OUT","valueType":"FLOAT"},{"signalID":"AO 1","direction":"OUT","valueType":"FLOAT"}],"webSocketURL":"/sources/wired-io"},{"sourceID":"ur-tool-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"}],"webSocketURL":"/sources/tool-io"}],"isDynamic":false},"ur-modbus":{"groupId":"ur-modbus","isDynamic":true,"version":"1.0.0","sources":[]},"ur-robot-io":{"type":"ur-robot-io","groupId":"ur-robot-io","isDynamic":false,"version":"1.0.2","sources":[{"sourceID":"ur-robot-wired-io","name":"Wired I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 0","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 1","valueType":"FLOAT"}]},{"sourceID":"ur-robot-tool-io","name":"Tool I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"}]}],"parameters":{"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{},"toolOutput":{"dualPinPower":false,"voltage":{"value":0,"unit":"V"},"powerOutput":{"DO 0":1,"DO 1":1}}},"migrateSourceConfigDone":true}}},"safety":{"settings":{"io":{"automaticModeSafeguardResetInput":{"name":"automaticModeSafeguardResetInput","valueA":255,"valueB":255},"automaticModeSafeguardStopInput":{"name":"automaticModeSafeguardStopInput","valueA":255,"valueB":255},"emergencyStopInput":{"name":"emergencyStopInput","valueA":255,"valueB":255},"notReducedModeOutput":{"name":"notReducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"operationalModeInput":{"name":"operationalModeInput","valueA":255,"valueB":255},"reducedModeInput":{"name":"reducedModeInput","valueA":255,"valueB":255},"reducedModeOutput":{"name":"reducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotMovingOutput":{"name":"robotMovingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotNotStoppingOutput":{"name":"robotNotStoppingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeHomeOutput":{"name":"safeHomeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeguardResetInput":{"name":"safeguardResetInput","valueA":0,"valueB":1},"systemEmergencyStoppedOutput":{"name":"systemEmergencyStoppedOutput","ossdEnabled":false,"valueA":255,"valueB":255},"threePositionSwitchInput":{"name":"threePositionSwitchInput","valueA":255,"valueB":255},"freedriveEnabledInput":{"name":"freedriveEnabledInput","valueA":255,"valueB":255},"threePositionEnablingStopOutput":{"name":"threePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255},"notThreePositionEnablingStopOutput":{"name":"notThreePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255}},"major":5,"minor":14,"normalJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"normalJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"normalRobotLimits":{"elbowForce":150,"elbowSpeed":1.5,"momentum":25,"power":300,"stoppingDistance":0.5,"stoppingTime":0.4,"toolForce":150,"toolSpeed":1.5},"reducedJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"reducedJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"reducedRobotLimits":{"elbowForce":120,"elbowSpeed":0.75,"momentum":10,"power":200,"stoppingDistance":0.3,"stoppingTime":0.3,"toolForce":120,"toolSpeed":0.75},"safetyHardware":{"injectionMoldingMachineInterface":"NONE","teachPendant":"NORMAL"},"safetyPlanes":{"planes":[{"id":"c7314701-34ec-1674-a33d-a226b1cd34bc","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"ed4d303b-25c3-9ef0-867d-5dd3d70201f9","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"79ace36e-a147-044d-c436-583abde29c09","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"52d5930b-4200-b2c2-ff14-ca60642554cd","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e1554217-d3da-bc37-57cc-d8e868766608","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"643c8131-1f1d-db3f-6447-d062bd6a41da","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"b531cb99-8f5b-2ecd-0da6-8b0009840661","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e367d34e-fba3-5a65-f9ed-0c4925240d21","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"}],"ioSafetyPlanes":[{"id":"dcbb3122-97a6-3196-c6fd-c234fc103963","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a1554adb-2b98-f7ec-a7d7-9877ebe7939c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"fb53caf6-eb68-bab8-bddc-4ccb8dd42f25","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"79c00e8d-7415-4510-1e40-6742240e86ff","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"70f45544-4998-52f8-5a91-adaf39459678","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a8678cc2-fd26-4c10-a10c-4904469c6e08","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"e6225a34-0085-7027-2f23-9cedb6cb3688","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"32d5f884-e587-e9fe-8970-456fff173c7f","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"}]},"safetySafeHome":{"base":-1,"elbow":-1,"shoulder":-1,"wrist1":-1,"wrist2":-1,"wrist3":-1,"enabled":false},"safetyAPIParameters":{"numberOfClients":0,"clients":[]},"safetyFieldbusses":{"enablePROFIsafe":false,"sourceAddressPROFIsafe":0,"destAddressPROFIsafe":0,"modeControlPROFIsafe":false},"threePosition":{"allowManualHighSpeed":true,"useTeachPendantAs3PE":false},"toolDirection":{"limitDeviation":6.2831855,"limitDirection":{"x":0,"y":0,"z":1},"limitRestriction":"DISABLED","tcp":{"id":"toolFlangeTcpId","name":"Tool_flange"},"toolPan":0,"toolTilt":0,"limitTilt":0,"limitRotation":0},"toolPositions":{"toolPositions":[{"name":"Tool Flange","center":{"x":0,"y":0,"z":0},"radius":0,"definition":2},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0}]},"normalWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"},"reducedWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"}},"crc":"2850523693","confirmed":true},"operatorScreens":[{"type":"ur-operator-screen-default","version":"0.0.2","parameters":{"status":[],"configuration":[]}}],"sidebarItems":[{"type":"ur-global-variables","version":"1.0.0","disabled":{"master":false,"automaticMode":false,"remoteMode":true}},{"type":"ur-log-messages-sidebar","version":"0.0.1","disabled":{"master":false,"automaticMode":false,"remoteMode":true}}],"activeOperatorScreen":"ur-operator-screen-default","smartSkills":[{"name":"Align to Plane","enabled":true,"type":"ur-align-to-plane","parameters":{"radius":0.05,"push_force":20,"n_plane_points":3,"max_distance":0.25,"velocity_slow":0.001,"velocity_search":0.035,"velocity_move":0.1,"acceleration":0.1}},{"name":"Align Z to Nearest Axis","enabled":true,"type":"ur-align-z-to-nearest-axis"},{"name":"Center","enabled":true,"type":"ur-center","parameters":{"push_force":10,"velocity_move":0.05,"acc_move":0.2,"max_radius_search":0.05,"num_fingers":3}},{"name":"Freedrive","enabled":true,"type":"ur-freedrive","version":"1.0.0","recordingFrequency":50,"recordingSignals":["timestamp","target_q","actual_TCP_pose","tcp_offset"]},{"name":"Move into Contact","enabled":true,"type":"ur-move-into-contact","parameters":{"force":10,"velocity":0.05,"acceleration":0.2,"max_distance":0.25,"retract":0}},{"name":"Retract","enabled":true,"type":"ur-retract","parameters":{"distance":-0.1,"acceleration":0.4,"velocity":0.1}},{"name":"Put into Box","enabled":false,"type":"ur-put-in-box","version":"1.0.0"},{"name":"Custom","enabled":false,"type":"ur-custom-smart-skill","parameters":{"includePreamble":true,"includeModules":false},"version":"1.0.0"},{"name":"Home","enabled":true,"type":"ur-position","version":"1.1.2","parameters":{"actualWaypoint":{"frame":"base","pose":{"position":[-1.8246917738038495E-9,-0.2329000001676105,1.0793999999522315],"orientation":[3.987257497300885E-9,2.2214414675120993,-2.221441467056474]},"qNear":{"base":0,"shoulder":-1.5707963249999999,"elbow":0,"wrist1":-1.5707963249999999,"wrist2":0,"wrist3":0}},"variable":{"name":"Home","reference":false,"type":"$$Variable","valueType":"waypoint","id":"8dbe361a-a570-5719-3461-20743ddc9310","_IDENTIFIER":"VariableDeclaration"}}}]},"script":{"script":"set_safety_mode_transition_hardness(1)\nreset_world_model()\nset_input_actions_to_default()\nset_analog_outputdomain(0,0)\nset_analog_outputdomain(1,0)\nset_standard_analog_input_domain(0,0)\nset_standard_analog_input_domain(1,0)\nset_tool_output_mode(0)\nset_tool_voltage(0)\nset_tool_digital_output_mode(0,1)\nset_tool_digital_output_mode(1,1)\nset_tool_analog_input_domain(0,0)\nset_tool_analog_input_domain(1,0)\nset_gravity([0, 0, 9.82])\nlocal existingBaseParent = get_frame_parent(\"base\")\nlocal basePose = get_pose(\"base\", existingBaseParent)\nbasePose[3] = 0\nbasePose[4] = 0\nbasePose[5] = 0\nmove_frame(\"base\", basePose, existingBaseParent)\nglobal base = \"base\"\nglobal tcp = \"tcp\"\nglobal world = \"world\"\nglobal flange = \"flange\"\nset_target_payload(0, [0, 0, 0], [0, 0, 0, 0, 0, 0])\nset_tcp(p[0, 0, 0, 0, 0, 0], \"Tool_flange\")\n# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper\n# Waypoint variable for Home smart skill\nglobal Home = struct(p=p[-1.8246917738038495e-9, -0.2329000001676105, 1.0793999999522315, 3.987257497300885e-9, 2.2214414675120993, -2.221441467056474], frame=\"base\", q=[0, -1.5707963249999999, 0, -1.5707963249999999, 0, 0])\n# Start of Align to Plane\n###\n# Align to plane will touch up a plane by moving the robot into contact with the table or part in several locations to determine its orientation. Afterwards the robot will orient its tool to the plane.\n# @param radius number Radius [m] of the circle within the plane will be touched up\n# @param push_force number How hard to robot pushed against the plane\n# @param n_plane_points number Number of points that the robot uses to compute the plane\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_slow number Velocity when pressing downwards\n# @param velocity_search number Velocity used when approaching the touch up point\n# @param velocity_move number Velocity used in freespace\n# @param acceleration number Acceleration of the robot\n# @param direction array 3D vector determining the direction of the TCP for touching up the plane\n###\ndef ur_align_to_plane(radius = 0.05, push_force = 20, n_plane_points = 3, max_distance = 0.25, velocity_slow = 0.001, velocity_search = 0.035, velocity_move = 0.10, acceleration = 0.1, direction = [0, 0, 1]):\n local angle = 2 * PI / n_plane_points\n local start_pos = get_target_tcp_pose()\n local retract_distance = -0.015\n ur_move_tcp_direction(retract_distance, direction, velocity_move, acceleration, 0)\n sleep(0.25)\n zero_ftsensor()\n local cnt = 0\n local t_base_target = get_target_tcp_pose()\n local mean_point = [0.0, 0.0, 0.0]\n local A = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]\n local b = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n while cnt < n_plane_points:\n local new_pos = pose_trans(t_base_target, p[cos(angle * cnt) * radius, sin(angle * cnt) * radius, 0.0, 0.0, 0.0, 0.0])\n local blend_radius = norm(point_dist(get_actual_tcp_pose(), new_pos))/5\n movel(new_pos, a = acceleration, v = velocity_move, r = blend_radius)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_search, acceleration, push_force)\n local movement = normalize(direction * -1) * 0.0005\n local target_pose = pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose)\n sleep(0.2)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_slow, acceleration, push_force)\n sleep(0.2)\n while (not is_steady()):\n sync()\n end\n local poked_point = get_target_tcp_pose()\n poked_point = pose_trans(inv(t_base_target), poked_point)\n A[cnt, 0] = poked_point[0]\n A[cnt, 1] = poked_point[1]\n A[cnt, 2] = 1.0\n b[cnt] = poked_point[2]\n mean_point = mean_point + [poked_point[0], poked_point[1], poked_point[2]]\n movel(new_pos, a = 0.2, v = velocity_move, r = blend_radius)\n cnt = cnt + 1\n end\n mean_point = mean_point / n_plane_points\n cnt = 0\n while cnt < n_plane_points:\n local cntj = 0\n while cntj < 2:\n A[cnt, cntj] = A[cnt, cntj] - mean_point[cntj]\n cntj = cntj + 1\n end\n b[cnt] = b[cnt] - mean_point[2]\n cnt = cnt + 1\n end\n local x1 = inv(transpose(A) * A) * transpose(A) * b\n local x = normalize([x1[0], x1[1], -1])\n local d = dot(mean_point, x)\n local dval = dot(direction, x)\n if dval < 0:\n x = -x\n dval = -dval\n end\n local eaa = [0.0, 0.0, 0.0]\n local EPSILON = 1e-10\n if norm(dval - 1) < EPSILON:\n # if the projection is close to 1 then the angle between the vectors are almost 0 and we cannot\n # reliably determine the perpendicular axis.\n # A good approximation is therefore just to set the EAA equal to 0.\n eaa = [0.0, 0.0, 0.0]\n else:\n local axis = cross(direction, x)\n local eaa = normalize(axis) * acos(dval)\n end\n local t_base_target_aligned = pose_trans(t_base_target, p[0, 0, 0, eaa[0], eaa[1], eaa[2]])\n movel(t_base_target_aligned, a = 0.2, v = velocity_move)\nend\n# End of Align to Plane\n# Start of Align Z to Nearest Axis\n###\n# Aligns the TCP Z axis to the nearest axis of the given frame\n# @param frame_id string frame_id to lookup frame\n###\ndef ur_align_z_to_nearest_axis(frame_id = \"world\"):\n ###\n # Given a reference frame as input this function returns a struct with the nearest\n # pose which aligns the z-axis of the robot TCP with the z-axis of the given reference frame.\n # The pose is in the reference of the given frame.\n # @param frame bool frame\n # @returns struct pose, distance, referencePose\n ###\n def get_aligned_z_pose(frame):\n local actualPose = get_actual_tcp_pose()\n local actualPoseInFrame = pose_trans(pose_inv(frame), actualPose)\n # Create rotation vector and convert that to RPY representation\n local actualRotInFrame = [actualPoseInFrame[3], actualPoseInFrame[4], actualPoseInFrame[5]]\n local actRPY = rotvec2rpy(actualRotInFrame)\n # Set RX and RY to 0 and convert back to rotation vector\n local alignedRot = rpy2rotvec([0, 0, actRPY[2]])\n local alignedRotFlipped = rpy2rotvec([PI, 0, actRPY[2]])\n local zUpPose = actualPoseInFrame\n zUpPose[3] = alignedRot[0]\n zUpPose[4] = alignedRot[1]\n zUpPose[5] = alignedRot[2]\n zUpStruct = struct(pose = zUpPose, distance=pose_dist(actualPoseInFrame, zUpPose), referencePose=frame)\n local zDownPose = actualPoseInFrame\n zDownPose[3] = alignedRotFlipped[0]\n zDownPose[4] = alignedRotFlipped[1]\n zDownPose[5] = alignedRotFlipped[2]\n local zDownStruct = struct(pose = zDownPose, distance=pose_dist(actualPoseInFrame, zDownPose), referencePose=frame)\n # Return the solution which is closer to the current robot pose\n if (zDownStruct.distance > zUpStruct.distance):\n return zUpStruct\n else:\n return zDownStruct\n end\n end\n local frame = get_pose(frame_id)\n # Rotate the given frame so that Z can be align to X-Y-Z respectively \n local rotZtoX = rpy2rotvec([0,0.5*PI,0])\n local rotZtoY = rpy2rotvec([0.5*PI,0,0])\n local rotZtoZ = rpy2rotvec([0,0,0])\n # Get aligned poses for each of the rotated frames\n local structAlignedToX = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoX[0],rotZtoX[1],rotZtoX[2]]))\n structAlignedToY = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoY[0],rotZtoY[1],rotZtoY[2]]))\n structAlignedToZ = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoZ[0],rotZtoZ[1],rotZtoZ[2]]))\n # Find the nearest alignement\n local structAligned = structAlignedToZ\n if(structAligned.distance > structAlignedToX.distance):\n structAligned = structAlignedToX \n end\n if(structAligned.distance > structAlignedToY.distance):\n structAligned = structAlignedToY \n end\n # Move the robot to the aligned pose\n movel(pose_trans(get_actual_tcp_pose(), p[0,0,0.00001,0,0,0]), v = 0.1)\n movel(pose_trans(structAligned.referencePose, structAligned.pose ), v = 0.1)\nend\n# End of Align Z to Nearest Axis\n# Start of Center to Object\n###\n# Centers to an object by touching the externals of it. It works well for fixtured or heavy parts.\n# @param push_force number Force the robot uses to determine if a contact has been achieved\n# @param velocity_move number Velocity in freespace\n# @param velocity_search number First move is used then search\n# @param acc_move number Acceleration in freespace\n# @param max_radius_search number Maximum search radius\n# @param num_fingers number Number of fingers that the gripper has\n###\ndef ur_center_to_object(push_force = 10, velocity_move = 0.10, velocity_search = 0.01, acc_move = 0.2, max_radius_search = 0.05, num_fingers = 3):\n def compute_circle_center(p_list):\n # Compute the circle center by circular regression\n # Source: https://math.stackexchange.com/questions/2898295/how-to-quickly-fit-a-circle-by-given-random-arc-points\n local itr = 0\n local x = 0\n local y = 1\n \n local m1 = [[0,0,0],[0,0,0],[0,0,0]]\n local m2 = [[0,0],[0,0],[0,0]]\n local m3 = [[0],[0],[0]]\n \n while(itr < get_list_length(p_list)):\n local p = p_list[itr]\n \n if(p_list[itr] == p[0,0,0,0,0,0]):\n break\n end\n \n m1[0,0] = m1[0,0] + (p[x]*p[x])\n m1[0,1] = m1[0,1] + (p[x]*p[y])\n m1[0,2] = m1[0,2] + (p[x])\n \n m1[1,0] = m1[1,0] + (p[x]*p[y])\n m1[1,1] = m1[1,1] + (p[y]*p[y])\n m1[1,2] = m1[1,2] + (p[y])\n \n m1[2,0] = m1[2,0] + (p[x])\n m1[2,1] = m1[2,1] + (p[y])\n \n m2[0,0] = m2[0,0] + (pow(p[x], 3))\n m2[0,1] = m2[0,1] + (p[x] * pow(p[y], 2))\n \n m2[1,0] = m2[1,0] + (pow(p[y], 3))\n m2[1,1] = m2[1,1] + (pow(p[x], 2) * p[y])\n \n m2[2,0] = m2[2,0] + (pow(p[x], 2))\n m2[2,1] = m2[2,1] + (pow(p[y], 2))\n \n itr = itr +1\n end\n \n if(itr < 2):\n return p[0,0,0,0,0,0]\n elif(itr > get_list_length(p_list)):\n return p[0,0,0,0,0,0]\n end\n \n m1[0,0] = 2 * m1[0,0]\n m1[0,1] = 2 * m1[0,1]\n m1[1,0] = 2 * m1[1,0]\n m1[1,1] = 2 * m1[1,1]\n m1[2,0] = 2 * m1[2,0]\n m1[2,1] = 2 * m1[2,1]\n m1[2,2] = itr\n m3[0,0] = m2[0,0] + m2[0,1]\n m3[1,0] = m2[1,0] + m2[1,1]\n m3[2,0] = m2[2,0] + m2[2,1]\n \n local center = inv(m1) * m3\n \n return p[center[0,0], center[1,0],0,0,0,0]\n end\n \n def sanity_checked_move(p_org, p_new, max_diff, acc, vel):\n if (pose_dist(p_org, p_new) > max_diff):\n movel(p_org, a = acc, v = vel)\n popup(\"New pose is too far away from original. Returning to original\", title = \"Failed\", warning = False, error = True, blocking = True)\n else:\n movel(p_new, a = acc, v = vel)\n end\n end\n # Start by zeroing the FT sensor\n sleep(0.25)\n zero_ftsensor()\n local p_start = get_actual_tcp_pose()\n local p0 = p[0,0,0,0,0,0]\n local DIR_X = [1, 0, 0]\n if (num_fingers == 2):\n local dir_list = [DIR_X, -DIR_X, DIR_X, -DIR_X]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0]\n elif (num_fingers == 3):\n local DIR_P1 = DIR_X\n local DIR_P2 = [-1 / 2, sqrt(3.0) / 2.0, 0]\n local DIR_P3 = [-1 / 2, -sqrt(3.0) / 2.0, 0]\n local dir_list = [DIR_P1, DIR_P2, DIR_P3, DIR_P1, DIR_P2, DIR_P3]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0, p0, p0]\n else:\n popup(\"Number of fingers not supported\")\n halt\n end\n # Loop through directions\n local it = 0\n local dir_list_size = size(dir_list)\n local dir_list_length = dir_list_size[0]\n while(it < dir_list_length):\n # Move to starting position if more than 3 positions is stored then calculate a new starting position\n if(it < 3):\n movel(pose_trans(p_start, start_offset[it]), a = acc_move, v = velocity_move)\n else:\n local p_start_temp = pose_trans(pose_trans(p_start, compute_circle_center(p_list)), start_offset[it])\n local p_start_w_offset = pose_trans(p_start, start_offset[it])\n sanity_checked_move(p_start_w_offset, p_start_temp, max_radius_search, acc_move, velocity_move)\n end\n local p_start_temp = get_actual_tcp_pose()\n # Move into contact and store contact point\n sleep(0.1)\n local contact_point = ur_move_until_force(distance = max_radius_search, direction = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]], velocity = velocity_search, acceleration = acc_move, stop_force = push_force)\n \n local dir = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]]\n dir = normalize(dir) * 0.05\n contact_point = pose_trans(contact_point, p[dir[0], dir[1], dir[2], 0, 0, 0])\n p_list[it] = pose_trans(pose_inv(p_start), contact_point)\n # Move out of contact\n movel(p_start_temp, a = acc_move, v = velocity_move)\n it = it + 1\n end\n # Find circle center based on n stored points\n local center_offset_xy = compute_circle_center(p_list)\n local p_center = pose_trans(p_start, center_offset_xy)\n \n # Move the robot to the center if it can\n sanity_checked_move(p_start, p_center, max_radius_search, acc_move, velocity_move)\nend\n# End of Center to Object\n# Start of Move Into Contact\n###\n# Moves the robot into contact in the TCP direction set\n# @param force number Force that determines when a contact has been achieved\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_search number velocity_search\n# @param retract number Retract distance after a contact has been found\n# @param move_tcp_dir array TCP direction (3D vector)\n# @param zero_ft_on_start bool Determines if the force-torque sensor should be zeroed on start\n###\ndef ur_move_into_contact(force = 10, velocity = 0.05, acceleration = 0.1, max_distance = 0.25, retract = 0.0, move_tcp_dir = [0, 0, 1], zero_ft_on_start = True):\n # Zero the force torque sensor\n if (zero_ft_on_start):\n sleep(0.25)\n zero_ftsensor()\n end\n # Move the robot\n ur_move_until_force(max_distance, move_tcp_dir, velocity, acceleration, force)\n # If a retract distance is set, move the robot back to that position\n if (retract != 0):\n # Compute position offset from TCP direction and retract distance\n local position = normalize(move_tcp_dir) * retract\n movel(pose_trans(get_actual_tcp_pose(), p[position[0], position[1], position[2], 0, 0, 0]))\n end\nend\n# End of Move Into Contact\n# Start of Retract\n###\n# Retract in the TCP direction set\n# @param distance number Retraction distance\n# @param direction array TCP direction to move in (3D vector)\n# @param acceleration number Acceleration used by the robot\n# @param velocity number Velocity used by the robot\n###\ndef ur_retract(distance = -0.1, direction = [0, 0, 1], acceleration = 0.4, velocity = 0.1):\n local movement = normalize(direction) * distance\n movel(pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0]), a = acceleration, v = velocity)\nend\n# End of Retract","nodeIDList":[]}} \ No newline at end of file +{"jsonContent":{"applicationContributions":{"universal-robots-external-control-external-control-application":{"type":"universal-robots-external-control-external-control-application","version":"1.0.0","port":50002,"robotIP":"192.168.56.1"},"ur-mounting":{"type":"ur-mounting","version":"0.0.1","mounting":{"baseAngle":{"value":0,"unit":"deg"},"tiltAngle":{"value":0,"unit":"deg"}}},"ur-frames":{"type":"ur-frames","version":"0.0.7","framesList":[{"name":"base","nameVariable":{"name":"base","reference":false,"type":"$$Variable","valueType":"frame","id":"6252a467-7b48-0790-36af-5a9122953653","_IDENTIFIER":"VariableDeclaration"},"parent":"world","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"tcp","nameVariable":{"name":"tcp","reference":false,"type":"$$Variable","valueType":"frame","id":"902de4ca-4cc6-24d1-d208-a7d64dca1939","_IDENTIFIER":"VariableDeclaration"},"parent":"flange","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"world","nameVariable":{"name":"world","reference":false,"type":"$$Variable","valueType":"frame","id":"1abb892b-4453-7a0b-b117-ab746b820185","_IDENTIFIER":"VariableDeclaration"},"pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"flange","nameVariable":{"name":"flange","reference":false,"type":"$$Variable","valueType":"frame","id":"f05af2d5-8459-68af-fae9-b1468f81a987","_IDENTIFIER":"VariableDeclaration"},"parent":"base","pose":{"position":[0,0,0],"orientation":[0,0,0]}}]},"ur-grid-pattern":{"type":"ur-grid-pattern","version":"0.0.3","grids":[{"grid":{"name":"grid","reference":false,"type":"$$Variable","valueType":"grid","id":"bb906c62-298c-7c7e-f5f7-8820f778f926","_IDENTIFIER":"VariableDeclaration"},"waypoint":{"name":"grid_iterator","reference":false,"type":"$$Variable","valueType":"waypoint","id":"6be80bf7-b0e6-2d12-c3e3-fb3503fde43e","_IDENTIFIER":"VariableDeclaration"},"corners":[null,null,null,null],"numRows":4,"numColumns":5}]},"ur-end-effector":{"type":"ur-end-effector","version":"0.0.2","endEffectors":[{"id":"3035d318-72cd-77ab-9edf-b665bb775514","name":"Robot","payload":{"weight":{"value":0,"unit":"kg"}},"cog":{"cx":{"value":0,"unit":"m"},"cy":{"value":0,"unit":"m"},"cz":{"value":0,"unit":"m"}},"inertia":{"Ixx":{"value":0,"unit":"kg*m^2"},"Iyy":{"value":0,"unit":"kg*m^2"},"Izz":{"value":0,"unit":"kg*m^2"},"Ixy":{"value":0,"unit":"kg*m^2"},"Ixz":{"value":0,"unit":"kg*m^2"},"Iyz":{"value":0,"unit":"kg*m^2"}},"useCustomInertia":false,"tcps":[{"id":"d645c72d-cb4c-148c-b939-c91def1d47c7","name":"Tool_flange","x":{"value":0,"unit":"m"},"y":{"value":0,"unit":"m"},"z":{"value":0,"unit":"m"},"rx":{"value":0,"unit":"rad"},"ry":{"value":0,"unit":"rad"},"rz":{"value":0,"unit":"rad"}}]}],"defaultTcp":{"endEffectorId":"3035d318-72cd-77ab-9edf-b665bb775514","tcpId":"d645c72d-cb4c-148c-b939-c91def1d47c7"}},"ur-motion-profiles":{"type":"ur-motion-profiles","version":"0.0.1","moveProfiles":{"joint":[{"isDefault":false,"profile":{"name":"Joint_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"0142e66e-ed0c-594b-9607-10ea1d224f74","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Joint_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"6469ab80-19ff-2edf-d4f1-696f6f1643f0","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"linear":[{"isDefault":false,"profile":{"name":"Linear_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"092041a5-d60a-b98e-8975-7b4b8c432127","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Linear_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"125202dc-7124-f4dc-70e1-6025e87d825d","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"process":[{"isDefault":true,"profile":{"name":"Process","reference":false,"type":"$$Variable","valueType":"profile","id":"31c939a7-423a-f3b0-1f74-5387636ccc77","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"Classic","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2}}}]}},"ur-smart-skills":{"type":"ur-smart-skills","version":"0.0.3","preamble":"# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper"},"ur-application-variables":{"type":"ur-application-variables","version":"0.0.1","variables":{}}},"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{}},"sourcesNodes":{"robot":{"groupId":"robot","version":"1.0.0.","sources":[{"sourceID":"ur-wired-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"},{"signalID":"AO 0","direction":"OUT","valueType":"FLOAT"},{"signalID":"AO 1","direction":"OUT","valueType":"FLOAT"}],"webSocketURL":"/sources/wired-io"},{"sourceID":"ur-tool-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"}],"webSocketURL":"/sources/tool-io"}],"isDynamic":false},"ur-modbus":{"groupId":"ur-modbus","isDynamic":true,"version":"1.0.0","sources":[]},"ur-robot-io":{"type":"ur-robot-io","groupId":"ur-robot-io","isDynamic":false,"version":"1.0.2","sources":[{"sourceID":"ur-robot-wired-io","name":"Wired I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 0","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 1","valueType":"FLOAT"}]},{"sourceID":"ur-robot-tool-io","name":"Tool I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"}]}],"parameters":{"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{},"toolOutput":{"dualPinPower":false,"voltage":{"value":0,"unit":"V"},"powerOutput":{"DO 0":1,"DO 1":1}}},"migrateSourceConfigDone":true}}},"safety":{"settings":{"io":{"automaticModeSafeguardResetInput":{"name":"automaticModeSafeguardResetInput","valueA":255,"valueB":255},"automaticModeSafeguardStopInput":{"name":"automaticModeSafeguardStopInput","valueA":255,"valueB":255},"emergencyStopInput":{"name":"emergencyStopInput","valueA":255,"valueB":255},"notReducedModeOutput":{"name":"notReducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"operationalModeInput":{"name":"operationalModeInput","valueA":255,"valueB":255},"reducedModeInput":{"name":"reducedModeInput","valueA":255,"valueB":255},"reducedModeOutput":{"name":"reducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotMovingOutput":{"name":"robotMovingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotNotStoppingOutput":{"name":"robotNotStoppingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeHomeOutput":{"name":"safeHomeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeguardResetInput":{"name":"safeguardResetInput","valueA":0,"valueB":1},"systemEmergencyStoppedOutput":{"name":"systemEmergencyStoppedOutput","ossdEnabled":false,"valueA":255,"valueB":255},"threePositionSwitchInput":{"name":"threePositionSwitchInput","valueA":255,"valueB":255},"freedriveEnabledInput":{"name":"freedriveEnabledInput","valueA":255,"valueB":255},"threePositionEnablingStopOutput":{"name":"threePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255},"notThreePositionEnablingStopOutput":{"name":"notThreePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255}},"major":5,"minor":14,"normalJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"normalJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"normalRobotLimits":{"elbowForce":150,"elbowSpeed":1.5,"momentum":25,"power":300,"stoppingDistance":0.5,"stoppingTime":0.4,"toolForce":150,"toolSpeed":1.5},"reducedJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"reducedJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"reducedRobotLimits":{"elbowForce":120,"elbowSpeed":0.75,"momentum":10,"power":200,"stoppingDistance":0.3,"stoppingTime":0.3,"toolForce":120,"toolSpeed":0.75},"safetyHardware":{"injectionMoldingMachineInterface":"NONE","teachPendant":"NORMAL"},"safetyPlanes":{"planes":[{"id":"fa9294a4-967c-0579-2598-bbad56efc589","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"215f99a1-821b-78ec-6ca8-ebf9af0305f9","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"54b27eb2-3f22-d0d6-4392-1bca84eaba07","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"c56f70d3-b7d5-5e11-efc2-cd03174894ef","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"24b0b581-f988-5112-2298-db6ec78b8697","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"0f8b6df0-cb79-53b4-b4e7-87e506d0b74a","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"31eeb60c-4d58-13be-cfc4-514e8c663223","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"f80f48d0-f136-fe07-0df6-2155d1bd261c","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"}],"ioSafetyPlanes":[{"id":"eabab9c5-2d28-c06f-3d80-2acac453bb2c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"fbe1a183-0d6d-5ffb-db55-0702ac3586d4","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"bebca814-b309-296e-3b85-f11afbbd7a34","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"f5585223-652e-a47b-ee33-1ea2fbc16f6c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"f21f0288-3694-1561-5529-15653ad65d6d","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"354479b5-9e7e-e940-1485-97c1ccf4c80b","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"5491a1c6-1740-6878-0fd5-45e1fdb3ed9a","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"85ceb891-c975-13c5-ca8f-5b2d051225d0","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"}]},"safetySafeHome":{"base":-1,"elbow":-1,"shoulder":-1,"wrist1":-1,"wrist2":-1,"wrist3":-1,"enabled":false},"safetyAPIParameters":{"numberOfClients":0,"clients":[]},"safetyFieldbusses":{"enablePROFIsafe":false,"sourceAddressPROFIsafe":0,"destAddressPROFIsafe":0,"modeControlPROFIsafe":false},"threePosition":{"allowManualHighSpeed":true,"useTeachPendantAs3PE":false},"toolDirection":{"limitDeviation":6.2831855,"limitDirection":{"x":0,"y":0,"z":1},"limitRestriction":"DISABLED","tcp":{"id":"toolFlangeTcpId","name":"Tool_flange"},"toolPan":0,"toolTilt":0,"limitTilt":0,"limitRotation":0},"toolPositions":{"toolPositions":[{"name":"Tool Flange","center":{"x":0,"y":0,"z":0},"radius":0,"definition":2},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0}]},"normalWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"},"reducedWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"}},"crc":"2850523693","confirmed":true},"operatorScreens":[{"type":"ur-operator-screen-default","version":"0.0.2","parameters":{"status":[],"configuration":[]}}],"sidebarItems":[{"type":"ur-global-variables","version":"1.0.0","disabled":{"master":false,"automaticMode":false,"remoteMode":true}},{"type":"ur-log-messages-sidebar","version":"0.0.1","disabled":{"master":false,"automaticMode":false,"remoteMode":true}}],"activeOperatorScreen":"ur-operator-screen-default","smartSkills":[{"name":"Align to Plane","enabled":true,"type":"ur-align-to-plane","parameters":{"radius":0.05,"push_force":20,"n_plane_points":3,"max_distance":0.25,"velocity_slow":0.001,"velocity_search":0.035,"velocity_move":0.1,"acceleration":0.1}},{"name":"Align Z to Nearest Axis","enabled":true,"type":"ur-align-z-to-nearest-axis"},{"name":"Center","enabled":true,"type":"ur-center","parameters":{"push_force":10,"velocity_move":0.05,"acc_move":0.2,"max_radius_search":0.05,"num_fingers":3}},{"name":"Freedrive","enabled":true,"type":"ur-freedrive","version":"1.0.0","recordingFrequency":50,"recordingSignals":["timestamp","target_q","actual_TCP_pose","tcp_offset"]},{"name":"Move into Contact","enabled":true,"type":"ur-move-into-contact","parameters":{"force":10,"velocity":0.05,"acceleration":0.2,"max_distance":0.25,"retract":0}},{"name":"Retract","enabled":true,"type":"ur-retract","parameters":{"distance":-0.1,"acceleration":0.4,"velocity":0.1}},{"name":"Put into Box","enabled":false,"type":"ur-put-in-box","version":"1.0.0"},{"name":"Custom","enabled":false,"type":"ur-custom-smart-skill","parameters":{"includePreamble":true,"includeModules":false},"version":"1.0.0"},{"name":"Home","enabled":true,"type":"ur-position","version":"1.1.2","parameters":{"actualWaypoint":{"frame":"base","pose":{"position":[-1.8246917738038495E-9,-0.2329000001676105,1.0793999999522315],"orientation":[3.987257497300885E-9,2.2214414675120993,-2.221441467056474]},"qNear":{"base":0,"shoulder":-1.5707963249999999,"elbow":0,"wrist1":-1.5707963249999999,"wrist2":0,"wrist3":0}},"variable":{"name":"Home","reference":false,"type":"$$Variable","valueType":"waypoint","id":"1a7b4663-70cf-4964-6c73-a28c5664b8a2","_IDENTIFIER":"VariableDeclaration"}}}]},"script":{"script":"set_safety_mode_transition_hardness(1)\nreset_world_model()\nset_input_actions_to_default()\nset_analog_outputdomain(0,0)\nset_analog_outputdomain(1,0)\nset_standard_analog_input_domain(0,0)\nset_standard_analog_input_domain(1,0)\nset_tool_output_mode(0)\nset_tool_voltage(0)\nset_tool_digital_output_mode(0,1)\nset_tool_digital_output_mode(1,1)\nset_tool_analog_input_domain(0,0)\nset_tool_analog_input_domain(1,0)\nset_gravity([0, 0, 9.82])\nlocal existingBaseParent = get_frame_parent(\"base\")\nlocal basePose = get_pose(\"base\", existingBaseParent)\nbasePose[3] = 0\nbasePose[4] = 0\nbasePose[5] = 0\nmove_frame(\"base\", basePose, existingBaseParent)\nglobal base = \"base\"\nglobal tcp = \"tcp\"\nglobal world = \"world\"\nglobal flange = \"flange\"\nset_target_payload(0, [0, 0, 0], [0, 0, 0, 0, 0, 0])\nset_tcp(p[0, 0, 0, 0, 0, 0], \"Tool_flange\")\n# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper\n# Waypoint variable for Home smart skill\nglobal Home = struct(p=p[-1.8246917738038495e-9, -0.2329000001676105, 1.0793999999522315, 3.987257497300885e-9, 2.2214414675120993, -2.221441467056474], frame=\"base\", q=[0, -1.5707963249999999, 0, -1.5707963249999999, 0, 0])\n# Start of Align to Plane\n###\n# Align to plane will touch up a plane by moving the robot into contact with the table or part in several locations to determine its orientation. Afterwards the robot will orient its tool to the plane.\n# @param radius number Radius [m] of the circle within the plane will be touched up\n# @param push_force number How hard to robot pushed against the plane\n# @param n_plane_points number Number of points that the robot uses to compute the plane\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_slow number Velocity when pressing downwards\n# @param velocity_search number Velocity used when approaching the touch up point\n# @param velocity_move number Velocity used in freespace\n# @param acceleration number Acceleration of the robot\n# @param direction array 3D vector determining the direction of the TCP for touching up the plane\n###\ndef ur_align_to_plane(radius = 0.05, push_force = 20, n_plane_points = 3, max_distance = 0.25, velocity_slow = 0.001, velocity_search = 0.035, velocity_move = 0.10, acceleration = 0.1, direction = [0, 0, 1]):\n local angle = 2 * PI / n_plane_points\n local start_pos = get_target_tcp_pose()\n local retract_distance = -0.015\n ur_move_tcp_direction(retract_distance, direction, velocity_move, acceleration, 0)\n sleep(0.25)\n zero_ftsensor()\n local cnt = 0\n local t_base_target = get_target_tcp_pose()\n local mean_point = [0.0, 0.0, 0.0]\n local A = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]\n local b = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n while cnt < n_plane_points:\n local new_pos = pose_trans(t_base_target, p[cos(angle * cnt) * radius, sin(angle * cnt) * radius, 0.0, 0.0, 0.0, 0.0])\n local blend_radius = norm(point_dist(get_actual_tcp_pose(), new_pos))/5\n movel(new_pos, a = acceleration, v = velocity_move, r = blend_radius)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_search, acceleration, push_force)\n local movement = normalize(direction * -1) * 0.0005\n local target_pose = pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose)\n sleep(0.2)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_slow, acceleration, push_force)\n sleep(0.2)\n while (not is_steady()):\n sync()\n end\n local poked_point = get_target_tcp_pose()\n poked_point = pose_trans(inv(t_base_target), poked_point)\n A[cnt, 0] = poked_point[0]\n A[cnt, 1] = poked_point[1]\n A[cnt, 2] = 1.0\n b[cnt] = poked_point[2]\n mean_point = mean_point + [poked_point[0], poked_point[1], poked_point[2]]\n movel(new_pos, a = 0.2, v = velocity_move, r = blend_radius)\n cnt = cnt + 1\n end\n mean_point = mean_point / n_plane_points\n cnt = 0\n while cnt < n_plane_points:\n local cntj = 0\n while cntj < 2:\n A[cnt, cntj] = A[cnt, cntj] - mean_point[cntj]\n cntj = cntj + 1\n end\n b[cnt] = b[cnt] - mean_point[2]\n cnt = cnt + 1\n end\n local x1 = inv(transpose(A) * A) * transpose(A) * b\n local x = normalize([x1[0], x1[1], -1])\n local d = dot(mean_point, x)\n local dval = dot(direction, x)\n if dval < 0:\n x = -x\n dval = -dval\n end\n local eaa = [0.0, 0.0, 0.0]\n local EPSILON = 1e-10\n if norm(dval - 1) < EPSILON:\n # if the projection is close to 1 then the angle between the vectors are almost 0 and we cannot\n # reliably determine the perpendicular axis.\n # A good approximation is therefore just to set the EAA equal to 0.\n eaa = [0.0, 0.0, 0.0]\n else:\n local axis = cross(direction, x)\n local eaa = normalize(axis) * acos(dval)\n end\n local t_base_target_aligned = pose_trans(t_base_target, p[0, 0, 0, eaa[0], eaa[1], eaa[2]])\n movel(t_base_target_aligned, a = 0.2, v = velocity_move)\nend\n# End of Align to Plane\n# Start of Align Z to Nearest Axis\n###\n# Aligns the TCP Z axis to the nearest axis of the given frame\n# @param frame_id string frame_id to lookup frame\n###\ndef ur_align_z_to_nearest_axis(frame_id = \"world\"):\n ###\n # Given a reference frame as input this function returns a struct with the nearest\n # pose which aligns the z-axis of the robot TCP with the z-axis of the given reference frame.\n # The pose is in the reference of the given frame.\n # @param frame bool frame\n # @returns struct pose, distance, referencePose\n ###\n def get_aligned_z_pose(frame):\n local actualPose = get_actual_tcp_pose()\n local actualPoseInFrame = pose_trans(pose_inv(frame), actualPose)\n # Create rotation vector and convert that to RPY representation\n local actualRotInFrame = [actualPoseInFrame[3], actualPoseInFrame[4], actualPoseInFrame[5]]\n local actRPY = rotvec2rpy(actualRotInFrame)\n # Set RX and RY to 0 and convert back to rotation vector\n local alignedRot = rpy2rotvec([0, 0, actRPY[2]])\n local alignedRotFlipped = rpy2rotvec([PI, 0, actRPY[2]])\n local zUpPose = actualPoseInFrame\n zUpPose[3] = alignedRot[0]\n zUpPose[4] = alignedRot[1]\n zUpPose[5] = alignedRot[2]\n zUpStruct = struct(pose = zUpPose, distance=pose_dist(actualPoseInFrame, zUpPose), referencePose=frame)\n local zDownPose = actualPoseInFrame\n zDownPose[3] = alignedRotFlipped[0]\n zDownPose[4] = alignedRotFlipped[1]\n zDownPose[5] = alignedRotFlipped[2]\n local zDownStruct = struct(pose = zDownPose, distance=pose_dist(actualPoseInFrame, zDownPose), referencePose=frame)\n # Return the solution which is closer to the current robot pose\n if (zDownStruct.distance > zUpStruct.distance):\n return zUpStruct\n else:\n return zDownStruct\n end\n end\n local frame = get_pose(frame_id)\n # Rotate the given frame so that Z can be align to X-Y-Z respectively \n local rotZtoX = rpy2rotvec([0,0.5*PI,0])\n local rotZtoY = rpy2rotvec([0.5*PI,0,0])\n local rotZtoZ = rpy2rotvec([0,0,0])\n # Get aligned poses for each of the rotated frames\n local structAlignedToX = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoX[0],rotZtoX[1],rotZtoX[2]]))\n structAlignedToY = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoY[0],rotZtoY[1],rotZtoY[2]]))\n structAlignedToZ = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoZ[0],rotZtoZ[1],rotZtoZ[2]]))\n # Find the nearest alignement\n local structAligned = structAlignedToZ\n if(structAligned.distance > structAlignedToX.distance):\n structAligned = structAlignedToX \n end\n if(structAligned.distance > structAlignedToY.distance):\n structAligned = structAlignedToY \n end\n # Move the robot to the aligned pose\n movel(pose_trans(get_actual_tcp_pose(), p[0,0,0.00001,0,0,0]), v = 0.1)\n movel(pose_trans(structAligned.referencePose, structAligned.pose ), v = 0.1)\nend\n# End of Align Z to Nearest Axis\n# Start of Center to Object\n###\n# Centers to an object by touching the externals of it. It works well for fixtured or heavy parts.\n# @param push_force number Force the robot uses to determine if a contact has been achieved\n# @param velocity_move number Velocity in freespace\n# @param velocity_search number First move is used then search\n# @param acc_move number Acceleration in freespace\n# @param max_radius_search number Maximum search radius\n# @param num_fingers number Number of fingers that the gripper has\n###\ndef ur_center_to_object(push_force = 10, velocity_move = 0.10, velocity_search = 0.01, acc_move = 0.2, max_radius_search = 0.05, num_fingers = 3):\n def compute_circle_center(p_list):\n # Compute the circle center by circular regression\n # Source: https://math.stackexchange.com/questions/2898295/how-to-quickly-fit-a-circle-by-given-random-arc-points\n local itr = 0\n local x = 0\n local y = 1\n \n local m1 = [[0,0,0],[0,0,0],[0,0,0]]\n local m2 = [[0,0],[0,0],[0,0]]\n local m3 = [[0],[0],[0]]\n \n while(itr < get_list_length(p_list)):\n local p = p_list[itr]\n \n if(p_list[itr] == p[0,0,0,0,0,0]):\n break\n end\n \n m1[0,0] = m1[0,0] + (p[x]*p[x])\n m1[0,1] = m1[0,1] + (p[x]*p[y])\n m1[0,2] = m1[0,2] + (p[x])\n \n m1[1,0] = m1[1,0] + (p[x]*p[y])\n m1[1,1] = m1[1,1] + (p[y]*p[y])\n m1[1,2] = m1[1,2] + (p[y])\n \n m1[2,0] = m1[2,0] + (p[x])\n m1[2,1] = m1[2,1] + (p[y])\n \n m2[0,0] = m2[0,0] + (pow(p[x], 3))\n m2[0,1] = m2[0,1] + (p[x] * pow(p[y], 2))\n \n m2[1,0] = m2[1,0] + (pow(p[y], 3))\n m2[1,1] = m2[1,1] + (pow(p[x], 2) * p[y])\n \n m2[2,0] = m2[2,0] + (pow(p[x], 2))\n m2[2,1] = m2[2,1] + (pow(p[y], 2))\n \n itr = itr +1\n end\n \n if(itr < 2):\n return p[0,0,0,0,0,0]\n elif(itr > get_list_length(p_list)):\n return p[0,0,0,0,0,0]\n end\n \n m1[0,0] = 2 * m1[0,0]\n m1[0,1] = 2 * m1[0,1]\n m1[1,0] = 2 * m1[1,0]\n m1[1,1] = 2 * m1[1,1]\n m1[2,0] = 2 * m1[2,0]\n m1[2,1] = 2 * m1[2,1]\n m1[2,2] = itr\n m3[0,0] = m2[0,0] + m2[0,1]\n m3[1,0] = m2[1,0] + m2[1,1]\n m3[2,0] = m2[2,0] + m2[2,1]\n \n local center = inv(m1) * m3\n \n return p[center[0,0], center[1,0],0,0,0,0]\n end\n \n def sanity_checked_move(p_org, p_new, max_diff, acc, vel):\n if (pose_dist(p_org, p_new) > max_diff):\n movel(p_org, a = acc, v = vel)\n popup(\"New pose is too far away from original. Returning to original\", title = \"Failed\", warning = False, error = True, blocking = True)\n else:\n movel(p_new, a = acc, v = vel)\n end\n end\n # Start by zeroing the FT sensor\n sleep(0.25)\n zero_ftsensor()\n local p_start = get_actual_tcp_pose()\n local p0 = p[0,0,0,0,0,0]\n local DIR_X = [1, 0, 0]\n if (num_fingers == 2):\n local dir_list = [DIR_X, -DIR_X, DIR_X, -DIR_X]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0]\n elif (num_fingers == 3):\n local DIR_P1 = DIR_X\n local DIR_P2 = [-1 / 2, sqrt(3.0) / 2.0, 0]\n local DIR_P3 = [-1 / 2, -sqrt(3.0) / 2.0, 0]\n local dir_list = [DIR_P1, DIR_P2, DIR_P3, DIR_P1, DIR_P2, DIR_P3]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0, p0, p0]\n else:\n popup(\"Number of fingers not supported\")\n halt\n end\n # Loop through directions\n local it = 0\n local dir_list_size = size(dir_list)\n local dir_list_length = dir_list_size[0]\n while(it < dir_list_length):\n # Move to starting position if more than 3 positions is stored then calculate a new starting position\n if(it < 3):\n movel(pose_trans(p_start, start_offset[it]), a = acc_move, v = velocity_move)\n else:\n local p_start_temp = pose_trans(pose_trans(p_start, compute_circle_center(p_list)), start_offset[it])\n local p_start_w_offset = pose_trans(p_start, start_offset[it])\n sanity_checked_move(p_start_w_offset, p_start_temp, max_radius_search, acc_move, velocity_move)\n end\n local p_start_temp = get_actual_tcp_pose()\n # Move into contact and store contact point\n sleep(0.1)\n local contact_point = ur_move_until_force(distance = max_radius_search, direction = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]], velocity = velocity_search, acceleration = acc_move, stop_force = push_force)\n \n local dir = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]]\n dir = normalize(dir) * 0.05\n contact_point = pose_trans(contact_point, p[dir[0], dir[1], dir[2], 0, 0, 0])\n p_list[it] = pose_trans(pose_inv(p_start), contact_point)\n # Move out of contact\n movel(p_start_temp, a = acc_move, v = velocity_move)\n it = it + 1\n end\n # Find circle center based on n stored points\n local center_offset_xy = compute_circle_center(p_list)\n local p_center = pose_trans(p_start, center_offset_xy)\n \n # Move the robot to the center if it can\n sanity_checked_move(p_start, p_center, max_radius_search, acc_move, velocity_move)\nend\n# End of Center to Object\n# Start of Move Into Contact\n###\n# Moves the robot into contact in the TCP direction set\n# @param force number Force that determines when a contact has been achieved\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_search number velocity_search\n# @param retract number Retract distance after a contact has been found\n# @param move_tcp_dir array TCP direction (3D vector)\n# @param zero_ft_on_start bool Determines if the force-torque sensor should be zeroed on start\n###\ndef ur_move_into_contact(force = 10, velocity = 0.05, acceleration = 0.1, max_distance = 0.25, retract = 0.0, move_tcp_dir = [0, 0, 1], zero_ft_on_start = True):\n # Zero the force torque sensor\n if (zero_ft_on_start):\n sleep(0.25)\n zero_ftsensor()\n end\n # Move the robot\n ur_move_until_force(max_distance, move_tcp_dir, velocity, acceleration, force)\n # If a retract distance is set, move the robot back to that position\n if (retract != 0):\n # Compute position offset from TCP direction and retract distance\n local position = normalize(move_tcp_dir) * retract\n movel(pose_trans(get_actual_tcp_pose(), p[position[0], position[1], position[2], 0, 0, 0]))\n end\nend\n# End of Move Into Contact\n# Start of Retract\n###\n# Retract in the TCP direction set\n# @param distance number Retraction distance\n# @param direction array TCP direction to move in (3D vector)\n# @param acceleration number Acceleration used by the robot\n# @param velocity number Velocity used by the robot\n###\ndef ur_retract(distance = -0.1, direction = [0, 0, 1], acceleration = 0.4, velocity = 0.1):\n local movement = normalize(direction) * distance\n movel(pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0]), a = acceleration, v = velocity)\nend\n# End of Retract","nodeIDList":[]}} \ No newline at end of file diff --git a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/7.blob b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/5.blob similarity index 74% rename from tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/7.blob rename to tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/5.blob index b47e7520f..f92d6e768 100644 --- a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/7.blob +++ b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/blobs/5.blob @@ -1 +1 @@ -{"jsonContent":{"applicationContributions":{"ur-mounting":{"type":"ur-mounting","version":"0.0.1","mounting":{"baseAngle":{"value":0,"unit":"deg"},"tiltAngle":{"value":0,"unit":"deg"}}},"ur-frames":{"type":"ur-frames","version":"0.0.7","framesList":[{"name":"base","nameVariable":{"name":"base","reference":false,"type":"$$Variable","valueType":"frame","id":"17c5e7dd-f5a3-ef14-19fb-881f12fb655a","_IDENTIFIER":"VariableDeclaration"},"parent":"world","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"tcp","nameVariable":{"name":"tcp","reference":false,"type":"$$Variable","valueType":"frame","id":"d96aa509-ec33-3065-09fe-4a23a9dabd7e","_IDENTIFIER":"VariableDeclaration"},"parent":"flange","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"world","nameVariable":{"name":"world","reference":false,"type":"$$Variable","valueType":"frame","id":"2b2fe453-df5f-d8b9-f496-673d978f005a","_IDENTIFIER":"VariableDeclaration"},"pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"flange","nameVariable":{"name":"flange","reference":false,"type":"$$Variable","valueType":"frame","id":"2e6d33a2-5ee3-b61d-e217-481053c1e028","_IDENTIFIER":"VariableDeclaration"},"parent":"base","pose":{"position":[0,0,0],"orientation":[0,0,0]}}]},"ur-grid-pattern":{"type":"ur-grid-pattern","version":"0.0.3","grids":[{"grid":{"name":"grid","reference":false,"type":"$$Variable","valueType":"grid","id":"48df2b01-e230-53d6-7907-915e1d764eac","_IDENTIFIER":"VariableDeclaration"},"waypoint":{"name":"grid_iterator","reference":false,"type":"$$Variable","valueType":"waypoint","id":"b93685a1-ba10-44ac-a2e5-22003cff5c6d","_IDENTIFIER":"VariableDeclaration"},"corners":[null,null,null,null],"numRows":4,"numColumns":5}]},"ur-end-effector":{"type":"ur-end-effector","version":"0.0.2","endEffectors":[{"id":"2e7f4047-a637-aa1f-d957-30b7358a50a6","name":"Robot","payload":{"weight":{"value":0,"unit":"kg"}},"cog":{"cx":{"value":0,"unit":"m"},"cy":{"value":0,"unit":"m"},"cz":{"value":0,"unit":"m"}},"inertia":{"Ixx":{"value":0,"unit":"kg*m^2"},"Iyy":{"value":0,"unit":"kg*m^2"},"Izz":{"value":0,"unit":"kg*m^2"},"Ixy":{"value":0,"unit":"kg*m^2"},"Ixz":{"value":0,"unit":"kg*m^2"},"Iyz":{"value":0,"unit":"kg*m^2"}},"useCustomInertia":false,"tcps":[{"id":"c2f98e6f-a449-4e6a-a701-9f8a54e67ef4","name":"Tool_flange","x":{"value":0,"unit":"m"},"y":{"value":0,"unit":"m"},"z":{"value":0,"unit":"m"},"rx":{"value":0,"unit":"rad"},"ry":{"value":0,"unit":"rad"},"rz":{"value":0,"unit":"rad"}}]}],"defaultTcp":{"endEffectorId":"2e7f4047-a637-aa1f-d957-30b7358a50a6","tcpId":"c2f98e6f-a449-4e6a-a701-9f8a54e67ef4"}},"ur-motion-profiles":{"type":"ur-motion-profiles","version":"0.0.1","moveProfiles":{"joint":[{"isDefault":false,"profile":{"name":"Joint_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"0ef8f8e8-cde2-9d57-cc5b-c7208c9fe3c2","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Joint_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"5346fd60-6b3d-e0a9-cfaa-3c2658924408","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"linear":[{"isDefault":false,"profile":{"name":"Linear_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"7c2febc9-1491-589e-1501-42442cc6893c","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Linear_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"8b590dc2-ec8b-3637-004c-9a57e7e84276","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"process":[{"isDefault":true,"profile":{"name":"Process","reference":false,"type":"$$Variable","valueType":"profile","id":"1e798479-1637-e766-859b-7040d73ebaf7","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"Classic","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2}}}]}},"ur-smart-skills":{"type":"ur-smart-skills","version":"0.0.3","preamble":"# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper"},"ur-application-variables":{"type":"ur-application-variables","version":"0.0.1","variables":{}},"universal-robots-external-control-external-control-application":{"type":"universal-robots-external-control-external-control-application","version":"1.0.0","port":50002,"robotIP":"192.168.56.1"}},"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{}},"sourcesNodes":{"robot":{"groupId":"robot","version":"1.0.0.","sources":[{"sourceID":"ur-wired-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"},{"signalID":"AO 0","direction":"OUT","valueType":"FLOAT"},{"signalID":"AO 1","direction":"OUT","valueType":"FLOAT"}],"webSocketURL":"/sources/wired-io"},{"sourceID":"ur-tool-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"}],"webSocketURL":"/sources/tool-io"}],"isDynamic":false},"ur-modbus":{"groupId":"ur-modbus","isDynamic":true,"version":"1.0.0","sources":[]},"ur-robot-io":{"type":"ur-robot-io","groupId":"ur-robot-io","isDynamic":false,"version":"1.0.2","sources":[{"sourceID":"ur-robot-wired-io","name":"Wired I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 0","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 1","valueType":"FLOAT"}]},{"sourceID":"ur-robot-tool-io","name":"Tool I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"}]}],"parameters":{"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{},"toolOutput":{"dualPinPower":false,"voltage":{"value":0,"unit":"V"},"powerOutput":{"DO 0":1,"DO 1":1}}},"migrateSourceConfigDone":true}}},"safety":{"settings":{"io":{"automaticModeSafeguardResetInput":{"name":"automaticModeSafeguardResetInput","valueA":255,"valueB":255},"automaticModeSafeguardStopInput":{"name":"automaticModeSafeguardStopInput","valueA":255,"valueB":255},"emergencyStopInput":{"name":"emergencyStopInput","valueA":255,"valueB":255},"notReducedModeOutput":{"name":"notReducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"operationalModeInput":{"name":"operationalModeInput","valueA":255,"valueB":255},"reducedModeInput":{"name":"reducedModeInput","valueA":255,"valueB":255},"reducedModeOutput":{"name":"reducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotMovingOutput":{"name":"robotMovingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotNotStoppingOutput":{"name":"robotNotStoppingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeHomeOutput":{"name":"safeHomeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeguardResetInput":{"name":"safeguardResetInput","valueA":0,"valueB":1},"systemEmergencyStoppedOutput":{"name":"systemEmergencyStoppedOutput","ossdEnabled":false,"valueA":255,"valueB":255},"threePositionSwitchInput":{"name":"threePositionSwitchInput","valueA":255,"valueB":255},"freedriveEnabledInput":{"name":"freedriveEnabledInput","valueA":255,"valueB":255},"threePositionEnablingStopOutput":{"name":"threePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255},"notThreePositionEnablingStopOutput":{"name":"notThreePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255}},"major":5,"minor":14,"normalJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"normalJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"normalRobotLimits":{"elbowForce":150,"elbowSpeed":1.5,"momentum":25,"power":300,"stoppingDistance":0.5,"stoppingTime":0.4,"toolForce":150,"toolSpeed":1.5},"reducedJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"reducedJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"reducedRobotLimits":{"elbowForce":120,"elbowSpeed":0.75,"momentum":10,"power":200,"stoppingDistance":0.3,"stoppingTime":0.3,"toolForce":120,"toolSpeed":0.75},"safetyHardware":{"injectionMoldingMachineInterface":"NONE","teachPendant":"NORMAL"},"safetyPlanes":{"planes":[{"id":"c7314701-34ec-1674-a33d-a226b1cd34bc","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"ed4d303b-25c3-9ef0-867d-5dd3d70201f9","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"79ace36e-a147-044d-c436-583abde29c09","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"52d5930b-4200-b2c2-ff14-ca60642554cd","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e1554217-d3da-bc37-57cc-d8e868766608","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"643c8131-1f1d-db3f-6447-d062bd6a41da","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"b531cb99-8f5b-2ecd-0da6-8b0009840661","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"e367d34e-fba3-5a65-f9ed-0c4925240d21","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"}],"ioSafetyPlanes":[{"id":"dcbb3122-97a6-3196-c6fd-c234fc103963","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a1554adb-2b98-f7ec-a7d7-9877ebe7939c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"fb53caf6-eb68-bab8-bddc-4ccb8dd42f25","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"79c00e8d-7415-4510-1e40-6742240e86ff","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"70f45544-4998-52f8-5a91-adaf39459678","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"a8678cc2-fd26-4c10-a10c-4904469c6e08","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"e6225a34-0085-7027-2f23-9cedb6cb3688","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"32d5f884-e587-e9fe-8970-456fff173c7f","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"}]},"safetySafeHome":{"base":-1,"elbow":-1,"shoulder":-1,"wrist1":-1,"wrist2":-1,"wrist3":-1,"enabled":false},"safetyAPIParameters":{"numberOfClients":0,"clients":[]},"safetyFieldbusses":{"enablePROFIsafe":false,"sourceAddressPROFIsafe":0,"destAddressPROFIsafe":0,"modeControlPROFIsafe":false},"threePosition":{"allowManualHighSpeed":true,"useTeachPendantAs3PE":false},"toolDirection":{"limitDeviation":6.2831855,"limitDirection":{"x":0,"y":0,"z":1},"limitRestriction":"DISABLED","tcp":{"id":"toolFlangeTcpId","name":"Tool_flange"},"toolPan":0,"toolTilt":0,"limitTilt":0,"limitRotation":0},"toolPositions":{"toolPositions":[{"name":"Tool Flange","center":{"x":0,"y":0,"z":0},"radius":0,"definition":2},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0}]},"normalWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"},"reducedWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"}},"crc":"2850523693","confirmed":true},"operatorScreens":[{"type":"ur-operator-screen-default","version":"0.0.2","parameters":{"status":[],"configuration":[]}}],"sidebarItems":[{"type":"ur-global-variables","version":"1.0.0","disabled":{"master":false,"automaticMode":false,"remoteMode":true}},{"type":"ur-log-messages-sidebar","version":"0.0.1","disabled":{"master":false,"automaticMode":false,"remoteMode":true}}],"activeOperatorScreen":"ur-operator-screen-default","smartSkills":[{"name":"Align to Plane","enabled":true,"type":"ur-align-to-plane","parameters":{"radius":0.05,"push_force":20,"n_plane_points":3,"max_distance":0.25,"velocity_slow":0.001,"velocity_search":0.035,"velocity_move":0.1,"acceleration":0.1}},{"name":"Align Z to Nearest Axis","enabled":true,"type":"ur-align-z-to-nearest-axis"},{"name":"Center","enabled":true,"type":"ur-center","parameters":{"push_force":10,"velocity_move":0.05,"acc_move":0.2,"max_radius_search":0.05,"num_fingers":3}},{"name":"Freedrive","enabled":true,"type":"ur-freedrive","version":"1.0.0","recordingFrequency":50,"recordingSignals":["timestamp","target_q","actual_TCP_pose","tcp_offset"]},{"name":"Move into Contact","enabled":true,"type":"ur-move-into-contact","parameters":{"force":10,"velocity":0.05,"acceleration":0.2,"max_distance":0.25,"retract":0}},{"name":"Retract","enabled":true,"type":"ur-retract","parameters":{"distance":-0.1,"acceleration":0.4,"velocity":0.1}},{"name":"Put into Box","enabled":false,"type":"ur-put-in-box","version":"1.0.0"},{"name":"Custom","enabled":false,"type":"ur-custom-smart-skill","parameters":{"includePreamble":true,"includeModules":false},"version":"1.0.0"},{"name":"Home","enabled":true,"type":"ur-position","version":"1.1.2","parameters":{"actualWaypoint":{"frame":"base","pose":{"position":[-1.8246917738038495E-9,-0.2329000001676105,1.0793999999522315],"orientation":[3.987257497300885E-9,2.2214414675120993,-2.221441467056474]},"qNear":{"base":0,"shoulder":-1.5707963249999999,"elbow":0,"wrist1":-1.5707963249999999,"wrist2":0,"wrist3":0}},"variable":{"name":"Home","reference":false,"type":"$$Variable","valueType":"waypoint","id":"8dbe361a-a570-5719-3461-20743ddc9310","_IDENTIFIER":"VariableDeclaration"}}}]},"script":{"script":"set_safety_mode_transition_hardness(1)\nreset_world_model()\nset_input_actions_to_default()\nset_analog_outputdomain(0,0)\nset_analog_outputdomain(1,0)\nset_standard_analog_input_domain(0,0)\nset_standard_analog_input_domain(1,0)\nset_tool_output_mode(0)\nset_tool_voltage(0)\nset_tool_digital_output_mode(0,1)\nset_tool_digital_output_mode(1,1)\nset_tool_analog_input_domain(0,0)\nset_tool_analog_input_domain(1,0)\nset_gravity([0, 0, 9.82])\nlocal existingBaseParent = get_frame_parent(\"base\")\nlocal basePose = get_pose(\"base\", existingBaseParent)\nbasePose[3] = 0\nbasePose[4] = 0\nbasePose[5] = 0\nmove_frame(\"base\", basePose, existingBaseParent)\nglobal base = \"base\"\nglobal tcp = \"tcp\"\nglobal world = \"world\"\nglobal flange = \"flange\"\nset_target_payload(0, [0, 0, 0], [0, 0, 0, 0, 0, 0])\nset_tcp(p[0, 0, 0, 0, 0, 0], \"Tool_flange\")\n# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper\n# Waypoint variable for Home smart skill\nglobal Home = struct(p=p[-1.8246917738038495e-9, -0.2329000001676105, 1.0793999999522315, 3.987257497300885e-9, 2.2214414675120993, -2.221441467056474], frame=\"base\", q=[0, -1.5707963249999999, 0, -1.5707963249999999, 0, 0])\n# Start of Align to Plane\n###\n# Align to plane will touch up a plane by moving the robot into contact with the table or part in several locations to determine its orientation. Afterwards the robot will orient its tool to the plane.\n# @param radius number Radius [m] of the circle within the plane will be touched up\n# @param push_force number How hard to robot pushed against the plane\n# @param n_plane_points number Number of points that the robot uses to compute the plane\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_slow number Velocity when pressing downwards\n# @param velocity_search number Velocity used when approaching the touch up point\n# @param velocity_move number Velocity used in freespace\n# @param acceleration number Acceleration of the robot\n# @param direction array 3D vector determining the direction of the TCP for touching up the plane\n###\ndef ur_align_to_plane(radius = 0.05, push_force = 20, n_plane_points = 3, max_distance = 0.25, velocity_slow = 0.001, velocity_search = 0.035, velocity_move = 0.10, acceleration = 0.1, direction = [0, 0, 1]):\n local angle = 2 * PI / n_plane_points\n local start_pos = get_target_tcp_pose()\n local retract_distance = -0.015\n ur_move_tcp_direction(retract_distance, direction, velocity_move, acceleration, 0)\n sleep(0.25)\n zero_ftsensor()\n local cnt = 0\n local t_base_target = get_target_tcp_pose()\n local mean_point = [0.0, 0.0, 0.0]\n local A = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]\n local b = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n while cnt < n_plane_points:\n local new_pos = pose_trans(t_base_target, p[cos(angle * cnt) * radius, sin(angle * cnt) * radius, 0.0, 0.0, 0.0, 0.0])\n local blend_radius = norm(point_dist(get_actual_tcp_pose(), new_pos))/5\n movel(new_pos, a = acceleration, v = velocity_move, r = blend_radius)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_search, acceleration, push_force)\n local movement = normalize(direction * -1) * 0.0005\n local target_pose = pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose)\n sleep(0.2)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_slow, acceleration, push_force)\n sleep(0.2)\n while (not is_steady()):\n sync()\n end\n local poked_point = get_target_tcp_pose()\n poked_point = pose_trans(inv(t_base_target), poked_point)\n A[cnt, 0] = poked_point[0]\n A[cnt, 1] = poked_point[1]\n A[cnt, 2] = 1.0\n b[cnt] = poked_point[2]\n mean_point = mean_point + [poked_point[0], poked_point[1], poked_point[2]]\n movel(new_pos, a = 0.2, v = velocity_move, r = blend_radius)\n cnt = cnt + 1\n end\n mean_point = mean_point / n_plane_points\n cnt = 0\n while cnt < n_plane_points:\n local cntj = 0\n while cntj < 2:\n A[cnt, cntj] = A[cnt, cntj] - mean_point[cntj]\n cntj = cntj + 1\n end\n b[cnt] = b[cnt] - mean_point[2]\n cnt = cnt + 1\n end\n local x1 = inv(transpose(A) * A) * transpose(A) * b\n local x = normalize([x1[0], x1[1], -1])\n local d = dot(mean_point, x)\n local dval = dot(direction, x)\n if dval < 0:\n x = -x\n dval = -dval\n end\n local eaa = [0.0, 0.0, 0.0]\n local EPSILON = 1e-10\n if norm(dval - 1) < EPSILON:\n # if the projection is close to 1 then the angle between the vectors are almost 0 and we cannot\n # reliably determine the perpendicular axis.\n # A good approximation is therefore just to set the EAA equal to 0.\n eaa = [0.0, 0.0, 0.0]\n else:\n local axis = cross(direction, x)\n local eaa = normalize(axis) * acos(dval)\n end\n local t_base_target_aligned = pose_trans(t_base_target, p[0, 0, 0, eaa[0], eaa[1], eaa[2]])\n movel(t_base_target_aligned, a = 0.2, v = velocity_move)\nend\n# End of Align to Plane\n# Start of Align Z to Nearest Axis\n###\n# Aligns the TCP Z axis to the nearest axis of the given frame\n# @param frame_id string frame_id to lookup frame\n###\ndef ur_align_z_to_nearest_axis(frame_id = \"world\"):\n ###\n # Given a reference frame as input this function returns a struct with the nearest\n # pose which aligns the z-axis of the robot TCP with the z-axis of the given reference frame.\n # The pose is in the reference of the given frame.\n # @param frame bool frame\n # @returns struct pose, distance, referencePose\n ###\n def get_aligned_z_pose(frame):\n local actualPose = get_actual_tcp_pose()\n local actualPoseInFrame = pose_trans(pose_inv(frame), actualPose)\n # Create rotation vector and convert that to RPY representation\n local actualRotInFrame = [actualPoseInFrame[3], actualPoseInFrame[4], actualPoseInFrame[5]]\n local actRPY = rotvec2rpy(actualRotInFrame)\n # Set RX and RY to 0 and convert back to rotation vector\n local alignedRot = rpy2rotvec([0, 0, actRPY[2]])\n local alignedRotFlipped = rpy2rotvec([PI, 0, actRPY[2]])\n local zUpPose = actualPoseInFrame\n zUpPose[3] = alignedRot[0]\n zUpPose[4] = alignedRot[1]\n zUpPose[5] = alignedRot[2]\n zUpStruct = struct(pose = zUpPose, distance=pose_dist(actualPoseInFrame, zUpPose), referencePose=frame)\n local zDownPose = actualPoseInFrame\n zDownPose[3] = alignedRotFlipped[0]\n zDownPose[4] = alignedRotFlipped[1]\n zDownPose[5] = alignedRotFlipped[2]\n local zDownStruct = struct(pose = zDownPose, distance=pose_dist(actualPoseInFrame, zDownPose), referencePose=frame)\n # Return the solution which is closer to the current robot pose\n if (zDownStruct.distance > zUpStruct.distance):\n return zUpStruct\n else:\n return zDownStruct\n end\n end\n local frame = get_pose(frame_id)\n # Rotate the given frame so that Z can be align to X-Y-Z respectively \n local rotZtoX = rpy2rotvec([0,0.5*PI,0])\n local rotZtoY = rpy2rotvec([0.5*PI,0,0])\n local rotZtoZ = rpy2rotvec([0,0,0])\n # Get aligned poses for each of the rotated frames\n local structAlignedToX = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoX[0],rotZtoX[1],rotZtoX[2]]))\n structAlignedToY = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoY[0],rotZtoY[1],rotZtoY[2]]))\n structAlignedToZ = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoZ[0],rotZtoZ[1],rotZtoZ[2]]))\n # Find the nearest alignement\n local structAligned = structAlignedToZ\n if(structAligned.distance > structAlignedToX.distance):\n structAligned = structAlignedToX \n end\n if(structAligned.distance > structAlignedToY.distance):\n structAligned = structAlignedToY \n end\n # Move the robot to the aligned pose\n movel(pose_trans(get_actual_tcp_pose(), p[0,0,0.00001,0,0,0]), v = 0.1)\n movel(pose_trans(structAligned.referencePose, structAligned.pose ), v = 0.1)\nend\n# End of Align Z to Nearest Axis\n# Start of Center to Object\n###\n# Centers to an object by touching the externals of it. It works well for fixtured or heavy parts.\n# @param push_force number Force the robot uses to determine if a contact has been achieved\n# @param velocity_move number Velocity in freespace\n# @param velocity_search number First move is used then search\n# @param acc_move number Acceleration in freespace\n# @param max_radius_search number Maximum search radius\n# @param num_fingers number Number of fingers that the gripper has\n###\ndef ur_center_to_object(push_force = 10, velocity_move = 0.10, velocity_search = 0.01, acc_move = 0.2, max_radius_search = 0.05, num_fingers = 3):\n def compute_circle_center(p_list):\n # Compute the circle center by circular regression\n # Source: https://math.stackexchange.com/questions/2898295/how-to-quickly-fit-a-circle-by-given-random-arc-points\n local itr = 0\n local x = 0\n local y = 1\n \n local m1 = [[0,0,0],[0,0,0],[0,0,0]]\n local m2 = [[0,0],[0,0],[0,0]]\n local m3 = [[0],[0],[0]]\n \n while(itr < get_list_length(p_list)):\n local p = p_list[itr]\n \n if(p_list[itr] == p[0,0,0,0,0,0]):\n break\n end\n \n m1[0,0] = m1[0,0] + (p[x]*p[x])\n m1[0,1] = m1[0,1] + (p[x]*p[y])\n m1[0,2] = m1[0,2] + (p[x])\n \n m1[1,0] = m1[1,0] + (p[x]*p[y])\n m1[1,1] = m1[1,1] + (p[y]*p[y])\n m1[1,2] = m1[1,2] + (p[y])\n \n m1[2,0] = m1[2,0] + (p[x])\n m1[2,1] = m1[2,1] + (p[y])\n \n m2[0,0] = m2[0,0] + (pow(p[x], 3))\n m2[0,1] = m2[0,1] + (p[x] * pow(p[y], 2))\n \n m2[1,0] = m2[1,0] + (pow(p[y], 3))\n m2[1,1] = m2[1,1] + (pow(p[x], 2) * p[y])\n \n m2[2,0] = m2[2,0] + (pow(p[x], 2))\n m2[2,1] = m2[2,1] + (pow(p[y], 2))\n \n itr = itr +1\n end\n \n if(itr < 2):\n return p[0,0,0,0,0,0]\n elif(itr > get_list_length(p_list)):\n return p[0,0,0,0,0,0]\n end\n \n m1[0,0] = 2 * m1[0,0]\n m1[0,1] = 2 * m1[0,1]\n m1[1,0] = 2 * m1[1,0]\n m1[1,1] = 2 * m1[1,1]\n m1[2,0] = 2 * m1[2,0]\n m1[2,1] = 2 * m1[2,1]\n m1[2,2] = itr\n m3[0,0] = m2[0,0] + m2[0,1]\n m3[1,0] = m2[1,0] + m2[1,1]\n m3[2,0] = m2[2,0] + m2[2,1]\n \n local center = inv(m1) * m3\n \n return p[center[0,0], center[1,0],0,0,0,0]\n end\n \n def sanity_checked_move(p_org, p_new, max_diff, acc, vel):\n if (pose_dist(p_org, p_new) > max_diff):\n movel(p_org, a = acc, v = vel)\n popup(\"New pose is too far away from original. Returning to original\", title = \"Failed\", warning = False, error = True, blocking = True)\n else:\n movel(p_new, a = acc, v = vel)\n end\n end\n # Start by zeroing the FT sensor\n sleep(0.25)\n zero_ftsensor()\n local p_start = get_actual_tcp_pose()\n local p0 = p[0,0,0,0,0,0]\n local DIR_X = [1, 0, 0]\n if (num_fingers == 2):\n local dir_list = [DIR_X, -DIR_X, DIR_X, -DIR_X]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0]\n elif (num_fingers == 3):\n local DIR_P1 = DIR_X\n local DIR_P2 = [-1 / 2, sqrt(3.0) / 2.0, 0]\n local DIR_P3 = [-1 / 2, -sqrt(3.0) / 2.0, 0]\n local dir_list = [DIR_P1, DIR_P2, DIR_P3, DIR_P1, DIR_P2, DIR_P3]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0, p0, p0]\n else:\n popup(\"Number of fingers not supported\")\n halt\n end\n # Loop through directions\n local it = 0\n local dir_list_size = size(dir_list)\n local dir_list_length = dir_list_size[0]\n while(it < dir_list_length):\n # Move to starting position if more than 3 positions is stored then calculate a new starting position\n if(it < 3):\n movel(pose_trans(p_start, start_offset[it]), a = acc_move, v = velocity_move)\n else:\n local p_start_temp = pose_trans(pose_trans(p_start, compute_circle_center(p_list)), start_offset[it])\n local p_start_w_offset = pose_trans(p_start, start_offset[it])\n sanity_checked_move(p_start_w_offset, p_start_temp, max_radius_search, acc_move, velocity_move)\n end\n local p_start_temp = get_actual_tcp_pose()\n # Move into contact and store contact point\n sleep(0.1)\n local contact_point = ur_move_until_force(distance = max_radius_search, direction = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]], velocity = velocity_search, acceleration = acc_move, stop_force = push_force)\n \n local dir = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]]\n dir = normalize(dir) * 0.05\n contact_point = pose_trans(contact_point, p[dir[0], dir[1], dir[2], 0, 0, 0])\n p_list[it] = pose_trans(pose_inv(p_start), contact_point)\n # Move out of contact\n movel(p_start_temp, a = acc_move, v = velocity_move)\n it = it + 1\n end\n # Find circle center based on n stored points\n local center_offset_xy = compute_circle_center(p_list)\n local p_center = pose_trans(p_start, center_offset_xy)\n \n # Move the robot to the center if it can\n sanity_checked_move(p_start, p_center, max_radius_search, acc_move, velocity_move)\nend\n# End of Center to Object\n# Start of Move Into Contact\n###\n# Moves the robot into contact in the TCP direction set\n# @param force number Force that determines when a contact has been achieved\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_search number velocity_search\n# @param retract number Retract distance after a contact has been found\n# @param move_tcp_dir array TCP direction (3D vector)\n# @param zero_ft_on_start bool Determines if the force-torque sensor should be zeroed on start\n###\ndef ur_move_into_contact(force = 10, velocity = 0.05, acceleration = 0.1, max_distance = 0.25, retract = 0.0, move_tcp_dir = [0, 0, 1], zero_ft_on_start = True):\n # Zero the force torque sensor\n if (zero_ft_on_start):\n sleep(0.25)\n zero_ftsensor()\n end\n # Move the robot\n ur_move_until_force(max_distance, move_tcp_dir, velocity, acceleration, force)\n # If a retract distance is set, move the robot back to that position\n if (retract != 0):\n # Compute position offset from TCP direction and retract distance\n local position = normalize(move_tcp_dir) * retract\n movel(pose_trans(get_actual_tcp_pose(), p[position[0], position[1], position[2], 0, 0, 0]))\n end\nend\n# End of Move Into Contact\n# Start of Retract\n###\n# Retract in the TCP direction set\n# @param distance number Retraction distance\n# @param direction array TCP direction to move in (3D vector)\n# @param acceleration number Acceleration used by the robot\n# @param velocity number Velocity used by the robot\n###\ndef ur_retract(distance = -0.1, direction = [0, 0, 1], acceleration = 0.4, velocity = 0.1):\n local movement = normalize(direction) * distance\n movel(pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0]), a = acceleration, v = velocity)\nend\n# End of Retract","nodeIDList":[]}} \ No newline at end of file +{"jsonContent":{"applicationContributions":{"universal-robots-external-control-external-control-application":{"type":"universal-robots-external-control-external-control-application","version":"1.0.0","port":50002,"robotIP":"192.168.56.1"},"ur-mounting":{"type":"ur-mounting","version":"0.0.1","mounting":{"baseAngle":{"value":0,"unit":"deg"},"tiltAngle":{"value":0,"unit":"deg"}}},"ur-frames":{"type":"ur-frames","version":"0.0.7","framesList":[{"name":"base","nameVariable":{"name":"base","reference":false,"type":"$$Variable","valueType":"frame","id":"6252a467-7b48-0790-36af-5a9122953653","_IDENTIFIER":"VariableDeclaration"},"parent":"world","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"tcp","nameVariable":{"name":"tcp","reference":false,"type":"$$Variable","valueType":"frame","id":"902de4ca-4cc6-24d1-d208-a7d64dca1939","_IDENTIFIER":"VariableDeclaration"},"parent":"flange","pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"world","nameVariable":{"name":"world","reference":false,"type":"$$Variable","valueType":"frame","id":"1abb892b-4453-7a0b-b117-ab746b820185","_IDENTIFIER":"VariableDeclaration"},"pose":{"position":[0,0,0],"orientation":[0,0,0]}},{"name":"flange","nameVariable":{"name":"flange","reference":false,"type":"$$Variable","valueType":"frame","id":"f05af2d5-8459-68af-fae9-b1468f81a987","_IDENTIFIER":"VariableDeclaration"},"parent":"base","pose":{"position":[0,0,0],"orientation":[0,0,0]}}]},"ur-grid-pattern":{"type":"ur-grid-pattern","version":"0.0.3","grids":[{"grid":{"name":"grid","reference":false,"type":"$$Variable","valueType":"grid","id":"bb906c62-298c-7c7e-f5f7-8820f778f926","_IDENTIFIER":"VariableDeclaration"},"waypoint":{"name":"grid_iterator","reference":false,"type":"$$Variable","valueType":"waypoint","id":"6be80bf7-b0e6-2d12-c3e3-fb3503fde43e","_IDENTIFIER":"VariableDeclaration"},"corners":[null,null,null,null],"numRows":4,"numColumns":5}]},"ur-end-effector":{"type":"ur-end-effector","version":"0.0.2","endEffectors":[{"id":"3035d318-72cd-77ab-9edf-b665bb775514","name":"Robot","payload":{"weight":{"value":0,"unit":"kg"}},"cog":{"cx":{"value":0,"unit":"m"},"cy":{"value":0,"unit":"m"},"cz":{"value":0,"unit":"m"}},"inertia":{"Ixx":{"value":0,"unit":"kg*m^2"},"Iyy":{"value":0,"unit":"kg*m^2"},"Izz":{"value":0,"unit":"kg*m^2"},"Ixy":{"value":0,"unit":"kg*m^2"},"Ixz":{"value":0,"unit":"kg*m^2"},"Iyz":{"value":0,"unit":"kg*m^2"}},"useCustomInertia":false,"tcps":[{"id":"d645c72d-cb4c-148c-b939-c91def1d47c7","name":"Tool_flange","x":{"value":0,"unit":"m"},"y":{"value":0,"unit":"m"},"z":{"value":0,"unit":"m"},"rx":{"value":0,"unit":"rad"},"ry":{"value":0,"unit":"rad"},"rz":{"value":0,"unit":"rad"}}]}],"defaultTcp":{"endEffectorId":"3035d318-72cd-77ab-9edf-b665bb775514","tcpId":"d645c72d-cb4c-148c-b939-c91def1d47c7"}},"ur-motion-profiles":{"type":"ur-motion-profiles","version":"0.0.1","moveProfiles":{"joint":[{"isDefault":false,"profile":{"name":"Joint_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"0142e66e-ed0c-594b-9607-10ea1d224f74","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Joint_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"6469ab80-19ff-2edf-d4f1-696f6f1643f0","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":1.0471975511965976,"unit":"rad/s"},"selectedType":"VALUE","value":1.0471975511965976},"acceleration":{"entity":{"value":1.3962634015954636,"unit":"rad/s^2"},"selectedType":"VALUE","value":1.3962634015954636},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"linear":[{"isDefault":false,"profile":{"name":"Linear_fast","reference":false,"type":"$$Variable","valueType":"profile","id":"092041a5-d60a-b98e-8975-7b4b8c432127","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":50,"unit":"%"},"selectedType":"VALUE","value":50},"optiMoveAcceleration":{"entity":{"value":25,"unit":"%"},"selectedType":"VALUE","value":25}}},{"isDefault":true,"profile":{"name":"Linear_slow","reference":false,"type":"$$Variable","valueType":"profile","id":"125202dc-7124-f4dc-70e1-6025e87d825d","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"OptiMove","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2},"optiMoveSpeed":{"entity":{"value":20,"unit":"%"},"selectedType":"VALUE","value":20},"optiMoveAcceleration":{"entity":{"value":4,"unit":"%"},"selectedType":"VALUE","value":4}}}],"process":[{"isDefault":true,"profile":{"name":"Process","reference":false,"type":"$$Variable","valueType":"profile","id":"31c939a7-423a-f3b0-1f74-5387636ccc77","_IDENTIFIER":"VariableDeclaration"},"parameters":{"speedType":"Classic","speed":{"entity":{"value":0.25,"unit":"m/s"},"selectedType":"VALUE","value":0.25},"acceleration":{"entity":{"value":1.2,"unit":"m/s^2"},"selectedType":"VALUE","value":1.2}}}]}},"ur-smart-skills":{"type":"ur-smart-skills","version":"0.0.3","preamble":"# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper"},"ur-application-variables":{"type":"ur-application-variables","version":"0.0.1","variables":{}}},"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{}},"sourcesNodes":{"robot":{"groupId":"robot","version":"1.0.0.","sources":[{"sourceID":"ur-wired-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 2","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 3","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 4","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 5","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 6","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CI 7","direction":"IN","valueType":"BOOLEAN"},{"signalID":"CO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 2","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 3","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 4","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 5","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 6","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"CO 7","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"},{"signalID":"AO 0","direction":"OUT","valueType":"FLOAT"},{"signalID":"AO 1","direction":"OUT","valueType":"FLOAT"}],"webSocketURL":"/sources/wired-io"},{"sourceID":"ur-tool-io","signals":[{"signalID":"DI 0","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DI 1","direction":"IN","valueType":"BOOLEAN"},{"signalID":"DO 0","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"DO 1","direction":"OUT","valueType":"BOOLEAN"},{"signalID":"AI 0","direction":"IN","valueType":"FLOAT"},{"signalID":"AI 1","direction":"IN","valueType":"FLOAT"}],"webSocketURL":"/sources/tool-io"}],"isDynamic":false},"ur-modbus":{"groupId":"ur-modbus","isDynamic":true,"version":"1.0.0","sources":[]},"ur-robot-io":{"type":"ur-robot-io","groupId":"ur-robot-io","isDynamic":false,"version":"1.0.2","sources":[{"sourceID":"ur-robot-wired-io","name":"Wired I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 2","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 3","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 4","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 5","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 6","valueType":"BOOLEAN"},{"direction":"IN","signalID":"CI 7","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 1","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 2","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 3","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 4","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 5","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 6","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"CO 7","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 0","valueType":"FLOAT"},{"direction":"OUT","signalID":"AO 1","valueType":"FLOAT"}]},{"sourceID":"ur-robot-tool-io","name":"Tool I/O","signals":[{"direction":"IN","signalID":"DI 0","valueType":"BOOLEAN"},{"direction":"IN","signalID":"DI 1","valueType":"BOOLEAN"},{"direction":"IN","signalID":"AI 0","valueType":"FLOAT"},{"direction":"IN","signalID":"AI 1","valueType":"FLOAT"},{"direction":"OUT","signalID":"DO 0","valueType":"BOOLEAN"},{"direction":"OUT","signalID":"DO 1","valueType":"BOOLEAN"}]}],"parameters":{"sourceConfig":{"labelMap":{},"analogDomainMap":{},"presets":{},"toolOutput":{"dualPinPower":false,"voltage":{"value":0,"unit":"V"},"powerOutput":{"DO 0":1,"DO 1":1}}},"migrateSourceConfigDone":true}}},"safety":{"settings":{"io":{"automaticModeSafeguardResetInput":{"name":"automaticModeSafeguardResetInput","valueA":255,"valueB":255},"automaticModeSafeguardStopInput":{"name":"automaticModeSafeguardStopInput","valueA":255,"valueB":255},"emergencyStopInput":{"name":"emergencyStopInput","valueA":255,"valueB":255},"notReducedModeOutput":{"name":"notReducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"operationalModeInput":{"name":"operationalModeInput","valueA":255,"valueB":255},"reducedModeInput":{"name":"reducedModeInput","valueA":255,"valueB":255},"reducedModeOutput":{"name":"reducedModeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotMovingOutput":{"name":"robotMovingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"robotNotStoppingOutput":{"name":"robotNotStoppingOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeHomeOutput":{"name":"safeHomeOutput","ossdEnabled":false,"valueA":255,"valueB":255},"safeguardResetInput":{"name":"safeguardResetInput","valueA":0,"valueB":1},"systemEmergencyStoppedOutput":{"name":"systemEmergencyStoppedOutput","ossdEnabled":false,"valueA":255,"valueB":255},"threePositionSwitchInput":{"name":"threePositionSwitchInput","valueA":255,"valueB":255},"freedriveEnabledInput":{"name":"freedriveEnabledInput","valueA":255,"valueB":255},"threePositionEnablingStopOutput":{"name":"threePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255},"notThreePositionEnablingStopOutput":{"name":"notThreePositionEnablingStopOutput","ossdEnabled":false,"valueA":255,"valueB":255}},"major":5,"minor":14,"normalJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"normalJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"normalRobotLimits":{"elbowForce":150,"elbowSpeed":1.5,"momentum":25,"power":300,"stoppingDistance":0.5,"stoppingTime":0.4,"toolForce":150,"toolSpeed":1.5},"reducedJointPositions":{"base":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"elbow":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"shoulder":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist1":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist2":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false},"wrist3":{"maximum":6.33555,"maximumJointPosition":0.05235988,"maximumRevolutionCounter":1,"minimum":-6.33555,"minimumJointPosition":6.2308254,"minimumRevolutionCounter":-2,"unlimited":false}},"reducedJointSpeeds":{"base":3.3415926,"shoulder":3.3415926,"elbow":3.3415926,"wrist1":3.3415926,"wrist2":3.3415926,"wrist3":3.3415926},"reducedRobotLimits":{"elbowForce":120,"elbowSpeed":0.75,"momentum":10,"power":200,"stoppingDistance":0.3,"stoppingTime":0.3,"toolForce":120,"toolSpeed":0.75},"safetyHardware":{"injectionMoldingMachineInterface":"NONE","teachPendant":"NORMAL"},"safetyPlanes":{"planes":[{"id":"fa9294a4-967c-0579-2598-bbad56efc589","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"215f99a1-821b-78ec-6ca8-ebf9af0305f9","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"54b27eb2-3f22-d0d6-4392-1bca84eaba07","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"c56f70d3-b7d5-5e11-efc2-cd03174894ef","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"24b0b581-f988-5112-2298-db6ec78b8697","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"0f8b6df0-cb79-53b4-b4e7-87e506d0b74a","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"31eeb60c-4d58-13be-cfc4-514e8c663223","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"},{"id":"f80f48d0-f136-fe07-0df6-2155d1bd261c","name":"UNDEFINED","safetyPlane":{"normalModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModePlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"reducedModeTriggerPlane":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true},"tilt":0,"offset":0,"rotation":0,"restriction":"disabled"}],"ioSafetyPlanes":[{"id":"eabab9c5-2d28-c06f-3d80-2acac453bb2c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"fbe1a183-0d6d-5ffb-db55-0702ac3586d4","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"bebca814-b309-296e-3b85-f11afbbd7a34","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"f5585223-652e-a47b-ee33-1ea2fbc16f6c","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"f21f0288-3694-1561-5529-15653ad65d6d","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"354479b5-9e7e-e940-1485-97c1ccf4c80b","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"5491a1c6-1740-6878-0fd5-45e1fdb3ed9a","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"},{"id":"85ceb891-c975-13c5-ca8f-5b2d051225d0","name":"UNDEFINED","ioSafetyPlane":{"triggerOutput":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"triggerSafeguard":{"distance":0,"vector":{"x":0,"y":0,"z":0}},"restrictsElbow":false,"restrictsToolFlange":true,"inputConfiguration":{"name":"UNDEFINED","valueA":255,"valueB":255},"outputConfiguration":{"name":"UNDEFINED","ossdEnabled":false,"valueA":255,"valueB":255}},"tilt":0,"offset":0,"rotation":0,"trigger":"disabled"}]},"safetySafeHome":{"base":-1,"elbow":-1,"shoulder":-1,"wrist1":-1,"wrist2":-1,"wrist3":-1,"enabled":false},"safetyAPIParameters":{"numberOfClients":0,"clients":[]},"safetyFieldbusses":{"enablePROFIsafe":false,"sourceAddressPROFIsafe":0,"destAddressPROFIsafe":0,"modeControlPROFIsafe":false},"threePosition":{"allowManualHighSpeed":true,"useTeachPendantAs3PE":false},"toolDirection":{"limitDeviation":6.2831855,"limitDirection":{"x":0,"y":0,"z":1},"limitRestriction":"DISABLED","tcp":{"id":"toolFlangeTcpId","name":"Tool_flange"},"toolPan":0,"toolTilt":0,"limitTilt":0,"limitRotation":0},"toolPositions":{"toolPositions":[{"name":"Tool Flange","center":{"x":0,"y":0,"z":0},"radius":0,"definition":2},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0},{"name":"UNDEFINED","center":{"x":0,"y":0,"z":0},"radius":0,"definition":0}]},"normalWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"},"reducedWristClamp":{"enableWristClampPosition":"LIMIT_ENABLED","enableWristClampTorque":"LIMIT_ENABLED"}},"crc":"2850523693","confirmed":true},"operatorScreens":[{"type":"ur-operator-screen-default","version":"0.0.2","parameters":{"status":[],"configuration":[]}}],"sidebarItems":[{"type":"ur-global-variables","version":"1.0.0","disabled":{"master":false,"automaticMode":false,"remoteMode":true}},{"type":"ur-log-messages-sidebar","version":"0.0.1","disabled":{"master":false,"automaticMode":false,"remoteMode":true}}],"activeOperatorScreen":"ur-operator-screen-default","smartSkills":[{"name":"Align to Plane","enabled":true,"type":"ur-align-to-plane","parameters":{"radius":0.05,"push_force":20,"n_plane_points":3,"max_distance":0.25,"velocity_slow":0.001,"velocity_search":0.035,"velocity_move":0.1,"acceleration":0.1}},{"name":"Align Z to Nearest Axis","enabled":true,"type":"ur-align-z-to-nearest-axis"},{"name":"Center","enabled":true,"type":"ur-center","parameters":{"push_force":10,"velocity_move":0.05,"acc_move":0.2,"max_radius_search":0.05,"num_fingers":3}},{"name":"Freedrive","enabled":true,"type":"ur-freedrive","version":"1.0.0","recordingFrequency":50,"recordingSignals":["timestamp","target_q","actual_TCP_pose","tcp_offset"]},{"name":"Move into Contact","enabled":true,"type":"ur-move-into-contact","parameters":{"force":10,"velocity":0.05,"acceleration":0.2,"max_distance":0.25,"retract":0}},{"name":"Retract","enabled":true,"type":"ur-retract","parameters":{"distance":-0.1,"acceleration":0.4,"velocity":0.1}},{"name":"Put into Box","enabled":false,"type":"ur-put-in-box","version":"1.0.0"},{"name":"Custom","enabled":false,"type":"ur-custom-smart-skill","parameters":{"includePreamble":true,"includeModules":false},"version":"1.0.0"},{"name":"Home","enabled":true,"type":"ur-position","version":"1.1.2","parameters":{"actualWaypoint":{"frame":"base","pose":{"position":[-1.8246917738038495E-9,-0.2329000001676105,1.0793999999522315],"orientation":[3.987257497300885E-9,2.2214414675120993,-2.221441467056474]},"qNear":{"base":0,"shoulder":-1.5707963249999999,"elbow":0,"wrist1":-1.5707963249999999,"wrist2":0,"wrist3":0}},"variable":{"name":"Home","reference":false,"type":"$$Variable","valueType":"waypoint","id":"1a7b4663-70cf-4964-6c73-a28c5664b8a2","_IDENTIFIER":"VariableDeclaration"}}}]},"script":{"script":"set_safety_mode_transition_hardness(1)\nreset_world_model()\nset_input_actions_to_default()\nset_analog_outputdomain(0,0)\nset_analog_outputdomain(1,0)\nset_standard_analog_input_domain(0,0)\nset_standard_analog_input_domain(1,0)\nset_tool_output_mode(0)\nset_tool_voltage(0)\nset_tool_digital_output_mode(0,1)\nset_tool_digital_output_mode(1,1)\nset_tool_analog_input_domain(0,0)\nset_tool_analog_input_domain(1,0)\nset_gravity([0, 0, 9.82])\nlocal existingBaseParent = get_frame_parent(\"base\")\nlocal basePose = get_pose(\"base\", existingBaseParent)\nbasePose[3] = 0\nbasePose[4] = 0\nbasePose[5] = 0\nmove_frame(\"base\", basePose, existingBaseParent)\nglobal base = \"base\"\nglobal tcp = \"tcp\"\nglobal world = \"world\"\nglobal flange = \"flange\"\nset_target_payload(0, [0, 0, 0], [0, 0, 0, 0, 0, 0])\nset_tcp(p[0, 0, 0, 0, 0, 0], \"Tool_flange\")\n# Start of Forces\n###\n# Transforms the force and torque values along the axes of the given pose\n# @param pose pose Any valid pose, defaults to base, the x, y, and z values are ignored\n# @return array 6D force torque vector with [Fx, Fy, Fz, Mx, My, Mz] aligned to pose in N and Nm respectively\n###\ndef get_tcp_wrench_in_frame(pose = p[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]):\n # we are only interested in the rotation of pose, set translations to zero\n local target_pose = pose\n target_pose[0] = 0\n target_pose[1] = 0\n target_pose[2] = 0\n # the conversion needs to happen as poses, so we need to convert back and forth a bit\n local force = get_tcp_force()\n local force_vector_as_pose = p[force[0], force[1], force[2], 0, 0, 0]\n local torque_vector_as_pose = p[force[3], force[4], force[5], 0, 0, 0]\n local transformed_force_as_pose = pose_trans(pose_inv(target_pose), force_vector_as_pose)\n local transformed_torque_as_pose = pose_trans(pose_inv(target_pose), torque_vector_as_pose)\n return [transformed_force_as_pose[0], transformed_force_as_pose[1], transformed_force_as_pose[2], transformed_torque_as_pose[0], transformed_torque_as_pose[1], transformed_torque_as_pose[2]]\nend\n###\n# See documentation for @link:get_tcp_wrench_in_frame()\n# @return forces and torques measured in TCP frame\n###\ndef get_tcp_wrench():\n return get_tcp_wrench_in_frame(get_target_tcp_pose())\nend\n###\n# Projects the measured TCP force along the axis given\n# @param axis array 3D vector\n###\ndef project_tcp_force(axis):\n local wrench = get_tcp_wrench()\n local force = [wrench[0], wrench[1], wrench[2]]\n return dot(force, axis)\nend\n# End of Forces\n# Start of Math\n# Definitions of constants\nglobal PI = acos(-1)\n###\n# Calculates the cross product between to 3D vectors\n# @param v1 array 3D vector\n# @param v2 array 3D vector\n###\ndef cross(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the cross product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n if length(v1) != 3:\n popup(str_cat(\"For computing the cross product, the two vectors must have length 3. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local cross = [0.0, 0.0, 0.0]\n local i = 0\n while i < 3:\n local j = (i + 1) % 3 # The next index in a cyclic order\n local k = (i + 2) % 3 # The next next index in a cyclic order\n cross[i] = v1[j] * v2[k] - v1[k] * v2[j]\n i = i + 1\n end\n return cross\nend\n###\n# Calculates the dot product between to n-dimensional vectors\n# @param v1 array nD vector\n# @param v2 array nD vector\n###\ndef dot(v1, v2):\n if length(v1) != length(v2):\n popup(str_cat(\"For computing the dot product, the two vectors must have the same length. Provided lengths: \", [length(v1), length(v2)]), error=True, blocking=True)\n return -1\n end\n local result = 0\n local i = 0\n while i < length(v1):\n result = result + (v1[i] * v2[i])\n i = i + 1\n end\n return result\nend\n###\n# Return the larger number of a and b\n# @param a number a\n# @param b number b\n###\ndef max(a, b):\n if a > b:\n return a\n end\n return b\nend\n###\n# Find the maximum value in a list. The list must be of non-zero length and contain numbers\n# @param list array list\n###\ndef list_max(list):\n local length = get_list_length(list)\n if length == 0:\n popup(\"Getting the maximum of an empty list is impossible in list_max().\", error = True, blocking = True)\n halt\n end\n local i = 0\n local max = list[0]\n while i < length:\n if list[i] > max:\n max = list[i]\n end\n i = i + 1\n sync_at_multiple(i, 30)\n end\n return max\nend\ndef sync_at_multiple(i, n):\n local tmp = i / n\n if tmp == floor(tmp):\n sync()\n end\nend\n# End of Math\n# Start of Move Helper\nur_move_until_force_distance = 0.1\nur_move_until_force_direction = [0, 0, 1]\nur_move_until_force_velocity = 0.1\nur_move_until_force_acceleration = 0.2\ndef ur_move_tcp_direction(distance, direction, velocity, acceleration, blend_radius):\n local current_pose = get_target_tcp_pose()\n local movement = normalize(direction) * distance\n local target_pose = pose_trans(current_pose, p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose, a = 0.2, v = velocity, r = blend_radius)\nend\nthread ur_move_until_force_thread():\n ur_move_tcp_direction(ur_move_until_force_distance, ur_move_until_force_direction, ur_move_until_force_velocity, ur_move_until_force_acceleration, 0)\n popup(\"No contact detected.\", title = \"No Contact\", warning = False, error = True, blocking = False)\n halt\nend\n###\n# Moves the robot in the TCP direction specified until a contact point is reached *or*\n# the robot reaches the maximum distance allowed specified by the distance parameter.\n# @param distance number The maximum distance the robot is allowed to travel in the direction specified\n# @param direction array 3D vector determining the move direction of the TCP\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param stop_force number Maximum search radius\n###\ndef ur_move_until_force(distance = 0.1, direction = [0, 0, 1], velocity = 0.1, acceleration = 0.2, stop_force = 20):\n ur_move_until_force_distance = distance\n ur_move_until_force_direction = direction\n ur_move_until_force_velocity = velocity\n ur_move_until_force_acceleration = acceleration\n \n thrd = run ur_move_until_force_thread()\n while - project_tcp_force(direction) < stop_force:\n sync()\n end\n kill thrd\n local actual_pose = get_actual_tcp_pose()\n stopl(1.0)\n return actual_pose\nend\ndef ur_get_joint_speeds_before_offset(previous_q, time):\n local current_q = get_joint_positions()\n local delta_q = current_q - previous_q\n return delta_q / time\nend\ndef ur_path_move(end_q, v, rampdown=False):\n # Calculate distance to target\n local start_q = get_joint_positions()\n local delta_q = end_q - start_q\n local positive_delta_q = [norm(delta_q[0]), norm(delta_q[1]), norm(delta_q[2]), norm(delta_q[3]), norm(delta_q[4]), norm(delta_q[5])]\n # Calculate time to move based on desired velocity\n local t = list_max(positive_delta_q) / v\n servoj(end_q , 0, 0, t, lookahead_time=0.1, gain=500)\n if(rampdown):\n while(norm(ur_get_joint_speeds_before_offset(start_q, t)) > 0.0001):\n t = max(t, 0.001)\n start_q = get_joint_positions()\n servoj(end_q , 0, 0, t)\n end\n end\nend\n# End of Move Helper\n# Waypoint variable for Home smart skill\nglobal Home = struct(p=p[-1.8246917738038495e-9, -0.2329000001676105, 1.0793999999522315, 3.987257497300885e-9, 2.2214414675120993, -2.221441467056474], frame=\"base\", q=[0, -1.5707963249999999, 0, -1.5707963249999999, 0, 0])\n# Start of Align to Plane\n###\n# Align to plane will touch up a plane by moving the robot into contact with the table or part in several locations to determine its orientation. Afterwards the robot will orient its tool to the plane.\n# @param radius number Radius [m] of the circle within the plane will be touched up\n# @param push_force number How hard to robot pushed against the plane\n# @param n_plane_points number Number of points that the robot uses to compute the plane\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_slow number Velocity when pressing downwards\n# @param velocity_search number Velocity used when approaching the touch up point\n# @param velocity_move number Velocity used in freespace\n# @param acceleration number Acceleration of the robot\n# @param direction array 3D vector determining the direction of the TCP for touching up the plane\n###\ndef ur_align_to_plane(radius = 0.05, push_force = 20, n_plane_points = 3, max_distance = 0.25, velocity_slow = 0.001, velocity_search = 0.035, velocity_move = 0.10, acceleration = 0.1, direction = [0, 0, 1]):\n local angle = 2 * PI / n_plane_points\n local start_pos = get_target_tcp_pose()\n local retract_distance = -0.015\n ur_move_tcp_direction(retract_distance, direction, velocity_move, acceleration, 0)\n sleep(0.25)\n zero_ftsensor()\n local cnt = 0\n local t_base_target = get_target_tcp_pose()\n local mean_point = [0.0, 0.0, 0.0]\n local A = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]\n local b = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n while cnt < n_plane_points:\n local new_pos = pose_trans(t_base_target, p[cos(angle * cnt) * radius, sin(angle * cnt) * radius, 0.0, 0.0, 0.0, 0.0])\n local blend_radius = norm(point_dist(get_actual_tcp_pose(), new_pos))/5\n movel(new_pos, a = acceleration, v = velocity_move, r = blend_radius)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_search, acceleration, push_force)\n local movement = normalize(direction * -1) * 0.0005\n local target_pose = pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0])\n movel(target_pose)\n sleep(0.2)\n ur_move_until_force(max_distance + norm(retract_distance), direction, velocity_slow, acceleration, push_force)\n sleep(0.2)\n while (not is_steady()):\n sync()\n end\n local poked_point = get_target_tcp_pose()\n poked_point = pose_trans(inv(t_base_target), poked_point)\n A[cnt, 0] = poked_point[0]\n A[cnt, 1] = poked_point[1]\n A[cnt, 2] = 1.0\n b[cnt] = poked_point[2]\n mean_point = mean_point + [poked_point[0], poked_point[1], poked_point[2]]\n movel(new_pos, a = 0.2, v = velocity_move, r = blend_radius)\n cnt = cnt + 1\n end\n mean_point = mean_point / n_plane_points\n cnt = 0\n while cnt < n_plane_points:\n local cntj = 0\n while cntj < 2:\n A[cnt, cntj] = A[cnt, cntj] - mean_point[cntj]\n cntj = cntj + 1\n end\n b[cnt] = b[cnt] - mean_point[2]\n cnt = cnt + 1\n end\n local x1 = inv(transpose(A) * A) * transpose(A) * b\n local x = normalize([x1[0], x1[1], -1])\n local d = dot(mean_point, x)\n local dval = dot(direction, x)\n if dval < 0:\n x = -x\n dval = -dval\n end\n local eaa = [0.0, 0.0, 0.0]\n local EPSILON = 1e-10\n if norm(dval - 1) < EPSILON:\n # if the projection is close to 1 then the angle between the vectors are almost 0 and we cannot\n # reliably determine the perpendicular axis.\n # A good approximation is therefore just to set the EAA equal to 0.\n eaa = [0.0, 0.0, 0.0]\n else:\n local axis = cross(direction, x)\n local eaa = normalize(axis) * acos(dval)\n end\n local t_base_target_aligned = pose_trans(t_base_target, p[0, 0, 0, eaa[0], eaa[1], eaa[2]])\n movel(t_base_target_aligned, a = 0.2, v = velocity_move)\nend\n# End of Align to Plane\n# Start of Align Z to Nearest Axis\n###\n# Aligns the TCP Z axis to the nearest axis of the given frame\n# @param frame_id string frame_id to lookup frame\n###\ndef ur_align_z_to_nearest_axis(frame_id = \"world\"):\n ###\n # Given a reference frame as input this function returns a struct with the nearest\n # pose which aligns the z-axis of the robot TCP with the z-axis of the given reference frame.\n # The pose is in the reference of the given frame.\n # @param frame bool frame\n # @returns struct pose, distance, referencePose\n ###\n def get_aligned_z_pose(frame):\n local actualPose = get_actual_tcp_pose()\n local actualPoseInFrame = pose_trans(pose_inv(frame), actualPose)\n # Create rotation vector and convert that to RPY representation\n local actualRotInFrame = [actualPoseInFrame[3], actualPoseInFrame[4], actualPoseInFrame[5]]\n local actRPY = rotvec2rpy(actualRotInFrame)\n # Set RX and RY to 0 and convert back to rotation vector\n local alignedRot = rpy2rotvec([0, 0, actRPY[2]])\n local alignedRotFlipped = rpy2rotvec([PI, 0, actRPY[2]])\n local zUpPose = actualPoseInFrame\n zUpPose[3] = alignedRot[0]\n zUpPose[4] = alignedRot[1]\n zUpPose[5] = alignedRot[2]\n zUpStruct = struct(pose = zUpPose, distance=pose_dist(actualPoseInFrame, zUpPose), referencePose=frame)\n local zDownPose = actualPoseInFrame\n zDownPose[3] = alignedRotFlipped[0]\n zDownPose[4] = alignedRotFlipped[1]\n zDownPose[5] = alignedRotFlipped[2]\n local zDownStruct = struct(pose = zDownPose, distance=pose_dist(actualPoseInFrame, zDownPose), referencePose=frame)\n # Return the solution which is closer to the current robot pose\n if (zDownStruct.distance > zUpStruct.distance):\n return zUpStruct\n else:\n return zDownStruct\n end\n end\n local frame = get_pose(frame_id)\n # Rotate the given frame so that Z can be align to X-Y-Z respectively \n local rotZtoX = rpy2rotvec([0,0.5*PI,0])\n local rotZtoY = rpy2rotvec([0.5*PI,0,0])\n local rotZtoZ = rpy2rotvec([0,0,0])\n # Get aligned poses for each of the rotated frames\n local structAlignedToX = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoX[0],rotZtoX[1],rotZtoX[2]]))\n structAlignedToY = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoY[0],rotZtoY[1],rotZtoY[2]]))\n structAlignedToZ = get_aligned_z_pose(pose_trans(frame, p[0,0,0,rotZtoZ[0],rotZtoZ[1],rotZtoZ[2]]))\n # Find the nearest alignement\n local structAligned = structAlignedToZ\n if(structAligned.distance > structAlignedToX.distance):\n structAligned = structAlignedToX \n end\n if(structAligned.distance > structAlignedToY.distance):\n structAligned = structAlignedToY \n end\n # Move the robot to the aligned pose\n movel(pose_trans(get_actual_tcp_pose(), p[0,0,0.00001,0,0,0]), v = 0.1)\n movel(pose_trans(structAligned.referencePose, structAligned.pose ), v = 0.1)\nend\n# End of Align Z to Nearest Axis\n# Start of Center to Object\n###\n# Centers to an object by touching the externals of it. It works well for fixtured or heavy parts.\n# @param push_force number Force the robot uses to determine if a contact has been achieved\n# @param velocity_move number Velocity in freespace\n# @param velocity_search number First move is used then search\n# @param acc_move number Acceleration in freespace\n# @param max_radius_search number Maximum search radius\n# @param num_fingers number Number of fingers that the gripper has\n###\ndef ur_center_to_object(push_force = 10, velocity_move = 0.10, velocity_search = 0.01, acc_move = 0.2, max_radius_search = 0.05, num_fingers = 3):\n def compute_circle_center(p_list):\n # Compute the circle center by circular regression\n # Source: https://math.stackexchange.com/questions/2898295/how-to-quickly-fit-a-circle-by-given-random-arc-points\n local itr = 0\n local x = 0\n local y = 1\n \n local m1 = [[0,0,0],[0,0,0],[0,0,0]]\n local m2 = [[0,0],[0,0],[0,0]]\n local m3 = [[0],[0],[0]]\n \n while(itr < get_list_length(p_list)):\n local p = p_list[itr]\n \n if(p_list[itr] == p[0,0,0,0,0,0]):\n break\n end\n \n m1[0,0] = m1[0,0] + (p[x]*p[x])\n m1[0,1] = m1[0,1] + (p[x]*p[y])\n m1[0,2] = m1[0,2] + (p[x])\n \n m1[1,0] = m1[1,0] + (p[x]*p[y])\n m1[1,1] = m1[1,1] + (p[y]*p[y])\n m1[1,2] = m1[1,2] + (p[y])\n \n m1[2,0] = m1[2,0] + (p[x])\n m1[2,1] = m1[2,1] + (p[y])\n \n m2[0,0] = m2[0,0] + (pow(p[x], 3))\n m2[0,1] = m2[0,1] + (p[x] * pow(p[y], 2))\n \n m2[1,0] = m2[1,0] + (pow(p[y], 3))\n m2[1,1] = m2[1,1] + (pow(p[x], 2) * p[y])\n \n m2[2,0] = m2[2,0] + (pow(p[x], 2))\n m2[2,1] = m2[2,1] + (pow(p[y], 2))\n \n itr = itr +1\n end\n \n if(itr < 2):\n return p[0,0,0,0,0,0]\n elif(itr > get_list_length(p_list)):\n return p[0,0,0,0,0,0]\n end\n \n m1[0,0] = 2 * m1[0,0]\n m1[0,1] = 2 * m1[0,1]\n m1[1,0] = 2 * m1[1,0]\n m1[1,1] = 2 * m1[1,1]\n m1[2,0] = 2 * m1[2,0]\n m1[2,1] = 2 * m1[2,1]\n m1[2,2] = itr\n m3[0,0] = m2[0,0] + m2[0,1]\n m3[1,0] = m2[1,0] + m2[1,1]\n m3[2,0] = m2[2,0] + m2[2,1]\n \n local center = inv(m1) * m3\n \n return p[center[0,0], center[1,0],0,0,0,0]\n end\n \n def sanity_checked_move(p_org, p_new, max_diff, acc, vel):\n if (pose_dist(p_org, p_new) > max_diff):\n movel(p_org, a = acc, v = vel)\n popup(\"New pose is too far away from original. Returning to original\", title = \"Failed\", warning = False, error = True, blocking = True)\n else:\n movel(p_new, a = acc, v = vel)\n end\n end\n # Start by zeroing the FT sensor\n sleep(0.25)\n zero_ftsensor()\n local p_start = get_actual_tcp_pose()\n local p0 = p[0,0,0,0,0,0]\n local DIR_X = [1, 0, 0]\n if (num_fingers == 2):\n local dir_list = [DIR_X, -DIR_X, DIR_X, -DIR_X]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0]\n elif (num_fingers == 3):\n local DIR_P1 = DIR_X\n local DIR_P2 = [-1 / 2, sqrt(3.0) / 2.0, 0]\n local DIR_P3 = [-1 / 2, -sqrt(3.0) / 2.0, 0]\n local dir_list = [DIR_P1, DIR_P2, DIR_P3, DIR_P1, DIR_P2, DIR_P3]\n local start_offset = [p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35], p[0,0,0,0,0,0.35]]\n local p_list = [p0, p0, p0, p0, p0, p0]\n else:\n popup(\"Number of fingers not supported\")\n halt\n end\n # Loop through directions\n local it = 0\n local dir_list_size = size(dir_list)\n local dir_list_length = dir_list_size[0]\n while(it < dir_list_length):\n # Move to starting position if more than 3 positions is stored then calculate a new starting position\n if(it < 3):\n movel(pose_trans(p_start, start_offset[it]), a = acc_move, v = velocity_move)\n else:\n local p_start_temp = pose_trans(pose_trans(p_start, compute_circle_center(p_list)), start_offset[it])\n local p_start_w_offset = pose_trans(p_start, start_offset[it])\n sanity_checked_move(p_start_w_offset, p_start_temp, max_radius_search, acc_move, velocity_move)\n end\n local p_start_temp = get_actual_tcp_pose()\n # Move into contact and store contact point\n sleep(0.1)\n local contact_point = ur_move_until_force(distance = max_radius_search, direction = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]], velocity = velocity_search, acceleration = acc_move, stop_force = push_force)\n \n local dir = [dir_list[it, 0], dir_list[it, 1], dir_list[it, 2]]\n dir = normalize(dir) * 0.05\n contact_point = pose_trans(contact_point, p[dir[0], dir[1], dir[2], 0, 0, 0])\n p_list[it] = pose_trans(pose_inv(p_start), contact_point)\n # Move out of contact\n movel(p_start_temp, a = acc_move, v = velocity_move)\n it = it + 1\n end\n # Find circle center based on n stored points\n local center_offset_xy = compute_circle_center(p_list)\n local p_center = pose_trans(p_start, center_offset_xy)\n \n # Move the robot to the center if it can\n sanity_checked_move(p_start, p_center, max_radius_search, acc_move, velocity_move)\nend\n# End of Center to Object\n# Start of Move Into Contact\n###\n# Moves the robot into contact in the TCP direction set\n# @param force number Force that determines when a contact has been achieved\n# @param velocity number Velocity of the robot\n# @param acceleration number Acceleration of the robot\n# @param max_distance number Maximum distance that the robot searches\n# @param velocity_search number velocity_search\n# @param retract number Retract distance after a contact has been found\n# @param move_tcp_dir array TCP direction (3D vector)\n# @param zero_ft_on_start bool Determines if the force-torque sensor should be zeroed on start\n###\ndef ur_move_into_contact(force = 10, velocity = 0.05, acceleration = 0.1, max_distance = 0.25, retract = 0.0, move_tcp_dir = [0, 0, 1], zero_ft_on_start = True):\n # Zero the force torque sensor\n if (zero_ft_on_start):\n sleep(0.25)\n zero_ftsensor()\n end\n # Move the robot\n ur_move_until_force(max_distance, move_tcp_dir, velocity, acceleration, force)\n # If a retract distance is set, move the robot back to that position\n if (retract != 0):\n # Compute position offset from TCP direction and retract distance\n local position = normalize(move_tcp_dir) * retract\n movel(pose_trans(get_actual_tcp_pose(), p[position[0], position[1], position[2], 0, 0, 0]))\n end\nend\n# End of Move Into Contact\n# Start of Retract\n###\n# Retract in the TCP direction set\n# @param distance number Retraction distance\n# @param direction array TCP direction to move in (3D vector)\n# @param acceleration number Acceleration used by the robot\n# @param velocity number Velocity used by the robot\n###\ndef ur_retract(distance = -0.1, direction = [0, 0, 1], acceleration = 0.4, velocity = 0.1):\n local movement = normalize(direction) * distance\n movel(pose_trans(get_actual_tcp_pose(), p[movement[0], movement[1], movement[2], 0, 0, 0]), a = acceleration, v = velocity)\nend\n# End of Retract","nodeIDList":[]}} \ No newline at end of file diff --git a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck b/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck deleted file mode 100644 index bdb8261a3..000000000 --- a/tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e/xd.lck +++ /dev/null @@ -1,70 +0,0 @@ -Private property of Exodus: 7@bcc1ff5ec5af - -jetbrains.exodus.io.LockingManager.lock(LockingManager.kt:88) -jetbrains.exodus.io.LockingManager.lock(LockingManager.kt:39) -jetbrains.exodus.io.FileDataWriter.lock(FileDataWriter.kt:70) -jetbrains.exodus.log.Log.tryLock(Log.kt:804) -jetbrains.exodus.log.Log.(Log.kt:117) -jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:117) -jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:81) -jetbrains.exodus.env.Environments.newLogInstance(Environments.kt:77) -jetbrains.exodus.env.Environments$newInstance$4.invoke(Environments.kt:46) -jetbrains.exodus.env.Environments$newInstance$4.invoke(Environments.kt:46) -jetbrains.exodus.env.Environments.prepare(Environments.kt:120) -jetbrains.exodus.env.Environments.newInstance(Environments.kt:46) -jetbrains.exodus.entitystore.PersistentEntityStores.newInstance(PersistentEntityStores.java:64) -jetbrains.exodus.entitystore.PersistentEntityStores.newInstance(PersistentEntityStores.java:70) -com.ur.web.application.service.internal.PersistentEntityStoreFactory.initializeStorage(PersistentEntityStoreFactory.java:90) -com.ur.web.application.service.internal.PersistentEntityStoreFactory.instance(PersistentEntityStoreFactory.java:72) -com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.doCreate(Unknown Source) -com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.create(Unknown Source) -com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.create(Unknown Source) -io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119) -io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38) -io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35) -io.quarkus.arc.impl.LazyValue.get(LazyValue.java:32) -io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69) -io.quarkus.arc.impl.ComputingCacheContextInstances.computeIfAbsent(ComputingCacheContextInstances.java:19) -io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35) -com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.get(Unknown Source) -com.ur.web.application.service.internal.PersistentEntityStoreFactory_ProducerMethod_instance_W2ZSeFeoRxDaexCscpkxL3d2Ko8_Bean.get(Unknown Source) -com.ur.web.application.service.internal.XodusProgramDataSource_Bean.doCreate(Unknown Source) -com.ur.web.application.service.internal.XodusProgramDataSource_Bean.create(Unknown Source) -com.ur.web.application.service.internal.XodusProgramDataSource_Bean.create(Unknown Source) -io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119) -io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38) -io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35) -io.quarkus.arc.impl.LazyValue.get(LazyValue.java:32) -io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69) -io.quarkus.arc.impl.ComputingCacheContextInstances.computeIfAbsent(ComputingCacheContextInstances.java:19) -io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35) -com.ur.web.application.service.internal.XodusProgramDataSource_Bean.get(Unknown Source) -com.ur.web.application.service.internal.XodusProgramDataSource_Bean.get(Unknown Source) -com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.doCreate(Unknown Source) -com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.create(Unknown Source) -com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.create(Unknown Source) -io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119) -io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38) -io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35) -io.quarkus.arc.impl.LazyValue.get(LazyValue.java:32) -io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69) -io.quarkus.arc.impl.ComputingCacheContextInstances.computeIfAbsent(ComputingCacheContextInstances.java:19) -io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35) -com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.get(Unknown Source) -com.ur.web.application.service.internal.DualWriteProgramDataSource_Bean.get(Unknown Source) -com.ur.web.application.service.internal.PersistentEntityStoreFactory_Observer_startup_K9EA9CTXa_UuSGId5mYynBPXgFA.notify(Unknown Source) -io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:365) -io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:347) -io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:81) -io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:163) -io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:114) -io.quarkus.runner.recorded.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source) -io.quarkus.runner.recorded.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source) -io.quarkus.runner.ApplicationImpl.doStart(Unknown Source) -io.quarkus.runtime.Application.start(Application.java:101) -io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:119) -io.quarkus.runtime.Quarkus.run(Quarkus.java:80) -io.quarkus.runtime.Quarkus.run(Quarkus.java:51) -com.ur.web.robot.service.impl.internal.Activator.main(Activator.java:100) -io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:69) -io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:37) From 7afd5ac97c2bca2d8cd4c52ca5a75df56568b4f6 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 08:54:33 +0200 Subject: [PATCH 07/14] Increase timeout for screenshots --- tests/test_dashboard_client_x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index 55a330394..2969ae0cf 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -530,7 +530,7 @@ class PolyScopeScreenshotListener : public ::testing::EmptyTestEventListener (screenshot_dir / (std::string(test_info.test_suite_name()) + "." + test_info.name() + ".png")).string(); std::string cmd = "python3 ../tests/resources/polyscopex_screenshot.py" " http://" + - g_ROBOT_IP + " " + filename + " 3000 2>/dev/null || true"; + g_ROBOT_IP + " " + filename + " 5000 2>/dev/null || true"; [[maybe_unused]] int ret = std::system(cmd.c_str()); } }; From f8c89a5ba5ee895b45f5eeb435c67b752e556466 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 08:56:57 +0200 Subject: [PATCH 08/14] Attempt to robustify program interaction test --- tests/test_dashboard_client_x.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index 2969ae0cf..ed55e0262 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -156,6 +156,7 @@ TEST_F(DashboardClientTestX, unlock_protective_stop) GTEST_SKIP_("Skipping test that would require remote control to be enabled on robot"); } ASSERT_TRUE(dashboard_client_->connect()); + dashboard_client_->commandPowerOff(); dashboard_client_->commandPowerOn(); ASSERT_NO_THROW(waitForRobotMode(RobotMode::IDLE)); DashboardResponse response; @@ -209,7 +210,7 @@ TEST_F(DashboardClientTestX, program_interaction) auto resp = dashboard_client_->commandGetLoadedProgram(); return std::get(resp.data["program_name"]) == "wait_program"; }, - std::chrono::milliseconds(1000)); + std::chrono::milliseconds(5000)); } response = dashboard_client_->commandPowerOn(); ASSERT_TRUE(response.ok); From 529c838a1043e9827d33e942ec3f0c4052516fc9 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 09:57:38 +0200 Subject: [PATCH 09/14] Add tests for modified start_ursim.sh --- tests/test_start_ursim.bats | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_start_ursim.bats b/tests/test_start_ursim.bats index e4f74b05b..32a594b5e 100644 --- a/tests/test_start_ursim.bats +++ b/tests/test_start_ursim.bats @@ -484,6 +484,30 @@ setup() { [ "$program_mount" = "$target_dir" ] } +@test "citadel_db_mounted_when_specified_for_polyscopex" { + target_dir=$(mktemp -d) + run main -v 10.13.0 -c "$target_dir" -t + echo "$output" + [ $status -eq 0 ] + citadel_mount=$(echo "$output" | tail -n1 | grep -Po "\-v\ [\/\w+\.\-]+:\/citadelDB" | cut -d ':' -f1 | cut -d " " -f 2) + [ "$citadel_mount" = "$target_dir" ] +} + +@test "citadel_db_not_mounted_without_flag_for_polyscopex" { + run main -v 10.13.0 -t + echo "$output" + [ $status -eq 0 ] + [[ "$(echo "$output" | tail -n1)" != *"/citadelDB"* ]] +} + +@test "citadel_db_not_mounted_for_e_series" { + target_dir=$(mktemp -d) + run main -v 5.26.0 -c "$target_dir" -t + echo "$output" + [ $status -eq 0 ] + [[ "$(echo "$output" | tail -n1)" != *"/citadelDB"* ]] +} + @test "setting_ip_addresss" { run main -t -i 123.123.123.123 echo "$output" From 5ea859959679cfeac0f8ec4f905cc9ec9083a27c Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 10:10:50 +0200 Subject: [PATCH 10/14] Wait for robot to be powered off --- tests/test_dashboard_client_x.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index ed55e0262..642f7e5b8 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -157,6 +157,7 @@ TEST_F(DashboardClientTestX, unlock_protective_stop) } ASSERT_TRUE(dashboard_client_->connect()); dashboard_client_->commandPowerOff(); + ASSERT_NO_THROW(waitForRobotMode(RobotMode::POWER_OFF)); dashboard_client_->commandPowerOn(); ASSERT_NO_THROW(waitForRobotMode(RobotMode::IDLE)); DashboardResponse response; From 92e243fb6bf91b439b3198ab659e8b12f5252b58 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 10:33:39 +0200 Subject: [PATCH 11/14] Fix word splitting issues with start_ursim.sh --- scripts/start_ursim.sh | 57 +++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/scripts/start_ursim.sh b/scripts/start_ursim.sh index f24508555..64f1042d2 100755 --- a/scripts/start_ursim.sh +++ b/scripts/start_ursim.sh @@ -477,12 +477,6 @@ main() { PORT_FORWARDING="" fi - DOCKER_ARGS="" - - if [ "$ROBOT_SERIES" == "polyscopex" ]; then - DOCKER_ARGS="$DOCKER_ARGS --privileged" - fi - if [ -n "$PROGRAM_STORAGE_ARG" ]; then PROGRAM_STORAGE="$PROGRAM_STORAGE_ARG" fi @@ -500,26 +494,22 @@ main() { mkdir -p "${PROGRAM_STORAGE}" PROGRAM_STORAGE=$(realpath "$PROGRAM_STORAGE") - CITADEL_DB_MOUNT="" + docker_args=(docker run --rm -d + --net ursim_net --ip "$IP_ADDRESS" + --privileged + -v "${PROGRAM_STORAGE}:/ur/bin/backend/applications" + -e "ROBOT_TYPE=${ROBOT_MODEL}" + ) + if [ -n "$CITADEL_DB_STORAGE_ARG" ]; then mkdir -p "$CITADEL_DB_STORAGE_ARG" CITADEL_DB_STORAGE=$(realpath "$CITADEL_DB_STORAGE_ARG") - CITADEL_DB_MOUNT="-v ${CITADEL_DB_STORAGE}:/citadelDB" + docker_args+=(-v "${CITADEL_DB_STORAGE}:/citadelDB") fi - ROBOT_MODEL_CONTROLLER_FLAG="" - verlte "10.7.0" "$URSIM_VERSION" && verlte "$URSIM_VERSION" "10.8.0" && ROBOT_MODEL_CONTROLLER_FLAG="-e ROBOT_TYPE_CONTROLLER=${ROBOT_MODEL}" - - docker_cmd="docker run --rm -d \ - --net ursim_net --ip $IP_ADDRESS \ - -v ${PROGRAM_STORAGE}:/ur/bin/backend/applications \ - $CITADEL_DB_MOUNT \ - -e ROBOT_TYPE=${ROBOT_MODEL} \ - $ROBOT_MODEL_CONTROLLER_FLAG \ - $PORT_FORWARDING \ - $DOCKER_ARGS \ - --name $CONTAINER_NAME \ - universalrobots/ursim_${ROBOT_SERIES}:$URSIM_VERSION" + verlte "10.7.0" "$URSIM_VERSION" && verlte "$URSIM_VERSION" "10.8.0" && \ + docker_args+=(-e "ROBOT_TYPE_CONTROLLER=${ROBOT_MODEL}") + else # Create local storage for programs and URCaps mkdir -p "${URCAP_STORAGE}" @@ -554,21 +544,26 @@ main() { fi fi fi - docker_cmd="docker run --rm -d --net ursim_net --ip $IP_ADDRESS\ - -v ${URCAP_STORAGE}:/urcaps \ - -v ${PROGRAM_STORAGE}:/ursim/programs \ - -v ${POLYSCOPE_STORAGE}:/ursim/.polyscope \ - -e ROBOT_MODEL=${ROBOT_MODEL} \ - $PORT_FORWARDING \ - --name $CONTAINER_NAME \ - universalrobots/ursim_${ROBOT_SERIES}:$URSIM_VERSION" + + docker_args=(docker run --rm -d + --net ursim_net --ip "$IP_ADDRESS" + -v "${URCAP_STORAGE}:/urcaps" + -v "${PROGRAM_STORAGE}:/ursim/programs" + -v "${POLYSCOPE_STORAGE}:/ursim/.polyscope" + -e "ROBOT_MODEL=${ROBOT_MODEL}" + ) fi + # PORT_FORWARDING is a space-separated list of -p flags; word-splitting is intentional + # shellcheck disable=SC2206 + [[ -n "$PORT_FORWARDING" ]] && docker_args+=($PORT_FORWARDING) + docker_args+=(--name "$CONTAINER_NAME" "universalrobots/ursim_${ROBOT_SERIES}:$URSIM_VERSION") + if [ "$TEST_RUN" = true ]; then - echo "$docker_cmd" | tr -s ' ' + echo "${docker_args[*]}" | tr -s ' ' exit 0 fi - $docker_cmd || exit 2 + "${docker_args[@]}" || exit 2 # Stop container when interrupted TRAP_CMD=" From 48347f3a0d2607d8bcdde0a228be95bd8002cf72 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 11:38:41 +0200 Subject: [PATCH 12/14] Use fork instead of std::system to generate the screenshots --- tests/test_dashboard_client_x.cpp | 38 +++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/tests/test_dashboard_client_x.cpp b/tests/test_dashboard_client_x.cpp index 642f7e5b8..d8a8788a2 100644 --- a/tests/test_dashboard_client_x.cpp +++ b/tests/test_dashboard_client_x.cpp @@ -35,6 +35,12 @@ #include #include #include +#include +#ifndef _WIN32 +# include +# include +# include +#endif #include "gtest/gtest.h" #include "test_utils.h" #include "ur_client_library/comm/tcp_socket.h" @@ -530,10 +536,34 @@ class PolyScopeScreenshotListener : public ::testing::EmptyTestEventListener std::string filename = (screenshot_dir / (std::string(test_info.test_suite_name()) + "." + test_info.name() + ".png")).string(); - std::string cmd = "python3 ../tests/resources/polyscopex_screenshot.py" - " http://" + - g_ROBOT_IP + " " + filename + " 5000 2>/dev/null || true"; - [[maybe_unused]] int ret = std::system(cmd.c_str()); + std::string url = "http://" + g_ROBOT_IP; + std::string script = "../tests/resources/polyscopex_screenshot.py"; + std::string delay = "5000"; + +#ifndef _WIN32 + // Build argv as a proper array — no shell involved, so spaces and metacharacters + // in url, filename, or script path are passed through safely. + std::vector args = { const_cast("python3"), const_cast(script.c_str()), + const_cast(url.c_str()), const_cast(filename.c_str()), + const_cast(delay.c_str()), nullptr }; + + pid_t pid = fork(); + if (pid == 0) + { + int devnull = open("/dev/null", O_WRONLY); + if (devnull >= 0) + { + dup2(devnull, STDERR_FILENO); + close(devnull); + } + execvp("python3", args.data()); + _exit(1); + } + else if (pid > 0) + { + waitpid(pid, nullptr, 0); + } +#endif } }; From cd2f8ca68344a97ceb8555855a02b7e95ed1bf65 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 12:03:12 +0200 Subject: [PATCH 13/14] Use python3 venv for installing playwright --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12e5611c7..f1924fb21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,7 +118,11 @@ jobs: run: sudo apt-get update && sudo apt-get install -y python3-pandas python3-lxml - name: Install Playwright for PolyScope X screenshots if: ${{ steps.check_polyscopex.outputs.is_polyscopex == 'true' }} - run: pip install playwright && playwright install chromium + run: | + python3 -m venv $RUNNER_TEMP/playwright-venv + $RUNNER_TEMP/playwright-venv/bin/pip install playwright + $RUNNER_TEMP/playwright-venv/bin/playwright install chromium + echo "$RUNNER_TEMP/playwright-venv/bin" >> $GITHUB_PATH - name: Generate rtde outputs lists run: python3 tests/resources/generate_rtde_outputs.py - name: test From 1a92f651df3bb567385a4f9e6f2cdb42ed1e4266 Mon Sep 17 00:00:00 2001 From: Felix Exner Date: Thu, 20 Aug 2026 12:23:43 +0200 Subject: [PATCH 14/14] Use pip to install pywright --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1924fb21..d4ee3bcda 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,15 +114,15 @@ jobs: - name: Access PolyScope if: ${{ steps.check_polyscopex.outputs.is_polyscopex == 'true' }} run: chrome --no-sandbox --disable-settuid-sandbox --headless=new 192.168.56.101 & + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' - name: Install Python dependencies - run: sudo apt-get update && sudo apt-get install -y python3-pandas python3-lxml + run: pip install pandas lxml - name: Install Playwright for PolyScope X screenshots if: ${{ steps.check_polyscopex.outputs.is_polyscopex == 'true' }} - run: | - python3 -m venv $RUNNER_TEMP/playwright-venv - $RUNNER_TEMP/playwright-venv/bin/pip install playwright - $RUNNER_TEMP/playwright-venv/bin/playwright install chromium - echo "$RUNNER_TEMP/playwright-venv/bin" >> $GITHUB_PATH + run: pip install playwright && playwright install chromium - name: Generate rtde outputs lists run: python3 tests/resources/generate_rtde_outputs.py - name: test