使用 Python 通过串行读取 MATLAB 单曲
Using Python to read MATLAB singles over serial
总结
我有一个 MATLAB 脚本使用一对遥测无线电向 Python 脚本发送串行消息。 MATLAB 数据都是单数(32 位浮点数,IEEE Standard 754)。但是,当 Python 收到串行消息时,它将每个数字解释为单个字节而不是 4。
背景
我是运行Windows10,MATLAB R2018a,Python3.7,用一对Holybro Telemetry Radios进行通信。这些无线电对于两个 MATLAB 脚本之间的串行通信工作得很好,这让我相信这个问题与 Python 如何解释 MATLAB 单一数据类型有关。
我的代码
MATLAB 发送器
这是发送消息的代码:
comport = 'COM6'
s = serial(comport);
s.BaudRate = 57600;
try
fopen(s);
headerToSend = single([112 112]);
packetToSend = single([3 4 5]);
dataToSend = [headerToSend packetToSend];
fwrite(s,dataToSend);
disp('Data sent is: ')
disp(dataToSend)
fclose(s);
delete(s);
whos dataToSend
catch ME
disp(ME.message)
end
请注意,消息可以包含转换为单数的整数或无法简化为整数的十进制数(如 0.1
)。
Python 接收器
这是接收消息的代码:
import serial
import time
import sys
dat = []
# Open serial port
ser = serial.Serial(
port='COM3',
baudrate=57600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=0.1)
try:
# Main loop
while (True):
buffer = ser.read(4)
print("Buffer: ")
print(buffer)
time.sleep(1)
except KeyboardInterrupt:
ser.close()
sys.exit()
MATLAB 接收器(用于比较)
为了比较,我在 MATLAB 中复制了一个接收器来验证发送器是否正常工作:
clc;clear;
comport = 'COM3';
s = serial(comport);
s.BaudRate = 57600;
try
fopen(s);
data = [];
% Receive response data
pause(0.5);
expectedDataLength = 20; % 2 headers and 3 msg, each 4 bytes
data = fread(s,expectedDataLength)
fclose(s);
delete(s);
catch ME
disp(ME.message)
end
if isempty(data)
disp('Unable to read any data.');
else
%Logic to find the packet after stripping the header
data = data';
header = single([112 112]);
%Find the starting indices of 'header' in the 'data' received. It is
%expected to be 112 in this case
k = strfind(data,header);
if ~isempty(k) && any(ismember(k,1))
%get the packet data by stripping the header
packet = data(length(header)+1:expectedDataLength);
end
% The msg values are in the order x, y, and z.
msg1 = typecast(single(packet(1)),'single');
msg2 = typecast(single(packet(2)),'single');
msg3 = typecast(single(packet(3)),'single');
%display the msg data on screen
disp(['Message Data ', num2str(msg1),' | ', num2str(msg2), ' | ', num2str(msg3), '.'])
end
预期结果
我希望缓冲区读取:
b'x00\x00\x00\x70'
b'x00\x00\x00\x70'
b'x00\x00\x00\x03'
b'x00\x00\x00\x04'
b'x00\x00\x00\x05'
对于包含 [112 112 3 4 5]
的消息
当使用上面显示的 MATLAB reader 时,它可以正确解释消息。请参阅底部的更新。
实际结果
缓冲区改为:
b'pp\x03\x04'
b'\x05'
似乎在 python 端,它已将消息的每个元素塞进一个字节(p
是 112
,x03
是 3
等等)。
使用 whois dataToSend
确认它是一个 1x5 的单身数组,由 20 个字节组成(或者至少是,在被接收之前)。
问题
知道为什么会发生这种情况以及如何使 python 将 MATLAB 单曲识别为 32 bits/4 字节吗?
更新
事实证明,即使是 MATLAB 也无法正确解释它的单曲;我已经意识到 MATLAB 接收器脚本等待我调用 MATLAB 发送器 4 次,因为它只将每个单个解释为字节(这意味着消息大小只有 5 个字节而不是 20 个字节)。此外,当消息的某个元素更改为小数(例如 5.7)时,则在输出时四舍五入为 6。
你的字节在那里,你只是看不到它们。
替换你的:
print(buffer)
有:
print(ord(buffer))
而且它们应该神奇地凭空出现。
您可能想使用 struct.unpack
来获得您想要的单身人士。
编辑: 如下所述,问题是您需要明确说明要用于从 Matlab 写入端口的精度。如果不这样做,它将使用无符号的 8 位默认值。
这样做:
fwrite(s, dataToSend, 'single')
已解决问题。
总结
我有一个 MATLAB 脚本使用一对遥测无线电向 Python 脚本发送串行消息。 MATLAB 数据都是单数(32 位浮点数,IEEE Standard 754)。但是,当 Python 收到串行消息时,它将每个数字解释为单个字节而不是 4。
背景
我是运行Windows10,MATLAB R2018a,Python3.7,用一对Holybro Telemetry Radios进行通信。这些无线电对于两个 MATLAB 脚本之间的串行通信工作得很好,这让我相信这个问题与 Python 如何解释 MATLAB 单一数据类型有关。
我的代码
MATLAB 发送器
这是发送消息的代码:
comport = 'COM6'
s = serial(comport);
s.BaudRate = 57600;
try
fopen(s);
headerToSend = single([112 112]);
packetToSend = single([3 4 5]);
dataToSend = [headerToSend packetToSend];
fwrite(s,dataToSend);
disp('Data sent is: ')
disp(dataToSend)
fclose(s);
delete(s);
whos dataToSend
catch ME
disp(ME.message)
end
请注意,消息可以包含转换为单数的整数或无法简化为整数的十进制数(如 0.1
)。
Python 接收器
这是接收消息的代码:
import serial
import time
import sys
dat = []
# Open serial port
ser = serial.Serial(
port='COM3',
baudrate=57600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
timeout=0.1)
try:
# Main loop
while (True):
buffer = ser.read(4)
print("Buffer: ")
print(buffer)
time.sleep(1)
except KeyboardInterrupt:
ser.close()
sys.exit()
MATLAB 接收器(用于比较)
为了比较,我在 MATLAB 中复制了一个接收器来验证发送器是否正常工作:
clc;clear;
comport = 'COM3';
s = serial(comport);
s.BaudRate = 57600;
try
fopen(s);
data = [];
% Receive response data
pause(0.5);
expectedDataLength = 20; % 2 headers and 3 msg, each 4 bytes
data = fread(s,expectedDataLength)
fclose(s);
delete(s);
catch ME
disp(ME.message)
end
if isempty(data)
disp('Unable to read any data.');
else
%Logic to find the packet after stripping the header
data = data';
header = single([112 112]);
%Find the starting indices of 'header' in the 'data' received. It is
%expected to be 112 in this case
k = strfind(data,header);
if ~isempty(k) && any(ismember(k,1))
%get the packet data by stripping the header
packet = data(length(header)+1:expectedDataLength);
end
% The msg values are in the order x, y, and z.
msg1 = typecast(single(packet(1)),'single');
msg2 = typecast(single(packet(2)),'single');
msg3 = typecast(single(packet(3)),'single');
%display the msg data on screen
disp(['Message Data ', num2str(msg1),' | ', num2str(msg2), ' | ', num2str(msg3), '.'])
end
预期结果
我希望缓冲区读取:
b'x00\x00\x00\x70'
b'x00\x00\x00\x70'
b'x00\x00\x00\x03'
b'x00\x00\x00\x04'
b'x00\x00\x00\x05'
对于包含 [112 112 3 4 5]
当使用上面显示的 MATLAB reader 时,它可以正确解释消息。请参阅底部的更新。
实际结果
缓冲区改为:
b'pp\x03\x04'
b'\x05'
似乎在 python 端,它已将消息的每个元素塞进一个字节(p
是 112
,x03
是 3
等等)。
使用 whois dataToSend
确认它是一个 1x5 的单身数组,由 20 个字节组成(或者至少是,在被接收之前)。
问题
知道为什么会发生这种情况以及如何使 python 将 MATLAB 单曲识别为 32 bits/4 字节吗?
更新
事实证明,即使是 MATLAB 也无法正确解释它的单曲;我已经意识到 MATLAB 接收器脚本等待我调用 MATLAB 发送器 4 次,因为它只将每个单个解释为字节(这意味着消息大小只有 5 个字节而不是 20 个字节)。此外,当消息的某个元素更改为小数(例如 5.7)时,则在输出时四舍五入为 6。
你的字节在那里,你只是看不到它们。
替换你的:
print(buffer)
有:
print(ord(buffer))
而且它们应该神奇地凭空出现。
您可能想使用 struct.unpack
来获得您想要的单身人士。
编辑: 如下所述,问题是您需要明确说明要用于从 Matlab 写入端口的精度。如果不这样做,它将使用无符号的 8 位默认值。
这样做:
fwrite(s, dataToSend, 'single')
已解决问题。