inspiredhand/jaka_robot/robot_controller.cpp

393 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "robot_controller.h"
#include <iostream>
#include <array>
#include <fstream>
#include <ctime>
#include <cstdio>
#include <sstream>
#include <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include <thread>
#include <chrono>
#include "error_codes.h"
#include "tools/tools.h"
#if defined(_WIN32)
#include <direct.h>
#else
#include <unistd.h>
#include <limits.h>
#endif
#if !defined(_WIN32)
#include <sys/stat.h>
#include <sys/types.h>
#endif
namespace {
// 将极小的浮点误差归零,避免打印出 -4.33e-19 这类值
inline double clamp_near_zero(double v, double eps = 1e-8)
{
return (std::fabs(v) < eps) ? 0.0 : v;
}
} // namespace
RobotController::RobotController() {
connected_ = false;
}
RobotController::~RobotController() {
if (connected_) {
demo_.login_out();
connected_ = false;
}
}
bool RobotController::connect(const std::string &addr) {
errno_t ret = demo_.login_in(addr.c_str());
if (ret == 0) {
connected_ = true;
return true;
}
std::cerr << "connect failed, err=" << ret << std::endl;
return false;
}
// ----------------- 速度/加速度 getter/setter 实现 -----------------
void RobotController::setJointSpeedDeg(double v) { joint_speed_deg_s_ = v; }
double RobotController::getJointSpeedDeg() const { return joint_speed_deg_s_; }
double RobotController::getJointSpeedRad() const { return joint_speed_deg_s_ * M_PI / 180.0; }
void RobotController::setJointAccDeg(double a) { joint_acc_deg_s2_ = a; }
double RobotController::getJointAccDeg() const { return joint_acc_deg_s2_; }
double RobotController::getJointAccRad() const { return joint_acc_deg_s2_ * M_PI / 180.0; }
void RobotController::setLineSpeed(double v_mm_s) { line_speed_mm_s_ = v_mm_s; }
double RobotController::getLineSpeed() const { return line_speed_mm_s_; }
void RobotController::setLineAcc(double a_mm_s2) { line_acc_mm_s2_ = a_mm_s2; }
double RobotController::getLineAcc() const { return line_acc_mm_s2_; }
void RobotController::setPoseSpeedDeg(double v_deg_s) { pose_speed_deg_s_ = v_deg_s; }
double RobotController::getPoseSpeedDeg() const { return pose_speed_deg_s_; }
double RobotController::getPoseSpeedRad() const { return pose_speed_deg_s_ * M_PI / 180.0; }
void RobotController::setPoseAccDeg(double a_deg_s2) { pose_acc_deg_s2_ = a_deg_s2; }
double RobotController::getPoseAccDeg() const { return pose_acc_deg_s2_; }
double RobotController::getPoseAccRad() const { return pose_acc_deg_s2_ * M_PI / 180.0; }
void RobotController::disconnect() {
if (connected_) {
demo_.login_out();
connected_ = false;
}
}
bool RobotController::powerOn() {
errno_t ret = demo_.power_on();
if (ret != 0) std::cerr << "power_on failed: " << ret << std::endl;
return ret == 0;
}
bool RobotController::powerOff() {
errno_t ret = demo_.power_off();
if (ret != 0) std::cerr << "power_off failed: " << ret << std::endl;
return ret == 0;
}
bool RobotController::enableRobot() {
errno_t ret = demo_.enable_robot();
if (ret != 0) std::cerr << "enable_robot failed: " << ret << std::endl;
return ret == 0;
}
bool RobotController::disableRobot() {
errno_t ret = demo_.disable_robot();
if (ret != 0) std::cerr << "disable_robot failed: " << ret << std::endl;
return ret == 0;
}
bool RobotController::getTcpPose(CartesianPose &pose) {
errno_t ret = demo_.get_tcp_position(&pose);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "get_tcp_position failed: " << ret << " -> " << describeError(ret) << std::endl;
return false;
}
// 对返回的姿态做一次浮点误差归零(尤其是接近 0 的角度/位置)
pose.tran.x = clamp_near_zero(pose.tran.x);
pose.tran.y = clamp_near_zero(pose.tran.y);
pose.tran.z = clamp_near_zero(pose.tran.z);
pose.rpy.rx = clamp_near_zero(pose.rpy.rx);
pose.rpy.ry = clamp_near_zero(pose.rpy.ry);
pose.rpy.rz = clamp_near_zero(pose.rpy.rz);
return true;
}
bool RobotController::getJointPositions(std::array<double,6> &out_joints_rad) {
JointValue jv;
errno_t ret = demo_.get_joint_position(&jv);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "get_joint_position failed: " << ret << " -> " << describeError(ret) << std::endl;
return false;
}
for (int i = 0; i < 6; ++i) {
out_joints_rad[i] = clamp_near_zero(jv.jVal[i]);
}
return true;
}
bool RobotController::getJointPositionsDeg(std::array<double,6> &out_joints_deg) {
std::array<double,6> rads;
if (!getJointPositions(rads)) return false;
for (int i = 0; i < 6; ++i) {
double deg = rads[i] * 180.0 / M_PI;
out_joints_deg[i] = clamp_near_zero(deg);
}
return true;
}
bool RobotController::forwardKinematics(const std::array<double,6> &joints_rad, CartesianPose &out_pose) {
JointValue jv;
for (int i = 0; i < 6; ++i) {
jv.jVal[i] = joints_rad[i];
}
errno_t ret = demo_.kine_forward(&jv, &out_pose);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "kine_forward failed: " << ret << " -> " << describeError(ret) << std::endl;
return false;
}
// 对计算结果做一次浮点误差归零
out_pose.tran.x = clamp_near_zero(out_pose.tran.x);
out_pose.tran.y = clamp_near_zero(out_pose.tran.y);
out_pose.tran.z = clamp_near_zero(out_pose.tran.z);
out_pose.rpy.rx = clamp_near_zero(out_pose.rpy.rx);
out_pose.rpy.ry = clamp_near_zero(out_pose.rpy.ry);
out_pose.rpy.rz = clamp_near_zero(out_pose.rpy.rz);
last_errno_ = ERR_SUCC;
return true;
}
bool RobotController::moveCartesianOffset(const std::array<double,6> &offset, MoveMode mode, double lin_speed, double lin_acc) {
// offset: dx,dy,dz (mm), drx,dry,drz (deg)
CartesianPose pose;
if (!getTcpPose(pose)) return false;
pose.tran.x += offset[0];
pose.tran.y += offset[1];
pose.tran.z += offset[2];
// orientation offsets: input degrees -> convert to radians
pose.rpy.rx += offset[3] * M_PI / 180.0;
pose.rpy.ry += offset[4] * M_PI / 180.0;
pose.rpy.rz += offset[5] * M_PI / 180.0;
double use_lin_speed = lin_speed > 0.0 ? lin_speed : line_speed_mm_s_;
double use_lin_acc = lin_acc > 0.0 ? lin_acc : line_acc_mm_s2_;
double ori_vel = getPoseSpeedRad();
double ori_acc = getPoseAccRad();
errno_t ret = demo_.linear_move(&pose, mode, TRUE, use_lin_speed, use_lin_acc, 1, NULL, ori_vel, ori_acc);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "moveCartesianOffset linear_move failed: " << ret << " -> " << describeError(ret) << std::endl;
// 不自动重试,按用户要求只报告错误信息
return false;
}
last_errno_ = ERR_SUCC;
return true;
}
bool RobotController::moveLinearToPose(const CartesianPose &pose,
MoveMode mode,
bool is_block,
double speed,
double accel,
double tol) {
CartesianPose target = pose;
double use_speed = speed > 0.0 ? speed : line_speed_mm_s_;
double use_acc = accel > 0.0 ? accel : line_acc_mm_s2_;
double ori_vel = getPoseSpeedRad();
double ori_acc = getPoseAccRad();
errno_t ret = demo_.linear_move(&target,
mode,
is_block ? TRUE : FALSE,
use_speed,
use_acc,
tol,
nullptr,
ori_vel,
ori_acc);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "moveLinearToPose linear_move failed: " << ret
<< " -> " << describeError(ret) << std::endl;
return false;
}
last_errno_ = ERR_SUCC;
return true;
}
bool RobotController::moveZRelative(double delta_z, double velocity, double accel) {
CartesianPose pose;
if (!getTcpPose(pose)) return false;
// 提示:传入 delta_z 单位为 mm正值为向上
pose.tran.z += delta_z;
errno_t ret = demo_.linear_move(&pose, ABS, true, velocity, accel, 1, NULL);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "linear_move failed: " << ret << " -> " << describeError(ret) << std::endl;
return false;
}
return true;
}
bool RobotController::moveCircular(const CartesianPose &mid_pos,
const CartesianPose &end_pos,
MoveMode mode,
bool is_block,
double speed,
double accel,
double tol,
int circle_cnt,
int circle_mode) {
CartesianPose mid = mid_pos;
CartesianPose end = end_pos;
double use_speed = speed > 0.0 ? speed : line_speed_mm_s_;
double use_acc = accel > 0.0 ? accel : line_acc_mm_s2_;
errno_t ret = demo_.circular_move(&end,
&mid,
mode,
is_block ? TRUE : FALSE,
use_speed,
use_acc,
tol,
nullptr,
circle_cnt,
circle_mode);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "moveCircular circular_move failed: " << ret
<< " -> " << describeError(ret) << std::endl;
return false;
}
last_errno_ = ERR_SUCC;
return true;
}
bool RobotController::moveJoints(const std::array<double,6> &joints, MoveMode mode, bool is_block, double speed, double acc, double tol) {
JointValue jv;
for (int i = 0; i < 6; ++i) jv.jVal[i] = joints[i];
errno_t ret = demo_.joint_move(&jv, mode, is_block ? TRUE : FALSE, speed, acc, tol, nullptr);
if (ret != 0) {
last_errno_ = ret;
std::cerr << "joint_move failed: " << ret << " -> " << describeError(ret) << std::endl;
return false;
}
return true;
}
void RobotController::motionAbort() {
demo_.motion_abort();
}
std::string RobotController::getSdkVersion() {
char ver[128] = {0};
demo_.get_sdk_version(ver);
return std::string(ver);
}
bool RobotController::recordCurrentPose(const std::string &comment, const std::string &fname) {
std::string out_fname = fname;
if (out_fname.empty()) {
out_fname = tools::get_cwd() + std::string("/../actions/recorded_points.csv");
}
// 确保目录存在(../actions
std::string dir = out_fname;
auto pos = dir.find_last_of('/');
if (pos == std::string::npos) pos = dir.find_last_of('\\');
if (pos != std::string::npos) dir = dir.substr(0, pos);
if (!dir.empty()) {
#if defined(_WIN32)
_mkdir(dir.c_str());
#else
mkdir(dir.c_str(), 0755);
#endif
}
std::array<double,6> cur_deg;
if (!getJointPositionsDeg(cur_deg)) {
last_errno_ = -1;
std::cerr << "recordCurrentPose: 获取关节位姿失败\n";
return false;
}
std::ofstream ofs(out_fname.c_str(), std::ios::app);
if (!ofs) {
std::cerr << "recordCurrentPose: 无法打开文件: " << out_fname << std::endl;
return false;
}
auto t = std::time(nullptr);
ofs << t;
for (int i=0;i<6;++i) ofs << "," << cur_deg[i];
ofs << "," << '"' << comment << '"' << std::endl;
ofs.close();
return true;
}
bool RobotController::deleteRecordedFile(const std::string &fname) {
std::string out_fname = fname;
if (out_fname.empty()) {
out_fname = tools::get_cwd() + std::string("/../actions/recorded_points.csv");
}
if (std::remove(out_fname.c_str()) == 0) return true;
return false;
}
bool RobotController::replayRecordedPoints(const std::string &fname) {
std::string in_fname = fname;
if (in_fname.empty()) in_fname = tools::get_cwd() + std::string("/../actions/recorded_points.csv");
std::ifstream ifs(in_fname.c_str());
if (!ifs) {
std::cerr << "无法打开记录文件: " << in_fname << std::endl;
return false;
}
std::string line;
int idx_line = 0;
while (std::getline(ifs, line)) {
++idx_line;
if (line.empty()) continue;
std::stringstream ss(line);
std::string token;
if (!std::getline(ss, token, ',')) { std::cerr << "解析第"<<idx_line<<"行失败\n"; continue; }
std::array<double,6> joints_deg = {0,0,0,0,0,0};
bool ok_parse = true;
for (int i=0;i<6;++i) {
if (!std::getline(ss, token, ',')) { ok_parse = false; break; }
try { joints_deg[i] = std::stod(token); } catch(...) { ok_parse = false; break; }
}
if (!ok_parse) { std::cerr << "解析第"<<idx_line<<"行关节数据失败\n"; continue; }
std::string comment;
if (std::getline(ss, comment)) {
if (!comment.empty() && comment.front() == '"') comment.erase(0,1);
if (!comment.empty() && comment.back() == '"') comment.pop_back();
} else comment = "";
std::array<double,6> joints_rad;
for (int i=0;i<6;++i) joints_rad[i] = joints_deg[i] * M_PI / 180.0;
std::cout << "复现第"<<idx_line<<",注释: " << comment << "\n";
bool moved = moveJoints(joints_rad, ABS, true, getJointSpeedRad(), getJointAccRad());
if (!moved) {
std::cerr << "移动到记录点 "<<idx_line<<" 失败,错误码="<< getLastErrorCode() <<"\n";
std::cout << "是否继续下一个点?(y/n): "; std::string yes; if (!std::getline(std::cin, yes)) yes = "n";
if (yes != "y" && yes != "Y") { ifs.close(); return false; }
} else {
std::cout << "完成第"<<idx_line<<"个点\n";
}
}
ifs.close();
std::cout << "顺序复现结束。\n";
return true;
}