Summary
I have a MATLAB script sending a serial message to a Python script using a pair of telemetry radios. The MATLAB data are all singles (32 bit float, IEEE Standard 754). When Python receives the serial message, however, it interprets each number as a single byte instead of 4.
Background
I'm running Windows 10, MATLAB R2018a, Python 3.7 and using a pair of Holybro Telemetry Radios to communicate. These radios work just fine for serial communication between two MATLAB scripts, which makes me believe the issue has to do with how Python interprets the MATLAB single data type.
My code
MATLAB Sender
This is the code that is sending the message:
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
Note that the message can contains integers that are converted to singles or decimal numbers (like 0.1
) that can't be simplified to ints.
Python Receiver
This is the code that is receiving the message:
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 Receiver (for comparison)
For comparison, I copied a receiver in MATLAB to verify that the sender was functioning properly:
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
Expected result
I would expect the buffer to read:
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'
For the message containing [112 112 3 4 5]
When using the MATLAB reader shown above, it can interpret the message properly. See the update at the bottom.
Actual result
Instead the buffer reads:
b'pp\x03\x04'
b'\x05'
It seems that, on the python end, it has crammed each element of the message into a single byte (p
being 112
, x03
being 3
and so forth).
Using whois dataToSend
confirms that it is a 1x5 array of singles, composed of 20 bytes (or at least it is, before being received).
The question
Any idea why this is happening and how to make python recognize MATLAB singles as 32 bits/4 bytes?
Update
So it turns out not even MATLAB can interpret its singles properly; I've realized that MATLAB receiver script waits for me to call the MATLAB sender 4 times, as it only interprets each single as byte (meaning the message size is only 5 bytes instead of 20). Furthermore, when an element of the message is changed to a decimal (say, 5.7), then at the output, it is rounded to 6.