MATLAB 串口读取姿态数据及GUI实时动态显示设计

上一篇实现了Matlab 对串口数据的读取,数据可以读取并且保存到本地。本文主要设计GUI并且动态的显示曲线。可以更直观的观察实时的姿态数据和传感器数据。

GUI设计效果:

《MATLAB 串口读取姿态数据及GUI实时动态显示设计》 姿态GUi.png

分别设置三个区域,分别为数据接收显示区域,串口设置区域和区域显示区域。
串口参数设置与上一篇基本一直,只是将串口号和波特率设置为全局变量。matlab GUI 编程可以看其他教程,主要调用函数参数与hObject,eventdata,handles。
hObject 和handles 都可以设置相应的空间的性能,但是区别在于hObject只是一个局部变量,而handles 相当于一个全局变量。当要在函数中设置另外控件的性能,只能调用handles。

参数设置区域

参数设置区域主要实现的是串口的选择和波特率的设置。GUI上通过下拉菜单选择。在相应空间的callback 函数中添加初始化代码:

  • COM callback 函数设置
% --- Executes on selection change in ppcom.
function ppcom_Callback(hObject, eventdata, handles)
% hObject    handle to ppcom (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns ppcom contents as cell array
%        contents{get(hObject,'Value')} returns selected item from ppcom
global COM;
val=get(hObject,'value');
switch val
    case 1
        COM='COM1';
        fprintf('ceshi_COM=1\n');
    case 2
        COM='COM2';
    case 3
        COM='COM3';
    case 4
        COM='COM4';
    case 5
        COM='COM5';
    case 6
        COM='COM6';
    case 7
        COM='COM7';
    case 8
        COM='COM8';
    case 9
        COM='COM9';
end

波特率callback 函数设置

function ppbandrate_Callback(hObject, eventdata, handles)
% hObject    handle to ppbandrate (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns ppbandrate contents as cell array
%        contents{get(hObject,'Value')} returns selected item from ppbandrate
global rate;
val=get(hObject,'value');
switch val
    case 1
        rate=9600;
    case 2
        rate=19200;
    case 3
        rate=38400;
    case 4
        rate=115200;
end

打开串口:

function activityReco_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to activityReco (see VARARGIN)

global COM;
global rate;
global act a;
global count;
global act_data t;
global p x;
count=1;x=-15;
act=zeros(12,1);
t=0;
p = plot(t,act,...
   'EraseMode','background','MarkerSize',5);
% axis([x x+20 -200 200]);
% grid(handles.axplotact,'on');
set(handles.axplotact,'XLim',[x x+20],'YLim',[-200 200]);
set(handles.axplotact,'XTickLabel',[]);
legendaxes=legend(handles.axplotact,{'Yaw','Pitch','Roll','Accx','Accy','Accz','GYROx','GYROy','GYROz','Magx','Magy','Magz'},1);
set(legendaxes,'Location','northeastoutside');
act_data=[]; a=[];
COM='COM5'
rate = 115200;
set(handles.ppcom,'value', 5);
set(handles.ppbandrate,'value',4);
set(handles.pbcloseserial,'Enable','off');
% Choose default command line output for activityReco
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);

关闭串口:

function pbcloseserial_Callback(hObject, eventdata, handles)
% hObject    handle to pbcloseserial (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global s;
fclose(s);
delete(s);
set(handles.pbcloseserial,'Enable','on');
set(handles.pbopenserial,'Enable','off');
fprintf('close com');

串口参数设置部分基本与上一篇博客一致,有问题可以对照理解。

姿态数据动态显示

姿态和传感器数据总共12位。具有不同的单位,为了显示效果,特地将各个数据归一在[-200,200]的范围显示,整体实现单线程串行显示。这里实现动态显示的方法是背景擦除方法。

《MATLAB 串口读取姿态数据及GUI实时动态显示设计》 姿态gui2.png

matlab单线程动态曲线绘制有几种方法,参见博客(http://www.cnblogs.com/duanp/archive/2008/12/02/Matlab-Plot-Animation.html)

【源方法】

t=[0]
m=[sin(t);cos(t)]
p = plot(t,m,...
   'EraseMode','background','MarkerSize',5);%%定义数据种类,因此t和m不能为空
x=-1.5*pi;           %坐标初始设置小于数据起始位置,任意设置
axis([x x+2*pi -1.5 1.5]); %绘图坐标设置,横坐标设置为x的参数
grid on;


for i=1:1000
    t=[t 0.1*i];                   %Matrix 1*(i+1)
    m=[m [sin(0.1*i);cos(0.1*i)]]; %Matrix 2*(i+1)
    set(p(1),'XData',t,'YData',m(1,:))
    set(p(2),'XData',t,'YData',m(2,:))    
    drawnow
    x=x+0.1;    
    axis([x x+2*pi -1.5 1.5]);
    pause(0.5);
end

这里我用的是采用背景擦除的方法,显示动态的曲线,并且动态改变坐标系。整体思路是显示的横坐标t和纵坐标act_data只存储400个数据,当大于400 ,则删除前端数据保持整体为400个。然后每次解算则显示一次。

function ReceiveCallback( obj,event,handles)     %创建中断响应函数  
   global s a fid;
   global count;
   global  act;
   global act_data;
   global t x p;
   str = fread(s,100,'uint8');%读取数据
   hex=dec2hex(str);
  IMU_data = [];Motion_data=[];
  sign_head1=hex2dec('A5');sign_head2 = hex2dec('5A');
  sign_finish=hex2dec('AA');sign_IMU=hex2dec('A1');sign_Motion=hex2dec('A2');

  a= [a;str];
  j=1;
  while (~isempty(a))
        if j>size(a,1)
           break;
        end
        if a(j)==sign_head1 && a(j+1) == sign_head2 
            if (j+a(j+2)+1) > size(a,1) 
                break;
            end
            index_start = j+2;
            index_finish= index_start + a(j+2)-1;
            pack = a(index_start:index_finish);
            if ~isempty(pack) &&pack(pack(1))== sign_finish
                  if pack(2) == sign_IMU
                        IMU_data(1,:) = Get_IMU(pack);
                        j = index_finish;
                        continue;
                  end
                   if pack(2) ==sign_Motion
                          Motion_data(1,:) = Get_Motion(pack);
                          j = index_finish;
                   end
                   if ~isempty(IMU_data) && ~isempty(Motion_data)
                        count=count+1;
                        act_data = [IMU_data,Motion_data]';
%                         fprintf(fid,'%8.1f%8.1f%8.1f%8.1f%8.1f%8.1f%8d%8d%8d%8d%8d%8d%8d%8d%8d\n',act_data);
                        t=[t 0.1*count]; 
                        act=[act,[act_data(1:3);act_data(7:9)*100/16384;act_data(10:12)*pi/180;act_data(13:15)]];%%绘图数据归一化-200-200
                        set(handles.edshowdata,'string',num2str(act_data));
             
                        axis(handles.axplotact);
                        if ~get(handles.rbpause,'Value')
                            if get(handles.rbshowangles,'Value')
                                    set(p(1),'XData',t,'YData',act(1,:));
                                    set(p(2),'XData',t,'YData',act(2,:));
                                    set(p(3),'XData',t,'YData',act(3,:));
                            end
                            if get(handles.rbshowacc,'Value')
                                    set(p(4),'XData',t,'YData',act(4,:));
                                    set(p(5),'XData',t,'YData',act(5,:));
                                    set(p(6),'XData',t,'YData',act(6,:));
                            end
                            if  get(handles.rbshowgyro,'Value')
                                    set(p(7),'XData',t,'YData',act(7,:));
                                    set(p(8),'XData',t,'YData',act(8,:));
                                    set(p(9),'XData',t,'YData',act(9,:));
                            end
                            if get(handles.rbshowmag,'Value')
                                    set(p(10),'XData',t,'YData',act(10,:));
                                    set(p(11),'XData',t,'YData',act(11,:));
                                    set(p(12),'XData',t,'YData',act(12,:));
                            end
                             drawnow
                              x=x+0.1;
                             set(handles.axplotact,'ytick',-200:50:200);
                             axis(handles.axplotact,[x x+20 -200 200]);
%                            set(handles.axplotact,'xtick',x:x+20);
                             if size(t,2) >400
                                 t(1)=[];
                                act(:,1)=[];
                              end
                        end 
                   end
%                   set(handles.edshowdata,'String',num2str(act));
                    Motion_data=[];IMU_data=[];
                    a(1:index_finish)=[];
                    j=1;
%                   pause(0.005);
            end
         else
                j=j+1;
        end
  end

需要注意axes 和axis的区别,axes 是GUI控件名,axis用来设置figure的坐标。这里

axis(handles.axplotact);

是用来锁定后面操作的对象,即后面几个set函数都是对handles.axplotact进行设置,就不必要每个set前面都添加handles.axplotact了。drawnow用来绘制,使整个过程更流畅。下面留了两个axes控件,用来实现三维传感器空间位置显示和相对坐标系解算的显示。
【源代码】上传到github

总结

整体来说MATLAB GUI设计还是挺好入手,了解一点callback就能入手了。基本需要注意的函数为hObject 和handles,get和set(属性获取和设置)。暂时只是显示数据,但是存在一点延时,还不确定是中断和fread的问题还是单线程串行显示的问题。后面打算实现三维空间显示和地球三维坐标解算和显示。

    原文作者:风火布衣
    原文地址: https://www.jianshu.com/p/6f22c8d35961
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