33 #include <ArmarXGui/interface/StaticPlotterInterface.h>
36 #include <RobotAPI/interface/units/RobotUnit/NjointZeroTorqueController.h>
44 Component::defaultName =
"controller_creator";
60 def->optional(properties.robotName,
"robotName");
61 def->optional(properties.robotUnitName,
"robotUnitName");
63 def->optional(properties.defaultRobotNodeSetLeft,
"default_robotNodeSet_left",
"default kinematic chain name of left arm.");
64 def->optional(properties.defaultRobotNodeSetRight,
"default_robotNodeSet_right",
"default kinematic chain name of right arm.");
66 def->component(m_robot_unit, properties.robotUnitName);
67 def->component(m_force_torque_observer, properties.ftObserverName);
136 m_robot =
addRobot(
"controller_creator_robot", VirtualRobot::RobotIO::eStructure);
141 m_rns_l = m_robot->getRobotNodeSet(properties.defaultRobotNodeSetLeft);
142 m_rns_r = m_robot->getRobotNodeSet(properties.defaultRobotNodeSetRight);
164 Component::createImpedanceController(
165 const std::string& controllerNamePrefix,
166 const std::string& robotNodeSet,
167 const std::string& configFilename)
170 auto builder = controllerBuilder<control::common::ControllerType::TSImpedance>();
171 builder.withNodeSet(robotNodeSet).withNamePrefix(controllerNamePrefix);
175 if (configFilename.empty())
177 const std::string controllerClassName =
179 const armarx::PackagePath configPath(
"armarx_control",
"controller_config/" + controllerClassName +
"/default.json");
181 ARMARX_CHECK(std::filesystem::exists(configPath.toSystemPath()));
183 builder.withConfig(configPath.toSystemPath());
187 builder.withConfig(configFilename);
198 if (builder.config().desiredNullspaceJointAngles.has_value())
206 const auto rns = m_robot->getRobotNodeSet(robotNodeSet);
209 builder.config().desiredPose = rns->getTCP()->getPoseInRootFrame();
215 auto ctrlWrapper = builder.create();
216 const std::string controllerName = builder.getControllerName();
217 m_robotNodeSets[controllerName] = rns;
218 m_controllerJointNumbers[controllerName] = rns->getJointValues().size();
222 ctrlWrapper->daemonize(
true);
226 m_ctrlTSImpedance[controllerName] = std::nullopt;
227 m_ctrlTSImpedance[controllerName].emplace(std::move(ctrlWrapper.value()));
231 m_ctrlTSImpedance[controllerName]->updateConfig();
232 m_ctrlTSImpedance[controllerName]->activate();
234 m_prevTargetPose[controllerName] = rns->getTCP()->getPoseInRootFrame();
235 m_prevNullspaceJointTarget[controllerName] = rns->getJointValuesEigen();
236 return controllerName;
240 Component::createImpedanceMPController(
241 const std::string& controllerNamePrefix,
242 const std::string& robotNodeSet,
243 const std::string& configFilename)
246 auto builder = controllerBuilder<control::common::ControllerType::TSImpedanceMP>();
247 builder.allowReuse(
true).withNodeSet(robotNodeSet).withNamePrefix(controllerNamePrefix);
251 if (configFilename.empty())
253 const std::string controllerClassName =
255 const armarx::PackagePath configPath(
"armarx_control",
"controller_config/" + controllerClassName +
"/default.json");
257 ARMARX_CHECK(std::filesystem::exists(configPath.toSystemPath()));
259 builder.withConfig(configPath.toSystemPath());
263 builder.withConfig(configFilename);
274 if (builder.config().desiredNullspaceJointAngles.has_value())
282 const auto rns = m_robot->getRobotNodeSet(robotNodeSet);
285 builder.config().desiredPose = rns->getTCP()->getPoseInRootFrame();
291 auto ctrlWrapper = builder.create();
292 const std::string controllerName = builder.getControllerName();
293 m_robotNodeSets[controllerName] = rns;
294 m_controllerJointNumbers[controllerName] = rns->getJointValues().size();
298 ctrlWrapper->daemonize(
true);
302 m_ctrlTSImpedanceMP[controllerName] = std::nullopt;
303 m_ctrlTSImpedanceMP[controllerName].emplace(std::move(ctrlWrapper.value()));
307 m_ctrlTSImpedanceMP[controllerName]->updateConfig();
313 m_ctrlTSImpedanceMP[controllerName]->activate();
315 m_prevTargetPose[controllerName] = rns->getTCP()->getPoseInRootFrame();
316 m_prevNullspaceJointTarget[controllerName] = rns->getJointValuesEigen();
327 return controllerName;
331 Component::createAdmittanceController(
332 const std::string &controllerNamePrefix,
333 const std::string &robotNodeSet,
334 const std::string& configFilename)
336 ARMARX_INFO <<
"creating ts admittance controller";
338 auto builder = controllerBuilder<control::common::ControllerType::TSAdmittance>();
339 builder.withNodeSet(robotNodeSet).withNamePrefix(controllerNamePrefix);
343 if (configFilename.empty())
345 const std::string controllerClassName =
347 const armarx::PackagePath configPath(
"armarx_control",
"controller_config/" + controllerClassName +
"/default.json");
349 ARMARX_CHECK(std::filesystem::exists(configPath.toSystemPath()));
351 builder.withConfig(configPath.toSystemPath());
355 builder.withConfig(configFilename);
362 const auto rns = m_robot->getRobotNodeSet(robotNodeSet);
364 builder.config().desiredPose = rns->getTCP()->getPoseInRootFrame();
370 auto ctrlWrapper = builder.create();
371 const std::string controllerName = builder.getControllerName();
372 m_robotNodeSets[controllerName] = rns;
373 m_controllerJointNumbers[controllerName] = rns->getJointValues().size();
377 ctrlWrapper->daemonize(
true);
381 m_ctrlTSAdmittance[controllerName] = std::nullopt;
382 m_ctrlTSAdmittance[controllerName].emplace(std::move(ctrlWrapper.value()));
386 m_ctrlTSAdmittance[controllerName]->updateConfig();
387 m_ctrlTSAdmittance[controllerName]->activate();
389 m_prevTargetPose[controllerName] = rns->getTCP()->getPoseInRootFrame();
390 m_prevNullspaceJointTarget[controllerName] = rns->getJointValuesEigen();
391 return controllerName;
397 const std::string& controllerNamePrefix,
398 const std::string& robotNodeSet,
399 const std::string& controllerType,
400 const std::string& configFilename,
403 ARMARX_INFO <<
"creating controller of type " << controllerType <<
" with robot node set " << robotNodeSet;
406 robotUnit->loadLibFromPackage(
"armarx_control",
"libarmarx_control_njoint_controller");
408 std::string controllerName;
413 controllerName = createImpedanceController(controllerNamePrefix, robotNodeSet, configFilename);
416 controllerName = createAdmittanceController(controllerNamePrefix, robotNodeSet, configFilename);
419 controllerName = createImpedanceMPController(controllerNamePrefix, robotNodeSet, configFilename);
423 ARMARX_INFO <<
"controller type: " << controllerType <<
" is not supported yet";
425 return controllerName;
430 const std::string &controllerName,
431 const std::string& controllerType,
432 const Ice::FloatSeq& targetPoseVector,
436 const bool is_in =
names.find(controllerType) !=
names.end();
443 if (targetPoseVector.size() != 7)
445 ARMARX_ERROR <<
"target pose vector " << targetPoseVector <<
" should follow (x, y, z, w, rx, ry, rz) convention";
449 m_prevTargetPose[controllerName] = VirtualRobot::MathTools::quat2eigen4f(targetPoseVector.at(4), targetPoseVector.at(5), targetPoseVector.at(6), targetPoseVector.at(3));
450 m_prevTargetPose[controllerName](0, 3) = targetPoseVector.at(0);
451 m_prevTargetPose[controllerName](1, 3) = targetPoseVector.at(1);
452 m_prevTargetPose[controllerName](2, 3) = targetPoseVector.at(2);
458 m_ctrlTSImpedance[controllerName]->config.desiredPose = m_prevTargetPose[controllerName];
459 m_ctrlTSImpedance[controllerName]->config.desiredNullspaceJointAngles = m_prevNullspaceJointTarget[controllerName];
460 m_ctrlTSImpedance[controllerName]->updateConfig();
464 m_ctrlTSAdmittance[controllerName]->config.desiredPose = m_prevTargetPose[controllerName];
465 m_ctrlTSAdmittance[controllerName]->config.desiredNullspaceJointAngles = m_prevNullspaceJointTarget[controllerName];
466 m_ctrlTSAdmittance[controllerName]->updateConfig();
470 ARMARX_INFO <<
"controller type: " << controllerType <<
" is not supported yet";
478 const std::string &controllerName,
479 const std::string &controllerType,
480 const Ice::FloatSeq& targetNullspaceJointAngle,
481 const Ice::Current &)
484 const bool is_in =
names.find(controllerType) !=
names.end();
485 ARMARX_CHECK_EQUAL(m_controllerJointNumbers[controllerName], targetNullspaceJointAngle.size());
492 Eigen::VectorXf targetJointAngles = Eigen::VectorXf::Zero(m_controllerJointNumbers[controllerName]);
493 for (
size_t i = 0; i < m_controllerJointNumbers[controllerName]; i++)
495 targetJointAngles(i) = targetNullspaceJointAngle[i];
502 m_ctrlTSImpedance[controllerName]->config.desiredNullspaceJointAngles = targetJointAngles;
503 m_ctrlTSImpedance[controllerName]->updateConfig();
507 m_ctrlTSAdmittance[controllerName]->config.desiredNullspaceJointAngles = targetJointAngles;
508 m_ctrlTSAdmittance[controllerName]->updateConfig();
512 ARMARX_INFO <<
"controller type: " << controllerType <<
" is not supported yet";
520 const std::string &controllerName,
521 const std::string &controllerType,
522 const Ice::FloatSeq& targetPoseVector,
523 const Ice::FloatSeq& targetNullspaceJointAngle,
524 const Ice::Current &)
527 const bool is_in =
names.find(controllerType) !=
names.end();
534 bool updataPose =
false;
535 if (targetPoseVector.size() > 0)
537 if (targetPoseVector.size() != 7)
539 ARMARX_ERROR <<
"target pose vector " << targetPoseVector <<
" should follow (x, y, z, w, rx, ry, rz) convention";
543 m_prevTargetPose[controllerName] = VirtualRobot::MathTools::quat2eigen4f(targetPoseVector.at(4), targetPoseVector.at(5), targetPoseVector.at(6), targetPoseVector.at(3));
544 m_prevTargetPose[controllerName](0, 3) = targetPoseVector.at(0);
545 m_prevTargetPose[controllerName](1, 3) = targetPoseVector.at(1);
546 m_prevTargetPose[controllerName](2, 3) = targetPoseVector.at(2);
549 bool updateNullspace =
false;
550 if (targetNullspaceJointAngle.size() > 0)
552 for (
size_t i = 0; i < m_controllerJointNumbers[controllerName]; i++)
554 m_prevNullspaceJointTarget[controllerName](i) = targetNullspaceJointAngle[i];
565 m_ctrlTSImpedance[controllerName]->config.desiredPose = m_prevTargetPose[controllerName];
569 m_ctrlTSImpedance[controllerName]->config.desiredNullspaceJointAngles = m_prevNullspaceJointTarget[controllerName];
571 m_ctrlTSImpedance[controllerName]->updateConfig();
577 m_ctrlTSAdmittance[controllerName]->config.desiredPose = m_prevTargetPose[controllerName];
581 m_ctrlTSAdmittance[controllerName]->config.desiredNullspaceJointAngles = m_prevNullspaceJointTarget[controllerName];
583 m_ctrlTSAdmittance[controllerName]->updateConfig();
587 ARMARX_INFO <<
"controller type: " << controllerType <<
" is not supported yet";
595 const std::string& kinematicChainName,
596 const std::string& side,
597 const std::string& fileName,
601 ARMARX_INFO <<
"Kinesthetic teaching: Initialize zero torque controllers for " <<
VAROUT(kinematicChainName);
602 const std::string ctrl_class_name =
"NJointZeroTorqueController";
603 const std::string ctrl_name =
getDefaultName() +
"_kinesthetic_teaching_" + ctrl_class_name;
605 NJointZeroTorqueControllerConfigPtr config(
new NJointZeroTorqueControllerConfig());
606 config->maxTorque = 0;
608 auto nodeSet = m_robot->getRobotNodeSet(kinematicChainName);
609 for (
auto& name : nodeSet->getNodeNames())
611 config->jointNames.push_back(name);
613 NJointZeroTorqueControllerInterfacePrx zeroTorqueController
614 = NJointZeroTorqueControllerInterfacePrx::checkedCast(
615 m_robot_unit->createNJointController(
622 float motionThresholdRadian = 0.1f;
623 float noMotionTimeoutMs = 2000.0f;
625 VirtualRobot::RobotNodeSetPtr rns = m_robot->getRobotNodeSet(kinematicChainName);
626 std::vector<std::string> jointNames = rns->getNodeNames();
629 bool initialMotionDetected =
false;
633 std::vector<std::vector<float>> jointData;
634 std::vector<std::vector<float>> cartData;
635 std::vector<float> timestamps;
638 Eigen::VectorXf jve = rns->getJointValuesEigen();
644 for (
size_t i = 0; i < jointNames.size(); i++)
646 std::vector<float> cjoint {};
648 jointData.push_back(cjoint);
652 float quatvec[] = {initPose(0, 3), initPose(1, 3), initPose(2, 3), initQuat.w, initQuat.x, initQuat.y, initQuat.z};
653 for (
size_t i = 0; i < 7; ++i)
655 std::vector<float> cpos {};
657 cartData.push_back(cpos);
661 int motionStartIndex = 0;
662 int motionEndIndex = 0;
667 float forceSpike = 0.0f;
668 Eigen::Vector3f initForce;
671 initForce = m_ft_r->getForce();
675 initForce = m_ft_l->getForce();
677 ARMARX_IMPORTANT <<
"=============== Waiting for force spike ===============";
678 while (forceSpike < 10.0f)
680 Eigen::Vector3f force;
683 force = m_ft_r->getForce();
687 force = m_ft_l->getForce();
689 forceSpike = (force - initForce).
norm();
693 zeroTorqueController->activateController();
700 Eigen::VectorXf jve2 = rns->getJointValuesEigen();
701 if ((jve2 - jve).
norm() > motionThresholdRadian)
703 if (!initialMotionDetected)
706 motionStartIndex = 0;
710 initialMotionDetected =
true;
711 lastMotionTime = now;
714 double t = (now - start).toSecondsDouble();
716 std::vector<float> jvs = rns->getJointValues();
717 for (
size_t i = 0; i < jvs.size(); i++)
719 jointData.at(i).push_back(jvs.at(i));
723 cartData.at(0).push_back(tcpPose(0, 3));
724 cartData.at(1).push_back(tcpPose(1, 3));
725 cartData.at(2).push_back(tcpPose(2, 3));
729 double dotProduct = quat.w * oldquatE.w + quat.x * oldquatE.x + quat.y * oldquatE.y + quat.z * oldquatE.z;
732 cartData.at(3).push_back(-quat.w);
733 cartData.at(4).push_back(-quat.x);
734 cartData.at(5).push_back(-quat.y);
735 cartData.at(6).push_back(-quat.z);
736 oldquatE.w = -quat.w;
737 oldquatE.x = -quat.x;
738 oldquatE.y = -quat.y;
739 oldquatE.z = -quat.z;
744 cartData.at(3).push_back(quat.w);
745 cartData.at(4).push_back(quat.x);
746 cartData.at(5).push_back(quat.y);
747 cartData.at(6).push_back(quat.z);
755 timestamps.push_back(t);
757 if (initialMotionDetected && (now - lastMotionTime).toMilliSeconds() > noMotionTimeoutMs)
760 motionEndIndex = timestamps.size();
768 zeroTorqueController->deactivateController();
769 while (zeroTorqueController->isControllerActive())
773 zeroTorqueController->deleteController();
776 motionStartIndex -= sigmaMs / sampleMs * 2;
777 if (motionStartIndex < 0)
779 motionStartIndex = 0;
790 timestamps = std::vector<float>(timestamps.begin() + motionStartIndex, timestamps.begin() + motionEndIndex);
791 for (
size_t n = 1; n < timestamps.size(); n++)
793 timestamps.at(n) = timestamps.at(n) - timestamps.at(0);
795 timestamps.at(0) = 0;
802 StringFloatSeqDict plotFiltered;
803 StringFloatSeqDict plotOrig;
804 StringFloatSeqDict plotResampled;
805 for (
size_t i = 0; i < jointData.size(); i++)
807 jointData.at(i) = std::vector<float>(jointData.at(i).begin() + motionStartIndex, jointData.at(i).begin() + motionEndIndex);
808 if (rns->getNode(i)->isLimitless())
812 plotOrig[jointNames.at(i)] = jointData.at(i);
814 plotResampled[jointNames.at(i)] = jointData.at(i);
816 plotFiltered[jointNames.at(i)] = jointData.at(i);
823 std::vector<std::string> cartName = {
"x",
"y",
"z",
"qw",
"qx",
"qy",
"qz"};
827 std::string trajName;
830 time_t timer = now.toSeconds();
833 ts = localtime(&timer);
834 strftime(buffer, 80,
"%Y-%m-%d-%H-%M-%S", ts);
835 std::string
str(buffer);
836 trajName = fileName +
"-" +
str;
840 double cutoutTime = (noMotionTimeoutMs / 1000.0f) * 0.8;
842 std::string packageName =
"armarx_control";
845 std::string dataDir = finder.
getDataDir() +
"/" + packageName +
"/kinesthetic_teaching/";
846 std::string returnFileNamePattern = dataDir + trajName;
850 std::string dmpForwardFile;
851 std::string dmpBackwardFile;
853 std::vector<std::string> header;
854 header.push_back(
"timestamp");
855 for (
size_t i = 0; i < cartName.size(); ++i)
857 header.push_back(cartName.at(i));
860 std::string ffname = trajName +
"-ts-forward.csv";
861 std::string bfname = trajName +
"-ts-backward.csv";
862 dmpForwardFile = dataDir + ffname;
863 dmpBackwardFile = dataDir + bfname;
864 std::vector<std::string> fflist;
865 fflist.push_back(ffname);
867 std::vector<std::string> bflist;
868 bflist.push_back(bfname);
870 CsvWriter fwriter(dmpForwardFile, header,
false);
871 CsvWriter bwriter(dmpBackwardFile, header,
false);
873 ARMARX_IMPORTANT <<
"writing taskspace trajectory as " << ffname <<
" and " << bfname;
875 double endTime = timestamps.at(timestamps.size() - 1);
876 for (
size_t n = 0; n < timestamps.size(); n++)
879 std::vector<float> row;
880 row.push_back(timestamps.at(n));
881 for (
size_t i = 0; i < cartData.size(); i++)
883 row.push_back(cartData.at(i).at(n));
887 if (endTime - timestamps.at(n) < cutoutTime)
889 Eigen::Matrix4f endPose = VirtualRobot::MathTools::quat2eigen4f(row.at(5), row.at(6), row.at(7), row.at(4));
890 endPose(0, 3) = row.at(1);
891 endPose(1, 3) = row.at(2);
892 endPose(2, 3) = row.at(3);
898 for (
int n = timestamps.size() - 1; n >= 0 && nt <
static_cast<int>(timestamps.size()); n--, nt++)
900 std::vector<float> row;
901 row.push_back(timestamps.at(nt));
902 for (
size_t i = 0; i < cartData.size(); i++)
904 row.push_back(cartData.at(i).at(n));
910 Eigen::Matrix4f endPose = VirtualRobot::MathTools::quat2eigen4f(row.at(5), row.at(6), row.at(7), row.at(4));
911 endPose(0, 3) = row.at(1);
912 endPose(1, 3) = row.at(2);
913 endPose(2, 3) = row.at(3);
922 std::string dmpJSForwardFile;
923 std::string dmpJSBackwardFile;
925 std::vector<std::string> header;
926 header.push_back(
"timestamp");
927 for (
size_t i = 0; i < jointNames.size(); ++i)
929 header.push_back(jointNames.at(i));
932 std::string ffname = trajName +
"-js-forward.csv";
933 std::string bfname = trajName +
"-js-backward.csv";
934 dmpJSForwardFile = dataDir + ffname;
935 dmpJSBackwardFile = dataDir + bfname;
936 std::vector<std::string> fflist;
937 fflist.push_back(ffname);
939 std::vector<std::string> bflist;
940 bflist.push_back(bfname);
942 CsvWriter fwriter(dmpJSForwardFile, header,
false);
943 CsvWriter bwriter(dmpJSBackwardFile, header,
false);
945 ARMARX_IMPORTANT <<
"writing jointspace trajectory as " << ffname <<
" and " << bfname;
947 double endTime = timestamps.at(timestamps.size() - 1);
948 for (
size_t n = 0; n < timestamps.size(); n++)
951 std::vector<float> row;
952 row.push_back(timestamps.at(n));
953 for (
size_t i = 0; i < jointNames.size(); i++)
955 row.push_back(jointData.at(i).at(n));
959 if (endTime - timestamps.at(n) < cutoutTime)
961 std::vector<float> endJointValue;
962 for (
size_t i = 0; i < jointNames.size(); i++)
964 endJointValue.push_back(jointData.at(i).at(n));
970 ARMARX_INFO <<
"forward joint space data written to fine!";
972 for (
int n = timestamps.size() - 1; n >= 0 && nt <
static_cast<int>(timestamps.size()); n--, nt++)
974 std::vector<float> row;
975 row.push_back(timestamps.at(nt));
976 for (
size_t i = 0; i < jointNames.size(); i++)
978 row.push_back(jointData.at(i).at(n));
984 std::vector<float> endJointValue;
985 for (
size_t i = 0; i < jointNames.size(); i++)
987 endJointValue.push_back(jointData.at(i).at(n));
994 return returnFileNamePattern;
1004 std::vector<std::string> joint_names = m_rns_l->getNodeNames();
1006 NameControlModeMap control_modes;
1007 for (
const std::string& joint_name : joint_names)
1009 control_modes[joint_name] = eVelocityControl;
1010 target_vels[joint_name] = 0;
1015 std::vector<std::string> joint_names = m_rns_r->getNodeNames();
1017 NameControlModeMap control_modes;
1018 for (
const std::string& joint_name : joint_names)
1020 control_modes[joint_name] = eVelocityControl;
1021 target_vels[joint_name] = 0;
1035 Eigen::Matrix4f pose = m_robot->getRobotNode(nodeName)->getPoseInRootFrame();
1037 std::vector<Ice::Float> pose_seq;
1038 for (
int i = 0; i < pose.rows(); i++){
1039 for (
int j = 0; j < pose.cols(); j++){
1040 pose_seq.push_back(pose(i, j));
1048 const std::string &controllerName,
1049 const Ice::Current&)
1051 std::vector<Ice::Float> pose_seq;
1052 for (
int i = 0; i < m_prevTargetPose[controllerName].rows(); i++){
1053 for (
int j = 0; j < m_prevTargetPose[controllerName].cols(); j++){
1054 pose_seq.push_back(m_prevTargetPose[controllerName](i, j));
1062 const std::string &controllerName,
1063 const Ice::Current&)
1065 std::vector<Ice::Float> angle_seq;
1066 for (
int i = 0; i < m_prevNullspaceJointTarget[controllerName].rows(); i++){
1067 angle_seq.push_back(m_prevNullspaceJointTarget[controllerName](i));
1076 return Component::defaultName;
1083 return Component::defaultName;