0、写在前面
- 使用Matlab内置功能即可实现转码;
- 需要MinGW-w64 C/C++编译器的支持;
- 代码转换只针对“.m函数文件”,而不是“.m脚本文件”;
1、安装MinGW-w64 C/C++编译器
- 登录Mathworks账号;
- 单击工具栏上的“附加功能”图标,在弹出的下拉菜单中选择“获取附加功能”选项;
- 找到“Matlab support for MinGW-w64 C/C++ Compiler”,点击安装;
- 需要等待数分钟,如果下载失败就换手机热点试试。
- 在matlab命令栏输入 mex-setup,并选择 mex -setup C++;
2、转码步骤
- 写好一个“.m函数”,函数内可调用其他函数。如下为机器人笛卡尔空间规划的算法函数,命名为Cartesian_Planning.m。
function [L_Cartesian_theta,R_Cartesian_theta] = Cartesian_Planning(L_p1, L_p2, L_p3,L_pose,L_StepSize,R_p1, R_p2, R_p3,R_pose,R_StepSize)
%% 进行直线插补、圆弧插补、抛物线插补判断
L_pos = Interpolation(L_p1, L_p2, L_p3,L_StepSize); %pos为3x(step+1)的矩阵
L_T=L_pos'; %求转置,T为(step+1)x3的矩阵
L_Q=zeros(L_StepSize+1,6); %用于保存逆解求的值,Q为(step+1)x6的矩阵
R_pos = Interpolation(R_p1, R_p2, R_p3,R_StepSize);
R_T=R_pos';
R_Q=zeros(R_StepSize+1,6);
%% 求逆解,并区其中关节角变化量最小的一组解
for i=1:L_StepSize+1
if i==1
% 第一次求解时与预设值作比较
% _ZY函数在逆解函数的基础上增加了角度判断,用于选出前后位置角度变化最小的一组解
% rpy的值为0,0,180,使末端始终向下。但逆解算法在90°的整数倍位置出会存在奇异问题,所以用179.9替代
L_Q(i,:)=I_Left_ZY([L_T(i,:),L_pose],[300,0,0,0,0,0]);
else
L_Q(i,:)=I_Left_ZY([L_T(i,:),L_pose],L_Q(i-1,:));
end
end
for i=1:R_StepSize+1
if i==1
% 第一次求解时与预设值作比较
% _ZY函数在逆解函数的基础上增加了角度判断,用于选出前后位置角度变化最小的一组解
% rpy的值为0,0,180,使末端始终向下。但逆解算法在90°的整数倍位置出会存在奇异问题,所以用179.9替代
R_Q(i,:)=I_Right_ZY([R_T(i,:),R_pose],[-300,0,0,0,0,0]);
else
R_Q(i,:)=I_Right_ZY([R_T(i,:),R_pose],R_Q(i-1,:));
end
end
L_Cartesian_theta = L_Q';
R_Cartesian_theta = R_Q';
end
- 写一个针对上述函数的调用脚本,用于转码时自动确认函数内的变量类型,命名为Cartesian_Planning_test.m;
clear;clc,close all;
%参数初始化
L_p1=[656,0,1];L_p2=[406,-350,200];L_p3=[656,0,-1];%位置
R_p1=[-656,0,1];R_p2=[-406,-350,200];R_p3=[-656,0,-1];
L_StepSize = 20; %规划点数量
R_StepSize = 15;
L_pose=[0,0,179.9]; %姿态
R_pose=[0,0,179.9];
[L_C_theta,R_C_theta]=Cartesian_Planning(L_p1, L_p2, L_p3,L_pose,L_StepSize,R_p1, R_p2, R_p3,R_pose,R_StepSize);
- 点击 APP -- MATLAB Coder,选择刚创建的函数文件Cartesian_Planning.m,点击Next;
- 选择针对上述函数的调用脚本Cartesian_Planning_test.m,再点击Autodefine Input Types,自动确定变量类型。完成后点击Next;
- 点击Check for Issues,完成代码自检;
- 选择C++,点击generate,开始生成C++代码;
- 生成成功;
3、C++代码使用
- 使用VS code软件打开codegen文件夹,在example子文件夹中打开main.cpp,发现有一个头文件找不到,追根溯源之后发现是缺少“tmwtypes.h”头文件。这个头文件可在matlab安装目录下检索到,复制粘贴过来即可;
- 将example文件夹中的main.cpp及main.h复制到上一层路径内,便于编译路径管理;
- 对于VS code来说,还需要配置launch.json和tasks.json文件,用于编译和调试。由于本项目涉及到多文件的联合编译,所以需将所有.cpp的文件路径写到tasks.json文件中,如下:
{
"tasks": [
{
"type": "shell",
"label": "C/C++: g++.exe build active file",
"command": "C:\\Program Files\\mingw-w64\\bin\\g++.exe",
"args": [
"-g",
"${file}",
"${fileDirname}\\acos.cpp",
"${fileDirname}\\asin.cpp",
"${fileDirname}\\Cartesian_Planning.cpp",
"${fileDirname}\\Cartesian_Planning_data.cpp",
"${fileDirname}\\Cartesian_Planning_emxAPI.cpp",
"${fileDirname}\\Cartesian_Planning_emxutil.cpp",
"${fileDirname}\\Cartesian_Planning_initialize.cpp",
"${fileDirname}\\Cartesian_Planning_rtwutil.cpp",
"${fileDirname}\\Cartesian_Planning_terminate.cpp",
"${fileDirname}\\char.cpp",
"${fileDirname}\\cross.cpp",
"${fileDirname}\\dec2hex.cpp",
"${fileDirname}\\dot.cpp",
"${fileDirname}\\hex2dec.cpp",
"${fileDirname}\\I_Left_ZY.cpp",
"${fileDirname}\\I_Right_ZY.cpp",
"${fileDirname}\\ifWhileCond.cpp",
"${fileDirname}\\Interpolation.cpp",
"${fileDirname}\\inv.cpp",
"${fileDirname}\\isequal.cpp",
"${fileDirname}\\mrdivide_helper.cpp",
"${fileDirname}\\norm.cpp",
"${fileDirname}\\round.cpp",
"${fileDirname}\\rt_nonfinite.cpp",
"${fileDirname}\\rtGetInf.cpp",
"${fileDirname}\\rtGetNaN.cpp",
"${fileDirname}\\singleOrHelper.cpp",
"${fileDirname}\\sqrt.cpp",
"${fileDirname}\\xzgetrf.cpp",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
}
}
],
"version": "2.0.0"
}
- 修改main.cpp文件:原main文件有很多可读性较差的内容,需稍作修改。
#include <iostream>
#include "rt_nonfinite.h"
#include "Cartesian_Planning.h"
#include "main.h"
#include "Cartesian_Planning_terminate.h"
#include "Cartesian_Planning_emxAPI.h"
#include "Cartesian_Planning_initialize.h"
using namespace std;
//左右臂位置点
static double L_p1[3] = {656, 0, 1};
static double L_p2[3] = {406, -350, 200};
static double L_p3[3] = {656, 0, -1};
static double R_p1[3] = {-656, 0, 1};
static double R_p2[3] = {-406, -350, 200};
static double R_p3[3] = {-656, 0, -1};
//左右臂姿态
static double L_pose[3] = {0, 0, 179.9};
static double R_pose[3] = {0, 0, 179.9};
//需要规划的点数
static double L_StepSize = 5;
static double R_StepSize = 5;
//PVT点与点之间的时间差,单位秒
static double L_step_time = 0.25;
static double R_step_time = 0.25;
static void main_Cartesian_Planning()
{
emxArray_real_T *L_Cartesian_PVT;
emxArray_real_T *R_Cartesian_PVT;
emxInitArray_real_T(&L_Cartesian_PVT, 2);
emxInitArray_real_T(&R_Cartesian_PVT, 2);
//1-3:左臂三个空间位置点; 4:需要保持的姿态; 5:需要规划的点数; 6:点与点的时间差;
//7-9:右臂三个空间位置点;10:需要保持的姿态;11:需要规划的点数;12:点与点的时间差;
//13:左臂规划后的PVT报文;14:右臂规划后的PVT报文;
Cartesian_Planning(L_p1, L_p2, L_p3, L_pose, L_StepSize, L_step_time,
R_p1, R_p2, R_p3, R_pose, R_StepSize, R_step_time,
L_Cartesian_PVT, R_Cartesian_PVT);
/* 将计算的PVT报文(ascll类型)赋值给新变量L_PVT和R_PVT(char类型) */
//左臂
int L_row = L_Cartesian_PVT->size[0]; //行
int L_column = L_Cartesian_PVT->size[1]; //列
int num_L_Cartesian_PVT = 0;
char L_PVT[L_row][L_column];
for (int i = 0; i < L_column; ++i)
{
for (int j = 0; j < L_row; ++j)
{
L_PVT[j][i] = (char)(L_Cartesian_PVT->data[num_L_Cartesian_PVT]);
num_L_Cartesian_PVT++;
}
}
//打印
cout << "L_PVT:" << endl;
for (int i = 0; i < L_row; ++i)
{
for (int j = 0; j < L_column; ++j)
{
cout << L_PVT[i][j];
}
cout << endl;
}
//右臂
int R_row = R_Cartesian_PVT->size[0]; //行
int R_column = R_Cartesian_PVT->size[1]; //列
int num_R_Cartesian_PVT = 0;
char R_PVT[R_row][R_column];
for (int i = 0; i < R_column; ++i)
{
for (int j = 0; j < R_row; ++j)
{
R_PVT[j][i] = (char)(R_Cartesian_PVT->data[num_R_Cartesian_PVT]);
num_R_Cartesian_PVT++;
}
}
//打印
cout << "R_PVT:" << endl;
for (int i = 0; i < R_row; ++i)
{
for (int j = 0; j < R_column; ++j)
{
cout << R_PVT[i][j];
}
cout << endl;
}
//清除内存
emxDestroyArray_real_T(R_Cartesian_PVT);
emxDestroyArray_real_T(L_Cartesian_PVT);
}
int main(int, const char *const[])
{
// 初始化
Cartesian_Planning_initialize();
// PVT笛卡尔空间运动规划
main_Cartesian_Planning();
// 结束
Cartesian_Planning_terminate();
return 0;
}
- 按F5编译运行,成功。