[036] Matlab代码转为C++代码

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编译运行,成功。

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值