一、简介
在使用SDK操作机器人时,常常需要用到正逆解等功能。本文重点讲述这些功能的使用方法。
二、操作流程
1、SDK里正逆解基于三方库KDL,需要该库的动态链接库,在代码仓里已经打包进去。编译时加上编译选项-DELITE_COMPILE_KIN_PLUGIN=ON
2、在不同的平台,存放位置不同,linux上位于plugin/kinematics/libelite_kdl_kinematics.so,windows上位于kin_plugin/KdlKinematicsPlugin/elite_kdl_kinematics.dll,需要采用宏判断加载不同平台的动态链接库类型。
3、首先需要连接Primary端口,获取kinematics info信息。
4、接着通过实例化KinematicsBase,并设置MDH,来获取FK 和 IK。
三、常见问题
1、Q:为什么会逆解失败?
A:大概率因为此时是奇异点,此时除数为零导致没有解,故逆解失败。
四、代码和附件
// SPDX-License-Identifier: MIT
// Copyright (c) 2025, Elite Robots.
#include <Elite/ClassLoader.hpp>
#include <Elite/KinematicsBase.hpp>
#include <Elite/Log.hpp>
#include <Elite/PrimaryPortInterface.hpp>
#include <Elite/RobotConfPackage.hpp>
#include <Elite/RobotException.hpp>
#include <Elite/RtsiIOInterface.hpp>
#include <boost/program_options.hpp>
#include <chrono>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
using namespace std::chrono;
using namespace ELITE;
namespace po = boost::program_options;
void logVector6d(const std::string& prefix, const vector6d_t& vec) {
std::string vec_str;
vec_str += "[";
for (const auto& val : vec) {
vec_str += std::to_string(val) + ", ";
}
vec_str += "]";
ELITE_LOG_INFO("%s %s", prefix.c_str(), vec_str.c_str());
}
int main(int argc, const char** argv) {
#if defined(ELITE_COMPILE_KIN_PLUGIN)
// Parse the ip arguments if given
std::string robot_ip;
// Parser param
po::options_description desc(
"Usage:\n"
"\t./kinematics_example <--robot-ip=ip>\n"
"Parameters:");
desc.add_options()("help,h", "Print help message")("robot-ip", po::value<std::string>(&robot_ip)->required(),
"\tRequired. IP address of the robot.");
po::variables_map vm;
try {
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("help")) {
std::cout << desc << std::endl;
return 0;
}
po::notify(vm);
} catch (const po::error& e) {
std::cerr << "Argument error: " << e.what() << "\n\n";
std::cerr << desc << "\n";
return 1;
}
auto primary = std::make_unique<PrimaryPortInterface>();
auto kin_info = std::make_shared<KinematicsInfo>();
// Connect robot 30001 port and get MDH param
if (!primary->connect(robot_ip, 30001)) {
ELITE_LOG_FATAL("Connect robot 30001 port fail.");
return 1;
}
if (!primary->getPackage(kin_info, 200)) {
ELITE_LOG_FATAL("Get robot kinematics info fail.");
return 1;
}
primary->disconnect();
ELITE_LOG_INFO("Got robot kinematics info.");
std::unique_ptr<RtsiIOInterface> io_interface = std::make_unique<RtsiIOInterface>("output_recipe.txt", "input_recipe.txt", 250);
if (!io_interface->connect(robot_ip)) {
ELITE_LOG_FATAL("Connect robot RTSI port fail.");
return 1;
}
auto current_joint = io_interface->getActualJointPositions();
ELITE_LOG_INFO("Got robot actual joint positions.");
auto current_tcp = io_interface->getActualTCPPose();
ELITE_LOG_INFO("Got robot actual TCP positions.");
#if defined(__linux__)
ClassLoader loader("../plugin/kinematics/libelite_kdl_kinematics.so");
#elif defined(_WIN32)
ClassLoader loader("../kin_plugin/KdlKinematicsPlugin/elite_kdl_kinematics.dll");
#else
#error "Unsupported platform"
#endif
if (!loader.loadLib()) {
ELITE_LOG_FATAL("Load plugin fail.");
return 1;
}
auto kin_solver = loader.createUniqueInstance<KinematicsBase>("ELITE::KdlKinematicsPlugin");
if (kin_solver == nullptr) {
ELITE_LOG_FATAL("Create KinematicsBase fail");
return 1;
}
// Set MDH params
kin_solver->setMDH(kin_info->dh_alpha_, kin_info->dh_a_, kin_info->dh_d_);
// Get FK and IK
vector6d_t fk_pose;
if (!kin_solver->getPositionFK(current_joint, fk_pose)) {
ELITE_LOG_FATAL("Get FK fail.");
return 1;
}
vector6d_t ik_joints;
KinematicsResult ik_result;
if (!kin_solver->getPositionIK(current_tcp, current_joint, ik_joints, ik_result)) {
ELITE_LOG_FATAL("Get IK fail.");
return 1;
}
logVector6d("Current TCP Pose:", current_tcp);
logVector6d("FK Pose:", fk_pose);
logVector6d("IK Result Joints:", ik_joints);
logVector6d("Current Joints:", current_joint);
#endif
return 0;
}