1. MATLAB App中显示3D模型

在很多项目中,我们需要在App中看到我们的模型。这就需要我们将我们在一些建模软件(例如solidworks)中建好的模型导入到app的坐标区当中。但是,MATLAB既不能直接打开solidworks文件,也不支持导入.stl文件(笔者了解过一些插件可能可以,但是水平所限,未能实现)。这种情况下,该怎么办呢?

1.1 SolidWorks导出Urdf文件

首先,我们要先把模型在MATLAB中显示出来。虽然MATLAB不能打开由SoildWorks导出的模型文件,但是可以打开Urdf文件。那么,我们就可以尝试将模型从SolidWorks导出成Urdf文件。

1.下载Urdf插件

将模型文件转化为Urdf文件并不是SolidWorks原本的功能,而是一个插件。我们需要将该插件下载下来并安装。下载地址为:Releases · ros/solidworks_urdf_exporter · GitHub。点进网址页面,如下图所示:
在这里插入图片描述
找到和自己SolidWorks对应的版本,下载“sw2urdfSetup.exe”文件。下载好后,双击安装即可。

2.启用Urdf插件

打开SolidWorks,在“设置”中找到“插件”,点击后,弹出如下界面:
在这里插入图片描述
将“其他插件”中的“SW2URDF”前面的勾选框勾中,点击确定。

3.按如下路径依次点击:“工具” → \rightarrow “File” → \rightarrow “Export as URDF”,弹出如下界面:

在这里插入图片描述
点击红框框出的按钮,选择保存路径,然后点击“Finish”按钮即可:

在这里插入图片描述
4.找到我们导出的文件夹:
在这里插入图片描述
可以看到Urdf文件了。

1.2 MATLAB打开Urdf文件并显示模型

获得了Urdf文件后,我们就可以在MATLAB中将其打开了。在这里,我使用.m文件和读者说明如何打开Urdf文件并将模型显示在图窗中。此处之所以不使用App,是因为打开Urdf并显示模型的代码并不能在App中运行。但是,后续的解决方案又和打开Urdf文件相关。因此,在这里我先要介绍MATLAB打开Urdf文件。

1.新建.m脚本文件,输入如下代码:

clc; clear; close all;

%% 打开urdf文件
[filename,pathname] = uigetfile('*.*');
robot = importrobot([pathname,filename]);
% 设置数据格式为列向量格式(或者row行向量格式)
robot.DataFormat = 'column';

%% 打开一个窗口显示模型
f = figure(1);
show(robot);

运行效果如下:

在这里插入图片描述
2.我们的模型在图窗中显示出来,并且还带有坐标系。那么,如果我们将这个代码移植到App中,放在一个按钮的回调函数中,会发生什么呢?

在这里插入图片描述
可以看到,这时候编辑器提醒我们,这样的写法是错误的。那么,我们就需要查询一下官方文档,有没有某种语法可以将rigidtree显示在App的坐标区控件上。

3.在命令行输入如下命令:

help show

然后点击“名为Show的其他函数”,找到“rigidBodyTree/show”,点击打开:
在这里插入图片描述
4.在关于show的文档中,我们找到show函数的四个语法:

show(robot)
show(robot,configuration)
show(___,Name,Value)
ax = show(___)

我们发现并没有将模型显示在指定坐标区的语法。但是在MATLAB App的坐标区中,我们又必须指定模型显示在某一个坐标区。使用show函数并不能解决这个问题。那该怎么办呢?解决方案将在1.3节中详细说明。

1.3 在MATLAB App的坐标区控件中显示模型

回到我们的脚本。思考这样一个问题:当我们使用诸如plot或者scatter函数进行绘图时,也都会显示出图窗、坐标区和图像。在plot绘制的图形中,图像本身是Line类型,坐标区是Axes类型,而图窗是figure类型,Line是Axes的子级,Axes又是figure的子级。那么,类比一下,使用show显示的模型,是不是可以使用调用子级的方式,查看它是什么类型呢?如果是类似Line可以使用plot等绘图函数绘制出来的类型,或许我们就可以把绘图数据提取出来,使用绘图函数指定坐标区绘制。这样,也就达到了在指定坐标区显示模型的效果。

1.按照这个思路,我们尝试使用“.Children”调用当前坐标区的子级:

