KeypointsImpedanceController.cpp
Go to the documentation of this file.
1 #include <fstream>
2 #include <boost/algorithm/clamp.hpp>
3 
4 #include <SimoxUtility/math/convert/rpy_to_mat3f.h>
5 #include <SimoxUtility/math/convert/mat4f_to_pos.h>
6 #include <SimoxUtility/math/convert/mat4f_to_quat.h>
7 #include <SimoxUtility/math/compare/is_equal.h>
8 #include <SimoxUtility/json.h>
9 
10 #include <VirtualRobot/MathTools.h>
13 
14 #include "../utils.h"
16 
17 
18 
20 {
21 
22  void
23  KeypointsImpedanceController::initialize(const VirtualRobot::RobotNodeSetPtr& rns)
24  {
26  tcp = rns->getTCP();
28  ik.reset(new VirtualRobot::DifferentialIK(
29  rns, rns->getRobot()->getRootNode(),
30  VirtualRobot::JacobiProvider::eSVDDamped));
31 
32  /// joint space variables
33  numOfJoints = rns->getSize();
34  I = Eigen::MatrixXf::Identity(numOfJoints, numOfJoints);
35  }
36 
37 
38  void
39  KeypointsImpedanceController::preactivateInit(const VirtualRobot::RobotNodeSetPtr& rns, const Config& c)
40  {
41  ARMARX_INFO << "preactivate control law KeypointsImpedanceController";
42  Eigen::Matrix4f currentPose = rns->getTCP()->getPoseInRootFrame();
43  {
44  NonRtStatus s;
45 
46  s.qpos = rns->getJointValuesEigen();
47  s.qvel.setZero(numOfJoints);
48 
49  s.currentPose = currentPose;
50  s.currentTwist.setZero();
51 
52  s.desiredPose = currentPose;
53  s.desiredVel.setZero();
54  s.desiredAcc.setZero();
55 
56  s.jacobi.setZero(6, numOfJoints);
57  s.jtpinv.setZero(6, numOfJoints);
58 
59  /// keypoint status
60  if (c.isRigid)
61  {
62  for (int i = 0; i < c.numPoints; i++)
63  {
64  s.currentKeypointPosition.segment(3*i, 3) = currentPose.block(0, 3, 3, 1);
65  }
66  s.currentKeypointPosition = s.currentKeypointPosition + c.fixedTranslation;
67  }
68  ARMARX_CHECK_EQUAL(s.currentKeypointPosition.size(), c.numPoints * 3);
69  s.currentKeypointVelocity.setZero(c.numPoints*3);
70 
71  s.pointTrackingForce.setZero();
72  s.filteredKeypointPosition = s.currentKeypointPosition;
73  s.previousKeypointPosition = s.currentKeypointPosition;
74 
75  s.desiredKeypointPosition = s.currentKeypointPosition;
76  s.desiredKeypointVelocity.setZero(c.numPoints*3);
77  s.desiredDensityForce.setZero(c.numPoints*3);
78 
79  bufferNonRtToRt.reinitAllBuffers(s);
80  bufferNonRtToOnPublish.reinitAllBuffers(s);
81  }
82 
83  {
84  RtStatus s;
85 
86  s.desiredPose = currentPose;
87  s.desiredTwist.setZero();
88 
89  s.forceImpedance.setZero();
90 
91  s.nullspaceTorque.setZero(numOfJoints);
92  s.desiredJointTorques.setZero(numOfJoints);
93 
95  }
96  }
97 
98  void
100  {
101  auto& sRt = bufferRtToOnPublish.getWriteBuffer();
102  auto& sNoneRt = bufferNonRtToRt.getUpToDateReadBuffer();
103 
104  sRt.desiredPose = sNoneRt.currentPose;
105  sRt.desiredTwist.setZero();
106 
107  sRt.forceImpedance.setZero();
108 
109  sRt.nullspaceTorque.setZero();
110  sRt.desiredJointTorques.setZero();
111 
113  }
114 
115 
116  bool
118  const Config& cfg,
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 = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
139  jacobi.block(0, 0, 3, numOfJoints) = 0.001 * jacobi.block(0, 0, 3, numOfJoints);
140  ARMARX_CHECK_EQUAL(numOfJoints, jacobi.cols());
141  ARMARX_CHECK_EQUAL(6, jacobi.rows());
142  s.jacobi = jacobi;
143 
144  s.jtpinv = ik->computePseudoInverseJacobianMatrix(s.jacobi.transpose(), lambda);
145  ARMARX_CHECK_EQUAL(numOfJoints, s.jtpinv.cols());
146  ARMARX_CHECK_EQUAL(6, s.jtpinv.rows());
147 
148  Eigen::VectorXf qvelRaw(numOfJoints);
149  for (size_t i = 0; i < robotStatus.jointVelocity.size(); ++i)
150  {
151  s.qpos(i) = robotStatus.jointPosition[i];
152  qvelRaw(i) = robotStatus.jointVelocity[i];
153  }
154  ARMARX_CHECK_EQUAL(s.qvel.rows(), qvelRaw.rows());
155 
156  s.qvel = (1 - cfg.qvelFilter) * s.qvel + cfg.qvelFilter * qvelRaw;
157  s.currentTwist = jacobi * s.qvel;
158 
159  /// ----------------------------- keypoint related ---------------------------------------------
160  /// compute (filtered) keypoint position
161  if (cfg.isRigid)
162  {
163  for (int i = 0; i < cfg.numPoints; i++)
164  {
165  s.currentKeypointPosition.segment(3*i, 3) = s.currentPose.block(0, 0, 3, 3) * cfg.fixedTranslation.segment(3*i, 3) + s.currentPose.block<3, 1>(0, 3);
166  }
167  }
168  ARMARX_CHECK_EQUAL(cfg.numPoints * 3, s.currentKeypointPosition.size());
169  s.filteredKeypointPosition = (1.0f - cfg.keypointPositionFilter) * s.filteredKeypointPosition + cfg.keypointPositionFilter * s.currentKeypointPosition;
170  ARMARX_CHECK_EQUAL(cfg.numPoints * 3, s.filteredKeypointPosition.size());
171  /// compute filtered keypoint velocity
172  if (cfg.isRigid)
173  {
174  Eigen::VectorXf currentKeypointVelocity;
175  currentKeypointVelocity.setZero(cfg.numPoints * 3);
176  for (int i = 0; i < cfg.numPoints; i++)
177  {
178  Eigen::Vector3f angular_vel = s.currentTwist.tail(3);
179  Eigen::Vector3f dist = cfg.fixedTranslation.segment(3*i, 3);
180  currentKeypointVelocity.segment(3*i, 3) = angular_vel.cross(dist) + s.currentTwist.head(3);
181  }
182  s.currentKeypointVelocity = (1.0f - cfg.keypointVelocityFilter) * s.currentKeypointVelocity
183  + cfg.keypointVelocityFilter * currentKeypointVelocity;
184  }
185  else
186  {
187  s.currentKeypointVelocity = (1.0f - cfg.keypointVelocityFilter) * s.currentKeypointVelocity
188  + cfg.keypointVelocityFilter * (s.filteredKeypointPosition - s.previousKeypointPosition) / static_cast<float>(robotStatus.deltaT);
189  }
190  s.previousKeypointPosition = s.filteredKeypointPosition;
191 
192  /// ----------------------------- compute keypoint tracking force ---------------------------------------------
193  auto difference = s.desiredKeypointPosition - s.filteredKeypointPosition;
194  /// in theory, we can also add s.desiredKeypointVelocity to the damping term
195  Eigen::VectorXf trackingForce = difference.cwiseProduct(cfg.keypointKp) - s.currentKeypointVelocity.cwiseProduct(cfg.keypointKd);
196  if (trackingForce.size() != 3 * cfg.numPoints)
197  {
198  trackingForce.setZero(3 * cfg.numPoints);
199  }
200 
201  Eigen::Vector3f meanKeypointPosition = Eigen::Vector3f::Zero();
202  for (int i = 0; i < cfg.numPoints; i++)
203  {
204  meanKeypointPosition = meanKeypointPosition + s.filteredKeypointPosition.segment(3*i, 3);
205  }
206  meanKeypointPosition = meanKeypointPosition / cfg.numPoints;
207 
208  s.pointTrackingForce.setZero();
209  for (int i = 0; i < cfg.numPoints; i++)
210  {
211  // Eigen::Vector3f dist = s.filteredKeypointPosition.segment(3*i, 3) - s.currentPose.block<3, 1>(0, 3);
212  Eigen::Vector3f dist = s.filteredKeypointPosition.segment(3*i, 3) - meanKeypointPosition;
213  dist = dist * 0.001;
214  Eigen::Vector3f force = trackingForce.segment(3*i, 3) + s.desiredDensityForce.segment(3*i, 3);
215  if (force.norm() > 1000)
216  {
217  ARMARX_RT_LOGF_WARN("force too large, set to zero");
218  force.setZero();
219  }
220  s.pointTrackingForce.head(3) += force;
221  s.pointTrackingForce.tail(3) += dist.cross(force);
222  }
223  Eigen::Vector6f acc =
224  cfg.kmAdmittance.cwiseProduct(s.pointTrackingForce) -
225  cfg.kdAdmittance.cwiseProduct(s.desiredVel);
226 
227  Eigen::Vector6f vel = s.desiredVel + 0.5 * static_cast<float>(robotStatus.deltaT) * (acc + s.desiredAcc);
228  Eigen::VectorXf deltaPose = 0.5 * static_cast<float>(robotStatus.deltaT) * (vel + s.desiredVel);
229  s.desiredAcc = acc;
230  s.desiredVel = vel;
231 
232  Eigen::Matrix3f deltaPoseMat = VirtualRobot::MathTools::rpy2eigen3f(deltaPose(3), deltaPose(4), deltaPose(5));
233  s.desiredPose.block<3, 1>(0, 3) += deltaPose.head(3);
234  s.desiredPose.block<3, 3>(0, 0) = deltaPoseMat * s.desiredPose.block<3, 3>(0, 0);
235 
236  bufferNonRtToOnPublish.getWriteBuffer() = s;
237 
238  bufferNonRtToOnPublish.commitWrite();
239  bufferNonRtToRt.commitWrite();
240 
241  isInitialized.store(true);
242  return true;
243  }
244 
245  void
247  const Config& c,
248  ControlTarget& targets)
249  {
250  /// run in rt thread
251 
252  auto& sRt = bufferRtToOnPublish.getWriteBuffer();
253  const auto& s = bufferNonRtToRt.getUpToDateReadBuffer();
254 
255  if (isInitialized.load())
256  {
257  if ((sRt.desiredPose.block<3, 1>(0, 3) - s.desiredPose.block<3, 1>(0, 3)).norm() > 100.0f)
258  {
259  ARMARX_RT_LOGF_WARN("new target \n\n %s\n\nis too far away from\n\n %s", VAROUT(s.desiredPose), VAROUT(sRt.desiredPose));
260  }
261  else
262  {
263  sRt.desiredPose = s.desiredPose;
264  }
265  }
266 
267  /// ----------------------------- Impedance control ---------------------------------------------
268  /// calculate pose error between target pose and current pose
269  /// !!! This is very important: you have to keep postion and orientation both
270  /// with UI unit (meter, radian) to calculate impedance force.
271 
272  Eigen::Matrix3f diffMat =
273  sRt.desiredPose.block<3, 3>(0, 0) * s.currentPose.block<3, 3>(0, 0).transpose();
274  Eigen::Vector6f poseErrorImp;
275  poseErrorImp.head(3) = 0.001 * (sRt.desiredPose.block<3, 1>(0, 3) - s.currentPose.block<3, 1>(0, 3));
276  poseErrorImp.tail(3) = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
277  sRt.forceImpedance =
278  c.kpImpedance.cwiseProduct(poseErrorImp) -
279  c.kdImpedance.cwiseProduct(s.currentTwist);
280 
281  /// ----------------------------- Nullspace PD Control --------------------------------------------------
282  ARMARX_CHECK_EQUAL((unsigned)numOfJoints, c.kpNullspace.rows());
283  ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.qpos.rows());
284  ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.qvel.rows());
285 
286  Eigen::VectorXf nullspaceTorque =
287  c.kpNullspace.cwiseProduct(c.desiredNullspaceJointAngles.value() - s.qpos) -
288  c.kdNullspace.cwiseProduct(s.qvel);
289 
290  /// ----------------------------- Map TS target force to JS --------------------------------------------------
291  ARMARX_CHECK_EQUAL((unsigned)6, s.jacobi.rows());
292  ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.jacobi.cols());
293 
294  ARMARX_CHECK_EQUAL((unsigned)6, s.jtpinv.rows());
295  ARMARX_CHECK_EQUAL((unsigned)numOfJoints, s.jtpinv.cols());
296 
297  sRt.desiredJointTorques =
298  s.jacobi.transpose() * sRt.forceImpedance +
299  (I - s.jacobi.transpose() * s.jtpinv) * nullspaceTorque;
300 
301  /// ----------------------------- write torque target --------------------------------------------------
302  for (size_t i = 0; i < (unsigned)sRt.desiredJointTorques.rows(); ++i)
303  {
304  sRt.desiredJointTorques(i) = std::clamp(sRt.desiredJointTorques(i), -c.torqueLimit, c.torqueLimit);
305  targets.targets.at(i) = sRt.desiredJointTorques(i);
306  }
307 
309  }
310 } /// namespace armarx::control::common::control_law
armarx::control::common::control_law::KeypointsImpedanceController::Config::qvelFilter
float qvelFilter
Definition: KeypointsImpedanceController.h:58
armarx::control::common::control_law::KeypointsImpedanceController::Config::fixedTranslation
Eigen::VectorXf fixedTranslation
Definition: KeypointsImpedanceController.h:64
armarx::control::common::control_law::KeypointsImpedanceController::Config
you can set the following values from outside of the rt controller via Ice interfaces
Definition: KeypointsImpedanceController.h:41
armarx::control::common::control_law::KeypointsImpedanceController::initialize
void initialize(const VirtualRobot::RobotNodeSetPtr &rns)
Definition: KeypointsImpedanceController.cpp:23
armarx::control::common::control_law::KeypointsImpedanceController::isInitialized
std::atomic< bool > isInitialized
Definition: KeypointsImpedanceController.h:157
armarx::control::common::control_law::ControlTarget::targets
std::vector< float > targets
Definition: common.h:50
armarx::TripleBuffer::getWriteBuffer
T & getWriteBuffer()
Definition: TripleBuffer.h:90
armarx::control::common::control_law::KeypointsImpedanceController::firstRun
void firstRun()
Definition: KeypointsImpedanceController.cpp:99
armarx::control::common::control_law::KeypointsImpedanceController::Config::kmAdmittance
Eigen::Vector6f kmAdmittance
Definition: KeypointsImpedanceController.h:50
armarx::control::common::control_law::KeypointsImpedanceController::Config::numPoints
int numPoints
keypoints related
Definition: KeypointsImpedanceController.h:61
armarx::TripleBuffer::commitWrite
void commitWrite()
Definition: TripleBuffer.h:146
armarx::control::common::control_law::RobotStatus::jointTorque
std::vector< float > jointTorque
Definition: common.h:34
ARMARX_CHECK_NOT_NULL
#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...
Definition: ExpressionException.h:206
armarx::control::common::control_law::KeypointsImpedanceController::NonRtStatus
Definition: KeypointsImpedanceController.h:90
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
armarx::control::common::control_law::KeypointsImpedanceController::tcp
VirtualRobot::RobotNodePtr tcp
Definition: KeypointsImpedanceController.h:137
armarx::control::common::control_law::RobotStatus::jointVelocity
std::vector< float > jointVelocity
Definition: common.h:33
armarx::control::common::control_law::KeypointsImpedanceController::Config::keypointPositionFilter
float keypointPositionFilter
Definition: KeypointsImpedanceController.h:70
armarx::control::common::control_law::KeypointsImpedanceController::Config::isRigid
bool isRigid
Definition: KeypointsImpedanceController.h:73
clamp
double clamp(double x, double a, double b)
Definition: point.hpp:125
armarx::control::common::control_law::KeypointsImpedanceController::RtStatus
internal status of the controller, containing intermediate variables, mutable targets
Definition: KeypointsImpedanceController.h:77
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:523
armarx::control::common::control_law::KeypointsImpedanceController::bufferNonRtToRt
TripleBuffer< NonRtStatus > bufferNonRtToRt
Definition: KeypointsImpedanceController.h:134
armarx::control::common::control_law::KeypointsImpedanceController::Config::kdAdmittance
Eigen::Vector6f kdAdmittance
Definition: KeypointsImpedanceController.h:49
armarx::control::common::control_law::KeypointsImpedanceController::bufferRtToOnPublish
TripleBuffer< RtStatus > bufferRtToOnPublish
Definition: KeypointsImpedanceController.h:132
armarx::control::common::control_law::KeypointsImpedanceController::preactivateInit
void preactivateInit(const VirtualRobot::RobotNodeSetPtr &rns, const Config &c)
Definition: KeypointsImpedanceController.cpp:39
if
if(!yyvaluep)
Definition: Grammar.cpp:724
armarx::control::common::control_law::RobotStatus
Definition: common.h:29
KeypointsImpedanceController.h
armarx::control::common::control_law::KeypointsImpedanceController::bufferNonRtToOnPublish
TripleBuffer< NonRtStatus > bufferNonRtToOnPublish
Definition: KeypointsImpedanceController.h:135
armarx::control::common::control_law
This file is part of ArmarX.
Definition: aron_conversions.cpp:68
armarx::control::common::control_law::KeypointsImpedanceController::run
void run(const Config &cfg, ControlTarget &targets)
Definition: KeypointsImpedanceController.cpp:246
armarx::control::common::control_law::RobotStatus::jointPosition
std::vector< float > jointPosition
Definition: common.h:32
armarx::control::common::control_law::KeypointsImpedanceController::Config::keypointKp
Eigen::VectorXf keypointKp
Definition: KeypointsImpedanceController.h:62
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:600
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:601
armarx::control::common::control_law::KeypointsImpedanceController::Config::keypointVelocityFilter
float keypointVelocityFilter
Definition: KeypointsImpedanceController.h:71
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:182
armarx::control::common::control_law::KeypointsImpedanceController::Config::keypointKd
Eigen::VectorXf keypointKd
Definition: KeypointsImpedanceController.h:63
armarx::control::common::control_law::KeypointsImpedanceController::updateControlStatus
bool updateControlStatus(const Config &cfg, const RobotStatus &robotStatus)
Definition: KeypointsImpedanceController.cpp:117
Eigen::Matrix< float, 6, 1 >
ControlThreadOutputBuffer.h
ARMARX_CHECK_EQUAL
#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...
Definition: ExpressionException.h:130
ARMARX_RT_LOGF_WARN
#define ARMARX_RT_LOGF_WARN(...)
Definition: ControlThreadOutputBuffer.h:345
ArmarXDataPath.h
armarx::control::common::control_law::ControlTarget
Definition: common.h:48
armarx::TripleBuffer::reinitAllBuffers
std::enable_if< std::is_copy_constructible< U >::value >::type reinitAllBuffers(const T &init)
Definition: TripleBuffer.h:153
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx::control::common::control_law::RobotStatus::deltaT
double deltaT
Definition: common.h:38