diff --git a/.github/workflows/black.yaml b/.github/workflows/black.yaml new file mode 100644 index 0000000..9065b5e --- /dev/null +++ b/.github/workflows/black.yaml @@ -0,0 +1,10 @@ +name: Lint + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: psf/black@stable diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..45d624f --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,27 @@ +name: Build + +on: + pull_request: + branches: + - main + workflow_dispatch: + schedule: + - cron: "0 0 * * *" + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + fri_version: [1.11, 1.14, 1.15, 1.16, 2.5, 2.7] + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.10 + - name: Export FRI_CLIENT_VERSION + run: export FRI_CLIENT_VERSION=${{ matrix.fri_version }} + - name: Test installation + run: pip3 install . diff --git a/CMakeLists.txt b/CMakeLists.txt index bd615ce..f4c830d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,21 +13,18 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(FRI_BUILD_EXAMPLES OFF) # set the FRI version -set(FRI_VERSION_MAJOR 1 CACHE STRING "The FRI major version." FORCE) -set(FRI_VERSION_MINOR 15 CACHE STRING "The FRI minor version." FORCE) +set(FRI_CLIENT_VERSION_MAJOR 1 CACHE STRING "The FRI client major version." FORCE) +set(FRI_CLIENT_VERSION_MINOR 15 CACHE STRING "The FRI client minor version." FORCE) # fetch the fri depending on the version FetchContent_Declare( FRI GIT_REPOSITORY https://github.com/lbr-stack/fri - GIT_TAG fri-${FRI_VERSION_MAJOR}.${FRI_VERSION_MINOR} + GIT_TAG fri-${FRI_CLIENT_VERSION_MAJOR}.${FRI_CLIENT_VERSION_MINOR} ) FetchContent_MakeAvailable(FRI) -# fri configure file -configure_file(fri_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/pyFRI/src/fri_config.h) - add_subdirectory(pybind) pybind11_add_module(_pyFRI ${CMAKE_CURRENT_SOURCE_DIR}/pyFRI/src/wrapper.cpp) diff --git a/README.md b/README.md index e8f82ac..ee3547c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # pyFRI +[![License](https://img.shields.io/github/license/lbr-stack/pyFRI)](https://github.com/lbr-stack/pyFRI/tree/main?tab=Apache-2.0-1-ov-file#readme) +[![Code Style: Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) + KUKA Fast Robot Interface Python SDK. The code in this repository, provides Python bindings for the FRI Client SDK C++. The interface has been designed to be as similar as possible to the documentation provided by KUKA. @@ -52,11 +55,18 @@ If you have a different version, please consider [forking](https://github.com/lb # Install 1. Clone repository (make sure you include `--recursive`): - - (ssh) `$ git clone --recursive git@github.com:lbr-stack/pyFRI.git` - - (https) `$ git clone --recursive https://github.com/lbr-stack/pyFRI.git` -2. Change directory: `$ cd pyFRI` -3. Modify `fri_config.py`: uncomment the line corresponding to your version of FRI. -4. Install: `$ pip install .` + ```shell + git clone --recursive https://github.com/lbr-stack/pyFRI.git + ``` +2. Change directory: + ```shell + cd pyFRI + ``` +3. Install: + ```shell + export FRI_CLIENT_VERSION=1.15 + pip3 install . + ``` ## Upgrading/switching between FRI Versions diff --git a/examples/LBRJointSineOverlay.py b/examples/LBRJointSineOverlay.py index 0623ca3..611c648 100644 --- a/examples/LBRJointSineOverlay.py +++ b/examples/LBRJointSineOverlay.py @@ -1,9 +1,11 @@ -import sys -import math import argparse +import math +import sys + +import matplotlib.pyplot as plt import numpy as np import pandas as pd -import matplotlib.pyplot as plt + import pyFRI as fri @@ -110,7 +112,7 @@ def cvt_joint_mask(value): def main(): - print("Running FRI Version:", fri.FRI_VERSION) + print("Running FRI Version:", fri.FRI_CLIENT_VERSION) args = get_arguments() client = LBRJointSineOverlayClient( diff --git a/examples/LBRTorqueSineOverlay.py b/examples/LBRTorqueSineOverlay.py index ea37aa2..31e872f 100644 --- a/examples/LBRTorqueSineOverlay.py +++ b/examples/LBRTorqueSineOverlay.py @@ -1,10 +1,11 @@ -import sys -import math import argparse -import pyFRI as fri +import math +import sys import numpy as np +import pyFRI as fri + class LBRTorqueSineOverlayClient(fri.LBRClient): def __init__(self, joint_mask, freq_hz, torque_amplitude): @@ -98,10 +99,12 @@ def cvt_joint_mask(value): def main(): - print("Running FRI Version:", fri.FRI_VERSION) + print("Running FRI Version:", fri.FRI_CLIENT_VERSION) args = get_arguments() - client = LBRTorqueSineOverlayClient(args.joint_mask, args.freq_hz, args.torque_amplitude) + client = LBRTorqueSineOverlayClient( + args.joint_mask, args.freq_hz, args.torque_amplitude + ) app = fri.ClientApplication(client) success = app.connect(args.port, args.hostname) diff --git a/examples/LBRWrenchSineOverlay.py b/examples/LBRWrenchSineOverlay.py index 67216a0..912cfe6 100644 --- a/examples/LBRWrenchSineOverlay.py +++ b/examples/LBRWrenchSineOverlay.py @@ -1,10 +1,11 @@ -import sys -import math import argparse -import pyFRI as fri +import math +import sys import numpy as np +import pyFRI as fri + class LBRWrenchSineOverlayClient(fri.LBRClient): def __init__(self, frequencyX, frequencyY, amplitudeX, amplitudeY): @@ -104,7 +105,7 @@ def get_arguments(): def main(): - print("Running FRI Version:", fri.FRI_VERSION) + print("Running FRI Version:", fri.FRI_CLIENT_VERSION) args = get_arguments() print(args) diff --git a/examples/admittance.py b/examples/admittance.py index 19c288f..644222d 100644 --- a/examples/admittance.py +++ b/examples/admittance.py @@ -1,8 +1,7 @@ +import numpy as np import optas from robot import load_robot -import numpy as np - class AdmittanceController: def __init__(self, lbr_med_num): diff --git a/examples/hand_guide.py b/examples/hand_guide.py index ecb8a6e..8786063 100644 --- a/examples/hand_guide.py +++ b/examples/hand_guide.py @@ -1,22 +1,20 @@ -import sys -import math import argparse +import sys + +import numpy as np +from admittance import AdmittanceController + import pyFRI as fri +from pyFRI.tools.filters import ExponentialStateFilter from pyFRI.tools.state_estimators import ( - JointStateEstimator, FRIExternalTorqueEstimator, + JointStateEstimator, WrenchEstimatorTaskOffset, ) -from pyFRI.tools.filters import ExponentialStateFilter - - -from admittance import AdmittanceController - -import numpy as np -if fri.FRI_VERSION_MAJOR == 1: +if fri.FRI_CLIENT_VERSION_MAJOR == 1: POSITION = fri.EClientCommandMode.POSITION -elif fri.FRI_VERSION_MAJOR == 2: +elif fri.FRI_CLIENT_VERSION_MAJOR == 2: POSITION = fri.EClientCommandMode.JOINT_POSITION @@ -103,7 +101,7 @@ def get_arguments(): def main(): - print("Running FRI Version:", fri.FRI_VERSION) + print("Running FRI Version:", fri.FRI_CLIENT_VERSION) args = get_arguments() client = HandGuideClient(args.lbr_ver) diff --git a/examples/ik.py b/examples/ik.py index 1173df3..e097b2a 100644 --- a/examples/ik.py +++ b/examples/ik.py @@ -3,7 +3,6 @@ class IK: - """ This class solves the following problem diff --git a/examples/joint_teleop.py b/examples/joint_teleop.py index 79609f4..bcb0282 100644 --- a/examples/joint_teleop.py +++ b/examples/joint_teleop.py @@ -1,11 +1,11 @@ import sys -# FRI Client: https://github.com/cmower/FRI-Client-SDK_Python -import pyFRI as fri - # PyGame: https://www.pygame.org/news import pygame +# FRI Client: https://github.com/cmower/FRI-Client-SDK_Python +import pyFRI as fri + pygame.init() # NumPy: https://numpy.org/ @@ -138,7 +138,7 @@ def get_arguments(): def main(): - print("Running FRI Version:", fri.FRI_VERSION) + print("Running FRI Version:", fri.FRI_CLIENT_VERSION) args = get_arguments() keyboard = Keyboard() diff --git a/examples/task_teleop.py b/examples/task_teleop.py index 98331a3..adca75d 100644 --- a/examples/task_teleop.py +++ b/examples/task_teleop.py @@ -1,13 +1,13 @@ -import sys import argparse +import sys from collections import OrderedDict -# FRI Client: https://github.com/cmower/FRI-Client-SDK_Python -import pyFRI as fri - # PyGame: https://www.pygame.org/news import pygame +# FRI Client: https://github.com/cmower/FRI-Client-SDK_Python +import pyFRI as fri + pygame.init() # NumPy: https://numpy.org/ @@ -157,7 +157,7 @@ def get_arguments(): def main(): - print("Running FRI Version:", fri.FRI_VERSION) + print("Running FRI Version:", fri.FRI_CLIENT_VERSION) args = get_arguments() ik = IK(args.lbr_ver) diff --git a/fri_config.h.in b/fri_config.h.in deleted file mode 100644 index 5257a4d..0000000 --- a/fri_config.h.in +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef FRI_CONFIG_H -#define FRI_CONFIG_H - -// Indicates the major version of FRI. -#define FRI_VERSION_MAJOR @FRI_VERSION_MAJOR@ - -// Indicates the minor version of FRI. -#define FRI_VERSION_MINOR @FRI_VERSION_MINOR@ - -#endif diff --git a/fri_config.py b/fri_config.py deleted file mode 100644 index e3cc4bf..0000000 --- a/fri_config.py +++ /dev/null @@ -1,3 +0,0 @@ -# Uncomment the line corresponding to your version of FRI. -# FRI_VERSION = "1.15" -# FRI_VERSION = "2.5" diff --git a/pyFRI/src/fri_config.h b/pyFRI/src/fri_config.h deleted file mode 100644 index 50f23b9..0000000 --- a/pyFRI/src/fri_config.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef FRI_CONFIG_H -#define FRI_CONFIG_H - -// Indicates the major version of FRI. -#define FRI_VERSION_MAJOR 1 - -// Indicates the minor version of FRI. -#define FRI_VERSION_MINOR 15 - -#endif diff --git a/pyFRI/src/wrapper.cpp b/pyFRI/src/wrapper.cpp index becb98c..d808e20 100644 --- a/pyFRI/src/wrapper.cpp +++ b/pyFRI/src/wrapper.cpp @@ -16,9 +16,9 @@ // KUKA FRI-Client-SDK_Cpp (using version hosted at: // https://github.com/cmower/FRI-Client-SDK_Cpp) #include "friClientApplication.h" +#include "friClientVersion.h" #include "friLBRClient.h" #include "friUdpConnection.h" -#include "fri_config.h" // Function for returning the current time long long getCurrentTimeInNanoseconds() { @@ -206,10 +206,10 @@ PYBIND11_MODULE(_pyFRI, m) { m.doc() = "Python bindings for the KUKA FRI Client SDK. THIS IS NOT A KUKA " "PRODUCT."; - m.attr("FRI_VERSION_MAJOR") = FRI_VERSION_MAJOR; - m.attr("FRI_VERSION_MINOR") = FRI_VERSION_MINOR; - m.attr("FRI_VERSION") = std::to_string(FRI_VERSION_MAJOR) + "." + - std::to_string(FRI_VERSION_MINOR); + m.attr("FRI_CLIENT_VERSION_MAJOR") = FRI_CLIENT_VERSION_MAJOR; + m.attr("FRI_CLIENT_VERSION_MINOR") = FRI_CLIENT_VERSION_MINOR; + m.attr("FRI_CLIENT_VERSION") = std::to_string(FRI_CLIENT_VERSION_MAJOR) + + "." + std::to_string(FRI_CLIENT_VERSION_MINOR); py::enum_(m, "ESessionState") .value("IDLE", KUKA::FRI::ESessionState::IDLE) @@ -262,9 +262,9 @@ PYBIND11_MODULE(_pyFRI, m) { .value("NO_COMMAND_MODE", KUKA::FRI::EClientCommandMode::NO_COMMAND_MODE) .value("WRENCH", KUKA::FRI::EClientCommandMode::WRENCH) .value("TORQUE", KUKA::FRI::EClientCommandMode::TORQUE) -#if FRI_VERSION_MAJOR == 1 +#if FRI_CLIENT_VERSION_MAJOR == 1 .value("POSITION", KUKA::FRI::EClientCommandMode::POSITION) -#elif FRI_VERSION_MAJOR == 2 +#elif FRI_CLIENT_VERSION_MAJOR == 2 .value("JOINT_POSITION", KUKA::FRI::EClientCommandMode::JOINT_POSITION) .value("CARTESIAN_POSE", KUKA::FRI::EClientCommandMode::CARTESIAN_POSE) #endif @@ -276,7 +276,7 @@ PYBIND11_MODULE(_pyFRI, m) { .value("CARTESIAN", KUKA::FRI::EOverlayType::CARTESIAN) .export_values(); -#if FRI_VERSION_MAJOR == 2 +#if FRI_CLIENT_VERSION_MAJOR == 2 py::enum_(m, "ERedundancyStrategy") .value("E1", KUKA::FRI::ERedundancyStrategy::E1) .value("NO_STRATEGY", KUKA::FRI::ERedundancyStrategy::NO_STRATEGY) @@ -392,7 +392,7 @@ PYBIND11_MODULE(_pyFRI, m) { .def("getBooleanIOValue", &KUKA::FRI::LBRState::getBooleanIOValue) .def("getDigitalIOValue", &KUKA::FRI::LBRState::getDigitalIOValue) .def("getAnalogIOValue", &KUKA::FRI::LBRState::getAnalogIOValue) -#if FRI_VERSION_MAJOR == 1 +#if FRI_CLIENT_VERSION_MAJOR == 1 .def("getCommandedJointPosition", [](const KUKA::FRI::LBRState &self) { // Declare variables @@ -410,7 +410,7 @@ PYBIND11_MODULE(_pyFRI, m) { return py::array_t({KUKA::FRI::LBRState::NUMBER_OF_JOINTS}, dataf); }) -#elif FRI_VERSION_MAJOR == 2 +#elif FRI_CLIENT_VERSION_MAJOR == 2 .def("getMeasuredCartesianPose", [](const KUKA::FRI::LBRState &self) { diff --git a/pyFRI/tools/state_estimators.py b/pyFRI/tools/state_estimators.py index 829f500..dccf71d 100644 --- a/pyFRI/tools/state_estimators.py +++ b/pyFRI/tools/state_estimators.py @@ -10,7 +10,6 @@ class JointStateEstimator: - """ JointStateEstimator @@ -85,7 +84,6 @@ def get_acceleration(self): class TaskSpaceStateEstimator: - """ TaskSpaceStateEstimator @@ -167,7 +165,6 @@ def get_external_torque(self): class WrenchEstimator(abc.ABC): - """ WrenchEstimator @@ -238,7 +235,6 @@ def get_wrench(self): class WrenchEstimatorJointOffset(WrenchEstimator): - """ WrenchEstimatorJointOffset @@ -261,7 +257,6 @@ def get_wrench(self): class WrenchEstimatorTaskOffset(WrenchEstimator): - """ WrenchEstimatorTaskOffset diff --git a/setup.py b/setup.py index e40d029..16cde53 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,10 @@ import os import re -import sys import subprocess +import sys from pathlib import Path -from setuptools import Extension, setup, find_packages + +from setuptools import Extension, find_packages, setup from setuptools.command.build_ext import build_ext @@ -13,21 +14,10 @@ def __init__(self, msg): super().__init__(msg) -FRI_VERSION = None -try: - from fri_config import FRI_VERSION -except ImportError: - pass - -if FRI_VERSION is None: - STARTC = "\033[91m" - ENDC = "\033[0m" +FRI_CLIENT_VERSION = os.environ.get("FRI_CLIENT_VERSION") +if FRI_CLIENT_VERSION is None: raise UserInputRequired( - "\n\n" - + STARTC - + ">> FRI_VERSION not set in fri_config.py, refer to the Install section in README.md. <<" - + ENDC - + "\n" + "Please set the environment variable FRI_CLIENT_VERSION to the version of the FRI Client SDK you are using." ) # Convert distutils Windows platform specifiers to CMake -A arguments @@ -134,10 +124,10 @@ def build_extension(self, ext: CMakeExtension) -> None: build_args += [f"-j{self.parallel}"] # Set the FRI version number - fri_ver_major = FRI_VERSION.split(".")[0] - fri_ver_minor = FRI_VERSION.split(".")[1] - cmake_args += [f"-DFRI_VERSION_MAJOR={fri_ver_major}"] - cmake_args += [f"-DFRI_VERSION_MINOR={fri_ver_minor}"] + fri_ver_major = FRI_CLIENT_VERSION.split(".")[0] + fri_ver_minor = FRI_CLIENT_VERSION.split(".")[1] + cmake_args += [f"-DFRI_CLIENT_VERSION_MAJOR={fri_ver_major}"] + cmake_args += [f"-DFRI_CLIENT_VERSION_MINOR={fri_ver_minor}"] build_temp = Path(self.build_temp) / ext.name if not build_temp.exists():