Controlando a Arduino com PHP via porta serial

É isso mesmo, o PHP pode escrever ou ler dados da porta serial, e com isso podemos controlar a Arduino.

Você pode ligar o seu ar-condicionado, cafeteira, luz, etc… via Internet, e de uma forma bem simples.
Serialproxy também é uma ótima forma de se conectar a Arduino via Internet, utilizei no projeto Twitter Hardware, mas este post é sobre PHP, então vamos lá.

Arduino + PHP Diagram

Vou utilizar o exemplo descrito no post “Controlando Led RGB com Arduino e Processing” (trocando o Processing pelo PHP).

A função fopen do PHP da suporte a escrita na porta serial:

1
2
3
$port = fopen('COM2', 'w');
fwrite($port, '1');
fclose($port);

Linha 1) Abre a conexão com a COM2 (porta serial onde a minha Arduino está conectada).
Linha 2) Escreve na porta
Linha 3) Fecha a conexão

Código PHP do exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
/**
 * Arduino + PHP
 *
 * @author  Bruno Soares
 * @website www.bsoares.com.br
 */


$color = $_REQUEST['color'];

if (isset($color) && !empty($color)) {
    $color = hexdec($color);
    $message = '^' . $color . '$';

    // USB Serial Port (COM2)
    $portAddress = 'COM2';
   
    // Open connection on port
    $port = fopen($portAddress, 'w');
   
    // Necessary when the Arduino reset after the connection
    sleep(2);
   
    // Send chars
    fwrite($port, $message);
   
    // Close connection
    fclose($port);
}
?>

Linha 12) Converte a cor de hexadecimal para decimal.
Linha 13) Coloca os caracteres que indicam o inicio e fim da mensagem.
Linha 16) Define a variável com o endereço da porta (no meu caso COM2).
Linha 19) Abre a “conexão” com a porta serial.
Linha 22) Pausa o código por 2 segundo, pois a Arduino costuma reiniciar quando é feita uma conexão a ela.
Linha 25) Escreve a mensagem com a cor na porta serial.
Linha 28) Fecha a “conexão” com a porta serial.

Update 09/07/2009:
Lendo dados:
Tenho recebido diversos e-mails e até alguns comentários de pessoas que precisam ler dados de um sensor, potenciometro, ou qualquer coisa conectada a Arduino, e isso via PHP. Então vamos lá, preparei um código que faz isso de forma fácil.
Acredito que um problema que o pessoal tem tido com esta tarefa é: você deve se dar tempo para a mensagem chegar a Arduino (não que isso seja muito tempo), e também para que a Arduino consiga responder:

Código Arduino:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * Arduino + PHP
 *
 * @author  Bruno Soares
 * @website www.bsoares.com.br
 */


#define ANALOG_PIN 4

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available() > 0) {
    if (Serial.read() == '1')
      Serial.print(analogRead(ANALOG_PIN), DEC);
  }
}

Código PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
/**
 * Arduino + PHP
 *
 * @author  Bruno Soares
 * @website www.bsoares.com.br
 */


// Conecta na porta
$port = fopen('COM2', 'w+');

// Em alguns casos a Arduino pode reiniciar, por isso
// é bom esperar para enviar informação depois de conectar
sleep(2);

// Envia "1" para o programa na Arduino saber que deve responder
fwrite($port, '1');

// Espera para que o dado enviado pelo PHP chegue até a Arduino
sleep(1);

// Agora que a Arduino "Provavelmente já respondeu", pega
// o valor da resposta
echo fgets($port);

// Fecha a conexão com a porta
fclose($port);
?>

O que esse código faz?
A Arduino fica em loop esperando receber pela porta serial o numero 1, assim que recebido ela lê a voltagem do pino analógico 4 e escreve na porta serial.
O PHP abre a porta serial, escreve “1″, e espera para ler novamente, quando lê novamente encontra o valor do pino analógico 4, assim como a Arduino escreveu.
Bom, espero que este exemplo acabe com as dúvidas do pessoal que precise ler dados da Arduino :)

Observações:
Caso você precise fazer um projeto onde muitos usuário vão acessar o script que escreve na porta serial, você deve implementar uma fila, de forma a não ter um usuário escrevendo na porta ao mesmo tempo que outro, isto geraria um erro.
O código fonte escrito para a Arduino é o mesmo do post Controlando Led RGB com Arduino e Processing

Faça o download do código fonte aqui.

Conteúdo relacionado:
Arduino: http://www.arduino.cc/
Referência: http://www.arduinoprojects.com/?q=node/10
jQuery ColorPicker: http://www.eyecon.ro/colorpicker/


