TaskspaceMixedImpedanceVelocityController.cpp
Go to the documentation of this file.
2#include <Eigen/Core>
3
4#include <SimoxUtility/math/convert/mat4f_to_quat.h>
5#include <VirtualRobot/IK/DifferentialIK.h>
6#include <VirtualRobot/IK/JacobiProvider.h>
7#include <VirtualRobot/MathTools.h>
8#include <VirtualRobot/Nodes/RobotNode.h>
9#include <VirtualRobot/Robot.h>
10#include <VirtualRobot/RobotNodeSet.h>
11
15
17
18#include "../utils.h"
19
21{
22
23 void
25 const VirtualRobot::RobotNodeSetPtr& rns,
26 const VirtualRobot::RobotNodeSetPtr& rtRns,
27 const std::vector<size_t>& torqueControlledIndex,
28 const std::vector<size_t>& velocityControlledIndex)
29 {
31 auto numOfJoints = rns->getSize();
32
33 jointIDTorqueMode = torqueControlledIndex;
34 jointIDVelocityMode = velocityControlledIndex;
35 ARMARX_CHECK_EQUAL(jointIDTorqueMode.size() + jointIDVelocityMode.size(), numOfJoints);
36 // nDoFTorque = jointIDTorqueMode.size();
37 // nDoFVelocity = jointIDVelocityMode.size();
38
39 tcp = rns->getTCP();
40 rtTCP = rtRns->getTCP();
42 ik.reset(new VirtualRobot::DifferentialIK(
43 rtRns, rtRns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
44
45 // I = Eigen::MatrixXf::Identity(numOfJoints, numOfJoints);
46 }
47
48 void
50 const VirtualRobot::RobotNodeSetPtr& rns)
51 {
52 }
53
54 void
59
60 bool
62 const std::vector<std::string>& nameList,
63 const std::map<std::string, std::string>& jointControlModeMap)
64 {
65 std::set<std::string> validModes = {"velocity", "torque"};
66
67 for (const auto& pair : jointControlModeMap)
68 {
69 if (std::find(nameList.begin(), nameList.end(), pair.first) == nameList.end())
70 {
71 ARMARX_ERROR << "TaskspaceMixedImpedanceVelocityController: joint name '"
72 << pair.first << "' not found in robot node set.";
73 return false;
74 }
75
76 if (validModes.find(pair.second) == validModes.end())
77 {
79 << "TaskspaceMixedImpedanceVelocityController: Invalid control mode for joint '"
80 << pair.first << "': " << pair.second << std::endl;
81 return false;
82 }
83 }
84
85 return true;
86 }
87
88 void
90 {
91 /// run in rt thread
92 rtStatus.currentPose = rtTCP->getPoseInRootFrame();
93
94 /// ---------------------------- safety guard by FT and target pose ------------------------
95 rtStatus.poseDiffMatImp =
96 c.desiredPose.block<3, 3>(0, 0) * rtStatus.currentPose.block<3, 3>(0, 0).transpose();
97 rtStatus.oriDiffAngleAxis.fromRotationMatrix(rtStatus.poseDiffMatImp);
98
99 /// this should not be moved to non rt, just in case non rt thread dies, rt still functions as safely
100 rtStatus.forceTorqueSafe = ftsensor.isSafe(c.ftConfig);
101 if (not rtStatus.forceTorqueSafe)
102 {
103 // ARMARX_INFO << "FTGuard indicates RT not safe";
104 if (c.ftConfig.resetToCurrentPoseOnSafeGuardTrigger)
105 {
106 // ARMARX_INFO << "reset to current pose " << rtStatus.currentPose;
107 c.desiredPose = rtStatus.currentPose;
108 }
109 else
110 {
111 // ARMARX_INFO << "reset to valid target pose " << rtStatus.desiredPose;
112 c.desiredPose = rtStatus.desiredPose;
113 }
114 // rtStatus.forceTorqueSafe = false;
115 // rtStatus.rtSafe = false;
116 // rtStatus.rtTargetSafe = true;
117 }
118
119 if ((c.desiredPose.block<3, 1>(0, 3) - rtStatus.currentPose.block<3, 1>(0, 3)).norm() >
120 c.safeDistanceMMToGoal or
121 std::fminf(rtStatus.oriDiffAngleAxis.angle(),
122 2 * M_PI - rtStatus.oriDiffAngleAxis.angle()) >
123 VirtualRobot::MathTools::deg2rad(c.safeRotAngleDegreeToGoal))
124 {
125 rtStatus.desiredPoseUnsafe = c.desiredPose;
126 c.desiredPose = rtStatus.desiredPose; // TODO: remove this?
127 // rtStatus.rtSafe = false;
128 rtStatus.rtTargetSafe = false;
129 // rtStatus.forceTorqueSafe = true;
130 }
131 else
132 {
133 rtStatus.rtTargetSafe = true;
134 }
135
136 rtStatus.rtSafe = rtStatus.forceTorqueSafe and rtStatus.rtTargetSafe;
137 if (rtStatus.rtSafe)
138 {
139 rtStatus.desiredPose = c.desiredPose;
140 // rtStatus.rtSafe = true;
141 // rtStatus.rtTargetSafe = true;
142 // rtStatus.forceTorqueSafe = true;
143 }
144
145 auto nDoF = static_cast<Eigen::Index>(rtStatus.nDoF);
146 /// ------------------------------ compute jacobi ------------------------------------------
147 // rtStatus.jacobi =
148 // ik->getJacobianMatrix(rtTCP, VirtualRobot::IKSolver::CartesianSelection::All);
149 ik->updateJacobianMatrix(rtStatus.jacobi, rtTCP, VirtualRobot::IKSolver::CartesianSelection::All);
150 ARMARX_CHECK_EQUAL(nDoF, rtStatus.jacobi.cols());
151 ARMARX_CHECK_EQUAL(6, rtStatus.jacobi.rows());
152
153 // rtStatus.jpinv = ik->computePseudoInverseJacobianMatrix(rtStatus.jacobi, lambda);
154 rtStatus.jpinv = ik->computePseudoInverseJacobianMatrix(
155 rtStatus.jacobi,
156 ik->getJacobiRegularization(VirtualRobot::IKSolver::CartesianSelection::All));
157 ARMARX_CHECK_EQUAL(6, rtStatus.jpinv.cols());
158 ARMARX_CHECK_EQUAL(nDoF, rtStatus.jpinv.rows());
159
160 rtStatus.jacobi.block(0, 0, 3, rtStatus.nDoF) =
161 0.001 * rtStatus.jacobi.block(0, 0, 3, rtStatus.nDoF);
162
163 rtStatus.jtpinv =
164 ik->computePseudoInverseJacobianMatrix(rtStatus.jacobi.transpose(), rtStatus.lambda);
165 ARMARX_CHECK_EQUAL(nDoF, rtStatus.jtpinv.cols());
166 ARMARX_CHECK_EQUAL(6, rtStatus.jtpinv.rows());
167
168 /// ------------------------------ update velocity/twist -----------------------------------
169 ARMARX_CHECK_EQUAL(nDoF, rtStatus.jointPosition.rows());
170 ARMARX_CHECK_EQUAL(nDoF, rtStatus.jointVelocity.rows());
171 ARMARX_CHECK_EQUAL(nDoF, rtStatus.qvelFiltered.rows());
172
173 rtStatus.qvelFiltered =
174 (1 - c.qvelFilter) * rtStatus.qvelFiltered + c.qvelFilter * rtStatus.jointVelocity;
175 rtStatus.currentTwist = rtStatus.jacobi * rtStatus.qvelFiltered;
176
177 /// ------------------------------------- Impedance control --------------------------------
178 /// calculate pose error between target pose and current pose
179 /// !!! This is very important: you have to keep position and orientation both
180 /// with UI unit (meter, radian) to calculate impedance force.
181
182 rtStatus.poseDiffMatImp = rtStatus.desiredPose.block<3, 3>(0, 0) *
183 rtStatus.currentPose.block<3, 3>(0, 0).transpose();
184 // rtStatus.poseErrorImp.head<3>() = 0.001 * (rtStatus.desiredPose.block<3, 1>(0, 3) -
185 // rtStatus.currentPose.block<3, 1>(0, 3));
186 rtStatus.poseErrorImp.head<3>() = (rtStatus.desiredPose.block<3, 1>(0, 3) -
187 rtStatus.currentPose.block<3, 1>(0, 3)); /// in mm
188 rtStatus.poseErrorImp.tail<3>() =
189 VirtualRobot::MathTools::eigen3f2rpy(rtStatus.poseDiffMatImp);
190
191 /// ------------------------------------- Velocity control ---------------------------------------------------
192 /// calculate pose error between target pose and current pose
193 /// !!! This is very important: you have to keep position and orientation both
194 /// with UI unit (meter, radian) to calculate desired Cartesian velocity.
195 rtStatus.cartesianVelTarget = c.kpCartesianVel.cwiseProduct(rtStatus.poseErrorImp) -
196 c.kdCartesianVel.cwiseProduct(rtStatus.currentTwist);
197
198 rtStatus.poseErrorImp.head<3>() *= 0.001;
199 rtStatus.forceImpedance = c.kpImpedance.cwiseProduct(rtStatus.poseErrorImp) -
200 c.kdImpedance.cwiseProduct(rtStatus.currentTwist);
201
202
203 /// ----------------------------- Nullspace PD Control --------------------------------------------------
204 ARMARX_CHECK_EQUAL(nDoF, c.kpNullspaceTorque.rows());
205 ARMARX_CHECK_EQUAL(nDoF, c.kdNullspaceTorque.rows());
206 ARMARX_CHECK_EQUAL(nDoF, rtStatus.nullspaceTorque.rows());
207 ARMARX_CHECK_EQUAL(nDoF, c.kpNullspaceVel.rows());
208 ARMARX_CHECK_EQUAL(nDoF, c.kdNullspaceVel.rows());
209 ARMARX_CHECK_EQUAL(nDoF, rtStatus.nullspaceVelocity.rows());
210 ARMARX_CHECK_EQUAL(nDoF, c.desiredNullspaceJointAngles.value().size());
211
212 rtStatus.nullspaceTorque = c.kpNullspaceTorque.cwiseProduct(
213 c.desiredNullspaceJointAngles.value() - rtStatus.jointPosition) -
214 c.kdNullspaceTorque.cwiseProduct(rtStatus.jointVelocity);
215 rtStatus.nullspaceVelocity =
216 c.kpNullspaceVel.cwiseProduct(c.desiredNullspaceJointAngles.value() -
217 rtStatus.jointPosition) -
218 c.kdNullspaceVel.cwiseProduct(rtStatus.qvelFiltered);
219
220 /// ----------------------------- Map TS target force/velocity to JS --------------------------------------------------
221 ARMARX_CHECK_EQUAL(nDoF, rtStatus.desiredJointTorque.rows());
222 ARMARX_CHECK_EQUAL(nDoF, rtStatus.desiredJointVelocity.rows());
223 rtStatus.desiredJointTorque =
224 rtStatus.jacobi.transpose() * rtStatus.forceImpedance +
225 (rtStatus.I - rtStatus.jacobi.transpose() * rtStatus.jtpinv) * rtStatus.nullspaceTorque;
226 rtStatus.desiredJointVelocity =
227 rtStatus.jpinv * rtStatus.cartesianVelTarget +
228 (rtStatus.I - rtStatus.jpinv * rtStatus.jacobi) * rtStatus.nullspaceVelocity;
229
230 /// ----------------------------- write torque target -------------------------------------
231 for (int i = 0; i < rtStatus.desiredJointTorque.rows(); ++i)
232 {
233 rtStatus.desiredJointTorque(i) =
234 std::clamp(rtStatus.desiredJointTorque(i), -c.torqueLimit, c.torqueLimit);
235 }
236 for (int i = 0; i < rtStatus.desiredJointVelocity.rows(); ++i)
237 {
238 rtStatus.desiredJointVelocity(i) =
239 std::clamp(rtStatus.desiredJointVelocity(i), -c.velocityLimit, c.velocityLimit);
240 }
241 }
242
243 // void
244 // TaskspaceMixedImpedanceVelocityController::RtStatus::reset(const unsigned int nDoF,
245 // const size_t numDoFTorque,
246 // const size_t numDoFVelocity)
247 // {
248 // /// This function can be called before the RT thread.
249 // /// base
250 // // jointPosition.resize(nDoF, 0.);
251 // // jointVelocity.resize(nDoF, 0.);
252 // // jointTorque.resize(nDoF, 0.);
253 // jointPosition.setZero(nDoF);
254 // jointVelocity.setZero(nDoF);
255 // jointTorque.setZero(nDoF);
256 // deltaT = 0.0;
257 // accumulateTime = 0.0;
258 // nDoF = nDoF;
259 // nDoFTorque = numDoFTorque;
260 // nDoFVelocity = numDoFVelocity;
261 // ARMARX_CHECK_EQUAL(nDoF, nDoFTorque + nDoFVelocity);
262 //
263 // /// targets
264 // desiredJointTorque.setZero(nDoF);
265 // desiredJointVelocity.setZero(nDoF);
266 // cartesianVelTarget.setZero();
267 // nullspaceTorque.setZero(nDoF);
268 // nullspaceVelocity.setZero(nDoF);
269 //
270 // /// force torque
271 // currentForceTorque.setZero();
272 // safeFTGuardOffset.setZero();
273 //
274 // /// task space variables
275 // forceImpedance.setZero();
276 //
277 // /// current status
278 // qvelFiltered.setZero(nDoF);
279 // currentPose.setZero();
280 // currentTwist.setZero();
281 // desiredPose.setZero();
282 // desiredPoseUnsafe.setZero();
283 //
284 // /// intermediate results
285 // poseDiffMatImp.setZero();
286 // poseErrorImp.setZero();
287 // oriDiffAngleAxis = Eigen::AngleAxisf::Identity();
288 //
289 // /// others
290 // jacobi.setZero(6, nDoF);
291 // jtpinv.setZero(6, nDoF);
292 // jpinv.setZero(nDoF, 6);
293 // rtSafe = false;
294 // rtTargetSafe = true;
295 // }
296 //
297 // void
298 // TaskspaceMixedImpedanceVelocityController::RtStatus::rtPreActivate(
299 // const Eigen::Matrix4f& currentTCPPose)
300 // {
301 // /// !!!! TO BE UPDATED IN PREACTIVATE !!!!
302 // /// only then the up-to-date robot joint information is available
303 // currentPose = currentTCPPose;
304 // desiredPose = currentTCPPose;
305 // accumulateTime = 0.0;
306 // }
307
308} // namespace armarx::control::common::control_law
#define M_PI
Definition MathTools.h:17
constexpr T c
void initialize(const VirtualRobot::RobotNodeSetPtr &rns, const VirtualRobot::RobotNodeSetPtr &rtRns, const std::vector< size_t > &torqueControlledIndex, const std::vector< size_t > &velocityControlledIndex)
bool isControlModeValid(const std::vector< std::string > &nameList, const std::map< std::string, std::string > &jointControlModeMap)
common::control_law::arondto::TaskspaceMixedImpedanceVelocityControllerConfig Config
#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_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
Eigen::Vector6f cartesianVelTarget
for impedance control
Definition common.h:75
Eigen::MatrixXf jtpinv
pseudo inverse of the jacobi transpose [6, nDoF], for torque control
Definition common.h:118
Eigen::MatrixXf I
for computing nullspace projection
Definition common.h:124
Eigen::MatrixXf jpinv
pseudo inverse of the jacobi [nDoF, 6], for vel control
Definition common.h:121
Eigen::MatrixXf jacobi
others jacobi matrix [6, nDoF]
Definition common.h:116
Eigen::Matrix3f poseDiffMatImp
intermediate results
Definition common.h:85
Eigen::VectorXf qvelFiltered
for velocity control
Definition common.h:78
float lambda
damping term for pseudo inverse of jacobian
Definition common.h:127
Eigen::Vector6f forceImpedance
task space variables (command in operation space)
Definition common.h:74