基于matlab的蓝牙串口通信

一、前言

  用蓝牙做主控串口和电脑通信的想法呢,是因为实践标定的时候需要持续的很稳的推动小车,而且要把jlink将电脑和主控连起来debug看数据又得给主控供5V电(当时忘记充电宝可以供5v电了,一时英明被摧毁),所以无线就没多想了。想过做很长的线、把电脑放在电竞椅上跟着小推车推着走,都不太靠谱,所以在标定的时候还是把电脑架在了小推车上

  标定进度完成了大半,现在得点空,还是想把这个蓝牙无线通信做起来,因为我在想这个方法是不是可以把WLan的网卡看参数替换掉,个人感觉那种Labview结合Matlab🐂是🐂,但是有点太麻烦了,路由器架在车上得自带一个充电宝,主控上的网线插槽老是松,还要先生成调试组文件带入主控更新…我电脑现在也是再也连不上了,所以这个我觉得某种程度上有一些必要


二、尝试pybluez模块

  之前竞培营的时候买过蓝牙,所以家里留了一个(也是为什么想蓝牙通信)。主控串口连接蓝牙再和电脑通信,问题不在串口,而在电脑是如何接收到的数据?什么形式的数据?怎么处理这类数据成为我想要看到的数据甚至生成动态曲线?由于觉得python无所不能,第一时间想到的就是它,结果在下载pybluez模块时出现问题,电脑提示我没有Microsoft Visual C++ 2014的组件工具,这个我百度了也是很多py模块下载时出现的问题

  有一个解决方法就是在一个国外大学提供实时更新的模块下载网站上先把需要的模块的类似安装包(whl类型文件)下载到本地,之后pip install 安装包绝对地址最后pip install 模块名称,不过这个方法我在尝试的时候仍然出现错误,个人认为是这个pybluez模块版本较老,有一些bug也比较正常

  这条路走不通,以后必须用到的时候再试试把。之后在想wifi也能无线传输数据,而且速率更高,pywifi模块的安装没有问题。不过我手上只有蓝牙模块啊,当务之急是选择什么方法在电脑上得到蓝牙传输的数据


三、Matlab成为选择

  此时,在寻找与蓝牙通信相关的过程中,看到了Matlab的字眼,对啊,之前怎么没想到它呢。说干就干,百度关键词Matlab蓝牙通信,果然就有,不过不多,好在matlab的使用者多,而且内置的help搜索向导非常方便,即使不太了解有的也有官方示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
%Examples
%Find available Bluetooth devices.

instrhwinfo('Bluetooth');
instrhwinfo('Bluetooth', RemoteName);
%Construct a Bluetooth object called b using channel 3 of a Lego Mindstorm robot with RemoteName of NXT.

b = Bluetooth('NXT', 3);
%Connect to the remote device.

fopen(b)
%Send a message to the remote device using the fwrite function.

fwrite(b, uint8([2,0,1,155]));
%Read data from the remote device using the fread function.

name = fread(b,35);
%Disconnect the Bluetooth device.

fclose(b);
%Clean up by deleting and clearing the object.

fclose(b);
clear('b');
  • 结合官方提供的例子,快速入手蓝牙通信,关键在于定义蓝牙的特定变量b = Bluetooth('NXT', 3);,以及fopen(b)来开启蓝牙通信。重点就在于数据的规范、格式。手册上介绍的函数如下:
Matlab蓝牙相关函数

You can read and write both text data (ASCII based) and binary data. For text data, use the fscanf and fprintf functions. For binary data, use the fread and fwrite functions.
你可以借助ASCII码或者二进制数据进行读写操作。对于txt数据使用fscanffprintf函数,对于二进制数据使用freadfwrite函数

  • 以下是目前我脚本中的蓝牙初始化操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
%% 配置蓝牙操作

instrhwinfo('Bluetooth');
instrhwinfo('Bluetooth','col_test');
col_test = Bluetooth('col_test',1);

% col_test.TimerPeriod = 0.1;
% col_test.TimerFcn = {@plotcallback,p};
col_test.Timeout = 10;


%% 开启蓝牙数据监控,同时开启定时器
% fopen(col_test);
try
fopen(col_test);
catch err
disp('col_test蓝牙通道打开失败');
flag = 0;
end

if err_flag
disp('col_test蓝牙通道成功打开');
fwrite(col_test,Command_data);
start(t);
end

