diff --git a/source/armarx/control/deprecated_njoint_mp_controller/task_space/NJointTaskSpaceImpedanceDMPController.cpp b/source/armarx/control/deprecated_njoint_mp_controller/task_space/NJointTaskSpaceImpedanceDMPController.cpp index 0eab5983c6b6c440d426f3b9e1bf5a2dfe2fcd32..86742d217dfcc1bd7bdb56c132da65bfda178394 100644 --- a/source/armarx/control/deprecated_njoint_mp_controller/task_space/NJointTaskSpaceImpedanceDMPController.cpp +++ b/source/armarx/control/deprecated_njoint_mp_controller/task_space/NJointTaskSpaceImpedanceDMPController.cpp @@ -1,21 +1,21 @@ // Simox -#include <VirtualRobot/Robot.h> #include <VirtualRobot/IK/DifferentialIK.h> +#include <VirtualRobot/Robot.h> // ArmarXCore -#include <ArmarXCore/core/time/CycleUtil.h> #include <ArmarXCore/core/ArmarXObjectScheduler.h> +#include <ArmarXCore/core/time/CycleUtil.h> // RobotAPI -#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h> #include <RobotAPI/components/units/RobotUnit/ControlTargets/ControlTarget1DoFActuator.h> #include <RobotAPI/components/units/RobotUnit/NJointControllers/NJointController.h> +#include <RobotAPI/components/units/RobotUnit/SensorValues/SensorValueForceTorque.h> // control -#include <armarx/control/deprecated_njoint_mp_controller/task_space/TaskSpaceImpedanceDMPControllerInterface.h> #include <armarx/control/deprecated_njoint_mp_controller/TaskSpaceVMP.h> -#include "NJointTaskSpaceImpedanceDMPController.h" +#include <armarx/control/deprecated_njoint_mp_controller/task_space/TaskSpaceImpedanceDMPControllerInterface.h> +#include "NJointTaskSpaceImpedanceDMPController.h" namespace armarx::control::deprecated_njoint_mp_controller::task_space { @@ -94,7 +94,8 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space taskSpaceDMPConfig.phaseStopParas.maxValue = cfg->phaseL; taskSpaceDMPConfig.phaseStopParas.slop = cfg->phaseK; - dmpCtrl.reset(new tsvmp::TaskSpaceDMPController("DMPController", taskSpaceDMPConfig, false)); + dmpCtrl.reset( + new tsvmp::TaskSpaceDMPController("DMPController", taskSpaceDMPConfig, false)); finished = false; useNullSpaceJointDMP = cfg->useNullSpaceJointDMP; @@ -158,7 +159,6 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space return "NJointTaskSpaceImpedanceDMPController"; } - void NJointTaskSpaceImpedanceDMPController::rtPreActivateController() { @@ -171,7 +171,6 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space reinitTripleBuffer(initData); } - void NJointTaskSpaceImpedanceDMPController::controllerRun() { @@ -496,7 +495,6 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space debugOutputData.commitWrite(); } - void NJointTaskSpaceImpedanceDMPController::learnDMPFromFiles(const Ice::StringSeq& fileNames, const Ice::Current&) @@ -558,7 +556,6 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space isNullSpaceJointDMPLearned = true; } - void NJointTaskSpaceImpedanceDMPController::resetDMP(const Ice::Current&) { @@ -589,7 +586,6 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space useNullSpaceJointDMP = enable; } - void NJointTaskSpaceImpedanceDMPController::runDMPWithTime(const Ice::DoubleSeq& goals, Ice::Double timeDuration, @@ -611,7 +607,7 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space while (firstRun || timeForCalibration < cfg->waitTimeForCalibration) { - if(prematurely_stopped.load()) + if (prematurely_stopped.load()) { ARMARX_WARNING << "StopDMP has been prematurely called; aborting runDMP"; return; @@ -634,7 +630,7 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space ARMARX_INFO << "Using Null Space Joint DMP"; } - if(prematurely_stopped.load()) + if (prematurely_stopped.load()) { ARMARX_WARNING << "StopDMP has been prematurely called; aborting runDMP"; return; @@ -645,7 +641,6 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space // controllerTask->start(); } - void NJointTaskSpaceImpedanceDMPController::onPublish(const SensorAndControl&, const DebugDrawerInterfacePrx&, @@ -861,7 +856,7 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space NJointTaskSpaceImpedanceDMPController::setNullspaceVelocityKd(const Eigen::VectorXf& kd, const Ice::Current&) { - ARMARX_CHECK_EQUAL(kd.size(), targets.size()); + ARMARX_CHECK_EQUAL(kd.size(), static_cast<long>(targets.size())); ARMARX_INFO << "set nullspace kd " << VAROUT(kd); LockGuardType guard(controllerMutex); ctrlParams.getWriteBuffer().dnull = kd; @@ -872,28 +867,28 @@ namespace armarx::control::deprecated_njoint_mp_controller::task_space NJointTaskSpaceImpedanceDMPController::setNullspaceVelocityKp(const Eigen::VectorXf& kp, const Ice::Current&) { - ARMARX_CHECK_EQUAL(kp.size(), targets.size()); + ARMARX_CHECK_EQUAL(kp.size(), static_cast<long>(targets.size())); ARMARX_INFO << "set linear kp " << VAROUT(kp); LockGuardType guard(controllerMutex); ctrlParams.getWriteBuffer().knull = kp; ctrlParams.commitWrite(); } - void NJointTaskSpaceImpedanceDMPController::setDefaultNullSpaceJointValues( const Eigen::VectorXf& jointValues, const Ice::Current&) { - ARMARX_CHECK_EQUAL(jointValues.size(), targets.size()); + ARMARX_CHECK_EQUAL(jointValues.size(), static_cast<long>(targets.size())); defaultNullSpaceJointValues.getWriteBuffer() = jointValues; defaultNullSpaceJointValues.commitWrite(); } - Ice::Double NJointTaskSpaceImpedanceDMPController::getVirtualTime(const Ice::Current&) + Ice::Double + NJointTaskSpaceImpedanceDMPController::getVirtualTime(const Ice::Current&) { return dmpCtrl->canVal; } -} // namespace armarx::ctrl::njoint_ctrl::dmp +} // namespace armarx::control::deprecated_njoint_mp_controller::task_space diff --git a/source/armarx/control/ethercat/CMakeLists.txt b/source/armarx/control/ethercat/CMakeLists.txt index 5924ad1d7dbdc873d6fcedfde5fc53180687c096..8d317d24459f0f851f905431415d91263a0b657d 100644 --- a/source/armarx/control/ethercat/CMakeLists.txt +++ b/source/armarx/control/ethercat/CMakeLists.txt @@ -2,6 +2,8 @@ armarx_add_library(ethercat SOURCES Bus.cpp DataInterface.cpp + LinearConvertedValue.cpp + ModularConvertedValue.cpp DeviceInterface.cpp RTUnit.cpp SlaveIdentifier.cpp @@ -24,6 +26,8 @@ armarx_add_library(ethercat HEADERS Bus.h DataInterface.h + LinearConvertedValue.h + ModularConvertedValue.h DeviceInterface.h RTUnit.h SlaveIdentifier.h diff --git a/source/armarx/control/ethercat/DataInterface.h b/source/armarx/control/ethercat/DataInterface.h index 5162a0de76cc8fc9829889174dc3bc7c33bd50c8..6502324221dbd02f9c7ca93752e6a4d4e231eee2 100644 --- a/source/armarx/control/ethercat/DataInterface.h +++ b/source/armarx/control/ethercat/DataInterface.h @@ -28,6 +28,7 @@ #include <cmath> #include <memory> #include <type_traits> + #include <SimoxUtility/math/periodic/periodic_clamp.h> #include <ArmarXCore/core/rapidxml/wrapper/DefaultRapidXmlReader.h> @@ -38,258 +39,12 @@ #include <armarx/control/hardware_config/Types.h> +#include "LinearConvertedValue.h" +#include "ModularConvertedValue.h" namespace armarx::control::ethercat { - /** - * @class LinearConvertedValue - * @ingroup Library-ethercat - * @brief Brief description of class LinearConvertedValue. - * - * Detailed description of class LinearConvertedValue. - */ - template <typename T> - class LinearConvertedValue - { - - public: - LinearConvertedValue() - { - raw = nullptr; - offset = factor = 0; - offsetBeforeFactor = true; - } - - /** - * @brief init - * @param raw - * @param node - * @param defaultValue - * @param offsetBeforeFactor if true the offset is added before multiplying with factor. If false: the other way around. - * @param nameForDebugging This name is printend in case an error is encountered (Its only purpose is to ease debugging) - */ - void - init(T* raw, - const hardware_config::types::LinearConfig linearConfig, - float defaultValue = std::nanf("1"), - bool offsetBeforeFactor = true, - const char* nameForDebugging = "") - { - init(raw, - linearConfig.getFactor(), - linearConfig.getOffset(), - defaultValue, - offsetBeforeFactor, - nameForDebugging); - } - - void - init(T* raw, - float factor, - float offset, - float defaultValue = std::nanf("1"), - bool offsetBeforeFactor = true, - const char* nameForDebugging = "") - { - const auto rawAsInt = reinterpret_cast<std::uint64_t>(raw); - ARMARX_CHECK_EXPRESSION((rawAsInt % alignof(T)) == 0) - << "\nThe alignment is wrong!\nIt has to be " << alignof(T) - << ", but the data is aligned with " << rawAsInt % alignof(std::max_align_t) - << "!\nThis is an offset of " << (rawAsInt % alignof(T)) - << " bytes!\nThe datatype is " << GetTypeString<T>() << "\nIts size is " - << sizeof(T) << "\nraw = " << raw << " bytes\nThe name is " << nameForDebugging; - this->offsetBeforeFactor = offsetBeforeFactor; - this->factor = factor; - this->offset = offset; - this->raw = raw; - if (!std::isnan(defaultValue)) - { - value = defaultValue; - write(); - } - else - { - value = 0; - read(); - } - } - - void - read() - { - if (offsetBeforeFactor) - { - value = ((*raw) + offset) * factor; - } - else - { - value = (*raw) * factor + offset; - } - } - - void - write() - { - if (offsetBeforeFactor) - { - *raw = static_cast<T>((value / factor) - offset); - } - else - { - *raw = static_cast<T>((value)-offset) / factor; - } - } - - float value; - - T - getRaw() const - { - return *raw; - } - - float - getFactor() const - { - return factor; - } - - float - getOffset() const - { - return offset; - } - - bool - getOffsetBeforeFactor() const - { - return offsetBeforeFactor; - } - - private: - T* raw; - float offset, factor; - bool offsetBeforeFactor; - }; - - - template <typename T, typename SignedT = T> - class ModularConvertedValue - { - - public: - ModularConvertedValue() - { - rawValue = nullptr; - zeroOffset = 0; - discontinuityOffset = 0; - maxValue = 0; - factor = 0; - isInverted = false; - } - - void - init(T* raw, - const hardware_config::types::ModularConvertedValueConfig modularConfig, - const char* nameForDebugging = "") - { - init(raw, - modularConfig.getZeroOffset(), - modularConfig.getDiscontinuityOffset(), - modularConfig.getMaxValue(), - modularConfig.getIsInverted(), - nameForDebugging); - } - - void - init(T* raw, - float zeroOffset, - float discontinuityOffset, - float maxValue, - bool isInverted, - const char* nameForDebugging = "") - { - const auto rawAsInt = reinterpret_cast<std::uint64_t>(raw); - ARMARX_CHECK_EQUAL((rawAsInt % alignof(T)), 0) - << "\nThe alignment is wrong!" - << "\nIt has to be " << alignof(T) << ", but the data is aligned with " - << rawAsInt % alignof(std::max_align_t) << "!" - << "\nThis is an offset of " << (rawAsInt % alignof(T)) << " bytes!" - << "\nThe datatype is " << GetTypeString<T>() << "\nIts size is " << sizeof(T) - << "\nraw = " << raw << " bytes" - << "\nThe name is '" << nameForDebugging << "'"; - - this->rawValue = raw; - this->zeroOffset = static_cast<SignedT>(zeroOffset); - this->discontinuityOffset = static_cast<SignedT>(discontinuityOffset); - this->maxValue = static_cast<T>(maxValue); - this->factor = 2 * M_PIf64 / maxValue; - this->isInverted = isInverted; - - ARMARX_CHECK_POSITIVE(maxValue) - << "max value must not be zero (cannot divide/modulo by 0)."; - - read(); - } - - void - read() - { - // "%" operator is not the real mathematical modulo operation but some creative ISO - // reinterpretation. This fixes it. - auto actual_real_modulo = [](SignedT dividend, SignedT divisor) -> SignedT - { - const SignedT result = dividend % divisor; - return result >= 0 ? result : result + divisor; - }; - - const SignedT rawValueSigned = static_cast<SignedT>(*rawValue); - const SignedT maxValueSigned = static_cast<SignedT>(maxValue); - - // Normalize direction of rotation. - const SignedT sign = isInverted ? -1 : 1; - const SignedT dirnorm = actual_real_modulo((sign * rawValueSigned), maxValueSigned); - - // Raw values within monotonic_raw_value are guaranteed to not fall into a - // discontinuity. - const SignedT monotonic_dirnorm = - actual_real_modulo((dirnorm + discontinuityOffset), maxValueSigned); - - // Zero shift. - const SignedT zeroshift_monotonic_dirnorm = monotonic_dirnorm - zeroOffset; - - // Convert ticks to rad. - const double zeroshift_monotonic_dirnorm_rad = - static_cast<double>(zeroshift_monotonic_dirnorm) * factor; - - value = zeroshift_monotonic_dirnorm_rad; - } - - void - write() - { - //*rawValue = static_cast<T>((value / factor) - offset); - } - - double value; - - T - getRaw() const - { - return *rawValue; - } - - private: - T* rawValue; - SignedT zeroOffset; - SignedT discontinuityOffset; - T maxValue; - double factor; - bool isInverted; - }; - - /** * @class DataInterface * @ingroup Library-ethercat diff --git a/source/armarx/control/ethercat/ErrorReporting.cpp b/source/armarx/control/ethercat/ErrorReporting.cpp index 32bb68b32d784fb37e8e9d29773cb99297c5c885..63f348c7d54f6c0007053a389ac07a68cbc52379 100644 --- a/source/armarx/control/ethercat/ErrorReporting.cpp +++ b/source/armarx/control/ethercat/ErrorReporting.cpp @@ -48,7 +48,6 @@ namespace armarx::control::ethercat::error return stream; } - struct Reporting::QueueImpl { static constexpr size_t queueSize = 20; diff --git a/source/armarx/control/ethercat/LinearConvertedValue.cpp b/source/armarx/control/ethercat/LinearConvertedValue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4319279e0338a61cce595f189fa5adda4206c484 --- /dev/null +++ b/source/armarx/control/ethercat/LinearConvertedValue.cpp @@ -0,0 +1,7 @@ +#include "LinearConvertedValue.h" + +namespace armarx::control::ethercat +{ + + +} // namespace armarx::control::ethercat diff --git a/source/armarx/control/ethercat/LinearConvertedValue.h b/source/armarx/control/ethercat/LinearConvertedValue.h new file mode 100644 index 0000000000000000000000000000000000000000..9744ba828e0a6efc1c5081451e0e65f8b8ebfd96 --- /dev/null +++ b/source/armarx/control/ethercat/LinearConvertedValue.h @@ -0,0 +1,168 @@ +/* + * This file is part of ArmarX. + * + * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), + * Karlsruhe Institute of Technology (KIT), all rights reserved. + * + * 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/>. + * + * @author Simon Ottenhaus (simon dot ottenhaus at kit dot edu) + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#pragma once + + +#include <cmath> + +#include <armarx/control/hardware_config/Types.h> + +namespace armarx::control::ethercat +{ + + /** + * @class LinearConvertedValue + * @ingroup Library-ethercat + * @brief Brief description of class LinearConvertedValue. + * + * Detailed description of class LinearConvertedValue. + */ + template <typename T> + class LinearConvertedValue + { + + public: + LinearConvertedValue() + { + raw = nullptr; + offset = factor = 0; + offsetBeforeFactor = true; + } + + /** + * @brief init + * @param raw + * @param node + * @param defaultValue + * @param offsetBeforeFactor if true the offset is added before multiplying with factor. If false: the other way around. + * @param nameForDebugging This name is printend in case an error is encountered (Its only purpose is to ease debugging) + */ + void + init(T* raw, + const hardware_config::types::LinearConfig linearConfig, + float defaultValue = std::nanf("1"), + bool offsetBeforeFactor = true, + const char* nameForDebugging = "") + { + init(raw, + linearConfig.getFactor(), + linearConfig.getOffset(), + defaultValue, + offsetBeforeFactor, + nameForDebugging); + } + + void + init(T* raw, + float factor, + float offset, + float defaultValue = std::nanf("1"), + bool offsetBeforeFactor = true, + const char* nameForDebugging = "") + { +#if 0 + const auto rawAsInt = reinterpret_cast<std::uint64_t>(raw); + ARMARX_CHECK_EQUAL((rawAsInt % alignof(T)), 0) + << "\nThe alignment is wrong!\nIt has to be " << alignof(T) + << ", but the data is aligned with " << rawAsInt % alignof(std::max_align_t) + << "!\nThis is an offset of " << (rawAsInt % alignof(T)) + << " bytes!\nThe datatype is " << GetTypeString<T>() << "\nIts size is " + << sizeof(T) << "\nraw = " << raw << " bytes\nThe name is " << nameForDebugging; +#endif + this->offsetBeforeFactor = offsetBeforeFactor; + this->factor = factor; + this->offset = offset; + this->raw = raw; + if (!std::isnan(defaultValue)) + { + value = defaultValue; + write(); + } + else + { + value = 0; + read(); + } + } + + void + read() + { + if (offsetBeforeFactor) + { + value = ((*raw) + offset) * factor; + } + else + { + value = (*raw) * factor + offset; + } + } + + void + write() + { + if (offsetBeforeFactor) + { + *raw = static_cast<T>((value / factor) - offset); + } + else + { + *raw = static_cast<T>((value)-offset) / factor; + } + } + + float value; + + T + getRaw() const + { + return *raw; + } + + float + getFactor() const + { + return factor; + } + + float + getOffset() const + { + return offset; + } + + bool + getOffsetBeforeFactor() const + { + return offsetBeforeFactor; + } + + private: + T* raw; + float offset, factor; + bool offsetBeforeFactor; + }; + +} // namespace armarx::control::ethercat diff --git a/source/armarx/control/ethercat/ModularConvertedValue.cpp b/source/armarx/control/ethercat/ModularConvertedValue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ac2b1e74be885a4ffc94478afc2c3aa4a09f713 --- /dev/null +++ b/source/armarx/control/ethercat/ModularConvertedValue.cpp @@ -0,0 +1,6 @@ +#include "ModularConvertedValue.h" + +namespace armarx::control::ethercat +{ + +} // namespace armarx::control::ethercat diff --git a/source/armarx/control/ethercat/ModularConvertedValue.h b/source/armarx/control/ethercat/ModularConvertedValue.h new file mode 100644 index 0000000000000000000000000000000000000000..20784860e515c71edc0d33b94cb1bc9eea7c3784 --- /dev/null +++ b/source/armarx/control/ethercat/ModularConvertedValue.h @@ -0,0 +1,172 @@ +/* + * This file is part of ArmarX. + * + * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), + * Karlsruhe Institute of Technology (KIT), all rights reserved. + * + * 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/>. + * + * @author Simon Ottenhaus (simon dot ottenhaus at kit dot edu) + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + + +#pragma once + + +#include <cmath> +#include <limits> +#include <type_traits> + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <armarx/control/hardware_config/Types.h> + +namespace armarx::control::ethercat +{ + + template <typename T, typename SignedT = std::int64_t> + class ModularConvertedValue + { + + public: + ModularConvertedValue() + { + rawValue = nullptr; + zeroOffset = 0; + discontinuityOffset = 0; + maxValue = 0; + factor = 0; + isInverted = false; + + static_assert(std::is_signed_v<SignedT>); + + if constexpr(std::is_unsigned_v<T>) + { + static_assert(sizeof(SignedT) > sizeof(T)); + } + + if constexpr(std::is_signed_v<T>) + { + static_assert(sizeof(SignedT) >= sizeof(T)); + } + } + + void + init(T* raw, + const hardware_config::types::ModularConvertedValueConfig modularConfig, + const char* nameForDebugging = "") + { + init(raw, + modularConfig.getZeroOffset(), + modularConfig.getDiscontinuityOffset(), + modularConfig.getMaxValue(), + modularConfig.getIsInverted(), + nameForDebugging); + } + + void + init(T* raw, + float zeroOffset, + float discontinuityOffset, + float maxValue, + bool isInverted, + const char* nameForDebugging = "") + { +#if 0 + const auto rawAsInt = reinterpret_cast<std::uint64_t>(raw); + ARMARX_CHECK_EQUAL((rawAsInt % alignof(T)), 0) + << "\nThe alignment is wrong!" + << "\nIt has to be " << alignof(T) << ", but the data is aligned with " + << rawAsInt % alignof(std::max_align_t) << "!" + << "\nThis is an offset of " << (rawAsInt % alignof(T)) << " bytes!" + << "\nThe datatype is " << GetTypeString<T>() << "\nIts size is " << sizeof(T) + << "\nraw = " << raw << " bytes" + << "\nThe name is '" << nameForDebugging << "'"; +#endif + ARMARX_CHECK_POSITIVE(maxValue) + << "max value must not be zero (cannot divide/modulo by 0)."; + + ARMARX_CHECK_LESS_EQUAL(maxValue, std::numeric_limits<T>::max()) + << "max value is greater than the maximum value of the datatype, " + << "the datatype is " << GetTypeString<T>(); + + this->rawValue = raw; + this->zeroOffset = static_cast<SignedT>(zeroOffset); + this->discontinuityOffset = static_cast<SignedT>(discontinuityOffset); + this->maxValue = static_cast<SignedT>(maxValue); + this->factor = 2 * M_PIf64 / maxValue; + this->isInverted = isInverted; + + read(); + } + + void + read() + { + // "%" operator is not the real mathematical modulo operation but some creative ISO + // reinterpretation. This fixes it. + auto actual_real_modulo = [](SignedT dividend, SignedT divisor) -> SignedT + { + const SignedT result = dividend % divisor; + return result >= 0 ? result : result + divisor; + }; + + const SignedT rawValueSigned = static_cast<SignedT>(*rawValue); + const SignedT maxValueSigned = static_cast<SignedT>(maxValue); + + + // Normalize direction of rotation. + const SignedT sign = isInverted ? -1 : 1; + const SignedT dirnorm = actual_real_modulo((sign * rawValueSigned), maxValueSigned); + + // Raw values within monotonic_raw_value are guaranteed to not fall into a + // discontinuity. + const SignedT monotonic_dirnorm = + actual_real_modulo((dirnorm + discontinuityOffset), maxValueSigned); + + // Zero shift. + const SignedT zeroshift_monotonic_dirnorm = monotonic_dirnorm - zeroOffset; + + // Convert ticks to rad. + const double zeroshift_monotonic_dirnorm_rad = + static_cast<double>(zeroshift_monotonic_dirnorm) * factor; + + value = zeroshift_monotonic_dirnorm_rad; + } + + void + write() + { + //*rawValue = static_cast<T>((value / factor) - offset); + } + + double value; + + T + getRaw() const + { + return *rawValue; + } + + private: + T* rawValue; + SignedT zeroOffset; + SignedT discontinuityOffset; + T maxValue; + double factor; + bool isInverted; + }; + +} // namespace armarx::control::ethercat