Question:
I'm using pyserial module to send serial data, so I have a list of values like:
Valores = [10,20,30,40,50,60,70,80,90,100]
I need to transform the list values into bytes to be able to send, because if I try to send like this:
Serial.write(Valores)
Or like this:
Serial.write(10)
I get this error:
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 518, in write
d = to_bytes(data)
File "/usr/lib/python3/dist-packages/serial/serialutil.py", line 61, in to_bytes
for item in seq:
TypeError: 'int' object is not iterable
But if you send it according to the line below it works!
Serial.write(b'10')
How can I do this conversion of values?
Answer:
In Python 3 the built-in "bytes" itself does this:
>>> bytes([40,10,20,30])
b'(\n\x14\x1e'
In Python 2, what are now "bytes" were the equivalent of strings. However in Python 3 they separated: strings are objects containing text, where each element is a unicode codepoint – and it doesn't matter its numerical value, and the old "byte-string" became known as bytes, and functioning as in C: if a value happens to have an ASCII representation (numeric value from 32 to 128), it is printed, otherwise it is printed with the encoding of two hexadecimal digits. Internally, it's just a numeric sequence of bytes, and it's already the type accepted by all relevant functions that deal with the serial port.
In the case of your examples specifically, you can do:
serial.write(bytes((10,))
(the (10,)
is a tuple of a single number – the trailing comma is not optional.
Or:
serial.write(b"\x0a")
The "b" prefix for the quotes indicates that it's a byte literal, not text – and you can put numbers directly in hex notation inside the quotes.
Since you are using serial communication, you may have to send data records with several fields of predetermined size. In this case, you can use the "struct" module that comes with Python: it transforms into a bytes object, in the correct order, a sequence of parameters according to a format string – https://docs.python.org/3/ library/struct.html
For example, if you have to send two unsigned 16-bit numbers, followed by a 32-bit floating point number:
>>> struct.pack("<HHf", 40000, 50000, 3.28)
b'@\x9cP\xc3\x85\xebQ@'
To extract the numbers from an object of type bytes, just use it as a normal sequence. In Python 3 an element of a sequence of bytes is an unsigned 8-bit number:
>>> a = b"minha_resposta:\xff"
>>> print(list(a))
[109, 105, 110, 104, 97, 95, 114, 101, 115, 112, 111, 115, 116, 97, 58, 255]
In Python 2 it is necessary to explicitly convert the element from bytes to integer – and the ord
function can be used for this:
Python 2.7.14 (default, Jan 17 2018, 14:28:32)
>>> a = b"minha_resposta:\xff"
>>> print(list(a))
['m', 'i', 'n', 'h', 'a', '_', 'r', 'e', 's', 'p', 'o', 's', 't', 'a', ':', '\xff']
>>> print(map(ord, a))
[109, 105, 110, 104, 97, 95, 114, 101, 115, 112, 111, 115, 116, 97, 58, 255]