【问题标题】:Using Python to read MATLAB singles over serial使用 Python 通过串行读取 MATLAB 单曲
【发布时间】:2019-08-13 00:02:38
【问题描述】:

总结

我有一个 MATLAB 脚本,它使用一对遥测无线电向 Python 脚本发送串行消息。 MATLAB 数据都是单数(32 位浮点数,IEEE Standard 754)。然而,当 Python 接收到串行消息时,它会将每个数字解释为单个字节而不是 4。

背景

我正在运行 Windows 10、MATLAB R2018a、Python 3.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 阅读器时,它可以正确解释消息。请参阅底部的更新。

实际结果

缓冲区改为:

b'pp\x03\x04'
b'\x05'

似乎,在 python 端,它把消息的每个元素都塞进了一个字节(p112x033 等等)。 使用whois dataToSend 确认它是一个 1x5 的单数数组,由 20 个字节组成(或者至少在接收之前是这样)。

问题

知道为什么会发生这种情况以及如何让 python 将 MATLAB 单曲识别为 32 位/4 字节吗?

更新

事实证明,即使 MATLAB 也无法正确解释其单曲;我已经意识到 MATLAB 接收器脚本等待我调用 MATLAB 发送器 4 次,因为它只将每个单个解释为字节(意味着消息大小只有 5 个字节而不是 20 个)。此外,当消息中的某个元素更改为小数(例如 5.7)时,在输出时,它会四舍五入为 6。

【问题讨论】:

    标签: python matlab serial-port


    【解决方案1】:

    你的字节在那里,你只是看不到它们。

    替换你的:

    print(buffer)
    

    与:

    print(ord(buffer))
    

    它们应该会神奇地凭空出现。

    您可能想使用struct.unpack 来获取您想要的单曲。

    编辑: 如下所述,问题是您需要明确说明要用于从 Matlab 写入端口的精度。如果不这样做,它将使用无符号的 8 位默认值。

    这样做:

    fwrite(s, dataToSend, 'single')

    解决了问题。

    【讨论】:

    • 如果单曲代表integer,则使用ord 有效,但在我的情况下,单曲也可以是十进制数;其中,它不起作用。我更新了我的问题,包括发送的数字可以是十进制的。我编写这些脚本是为了调试为什么 struct.unpack 在我的主程序中不起作用,所以恐怕这也不起作用(至少,没有一些更详细的指导)。
    • 我明白了......如果没有其他人加入,我明天会更新我的答案。
    • 为什么它们会“神奇地凭空出现”?为什么当我逐字节读取时没有检测到它们,但使用ord 出现?谢谢回答!我希望我可以只使用整数,但不幸的是我需要精度
    • 再看一遍,我不太明白:你确定 Matlab 发送的是前导零吗?如果您没有明确指出您想要的精度,我认为它们会被丢弃。也许你可以试试fwrite(s,dataToSend,'single')
    • fwrite(s,dataToSend,'single') 中指定single 成功了! MATLAB documentation 实际上指定:"If precision is not specified, uchar (an 8-bit unsigned character) is used." 所以添加 single 修复了 python 脚本的输出:b'\x00\x00\xe0B' b'\x00\x00\xe0B' b'\x00\x00@@' b'\x00\x00\x80@' b'ff\xb6@'(正确的值)。太感谢了!您能否修改您的原始答案以包括将single 添加到fwrite 命令?我会将其标记为已接受的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    • 2018-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-11-04
    • 2019-01-19
    相关资源
    最近更新 更多