Pular para o conteúdo

Firmata: a placa como periférico

O protocolo, os doze modos de pino, o relatório periódico — e o erro nº 1 de quem começa.

Com o StandardFirmata gravado, a placa deixa de ter um programa e passa a ter um protocolo: ela obedece. Quem decide é o computador, e isso muda o ciclo de trabalho por inteiro.

Sem FirmataCom Firmata
escrever C++, compilar, gravar, testarchamar placa.escrever(13, yes) e ver o LED
~20 s a cada tentativamilissegundos
depurar por Serial.printlndepurar com dataforge debug

Todo pino tem um modo, e ele é declarado#

os modos mais usados
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")

placa.modo(13, "saida")          // LED, relé
placa.modo(2, "entrada_pullup")  // botão, sem resistor externo
placa.modo(9, "pwm")             // brilho, velocidade
placa.modo(3, "servo")           // posição
placa.modo(14, "analogico")      // A0 — sensor

assert "pwm" in IoT.modos()      // a lista dos doze
placa.fechar()
dataforge
adopt Arcane.IoT as IoT

out IoT.modos()
assert len(IoT.modos()) is 12

Declarar o modo por conta própria seria conveniente e errado: um pino em saida recebendo PWM acende no talo, e quem lê o programa não veria onde o modo mudou. Por isso pwm e servo exigem o modo já declarado:

dataforge
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")
monitor:
    placa.pwm(9, 128)                 // sem o modo
handle Error as e:
    out e.message                     // …precisa do modo declarado
placa.modo(9, "pwm")
assert placa.pwm(9, 128) is 128
placa.fechar()

O erro nº 1: ler analógico sem pedir o relatório#

A placa não responde perguntas sobre o analógico: ela envia sozinha, de tempos em tempos, os canais que você mandou relatar. Sem relatar_analogico, o pino está certo, o sensor está certo, e a leitura é zero — sem nenhum erro.

dataforge
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")
placa.modo(14, "analogico")
placa.simulador.definir_analogico(0, 900)   // o sensor "vale" 900
sleep(100)
assert placa.analogico(0) is 0              // e chega ZERO

placa.relatar_analogico(0)                  // é esta linha que falta
sleep(120)
assert placa.analogico(0) is 900
placa.fechar()

A amostragem é uma troca#

dataforge
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")
assert placa.amostragem(50) is 50       // de 10 a 10000 ms; o padrão é 19
placa.fechar()
  • Baixa demais enche a serial de mensagens e atrasa as ordens que você manda — o LED demora a responder ao clique.
  • Alta demais faz o gráfico perder detalhe, e um botão lido por relatório parecer que "não pegou".
  • Para um sensor de temperatura, 500 ms é generoso. Para um potenciômetro que move um servo, 20 ms.

Reagir, em vez de perguntar#

dataforge
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")
vistos := []
placa.observar(lambda e: vistos.append(e["tipo"]))

placa.modo(2, "entrada_pullup")
placa.simulador.definir_digital(2, 1)
sleep(120)
placa.simulador.definir_digital(2, 0)
sleep(120)

assert "digital" in vistos
placa.fechar()

O sketch também fala#

Firmata.sendString("…") no C++ chega aqui como texto — é o println de quem usa Firmata:

dataforge
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")
placa.simulador.mandar_texto("calibração concluída — ção, á, ê")
sleep(120)
assert "calibração" in placa.textos()[0]
placa.fechar()

Fechar desliga as saídas#

dataforge
adopt Arcane.IoT as IoT

placa := IoT.conectar_simulada("uno")
placa.modo(13, "saida")
placa.escrever(13, yes)
placa.fechar()
assert placa.simulador.pino(13) is 0        // apagou ao sair

Um programa que termina deixando um relé ligado é o defeito mais caro desta área: o resto do sistema continua, sem ninguém olhando. fechar é idempotente — chamá-lo num defer e de novo no fim não é erro.