I have ArduinoUNO, I use Python3. I want to make a single LED ON and OFF on command. But I get errors.
ON
TypeError: unicode strings are not supported, please encode to bytes: 'H'
OFF
TypeError: unicode strings are not supported, please encode to bytes: 'L'
What I am doing wrong?
Here's my code:
import serial
import time
arduino = serial.Serial("COM3", 9600)
def onOffFunction():
command = input("Type in something (on/off/bye): ");
if command == "on":
print ("The LED is ON")
time.sleep(1)
arduino.write('H')
onOffFunction()
elif command == "off":
print ("The LED is OFF")
time.sleep(1)
arduino.write('L')
onOffFunction()
elif command == "bye":
print ("Bye Bye!")
time.sleep(1)
arduino.close()
else:
print ("Sorry.. Try typing something else.")
onOffFunction()
time.sleep(2)
onOffFunction()
An explanation can be found here:
Writing data to Arduino is easy too (the following applies to Python
2.x):
import serial # if you have not already done so
ser = serial.Serial('/dev/tty.usbserial', 9600)
ser.write('5')
In Python 3.x the strings are Unicode by default. When sending data to
Arduino, they have to be converted to bytes. This can be done by
prefixing the string with b:
ser.write(b'5') # prefix b is required for Python 3.x, optional for Python 2.x
Adding prefix b' (byte conversion) has helped to make code errorless, however, ArduinoUNO does not respond to Python3 but responds to ArduinoIDE.
Related
We are trying to communicate from Python to our Arduino, but are encountering an issue when writing to the serial port from python
import serial
import time
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
time.sleep(2)
user_input = 'L'
while user_input != 'q':
user_input = input('H = on, L = off, q = quit' )
byte_command = user_input.encode()
print(byte_command)
ser.writelines(byte_command) # This line gives us the error.
time.sleep(0.5) # wait 0.5 seconds
print('q entered. Exiting the program')
ser.close()
The following is the error that we receive:
return len(data)
TypeError: object of type 'int' has no len()
Your code works on my computer. I think the function you're trying to use (writelines) was added not that long ago to pyserial so maybe you are running on an outdated version.
In any case, as far as I know, writelines is inherited from the file handling class and you don't really need to use it for what you're trying to do. Actually I don't think it's even well documented
Just change it to:
ser.write(byte_command)
If you prefer you can see what version of pyserial you have and/or update.
To check your version run: pip3 list | grep serial
If you don't have version 3.4 you can update with: pip3 install pyserial --upgrade
Considering how writelines works for files (see, for instance here) your error might actually be related to the core Python you have (for your reference I'm running Python 3.7.3).
writelines accepts a list of strings so you can't use it to send a single string. Instead use write:
import serial
import time
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
time.sleep(2)
user_input = 'L'
while user_input != 'q':
user_input = input('H = on, L = off, q = quit')
byte_command = user_input.encode()
print(byte_command)
ser.write(byte_command) # This line gives us the error.
time.sleep(0.5) # wait 0.5 seconds
print('q entered. Exiting the program')
ser.close()
I have a small python example I got off another website. I am trying to understand how to read from serial using it.
I am sending a message from a FRDM K64f board over serial and the python program reads this but returns a strange values, below is an example of one of them:
YVkJ�ZC
My python code:
import time
import serial
# configure the serial connections (the parameters differs on the device you are connecting to)
ser = serial.Serial(
port='/dev/ttyACM0',
baudrate=9600,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS
)
ser.isOpen()
print 'Enter your commands below.\r\nInsert "exit" to leave the application.'
input=1
while 1 :
# get keyboard input
input = raw_input(">> ")
# Python 3 users
# input = input(">> ")
if input == 'exit':
ser.close()
exit()
else:
# send the character to the device
# (note that I happend a \r\n carriage return and line feed to the characters - this is requested by my device)
ser.write(input + '\r\n')
out = ''
# let's wait one second before reading output (let's give device time to answer)
time.sleep(1)
while ser.inWaiting() > 0:
out += ser.read(1)
if out != '':
print ">>" + out
This is my code for the board:
int main(){
Serial pc(USBTX, USBRX);
pc.baud(9600);
while(1){
char c = pc.getc();
if((c == 'w')) {
pc.printf("Hello");
}
}
}
The exact return I get is this:
Enter your commands below.
Insert "exit" to leave the application.
>> w
>>YVkJ�ZC
>>
Managed to solve this.
My declaration of serial didn't seem to be working properly.
Went back to pyserial documentation and declaring my serial like below and using readline() solved the problem.
ser = serial.Serial('/dev/ttyACM0')
I wrote a Python script in which I can send fixed bytes through a COM port.
ser.write(bytes('0123456789',encoding='ascii'))
I want to parameterize the number of bytes that the script can send.
Can anyone please suggest me how I can do this?
Thanks.
By "random" I think you mean "arbitrary", i.e. how to send an arbitrary number of bytes...
You can generate a sequence of repeating digits like this:
>>> ''.join([str(i%10) for i in range(21)])
'012345678901234567890'
The number of bytes required can be passed to the script as a command line argument. Its value will be available in the sys.argv[] list.
import sys
import serial
try:
num_bytes = int(sys.argv[1])
except (IndexError, ValueError):
sys.stderr.write('Usage: {} num-bytes\n'.format(sys.argv[0]))
sys.exit(1)
ser = serial.Serial() # set up your serial port
digits = ''.join(str(i%10) for i in range(num_bytes))
num_written = ser.write(bytes(digits, 'ascii'))
Invoke the command like this:
$ python3 send_bytes.py 42
I am trying to send the followings ASCII command:
close1
using PySerial, below is my attempt:
import serial
#Using pyserial Library to establish connection
#Global Variables
ser = 0
#Initialize Serial Port
def serial_connection():
COMPORT = 3
global ser
ser = serial.Serial()
ser.baudrate = 38400
ser.port = COMPORT - 1 #counter for port name starts at 0
#check to see if port is open or closed
if (ser.isOpen() == False):
print ('The Port %d is Open '%COMPORT + ser.portstr)
#timeout in seconds
ser.timeout = 10
ser.open()
else:
print ('The Port %d is closed' %COMPORT)
#call the serial_connection() function
serial_connection()
ser.write('open1\r\n')
but as a result I am receiving the following error:
Traceback (most recent call last):
, line 31, in <module>
ser.write('open1\r\n')
, line 283, in write
data = to_bytes(data)
File "C:\Python34\lib\site-packages\serial\serialutil.py", line 76, in to_bytes
b.append(item) # this one handles int and str for our emulation and ints for Python 3.x
TypeError: an integer is required
Not sure how I would be able to resolve that. close1 is just an example of an ASCII command I want to send there is also status1 to see if my locks are open or close, etc.
Thanks in advance
This issue arises because Python 3 stores its strings internally as unicode but Python 2.x does not. PySerial is expecting to get a bytes or bytearray as a parameter to write. In Python 2.x the string type would be fine for this but in Python 3.x the string type is Unicode and hence not compatible with what pySerial write needs.
In order to use pySerial with Python 3 you need to use a bytearray. So your code would look need to look like this instead:
ser.write(b'open1\r\n')
Based on Chapter 12 of the OTP in Action book and Cesarini's book I wrote this Erlang code:
Erlang:
p(Param) ->
?DBG("Starting~n", []),
Cmd = "python test.py",
Port = open_port({spawn,Cmd}, [stream,{line, 1024}, exit_status]),
?DBG("Opened the port: ~w~n", [Port]),
Payload = term_to_binary(list_to_binary(integer_to_list(Param))),
erlang:port_command(Port, Payload),
?DBG("Sent command to port: ~w~n", [Payload]),
?DBG("Ready to receive results for command: ~w~n", [Payload]),
receive
{Port, {data, Data}} ->
?DBG("Received data: ~w~n", [Data]),
{result, Text} = binary_to_term(Data),
Blah = binary_to_list(Text),
io:format("~p~n", [Blah]);
Other ->
io:format("Unexpected data: ~p~n", [Other])
end.
Python:
import sys
def main():
while True:
line = sys.stdin.readline().strip()
if line == "stop-good":
return 0
elif line == "stop-bad":
return 1
sys.stdout.write("Python got ")
sys.stdout.write(line)
sys.stdout.write("\n")
sys.stdout.flush()
if __name__ == "__main__":
sys.exit(main())
The Erlang code suspends at the recieve clause - it never gets any message.
I have also checked Python from a regular Linux shell - it prints out every user input (1 - "Python got 1").
Where is the mistake here? Why doesn't my Erlang code get anything back?
There are two points:
make sure that Python does not buffer your output, try running python -u in open_port
using term_to_binary/1 and binary_to_term/1 won't work, since they assume that Python is able to encode/decode Erlang External Term Format, which does not seem to be the case. If you want to go this route, check out ErlPort
Does your Param contain the command limiter for Python? (in this case I assume newline, "\n"). Also, list_to_binary/1 and then a term_to_binary/1 feels kinda wrong. term_to_binary/1 directly (including the newline) should be sufficient.