能否将MATLAB工作区实时更新的全局变量用于Simulink?
我用MATLAB编写程序,通过串口连接ESP32读取数据,提取角度(单位:度或弧度)和角速度(单位:度/秒或弧度/秒),分别存储为变量th和vth。ESP32发送的数据格式为E1, t, thx , th_y , th_z, vth_x, vth_y, vth_z \n,我通过readline函数循环读取每行字符串,并使用以下代码配置回调实现持续读取:
configureCallback(device, "terminator", @readSerialData)
为了将t、th、vth存入工作区,我声明了全局变量,通过回调函数实现数据实时覆盖更新,完整代码如下:
clc clear close global splitdata t th vth portavailable = serialportlist("available"); device = serialport("COM8",500000); %data = read(device,47,"string") %splitdata = splitlines(data) configureCallback(device,"terminator", @readSerialData) function readSerialData(src,~) global splitdata t th vth alinedata = readline(src); disp(alinedata); data = evalc('disp(alinedata)'); splitdata = split(data,','); %disp(splitdata) t = str2double(splitdata{2})/1000; th(1) = str2double(splitdata{3}); th(2) = str2double(splitdata{4}); th(3) = str2double(splitdata{5}); vth(1) = str2double(splitdata{6}); vth(2) = str2double(splitdata{7}); vth(3) = str2double(splitdata{8}); end
我尝试用Simulink的From Workspace块调用这些变量,但运行Simulink仿真时,MATLAB的回调停止,变量不再更新。请问这种方式可行吗?若不可行,应如何解决?
这种直接通过全局变量+From Workspace块的方式不可行,核心原因是:Simulink仿真运行时会独占MATLAB的执行线程,而MATLAB的串口回调是基于单线程事件队列实现的——仿真过程中事件队列会被暂停,导致串口数据无法被实时处理和更新。
推荐两种解决方法,优先选择第一种:
方法1:使用Simulink原生串口模块直接读取数据
Simulink的Instrument Control Toolbox提供了专门的串口通信模块,无需依赖MATLAB脚本回调,可直接在模型内完成数据读取与解析:
- 拖入
Serial Receive模块,配置端口为COM8、波特率500000,终止符设置为\n - 使用
String Split模块(或MATLAB Function模块)拆分收到的字符串,提取t、th各分量、vth各分量 - 直接在Simulink模型中使用解析后的数据,无需依赖工作区变量
这种方式的优势是Simulink会独立处理串口数据的实时读取,与仿真线程完全兼容,不会出现阻塞问题,流程更简洁可靠。
方法2:通过数据存储区实现Simulink与MATLAB工作区的实时交互
如果必须保留MATLAB脚本的回调逻辑,可以借助Simulink的Data Store系列模块实现数据同步:
- 在MATLAB中准备数据存储区:
- 在工作区创建数据存储对象:
t_ds = Simulink.Signal; t_ds.DataType = 'double'; th_ds = Simulink.Signal; th_ds.DataType = 'double'; th_ds.Dimensions = [1 3]; vth_ds = Simulink.Signal; vth_ds.DataType = 'double'; vth_ds.Dimensions = [1 3]; - 修改回调函数,去掉冗余的
evalc操作,直接拆分字符串并将数据写入工作区,同时更新数据存储区:function readSerialData(src,~) alinedata = readline(src); splitdata = split(alinedata,','); % 更新工作区变量 t_val = str2double(splitdata{2})/1000; th_val = [str2double(splitdata{3}), str2double(splitdata{4}), str2double(splitdata{5})]; vth_val = [str2double(splitdata{6}), str2double(splitdata{7}), str2double(splitdata{8})]; assignin('base','t', t_val); assignin('base','th', th_val); assignin('base','vth', vth_val); % 更新Simulink数据存储区 set_param('你的模型名称/Data Store Memory_t','Value','t'); set_param('你的模型名称/Data Store Memory_th','Value','th'); set_param('你的模型名称/Data Store Memory_vth','Value','vth'); end
- 在工作区创建数据存储对象:
- 在Simulink模型中配置数据存储:
- 添加三个
Data Store Memory模块,分别命名为Data Store Memory_t、Data Store Memory_th、Data Store Memory_vth,对应设置数据类型和维度 - 使用
Data Store Read模块读取数据,替代原来的From Workspace块
- 添加三个
另外,原回调中的evalc('disp(alinedata)')完全多余,直接用alinedata拆分字符串即可,这部分优化能减少不必要的性能开销。
内容的提问来源于stack exchange,提问作者TRIMET JINDAIN

