KeypointsImpedanceController.cpp
Go to the documentation of this file.
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 <SimoxUtility/math/convert/rpy_to_mat3f.h>
8#include <VirtualRobot/IK/DifferentialIK.h>
9#include <VirtualRobot/IK/JacobiProvider.h>
10#include <VirtualRobot/MathTools.h>
11#include <VirtualRobot/Robot.h>
12#include <VirtualRobot/RobotNodeSet.h>
13
15
19
20#include "../utils.h"
21
23{
24
25 void
26 KeypointsImpedanceController::initialize(const VirtualRobot::RobotNodeSetPtr& rns)
27 {
29 tcp = rns->getTCP();
31 ik.reset(new VirtualRobot::DifferentialIK(
32 rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
33
34 /// joint space variables
35 numOfJoints = rns->getSize();
36 I = Eigen::MatrixXf::Identity(numOfJoints, numOfJoints);
37 }
38
39 void
40 KeypointsImpedanceController::preactivateInit(const VirtualRobot::RobotNodeSetPtr& rns,
41 const Config& c)
42 {
43 ARMARX_INFO << "preactivate control law KeypointsImpedanceController";
44 Eigen::Matrix4f currentPose = rns->getTCP()->getPoseInRootFrame();
45 {
47
48 s.qpos = rns->getJointValuesEigen();
49 s.qvel.setZero(numOfJoints);
50
51 s.currentPose = currentPose;
52 s.currentTwist.setZero();
53
54 s.desiredPose = currentPose;
55 s.desiredVel.setZero();
56 s.desiredAcc.setZero();
57
58 s.jacobi.setZero(6, numOfJoints);
59 s.jtpinv.setZero(6, numOfJoints);
60
61 /// keypoint status
62 if (c.isRigid)
63 {
64 for (int i = 0; i < c.numPoints; i++)
65 {
66 s.currentKeypointPosition.segment(3 * i, 3) = currentPose.block(0, 3, 3, 1);
67 }
68 s.currentKeypointPosition = s.currentKeypointPosition + c.fixedTranslation;
69 }
70 ARMARX_CHECK_EQUAL(s.currentKeypointPosition.size(), c.numPoints * 3);
71 s.currentKeypointVelocity.setZero(c.numPoints * 3);
72
73 s.pointTrackingForce.setZero();
74 s.filteredKeypointPosition = s.currentKeypointPosition;
75 s.previousKeypointPosition = s.currentKeypointPosition;
76
77 s.desiredKeypointPosition = s.currentKeypointPosition;
78 s.desiredKeypointVelocity.setZero(c.numPoints * 3);
79 s.desiredDensityForce.setZero(c.numPoints * 3);
80
81 bufferNonRtToRt.reinitAllBuffers(s);
82 bufferNonRtToOnPublish.reinitAllBuffers(s);
83 }
84
85 {
86 RtStatus s;
87
88 s.desiredPose = currentPose;
89 s.desiredTwist.setZero();
90
91 s.forceImpedance.setZero();
92
93 s.nullspaceTorque.setZero(numOfJoints);
94 s.desiredJointTorques.setZero(numOfJoints);
95
96 bufferRtToOnPublish.reinitAllBuffers(s);
97 }
98 }
99
100 void
102 {
103 auto& sRt = bufferRtToOnPublish.getWriteBuffer();
104 auto& sNoneRt = bufferNonRtToRt.getUpToDateReadBuffer();
105
106 sRt.desiredPose = sNoneRt.currentPose;
107 sRt.desiredTwist.setZero();
108
109 sRt.forceImpedance.setZero();
110
111 sRt.nullspaceTorque.setZero();
112 sRt.desiredJointTorques.setZero();
113
114 bufferRtToOnPublish.commitWrite();
115 }
116
117 bool
119 const RobotStatus& robotStatus)
120 {
121 auto& s = bufferNonRtToRt.getWriteBuffer();
122
123 /// check size and value
124 {
125 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, robotStatus.jointPosition.size());
126 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, robotStatus.jointVelocity.size());
127 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, robotStatus.jointTorque.size());
128 }
129
130 /// ----------------------------- get current status of robot ---------------------------------------------
131 /// original data in ArmarX use the following units:
132 /// position in mm,
133 /// joint angles and orientation in radian,
134 /// velocity in mm/s and radian/s, etc.
135 /// here we convert mm to m, if you use MP from outside, make sure to convert it back to mm
136
137 s.currentPose = tcp->getPoseInRootFrame();
138 Eigen::MatrixXf jacobi =
139 ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
140 jacobi.block(0, 0, 3, numOfJoints) = 0.001 * jacobi.block(0, 0, 3, numOfJoints);
141 ARMARX_CHECK_EQUAL(numOfJoints, jacobi.cols());
142 ARMARX_CHECK_EQUAL(6, jacobi.rows());
143 s.jacobi = jacobi;
144
145 s.jtpinv = ik->computePseudoInverseJacobianMatrix(s.jacobi.transpose(), lambda);
146 ARMARX_CHECK_EQUAL(numOfJoints, s.jtpinv.cols());
147 ARMARX_CHECK_EQUAL(6, s.jtpinv.rows());
148
149 Eigen::VectorXf qvelRaw(numOfJoints);
150 for (size_t i = 0; i < robotStatus.jointVelocity.size(); ++i)
151 {
152 s.qpos(i) = robotStatus.jointPosition[i];
153 qvelRaw(i) = robotStatus.jointVelocity[i];
154 }
155 ARMARX_CHECK_EQUAL(s.qvel.rows(), qvelRaw.rows());
156
157 s.qvel = (1 - cfg.qvelFilter) * s.qvel + cfg.qvelFilter * qvelRaw;
158 s.currentTwist = jacobi * s.qvel;
159
160 /// ----------------------------- keypoint related ---------------------------------------------
161 /// compute (filtered) keypoint position
162 if (cfg.isRigid)
163 {
164 for (int i = 0; i < cfg.numPoints; i++)
165 {
166 s.currentKeypointPosition.segment(3 * i, 3) =
167 s.currentPose.block(0, 0, 3, 3) * cfg.fixedTranslation.segment(3 * i, 3) +
168 s.currentPose.block<3, 1>(0, 3);
169 }
170 }
171 ARMARX_CHECK_EQUAL(cfg.numPoints * 3, s.currentKeypointPosition.size());
172 s.filteredKeypointPosition =
173 (1.0f - cfg.keypointPositionFilter) * s.filteredKeypointPosition +
174 cfg.keypointPositionFilter * s.currentKeypointPosition;
175 ARMARX_CHECK_EQUAL(cfg.numPoints * 3, s.filteredKeypointPosition.size());
176 /// compute filtered keypoint velocity
177 if (cfg.isRigid)
178 {
179 Eigen::VectorXf currentKeypointVelocity;
180 currentKeypointVelocity.setZero(cfg.numPoints * 3);
181 for (int i = 0; i < cfg.numPoints; i++)
182 {
183 Eigen::Vector3f angular_vel = s.currentTwist.tail<3>();
184 Eigen::Vector3f dist = cfg.fixedTranslation.segment(3 * i, 3);
185 currentKeypointVelocity.segment(3 * i, 3) =
186 angular_vel.cross(dist) + s.currentTwist.head<3>();
187 }
188 s.currentKeypointVelocity =
189 (1.0f - cfg.keypointVelocityFilter) * s.currentKeypointVelocity +
190 cfg.keypointVelocityFilter * currentKeypointVelocity;
191 }
192 else
193 {
194 s.currentKeypointVelocity =
195 (1.0f - cfg.keypointVelocityFilter) * s.currentKeypointVelocity +
197 (s.filteredKeypointPosition - s.previousKeypointPosition) /
198 static_cast<float>(robotStatus.deltaT);
199 }
200 s.previousKeypointPosition = s.filteredKeypointPosition;
201
202 /// ----------------------------- compute keypoint tracking force ---------------------------------------------
203 auto difference = s.desiredKeypointPosition - s.filteredKeypointPosition;
204 /// in theory, we can also add s.desiredKeypointVelocity to the damping term
205 Eigen::VectorXf trackingForce = difference.cwiseProduct(cfg.keypointKp) -
206 s.currentKeypointVelocity.cwiseProduct(cfg.keypointKd);
207 if (trackingForce.size() != 3 * cfg.numPoints)
208 {
209 trackingForce.setZero(3 * cfg.numPoints);
210 }
211
212 Eigen::Vector3f meanKeypointPosition = Eigen::Vector3f::Zero();
213 for (int i = 0; i < cfg.numPoints; i++)
214 {
215 meanKeypointPosition =
216 meanKeypointPosition + s.filteredKeypointPosition.segment(3 * i, 3);
217 }
218 meanKeypointPosition = meanKeypointPosition / cfg.numPoints;
219
220 s.pointTrackingForce.setZero();
221 for (int i = 0; i < cfg.numPoints; i++)
222 {
223 // Eigen::Vector3f dist = s.filteredKeypointPosition.segment(3*i, 3) - s.currentPose.block<3, 1>(0, 3);
224 Eigen::Vector3f dist =
225 s.filteredKeypointPosition.segment(3 * i, 3) - meanKeypointPosition;
226 dist = dist * 0.001;
227 Eigen::Vector3f force =
228 trackingForce.segment(3 * i, 3) + s.desiredDensityForce.segment(3 * i, 3);
229 if (force.norm() > 1000)
230 {
231 ARMARX_RT_LOGF_WARN("force too large, set to zero");
232 force.setZero();
233 }
234 s.pointTrackingForce.head<3>() += force;
235 s.pointTrackingForce.tail<3>() += dist.cross(force);
236 }
237 Eigen::Vector6f acc = cfg.kmAdmittance.cwiseProduct(s.pointTrackingForce) -
238 cfg.kdAdmittance.cwiseProduct(s.desiredVel);
239
240 Eigen::Vector6f vel =
241 s.desiredVel + 0.5 * static_cast<float>(robotStatus.deltaT) * (acc + s.desiredAcc);
242 Eigen::VectorXf deltaPose =
243 0.5 * static_cast<float>(robotStatus.deltaT) * (vel + s.desiredVel);
244 s.desiredAcc = acc;
245 s.desiredVel = vel;
246
247 Eigen::Matrix3f deltaPoseMat =
248 VirtualRobot::MathTools::rpy2eigen3f(deltaPose(3), deltaPose(4), deltaPose(5));
249 s.desiredPose.block<3, 1>(0, 3) += deltaPose.head<3>();
250 s.desiredPose.block<3, 3>(0, 0) = deltaPoseMat * s.desiredPose.block<3, 3>(0, 0);
251
252 bufferNonRtToOnPublish.getWriteBuffer() = s;
253
254 bufferNonRtToOnPublish.commitWrite();
255 bufferNonRtToRt.commitWrite();
256
257 isInitialized.store(true);
258 return true;
259 }
260
261 void
263 {
264 /// run in rt thread
265
266 auto& sRt = bufferRtToOnPublish.getWriteBuffer();
267 const auto& s = bufferNonRtToRt.getUpToDateReadBuffer();
268
269 if (isInitialized.load())
270 {
271 if ((sRt.desiredPose.block<3, 1>(0, 3) - s.desiredPose.block<3, 1>(0, 3)).norm() >
272 100.0f)
273 {
274 ARMARX_RT_LOGF_WARN("new target \n\n %s\n\nis too far away from\n\n %s",
275 VAROUT(s.desiredPose),
276 VAROUT(sRt.desiredPose));
277 }
278 else
279 {
280 sRt.desiredPose = s.desiredPose;
281 }
282 }
283
284 /// ----------------------------- Impedance control ---------------------------------------------
285 /// calculate pose error between target pose and current pose
286 /// !!! This is very important: you have to keep postion and orientation both
287 /// with UI unit (meter, radian) to calculate impedance force.
288
289 Eigen::Matrix3f diffMat =
290 sRt.desiredPose.block<3, 3>(0, 0) * s.currentPose.block<3, 3>(0, 0).transpose();
291 Eigen::Vector6f poseErrorImp;
292 poseErrorImp.head<3>() =
293 0.001 * (sRt.desiredPose.block<3, 1>(0, 3) - s.currentPose.block<3, 1>(0, 3));
294 poseErrorImp.tail<3>() = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
295 sRt.forceImpedance =
296 c.kpImpedance.cwiseProduct(poseErrorImp) - c.kdImpedance.cwiseProduct(s.currentTwist);
297
298 /// ----------------------------- Nullspace PD Control --------------------------------------------------
299 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, c.kpNullspaceTorque.rows());
300 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.qpos.rows());
301 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.qvel.rows());
302
303 Eigen::VectorXf nullspaceTorque =
304 c.kpNullspaceTorque.cwiseProduct(c.desiredNullspaceJointAngles.value() - s.qpos) -
305 c.kdNullspaceTorque.cwiseProduct(s.qvel);
306
307 /// ----------------------------- Map TS target force to JS --------------------------------------------------
308 ARMARX_CHECK_EQUAL((unsigned)6, s.jacobi.rows());
309 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.jacobi.cols());
310
311 ARMARX_CHECK_EQUAL((unsigned)6, s.jtpinv.rows());
312 ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.jtpinv.cols());
313
314 sRt.desiredJointTorques = s.jacobi.transpose() * sRt.forceImpedance +
315 (I - s.jacobi.transpose() * s.jtpinv) * nullspaceTorque;
316
317 /// ----------------------------- write torque target --------------------------------------------------
318 for (size_t i = 0; i < (unsigned)sRt.desiredJointTorques.rows(); ++i)
319 {
320 sRt.desiredJointTorques(i) =
321 std::clamp(sRt.desiredJointTorques(i), -c.torqueLimit, c.torqueLimit);
322 targets.targets.at(i) = sRt.desiredJointTorques(i);
323 }
324
325 bufferRtToOnPublish.commitWrite();
326 }
327} // namespace armarx::control::common::control_law
#define ARMARX_RT_LOGF_WARN(...)
#define VAROUT(x)
constexpr T c
bool updateControlStatus(const Config &cfg, const RobotStatus &robotStatus)
void preactivateInit(const VirtualRobot::RobotNodeSetPtr &rns, const Config &c)
Brief description of class targets.
Definition targets.h:39
#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_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...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
Matrix< float, 6, 1 > Vector6f
TODO remove, only used by keypoint controllers.
Definition common.h:146
you can set the following values from outside of the rt controller via Ice interfaces
internal status of the controller, containing intermediate variables, mutable targets