Python – Comunicação serial com Arduino e pyserial

ArduinoPythonComSerialTopo

Finalmente escrevi o post que de tempos em tempos recebia alguma pergunta ou notava essa questão em fóruns e listas de discussão, sobre como comunicar Python com interface serial, nada melhor do que um exemplo e aproveitando o caso utilizei o próprio Arduino UNO e o modulo pyserial.

 

Vamos ver do que precisamos e em poucas linhas como comunicamos via serial:

(*) Python instalado, eu estou usando a versão 2.7.2
(*) A library python-serial (pyserial)
(*) Arduino UNO
(*) Firmware já gravado no Arduino, no caso usei este aqui que escrevi a um tempo atras

 

 

PySerial

 

No firmware exemplo ele irá me retornar a temperatura quando eu enviar o caractere ‘t’ pela serial.
Confirmando a versão do Python e do Pyserial:

Caso não aparecer nada com o comando pip freeze acima você deve instalar com o comando abaixo:

Agora um exemplo básico para trabalhar com o modulo pyserial:

Vamos entender como funciona, primeiro na linha 4 antes de qualquer coisa eu importo o modulo serial, depois deve iniciar a conexão com a serial com serial.Serial(PORTA_SERIAL, BAUD_RATE), no caso estou usando Linux e o Arduino é um SerialUSB CDC então minha serial é /dev/ttyUSB0 no caso de Windows não tentei mas me parece que é apenas o numero sem o COM, enfim após essa configuração e o baudrate correto no meu caso é 9600 na linha seguinte 7 envio o carácter 5 ao dispositivo pela serial, se tudo ocorrer bem e algo estiver programado para responder na linha 9 é realizado a leitura do que chegar da serial para o computador. Facil não? Python é demais!

Agora utilizando o firmware que já fiz aqui vamos escrever uma aplicação para comunicar com ele.

Código:

Saída:

Beleza, funcionou! Agora vamos entender o que mudou nesse script porque tem coisa nova, eu importei o modulo time que vou explicar já já porque, para iniciar a serial foi do mesmo jeito porém logo abaixo tem o mesmo modulo comentado e com acréscimo de um parâmetro novo o timeout=1, porque no caso se eu mandar conectar e o dispositivo não responder ele vai ficar ocioso aguardando, já se eu setar timeout=1 tem um tempo de 1s para a conexão responder.
Ae criei duas variáveis uma com o carácter ‘t’ na linha 11 e na linha 12 a mesma coisa só que usando o valor em ASCII, na linha 15 implementei algo que não achei na documentação mas como já havia passado por isso que é o tempo de conexão do mesmo e para escrever, deve haver um delay nesse intervalo no caso deste exemplo entre 1.5s e 1.8s fico perfeito, mas já teve caso de .2 ou .5 ficar certo também, e na linha 17 ou 18 escrevo na serial usando ASCII ou o carácter logo na sequencia vem o comport.readline() na linha 20 que irá receber o valor e armazenar na minha variável que logo em seguida é dado um print para mostrar na tela, tudo isso ocorrendo sem grandes emoções finalizamos com o fim da conexão com comport.close() na linha 25.
Só mais um detalhe na conexão da linha 8, que as ações com a serial serão manipuladas pela variável que recebe essa conexão podemos dizer nosso file descriptor da conexão até o momento em que encerramos a comunicação.

Agora se você prestar atenção no exemplo básico que citei e no nosso programa a parte de recepção é diferente, no primeiro instante eu usei ser.read() e depois comport.readline(), é a mesma coisa? Não!

Vamos ver o que muda:

Saída:

Agora usando o terceiro modo:

Saída:

Conseguiu notar a diferença?
comport.readline() : Ira ler até o n ou a linha toda
comport.read() : Ira ler 1 byte
comport.read(N) : Ira ler N bytes informados

No nosso caso 27.37 são 5 caracteres então 5 bytes, vamos tirar a prova.

Saída:

Além dessas opções para o read() temos outras que poucos conhecem/utilizam quando se usa pyserial que são isOpen, name, o próprio file descriptor e as N opções de configuração da conexão, vamos analisar:

Saída:

Opções interessantes, pois com isOpen podemos ver se a porta já esta aberta antes de prosseguir algo, name obtemos o device name da porta conectada e usando o nome do file descriptor da conexão temos um print das configurações que estão sendo utilizadas.
E se eu quiser mudar algum parâmetro da configuração da conexão serial?

Eu adicionei alguns variáveis globais com as configurações desejadas que são da linha 11 a 16 e apliquei meus parâmetros em serial.Serial().
Bom acho que abordei um conteúdo bom sobre conexão serial em Python e que todos consigam usar, qualquer coisa post a duvida nos comentários.

Até a próxima!

Referências

http://pyserial.sourceforge.net/
http://playground.arduino.cc/interfacing/python#.UzNiv86Gcno

Share Button

