ModularConvertedValue.h
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T),
5 * Karlsruhe Institute of Technology (KIT), all rights reserved.
6 *
7 * ArmarX is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * ArmarX is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * @author Simon Ottenhaus (simon dot ottenhaus at kit dot edu)
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24
25#pragma once
26
27
28#include <cmath>
29#include <cstdint>
30#include <limits>
31#include <type_traits>
32
34
36
38{
39
40 template <typename T, typename SignedT = std::int64_t>
42 {
43
44 public:
46 {
47 rawValue = nullptr;
48 zeroOffset = 0;
49 discontinuityOffset = 0;
50 maxValue = 0;
51 factor = 0;
52 isInverted = false;
53
54 static_assert(std::is_signed_v<SignedT>);
55
56 if constexpr (std::is_unsigned_v<T>)
57 {
58 static_assert(sizeof(SignedT) > sizeof(T));
59 }
60
61 if constexpr (std::is_signed_v<T>)
62 {
63 static_assert(sizeof(SignedT) >= sizeof(T));
64 }
65 }
66
67 void
68 init(T* raw,
70 const char* nameForDebugging = "")
71 {
72 init(raw,
73 modularConfig.getZeroOffset(),
74 modularConfig.getDiscontinuityOffset(),
75 modularConfig.getMaxValue(),
76 modularConfig.getIsInverted(),
77 nameForDebugging);
78 }
79
80 void
81 init(T* raw,
82 float zeroOffset,
83 float discontinuityOffset,
84 float maxValue,
85 bool isInverted,
86 const char* nameForDebugging = "")
87 {
88#if 0
89 const auto rawAsInt = reinterpret_cast<std::uint64_t>(raw);
90 ARMARX_CHECK_EQUAL((rawAsInt % alignof(T)), 0)
91 << "\nThe alignment is wrong!"
92 << "\nIt has to be " << alignof(T) << ", but the data is aligned with "
93 << rawAsInt % alignof(std::max_align_t) << "!"
94 << "\nThis is an offset of " << (rawAsInt % alignof(T)) << " bytes!"
95 << "\nThe datatype is " << GetTypeString<T>() << "\nIts size is " << sizeof(T)
96 << "\nraw = " << raw << " bytes"
97 << "\nThe name is '" << nameForDebugging << "'";
98#endif
99 ARMARX_CHECK_POSITIVE(maxValue)
100 << "max value must not be zero (cannot divide/modulo by 0).";
101
102 ARMARX_CHECK_LESS_EQUAL(maxValue, std::numeric_limits<T>::max())
103 << "max value is greater than the maximum value of the datatype, "
104 << "the datatype is " << GetTypeString<T>();
105
106 this->rawValue = raw;
107 this->zeroOffset = static_cast<SignedT>(zeroOffset);
108 this->discontinuityOffset = static_cast<SignedT>(discontinuityOffset);
109 this->maxValue = static_cast<SignedT>(maxValue);
110 this->factor = 2 * M_PIf64 / maxValue;
111 this->isInverted = isInverted;
112
113 read();
114 }
115
116 void
118 {
119 // "%" operator is not the real mathematical modulo operation but some creative ISO
120 // reinterpretation. This fixes it.
121 auto actual_real_modulo = [](SignedT dividend, SignedT divisor) -> SignedT
122 {
123 const SignedT result = dividend % divisor;
124 return result >= 0 ? result : result + divisor;
125 };
126
127 const SignedT rawValueSigned = static_cast<SignedT>(*rawValue);
128 const SignedT maxValueSigned = static_cast<SignedT>(maxValue);
129
130
131 // Normalize direction of rotation.
132 const SignedT sign = isInverted ? -1 : 1;
133 const SignedT dirnorm = actual_real_modulo((sign * rawValueSigned), maxValueSigned);
134
135 // Raw values within monotonic_raw_value are guaranteed to not fall into a
136 // discontinuity.
137 const SignedT monotonic_dirnorm =
138 actual_real_modulo((dirnorm + discontinuityOffset), maxValueSigned);
139
140 // Zero shift.
141 const SignedT zeroshift_monotonic_dirnorm = monotonic_dirnorm - zeroOffset;
142
143 // Convert ticks to rad.
144 const double zeroshift_monotonic_dirnorm_rad =
145 static_cast<double>(zeroshift_monotonic_dirnorm) * factor;
146
147 value = zeroshift_monotonic_dirnorm_rad;
148 }
149
150 void
152 {
153 //*rawValue = static_cast<T>((value / factor) - offset);
154 }
155
156 double value;
157
158 T
159 getRaw() const
160 {
161 return *rawValue;
162 }
163
164 inline void
165 setDiscontinuityOffset(SignedT discontinuityOffset)
166 {
167 this->discontinuityOffset = discontinuityOffset;
168 }
169
170 inline void
171 setZeroOffset(SignedT zeroOffset)
172 {
173 this->zeroOffset = zeroOffset;
174 }
175
176 private:
177 T* rawValue;
178 SignedT zeroOffset;
179 SignedT discontinuityOffset;
180 T maxValue;
181 double factor;
182 bool isInverted;
183 };
184
185} // namespace armarx::control::ethercat
void init(T *raw, float zeroOffset, float discontinuityOffset, float maxValue, bool isInverted, const char *nameForDebugging="")
void init(T *raw, const hardware_config::types::ModularConvertedValueConfig modularConfig, const char *nameForDebugging="")
void setDiscontinuityOffset(SignedT discontinuityOffset)
#define ARMARX_CHECK_POSITIVE(number)
This macro evaluates whether number is positive (> 0) and if it turns out to be false it will throw a...
#define ARMARX_CHECK_LESS_EQUAL(lhs, rhs)
This macro evaluates whether lhs is less or equal (<=) rhs and if it turns out to be false it will th...
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
std::string GetTypeString(const std::type_info &tinf, bool withoutNamespaceSpecifier=false)
T sign(T t)
Definition algorithm.h:214