diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 4edb1cd..445bd81 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -23,14 +23,14 @@ jobs: - uses: actions/checkout@v2 - name: Build and install dependencies - # Build and install all dependencies to flexiv_omni_teleop installation directory. + # Build and install all dependencies to flexiv_tdk installation directory. run: | cd ${{github.workspace}} cd thirdparty bash build_and_install_dependencies.sh ~/teleop_install - name: Build and install library - # Configure CMake, then build and install the flexiv_omni_teleop INTERFACE library to flexiv_omni_teleop installation directory. + # Configure CMake, then build and install the flexiv_tdk INTERFACE library to TDK installation directory. run: | cd ${{github.workspace}} mkdir -p build && cd build @@ -38,7 +38,7 @@ jobs: make install - name: Build examples - # Find and link to the flexiv_omni_teleop INTERFACE library, then build all examples. + # Find and link to the flexiv_tdk INTERFACE library, then build all examples. run: | cd ${{github.workspace}}/example mkdir -p build && cd build @@ -46,9 +46,39 @@ jobs: make -j$(nproc) # - name: Build tests - # # Find and link to the flexiv_omni_teleop INTERFACE library, then build all tests. + # # Find and link to the flexiv_tdk INTERFACE library, then build all tests. # run: | # cd ${{github.workspace}}/test # mkdir -p build && cd build # cmake .. -DCMAKE_INSTALL_PREFIX=~/teleop_install # make -j$(nproc) + + build-ubuntu-20: + # Use GitHub-hosted Ubuntu 20.04 runner + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + + - name: Build and install dependencies + # Build and install all dependencies to TDK installation directory. + run: | + cd ${{github.workspace}} + cd thirdparty + bash build_and_install_dependencies.sh ~/tdk_install $(nproc) + + - name: Build and install library + # Configure CMake, then build and install the flexiv_tdk INTERFACE library to TDK installation directory. + run: | + cd ${{github.workspace}} + mkdir -p build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX=~/tdk_install + make install + + - name: Build examples + # Find and link to the flexiv_tdk INTERFACE library, then build all examples. + run: | + cd ${{github.workspace}}/example + mkdir -p build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX=~/tdk_install + make -j$(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48f5061..7a359f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 3.22.1) +cmake_minimum_required(VERSION 3.16.3) # =================================================================== # PROJECT SETUP # =================================================================== -project(flexiv_omni_teleop VERSION 1.0.0) +project(flexiv_tdk VERSION 1.1.0) # Configure build type if(NOT CMAKE_BUILD_TYPE) @@ -17,7 +17,7 @@ message("Processor: ${CMAKE_SYSTEM_PROCESSOR}") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") - set(TELEOP_STATIC_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/lib/libflexiv_omni_teleop.x86_64-linux-gnu.a") + set(TELEOP_STATIC_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/lib/libflexiv_tdk.x86_64-linux-gnu.a") else() message(FATAL_ERROR "Linux with ${CMAKE_SYSTEM_PROCESSOR} processor is currently not supported.") endif() @@ -36,36 +36,6 @@ list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}) # =================================================================== # PROJECT DEPENDENCIES # =================================================================== -# Threads -set(THREADS_PREFER_PTHREAD_FLAG ON) -find_package(Threads REQUIRED) -if(Threads_FOUND) - message(STATUS "Found Threads: HAVE_PTHREAD = ${THREADS_HAVE_PTHREAD_ARG}") -endif() - -# Eigen3 -find_package(Eigen3 REQUIRED) -if(Eigen3_FOUND) - message(STATUS "Found Eigen3: ${Eigen3_DIR}") -endif() - -# Fast-CDR -find_package(fastcdr 1.0.24 REQUIRED) -if(fastcdr_FOUND) - message(STATUS "Found fastcdr: ${fastcdr_DIR}") -endif() - -# Fast-DDS (Fast-RTPS) -find_package(fastrtps 2.6.2 REQUIRED) -if(fastrtps_FOUND) - message(STATUS "Found fastrtps: ${fastrtps_DIR}") -endif() - -# Boost-filesystem -find_package(Boost 1.72.0 COMPONENTS filesystem REQUIRED) -if(Boost_FOUND) - message(STATUS "Found Boost: ${Boost_DIR}") -endif() # OpenSSL find_package(OpenSSL REQUIRED) @@ -73,6 +43,11 @@ if(OpenSSL_FOUND) message(STATUS "Found OpenSSL, version: ${OPENSSL_VERSION}, libraries: ${OPENSSL_LIBRARIES}") endif() +# flexiv_rdk +find_package(flexiv_rdk REQUIRED) +if(flexiv_rdk_FOUND) + message(STATUS "Found flexiv_rdk: ${flexiv_rdk_DIR}") +endif() # =================================================================== # CREATE LIBRARY @@ -82,7 +57,7 @@ add_library(${PROJECT_NAME} INTERFACE) # Create an alias of the library using flexiv namespace, # to imitate the install target which uses flexiv namespace. -add_library(flexiv::omni::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) +add_library(flexiv::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE $ @@ -92,11 +67,7 @@ target_include_directories(${PROJECT_NAME} INTERFACE target_link_libraries(${PROJECT_NAME} INTERFACE ${TELEOP_STATIC_LIBRARY} ${OPENSSL_LIBRARIES} - Threads::Threads - Eigen3::Eigen - fastrtps - fastcdr - Boost::filesystem + flexiv::flexiv_rdk ) # Use moderate compiler warning option diff --git a/README.md b/README.md index 326b4df..7c8c96e 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,75 @@ -# Flexiv Omni Teleop +# Flexiv TDK -![CMake Badge](https://github.com/flexivrobotics/flexiv_omni_teleop/actions/workflows/cmake.yml/badge.svg) ![Version](https://img.shields.io/badge/version-1.0-blue.svg) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +![CMake Badge](https://github.com/flexivrobotics/flexiv_tdk/actions/workflows/cmake.yml/badge.svg) ![Version](https://img.shields.io/badge/version-1.1-blue.svg) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) -The Flexiv Omni Teleop is an SDK provides C++ APIs for developing complex and customized applications involving robot-robot or device-robot teleoperation. The supported devices are listed below. +Flexiv TDK (Teleoperation Development Kit) is an SDK provides C++ APIs for developing complex and customized applications involving robot-robot or device-robot teleoperation. The supported devices are listed below. ## Supported devices -| **Supported teleop type** | **Supported local machine** | **Supported remote machine** | +| **Supported teleop type** | **Supported local devices** | **Supported remote devices** | | ------------------------- | --------------------------- | ---------------------------- | | robot-robot | Rizon4s | Rizon4s | ## Compatibility -| **Supported OS** | **Supported processor** | **Supported language** | **Required compiler kit** | -| -------------------- | ----------------------- | ---------------------- | ------------------------- | -| Linux (Ubuntu 22.04) | x86_64 | C++ | build-essential | +| **Supported OS** | **Supported processor** | **Supported language** | **Required compiler kit** | +| -------------------------- | ----------------------- | ---------------------- | ------------------------- | +| Linux (Ubuntu 20.04/22.04) | x86_64 | C++ | build-essential | -### Compile and install for Linux +### Install on Linux 1. In a new Terminal, install C++ compiler, libssl-dev, net-tools, Git, and CMake (with GUI) using the package manager: - sudo apt install build-essential libssl-dev net-tools git cmake cmake-qt-gui -y + sudo apt install build-essential libssl-dev net-tools git cmake cmake-qt-gui -y -2. Choose a directory for installing ``flexiv_omni_teleop`` library and all its dependencies. For example, a new folder named ``teleop_install`` under the home directory. +2. Choose a directory for installing ``flexiv_tdk`` library and all its dependencies. For example, a new folder named ``tdk_install`` under the home directory. 3. Please ensure that your network connection is unobstructed. Then, in a new Terminal, run the provided script to compile and install all dependencies to the installation directory chosen in step 2: - cd flexiv_omni_teleop/thirdparty - bash build_and_install_dependencies.sh ~/teleop_install + cd flexiv_tdk/thirdparty + bash build_and_install_dependencies.sh ~/tdk_install -4. In a new Terminal, use CMake to configure `flexiv_omni_teleop`: +4. In a new Terminal, use CMake to configure `flexiv_tdk`: - cd flexiv_omni_teleop - mkdir build && cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/teleop_install + cd flexiv_tdk + mkdir build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX=~/tdk_install NOTE: ``-D`` followed by ``CMAKE_INSTALL_PREFIX`` is a CMake parameter specifying the path of the chosen installation directory. Alternatively, this configuration step can also be done through CMake GUI. -5. Compile and install `flexiv_omni_teleop` library: +5. Install `flexiv_tdk` library: - cd flexiv_omni_teleop/build - cmake --build . --target install --config Release + cd flexiv_tdk/build + cmake --build . --target install --config Release - NOTE: the installation of `flexiv_omni_teleop` library is complete now. The following steps show how to link to the installed library from a user project. + NOTE: the installation of `flexiv_tdk` library is complete now. The following steps show how to link to the installed library from a user project. ### Link to the installed library to a user project -1. To find and link to the installed `flexiv_omni_teleop` library to a user project, using the provided example project for instance: +1. To find and link to the installed `flexiv_tdk` library to a user project, using the provided example project for instance: - cd flexiv_omni_teleop/example - mkdir build && cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/teleop_install - cmake --build . --config Release -j 4 + cd flexiv_tdk/example + mkdir build && cd build + cmake .. -DCMAKE_INSTALL_PREFIX=~/tdk_install + cmake --build . --config Release -j 4 - NOTE: ``-D`` followed by ``CMAKE_INSTALL_PREFIX`` tells user project's CMake where to find the installed `flexiv_omni_teleop` library. + NOTE: ``-D`` followed by ``CMAKE_INSTALL_PREFIX`` tells user project's CMake where to find the installed `flexiv_tdk` library. -### Run Omni-Teleop +### Run tdk example -1. Apply for Omni license to run Omni-Teleop. See [Omni_license.md](omni_license_generator/Omni_license.md) +1. Apply for license to run tdk. See [apply_for_license.md](./license_generator/apply_for_license.md) -2. Set all the robots to `Auto/Remote Mode` via flexiv Elements, then to run the compiled example program: +2. Set all the robots to `Auto/Remote Mode` via Flexiv Elements, then to run the compiled example program: - ./ [remote_robot_SN] [local_robot_SN] [path_to_omni_licenseCfg.json] + ./ [local_robot_serial_number] [remote_robot_serial_number] [path_to_omni_licenseCfg.json] -### API Documentation + +## API Documentation API doc can be generated using doxygen sudo apt install doxygen-latex graphviz - cd flexiv_omni_teleop - doxygen doc/Doxygen.in + cd flexiv_tdk + doxygen doc/Doxyfile.in -The generated API doc is under ```flexiv_omni_teleop/doc/html ```. You can open any of the html file with your web browser to view it. +The generated API doc is under ```flexiv_tdk/doc/html ```. You can open any of the html file with your web browser to view it. diff --git a/cmake/FlexivInstallLibrary.cmake b/cmake/FlexivInstallLibrary.cmake index f782a0a..ef3c34f 100644 --- a/cmake/FlexivInstallLibrary.cmake +++ b/cmake/FlexivInstallLibrary.cmake @@ -64,14 +64,14 @@ macro(FlexivInstallLibrary) include(CMakePackageConfigHelpers) write_basic_package_version_file( "${PROJECT_NAME}-config-version.cmake" - VERSION ${PACKAGE_VERSION} + VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) # copy the *-targets.cmake file to the CMAKE_INSTALL_PREFIX directory install(EXPORT "${PROJECT_NAME}-targets" FILE "${PROJECT_NAME}-targets.cmake" - NAMESPACE "flexiv::omni::" + NAMESPACE "flexiv::" DESTINATION "lib/cmake/${PROJECT_NAME}" ) @@ -83,13 +83,13 @@ macro(FlexivInstallLibrary) ) # Use the CPack Package Generator - set(CPACK_PACKAGE_VENDOR "flexiv") + set(CPACK_PACKAGE_VENDOR "Flexiv") set(CPACK_PACKAGE_CONTACT "support@flexiv.com") - set(CPACK_PACKAGE_DESCRIPTION "flexiv omni teleop ") + set(CPACK_PACKAGE_DESCRIPTION "Flexiv Teleop Development Kit (TDK)") set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") - set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") + set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") include(CPack) endmacro() \ No newline at end of file diff --git a/cmake/flexiv_omni_teleop-config.cmake.in b/cmake/flexiv_omni_teleop-config.cmake.in deleted file mode 100644 index db85efd..0000000 --- a/cmake/flexiv_omni_teleop-config.cmake.in +++ /dev/null @@ -1,12 +0,0 @@ -include(CMakeFindDependencyMacro) - -# Find dependency -set(THREADS_PREFER_PTHREAD_FLAG ON) -find_dependency(Threads REQUIRED) -find_dependency(Eigen3 REQUIRED) -find_dependency(fastrtps 2.6.2 REQUIRED) -find_dependency(fastcdr 1.0.24 REQUIRED) -find_dependency(Boost COMPONENTS filesystem REQUIRED) - -# Add targets file -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") diff --git a/cmake/flexiv_tdk-config.cmake.in b/cmake/flexiv_tdk-config.cmake.in new file mode 100644 index 0000000..81c49d1 --- /dev/null +++ b/cmake/flexiv_tdk-config.cmake.in @@ -0,0 +1,7 @@ +include(CMakeFindDependencyMacro) + +# Find dependency +find_dependency(flexiv_rdk REQUIRED) +find_package(OpenSSL REQUIRED) +# Add targets file +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") diff --git a/doc/Doxygen.in b/doc/Doxyfile.in similarity index 93% rename from doc/Doxygen.in rename to doc/Doxyfile.in index b9d9013..2601c8e 100644 --- a/doc/Doxygen.in +++ b/doc/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.17 +# Doxyfile 1.9.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -32,13 +32,13 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "Flexiv Omni Teleop" +PROJECT_NAME = "Flexiv TDK APIs" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "1.0" +PROJECT_NUMBER = 1.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -227,6 +227,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -263,12 +271,6 @@ TAB_SIZE = 4 ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -310,18 +312,21 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, # Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is -# Fortran), use: inc=Fortran f=C. +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = @@ -455,6 +460,19 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which efficively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -518,6 +536,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -555,11 +580,18 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# (including Cygwin) ands Mac users are advised to set this option to NO. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. # The default value is: system dependent. CASE_SENSE_NAMES = NO @@ -798,7 +830,10 @@ WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO @@ -831,15 +866,15 @@ WARN_LOGFILE = INPUT = README.md \ doc \ - include \ example \ - lib + include \ + lib \ + license_generator # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv/) for the list of -# possible encodings. +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 @@ -852,13 +887,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen -# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. +# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, +# *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -891,8 +928,6 @@ FILE_PATTERNS = *.c \ *.md \ *.mm \ *.dox \ - *.doc \ - *.txt \ *.py \ *.pyw \ *.f90 \ @@ -906,7 +941,7 @@ FILE_PATTERNS = *.c \ *.vhdl \ *.ucf \ *.qsf \ - *.ice + *.proto # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -938,6 +973,8 @@ EXCLUDE_SYMLINKS = NO # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = */build/* \ + *.pb.h \ + *.pb.cc # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -1119,16 +1156,22 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO +# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to +# YES then doxygen will add the directory of each input to the include path. +# The default value is: YES. + +CLANG_ADD_INC_PATHS = YES + # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories @@ -1138,10 +1181,13 @@ CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the -# path to the compilation database (see: -# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files -# were built. This is equivalent to specifying the "-p" option to a clang tool, -# such as clang-check. These options will then be passed to the parser. +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. @@ -1158,13 +1204,6 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored @@ -1335,10 +1374,11 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/xcode/), introduced with OSX -# 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1380,8 +1420,8 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# (see: +# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1411,7 +1451,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1456,7 +1496,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1464,8 +1505,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1473,16 +1514,16 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = @@ -1494,9 +1535,9 @@ QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1573,6 +1614,17 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1612,7 +1664,7 @@ USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1628,7 +1680,7 @@ MATHJAX_FORMAT = HTML-CSS # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest @@ -1642,7 +1694,8 @@ MATHJAX_EXTENSIONS = TeX/AMSmath # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1689,7 +1742,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1702,8 +1756,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1867,9 +1922,11 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2380,10 +2437,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2575,9 +2654,11 @@ DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc and +# plantuml temporary files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. -DOT_CLEANUP = YES +DOT_CLEANUP = YES \ No newline at end of file diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 1358c30..c1fa10d 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,9 +1,14 @@ -cmake_minimum_required(VERSION 3.22.1) +cmake_minimum_required(VERSION 3.16.3) -project(flexiv_omni_teleop_example) +project(flexiv_tdk-examples) +message("OS: ${CMAKE_SYSTEM_NAME}") +message("Processor: ${CMAKE_SYSTEM_PROCESSOR}") + +# Show verbose build info SET(CMAKE_VERBOSE_MAKEFILE ON) +# Configure build type if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "CMake build type" FORCE) endif() @@ -21,15 +26,18 @@ set(EXAMPLE_LIST basics1_cartesian_teleop ) -find_package(flexiv_omni_teleop REQUIRED) -if(flexiv_omni_teleop_FOUND) - message(STATUS "Found flexiv_omni_teleop:${flexiv_omni_teleop_DIR}") +# Find flexiv_tdk INTERFACE library +find_package(flexiv_tdk 1.1.0 REQUIRED) +if(flexiv_tdk_FOUND) + message(STATUS "Found flexiv_tdk:${flexiv_tdk_DIR}") endif() - +# Build all examples foreach(example ${EXAMPLE_LIST}) add_executable(${example} ${example}.cpp) - target_link_libraries(${example} flexiv::omni::flexiv_omni_teleop) + target_link_libraries(${example} flexiv::flexiv_tdk) + + # C++17 required set_target_properties(${example} PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) diff --git a/example/basics1_cartesian_teleop.cpp b/example/basics1_cartesian_teleop.cpp index b72dc6b..8404286 100644 --- a/example/basics1_cartesian_teleop.cpp +++ b/example/basics1_cartesian_teleop.cpp @@ -1,64 +1,71 @@ /** - * @file basics1_cartesian_teleop.cpp + * @example basics1_cartesian_teleop.cpp * @copyright Copyright (C) 2016-2024 Flexiv Ltd. All Rights Reserved. - * @brief Basic Omni-Teleop example - * @date 2024-05-10 + * @brief This is an example program for cartesian space teleoperation + * @author Flexiv */ -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace { -constexpr std::array k_preferredJntPos - = {-0.67, -0.98, 0.89, 1.55, -0.85, 0.54, 0.46}; ///< Preferred joint position -const std::array k_defaultMaxRemoteWrench - = {80.0, 80.0, 80.0, 24.0, 24.0, 24.0}; ///< Maximum contact wrench of remote robot -std::atomic g_stop_sched = {false}; ///< Atomic signal to stop scheduler tasks -} +std::vector kPreferredJntPos + = {60 * M_PI / 180.0, -60 * M_PI / 180.0, -85 * M_PI / 180.0, 115 * M_PI / 180.0, + 70 * M_PI / 180.0, 0 * M_PI / 180.0, 0 * M_PI / 180.0}; ///< Preferred joint position +const std::array kDefaultMaxContactWrench + = {200.0, 200.0, 200.0, 40.0, 40.0, 40.0}; ///< Maximum contact wrench + +std::atomic g_stop_sched = {false}; ///< Atomic signal to stop scheduler tasks +} // namespace + +/** + * @brief Helper function to print program usage help + */ void printHelp() { // clang-format off - std::cout << "Invalid program arguments"<"<"); // clang-format on } /** - * @brief Callback function for teleop task + * @brief 1000Hz callback function for main teleop task */ -void periodicTeleopTask(flexiv::omni::teleop::Robot2RobotTeleop& teleop) +void PeriodicTeleopTask(flexiv::tdk::Robot2RobotTeleop& teleop) { try { - // Monitor status of the teleop robots - if (!teleop.isOperational()) { + // Monitor fault on the teleop robots + if (!teleop.operational()) { throw std::runtime_error( - "periodicTeleopTask: Fault occurred during teleoperation, exiting ..."); + "PeriodicTeleopTask: Fault occurred during teleoperation, exiting ..."); } // Step teleop - teleop.step(); + teleop.Step(); } catch (const std::exception& e) { - std::cerr << e.what() << '\n'; + spdlog::error(e.what()); g_stop_sched = true; } } /** - * @brief Callback function for axis lock/unlock test + * @brief 1Hz callback function for several APIs call */ -void periodicConsoleTask(flexiv::omni::teleop::Robot2RobotTeleop& teleop) +void PeriodicConsoleTask(flexiv::tdk::Robot2RobotTeleop& teleop) { - flexiv::omni::teleop::AxisLockDefs cmd; - teleop.getLocalAxisLockState(cmd); + flexiv::tdk::AxisLock cmd; + teleop.GetLocalAxisLockState(cmd); while (!g_stop_sched) { @@ -66,184 +73,157 @@ void periodicConsoleTask(flexiv::omni::teleop::Robot2RobotTeleop& teleop) std::getline(std::cin, userInput); switch (userInput[0]) { - case 'm': - std::cout << ">>> Simple command line GUI for teleop robot axis lock <<<" - << std::endl; - std::cout << "- x: lock/unlock translational motion along X axis in World frame." - << std::endl; - std::cout << "- y: lock/unlock translational motion along Y axis in World frame." - << std::endl; - std::cout << "- z: lock/unlock translational motion along Z axis in World frame." - << std::endl; - - std::cout << "- q: lock/unlock rotational motion along X axis in World frame." - << std::endl; - std::cout << "- w: lock/unlock rotational motion along Y axis in World frame." - << std::endl; - std::cout << "- e: lock/unlock rotational motion along Z axis in World frame." - << std::endl; - - std::cout << "- X: lock/unlock translational motion along X axis in TCP frame." - << std::endl; - std::cout << "- Y: lock/unlock translational motion along Y axis in TCP frame." - << std::endl; - std::cout << "- Z: lock/unlock translational motion along Z axis in TCP frame." - << std::endl; - - std::cout << "- Q: lock/unlock rotational motion along X axis in TCP frame." - << std::endl; - std::cout << "- W: lock/unlock rotational motion along Y axis in TCP frame." - << std::endl; - std::cout << "- E: lock/unlock rotational motion along Z axis in TCP frame." - << std::endl; - std::cout << "please input command >> " << std::endl; - break; case 'x': - cmd.trans_axis_lock_list_[0] = !cmd.trans_axis_lock_list_[0]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_WORLD; - + cmd.lock_trans_axis[0] = !cmd.lock_trans_axis[0]; + cmd.coord = flexiv::tdk::CoordType::COORD_WORLD; break; case 'y': - cmd.trans_axis_lock_list_[1] = !cmd.trans_axis_lock_list_[1]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_WORLD; + cmd.lock_trans_axis[1] = !cmd.lock_trans_axis[1]; + cmd.coord = flexiv::tdk::CoordType::COORD_WORLD; break; case 'z': - cmd.trans_axis_lock_list_[2] = !cmd.trans_axis_lock_list_[2]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_WORLD; + cmd.lock_trans_axis[2] = !cmd.lock_trans_axis[2]; + cmd.coord = flexiv::tdk::CoordType::COORD_WORLD; break; case 'q': - cmd.ori_axis_lock_list_[0] = !cmd.ori_axis_lock_list_[0]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_WORLD; + cmd.lock_ori_axis[0] = !cmd.lock_ori_axis[0]; + cmd.coord = flexiv::tdk::CoordType::COORD_WORLD; break; case 'w': - cmd.ori_axis_lock_list_[1] = !cmd.ori_axis_lock_list_[1]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_WORLD; + cmd.lock_ori_axis[1] = !cmd.lock_ori_axis[1]; + cmd.coord = flexiv::tdk::CoordType::COORD_WORLD; break; case 'e': - cmd.ori_axis_lock_list_[2] = !cmd.ori_axis_lock_list_[2]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_WORLD; + cmd.lock_ori_axis[2] = !cmd.lock_ori_axis[2]; + cmd.coord = flexiv::tdk::CoordType::COORD_WORLD; break; case 'X': - cmd.trans_axis_lock_list_[0] = !cmd.trans_axis_lock_list_[0]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_TCP; + cmd.lock_trans_axis[0] = !cmd.lock_trans_axis[0]; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; break; case 'Y': - cmd.trans_axis_lock_list_[1] = !cmd.trans_axis_lock_list_[1]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_TCP; + cmd.lock_trans_axis[1] = !cmd.lock_trans_axis[1]; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; break; case 'Z': - cmd.trans_axis_lock_list_[2] = !cmd.trans_axis_lock_list_[2]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_TCP; + cmd.lock_trans_axis[2] = !cmd.lock_trans_axis[2]; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; break; case 'Q': - cmd.ori_axis_lock_list_[0] = !cmd.ori_axis_lock_list_[0]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_TCP; + cmd.lock_ori_axis[0] = !cmd.lock_ori_axis[0]; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; break; case 'W': - cmd.ori_axis_lock_list_[1] = !cmd.ori_axis_lock_list_[1]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_TCP; + cmd.lock_ori_axis[1] = !cmd.lock_ori_axis[1]; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; break; case 'E': - cmd.ori_axis_lock_list_[2] = !cmd.ori_axis_lock_list_[2]; - cmd.coord = flexiv::omni::teleop::CoordType::CD_TCP; + cmd.lock_ori_axis[2] = !cmd.lock_ori_axis[2]; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; + break; + case 'r': + teleop.Engage(true); + break; + case 'R': + teleop.Engage(false); + break; + case 's': + cmd.lock_ori_axis = {false, false, false}; + cmd.lock_trans_axis = {false, false, false}; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; + break; + case 'S': + cmd.lock_ori_axis = {true, true, true}; + cmd.lock_trans_axis = {true, true, true}; + cmd.coord = flexiv::tdk::CoordType::COORD_TCP; + break; + case 't': + teleop.SetRepulsiveForce({0, 0, -5}); + break; + case 'T': + teleop.SetWrenchFeedbackScalingFactor(0.5); break; - default: - std::cerr << "Invalid command, please enter \'m\' for help \n"; + spdlog::warn("Invalid command!"); break; } - teleop.setLocalAxisLockCmd(cmd); - std::cout << " Axis [X] in " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << " frame locking status : " << cmd.trans_axis_lock_list_[0] << std::endl; - std::cout << " Axis [Y] in " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << " frame locking status : " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << cmd.trans_axis_lock_list_[1] << std::endl; - std::cout << " Axis [Z] in " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << " frame locking status : " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << cmd.trans_axis_lock_list_[2] << std::endl; - std::cout << " Axis [Rx] in " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << " frame locking status : " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << cmd.ori_axis_lock_list_[0] << std::endl; - std::cout << " Axis [Ry] in " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << " frame locking status : " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << cmd.ori_axis_lock_list_[1] << std::endl; - std::cout << " Axis [Rz] in " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << " frame locking status : " << flexiv::omni::teleop::CoordTypeStr[cmd.coord] - << cmd.ori_axis_lock_list_[2] << std::endl; + teleop.SetLocalAxisLockCmd(cmd); } return; } int main(int argc, char* argv[]) { - std::string remoteSN; - std::string localSN; - std::string licCfgPath; - + // Program Setup + // ============================================================================================= if (argc != 4) { printHelp(); return 1; } - remoteSN = argv[1]; - localSN = argv[2]; - licCfgPath = argv[3]; - - std::cout << "Flexiv Omni-Teleop example" << std::endl; - std::cout << "Copyright (C) 2016-2024 Flexiv" << std::endl; - std::cout << "All Rights Reserved." << std::endl << std::endl; - - std::cout << "Remote SN: " + remoteSN << std::endl; - std::cout << "Local SN: " + localSN << std::endl; - std::cout << "License config file: " + licCfgPath << std::endl; + // Serial number of the local robot to connect to. Remove any space, for example: Rizon4s-062001 + std::string local_sn = argv[1]; + // Serial number of the remote robot to connect to. Remove any space, for example: + // Rizon4s-Rizon4s-062002 + std::string remote_sn = argv[2]; + // Path to license config json file. for example: ~/my_license/omni_licenseCfg.json + std::string path_to_lic_jsn = argv[3]; + + // Parse parameters + if (local_sn.empty() || remote_sn.empty() || path_to_lic_jsn.empty()) { + printHelp(); + return 1; + } try { - // Create Omni-Teleop - flexiv::omni::teleop::Robot2RobotTeleop teleop(localSN, remoteSN, licCfgPath); + // TDK Initialization + // ========================================================================================= + // Instantiate main teleop interface + flexiv::tdk::Robot2RobotTeleop teleop(local_sn, remote_sn, path_to_lic_jsn); - // Enable teleop robots - teleop.enable(); + // Enable cart teleop + teleop.Enable(); - // Init teleop robots - teleop.init(); + // Init cart teleop + teleop.Init(); - // Set preferred joint position to a better configuration - teleop.setLocalNullSpacePosture(k_preferredJntPos); - teleop.setRemoteNullSpacePosture(k_preferredJntPos); + // Set preferred joint position + teleop.SetLocalNullSpacePosture(kPreferredJntPos); + teleop.SetRemoteNullSpacePosture(kPreferredJntPos); - // Set max remote contact wrench - teleop.setRemoteMaxWrench(k_defaultMaxRemoteWrench); + // Set max contact wrench + teleop.SetMaxContactWrench(kDefaultMaxContactWrench); // Create real-time scheduler to step periodic tasks - flexiv::omni::teleop::Scheduler scheduler; + flexiv::rdk::Scheduler scheduler; - // Wait for elbow posture ready + // Wait for null-space posture ready std::this_thread::sleep_for(std::chrono::seconds(3)); - // Add periodic task with 1ms interval and highest applicable priority - scheduler.AddTask(std::bind(&periodicTeleopTask, std::ref(teleop)), "HP periodic teleop", 1, + // Add periodic teleop task with 1ms interval and highest applicable priority + scheduler.AddTask(std::bind(&PeriodicTeleopTask, std::ref(teleop)), "HP periodic teleop", 1, scheduler.max_priority()); - scheduler.AddTask(std::bind(&periodicConsoleTask, std::ref(teleop)), "LP Periodic console", + // Add periodic console task with 1s interval and lowest applicable priority + scheduler.AddTask(std::bind(&PeriodicConsoleTask, std::ref(teleop)), "LP Periodic console", 1000, scheduler.min_priority()); // Start all added tasks, this is by default a blocking method scheduler.Start(); - std::cout << "Flexiv Omni-Teleop started ... "; - - // Wait a bit for any last-second robot log message to arrive and get printed - std::this_thread::sleep_for(std::chrono::seconds(1)); + spdlog::info("Flexiv TDK example started ... "); - // Block until signal received + // Block and wait for signal to stop scheduler tasks while (!g_stop_sched) { - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } + // Received signal to stop scheduler tasks + scheduler.Stop(); } catch (const std::exception& e) { - std::cerr << (e.what()); + spdlog::error(e.what()); return 1; } return 0; -} \ No newline at end of file +} diff --git a/include/flexiv/omni/teleop/Robot2RobotTeleop.hpp b/include/flexiv/omni/teleop/Robot2RobotTeleop.hpp deleted file mode 100644 index 7a0b840..0000000 --- a/include/flexiv/omni/teleop/Robot2RobotTeleop.hpp +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @file Robot2RobotTeleop.hpp - * @copyright Copyright (C) 2016-2024 Flexiv Ltd. All Rights Reserved. - */ -#pragma once - -#include -#include -#include -namespace flexiv { -namespace omni { -namespace teleop { - -/** - * @brief Main interface for robot-robot teleop in Cartesian space, containing several function - * categories and background services. - */ -class Robot2RobotTeleop -{ -public: - Robot2RobotTeleop() = delete; - Robot2RobotTeleop(const Robot2RobotTeleop&) = delete; - Robot2RobotTeleop(Robot2RobotTeleop&&) = delete; - Robot2RobotTeleop& operator=(const Robot2RobotTeleop&) = delete; - /** - * @brief [Blocking] Create a flexiv::omni::teleop instance as the main Omni-Teleop interface. - * Omni-Teleop services will initialize and connection with the local and remote robot will be - * established. - * @param[in] localSN Serial number of the local robot, e.g. Rizon4s-062001. Only Rizon4s is - * supported. - * @param[in] remoteSN Serial number of the remote robot, e.g. Rizon4s-062002. Only Rizon4s is - * supported. - * @param [in] licensePath Path to the omni license config json file. See README.md to apply for - * omni license. - * @throw std::runtime_error if the initialization sequence failed. - * @throw std::logic_error if the connected robot does not have a valid license; or this - * Teleop library version is incompatible with the connected robot; or model of the connected - * robot is not supported. - * @warning This constructor blocks until the initialization sequence is successfully finished - * and connection with the robot is established. - */ - Robot2RobotTeleop( - const std::string& localSN, const std::string& remoteSN, const std::string& licensePath); - virtual ~Robot2RobotTeleop(); - - /** - * @brief [Blocking] Initialize Omni-Teleop robots states, this will zeroing force/torque sensors, - * make sure nothing is in contact with the local and remote robots. - * @throw std::logic_error if robots are not connected. - * @throw std::runtime_error if failed to execute the request. - * @note This function blocks until the request is successfully executed. - */ - void init(void); - - /** - * @brief [Blocking] Enable the Omni-Teleop, if all E-stop are released and there's no - * fault, both local and remote robots will release brakes, and becomes operational a few seconds - * later. - * @throw std::logic_error if the robot is not connected. - * @throw std::runtime_error if failed to execute the request. - * @note This function blocks until the request is successfully executed. - */ - void enable(void); - - /** - * @brief [Blocking] Stop Omni-Teleop. - * @throw std::runtime_error if failed to stop Omni-Teleop. - * @note This function blocks until Omni-Teleop comes to a complete stop. - */ - void stop(void); - - /** - * @brief [Non-blocking] Check if robots in fault state. - * @return True: Omni-Teleop has fault, false: everything normal. - */ - bool isFault(void); - - /** - * @brief [Non-blocking] Whether the local and remote robots are normally operational, which - * requires the following conditions to be met: enabled, brakes fully released, in auto-remote - * mode, no fault, and not in reduced state. - * @return True: operational, false: not operational. - * @warning The robot won't execute any command until it becomes normally operational. - */ - bool isOperational(void); - - /** - * @brief [Blocking] Clear minor fault of the local and remote robots. - * @return True: successfully cleared fault, false: cannot clear fault. - * @throw std::runtime_error if failed to deliver the request. - * @note This function blocks until fault on local and remote is successfully cleared or - * maximum number of attempts is reached. - */ - bool clearFault(void); - - /** - * @brief [Non-blocking] Periodically step Omni-Teleop and the called frequency should be 1KHz. - * The remote will always imitate the movements of the local and feedback the external wrench to - * the local. - * @note The remote pose will not exactly the same as that of the local. User can keep the remote - * still by releasing the pedal, while the local can drag freely. When the local reaches an - * appropriate pose, press down the pedal and the remote will follow the local again. - * @note Please connect the pedal to the DI0 and 24V channel of the local control box. And - * ensure that the circuit only connects when the pedal is pressed down. - * @throw std::runtime_error if failed to execute the request. - */ - void step(void); - - /** - * @brief [Non-blocking] Set preferred joint positions for the null-space posture control of local - * robot. - * @param[in] preferredPositions Preferred joint positions for the null-space posture control: - * \f$ q_{ns} \in \mathbb{R}^{n \times 1} \f$. Valid range: [TeleopRobotInfo::qMin, - * TeleopRobotInfo::qMax]. Unit: \f$ [rad] \f$. - * @throw std::invalid_argument if [preferredPositions] contains any value outside the valid - * range. - * @throw std::logic_error if Omni-Teleop was not successfully initialized. - * @note This setting will persist across the applicable control modes until changed again. - * @par Null-space posture control - * Similar to human arm, a robotic arm with redundant joint-space degree(s) of freedom (DOF > 6) - * can change its overall posture without affecting the ongoing primary task. This is achieved - * through a technique called "null-space control". After the preferred joint positions for a - * desired robot posture is set using this function, the robot's null-space control module will - * try to pull the arm as close to this posture as possible without affecting the primary - * Cartesian motion-force control task. - */ - void setLocalNullSpacePosture(const std::array& preferredPositions); - - /** - * @brief [Non-blocking] Set preferred joint positions for the null-space posture control of - * remote robot. - * @param[in] preferredPositions Preferred joint positions for the null-space posture control: - * \f$ q_{ns} \in \mathbb{R}^{n \times 1} \f$. Valid range: [TeleopRobotInfo::qMin, - * TeleopRobotInfo::qMax]. Unit: \f$ [rad] \f$. - * @throw std::invalid_argument if [preferredPositions] contains any value outside the valid - * range. - * @throw std::logic_error if Omni-Teleop was not successfully initialized. - * @note This setting will persist across the applicable control modes until changed again. - * @par Null-space posture control - * Similar to human arm, a robotic arm with redundant joint-space degree(s) of freedom (DOF > 6) - * can change its overall posture without affecting the ongoing primary task. This is achieved - * through a technique called "null-space control". After the preferred joint positions for a - * desired robot posture is set using this function, the robot's null-space control module will - * try to pull the arm as close to this posture as possible without affecting the primary - * Cartesian motion-force control task. - */ - void setRemoteNullSpacePosture(const std::array& preferredPositions); - - /** - * @brief [Non-blocking] Set maximum wrench for the remote robot. The controller will regulate its - * output to maintain contact wrench (force and moment) with the environment under the set values. - * @param[in] max_wrench Maximum contact wrench (force and moment): \f$ F_max \in \mathbb{R}^{6 - * \times 1} \f$. Consists of \f$ \mathbb{R}^{3 \times 1} \f$ maximum force and \f$ - * \mathbb{R}^{3 \times 1} \f$ maximum moment: \f$ [f_x, f_y, f_z, m_x, m_y, m_z]^T \f$. Unit: - * \f$ [N]~[Nm] \f$. - * @throw std::invalid_argument if [max_wrench] contains any negative value. - */ - void setRemoteMaxWrench(const std::array& max_wrench); - - /** - * @brief [Non-blocking] Set the repulsive wrench in world/TCP frame for the remote robot. - * @param[in] repulsiveWrench The virtual repulsive wrench that will applied on the remote - * robot.(force and moment): \f$ repulsiveW \in \mathbb{R}^{6 \times 1} \f$. Consists of \f$ - * \mathbb{R}^{3 \times 1} \f$ repulsive force and \f$ \mathbb{R}^{3 \times 1} \f$ repulsive - * moment: \f$ [f_x, f_y, f_z, m_x, m_y, m_z]^T \f$. Unit: \f$ [N]~[Nm] \f$. - * @param[in] inWorld Flag to indicate that the repulsive wrench is in World frame or TCP frame. - * true in World frame, false in TCP frame. - * @note This virtual repulsive wrench will only work on those unlocked axis. - * @see setLocalAxisLockCmd - * @see getLocalAxisLockState - */ - void setRepulsiveWrench( - const std::array& repulsiveWrench, bool inWorld = true); - - /** - * @brief [Non-blocking] Access general information of the local robot. - * @return TeleopRobotInfo instance. - */ - TeleopRobotInfo getLocalInfo(void) const; - - /** - * @brief [Non-blocking] Access general information of the remote robot. - * @return TeleopRobotInfo instance. - */ - TeleopRobotInfo getRemoteInfo(void) const; - - /** - * @brief [Non-blocking] Set the local robot axis locking command. - * @param[in] cmd User input command to lock the motion of the specified axis in the reference - * coordinate. - */ - void setLocalAxisLockCmd(const AxisLockDefs& cmd); - - /** - * @brief [Non-blocking] Get the local robot axis locking status - * @param[out] data Current axis locking state of local robot. - */ - void getLocalAxisLockState(AxisLockDefs& data); - - /** - * @brief [Non-blocking] Get the local robot axis locking status - * @warning This fuction is less efficient than the other overloaded one as additional runtime - * memory allocation and data copying are performed. - * @return AxisLockDefs - */ - AxisLockDefs getLocalAxisLockState(void); - -private: - class Impl; - std::unique_ptr pimpl_; -}; - -} // namespace teleop -} // namespace omni -} // namespace flexiv diff --git a/include/flexiv/omni/teleop/Scheduler.hpp b/include/flexiv/omni/teleop/Scheduler.hpp deleted file mode 100644 index 6fbd2c3..0000000 --- a/include/flexiv/omni/teleop/Scheduler.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @file scheduler.hpp - * @copyright Copyright (C) 2016-2024 Flexiv Ltd. All Rights Reserved. - */ -#pragma once -#include -#include -#include -namespace flexiv { -namespace omni { -namespace teleop { -/** - * @class Scheduler - * @brief Real-time scheduler that can simultaneously run multiple periodic - * tasks. Parameters for each task are configured independently. - */ -class Scheduler -{ -public: - /** - * @brief [Blocking] Create an instance and initialize the real-time scheduler. - * @throw std::runtime_error if the initialization sequence failed. - * @warning This constructor blocks until the initialization sequence is successfully finished. - */ - Scheduler(); - virtual ~Scheduler(); - - /** - * @brief [Non-blocking] Add a new periodic task to the scheduler's task pool. Each task in the - * pool is assigned to a dedicated thread with independent thread configuration. - * @param[in] callback Callback function of user task. - * @param[in] task_name A unique name for this task. - * @param[in] interval Execution interval of this periodic task [ms]. The minimum available - * interval is 1 ms, equivalent to 1 kHz loop frequency. - * @param[in] priority Priority for this task thread, can be set to - * min_priority()–max_priority() for real-time scheduling, or 0 for non-real-time scheduling. - * When the priority is set to use real-time scheduling, this thread becomes a real-time thread - * and can only be interrupted by threads with higher priority. When the priority is set to use - * non-real-time scheduling (i.e. 0), this thread becomes a non-real-time thread and can be - * interrupted by any real-time threads. The common practice is to set priority of the most - * critical tasks to max_priority() or near, and set priority of other non-critical tasks to 0 - * or near. To avoid race conditions, the same priority should be assigned to only one task. - * @param[in] cpu_affinity CPU core for this task thread to bind to, can be set to 2–(num_cores - * - 1). This task thread will only run on the specified CPU core. If left with the default - * value (-1), then this task thread will not bind to any CPU core, and the system will decide - * which core to run this task thread on according to the system's own strategy. The common - * practice is to bind the high-priority task to a dedicated spare core, and bind low-priority - * tasks to other cores or just leave them unbound (cpu_affinity = -1). - * @throw std::logic_error if the scheduler is already started or is not fully initialized yet. - * @throw std::invalid_argument if the specified interval/priority/affinity is invalid or the - * specified task name is duplicate. - * @throw std::runtime_error if an error is triggered by the client computer. - * @note Setting CPU affinity on macOS has no effect, as its Mach kernel takes full control of - * thread placement so CPU binding is not supported. - * @warning Calling this method after start() is not allowed. - * @warning For maximum scheduling performance, setting CPU affinity to 0 or 1 is not allowed: - * core 0 is usually the default core for system processes and can be crowded; core 1 is - * reserved for the scheduler itself. - */ - void AddTask(std::function&& callback, const std::string& task_name, int interval, - int priority, int cpu_affinity = -1); - - /** - * @brief [Blocking] Start all added tasks. A dedicated thread will be created for each added - * task and the periodic execution will begin. - * @throw std::logic_error if the scheduler is not initialized yet. - * @throw std::runtime_error if failed to start the tasks. - * @note This function blocks until all added tasks are started. - */ - void Start(); - - /** - * @brief [Blocking] Stop all added tasks. The periodic execution will stop and all task threads - * will be closed with the resources released. - * @throw std::logic_error if the scheduler is not initialized or the tasks are not started yet. - * @throw std::runtime_error if failed to stop the tasks. - * @note Calling start() again can restart the added tasks. - * @note This function blocks until all task threads have exited and resources are released. - * @warning This function cannot be called from within a task thread. - */ - void Stop(); - - /** - * @brief [Non-blocking] Get maximum available priority for user tasks. - * @return The maximum priority that can be set for a user task with real-time scheduling policy - * when calling AddTask(). - */ - int max_priority() const; - - /** - * @brief [Non-blocking] Get minimum available priority for user tasks. - * @return The minimum priority that can be set for a user task with real-time scheduling policy - * when calling AddTask(). - */ - int min_priority() const; - - /** - * @brief [Non-blocking] Get number of tasks added to the scheduler. - * @return Number of added tasks. - */ - size_t num_tasks() const; - -private: - class Impl; - std::unique_ptr pimpl_; -}; - -} // namespace teleop -} // namespace omni -} // namespace flexiv diff --git a/include/flexiv/omni/teleop/TeleopDefs.hpp b/include/flexiv/omni/teleop/TeleopDefs.hpp deleted file mode 100644 index c2b0c04..0000000 --- a/include/flexiv/omni/teleop/TeleopDefs.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file TeleopDefs.hpp - * @copyright Copyright (C) 2016-2024 Flexiv Ltd. All Rights Reserved. - * - */ -#pragma once -#include -#include - -namespace flexiv { -namespace omni { -namespace teleop { - -/** Robot Cartesian-space degrees of freedom \f$ m \f$ */ -constexpr size_t k_cartDOF = 6; - -/** Robot joint-space degrees of freedom \f$ n \f$ */ -constexpr size_t k_jointDOF = 7; - -/** - * @brief Reference coordinate that the axis to be locked - */ -enum CoordType -{ - CD_UNKNOWN = 0, ///> Unknown coordinate - CD_TCP, ///> TCP coordinate of local robot - CD_WORLD ///> WORLD coordinate of local robot - -}; - -static const std::string CoordTypeStr[] = {"UNKNOWN", "TCP", "BASE"}; - -/** - * @brief Get the Ref Coord Type object - * - * @param[in] str string name of the coordinate - * @return CoordType - */ -static inline CoordType getCoordType(const std::string& str) -{ - for (size_t i = 0; i < CD_WORLD - CD_UNKNOWN + 1; i++) { - if (str == CoordTypeStr[i]) { - return static_cast(i); - } - } - return CD_UNKNOWN; -} - -/** - * @brief Data for locking axis, including reference frame and axis to be locked. - * Coordinate type options are: "CD_TCP" for TCP frame and "CD_WORLD" for WORLD frame. - */ -struct AxisLockDefs -{ - /** - * @brief Reference coordinate that the axis to be locked - */ - CoordType coord = CoordType::CD_UNKNOWN; - - /** - * @brief Translation axis locking list, the corresponding axis order is \f$ [X, Y, Z] \f$. True - * for locking, false for floating. - */ - std::array trans_axis_lock_list_ = {false, false, false}; - - /** - * @brief Orientation axis locking list, the corresponding axis order is \f$ [Rx, Ry, Rz] \f$. - * True for locking, false for floating. - */ - std::array ori_axis_lock_list_ = {false, false, false}; -}; - -struct TeleopRobotInfo -{ - /** - * Lower limits of joint positions: \f$ q_{min} \in \mathbb{R}^{n \times 1} \f$. - * Unit: \f$ [rad] \f$. - */ - std::array qMin = {}; - - /** - * Upper limits of joint positions: \f$ q_{max} \in \mathbb{R}^{n \times 1} \f$. - * Unit: \f$ [rad] \f$. - */ - std::array qMax = {}; - - /** - * Measured joint positions using link-side encoder: \f$ q \in \mathbb{R}^{n \times 1} \f$. - * This is the direct measurement of joint positions, preferred for most cases. - * Unit: \f$ [rad] \f$. - */ - std::array qCurrent = {}; -}; - -} // namespace teleop -} // namespace omni -} // namespace flexiv diff --git a/include/flexiv/tdk/data.hpp b/include/flexiv/tdk/data.hpp new file mode 100644 index 0000000..5ceb223 --- /dev/null +++ b/include/flexiv/tdk/data.hpp @@ -0,0 +1,66 @@ +/** + * @file data.hpp + * @copyright Copyright (C) 2016-2024 Flexiv Ltd. All Rights Reserved. + * + */ +#pragma once +#include +#include +#include + +namespace flexiv { +namespace tdk { + +/** + * @brief Reference coordinate that the axis to be locked + */ +enum CoordType +{ + COORD_UNKNOWN = 0, ///> Unknown coordinate + COORD_TCP, ///> TCP coordinate of local robot + COORD_WORLD ///> WORLD coordinate of local robot +}; + +static const std::string CoordTypeStr[] = {"UNKNOWN", "TCP", "WORLD"}; + +/** + * @brief Get the coordinate type of axis locking status + * @param[in] str string name of the coordinate + * @return CoordType + */ +static inline CoordType GetCoordType(const std::string& str) +{ + for (size_t i = 0; i < COORD_WORLD - COORD_UNKNOWN + 1; i++) { + if (str == CoordTypeStr[i]) { + return static_cast(i); + } + } + return COORD_UNKNOWN; +} + +/** + * @brief Data for locking axis, including reference frame and axis to be locked. + * Coordinate type options are: "COORD_TCP" for TCP frame and "COORD_WORLD" for WORLD frame. + */ +struct AxisLock +{ + /** + * @brief Reference coordinate that the axis to be locked + */ + CoordType coord = CoordType::COORD_UNKNOWN; + + /** + * @brief Translation axis lock, the corresponding axis order is \f$ [X, Y, Z] \f$. True + * for locking, false for floating. + */ + std::array lock_trans_axis = {false, false, false}; + + /** + * @brief Orientation axis lock, the corresponding axis order is \f$ [Rx, Ry, Rz] \f$. + * True for locking, false for floating. + */ + std::array lock_ori_axis = {false, false, false}; +}; + +} // namespace tdk +} // namespace flexiv diff --git a/include/flexiv/tdk/robot_robot_teleop.hpp b/include/flexiv/tdk/robot_robot_teleop.hpp new file mode 100644 index 0000000..5519064 --- /dev/null +++ b/include/flexiv/tdk/robot_robot_teleop.hpp @@ -0,0 +1,225 @@ +/** + * @file robot_robot_teleop.hpp + * @copyright Copyright (C) 2016-2024 Flexiv Ltd. All Rights Reserved. + */ +#pragma once + +#include +#include +#include +#include +namespace flexiv { +namespace tdk { + +/** + * @brief Main interface for Rizon series robot-robot teleop in Cartesian space, containing several + * function categories and background services. Robot2RobotTeleop consists of a collection of + * local-remote adaptive robot arms. It performs synchronized, force guided real-time motions and + * provides the operator with high-fidelity perceptual feedback. + */ +class Robot2RobotTeleop +{ +public: + Robot2RobotTeleop() = delete; + Robot2RobotTeleop(const Robot2RobotTeleop&) = delete; + Robot2RobotTeleop(Robot2RobotTeleop&&) = delete; + Robot2RobotTeleop& operator=(const Robot2RobotTeleop&) = delete; + /** + * @brief [Blocking] Create a flexiv::tdk::Robot2RobotTeleop instance as the main interface. + * Teleop services will initialize and connection with the local and remote robot will be + * established. + * @param[in] local_sn Serial number of the local robot, e.g. Rizon4s-062001. + * @param[in] remote_sn Serial number of the remote robot, e.g. Rizon4s-062002. + * @param [in] path_to_license_jsn Path to the omni license config json file. See README.md to + * apply for license. + * @throw std::runtime_error if the initialization sequence failed. + * @throw std::logic_error if the connected robot does not have a valid license; or this teleop + * library version is incompatible with the connected robot; or model of the connected robot is + * not supported. + * @warning This constructor blocks until the initialization sequence is successfully finished + * and connection with the robot is established. + */ + Robot2RobotTeleop(const std::string& local_sn, const std::string& remote_sn, + const std::string& path_to_license_jsn); + virtual ~Robot2RobotTeleop(); + + /** + * @brief [Blocking] Initialize local and remote robots states and commands. + * @throw std::logic_error if robots are not connected. + * @throw std::runtime_error if failed to execute the request. + * @note This function blocks until the request is successfully executed. + * @warning This will zeroing force/torque sensors, make sure nothing is in contact with the + * local and remote robot. + */ + void Init(void); + + /** + * @brief [Blocking] Enable the local and remote robots. If all E-stop are released and there's + * no fault, both local and remote will release brakes, and becomes operational a few seconds + * later. + * @throw std::logic_error if the robot is not connected. + * @throw std::runtime_error if failed to execute the request. + * @note This function blocks until the request is successfully executed. + */ + void Enable(void); + + /** + * @brief [Non-blocking] Engage/disengage the local and remote robot. TDK supports teleop local + * and remote robots in different configurations. When disengaged, the operators can move the + * local robot to the center of the workspace or re-orientated for better ergonomics. Meanwhile, + * the remote robot will remain stationary. When engaged again, the remote robot will only + * mimics the local's relative motion instead of simply mirroring the pose. + * @param[in] flag True to engage the teleop, false to disengage. + * @note The teleop will keep disengaged by default. + */ + void Engage(bool flag); + + /** + * @brief [Non-blocking] Stop teleop by lock all the axes in World frame. Both local and remote + * will stop moving. + */ + void Stop(void); + + /** + * @brief [Non-blocking] Check if robots in fault state. + * @return True: Teleop has fault, false: everything normal. + */ + bool fault(void); + + /** + * @brief [Non-blocking] Whether the local and remote robots are normally operational, which + * requires the following conditions to be met: enabled, brakes fully released, in auto-remote + * mode, no fault, and not in reduced state. + * @return True: operational, false: not operational. + * @warning The robot won't execute any command until it becomes normally operational. + */ + bool operational(void); + + /** + * @brief [Blocking] Clear fault of the local and remote robots. + * @return True: successfully cleared fault, false: cannot clear fault. + * @throw std::runtime_error if failed to deliver the request. + * @note This function blocks until fault on local and remote is successfully cleared or + * maximum number of attempts is reached. + */ + bool ClearFault(void); + + /** + * @brief [Non-blocking] Periodically step teleop and the called frequency should be 1000Hz. + * The remote will always imitate the movements of the local and feedback the external wrench to + * the local. + * @throw std::runtime_error if robot becomes inoperable during teleoperation. + * @warning This is the main function doing the real-time teleop task computing, the called + * frequency should be strictly 1000Hz. + */ + void Step(void); + + /** + * @brief [Non-blocking] Set preferred joint positions for the null-space posture of local + * robot. + * @param[in] preferred_joint_pos Preferred joint positions for the null-space posture control: + * \f$ q_{ns} \in \mathbb{R}^{n \times 1} \f$. Valid range: [flexiv::rdk::RobotInfo::q_min, + * flexiv::rdk::RobotInfo::q_max]. Unit: \f$ [rad] \f$. + * @throw std::invalid_argument if [preferred_joint_pos] contains any value outside the valid + * range. + * @throw std::logic_error if teleop was not successfully initialized. + * @note This setting will persist across the applicable control modes until changed again. + * @par Null-space posture control + * Similar to human arm, a robotic arm with redundant joint-space degree(s) of freedom (DOF > 6) + * can change its overall posture without affecting the ongoing primary task. This is achieved + * through a technique called "null-space control". After the preferred joint positions for a + * desired robot posture is set using this function, the robot's null-space control module will + * try to pull the arm as close to this posture as possible without affecting the primary + * Cartesian motion-force control task. + */ + void SetLocalNullSpacePosture(const std::vector& preferred_joint_pos); + + /** + * @brief [Non-blocking] Set preferred joint positions for the null-space posture of remote + * robot. + * @param[in] preferred_joint_pos Preferred joint positions for the null-space posture control: + * \f$ q_{ns} \in \mathbb{R}^{n \times 1} \f$. Valid range: [flexiv::rdk::RobotInfo::q_min, + * flexiv::rdk::RobotInfo::q_max]. Unit: \f$ [rad] \f$. + * @throw std::invalid_argument if [preferred_joint_pos] contains any value outside the valid + * range. + * @throw std::logic_error if teleop was not successfully initialized. + * @note This setting will persist across the applicable control modes until changed again. + * @par Null-space posture control + * Similar to human arm, a robotic arm with redundant joint-space degree(s) of freedom (DOF > 6) + * can change its overall posture without affecting the ongoing primary task. This is achieved + * through a technique called "null-space control". After the preferred joint positions for a + * desired robot posture is set using this function, the robot's null-space control module will + * try to pull the arm as close to this posture as possible without affecting the primary + * Cartesian motion-force control task. + */ + void SetRemoteNullSpacePosture(const std::vector& preferred_joint_pos); + + /** + * @brief [Non-blocking] Set maximum contact wrench for the teleop robot. The controller will + * regulate its output to maintain contact wrench (force and moment) with the environment under + * the set values. + * @param[in] max_wrench Maximum contact wrench (force and moment): \f$ F_max \in \mathbb{R}^{6 + * \times 1} \f$. Consists of \f$ \mathbb{R}^{3 \times 1} \f$ maximum force and \f$ + * \mathbb{R}^{3 \times 1} \f$ maximum moment: \f$ [f_x, f_y, f_z, m_x, m_y, m_z]^T \f$. Unit: + * \f$ [N]~[Nm] \f$. + * @throw std::invalid_argument if [max_wrench] contains any negative value. + * @throw std::logic_error if teleop is not initialized. + */ + void SetMaxContactWrench(const std::array& max_wrench); + + /** + * @brief [Non-blocking] Set the repulsive force in World/Tcp frame for the remote robot. + * @param[in] repulsive_force The virtual repulsive force that will applied on the remote + * robot.: \f$ repulsiveF \in \mathbb{R}^{3 \times 1} \f$. Consists of \f$ \mathbb{R}^{3 \times + * 1} \f$ repulsive force : \f$ [f_x, f_y, f_z]^T \f$. Unit: \f$ [N] \f$. + * @param[in] in_world Flag to indicate that the repulsive force is in World frame or Tcp + * frame. true in World frame, false in Tcp frame. + * @note This virtual repulsive wrench will only work on those unlocked axis. + * @see SetLocalAxisLockCmd + * @see GetLocalAxisLockState + */ + void SetRepulsiveForce(const std::array& repulsive_force, bool in_world = true); + + /** + * @brief[Non-blocking] Set the wrench feedback scaling factor. + * @param[in] factor This coefficient will scale the feedback wrench of the remote robot. Scale + * factor greater than 1 means that the external force received by the remote robot is + * amplified, otherwise it will be reduced. Setting scale to zero means no wrench feedback and 1 + * means 100% transparency. Valid range: [0, kMaxWrenchFeedbackScale] + * @throw std::invalid_argument if input scale is outside the valid range. + * @warning Only when the user ensures that the interaction force between the remote robot and + * workpiece is very small, such as when operating a very soft object, do they need to set the + * factor to be greater than 1. If the object in contact with the remote robot has high + * stiffness, please set the factor very carefully. The higher the scale, the greater the force + * feedback to the local robot will be. Using a scaling factor of 1 is recommended. + */ + void SetWrenchFeedbackScalingFactor(double factor = 1.0); + + /** + * @brief [Non-blocking] Set the local robot axis locking command. + * @param[in] cmd User input command to lock the motion of the specified axis in the reference + * coordinate. + */ + void SetLocalAxisLockCmd(const AxisLock& cmd); + + /** + * @brief [Non-blocking] Get the local robot axis locking status + * @param[out] data Current axis locking state of local robot. + */ + void GetLocalAxisLockState(AxisLock& data); + + /** + * @brief [Non-blocking] Get the local robot axis locking status + * @warning This fuction is less efficient than the other overloaded one as additional runtime + * memory allocation and data copying are performed. + * @return AxisLock + */ + AxisLock GetLocalAxisLockState(void); + +private: + class Impl; + std::unique_ptr pimpl_; +}; + +} // namespace tdk +} // namespace flexiv diff --git a/lib/libflexiv_omni_teleop.x86_64-linux-gnu.a b/lib/libflexiv_omni_teleop.x86_64-linux-gnu.a deleted file mode 100644 index f892871..0000000 Binary files a/lib/libflexiv_omni_teleop.x86_64-linux-gnu.a and /dev/null differ diff --git a/lib/libflexiv_tdk.x86_64-linux-gnu.a b/lib/libflexiv_tdk.x86_64-linux-gnu.a new file mode 100644 index 0000000..c1afda6 Binary files /dev/null and b/lib/libflexiv_tdk.x86_64-linux-gnu.a differ diff --git a/license_generator/apply_for_license.md b/license_generator/apply_for_license.md new file mode 100644 index 0000000..993dc47 --- /dev/null +++ b/license_generator/apply_for_license.md @@ -0,0 +1,19 @@ +# Applying for license +> [!NOTE] +> The license is forcibly bound to the user's computer hardware, so before proceeding with the following steps, make sure you have prepared a physical computer with Ubuntu 20.04/22.04 and CPU platform x86_64. Using virtual machine is highly NOT recommended. If you need to compatible with other operating systems or CPU architectures, please contact Flexiv Ltd. + +1. Install net-tools + ```bash + sudo apt update + sudo apt install net-tools + ``` +2. Run the generator under ``flexiv_tdk/license_generator`` on your computer. + ```bash + ./generator + ``` + This will generate a feature_id.txt. Send this file to Flexiv to apply for the license. + +> [!NOTE] +> The feature id is a unique identifier and is bound to your computer hardware. You CANNOT use your license and run flexiv_tdk on other devices. Please generate feature_id and use license on the same computer. +3. After received the license package, extract the zip package and put the .lic, .signature and .json file to a safe directory. For example, a new folder named ``omni_license`` under your home directory. +4. Parse the path of omni_licenseCfg.json file when construct tdk class in your code. \ No newline at end of file diff --git a/license_generator/generator b/license_generator/generator new file mode 100755 index 0000000..535ab9c Binary files /dev/null and b/license_generator/generator differ diff --git a/omni_license_generator/Omni_license.md b/omni_license_generator/Omni_license.md deleted file mode 100644 index 76cb5bd..0000000 --- a/omni_license_generator/Omni_license.md +++ /dev/null @@ -1,16 +0,0 @@ -# Applying for Omni license -1. The Omni license is forcibly bound to the user's Ubuntu computer hardware, so before proceeding with the following steps, make sure you have prepared a physical computer with Ubuntu 22.04 and CPU platform x86_64. If you need compatible with other operating systems or CPU architectures, please contact Flexiv. -2. Install net-tools - ```bash - sudo apt update - sudo apt install net-tools - ``` -3. Run the generator under ``flexiv_omni_teleop/omni_license_generator`` on your computer. - ```bash - ./generator - ``` - This will generate a feature_id.txt. Send this file to Flexiv to apply for the Omni license. - - Note: The feature id is a unique identifier for your application and is bound to your computer. You CANNOT use your Omni license and run Omni-Teleop on other devices. Please generate feature_id and use Omni license on the same computer. -4. After received the Omni license, extract the zip package and put the .lic, .signature and .json file to a safe directory. For example, a new folder named ``omni_license`` under your home directory. -5. Parse the path of omni_licenseCfg.json file when construct Omni-Teleop class in your code. \ No newline at end of file diff --git a/omni_license_generator/generator b/omni_license_generator/generator deleted file mode 100755 index 9c853a9..0000000 Binary files a/omni_license_generator/generator and /dev/null differ diff --git a/thirdparty/build_and_install_dependencies.sh b/thirdparty/build_and_install_dependencies.sh index 4111bca..f313020 100644 --- a/thirdparty/build_and_install_dependencies.sh +++ b/thirdparty/build_and_install_dependencies.sh @@ -32,11 +32,5 @@ echo "Number of parallel build jobs: $NUM_JOBS" mkdir -p cloned && cd cloned # Build and install all dependencies to INSTALL_DIR -bash $SCRIPTPATH/scripts/install_eigen.sh $INSTALL_DIR -bash $SCRIPTPATH/scripts/install_tinyxml2.sh $INSTALL_DIR -bash $SCRIPTPATH/scripts/install_foonathan_memory.sh $INSTALL_DIR -bash $SCRIPTPATH/scripts/install_Fast-CDR.sh $INSTALL_DIR -bash $SCRIPTPATH/scripts/install_Fast-DDS.sh $INSTALL_DIR -bash $SCRIPTPATH/scripts/install_boost.sh $INSTALL_DIR - +bash $SCRIPTPATH/scripts/install_rdk.sh $INSTALL_DIR echo ">>>>>>>>>> Finished <<<<<<<<<<" diff --git a/thirdparty/scripts/install_Fast-CDR.sh b/thirdparty/scripts/install_Fast-CDR.sh deleted file mode 100644 index d4a8289..0000000 --- a/thirdparty/scripts/install_Fast-CDR.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -e -echo "Installing Fast-CDR" - -# Get install directory as script argument -INSTALL_DIR=$1 - -# Clone source code -if [ ! -d Fast-CDR ] ; then - git clone https://github.com/eProsima/Fast-CDR.git - cd Fast-CDR -else - cd Fast-CDR -fi - -# Use specific version -git checkout v1.0.24 -git submodule update --init --recursive - -# Configure CMake -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - -DCMAKE_PREFIX_PATH=$INSTALL_DIR \ - -DCOMPILE_EXAMPLES=OFF - -# Build and install -cmake --build . --target install --config Release -j $NUM_JOBS - -echo "Installed Fast-CDR" diff --git a/thirdparty/scripts/install_Fast-DDS.sh b/thirdparty/scripts/install_Fast-DDS.sh deleted file mode 100644 index cf5d83d..0000000 --- a/thirdparty/scripts/install_Fast-DDS.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# Depends on: foonathan_memory, tinyxml2, Fast-CDR -set -e -echo "Installing Fast-DDS" - -# Get install directory as script argument -INSTALL_DIR=$1 - -# Clone source code -if [ ! -d Fast-DDS ] ; then - git clone https://github.com/eProsima/Fast-DDS.git - cd Fast-DDS -else - cd Fast-DDS -fi - -# Use specific version -git checkout v2.6.7 -git submodule update --init --recursive - -# Configure CMake -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - -DCMAKE_PREFIX_PATH=$INSTALL_DIR \ - -DTHIRDPARTY_Asio=ON \ - -DCOMPILE_EXAMPLES=OFF \ - -DSQLITE3_SUPPORT=OFF \ - -DOPENSSL_USE_STATIC_LIBS=ON - -# Build and install -cmake --build . --target install --config Release -j $NUM_JOBS - -echo "Installed Fast-DDS" diff --git a/thirdparty/scripts/install_boost.sh b/thirdparty/scripts/install_boost.sh deleted file mode 100644 index 7291d99..0000000 --- a/thirdparty/scripts/install_boost.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -set -e -echo "Installing boost" - -# Get install directory as script argument -INSTALL_DIR=$1 - -# Download source code -if [ ! -d boost_1_74_0 ] ; then - # download is faster than clone - URL="https://boostorg.jfrog.io/artifactory/main/release/1.74.0/source/boost_1_74_0.tar.bz2" - echo "-- Downloading: $URL" - wget $URL --no-clobber --quiet --show-progress --progress=bar:force 2>&1 - # Unzip - echo "-- Extracting: boost_1_74_0.tar.bz2" - tar --bzip2 -xf "boost_1_74_0.tar.bz2" - cd boost_1_74_0 -else - cd boost_1_74_0 -fi - -# Build and install -./bootstrap.sh --prefix=$INSTALL_DIR --with-libraries=filesystem -./b2 variant=release install - -echo "Installed boost" diff --git a/thirdparty/scripts/install_eigen.sh b/thirdparty/scripts/install_eigen.sh deleted file mode 100644 index 3759dc3..0000000 --- a/thirdparty/scripts/install_eigen.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -set -e -echo "Installing eigen" - -# Get install directory as script argument -INSTALL_DIR=$1 - -# Clone source code -if [ ! -d eigen ] ; then - git clone https://gitlab.com/libeigen/eigen.git - cd eigen -else - cd eigen -fi - -# Use specific version -git checkout 3.3.7 -git submodule update --init --recursive - -# Configure CMake -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - -DCMAKE_PREFIX_PATH=$INSTALL_DIR - -# Build and install -cmake --build . --target install --config Release -j $NUM_JOBS - -echo "Installed eigen" diff --git a/thirdparty/scripts/install_foonathan_memory.sh b/thirdparty/scripts/install_foonathan_memory.sh deleted file mode 100644 index bfee855..0000000 --- a/thirdparty/scripts/install_foonathan_memory.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -set -e -echo "Installing foonathan_memory" - -# Get install directory as script argument -INSTALL_DIR=$1 - -# Clone source code -if [ ! -d foonathan_memory_vendor ] ; then - git clone https://github.com/eProsima/foonathan_memory_vendor.git - cd foonathan_memory_vendor -else - cd foonathan_memory_vendor -fi - -# Use specific version -git checkout v1.2.1 -git submodule update --init --recursive - -# Configure CMake -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - -DCMAKE_PREFIX_PATH=$INSTALL_DIR - -# Build and install -cmake --build . --target install --config Release -j $NUM_JOBS - -echo "Installed foonathan_memory" diff --git a/thirdparty/scripts/install_rdk.sh b/thirdparty/scripts/install_rdk.sh new file mode 100644 index 0000000..2aef391 --- /dev/null +++ b/thirdparty/scripts/install_rdk.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -e +echo "Installing flexiv_rdk" + +# Get install directory as script argument +INSTALL_DIR=$1 + + +# Clone source code +if [ ! -d flexiv_rdk ] ; then + git clone https://github.com/flexivrobotics/flexiv_rdk.git + cd flexiv_rdk +else + cd flexiv_rdk +fi + +# Set absolute path of flexiv_rdk +RDK_DIR="$PWD" + +# Use specific version +git fetch -p +git checkout v1.4 + +# Build and install dependencies +cd $RDK_DIR/thirdparty +bash build_and_install_dependencies.sh $INSTALL_DIR + +cd $RDK_DIR +# Configure CMake +mkdir -p build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ + -DCMAKE_PREFIX_PATH=$INSTALL_DIR + +# Build and install +cmake --build . --target install --config Release -j $NUM_JOBS + +echo "Installed flexiv_rdk" diff --git a/thirdparty/scripts/install_tinyxml2.sh b/thirdparty/scripts/install_tinyxml2.sh deleted file mode 100644 index 1a29597..0000000 --- a/thirdparty/scripts/install_tinyxml2.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -set -e -echo "Installing tinyxml2" - -# Get install directory as script argument -INSTALL_DIR=$1 - -# Clone source code -if [ ! -d tinyxml2 ] ; then - git clone https://github.com/leethomason/tinyxml2.git - cd tinyxml2 -else - cd tinyxml2 -fi - -# Use specific version -git checkout 8.0.0 -git submodule update --init --recursive - -# Configure CMake -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ - -DCMAKE_PREFIX_PATH=$INSTALL_DIR - -# Build and install -cmake --build . --target install --config Release -j $NUM_JOBS - -echo "Installed tinyxml2"