diff --git a/source/RobotAPI/applications/CMakeLists.txt b/source/RobotAPI/applications/CMakeLists.txt index 53e7a0b568e114e77a255be8274e0cd3dc7d227c..e98d4a57647f581f282f0b6447169c6911343abf 100644 --- a/source/RobotAPI/applications/CMakeLists.txt +++ b/source/RobotAPI/applications/CMakeLists.txt @@ -46,3 +46,5 @@ add_subdirectory(RobotHealthDummy) add_subdirectory(GraspCandidateObserver) add_subdirectory(FrameTracking) + +add_subdirectory(KITHandUnit) \ No newline at end of file diff --git a/source/RobotAPI/applications/KITHandUnit/CMakeLists.txt b/source/RobotAPI/applications/KITHandUnit/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7dd589b24ff8824005237c57a281ef5868b889d --- /dev/null +++ b/source/RobotAPI/applications/KITHandUnit/CMakeLists.txt @@ -0,0 +1,11 @@ +armarx_component_set_name("KITHandUnitApp") +set(COMPONENT_LIBS KITHandUnit) +armarx_add_component_executable(main.cpp) + +#find_package(MyLib QUIET) +#armarx_build_if(MyLib_FOUND "MyLib not available") +# all target_include_directories must be guarded by if(Xyz_FOUND) +# for multiple libraries write: if(X_FOUND AND Y_FOUND).... +#if(MyLib_FOUND) +# target_include_directories(KITHandUnit PUBLIC ${MyLib_INCLUDE_DIRS}) +#endif() diff --git a/source/RobotAPI/applications/KITHandUnit/main.cpp b/source/RobotAPI/applications/KITHandUnit/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9dcea70a7cc5d94cbc8e19649306734ae411252 --- /dev/null +++ b/source/RobotAPI/applications/KITHandUnit/main.cpp @@ -0,0 +1,32 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::application::KITHandUnit + * @author Stefan Reither ( stefan dot reither at kit dot edu ) + * @date 2019 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include <RobotAPI/components/KITHandUnit/KITHandUnit.h> + +#include <ArmarXCore/core/application/Application.h> +#include <ArmarXCore/core/Component.h> +#include <ArmarXCore/core/logging/Logging.h> + +int main(int argc, char* argv[]) +{ + return armarx::runSimpleComponentApp < armarx::KITHandUnit > (argc, argv, "KITHandUnit"); +} diff --git a/source/RobotAPI/components/CMakeLists.txt b/source/RobotAPI/components/CMakeLists.txt index 7bec9c6c9fd32508e487c43cc3ef2a983f2e6152..9157c99873b7abfc44defe843a7264f68904acac 100644 --- a/source/RobotAPI/components/CMakeLists.txt +++ b/source/RobotAPI/components/CMakeLists.txt @@ -10,3 +10,5 @@ add_subdirectory(KITProstheticHandUnit) add_subdirectory(CyberGloveObserver) add_subdirectory(RobotHealth) add_subdirectory(FrameTracking) + +add_subdirectory(KITHandUnit) \ No newline at end of file diff --git a/source/RobotAPI/components/KITHandUnit/CMakeLists.txt b/source/RobotAPI/components/KITHandUnit/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..569fabf81e568580066228074781b7fcdd6ffeeb --- /dev/null +++ b/source/RobotAPI/components/KITHandUnit/CMakeLists.txt @@ -0,0 +1,26 @@ +armarx_component_set_name("KITHandUnit") + +find_package(KITHand REQUIRED) +armarx_build_if(KITHand_FOUND "KITHand stand-alone lib not available") + +set(COMPONENT_LIBS + ArmarXCore + ArmarXCoreInterfaces + RobotAPIUnits + KITHandCommunicationDriver +) + +set(SOURCES + ./KITHandUnit.cpp +#@TEMPLATE_LINE@@COMPONENT_PATH@/@COMPONENT_NAME@.cpp +) +set(HEADERS + ./KITHandUnit.h +#@TEMPLATE_LINE@@COMPONENT_PATH@/@COMPONENT_NAME@.h +) + + +armarx_add_component("${SOURCES}" "${HEADERS}") + +# add unit tests +add_subdirectory(test) diff --git a/source/RobotAPI/components/KITHandUnit/KITHandUnit.cpp b/source/RobotAPI/components/KITHandUnit/KITHandUnit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d54559b72c1ea34aa2d8323cdc97d30dae939b0 --- /dev/null +++ b/source/RobotAPI/components/KITHandUnit/KITHandUnit.cpp @@ -0,0 +1,187 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::KITHandUnit + * @author Stefan Reither ( stefan dot reither at kit dot edu ) + * @date 2019 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include "KITHandUnit.h" +#include <ArmarXCore/core/ArmarXManager.h> + +using namespace KITHand; + +namespace armarx +{ + KITHandUnitPropertyDefinitions::KITHandUnitPropertyDefinitions(std::string prefix) : + armarx::HandUnitPropertyDefinitions(prefix) + { + defineOptionalProperty<KITHandCommunicationDriver::ScanMode>("ConnectionType", KITHandCommunicationDriver::ScanMode::Bluetooth, "Type of the connection to the hand, either Bluetooth or Serial") + .map("Bluetooth", KITHandCommunicationDriver::ScanMode::Bluetooth) + .map("Serial", KITHandCommunicationDriver::ScanMode::Serial); + defineRequiredProperty<std::string>("MAC-Address", "MAC-Address of the hand to connect to."); + defineOptionalProperty<bool>("AutomaticReconnectActive", false, "Whether the hand unit should try to reconnect after the connection is lost."); + defineOptionalProperty<bool>("ScanUntilHandFound", true, "Wheather to keep scanning until the hand with the given MAC-Address is found."); + defineOptionalProperty<int>("ScanTimeout", 5, "Timeout for scanning repeatedly."); + } + + + std::string KITHandUnit::getDefaultName() const + { + return "KITHandUnit"; + } + + void KITHandUnit::onInitHandUnit() + { + //addShapeName("Open"); //is added by something else already + addShapeName("Close"); + addShapeName("G0"); + addShapeName("G1"); + addShapeName("G2"); + addShapeName("G3"); + addShapeName("G4"); + addShapeName("G5"); + addShapeName("G6"); + addShapeName("G7"); + addShapeName("G8"); + +// KITHand::INIT_LOG + _driver = std::make_unique<KITHandCommunicationDriver>(); + _driver->registerConnectionStateChangedCallback(std::bind(&KITHandUnit::connectionStateChangedCallback, this, std::placeholders::_1)); + } + + void KITHandUnit::onStartHandUnit() + { + std::string macAddress = getProperty<std::string>("MAC-Address"); + KITHandCommunicationDriver::ScanMode mode = getProperty<KITHandCommunicationDriver::ScanMode>("ConnectionType").getValue(); + bool found = false; + auto start = std::chrono::system_clock::now(); + do { + std::vector<HandDevice> devices = _driver->scanForDevices(mode); + for (HandDevice& d : devices) + { + ARMARX_INFO << "Found device with MAC-Address: " << d.macAdress; + if (d.macAdress == macAddress) + { + d.hardwareTarget = mode == KITHandCommunicationDriver::ScanMode::Bluetooth ? KITHand::HardwareTarget::Bluetooth : KITHand::HardwareTarget::Serial; + _driver->connect(d); + while (!_driver->connected()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + return; + } + } + } + while (getProperty<bool>("ScanUntilHandFound").getValue() + && !found + && std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - start).count() < getProperty<int>("ScanTimeout").getValue()); + + ARMARX_WARNING << "Could not find hand with the given MAC-Address: " << macAddress << " Shutting down this KITHandUnit."; + getArmarXManager()->asyncShutdown(); + } + + void KITHandUnit::onExitHandUnit() + { + ARMARX_IMPORTANT << "Calling driver disconnect"; + _driver->disconnect(); + _driver.reset(); + } + + void KITHandUnit::setShape(const std::string &shapeName, const Ice::Current &) + { + if (std::regex_match(shapeName, std::regex{"[gG](0|[1-9][0-9]*)"}) && _driver->getCurrentConnectedDevice()->abilities.receivesAdditionalGraspCommands) + { + _driver->sendGrasp(std::stoul(shapeName.substr(1))); + } + else if (shapeName == "Open") + { + _driver->sendGrasp(0); + } + else if (shapeName == "Close") + { + _driver->sendGrasp(1); + } + else if (!_shapes.count(shapeName)) + { + ARMARX_WARNING << "Unknown shape name '" << shapeName + << "'\nKnown shapes: " << _shapes; + } + else + { + setJointAngles(_shapes.at(shapeName)); + } + } + + void KITHandUnit::setJointAngles(const NameValueMap &targetJointAngles, const Ice::Current &) + { + ARMARX_CHECK_NOT_NULL(_driver); + + for (const std::pair<std::string, float>& pair : targetJointAngles) + { + if (pair.first == "Fingers") + { + _driver->sendFingersPosition(static_cast<std::uint64_t>(pair.second * KITHand::ControlOptions::maxPosFingers)); + } + else if (pair.first == "Thumb") + { + _driver->sendThumbPosition(static_cast<std::uint64_t>(pair.second * KITHand::ControlOptions::maxPosThumb)); + } + else + { + ARMARX_WARNING << "Invalid HandJointName '" << pair.first << "', ignoring."; + } + } + } + + NameValueMap KITHandUnit::getCurrentJointValues(const Ice::Current &) + { + NameValueMap jointValues; + jointValues["Fingers"] = _driver->getFingersPos() * 1.f / KITHand::ControlOptions::maxPosFingers; + jointValues["Thumb"] = _driver->getThumbPos() * 1.f / KITHand::ControlOptions::maxPosThumb; + return jointValues; + } + + void KITHandUnit::addShape(const std::string& name, const std::map<std::string, float>& shape) + { + _shapes[name] = shape; + addShapeName(name); + } + + void KITHandUnit::addShapeName(const std::string& name) + { + Variant currentPreshape; + currentPreshape.setString(name); + shapeNames->addVariant(currentPreshape); + } + + + armarx::PropertyDefinitionsPtr KITHandUnit::createPropertyDefinitions() + { + return armarx::PropertyDefinitionsPtr(new KITHandUnitPropertyDefinitions( + getConfigIdentifier())); + } + + void KITHandUnit::connectionStateChangedCallback(const State state) + { + if (state == State::DeviceLost) + { + _driver.reset(); + getArmarXManager()->asyncShutdown(); + } + } +} diff --git a/source/RobotAPI/components/KITHandUnit/KITHandUnit.h b/source/RobotAPI/components/KITHandUnit/KITHandUnit.h new file mode 100644 index 0000000000000000000000000000000000000000..d989ab9e3a38ae0b4459c6d89429eecb5d01e092 --- /dev/null +++ b/source/RobotAPI/components/KITHandUnit/KITHandUnit.h @@ -0,0 +1,90 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::KITHandUnit + * @author Stefan Reither ( stefan dot reither at kit dot edu ) + * @date 2019 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <ArmarXCore/core/Component.h> + +#include <ArmarXCore/interface/observers/ObserverInterface.h> + +#include <RobotAPI/components/units/HandUnit.h> + +#include <KITHandCommunicationDriver.h> + +namespace armarx +{ + /** + * @class KITHandUnitPropertyDefinitions + * @brief + */ + class KITHandUnitPropertyDefinitions : + public armarx::HandUnitPropertyDefinitions + { + public: + KITHandUnitPropertyDefinitions(std::string prefix); + }; + + + + /** + * @defgroup Component-KITHandUnit KITHandUnit + * @ingroup RobotAPI-Components + * A description of the component KITHandUnit. + * + * @class KITHandUnit + * @ingroup Component-KITHandUnit + * @brief Brief description of class KITHandUnit. + * + * Detailed description of class KITHandUnit. + */ + class KITHandUnit : + virtual public armarx::HandUnit + { + public: + + /// @see armarx::ManagedIceObject::getDefaultName() + virtual std::string getDefaultName() const override; + + void onInitHandUnit() override; + void onStartHandUnit() override; + void onExitHandUnit() override; + void setShape(const std::string &shapeName, const Ice::Current & = Ice::emptyCurrent) override; + void setJointAngles(const NameValueMap &targetJointAngles, const Ice::Current & = Ice::emptyCurrent) override; + NameValueMap getCurrentJointValues(const Ice::Current& = Ice::emptyCurrent) override; + + void addShape(const std::string& name, const std::map<std::string, float>& shape); + void addShapeName(const std::string& name); + + protected: + + /// @see PropertyUser::createPropertyDefinitions() + virtual armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; + + void connectionStateChangedCallback(const KITHand::State state); + + private: + KITHand::KITHandCommunicationDriverPtr _driver; + + std::map<std::string, std::map<std::string, float>> _shapes; + + }; +} diff --git a/source/RobotAPI/components/KITHandUnit/test/CMakeLists.txt b/source/RobotAPI/components/KITHandUnit/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..39efa64bf38e2ee7ddd2d0aee750e6203cce7a29 --- /dev/null +++ b/source/RobotAPI/components/KITHandUnit/test/CMakeLists.txt @@ -0,0 +1,5 @@ + +# Libs required for the tests +SET(LIBS ${LIBS} ArmarXCore KITHandUnit) + +armarx_add_test(KITHandUnitTest KITHandUnitTest.cpp "${LIBS}") diff --git a/source/RobotAPI/components/KITHandUnit/test/KITHandUnitTest.cpp b/source/RobotAPI/components/KITHandUnit/test/KITHandUnitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4350346ba4141202887160e311aecac65e227d0e --- /dev/null +++ b/source/RobotAPI/components/KITHandUnit/test/KITHandUnitTest.cpp @@ -0,0 +1,37 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package RobotAPI::ArmarXObjects::KITHandUnit + * @author Stefan Reither ( stefan dot reither at kit dot edu ) + * @date 2019 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#define BOOST_TEST_MODULE RobotAPI::ArmarXObjects::KITHandUnit + +#define ARMARX_BOOST_TEST + +#include <RobotAPI/Test.h> +#include <RobotAPI/components/KITHandUnit/KITHandUnit.h> + +#include <iostream> + +BOOST_AUTO_TEST_CASE(testExample) +{ + armarx::KITHandUnit instance; + + BOOST_CHECK_EQUAL(true, true); +}