ax = gca;
model = ax.Children;

2.在命令行中输入“model”,调出变量属性。可以发现,model是一个3×1的graphics数组:
在这里插入图片描述
这说明,当前坐标区中有三个绘图元素,分别是两个Patch类变量和一个Light类变量。Light类变量是一个光源,为了使模型看起来更有光泽。下图中,模型头部的高光部就是这个光源照在模型头部的效果。
在这里插入图片描述
3.那另外两个Patch变量是什么呢?我们在命令行中输入如下代码:

model_1 = model(1)

命令行弹出如下内容:
在这里插入图片描述
关于Patch函数的使用,读者可以参考官方文档。简单来说,该函数是用来绘制三维图像,以绘制网格面的方法来绘制。其中,“Faces”和“Vertices”是绘制Patch的数据。但是,model中有两个Patch变量,我们如何得知哪个Patch变量是我们的模型变量呢?而另一个变量又是什么呢?

3.点击“所有属性”,找到“Visible”属性:
在这里插入图片描述
在命令行输入如下代码:

model_1.Visible = 'off';

这时候再打开显示模型的图窗:

在这里插入图片描述
发现我们的模型不再显示,而坐标区中间留下了一个坐标轴。那么这时候,我们就可以确认,graphics数组的第一个元素为我们的模型变量,而第二个变量为上图中的这个坐标轴。因此,我们新声明两个变量:“F”和“V”,分别表示“Faces”数据和“Vertices”数据:

F = model_1.Faces;
V = model_1.Vertices;

然后,在命令行中使用patch函数,以F和V作为输入绘制面网格:

patch('Faces',F,'Vertices',V);

效果如下:

在这里插入图片描述
4.这个时候,坐标区出现了一个纯黑色的模型。这就表示,我们可以利用Vertices和Faces的数据,使用patch函数在指定坐标区绘制模型。那么首先,我们需要把绘图数据保存下来,方便我们的App使用。在脚本中写入如下代码并运行:

%% 将模型绘制数据保存下来
modelData = cell(2,1);
modelData{1} = model_1.Faces;
modelData{2} = model_1.Vertices;

运行后,在“工作区”找到“modelData”变量,右键点击选择保存。保存的.mat文件命名为“salmon”。

5.回忆一下我们在MATLAB Appdesigner开发独立桌面App全流程(一):以打开串口功能为例介绍Appdesigner的基本使用第8节所涉及的按钮回调函数的编写,我们在App的画布上新建一个按钮控件,将其显示名称改为“打开模型”,按钮变量命名为“OpenModelButton”。然后给按钮添加回调函数,在公共属性和回调函数中添加如下代码:

properties (Access = public)
    ser; % Serial
    serialname;
    model; % To store the model data
    modelvisual; % Store the patch handle
    baud = 115200; % baud rate
    datetimer; % To show time
    SerialData;
end

% Button pushed function: OpenModelButton
function OpenModelButtonPushed(app, event)
    try
        cla(app.ModelUIAxes);
        [filename,pathname] = uigetfile('salmon.mat');
        % 打开模型数据文件
        %%% 这个地方建议使用load函数而不是open函数,因为在测试中,封装好的app无法调用open函数
        app.model = load([pathname,filename]);
        % 显示模型在监视框中
        %%% 这个地方要写成 app.model.modelData{2}的形式是因为.mat文件使用load函数读取后是一个struct变量,这种类型的变量需要通过.来调用。
        app.modelvisual = patch(app.ModelUIAxes,"Faces",app.model.modelData{2},...
        	"Vertices",app.model.modelData{1},...
            "FaceColor",'interp');
        light(app.ModelUIAxes);
        set(app.modelvisual,"FaceColor",[0.93,0.42,0]);
        set(app.modelvisual,"EdgeColor",[0.93,0.42,0]);
    catch ME
        report = getReport(ME);
        uialert(app.UIFigure,report,'Error Message','Interpreter','html');
    end
end

在公共属性中,新建了“model”和“modelvisual”变量,分别用来存储模型的数据和patch句柄。

6.第5步完成后,点击运行,然后点击“打开模型”按钮,选中我们的模型文件后,点击打开。效果如下图所示:

在这里插入图片描述
这样,我们就把一个三维模型显示在了App的图窗当中。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