CC BY-NC-SA 4.0 Python – Comunicação serial com Arduino e pyserial by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

  • Humberto

    Olá Cleiton,
    Muito legal os exemplos postados. Gostaria de expor uma dúvida, da qual não consegui encontrar
    alguém com mesma situação (após um googlada, nenhuma postagem).

    Estou tentando fazer piscar o LED do Arduino utilizando o módulo Serial da Python (Pyserial). Criei botões com Tkinter para ligar e desligar o LED para acionar a comunicação e até esse ponto, tudo bem. No entanto ele envia o comando, o LED é acionado, mas não fica ligado. Apenas dá algumas rápidas piscadelas e apaga. Os códigos parecem Okays, para o arduino e para o Python. Eu observei duas coisas …
    1) O LED só fica acesso, quando antes de acionar pelo Python eu uso o monitor do Arduino para enviar algum comando. Após isso, ele funciona a contento. Inclusive o botão de desligar funciona bem nesta nova situação. O detalhe é que estou importando somente a biblioteca Serial da pyserial, dá forma como publicada em diversos sites (import serial, … ser = serial.Serial(‘porta’,baud_rate), etc …

    2) No entanto quando eu carrego todas bibliotecas da pyserial (serial), o código funciona sem fazer a gambiarra de abrir o monitor e enviar alguma coisa para o arduino. Mas o preço pago
    é que são carregados comandos desnecessários, tornando o código mais carregado.

    Você já passou por isso, e tem alguma explicação para o que ocorre?
    Agradeço qualquer ajuda no sentido de explicar essa esquisitice!?!? :-)))

    Códigos Arduino:

    char val;

    void setup()
    {
    pinMode(13, OUTPUT);
    Serial.begin(9600);

    }

    void loop()

    {
    if(Serial.available() > 0)
    {
    val = Serial.read();
    if(val == ‘a’) digitalWrite(13, HIGH);
    if(val == ‘b’) digitalWrite(13, LOW);
    }

    }

    ===============================================
    Código Python

    # -*- coding: utf-8 -*-
    “””
    Created on Thu Jun 5 20:16:39 2014

    @author: humberto
    “””

    from Tkinter import *
    from serial import *
    #import serial
    import sys
    import time

    s = Serial()
    #s = serial.Serial()
    s.port = ‘/dev/ttyACM0’
    s.baud_rate = 115200
    #timeout = 0
    #s.xonxoff = True

    def Ligar():
    s.open()
    time.sleep(0.1)
    s.setDTR(level=0)
    time.sleep(0.1)
    s.write(‘a’)
    #time.sleep(2)
    s.close()
    #time.sleep(2)

    def Desligar():
    s.open()
    s.write(‘b’)
    s.close()

    GUI = Tk()

    GUI.geometry(“150×100”) # Adicionando um tamanho à janela
    GUI.title(“GuiBlink”) # Adicionando um título à janela

    B1 = Button(text = (“Ligar”), command = Ligar).pack(side = LEFT)
    B2 = Button(text = (“Desligar”), command = Desligar).pack(side = LEFT)

    GUI.mainloop()

    • Vou implementar o cenários e realizar os testes, posto resultados e conclusões em breve.

    • Humberto, demorei mas estou vindo com a solução ;)
      No código Arduino não precisa alterar nada para o seu caso irá funcionar, agora no Python eu mudei algumas coisas e corrigi um problema.

      Vamos lá:

      Código Python

      # -*- coding: utf-8 -*-
      “””
      Created on Thu Jun 5 20:16:39 2014

      @author: humberto
      “””

      from Tkinter import *
      from serial import *
      #import serial
      import sys
      import time

      s = Serial()
      #s = serial.Serial()
      s.port = ‘/dev/ttyACM0′
      #s.baud_rate = 115200
      s.baud_rate = 9600 # Aqui voce deve setar o mesmo baud_rate que esta no Arduino 115200 e 9600 voce terá problemas hoje ou amanha ;)
      #timeout = 0
      #s.xonxoff = True

      print ‘Iniciando comunicacao serial’
      print
      s.open() # Abrindo a comunicacao serial apenas 1 vez

      def Ligar():
      s.write(‘a’)
      #time.sleep(0.4)

      def Desligar():
      s.write(‘b’)
      #time.sleep(0.4)

      GUI = Tk()

      GUI.geometry(“150×100″) # Adicionando um tamanho à janela
      GUI.title(“GuiBlink”) # Adicionando um título à janela

      B1 = Button(text = (“Ligar”), command = Ligar).pack(side = LEFT)
      B2 = Button(text = (“Desligar”), command = Desligar).pack(side = LEFT)

      GUI.mainloop()
      print
      print ‘Fechando comunicacao serial’
      s.close() # Fechando a comunicacao serial apenas 1 vez

      Com essas correções é para funcionar perfeitamente, conectando e desconectado apenas 1 vez e nos def ficando apenas os comandos, não sei como esta seu ambiente mas caso tiver problemas execute o script python com sudo ok?

      Qualquer problema reporte novamente, abraço.

  • GILBERTO FETZNER FILHO

    Oi Cleiton.
    Gostaria de saber como posso fazer para receber 10 dados de tempo gerados pelo arduino para plotar um gráfico. Detalhe. Consigo fazer o gráfico copiando os dados, mas não consigo fazer com que estes dados cheguem até o python.
    Agradeço a atenção.

    • Gilberto, não sei se entendi muito bem sua duvida. Mas se for uma comunicação serial é como fiz no exemplo:

      VALUE_SERIAL=comport.read(5)

      O valor estará no VALUE_SERIAL, você pode combinar e usar uma lista ou dicionario com um for e esses dados depois de N tempos você plota.

      Ajudou?

  • Sergio Jacob

    Valeu, Cleiton!!! Muito didático e vai me ser muito útil.