通信接口的回调函数

  • 在搜索帮助中有对串口接收数据的中断回调函数,终端的类型我所了解的有
    • 设定接受字节数触发
    • 设定截至字符触发
    • 定时间间隔触发
  • 不过目前没尝试出来,而且我觉得也没有那个必要所以暂时搁置了研究

四、如何有效的接受主控数据

  如果需要监控主控数据,那么每一次就要同时接收数十个浮点数类型的数据。

  1. 接受的方式不可能是直接不停循环接收数据,那么对于高速率传输数据的串口,错误必然存在而且经验证发现错误率不低,所以需要加密再解码确保数据准确。
  2. 其次,由于测试发现fread函数接受蓝牙数据是以字节(8bit)为单位,多个字节数据如何正确转换为float类型我之前没接触过。
  3. 最后蓝牙的速率不出众,那么我也需要测试一下他的速度究竟能有多快?

4.1 报文形式发送与接收

  • 主控上的串口dma接收发送不必多说,使用串口六,定义两个结构体Bluez_TXBluez_RX包含同样的两帧头两帧尾,那么在Matlab脚本中就需要相似的对于报文的解包,这一部分不难,那么我认为matlab接收数据的优点在于in/outputbuf数据一边进另一边出,在读取过程中的操作十分方便。
  • 还有一点就是我的脚本中做到,matlab向主控发送一帧数据,命令主控开始发送数据给蓝牙从而开始数据监控。也有停止命令,非常方便。操作就是在主控中的dma发送函数判断一个标志位(发送函数写在一个任务中)

4.2 多个单字节与浮点数的转换

  • 已知,主控中的dma发送是将发送结构体变量bluez_tx的头指针作为地址,那么这种方式下浮点数就是按一般的占据4字节进行发送。在Matlab中可以接收到4个字节与该浮点数对应。
1
2
3
raw_data1 = [byte1 byte2 byte3 byte4];
temp = uint8(raw_data1);
stRobot_x(count) = typecast(temp,'single');
  • 通过上述方法进行通信之后的变量类型转换成功

4.3 速率监测

  • 一开始我都是用串口调试助手来研究的,没有用上主控,中间尝试过一次发现主控确实在发送数据,但是Matlab端就是感觉没接收到,很是奇怪。那么我用调试助手时发现,一个包里有单个数据或是多个数据并不影响接收帧率增大串口波特率略微提高解包帧率,但是在发送帧率到达1000fps时,数据的接收帧率只能到650fps左右。
  • 我发现,并不是Matlab没接收到主控的数据,而是没有成功解包,这个问题也一直困扰我,发送结构体变量中的总字节数理论上和实际发的不一样,在帧头和数据之间有两位0x00并不知道从何而来,这样总字节数多了2,dma发送字节数加了2,且在解包过程中多两个字节消耗掉就行了
  • 结果在测试主控与Matlab通信时又发现问题,由于设置的波特率为921600,虽然配置没错但是串口发送的数完全不对,向下减小一些至460800就正常了,看来这种情况波特率有了限制。并且波特率460800时帧数据肉眼可见的概率会发生传输数据错误,说明串口确实不太稳定
  • 最后我一共让主控一帧传输20个数据,能够正常接收,100fps的发送帧率对应100fps的解包帧率。再次说明数据量不影响接受帧率,并且最大帧率在600fps(发送帧率1000fps),不过这种情况在接受10s时间左右程序不再接受蓝牙数据,未找到原因。
  • 另外,如果要在接收过程中画出实时曲线,势必影响接收帧率,我尝试在发送帧率100fps的情况下,每解完一次包绘制两个变量的曲线,结果接受帧率掉到70fps。因此,不画实时图像或者仅绘制1-2张是允许的,不然影响过大。

4.3.1 帧率计算timer

  • Matlab中也有定时器,我通过定时器1s定时来计算每秒钟的接收帧率,特别提醒往往回调函数的函数名的定义变量规范很重要。具体可以查阅帮助,下面是代码部分:
1
2
3
4
5
6
7
t = timer('StartDelay',1,'TimerFcn',@t_TimerFcn,'Period',1,'ExecutionMode','fixedRate');
%StartDelay:开始计时后的延时;TimerFcn:定时中断函数;Period:定时时间周期;ExecutionMode:优先级

start(t)

stop(t)
Delete(t)

4.3.2 打印变量disp()

1
2
string = sprintf('Have received stRobot_x:%d',stRobot_x(count));
disp(string)
  • 类似于format格式化输出,打印在命令行区
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×