sexta-feira, 9 de janeiro de 2015

Arduino através de PHP

Neste post vamos criar um projeto que vai implicar utilizar três linguagens de programação diferentes e tudo para permitir comunicar com um Arduino através do browser.

O objetivo é criar uma página Web que permitirá enviar e receber dados de um Arduino ligado a um servidor Web.

No Arduino implementamos um protocolo muito simples de comunicação que faz a interação com os sensores e comunica com o servidor Web.

O servidor Web é um computador com Windows a correr o Apache e a linguagem de programação utilizada para a criação das páginas será o PHP.

Para permitir a comunicação do PHP com a porta USB do Arduino será desenvolvimento um pequeno programa em C#, modo Consola, que será chamado a partir do PHP com alguns parâmetros e que posteriormente fará a ligação ao Arduino.

Apesar de existirem livrarias de funções em PHP para utilizar a porta série não consegui fazer com que funcionassem em Windows.



No Arduino vamos ter um servo ligado ao pino 9, um LED ligado ao pino 12 e um LDR no pino A0. O pino 9 e o pino 12 são digitais, o pino A0 é um pino analógico. Os pinos analógicos estão ligados a um ADC (Analog Digital Convert) que faz a conversão entre a tensão elétrica recebida e um valor entre 0 e 1024. O valor máximo, por defeito, é de 5 volts que corresponde a 1024.
O pino 9 é um pino com função PWM (Pulse Width Modulation) que permite simular o envio de valores entre 0 (LOW) e 1 (HIGH), é esta função que permite fazer efeito de fade com LEDs.

Neste caso vamos ter um protocolo muito simples que respeita as seguintes regras:
- Se o valor recebido pelo Arduino estiver entre 0 e 180, inclusive, este corresponderá ao ângulo de posicionamento do servo.
- Se o valor recebido é 181 então o LED liga ou desliga, de acordo com o estado anterior.
- Se o valor recebido é 182 então o Arduino envia o valor do LDR.

Assim o código do Arduino fica:

 #include <Servo.h>

Servo myservo; 
int pos = 0;   
int led=0;
int ledPort=12;
int ldrPin=A0;
byte nivelLuz=0;

void setup()
{
  myservo.attach(9); 
  Serial.begin(9600);
  pinMode(ledPort,OUTPUT);
}

void loop()
{
    byte valor;
    if(Serial.available()){
    valor=Serial.read();
    if(valor>=0 && valor<=180) myservo.write(valor);
    if(valor==181){
      if(led==0){
        digitalWrite(ledPort,HIGH);
        led=1; 
      }else{
        digitalWrite(ledPort,LOW);
        led=0;
      }
    }
    if(valor==182){
      delay(150);
      nivelLuz=analogRead(ldrPin);
      Serial.println(nivelLuz);
    }
  }
}

A página Web vai conter um formulário simples com três botões para controlar cada um dos dispositivos presentes no Arduino (LED, LDR e o servo).
Cada botão invoca o programa desenvolvido em C# com o comando e a porta séria a utilizar.

O código PHP fica:
<html>
<body>
    <form method="POST">
        <input type="text" name="angulo">
        <input type="submit" name="bt" value="Servo">
        <input type="submit" name="bt_luz" value="Led">
        <input type="submit" name="bt_ldr" value="Luz">
    </form>
</body>
</html>
<?php
    ini_set("display_errors",1);
    if(!empty($_POST)){
        if(!empty($_POST["bt"])){
            echo "POST servo<br>";
            if(empty($_POST["angulo"])){
                echo "Preencha o angulo<br>";
                return;
            }
            $angulo=$_POST["angulo"];
            $comando="console_servo.exe COM18 ".$angulo;
            $resultado=exec($comando);
        }
        if(!empty($_POST["bt_luz"])){
            echo "POST led<br>";
            $resultado=exec("console_servo.exe COM18 181");
        }
        if(!empty($_POST["bt_ldr"])){
            echo "POST ldr<br>";
            $resultado=exec("console_servo.exe COM18 182 er");
            $resultado=(int)$resultado;
        }
        if($resultado<0) $resultado="";
        echo $resultado."<br>";
    }
?>

O programa em C# inclui uma classe que implementa a comunicação com a porta série.
O código do programa começa por verificar os parâmetros que são passados e em função deles utilizar um objeto criado com base na classe de comunicação para enviar e receber os dados do Arduino.

namespace console_servo
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 1)
            {
                string strler = args[0];
                Comunica portaler = new Comunica(strler);
                int valorlido=portaler.lerLinha();
                Console.Write(valorlido.ToString());
                return;
            }
            if (args.Length == 3)
            {
                string strenvia = args[0];
                byte valorenviar;
                if (byte.TryParse(args[1], out valorenviar) == false)
                {
                    Console.Write("Usage: servo porta valor er");
                    return;
                }
                Comunica portalerenviar = new Comunica(strenvia);
                portalerenviar.envia(valorenviar);
                Thread.Sleep(150);
                int valordevolver = portalerenviar.lerLinha();
                Console.Write(valordevolver);
                return;
            }
            if (args.Length != 2)
            {
                Console.Write("Usage: servo porta valor");
                return;
            }
            byte valor = 0;
            if (byte.TryParse(args[1], out valor)==false)
            {
                Console.Write("Usage: servo porta valor");
                return;
            }
            string str=args[0];
            Comunica porta = new Comunica(str);
            porta.envia(valor);
            Console.Write("ok");
        }

    }
    class Comunica
    {
        string porta;
        SerialPort sp;
        string buffer;

        public Comunica(string porta)
        {
            this.porta = porta;
            sp = new SerialPort(porta);
            sp.Open();
        }
        ~Comunica()
        {
            if (sp.IsOpen) sp.Close();
            sp.Dispose();
        }
        void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            buffer = sp.ReadExisting();
        }
        public void envia(byte x)
        {
            byte[] valores = new byte[2];
            valores[0] = x;
            sp.Write(valores, 0, 1);
        }
        public byte ler()
        {
            byte[] valores=new byte[2];
           
            sp.Read(valores, 0, 1);
            return valores[0];
        }
        public int lerLinha()
        {
            string linha =sp.ReadLine();
            int valor = 0;
            if(int.TryParse(linha, out valor)==false)
                return -1;
            else
                return valor;
        }
    }
}

O projeto completo pode ser descarregado aqui.

Sem comentários:

Enviar um comentário