FTSensor.cpp
Go to the documentation of this file.
1#include "FTSensor.h"
2
3#include <SimoxUtility/json.h>
4#include <SimoxUtility/math/compare/is_equal.h>
5#include <SimoxUtility/math/convert/mat4f_to_pos.h>
6#include <SimoxUtility/math/convert/mat4f_to_quat.h>
7#include <VirtualRobot/MathTools.h>
8#include <VirtualRobot/Nodes/RobotNode.h>
9#include <VirtualRobot/Nodes/Sensor.h>
10#include <VirtualRobot/RobotNodeSet.h>
11
13
16
17#include "../utils.h"
18
20{
21
22 void
23 FTSensor::initialize(const VirtualRobot::RobotNodeSetPtr& rns,
24 const RobotUnitPtr& robotUnit,
25 const FTConfig& c)
26 {
27 ARMARX_INFO << "--> Initializing force torque sensor " << c.sensorName;
28 const SensorValueBase* svlf = robotUnit->getSensorDevice(c.sensorName)->getSensorValue();
29 forceSensor = svlf->asA<SensorValueForceTorque>();
30
32 sensorNode = rns->getRobot()->getSensor(c.sensorName)->getRobotNode();
33
34 if (c.sensorName == "FT R")
35 {
36 tcpMass = calibDefaults.tcpMassRight;
37 tcpCoMInFTSensorFrame = calibDefaults.tcpCoMInFTFrameRight;
38 }
39 else if (c.sensorName == "FT L")
40 {
41 tcpMass = calibDefaults.tcpMassLeft;
42 tcpCoMInFTSensorFrame = calibDefaults.tcpCoMInFTFrameLeft;
43 }
44
45 rawForce.setZero();
46 rawTorque.setZero();
47 filteredForce.setZero();
48 filteredTorque.setZero();
49 filteredForceInRoot.setZero();
50 filteredTorqueInRoot.setZero();
51
52 tcpGravityCompensation.setZero();
53 tcpGravForceVec.setZero();
54 tcpGravTorqueVec.setZero();
55
56 sensorOriInRoot = Eigen::Matrix3f::Identity();
57 reset();
58 ARMARX_INFO << "<-- Force torque sensor initialized.";
59 }
60
61 //FTSensor::FTConfig FTSensor::reconfigure(const std::string &configFileName)
62 //{
63 // nlohmann::json userConfig;
64 // std::ifstream ifs{configFileName};
65 // ifs >> userConfig;
66 // auto c = userConfig["force_torque"];
67 // FTConfig config = FTConfig();
68 // std::string name = getValueWithDefault<std::string>(c, "", "sensor_name");
69 // if (name != sensorName)
70 // {
71 // ARMARX_ERROR << "the sensor name: " << name << " is not the same as initialized: " << sensorName << ", please consider to switch controllers instead of reuse";
72 // }
73 // config.ftFilter = getValueWithDefault<float>(c, s.ftFilter, "force_filter_coeff");
74 // config.deadZoneForce = getValueWithDefault<float>(c, s.deadZoneForce, "force_dead_zone");
75 // config.deadZoneTorque = getValueWithDefault<float>(c, s.deadZoneTorque, "torque_dead_zone");
76 // config.timeLimit = getValueWithDefault<float>(c, s.timeLimit, "wait_time_for_calibration");
77 // s.timeLimit = config.timeLimit;
78
79 // config.enableTCPGravityCompensation = getValueWithDefault<bool>(c, s.enableTCPGravityCompensation, "enable_tcp_gravity_compensation");
80 // nlohmann::json compCfg;
81 // if (c.find(sensorName) != c.end())
82 // auto compCfg = c[sensorName];
83 // config.tcpMass = getValueWithDefault<float>(compCfg, s.tcpMass, "tcp_mass");
84 // config.tcpCoMInFTSensorFrame = getEigenVecWithDefault(compCfg, s.tcpCoMInFTSensorFrame, "tcp_CoM_in_FT_frame");
85 // config.forceBaseline.setZero();
86 // config.torqueBaseline.setZero();
87 // return config;
88 //}
89
90 void
92 {
93 /// you have to call this method **only** in the first loop of rtRun
94 // s.tcpMass = 0.0f;
95 // s.tcpCoMInFTSensorFrame.setZero();
96
97 forceOffset.setZero();
98 torqueOffset.setZero();
99 ft.setZero();
100
101 calibrated.store(false);
102 timeForCalibration = 0.0f;
103
104 safeGuardForceOffset.setZero();
105 safeGuardTorqueOffset.setZero();
106
107 safeGuardEnabledForce.store(false);
108 safeGuardEnabledTorque.store(false);
109
110 resetForceGuard.store(true);
111 resetTorqueGuard.store(true);
112
113 ftWasNotSafe.store(false);
114
115 // Eigen::Matrix4f forceFrameInRoot = sensorNode->getPoseInRootFrame();
116 // forceFrameInTCP.block<3, 3>(0, 0) = currentPose.block<3, 3>(0, 0).transpose() * forceFrameInRoot.block<3, 3>(0, 0);
117 // tcpCoMInTCPFrame = forceFrameInTCP.block<3, 3>(0, 0) * tcpCoMInFTSensorFrame;
118 }
119
120 void
122 Eigen::Vector6f& currentFT,
123 double deltaT,
124 bool firstRun)
125 {
126 if (firstRun)
127 {
128 reset();
129 return;
130 }
131 sensorOriInRoot = sensorNode->getOrientationInRootFrame();
132 rawForce = forceSensor->force;
133 rawTorque = forceSensor->torque;
134
135 if (c.reCalibrate)
136 {
137 calibrated.store(false);
138 /// TODO how to toggle recalibration?
139 }
141 if (!calibrated.load())
142 {
143 if (calibrate(c, deltaT))
144 {
145 calibrated.store(true);
146 }
147 }
148 else
149 {
150 currentFT = getFilteredForceTorque(c);
151 }
153 }
154
155 void
157 {
158 if (c.enableSafeGuardForce and resetForceGuard.load())
159 {
160 safeGuardForceOffset = filteredForceInRoot;
161 ARMARX_INFO << "Resetting force safe guard with baseline "
162 << VAROUT(filteredForceInRoot);
163 ftWasNotSafe.store(false);
164 safeGuardEnabledForce.store(true);
165 resetForceGuard.store(false);
166 }
167 if (c.enableSafeGuardTorque and resetTorqueGuard.load())
168 {
169 safeGuardTorqueOffset = filteredTorqueInRoot;
170 ftWasNotSafe.store(false);
171 safeGuardEnabledTorque.store(true);
172 resetTorqueGuard.store(false);
173 }
174 }
175
176 void
177 FTSensor::enableSafeGuard(bool enableForceGuard, bool enableTorqueGuard)
178 {
179 if (enableForceGuard)
180 {
181 resetForceGuard.store(true);
182 }
183 if (enableTorqueGuard)
184 {
185 resetTorqueGuard.store(true);
186 }
187 }
188
189 bool
191 {
192 return safeGuardEnabledForce.load();
193 }
194
195 bool
197 {
198 return safeGuardEnabledTorque.load();
199 }
200
201 bool
203 {
204 auto unsafeFlag =
205 (c.enableSafeGuardForce and
206 (filteredForceInRoot - safeGuardForceOffset).norm() > c.safeGuardForceThreshold) or
207 (c.enableSafeGuardTorque and
208 (filteredTorqueInRoot - safeGuardTorqueOffset).norm() > c.safeGuardTorqueThreshold);
209 ftSafe.store(not unsafeFlag);
210 if (unsafeFlag)
211 {
212 ftWasNotSafe.store(true);
213 }
214
215 return ftSafe.load();
216 }
217
218 bool
219 FTSensor::calibrate(const FTConfig& c, double deltaT)
220 {
221 /// this will calibrate the force torque value in FTSensorFrame until timeLimit is reached
222 // sensorOriInRoot = sensorNode->getOrientationInRootFrame();
223 forceOffset = (1 - c.ftFilter) * forceOffset +
224 c.ftFilter * (forceSensor->force -
225 sensorOriInRoot.transpose() * tcpGravityCompensation.head<3>());
226 torqueOffset = (1 - c.ftFilter) * torqueOffset +
227 c.ftFilter * (forceSensor->torque - sensorOriInRoot.transpose() *
228 tcpGravityCompensation.tail<3>());
229
230 timeForCalibration = timeForCalibration + deltaT;
231 if (timeForCalibration > c.timeLimit)
232 {
233 calibrated.store(true);
234 /// rt is ready only if the FT sensor is calibrated, and the rt2interface buffer is updated (see above)
236 "FT calibration done \n"
237 "-- force offset: [%.2f, %.2f, %.2f] \n"
238 "-- torque offset: [%.2f, %.2f, %.2f] \n"
239 "-- gravity compensation: [%.2f, %.2f, %.2f, %.2f, %.2f, %.2f]",
240 forceOffset(0),
241 forceOffset(1),
242 forceOffset(2),
243 torqueOffset(0),
244 torqueOffset(1),
245 torqueOffset(2),
246 tcpGravityCompensation(0),
247 tcpGravityCompensation(1),
248 tcpGravityCompensation(2),
249 tcpGravityCompensation(3),
250 tcpGravityCompensation(4),
251 tcpGravityCompensation(5));
252 }
253 return calibrated.load();
254 }
255
256 //void FTSensor::enableGravityCompensation(const float mass, const Eigen::Vector3f& tcpCoMInFTFrame)
257 //{
258 // enableTCPGravityCompensation.store(true);
259 // tcpMass = mass;
260 // tcpCoMInFTSensorFrame = tcpCoMInFTFrame;
261 //}
262
263 //void FTSensor::disableGravityCompensation()
264 //{
265 // enableTCPGravityCompensation.store(false);
266 // tcpMass = 0.0f;
267 // tcpCoMInFTSensorFrame.setZero();
268 // tcpGravityCompensation.setZero();
269 //}
270
273 {
274 // /// update variables from rt buffer
275 // tcpMass = data.tcpMass;
276 // tcpCoMInTCPFrame = forceFrameInTCP.block<3, 3>(0, 0) * data.tcpCoMInFTSensorFrame;
277
278 /// static compensation in root frame
279 if (c.enableTCPGravityCompensation)
280 {
281
282 tcpGravForceVec = tcpMass * gravity.head<3>();
283 tcpGravTorqueVec = (sensorOriInRoot * tcpCoMInFTSensorFrame).cross(tcpGravForceVec);
284 // tcpGravityCompensation << forceVec, torqueVec;
285 // Eigen::Vector3f localGravity = currentPose.block<3, 3>(0, 0).transpose() * gravity;
286 // Eigen::Vector3f localForceVec = tcpMass * localGravity;
287 // Eigen::Vector3f localTorqueVec = tcpCoMInTCPFrame.cross(localForceVec);
288
289 // tcpGravityCompensation << localForceVec, localTorqueVec;
290 tcpGravityCompensation.head<3>() = tcpGravForceVec;
291 tcpGravityCompensation.tail<3>() = tcpGravTorqueVec;
292 }
293 else
294 {
295 tcpGravityCompensation.setZero();
296 }
297 return tcpGravityCompensation;
298 }
299
302 {
303 filteredForce = (1 - c.ftFilter) * filteredForce + c.ftFilter * rawForce;
304 filteredTorque = (1 - c.ftFilter) * filteredTorque + c.ftFilter * rawTorque;
305
306 filteredForceInRoot = sensorOriInRoot * (filteredForce - forceOffset) -
307 tcpGravityCompensation.head<3>() - c.forceBaseline;
308 filteredTorqueInRoot = sensorOriInRoot * (filteredTorque - torqueOffset) -
309 tcpGravityCompensation.tail<3>() - c.torqueBaseline;
310
311 for (size_t i = 0; i < 3; ++i)
312 {
313 if (fabs(filteredForceInRoot(i)) > c.deadZoneForce)
314 {
315 filteredForceInRoot(i) -=
316 (filteredForceInRoot(i) / fabs(filteredForceInRoot(i))) * c.deadZoneForce;
317 }
318 else
319 {
320 filteredForceInRoot(i) = 0;
321 }
322
323 if (fabs(filteredTorqueInRoot(i)) > c.deadZoneTorque)
324 {
325 filteredTorqueInRoot(i) -=
326 (filteredTorqueInRoot(i) / fabs(filteredTorqueInRoot(i))) * c.deadZoneTorque;
327 }
328 else
329 {
330 filteredTorqueInRoot(i) = 0;
331 }
332 }
333
334 ft.head<3>() = filteredForceInRoot;
335 ft.tail<3>() = filteredTorqueInRoot;
336 return ft;
337 }
338
339 Eigen::Vector3f&
341 {
342 return safeGuardForceOffset;
343 }
344} // namespace armarx::control::common::ft
#define ARMARX_RT_LOGF_IMPORTANT(...)
#define VAROUT(x)
constexpr T c
The SensorValueBase class.
const T * asA() const
bool isSafe(const FTConfig &c)
Definition FTSensor.cpp:202
Eigen::Vector3f & getSafeGuardForceOffset()
Definition FTSensor.cpp:340
Eigen::Vector6f & getFilteredForceTorque(const FTConfig &data)
Definition FTSensor.cpp:301
void enableSafeGuard(bool enableForceGuard, bool enableTorqueGuard)
Definition FTSensor.cpp:177
Eigen::Vector6f & compensateTCPGravity(const FTConfig &data)
Definition FTSensor.cpp:272
void initialize(const VirtualRobot::RobotNodeSetPtr &rns, const armarx::RobotUnitPtr &robotUnit, const FTConfig &c)
Definition FTSensor.cpp:23
bool calibrate(const FTConfig &c, double deltaT)
Definition FTSensor.cpp:219
void updateStatus(const FTConfig &c, Eigen::Vector6f &currentFT, double deltaT, bool firstRun)
Definition FTSensor.cpp:121
void resetSafeGuardOffset(const FTConfig &c)
Definition FTSensor.cpp:156
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
Matrix< float, 6, 1 > Vector6f
This file is part of ArmarX.
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34
double norm(const Point &a)
Definition point.hpp:102
Point cross(const Point &x, const Point &y)
Definition point.hpp:35