simulink和c++间通信

最近在做一个小型项目,需要在c++中调用simulink,于是对这一开发技术进行了调研。下面是三种实现方式,理论上来说,三种方法都是可以实现预期的效果,但是开发难度和使用难度等各不相同。

方法1:使用mcc命令

使用mcc命令,把m文件编译转为h,lib,dll文件,(暂时还没有调通,猜测是因为路径配置的原因)

仿真模型编写

编写一个仿真文件,只有一个正弦信号发送器和一个scope。

m文件控制仿真过程

两个m文件,分别是
simulinkstart.m 用于设置仿真参数,并启动仿真

load_system('testcpp');
set_param('testcpp','SolverType','Fixed-step');
set_param('testcpp','Solver','FixedStepDiscrete');
set_param('testcpp','FixedStep','0.1');

set_param('testcpp','SimulationCommand','start');
set_param('testcpp','SimulationCommand','pause');
set_param('testcpp','SimulationCommand','step');
% set_param('testcpp','SimulationCommand','stop');
pause(0.1);

simulinkstep.m 用于控制仿真步进一步,并把结果输出并返回

function ret = simulinkstep()
    set_param('testcpp','SimulationCommand','step');
    simulationdata = get_param('testcpp/Scope','RuntimeObject');
    ret = simulationdata.InputPort(1).Data(1);
end

这两个m文件在matlab中测试没有问题。

mcc命令编译

把它们使用如下命令进行编译

mcc -W cpplib:libsimulinkstart  -T link:lib simulinkstart.m
mcc -W cpplib:libsimulinkstep  -T link:lib simulinkstep.m

分别得到h,lib,dll文件。

在vs中使用

在vs工程中加入h和lib,并把dll放到等会编译出的可执行文件目录或者把其路径加入环境变量
具体main函数代码

#include 
#include "libsimulinkstart.h"
#include "libsimulinkstep.h"
using namespace std;

int main()
{
	if (!libsimulinkstartInitialize())
	{
		return -1;
	}
	if (!libsimulinkstepInitialize())
	{
		return -1;
	}
	cout << "初始化成功" << endl;

	simulinkstart();

	cout << "仿真启动成功" << endl;

	while (1)
	{
		mwArray ret(1, 1, mxDOUBLE_CLASS);
		simulinkstep(1,ret);
		double retc = ret.Get(1, 1);
		cout << retc << endl;
		Sleep(100);
	}
	libsimulinkstartTerminate();
	libsimulinkstepTerminate();
	return 0;
}

在这个main函数中,首先对这两个模块进行初始化,然后启动仿真,再用while循环获取每一步仿真后的值。编译完成后在命令行中运行(否则结果一闪而过)。

目前会报错误:

未定义函数或变量 load_system

但是使用如下一个很简单的函数就可以

在matlab端

function c = simpleadd(a,b)
    c = a+b;
end

在c++端

	if (!libAddInitialize())
		return -1;
	int a = 10;
	int b = 20;
	int c;
	mwArray mwA(1, 1, mxINT32_CLASS);
	mwArray mwB(1, 1, mxINT32_CLASS);
	mwArray mwC(1, 1, mxINT32_CLASS);

	mwA.SetData(&a, 1);
	mwB.SetData(&b, 1);
	simpleadd(1, mwC, mwA, mwB);
	c = mwC.Get(1, 1);
	cout << c << endl;
	libAddTerminate();

经查,这是一个simulink工具箱用到的函数,未定义应该是路径没有设置好。不可能matlab核心的函数可以调用,而simulink的函数不能调用。

方法二:使用mex命令

使用mex命令,把cpp文件编译为exe。
在cpp文件中,使用matlab提供的c++ API 控制仿真。然后在自己的c++程序中调用生成的exe,在qt中可以方便的使用QProcess实现这一功能。

cpp的实现

#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include 
void callSQRT() {

    using namespace matlab::engine;
    
    // Start MATLAB engine synchronously
    std::unique_ptr matlabPtr = startMATLAB();

    // Load Simulink model
    FutureResult loadFuture = matlabPtr->evalAsync(u"load_system('testcpp')");
    std::cout << "Loading Simulink model... " << std::endl;
    std::future_status loadStatus;
    do {
        loadStatus = loadFuture.wait_for(std::chrono::seconds(1));
    } while (loadStatus != std::future_status::ready);
    std::cout << "Simulink model loaded\n";
}

int main() {
    callSQRT();
    return 0;
}

在matlab中编译

使用

mex -v -client engine testFeval.cpp

命令进行编译,得到testFeva.exe。

运行生成的exe

经验证testFeva.exe可以正常加载testcpp仿真。
在这里插入图片描述

方法三:simulink 的UDP模块

这种方法最简单,详细过程就不再介绍。但这个方法有一个缺点,在使用时必须打开matlab。

simulink图

udp接收的图

三种方法比较

使用方法一,在使用时不需要打开matlab,并且操作最为简单,只需要在matlab中建立仿真模型即可,在c++程序中可以直接加载仿真模型,并读取仿真过程中的变量值。可以做大量的仿真模型,只要输出输出接口一致,都能加载。所以方便做成插件的方式,在c++程序中加载不用的仿真模型,实现定制化的效果。

使用方法二,在使用时不需要打开matlab,但是操作繁琐,对于每一个仿真模型,都需要单独的cpp文件,在matlab中使用mex命令编译为exe文件。并且在自己的程序中调用exe,两个程序间的通信也是比较复杂的问题。
通信问题使用qt的qprocess可以解决,但是由于要对每一个仿真模型进行cpp文件的修改和编译,所以不具有扩展性,所以不再这一方法下继续往下做。

使用方法三,在使用时需要打开matlab并且运行仿真。只要在c++程序中写好接收和发送udp消息的逻辑,就能实现c++代码和simulink进行通信,操作也比较简单。

你可能感兴趣的:(matlab,开发技术)