Posts relacionados:

  1. Controlando Led RGB com Arduino e Processing
  2. PianoDuino (Arduino + Processing + SoundCipher)
  3. Ping Pong com Matriz de Leds 8×8
  4. Operações binárias
  5. Classe C++ para controlar Display de 7 seguimentos

  1. Bruno Soares disse:

    Respondendo a pergunta de Leandro (via contato por e-mail), sim é possível ler dados da porta serial via php. O comando file_get_contents, fread, fgets, e outros podem ler esses dados.
    Mas dependendo da aplicação recomendo usar um Serialproxy (como feito no projeto Twitter Hardware). Estou para fazer um post sobre este assunto já faz um bom tempo, só preciso finalizar um outro experimento para utilizar a arduino na montagem de um post sobre o Serialproxy..

    Caso seja melhor para o seu projeto ler a porta via PHP, recomendo que você escreva um bit pedindo o dado e prepare a arduino para escrever o valor necessário toda vez que receber esse bit da porta. Você só precisa tomar cuidado que a arduino costuma reiniciar quando é feita uma conexão via porta serial.

    De qualquer forma, experimente o Serialproxy ;-)

  2. jacob disse:

    Could I control the my security cameras with it. debt

  3. Bruno Soares disse:

    Olá jacob, você pode sim, mas aconselho a usar serial proxy! tem uma resposta muito boa.

  4. Bruno Soares disse:

    Dê uma olhada no post http://blog.bsoares.com.br/arduino/twitter-hardware , você pode usar de exemplo. Fiz um programa em Adobe AIR (ActionScript) que se conecta no serialproxy de uma maquina qualquer para enviar comandos para a Arduino.

  5. Amauri disse:

    Ai amigo…sou estudante na area de desenvolvimento…
    emulei aqui uma porta serial e tudo funcionou….mas só enviando dados…
    o lance agora é ler….
    não acho nenhuma documentação…só me resta vc msm amigo.. srsrsrrsrs…
    estamos aqui no aguardo…
    abraços

  6. Bruno Soares disse:

    Olá Amauri, então o primeiro comentário responde a sua pergunta http://blog.bsoares.com.br/php/controlling-arduino-with-php/comment-page-1#comment-1677

    Caso seja melhor para o seu projeto ler a porta via PHP, recomendo que você escreva um bit pedindo o dado e prepare a arduino para escrever o valor necessário toda vez que receber esse bit da porta. Você só precisa tomar cuidado que a arduino costuma reiniciar quando é feita uma conexão via porta serial.

    De qualquer forma, experimente o Serialproxy ;-)

  7. Amauri disse:

    Blz amigo….vou dar uma estudada …
    Só mais uma coisa acima vc falou que eu poderia fazer a leitura com fread,fgets e por ai vai…..
    eu até consigo enviar dados para a serial…mas não ler esses dados…
    amigo será q vc poderia mandar um exemplo vc iria estar dando uma força e tanto…
    só o trexo de leitura pq enviar dados eu consigo…
    abraços e to no aguardo amigo…

  8. Bruno Soares disse:

    Salve Amauri! Acabei achando melhor fazer um Update no meu post explicando melhor a sua dúvida, da um olhada, preparei o código e comentei ele para não ter erro :)

    []’s

  9. Amauri disse:

    Opá..amigo obrigado pela explicação…
    Mas eu quero msm é fazer a troca de dados com relogio de ponto catraca para controle de acesso e tal…e tipo..consigo mandar dados tranquilamente, mas não consigo fazer a leitura..
    esse tipo de conexão é realizada de forma diferente ?? ou posso usar da msm forma ??

  10. Bruno Soares disse:

    Amauri, da uma olhada no post na parte “Lendo dados” que tem um exemplo bem bacana. Presta bem atenção no delay que você precisa dar para esperar o dado chegar a porta…

  11. felipe duardo disse:

    Olá!

    é exatamente isso que eu preciso! ler um porta serial ou usb…
    só que agora quero saber se a porta serial poderia ser lida do
    client ? ou nao tem como?

    exemplo o cara vai ter um botão ali que ele clica e pega os dados
    da porta que esta na maquina dele, acho que por php nao seria possivel
    mas quem sabe por js ou sei la sabe me dizer se tem como?

  12. Bruno Soares disse:

    Então Felipe, é possível sim, assim como mostro no vídeo…
    No caso do exemplo deste tutorial estou apenas enviando o RGB para o servidor (via PHP), mas no post tem a explicação de como ler um dado da porta serial via PHP, (Update 09/07/2009: Lendo dados), e como você pode utilizar PHP este dados podem estar em um servidor (ou seja, a máquina que controla a arduino tem PHP e um servidor Apache, IIS.. instalado).

    Mas antes de fazer qualquer coisa com PHP dê uma olhada no post http://blog.bsoares.com.br/arduino/twitter-hardware , você pode usar de exemplo. Fiz um programa em Adobe AIR (ActionScript) que se conecta no serialproxy de uma maquina qualquer para enviar comandos para a Arduino.

    []’s

  13. felipe duardo disse:

    então bruno…
    o que estou precisando é para o uso com um periférico que sera desenvolvido
    aqui pelo pessoal do hardware da empresa, não se sabe se será usb ou serial,
    mas por exemplo eu vou ate uma lan house qualquer conecto o periférico, faço
    um login de acesso restrito a uma pagina e daquela maquina na lan house, que
    conectei o periférico que vou ter que ler a porta serial ou usb, não no php server…
    não sei se estava sendo tão esclarecedor…

  14. Bruno Soares disse:

    Entendi!, bom dessa forma não da não…
    E acredito que você não vai conseguir fazer isso sem ter que instalar um software na maquina, se conseguir da um toque! Bom da uma olhana em processing, pois o export do processing é um Applet, e vc pode usar isso em uma página HTML, mas acredito que acesso a porta COM1, COM2… você não vai ter via internet, mas você pode tentar, se conseguir me da um toque :)

    []’s

  15. Daniel disse:

    Olá Bruno!Seguinte, eu vou ter que fazer um sistema que envie os dados para um letreiro.Para isso, tem o programa VBPainéis.Ainda não sei se este vai ser acessado na porta serial ou pela USB.Foi me passado o protocolo desse programa e tudo mais, mas a minha dúvida é a seguinte:para eu enviar os dados para esse programa o letreiro tem que estar conectado em alguma porta?

  16. Bruno Soares disse:

    Olá Daniel, imagino que você queira utilizar o PHP para enviar estes dados, bom, vc pode tentar enviar a informação via porta serial sem utilizar o VBPainéis.
    Caso este software tenha alguma forma de receber informações de diferentes formas, como um xml salvo em um determinado diretório ou webservices talvez. Você poderia tentar da forma que ele se entegra com software de terceiros.
    Boa sorte

  17. Marcos disse:

    Bruno tenho tentado de todas as formas enviar dados ao arduino pela porta serial (usb) via PHP.

    Tentei com o fwrite e com fputs, mas nenhum dá certo. O RX do arduino nem pisca.
    Mas se eu vou lá no monitor do arduino e digito qualquer valor, o arduino recebe.

    Olha o código PHP que eu estou tentanto:

    if ($port = fopen(“COM11″, “w”)) //COM11 é minha porta USB.
    {
    echo “abriu a porta serial “;
    if (fwrite($port, ‘2′))
    {
    echo “enviou 2 “;
    }
    else
    {
    echo “não enviou “;
    }
    }
    else
    {
    echo “a porta seral NÃO abriu! “;
    }
    fclose($port);

    Se puder me dar uma força, agradeço muito.
    Já tentei em dois PCs rodando WinXP + Apache + PHP e nada até agora.

    Abraço

  18. Bruno Soares disse:

    Olá Marcos, da uma olhada agora, fiz uma pequena alteração, me parece que você esta tendo um problema atipico. Dependendo do seu código a Arduino pode reiniciar quando você se conecta a ela, então se você der uma pausa no seu script, ela volta a funcionar e recebe o dado enviado. Tente usar o comando “sleep” antes de enviar os dados e depois de abrir a porta com a Arduino.

    if ($port = fopen(”COM11″, “w”)) //COM11 é minha porta USB.
    {
    echo “abriu a porta serial “;
    sleep(2);
    if (fwrite($port, ‘2′))
    {
    echo “enviou 2 “;
    }
    else
    {
    echo “não enviou “;
    }
    }
    else
    {
    echo “a porta serial NÃO abriu! “;
    }
    fclose($port);

  19. Marcos disse:

    Bruno, achei o problema!!!!
    Na verdade o problema não estava em nenhuma das duas programações e sim no Windows.
    Veja que eu tava usando COM11 (USB serial), no exemplo que eu passei.

    Descobri que o Windows atribui sempre valores acima de 10 para a COM, quando esta for uma USB. Não sei porque cargas d’água essa comunicação serial não aceita dois caracteres numéricos na “COM”, então ela funciona somente da COM1 até a COM9.

    Vi no site da Microsoft que portas acima de COM9 tem que declarar diferente nas comunicações seriais: “\\.\COM15″, por exemplo. Mas isso não funcionou tb.

    Então a solução foi mudar a porta para uma COM disponível abaixo de 10.

    Para fazer isso temos que entrar no Gerenciador de Hardware e mudar a COM usada pela “USB Serial Port”. A minha COM2 estava livre, coloquei nela daí o sistema funcionou de primeira.

    Coisas de Windows…. Fazer o que, né?
    Bom agora que deu tudo certo, vou ver se organizo essa informação toda e posto no fórum do Arduino, pois deve ter muita gente apanhando disso.

    Mesmo assim te agradeço mto.
    Marcos

  20. Marcos disse:

    Bruno, sabe se tem um jeito de ler a porta serial um pouco mais rápido. Sem usar o Sleep(2) e Speep(1)?

    Pelo que vc falou ela reseta se não usar. É isso mesmo?
    Tem como não resetar.

    Quanto eu testo pelo Serial Monitor na app do Arduino, consigo fazer praticamente em tempo real. Sei que pelo PHP depende de recarregar a página, mas se ficar um pouco mais rápido já melhora bastante.

    Abraço

  21. Bruno Soares disse:

    Salve Marcos, da uma olhada no forum da Arduino, tem outras pessoas com o problema la:
    http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213719666/28#28
    Não testei mas deve funcionar.

    []’s

  22. Rudrigo Lima disse:

    Caro, Amigo

    Estou tentando comunicar com PHP a LPT1(porta paralela) acionar bit’s nos pinos de 2-9 isso é possível assim como a com(serial)

  1. There are no trackbacks for this post yet.

Leave a Reply